diff --git a/README.md b/README.md index 31f97c3..5de4742 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,6 @@ See a tree overview of your Infrastructure costs. See which projects, files and Open VS Code and install the [Infracost extension](https://marketplace.visualstudio.com/items?itemName=Infracost.infracost). -This will also install the the [Hashicorp Terraform extension](https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform) extension if you don't already have it. - ![](https://github.com/infracost/vscode-infracost/blob/master/.github/assets/infracost-install.png?raw=true) - ### 2. Connect VS Code to Infracost Once you've installed the extension, you'll need to connect to your editor to your Infracost account. Click the "connect to Infracost" button in the Infracost sidebar. @@ -179,8 +176,7 @@ We love any contribution, big or small. If you want to change the Infracost VS C 1. Clone the repo. 2. `yarn` install all the dependencies. 3. Open the repo in VS Code. -4. Install the [Terraform VS Code extension](https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform) in VS Code. -5. Inside the editor, press F5. VS Code will compile and run the extension in a new Development Host window. -6. Open a Terraform project, and navigate to a valid file. If all the previous steps have been followed correctly, you should see Infracost cost estimates above supported resource blocks. +4. Inside the editor, press F5. VS Code will compile and run the extension in a new Development Host window. +5. Open a Terraform project, and navigate to a valid file. If all the previous steps have been followed correctly, you should see Infracost cost estimates above supported resource blocks. Once you're finished with your work, open a PR, and we'll be happy to review it as soon as possible. diff --git a/package.json b/package.json index a0b51dd..1a16242 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "infracost", "displayName": "Infracost", "description": "Cloud cost estimates for Terraform in your editor", - "version": "0.2.22", + "version": "0.2.23", "publisher": "Infracost", "license": "Apache-2.0", "icon": "infracost-logo.png", @@ -19,9 +19,7 @@ "terraform", "hcl" ], - "extensionDependencies": [ - "HashiCorp.terraform" - ], + "extensionDependencies": [], "repository": { "type": "git", "url": "https://github.com/infracost/vscode-infracost.git" diff --git a/src/block.ts b/src/block.ts index 2175fed..70f7d11 100644 --- a/src/block.ts +++ b/src/block.ts @@ -1,4 +1,4 @@ -import { ViewColumn, WebviewPanel, window } from 'vscode'; +import { Position, Range, ViewColumn, WebviewPanel, window } from 'vscode'; import { TemplateDelegate } from 'handlebars'; import { infracostJSON } from './cli'; import webviews from './webview'; @@ -8,8 +8,11 @@ export default class Block { webview: WebviewPanel | undefined; + lensPosition: Range; + constructor( public name: string, + public startLine: number, public filename: string, public currency: string, public template: TemplateDelegate @@ -21,6 +24,9 @@ export default class Block { this.webview = undefined; }); } + + const position = new Position(this.startLine - 1, 0); + this.lensPosition = new Range(position, position); } key(): string { diff --git a/src/cli.ts b/src/cli.ts index dc59538..9e1eabc 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -16,12 +16,14 @@ export namespace infracostJSON { export interface ResourceMetadata { filename: string; + startLine: number; calls: Call[]; } export interface Call { blockName: string; filename: string; + startLine: number; } export interface CostComponent { @@ -105,6 +107,7 @@ export default class CLI { INFRACOST_CLI_PLATFORM: 'vscode', INFRACOST_NO_COLOR: 'true', INFRACOST_SKIP_UPDATE_CHECK: 'true', + INFRACOST_GRAPH_EVALUATOR: 'true' }, }); diff --git a/src/file.ts b/src/file.ts index b303908..3bc5357 100644 --- a/src/file.ts +++ b/src/file.ts @@ -24,9 +24,9 @@ export default class File { return formatter.format(cost); } - setBlock(name: string): Block { + setBlock(name: string, startLine: number): Block { if (this.blocks[name] === undefined) { - this.blocks[name] = new Block(name, this.name, this.currency, this.template); + this.blocks[name] = new Block(name, startLine, this.name, this.currency, this.template); } return this.blocks[name]; diff --git a/src/lens.ts b/src/lens.ts index bf679a2..a60037a 100644 --- a/src/lens.ts +++ b/src/lens.ts @@ -1,12 +1,8 @@ import { + CodeLens, CodeLensProvider, Event, TextDocument, - CodeLens, - commands, - SymbolInformation, - Position, - DocumentSymbol, } from 'vscode'; import Workspace from './workspace'; import { cleanFilename } from './utils'; @@ -34,75 +30,22 @@ export default class InfracostLensProvider implements CodeLensProvider { logger.debug(`providing codelens for file ${filename}`); const blocks = this.workspace.project(filename); - - const symbols = await commands.executeCommand( - 'vscode.executeDocumentSymbolProvider', - document.uri - ); - if (symbols === undefined) { - logger.debug(`no valid symbols found for file ${filename}`); - return lenses; - } - - for (const sym of symbols) { - logger.debug(`evaluating symbol: ${sym.name}`); - - if (sym.name.indexOf('resource') === -1 && sym.name.indexOf('module') === -1) { - logger.debug(`skipping symbol as not supported for Infracost costs`); + for (const block of Object.values(blocks)) { + if (block.filename !== filename) { continue; } - const line = document.lineAt(getRangeFromSymbol(sym).start); - const resourceKey = sym.name - .replace(/\s+/g, '.') - .replace(/"/g, '') - .replace(/^resource\./g, ''); - - logger.debug(`finding symbol cost using key: ${resourceKey}`); - - if (blocks[resourceKey] !== undefined) { - const block = blocks[resourceKey]; - const cost = block.cost(); - logger.debug(`found Infracost price for symbol: ${resourceKey} cost: ${cost}`); - - let msg = `Total monthly cost: ${cost}`; - if (this.workspace.loading) { - msg = 'loading...'; - } + const cost = block.cost(); - const cmd = new InfracostCommand(msg, block); - lenses.push(new CodeLens(line.range.with(new Position(line.range.start.line, 0)), cmd)); - continue; + let msg = `Total monthly cost: ${cost}`; + if (this.workspace.loading) { + msg = 'loading...'; } - logger.debug(`no registered blocks matching key: ${resourceKey}`); + const cmd = new InfracostCommand(msg, block); + lenses.push(new CodeLens(block.lensPosition, cmd)); } return lenses; } } - -function getRangeFromSymbol(symbol: DocumentSymbol | SymbolInformation) { - return isDocumentSymbol(symbol) ? symbol.range : symbol.location.range; -} - -function isDocumentSymbol(symbol: DocumentSymbol | SymbolInformation): symbol is DocumentSymbol { - return is(symbol, 'children'); -} - -/* eslint-disable @typescript-eslint/no-explicit-any */ -function is(o: T | null | undefined): o is T; -function is(o: object, prop: keyof T, value?: any): o is T; -function is(o: object, matcher: (o: object) => boolean): o is T; -function is( - o: object, - propOrMatcher?: keyof T | ((o: any) => boolean), - value?: any -): o is T { - if (propOrMatcher == null) return o != null; - if (typeof propOrMatcher === 'function') return propOrMatcher(o); - - return value === undefined - ? (o as any)[propOrMatcher] !== undefined - : (o as any)[propOrMatcher] === value; -} diff --git a/src/project.ts b/src/project.ts index cbdcadf..bf12f51 100644 --- a/src/project.ts +++ b/src/project.ts @@ -14,13 +14,13 @@ export default class Project { public template: TemplateDelegate ) {} - setBlock(filename: string, name: string): Block { + setBlock(filename: string, name: string, startLine: number): Block { if (this.files[filename] === undefined) { this.files[filename] = new File(filename, this.currency, this.template); } const file = this.files[filename]; - const block = file.setBlock(name); + const block = file.setBlock(name, startLine); if (this.blocks[name] === undefined) { this.blocks[name] = block; diff --git a/src/workspace.ts b/src/workspace.ts index f2e895d..26441dc 100644 --- a/src/workspace.ts +++ b/src/workspace.ts @@ -305,7 +305,7 @@ export default class Workspace { const filename = cleanFilename(call.filename); logger.debug(`adding file: ${filename} to project: ${projectPath}`); - formatted.setBlock(filename, call.blockName).resources.push(resource); + formatted.setBlock(filename, call.blockName, call.startLine).resources.push(resource); this.addProjectToFile(filename, projectPath); } }