@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,486 @@
|
|
|
1
|
+
# Graph Analyzer Architecture
|
|
2
|
+
|
|
3
|
+
This document explains the technical architecture of the Nexus IoC Graph Analyzer, including how it works internally and the design decisions behind it.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [Architecture Diagram](#architecture-diagram)
|
|
9
|
+
- [Core Components](#core-components)
|
|
10
|
+
- [Analysis Pipeline](#analysis-pipeline)
|
|
11
|
+
- [Dependency Extraction](#dependency-extraction)
|
|
12
|
+
- [Design Decisions](#design-decisions)
|
|
13
|
+
- [Performance Considerations](#performance-considerations)
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
The Graph Analyzer is a static analysis tool that builds a complete dependency injection graph from TypeScript source code without executing it. It uses the TypeScript Compiler API to parse and analyze code, extracting metadata about modules, providers, and their dependencies.
|
|
18
|
+
|
|
19
|
+
### Key Principles
|
|
20
|
+
|
|
21
|
+
1. **Static Analysis Only** - No code execution required
|
|
22
|
+
2. **AST-Based** - Uses TypeScript's Abstract Syntax Tree
|
|
23
|
+
3. **Decorator-Aware** - Understands both legacy and TC39 Stage 3 decorators
|
|
24
|
+
4. **Import Resolution** - Follows module imports to build complete graph
|
|
25
|
+
5. **Type-Safe** - Leverages TypeScript's type system
|
|
26
|
+
|
|
27
|
+
## Architecture Diagram
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
31
|
+
│ Entry Point │
|
|
32
|
+
│ (CLI or API) │
|
|
33
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
37
|
+
│ ParseTsConfig │
|
|
38
|
+
│ (Load TypeScript Config) │
|
|
39
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
40
|
+
│
|
|
41
|
+
▼
|
|
42
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
43
|
+
│ ParseEntryFile │
|
|
44
|
+
│ (Find Root Module from Entry) │
|
|
45
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
46
|
+
│
|
|
47
|
+
▼
|
|
48
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
49
|
+
│ Module Traversal │
|
|
50
|
+
│ (Recursively Parse All Modules) │
|
|
51
|
+
│ │
|
|
52
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
53
|
+
│ │ ParseNsModule│───▶│ ParseNsModule│───▶│ ParseNsModule│ │
|
|
54
|
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
55
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
56
|
+
│
|
|
57
|
+
▼
|
|
58
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
59
|
+
│ Provider Analysis │
|
|
60
|
+
│ │
|
|
61
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
62
|
+
│ │ ClassParser │ │UseValueParser│ │UseFactoryPar.│ │
|
|
63
|
+
│ └──────┬───────┘ └──────────────┘ └──────────────┘ │
|
|
64
|
+
│ │ │
|
|
65
|
+
│ ▼ │
|
|
66
|
+
│ ┌──────────────────────────────────┐ │
|
|
67
|
+
│ │ DependencyExtractor │ │
|
|
68
|
+
│ │ (Extract @Inject, @Optional) │ │
|
|
69
|
+
│ └──────────────────────────────────┘ │
|
|
70
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
71
|
+
│
|
|
72
|
+
▼
|
|
73
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
74
|
+
│ Graph Building │
|
|
75
|
+
│ (Construct Dependency Graph) │
|
|
76
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
77
|
+
│
|
|
78
|
+
▼
|
|
79
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
80
|
+
│ Output Generation │
|
|
81
|
+
│ │
|
|
82
|
+
│ ┌──────────────┐ ┌──────────────┐ │
|
|
83
|
+
│ │JsonFormatter │ │GraphVisualizer│ │
|
|
84
|
+
│ │ (JSON Data) │ │ (PNG Image) │ │
|
|
85
|
+
│ └──────────────┘ └──────────────┘ │
|
|
86
|
+
└─────────────────────────────────────────────────────────────┘
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Core Components
|
|
90
|
+
|
|
91
|
+
### 1. ParseTsConfig
|
|
92
|
+
|
|
93
|
+
**Purpose**: Load and parse TypeScript configuration
|
|
94
|
+
|
|
95
|
+
**Responsibilities**:
|
|
96
|
+
- Read tsconfig.json
|
|
97
|
+
- Parse compiler options
|
|
98
|
+
- Resolve path aliases
|
|
99
|
+
- Provide configuration to other components
|
|
100
|
+
|
|
101
|
+
**Key Methods**:
|
|
102
|
+
- `constructor(configContent, basePath)` - Initialize with config
|
|
103
|
+
- `getCompilerOptions()` - Get TypeScript compiler options
|
|
104
|
+
|
|
105
|
+
### 2. ParseEntryFile
|
|
106
|
+
|
|
107
|
+
**Purpose**: Parse the application entry point
|
|
108
|
+
|
|
109
|
+
**Responsibilities**:
|
|
110
|
+
- Find the root module from entry file
|
|
111
|
+
- Extract bootstrap information
|
|
112
|
+
- Identify the starting point for graph traversal
|
|
113
|
+
|
|
114
|
+
**Key Methods**:
|
|
115
|
+
- `parse()` - Parse entry file and find root module
|
|
116
|
+
- `getName()` - Get root module name
|
|
117
|
+
|
|
118
|
+
### 3. ParseNsModule
|
|
119
|
+
|
|
120
|
+
**Purpose**: Parse individual Nexus IoC modules
|
|
121
|
+
|
|
122
|
+
**Responsibilities**:
|
|
123
|
+
- Extract module metadata (@NsModule decorator)
|
|
124
|
+
- Parse imports, exports, providers
|
|
125
|
+
- Identify global modules
|
|
126
|
+
- Trigger provider parsing
|
|
127
|
+
|
|
128
|
+
**Key Methods**:
|
|
129
|
+
- `parse()` - Parse module decorator and metadata
|
|
130
|
+
- `getProviders()` - Get module's providers
|
|
131
|
+
- `getImports()` - Get imported modules
|
|
132
|
+
|
|
133
|
+
### 4. Provider Parsers
|
|
134
|
+
|
|
135
|
+
**ClassParser**: Parses class providers
|
|
136
|
+
- Extracts class metadata
|
|
137
|
+
- Triggers dependency extraction
|
|
138
|
+
- Handles scope (Singleton, Transient, Request)
|
|
139
|
+
|
|
140
|
+
**UseValueParser**: Parses value providers
|
|
141
|
+
- Extracts static values
|
|
142
|
+
- No dependency extraction needed
|
|
143
|
+
|
|
144
|
+
**UseFactoryParser**: Parses factory providers
|
|
145
|
+
- Extracts factory function
|
|
146
|
+
- Analyzes factory dependencies
|
|
147
|
+
|
|
148
|
+
**UseClassParser**: Parses class-based providers
|
|
149
|
+
- Similar to ClassParser
|
|
150
|
+
- Handles interface-to-implementation mapping
|
|
151
|
+
|
|
152
|
+
### 5. DependencyExtractor
|
|
153
|
+
|
|
154
|
+
**Purpose**: Extract dependency injection metadata from classes
|
|
155
|
+
|
|
156
|
+
**Responsibilities**:
|
|
157
|
+
- Parse @Inject decorators on constructor parameters
|
|
158
|
+
- Parse @Inject decorators on properties
|
|
159
|
+
- Detect @Optional decorators
|
|
160
|
+
- Support TC39 Stage 3 static dependencies
|
|
161
|
+
- Identify token types (class, string, symbol)
|
|
162
|
+
|
|
163
|
+
**Key Methods**:
|
|
164
|
+
- `extractDependencies(classDeclaration)` - Main extraction method
|
|
165
|
+
- `extractConstructorDependencies()` - Constructor injection
|
|
166
|
+
- `extractPropertyDependencies()` - Property injection
|
|
167
|
+
- `extractStaticDependencies()` - TC39 Stage 3 pattern
|
|
168
|
+
|
|
169
|
+
**Algorithm**:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
1. Find class declaration in AST
|
|
173
|
+
2. Check for static dependencies array (TC39 Stage 3)
|
|
174
|
+
- If found, parse structured dependency objects
|
|
175
|
+
- Return early
|
|
176
|
+
3. Find constructor
|
|
177
|
+
- For each parameter:
|
|
178
|
+
- Check for @Inject decorator
|
|
179
|
+
- Extract token (class, string, or symbol)
|
|
180
|
+
- Check for @Optional decorator
|
|
181
|
+
- Store with index
|
|
182
|
+
4. Find properties
|
|
183
|
+
- For each property:
|
|
184
|
+
- Check for @Inject decorator
|
|
185
|
+
- Extract token
|
|
186
|
+
- Check for @Optional decorator
|
|
187
|
+
- Store with property name
|
|
188
|
+
5. Return combined dependencies
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 6. GraphAnalyzer
|
|
192
|
+
|
|
193
|
+
**Purpose**: Coordinate analysis and output generation
|
|
194
|
+
|
|
195
|
+
**Responsibilities**:
|
|
196
|
+
- Accept module graph
|
|
197
|
+
- Generate JSON output via JsonFormatter
|
|
198
|
+
- Generate PNG output via Graphviz
|
|
199
|
+
- Handle output format options
|
|
200
|
+
|
|
201
|
+
**Key Methods**:
|
|
202
|
+
- `parse()` - Main analysis method
|
|
203
|
+
- `generateJson()` - Create JSON output
|
|
204
|
+
- `generatePng()` - Create PNG visualization
|
|
205
|
+
|
|
206
|
+
### 7. JsonFormatter
|
|
207
|
+
|
|
208
|
+
**Purpose**: Format graph as structured JSON
|
|
209
|
+
|
|
210
|
+
**Responsibilities**:
|
|
211
|
+
- Traverse module graph
|
|
212
|
+
- Extract all metadata
|
|
213
|
+
- Create structured output
|
|
214
|
+
- Generate statistics
|
|
215
|
+
|
|
216
|
+
**Output Structure**:
|
|
217
|
+
```typescript
|
|
218
|
+
interface GraphOutput {
|
|
219
|
+
modules: ModuleInfo[];
|
|
220
|
+
providers: ProviderInfo[];
|
|
221
|
+
metadata: GraphMetadata;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Analysis Pipeline
|
|
226
|
+
|
|
227
|
+
### Phase 1: Configuration Loading
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
const tsConfig = new ParseTsConfig(configContent, basePath);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
- Loads tsconfig.json
|
|
234
|
+
- Parses compiler options
|
|
235
|
+
- Sets up path alias resolution
|
|
236
|
+
|
|
237
|
+
### Phase 2: Entry Point Analysis
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
const entryFile = new ParseEntryFile(sourceFile, filePath, tsConfig);
|
|
241
|
+
entryFile.parse();
|
|
242
|
+
const rootModuleName = entryFile.getName();
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
- Parses entry file (e.g., main.ts)
|
|
246
|
+
- Finds bootstrap call
|
|
247
|
+
- Extracts root module name
|
|
248
|
+
|
|
249
|
+
### Phase 3: Module Graph Traversal
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
const modulesGraph = new Map();
|
|
253
|
+
// Recursive traversal
|
|
254
|
+
function traverseModule(moduleName) {
|
|
255
|
+
const module = new ParseNsModule(sourceFile, filePath, tsConfig);
|
|
256
|
+
module.parse();
|
|
257
|
+
modulesGraph.set(moduleName, module);
|
|
258
|
+
|
|
259
|
+
for (const importedModule of module.getImports()) {
|
|
260
|
+
if (!modulesGraph.has(importedModule)) {
|
|
261
|
+
traverseModule(importedModule);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
- Starts from root module
|
|
268
|
+
- Recursively follows imports
|
|
269
|
+
- Builds complete module graph
|
|
270
|
+
- Detects circular imports
|
|
271
|
+
|
|
272
|
+
### Phase 4: Provider Analysis
|
|
273
|
+
|
|
274
|
+
For each module:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
const providers = module.getProviders();
|
|
278
|
+
for (const provider of providers) {
|
|
279
|
+
const parser = selectParser(provider); // ClassParser, UseValueParser, etc.
|
|
280
|
+
const metadata = parser.parse();
|
|
281
|
+
|
|
282
|
+
if (parser instanceof ClassParser) {
|
|
283
|
+
const dependencies = dependencyExtractor.extractDependencies(classNode);
|
|
284
|
+
metadata.dependencies = dependencies;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
- Parses each provider
|
|
290
|
+
- Extracts provider metadata
|
|
291
|
+
- For class providers, extracts dependencies
|
|
292
|
+
|
|
293
|
+
### Phase 5: Output Generation
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
const analyzer = new GraphAnalyzer(modulesGraph, entryPoint, options);
|
|
297
|
+
const output = analyzer.parse();
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
- Creates GraphAnalyzer instance
|
|
301
|
+
- Generates requested output format(s)
|
|
302
|
+
- Writes to file(s)
|
|
303
|
+
|
|
304
|
+
## Dependency Extraction
|
|
305
|
+
|
|
306
|
+
### Legacy Decorators (TypeScript Experimental)
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
@Injectable()
|
|
310
|
+
class UserService {
|
|
311
|
+
constructor(
|
|
312
|
+
@Inject(UserRepository) private repo: UserRepository
|
|
313
|
+
) {}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**AST Pattern**:
|
|
318
|
+
```
|
|
319
|
+
ClassDeclaration
|
|
320
|
+
└── Constructor
|
|
321
|
+
└── Parameter
|
|
322
|
+
└── Decorator (@Inject)
|
|
323
|
+
└── CallExpression
|
|
324
|
+
└── Argument (UserRepository)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Extraction**:
|
|
328
|
+
1. Find constructor node
|
|
329
|
+
2. Iterate parameters
|
|
330
|
+
3. Find @Inject decorator
|
|
331
|
+
4. Extract argument as token
|
|
332
|
+
5. Check for @Optional decorator
|
|
333
|
+
|
|
334
|
+
### TC39 Stage 3 Decorators
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
@Injectable()
|
|
338
|
+
class UserService {
|
|
339
|
+
static dependencies = [
|
|
340
|
+
{ index: 0, token: UserRepository, optional: false }
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**AST Pattern**:
|
|
346
|
+
```
|
|
347
|
+
ClassDeclaration
|
|
348
|
+
└── PropertyDeclaration (static dependencies)
|
|
349
|
+
└── ArrayLiteralExpression
|
|
350
|
+
└── ObjectLiteralExpression
|
|
351
|
+
├── index: 0
|
|
352
|
+
├── token: UserRepository
|
|
353
|
+
└── optional: false
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Extraction**:
|
|
357
|
+
1. Find static dependencies property
|
|
358
|
+
2. Parse array literal
|
|
359
|
+
3. Extract structured objects
|
|
360
|
+
4. Map to Dependency interface
|
|
361
|
+
|
|
362
|
+
### Token Type Detection
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
function detectTokenType(token: ts.Node): 'class' | 'string' | 'symbol' {
|
|
366
|
+
if (ts.isIdentifier(token)) return 'class';
|
|
367
|
+
if (ts.isStringLiteral(token)) return 'string';
|
|
368
|
+
if (isSymbolExpression(token)) return 'symbol';
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Design Decisions
|
|
373
|
+
|
|
374
|
+
### Why TypeScript Compiler API?
|
|
375
|
+
|
|
376
|
+
**Pros**:
|
|
377
|
+
- Accurate AST parsing
|
|
378
|
+
- Type information available
|
|
379
|
+
- Handles all TypeScript syntax
|
|
380
|
+
- Well-maintained by Microsoft
|
|
381
|
+
|
|
382
|
+
**Cons**:
|
|
383
|
+
- Large dependency
|
|
384
|
+
- Complex API
|
|
385
|
+
- Performance overhead
|
|
386
|
+
|
|
387
|
+
**Decision**: The accuracy and completeness outweigh the complexity.
|
|
388
|
+
|
|
389
|
+
### Why tsquery?
|
|
390
|
+
|
|
391
|
+
**Pros**:
|
|
392
|
+
- CSS-selector-like syntax for AST queries
|
|
393
|
+
- Simpler than manual AST traversal
|
|
394
|
+
- Good for finding specific patterns
|
|
395
|
+
|
|
396
|
+
**Usage**:
|
|
397
|
+
```typescript
|
|
398
|
+
const decorators = tsquery(node, 'Decorator[expression.expression.name="Inject"]');
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Why Separate Parsers?
|
|
402
|
+
|
|
403
|
+
Each provider type (Class, UseValue, UseFactory, UseClass) has different parsing logic:
|
|
404
|
+
- **Separation of Concerns**: Each parser handles one type
|
|
405
|
+
- **Extensibility**: Easy to add new provider types
|
|
406
|
+
- **Testability**: Each parser can be tested independently
|
|
407
|
+
|
|
408
|
+
### Why Two-Phase Analysis?
|
|
409
|
+
|
|
410
|
+
1. **Module Traversal** - Build complete graph
|
|
411
|
+
2. **Dependency Extraction** - Extract detailed metadata
|
|
412
|
+
|
|
413
|
+
**Rationale**:
|
|
414
|
+
- Allows circular dependency detection
|
|
415
|
+
- Enables lazy loading of class files
|
|
416
|
+
- Separates graph structure from implementation details
|
|
417
|
+
|
|
418
|
+
## Performance Considerations
|
|
419
|
+
|
|
420
|
+
### Caching
|
|
421
|
+
|
|
422
|
+
- Parsed modules are cached in Map
|
|
423
|
+
- Prevents re-parsing same module
|
|
424
|
+
- Reduces file I/O
|
|
425
|
+
|
|
426
|
+
### Lazy Loading
|
|
427
|
+
|
|
428
|
+
- Class files loaded only when needed
|
|
429
|
+
- Import resolution on-demand
|
|
430
|
+
- Reduces memory footprint
|
|
431
|
+
|
|
432
|
+
### AST Reuse
|
|
433
|
+
|
|
434
|
+
- TypeScript AST is reused across parsers
|
|
435
|
+
- No re-parsing of same file
|
|
436
|
+
- Faster analysis
|
|
437
|
+
|
|
438
|
+
### Optimization Opportunities
|
|
439
|
+
|
|
440
|
+
1. **Parallel Parsing**: Parse independent modules in parallel
|
|
441
|
+
2. **Incremental Analysis**: Only re-analyze changed files
|
|
442
|
+
3. **AST Caching**: Cache parsed ASTs to disk
|
|
443
|
+
4. **Selective Analysis**: Only analyze specific modules
|
|
444
|
+
|
|
445
|
+
## Error Handling
|
|
446
|
+
|
|
447
|
+
### File Not Found
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
if (!fs.existsSync(filePath)) {
|
|
451
|
+
throw new Error(`File not found: ${filePath}`);
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Invalid Decorator
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
if (!decorator || !decorator.expression) {
|
|
459
|
+
console.warn(`Invalid decorator on ${className}`);
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Circular Dependencies
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
const visited = new Set();
|
|
468
|
+
function detectCircular(module, path = []) {
|
|
469
|
+
if (visited.has(module)) {
|
|
470
|
+
console.warn(`Circular dependency: ${path.join(' -> ')}`);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
visited.add(module);
|
|
474
|
+
// Continue traversal
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Future Enhancements
|
|
479
|
+
|
|
480
|
+
1. **Incremental Analysis**: Only re-analyze changed files
|
|
481
|
+
2. **Watch Mode**: Continuously monitor and update graph
|
|
482
|
+
3. **Plugin System**: Allow custom analyzers
|
|
483
|
+
4. **Performance Profiling**: Identify bottlenecks
|
|
484
|
+
5. **Validation Rules**: Detect anti-patterns
|
|
485
|
+
6. **Interactive Visualization**: Web-based graph explorer
|
|
486
|
+
|