Skip to content

Commit 3011568

Browse files
committed
Now showing services injected into services in the dependency injection graph.
1 parent 7287ab8 commit 3011568

File tree

3 files changed

+144
-136
lines changed

3 files changed

+144
-136
lines changed
Lines changed: 137 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,156 @@
11
import { ShowHierarchyBase } from './showHierarchyBase';
22
import { 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';
44
import * as fs from 'fs';
55
import * as path from 'path';
66
import * as vscode from 'vscode';
77

88
export 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
}

src/model/Node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export class Node {
155155
case NodeType.directive:
156156
return 'Directive';
157157
case NodeType.injectable:
158-
return 'Injectable';
158+
return 'Service';
159159
case NodeType.module:
160160
return 'Module';
161161
case NodeType.pipe:

src/moduleManager.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ export class ModuleManager {
3434
project.injectables.forEach(injectable => {
3535
this.setFilenames(injectable.dependencies, project);
3636
});
37+
project.directives.forEach(directive => {
38+
this.setFilenames(directive.dependencies, project);
39+
});
40+
project.pipes.forEach(pipe => {
41+
this.setFilenames(pipe.dependencies, project);
42+
});
3743
return project;
3844
}
3945

0 commit comments

Comments
 (0)