@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,747 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
Complete API documentation for using the Graph Analyzer programmatically.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [Core Classes](#core-classes)
|
|
10
|
+
- [Interfaces](#interfaces)
|
|
11
|
+
- [Usage Examples](#usage-examples)
|
|
12
|
+
- [Advanced Topics](#advanced-topics)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install --save-dev graph-analyzer
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { GraphAnalyzer, ParseEntryFile, ParseTsConfig } from 'graph-analyzer';
|
|
24
|
+
import * as fs from 'fs';
|
|
25
|
+
import * as ts from 'typescript';
|
|
26
|
+
|
|
27
|
+
// Load and parse entry file
|
|
28
|
+
const entryContent = fs.readFileSync('src/main.ts', 'utf8');
|
|
29
|
+
const sourceFile = ts.createSourceFile(
|
|
30
|
+
'src/main.ts',
|
|
31
|
+
entryContent,
|
|
32
|
+
ts.ScriptTarget.Latest,
|
|
33
|
+
true
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Parse TypeScript config
|
|
37
|
+
const tsConfigContent = fs.readFileSync('tsconfig.json', 'utf8');
|
|
38
|
+
const tsConfig = new ParseTsConfig(tsConfigContent, process.cwd());
|
|
39
|
+
|
|
40
|
+
// Parse entry file
|
|
41
|
+
const entryFile = new ParseEntryFile(sourceFile, 'src/main.ts', tsConfig);
|
|
42
|
+
entryFile.parse();
|
|
43
|
+
|
|
44
|
+
// Build module graph (simplified - see full example below)
|
|
45
|
+
const modulesGraph = new Map();
|
|
46
|
+
modulesGraph.set('entry', entryFile);
|
|
47
|
+
|
|
48
|
+
// Analyze and generate output
|
|
49
|
+
const analyzer = new GraphAnalyzer(modulesGraph, 'src/main.ts', {
|
|
50
|
+
outputFormat: 'json',
|
|
51
|
+
jsonOutputPath: './graph.json'
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const output = analyzer.parse();
|
|
55
|
+
console.log(output);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Core Classes
|
|
59
|
+
|
|
60
|
+
### GraphAnalyzer
|
|
61
|
+
|
|
62
|
+
Main class for analyzing dependency graphs and generating output.
|
|
63
|
+
|
|
64
|
+
#### Constructor
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
constructor(
|
|
68
|
+
graph: Map<string, ParseNsModule | ParseEntryFile>,
|
|
69
|
+
entryPoint: string,
|
|
70
|
+
options?: GraphAnalyzerOptions
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Parameters**:
|
|
75
|
+
- `graph`: Map of module name to parsed module
|
|
76
|
+
- `entryPoint`: Path to entry file
|
|
77
|
+
- `options`: Optional configuration
|
|
78
|
+
|
|
79
|
+
**Options**:
|
|
80
|
+
```typescript
|
|
81
|
+
interface GraphAnalyzerOptions {
|
|
82
|
+
outputFormat?: 'json' | 'png' | 'both';
|
|
83
|
+
outputPath?: string;
|
|
84
|
+
jsonOutputPath?: string;
|
|
85
|
+
pngOutputPath?: string;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### Methods
|
|
90
|
+
|
|
91
|
+
##### `parse(): GraphOutput | void`
|
|
92
|
+
|
|
93
|
+
Analyze the graph and generate output based on format option.
|
|
94
|
+
|
|
95
|
+
**Returns**:
|
|
96
|
+
- `GraphOutput` if format is 'json' or 'both'
|
|
97
|
+
- `void` if format is 'png'
|
|
98
|
+
|
|
99
|
+
**Example**:
|
|
100
|
+
```typescript
|
|
101
|
+
const analyzer = new GraphAnalyzer(graph, 'src/main.ts', {
|
|
102
|
+
outputFormat: 'json'
|
|
103
|
+
});
|
|
104
|
+
const output = analyzer.parse();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
##### `generateJson(): GraphOutput`
|
|
108
|
+
|
|
109
|
+
Generate JSON output.
|
|
110
|
+
|
|
111
|
+
**Returns**: `GraphOutput` object
|
|
112
|
+
|
|
113
|
+
**Example**:
|
|
114
|
+
```typescript
|
|
115
|
+
const jsonOutput = analyzer.generateJson();
|
|
116
|
+
console.log(jsonOutput.metadata.totalProviders);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
##### `generatePng(): void`
|
|
120
|
+
|
|
121
|
+
Generate PNG visualization using Graphviz.
|
|
122
|
+
|
|
123
|
+
**Side Effects**: Writes PNG file to disk
|
|
124
|
+
|
|
125
|
+
**Example**:
|
|
126
|
+
```typescript
|
|
127
|
+
analyzer.generatePng();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### JsonFormatter
|
|
133
|
+
|
|
134
|
+
Formats dependency graph as structured JSON.
|
|
135
|
+
|
|
136
|
+
#### Constructor
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
constructor(
|
|
140
|
+
graph: Map<string, ParseNsModule | ParseEntryFile>,
|
|
141
|
+
entryPoint: string
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Parameters**:
|
|
146
|
+
- `graph`: Module graph to format
|
|
147
|
+
- `entryPoint`: Entry file path
|
|
148
|
+
|
|
149
|
+
#### Methods
|
|
150
|
+
|
|
151
|
+
##### `format(): GraphOutput`
|
|
152
|
+
|
|
153
|
+
Format graph as structured object.
|
|
154
|
+
|
|
155
|
+
**Returns**: `GraphOutput` with modules, providers, and metadata
|
|
156
|
+
|
|
157
|
+
**Example**:
|
|
158
|
+
```typescript
|
|
159
|
+
const formatter = new JsonFormatter(graph, 'src/main.ts');
|
|
160
|
+
const output = formatter.format();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
##### `formatAsString(indent?: number): string`
|
|
164
|
+
|
|
165
|
+
Format graph as JSON string.
|
|
166
|
+
|
|
167
|
+
**Parameters**:
|
|
168
|
+
- `indent`: Number of spaces for indentation (default: 2)
|
|
169
|
+
|
|
170
|
+
**Returns**: JSON string
|
|
171
|
+
|
|
172
|
+
**Example**:
|
|
173
|
+
```typescript
|
|
174
|
+
const jsonString = formatter.formatAsString(4);
|
|
175
|
+
fs.writeFileSync('graph.json', jsonString);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### DependencyExtractor
|
|
181
|
+
|
|
182
|
+
Extracts dependency injection metadata from classes.
|
|
183
|
+
|
|
184
|
+
#### Constructor
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
constructor(
|
|
188
|
+
sourceFile: ts.SourceFile,
|
|
189
|
+
tsConfig: ParseTsConfig
|
|
190
|
+
)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Parameters**:
|
|
194
|
+
- `sourceFile`: TypeScript source file
|
|
195
|
+
- `tsConfig`: TypeScript configuration
|
|
196
|
+
|
|
197
|
+
#### Methods
|
|
198
|
+
|
|
199
|
+
##### `extractDependencies(classDeclaration: ts.ClassDeclaration): Dependency[]`
|
|
200
|
+
|
|
201
|
+
Extract all dependencies from a class.
|
|
202
|
+
|
|
203
|
+
**Parameters**:
|
|
204
|
+
- `classDeclaration`: TypeScript class declaration node
|
|
205
|
+
|
|
206
|
+
**Returns**: Array of `Dependency` objects
|
|
207
|
+
|
|
208
|
+
**Example**:
|
|
209
|
+
```typescript
|
|
210
|
+
const extractor = new DependencyExtractor(sourceFile, tsConfig);
|
|
211
|
+
const dependencies = extractor.extractDependencies(classNode);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### ParseTsConfig
|
|
217
|
+
|
|
218
|
+
Parses and manages TypeScript configuration.
|
|
219
|
+
|
|
220
|
+
#### Constructor
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
constructor(
|
|
224
|
+
configContent: string,
|
|
225
|
+
basePath: string
|
|
226
|
+
)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Parameters**:
|
|
230
|
+
- `configContent`: tsconfig.json content as string
|
|
231
|
+
- `basePath`: Base directory path
|
|
232
|
+
|
|
233
|
+
**Example**:
|
|
234
|
+
```typescript
|
|
235
|
+
const content = fs.readFileSync('tsconfig.json', 'utf8');
|
|
236
|
+
const tsConfig = new ParseTsConfig(content, process.cwd());
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### Methods
|
|
240
|
+
|
|
241
|
+
##### `getCompilerOptions(): ts.CompilerOptions`
|
|
242
|
+
|
|
243
|
+
Get TypeScript compiler options.
|
|
244
|
+
|
|
245
|
+
**Returns**: Compiler options object
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
### ParseEntryFile
|
|
250
|
+
|
|
251
|
+
Parses application entry point file.
|
|
252
|
+
|
|
253
|
+
#### Constructor
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
constructor(
|
|
257
|
+
sourceFile: ts.SourceFile,
|
|
258
|
+
filePath: string,
|
|
259
|
+
tsConfig: ParseTsConfig
|
|
260
|
+
)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Parameters**:
|
|
264
|
+
- `sourceFile`: TypeScript source file
|
|
265
|
+
- `filePath`: File path
|
|
266
|
+
- `tsConfig`: TypeScript configuration
|
|
267
|
+
|
|
268
|
+
#### Methods
|
|
269
|
+
|
|
270
|
+
##### `parse(): void`
|
|
271
|
+
|
|
272
|
+
Parse entry file and extract root module.
|
|
273
|
+
|
|
274
|
+
**Side Effects**: Populates internal state
|
|
275
|
+
|
|
276
|
+
##### `getName(): string | null`
|
|
277
|
+
|
|
278
|
+
Get root module name.
|
|
279
|
+
|
|
280
|
+
**Returns**: Module name or null
|
|
281
|
+
|
|
282
|
+
**Example**:
|
|
283
|
+
```typescript
|
|
284
|
+
const entryFile = new ParseEntryFile(sourceFile, 'src/main.ts', tsConfig);
|
|
285
|
+
entryFile.parse();
|
|
286
|
+
const rootModule = entryFile.getName(); // 'AppModule'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
### ParseNsModule
|
|
292
|
+
|
|
293
|
+
Parses Nexus IoC module.
|
|
294
|
+
|
|
295
|
+
#### Constructor
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
constructor(
|
|
299
|
+
sourceFile: ts.SourceFile,
|
|
300
|
+
filePath: string,
|
|
301
|
+
tsConfig: ParseTsConfig
|
|
302
|
+
)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### Methods
|
|
306
|
+
|
|
307
|
+
##### `parse(): void`
|
|
308
|
+
|
|
309
|
+
Parse module decorator and metadata.
|
|
310
|
+
|
|
311
|
+
##### `getProviders(): Provider[]`
|
|
312
|
+
|
|
313
|
+
Get module's providers.
|
|
314
|
+
|
|
315
|
+
**Returns**: Array of provider objects
|
|
316
|
+
|
|
317
|
+
##### `getImports(): string[]`
|
|
318
|
+
|
|
319
|
+
Get imported module names.
|
|
320
|
+
|
|
321
|
+
**Returns**: Array of module names
|
|
322
|
+
|
|
323
|
+
##### `getExports(): string[]`
|
|
324
|
+
|
|
325
|
+
Get exported provider tokens.
|
|
326
|
+
|
|
327
|
+
**Returns**: Array of token names
|
|
328
|
+
|
|
329
|
+
**Example**:
|
|
330
|
+
```typescript
|
|
331
|
+
const module = new ParseNsModule(sourceFile, 'app.module.ts', tsConfig);
|
|
332
|
+
module.parse();
|
|
333
|
+
|
|
334
|
+
const providers = module.getProviders();
|
|
335
|
+
const imports = module.getImports();
|
|
336
|
+
const exports = module.getExports();
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Interfaces
|
|
342
|
+
|
|
343
|
+
### GraphOutput
|
|
344
|
+
|
|
345
|
+
Complete graph analysis output.
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
interface GraphOutput {
|
|
349
|
+
modules: ModuleInfo[];
|
|
350
|
+
providers: ProviderInfo[];
|
|
351
|
+
metadata: GraphMetadata;
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### ModuleInfo
|
|
356
|
+
|
|
357
|
+
Information about a single module.
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
interface ModuleInfo {
|
|
361
|
+
name: string;
|
|
362
|
+
path: string;
|
|
363
|
+
imports: string[];
|
|
364
|
+
exports: string[];
|
|
365
|
+
providers: string[];
|
|
366
|
+
isGlobal: boolean;
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### ProviderInfo
|
|
371
|
+
|
|
372
|
+
Information about a single provider.
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
interface ProviderInfo {
|
|
376
|
+
token: string;
|
|
377
|
+
type: 'Class' | 'UseValue' | 'UseFactory' | 'UseClass';
|
|
378
|
+
module: string;
|
|
379
|
+
scope?: 'Singleton' | 'Transient' | 'Request';
|
|
380
|
+
dependencies?: Dependency[];
|
|
381
|
+
value?: any;
|
|
382
|
+
factory?: string;
|
|
383
|
+
useClass?: string;
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Dependency
|
|
388
|
+
|
|
389
|
+
Dependency injection metadata.
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
interface Dependency {
|
|
393
|
+
type: 'constructor' | 'property';
|
|
394
|
+
index?: number; // For constructor dependencies
|
|
395
|
+
key?: string; // For property dependencies
|
|
396
|
+
token: string;
|
|
397
|
+
tokenType: 'class' | 'string' | 'symbol';
|
|
398
|
+
optional: boolean;
|
|
399
|
+
raw?: string;
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### GraphMetadata
|
|
404
|
+
|
|
405
|
+
Analysis metadata.
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
interface GraphMetadata {
|
|
409
|
+
entryPoint: string;
|
|
410
|
+
rootModule: string;
|
|
411
|
+
analyzedAt: string;
|
|
412
|
+
version: string;
|
|
413
|
+
totalModules: number;
|
|
414
|
+
totalProviders: number;
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Usage Examples
|
|
421
|
+
|
|
422
|
+
### Example 1: Basic Analysis
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { GraphAnalyzer, ParseEntryFile, ParseTsConfig } from 'graph-analyzer';
|
|
426
|
+
import * as fs from 'fs';
|
|
427
|
+
import * as ts from 'typescript';
|
|
428
|
+
|
|
429
|
+
function analyzeApplication(entryPath: string): void {
|
|
430
|
+
// Load files
|
|
431
|
+
const entryContent = fs.readFileSync(entryPath, 'utf8');
|
|
432
|
+
const tsConfigContent = fs.readFileSync('tsconfig.json', 'utf8');
|
|
433
|
+
|
|
434
|
+
// Parse
|
|
435
|
+
const sourceFile = ts.createSourceFile(
|
|
436
|
+
entryPath,
|
|
437
|
+
entryContent,
|
|
438
|
+
ts.ScriptTarget.Latest,
|
|
439
|
+
true
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
const tsConfig = new ParseTsConfig(tsConfigContent, process.cwd());
|
|
443
|
+
const entryFile = new ParseEntryFile(sourceFile, entryPath, tsConfig);
|
|
444
|
+
entryFile.parse();
|
|
445
|
+
|
|
446
|
+
// Build graph
|
|
447
|
+
const graph = new Map();
|
|
448
|
+
graph.set('entry', entryFile);
|
|
449
|
+
|
|
450
|
+
// Analyze
|
|
451
|
+
const analyzer = new GraphAnalyzer(graph, entryPath, {
|
|
452
|
+
outputFormat: 'both',
|
|
453
|
+
jsonOutputPath: './output/graph.json',
|
|
454
|
+
pngOutputPath: './output/graph.png'
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
analyzer.parse();
|
|
458
|
+
console.log('Analysis complete!');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
analyzeApplication('src/main.ts');
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Example 2: Extract Specific Information
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
import { JsonFormatter } from 'graph-analyzer';
|
|
468
|
+
|
|
469
|
+
function findCircularDependencies(graph: Map<any, any>): string[] {
|
|
470
|
+
const formatter = new JsonFormatter(graph, 'src/main.ts');
|
|
471
|
+
const output = formatter.format();
|
|
472
|
+
|
|
473
|
+
const circular: string[] = [];
|
|
474
|
+
const visited = new Set<string>();
|
|
475
|
+
const stack = new Set<string>();
|
|
476
|
+
|
|
477
|
+
function visit(moduleName: string): void {
|
|
478
|
+
if (stack.has(moduleName)) {
|
|
479
|
+
circular.push(moduleName);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (visited.has(moduleName)) return;
|
|
483
|
+
|
|
484
|
+
visited.add(moduleName);
|
|
485
|
+
stack.add(moduleName);
|
|
486
|
+
|
|
487
|
+
const module = output.modules.find(m => m.name === moduleName);
|
|
488
|
+
if (module) {
|
|
489
|
+
module.imports.forEach(visit);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
stack.delete(moduleName);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
output.modules.forEach(m => visit(m.name));
|
|
496
|
+
return circular;
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Example 3: Custom Output Processing
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
import { JsonFormatter } from 'graph-analyzer';
|
|
504
|
+
|
|
505
|
+
interface DependencyReport {
|
|
506
|
+
totalProviders: number;
|
|
507
|
+
providersByType: Record<string, number>;
|
|
508
|
+
unusedProviders: string[];
|
|
509
|
+
globalModules: string[];
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function generateReport(graph: Map<any, any>): DependencyReport {
|
|
513
|
+
const formatter = new JsonFormatter(graph, 'src/main.ts');
|
|
514
|
+
const output = formatter.format();
|
|
515
|
+
|
|
516
|
+
// Count providers by type
|
|
517
|
+
const providersByType: Record<string, number> = {};
|
|
518
|
+
output.providers.forEach(p => {
|
|
519
|
+
providersByType[p.type] = (providersByType[p.type] || 0) + 1;
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
// Find unused providers (not injected anywhere)
|
|
523
|
+
const usedTokens = new Set<string>();
|
|
524
|
+
output.providers.forEach(p => {
|
|
525
|
+
p.dependencies?.forEach(d => usedTokens.add(d.token));
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
const unusedProviders = output.providers
|
|
529
|
+
.map(p => p.token)
|
|
530
|
+
.filter(token => !usedTokens.has(token));
|
|
531
|
+
|
|
532
|
+
// Find global modules
|
|
533
|
+
const globalModules = output.modules
|
|
534
|
+
.filter(m => m.isGlobal)
|
|
535
|
+
.map(m => m.name);
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
totalProviders: output.metadata.totalProviders,
|
|
539
|
+
providersByType,
|
|
540
|
+
unusedProviders,
|
|
541
|
+
globalModules
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Example 4: Integration with Build Tools
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
// webpack-plugin.ts
|
|
550
|
+
import { GraphAnalyzer } from 'graph-analyzer';
|
|
551
|
+
|
|
552
|
+
class DependencyGraphPlugin {
|
|
553
|
+
apply(compiler: any) {
|
|
554
|
+
compiler.hooks.emit.tapAsync(
|
|
555
|
+
'DependencyGraphPlugin',
|
|
556
|
+
(compilation: any, callback: any) => {
|
|
557
|
+
// Analyze during build
|
|
558
|
+
const analyzer = new GraphAnalyzer(/* ... */);
|
|
559
|
+
const output = analyzer.parse();
|
|
560
|
+
|
|
561
|
+
// Add to build assets
|
|
562
|
+
compilation.assets['dependency-graph.json'] = {
|
|
563
|
+
source: () => JSON.stringify(output, null, 2),
|
|
564
|
+
size: () => JSON.stringify(output).length
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
callback();
|
|
568
|
+
}
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### Example 5: Validation Rules
|
|
575
|
+
|
|
576
|
+
```typescript
|
|
577
|
+
import { JsonFormatter, GraphOutput } from 'graph-analyzer';
|
|
578
|
+
|
|
579
|
+
interface ValidationRule {
|
|
580
|
+
name: string;
|
|
581
|
+
validate: (output: GraphOutput) => string[];
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const rules: ValidationRule[] = [
|
|
585
|
+
{
|
|
586
|
+
name: 'No circular dependencies',
|
|
587
|
+
validate: (output) => {
|
|
588
|
+
// Implementation from Example 2
|
|
589
|
+
return [];
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
name: 'All providers used',
|
|
594
|
+
validate: (output) => {
|
|
595
|
+
const errors: string[] = [];
|
|
596
|
+
const usedTokens = new Set<string>();
|
|
597
|
+
|
|
598
|
+
output.providers.forEach(p => {
|
|
599
|
+
p.dependencies?.forEach(d => usedTokens.add(d.token));
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
output.providers.forEach(p => {
|
|
603
|
+
if (!usedTokens.has(p.token) && !output.modules.some(m => m.exports.includes(p.token))) {
|
|
604
|
+
errors.push(`Unused provider: ${p.token}`);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
return errors;
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
name: 'No missing dependencies',
|
|
613
|
+
validate: (output) => {
|
|
614
|
+
const errors: string[] = [];
|
|
615
|
+
const availableTokens = new Set(output.providers.map(p => p.token));
|
|
616
|
+
|
|
617
|
+
output.providers.forEach(p => {
|
|
618
|
+
p.dependencies?.forEach(d => {
|
|
619
|
+
if (!d.optional && !availableTokens.has(d.token)) {
|
|
620
|
+
errors.push(`Missing dependency: ${d.token} required by ${p.token}`);
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
return errors;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
];
|
|
629
|
+
|
|
630
|
+
function validateGraph(graph: Map<any, any>): void {
|
|
631
|
+
const formatter = new JsonFormatter(graph, 'src/main.ts');
|
|
632
|
+
const output = formatter.format();
|
|
633
|
+
|
|
634
|
+
let hasErrors = false;
|
|
635
|
+
|
|
636
|
+
rules.forEach(rule => {
|
|
637
|
+
const errors = rule.validate(output);
|
|
638
|
+
if (errors.length > 0) {
|
|
639
|
+
console.error(`\n❌ ${rule.name}:`);
|
|
640
|
+
errors.forEach(err => console.error(` - ${err}`));
|
|
641
|
+
hasErrors = true;
|
|
642
|
+
} else {
|
|
643
|
+
console.log(`✅ ${rule.name}`);
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
if (hasErrors) {
|
|
648
|
+
process.exit(1);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
## Advanced Topics
|
|
654
|
+
|
|
655
|
+
### Custom Parsers
|
|
656
|
+
|
|
657
|
+
Extend the parser system for custom provider types:
|
|
658
|
+
|
|
659
|
+
```typescript
|
|
660
|
+
import { ProviderParser } from 'graph-analyzer';
|
|
661
|
+
|
|
662
|
+
class CustomProviderParser extends ProviderParser {
|
|
663
|
+
parse(): Provider {
|
|
664
|
+
// Custom parsing logic
|
|
665
|
+
return {
|
|
666
|
+
token: 'CustomToken',
|
|
667
|
+
type: 'Custom',
|
|
668
|
+
// ...
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### AST Manipulation
|
|
675
|
+
|
|
676
|
+
Work directly with TypeScript AST:
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
import * as ts from 'typescript';
|
|
680
|
+
import { tsquery } from '@phenomnomnominal/tsquery';
|
|
681
|
+
|
|
682
|
+
function findAllInjectDecorators(sourceFile: ts.SourceFile): ts.Decorator[] {
|
|
683
|
+
return tsquery(
|
|
684
|
+
sourceFile,
|
|
685
|
+
'Decorator[expression.expression.name="Inject"]'
|
|
686
|
+
) as ts.Decorator[];
|
|
687
|
+
}
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### Performance Optimization
|
|
691
|
+
|
|
692
|
+
For large codebases:
|
|
693
|
+
|
|
694
|
+
```typescript
|
|
695
|
+
// Cache parsed modules
|
|
696
|
+
const moduleCache = new Map<string, ParseNsModule>();
|
|
697
|
+
|
|
698
|
+
function getOrParseModule(path: string): ParseNsModule {
|
|
699
|
+
if (moduleCache.has(path)) {
|
|
700
|
+
return moduleCache.get(path)!;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const module = new ParseNsModule(/* ... */);
|
|
704
|
+
module.parse();
|
|
705
|
+
moduleCache.set(path, module);
|
|
706
|
+
return module;
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
## TypeScript Types
|
|
711
|
+
|
|
712
|
+
All types are exported and can be imported:
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
import type {
|
|
716
|
+
GraphOutput,
|
|
717
|
+
ModuleInfo,
|
|
718
|
+
ProviderInfo,
|
|
719
|
+
Dependency,
|
|
720
|
+
GraphMetadata,
|
|
721
|
+
GraphAnalyzerOptions
|
|
722
|
+
} from 'graph-analyzer';
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
## Error Handling
|
|
726
|
+
|
|
727
|
+
```typescript
|
|
728
|
+
try {
|
|
729
|
+
const analyzer = new GraphAnalyzer(graph, entryPoint);
|
|
730
|
+
const output = analyzer.parse();
|
|
731
|
+
} catch (error) {
|
|
732
|
+
if (error.message.includes('Empty entry module')) {
|
|
733
|
+
console.error('No root module found in entry file');
|
|
734
|
+
} else if (error.message.includes('File not found')) {
|
|
735
|
+
console.error('Entry file does not exist');
|
|
736
|
+
} else {
|
|
737
|
+
console.error('Analysis failed:', error);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
## See Also
|
|
743
|
+
|
|
744
|
+
- [README](../README.md) - Overview and quick start
|
|
745
|
+
- [CLI Guide](./CLI_GUIDE.md) - Command-line usage
|
|
746
|
+
- [Architecture](./ARCHITECTURE.md) - Technical details
|
|
747
|
+
|