import * as path from 'path' ; import * as vscode from 'vscode' ; import { ExecuteCommandParams , ExecuteCommandRequest } from 'vscode-languageclient' ; import { Utils } from 'vscode-uri' ; import { ClientHandler } from '../clientHandler' ; import { getActiveTextEditor , isTerraformFile } from '../vscodeUtils' ; interface ModuleCall { name : string ; source_addr : string ; version ? : string ; source_type ? : string ; docs_link ? : string ; dependent_modules : ModuleCall [ ] ; } interface ModuleCallsResponse { v : number ; module_calls : ModuleCall [ ] ; } class ModuleCallItem extends vscode . TreeItem { constructor ( public label , public sourceAddr , public version , public sourceType , public docsLink , public terraformIcon , public readonly children ) { super ( label , children . length >= 1 ? vscode . TreeItemCollapsibleState . Collapsed : vscode . TreeItemCollapsibleState . None ) ; this . description = this . version ? `${ this . version }` : '' ; if ( this . version === undefined ) { this . tooltip = `${ this . sourceAddr }` ; } else { this . tooltip = `${ this . sourceAddr }@${ this . version }` ; } } iconPath = this . getIcon ( this . sourceType ) ; getIcon ( type ) { switch ( type ) { case 'tfregistry' : return { light : this . terraformIcon , dark : this . terraformIcon , } ; case 'local' : return new vscode . ThemeIcon ( 'symbol-folder' ) ; case 'github' : return new vscode . ThemeIcon ( 'github' ) ; case 'git' : return new vscode . ThemeIcon ( 'git-branch' ) ; default : return new vscode . ThemeIcon ( 'extensions-view-icon' ) ; } } } export class ModuleCallsDataProvider implements vscode . TreeDataProvider < ModuleCallItem > { private _onDidChangeTreeData : vscode . EventEmitter < ModuleCallItem | undefined | null | void > = new vscode . EventEmitter < ModuleCallItem | undefined | null | void > ( ) ; readonly onDidChangeTreeData : vscode . Event < ModuleCallItem | undefined | null | void > = this . _onDidChangeTreeData . event ; private svg = '' ; constructor ( ctx , public handler ) { this . svg = ctx . asAbsolutePath ( path . join ( 'assets' , 'icons' , 'terraform.svg' ) ) ; ctx . subscriptions . push ( vscode . commands . registerCommand ( 'terraform.modules.refreshList' , ( ) => this . refresh ( ) ) , vscode . commands . registerCommand ( 'terraform.modules.openDocumentation' , ( module ) => { if ( module . docsLink ) { vscode . env . openExternal ( vscode . Uri . parse ( module . docsLink ) ) ; } } ) , vscode . window . onDidChangeActiveTextEditor ( async ( event ) => { const activeEditor = getActiveTextEditor ( ) ; if ( ! isTerraformFile ( activeEditor ?. document ) ) { return ; } if ( event && activeEditor ) { this . refresh ( ) ; } } ) ) ; } refresh ( ) { this . _onDidChangeTreeData . fire ( ) ; } getTreeItem ( element ) { return element ; } getChildren ( element ? ) { if ( element ) { return Promise . resolve ( element . children ) ; } else { const m = this . getModules ( ) ; return Promise . resolve ( m ) ; } } async getModules ( ) { const activeEditor = getActiveTextEditor ( ) ; if ( activeEditor ?. document === undefined ) { return [ ] ; } if ( ! isTerraformFile ( activeEditor . document ) ) { return [ ] ; } const editor = activeEditor . document . uri ; const documentURI = Utils . dirname ( editor ) ; const handler = this . handler . getClient ( ) ; if ( handler === undefined ) { return [ ] ; } return await handler . client . onReady ( ) . then ( async ( ) => { const moduleCallsSupported = this . handler . clientSupportsCommand ( `${ handler . commandPrefix }.terraform-ls.module.calls` ) ; if ( ! moduleCallsSupported ) { return Promise . resolve ( [ ] ) ; } const params = { command : `${ handler . commandPrefix }.terraform-ls.module.calls` , arguments : [ `uri=${ documentURI }` ] , } ; const response = await handler . client . sendRequest < ExecuteCommandParams , ModuleCallsResponse , void > ( ExecuteCommandRequest . type , params ) ; if ( response === null ) { return Promise . resolve ( [ ] ) ; } const list = response . module_calls . map ( ( m ) => this . toModuleCall ( m . name , m . source_addr , m . version , m . source_type , m . docs_link , this . svg , m . dependent_modules ) ) ; return list ; } ) ; } toModuleCall ( name , sourceAddr , version , sourceType , docsLink , terraformIcon , dependents ) { let deps = [ ] ; if ( dependents . length !== 0 ) { deps = dependents . map ( ( dp ) => this . toModuleCall ( dp . name , dp . source_addr , dp . version , dp . source_type , dp . docs_link , terraformIcon , dp . dependent_modules ) ) ; } return new ModuleCallItem ( name , sourceAddr , version , sourceType , docsLink , terraformIcon , deps ) ; } }