nest-scramble 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.
Files changed (46) hide show
  1. package/README.md +304 -0
  2. package/dist/NestScrambleModule.d.ts +16 -0
  3. package/dist/NestScrambleModule.d.ts.map +1 -0
  4. package/dist/NestScrambleModule.js +73 -0
  5. package/dist/NestScrambleModule.js.map +1 -0
  6. package/dist/cli.d.ts +4 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +77 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/controllers/DemoController.d.ts +53 -0
  11. package/dist/controllers/DemoController.d.ts.map +1 -0
  12. package/dist/controllers/DemoController.js +91 -0
  13. package/dist/controllers/DemoController.js.map +1 -0
  14. package/dist/controllers/DocsController.d.ts +7 -0
  15. package/dist/controllers/DocsController.d.ts.map +1 -0
  16. package/dist/controllers/DocsController.js +69 -0
  17. package/dist/controllers/DocsController.js.map +1 -0
  18. package/dist/generators/PostmanCollectionGenerator.d.ts +61 -0
  19. package/dist/generators/PostmanCollectionGenerator.d.ts.map +1 -0
  20. package/dist/generators/PostmanCollectionGenerator.js +97 -0
  21. package/dist/generators/PostmanCollectionGenerator.js.map +1 -0
  22. package/dist/index.d.ts +10 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +26 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/middleware/MockMiddleware.d.ts +15 -0
  27. package/dist/middleware/MockMiddleware.d.ts.map +1 -0
  28. package/dist/middleware/MockMiddleware.js +94 -0
  29. package/dist/middleware/MockMiddleware.js.map +1 -0
  30. package/dist/scanner/ScannerService.d.ts +34 -0
  31. package/dist/scanner/ScannerService.d.ts.map +1 -0
  32. package/dist/scanner/ScannerService.js +114 -0
  33. package/dist/scanner/ScannerService.js.map +1 -0
  34. package/dist/utils/DtoAnalyzer.d.ts +25 -0
  35. package/dist/utils/DtoAnalyzer.d.ts.map +1 -0
  36. package/dist/utils/DtoAnalyzer.js +93 -0
  37. package/dist/utils/DtoAnalyzer.js.map +1 -0
  38. package/dist/utils/MockGenerator.d.ts +18 -0
  39. package/dist/utils/MockGenerator.d.ts.map +1 -0
  40. package/dist/utils/MockGenerator.js +135 -0
  41. package/dist/utils/MockGenerator.js.map +1 -0
  42. package/dist/utils/OpenApiTransformer.d.ts +38 -0
  43. package/dist/utils/OpenApiTransformer.d.ts.map +1 -0
  44. package/dist/utils/OpenApiTransformer.js +182 -0
  45. package/dist/utils/OpenApiTransformer.js.map +1 -0
  46. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # Nest-Scramble
