archetype-engine 2.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 (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +241 -0
  3. package/dist/src/ai/adapters/anthropic.d.ts +31 -0
  4. package/dist/src/ai/adapters/anthropic.d.ts.map +1 -0
  5. package/dist/src/ai/adapters/anthropic.js +75 -0
  6. package/dist/src/ai/adapters/openai.d.ts +33 -0
  7. package/dist/src/ai/adapters/openai.d.ts.map +1 -0
  8. package/dist/src/ai/adapters/openai.js +120 -0
  9. package/dist/src/ai/adapters/vercel.d.ts +434 -0
  10. package/dist/src/ai/adapters/vercel.d.ts.map +1 -0
  11. package/dist/src/ai/adapters/vercel.js +162 -0
  12. package/dist/src/ai/index.d.ts +492 -0
  13. package/dist/src/ai/index.d.ts.map +1 -0
  14. package/dist/src/ai/index.js +71 -0
  15. package/dist/src/ai/state.d.ts +13 -0
  16. package/dist/src/ai/state.d.ts.map +1 -0
  17. package/dist/src/ai/state.js +215 -0
  18. package/dist/src/ai/tools.d.ts +13 -0
  19. package/dist/src/ai/tools.d.ts.map +1 -0
  20. package/dist/src/ai/tools.js +257 -0
  21. package/dist/src/ai/types.d.ts +196 -0
  22. package/dist/src/ai/types.d.ts.map +1 -0
  23. package/dist/src/ai/types.js +9 -0
  24. package/dist/src/cli.d.ts +3 -0
  25. package/dist/src/cli.d.ts.map +1 -0
  26. package/dist/src/cli.js +540 -0
  27. package/dist/src/core/utils.d.ts +27 -0
  28. package/dist/src/core/utils.d.ts.map +1 -0
  29. package/dist/src/core/utils.js +56 -0
  30. package/dist/src/entity.d.ts +165 -0
  31. package/dist/src/entity.d.ts.map +1 -0
  32. package/dist/src/entity.js +108 -0
  33. package/dist/src/fields.d.ts +207 -0
  34. package/dist/src/fields.d.ts.map +1 -0
  35. package/dist/src/fields.js +291 -0
  36. package/dist/src/generators/erd-ir.d.ts +10 -0
  37. package/dist/src/generators/erd-ir.d.ts.map +1 -0
  38. package/dist/src/generators/erd-ir.js +119 -0
  39. package/dist/src/index.d.ts +51 -0
  40. package/dist/src/index.d.ts.map +1 -0
  41. package/dist/src/index.js +101 -0
  42. package/dist/src/init/dependencies.d.ts +31 -0
  43. package/dist/src/init/dependencies.d.ts.map +1 -0
  44. package/dist/src/init/dependencies.js +101 -0
  45. package/dist/src/init/entity-templates.d.ts +42 -0
  46. package/dist/src/init/entity-templates.d.ts.map +1 -0
  47. package/dist/src/init/entity-templates.js +367 -0
  48. package/dist/src/init/index.d.ts +10 -0
  49. package/dist/src/init/index.d.ts.map +1 -0
  50. package/dist/src/init/index.js +250 -0
  51. package/dist/src/init/prompts.d.ts +11 -0
  52. package/dist/src/init/prompts.d.ts.map +1 -0
  53. package/dist/src/init/prompts.js +275 -0
  54. package/dist/src/init/templates.d.ts +24 -0
  55. package/dist/src/init/templates.d.ts.map +1 -0
  56. package/dist/src/init/templates.js +587 -0
  57. package/dist/src/json/index.d.ts +11 -0
  58. package/dist/src/json/index.d.ts.map +1 -0
  59. package/dist/src/json/index.js +26 -0
  60. package/dist/src/json/parser.d.ts +61 -0
  61. package/dist/src/json/parser.d.ts.map +1 -0
  62. package/dist/src/json/parser.js +309 -0
  63. package/dist/src/json/types.d.ts +275 -0
  64. package/dist/src/json/types.d.ts.map +1 -0
  65. package/dist/src/json/types.js +10 -0
  66. package/dist/src/manifest.d.ts +147 -0
  67. package/dist/src/manifest.d.ts.map +1 -0
  68. package/dist/src/manifest.js +104 -0
  69. package/dist/src/relations.d.ts +96 -0
  70. package/dist/src/relations.d.ts.map +1 -0
  71. package/dist/src/relations.js +108 -0
  72. package/dist/src/source.d.ts +93 -0
  73. package/dist/src/source.d.ts.map +1 -0
  74. package/dist/src/source.js +89 -0
  75. package/dist/src/template/context.d.ts +34 -0
  76. package/dist/src/template/context.d.ts.map +1 -0
  77. package/dist/src/template/context.js +31 -0
  78. package/dist/src/template/index.d.ts +6 -0
  79. package/dist/src/template/index.d.ts.map +1 -0
  80. package/dist/src/template/index.js +12 -0
  81. package/dist/src/template/registry.d.ts +18 -0
  82. package/dist/src/template/registry.d.ts.map +1 -0
  83. package/dist/src/template/registry.js +89 -0
  84. package/dist/src/template/runner.d.ts +9 -0
  85. package/dist/src/template/runner.d.ts.map +1 -0
  86. package/dist/src/template/runner.js +125 -0
  87. package/dist/src/template/types.d.ts +73 -0
  88. package/dist/src/template/types.d.ts.map +1 -0
  89. package/dist/src/template/types.js +3 -0
  90. package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts +22 -0
  91. package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts.map +1 -0
  92. package/dist/src/templates/nextjs-drizzle-trpc/generators/api.js +866 -0
  93. package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts +20 -0
  94. package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts.map +1 -0
  95. package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.js +273 -0
  96. package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts +22 -0
  97. package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts.map +1 -0
  98. package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.js +237 -0
  99. package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts +30 -0
  100. package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts.map +1 -0
  101. package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.js +345 -0
  102. package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts +25 -0
  103. package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts.map +1 -0
  104. package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.js +199 -0
  105. package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts +8 -0
  106. package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts.map +1 -0
  107. package/dist/src/templates/nextjs-drizzle-trpc/generators/index.js +18 -0
  108. package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts +22 -0
  109. package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts.map +1 -0
  110. package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.js +270 -0
  111. package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts +23 -0
  112. package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts.map +1 -0
  113. package/dist/src/templates/nextjs-drizzle-trpc/generators/service.js +304 -0
  114. package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts +21 -0
  115. package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts.map +1 -0
  116. package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.js +248 -0
  117. package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts +30 -0
  118. package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts.map +1 -0
  119. package/dist/src/templates/nextjs-drizzle-trpc/index.js +71 -0
  120. package/dist/src/validation/index.d.ts +71 -0
  121. package/dist/src/validation/index.d.ts.map +1 -0
  122. package/dist/src/validation/index.js +314 -0
  123. package/package.json +86 -0
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * AI Module Types
4
+ *
5
+ * Type definitions for AI tool integrations.
6
+ *
7
+ * @module ai/types
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,540 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const http = __importStar(require("http"));
40
+ const child_process_1 = require("child_process");
41
+ const module_1 = require("module");
42
+ const erd_ir_1 = require("./generators/erd-ir");
43
+ const init_1 = require("./init");
44
+ const template_1 = require("./template");
45
+ const parser_1 = require("./json/parser");
46
+ const validation_1 = require("./validation");
47
+ const command = process.argv[2];
48
+ // Find config path - first non-flag argument after command
49
+ const args = process.argv.slice(2);
50
+ const configPath = args.find(a => a !== command && !a.startsWith('-')) || 'archetype.config.ts';
51
+ // Parse CLI flags
52
+ const templateArg = args.find(a => a.startsWith('--template='));
53
+ const templateOverride = templateArg?.split('=')[1];
54
+ const yesFlag = args.includes('--yes') || args.includes('-y');
55
+ const headlessFlag = args.includes('--headless');
56
+ const jsonOutputFlag = args.includes('--json') || args.includes('--output=json');
57
+ const stdinFlag = args.includes('--stdin');
58
+ /**
59
+ * Output helper - formats output based on --json flag
60
+ */
61
+ function output(data) {
62
+ if (jsonOutputFlag) {
63
+ console.log(JSON.stringify(data, null, 2));
64
+ }
65
+ else if (typeof data === 'string') {
66
+ console.log(data);
67
+ }
68
+ else {
69
+ console.log(data);
70
+ }
71
+ }
72
+ /**
73
+ * Error output helper
74
+ */
75
+ function errorOutput(message, data) {
76
+ if (jsonOutputFlag) {
77
+ console.log(JSON.stringify({ success: false, error: message, ...data }, null, 2));
78
+ }
79
+ else {
80
+ console.error(message);
81
+ }
82
+ }
83
+ /**
84
+ * Read JSON manifest from stdin
85
+ */
86
+ async function readStdin() {
87
+ return new Promise((resolve, reject) => {
88
+ let data = '';
89
+ process.stdin.setEncoding('utf8');
90
+ process.stdin.on('data', chunk => { data += chunk; });
91
+ process.stdin.on('end', () => resolve(data));
92
+ process.stdin.on('error', reject);
93
+ });
94
+ }
95
+ /**
96
+ * Load manifest from JSON file or string
97
+ */
98
+ function loadManifestFromJSON(jsonContent) {
99
+ try {
100
+ return (0, parser_1.parseManifestJSON)(jsonContent);
101
+ }
102
+ catch (err) {
103
+ const message = err instanceof Error ? err.message : 'Unknown error';
104
+ if (jsonOutputFlag) {
105
+ errorOutput('Failed to parse JSON manifest', { parseError: message });
106
+ process.exit(1);
107
+ }
108
+ console.error('Failed to parse JSON manifest:', message);
109
+ process.exit(1);
110
+ }
111
+ }
112
+ /**
113
+ * Load manifest from TypeScript config file or JSON file
114
+ */
115
+ function loadManifest(configFile) {
116
+ const absolutePath = path.resolve(configFile);
117
+ // Check if file exists
118
+ if (!fs.existsSync(absolutePath)) {
119
+ // Try common alternatives
120
+ const alternatives = [
121
+ 'archetype.config.ts',
122
+ 'archetype.config.js',
123
+ 'manifest.json',
124
+ 'archetype.json',
125
+ 'archetype/index.ts', // Legacy
126
+ 'archetype/index.js', // Legacy
127
+ ];
128
+ for (const alt of alternatives) {
129
+ const altPath = path.resolve(alt);
130
+ if (fs.existsSync(altPath)) {
131
+ if (!jsonOutputFlag)
132
+ console.log(`Using config: ${alt}`);
133
+ return loadManifest(alt);
134
+ }
135
+ }
136
+ if (jsonOutputFlag) {
137
+ errorOutput(`Config file not found: ${configFile}`);
138
+ process.exit(1);
139
+ }
140
+ console.error(`Config file not found: ${configFile}`);
141
+ console.error('Run "archetype init" to create one, or create manually:');
142
+ console.error(' - archetype.config.ts (TypeScript)');
143
+ console.error(' - manifest.json (JSON for AI agents)');
144
+ process.exit(1);
145
+ }
146
+ // If it's a JSON file, use JSON parser
147
+ if (absolutePath.endsWith('.json')) {
148
+ const content = fs.readFileSync(absolutePath, 'utf-8');
149
+ return loadManifestFromJSON(content);
150
+ }
151
+ // Get the config file's directory for module resolution
152
+ const configDir = path.dirname(absolutePath);
153
+ // Create a require function rooted in the project directory
154
+ // This ensures npm link and local dependencies are resolved correctly
155
+ const projectRequire = (0, module_1.createRequire)(path.join(configDir, 'package.json'));
156
+ // Clear require cache for fresh load
157
+ delete projectRequire.cache[absolutePath];
158
+ // Register TypeScript if needed
159
+ if (absolutePath.endsWith('.ts')) {
160
+ try {
161
+ // Use the project's ts-node if available, fall back to ours
162
+ let tsNode;
163
+ try {
164
+ tsNode = projectRequire('ts-node');
165
+ }
166
+ catch {
167
+ tsNode = require('ts-node');
168
+ }
169
+ tsNode.register({
170
+ transpileOnly: true,
171
+ cwd: configDir,
172
+ compilerOptions: {
173
+ module: 'commonjs',
174
+ moduleResolution: 'node',
175
+ },
176
+ });
177
+ }
178
+ catch {
179
+ // ts-node should already be registered if running via ts-node
180
+ }
181
+ }
182
+ // Load the module using the project-rooted require
183
+ const loadedModule = projectRequire(absolutePath);
184
+ const manifest = loadedModule.default || loadedModule;
185
+ if (!manifest.entities) {
186
+ console.error('Invalid manifest: missing "entities" property');
187
+ console.error('Make sure your config exports a manifest created with defineManifest()');
188
+ process.exit(1);
189
+ }
190
+ return manifest;
191
+ }
192
+ function openBrowser(url) {
193
+ const cmd = process.platform === 'darwin'
194
+ ? 'open'
195
+ : process.platform === 'win32'
196
+ ? 'start'
197
+ : 'xdg-open';
198
+ (0, child_process_1.exec)(`${cmd} "${url}"`);
199
+ }
200
+ function serveERD(mermaidCode, port = 3333, maxAttempts = 10) {
201
+ const html = buildHTML(mermaidCode);
202
+ const server = http.createServer((_, res) => {
203
+ res.writeHead(200, { 'Content-Type': 'text/html' });
204
+ res.end(html);
205
+ });
206
+ server.on('error', (err) => {
207
+ if (err.code === 'EADDRINUSE') {
208
+ const nextPort = port + 1;
209
+ if (nextPort - 3333 < maxAttempts) {
210
+ console.log(`Port ${port} is in use, trying ${nextPort}...`);
211
+ serveERD(mermaidCode, nextPort, maxAttempts);
212
+ }
213
+ else {
214
+ console.error(`Could not find an available port (tried ${3333}-${port})`);
215
+ console.error('Try killing the process using the port:');
216
+ console.error(` lsof -i :3333 | grep LISTEN | awk '{print $2}' | xargs kill -9`);
217
+ process.exit(1);
218
+ }
219
+ }
220
+ else {
221
+ console.error('Server error:', err.message);
222
+ process.exit(1);
223
+ }
224
+ });
225
+ server.listen(port, () => {
226
+ console.log(`http://localhost:${port}`);
227
+ console.log('Ctrl+C to stop');
228
+ openBrowser(`http://localhost:${port}`);
229
+ });
230
+ }
231
+ function buildHTML(mermaidCode) {
232
+ return `<!DOCTYPE html>
233
+ <html lang="en">
234
+ <head>
235
+ <meta charset="UTF-8">
236
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
237
+ <title>ERD Viewer</title>
238
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
239
+ <script src="https://cdn.jsdelivr.net/npm/panzoom@9/dist/panzoom.min.js"></script>
240
+ <style>
241
+ * { margin: 0; padding: 0; box-sizing: border-box; }
242
+ body {
243
+ background: #0d1117;
244
+ width: 100vw;
245
+ height: 100vh;
246
+ overflow: hidden;
247
+ }
248
+ #container {
249
+ width: 100%;
250
+ height: 100%;
251
+ }
252
+ #diagram {
253
+ display: inline-block;
254
+ padding: 48px;
255
+ }
256
+ #diagram svg {
257
+ display: block;
258
+ }
259
+ </style>
260
+ </head>
261
+ <body>
262
+ <div id="container">
263
+ <div id="diagram">
264
+ <pre class="mermaid">${mermaidCode}</pre>
265
+ </div>
266
+ </div>
267
+ <script>
268
+ mermaid.initialize({
269
+ startOnLoad: true,
270
+ theme: 'dark',
271
+ er: { useMaxWidth: false }
272
+ });
273
+
274
+ window.addEventListener('load', () => {
275
+ setTimeout(() => {
276
+ const diagram = document.getElementById('diagram');
277
+ const rect = diagram.getBoundingClientRect();
278
+
279
+ const padding = 64;
280
+ const scaleX = (window.innerWidth - padding * 2) / rect.width;
281
+ const scaleY = (window.innerHeight - padding * 2) / rect.height;
282
+ const scale = Math.min(scaleX, scaleY, 1);
283
+
284
+ const instance = panzoom(diagram, {
285
+ maxZoom: 5,
286
+ minZoom: 0.05,
287
+ bounds: false
288
+ });
289
+
290
+ instance.zoomAbs(0, 0, scale);
291
+
292
+ setTimeout(() => {
293
+ const newRect = diagram.getBoundingClientRect();
294
+ const x = (window.innerWidth - newRect.width) / 2;
295
+ const y = (window.innerHeight - newRect.height) / 2;
296
+ instance.moveTo(x, y);
297
+ }, 50);
298
+ }, 300);
299
+ });
300
+ </script>
301
+ </body>
302
+ </html>`;
303
+ }
304
+ async function runGenerate(manifest) {
305
+ // Determine template: CLI flag > config > error
306
+ const templateId = templateOverride || manifest.template;
307
+ if (!templateId) {
308
+ if (jsonOutputFlag) {
309
+ errorOutput('No template specified', {
310
+ suggestion: 'Add template to config or use --template flag',
311
+ availableTemplates: (0, template_1.listTemplates)().map(t => t.id),
312
+ });
313
+ process.exit(1);
314
+ }
315
+ console.error('No template specified.');
316
+ console.error('');
317
+ console.error('Either:');
318
+ console.error(' 1. Set "template" in archetype.config.ts');
319
+ console.error(' 2. Use --template flag: archetype generate --template=nextjs-drizzle-trpc');
320
+ console.error('');
321
+ console.error('Available templates:');
322
+ for (const t of (0, template_1.listTemplates)()) {
323
+ console.error(` - ${t.id}: ${t.description}`);
324
+ }
325
+ process.exit(1);
326
+ }
327
+ if (!jsonOutputFlag) {
328
+ console.log(`Generating with template: ${templateId}`);
329
+ console.log(`Entities: ${manifest.entities.map(e => e.name).join(', ')}`);
330
+ console.log('');
331
+ }
332
+ // Get template from registry
333
+ const template = await (0, template_1.getTemplate)(templateId);
334
+ if (!template) {
335
+ if (jsonOutputFlag) {
336
+ errorOutput(`Template not found: ${templateId}`, {
337
+ availableTemplates: (0, template_1.listTemplates)().map(t => t.id),
338
+ });
339
+ process.exit(1);
340
+ }
341
+ console.error(`Template not found: ${templateId}`);
342
+ console.error('');
343
+ console.error('Available templates:');
344
+ for (const t of (0, template_1.listTemplates)()) {
345
+ console.error(` - ${t.id}: ${t.description}`);
346
+ }
347
+ process.exit(1);
348
+ }
349
+ // Run template and collect generated files
350
+ const generatedFiles = await (0, template_1.runTemplate)(template, manifest, { dryRun: false });
351
+ // Generate ERD (always generate regardless of template)
352
+ const outputDir = template.defaultConfig.outputDir;
353
+ (0, erd_ir_1.saveERDFromIR)(manifest, `${outputDir}/erd.md`);
354
+ if (jsonOutputFlag) {
355
+ // Output structured JSON result
356
+ const files = generatedFiles.map(f => f.path);
357
+ files.push(`${outputDir}/erd.md`);
358
+ output({
359
+ success: true,
360
+ template: templateId,
361
+ entities: manifest.entities.map(e => e.name),
362
+ files,
363
+ });
364
+ }
365
+ else {
366
+ console.log(` Created: ${outputDir}/erd.md`);
367
+ console.log('');
368
+ console.log('Generation complete!');
369
+ }
370
+ }
371
+ /**
372
+ * Run validation command
373
+ */
374
+ async function runValidate(manifest) {
375
+ const result = (0, validation_1.validateManifest)(manifest);
376
+ if (jsonOutputFlag) {
377
+ output(result);
378
+ }
379
+ else {
380
+ if (result.valid) {
381
+ console.log('Manifest is valid!');
382
+ if (result.warnings.length > 0) {
383
+ console.log('');
384
+ console.log('Warnings:');
385
+ for (const w of result.warnings) {
386
+ console.log(` - [${w.code}] ${w.path}: ${w.message}`);
387
+ if (w.suggestion)
388
+ console.log(` Fix: ${w.suggestion}`);
389
+ }
390
+ }
391
+ }
392
+ else {
393
+ console.error('Validation failed!');
394
+ console.error('');
395
+ console.error('Errors:');
396
+ for (const e of result.errors) {
397
+ console.error(` - [${e.code}] ${e.path}: ${e.message}`);
398
+ if (e.suggestion)
399
+ console.error(` Fix: ${e.suggestion}`);
400
+ }
401
+ if (result.warnings.length > 0) {
402
+ console.error('');
403
+ console.error('Warnings:');
404
+ for (const w of result.warnings) {
405
+ console.error(` - [${w.code}] ${w.path}: ${w.message}`);
406
+ if (w.suggestion)
407
+ console.error(` Fix: ${w.suggestion}`);
408
+ }
409
+ }
410
+ }
411
+ }
412
+ process.exit(result.valid ? 0 : 1);
413
+ }
414
+ /**
415
+ * Load JSON manifest for validation (doesn't convert to IR yet)
416
+ */
417
+ function loadJSONManifest(configFile) {
418
+ const absolutePath = path.resolve(configFile);
419
+ if (!fs.existsSync(absolutePath)) {
420
+ if (jsonOutputFlag) {
421
+ errorOutput(`File not found: ${configFile}`);
422
+ process.exit(1);
423
+ }
424
+ console.error(`File not found: ${configFile}`);
425
+ process.exit(1);
426
+ }
427
+ // For JSON files, parse and return
428
+ if (absolutePath.endsWith('.json')) {
429
+ const content = fs.readFileSync(absolutePath, 'utf-8');
430
+ try {
431
+ return JSON.parse(content);
432
+ }
433
+ catch (err) {
434
+ const message = err instanceof Error ? err.message : 'Unknown error';
435
+ if (jsonOutputFlag) {
436
+ errorOutput('Failed to parse JSON', { parseError: message });
437
+ process.exit(1);
438
+ }
439
+ console.error('Failed to parse JSON:', message);
440
+ process.exit(1);
441
+ }
442
+ }
443
+ // For TypeScript files, load and convert to JSON-like structure
444
+ // (validation works on the JSON structure, not the IR)
445
+ const manifest = loadManifest(configFile);
446
+ // Convert IR back to JSON-like structure for validation
447
+ return {
448
+ entities: manifest.entities.map(e => ({
449
+ name: e.name,
450
+ fields: Object.fromEntries(Object.entries(e.fields).map(([name, field]) => [
451
+ name,
452
+ { type: field.type, required: field.required, unique: field.unique }
453
+ ])),
454
+ relations: Object.fromEntries(Object.entries(e.relations).map(([name, rel]) => [
455
+ name,
456
+ { type: rel.type, entity: rel.entity, field: rel.field }
457
+ ])),
458
+ behaviors: e.behaviors,
459
+ auth: e.auth,
460
+ protected: e.protected,
461
+ })),
462
+ database: manifest.database,
463
+ mode: manifest.mode.type,
464
+ auth: manifest.auth,
465
+ template: manifest.template,
466
+ };
467
+ }
468
+ // Main CLI logic
469
+ async function main() {
470
+ if (command === 'generate') {
471
+ let manifest;
472
+ if (stdinFlag) {
473
+ // Read from stdin
474
+ const jsonContent = await readStdin();
475
+ manifest = loadManifestFromJSON(jsonContent);
476
+ }
477
+ else {
478
+ manifest = loadManifest(configPath);
479
+ }
480
+ await runGenerate(manifest);
481
+ }
482
+ else if (command === 'validate') {
483
+ let manifestJSON;
484
+ if (stdinFlag) {
485
+ // Read from stdin
486
+ const jsonContent = await readStdin();
487
+ try {
488
+ manifestJSON = JSON.parse(jsonContent);
489
+ }
490
+ catch (err) {
491
+ const message = err instanceof Error ? err.message : 'Unknown error';
492
+ errorOutput('Failed to parse JSON from stdin', { parseError: message });
493
+ process.exit(1);
494
+ }
495
+ }
496
+ else {
497
+ manifestJSON = loadJSONManifest(configPath);
498
+ }
499
+ await runValidate(manifestJSON);
500
+ }
501
+ else if (command === 'view') {
502
+ const manifest = loadManifest(configPath);
503
+ const erd = (0, erd_ir_1.generateERDFromIR)(manifest);
504
+ serveERD(erd);
505
+ }
506
+ else if (command === 'init') {
507
+ // Run the TUI init flow
508
+ await (0, init_1.init)({ yes: yesFlag, headless: headlessFlag });
509
+ }
510
+ else {
511
+ console.log('Usage:');
512
+ console.log(' archetype init - Interactive setup with prompts');
513
+ console.log(' archetype init --yes - Quick setup with defaults (full mode)');
514
+ console.log(' archetype init --headless - Quick setup for headless mode (no database)');
515
+ console.log(' archetype generate [config] - Generate code from entities');
516
+ console.log(' archetype validate [config] - Validate manifest without generating');
517
+ console.log(' archetype view [config] - View ERD diagram in browser');
518
+ console.log('');
519
+ console.log('Flags:');
520
+ console.log(' --json - Output as JSON (for AI agents)');
521
+ console.log(' --stdin - Read JSON manifest from stdin');
522
+ console.log(' --template=<id> - Override template');
523
+ console.log('');
524
+ console.log('Config defaults to archetype.config.ts or manifest.json');
525
+ console.log('');
526
+ console.log('Available templates:');
527
+ for (const t of (0, template_1.listTemplates)()) {
528
+ console.log(` - ${t.id}: ${t.description}`);
529
+ }
530
+ }
531
+ }
532
+ main().catch(err => {
533
+ if (jsonOutputFlag) {
534
+ errorOutput(err.message || 'Unknown error');
535
+ }
536
+ else {
537
+ console.error('Error:', err.message || err);
538
+ }
539
+ process.exit(1);
540
+ });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Convert camelCase or PascalCase to snake_case
3
+ */
4
+ export declare function toSnakeCase(str: string): string;
5
+ /**
6
+ * Simple pluralization rules
7
+ */
8
+ export declare function pluralize(name: string): string;
9
+ /**
10
+ * Convert to camelCase (first letter lowercase)
11
+ */
12
+ export declare function toCamelCase(str: string): string;
13
+ /**
14
+ * Convert to PascalCase (first letter uppercase)
15
+ */
16
+ export declare function toPascalCase(str: string): string;
17
+ /**
18
+ * Get database table name from entity name
19
+ * Example: "User" -> "users", "Category" -> "categories"
20
+ */
21
+ export declare function getTableName(entityName: string): string;
22
+ /**
23
+ * Get database column name from field name
24
+ * Example: "firstName" -> "first_name"
25
+ */
26
+ export declare function getColumnName(fieldName: string): string;
27
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS9C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ // Shared utilities for code generation
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.toSnakeCase = toSnakeCase;
5
+ exports.pluralize = pluralize;
6
+ exports.toCamelCase = toCamelCase;
7
+ exports.toPascalCase = toPascalCase;
8
+ exports.getTableName = getTableName;
9
+ exports.getColumnName = getColumnName;
10
+ /**
11
+ * Convert camelCase or PascalCase to snake_case
12
+ */
13
+ function toSnakeCase(str) {
14
+ return str
15
+ .replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)
16
+ .replace(/^_/, '');
17
+ }
18
+ /**
19
+ * Simple pluralization rules
20
+ */
21
+ function pluralize(name) {
22
+ if (name.endsWith('y')) {
23
+ return name.slice(0, -1) + 'ies';
24
+ }
25
+ if (name.endsWith('s') || name.endsWith('x') ||
26
+ name.endsWith('ch') || name.endsWith('sh')) {
27
+ return name + 'es';
28
+ }
29
+ return name + 's';
30
+ }
31
+ /**
32
+ * Convert to camelCase (first letter lowercase)
33
+ */
34
+ function toCamelCase(str) {
35
+ return str.charAt(0).toLowerCase() + str.slice(1);
36
+ }
37
+ /**
38
+ * Convert to PascalCase (first letter uppercase)
39
+ */
40
+ function toPascalCase(str) {
41
+ return str.charAt(0).toUpperCase() + str.slice(1);
42
+ }
43
+ /**
44
+ * Get database table name from entity name
45
+ * Example: "User" -> "users", "Category" -> "categories"
46
+ */
47
+ function getTableName(entityName) {
48
+ return toSnakeCase(pluralize(entityName));
49
+ }
50
+ /**
51
+ * Get database column name from field name
52
+ * Example: "firstName" -> "first_name"
53
+ */
54
+ function getColumnName(fieldName) {
55
+ return toSnakeCase(fieldName);
56
+ }