nestjs-d2-diagrams 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License Copyright (c) 2025 Tomás Yañez
2
+
3
+ Permission is hereby granted, free of
4
+ charge, to any person obtaining a copy of this software and associated
5
+ documentation files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use, copy, modify, merge,
7
+ publish, distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice
12
+ (including the next paragraph) shall be included in all copies or substantial
13
+ portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
16
+ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
18
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,233 @@
1
+ # NestJS D2 Diagrams
2
+
3
+ Generate beautiful C4-style component and class diagrams from your NestJS projects using [D2](https://d2lang.com/).
4
+
5
+ ## Features
6
+
7
+ - 📦 **Component Diagrams** - Visualize your NestJS modules and their dependencies
8
+ - 🔗 **Class Diagrams** - Map out dependency injection relationships between classes
9
+ - 🎨 **C4 Model Style** - Generates diagrams following C4 architecture diagram conventions
10
+ - 🤝 **Interactive Mode** - Add rich metadata (technology stack, descriptions) to components
11
+ - 🎯 **Universal DI Support** - Detects all constructor injections, not just `@Injectable` classes
12
+
13
+ ## Installation
14
+
15
+ NPM:
16
+ ```bash
17
+ npm install -D nestjs-d2-diagrams
18
+ ```
19
+
20
+ Yarn:
21
+ ```bash
22
+ yarn add -D nestjs-d2-diagrams
23
+ ```
24
+
25
+ PNPM:
26
+ ```bash
27
+ pnpm add -D nestjs-d2-diagrams
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ Generate both diagrams
33
+ ```bash
34
+ npx nest-d2 generate
35
+ ```
36
+
37
+ Interactive mode (add metadata to components)
38
+ ```bash
39
+ npx nest-d2 generate -i
40
+ ```
41
+
42
+ Generate only component diagram
43
+ ```bash
44
+ npx nest-d2 generate --component-only
45
+ ```
46
+
47
+ Generate only class diagram
48
+ ```bash
49
+ npx nest-d2 generate --class-only
50
+ ```
51
+
52
+ Specify custom paths
53
+ ```bash
54
+ npx nest-d2 generate --project ./my-app --output ./docs/diagrams
55
+ ```
56
+
57
+ ## Output
58
+
59
+ The tool generates two D2 files:
60
+ - `component-diagram.d2` - Shows modules and their import relationships
61
+ - `class-diagram.d2` - Shows classes and their dependency injection relationships
62
+
63
+ ## Rendering Diagrams
64
+
65
+ Use the [D2 CLI](https://github.com/terrastruct/d2) to render your diagrams:
66
+
67
+ ```bash
68
+ # Install D2
69
+ curl -fsSL https://d2lang.com/install.sh | sh -s --
70
+
71
+ # Render to SVG
72
+ d2 diagrams/component-diagram.d2 diagrams/component-diagram.svg
73
+
74
+ # Render with C4 theme (recommended)
75
+ d2 --theme=c4 diagrams/component-diagram.d2 diagrams/component-diagram.svg
76
+
77
+ # Render to PNG
78
+ d2 diagrams/class-diagram.d2 diagrams/class-diagram.png
79
+ ```
80
+
81
+ ## Interactive Mode
82
+
83
+ When using interactive mode, you'll be prompted to add metadata to each module:
84
+
85
+ ```bash
86
+ npx nest-d2 generate -i
87
+ ```
88
+
89
+ **Example prompts:**
90
+ ```
91
+ Do you want to add metadata (technology, descriptions) to components? › Yes
92
+ Enter default technology for all components: › NestJS
93
+
94
+ --- UserModule ---
95
+ Technology (press Enter for "NestJS"): › [Enter]
96
+ Description (what does this module do?): › Handles user authentication and authorization
97
+
98
+ --- ProductModule ---
99
+ Technology (press Enter for "NestJS"): › [Enter]
100
+ Description (what does this module do?): › Manages product catalog and inventory
101
+ ```
102
+
103
+ This generates C4-style component diagrams with rich descriptions:
104
+
105
+ ```d2
106
+ UserModule: |md
107
+ ### UserModule
108
+ ---
109
+ **[Component: NestJS]**
110
+
111
+ Handles user authentication and authorization
112
+ | {
113
+ class: [component]
114
+ }
115
+ ```
116
+
117
+ ## Component Diagram
118
+
119
+ Analyzes `*.module.ts` files and extracts:
120
+ - Module names
121
+ - Imports (dependencies on other modules)
122
+ - Providers (services)
123
+ - Controllers
124
+ - Exports
125
+
126
+ The diagram shows module relationships and, in non-interactive mode, nested providers and controllers.
127
+
128
+ ## Class Diagram
129
+
130
+ Analyzes all TypeScript classes and detects:
131
+ - Constructor parameter dependencies (typed injections)
132
+ - `@Inject()` token-based injections
133
+ - Optional dependencies (`?` or `@Optional()`)
134
+ - Classes with `@Injectable()` decorator (highlighted in blue)
135
+
136
+ **Universal DI Detection**: Unlike tools that only look for `@Injectable()` classes, this analyzer detects all constructor injections. This is especially useful for:
137
+ - Use cases in Clean/Onion Architecture
138
+ - Domain services without decorators
139
+ - Any class participating in dependency injection
140
+
141
+ ## CLI Options
142
+
143
+ ```
144
+ Usage: nest-d2 generate [options]
145
+
146
+ Options:
147
+ -p, --project <path> Path to NestJS project (default: current directory)
148
+ -o, --output <path> Output directory for diagrams (default: "./diagrams")
149
+ -i, --interactive Enable interactive mode for adding metadata
150
+ --component-only Generate only component diagram
151
+ --class-only Generate only class diagram
152
+ -h, --help Display help for command
153
+ ```
154
+
155
+ ## Requirements
156
+
157
+ - Node.js 16+
158
+ - A NestJS project with `tsconfig.json` in the root
159
+ - [D2](https://d2lang.com/) CLI for rendering diagrams (optional, for visualization)
160
+
161
+ ## Examples
162
+
163
+ ### Component Diagram Output
164
+ ```d2
165
+ # NestJS Component Diagram
166
+
167
+ direction: right
168
+
169
+ AppModule: |md
170
+ ### AppModule
171
+ ---
172
+ **[Component: NestJS]**
173
+
174
+ Main application module
175
+ | {
176
+ class: [component]
177
+ }
178
+
179
+ UserModule: |md
180
+ ### UserModule
181
+ ---
182
+ **[Component: NestJS]**
183
+
184
+ User management and authentication
185
+ | {
186
+ class: [component]
187
+ }
188
+
189
+ AppModule -> UserModule: imports
190
+ ```
191
+
192
+ ### Class Diagram Output
193
+ ```d2
194
+ # NestJS Class Diagram
195
+
196
+ direction: down
197
+
198
+ UserController: UserController {
199
+ shape: class
200
+ # Dependencies
201
+ userService: UserService
202
+ }
203
+
204
+ UserService: UserService {
205
+ shape: class
206
+ style.fill: "#e3f2fd"
207
+ # Dependencies
208
+ userRepository: Repository
209
+ }
210
+
211
+ UserController -> UserService: depends on
212
+ ```
213
+
214
+ ## How It Works
215
+
216
+ 1. **TypeScript AST Parsing** - Uses `ts-morph` to parse your TypeScript source files
217
+ 2. **Module Analysis** - Extracts `@Module()` decorator metadata from `*.module.ts` files
218
+ 3. **Class Analysis** - Analyzes constructor parameters to detect all dependency injections
219
+ 4. **D2 Generation** - Converts the analysis into D2 diagram syntax with C4 styling
220
+
221
+ ## Contributing
222
+
223
+ Contributions are welcome! Please feel free to submit a Pull Request.
224
+
225
+ ## License
226
+
227
+ MIT
228
+
229
+ ## Links
230
+
231
+ - [D2 Language](https://d2lang.com/)
232
+ - [C4 Model](https://c4model.com/)
233
+ - [NestJS](https://nestjs.com/)
@@ -0,0 +1,13 @@
1
+ import { ClassInfo } from '../types';
2
+ export declare class ClassAnalyzer {
3
+ private project;
4
+ constructor(projectPath: string);
5
+ analyze(): ClassInfo[];
6
+ private analyzeSourceFile;
7
+ private analyzeClass;
8
+ private extractDependencies;
9
+ private extractTypeName;
10
+ private isPrimitiveOrCommon;
11
+ private hasInjectableDecorator;
12
+ }
13
+ //# sourceMappingURL=class-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzers/class-analyzer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAkB,MAAM,UAAU,CAAC;AAErD,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAU;gBAEb,WAAW,EAAE,MAAM;IAQ/B,OAAO,IAAI,SAAS,EAAE;IAYtB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,mBAAmB;IAsD3B,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,sBAAsB;CAG/B"}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClassAnalyzer = void 0;
4
+ const ts_morph_1 = require("ts-morph");
5
+ class ClassAnalyzer {
6
+ constructor(projectPath) {
7
+ this.project = new ts_morph_1.Project({
8
+ tsConfigFilePath: `${projectPath}/tsconfig.json`,
9
+ skipAddingFilesFromTsConfig: true,
10
+ });
11
+ this.project.addSourceFilesAtPaths(`${projectPath}/src/**/*.ts`);
12
+ }
13
+ analyze() {
14
+ const classes = [];
15
+ const sourceFiles = this.project.getSourceFiles();
16
+ for (const sourceFile of sourceFiles) {
17
+ const classInfos = this.analyzeSourceFile(sourceFile);
18
+ classes.push(...classInfos);
19
+ }
20
+ return classes;
21
+ }
22
+ analyzeSourceFile(sourceFile) {
23
+ const classes = [];
24
+ const classDeclarations = sourceFile.getClasses();
25
+ for (const classDeclaration of classDeclarations) {
26
+ const classInfo = this.analyzeClass(classDeclaration, sourceFile);
27
+ if (classInfo) {
28
+ classes.push(classInfo);
29
+ }
30
+ }
31
+ return classes;
32
+ }
33
+ analyzeClass(classDeclaration, sourceFile) {
34
+ const name = classDeclaration.getName();
35
+ if (!name)
36
+ return null;
37
+ const dependencies = this.extractDependencies(classDeclaration);
38
+ const isInjectable = this.hasInjectableDecorator(classDeclaration);
39
+ return {
40
+ name,
41
+ filePath: sourceFile.getFilePath(),
42
+ dependencies,
43
+ isInjectable,
44
+ };
45
+ }
46
+ extractDependencies(classDeclaration) {
47
+ const dependencies = [];
48
+ const constructors = classDeclaration.getConstructors();
49
+ if (constructors.length === 0)
50
+ return dependencies;
51
+ const constructor = constructors[0];
52
+ const parameters = constructor.getParameters();
53
+ for (const param of parameters) {
54
+ // Try to get the type from the type annotation first
55
+ const typeNode = param.getTypeNode();
56
+ let typeName;
57
+ if (typeNode) {
58
+ // Get the text directly from the source code (not resolved)
59
+ typeName = typeNode.getText();
60
+ }
61
+ else {
62
+ // Fallback to resolved type
63
+ const type = param.getType();
64
+ typeName = type.getText();
65
+ }
66
+ // Clean up the type name
67
+ typeName = this.extractTypeName(typeName);
68
+ // Skip primitive types and common non-injectable types
69
+ if (this.isPrimitiveOrCommon(typeName))
70
+ continue;
71
+ // Check for @Inject decorator
72
+ const injectDecorator = param.getDecorator('Inject');
73
+ let token;
74
+ if (injectDecorator) {
75
+ const args = injectDecorator.getArguments();
76
+ if (args.length > 0) {
77
+ token = args[0].getText().replace(/['"]/g, '');
78
+ }
79
+ }
80
+ // Check if optional (has ? or @Optional decorator)
81
+ const isOptional = param.hasQuestionToken() || param.getDecorator('Optional') !== undefined;
82
+ dependencies.push({
83
+ name: param.getName(),
84
+ type: typeName,
85
+ isOptional,
86
+ token,
87
+ });
88
+ }
89
+ return dependencies;
90
+ }
91
+ extractTypeName(typeText) {
92
+ // Remove import() wrappers if present
93
+ let cleaned = typeText.replace(/import\([^)]+\)\./g, '');
94
+ // Remove array brackets
95
+ cleaned = cleaned.replace(/\[\]/g, '');
96
+ // Remove generics
97
+ cleaned = cleaned.replace(/<[^>]+>/g, '');
98
+ // Handle union types - take the first non-undefined type
99
+ if (cleaned.includes('|')) {
100
+ const types = cleaned.split('|').map(t => t.trim());
101
+ cleaned = types.find(t => t !== 'undefined' && t !== 'null') || types[0];
102
+ }
103
+ // If it still contains a path separator, extract just the last part (class name)
104
+ if (cleaned.includes('/') || cleaned.includes('\\')) {
105
+ const parts = cleaned.split(/[/\\]/);
106
+ cleaned = parts[parts.length - 1];
107
+ // Remove any remaining quotes or special chars
108
+ cleaned = cleaned.replace(/["']/g, '');
109
+ }
110
+ return cleaned.trim();
111
+ }
112
+ isPrimitiveOrCommon(typeText) {
113
+ const primitives = [
114
+ 'string', 'number', 'boolean', 'any', 'unknown', 'void', 'never',
115
+ 'String', 'Number', 'Boolean', 'undefined', 'null'
116
+ ];
117
+ const cleanType = this.extractTypeName(typeText).toLowerCase();
118
+ return primitives.includes(cleanType);
119
+ }
120
+ hasInjectableDecorator(classDeclaration) {
121
+ return classDeclaration.getDecorator('Injectable') !== undefined;
122
+ }
123
+ }
124
+ exports.ClassAnalyzer = ClassAnalyzer;
125
+ //# sourceMappingURL=class-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-analyzer.js","sourceRoot":"","sources":["../../src/analyzers/class-analyzer.ts"],"names":[],"mappings":";;;AAAA,uCAAmF;AAGnF,MAAa,aAAa;IAGxB,YAAY,WAAmB;QAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,kBAAO,CAAC;YACzB,gBAAgB,EAAE,GAAG,WAAW,gBAAgB;YAChD,2BAA2B,EAAE,IAAI;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,GAAG,WAAW,cAAc,CAAC,CAAC;IACnE,CAAC;IAED,OAAO;QACL,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAElD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;QAC9B,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,iBAAiB,CAAC,UAAsB;QAC9C,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,MAAM,iBAAiB,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC;QAElD,KAAK,MAAM,gBAAgB,IAAI,iBAAiB,EAAE,CAAC;YACjD,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;YAClE,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,YAAY,CAClB,gBAAkC,EAClC,UAAsB;QAEtB,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAEvB,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;QAChE,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;QAEnE,OAAO;YACL,IAAI;YACJ,QAAQ,EAAE,UAAU,CAAC,WAAW,EAAE;YAClC,YAAY;YACZ,YAAY;SACb,CAAC;IACJ,CAAC;IAEO,mBAAmB,CAAC,gBAAkC;QAC5D,MAAM,YAAY,GAAqB,EAAE,CAAC;QAC1C,MAAM,YAAY,GAAG,gBAAgB,CAAC,eAAe,EAAE,CAAC;QAExD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,YAAY,CAAC;QAEnD,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,EAAE,CAAC;QAE/C,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,qDAAqD;YACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YACrC,IAAI,QAAgB,CAAC;YAErB,IAAI,QAAQ,EAAE,CAAC;gBACb,4DAA4D;gBAC5D,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,4BAA4B;gBAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC7B,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,CAAC;YAED,yBAAyB;YACzB,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;YAE1C,uDAAuD;YACvD,IAAI,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAEjD,8BAA8B;YAC9B,MAAM,eAAe,GAAG,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrD,IAAI,KAAyB,CAAC;YAE9B,IAAI,eAAe,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,eAAe,CAAC,YAAY,EAAE,CAAC;gBAC5C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACpB,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;YAED,mDAAmD;YACnD,MAAM,UAAU,GAAG,KAAK,CAAC,gBAAgB,EAAE,IAAI,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,SAAS,CAAC;YAE5F,YAAY,CAAC,IAAI,CAAC;gBAChB,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE;gBACrB,IAAI,EAAE,QAAQ;gBACd,UAAU;gBACV,KAAK;aACN,CAAC,CAAC;QACL,CAAC;QAED,OAAO,YAAY,CAAC;IACtB,CAAC;IAEO,eAAe,CAAC,QAAgB;QACtC,sCAAsC;QACtC,IAAI,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;QAEzD,wBAAwB;QACxB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAEvC,kBAAkB;QAClB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAE1C,yDAAyD;QACzD,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACpD,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3E,CAAC;QAED,iFAAiF;QACjF,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACrC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAClC,+CAA+C;YAC/C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAEO,mBAAmB,CAAC,QAAgB;QAC1C,MAAM,UAAU,GAAG;YACjB,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO;YAChE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM;SACnD,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/D,OAAO,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAEO,sBAAsB,CAAC,gBAAkC;QAC/D,OAAO,gBAAgB,CAAC,YAAY,CAAC,YAAY,CAAC,KAAK,SAAS,CAAC;IACnE,CAAC;CACF;AArJD,sCAqJC"}
@@ -0,0 +1,9 @@
1
+ import { ModuleInfo } from '../types';
2
+ export declare class ModuleAnalyzer {
3
+ private project;
4
+ constructor(projectPath: string);
5
+ analyze(): ModuleInfo[];
6
+ private analyzeModuleFile;
7
+ private extractArrayPropertyValues;
8
+ }
9
+ //# sourceMappingURL=module-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzers/module-analyzer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAU;gBAEb,WAAW,EAAE,MAAM;IAQ/B,OAAO,IAAI,UAAU,EAAE;IAcvB,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,0BAA0B;CAiCnC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ModuleAnalyzer = void 0;
4
+ const ts_morph_1 = require("ts-morph");
5
+ class ModuleAnalyzer {
6
+ constructor(projectPath) {
7
+ this.project = new ts_morph_1.Project({
8
+ tsConfigFilePath: `${projectPath}/tsconfig.json`,
9
+ skipAddingFilesFromTsConfig: true,
10
+ });
11
+ this.project.addSourceFilesAtPaths(`${projectPath}/src/**/*.module.ts`);
12
+ }
13
+ analyze() {
14
+ const modules = [];
15
+ const sourceFiles = this.project.getSourceFiles();
16
+ for (const sourceFile of sourceFiles) {
17
+ const moduleInfo = this.analyzeModuleFile(sourceFile);
18
+ if (moduleInfo) {
19
+ modules.push(moduleInfo);
20
+ }
21
+ }
22
+ return modules;
23
+ }
24
+ analyzeModuleFile(sourceFile) {
25
+ const classes = sourceFile.getClasses();
26
+ for (const classDeclaration of classes) {
27
+ const decorator = classDeclaration.getDecorator('Module');
28
+ if (!decorator)
29
+ continue;
30
+ const decoratorArgs = decorator.getArguments();
31
+ if (decoratorArgs.length === 0)
32
+ continue;
33
+ const configObject = decoratorArgs[0];
34
+ if (!ts_morph_1.Node.isObjectLiteralExpression(configObject))
35
+ continue;
36
+ const name = classDeclaration.getName() || 'UnknownModule';
37
+ const filePath = sourceFile.getFilePath();
38
+ return {
39
+ name,
40
+ filePath,
41
+ imports: this.extractArrayPropertyValues(configObject, 'imports'),
42
+ providers: this.extractArrayPropertyValues(configObject, 'providers'),
43
+ controllers: this.extractArrayPropertyValues(configObject, 'controllers'),
44
+ exports: this.extractArrayPropertyValues(configObject, 'exports'),
45
+ };
46
+ }
47
+ return null;
48
+ }
49
+ extractArrayPropertyValues(objectLiteral, propertyName) {
50
+ const property = objectLiteral.getProperty(propertyName);
51
+ if (!property)
52
+ return [];
53
+ const initializer = property.getInitializer?.();
54
+ if (!initializer || !ts_morph_1.Node.isArrayLiteralExpression(initializer))
55
+ return [];
56
+ return initializer.getElements().map((element) => {
57
+ // Handle identifiers (e.g., UserService)
58
+ if (ts_morph_1.Node.isIdentifier(element)) {
59
+ return element.getText();
60
+ }
61
+ // Handle property access (e.g., TypeOrmModule.forRoot())
62
+ if (ts_morph_1.Node.isCallExpression(element)) {
63
+ const expression = element.getExpression();
64
+ if (ts_morph_1.Node.isPropertyAccessExpression(expression)) {
65
+ return expression.getExpression().getText();
66
+ }
67
+ return expression.getText();
68
+ }
69
+ // Handle property access without calls (e.g., SomeModule)
70
+ if (ts_morph_1.Node.isPropertyAccessExpression(element)) {
71
+ return element.getExpression().getText();
72
+ }
73
+ return element.getText();
74
+ });
75
+ }
76
+ }
77
+ exports.ModuleAnalyzer = ModuleAnalyzer;
78
+ //# sourceMappingURL=module-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-analyzer.js","sourceRoot":"","sources":["../../src/analyzers/module-analyzer.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const module_analyzer_1 = require("./analyzers/module-analyzer");
8
+ const class_analyzer_1 = require("./analyzers/class-analyzer");
9
+ const component_diagram_1 = require("./generators/component-diagram");
10
+ const class_diagram_1 = require("./generators/class-diagram");
11
+ const interactive_1 = require("./interactive");
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name('nest-d2')
15
+ .description('Generate D2 diagrams from NestJS projects')
16
+ .version('1.0.0');
17
+ program
18
+ .command('generate')
19
+ .description('Generate component and class diagrams')
20
+ .option('-p, --project <path>', 'Path to NestJS project', process.cwd())
21
+ .option('-o, --output <path>', 'Output directory for diagrams', './diagrams')
22
+ .option('--component-only', 'Generate only component diagram')
23
+ .option('--class-only', 'Generate only class diagram')
24
+ .option('-i, --interactive', 'Enable interactive mode for adding metadata')
25
+ .action(async (options) => {
26
+ try {
27
+ const projectPath = (0, path_1.resolve)(options.project);
28
+ const outputDir = (0, path_1.resolve)(options.output);
29
+ console.log(`Analyzing NestJS project at: ${projectPath}`);
30
+ // Check if tsconfig.json exists
31
+ if (!(0, fs_1.existsSync)(`${projectPath}/tsconfig.json`)) {
32
+ console.error('Error: tsconfig.json not found in project root');
33
+ process.exit(1);
34
+ }
35
+ // Create output directory if it doesn't exist
36
+ if (!(0, fs_1.existsSync)(outputDir)) {
37
+ (0, fs_1.mkdirSync)(outputDir, { recursive: true });
38
+ }
39
+ // Check for interactive mode
40
+ let isInteractive = options.interactive;
41
+ let defaultTechnology = '';
42
+ if (!isInteractive && !options.classOnly) {
43
+ isInteractive = await (0, interactive_1.promptForInteractiveMode)();
44
+ }
45
+ if (isInteractive) {
46
+ defaultTechnology = await (0, interactive_1.promptForDefaultTechnology)();
47
+ }
48
+ // Generate component diagram
49
+ if (!options.classOnly) {
50
+ console.log('\nAnalyzing modules...');
51
+ const moduleAnalyzer = new module_analyzer_1.ModuleAnalyzer(projectPath);
52
+ let modules = moduleAnalyzer.analyze();
53
+ console.log(`Found ${modules.length} modules`);
54
+ // Enrich modules with metadata if interactive
55
+ if (isInteractive) {
56
+ console.log('\n=== Adding metadata to modules ===');
57
+ const enrichedModules = [];
58
+ for (const module of modules) {
59
+ const enriched = await (0, interactive_1.enrichModuleWithMetadata)(module, defaultTechnology);
60
+ enrichedModules.push(enriched);
61
+ }
62
+ modules = enrichedModules;
63
+ }
64
+ const componentGen = new component_diagram_1.ComponentDiagramGenerator();
65
+ const componentD2 = componentGen.generate(modules);
66
+ const componentPath = `${outputDir}/component-diagram.d2`;
67
+ (0, fs_1.writeFileSync)(componentPath, componentD2);
68
+ console.log(`\n✓ Component diagram saved to: ${componentPath}`);
69
+ }
70
+ // Generate class diagram
71
+ if (!options.componentOnly) {
72
+ console.log('\nAnalyzing classes...');
73
+ const classAnalyzer = new class_analyzer_1.ClassAnalyzer(projectPath);
74
+ const classes = classAnalyzer.analyze();
75
+ console.log(`Found ${classes.length} classes`);
76
+ const classGen = new class_diagram_1.ClassDiagramGenerator();
77
+ const classD2 = classGen.generate(classes);
78
+ const classPath = `${outputDir}/class-diagram.d2`;
79
+ (0, fs_1.writeFileSync)(classPath, classD2);
80
+ console.log(`✓ Class diagram saved to: ${classPath}`);
81
+ }
82
+ console.log('\nDone! 🎉');
83
+ }
84
+ catch (error) {
85
+ console.error('Error generating diagrams:', error);
86
+ process.exit(1);
87
+ }
88
+ });
89
+ program.parse();
90
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { ClassInfo } from '../types';
2
+ export declare class ClassDiagramGenerator {
3
+ generate(classes: ClassInfo[]): string;
4
+ private findRelevantClasses;
5
+ private sanitizeName;
6
+ }
7
+ //# sourceMappingURL=class-diagram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-diagram.d.ts","sourceRoot":"","sources":["../../src/generators/class-diagram.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,qBAAa,qBAAqB;IAChC,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM;IA0DtC,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,YAAY;CAMrB"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClassDiagramGenerator = void 0;
4
+ class ClassDiagramGenerator {
5
+ generate(classes) {
6
+ const lines = [];
7
+ lines.push('# NestJS Class Diagram');
8
+ lines.push('');
9
+ lines.push('direction: down');
10
+ lines.push('');
11
+ // Filter to only classes that have dependencies or are depended upon
12
+ const relevantClasses = this.findRelevantClasses(classes);
13
+ // Create nodes for each class
14
+ for (const classInfo of relevantClasses) {
15
+ const className = this.sanitizeName(classInfo.name);
16
+ lines.push(`${className}: ${classInfo.name} {`);
17
+ lines.push(' shape: class');
18
+ // Add a note if it has @Injectable
19
+ if (classInfo.isInjectable) {
20
+ lines.push(' style.fill: "#e3f2fd"');
21
+ }
22
+ // List dependencies as attributes
23
+ if (classInfo.dependencies.length > 0) {
24
+ lines.push(' # Dependencies');
25
+ for (const dep of classInfo.dependencies) {
26
+ const optional = dep.isOptional ? '?' : '';
27
+ const token = dep.token ? ` (@Inject('${dep.token}'))` : '';
28
+ lines.push(` ${dep.name}${optional}: ${dep.type}${token}`);
29
+ }
30
+ }
31
+ lines.push('}');
32
+ lines.push('');
33
+ }
34
+ // Create edges for dependencies
35
+ for (const classInfo of relevantClasses) {
36
+ const className = this.sanitizeName(classInfo.name);
37
+ for (const dep of classInfo.dependencies) {
38
+ const depClassName = this.sanitizeName(dep.type);
39
+ // Check if the dependency class exists in our analysis
40
+ const exists = relevantClasses.some(c => this.sanitizeName(c.name) === depClassName);
41
+ if (exists) {
42
+ const style = dep.isOptional ? ' {style.stroke-dash: 3}' : '';
43
+ lines.push(`${className} -> ${depClassName}: depends on${style}`);
44
+ }
45
+ }
46
+ }
47
+ return lines.join('\n');
48
+ }
49
+ findRelevantClasses(classes) {
50
+ // Find classes that either have dependencies or are referenced as dependencies
51
+ const classNames = new Set(classes.map(c => c.name));
52
+ const referencedTypes = new Set();
53
+ // Collect all referenced types
54
+ for (const classInfo of classes) {
55
+ for (const dep of classInfo.dependencies) {
56
+ referencedTypes.add(dep.type);
57
+ }
58
+ }
59
+ // Include classes that have dependencies or are referenced
60
+ return classes.filter(classInfo => {
61
+ const hasDependencies = classInfo.dependencies.length > 0;
62
+ const isReferenced = referencedTypes.has(classInfo.name);
63
+ return hasDependencies || isReferenced;
64
+ });
65
+ }
66
+ sanitizeName(name) {
67
+ // Remove special characters and make valid D2 identifier
68
+ return name
69
+ .replace(/[^a-zA-Z0-9_]/g, '_')
70
+ .replace(/^(\d)/, '_$1'); // D2 identifiers can't start with numbers
71
+ }
72
+ }
73
+ exports.ClassDiagramGenerator = ClassDiagramGenerator;
74
+ //# sourceMappingURL=class-diagram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-diagram.js","sourceRoot":"","sources":["../../src/generators/class-diagram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { ModuleInfo } from '../types';
2
+ export declare class ComponentDiagramGenerator {
3
+ generate(modules: ModuleInfo[], showNesting?: boolean): string;
4
+ private sanitizeName;
5
+ }
6
+ //# sourceMappingURL=component-diagram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-diagram.d.ts","sourceRoot":"","sources":["../../src/generators/component-diagram.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,qBAAa,yBAAyB;IACpC,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,WAAW,GAAE,OAAe,GAAG,MAAM;IA2FrE,OAAO,CAAC,YAAY;CAMrB"}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ComponentDiagramGenerator = void 0;
4
+ class ComponentDiagramGenerator {
5
+ generate(modules, showNesting = false) {
6
+ const lines = [];
7
+ lines.push('# NestJS Component Diagram');
8
+ lines.push('');
9
+ lines.push('direction: right');
10
+ lines.push('');
11
+ lines.push('classes: {');
12
+ lines.push(' component: {');
13
+ lines.push(' shape: rectangle');
14
+ lines.push(' style.fill: "#87CEEB"');
15
+ lines.push(' style.border-radius: 32');
16
+ lines.push(' }');
17
+ lines.push('}');
18
+ lines.push('');
19
+ // Create nodes for each module
20
+ for (const module of modules) {
21
+ const moduleName = this.sanitizeName(module.name);
22
+ // Build the label in C4 markdown style
23
+ let label = `### ${module.name}`;
24
+ label += `\n ---`;
25
+ if (module.technology) {
26
+ label += `\n **[Component: ${module.technology}]**`;
27
+ }
28
+ if (module.description) {
29
+ label += `\n\n ${module.description}`;
30
+ }
31
+ // Start module block
32
+ lines.push(`${moduleName}: |md`);
33
+ lines.push(` ${label}`);
34
+ lines.push(`| {`);
35
+ lines.push(' class: [component]');
36
+ // Only show nesting if explicitly requested (non-interactive mode)
37
+ if (showNesting) {
38
+ // Add providers as nested elements
39
+ if (module.providers.length > 0) {
40
+ lines.push('');
41
+ lines.push(' providers: Providers {');
42
+ lines.push(' shape: rectangle');
43
+ for (const provider of module.providers) {
44
+ const providerName = this.sanitizeName(provider);
45
+ lines.push(` ${providerName}: ${provider}`);
46
+ }
47
+ lines.push(' }');
48
+ }
49
+ // Add controllers as nested elements
50
+ if (module.controllers.length > 0) {
51
+ lines.push('');
52
+ lines.push(' controllers: Controllers {');
53
+ lines.push(' shape: rectangle');
54
+ for (const controller of module.controllers) {
55
+ const controllerName = this.sanitizeName(controller);
56
+ lines.push(` ${controllerName}: ${controller}`);
57
+ }
58
+ lines.push(' }');
59
+ }
60
+ }
61
+ lines.push('}');
62
+ lines.push('');
63
+ }
64
+ // Create edges for imports
65
+ for (const module of modules) {
66
+ const moduleName = this.sanitizeName(module.name);
67
+ for (const importedModule of module.imports) {
68
+ const importedModuleName = this.sanitizeName(importedModule);
69
+ // Check if the imported module exists in our analysis
70
+ const exists = modules.some(m => this.sanitizeName(m.name) === importedModuleName);
71
+ if (exists) {
72
+ lines.push(`${moduleName} -> ${importedModuleName}: imports`);
73
+ }
74
+ }
75
+ }
76
+ return lines.join('\n');
77
+ }
78
+ sanitizeName(name) {
79
+ // Remove special characters and make valid D2 identifier
80
+ return name
81
+ .replace(/[^a-zA-Z0-9_]/g, '_')
82
+ .replace(/^(\d)/, '_$1'); // D2 identifiers can't start with numbers
83
+ }
84
+ }
85
+ exports.ComponentDiagramGenerator = ComponentDiagramGenerator;
86
+ //# sourceMappingURL=component-diagram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-diagram.js","sourceRoot":"","sources":["../../src/generators/component-diagram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { ModuleInfo } from './types';
2
+ export declare function promptForInteractiveMode(): Promise<boolean>;
3
+ export declare function promptForDefaultTechnology(): Promise<string>;
4
+ export declare function enrichModuleWithMetadata(module: ModuleInfo, defaultTechnology: string): Promise<ModuleInfo>;
5
+ //# sourceMappingURL=interactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,OAAO,CAAC,CASjE;AAED,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,MAAM,CAAC,CASlE;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,UAAU,EAClB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,UAAU,CAAC,CAqCrB"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.promptForInteractiveMode = promptForInteractiveMode;
7
+ exports.promptForDefaultTechnology = promptForDefaultTechnology;
8
+ exports.enrichModuleWithMetadata = enrichModuleWithMetadata;
9
+ const prompts_1 = __importDefault(require("prompts"));
10
+ async function promptForInteractiveMode() {
11
+ const response = await (0, prompts_1.default)({
12
+ type: 'confirm',
13
+ name: 'interactive',
14
+ message: 'Do you want to add metadata (technology, descriptions) to components?',
15
+ initial: false,
16
+ });
17
+ return response.interactive;
18
+ }
19
+ async function promptForDefaultTechnology() {
20
+ const response = await (0, prompts_1.default)({
21
+ type: 'text',
22
+ name: 'technology',
23
+ message: 'Enter default technology for all components (leave empty to prompt for each):',
24
+ initial: 'NestJS',
25
+ });
26
+ return response.technology || '';
27
+ }
28
+ async function enrichModuleWithMetadata(module, defaultTechnology) {
29
+ console.log(`\n--- ${module.name} ---`);
30
+ const questions = [];
31
+ // Technology question
32
+ if (defaultTechnology) {
33
+ questions.push({
34
+ type: 'text',
35
+ name: 'technology',
36
+ message: `Technology (press Enter for "${defaultTechnology}"):`,
37
+ initial: defaultTechnology,
38
+ });
39
+ }
40
+ else {
41
+ questions.push({
42
+ type: 'text',
43
+ name: 'technology',
44
+ message: 'Technology (e.g., NestJS, Spring Boot):',
45
+ initial: 'NestJS',
46
+ });
47
+ }
48
+ // Description question
49
+ questions.push({
50
+ type: 'text',
51
+ name: 'description',
52
+ message: 'Description (what does this module do?):',
53
+ initial: '',
54
+ });
55
+ const answers = await (0, prompts_1.default)(questions);
56
+ return {
57
+ ...module,
58
+ technology: answers.technology || defaultTechnology || 'NestJS',
59
+ description: answers.description || '',
60
+ };
61
+ }
62
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":";;;;;AAGA,4DASC;AAED,gEASC;AAED,4DAwCC;AAjED,sDAA8B;AAGvB,KAAK,UAAU,wBAAwB;IAC5C,MAAM,QAAQ,GAAG,MAAM,IAAA,iBAAO,EAAC;QAC7B,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,uEAAuE;QAChF,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,WAAW,CAAC;AAC9B,CAAC;AAEM,KAAK,UAAU,0BAA0B;IAC9C,MAAM,QAAQ,GAAG,MAAM,IAAA,iBAAO,EAAC;QAC7B,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,+EAA+E;QACxF,OAAO,EAAE,QAAQ;KAClB,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC;AACnC,CAAC;AAEM,KAAK,UAAU,wBAAwB,CAC5C,MAAkB,EAClB,iBAAyB;IAEzB,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC;IAExC,MAAM,SAAS,GAA2B,EAAE,CAAC;IAE7C,sBAAsB;IACtB,IAAI,iBAAiB,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,gCAAgC,iBAAiB,KAAK;YAC/D,OAAO,EAAE,iBAAiB;SAC3B,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,yCAAyC;YAClD,OAAO,EAAE,QAAQ;SAClB,CAAC,CAAC;IACL,CAAC;IAED,uBAAuB;IACvB,SAAS,CAAC,IAAI,CAAC;QACb,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,0CAA0C;QACnD,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,IAAA,iBAAO,EAAC,SAAS,CAAC,CAAC;IAEzC,OAAO;QACL,GAAG,MAAM;QACT,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,iBAAiB,IAAI,QAAQ;QAC/D,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;KACvC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ export interface ModuleInfo {
2
+ name: string;
3
+ filePath: string;
4
+ imports: string[];
5
+ providers: string[];
6
+ controllers: string[];
7
+ exports: string[];
8
+ technology?: string;
9
+ description?: string;
10
+ }
11
+ export interface ClassInfo {
12
+ name: string;
13
+ filePath: string;
14
+ dependencies: DependencyInfo[];
15
+ isInjectable: boolean;
16
+ }
17
+ export interface DependencyInfo {
18
+ name: string;
19
+ type: string;
20
+ isOptional: boolean;
21
+ token?: string;
22
+ }
23
+ export interface AnalysisResult {
24
+ modules: ModuleInfo[];
25
+ classes: ClassInfo[];
26
+ }
27
+ export interface DiagramOptions {
28
+ outputDir: string;
29
+ projectPath: string;
30
+ includePrivate?: boolean;
31
+ interactive?: boolean;
32
+ defaultTechnology?: string;
33
+ }
34
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "nestjs-d2-diagrams",
3
+ "version": "1.0.0",
4
+ "description": "Generate D2 component and class diagrams from NestJS projects",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "nest-d2": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/TSYF/NestJS-D2-Diagrams.git"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/TSYF/NestJS-D2-Diagrams/issues"
20
+ },
21
+ "homepage": "https://github.com/TSYF/NestJS-D2-Diagrams#readme",
22
+ "author": "Tomás Yañez <tsyf1999@gmail.com>",
23
+ "keywords": [
24
+ "nestjs",
25
+ "d2",
26
+ "diagram",
27
+ "visualization",
28
+ "architecture",
29
+ "c4"
30
+ ],
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "commander": "^11.1.0",
34
+ "prompts": "^2.4.2",
35
+ "ts-morph": "^21.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.10.0",
39
+ "@types/prompts": "^2.4.9",
40
+ "typescript": "^5.3.0"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc",
44
+ "dev": "tsc --watch"
45
+ }
46
+ }