@claudetools/tools 0.8.10 → 0.9.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/codedna/generators/astro.d.ts +18 -0
- package/dist/codedna/generators/astro.js +91 -0
- package/dist/codedna/generators/authjs.d.ts +18 -0
- package/dist/codedna/generators/authjs.js +68 -0
- package/dist/codedna/generators/better-auth.d.ts +18 -0
- package/dist/codedna/generators/better-auth.js +62 -0
- package/dist/codedna/generators/drizzle-orm.d.ts +18 -0
- package/dist/codedna/generators/drizzle-orm.js +65 -0
- package/dist/codedna/generators/elysia-api.d.ts +12 -0
- package/dist/codedna/generators/elysia-api.js +64 -0
- package/dist/codedna/generators/hono-api.d.ts +12 -0
- package/dist/codedna/generators/hono-api.js +64 -0
- package/dist/codedna/generators/lucia-auth.d.ts +18 -0
- package/dist/codedna/generators/lucia-auth.js +69 -0
- package/dist/codedna/generators/prisma.d.ts +18 -0
- package/dist/codedna/generators/prisma.js +64 -0
- package/dist/codedna/generators/react-router-v7.d.ts +18 -0
- package/dist/codedna/generators/react-router-v7.js +77 -0
- package/dist/codedna/generators/react19-shadcn.d.ts +21 -0
- package/dist/codedna/generators/react19-shadcn.js +367 -0
- package/dist/codedna/generators/sveltekit.d.ts +18 -0
- package/dist/codedna/generators/sveltekit.js +73 -0
- package/dist/codedna/generators/tanstack-start-drizzle.d.ts +92 -0
- package/dist/codedna/generators/tanstack-start-drizzle.js +824 -0
- package/dist/codedna/generators/trpc-api.d.ts +12 -0
- package/dist/codedna/generators/trpc-api.js +64 -0
- package/dist/codedna/index.d.ts +31 -0
- package/dist/codedna/index.js +39 -0
- package/dist/codedna/kappa-api-generator.d.ts +89 -0
- package/dist/codedna/kappa-api-generator.js +493 -0
- package/dist/codedna/kappa-ast.d.ts +552 -0
- package/dist/codedna/kappa-ast.js +141 -0
- package/dist/codedna/kappa-cli.d.ts +2 -0
- package/dist/codedna/kappa-cli.js +302 -0
- package/dist/codedna/kappa-component-generator.d.ts +47 -0
- package/dist/codedna/kappa-component-generator.js +295 -0
- package/dist/codedna/kappa-design-generator.d.ts +52 -0
- package/dist/codedna/kappa-design-generator.js +365 -0
- package/dist/codedna/kappa-drizzle-generator.d.ts +45 -0
- package/dist/codedna/kappa-drizzle-generator.js +355 -0
- package/dist/codedna/kappa-form-generator.d.ts +51 -0
- package/dist/codedna/kappa-form-generator.js +319 -0
- package/dist/codedna/kappa-lexer.d.ts +268 -0
- package/dist/codedna/kappa-lexer.js +757 -0
- package/dist/codedna/kappa-page-generator.d.ts +57 -0
- package/dist/codedna/kappa-page-generator.js +338 -0
- package/dist/codedna/kappa-parser.d.ts +261 -0
- package/dist/codedna/kappa-parser.js +2547 -0
- package/dist/codedna/kappa-provenance.d.ts +101 -0
- package/dist/codedna/kappa-provenance.js +199 -0
- package/dist/codedna/kappa-types-generator.d.ts +37 -0
- package/dist/codedna/kappa-types-generator.js +159 -0
- package/dist/codedna/kappa-validator.d.ts +86 -0
- package/dist/codedna/kappa-validator.js +638 -0
- package/dist/codedna/kappa-zod-generator.d.ts +32 -0
- package/dist/codedna/kappa-zod-generator.js +216 -0
- package/dist/handlers/codedna-handlers.d.ts +1 -1
- package/dist/handlers/kappa-handlers.d.ts +116 -0
- package/dist/handlers/kappa-handlers.js +465 -0
- package/dist/handlers/tool-handlers.js +121 -0
- package/dist/templates/claude-md.d.ts +1 -1
- package/dist/templates/claude-md.js +166 -9
- package/dist/tools.js +199 -0
- package/docs/research/2026-01-02-codedna-il-specification.md +639 -0
- package/docs/research/2026-01-02-codedna-v2-research.md +943 -0
- package/docs/research/2026-01-02-computation-foundations.md +564 -0
- package/docs/research/2026-01-02-hardware-description.md +814 -0
- package/docs/research/2026-01-02-kappa-specification.md +697 -0
- package/docs/research/2026-01-02-kappa-tanstack-example.md +527 -0
- package/docs/research/2026-01-02-kappa-v2-synthesis.md +406 -0
- package/docs/research/2026-01-02-kappa-v2.5-specification.md +1218 -0
- package/docs/research/2026-01-02-kappa-v3-specification.md +1864 -0
- package/docs/research/2026-01-02-kappa-whitepaper.md +662 -0
- package/docs/research/2026-01-02-logic-constraint.md +731 -0
- package/docs/research/2026-01-02-quantum-computation.md +635 -0
- package/package.json +4 -2
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Kappa v2.5 API Generator
|
|
3
|
+
// =============================================================================
|
|
4
|
+
//
|
|
5
|
+
// Generates API route handlers from Kappa API blocks.
|
|
6
|
+
// Supports multiple frameworks: Express, Hono, tRPC.
|
|
7
|
+
//
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// CRUD Action to HTTP Method Mapping
|
|
10
|
+
// =============================================================================
|
|
11
|
+
const CRUD_METHOD_MAP = {
|
|
12
|
+
create: 'post',
|
|
13
|
+
read: 'get',
|
|
14
|
+
update: 'patch',
|
|
15
|
+
delete: 'delete',
|
|
16
|
+
list: 'get',
|
|
17
|
+
};
|
|
18
|
+
const CRUD_PATH_SUFFIX = {
|
|
19
|
+
create: '',
|
|
20
|
+
read: '/:id',
|
|
21
|
+
update: '/:id',
|
|
22
|
+
delete: '/:id',
|
|
23
|
+
list: '',
|
|
24
|
+
};
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Type Mappings
|
|
27
|
+
// =============================================================================
|
|
28
|
+
const PRIMITIVE_ZOD_MAP = {
|
|
29
|
+
string: 'z.string()',
|
|
30
|
+
int: 'z.number().int()',
|
|
31
|
+
float: 'z.number()',
|
|
32
|
+
bool: 'z.boolean()',
|
|
33
|
+
email: 'z.string().email()',
|
|
34
|
+
url: 'z.string().url()',
|
|
35
|
+
uuid: 'z.string().uuid()',
|
|
36
|
+
phone: 'z.string()',
|
|
37
|
+
slug: 'z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)',
|
|
38
|
+
markdown: 'z.string()',
|
|
39
|
+
json: 'z.record(z.unknown())',
|
|
40
|
+
timestamp: 'z.string().datetime()',
|
|
41
|
+
date: 'z.string().date()',
|
|
42
|
+
time: 'z.string().time()',
|
|
43
|
+
duration: 'z.string()',
|
|
44
|
+
};
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// Generator Class
|
|
47
|
+
// =============================================================================
|
|
48
|
+
export class KappaAPIGenerator {
|
|
49
|
+
framework;
|
|
50
|
+
provenance;
|
|
51
|
+
validation;
|
|
52
|
+
errorTypes;
|
|
53
|
+
basePath;
|
|
54
|
+
authMiddleware;
|
|
55
|
+
openapi;
|
|
56
|
+
constructor(options = {}) {
|
|
57
|
+
this.framework = options.framework ?? 'hono';
|
|
58
|
+
this.provenance = options.provenance ?? true;
|
|
59
|
+
this.validation = options.validation ?? true;
|
|
60
|
+
this.errorTypes = options.errorTypes ?? true;
|
|
61
|
+
this.basePath = options.basePath ?? '/api';
|
|
62
|
+
this.authMiddleware = options.authMiddleware ?? 'requireAuth';
|
|
63
|
+
this.openapi = options.openapi ?? false;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generate API code from API blocks
|
|
67
|
+
*/
|
|
68
|
+
generate(apis) {
|
|
69
|
+
const routes = this.generateRoutes(apis);
|
|
70
|
+
const result = { routes };
|
|
71
|
+
if (this.validation) {
|
|
72
|
+
result.validation = this.generateValidation(apis);
|
|
73
|
+
}
|
|
74
|
+
if (this.errorTypes) {
|
|
75
|
+
result.errors = this.generateErrors(apis);
|
|
76
|
+
}
|
|
77
|
+
if (this.openapi) {
|
|
78
|
+
result.openapi = this.generateOpenAPI(apis);
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
// ===========================================================================
|
|
83
|
+
// Route Analysis
|
|
84
|
+
// ===========================================================================
|
|
85
|
+
/**
|
|
86
|
+
* Extract all routes from API blocks
|
|
87
|
+
*/
|
|
88
|
+
extractRoutes(apis) {
|
|
89
|
+
const routes = [];
|
|
90
|
+
for (const api of apis) {
|
|
91
|
+
const apiPath = `${this.basePath}/${this.toKebabCase(api.name)}`;
|
|
92
|
+
// Process explicit operations
|
|
93
|
+
for (const op of api.operations) {
|
|
94
|
+
routes.push(this.operationToRoute(op, apiPath));
|
|
95
|
+
}
|
|
96
|
+
// Process CRUD shorthands
|
|
97
|
+
for (const crud of api.crud) {
|
|
98
|
+
routes.push(...this.crudToRoutes(crud, apiPath));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return routes;
|
|
102
|
+
}
|
|
103
|
+
operationToRoute(op, apiPath) {
|
|
104
|
+
// Determine HTTP method from operation name patterns
|
|
105
|
+
const method = this.inferMethod(op.name);
|
|
106
|
+
const path = `${apiPath}/${this.toKebabCase(op.name)}`;
|
|
107
|
+
return {
|
|
108
|
+
method,
|
|
109
|
+
path,
|
|
110
|
+
handlerName: `handle${this.toPascalCase(op.name)}`,
|
|
111
|
+
operationName: op.name,
|
|
112
|
+
effects: op.effects,
|
|
113
|
+
requiresAuth: op.effects.includes('Auth'),
|
|
114
|
+
parameters: op.parameters,
|
|
115
|
+
check: op.check,
|
|
116
|
+
rateLimit: op.rateLimit,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
crudToRoutes(crud, apiPath) {
|
|
120
|
+
const routes = [];
|
|
121
|
+
const entityPath = `${apiPath}/${this.toKebabCase(crud.entity)}s`;
|
|
122
|
+
for (const action of crud.actions) {
|
|
123
|
+
const method = CRUD_METHOD_MAP[action.action] ?? 'get';
|
|
124
|
+
const pathSuffix = CRUD_PATH_SUFFIX[action.action] ?? '';
|
|
125
|
+
routes.push({
|
|
126
|
+
method,
|
|
127
|
+
path: `${entityPath}${pathSuffix}`,
|
|
128
|
+
handlerName: `handle${this.toPascalCase(action.action)}${crud.entity}`,
|
|
129
|
+
operationName: `${action.action}${crud.entity}`,
|
|
130
|
+
effects: action.effects,
|
|
131
|
+
requiresAuth: action.effects.includes('Auth'),
|
|
132
|
+
parameters: [],
|
|
133
|
+
check: action.check,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return routes;
|
|
137
|
+
}
|
|
138
|
+
inferMethod(operationName) {
|
|
139
|
+
const name = operationName.toLowerCase();
|
|
140
|
+
if (name.startsWith('get') ||
|
|
141
|
+
name.startsWith('list') ||
|
|
142
|
+
name.startsWith('find') ||
|
|
143
|
+
name.startsWith('health') ||
|
|
144
|
+
name.startsWith('check') ||
|
|
145
|
+
name.startsWith('fetch') ||
|
|
146
|
+
name.startsWith('search')) {
|
|
147
|
+
return 'get';
|
|
148
|
+
}
|
|
149
|
+
if (name.startsWith('create') || name.startsWith('add') || name.startsWith('register')) {
|
|
150
|
+
return 'post';
|
|
151
|
+
}
|
|
152
|
+
if (name.startsWith('update') || name.startsWith('edit') || name.startsWith('modify')) {
|
|
153
|
+
return 'patch';
|
|
154
|
+
}
|
|
155
|
+
if (name.startsWith('delete') || name.startsWith('remove')) {
|
|
156
|
+
return 'delete';
|
|
157
|
+
}
|
|
158
|
+
// Default to POST for actions like login, signup, etc.
|
|
159
|
+
return 'post';
|
|
160
|
+
}
|
|
161
|
+
// ===========================================================================
|
|
162
|
+
// Route Generation
|
|
163
|
+
// ===========================================================================
|
|
164
|
+
generateRoutes(apis) {
|
|
165
|
+
switch (this.framework) {
|
|
166
|
+
case 'hono':
|
|
167
|
+
return this.generateHonoRoutes(apis);
|
|
168
|
+
case 'express':
|
|
169
|
+
return this.generateExpressRoutes(apis);
|
|
170
|
+
case 'trpc':
|
|
171
|
+
return this.generateTRPCRoutes(apis);
|
|
172
|
+
default:
|
|
173
|
+
return this.generateHonoRoutes(apis);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
generateHonoRoutes(apis) {
|
|
177
|
+
const lines = [];
|
|
178
|
+
const routes = this.extractRoutes(apis);
|
|
179
|
+
// Header
|
|
180
|
+
if (this.provenance) {
|
|
181
|
+
lines.push('// Generated by Kappa v2.5 CodeDNA');
|
|
182
|
+
lines.push(`// Framework: Hono`);
|
|
183
|
+
lines.push('');
|
|
184
|
+
}
|
|
185
|
+
// Imports
|
|
186
|
+
lines.push("import { Hono } from 'hono';");
|
|
187
|
+
if (this.validation) {
|
|
188
|
+
lines.push("import { zValidator } from '@hono/zod-validator';");
|
|
189
|
+
lines.push("import * as schemas from './validation.js';");
|
|
190
|
+
}
|
|
191
|
+
lines.push(`import { ${this.authMiddleware} } from '../middleware/auth.js';`);
|
|
192
|
+
lines.push('');
|
|
193
|
+
// Create app
|
|
194
|
+
lines.push('const app = new Hono();');
|
|
195
|
+
lines.push('');
|
|
196
|
+
// Generate route handlers
|
|
197
|
+
for (const route of routes) {
|
|
198
|
+
lines.push(this.generateHonoRoute(route));
|
|
199
|
+
lines.push('');
|
|
200
|
+
}
|
|
201
|
+
lines.push('export default app;');
|
|
202
|
+
lines.push('');
|
|
203
|
+
return lines.join('\n');
|
|
204
|
+
}
|
|
205
|
+
generateHonoRoute(route) {
|
|
206
|
+
const lines = [];
|
|
207
|
+
const middlewares = [];
|
|
208
|
+
// Auth middleware
|
|
209
|
+
if (route.requiresAuth) {
|
|
210
|
+
middlewares.push(this.authMiddleware);
|
|
211
|
+
}
|
|
212
|
+
// Validation middleware
|
|
213
|
+
if (this.validation && route.parameters.length > 0) {
|
|
214
|
+
const schemaName = `${route.operationName}Schema`;
|
|
215
|
+
middlewares.push(`zValidator('json', schemas.${schemaName})`);
|
|
216
|
+
}
|
|
217
|
+
// Build middleware string
|
|
218
|
+
const middlewareStr = middlewares.length > 0 ? middlewares.join(', ') + ', ' : '';
|
|
219
|
+
// Route definition
|
|
220
|
+
lines.push(`// ${route.operationName}`);
|
|
221
|
+
if (route.check) {
|
|
222
|
+
lines.push(`// Permission check: ${route.check}`);
|
|
223
|
+
}
|
|
224
|
+
lines.push(`app.${route.method}('${route.path}', ${middlewareStr}async (c) => {`);
|
|
225
|
+
lines.push(` // TODO: Implement ${route.operationName}`);
|
|
226
|
+
// Generate effect comments
|
|
227
|
+
if (route.effects.length > 0) {
|
|
228
|
+
lines.push(` // Effects: ${route.effects.join(', ')}`);
|
|
229
|
+
}
|
|
230
|
+
lines.push(` return c.json({ message: 'Not implemented' }, 501);`);
|
|
231
|
+
lines.push('});');
|
|
232
|
+
return lines.join('\n');
|
|
233
|
+
}
|
|
234
|
+
generateExpressRoutes(apis) {
|
|
235
|
+
const lines = [];
|
|
236
|
+
const routes = this.extractRoutes(apis);
|
|
237
|
+
// Header
|
|
238
|
+
if (this.provenance) {
|
|
239
|
+
lines.push('// Generated by Kappa v2.5 CodeDNA');
|
|
240
|
+
lines.push(`// Framework: Express`);
|
|
241
|
+
lines.push('');
|
|
242
|
+
}
|
|
243
|
+
// Imports
|
|
244
|
+
lines.push("import { Router } from 'express';");
|
|
245
|
+
if (this.validation) {
|
|
246
|
+
lines.push("import { validateRequest } from '../middleware/validate.js';");
|
|
247
|
+
lines.push("import * as schemas from './validation.js';");
|
|
248
|
+
}
|
|
249
|
+
lines.push(`import { ${this.authMiddleware} } from '../middleware/auth.js';`);
|
|
250
|
+
lines.push('');
|
|
251
|
+
// Create router
|
|
252
|
+
lines.push('const router = Router();');
|
|
253
|
+
lines.push('');
|
|
254
|
+
// Generate route handlers
|
|
255
|
+
for (const route of routes) {
|
|
256
|
+
lines.push(this.generateExpressRoute(route));
|
|
257
|
+
lines.push('');
|
|
258
|
+
}
|
|
259
|
+
lines.push('export default router;');
|
|
260
|
+
lines.push('');
|
|
261
|
+
return lines.join('\n');
|
|
262
|
+
}
|
|
263
|
+
generateExpressRoute(route) {
|
|
264
|
+
const lines = [];
|
|
265
|
+
const middlewares = [];
|
|
266
|
+
// Auth middleware
|
|
267
|
+
if (route.requiresAuth) {
|
|
268
|
+
middlewares.push(this.authMiddleware);
|
|
269
|
+
}
|
|
270
|
+
// Validation middleware
|
|
271
|
+
if (this.validation && route.parameters.length > 0) {
|
|
272
|
+
const schemaName = `${route.operationName}Schema`;
|
|
273
|
+
middlewares.push(`validateRequest(schemas.${schemaName})`);
|
|
274
|
+
}
|
|
275
|
+
// Build middleware array
|
|
276
|
+
const middlewareArgs = middlewares.length > 0 ? middlewares.join(', ') + ', ' : '';
|
|
277
|
+
// Route definition
|
|
278
|
+
lines.push(`// ${route.operationName}`);
|
|
279
|
+
lines.push(`router.${route.method}('${route.path}', ${middlewareArgs}async (req, res) => {`);
|
|
280
|
+
lines.push(` // TODO: Implement ${route.operationName}`);
|
|
281
|
+
// Generate effect comments
|
|
282
|
+
if (route.effects.length > 0) {
|
|
283
|
+
lines.push(` // Effects: ${route.effects.join(', ')}`);
|
|
284
|
+
}
|
|
285
|
+
lines.push(` res.status(501).json({ message: 'Not implemented' });`);
|
|
286
|
+
lines.push('});');
|
|
287
|
+
return lines.join('\n');
|
|
288
|
+
}
|
|
289
|
+
generateTRPCRoutes(apis) {
|
|
290
|
+
const lines = [];
|
|
291
|
+
const routes = this.extractRoutes(apis);
|
|
292
|
+
// Header
|
|
293
|
+
if (this.provenance) {
|
|
294
|
+
lines.push('// Generated by Kappa v2.5 CodeDNA');
|
|
295
|
+
lines.push(`// Framework: tRPC`);
|
|
296
|
+
lines.push('');
|
|
297
|
+
}
|
|
298
|
+
// Imports
|
|
299
|
+
lines.push("import { router, publicProcedure, protectedProcedure } from '../trpc.js';");
|
|
300
|
+
if (this.validation) {
|
|
301
|
+
lines.push("import * as schemas from './validation.js';");
|
|
302
|
+
}
|
|
303
|
+
lines.push('');
|
|
304
|
+
// Create router
|
|
305
|
+
lines.push('export const apiRouter = router({');
|
|
306
|
+
// Generate procedures
|
|
307
|
+
for (let i = 0; i < routes.length; i++) {
|
|
308
|
+
const route = routes[i];
|
|
309
|
+
const isLast = i === routes.length - 1;
|
|
310
|
+
lines.push(this.generateTRPCProcedure(route, isLast));
|
|
311
|
+
}
|
|
312
|
+
lines.push('});');
|
|
313
|
+
lines.push('');
|
|
314
|
+
lines.push('export type ApiRouter = typeof apiRouter;');
|
|
315
|
+
lines.push('');
|
|
316
|
+
return lines.join('\n');
|
|
317
|
+
}
|
|
318
|
+
generateTRPCProcedure(route, isLast) {
|
|
319
|
+
const lines = [];
|
|
320
|
+
const procedure = route.requiresAuth ? 'protectedProcedure' : 'publicProcedure';
|
|
321
|
+
const isMutation = ['post', 'put', 'patch', 'delete'].includes(route.method);
|
|
322
|
+
const procedureType = isMutation ? 'mutation' : 'query';
|
|
323
|
+
lines.push(` // ${route.operationName}`);
|
|
324
|
+
lines.push(` ${route.operationName}: ${procedure}`);
|
|
325
|
+
// Add input validation
|
|
326
|
+
if (this.validation && route.parameters.length > 0) {
|
|
327
|
+
const schemaName = `${route.operationName}Schema`;
|
|
328
|
+
lines.push(` .input(schemas.${schemaName})`);
|
|
329
|
+
}
|
|
330
|
+
lines.push(` .${procedureType}(async ({ ctx, input }) => {`);
|
|
331
|
+
lines.push(` // TODO: Implement ${route.operationName}`);
|
|
332
|
+
// Generate effect comments
|
|
333
|
+
if (route.effects.length > 0) {
|
|
334
|
+
lines.push(` // Effects: ${route.effects.join(', ')}`);
|
|
335
|
+
}
|
|
336
|
+
lines.push(` throw new Error('Not implemented');`);
|
|
337
|
+
lines.push(` })${isLast ? '' : ','}`);
|
|
338
|
+
return lines.join('\n');
|
|
339
|
+
}
|
|
340
|
+
// ===========================================================================
|
|
341
|
+
// Validation Generation
|
|
342
|
+
// ===========================================================================
|
|
343
|
+
generateValidation(apis) {
|
|
344
|
+
const lines = [];
|
|
345
|
+
const routes = this.extractRoutes(apis);
|
|
346
|
+
// Header
|
|
347
|
+
if (this.provenance) {
|
|
348
|
+
lines.push('// Generated by Kappa v2.5 CodeDNA');
|
|
349
|
+
lines.push('// Validation schemas');
|
|
350
|
+
lines.push('');
|
|
351
|
+
}
|
|
352
|
+
lines.push("import { z } from 'zod';");
|
|
353
|
+
lines.push('');
|
|
354
|
+
// Generate schema for each operation with parameters
|
|
355
|
+
for (const route of routes) {
|
|
356
|
+
if (route.parameters.length > 0) {
|
|
357
|
+
lines.push(this.generateValidationSchema(route));
|
|
358
|
+
lines.push('');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return lines.join('\n');
|
|
362
|
+
}
|
|
363
|
+
generateValidationSchema(route) {
|
|
364
|
+
const lines = [];
|
|
365
|
+
const schemaName = `${route.operationName}Schema`;
|
|
366
|
+
lines.push(`export const ${schemaName} = z.object({`);
|
|
367
|
+
for (const param of route.parameters) {
|
|
368
|
+
const zodType = this.fieldTypeToZod(param.type);
|
|
369
|
+
const optional = param.optional ? '.optional()' : '';
|
|
370
|
+
lines.push(` ${param.name}: ${zodType}${optional},`);
|
|
371
|
+
}
|
|
372
|
+
lines.push('});');
|
|
373
|
+
lines.push('');
|
|
374
|
+
lines.push(`export type ${this.toPascalCase(route.operationName)}Input = z.infer<typeof ${schemaName}>;`);
|
|
375
|
+
return lines.join('\n');
|
|
376
|
+
}
|
|
377
|
+
fieldTypeToZod(type) {
|
|
378
|
+
switch (type.kind) {
|
|
379
|
+
case 'primitive':
|
|
380
|
+
return PRIMITIVE_ZOD_MAP[type.type] || 'z.unknown()';
|
|
381
|
+
case 'enum':
|
|
382
|
+
return `z.enum([${type.values.map(v => `'${v}'`).join(', ')}])`;
|
|
383
|
+
case 'reference':
|
|
384
|
+
return 'z.string().uuid()';
|
|
385
|
+
case 'array':
|
|
386
|
+
return `z.array(${this.fieldTypeToZod(type.itemType)})`;
|
|
387
|
+
default:
|
|
388
|
+
return 'z.unknown()';
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// ===========================================================================
|
|
392
|
+
// Error Types Generation
|
|
393
|
+
// ===========================================================================
|
|
394
|
+
generateErrors(apis) {
|
|
395
|
+
const lines = [];
|
|
396
|
+
const errorTypes = new Set();
|
|
397
|
+
// Collect all error types from operations
|
|
398
|
+
for (const api of apis) {
|
|
399
|
+
for (const op of api.operations) {
|
|
400
|
+
if (op.throws) {
|
|
401
|
+
for (const error of op.throws) {
|
|
402
|
+
errorTypes.add(error);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Header
|
|
408
|
+
if (this.provenance) {
|
|
409
|
+
lines.push('// Generated by Kappa v2.5 CodeDNA');
|
|
410
|
+
lines.push('// API error types');
|
|
411
|
+
lines.push('');
|
|
412
|
+
}
|
|
413
|
+
// Base error class
|
|
414
|
+
lines.push('export class APIError extends Error {');
|
|
415
|
+
lines.push(' constructor(');
|
|
416
|
+
lines.push(' public code: string,');
|
|
417
|
+
lines.push(' public status: number,');
|
|
418
|
+
lines.push(' message: string');
|
|
419
|
+
lines.push(' ) {');
|
|
420
|
+
lines.push(' super(message);');
|
|
421
|
+
lines.push(" this.name = 'APIError';");
|
|
422
|
+
lines.push(' }');
|
|
423
|
+
lines.push('}');
|
|
424
|
+
lines.push('');
|
|
425
|
+
// Generate specific error classes
|
|
426
|
+
for (const errorType of errorTypes) {
|
|
427
|
+
const className = `${errorType}Error`;
|
|
428
|
+
const status = this.inferErrorStatus(errorType);
|
|
429
|
+
lines.push(`export class ${className} extends APIError {`);
|
|
430
|
+
lines.push(` constructor(message = '${this.toSentenceCase(errorType)}') {`);
|
|
431
|
+
lines.push(` super('${errorType}', ${status}, message);`);
|
|
432
|
+
lines.push(` this.name = '${className}';`);
|
|
433
|
+
lines.push(' }');
|
|
434
|
+
lines.push('}');
|
|
435
|
+
lines.push('');
|
|
436
|
+
}
|
|
437
|
+
return lines.join('\n');
|
|
438
|
+
}
|
|
439
|
+
inferErrorStatus(errorType) {
|
|
440
|
+
const type = errorType.toLowerCase();
|
|
441
|
+
if (type.includes('notfound'))
|
|
442
|
+
return 404;
|
|
443
|
+
if (type.includes('unauthorized') || type.includes('auth'))
|
|
444
|
+
return 401;
|
|
445
|
+
if (type.includes('forbidden') || type.includes('permission'))
|
|
446
|
+
return 403;
|
|
447
|
+
if (type.includes('validation') || type.includes('invalid'))
|
|
448
|
+
return 400;
|
|
449
|
+
if (type.includes('conflict') || type.includes('duplicate'))
|
|
450
|
+
return 409;
|
|
451
|
+
if (type.includes('ratelimit'))
|
|
452
|
+
return 429;
|
|
453
|
+
return 500;
|
|
454
|
+
}
|
|
455
|
+
// ===========================================================================
|
|
456
|
+
// OpenAPI Generation (stub)
|
|
457
|
+
// ===========================================================================
|
|
458
|
+
generateOpenAPI(_apis) {
|
|
459
|
+
// TODO: Implement OpenAPI schema generation
|
|
460
|
+
return '// OpenAPI schema generation not yet implemented\n';
|
|
461
|
+
}
|
|
462
|
+
// ===========================================================================
|
|
463
|
+
// Utility Functions
|
|
464
|
+
// ===========================================================================
|
|
465
|
+
toKebabCase(str) {
|
|
466
|
+
return str
|
|
467
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
468
|
+
.replace(/[\s_]+/g, '-')
|
|
469
|
+
.toLowerCase();
|
|
470
|
+
}
|
|
471
|
+
toPascalCase(str) {
|
|
472
|
+
return str
|
|
473
|
+
.replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
|
|
474
|
+
.replace(/^./, s => s.toUpperCase());
|
|
475
|
+
}
|
|
476
|
+
toSentenceCase(str) {
|
|
477
|
+
return str
|
|
478
|
+
.replace(/([A-Z])/g, ' $1')
|
|
479
|
+
.trim()
|
|
480
|
+
.toLowerCase()
|
|
481
|
+
.replace(/^./, s => s.toUpperCase());
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
// =============================================================================
|
|
485
|
+
// Convenience Function
|
|
486
|
+
// =============================================================================
|
|
487
|
+
/**
|
|
488
|
+
* Generate API code from Kappa API blocks
|
|
489
|
+
*/
|
|
490
|
+
export function generateAPI(apis, options = {}) {
|
|
491
|
+
const generator = new KappaAPIGenerator(options);
|
|
492
|
+
return generator.generate(apis);
|
|
493
|
+
}
|