Skip to content

Commit 3f0fd0e

Browse files
committed
Refactoring: Implemented ComponentManager. Moved component scanning methods to ComponentManager
1 parent b5e3d43 commit 3f0fd0e

File tree

3 files changed

+112
-184
lines changed

3 files changed

+112
-184
lines changed

src/commands/componentHierarchyDgml.ts

Lines changed: 2 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,25 @@ import * as path from 'path';
33
import * as vscode from 'vscode';
44
import * as xmldom from 'xmldom';
55

6+
import { Component, ComponentManager } from '../componentManager';
67
import { Config } from '../config';
78
import { FileSystemUtils } from '../filesystemUtils';
89

910
const prettifyXml = require('prettify-xml');
1011
const xmlSerializer = require('xmlserializer');
1112

12-
class Component {
13-
14-
constructor(tsFilename: string, templateFilename: string, selector: string, subComponents: Component[], isRoot: boolean) {
15-
this.tsFilename = tsFilename;
16-
this.templateFilename = templateFilename;
17-
this.selector = selector;
18-
this.subComponents = subComponents;
19-
this.isRoot = isRoot;
20-
}
21-
public tsFilename: string;
22-
public templateFilename: string;
23-
public selector: string;
24-
public subComponents: Component[];
25-
public isRoot: boolean;
26-
}
27-
2813
export class ComponentHierarchyDgml {
2914

3015
public static get commandName(): string { return 'componentHierarchyDgml'; }
3116

3217
public execute() {
3318
const fsUtils = new FileSystemUtils();
3419
var directoryPath: string = fsUtils.getWorkspaceFolder();
35-
const componentFilenames = fsUtils.listFiles(directoryPath, Config.excludeDirectories, this.isComponentFile);
36-
const components = this.findComponents(componentFilenames);
37-
this.scanComponentTemplates(components);
20+
const components = ComponentManager.findComponents(directoryPath);
3821

3922
const domImpl = new xmldom.DOMImplementation();
4023
const documentParser = new xmldom.DOMParser();
4124
let xmlDocument: Document;
42-
let root: Element;
4325

4426
try {
4527
// if the graph file already exists, then read it and parse it into a xml document object
@@ -64,7 +46,6 @@ export class ComponentHierarchyDgml {
6446
fileContent = fileContent.replace('HasCategory('RootComponent')', "HasCategory('RootComponent')");
6547

6648
// Write the prettified xml string to the ReadMe-ProjectStructure.dgml file.
67-
const fsUtils = new FileSystemUtils();
6849
fsUtils.writeFile(path.join(directoryPath, Config.dgmlGraphFilename), fileContent, () => {
6950
vscode.window.showInformationMessage('The project structure has been analyzed and a Directed Graph Markup Language (dgml) file has been created\nThe ReadMe-ProjectStructure.dgml file can now be viewed in Visual Studio');
7051
});
@@ -73,76 +54,6 @@ export class ComponentHierarchyDgml {
7354
}
7455
}
7556

76-
private isComponentFile(filename: string): boolean {
77-
return filename.endsWith('.component.ts');
78-
}
79-
80-
private findComponents(componentFilenames: string[]) {
81-
const compHash: { [selector: string]: Component; } = {};
82-
const componentRegex = /@Component\({/ig;
83-
const templateUrlRegex = /.*templateUrl:.+\/(.+)\'/i;
84-
const selectorRegex = /.*selector:.+\'(.+)\'/i;
85-
const endBracketRegex = /}\)/i;
86-
componentFilenames.forEach((componentFilename) => {
87-
let componentDefinitionFound = false;
88-
let currentComponent = new Component(componentFilename, "", "", [], true);
89-
const content = fs.readFileSync(componentFilename, 'utf8');
90-
const lines: string[] = content.split('\n');
91-
for (let i: number = 0; i < lines.length; i++) {
92-
let line = lines[i];
93-
let match = componentRegex.exec(line);
94-
if (match) {
95-
componentDefinitionFound = true;
96-
}
97-
if (componentDefinitionFound) {
98-
match = templateUrlRegex.exec(line);
99-
if (match) {
100-
currentComponent.templateFilename = path.join(path.dirname(componentFilename), match[1]);
101-
}
102-
match = selectorRegex.exec(line);
103-
if (match) {
104-
let currentSelector = match[1];
105-
currentSelector = currentSelector.replace("[", "");
106-
currentSelector = currentSelector.replace("]", "");
107-
currentComponent.selector = currentSelector;
108-
}
109-
match = endBracketRegex.exec(line);
110-
if (match) {
111-
break;
112-
}
113-
}
114-
}
115-
compHash[currentComponent.selector] = currentComponent;
116-
});
117-
return compHash;
118-
}
119-
120-
private scanComponentTemplates(componentHash: { [selector: string]: Component; }) {
121-
for (let selector1 in componentHash) {
122-
if (fs.existsSync(componentHash[selector1].templateFilename)) {
123-
const template = fs.readFileSync(componentHash[selector1].templateFilename); // We read the entire template file
124-
for (let selector2 in componentHash) { // then we check if the template contains each of the selectors we found in the components
125-
let pattern = `</${selector2}>`;
126-
let index = template.indexOf(pattern);
127-
if (index >= 0) {
128-
componentHash[selector1].subComponents = componentHash[selector1].subComponents.concat(componentHash[selector2]);
129-
// If selector2 has been found in a template then it is not root
130-
componentHash[selector2].isRoot = false;
131-
}
132-
else {
133-
pattern = ` ${selector2}`;
134-
index = template.indexOf(pattern);
135-
if (index >= 0) {
136-
componentHash[selector1].subComponents = componentHash[selector1].subComponents.concat(componentHash[selector2]);
137-
// If selector2 has been found in a template then it is not root
138-
componentHash[selector2].isRoot = false;
139-
}
140-
}
141-
}
142-
}
143-
}
144-
}
145-
14657
private createNewDirectedGraph(domImpl: DOMImplementation) {
14758
let xmlDoc: Document = domImpl.createDocument('', null, null);
14859
const root = xmlDoc.createElement("DirectedGraph");

src/commands/showComponentHierarchy.ts

Lines changed: 7 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,10 @@ import { Base64 } from 'js-base64';
33
import * as path from 'path';
44
import * as vscode from 'vscode';
55

6+
import { Component, ComponentManager } from '../componentManager';
67
import { Config } from '../config';
78
import { FileSystemUtils } from '../filesystemUtils';
89

9-
class Component {
10-
11-
constructor(tsFilename: string, templateFilename: string, selector: string, subComponents: Component[], isRoot: boolean) {
12-
this.tsFilename = tsFilename;
13-
this.templateFilename = templateFilename;
14-
this.selector = selector;
15-
this.subComponents = subComponents;
16-
this.isRoot = isRoot;
17-
}
18-
public tsFilename: string;
19-
public templateFilename: string;
20-
public selector: string;
21-
public subComponents: Component[];
22-
public isRoot: boolean;
23-
}
24-
2510
class Node {
2611
constructor(id: string, tsFilename: string, isRoot: boolean) {
2712
this.id = id;
@@ -36,6 +21,7 @@ class Node {
3621
return `{id: "${this.id}", label: "${this.id}"}`;
3722
}
3823
}
24+
3925
class Edge {
4026
constructor(id: string, source: string, target: string) {
4127
this.id = id;
@@ -76,9 +62,7 @@ export class ShowComponentHierarchy {
7662
);
7763

7864
var directoryPath: string = this.fsUtils.getWorkspaceFolder();
79-
const componentFilenames = this.fsUtils.listFiles(directoryPath, Config.excludeDirectories, this.isComponentFile);
80-
const components = this.findComponents(componentFilenames);
81-
this.enrichComponentsFromComponentTemplates(components);
65+
const components = ComponentManager.findComponents(directoryPath);
8266

8367
let nodes: Node[] = [];
8468
const appendNodes = (nodeList: Node[]) => {
@@ -89,14 +73,14 @@ export class ShowComponentHierarchy {
8973
});
9074
};
9175
let edges: Edge[] = [];
92-
const appendLinks = (edgeList: Edge[]) => {
76+
const appendEdges = (edgeList: Edge[]) => {
9377
edgeList.forEach(newEdge => {
9478
if (!edges.some(edge => edge.source === newEdge.source && edge.target === newEdge.target)) {
9579
edges = edges.concat(newEdge);
9680
}
9781
});
9882
};
99-
this.addNodesAndLinks(components, appendNodes, appendLinks);
83+
this.addNodesAndEdges(components, appendNodes, appendEdges);
10084

10185
const nodesJson = nodes
10286
.map((node, index, arr) => { return node.toJsonString(); })
@@ -127,77 +111,7 @@ export class ShowComponentHierarchy {
127111
}
128112
}
129113

130-
private isComponentFile(filename: string): boolean {
131-
return filename.endsWith('.component.ts');
132-
}
133-
134-
private findComponents(componentFilenames: string[]) {
135-
const compHash: { [selector: string]: Component; } = {};
136-
const componentRegex = /@Component\({/ig;
137-
const templateUrlRegex = /.*templateUrl:.+\/(.+)\'/i;
138-
const selectorRegex = /.*selector:.+\'(.+)\'/i;
139-
const endBracketRegex = /}\)/i;
140-
componentFilenames.forEach((componentFilename) => {
141-
let componentDefinitionFound = false;
142-
let currentComponent = new Component(componentFilename, "", "", [], true);
143-
const content = fs.readFileSync(componentFilename, 'utf8');
144-
const lines: string[] = content.split('\n');
145-
for (let i: number = 0; i < lines.length; i++) {
146-
let line = lines[i];
147-
let match = componentRegex.exec(line);
148-
if (match) {
149-
componentDefinitionFound = true;
150-
}
151-
if (componentDefinitionFound) {
152-
match = templateUrlRegex.exec(line);
153-
if (match) {
154-
currentComponent.templateFilename = path.join(path.dirname(componentFilename), match[1]);
155-
}
156-
match = selectorRegex.exec(line);
157-
if (match) {
158-
let currentSelector = match[1];
159-
currentSelector = currentSelector.replace("[", "");
160-
currentSelector = currentSelector.replace("]", "");
161-
currentComponent.selector = currentSelector;
162-
}
163-
match = endBracketRegex.exec(line);
164-
if (match) {
165-
break;
166-
}
167-
}
168-
}
169-
compHash[currentComponent.selector] = currentComponent;
170-
});
171-
return compHash;
172-
}
173-
174-
private enrichComponentsFromComponentTemplates(componentHash: { [selector: string]: Component; }) {
175-
for (let selector1 in componentHash) {
176-
if (fs.existsSync(componentHash[selector1].templateFilename)) {
177-
const template = fs.readFileSync(componentHash[selector1].templateFilename); // We read the entire template file
178-
for (let selector2 in componentHash) { // then we check if the template contains each of the selectors we found in the components
179-
let pattern = `</${selector2}>`;
180-
let index = template.indexOf(pattern);
181-
if (index >= 0) {
182-
componentHash[selector1].subComponents = componentHash[selector1].subComponents.concat(componentHash[selector2]);
183-
// If selector2 has been found in a template then it is not root
184-
componentHash[selector2].isRoot = false;
185-
}
186-
else {
187-
pattern = ` ${selector2}`;
188-
index = template.indexOf(pattern);
189-
if (index >= 0) {
190-
componentHash[selector1].subComponents = componentHash[selector1].subComponents.concat(componentHash[selector2]);
191-
// If selector2 has been found in a template then it is not root
192-
componentHash[selector2].isRoot = false;
193-
}
194-
}
195-
}
196-
}
197-
}
198-
}
199-
200-
private addNodesAndLinks(componentHash: { [selector: string]: Component; }, appendNodes: (nodeList: Node[]) => void, appendLinks: (edgeList: Edge[]) => void) {
114+
private addNodesAndEdges(componentHash: { [selector: string]: Component; }, appendNodes: (nodeList: Node[]) => void, appendLinks: (edgeList: Edge[]) => void) {
201115
for (let selector in componentHash) {
202116
const component = componentHash[selector];
203117
if (component.isRoot) {
@@ -284,7 +198,7 @@ export class ShowComponentHierarchy {
284198
const newFilePath = path.join(workspaceDirectory, Config.componentHierarchyFilename);
285199
this.fsUtils.writeFile(newFilePath, u8arr, () => {});
286200

287-
vscode.window.showInformationMessage('The file ComponentHierarchy.png has been created in the root of the workspace.');
201+
vscode.window.showInformationMessage(`The file ${Config.componentHierarchyFilename} has been created in the root of the workspace.`);
288202
}
289203
}
290204
}

src/componentManager.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import * as fs from 'fs';
2+
import path = require('path');
3+
4+
import { Config } from './config';
5+
import { FileSystemUtils } from './filesystemUtils';
6+
7+
export class Component {
8+
9+
constructor(tsFilename: string, templateFilename: string, selector: string, subComponents: Component[], isRoot: boolean) {
10+
this.tsFilename = tsFilename;
11+
this.templateFilename = templateFilename;
12+
this.selector = selector;
13+
this.subComponents = subComponents;
14+
this.isRoot = isRoot;
15+
}
16+
17+
public tsFilename: string;
18+
public templateFilename: string;
19+
public selector: string;
20+
public subComponents: Component[];
21+
public isRoot: boolean;
22+
}
23+
24+
export class ComponentManager {
25+
26+
public static findComponents(directoryPath: string): { [selector: string]: Component; } {
27+
const fsUtils = new FileSystemUtils();
28+
const componentFilenames = fsUtils.listFiles(directoryPath, Config.excludeDirectories, ComponentManager.isComponentFile);
29+
const components = ComponentManager.scanWorkspaceForComponents(componentFilenames);
30+
ComponentManager.enrichComponentsFromComponentTemplates(components);
31+
return components;
32+
}
33+
34+
private static isComponentFile(filename: string): boolean {
35+
return filename.endsWith('.component.ts');
36+
}
37+
38+
private static scanWorkspaceForComponents(componentFilenames: string[]): { [selector: string]: Component; } {
39+
const compHash: { [selector: string]: Component; } = {};
40+
const componentRegex = /@Component\({/ig;
41+
const templateUrlRegex = /.*templateUrl:.+\/(.+)\'/i;
42+
const selectorRegex = /.*selector:.+\'(.+)\'/i;
43+
const endBracketRegex = /}\)/i;
44+
componentFilenames.forEach((componentFilename) => {
45+
let componentDefinitionFound = false;
46+
let currentComponent = new Component(componentFilename, "", "", [], true);
47+
const content = fs.readFileSync(componentFilename, 'utf8');
48+
const lines: string[] = content.split('\n');
49+
for (let i: number = 0; i < lines.length; i++) {
50+
let line = lines[i];
51+
let match = componentRegex.exec(line);
52+
if (match) {
53+
componentDefinitionFound = true;
54+
}
55+
if (componentDefinitionFound) {
56+
match = templateUrlRegex.exec(line);
57+
if (match) {
58+
currentComponent.templateFilename = path.join(path.dirname(componentFilename), match[1]);
59+
}
60+
match = selectorRegex.exec(line);
61+
if (match) {
62+
let currentSelector = match[1];
63+
currentSelector = currentSelector.replace("[", "");
64+
currentSelector = currentSelector.replace("]", "");
65+
currentComponent.selector = currentSelector;
66+
}
67+
match = endBracketRegex.exec(line);
68+
if (match) {
69+
break;
70+
}
71+
}
72+
}
73+
compHash[currentComponent.selector] = currentComponent;
74+
});
75+
return compHash;
76+
}
77+
78+
private static enrichComponentsFromComponentTemplates(componentHash: { [selector: string]: Component; }) {
79+
for (let selector1 in componentHash) {
80+
if (fs.existsSync(componentHash[selector1].templateFilename)) {
81+
const template = fs.readFileSync(componentHash[selector1].templateFilename); // We read the entire template file
82+
for (let selector2 in componentHash) { // then we check if the template contains each of the selectors we found in the components
83+
let pattern = `</${selector2}>`;
84+
let index = template.indexOf(pattern);
85+
if (index >= 0) {
86+
componentHash[selector1].subComponents = componentHash[selector1].subComponents.concat(componentHash[selector2]);
87+
// If selector2 has been found in a template then it is not root
88+
componentHash[selector2].isRoot = false;
89+
}
90+
else {
91+
pattern = ` ${selector2}`;
92+
index = template.indexOf(pattern);
93+
if (index >= 0) {
94+
componentHash[selector1].subComponents = componentHash[selector1].subComponents.concat(componentHash[selector2]);
95+
// If selector2 has been found in a template then it is not root
96+
componentHash[selector2].isRoot = false;
97+
}
98+
}
99+
}
100+
}
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)