@mena-emad/documind 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/README.md ADDED
@@ -0,0 +1,221 @@
1
+ # DocuMind
2
+
3
+ [![Version](https://img.shields.io/badge/version-1.0.0-blue)](https://github.com/mena-emad/DocuMind) [![License](https://img.shields.io/badge/license-ISC-yellow)](./LICENSE) [![Language](https://img.shields.io/badge/language-TypeScript-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
4
+
5
+ > Generate production-ready Swagger/OpenAPI docs from Express.js code using Gemini AI and smart context stitching.
6
+
7
+ ## šŸš€ Why DocuMind?
8
+
9
+ DocuMind is designed to fix the common problem of shallow or empty generated API docs.
10
+ Instead of only parsing route definitions, it intelligently collects surrounding business logic so Gemini understands each endpoint in context.
11
+
12
+ - Extracts routes, controllers, services, models, and validations
13
+ - Encourages deep summaries and descriptions from Gemini
14
+ - Prevents empty `paths` and weak documentation
15
+ - Keeps generated output aligned with your implementation
16
+
17
+ ## šŸŽÆ Showcase
18
+
19
+ ### Input
20
+ A simple Express route plus related service and validation code.
21
+
22
+ ```ts
23
+ // src/routes/auth.ts
24
+ router.post('/login', authController.login);
25
+ ```
26
+
27
+ ### Output
28
+
29
+ ```yaml
30
+ openapi: 3.0.0
31
+ info:
32
+ title: DocuMind Generated API
33
+ version: 1.0.0
34
+ description: Automated OpenAPI documentation generated by DocuMind AI.
35
+ paths:
36
+ /login:
37
+ post:
38
+ tags:
39
+ - Auth
40
+ summary: Authenticate user and issue a JWT token.
41
+ description: |
42
+ Verifies credentials against the hashed user password, checks authorization
43
+ roles, signs a JWT token, and returns a session payload.
44
+ requestBody:
45
+ required: true
46
+ content:
47
+ application/json:
48
+ schema:
49
+ $ref: '#/components/schemas/LoginRequest'
50
+ responses:
51
+ '200':
52
+ description: User authenticated successfully.
53
+ components:
54
+ schemas:
55
+ LoginRequest:
56
+ type: object
57
+ properties:
58
+ email:
59
+ type: string
60
+ format: email
61
+ password:
62
+ type: string
63
+ ```
64
+
65
+ ## 🧠 How it Works
66
+
67
+ ### Context Stitching
68
+ DocuMind attaches nearby compute context to route files so Gemini sees the full backend flow.
69
+
70
+ ```mermaid
71
+ flowchart LR
72
+ A[Route File] --> B[Controller Code]
73
+ A --> C[Service Logic]
74
+ A --> D[Validation / Models]
75
+ B --> E[AI Prompt]
76
+ C --> E
77
+ D --> E
78
+ E --> F[Gemini AI]
79
+ F --> G[OpenAPI Output]
80
+ ```
81
+
82
+ ### Generation Flow
83
+
84
+ ```mermaid
85
+ flowchart TD
86
+ A[CLI Start] --> B[Parse CLI Options]
87
+ B --> C[Scan Project Directory]
88
+ C --> D[Filter Express Route Files]
89
+ D --> E[Collect Related Context]
90
+ E --> F[Call Gemini Model]
91
+ F --> G[Defensive Merge Output]
92
+ G --> H[Write swagger.yaml / json]
93
+ ```
94
+
95
+ ## ✨ Key Features
96
+
97
+ - **Smart File Scanning**: finds Express route files across the project.
98
+ - **Context Stitching**: includes controllers, services, models, and validation code.
99
+ - **Defensive Merging**: merges AI-generated `paths` and `schemas` safely.
100
+ - **Rich Descriptions**: forces Gemini to explain workflows like hashing, JWT creation, roles, and errors.
101
+ - **Interactive CLI**: animated progress using `ora`.
102
+
103
+ ## 🧰 Tech Stack
104
+
105
+ - Node.js (>= 18.0.0)
106
+ - TypeScript
107
+ - Google Gen AI SDK (`@google/genai`)
108
+ - Commander.js
109
+ - Ora
110
+ - Dotenv
111
+ - yaml
112
+
113
+ ## šŸ“„ Installation
114
+
115
+ ### Global
116
+
117
+ ```bash
118
+ npm install -g @mena-emad/documind
119
+ ```
120
+
121
+ ### Local
122
+
123
+ ```bash
124
+ git clone https://github.com/mena-emad/DocuMind.git
125
+ cd DocuMind
126
+ npm install
127
+ npm run build
128
+ ```
129
+
130
+ Run in development mode:
131
+
132
+ ```bash
133
+ npm run dev
134
+ ```
135
+
136
+ Run locally:
137
+
138
+ ```bash
139
+ npx @mena-emad/documind
140
+ ```
141
+
142
+ ## šŸ”§ Environment Variables
143
+
144
+ DocuMind reads the Gemini API key from `.env`:
145
+
146
+ ```env
147
+ DOCUMIND_API_KEY=your_gemini_api_key_here
148
+ ```
149
+
150
+ Or pass the key directly using `-k`.
151
+
152
+ ## ā–¶ļø Usage
153
+
154
+ ```bash
155
+ documind [options]
156
+ ```
157
+
158
+ ### CLI Options
159
+
160
+ | Option | Description | Default |
161
+ |---|---|---|
162
+ | `-k, --key <api-key>` | Gemini API Key | `DOCUMIND_API_KEY` from `.env` |
163
+ | `-d, --dir [directory]` | Directory to scan | `./` |
164
+ | `-o, --output [file-name]` | Output filename | `swagger.yaml` |
165
+ | `--title [title]` | OpenAPI `info.title` | auto-generated |
166
+ | `--api-version [version]` | OpenAPI `info.version` | auto-generated |
167
+ | `--desc [description]` | OpenAPI `info.description` | auto-generated |
168
+ | `-v, --version` | Show CLI version | - |
169
+
170
+ ### Examples
171
+
172
+ Generate default output:
173
+
174
+ ```bash
175
+ documind
176
+ ```
177
+
178
+ Generate docs for a custom source directory:
179
+
180
+ ```bash
181
+ documind -d ./src -o api-docs.yaml
182
+ ```
183
+
184
+ Use the API key directly:
185
+
186
+ ```bash
187
+ documind -k sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
188
+ ```
189
+
190
+ Provide OpenAPI metadata:
191
+
192
+ ```bash
193
+ documind --title "My App API" --api-version "2.0.0" --desc "AI-generated Swagger docs from Express source code."
194
+ ```
195
+
196
+ ## šŸ” How DocuMind Processes Code
197
+
198
+ 1. **Scan files**
199
+ - Recursively collect `.js` and `.ts` files.
200
+ 2. **Filter Express routes**
201
+ - Detect route patterns and Express router usage.
202
+ 3. **Gather related context**
203
+ - Add matching service, controller, model, and validation files.
204
+ 4. **Ask Gemini**
205
+ - Send a prompt that demands valid OpenAPI JSON and rich documentation.
206
+ 5. **Merge outputs defensively**
207
+ - Combine returned `paths` and `components` while handling missing or malformed sections.
208
+ 6. **Write output**
209
+ - Save YAML or JSON based on the requested filename.
210
+
211
+ ## šŸ‘Øā€šŸ’» About the Author
212
+
213
+ Built by **Mena Emad Sawares**.
214
+
215
+ - Website: [https://menaemad.vercel.app/](https://menaemad.vercel.app/)
216
+ - GitHub: [https://github.com/mena-emad](https://github.com/mena-emad)
217
+ - Email: [menaemad6543@gmail.com](mailto:menaemad6543@gmail.com)
218
+
219
+ ## šŸ“œ License
220
+
221
+ DocuMind is released under the **ISC License**.
@@ -0,0 +1,15 @@
1
+ interface CLIOptions {
2
+ key?: string;
3
+ dir: string;
4
+ output: string;
5
+ title?: string;
6
+ description?: string;
7
+ version?: string;
8
+ }
9
+ /**
10
+ * Parses and returns command-line options for DocuMind.
11
+ * @returns Parsed CLI options.
12
+ */
13
+ export default function parseCLI(): CLIOptions;
14
+ export {};
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAEA,UAAU,UAAU;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,IAAI,UAAU,CAkB7C"}
@@ -0,0 +1,22 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * Parses and returns command-line options for DocuMind.
4
+ * @returns Parsed CLI options.
5
+ */
6
+ export default function parseCLI() {
7
+ const program = new Command();
8
+ program
9
+ .name("documind")
10
+ .description("AI-Powered Swagger/OpenAPI Documentation Generator for Express.js")
11
+ .version("1.0.0", "-v, --version", "--version for version of documind CLI");
12
+ program
13
+ .option('-d, --dir [directory]', 'The directory to scan for Express routes', './')
14
+ .option('-k, --key <api-key>', 'Your Gemini API Key (Alternative to .env)')
15
+ .option('-o, --output [file-name]', 'The output file name', 'swagger.yaml')
16
+ .option('--title [title]', 'API Documentation Title')
17
+ .option('--api-version [version]', 'API Document Version')
18
+ .option('--desc [description]', 'API Description');
19
+ program.parse(process.argv);
20
+ return program.opts();
21
+ }
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ;IAC5B,MAAM,OAAO,GAAY,IAAI,OAAO,EAAE,CAAC;IAEvC,OAAO;SACN,IAAI,CAAC,UAAU,CAAC;SAChB,WAAW,CAAC,mEAAmE,CAAC;SAChF,OAAO,CAAC,OAAO,EAAC,eAAe,EAAG,uCAAuC,CAAC,CAAC;IAE5E,OAAO;SACN,MAAM,CAAC,uBAAuB,EAAE,0CAA0C,EAAE,IAAI,CAAC;SACjF,MAAM,CAAC,qBAAqB,EAAE,2CAA2C,CAAC;SAC1E,MAAM,CAAC,0BAA0B,EAAE,sBAAsB,EAAE,cAAc,CAAC;SAC1E,MAAM,CAAC,iBAAiB,EAAE,yBAAyB,CAAC;SACpD,MAAM,CAAC,yBAAyB,EAAE,sBAAsB,CAAC;SACzD,MAAM,CAAC,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;IACnD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B,OAAO,OAAO,CAAC,IAAI,EAAc,CAAC;AACtC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+ import parseCLI from './cli/index.js';
3
+ import { AIService } from './services/aiService.js';
4
+ import scanDirectory from './parser/fileScanner.js';
5
+ import isExpressRouteFile from './parser/routerExtractor.js';
6
+ import { writeSwaggerFile } from './utils/fileWriter.js';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import ora from 'ora';
10
+ /**
11
+ * Entry point for the DocuMind CLI.
12
+ * It scans the project, sends merged route context to Gemini, merges responses, and writes the output file.
13
+ */
14
+ async function main() {
15
+ console.log("🧠 Welcome to DocuMind! Let's build some magic...\n");
16
+ const options = parseCLI();
17
+ let aiService;
18
+ try {
19
+ aiService = new AIService(options.key);
20
+ }
21
+ catch (err) {
22
+ console.error(err.message);
23
+ process.exit(1);
24
+ }
25
+ let dirInput = './';
26
+ if (typeof options.dir === 'string') {
27
+ dirInput = options.dir;
28
+ }
29
+ const targetDir = path.resolve(dirInput);
30
+ const outputFileName = typeof options.output === 'string' ? options.output : 'swagger.yaml';
31
+ const scanSpinner = ora(`Scanning directory: ${targetDir}`).start();
32
+ const allFiles = scanDirectory(targetDir);
33
+ const validRouteFiles = allFiles.filter(file => isExpressRouteFile(file));
34
+ scanSpinner.succeed(`šŸ“ Found ${allFiles.length} total files. | šŸŽÆ ${validRouteFiles.length} Express controller/route files detected.\n`);
35
+ if (validRouteFiles.length === 0) {
36
+ console.log("āš ļø No valid Express routes or controllers detected to document.");
37
+ return;
38
+ }
39
+ const finalPaths = {};
40
+ const finalComponents = {};
41
+ for (const file of validRouteFiles) {
42
+ const fileName = path.basename(file);
43
+ if (fileName === 'app.js' || fileName === 'index.js' || fileName === 'server.js') {
44
+ continue;
45
+ }
46
+ const fileSpinner = ora(`Analyzing file: ${fileName}...`).start();
47
+ const fileContent = fs.readFileSync(file, 'utf8');
48
+ const prefix = fileName.split('.')[0] || '';
49
+ let additionalContext = '';
50
+ const relatedFiles = allFiles.filter(f => {
51
+ const name = path.basename(f).toLowerCase();
52
+ return name.startsWith(prefix.toLowerCase()) && f !== file;
53
+ });
54
+ for (const related of relatedFiles) {
55
+ const relName = path.basename(related);
56
+ if (relName.includes('service') || relName.includes('controller') || relName.includes('validation') || relName.includes('model')) {
57
+ fileSpinner.text = `šŸ”— Injecting context into ${fileName} from: ${relName}`;
58
+ additionalContext += `\n\n[Attached Related Context - ${relName}]:\n${fs.readFileSync(related, 'utf8')}`;
59
+ }
60
+ }
61
+ const totalPayload = fileContent + additionalContext;
62
+ fileSpinner.text = `ā³ Waiting for Gemini to generate docs for ${fileName}...`;
63
+ try {
64
+ const docResult = await aiService.generateDoc(totalPayload);
65
+ fileSpinner.stop();
66
+ fileSpinner.start(`Processing and merging JSON data for ${fileName}...`);
67
+ const aiJson = JSON.parse(docResult);
68
+ if (aiJson.paths && Object.keys(aiJson.paths).length > 0) {
69
+ Object.assign(finalPaths, aiJson.paths);
70
+ }
71
+ else {
72
+ const upperPaths = aiJson.Paths || aiJson.PATHS;
73
+ if (upperPaths)
74
+ Object.assign(finalPaths, upperPaths);
75
+ }
76
+ if (aiJson.components) {
77
+ if (aiJson.components.schemas) {
78
+ finalComponents.schemas = {
79
+ ...finalComponents.schemas,
80
+ ...aiJson.components.schemas
81
+ };
82
+ }
83
+ for (const key of Object.keys(aiJson.components)) {
84
+ if (key !== 'schemas') {
85
+ finalComponents[key] = {
86
+ ...finalComponents[key],
87
+ ...aiJson.components[key]
88
+ };
89
+ }
90
+ }
91
+ }
92
+ fileSpinner.succeed(`āœ… ${fileName} parsed and merged successfully.`);
93
+ }
94
+ catch (err) {
95
+ fileSpinner.fail(`āŒ Failed to parse AI response for ${fileName}. Raw response structure invalid.`);
96
+ }
97
+ }
98
+ const totalData = {
99
+ openapi: '3.0.0',
100
+ paths: finalPaths,
101
+ ...(Object.keys(finalComponents).length > 0 ? { components: finalComponents } : {})
102
+ };
103
+ console.log('\nšŸš€ Final Data Object Structure Ready.');
104
+ const writeSpinner = ora('Writing final Swagger documentation...').start();
105
+ try {
106
+ writeSwaggerFile(outputFileName, totalData, {
107
+ title: typeof options.title === 'string' ? options.title : undefined,
108
+ version: typeof options.apiVersion === 'string' ? options.apiVersion : undefined,
109
+ desc: typeof options.desc === 'string' ? options.desc : undefined
110
+ });
111
+ writeSpinner.succeed(`šŸŽ‰ Success! Swagger documentation saved to: ${outputFileName}`);
112
+ }
113
+ catch (writeError) {
114
+ writeSpinner.fail('āŒ Failed to write the documentation file.');
115
+ }
116
+ }
117
+ main();
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Recursively scans a directory for JavaScript and TypeScript files.
3
+ * @param dir Directory to scan.
4
+ * @returns Array of matched file paths.
5
+ */
6
+ export default function scanDirectory(dir: string): string[];
7
+ //# sourceMappingURL=fileScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileScanner.d.ts","sourceRoot":"","sources":["../../src/parser/fileScanner.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAuB3D"}
@@ -0,0 +1,29 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ /**
4
+ * Recursively scans a directory for JavaScript and TypeScript files.
5
+ * @param dir Directory to scan.
6
+ * @returns Array of matched file paths.
7
+ */
8
+ export default function scanDirectory(dir) {
9
+ let results = [];
10
+ const list = fs.readdirSync(dir);
11
+ list.forEach((file) => {
12
+ const fullPath = path.join(dir, file);
13
+ const stat = fs.statSync(fullPath);
14
+ if (file === 'node_modules' || file.startsWith('.')) {
15
+ return;
16
+ }
17
+ if (stat && stat.isDirectory()) {
18
+ results = results.concat(scanDirectory(fullPath));
19
+ }
20
+ else {
21
+ const ext = path.extname(fullPath);
22
+ if (['.js', '.ts'].includes(ext)) {
23
+ results.push(fullPath);
24
+ }
25
+ }
26
+ });
27
+ return results;
28
+ }
29
+ //# sourceMappingURL=fileScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileScanner.js","sourceRoot":"","sources":["../../src/parser/fileScanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,GAAW;IAC7C,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAEjC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAClD,OAAO;QACX,CAAC;QAED,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YAC7B,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACJ,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC3B,CAAC;QACL,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACnB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * دالة ذكية تفحص Ł…Ų­ŲŖŁˆŁ‰ الملف وتحدد هل Ł‡Łˆ ملف Express Controller/Router Ų­Ł‚ŁŠŁ‚ŁŠ ŁŠŲ³ŲŖŲ­Ł‚ الـ Documentation أم لا
3
+ * @param filePath المسار Ų§Ł„ŁƒŲ§Ł…Ł„ للملف المراد فحصه
4
+ * @returns boolean (true Ł„Łˆ الملف يحتوي على كود ؄كسبريس Ų­Ł‚ŁŠŁ‚ŁŠ)
5
+ */
6
+ export default function isExpressRouteFile(filePath: string): boolean;
7
+ //# sourceMappingURL=routerExtractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routerExtractor.d.ts","sourceRoot":"","sources":["../../src/parser/routerExtractor.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAsBpE"}
@@ -0,0 +1,27 @@
1
+ import * as fs from 'fs';
2
+ /**
3
+ * دالة ذكية تفحص Ł…Ų­ŲŖŁˆŁ‰ الملف وتحدد هل Ł‡Łˆ ملف Express Controller/Router Ų­Ł‚ŁŠŁ‚ŁŠ ŁŠŲ³ŲŖŲ­Ł‚ الـ Documentation أم لا
4
+ * @param filePath المسار Ų§Ł„ŁƒŲ§Ł…Ł„ للملف المراد فحصه
5
+ * @returns boolean (true Ł„Łˆ الملف يحتوي على كود ؄كسبريس Ų­Ł‚ŁŠŁ‚ŁŠ)
6
+ */
7
+ export default function isExpressRouteFile(filePath) {
8
+ if (filePath.endsWith('.d.ts') ||
9
+ filePath.includes('.test.') ||
10
+ filePath.includes('.spec.') ||
11
+ filePath.endsWith('tsconfig.json') ||
12
+ filePath.endsWith('package.json')) {
13
+ return false;
14
+ }
15
+ try {
16
+ const content = fs.readFileSync(filePath, 'utf8');
17
+ const hasExpress = content.includes('express');
18
+ const hasRouter = content.includes('Router') || content.includes('router.');
19
+ const hasHttpMethods = /router\.(get|post|put|delete|patch)/i.test(content) || /app\.(get|post|put|delete|patch)/i.test(content);
20
+ const hasReqRes = content.includes('req,res') && content.includes('request,response');
21
+ return (hasExpress && hasRouter) || hasHttpMethods || hasReqRes;
22
+ }
23
+ catch (error) {
24
+ return false;
25
+ }
26
+ }
27
+ //# sourceMappingURL=routerExtractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routerExtractor.js","sourceRoot":"","sources":["../../src/parser/routerExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,QAAgB;IACvD,IACI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC1B,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC3B,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC3B,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC;QAClC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EACnC,CAAC;QACC,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAClD,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC5E,MAAM,cAAc,GAAG,sCAAsC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,mCAAmC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjI,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;QAEtF,OAAO,CAAC,UAAU,IAAI,SAAS,CAAC,IAAI,cAAc,IAAI,SAAS,CAAC;IACpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * AIService wraps the Google Gemini client to generate OpenAPI documentation.
3
+ */
4
+ export declare class AIService {
5
+ private ai;
6
+ constructor(apiKey?: string);
7
+ /**
8
+ * Generates documentation output for the provided source code context.
9
+ * @param fileContent Combined route file content and attached context.
10
+ * @returns A JSON string representing the generated OpenAPI payload.
11
+ */
12
+ generateDoc(fileContent: string): Promise<string>;
13
+ }
14
+ //# sourceMappingURL=aiService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiService.d.ts","sourceRoot":"","sources":["../../src/services/aiService.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,EAAE,CAAc;gBAEZ,MAAM,CAAC,EAAE,MAAM;IAQ3B;;;;OAIG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAsDxD"}
@@ -0,0 +1,75 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ import * as dotenv from 'dotenv';
3
+ import * as path from 'path';
4
+ dotenv.config({ path: path.resolve(process.cwd(), '.env') });
5
+ /**
6
+ * AIService wraps the Google Gemini client to generate OpenAPI documentation.
7
+ */
8
+ export class AIService {
9
+ ai;
10
+ constructor(apiKey) {
11
+ const key = apiKey || process.env.DOCUMIND_API_KEY;
12
+ if (!key) {
13
+ throw new Error('āŒ Gemini API Key is missing! Please provide it via -k or set DOCUMIND_API_KEY environment variable.');
14
+ }
15
+ this.ai = new GoogleGenAI({ apiKey: key });
16
+ }
17
+ /**
18
+ * Generates documentation output for the provided source code context.
19
+ * @param fileContent Combined route file content and attached context.
20
+ * @returns A JSON string representing the generated OpenAPI payload.
21
+ */
22
+ async generateDoc(fileContent) {
23
+ const prompt = `
24
+ You are an expert Senior Backend Engineer and a world-class OpenAPI/Swagger Architect.
25
+ Analyze the following Express.js source code (including its routes, controllers, and validations).
26
+
27
+ Your absolute main task is to extract all API endpoints, methods, and schemas to populate a valid OpenAPI 3.0 JSON object.
28
+
29
+ Strict Instructions for High-Quality Documentation:
30
+ 1. **DO NOT return an empty paths object**. You must extract the routes found in the code (e.g., /register, /login, /logout, /profile).
31
+ 2. **RICH DESCRIPTIONS AND SUMMARIES (CRITICAL)**: For every single operation (get, post, put, delete, etc.) under each route, you MUST include:
32
+ - "summary": A short, clear, one-sentence explanation of what the endpoint does.
33
+ - "description": A highly detailed paragraph explaining the inner mechanics and business logic of the endpoint. For example, explain if it performs password hashing, check if user exists, generates a JWT session token, or requires specific middleware/roles. Do not make it generic.
34
+ 3. For each route, trace its controller function to document the expected request body, parameters, and HTTP response status codes (like 200, 201, 400, 401, 500) with descriptive answers for each status.
35
+ 4. Extract payload fields into components.schemas.
36
+ 5. **CRITICAL REGEX HANDLING**: If you write any regular expressions inside string patterns, double-escape all backslashes (use \\\\ instead of \\) so the output is perfectly valid JSON.
37
+ 6. Return ONLY a valid JSON object matching this schema style:
38
+ {
39
+ "paths": {
40
+ "/api/route": {
41
+ "post": {
42
+ "tags": ["Auth"],
43
+ "summary": "...",
44
+ "description": "...",
45
+ "requestBody": { ... },
46
+ "responses": { ... }
47
+ }
48
+ }
49
+ },
50
+ "components": {
51
+ "schemas": { ... }
52
+ }
53
+ }
54
+ `;
55
+ try {
56
+ const response = await this.ai.models.generateContent({
57
+ model: 'gemini-2.5-flash',
58
+ contents: [prompt, fileContent],
59
+ config: {
60
+ responseMimeType: 'application/json'
61
+ }
62
+ });
63
+ let cleanText = response.text || '{}';
64
+ if (cleanText.includes('```')) {
65
+ cleanText = cleanText.replace(/```json/g, '').replace(/```/g, '').trim();
66
+ }
67
+ return cleanText;
68
+ }
69
+ catch (apiError) {
70
+ console.error(`\nāŒ Gemini API Error: ${apiError.message}`);
71
+ return '{}';
72
+ }
73
+ }
74
+ }
75
+ //# sourceMappingURL=aiService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiService.js","sourceRoot":"","sources":["../../src/services/aiService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAE7D;;GAEG;AACH,MAAM,OAAO,SAAS;IACZ,EAAE,CAAc;IAExB,YAAY,MAAe;QACzB,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QACnD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,qGAAqG,CAAC,CAAC;QACzH,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,CAAC,WAAmB;QACnC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BlB,CAAC;QAEE,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC;gBACpD,KAAK,EAAE,kBAAkB;gBACzB,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;gBAC/B,MAAM,EAAE;oBACN,gBAAgB,EAAE,kBAAkB;iBACrC;aACF,CAAC,CAAC;YAEH,IAAI,SAAS,GAAG,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC;YACtC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAC3E,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,QAAa,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,yBAAyB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ interface SwaggerOptions {
2
+ title?: string | undefined;
3
+ version?: string | undefined;
4
+ desc?: string | undefined;
5
+ }
6
+ /**
7
+ * Writes an OpenAPI document as YAML or JSON to disk.
8
+ * @param outputPath Destination file path.
9
+ * @param pathsData Merged OpenAPI paths and components.
10
+ * @param options Title, version, and description metadata.
11
+ */
12
+ export declare function writeSwaggerFile(outputPath: string, pathsData: Record<string, any>, options: SwaggerOptions): void;
13
+ export {};
14
+ //# sourceMappingURL=fileWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileWriter.d.ts","sourceRoot":"","sources":["../../src/utils/fileWriter.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAsClH"}
@@ -0,0 +1,48 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import yaml from 'yaml';
4
+ /**
5
+ * Writes an OpenAPI document as YAML or JSON to disk.
6
+ * @param outputPath Destination file path.
7
+ * @param pathsData Merged OpenAPI paths and components.
8
+ * @param options Title, version, and description metadata.
9
+ */
10
+ export function writeSwaggerFile(outputPath, pathsData, options) {
11
+ let localTitle = 'DocuMind Generated API';
12
+ let localVersion = '1.0.0';
13
+ let localDesc = 'Automated OpenAPI documentation generated by DocuMind AI.';
14
+ try {
15
+ const localPackageJsonPath = path.resolve('./package.json');
16
+ if (fs.existsSync(localPackageJsonPath)) {
17
+ const pkg = JSON.parse(fs.readFileSync(localPackageJsonPath, 'utf8'));
18
+ if (pkg.name)
19
+ localTitle = `${pkg.name} API Documentation`;
20
+ if (pkg.version)
21
+ localVersion = pkg.version;
22
+ if (pkg.description)
23
+ localDesc = pkg.description;
24
+ }
25
+ }
26
+ catch (e) { }
27
+ const swaggerDoc = {
28
+ openapi: '3.0.0',
29
+ info: {
30
+ title: options.title || localTitle,
31
+ version: options.version || localVersion,
32
+ description: options.desc || localDesc
33
+ },
34
+ ...pathsData
35
+ };
36
+ const fullPath = path.resolve(outputPath);
37
+ const fileExtension = path.extname(fullPath).toLowerCase();
38
+ let fileContent;
39
+ if (fileExtension === '.yaml' || fileExtension === '.yml') {
40
+ fileContent = yaml.stringify(swaggerDoc);
41
+ }
42
+ else {
43
+ fileContent = JSON.stringify(swaggerDoc, null, 2);
44
+ }
45
+ fs.writeFileSync(fullPath, fileContent, 'utf8');
46
+ console.log(`\nšŸŽ‰ Success! Swagger documentation saved to: ${fullPath}`);
47
+ }
48
+ //# sourceMappingURL=fileWriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileWriter.js","sourceRoot":"","sources":["../../src/utils/fileWriter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,SAA8B,EAAE,OAAuB;IACxG,IAAI,UAAU,GAAG,wBAAwB,CAAC;IAC1C,IAAI,YAAY,GAAG,OAAO,CAAC;IAC3B,IAAI,SAAS,GAAG,2DAA2D,CAAC;IAE5E,IAAI,CAAC;QACD,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC5D,IAAI,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC,CAAC;YACtE,IAAI,GAAG,CAAC,IAAI;gBAAE,UAAU,GAAG,GAAG,GAAG,CAAC,IAAI,oBAAoB,CAAC;YAC3D,IAAI,GAAG,CAAC,OAAO;gBAAE,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC;YAC5C,IAAI,GAAG,CAAC,WAAW;gBAAE,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC;QACrD,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;IAEd,MAAM,UAAU,GAAG;QACf,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACF,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,UAAU;YAClC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,YAAY;YACxC,WAAW,EAAE,OAAO,CAAC,IAAI,IAAI,SAAS;SACzC;QACD,GAAG,SAAS;KACf,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAE3D,IAAI,WAAmB,CAAC;IAExB,IAAI,aAAa,KAAK,OAAO,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;QACxD,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACJ,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,iDAAiD,QAAQ,EAAE,CAAC,CAAC;AAC7E,CAAC"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@mena-emad/documind",
3
+ "version": "1.0.0",
4
+ "description": "AI-Powered Swagger/OpenAPI Documentation Generator for Express.js projects with intelligent context stitching.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "type": "module",
11
+ "bin": {
12
+ "documind": "./dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsx watch src/index.ts",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "cli",
24
+ "swagger",
25
+ "openapi",
26
+ "express",
27
+ "gemini",
28
+ "ai",
29
+ "automation",
30
+ "documentation"
31
+ ],
32
+ "author": {
33
+ "name": "Mena Emad Sawares",
34
+ "url": "https://menaemad.vercel.app/",
35
+ "email": "menaemad6543@gmail.com",
36
+ "github": "https://github.com/mena-emad"
37
+ },
38
+ "license": "ISC",
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "tsx": "^4.19.0",
45
+ "typescript": "^5.7.0"
46
+ },
47
+ "dependencies": {
48
+ "@google/genai": "^0.1.2",
49
+ "commander": "^13.1.0",
50
+ "dotenv": "^16.4.7",
51
+ "ora": "^8.1.1",
52
+ "yaml": "^2.7.0"
53
+ }
54
+ }