@mg21st/dev-assist 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/.eslintrc.json +17 -0
- package/.github/workflows/ci.yml +42 -0
- package/.github/workflows/docs.yml +49 -0
- package/.github/workflows/publish.yml +49 -0
- package/README.md +117 -0
- package/bin/dev-assist.js +4 -0
- package/dev-assist.config.js +10 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +133 -0
- package/dist/cli/wizard.d.ts +5 -0
- package/dist/cli/wizard.d.ts.map +1 -0
- package/dist/cli/wizard.js +66 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +62 -0
- package/dist/generators/docsGenerator.d.ts +15 -0
- package/dist/generators/docsGenerator.d.ts.map +1 -0
- package/dist/generators/docsGenerator.js +186 -0
- package/dist/generators/testGenerator.d.ts +12 -0
- package/dist/generators/testGenerator.d.ts.map +1 -0
- package/dist/generators/testGenerator.js +185 -0
- package/dist/parser/astParser.d.ts +7 -0
- package/dist/parser/astParser.d.ts.map +1 -0
- package/dist/parser/astParser.js +194 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +247 -0
- package/dist/shared/types.d.ts +77 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +3 -0
- package/docs/_config.yml +22 -0
- package/docs/api-reference.md +173 -0
- package/docs/architecture.md +90 -0
- package/docs/configuration.md +52 -0
- package/docs/contributing.md +101 -0
- package/docs/index.md +50 -0
- package/docs/installation.md +95 -0
- package/docs/usage.md +107 -0
- package/package.json +58 -0
- package/src/cli/index.ts +108 -0
- package/src/cli/wizard.ts +63 -0
- package/src/config.ts +29 -0
- package/src/generators/docsGenerator.ts +192 -0
- package/src/generators/testGenerator.ts +174 -0
- package/src/parser/astParser.ts +172 -0
- package/src/server/index.ts +238 -0
- package/src/shared/types.ts +83 -0
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +19 -0
- package/ui/index.html +13 -0
- package/ui/package-lock.json +3086 -0
- package/ui/package.json +31 -0
- package/ui/postcss.config.js +6 -0
- package/ui/src/App.tsx +36 -0
- package/ui/src/components/ApiDocsTab.tsx +184 -0
- package/ui/src/components/ApiTestingTab.tsx +363 -0
- package/ui/src/components/Dashboard.tsx +128 -0
- package/ui/src/components/Layout.tsx +76 -0
- package/ui/src/components/TestsTab.tsx +149 -0
- package/ui/src/main.tsx +10 -0
- package/ui/src/styles/index.css +41 -0
- package/ui/tailwind.config.js +20 -0
- package/ui/tsconfig.json +19 -0
- package/ui/vite.config.ts +19 -0
|
@@ -0,0 +1,247 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.startServer = startServer;
|
|
40
|
+
const express_1 = __importDefault(require("express"));
|
|
41
|
+
const cors_1 = __importDefault(require("cors"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const http_1 = require("http");
|
|
45
|
+
const socket_io_1 = require("socket.io");
|
|
46
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
47
|
+
const open_1 = __importDefault(require("open"));
|
|
48
|
+
const chokidar_1 = __importDefault(require("chokidar"));
|
|
49
|
+
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
50
|
+
const astParser_1 = require("../parser/astParser");
|
|
51
|
+
const testGenerator_1 = require("../generators/testGenerator");
|
|
52
|
+
const docsGenerator_1 = require("../generators/docsGenerator");
|
|
53
|
+
const config_1 = require("../config");
|
|
54
|
+
async function startServer(options) {
|
|
55
|
+
const app = (0, express_1.default)();
|
|
56
|
+
const httpServer = (0, http_1.createServer)(app);
|
|
57
|
+
const io = new socket_io_1.Server(httpServer, { cors: { origin: '*' } });
|
|
58
|
+
const config = await (0, config_1.loadConfig)();
|
|
59
|
+
app.use((0, cors_1.default)());
|
|
60
|
+
app.use(express_1.default.json());
|
|
61
|
+
// Rate limiter: max 60 requests per minute per IP for API routes
|
|
62
|
+
const apiLimiter = (0, express_rate_limit_1.default)({
|
|
63
|
+
windowMs: 60000,
|
|
64
|
+
max: 60,
|
|
65
|
+
standardHeaders: true,
|
|
66
|
+
legacyHeaders: false,
|
|
67
|
+
message: { error: 'Too many requests, please try again later.' },
|
|
68
|
+
});
|
|
69
|
+
const uiDistPath = path.join(__dirname, '../../ui/dist');
|
|
70
|
+
if (fs.existsSync(uiDistPath)) {
|
|
71
|
+
app.use(express_1.default.static(uiDistPath));
|
|
72
|
+
}
|
|
73
|
+
const parser = new astParser_1.AstParser();
|
|
74
|
+
const testGenerator = new testGenerator_1.TestGenerator();
|
|
75
|
+
const docsGenerator = new docsGenerator_1.DocsGenerator();
|
|
76
|
+
app.get('/api/summary', apiLimiter, async (_req, res) => {
|
|
77
|
+
try {
|
|
78
|
+
const sourceDir = config.sourceDir || './src';
|
|
79
|
+
const parsedFiles = await parser.parseDirectory(path.resolve(process.cwd(), sourceDir));
|
|
80
|
+
let totalFunctions = 0;
|
|
81
|
+
let totalRoutes = 0;
|
|
82
|
+
for (const file of parsedFiles) {
|
|
83
|
+
totalFunctions += file.functions.length;
|
|
84
|
+
totalRoutes += file.routes.length;
|
|
85
|
+
}
|
|
86
|
+
res.json({
|
|
87
|
+
totalFiles: parsedFiles.length,
|
|
88
|
+
totalFunctions,
|
|
89
|
+
totalRoutes,
|
|
90
|
+
totalTests: 0,
|
|
91
|
+
generatedAt: new Date().toISOString(),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
res.status(500).json({ error: String(error) });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
app.get('/api/files', apiLimiter, async (_req, res) => {
|
|
99
|
+
try {
|
|
100
|
+
const sourceDir = config.sourceDir || './src';
|
|
101
|
+
const parsedFiles = await parser.parseDirectory(path.resolve(process.cwd(), sourceDir));
|
|
102
|
+
res.json(parsedFiles);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
res.status(500).json({ error: String(error) });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
app.post('/api/generate/tests', apiLimiter, async (req, res) => {
|
|
109
|
+
try {
|
|
110
|
+
const { sourceDir, outputDir, framework } = req.body;
|
|
111
|
+
const generated = await testGenerator.generate({
|
|
112
|
+
sourceDir: sourceDir || config.sourceDir || './src',
|
|
113
|
+
outputDir: outputDir || config.testOutputDir || './__tests__',
|
|
114
|
+
framework: (framework || config.testFramework || 'jest'),
|
|
115
|
+
});
|
|
116
|
+
res.json({ success: true, files: generated });
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
res.status(500).json({ error: String(error) });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
app.post('/api/generate/docs', apiLimiter, async (req, res) => {
|
|
123
|
+
try {
|
|
124
|
+
const { sourceDir, outputDir } = req.body;
|
|
125
|
+
const doc = await docsGenerator.generate({
|
|
126
|
+
sourceDir: sourceDir || config.sourceDir || './src',
|
|
127
|
+
outputDir: outputDir || config.docsOutputDir || './docs',
|
|
128
|
+
baseUrl: config.baseUrl,
|
|
129
|
+
});
|
|
130
|
+
res.json({ success: true, doc });
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
res.status(500).json({ error: String(error) });
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
app.get('/api/docs', apiLimiter, async (_req, res) => {
|
|
137
|
+
try {
|
|
138
|
+
const docsPath = path.join(process.cwd(), config.docsOutputDir || './docs', 'api-docs.json');
|
|
139
|
+
if (fs.existsSync(docsPath)) {
|
|
140
|
+
const docs = JSON.parse(fs.readFileSync(docsPath, 'utf-8'));
|
|
141
|
+
res.json(docs);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
res.json({ endpoints: [], title: 'API Documentation', version: '1.0.0', baseUrl: config.baseUrl });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
res.status(500).json({ error: String(error) });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
app.get('/api/tests', apiLimiter, async (_req, res) => {
|
|
152
|
+
try {
|
|
153
|
+
const testDir = path.join(process.cwd(), config.testOutputDir || './__tests__');
|
|
154
|
+
const tests = [];
|
|
155
|
+
if (fs.existsSync(testDir)) {
|
|
156
|
+
const getTestFiles = (dir) => {
|
|
157
|
+
const files = [];
|
|
158
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
159
|
+
for (const entry of entries) {
|
|
160
|
+
const fullPath = path.join(dir, entry.name);
|
|
161
|
+
if (entry.isDirectory())
|
|
162
|
+
files.push(...getTestFiles(fullPath));
|
|
163
|
+
else if (entry.isFile() && entry.name.includes('.test.'))
|
|
164
|
+
files.push(fullPath);
|
|
165
|
+
}
|
|
166
|
+
return files;
|
|
167
|
+
};
|
|
168
|
+
const testFiles = getTestFiles(testDir);
|
|
169
|
+
for (const file of testFiles) {
|
|
170
|
+
tests.push({
|
|
171
|
+
filePath: path.relative(process.cwd(), file),
|
|
172
|
+
content: fs.readFileSync(file, 'utf-8'),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
res.json(tests);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
res.status(500).json({ error: String(error) });
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
app.post('/api/proxy', async (req, res) => {
|
|
183
|
+
try {
|
|
184
|
+
const { url, method, headers, body } = req.body;
|
|
185
|
+
const startTime = Date.now();
|
|
186
|
+
const fetchOptions = {
|
|
187
|
+
method: method || 'GET',
|
|
188
|
+
headers: {
|
|
189
|
+
'Content-Type': 'application/json',
|
|
190
|
+
...(headers || {}),
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
if (body && ['POST', 'PUT', 'PATCH'].includes(method?.toUpperCase() || '')) {
|
|
194
|
+
fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
|
|
195
|
+
}
|
|
196
|
+
const response = await fetch(url, fetchOptions);
|
|
197
|
+
const responseTime = Date.now() - startTime;
|
|
198
|
+
let responseData;
|
|
199
|
+
const contentType = response.headers.get('content-type') || '';
|
|
200
|
+
if (contentType.includes('application/json')) {
|
|
201
|
+
responseData = await response.json();
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
responseData = await response.text();
|
|
205
|
+
}
|
|
206
|
+
res.json({
|
|
207
|
+
status: response.status,
|
|
208
|
+
statusText: response.statusText,
|
|
209
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
210
|
+
data: responseData,
|
|
211
|
+
responseTime,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
res.status(500).json({ error: String(error) });
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
app.get('*', apiLimiter, (_req, res) => {
|
|
219
|
+
const indexPath = path.join(__dirname, '../../ui/dist/index.html');
|
|
220
|
+
if (fs.existsSync(indexPath)) {
|
|
221
|
+
res.sendFile(indexPath);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
res.json({ message: 'DevAssist API Server', status: 'running' });
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
if (config.watchMode) {
|
|
228
|
+
const watcher = chokidar_1.default.watch(config.sourceDir || './src', {
|
|
229
|
+
ignored: /node_modules/,
|
|
230
|
+
persistent: true,
|
|
231
|
+
});
|
|
232
|
+
watcher.on('change', (filePath) => {
|
|
233
|
+
io.emit('file-changed', { filePath });
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
io.on('connection', (socket) => {
|
|
237
|
+
socket.emit('connected', { message: 'DevAssist server connected' });
|
|
238
|
+
});
|
|
239
|
+
httpServer.listen(options.port, () => {
|
|
240
|
+
console.log(chalk_1.default.green.bold(`\n✅ DevAssist UI running at http://localhost:${options.port}\n`));
|
|
241
|
+
console.log(chalk_1.default.gray('Press Ctrl+C to stop the server\n'));
|
|
242
|
+
if (options.openBrowser) {
|
|
243
|
+
(0, open_1.default)(`http://localhost:${options.port}`);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export interface ParsedFunction {
|
|
2
|
+
name: string;
|
|
3
|
+
params: string[];
|
|
4
|
+
isAsync: boolean;
|
|
5
|
+
isExported: boolean;
|
|
6
|
+
returnType?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ParsedRoute {
|
|
9
|
+
method: string;
|
|
10
|
+
path: string;
|
|
11
|
+
handler: string;
|
|
12
|
+
params: string[];
|
|
13
|
+
middleware: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface ParsedFile {
|
|
16
|
+
filePath: string;
|
|
17
|
+
functions: ParsedFunction[];
|
|
18
|
+
routes: ParsedRoute[];
|
|
19
|
+
imports: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface GeneratedTest {
|
|
22
|
+
filePath: string;
|
|
23
|
+
sourceFile: string;
|
|
24
|
+
framework: 'jest' | 'vitest';
|
|
25
|
+
content: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ApiEndpoint {
|
|
28
|
+
method: string;
|
|
29
|
+
path: string;
|
|
30
|
+
params: PathParam[];
|
|
31
|
+
queryParams: QueryParam[];
|
|
32
|
+
bodySchema?: BodySchema;
|
|
33
|
+
description?: string;
|
|
34
|
+
exampleRequest?: Record<string, unknown>;
|
|
35
|
+
exampleResponse?: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
export interface PathParam {
|
|
38
|
+
name: string;
|
|
39
|
+
type: string;
|
|
40
|
+
required: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface QueryParam {
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
required: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface BodySchema {
|
|
48
|
+
type: string;
|
|
49
|
+
properties: Record<string, {
|
|
50
|
+
type: string;
|
|
51
|
+
required?: boolean;
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
export interface ApiDoc {
|
|
55
|
+
title: string;
|
|
56
|
+
version: string;
|
|
57
|
+
baseUrl: string;
|
|
58
|
+
endpoints: ApiEndpoint[];
|
|
59
|
+
generatedAt: string;
|
|
60
|
+
}
|
|
61
|
+
export interface DevAssistConfig {
|
|
62
|
+
testFramework: 'jest' | 'vitest';
|
|
63
|
+
sourceDir: string;
|
|
64
|
+
testOutputDir: string;
|
|
65
|
+
docsOutputDir: string;
|
|
66
|
+
port: number;
|
|
67
|
+
watchMode: boolean;
|
|
68
|
+
baseUrl: string;
|
|
69
|
+
}
|
|
70
|
+
export interface ProjectSummary {
|
|
71
|
+
totalFiles: number;
|
|
72
|
+
totalFunctions: number;
|
|
73
|
+
totalRoutes: number;
|
|
74
|
+
totalTests: number;
|
|
75
|
+
generatedAt: string;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/docs/_config.yml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
title: DevAssist
|
|
2
|
+
description: All-in-one developer toolkit — Auto Test Generator, API Docs Generator & API Testing UI
|
|
3
|
+
remote_theme: just-the-docs/just-the-docs
|
|
4
|
+
|
|
5
|
+
url: https://moazzamgodil.github.io
|
|
6
|
+
baseurl: /dev-assist
|
|
7
|
+
|
|
8
|
+
aux_links:
|
|
9
|
+
"View on GitHub":
|
|
10
|
+
- "https://github.com/moazzamgodil/dev-assist"
|
|
11
|
+
|
|
12
|
+
aux_links_new_tab: true
|
|
13
|
+
|
|
14
|
+
nav_sort: case_insensitive
|
|
15
|
+
|
|
16
|
+
color_scheme: light
|
|
17
|
+
|
|
18
|
+
footer_content: "DevAssist is released under the <a href=\"https://opensource.org/licenses/MIT\">MIT License</a>."
|
|
19
|
+
|
|
20
|
+
plugins:
|
|
21
|
+
- jekyll-remote-theme
|
|
22
|
+
- jekyll-seo-tag
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: API Reference
|
|
3
|
+
nav_order: 5
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# API Reference
|
|
7
|
+
|
|
8
|
+
When you run `dev-assist serve`, an Express server starts locally. The UI communicates with this server, but you can also call these endpoints directly.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Base URL
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
http://localhost:<port>/api
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The default port is `3000`. Configure it via `--port` or `port` in `dev-assist.config.js`.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Endpoints
|
|
23
|
+
|
|
24
|
+
### GET `/api/summary`
|
|
25
|
+
|
|
26
|
+
Returns a summary of the project statistics.
|
|
27
|
+
|
|
28
|
+
**Response**
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"totalFiles": 12,
|
|
33
|
+
"totalFunctions": 47,
|
|
34
|
+
"totalRoutes": 8,
|
|
35
|
+
"testFiles": 12,
|
|
36
|
+
"docsFiles": 3
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
### GET `/api/files`
|
|
43
|
+
|
|
44
|
+
Returns the list of parsed source files.
|
|
45
|
+
|
|
46
|
+
**Response**
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
[
|
|
50
|
+
{
|
|
51
|
+
"path": "src/server/index.ts",
|
|
52
|
+
"functions": ["startServer", "setupMiddleware"],
|
|
53
|
+
"routes": ["GET /api/summary", "POST /api/generate/tests"]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### GET `/api/tests`
|
|
61
|
+
|
|
62
|
+
Returns the list of generated test files.
|
|
63
|
+
|
|
64
|
+
**Response**
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
[
|
|
68
|
+
{
|
|
69
|
+
"file": "__tests__/server/index.test.ts",
|
|
70
|
+
"content": "..."
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### GET `/api/docs`
|
|
78
|
+
|
|
79
|
+
Returns the generated API documentation.
|
|
80
|
+
|
|
81
|
+
**Response**
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
[
|
|
85
|
+
{
|
|
86
|
+
"file": "docs/api.md",
|
|
87
|
+
"content": "..."
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### POST `/api/generate/tests`
|
|
95
|
+
|
|
96
|
+
Triggers test stub generation.
|
|
97
|
+
|
|
98
|
+
**Request body**
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"source": "./src",
|
|
103
|
+
"output": "./__tests__",
|
|
104
|
+
"framework": "jest"
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Response**
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"success": true,
|
|
113
|
+
"filesGenerated": 12
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### POST `/api/generate/docs`
|
|
120
|
+
|
|
121
|
+
Triggers API documentation generation.
|
|
122
|
+
|
|
123
|
+
**Request body**
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"source": "./src",
|
|
128
|
+
"output": "./docs"
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Response**
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"success": true,
|
|
137
|
+
"filesGenerated": 3
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### POST `/api/proxy`
|
|
144
|
+
|
|
145
|
+
Proxies an HTTP request to any URL. Used by the built-in API testing client.
|
|
146
|
+
|
|
147
|
+
**Request body**
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"method": "GET",
|
|
152
|
+
"url": "http://localhost:3000/api/summary",
|
|
153
|
+
"headers": {},
|
|
154
|
+
"body": null
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Response**
|
|
159
|
+
|
|
160
|
+
The proxied response body along with status code and headers.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## WebSocket Events
|
|
165
|
+
|
|
166
|
+
DevAssist uses [Socket.IO](https://socket.io/) for real-time updates. Connect to the server on the same port:
|
|
167
|
+
|
|
168
|
+
| Event | Direction | Description |
|
|
169
|
+
|-------|-----------|-------------|
|
|
170
|
+
| `generation:start` | Server → Client | Fired when generation begins |
|
|
171
|
+
| `generation:progress` | Server → Client | Progress updates during generation |
|
|
172
|
+
| `generation:done` | Server → Client | Fired when generation completes |
|
|
173
|
+
| `generation:error` | Server → Client | Fired when generation fails |
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Architecture
|
|
3
|
+
nav_order: 6
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Architecture
|
|
7
|
+
|
|
8
|
+
## Project Layout
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
dev-assist/
|
|
12
|
+
├── bin/
|
|
13
|
+
│ └── dev-assist.js # Node.js shebang entry point (calls dist/cli/index.js)
|
|
14
|
+
├── src/
|
|
15
|
+
│ ├── cli/
|
|
16
|
+
│ │ ├── index.ts # Commander CLI — registers commands and flags
|
|
17
|
+
│ │ └── wizard.ts # Inquirer interactive wizard
|
|
18
|
+
│ ├── generators/
|
|
19
|
+
│ │ ├── testGenerator.ts # Generates Jest/Vitest test stubs from AST
|
|
20
|
+
│ │ └── docsGenerator.ts # Generates OpenAPI spec + Markdown from routes
|
|
21
|
+
│ ├── parser/
|
|
22
|
+
│ │ └── astParser.ts # Babel-based AST parser for JS/TS source files
|
|
23
|
+
│ ├── server/
|
|
24
|
+
│ │ └── index.ts # Express + Socket.IO API server
|
|
25
|
+
│ ├── shared/
|
|
26
|
+
│ │ └── types.ts # Shared TypeScript interfaces and types
|
|
27
|
+
│ └── config.ts # Config file loader (dev-assist.config.js)
|
|
28
|
+
├── ui/ # React + Vite + Tailwind frontend
|
|
29
|
+
│ ├── src/
|
|
30
|
+
│ │ ├── components/ # Reusable UI components
|
|
31
|
+
│ │ └── pages/ # Dashboard, Tests, Docs, API Tester pages
|
|
32
|
+
│ └── vite.config.ts
|
|
33
|
+
├── docs/ # This documentation site (GitHub Pages)
|
|
34
|
+
├── dev-assist.config.js # Example configuration file
|
|
35
|
+
└── package.json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Data Flow
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
User invokes CLI
|
|
44
|
+
│
|
|
45
|
+
▼
|
|
46
|
+
bin/dev-assist.js
|
|
47
|
+
│
|
|
48
|
+
▼
|
|
49
|
+
src/cli/index.ts ──── interactive? ──► src/cli/wizard.ts
|
|
50
|
+
│
|
|
51
|
+
├── generate --tests ──► src/generators/testGenerator.ts
|
|
52
|
+
│ │
|
|
53
|
+
│ └── src/parser/astParser.ts
|
|
54
|
+
│
|
|
55
|
+
├── generate --docs ──► src/generators/docsGenerator.ts
|
|
56
|
+
│ │
|
|
57
|
+
│ └── src/parser/astParser.ts
|
|
58
|
+
│
|
|
59
|
+
└── serve ──► src/server/index.ts ──► ui/ (static files)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Key Technologies
|
|
65
|
+
|
|
66
|
+
| Layer | Technology | Purpose |
|
|
67
|
+
|-------|-----------|---------|
|
|
68
|
+
| CLI | [Commander.js](https://github.com/tj/commander.js) | Argument parsing and command registration |
|
|
69
|
+
| CLI | [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) | Interactive prompts |
|
|
70
|
+
| Parser | [@babel/parser](https://babeljs.io/docs/babel-parser) | AST parsing of JS/TS source files |
|
|
71
|
+
| Parser | [@babel/traverse](https://babeljs.io/docs/babel-traverse) | AST traversal to extract functions and routes |
|
|
72
|
+
| Server | [Express](https://expressjs.com/) | REST API backend |
|
|
73
|
+
| Server | [Socket.IO](https://socket.io/) | Real-time progress events |
|
|
74
|
+
| UI | [React](https://react.dev/) | Component-based frontend |
|
|
75
|
+
| UI | [Vite](https://vitejs.dev/) | Fast bundler and dev server |
|
|
76
|
+
| UI | [Tailwind CSS](https://tailwindcss.com/) | Utility-first styling |
|
|
77
|
+
| Styling (CLI) | [Chalk](https://github.com/chalk/chalk) | Terminal colors |
|
|
78
|
+
| Styling (CLI) | [Ora](https://github.com/sindresorhus/ora) | Spinner animations |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Build Pipeline
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
npm run build
|
|
86
|
+
├── tsc -p tsconfig.build.json → dist/ (CLI + server)
|
|
87
|
+
└── cd ui && npm run build → ui/dist/ (React app)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The compiled UI assets are served as static files by the Express server.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration
|
|
3
|
+
nav_order: 4
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Configuration
|
|
7
|
+
|
|
8
|
+
DevAssist looks for a `dev-assist.config.js` file in the root of your project. If the file is absent, built-in defaults are used.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Creating the Config File
|
|
13
|
+
|
|
14
|
+
Run the interactive wizard and it will offer to create the file, or create it manually:
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
// dev-assist.config.js
|
|
18
|
+
module.exports = {
|
|
19
|
+
testFramework: 'jest', // 'jest' | 'vitest'
|
|
20
|
+
sourceDir: './src',
|
|
21
|
+
testOutputDir: './__tests__',
|
|
22
|
+
docsOutputDir: './docs',
|
|
23
|
+
port: 3000,
|
|
24
|
+
watchMode: false,
|
|
25
|
+
baseUrl: 'http://localhost:3000',
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Options Reference
|
|
32
|
+
|
|
33
|
+
| Option | Type | Default | Description |
|
|
34
|
+
|--------|------|---------|-------------|
|
|
35
|
+
| `testFramework` | `string` | `'jest'` | Test framework to use for generated stubs. Accepts `'jest'` or `'vitest'`. |
|
|
36
|
+
| `sourceDir` | `string` | `'./src'` | Directory containing your source files to parse. |
|
|
37
|
+
| `testOutputDir` | `string` | `'./__tests__'` | Directory where generated test files are written. |
|
|
38
|
+
| `docsOutputDir` | `string` | `'./docs'` | Directory where generated API documentation is written. |
|
|
39
|
+
| `port` | `number` | `3000` | Port for the local UI server (`dev-assist serve`). |
|
|
40
|
+
| `watchMode` | `boolean` | `false` | When `true`, re-generates output automatically when source files change. |
|
|
41
|
+
| `baseUrl` | `string` | `'http://localhost:3000'` | Base URL used by the built-in HTTP client for API testing. |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## CLI Flags vs Config File
|
|
46
|
+
|
|
47
|
+
CLI flags always override values from `dev-assist.config.js`. This allows you to keep default settings in the config file while overriding specific values for one-off runs:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Use config defaults except for the port
|
|
51
|
+
dev-assist serve --port 4000
|
|
52
|
+
```
|