2
+
3
+ > Zero-config API Documentation & Postman Generator for NestJS using static analysis
4
+
5
+ [![npm version](https://badge.fury.io/js/nest-scramble.svg)](https://badge.fury.io/js/nest-scramble)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![GitHub stars](https://img.shields.io/github/stars/Eng-MMustafa/nest-scramble.svg)](https://github.com/Eng-MMustafa/nest-scramble)
8
+ [![Author](https://img.shields.io/badge/Author-Mohamed%20Mustafa-blue.svg)](https://github.com/Eng-MMustafa)
9
+
10
+ ## 🚀 Why Nest-Scramble?
11
+
12
+ As a NestJS developer, I was tired of drowning in `@ApiProperty` decorators just to get basic API documentation. I longed for a zero-config solution where docs just worked without polluting my code. **Nest-Scramble changes that** by using static TypeScript analysis to automatically generate:
13
+
14
+ - ✅ **OpenAPI 3.0 specifications** from your DTOs
15
+ - ✅ **Postman collections** with smart mock data
16
+ - ✅ **Interactive documentation** with code samples
17
+ - ✅ **Live mocking** for rapid prototyping
18
+
19
+ **Zero configuration. Zero decorators. Just pure TypeScript.**
20
+
21
+ ## 📖 The Story Behind Nest-Scramble
22
+
23
+ It all started with a vision: API documentation should be effortless. As a developer passionate about clean code and developer experience, I knew there had to be a better way than manual decorators and runtime reflection.
24
+
25
+ When I switched to NestJS for its powerful architecture and TypeScript-first approach, I was disappointed by the lack of zero-config documentation tools. Hours wasted on `@ApiProperty({ type: String })` instead of building features.
26
+
27
+ I knew there had to be a better way. Leveraging my expertise in static analysis and Abstract Syntax Trees (AST), I built Nest-Scramble to bring that same developer experience to the Node.js ecosystem. It's not just a tool—it's my mission to make API documentation as effortless as it should be.
28
+
29
+ ## 🏆 Features Gallery
30
+
31
+ | Feature | Nest-Scramble | Swagger (@nestjs/swagger) |
32
+ |---------|---------------|---------------------------|
33
+ | Analysis Method | Static AST Traversal | Runtime Reflection |
34
+ | Performance Impact | Zero Overhead | Decorator Runtime Cost |
35
+ | Type Accuracy | Full TypeScript Inference | Partial Mapping |
36
+ | Circular References | Auto-Detected & Resolved | Manual Workarounds |
37
+ | Bundle Size | Minimal | Heavy with Decorators |
38
+ | Code Purity | Zero Decorators | Decorator Pollution |
39
+ | Future Compatibility | TypeScript Evolution Ready | Framework Dependent |
40
+
41
+ ## 🧠 The Vision
42
+
43
+ Nest-Scramble embodies my engineering philosophy: **Clean Code through Automation**. As a developer who values TypeScript's type safety and NestJS's architecture, I believe that documentation should never compromise code quality.
44
+
45
+ This library represents a paradigm shift—from manual, error-prone decorators to intelligent, compile-time analysis. It's about empowering developers to focus on building features, not fighting frameworks.
46
+
47
+ ## 🔬 How it's Built
48
+
49
+ Nest-Scramble is engineered using cutting-edge static analysis techniques that traditional tools cannot match:
50
+
51
+ - **Abstract Syntax Tree (AST) Traversal**: Direct manipulation of TypeScript's AST using `ts-morph` for unparalleled type inference
52
+ - **Zero-Decorator Architecture**: Pure TypeScript classes remain untouched, preserving domain integrity
53
+ - **Compile-Time Intelligence**: All analysis happens at build-time, eliminating runtime performance costs
54
+ - **Circular Reference Mastery**: Advanced algorithms detect and handle complex type relationships automatically
55
+
56
+ This approach delivers what runtime reflection simply cannot: perfect accuracy, zero overhead, and future-proof compatibility with TypeScript's evolving type system.
57
+
58
+ ## ⚡ Quick Start (3 Steps)
59
+
60
+ ### 1. Install
61
+ ```bash
62
+ npm install nest-scramble
63
+ ```
64
+
65
+ ### 2. Import Module
66
+ ```typescript
67
+ // app.module.ts
68
+ import { NestScrambleModule } from 'nest-scramble';
69
+
70
+ @Module({
71
+ imports: [
72
+ NestScrambleModule.forRoot({
73
+ enableMock: true,
74
+ autoExportPostman: true,
75
+ }),
76
+ ],
77
+ })
78
+ export class AppModule {}
79
+ ```
80
+
81
+ ### 3. Visit Documentation
82
+ - **📖 API Docs**: http://localhost:3000/docs
83
+ - **🎭 Live Mocking**: http://localhost:3000/scramble-mock/users
84
+ - **📤 Postman Collection**: Auto-generated at `collection.json`
85
+
86
+ ![Zero-config setup demo](demo.gif)
87
+
88
+ ## ⚙️ Configuration API
89
+
90
+ ```typescript
91
+ NestScrambleModule.forRoot({
92
+ // Documentation path
93
+ path: '/docs', // default: '/docs'
94
+
95
+ // Enable live mocking
96
+ enableMock: true, // default: true
97
+
98
+ // Auto-export Postman collection
99
+ autoExportPostman: true, // default: false
100
+
101
+ // Output paths
102
+ postmanOutputPath: 'collection.json',
103
+ openApiOutputPath: 'openapi.json',
104
+
105
+ // API base URL
106
+ baseUrl: 'http://localhost:3000',
107
+
108
+ // Source directory to scan
109
+ sourcePath: 'src', // default: 'src'
110
+ })
111
+ ```
112
+
113
+ ## 🎭 Live Mocking Guide
114
+
115
+ Nest-Scramble provides **instant API mocking** without writing controllers:
116
+
117
+ ### How It Works
118
+ 1. Define your DTOs and controllers normally
119
+ 2. Enable `enableMock: true`
120
+ 3. All requests to `/scramble-mock/*` return smart mock data
121
+
122
+ ### Example
123
+
124
+ **Controller:**
125
+ ```typescript
126
+ @Controller('users')
127
+ export class UserController {
128
+ @Get(':id')
129
+ getUser(@Param('id') id: number): UserDto {
130
+ // Your logic here
131
+ }
132
+ }
133
+ ```
134
+
135
+ **Mock Response:**
136
+ ```bash
137
+ GET /scramble-mock/users/123
138
+ # Returns: { "id": 123, "name": "John Doe", "email": "john@example.com" }
139
+ ```
140
+
141
+ **Smart Mocking Examples:**
142
+ - `email` → `faker.internet.email()`
143
+ - `name` → `faker.person.fullName()`
144
+ - `createdAt` → `faker.date.recent()`
145
+ - `posts` → Array of mock posts
146
+
147
+ ![Live mocking demo](mock-demo.gif)
148
+
149
+ ## 🔧 Advanced Usage
150
+
151
+ ### CLI Generation
152
+ ```bash
153
+ npx nest-scramble generate src --output my-api.json
154
+ ```
155
+
156
+ ### Programmatic API
157
+ ```typescript
158
+ import { ScannerService, OpenApiTransformer } from 'nest-scramble';
159
+
160
+ const scanner = new ScannerService();
161
+ const controllers = scanner.scanControllers('src');
162
+
163
+ const transformer = new OpenApiTransformer();
164
+ const spec = transformer.transform(controllers);
165
+ ```
166
+
167
+ ### Watch Mode
168
+ ```bash
169
+ npm run watch-generate
170
+ ```
171
+ Automatically regenerates docs on file changes.
172
+
173
+ ## 🎨 UI Integration
174
+
175
+ ### Using Scalar UI
176
+ For the modern Scalar documentation UI:
177
+
178
+ ```typescript
179
+ import { ApiReference } from '@scalar/nestjs';
180
+
181
+ @Module({
182
+ imports: [
183
+ NestScrambleModule.forRoot(),
184
+ ApiReference({
185
+ path: '/docs',
186
+ spec: {
187
+ content: () => {
188
+ const scanner = new ScannerService();
189
+ const controllers = scanner.scanControllers('src');
190
+ const transformer = new OpenApiTransformer();
191
+ return transformer.transform(controllers);
192
+ },
193
+ },
194
+ }),
195
+ ],
196
+ })
197
+ export class AppModule {}
198
+ ```
199
+
200
+ *Note: If `@scalar/nestjs` is not available, the default HTML UI is served.*
201
+
202
+ ![Scalar UI demo](ui-demo.gif)
203
+
204
+ ## ✅ Supported Features
205
+
206
+ ### Type Analysis
207
+ - ✅ Primitive types (string, number, boolean)
208
+ - ✅ Arrays and nested objects
209
+ - ✅ Union types
210
+ - ✅ Enums
211
+ - ✅ Optional properties
212
+ - ✅ Circular references (auto-detected)
213
+
214
+ ### HTTP Methods
215
+ - ✅ GET, POST, PUT, DELETE, PATCH
216
+ - ✅ Path parameters (@Param)
217
+ - ✅ Query parameters (@Query)
218
+ - ✅ Request bodies (@Body)
219
+
220
+ ### Code Generation
221
+ - ✅ Curl commands
222
+ - ✅ JavaScript Fetch
223
+ - ✅ TypeScript with types
224
+
225
+ ## 🧪 Testing with Demo Controller
226
+
227
+ The library includes a `DemoController` with complex DTOs:
228
+
229
+ ```typescript
230
+ // Complex DTOs with circular references
231
+ export class UserDto {
232
+ id: number;
233
+ name: string;
234
+ email: string;
235
+ role: UserRole; // Enum
236
+ address: AddressDto; // Nested
237
+ posts: PostDto[]; // Circular reference
238
+ }
239
+
240
+ export class PostDto {
241
+ id: number;
242
+ title: string;
243
+ content: string;
244
+ author: UserDto; // Circular reference
245
+ }
246
+ ```
247
+
248
+ Run the demo to verify everything works perfectly.
249
+
250
+ ## 🗺️ Roadmap
251
+
252
+ - [ ] GraphQL support
253
+ - [ ] Custom mock data providers
254
+ - [ ] Authentication integration
255
+ - [ ] API versioning
256
+ - [ ] Performance optimizations
257
+ - [ ] Plugin system for custom analyzers
258
+
259
+ ## 🔧 Troubleshooting
260
+
261
+ ### Common Issues
262
+
263
+ **TypeScript Path Mapping Issues:**
264
+ If you're using custom `tsconfig` paths, ensure the scanner can resolve them:
265
+ ```json
266
+ {
267
+ "compilerOptions": {
268
+ "baseUrl": ".",
269
+ "paths": {
270
+ "@/*": ["src/*"]
271
+ }
272
+ }
273
+ }
274
+ ```
275
+
276
+ **Circular Reference Errors:**
277
+ Nest-Scramble auto-detects circular references, but if you encounter issues, simplify your DTOs or use interfaces instead of classes.
278
+
279
+ **Mock Data Not Generating:**
280
+ Ensure `@faker-js/faker` is installed and your property names follow common conventions (e.g., `email`, `name`).
281
+
282
+ For more help, check the [issues](https://github.com/Eng-MMustafa/nest-scramble/issues) or start a discussion.
283
+
284
+ ## 🤝 Contributing
285
+
286
+ We welcome contributions! Please:
287
+
288
+ 1. Fork the repository
289
+ 2. Create a feature branch
290
+ 3. Add tests for new features
291
+ 4. Submit a pull request
292
+
293
+ ## 📄 License
294
+
295
+ MIT License - see [LICENSE](LICENSE) file.
296
+
297
+ ## ‍💻 About the Author
298
+
299
+ ![Mohamed Mustafa](https://via.placeholder.com/150x150?text=Mohamed+Mustafa)
300
+
301
+ Mohamed Mustafa is a passionate full-stack developer with a deep love for TypeScript and modern web frameworks. His mission is to build tools that enhance developer experience and eliminate repetitive tasks. When he's not crafting open-source libraries, you'll find him exploring new technologies, contributing to the developer community, or sharing insights through technical writing.
302
+
303
+ - [GitHub](https://github.com/Eng-MMustafa)
304
+ - [LinkedIn](https://www.linkedin.com/in/engmohammedmustafa/)
@@ -0,0 +1,16 @@
1
+ /** Nest-Scramble | Developed by Mohamed Mustafa | MIT License **/
2
+ import { DynamicModule, MiddlewareConsumer } from '@nestjs/common';
3
+ export interface NestScrambleOptions {
4
+ path?: string;
5
+ enableMock?: boolean;
6
+ autoExportPostman?: boolean;
7
+ postmanOutputPath?: string;
8
+ baseUrl?: string;
9
+ sourcePath?: string;
10
+ }
11
+ export declare class NestScrambleModule {
12
+ static forRoot(options?: NestScrambleOptions): DynamicModule;
13
+ static forRootAsync(options?: NestScrambleOptions): DynamicModule;
14
+ configure(consumer: MiddlewareConsumer): void;
15
+ }
16
+ //# sourceMappingURL=NestScrambleModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NestScrambleModule.d.ts","sourceRoot":"","sources":["../src/NestScrambleModule.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAyB,MAAM,gBAAgB,CAAC;AAQ1F,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBACa,kBAAkB;IAC7B,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,mBAAwB,GAAG,aAAa;IAiDhE,MAAM,CAAC,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,aAAa;IAKrE,SAAS,CAAC,QAAQ,EAAE,kBAAkB;CAMvC"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var NestScrambleModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.NestScrambleModule = void 0;
11
+ /** Nest-Scramble | Developed by Mohamed Mustafa | MIT License **/
12
+ const common_1 = require("@nestjs/common");
13
+ const PostmanCollectionGenerator_1 = require("./generators/PostmanCollectionGenerator");
14
+ const MockMiddleware_1 = require("./middleware/MockMiddleware");
15
+ const ScannerService_1 = require("./scanner/ScannerService");
16
+ const MockGenerator_1 = require("./utils/MockGenerator");
17
+ const OpenApiTransformer_1 = require("./utils/OpenApiTransformer");
18
+ const DocsController_1 = require("./controllers/DocsController");
19
+ let NestScrambleModule = NestScrambleModule_1 = class NestScrambleModule {
20
+ static forRoot(options = {}) {
21
+ const { path = '/docs', enableMock = true, autoExportPostman = false, postmanOutputPath = 'collection.json', baseUrl = 'http://localhost:3000', sourcePath = 'src', } = options;
22
+ // Scan controllers and generate spec
23
+ const scanner = new ScannerService_1.ScannerService();
24
+ const controllers = scanner.scanControllers(sourcePath);
25
+ const transformer = new OpenApiTransformer_1.OpenApiTransformer(baseUrl);
26
+ const openApiSpec = transformer.transform(controllers, 'NestJS API', '1.0.0', baseUrl);
27
+ // Auto export Postman if enabled
28
+ if (autoExportPostman) {
29
+ const generator = new PostmanCollectionGenerator_1.PostmanCollectionGenerator(baseUrl);
30
+ const collection = generator.generateCollection(controllers);
31
+ require('fs').writeFileSync(postmanOutputPath, JSON.stringify(collection, null, 2));
32
+ }
33
+ return {
34
+ module: NestScrambleModule_1,
35
+ providers: [
36
+ ScannerService_1.ScannerService,
37
+ PostmanCollectionGenerator_1.PostmanCollectionGenerator,
38
+ OpenApiTransformer_1.OpenApiTransformer,
39
+ MockGenerator_1.MockGenerator,
40
+ {
41
+ provide: 'NEST_SCRAMBLE_CONTROLLERS',
42
+ useValue: controllers,
43
+ },
44
+ {
45
+ provide: 'NEST_SCRAMBLE_OPENAPI',
46
+ useValue: openApiSpec,
47
+ },
48
+ {
49
+ provide: 'NEST_SCRAMBLE_OPTIONS',
50
+ useValue: options,
51
+ },
52
+ ],
53
+ exports: [ScannerService_1.ScannerService, PostmanCollectionGenerator_1.PostmanCollectionGenerator, OpenApiTransformer_1.OpenApiTransformer],
54
+ controllers: [DocsController_1.DocsController],
55
+ imports: [],
56
+ };
57
+ }
58
+ static forRootAsync(options = {}) {
59
+ // Similar to forRoot but with async providers if needed
60
+ return this.forRoot(options);
61
+ }
62
+ configure(consumer) {
63
+ // Apply mock middleware if enabled
64
+ consumer
65
+ .apply(MockMiddleware_1.MockMiddleware)
66
+ .forRoutes({ path: 'scramble-mock/*', method: common_1.RequestMethod.ALL });
67
+ }
68
+ };
69
+ exports.NestScrambleModule = NestScrambleModule;
70
+ exports.NestScrambleModule = NestScrambleModule = NestScrambleModule_1 = __decorate([
71
+ (0, common_1.Module)({})
72
+ ], NestScrambleModule);
73
+ //# sourceMappingURL=NestScrambleModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NestScrambleModule.js","sourceRoot":"","sources":["../src/NestScrambleModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,kEAAkE;AAClE,2CAA0F;AAC1F,wFAAqF;AACrF,gEAA6D;AAC7D,6DAA0D;AAC1D,yDAAsD;AACtD,mEAAgE;AAChE,iEAA8D;AAYvD,IAAM,kBAAkB,0BAAxB,MAAM,kBAAkB;IAC7B,MAAM,CAAC,OAAO,CAAC,UAA+B,EAAE;QAC9C,MAAM,EACJ,IAAI,GAAG,OAAO,EACd,UAAU,GAAG,IAAI,EACjB,iBAAiB,GAAG,KAAK,EACzB,iBAAiB,GAAG,iBAAiB,EACrC,OAAO,GAAG,uBAAuB,EACjC,UAAU,GAAG,KAAK,GACnB,GAAG,OAAO,CAAC;QAEZ,qCAAqC;QACrC,MAAM,OAAO,GAAG,IAAI,+BAAc,EAAE,CAAC;QACrC,MAAM,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,IAAI,uCAAkB,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,WAAW,CAAC,SAAS,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAEvF,iCAAiC;QACjC,IAAI,iBAAiB,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,IAAI,uDAA0B,CAAC,OAAO,CAAC,CAAC;YAC1D,MAAM,UAAU,GAAG,SAAS,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACtF,CAAC;QAED,OAAO;YACL,MAAM,EAAE,oBAAkB;YAC1B,SAAS,EAAE;gBACT,+BAAc;gBACd,uDAA0B;gBAC1B,uCAAkB;gBAClB,6BAAa;gBACb;oBACE,OAAO,EAAE,2BAA2B;oBACpC,QAAQ,EAAE,WAAW;iBACtB;gBACD;oBACE,OAAO,EAAE,uBAAuB;oBAChC,QAAQ,EAAE,WAAW;iBACtB;gBACD;oBACE,OAAO,EAAE,uBAAuB;oBAChC,QAAQ,EAAE,OAAO;iBAClB;aACF;YACD,OAAO,EAAE,CAAC,+BAAc,EAAE,uDAA0B,EAAE,uCAAkB,CAAC;YACzE,WAAW,EAAE,CAAC,+BAAc,CAAC;YAC7B,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,UAA+B,EAAE;QACnD,wDAAwD;QACxD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED,SAAS,CAAC,QAA4B;QACpC,mCAAmC;QACnC,QAAQ;aACL,KAAK,CAAC,+BAAc,CAAC;aACrB,SAAS,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,sBAAa,CAAC,GAAG,EAAE,CAAC,CAAC;IACvE,CAAC;CACF,CAAA;AA7DY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,kBAAkB,CA6D9B"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ /** Nest-Scramble | Developed by Mohamed Mustafa | MIT License **/
3
+ export {};
4
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,kEAAkE"}
package/dist/cli.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /** Nest-Scramble | Developed by Mohamed Mustafa | MIT License **/
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const commander_1 = require("commander");
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const PostmanCollectionGenerator_1 = require("./generators/PostmanCollectionGenerator");
42
+ const ScannerService_1 = require("./scanner/ScannerService");
43
+ const program = new commander_1.Command();
44
+ program
45
+ .name('nest-scramble')
46
+ .description('Zero-config API Documentation & Postman Generator for NestJS')
47
+ .version('1.0.0');
48
+ program
49
+ .command('generate')
50
+ .description('Generate Postman collection from NestJS project')
51
+ .argument('<sourcePath>', 'Path to the source directory (e.g., src)')
52
+ .option('-o, --output <file>', 'Output file path', 'collection.json')
53
+ .option('-b, --baseUrl <url>', 'Base URL for the API', '{{baseUrl}}')
54
+ .action(async (sourcePath, options) => {
55
+ try {
56
+ console.log('Scanning controllers...');
57
+ const scanner = new ScannerService_1.ScannerService();
58
+ const controllers = scanner.scanControllers(sourcePath);
59
+ if (controllers.length === 0) {
60
+ console.log('No controllers found.');
61
+ return;
62
+ }
63
+ console.log(`Found ${controllers.length} controllers with ${controllers.reduce((sum, c) => sum + c.methods.length, 0)} methods.`);
64
+ console.log('Generating Postman collection...');
65
+ const generator = new PostmanCollectionGenerator_1.PostmanCollectionGenerator(options.baseUrl);
66
+ const collection = generator.generateCollection(controllers);
67
+ const outputPath = path.resolve(options.output);
68
+ fs.writeFileSync(outputPath, JSON.stringify(collection, null, 2));
69
+ console.log(`Postman collection saved to ${outputPath}`);
70
+ }
71
+ catch (error) {
72
+ console.error('Error:', error);
73
+ process.exit(1);
74
+ }
75
+ });
76
+ program.parse();
77
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AACA,kEAAkE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElE,yCAAoC;AACpC,uCAAyB;AACzB,2CAA6B;AAC7B,wFAAqF;AACrF,6DAA0D;AAE1D,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,eAAe,CAAC;KACrB,WAAW,CAAC,8DAA8D,CAAC;KAC3E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,iDAAiD,CAAC;KAC9D,QAAQ,CAAC,cAAc,EAAE,0CAA0C,CAAC;KACpE,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,EAAE,iBAAiB,CAAC;KACpE,MAAM,CAAC,qBAAqB,EAAE,sBAAsB,EAAE,aAAa,CAAC;KACpE,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,OAA4C,EAAE,EAAE;IACjF,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,+BAAc,EAAE,CAAC;QACrC,MAAM,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QAExD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,SAAS,WAAW,CAAC,MAAM,qBAAqB,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;QAElI,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,IAAI,uDAA0B,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,SAAS,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAE7D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChD,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,53 @@
1
+ export declare enum UserRole {
2
+ ADMIN = "admin",
3
+ USER = "user",
4
+ MODERATOR = "moderator"
5
+ }
6
+ export declare class AddressDto {
7
+ street: string;
8
+ city: string;
9
+ country: string;
10
+ zipCode?: string;
11
+ }
12
+ export declare class PostDto {
13
+ id: number;
14
+ title: string;
15
+ content: string;
16
+ author: UserDto;
17
+ tags: string[];
18
+ createdAt: Date;
19
+ published: boolean;
20
+ }
21
+ export declare class UserDto {
22
+ id: number;
23
+ name: string;
24
+ email: string;
25
+ role: UserRole;
26
+ address: AddressDto;
27
+ posts: PostDto[];
28
+ isActive: boolean;
29
+ createdAt: Date;
30
+ }
31
+ export declare class CreateUserDto {
32
+ name: string;
33
+ email: string;
34
+ role?: UserRole;
35
+ address: AddressDto;
36
+ }
37
+ export declare class UpdateUserDto {
38
+ name?: string;
39
+ email?: string;
40
+ role?: UserRole;
41
+ address?: AddressDto;
42
+ isActive?: boolean;
43
+ }
44
+ export declare class DemoController {
45
+ getUsers(limit?: number, offset?: number): UserDto[];
46
+ getUser(id: number): UserDto;
47
+ createUser(createUserDto: CreateUserDto): UserDto;
48
+ createPostForUser(userId: number, postData: {
49
+ title: string;
50
+ content: string;
51
+ }): PostDto;
52
+ }
53
+ //# sourceMappingURL=DemoController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DemoController.d.ts","sourceRoot":"","sources":["../../src/controllers/DemoController.ts"],"names":[],"mappings":"AAGA,oBAAY,QAAQ;IAClB,KAAK,UAAU;IACf,IAAI,SAAS;IACb,SAAS,cAAc;CACxB;AAED,qBAAa,UAAU;IACrB,MAAM,EAAG,MAAM,CAAC;IAChB,IAAI,EAAG,MAAM,CAAC;IACd,OAAO,EAAG,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,OAAO;IAClB,EAAE,EAAG,MAAM,CAAC;IACZ,KAAK,EAAG,MAAM,CAAC;IACf,OAAO,EAAG,MAAM,CAAC;IACjB,MAAM,EAAG,OAAO,CAAC;IACjB,IAAI,EAAG,MAAM,EAAE,CAAC;IAChB,SAAS,EAAG,IAAI,CAAC;IACjB,SAAS,EAAG,OAAO,CAAC;CACrB;AAED,qBAAa,OAAO;IAClB,EAAE,EAAG,MAAM,CAAC;IACZ,IAAI,EAAG,MAAM,CAAC;IACd,KAAK,EAAG,MAAM,CAAC;IACf,IAAI,EAAG,QAAQ,CAAC;IAChB,OAAO,EAAG,UAAU,CAAC;IACrB,KAAK,EAAG,OAAO,EAAE,CAAC;IAClB,QAAQ,EAAG,OAAO,CAAC;IACnB,SAAS,EAAG,IAAI,CAAC;CAClB;AAED,qBAAa,aAAa;IACxB,IAAI,EAAG,MAAM,CAAC;IACd,KAAK,EAAG,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAG,UAAU,CAAC;CACtB;AAED,qBAAa,aAAa;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBACa,cAAc;IAEzB,QAAQ,CAAiB,KAAK,CAAC,EAAE,MAAM,EAAmB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE;IAMrF,OAAO,CAAc,EAAE,EAAE,MAAM,GAAG,OAAO;IAMzC,UAAU,CAAS,aAAa,EAAE,aAAa,GAAG,OAAO;IAMzD,iBAAiB,CAAc,MAAM,EAAE,MAAM,EAAU,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;CAI9G"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.DemoController = exports.UpdateUserDto = exports.CreateUserDto = exports.UserDto = exports.PostDto = exports.AddressDto = exports.UserRole = void 0;
16
+ /** Nest-Scramble | Developed by Mohamed Mustafa | MIT License **/
17
+ const common_1 = require("@nestjs/common");
18
+ var UserRole;
19
+ (function (UserRole) {
20
+ UserRole["ADMIN"] = "admin";
21
+ UserRole["USER"] = "user";
22
+ UserRole["MODERATOR"] = "moderator";
23
+ })(UserRole || (exports.UserRole = UserRole = {}));
24
+ class AddressDto {
25
+ }
26
+ exports.AddressDto = AddressDto;
27
+ class PostDto {
28
+ }
29
+ exports.PostDto = PostDto;
30
+ class UserDto {
31
+ }
32
+ exports.UserDto = UserDto;
33
+ class CreateUserDto {
34
+ }
35
+ exports.CreateUserDto = CreateUserDto;
36
+ class UpdateUserDto {
37
+ }
38
+ exports.UpdateUserDto = UpdateUserDto;
39
+ let DemoController = class DemoController {
40
+ getUsers(limit, offset) {
41
+ // This would return an array of users
42
+ return [];
43
+ }
44
+ getUser(id) {
45
+ // This would return a single user
46
+ return {};
47
+ }
48
+ createUser(createUserDto) {
49
+ // This would create and return a user
50
+ return {};
51
+ }
52
+ createPostForUser(userId, postData) {
53
+ // This would create a post for a user
54
+ return {};
55
+ }
56
+ };
57
+ exports.DemoController = DemoController;
58
+ __decorate([
59
+ (0, common_1.Get)(),
60
+ __param(0, (0, common_1.Query)('limit')),
61
+ __param(1, (0, common_1.Query)('offset')),
62
+ __metadata("design:type", Function),
63
+ __metadata("design:paramtypes", [Number, Number]),
64
+ __metadata("design:returntype", Array)
65
+ ], DemoController.prototype, "getUsers", null);
66
+ __decorate([
67
+ (0, common_1.Get)(':id'),
68
+ __param(0, (0, common_1.Param)('id')),
69
+ __metadata("design:type", Function),
70
+ __metadata("design:paramtypes", [Number]),
71
+ __metadata("design:returntype", UserDto)
72
+ ], DemoController.prototype, "getUser", null);
73
+ __decorate([
74
+ (0, common_1.Post)(),
75
+ __param(0, (0, common_1.Body)()),
76
+ __metadata("design:type", Function),
77
+ __metadata("design:paramtypes", [CreateUserDto]),
78
+ __metadata("design:returntype", UserDto)
79
+ ], DemoController.prototype, "createUser", null);
80
+ __decorate([
81
+ (0, common_1.Post)(':id/posts'),
82
+ __param(0, (0, common_1.Param)('id')),
83
+ __param(1, (0, common_1.Body)()),
84
+ __metadata("design:type", Function),
85
+ __metadata("design:paramtypes", [Number, Object]),
86
+ __metadata("design:returntype", PostDto)
87
+ ], DemoController.prototype, "createPostForUser", null);
88
+ exports.DemoController = DemoController = __decorate([
89
+ (0, common_1.Controller)('users')
90
+ ], DemoController);
91
+ //# sourceMappingURL=DemoController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DemoController.js","sourceRoot":"","sources":["../../src/controllers/DemoController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,kEAAkE;AAClE,2CAA2E;AAE3E,IAAY,QAIX;AAJD,WAAY,QAAQ;IAClB,2BAAe,CAAA;IACf,yBAAa,CAAA;IACb,mCAAuB,CAAA;AACzB,CAAC,EAJW,QAAQ,wBAAR,QAAQ,QAInB;AAED,MAAa,UAAU;CAKtB;AALD,gCAKC;AAED,MAAa,OAAO;CAQnB;AARD,0BAQC;AAED,MAAa,OAAO;CASnB;AATD,0BASC;AAED,MAAa,aAAa;CAKzB;AALD,sCAKC;AAED,MAAa,aAAa;CAMzB;AAND,sCAMC;AAGM,IAAM,cAAc,GAApB,MAAM,cAAc;IAEzB,QAAQ,CAAiB,KAAc,EAAmB,MAAe;QACvE,sCAAsC;QACtC,OAAO,EAAE,CAAC;IACZ,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,kCAAkC;QAClC,OAAO,EAAa,CAAC;IACvB,CAAC;IAGD,UAAU,CAAS,aAA4B;QAC7C,sCAAsC;QACtC,OAAO,EAAa,CAAC;IACvB,CAAC;IAGD,iBAAiB,CAAc,MAAc,EAAU,QAA4C;QACjG,sCAAsC;QACtC,OAAO,EAAa,CAAC;IACvB,CAAC;CACF,CAAA;AAxBY,wCAAc;AAEzB;IADC,IAAA,YAAG,GAAE;IACI,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;IAAkB,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;8CAGxD;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;oCAAc,OAAO;6CAGxC;AAGD;IADC,IAAA,aAAI,GAAE;IACK,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAgB,aAAa;oCAAG,OAAO;gDAGxD;AAGD;IADC,IAAA,aAAI,EAAC,WAAW,CAAC;IACC,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAkB,WAAA,IAAA,aAAI,GAAE,CAAA;;;oCAAgD,OAAO;uDAG5G;yBAvBU,cAAc;IAD1B,IAAA,mBAAU,EAAC,OAAO,CAAC;GACP,cAAc,CAwB1B"}
@@ -0,0 +1,7 @@
1
+ export declare class DocsController {
2
+ private openApiSpec;
3
+ constructor(openApiSpec: any);
4
+ getDocs(): string;
5
+ getOpenApiSpec(): any;
6
+ }
7
+ //# sourceMappingURL=DocsController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocsController.d.ts","sourceRoot":"","sources":["../../src/controllers/DocsController.ts"],"names":[],"mappings":"AAGA,qBACa,cAAc;IAEU,OAAO,CAAC,WAAW;gBAAX,WAAW,EAAE,GAAG;IAI3D,OAAO;IA2BP,cAAc;CAGf"}