zero-doc 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/dist/ai-enricher.d.ts +15 -0
- package/dist/ai-enricher.js +103 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +312 -0
- package/dist/gemini-enricher.d.ts +14 -0
- package/dist/gemini-enricher.js +96 -0
- package/dist/generator.d.ts +22 -0
- package/dist/generator.js +113 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +26 -0
- package/dist/parser.d.ts +14 -0
- package/dist/parser.js +176 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.js +2 -0
- package/package.json +57 -0
- package/scripts/copy-viewer.js +30 -0
- package/viewer/README.md +41 -0
- package/viewer/index.html +14 -0
- package/viewer/package.json +26 -0
- package/viewer/postcss.config.js +6 -0
- package/viewer/public/api-inventory.json +151 -0
- package/viewer/src/App.tsx +79 -0
- package/viewer/src/components/CodeSnippet.tsx +136 -0
- package/viewer/src/components/EndpointView.tsx +106 -0
- package/viewer/src/components/ParameterTable.tsx +71 -0
- package/viewer/src/components/Sidebar.tsx +244 -0
- package/viewer/src/contexts/ThemeContext.tsx +62 -0
- package/viewer/src/index.css +32 -0
- package/viewer/src/main.tsx +11 -0
- package/viewer/src/types.ts +54 -0
- package/viewer/tailwind.config.js +13 -0
- package/viewer/tsconfig.json +22 -0
- package/viewer/tsconfig.node.json +11 -0
- package/viewer/vite.config.ts +11 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.GeminiEnricher = exports.AIEnricher = exports.APIInventoryGenerator = exports.RouteParser = void 0;
|
|
18
|
+
var parser_1 = require("./parser");
|
|
19
|
+
Object.defineProperty(exports, "RouteParser", { enumerable: true, get: function () { return parser_1.RouteParser; } });
|
|
20
|
+
var generator_1 = require("./generator");
|
|
21
|
+
Object.defineProperty(exports, "APIInventoryGenerator", { enumerable: true, get: function () { return generator_1.APIInventoryGenerator; } });
|
|
22
|
+
var ai_enricher_1 = require("./ai-enricher");
|
|
23
|
+
Object.defineProperty(exports, "AIEnricher", { enumerable: true, get: function () { return ai_enricher_1.AIEnricher; } });
|
|
24
|
+
var gemini_enricher_1 = require("./gemini-enricher");
|
|
25
|
+
Object.defineProperty(exports, "GeminiEnricher", { enumerable: true, get: function () { return gemini_enricher_1.GeminiEnricher; } });
|
|
26
|
+
__exportStar(require("./types"), exports);
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RouteEndpoint } from './types';
|
|
2
|
+
export declare class RouteParser {
|
|
3
|
+
private project;
|
|
4
|
+
private routes;
|
|
5
|
+
constructor(tsConfigPath?: string);
|
|
6
|
+
addSourceFiles(pattern: string): void;
|
|
7
|
+
parse(): RouteEndpoint[];
|
|
8
|
+
private extractRoute;
|
|
9
|
+
private extractGroup;
|
|
10
|
+
private extractPath;
|
|
11
|
+
private extractHandler;
|
|
12
|
+
private extractParameters;
|
|
13
|
+
getRoutes(): RouteEndpoint[];
|
|
14
|
+
}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RouteParser = void 0;
|
|
4
|
+
const ts_morph_1 = require("ts-morph");
|
|
5
|
+
const nanoid_1 = require("nanoid");
|
|
6
|
+
class RouteParser {
|
|
7
|
+
constructor(tsConfigPath) {
|
|
8
|
+
this.routes = [];
|
|
9
|
+
this.project = new ts_morph_1.Project({
|
|
10
|
+
tsConfigFilePath: tsConfigPath,
|
|
11
|
+
skipAddingFilesFromTsConfig: true,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
addSourceFiles(pattern) {
|
|
15
|
+
this.project.addSourceFilesAtPaths(pattern);
|
|
16
|
+
}
|
|
17
|
+
parse() {
|
|
18
|
+
this.routes = [];
|
|
19
|
+
this.project.getSourceFiles().forEach(sourceFile => {
|
|
20
|
+
const filePath = sourceFile.getFilePath();
|
|
21
|
+
sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression).forEach(call => {
|
|
22
|
+
const route = this.extractRoute(call, filePath);
|
|
23
|
+
if (route) {
|
|
24
|
+
this.routes.push(route);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
return this.routes;
|
|
29
|
+
}
|
|
30
|
+
extractRoute(call, filePath) {
|
|
31
|
+
const expression = call.getExpression();
|
|
32
|
+
const expressionText = expression.getText();
|
|
33
|
+
// Supports: app.get, router.post, fastify.put, etc.
|
|
34
|
+
const methodMatch = expressionText.match(/\.(get|post|put|delete|patch)$/i);
|
|
35
|
+
if (!methodMatch)
|
|
36
|
+
return null;
|
|
37
|
+
const method = methodMatch[1].toUpperCase();
|
|
38
|
+
const args = call.getArguments();
|
|
39
|
+
if (args.length < 2)
|
|
40
|
+
return null; // Needs at least (path, handler)
|
|
41
|
+
// Extract path (first argument)
|
|
42
|
+
const pathArg = args[0];
|
|
43
|
+
const path = this.extractPath(pathArg);
|
|
44
|
+
if (!path)
|
|
45
|
+
return null;
|
|
46
|
+
// Extract handler (usually last argument)
|
|
47
|
+
const handlerArg = args[args.length - 1];
|
|
48
|
+
const handler = this.extractHandler(handlerArg);
|
|
49
|
+
// Extract parameters from req.body and req.query
|
|
50
|
+
const parameters = this.extractParameters(handlerArg);
|
|
51
|
+
// Extract group from path (first segment after /)
|
|
52
|
+
const group = this.extractGroup(path);
|
|
53
|
+
return {
|
|
54
|
+
id: (0, nanoid_1.nanoid)(10),
|
|
55
|
+
method,
|
|
56
|
+
path,
|
|
57
|
+
group,
|
|
58
|
+
file: filePath,
|
|
59
|
+
line: call.getStartLineNumber(),
|
|
60
|
+
handler,
|
|
61
|
+
parameters,
|
|
62
|
+
metadata: {},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
extractGroup(path) {
|
|
66
|
+
const segments = path.split('/').filter(s => s && !s.startsWith(':'));
|
|
67
|
+
if (segments.length === 0) {
|
|
68
|
+
return 'Root';
|
|
69
|
+
}
|
|
70
|
+
const firstSegment = segments[0];
|
|
71
|
+
const capitalized = firstSegment.charAt(0).toUpperCase() + firstSegment.slice(1);
|
|
72
|
+
return capitalized;
|
|
73
|
+
}
|
|
74
|
+
extractPath(node) {
|
|
75
|
+
const text = node.getText();
|
|
76
|
+
// Remove quotes and template literals
|
|
77
|
+
const cleaned = text.replace(/^['"`]|['"`]$/g, '');
|
|
78
|
+
// Validate if it looks like a path
|
|
79
|
+
if (cleaned.startsWith('/')) {
|
|
80
|
+
return cleaned;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
extractHandler(node) {
|
|
85
|
+
const isAsync = node.getText().includes('async');
|
|
86
|
+
// Try to extract function name if it's a named function
|
|
87
|
+
let name;
|
|
88
|
+
if (ts_morph_1.Node.isIdentifier(node)) {
|
|
89
|
+
name = node.getText();
|
|
90
|
+
}
|
|
91
|
+
// Extract function parameters (req, res, next, etc.)
|
|
92
|
+
const parameters = [];
|
|
93
|
+
if (ts_morph_1.Node.isArrowFunction(node) || ts_morph_1.Node.isFunctionExpression(node)) {
|
|
94
|
+
node.getParameters().forEach(param => {
|
|
95
|
+
parameters.push(param.getName());
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
name,
|
|
100
|
+
isAsync,
|
|
101
|
+
parameters,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
extractParameters(handlerNode) {
|
|
105
|
+
const parameters = [];
|
|
106
|
+
// Look for accesses to req.body, req.query, req.params
|
|
107
|
+
if (ts_morph_1.Node.isArrowFunction(handlerNode) || ts_morph_1.Node.isFunctionExpression(handlerNode)) {
|
|
108
|
+
const body = handlerNode.getBody();
|
|
109
|
+
if (body) {
|
|
110
|
+
// Look for PropertyAccessExpression: req.body.email, req.query.page, etc.
|
|
111
|
+
body.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertyAccessExpression).forEach(prop => {
|
|
112
|
+
const fullText = prop.getText();
|
|
113
|
+
// req.body.fieldName
|
|
114
|
+
const bodyMatch = fullText.match(/req\.body\.(\w+)/);
|
|
115
|
+
if (bodyMatch) {
|
|
116
|
+
parameters.push({
|
|
117
|
+
name: bodyMatch[1],
|
|
118
|
+
in: 'body',
|
|
119
|
+
required: true, // Can be refined later
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// req.query.fieldName
|
|
123
|
+
const queryMatch = fullText.match(/req\.query\.(\w+)/);
|
|
124
|
+
if (queryMatch) {
|
|
125
|
+
parameters.push({
|
|
126
|
+
name: queryMatch[1],
|
|
127
|
+
in: 'query',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// req.params.fieldName
|
|
131
|
+
const paramsMatch = fullText.match(/req\.params\.(\w+)/);
|
|
132
|
+
if (paramsMatch) {
|
|
133
|
+
parameters.push({
|
|
134
|
+
name: paramsMatch[1],
|
|
135
|
+
in: 'path',
|
|
136
|
+
required: true,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
// Look for destructuring: const { email, password } = req.body
|
|
141
|
+
body.getDescendantsOfKind(ts_morph_1.SyntaxKind.VariableDeclaration).forEach(varDecl => {
|
|
142
|
+
const initializer = varDecl.getInitializer();
|
|
143
|
+
if (initializer?.getText().startsWith('req.')) {
|
|
144
|
+
const sourceText = initializer.getText();
|
|
145
|
+
const name = varDecl.getName();
|
|
146
|
+
// If it's destructuring
|
|
147
|
+
if (name.startsWith('{')) {
|
|
148
|
+
const fields = name
|
|
149
|
+
.replace(/[{}]/g, '')
|
|
150
|
+
.split(',')
|
|
151
|
+
.map(f => f.trim());
|
|
152
|
+
let location = 'body';
|
|
153
|
+
if (sourceText.includes('req.query'))
|
|
154
|
+
location = 'query';
|
|
155
|
+
if (sourceText.includes('req.params'))
|
|
156
|
+
location = 'path';
|
|
157
|
+
fields.forEach(field => {
|
|
158
|
+
parameters.push({
|
|
159
|
+
name: field,
|
|
160
|
+
in: location,
|
|
161
|
+
required: location !== 'query',
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Remove duplicates
|
|
170
|
+
return parameters.filter((param, index, self) => index === self.findIndex(p => p.name === param.name && p.in === param.in));
|
|
171
|
+
}
|
|
172
|
+
getRoutes() {
|
|
173
|
+
return this.routes;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.RouteParser = RouteParser;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface RouteParameter {
|
|
2
|
+
name: string;
|
|
3
|
+
in: 'path' | 'query' | 'body' | 'header';
|
|
4
|
+
type?: string;
|
|
5
|
+
required?: boolean;
|
|
6
|
+
description?: string;
|
|
7
|
+
inferredType?: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
8
|
+
}
|
|
9
|
+
export interface RouteEndpoint {
|
|
10
|
+
id: string;
|
|
11
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
12
|
+
path: string;
|
|
13
|
+
group: string;
|
|
14
|
+
file: string;
|
|
15
|
+
line: number;
|
|
16
|
+
handler: {
|
|
17
|
+
name?: string;
|
|
18
|
+
isAsync: boolean;
|
|
19
|
+
parameters: string[];
|
|
20
|
+
};
|
|
21
|
+
parameters: RouteParameter[];
|
|
22
|
+
requestBody?: {
|
|
23
|
+
required: boolean;
|
|
24
|
+
fields: RouteParameter[];
|
|
25
|
+
};
|
|
26
|
+
response?: {
|
|
27
|
+
statusCode: number;
|
|
28
|
+
type?: string;
|
|
29
|
+
};
|
|
30
|
+
metadata?: {
|
|
31
|
+
tags?: string[];
|
|
32
|
+
summary?: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
deprecated?: boolean;
|
|
35
|
+
title?: string;
|
|
36
|
+
aiGenerated?: boolean;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface APIInventory {
|
|
40
|
+
version: string;
|
|
41
|
+
generatedAt: string;
|
|
42
|
+
project: {
|
|
43
|
+
name?: string;
|
|
44
|
+
framework: 'express' | 'fastify' | 'unknown';
|
|
45
|
+
};
|
|
46
|
+
endpoints: RouteEndpoint[];
|
|
47
|
+
stats: {
|
|
48
|
+
totalEndpoints: number;
|
|
49
|
+
byMethod: Record<string, number>;
|
|
50
|
+
};
|
|
51
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zero-doc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Zero-Config API Documentation Generator - Generate beautiful API docs from your code automatically",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"zero-doc": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"api",
|
|
11
|
+
"documentation",
|
|
12
|
+
"docs",
|
|
13
|
+
"openapi",
|
|
14
|
+
"swagger",
|
|
15
|
+
"express",
|
|
16
|
+
"fastify",
|
|
17
|
+
"typescript",
|
|
18
|
+
"static-analysis",
|
|
19
|
+
"ai",
|
|
20
|
+
"zero-config"
|
|
21
|
+
],
|
|
22
|
+
"author": "Lucas Sens",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": ""
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"viewer",
|
|
31
|
+
"scripts"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc && npm run copy-viewer",
|
|
35
|
+
"copy-viewer": "node scripts/copy-viewer.js",
|
|
36
|
+
"dev": "ts-node src/cli.ts",
|
|
37
|
+
"generate": "ts-node src/cli.ts generate"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@google/generative-ai": "^0.21.0",
|
|
41
|
+
"commander": "^11.0.0",
|
|
42
|
+
"dotenv": "^16.3.1",
|
|
43
|
+
"fs-extra": "^11.2.0",
|
|
44
|
+
"nanoid": "^3.3.7",
|
|
45
|
+
"openai": "^4.20.0",
|
|
46
|
+
"tmp": "^0.2.1",
|
|
47
|
+
"ts-morph": "^21.0.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/fs-extra": "^11.0.4",
|
|
51
|
+
"@types/node": "^20.0.0",
|
|
52
|
+
"@types/tmp": "^0.2.6",
|
|
53
|
+
"ts-node": "^10.9.0",
|
|
54
|
+
"typescript": "^5.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fse = require('fs-extra');
|
|
4
|
+
|
|
5
|
+
// Get the monorepo root (go up from packages/cli/scripts to root)
|
|
6
|
+
const monorepoRoot = path.join(__dirname, '../../../');
|
|
7
|
+
const viewerSource = path.join(monorepoRoot, 'apps/viewer');
|
|
8
|
+
const viewerDest = path.join(__dirname, '../viewer');
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(viewerSource)) {
|
|
11
|
+
console.error('❌ Viewer source not found at:', viewerSource);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (fs.existsSync(viewerDest)) {
|
|
16
|
+
fse.removeSync(viewerDest);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fse.copySync(viewerSource, viewerDest, {
|
|
20
|
+
filter: (src) => {
|
|
21
|
+
const relativePath = path.relative(viewerSource, src);
|
|
22
|
+
return !relativePath.includes('node_modules') &&
|
|
23
|
+
!relativePath.includes('dist') &&
|
|
24
|
+
!relativePath.startsWith('.git') &&
|
|
25
|
+
!relativePath.includes('package-lock.json');
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
console.log('✅ Viewer copied to packages/cli/viewer');
|
|
30
|
+
|
package/viewer/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Zero-Doc Viewer
|
|
2
|
+
|
|
3
|
+
Beautiful API documentation viewer built with React + Vite + Tailwind.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd apps/viewer
|
|
9
|
+
npm install
|
|
10
|
+
npm run dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The viewer will automatically load `api-inventory.json` from the `public` folder.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- ✅ Stripe-style documentation layout
|
|
18
|
+
- ✅ Sidebar navigation grouped by HTTP method
|
|
19
|
+
- ✅ Color-coded method badges (GET=green, POST=blue, etc.)
|
|
20
|
+
- ✅ Automatic parameter tables
|
|
21
|
+
- ✅ Code snippets (fetch & axios)
|
|
22
|
+
- ✅ Dark mode code blocks
|
|
23
|
+
- ✅ Responsive design
|
|
24
|
+
|
|
25
|
+
## Structure
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
apps/viewer/
|
|
29
|
+
├── src/
|
|
30
|
+
│ ├── components/
|
|
31
|
+
│ │ ├── Sidebar.tsx # Navigation sidebar
|
|
32
|
+
│ │ ├── EndpointView.tsx # Main endpoint documentation
|
|
33
|
+
│ │ ├── ParameterTable.tsx # Auto-generated parameter tables
|
|
34
|
+
│ │ └── CodeSnippet.tsx # fetch/axios code examples
|
|
35
|
+
│ ├── App.tsx # Main app component
|
|
36
|
+
│ ├── types.ts # TypeScript types
|
|
37
|
+
│ └── main.tsx # Entry point
|
|
38
|
+
└── public/
|
|
39
|
+
└── api-inventory.json # Generated API inventory
|
|
40
|
+
```
|
|
41
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>API Documentation - Zero Doc</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
14
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zero-doc/viewer",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"react": "^18.2.0",
|
|
13
|
+
"react-dom": "^18.2.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/react": "^18.2.43",
|
|
17
|
+
"@types/react-dom": "^18.2.17",
|
|
18
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
19
|
+
"autoprefixer": "^10.4.16",
|
|
20
|
+
"postcss": "^8.4.32",
|
|
21
|
+
"tailwindcss": "^3.3.6",
|
|
22
|
+
"typescript": "^5.2.2",
|
|
23
|
+
"vite": "^5.0.8"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"generatedAt": "2025-12-28T06:58:49.389Z",
|
|
4
|
+
"project": {
|
|
5
|
+
"framework": "express"
|
|
6
|
+
},
|
|
7
|
+
"endpoints": [
|
|
8
|
+
{
|
|
9
|
+
"id": "-C8ltf6rc1",
|
|
10
|
+
"method": "GET",
|
|
11
|
+
"path": "/users",
|
|
12
|
+
"group": "Users",
|
|
13
|
+
"file": "C:/trampos/Projetos/Zero-Config API Reference/packages/cli/examples/express-routes.ts",
|
|
14
|
+
"line": 7,
|
|
15
|
+
"handler": {
|
|
16
|
+
"isAsync": false,
|
|
17
|
+
"parameters": [
|
|
18
|
+
"req",
|
|
19
|
+
"res"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"parameters": [
|
|
23
|
+
{
|
|
24
|
+
"name": "page",
|
|
25
|
+
"in": "query"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "limit",
|
|
29
|
+
"in": "query"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"metadata": {}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "ksWVmn7IFn",
|
|
36
|
+
"method": "GET",
|
|
37
|
+
"path": "/users/:id",
|
|
38
|
+
"group": "Users",
|
|
39
|
+
"file": "C:/trampos/Projetos/Zero-Config API Reference/packages/cli/examples/express-routes.ts",
|
|
40
|
+
"line": 14,
|
|
41
|
+
"handler": {
|
|
42
|
+
"isAsync": true,
|
|
43
|
+
"parameters": [
|
|
44
|
+
"req",
|
|
45
|
+
"res"
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
"parameters": [
|
|
49
|
+
{
|
|
50
|
+
"name": "id",
|
|
51
|
+
"in": "path",
|
|
52
|
+
"required": true
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"metadata": {}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "-nScJ4hpeC",
|
|
59
|
+
"method": "POST",
|
|
60
|
+
"path": "/users",
|
|
61
|
+
"group": "Users",
|
|
62
|
+
"file": "C:/trampos/Projetos/Zero-Config API Reference/packages/cli/examples/express-routes.ts",
|
|
63
|
+
"line": 20,
|
|
64
|
+
"handler": {
|
|
65
|
+
"isAsync": true,
|
|
66
|
+
"parameters": [
|
|
67
|
+
"req",
|
|
68
|
+
"res"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"parameters": [
|
|
72
|
+
{
|
|
73
|
+
"name": "email",
|
|
74
|
+
"in": "body",
|
|
75
|
+
"required": true
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "password",
|
|
79
|
+
"in": "body",
|
|
80
|
+
"required": true
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "name",
|
|
84
|
+
"in": "body",
|
|
85
|
+
"required": true
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"metadata": {}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "J2WEY9IHsB",
|
|
92
|
+
"method": "PUT",
|
|
93
|
+
"path": "/users/:id",
|
|
94
|
+
"group": "Users",
|
|
95
|
+
"file": "C:/trampos/Projetos/Zero-Config API Reference/packages/cli/examples/express-routes.ts",
|
|
96
|
+
"line": 26,
|
|
97
|
+
"handler": {
|
|
98
|
+
"isAsync": false,
|
|
99
|
+
"parameters": [
|
|
100
|
+
"req",
|
|
101
|
+
"res"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
"parameters": [
|
|
105
|
+
{
|
|
106
|
+
"name": "id",
|
|
107
|
+
"in": "path",
|
|
108
|
+
"required": true
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "email",
|
|
112
|
+
"in": "body",
|
|
113
|
+
"required": true
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"metadata": {}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"id": "Nam618R71j",
|
|
120
|
+
"method": "DELETE",
|
|
121
|
+
"path": "/users/:id",
|
|
122
|
+
"group": "Users",
|
|
123
|
+
"file": "C:/trampos/Projetos/Zero-Config API Reference/packages/cli/examples/express-routes.ts",
|
|
124
|
+
"line": 33,
|
|
125
|
+
"handler": {
|
|
126
|
+
"isAsync": true,
|
|
127
|
+
"parameters": [
|
|
128
|
+
"req",
|
|
129
|
+
"res"
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"parameters": [
|
|
133
|
+
{
|
|
134
|
+
"name": "id",
|
|
135
|
+
"in": "path",
|
|
136
|
+
"required": true
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"metadata": {}
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
"stats": {
|
|
143
|
+
"totalEndpoints": 5,
|
|
144
|
+
"byMethod": {
|
|
145
|
+
"GET": 2,
|
|
146
|
+
"POST": 1,
|
|
147
|
+
"PUT": 1,
|
|
148
|
+
"DELETE": 1
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|