@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.
Files changed (65) hide show
  1. package/.eslintrc.json +17 -0
  2. package/.github/workflows/ci.yml +42 -0
  3. package/.github/workflows/docs.yml +49 -0
  4. package/.github/workflows/publish.yml +49 -0
  5. package/README.md +117 -0
  6. package/bin/dev-assist.js +4 -0
  7. package/dev-assist.config.js +10 -0
  8. package/dist/cli/index.d.ts +3 -0
  9. package/dist/cli/index.d.ts.map +1 -0
  10. package/dist/cli/index.js +133 -0
  11. package/dist/cli/wizard.d.ts +5 -0
  12. package/dist/cli/wizard.d.ts.map +1 -0
  13. package/dist/cli/wizard.js +66 -0
  14. package/dist/config.d.ts +3 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +62 -0
  17. package/dist/generators/docsGenerator.d.ts +15 -0
  18. package/dist/generators/docsGenerator.d.ts.map +1 -0
  19. package/dist/generators/docsGenerator.js +186 -0
  20. package/dist/generators/testGenerator.d.ts +12 -0
  21. package/dist/generators/testGenerator.d.ts.map +1 -0
  22. package/dist/generators/testGenerator.js +185 -0
  23. package/dist/parser/astParser.d.ts +7 -0
  24. package/dist/parser/astParser.d.ts.map +1 -0
  25. package/dist/parser/astParser.js +194 -0
  26. package/dist/server/index.d.ts +5 -0
  27. package/dist/server/index.d.ts.map +1 -0
  28. package/dist/server/index.js +247 -0
  29. package/dist/shared/types.d.ts +77 -0
  30. package/dist/shared/types.d.ts.map +1 -0
  31. package/dist/shared/types.js +3 -0
  32. package/docs/_config.yml +22 -0
  33. package/docs/api-reference.md +173 -0
  34. package/docs/architecture.md +90 -0
  35. package/docs/configuration.md +52 -0
  36. package/docs/contributing.md +101 -0
  37. package/docs/index.md +50 -0
  38. package/docs/installation.md +95 -0
  39. package/docs/usage.md +107 -0
  40. package/package.json +58 -0
  41. package/src/cli/index.ts +108 -0
  42. package/src/cli/wizard.ts +63 -0
  43. package/src/config.ts +29 -0
  44. package/src/generators/docsGenerator.ts +192 -0
  45. package/src/generators/testGenerator.ts +174 -0
  46. package/src/parser/astParser.ts +172 -0
  47. package/src/server/index.ts +238 -0
  48. package/src/shared/types.ts +83 -0
  49. package/tsconfig.build.json +8 -0
  50. package/tsconfig.json +19 -0
  51. package/ui/index.html +13 -0
  52. package/ui/package-lock.json +3086 -0
  53. package/ui/package.json +31 -0
  54. package/ui/postcss.config.js +6 -0
  55. package/ui/src/App.tsx +36 -0
  56. package/ui/src/components/ApiDocsTab.tsx +184 -0
  57. package/ui/src/components/ApiTestingTab.tsx +363 -0
  58. package/ui/src/components/Dashboard.tsx +128 -0
  59. package/ui/src/components/Layout.tsx +76 -0
  60. package/ui/src/components/TestsTab.tsx +149 -0
  61. package/ui/src/main.tsx +10 -0
  62. package/ui/src/styles/index.css +41 -0
  63. package/ui/tailwind.config.js +20 -0
  64. package/ui/tsconfig.json +19 -0
  65. 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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -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
+ ```