Skip to content

Commit 8a18529

Browse files
authored
feat(dependency-traversal): Implement comprehensive type dependency traversal (#12)
This commit introduces a comprehensive type dependency traversal implementation that combines AST traversal, dependency collection, and analysis. The key changes are: - Implement `DependencyTraversal` class that manages the dependency graph using Graphology library - Add methods to extract interface and type alias references from type declarations - Introduce `TypeReferenceExtractor` interface to allow customization of type reference extraction - Implement `ProcessingOrderResult` to analyze the optimal processing order for interfaces and type aliases These changes enable efficient management of type dependencies, which is crucial for generating code that respects the correct order of type declarations.
1 parent dea3c9c commit 8a18529

18 files changed

+1664
-1468
lines changed

ARCHITECTURE.md

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,17 @@ The main logic for code generation resides in the <mcfile name="ts-morph-codegen
7575

7676
The code generation process includes sophisticated import resolution and dependency management to handle complex type hierarchies and multi-level import chains:
7777

78-
#### DependencyCollector
78+
#### DependencyTraversal
7979

80-
The <mcfile name="dependency-collector.ts" path="src/traverse/dependency-collector.ts"></mcfile> module implements a `DependencyCollector` class that:
80+
The <mcfile name="dependency-traversal.ts" path="src/traverse/dependency-traversal.ts"></mcfile> module implements a unified `DependencyTraversal` class that exclusively uses Graphology for all dependency management:
8181

82+
- **Graphology-Only Architecture**: Uses Graphology's DirectedGraph exclusively for all dependency tracking, eliminating Map-based and other tracking mechanisms
83+
- **Unified Data Management**: All dependency information is stored and managed through the Graphology graph structure with node attributes
84+
- **Topological Sorting**: Employs graphology-dag for robust dependency ordering with circular dependency detection and preference-based sorting
8285
- **Traverses Import Chains**: Recursively follows import declarations to collect all type dependencies from external files
83-
- **Builds Dependency Graph**: Creates a comprehensive map of type dependencies, tracking which types depend on which other types
84-
- **Topological Sorting**: Performs topological sorting to ensure types are generated in the correct dependency order
8586
- **Handles Multi-level Imports**: Supports complex scenarios with 3+ levels of nested imports (e.g., `TypeA` imports `TypeB` which imports `TypeC`)
87+
- **Graph-Based Caching**: Uses Graphology node attributes for caching type information and dependency relationships
88+
- **Export-Aware Ordering**: Provides specialized ordering logic for `exportEverything=false` scenarios to ensure proper dependency resolution
8689

8790
#### Key Features
8891

@@ -93,19 +96,58 @@ The <mcfile name="dependency-collector.ts" path="src/traverse/dependency-collect
9396

9497
#### Implementation Details
9598

96-
The import resolution process works in two phases:
99+
The import resolution process works in three phases using the unified architecture:
97100

98101
1. **Collection Phase**:
99-
- `DependencyCollector.collectFromImports()` traverses all import declarations
100-
- `DependencyCollector.addLocalTypes()` adds local type aliases
101-
- Dependencies are tracked in a `Map<string, TypeInfo>` structure
102+
- `DependencyTraversal.collectFromImports()` traverses all import declarations using integrated AST traversal
103+
- `DependencyTraversal.addLocalTypes()` adds local type aliases with unified type reference extraction
104+
- Dependencies are tracked using Graphology's DirectedGraph with nodes and edges representing type relationships
102105

103-
2. **Generation Phase**:
104-
- `DependencyCollector.getTopologicallySortedTypes()` returns types in dependency order
106+
2. **Analysis Phase**:
107+
- `DependencyTraversal.getTopologicallySortedTypesWithPreference()` performs dependency ordering with export-aware preferences
108+
- Uses graphology-dag for circular dependency detection and topological sorting
109+
- Handles complex dependency scenarios including imported vs. local type ordering based on `exportEverything` flag
110+
111+
3. **Generation Phase**:
112+
- `DependencyTraversal.getTopologicallySortedTypes()` returns types in dependency order
105113
- `TypeAliasParser.parseWithImportFlag()` generates code with appropriate export handling
106114
- Types are processed sequentially in the sorted order
107115

108-
This approach ensures that complex import scenarios work correctly and generated code compiles without dependency errors.
116+
This unified approach ensures robust handling of complex import scenarios, circular dependencies, and generates code that compiles without dependency errors while maintaining optimal performance through reduced module boundaries.
117+
118+
### Unified Dependency Management
119+
120+
The dependency management system is built on a unified architecture that integrates all dependency-related functionality:
121+
122+
#### DependencyTraversal Integration
123+
124+
The <mcfile name="dependency-traversal.ts" path="src/traverse/dependency-traversal.ts"></mcfile> module provides comprehensive dependency management:
125+
126+
- **Integrated AST Traversal**: Combines AST traversal logic with dependency collection for optimal performance
127+
- **Direct Graphology Usage**: Uses Graphology's DirectedGraph directly for dependency tracking without abstraction layers
128+
- **Unified Type Reference Extraction**: Consolidates type reference extraction logic within the main traversal module
129+
- **Export-Aware Processing**: Implements specialized logic for handling `exportEverything=false` scenarios with proper dependency ordering
130+
- **Performance Optimization**: Eliminates module boundaries and reduces function call overhead through unified architecture
131+
132+
#### Graph-Based Dependency Resolution
133+
134+
The unified module leverages Graphology's ecosystem for robust dependency management:
135+
136+
- **DirectedGraph**: Uses Graphology's optimized graph data structure for dependency relationships
137+
- **Topological Sorting**: Employs `topologicalSort` from `graphology-dag` for dependency ordering with circular dependency detection
138+
- **Preference-Based Ordering**: Implements `getTopologicallySortedTypesWithPreference()` for export-aware type ordering
139+
- **Memory Efficiency**: Direct Graphology usage provides optimal memory management for large dependency graphs
140+
- **Type Safety**: Full TypeScript support through graphology-types package
141+
142+
#### Simplified Architecture Benefits
143+
144+
The Graphology-only approach provides several advantages:
145+
146+
- **Simplified Architecture**: Eliminates multiple tracking mechanisms (Map-based dependencies, visitedFiles, various caches) in favor of a single graph-based solution
147+
- **Enhanced Performance**: Direct Graphology operations provide optimized graph algorithms and data structures
148+
- **Improved Maintainability**: Single dependency tracking mechanism reduces complexity and potential inconsistencies
149+
- **Better Memory Management**: Graphology's optimized memory handling for large dependency graphs
150+
- **Unified Data Model**: All dependency information stored consistently in graph nodes and edges
109151

110152
## Interface Inheritance Support
111153

@@ -115,13 +157,13 @@ The codebase provides comprehensive support for TypeScript interface inheritance
115157

116158
The main codegen logic in <mcfile name="ts-morph-codegen.ts" path="src/ts-morph-codegen.ts"></mcfile> implements sophisticated processing order management:
117159

118-
1. **Dependency Analysis**: Uses `InterfaceTypeDependencyAnalyzer` to analyze complex relationships between interfaces and type aliases
119-
2. **Conditional Processing**: Handles three scenarios:
120-
- Interfaces depending on type aliases only
121-
- Type aliases depending on interfaces only
122-
- Both dependencies present (three-phase processing)
123-
3. **Topological Sorting**: Ensures types are processed in correct dependency order to prevent "type not found" errors
124-
4. **Circular Dependency Detection**: The algorithm detects and handles circular inheritance scenarios gracefully
160+
1. **Unified Dependency Analysis**: Uses <mcfile name="dependency-traversal.ts" path="src/traverse/dependency-traversal.ts"></mcfile> with integrated graph-based architecture to analyze complex relationships between interfaces and type aliases
161+
2. **Direct Graph Processing**: Leverages Graphology's DirectedGraph and topological sorting for robust dependency ordering without abstraction layers
162+
3. **Export-Aware Processing**: Handles dependency ordering based on `exportEverything` flag:
163+
- `exportEverything=true`: Prioritizes imported types for consistent ordering
164+
- `exportEverything=false`: Ensures dependency-aware ordering while respecting local type preferences
165+
4. **Topological Sorting**: Uses `getTopologicallySortedTypesWithPreference()` to ensure types are processed in correct dependency order to prevent "type not found" errors
166+
5. **Circular Dependency Detection**: The graph-based algorithm detects and handles circular inheritance scenarios gracefully with detailed error reporting
125167

126168
### TypeBox Composite Generation
127169

@@ -277,7 +319,25 @@ When implementing new type handlers or modifying existing ones, it is crucial to
277319

278320
## Performance Optimizations
279321

280-
Several optimizations have been implemented to improve the performance of the code generation process, particularly for import resolution:
322+
Several optimizations have been implemented to improve the performance of the code generation process, particularly for import resolution and dependency management:
323+
324+
### Unified Dependency Management with Graphology
325+
326+
The project uses **Graphology** through a unified architecture for all dependency graph operations, providing:
327+
328+
- **Production-Ready Graph Library**: Leverages Graphology's battle-tested graph data structures and algorithms
329+
- **Optimized Performance**: Benefits from Graphology's highly optimized internal implementations for graph operations
330+
- **Advanced Graph Algorithms**: Direct access to specialized algorithms through Graphology ecosystem (graphology-dag, graphology-traversal)
331+
- **Type Safety**: Full TypeScript support through graphology-types package
332+
- **Memory Efficiency**: Graphology's optimized memory management for large graphs
333+
- **Unified Architecture**: Single module eliminates abstraction layers and reduces complexity
334+
335+
#### Core Architecture
336+
337+
- **DependencyTraversal**: Uses Graphology's `DirectedGraph` exclusively for all dependency tracking, with no fallback to Map-based structures
338+
- **Integrated Topological Sorting**: Leverages `topologicalSort` from `graphology-dag` for ordering dependencies with export-aware preferences
339+
- **Graph-Based Data Storage**: All dependency information, visited files, and type metadata stored as Graphology node attributes
340+
- **Export-Aware Processing**: Implements specialized ordering logic for different export scenarios using graph-based algorithms
281341

282342
### TypeBox Type Handler Optimization
283343

bun.lock

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,33 @@
33
"workspaces": {
44
"": {
55
"name": "new-bun-project",
6+
"dependencies": {
7+
"graphology": "^0.26.0",
8+
"graphology-dag": "^0.4.1",
9+
"graphology-traversal": "^0.3.1",
10+
},
611
"devDependencies": {
7-
"@eslint/js": "latest",
8-
"@prettier/sync": "latest",
9-
"@sinclair/typebox-codegen": "latest",
10-
"@types/bun": "latest",
11-
"@typescript-eslint/eslint-plugin": "latest",
12-
"@typescript-eslint/parser": "latest",
13-
"eslint": "latest",
14-
"eslint-config-prettier": "latest",
15-
"eslint-plugin-no-relative-import-paths": "latest",
16-
"eslint-plugin-prettier": "latest",
17-
"globals": "latest",
18-
"jiti": "latest",
19-
"prettier": "latest",
20-
"prettier-plugin-organize-imports": "latest",
21-
"ts-morph": "latest",
22-
"typescript-eslint": "latest",
23-
"wikibase-sdk": "latest",
12+
"@eslint/js": "^9.34.0",
13+
"@prettier/sync": "^0.6.1",
14+
"@sinclair/typebox-codegen": "^0.11.1",
15+
"@types/bun": "^1.2.21",
16+
"@typescript-eslint/eslint-plugin": "^8.41.0",
17+
"@typescript-eslint/parser": "^8.41.0",
18+
"eslint": "^9.34.0",
19+
"eslint-config-prettier": "^10.1.8",
20+
"eslint-plugin-no-relative-import-paths": "^1.6.1",
21+
"eslint-plugin-prettier": "^5.5.4",
22+
"globals": "^16.3.0",
23+
"graphology-types": "^0.24.8",
24+
"jiti": "^2.5.1",
25+
"prettier": "^3.6.2",
26+
"prettier-plugin-organize-imports": "^4.2.0",
27+
"ts-morph": "^26.0.0",
28+
"typescript-eslint": "^8.41.0",
29+
"wikibase-sdk": "^10.2.3",
2430
},
2531
"peerDependencies": {
26-
"typescript": "latest",
32+
"typescript": "~5.9.2",
2733
},
2834
},
2935
},
@@ -166,6 +172,8 @@
166172

167173
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
168174

175+
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
176+
169177
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
170178

171179
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
@@ -194,6 +202,18 @@
194202

195203
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
196204

205+
"graphology": ["graphology@0.26.0", "", { "dependencies": { "events": "^3.3.0" }, "peerDependencies": { "graphology-types": ">=0.24.0" } }, "sha512-8SSImzgUUYC89Z042s+0r/vMibY7GX/Emz4LDO5e7jYXhuoWfHISPFJYjpRLUSJGq6UQ6xlenvX1p/hJdfXuXg=="],
206+
207+
"graphology-dag": ["graphology-dag@0.4.1", "", { "dependencies": { "graphology-utils": "^2.4.1", "mnemonist": "^0.39.0" }, "peerDependencies": { "graphology-types": ">=0.19.0" } }, "sha512-3ch9oOAnHZDoT043vyg7ukmSkKJ505nFzaHaYOn0IF2PgGo5VtIavyVK4UpbIa4tli3hhGm1ZTdBsubTmaxu/w=="],
208+
209+
"graphology-indices": ["graphology-indices@0.17.0", "", { "dependencies": { "graphology-utils": "^2.4.2", "mnemonist": "^0.39.0" }, "peerDependencies": { "graphology-types": ">=0.20.0" } }, "sha512-A7RXuKQvdqSWOpn7ZVQo4S33O0vCfPBnUSf7FwE0zNCasqwZVUaCXePuWo5HBpWw68KJcwObZDHpFk6HKH6MYQ=="],
210+
211+
"graphology-traversal": ["graphology-traversal@0.3.1", "", { "dependencies": { "graphology-indices": "^0.17.0", "graphology-utils": "^2.0.0" }, "peerDependencies": { "graphology-types": ">=0.20.0" } }, "sha512-lGLrLKEDKtNgAKgHVhVftKf3cb/nuWwuVPQZHXRnN90JWn0RSjco/s+NB2ARSlMapEMlbnPgv6j++427yTnU3Q=="],
212+
213+
"graphology-types": ["graphology-types@0.24.8", "", {}, "sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q=="],
214+
215+
"graphology-utils": ["graphology-utils@2.5.2", "", { "peerDependencies": { "graphology-types": ">=0.23.0" } }, "sha512-ckHg8MXrXJkOARk56ZaSCM1g1Wihe2d6iTmz1enGOz4W/l831MBCKSayeFQfowgF8wd+PQ4rlch/56Vs/VZLDQ=="],
216+
197217
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
198218

199219
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
@@ -236,10 +256,14 @@
236256

237257
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
238258

259+
"mnemonist": ["mnemonist@0.39.8", "", { "dependencies": { "obliterator": "^2.0.1" } }, "sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ=="],
260+
239261
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
240262

241263
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
242264

265+
"obliterator": ["obliterator@2.0.5", "", {}, "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw=="],
266+
243267
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
244268

245269
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"eslint-plugin-no-relative-import-paths": "^1.6.1",
1616
"eslint-plugin-prettier": "^5.5.4",
1717
"globals": "^16.3.0",
18+
"graphology-types": "^0.24.8",
1819
"jiti": "^2.5.1",
1920
"prettier": "^3.6.2",
2021
"prettier-plugin-organize-imports": "^4.2.0",
@@ -32,5 +33,10 @@
3233
"typecheck": "tsc --noEmit",
3334
"lint": "eslint"
3435
},
35-
"type": "module"
36+
"type": "module",
37+
"dependencies": {
38+
"graphology": "^0.26.0",
39+
"graphology-dag": "^0.4.1",
40+
"graphology-traversal": "^0.3.1"
41+
}
3642
}

src/traverse/ast-traversal.ts

Lines changed: 0 additions & 111 deletions
This file was deleted.

0 commit comments

Comments
 (0)