@rx-now/analysis
Version:
analysis tool for visualizing for code dependencies in typescript
99 lines (98 loc) • 3.66 kB
JavaScript
import { MethodDeclaration, Project, SyntaxKind } from "ts-morph";
import minimatch from "minimatch";
import { Graph } from "./graph";
import { getName } from "./toG6";
export class Workspace extends Graph {
constructor(entryPath, tsConfigFilePath, ignoreList) {
super();
this.ignoreList = [];
this.project = new Project({ tsConfigFilePath });
const entryFile = this.project.getSourceFileOrThrow(entryPath);
this.ignoreList = ignoreList;
this.graph = {
value: entryFile,
parent: new Set(),
children: new Set(),
};
this.vertices.add(this.graph);
this.collectDescendants(this.graph);
}
getG6Data() {
throw new Error("Method not implemented.");
}
generateHtmlFile() {
throw new Error("Method not implemented.");
}
getId(v) {
if (v instanceof MethodDeclaration) {
return `${v.getSourceFile().getFilePath()}.${v.getName()}`;
}
return v.getFilePath();
}
getName(v) {
if (v instanceof MethodDeclaration) {
return `${getName(v.getSourceFile())}.${v.getName()}`;
}
return getName(v);
}
collectDescendants(current) {
const sourceFile = current.value;
const allImports = [];
// static import statements
sourceFile
.getImportDeclarations()
.map((i) => i
.getNamedImports()
.map((o) => o.getNameNode().getDefinitionNodes())
.reduce((prev, curr) => prev.concat(curr), []))
.reduce((prev, curr) => prev.concat(curr), [])
.filter((n) => !this.ignoreFile(n.getSourceFile()))
.forEach((n) => {
allImports.push(n.getSourceFile());
});
// dynamic import statements
sourceFile
.getVariableStatements()
.filter((o) => o.getDescendantsOfKind(SyntaxKind.ImportKeyword).length > 0)
.forEach((o) => {
const dynamicImports = o.getDescendantsOfKind(SyntaxKind.ImportKeyword);
if (dynamicImports.length > 0) {
dynamicImports.forEach((d) => {
var _a;
const str = d
.getParentOrThrow()
.getDescendantsOfKind(SyntaxKind.StringLiteral)[0];
(_a = str
.getSymbol()) === null || _a === void 0 ? void 0 : _a.getDeclarations().filter((p) => !this.ignoreFile(p.getSourceFile())).map((p) => p.getSourceFile()).forEach((p) => allImports.push(p));
});
}
});
// eslint-disable-next-line no-param-reassign
current.children = new Set();
allImports.forEach((dest) => {
const node = (this.getNodeByValue(dest) || {
value: dest,
parent: new Set(),
children: new Set(),
});
node.parent.add(current);
current.children.add(node);
if (!this.vertices.has(node)) {
this.vertices.add(node);
this.collectDescendants(node);
}
});
}
ignoreFile(source) {
return !!this.ignoreList.find((rule) => minimatch(source.getFilePath(), rule));
}
toString() {
const res = [];
Array.from(this.vertices).forEach((o) => {
res.push(`${o.value.getSourceFile().getFilePath()} => ${Array.from(o.children)
.map((p) => p.value.getSourceFile().getFilePath())
.join(", ")}`);
});
return res.join("\n");
}
}