zero-doc 1.0.1 โ 1.0.2
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/dist/ai-analyzer.js +2 -33
- package/dist/cli.js +14 -3
- package/package.json +1 -1
package/dist/ai-analyzer.js
CHANGED
|
@@ -47,10 +47,8 @@ class AIAnalyzer {
|
|
|
47
47
|
this.filePatterns = options.filePatterns;
|
|
48
48
|
}
|
|
49
49
|
async analyzeProject() {
|
|
50
|
-
console.log('๐ค Analyzing project with AI...\n');
|
|
51
50
|
// Find all relevant files
|
|
52
51
|
const files = await this.findProjectFiles();
|
|
53
|
-
console.log(`๐ Found ${files.length} files to analyze\n`);
|
|
54
52
|
// Read and analyze files
|
|
55
53
|
const fileContents = [];
|
|
56
54
|
for (const file of files.slice(0, 50)) { // Limit to 50 files for now
|
|
@@ -59,7 +57,6 @@ class AIAnalyzer {
|
|
|
59
57
|
fileContents.push({ path: path.relative(this.projectRoot, file), content });
|
|
60
58
|
}
|
|
61
59
|
catch (error) {
|
|
62
|
-
console.warn(`โ ๏ธ Could not read file: ${file}`);
|
|
63
60
|
}
|
|
64
61
|
}
|
|
65
62
|
// Analyze with AI
|
|
@@ -88,7 +85,6 @@ class AIAnalyzer {
|
|
|
88
85
|
};
|
|
89
86
|
// Validate inventory structure
|
|
90
87
|
if (!inventory.endpoints || !Array.isArray(inventory.endpoints)) {
|
|
91
|
-
console.warn('โ ๏ธ Warning: endpoints is not an array, setting to empty array');
|
|
92
88
|
inventory.endpoints = [];
|
|
93
89
|
}
|
|
94
90
|
if (!inventory.stats) {
|
|
@@ -101,8 +97,6 @@ class AIAnalyzer {
|
|
|
101
97
|
}
|
|
102
98
|
async findProjectFiles() {
|
|
103
99
|
const allFiles = [];
|
|
104
|
-
console.log(`๐ Searching for files in: ${this.projectRoot}`);
|
|
105
|
-
console.log(`๐ Patterns: ${this.filePatterns.join(', ')}\n`);
|
|
106
100
|
for (const pattern of this.filePatterns) {
|
|
107
101
|
try {
|
|
108
102
|
const files = await (0, glob_1.glob)(pattern, {
|
|
@@ -110,23 +104,14 @@ class AIAnalyzer {
|
|
|
110
104
|
absolute: true,
|
|
111
105
|
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**'],
|
|
112
106
|
});
|
|
113
|
-
console.log(` Pattern "${pattern}": found ${files.length} files`);
|
|
114
|
-
if (files.length > 0 && files.length <= 5) {
|
|
115
|
-
files.forEach(f => console.log(` - ${path.relative(this.projectRoot, f)}`));
|
|
116
|
-
}
|
|
117
|
-
else if (files.length > 5) {
|
|
118
|
-
files.slice(0, 5).forEach(f => console.log(` - ${path.relative(this.projectRoot, f)}`));
|
|
119
|
-
console.log(` ... and ${files.length - 5} more`);
|
|
120
|
-
}
|
|
121
107
|
allFiles.push(...files);
|
|
122
108
|
}
|
|
123
109
|
catch (error) {
|
|
124
|
-
|
|
110
|
+
// Silently ignore pattern errors
|
|
125
111
|
}
|
|
126
112
|
}
|
|
127
113
|
const uniqueFiles = [...new Set(allFiles)];
|
|
128
114
|
if (uniqueFiles.length === 0) {
|
|
129
|
-
console.log('\nโ ๏ธ No files found! Trying alternative patterns...\n');
|
|
130
115
|
// Try alternative patterns
|
|
131
116
|
const alternativePatterns = [
|
|
132
117
|
'**/*.ts',
|
|
@@ -148,7 +133,6 @@ class AIAnalyzer {
|
|
|
148
133
|
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**'],
|
|
149
134
|
});
|
|
150
135
|
if (files.length > 0) {
|
|
151
|
-
console.log(` Found ${files.length} files with pattern "${altPattern}"`);
|
|
152
136
|
uniqueFiles.push(...files);
|
|
153
137
|
break; // Use first pattern that finds files
|
|
154
138
|
}
|
|
@@ -162,7 +146,6 @@ class AIAnalyzer {
|
|
|
162
146
|
}
|
|
163
147
|
async analyzeWithAI(files) {
|
|
164
148
|
const prompt = this.buildAnalysisPrompt(files);
|
|
165
|
-
console.log('๐ Sending project files to AI for analysis...\n');
|
|
166
149
|
try {
|
|
167
150
|
const result = await this.model.generateContent(prompt);
|
|
168
151
|
const response = await result.response;
|
|
@@ -176,13 +159,11 @@ class AIAnalyzer {
|
|
|
176
159
|
if (!aiResult.endpoints || !Array.isArray(aiResult.endpoints)) {
|
|
177
160
|
throw new Error('Invalid response format from AI');
|
|
178
161
|
}
|
|
179
|
-
console.log(`โ
AI found ${aiResult.endpoints.length} endpoints\n`);
|
|
180
162
|
// Validate and map endpoints
|
|
181
163
|
const mappedEndpoints = aiResult.endpoints.map((ep, index) => {
|
|
182
164
|
// Ensure method is uppercase
|
|
183
165
|
const method = (ep.method || 'GET').toUpperCase();
|
|
184
166
|
if (!['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)) {
|
|
185
|
-
console.warn(`โ ๏ธ Invalid method "${ep.method}" for endpoint ${index}, defaulting to GET`);
|
|
186
167
|
}
|
|
187
168
|
return {
|
|
188
169
|
id: `ep-${index}`,
|
|
@@ -209,17 +190,10 @@ class AIAnalyzer {
|
|
|
209
190
|
};
|
|
210
191
|
});
|
|
211
192
|
// Log first endpoint for debugging
|
|
212
|
-
|
|
213
|
-
console.log(`๐ Sample endpoint structure:`);
|
|
214
|
-
console.log(` ${mappedEndpoints[0].method} ${mappedEndpoints[0].path}`);
|
|
215
|
-
console.log(` Group: ${mappedEndpoints[0].group}`);
|
|
216
|
-
console.log(` Parameters: ${mappedEndpoints[0].parameters.length}`);
|
|
217
|
-
console.log(` Responses: ${mappedEndpoints[0].responses?.length || 0}\n`);
|
|
218
|
-
}
|
|
193
|
+
// Logs removed for clean progress bar output
|
|
219
194
|
return mappedEndpoints;
|
|
220
195
|
}
|
|
221
196
|
catch (error) {
|
|
222
|
-
console.error('โ Error analyzing with AI:', error);
|
|
223
197
|
throw error;
|
|
224
198
|
}
|
|
225
199
|
}
|
|
@@ -379,21 +353,18 @@ CRITICAL:
|
|
|
379
353
|
const key = `${endpoint.method}:${endpoint.path}`;
|
|
380
354
|
// Skip duplicates
|
|
381
355
|
if (seen.has(key)) {
|
|
382
|
-
console.log(`โ ๏ธ Skipping duplicate: ${endpoint.method} ${endpoint.path}`);
|
|
383
356
|
continue;
|
|
384
357
|
}
|
|
385
358
|
// Skip root routes unless they have meaningful content
|
|
386
359
|
if (endpoint.path === '/' && (!endpoint.metadata?.title || endpoint.metadata.title === 'API Root' || endpoint.metadata.title === 'GET /')) {
|
|
387
360
|
// Only skip if it's a simple root route without meaningful content
|
|
388
361
|
if (!endpoint.parameters.length && (!endpoint.responses || endpoint.responses.length === 0)) {
|
|
389
|
-
console.log(`โ ๏ธ Skipping empty root route: ${endpoint.path}`);
|
|
390
362
|
continue;
|
|
391
363
|
}
|
|
392
364
|
}
|
|
393
365
|
seen.add(key);
|
|
394
366
|
filtered.push(endpoint);
|
|
395
367
|
}
|
|
396
|
-
console.log(`๐งน Filtered ${endpoints.length} โ ${filtered.length} endpoints (removed ${endpoints.length - filtered.length} duplicates/empty)\n`);
|
|
397
368
|
return filtered;
|
|
398
369
|
}
|
|
399
370
|
detectBaseUrl(endpoints) {
|
|
@@ -420,7 +391,6 @@ CRITICAL:
|
|
|
420
391
|
if (segments.length >= 2) {
|
|
421
392
|
// Take first 2 segments as base (e.g., /api/instagram)
|
|
422
393
|
const basePath = '/' + segments.slice(0, 2).join('/');
|
|
423
|
-
console.log(`๐ Detected base URL: ${basePath}\n`);
|
|
424
394
|
// Remove base path from endpoint paths
|
|
425
395
|
endpoints.forEach(ep => {
|
|
426
396
|
if (ep.path.startsWith(basePath)) {
|
|
@@ -431,7 +401,6 @@ CRITICAL:
|
|
|
431
401
|
}
|
|
432
402
|
else if (segments.length === 1) {
|
|
433
403
|
const basePath = '/' + segments[0];
|
|
434
|
-
console.log(`๐ Detected base URL: ${basePath}\n`);
|
|
435
404
|
// Remove base path from endpoint paths
|
|
436
405
|
endpoints.forEach(ep => {
|
|
437
406
|
if (ep.path.startsWith(basePath)) {
|
package/dist/cli.js
CHANGED
|
@@ -51,9 +51,21 @@ function updateProgress(current, total, label = '') {
|
|
|
51
51
|
const bar = 'โ'.repeat(filled) + 'โ'.repeat(empty);
|
|
52
52
|
process.stdout.write(`\r${label} [${bar}] ${percentage}%`);
|
|
53
53
|
if (percentage === 100) {
|
|
54
|
-
|
|
54
|
+
// Clear the progress bar line
|
|
55
|
+
process.stdout.write('\r' + ' '.repeat(process.stdout.columns || 80) + '\r');
|
|
55
56
|
}
|
|
56
57
|
}
|
|
58
|
+
// Display final URL with formatting
|
|
59
|
+
function displayUrl(url) {
|
|
60
|
+
// ANSI color codes
|
|
61
|
+
const reset = '\x1b[0m';
|
|
62
|
+
const red = '\x1b[31m';
|
|
63
|
+
const blue = '\x1b[34m';
|
|
64
|
+
const bold = '\x1b[1m';
|
|
65
|
+
const underline = '\x1b[4m';
|
|
66
|
+
// โ in red, "Local:" in bold, URL in blue with underline
|
|
67
|
+
process.stdout.write(`${red}โ${reset} ${bold}Local:${reset} ${blue}${underline}${url}${reset}\n`);
|
|
68
|
+
}
|
|
57
69
|
commander_1.program
|
|
58
70
|
.name('zero-doc')
|
|
59
71
|
.description('Zero-Config API Documentation Generator')
|
|
@@ -405,8 +417,7 @@ commander_1.program
|
|
|
405
417
|
else if (output.includes('ready in') && !serverReady) {
|
|
406
418
|
serverReady = true;
|
|
407
419
|
updateProgress(100, 100, 'Starting server');
|
|
408
|
-
|
|
409
|
-
console.log('http://localhost:7777');
|
|
420
|
+
displayUrl('http://localhost:7777/');
|
|
410
421
|
}
|
|
411
422
|
else if (!output.includes('VITE') && !output.includes('vite') && !output.trim().startsWith('โ')) {
|
|
412
423
|
// Only show non-Vite messages (errors, etc.)
|