@nexus-ioc/graph-analyzer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +112 -0
- package/LICENSE +21 -0
- package/README.md +742 -0
- package/dist/analyzer/circular-dependency-detector.d.ts +94 -0
- package/dist/analyzer/circular-dependency-detector.js +203 -0
- package/dist/analyzer/circular-dependency-detector.js.map +1 -0
- package/dist/analyzer/module-depth-analyzer.d.ts +117 -0
- package/dist/analyzer/module-depth-analyzer.js +221 -0
- package/dist/analyzer/module-depth-analyzer.js.map +1 -0
- package/dist/analyzer/provider-scope-analyzer.d.ts +91 -0
- package/dist/analyzer/provider-scope-analyzer.js +137 -0
- package/dist/analyzer/provider-scope-analyzer.js.map +1 -0
- package/dist/analyzer/unused-provider-detector.d.ts +73 -0
- package/dist/analyzer/unused-provider-detector.js +147 -0
- package/dist/analyzer/unused-provider-detector.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +537 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/config-loader.d.ts +27 -0
- package/dist/config/config-loader.js +205 -0
- package/dist/config/config-loader.js.map +1 -0
- package/dist/config/config-schema.d.ts +83 -0
- package/dist/config/config-schema.js +97 -0
- package/dist/config/config-schema.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/graph-output.interface.d.ts +126 -0
- package/dist/interfaces/graph-output.interface.js +3 -0
- package/dist/interfaces/graph-output.interface.js.map +1 -0
- package/dist/interfaces/providers.interface.d.ts +10 -0
- package/dist/interfaces/providers.interface.js +3 -0
- package/dist/interfaces/providers.interface.js.map +1 -0
- package/dist/parser/dependency-extractor.d.ts +88 -0
- package/dist/parser/dependency-extractor.js +334 -0
- package/dist/parser/dependency-extractor.js.map +1 -0
- package/dist/parser/parse-entry-file.d.ts +15 -0
- package/dist/parser/parse-entry-file.js +46 -0
- package/dist/parser/parse-entry-file.js.map +1 -0
- package/dist/parser/parse-imports.d.ts +15 -0
- package/dist/parser/parse-imports.js +65 -0
- package/dist/parser/parse-imports.js.map +1 -0
- package/dist/parser/parse-ns-module.d.ts +39 -0
- package/dist/parser/parse-ns-module.js +122 -0
- package/dist/parser/parse-ns-module.js.map +1 -0
- package/dist/parser/parse-provider.d.ts +2 -0
- package/dist/parser/parse-provider.js +7 -0
- package/dist/parser/parse-provider.js.map +1 -0
- package/dist/parser/parse-ts-config.d.ts +10 -0
- package/dist/parser/parse-ts-config.js +40 -0
- package/dist/parser/parse-ts-config.js.map +1 -0
- package/dist/parser/parser-rec.d.ts +1 -0
- package/dist/parser/parser-rec.js +52 -0
- package/dist/parser/parser-rec.js.map +1 -0
- package/dist/parser/parser.d.ts +1 -0
- package/dist/parser/parser.js +61 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/parser/provider/class-parser.d.ts +20 -0
- package/dist/parser/provider/class-parser.js +137 -0
- package/dist/parser/provider/class-parser.js.map +1 -0
- package/dist/parser/provider/providers-parser.d.ts +9 -0
- package/dist/parser/provider/providers-parser.js +32 -0
- package/dist/parser/provider/providers-parser.js.map +1 -0
- package/dist/parser/provider/use-class-parser.d.ts +25 -0
- package/dist/parser/provider/use-class-parser.js +161 -0
- package/dist/parser/provider/use-class-parser.js.map +1 -0
- package/dist/parser/provider/use-factory-parser.d.ts +15 -0
- package/dist/parser/provider/use-factory-parser.js +53 -0
- package/dist/parser/provider/use-factory-parser.js.map +1 -0
- package/dist/parser/provider/use-value-parser.d.ts +13 -0
- package/dist/parser/provider/use-value-parser.js +41 -0
- package/dist/parser/provider/use-value-parser.js.map +1 -0
- package/dist/parser/rules.d.ts +10 -0
- package/dist/parser/rules.js +37 -0
- package/dist/parser/rules.js.map +1 -0
- package/dist/utils/error-formatter.d.ts +27 -0
- package/dist/utils/error-formatter.js +177 -0
- package/dist/utils/error-formatter.js.map +1 -0
- package/dist/utils/validator.d.ts +45 -0
- package/dist/utils/validator.js +252 -0
- package/dist/utils/validator.js.map +1 -0
- package/dist/visualize/generator.d.ts +26 -0
- package/dist/visualize/generator.js +75 -0
- package/dist/visualize/generator.js.map +1 -0
- package/dist/visualize/graph-analyzer.d.ts +126 -0
- package/dist/visualize/graph-analyzer.js +199 -0
- package/dist/visualize/graph-analyzer.js.map +1 -0
- package/dist/visualize/html-generator.d.ts +71 -0
- package/dist/visualize/html-generator.js +1312 -0
- package/dist/visualize/html-generator.js.map +1 -0
- package/dist/visualize/json-formatter.d.ts +106 -0
- package/dist/visualize/json-formatter.js +252 -0
- package/dist/visualize/json-formatter.js.map +1 -0
- package/docs/API_REFERENCE.md +747 -0
- package/docs/ARCHITECTURE.md +486 -0
- package/docs/CLI_GUIDE.md +576 -0
- package/docs/HTML_VISUALIZATION.md +365 -0
- package/package.json +85 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Validator = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_child_process_1 = require("node:child_process");
|
|
6
|
+
const fs = tslib_1.__importStar(require("node:fs"));
|
|
7
|
+
const path = tslib_1.__importStar(require("node:path"));
|
|
8
|
+
class Validator {
|
|
9
|
+
/**
|
|
10
|
+
* Validate that a file exists
|
|
11
|
+
*/
|
|
12
|
+
static validateFileExists(filePath) {
|
|
13
|
+
const absolutePath = path.resolve(filePath);
|
|
14
|
+
if (!fs.existsSync(absolutePath)) {
|
|
15
|
+
return {
|
|
16
|
+
type: "FILE_NOT_FOUND",
|
|
17
|
+
message: `File not found: ${absolutePath}`,
|
|
18
|
+
suggestions: [
|
|
19
|
+
"Check if the file path is correct",
|
|
20
|
+
"Make sure you're in the project root directory",
|
|
21
|
+
"Use an absolute path or relative path from current directory",
|
|
22
|
+
`Current directory: ${process.cwd()}`,
|
|
23
|
+
],
|
|
24
|
+
details: `Looking for: ${absolutePath}`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Validate that a file has a valid TypeScript extension
|
|
31
|
+
*/
|
|
32
|
+
static validateTypeScriptFile(filePath) {
|
|
33
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
34
|
+
const validExtensions = [".ts", ".tsx"];
|
|
35
|
+
if (!validExtensions.includes(ext)) {
|
|
36
|
+
return {
|
|
37
|
+
type: "INVALID_FILE_EXTENSION",
|
|
38
|
+
message: `Invalid file extension: ${ext}`,
|
|
39
|
+
suggestions: [
|
|
40
|
+
"Entry file must be a TypeScript file (.ts or .tsx)",
|
|
41
|
+
`Provided file: ${filePath}`,
|
|
42
|
+
"Example: graph-analyzer src/main.ts",
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validate that a file is readable
|
|
50
|
+
*/
|
|
51
|
+
static validateFileReadable(filePath) {
|
|
52
|
+
const absolutePath = path.resolve(filePath);
|
|
53
|
+
try {
|
|
54
|
+
fs.accessSync(absolutePath, fs.constants.R_OK);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
type: "FILE_NOT_READABLE",
|
|
60
|
+
message: `Cannot read file: ${absolutePath}`,
|
|
61
|
+
suggestions: [
|
|
62
|
+
"Check file permissions",
|
|
63
|
+
"Make sure you have read access to the file",
|
|
64
|
+
"Try running with appropriate permissions",
|
|
65
|
+
],
|
|
66
|
+
details: error.message,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Validate that tsconfig.json exists if specified
|
|
72
|
+
*/
|
|
73
|
+
static validateTsConfig(tsConfigPath) {
|
|
74
|
+
if (!tsConfigPath) {
|
|
75
|
+
return null; // Optional, so no error if not provided
|
|
76
|
+
}
|
|
77
|
+
const absolutePath = path.resolve(tsConfigPath);
|
|
78
|
+
if (!fs.existsSync(absolutePath)) {
|
|
79
|
+
return {
|
|
80
|
+
type: "TSCONFIG_NOT_FOUND",
|
|
81
|
+
message: `TypeScript configuration file not found: ${absolutePath}`,
|
|
82
|
+
suggestions: [
|
|
83
|
+
"Check if tsconfig.json exists in your project",
|
|
84
|
+
"Verify the path to tsconfig.json is correct",
|
|
85
|
+
"Create a tsconfig.json file if it doesn't exist",
|
|
86
|
+
"Omit the -c flag to auto-detect tsconfig.json",
|
|
87
|
+
],
|
|
88
|
+
details: `Looking for: ${absolutePath}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Validate it's a valid JSON file
|
|
92
|
+
try {
|
|
93
|
+
const content = fs.readFileSync(absolutePath, "utf8");
|
|
94
|
+
JSON.parse(content);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
return {
|
|
99
|
+
type: "INVALID_TSCONFIG",
|
|
100
|
+
message: `Invalid TypeScript configuration file: ${absolutePath}`,
|
|
101
|
+
suggestions: [
|
|
102
|
+
"Check that tsconfig.json is valid JSON",
|
|
103
|
+
"Fix any syntax errors in the file",
|
|
104
|
+
"Validate your tsconfig.json using a JSON validator",
|
|
105
|
+
],
|
|
106
|
+
details: error.message,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check if Graphviz is installed (required for PNG generation)
|
|
112
|
+
*/
|
|
113
|
+
static validateGraphvizInstalled(format) {
|
|
114
|
+
// Only check if PNG output is requested
|
|
115
|
+
if (format !== "png" && format !== "both" && format !== undefined) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const result = (0, node_child_process_1.spawnSync)("dot", ["-V"], {
|
|
120
|
+
stdio: "pipe",
|
|
121
|
+
encoding: "utf8",
|
|
122
|
+
});
|
|
123
|
+
// Graphviz returns version info on stderr
|
|
124
|
+
if (result.error || (!result.stdout && !result.stderr)) {
|
|
125
|
+
return {
|
|
126
|
+
type: "GRAPHVIZ_NOT_FOUND",
|
|
127
|
+
message: "Graphviz is not installed or not in PATH",
|
|
128
|
+
suggestions: [
|
|
129
|
+
"Install Graphviz to generate PNG visualizations",
|
|
130
|
+
"",
|
|
131
|
+
"Installation instructions:",
|
|
132
|
+
" • macOS: brew install graphviz",
|
|
133
|
+
" • Ubuntu/Debian: sudo apt-get install graphviz",
|
|
134
|
+
" • Windows: choco install graphviz",
|
|
135
|
+
" • Or download from: https://graphviz.org/download/",
|
|
136
|
+
"",
|
|
137
|
+
"Alternatively, use JSON or HTML format instead:",
|
|
138
|
+
" graph-analyzer -f json src/main.ts",
|
|
139
|
+
" graph-analyzer -f html src/main.ts",
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
catch (_error) {
|
|
146
|
+
return {
|
|
147
|
+
type: "GRAPHVIZ_NOT_FOUND",
|
|
148
|
+
message: "Graphviz is not installed or not in PATH",
|
|
149
|
+
suggestions: [
|
|
150
|
+
"Install Graphviz to generate PNG visualizations",
|
|
151
|
+
"",
|
|
152
|
+
"Installation instructions:",
|
|
153
|
+
" • macOS: brew install graphviz",
|
|
154
|
+
" • Ubuntu/Debian: sudo apt-get install graphviz",
|
|
155
|
+
" • Windows: choco install graphviz",
|
|
156
|
+
" • Or download from: https://graphviz.org/download/",
|
|
157
|
+
"",
|
|
158
|
+
"Alternatively, use JSON or HTML format instead:",
|
|
159
|
+
" graph-analyzer -f json src/main.ts",
|
|
160
|
+
" graph-analyzer -f html src/main.ts",
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Validate entry file comprehensively
|
|
167
|
+
*/
|
|
168
|
+
static validateEntryFile(filePath) {
|
|
169
|
+
// Check if file exists
|
|
170
|
+
const existsError = Validator.validateFileExists(filePath);
|
|
171
|
+
if (existsError)
|
|
172
|
+
return existsError;
|
|
173
|
+
// Check if it's a TypeScript file
|
|
174
|
+
const tsError = Validator.validateTypeScriptFile(filePath);
|
|
175
|
+
if (tsError)
|
|
176
|
+
return tsError;
|
|
177
|
+
// Check if file is readable
|
|
178
|
+
const readableError = Validator.validateFileReadable(filePath);
|
|
179
|
+
if (readableError)
|
|
180
|
+
return readableError;
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Validate output directory is writable
|
|
185
|
+
*/
|
|
186
|
+
static validateOutputDirectory(outputPath) {
|
|
187
|
+
const dir = path.dirname(path.resolve(outputPath));
|
|
188
|
+
// Check if directory exists
|
|
189
|
+
if (!fs.existsSync(dir)) {
|
|
190
|
+
try {
|
|
191
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
return {
|
|
196
|
+
type: "OUTPUT_DIR_NOT_WRITABLE",
|
|
197
|
+
message: `Cannot create output directory: ${dir}`,
|
|
198
|
+
suggestions: [
|
|
199
|
+
"Check that you have write permissions",
|
|
200
|
+
"Verify the parent directory exists",
|
|
201
|
+
"Try using a different output path",
|
|
202
|
+
],
|
|
203
|
+
details: error.message,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Check if directory is writable
|
|
208
|
+
try {
|
|
209
|
+
fs.accessSync(dir, fs.constants.W_OK);
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
return {
|
|
214
|
+
type: "OUTPUT_DIR_NOT_WRITABLE",
|
|
215
|
+
message: `Output directory is not writable: ${dir}`,
|
|
216
|
+
suggestions: [
|
|
217
|
+
"Check directory permissions",
|
|
218
|
+
"Make sure you have write access to the directory",
|
|
219
|
+
"Try running with appropriate permissions",
|
|
220
|
+
"Use a different output directory",
|
|
221
|
+
],
|
|
222
|
+
details: error.message,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Run all pre-flight validations
|
|
228
|
+
*/
|
|
229
|
+
static runPreflightChecks(options) {
|
|
230
|
+
// Validate entry file
|
|
231
|
+
const entryError = Validator.validateEntryFile(options.entryFile);
|
|
232
|
+
if (entryError)
|
|
233
|
+
return entryError;
|
|
234
|
+
// Validate tsconfig if provided
|
|
235
|
+
const tsConfigError = Validator.validateTsConfig(options.tsConfig);
|
|
236
|
+
if (tsConfigError)
|
|
237
|
+
return tsConfigError;
|
|
238
|
+
// Validate Graphviz for PNG generation
|
|
239
|
+
const graphvizError = Validator.validateGraphvizInstalled(options.format);
|
|
240
|
+
if (graphvizError)
|
|
241
|
+
return graphvizError;
|
|
242
|
+
// Validate output directory if provided
|
|
243
|
+
if (options.output) {
|
|
244
|
+
const outputError = Validator.validateOutputDirectory(options.output);
|
|
245
|
+
if (outputError)
|
|
246
|
+
return outputError;
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
exports.Validator = Validator;
|
|
252
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/utils/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type ModuleInfo = {
|
|
2
|
+
name: string;
|
|
3
|
+
imports: string[];
|
|
4
|
+
exports: string[];
|
|
5
|
+
isGlobal: boolean;
|
|
6
|
+
providers: any[];
|
|
7
|
+
dependencies: string[];
|
|
8
|
+
};
|
|
9
|
+
type ModulesData = {
|
|
10
|
+
[key: string]: ModuleInfo;
|
|
11
|
+
};
|
|
12
|
+
export declare class GraphGenerator {
|
|
13
|
+
private readonly json;
|
|
14
|
+
private readonly outputPath;
|
|
15
|
+
constructor(json: ModulesData, outputPath: string);
|
|
16
|
+
private typeColors;
|
|
17
|
+
/**
|
|
18
|
+
* Escape special characters for DOT format
|
|
19
|
+
* Escapes quotes, backslashes, and newlines to prevent injection
|
|
20
|
+
*/
|
|
21
|
+
private escapeDotString;
|
|
22
|
+
private generateDotGraph;
|
|
23
|
+
scan(): void;
|
|
24
|
+
protected ensureDirectoryExists(filePath: string): void;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GraphGenerator = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
class GraphGenerator {
|
|
8
|
+
constructor(json, outputPath) {
|
|
9
|
+
this.json = json;
|
|
10
|
+
this.outputPath = outputPath;
|
|
11
|
+
this.typeColors = {
|
|
12
|
+
Class: "lightblue",
|
|
13
|
+
UseValue: "lightgreen",
|
|
14
|
+
UseFactory: "lightcoral",
|
|
15
|
+
UseClass: "lightyellow",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Escape special characters for DOT format
|
|
20
|
+
* Escapes quotes, backslashes, and newlines to prevent injection
|
|
21
|
+
*/
|
|
22
|
+
escapeDotString(str) {
|
|
23
|
+
return str
|
|
24
|
+
.replace(/\\/g, "\\\\") // Escape backslashes first
|
|
25
|
+
.replace(/"/g, '\\"') // Escape quotes
|
|
26
|
+
.replace(/\n/g, "\\n") // Escape newlines
|
|
27
|
+
.replace(/\r/g, "\\r"); // Escape carriage returns
|
|
28
|
+
}
|
|
29
|
+
generateDotGraph() {
|
|
30
|
+
let dot = "digraph G {\n";
|
|
31
|
+
dot += " node [shape=box];\n"; // Set node shape
|
|
32
|
+
dot += " rankdir=LR;\n"; // Set horizontal graph direction
|
|
33
|
+
for (const [moduleName, moduleInfo] of Object.entries(this.json)) {
|
|
34
|
+
const escapedModuleName = this.escapeDotString(moduleName);
|
|
35
|
+
dot += ` "${escapedModuleName}" [label="${escapedModuleName}", style=filled, fillcolor="lightgray"];\n`;
|
|
36
|
+
if (moduleInfo.providers && moduleInfo.providers.length > 0) {
|
|
37
|
+
moduleInfo.providers.forEach((provider, index) => {
|
|
38
|
+
const providerName = `${escapedModuleName}_Provider${index}`;
|
|
39
|
+
const escapedToken = this.escapeDotString(provider.token);
|
|
40
|
+
const escapedType = this.escapeDotString(provider.type);
|
|
41
|
+
const providerLabel = `"${escapedToken} (${escapedType})"`;
|
|
42
|
+
const color = this.typeColors[provider.type] || "white";
|
|
43
|
+
dot += ` "${providerName}" [label=${providerLabel}, style=filled, fillcolor="${color}"];\n`;
|
|
44
|
+
dot += ` "${escapedModuleName}" -> "${providerName}";\n`;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
for (const imp of moduleInfo.imports) {
|
|
48
|
+
const escapedImp = this.escapeDotString(imp);
|
|
49
|
+
dot += ` "${escapedModuleName}" -> "${escapedImp}";\n`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
dot += "}\n";
|
|
53
|
+
return dot;
|
|
54
|
+
}
|
|
55
|
+
scan() {
|
|
56
|
+
const dotGraph = this.generateDotGraph();
|
|
57
|
+
this.ensureDirectoryExists(this.outputPath);
|
|
58
|
+
const dotProcess = (0, node_child_process_1.spawnSync)("dot", ["-Tpng", "-o", this.outputPath], {
|
|
59
|
+
input: dotGraph,
|
|
60
|
+
encoding: "utf-8",
|
|
61
|
+
});
|
|
62
|
+
if (dotProcess.error) {
|
|
63
|
+
console.error("Error running dot command:", dotProcess.error);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log(`Graph visualized as ${this.outputPath}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
ensureDirectoryExists(filePath) {
|
|
70
|
+
const dir = (0, node_path_1.dirname)(filePath);
|
|
71
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.GraphGenerator = GraphGenerator;
|
|
75
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/visualize/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { GraphOutput } from "../interfaces/graph-output.interface";
|
|
2
|
+
import type { ParseEntryFile } from "../parser/parse-entry-file";
|
|
3
|
+
import type { ParseNsModule } from "../parser/parse-ns-module";
|
|
4
|
+
import { type HtmlGeneratorOptions } from "./html-generator";
|
|
5
|
+
/**
|
|
6
|
+
* Options for configuring GraphAnalyzer output
|
|
7
|
+
*/
|
|
8
|
+
export interface GraphAnalyzerOptions {
|
|
9
|
+
/** Output format: 'json', 'png', 'html', or 'both' (default: 'both') */
|
|
10
|
+
outputFormat?: "json" | "png" | "html" | "both";
|
|
11
|
+
/** Output file path (used when format is not 'both') */
|
|
12
|
+
outputPath?: string;
|
|
13
|
+
/** JSON output file path (default: './graph.json') */
|
|
14
|
+
jsonOutputPath?: string;
|
|
15
|
+
/** PNG output file path (default: './graph.png') */
|
|
16
|
+
pngOutputPath?: string;
|
|
17
|
+
/** HTML output file path (default: './graph.html') */
|
|
18
|
+
htmlOutputPath?: string;
|
|
19
|
+
/** HTML generator options */
|
|
20
|
+
htmlOptions?: HtmlGeneratorOptions;
|
|
21
|
+
/** Enable circular dependency detection (default: false) */
|
|
22
|
+
checkCircular?: boolean;
|
|
23
|
+
/** Enable unused provider detection (default: false) */
|
|
24
|
+
checkUnused?: boolean;
|
|
25
|
+
/** Enable module depth analysis (default: false) */
|
|
26
|
+
checkDepth?: boolean;
|
|
27
|
+
/** Threshold for identifying deep modules (default: 5) */
|
|
28
|
+
deepModuleThreshold?: number;
|
|
29
|
+
/** Enable provider scope analysis (default: false) */
|
|
30
|
+
checkScope?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Main analyzer class for dependency injection graphs
|
|
34
|
+
*
|
|
35
|
+
* Analyzes Nexus IoC dependency graphs and generates JSON and/or PNG outputs.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const analyzer = new GraphAnalyzer(modulesGraph, 'src/main.ts', {
|
|
40
|
+
* outputFormat: 'json',
|
|
41
|
+
* jsonOutputPath: './output/graph.json'
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* const output = analyzer.parse();
|
|
45
|
+
* console.log(`Found ${output.metadata.totalProviders} providers`);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare class GraphAnalyzer {
|
|
49
|
+
private readonly graph;
|
|
50
|
+
private readonly entryPoint;
|
|
51
|
+
private readonly options;
|
|
52
|
+
/**
|
|
53
|
+
* Create a new GraphAnalyzer instance
|
|
54
|
+
*
|
|
55
|
+
* @param graph - Map of module names to parsed modules
|
|
56
|
+
* @param entryPoint - Path to application entry point file
|
|
57
|
+
* @param options - Configuration options for output generation
|
|
58
|
+
*/
|
|
59
|
+
constructor(graph: Map<string, ParseNsModule | ParseEntryFile>, entryPoint: string, options?: GraphAnalyzerOptions);
|
|
60
|
+
/**
|
|
61
|
+
* Parse the dependency graph and generate output based on configured format
|
|
62
|
+
*
|
|
63
|
+
* @returns GraphOutput object if format is 'json', 'html', or 'both', void if format is 'png'
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* // Generate JSON only
|
|
68
|
+
* const output = analyzer.parse();
|
|
69
|
+
*
|
|
70
|
+
* // Generate PNG only
|
|
71
|
+
* analyzer.parse(); // Returns void
|
|
72
|
+
*
|
|
73
|
+
* // Generate HTML only
|
|
74
|
+
* analyzer.parse(); // Returns void
|
|
75
|
+
*
|
|
76
|
+
* // Generate both JSON and PNG
|
|
77
|
+
* const output = analyzer.parse(); // Returns GraphOutput and creates PNG
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
parse(): GraphOutput | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Generate JSON output of the dependency graph
|
|
83
|
+
*
|
|
84
|
+
* Creates a structured JSON representation of all modules, providers, and dependencies.
|
|
85
|
+
* Optionally writes the output to a file if jsonOutputPath or outputPath is configured.
|
|
86
|
+
*
|
|
87
|
+
* @returns GraphOutput object containing modules, providers, and metadata
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const output = analyzer.generateJson();
|
|
92
|
+
* console.log(`Total modules: ${output.metadata.totalModules}`);
|
|
93
|
+
* console.log(`Total providers: ${output.metadata.totalProviders}`);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
generateJson(): GraphOutput;
|
|
97
|
+
/**
|
|
98
|
+
* Generate PNG visualization of the dependency graph using Graphviz
|
|
99
|
+
*
|
|
100
|
+
* Creates a visual graph representation showing modules as nodes and dependencies as edges.
|
|
101
|
+
* Requires Graphviz to be installed on the system.
|
|
102
|
+
*
|
|
103
|
+
* @throws Error if Graphviz is not installed or graph generation fails
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* analyzer.generatePng();
|
|
108
|
+
* // Creates graph.png in the configured output path
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
generatePng(): void;
|
|
112
|
+
/**
|
|
113
|
+
* Generate interactive HTML visualization of the dependency graph
|
|
114
|
+
*
|
|
115
|
+
* Creates an interactive HTML page with a graph visualization using Cytoscape.js.
|
|
116
|
+
* The HTML includes zoom/pan controls, node details, search functionality, and
|
|
117
|
+
* clickable file paths that open in your IDE.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* analyzer.generateHtml();
|
|
122
|
+
* // Creates graph.html in the configured output path
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
generateHtml(): void;
|
|
126
|
+
}
|