11import { ShowHierarchyBase } from './showHierarchyBase' ;
22import { ModuleManager } from '@src' ;
3- import { ArrowType , Component , Edge , GraphState , Node , NodeType , Project } from '@model' ;
3+ import { ArrowType , Component , Edge , GraphState , NamedEntity , Node , NodeType , Project } from '@model' ;
44import * as fs from 'fs' ;
55import * as path from 'path' ;
66import * as vscode from 'vscode' ;
77
88export class GenerateDependencyInjectionGraph extends ShowHierarchyBase {
9- static get commandName ( ) { return 'generateDependencyInjectionGraph' ; }
10- public execute ( webview : vscode . Webview ) {
11- this . checkForOpenWorkspace ( ) ;
12- webview . onDidReceiveMessage (
13- message => {
14- switch ( message . command ) {
15- case 'saveAsPng' : {
16- this . saveAsPng ( this . config . dependencyInjectionPngFilename , message . text ) ;
17- return ;
18- }
19- case 'saveAsDgml' : {
20- this . saveAsDgml ( this . config . dependencyInjectionDgmlGraphFilename , message . text , `'The components hierarchy has been analyzed and a Directed Graph Markup Language (dgml) file '${ this . config . dependencyInjectionDgmlGraphFilename } ' has been created'` ) ;
21- return ;
22- }
23- case 'saveAsDot' : {
24- this . saveAsDot ( this . config . dependencyInjectionDotGraphFilename , message . text , 'dependencyInjectionGraph' , `'The components hierarchy has been analyzed and a GraphViz (dot) file '${ this . config . dependencyInjectionDotGraphFilename } ' has been created'` ) ;
25- return ;
26- }
27- case 'setGraphState' : {
28- const newGraphState : GraphState = JSON . parse ( message . text ) ;
29- this . graphState = newGraphState ;
30- this . setNewState ( this . graphState ) ;
31- this . nodes . forEach ( node => {
32- node . position = this . graphState . nodePositions [ node . id ] ;
33- } ) ;
34- this . addNodesAndEdges ( project , this . appendNodes , this . appendEdges ) ;
35- this . generateAndSaveJavascriptContent ( ( ) => { } ) ;
36- return ;
37- }
38- case 'openFile' : {
39- const filename = message . text ;
40- if ( this . fsUtils . fileExists ( filename ) ) {
41- var openPath = vscode . Uri . parse ( "file:///" + filename ) ;
42- vscode . workspace . openTextDocument ( openPath ) . then ( doc => {
43- vscode . window . showTextDocument ( doc ) ;
44- } ) ;
45- }
46- return ;
47- }
9+ static get commandName ( ) { return 'generateDependencyInjectionGraph' ; }
10+ public execute ( webview : vscode . Webview ) {
11+ this . checkForOpenWorkspace ( ) ;
12+ webview . onDidReceiveMessage (
13+ message => {
14+ switch ( message . command ) {
15+ case 'saveAsPng' : {
16+ this . saveAsPng ( this . config . dependencyInjectionPngFilename , message . text ) ;
17+ return ;
18+ }
19+ case 'saveAsDgml' : {
20+ this . saveAsDgml ( this . config . dependencyInjectionDgmlGraphFilename , message . text , `'The components hierarchy has been analyzed and a Directed Graph Markup Language (dgml) file '${ this . config . dependencyInjectionDgmlGraphFilename } ' has been created'` ) ;
21+ return ;
22+ }
23+ case 'saveAsDot' : {
24+ this . saveAsDot ( this . config . dependencyInjectionDotGraphFilename , message . text , 'dependencyInjectionGraph' , `'The components hierarchy has been analyzed and a GraphViz (dot) file '${ this . config . dependencyInjectionDotGraphFilename } ' has been created'` ) ;
25+ return ;
26+ }
27+ case 'setGraphState' : {
28+ const newGraphState : GraphState = JSON . parse ( message . text ) ;
29+ this . graphState = newGraphState ;
30+ this . setNewState ( this . graphState ) ;
31+ this . nodes . forEach ( node => {
32+ node . position = this . graphState . nodePositions [ node . id ] ;
33+ } ) ;
34+ this . addNodesAndEdges ( project ) ;
35+ this . generateAndSaveJavascriptContent ( ( ) => { } ) ;
36+ return ;
37+ }
38+ case 'openFile' : {
39+ const filename = message . text ;
40+ if ( this . fsUtils . fileExists ( filename ) ) {
41+ var openPath = vscode . Uri . parse ( "file:///" + filename ) ;
42+ vscode . workspace . openTextDocument ( openPath ) . then ( doc => {
43+ vscode . window . showTextDocument ( doc ) ;
44+ } ) ;
45+ }
46+ return ;
47+ }
48+ }
49+ } ,
50+ undefined ,
51+ this . extensionContext . subscriptions
52+ ) ;
53+ var workspaceFolder = this . fsUtils . getWorkspaceFolder ( ) ;
54+ const errors : string [ ] = [ ] ;
55+ const project : Project = ModuleManager . scanProject ( workspaceFolder , errors , this . isTypescriptFile ) ;
56+ this . nodes = [ ] ;
57+ this . edges = [ ] ;
58+ this . addNodesAndEdges ( project ) ;
59+ let htmlContent = this . generateHtmlContent ( webview , this . showModuleHierarchyJsFilename ) ;
60+ // this.fsUtils.writeFile(this.extensionContext?.asAbsolutePath(path.join('out', GenerateDependencyInjectionGraph.commandName + '.html')), htmlContent, () => { }); // For debugging
61+ this . generateAndSaveJavascriptContent ( ( ) => { webview . html = htmlContent ; } ) ;
62+ if ( errors . length > 0 ) {
63+ this . showErrors ( errors , `Parsing of ${ errors . length > 1 ? 'some' : 'one' } of the project files failed.\n` ) ;
4864 }
49- } ,
50- undefined ,
51- this . extensionContext . subscriptions
52- ) ;
53- var workspaceFolder = this . fsUtils . getWorkspaceFolder ( ) ;
54- const errors : string [ ] = [ ] ;
55- const project : Project = ModuleManager . scanProject ( workspaceFolder , errors , this . isTypescriptFile ) ;
56- this . nodes = [ ] ;
57- this . edges = [ ] ;
58- this . addNodesAndEdges ( project , this . appendNodes , this . appendEdges ) ;
59- let htmlContent = this . generateHtmlContent ( webview , this . showModuleHierarchyJsFilename ) ;
60- // this.fsUtils.writeFile(this.extensionContext?.asAbsolutePath(path.join('out', GenerateDependencyInjectionGraph.commandName + '.html')), htmlContent, () => { }); // For debugging
61- this . generateAndSaveJavascriptContent ( ( ) => { webview . html = htmlContent ; } ) ;
62- if ( errors . length > 0 ) {
63- this . showErrors ( errors , `Parsing of ${ errors . length > 1 ? 'some' : 'one' } of the project files failed.\n` ) ;
6465 }
65- }
6666
67- private generateAndSaveJavascriptContent ( callback : ( ) => any ) {
68- const nodesJson = this . nodes
69- . map ( node => { return node . toJsonString ( ) ; } )
70- . join ( ',\n' ) ;
71- const edgesJson = this . edges
72- . map ( edge => { return edge . toJsonString ( ) ; } )
73- . join ( ',\n' ) ;
67+ private generateAndSaveJavascriptContent ( callback : ( ) => any ) {
68+ const nodesJson = this . nodes
69+ . map ( node => { return node . toJsonString ( ) ; } )
70+ . join ( ',\n' ) ;
71+ const edgesJson = this . edges
72+ . map ( edge => { return edge . toJsonString ( ) ; } )
73+ . join ( ',\n' ) ;
7474
75- try {
76- const jsContent = this . generateJavascriptContent ( nodesJson , edgesJson ) ;
77- this . fsUtils . writeFile (
78- this . extensionContext ?. asAbsolutePath ( path . join ( '.' , this . showModuleHierarchyJsFilename ) ) ,
79- jsContent ,
80- callback
81- ) ;
82- }
83- catch ( ex ) {
84- console . log ( 'Angular Tools Exception:' + ex ) ;
75+ try {
76+ const jsContent = this . generateJavascriptContent ( nodesJson , edgesJson ) ;
77+ this . fsUtils . writeFile (
78+ this . extensionContext ?. asAbsolutePath ( path . join ( '.' , this . showModuleHierarchyJsFilename ) ) ,
79+ jsContent ,
80+ callback
81+ ) ;
82+ }
83+ catch ( ex ) {
84+ console . log ( 'Angular Tools Exception:' + ex ) ;
85+ }
8586 }
86- }
8787
88- generatedComponentNode ( component : Component ) : string {
89- let nodeContent : string = '' ;
90- nodeContent = `<b>${ component . name } </b>` ;
91- if ( component . inputs . length > 0 ) {
92- const inputs = component . inputs . map ( i => i . name ) . join ( ", " ) ;
93- nodeContent += `\\n<b>Inputs: </b> ${ inputs } ` ;
94- }
95- if ( component . outputs . length > 0 ) {
96- const outputs = component . outputs . map ( i => i . name ) . join ( ", " ) ;
97- nodeContent += `\\n<b>Outputs: </b> ${ outputs } ` ;
98- }
99- if ( component . viewChilds . length > 0 ) {
100- const viewchilds = component . viewChilds . map ( i => i . name ) . join ( ", " ) ;
101- nodeContent += `\\n<b>Viewchilds: </b> ${ viewchilds } ` ;
102- }
103- if ( component . viewChildren . length > 0 ) {
104- const viewchildren = component . viewChildren . map ( i => i . name ) . join ( ", " ) ;
105- nodeContent += `\\n<b>Viewchildren: </b> ${ viewchildren } ` ;
106- }
107- if ( component . contentChilds . length > 0 ) {
108- const contentchilds = component . contentChilds . map ( i => i . name ) . join ( ", " ) ;
109- nodeContent += `\\n<b>Contentchilds: </b> ${ contentchilds } ` ;
88+ private getNodeLabel ( entity : Component | NamedEntity ) : string {
89+ let nodeContent : string = '' ;
90+ nodeContent = `<b>${ entity . name } </b>` ;
91+ if ( entity instanceof Component ) {
92+ if ( entity . inputs . length > 0 ) {
93+ const inputs = entity . inputs . map ( i => i . name ) . join ( ", " ) ;
94+ nodeContent += `\\n<b>Inputs: </b> ${ inputs } ` ;
95+ }
96+ if ( entity . outputs . length > 0 ) {
97+ const outputs = entity . outputs . map ( i => i . name ) . join ( ", " ) ;
98+ nodeContent += `\\n<b>Outputs: </b> ${ outputs } ` ;
99+ }
100+ if ( entity . viewChilds . length > 0 ) {
101+ const viewchilds = entity . viewChilds . map ( i => i . name ) . join ( ", " ) ;
102+ nodeContent += `\\n<b>Viewchilds: </b> ${ viewchilds } ` ;
103+ }
104+ if ( entity . viewChildren . length > 0 ) {
105+ const viewchildren = entity . viewChildren . map ( i => i . name ) . join ( ", " ) ;
106+ nodeContent += `\\n<b>Viewchildren: </b> ${ viewchildren } ` ;
107+ }
108+ if ( entity . contentChilds . length > 0 ) {
109+ const contentchilds = entity . contentChilds . map ( i => i . name ) . join ( ", " ) ;
110+ nodeContent += `\\n<b>Contentchilds: </b> ${ contentchilds } ` ;
111+ }
112+ if ( entity . contentChildren . length > 0 ) {
113+ const contentchildren = entity . contentChildren . map ( i => i . name ) . join ( ", " ) ;
114+ nodeContent += `\\n<b>Contentchildren: </b> ${ contentchildren } ` ;
115+ }
116+ }
117+ return nodeContent ;
110118 }
111- if ( component . contentChildren . length > 0 ) {
112- const contentchildren = component . contentChildren . map ( i => i . name ) . join ( ", " ) ;
113- nodeContent += `\\n<b>Contentchildren: </b> ${ contentchildren } ` ;
119+
120+ private addNodesAndEdges ( project : Project ) {
121+ this . addNamedEntityNodeAndEdges ( project . components , NodeType . component , ArrowType . injectable ) ;
122+ this . addNamedEntityNodeAndEdges ( project . injectables , NodeType . injectable , ArrowType . injectable ) ;
123+ this . addNamedEntityNodeAndEdges ( project . directives , NodeType . directive , ArrowType . injectable ) ;
124+ this . addNamedEntityNodeAndEdges ( project . pipes , NodeType . pipe , ArrowType . injectable ) ;
114125 }
115- return nodeContent ;
116- }
117126
118- addNodesAndEdges ( project : Project , appendNodes : ( nodeList : Node [ ] ) => void , appendEdges : ( edgeList : Edge [ ] ) => void ) {
119- project . components . forEach ( component => {
120- let componentFilename = component . filename . replace ( this . workspaceDirectory , '.' ) ;
121- componentFilename = componentFilename . split ( '\\' ) . join ( '/' ) ;
122- const componentPosition = this . graphState . nodePositions [ component . name ] ;
123- appendNodes ( [ new Node ( component . name , this . generatedComponentNode ( component ) , componentFilename , component . filename , false , NodeType . component , componentPosition ) ] ) ;
124- component . dependencies . forEach ( injectable => {
125- const injectablePosition = this . graphState . nodePositions [ injectable . name ] ;
126- appendNodes ( [ new Node ( injectable . name , injectable . name , injectable . filename . replace ( this . workspaceDirectory , '' ) , injectable . filename , false , NodeType . injectable , injectablePosition ) ] ) ;
127- appendEdges ( [ new Edge ( ( this . edges . length + 1 ) . toString ( ) , injectable . name , component . name , ArrowType . injectable ) ] ) ;
127+ private addNamedEntityNodeAndEdges ( namedEntityMap : Map < string , Component | NamedEntity > , noteType : NodeType , arrowType : ArrowType ) {
128+ namedEntityMap . forEach ( namedEntity => {
129+ let namedEntityFilename = namedEntity . filename . replace ( this . workspaceDirectory , '.' ) ;
130+ namedEntityFilename = namedEntityFilename . split ( '\\' ) . join ( '/' ) ;
131+ const entityPosition = this . graphState . nodePositions [ namedEntity . name ] ;
132+ this . appendNodes ( [ new Node ( namedEntity . name , this . getNodeLabel ( namedEntity ) , namedEntityFilename , namedEntity . filename , false , noteType , entityPosition ) ] ) ;
133+ namedEntity . dependencies . forEach ( dependency => {
134+ const dependencyPosition = this . graphState . nodePositions [ dependency . name ] ;
135+ this . appendNodes ( [ new Node ( dependency . name , dependency . name , dependency . filename . replace ( this . workspaceDirectory , '' ) , dependency . filename , false , NodeType . injectable , dependencyPosition ) ] ) ;
136+ this . appendEdges ( [ new Edge ( ( this . edges . length + 1 ) . toString ( ) , dependency . name , namedEntity . name , arrowType ) ] ) ;
137+ } ) ;
128138 } ) ;
129- } ) ;
130- project . injectables . forEach ( injectable => {
131- injectable . dependencies . forEach ( dependency => {
132- const dependencyPosition = this . graphState . nodePositions [ dependency . name ] ;
133- appendNodes ( [ new Node ( dependency . name , dependency . name , dependency . filename . replace ( this . workspaceDirectory , '' ) , dependency . filename , false , NodeType . injectable , dependencyPosition ) ] ) ;
134- appendEdges ( [ new Edge ( ( this . edges . length + 1 ) . toString ( ) , dependency . name , injectable . name , ArrowType . injectable ) ] ) ;
135- } ) ;
136- } ) ;
137- }
139+ }
138140
139- generateJavascriptContent ( nodesJson : string , edgesJson : string ) {
140- let template = fs . readFileSync ( this . extensionContext ?. asAbsolutePath ( path . join ( 'templates' , this . templateJsFilename ) ) , 'utf8' ) ;
141- let jsContent = template . replace ( 'const nodes = new vis.DataSet([]);' , `var nodes = new vis.DataSet([${ nodesJson } ]);` ) ;
142- jsContent = jsContent . replace ( 'const edges = new vis.DataSet([]);' , `var edges = new vis.DataSet([${ edgesJson } ]);` ) ;
143- jsContent = jsContent . replace ( 'type: "triangle" // edge arrow to type' , `type: "${ this . config . dependencyInjectionEdgeArrowToType } " // edge arrow to type}` ) ;
144- jsContent = jsContent . replace ( 'ctx.strokeStyle = \'blue\'; // graph selection guideline color' , `ctx.strokeStyle = '${ this . config . graphSelectionGuidelineColor } '; // graph selection guideline color` ) ;
145- jsContent = jsContent . replace ( 'ctx.lineWidth = 1; // graph selection guideline width' , `ctx.lineWidth = ${ this . config . graphSelectionGuidelineWidth } ; // graph selection guideline width` ) ;
146- jsContent = jsContent . replace ( 'selectionCanvasContext.strokeStyle = \'red\';' , `selectionCanvasContext.strokeStyle = '${ this . config . graphSelectionColor } ';` ) ;
147- jsContent = jsContent . replace ( 'selectionCanvasContext.lineWidth = 2;' , `selectionCanvasContext.lineWidth = ${ this . config . graphSelectionWidth } ;` ) ;
148- jsContent = jsContent . replace ( 'let showHierarchicalOptionsCheckboxChecked = false;' , `let showHierarchicalOptionsCheckboxChecked = ${ this . graphState . showHierarchicalOptions } ;` ) ;
149- jsContent = jsContent . replace ( 'let hierarchicalOptionsDirectionSelectValue = undefined;' , `let hierarchicalOptionsDirectionSelectValue = '${ this . graphState . graphDirection } ';` ) ;
150- jsContent = jsContent . replace ( 'let hierarchicalOptionsSortMethodSelectValue = undefined;' , `let hierarchicalOptionsSortMethodSelectValue = '${ this . graphState . graphLayout } ';` ) ;
151- jsContent = this . setGraphState ( jsContent ) ;
152- return jsContent ;
153- }
141+ private generateJavascriptContent ( nodesJson : string , edgesJson : string ) {
142+ let template = fs . readFileSync ( this . extensionContext ?. asAbsolutePath ( path . join ( 'templates' , this . templateJsFilename ) ) , 'utf8' ) ;
143+ let jsContent = template . replace ( 'const nodes = new vis.DataSet([]);' , `var nodes = new vis.DataSet([${ nodesJson } ]);` ) ;
144+ jsContent = jsContent . replace ( 'const edges = new vis.DataSet([]);' , `var edges = new vis.DataSet([${ edgesJson } ]);` ) ;
145+ jsContent = jsContent . replace ( 'type: "triangle" // edge arrow to type' , `type: "${ this . config . dependencyInjectionEdgeArrowToType } " // edge arrow to type}` ) ;
146+ jsContent = jsContent . replace ( 'ctx.strokeStyle = \'blue\'; // graph selection guideline color' , `ctx.strokeStyle = '${ this . config . graphSelectionGuidelineColor } '; // graph selection guideline color` ) ;
147+ jsContent = jsContent . replace ( 'ctx.lineWidth = 1; // graph selection guideline width' , `ctx.lineWidth = ${ this . config . graphSelectionGuidelineWidth } ; // graph selection guideline width` ) ;
148+ jsContent = jsContent . replace ( 'selectionCanvasContext.strokeStyle = \'red\';' , `selectionCanvasContext.strokeStyle = '${ this . config . graphSelectionColor } ';` ) ;
149+ jsContent = jsContent . replace ( 'selectionCanvasContext.lineWidth = 2;' , `selectionCanvasContext.lineWidth = ${ this . config . graphSelectionWidth } ;` ) ;
150+ jsContent = jsContent . replace ( 'let showHierarchicalOptionsCheckboxChecked = false;' , `let showHierarchicalOptionsCheckboxChecked = ${ this . graphState . showHierarchicalOptions } ;` ) ;
151+ jsContent = jsContent . replace ( 'let hierarchicalOptionsDirectionSelectValue = undefined;' , `let hierarchicalOptionsDirectionSelectValue = '${ this . graphState . graphDirection } ';` ) ;
152+ jsContent = jsContent . replace ( 'let hierarchicalOptionsSortMethodSelectValue = undefined;' , `let hierarchicalOptionsSortMethodSelectValue = '${ this . graphState . graphLayout } ';` ) ;
153+ jsContent = this . setGraphState ( jsContent ) ;
154+ return jsContent ;
155+ }
154156}
0 commit comments