@specverse/engines 4.1.5 → 4.1.7

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 (122) hide show
  1. package/dist/libs/instance-factories/applications/templates/generic/backend-env-generator.js +22 -0
  2. package/dist/libs/instance-factories/applications/templates/generic/backend-package-json-generator.js +66 -0
  3. package/dist/libs/instance-factories/applications/templates/generic/backend-tsconfig-generator.js +54 -0
  4. package/dist/libs/instance-factories/applications/templates/generic/main-generator.js +290 -0
  5. package/dist/libs/instance-factories/applications/templates/react/_view-components-source.js +530 -0
  6. package/dist/libs/instance-factories/applications/templates/react/api-client-generator.js +437 -0
  7. package/dist/libs/instance-factories/applications/templates/react/api-types-generator.js +146 -0
  8. package/dist/libs/instance-factories/applications/templates/react/app-tsx-generator.js +73 -0
  9. package/dist/libs/instance-factories/applications/templates/react/env-example-generator.js +18 -0
  10. package/dist/libs/instance-factories/applications/templates/react/field-helpers-generator.js +99 -0
  11. package/dist/libs/instance-factories/applications/templates/react/gitignore-generator.js +35 -0
  12. package/dist/libs/instance-factories/applications/templates/react/index-css-generator.js +9 -0
  13. package/dist/libs/instance-factories/applications/templates/react/index-html-generator.js +23 -0
  14. package/dist/libs/instance-factories/applications/templates/react/main-tsx-generator.js +29 -0
  15. package/dist/libs/instance-factories/applications/templates/react/package-json-generator.js +49 -0
  16. package/dist/libs/instance-factories/applications/templates/react/pattern-adapter-generator.js +156 -0
  17. package/dist/libs/instance-factories/applications/templates/react/react-pattern-adapter.js +935 -0
  18. package/dist/libs/instance-factories/applications/templates/react/relationship-field-generator.js +143 -0
  19. package/dist/libs/instance-factories/applications/templates/react/runtime-app-tsx-generator.js +101 -0
  20. package/dist/libs/instance-factories/applications/templates/react/runtime-package-json-generator.js +50 -0
  21. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.js +646 -0
  22. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.js +65 -0
  23. package/dist/libs/instance-factories/applications/templates/react/tsconfig-generator.js +28 -0
  24. package/dist/libs/instance-factories/applications/templates/react/use-api-hooks-generator.js +132 -0
  25. package/dist/libs/instance-factories/applications/templates/react/view-dashboard-generator.js +143 -0
  26. package/dist/libs/instance-factories/applications/templates/react/view-detail-generator.js +143 -0
  27. package/dist/libs/instance-factories/applications/templates/react/view-form-generator.js +355 -0
  28. package/dist/libs/instance-factories/applications/templates/react/view-list-generator.js +91 -0
  29. package/dist/libs/instance-factories/applications/templates/react/view-router-generator.js +79 -0
  30. package/dist/libs/instance-factories/applications/templates/react/vite-config-generator.js +42 -0
  31. package/dist/libs/instance-factories/cli/templates/commander/cli-bin-wrapper-generator.js +11 -0
  32. package/dist/libs/instance-factories/cli/templates/commander/cli-entry-generator.js +111 -0
  33. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +928 -0
  34. package/dist/libs/instance-factories/communication/templates/eventemitter/bus-generator.js +83 -0
  35. package/dist/libs/instance-factories/communication/templates/eventemitter/publisher-generator.js +91 -0
  36. package/dist/libs/instance-factories/communication/templates/eventemitter/subscriber-generator.js +86 -0
  37. package/dist/libs/instance-factories/controllers/templates/fastify/meta-routes-generator.js +93 -0
  38. package/dist/libs/instance-factories/controllers/templates/fastify/routes-generator.js +280 -0
  39. package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +125 -0
  40. package/dist/libs/instance-factories/infrastructure/templates/docker-k8s/infrastructure-generator.js +25 -0
  41. package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +371 -0
  42. package/dist/libs/instance-factories/orms/templates/prisma/services-generator.js +266 -0
  43. package/dist/libs/instance-factories/scaffolding/templates/generic/env-example-generator.js +51 -0
  44. package/dist/libs/instance-factories/scaffolding/templates/generic/env-generator.js +61 -0
  45. package/dist/libs/instance-factories/scaffolding/templates/generic/gitignore-generator.js +59 -0
  46. package/dist/libs/instance-factories/scaffolding/templates/generic/package-json-generator.js +126 -0
  47. package/dist/libs/instance-factories/scaffolding/templates/generic/readme-generator.js +159 -0
  48. package/dist/libs/instance-factories/scaffolding/templates/generic/tsconfig-generator.js +56 -0
  49. package/dist/libs/instance-factories/scaffolding/templates/generic/tsconfig-react-generator.js +37 -0
  50. package/dist/libs/instance-factories/sdks/templates/python/sdk-generator.js +29 -0
  51. package/dist/libs/instance-factories/sdks/templates/typescript/sdk-generator.js +28 -0
  52. package/dist/libs/instance-factories/services/templates/memory/generate-interpreter.js +14 -0
  53. package/dist/libs/instance-factories/services/templates/memory/step-conventions-memory.js +415 -0
  54. package/dist/libs/instance-factories/services/templates/prisma/behavior-generator.js +177 -0
  55. package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +413 -0
  56. package/dist/libs/instance-factories/services/templates/prisma/service-generator.js +243 -0
  57. package/dist/libs/instance-factories/services/templates/prisma/step-conventions.js +264 -0
  58. package/dist/libs/instance-factories/services/templates/shared-patterns.js +24 -0
  59. package/dist/libs/instance-factories/shared/path-resolver.js +59 -0
  60. package/dist/libs/instance-factories/storage/templates/mongodb/config-generator.js +13 -0
  61. package/dist/libs/instance-factories/storage/templates/mongodb/docker-generator.js +16 -0
  62. package/dist/libs/instance-factories/storage/templates/postgresql/config-generator.js +45 -0
  63. package/dist/libs/instance-factories/storage/templates/postgresql/docker-generator.js +46 -0
  64. package/dist/libs/instance-factories/storage/templates/redis/config-generator.js +14 -0
  65. package/dist/libs/instance-factories/storage/templates/redis/docker-generator.js +16 -0
  66. package/dist/libs/instance-factories/test-generation.js +145 -0
  67. package/dist/libs/instance-factories/testing/templates/vitest/tests-generator.js +30 -0
  68. package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +149 -0
  69. package/dist/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.js +232 -0
  70. package/dist/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.js +49 -0
  71. package/dist/libs/instance-factories/tools/templates/mcp/static/src/index.js +18 -0
  72. package/dist/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.js +0 -0
  73. package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.js +97 -0
  74. package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.js +64 -0
  75. package/dist/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.js +182 -0
  76. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.js +1210 -0
  77. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.js +172 -0
  78. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.js +240 -0
  79. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.js +147 -0
  80. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.js +281 -0
  81. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.js +409 -0
  82. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.js +414 -0
  83. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.js +467 -0
  84. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.js +135 -0
  85. package/dist/libs/instance-factories/tools/templates/mcp/static/src/types/index.js +0 -0
  86. package/dist/libs/instance-factories/tools/templates/vscode/static/extension.js +965 -0
  87. package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js +238 -0
  88. package/dist/libs/instance-factories/validation/templates/zod/validation-generator.js +25 -0
  89. package/dist/libs/instance-factories/views/index.js +48 -0
  90. package/dist/libs/instance-factories/views/templates/react/adapters/antd-adapter.js +742 -0
  91. package/dist/libs/instance-factories/views/templates/react/adapters/mui-adapter.js +824 -0
  92. package/dist/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.js +719 -0
  93. package/dist/libs/instance-factories/views/templates/react/app-generator.js +45 -0
  94. package/dist/libs/instance-factories/views/templates/react/components-generator.js +779 -0
  95. package/dist/libs/instance-factories/views/templates/react/forms-generator.js +285 -0
  96. package/dist/libs/instance-factories/views/templates/react/frontend-package-json-generator.js +46 -0
  97. package/dist/libs/instance-factories/views/templates/react/hooks-generator.js +111 -0
  98. package/dist/libs/instance-factories/views/templates/react/index-css-generator.js +9 -0
  99. package/dist/libs/instance-factories/views/templates/react/index-html-generator.js +23 -0
  100. package/dist/libs/instance-factories/views/templates/react/main-tsx-generator.js +21 -0
  101. package/dist/libs/instance-factories/views/templates/react/react-component-generator.js +299 -0
  102. package/dist/libs/instance-factories/views/templates/react/router-generator.js +136 -0
  103. package/dist/libs/instance-factories/views/templates/react/router-generic-generator.js +107 -0
  104. package/dist/libs/instance-factories/views/templates/react/shared-utils-generator.js +179 -0
  105. package/dist/libs/instance-factories/views/templates/react/spec-json-generator.js +7 -0
  106. package/dist/libs/instance-factories/views/templates/react/types-generator.js +56 -0
  107. package/dist/libs/instance-factories/views/templates/react/views-metadata-generator.js +27 -0
  108. package/dist/libs/instance-factories/views/templates/react/vite-config-generator.js +29 -0
  109. package/dist/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js +261 -0
  110. package/dist/libs/instance-factories/views/templates/shared/adapter-types.js +34 -0
  111. package/dist/libs/instance-factories/views/templates/shared/atomic-components-registry.js +800 -0
  112. package/dist/libs/instance-factories/views/templates/shared/base-generator.js +305 -0
  113. package/dist/libs/instance-factories/views/templates/shared/component-metadata.js +517 -0
  114. package/dist/libs/instance-factories/views/templates/shared/composite-pattern-types.js +0 -0
  115. package/dist/libs/instance-factories/views/templates/shared/composite-patterns.js +445 -0
  116. package/dist/libs/instance-factories/views/templates/shared/index.js +80 -0
  117. package/dist/libs/instance-factories/views/templates/shared/pattern-validator.js +210 -0
  118. package/dist/libs/instance-factories/views/templates/shared/property-mapper.js +492 -0
  119. package/dist/libs/instance-factories/views/templates/shared/syntax-mapper.js +321 -0
  120. package/dist/realize/index.js +36 -12
  121. package/dist/realize/index.js.map +1 -1
  122. package/package.json +3 -2
@@ -0,0 +1,125 @@
1
+ function normalizeSpec(spec) {
2
+ if (!spec) return spec;
3
+ const normalized = { ...spec };
4
+ if (normalized.models && typeof normalized.models === "object") {
5
+ for (const [name, model] of Object.entries(normalized.models)) {
6
+ if (Array.isArray(model.attributes)) {
7
+ const obj = {};
8
+ for (const attr of model.attributes) {
9
+ if (attr.name) obj[attr.name] = attr;
10
+ }
11
+ model.attributes = obj;
12
+ }
13
+ if (Array.isArray(model.relationships)) {
14
+ const obj = {};
15
+ for (const rel of model.relationships) {
16
+ if (rel.name) obj[rel.name] = { ...rel, targetModel: rel.target || rel.targetModel };
17
+ }
18
+ model.relationships = obj;
19
+ }
20
+ if (Array.isArray(model.lifecycles)) {
21
+ const obj = {};
22
+ for (const lc of model.lifecycles) {
23
+ if (lc.name) obj[lc.name] = lc;
24
+ }
25
+ model.lifecycles = obj;
26
+ }
27
+ if (model.lifecycles && typeof model.lifecycles === "object") {
28
+ for (const lc of Object.values(model.lifecycles)) {
29
+ if (lc.flow && typeof lc.flow === "string" && !lc.states) {
30
+ const stateNames = lc.flow.split("->").map((s) => s.trim()).filter(Boolean);
31
+ lc.states = stateNames.map((s) => ({ name: s }));
32
+ lc.transitions = [];
33
+ lc.initialState = stateNames[0];
34
+ for (let i = 0; i < stateNames.length - 1; i++) {
35
+ lc.transitions.push({ from: stateNames[i], to: stateNames[i + 1] });
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
42
+ if (normalized.views && typeof normalized.views === "object") {
43
+ for (const view of Object.values(normalized.views)) {
44
+ if (Array.isArray(view.model)) {
45
+ view.models = view.model;
46
+ view.model = view.model[0];
47
+ }
48
+ }
49
+ }
50
+ return normalized;
51
+ }
52
+ function generateFastifyServer(context) {
53
+ const { spec, models } = context;
54
+ const allModels = models || (spec?.models ? Object.values(spec.models) : []);
55
+ const modelNames = allModels.map((m) => m.name).filter(Boolean);
56
+ const routeImports = modelNames.map(
57
+ (name) => `import ${name}Routes from './routes/${name}Controller.js';`
58
+ ).join("\n");
59
+ const routeRegistrations = modelNames.map((name) => {
60
+ const path = `/api/${name.toLowerCase()}s`;
61
+ return ` await fastify.register(${name}Routes, { prefix: '${path}', controllers: { ${name}Controller: new (await import('./controllers/${name}Controller.js')).${name}Controller() } });`;
62
+ }).join("\n");
63
+ return `/**
64
+ * Fastify Server
65
+ * Generated from SpecVerse specification
66
+ */
67
+
68
+ import Fastify from 'fastify';
69
+ import cors from '@fastify/cors';
70
+ import { PrismaClient } from '@prisma/client';
71
+
72
+ // Initialize Prisma
73
+ export const prisma = new PrismaClient();
74
+
75
+ // Initialize Fastify
76
+ const fastify = Fastify({
77
+ logger: { level: 'info' },
78
+ });
79
+
80
+ // Register plugins
81
+ await fastify.register(cors, { origin: true, credentials: true });
82
+
83
+ // Health check
84
+ fastify.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
85
+ fastify.get('/', async () => ({ name: 'SpecVerse Generated API', models: ${JSON.stringify(modelNames)} }));
86
+
87
+ // Spec endpoint \u2014 serves the specification for the runtime frontend
88
+ const embeddedSpec = ${JSON.stringify(normalizeSpec(spec), null, 2)};
89
+ fastify.get('/api/spec', async () => embeddedSpec);
90
+
91
+ // Runtime info endpoint \u2014 models and controllers for DevShell
92
+ fastify.get('/api/runtime/info', async () => ({
93
+ controllers: ${JSON.stringify(modelNames.map((n) => `${n}Controller`))},
94
+ models: ${JSON.stringify(modelNames)},
95
+ events: [],
96
+ services: []
97
+ }));
98
+
99
+ // Register routes
100
+ ${routeImports}
101
+
102
+ async function registerRoutes() {
103
+ ${routeRegistrations}
104
+ }
105
+
106
+ // Start server
107
+ const start = async () => {
108
+ try {
109
+ await registerRoutes();
110
+ const port = parseInt(process.env.PORT || '3000');
111
+ await fastify.listen({ port, host: '0.0.0.0' });
112
+ console.log(\`Server running at http://localhost:\${port}\`);
113
+ console.log(\`API endpoints: ${modelNames.map((n) => `/api/${n.toLowerCase()}s`).join(", ")}\`);
114
+ } catch (err) {
115
+ fastify.log.error(err);
116
+ process.exit(1);
117
+ }
118
+ };
119
+
120
+ start();
121
+ `;
122
+ }
123
+ export {
124
+ generateFastifyServer as default
125
+ };
@@ -0,0 +1,25 @@
1
+ import { generateInfrastructure } from "../../../../../scripts/generate-infrastructure.js";
2
+ function generateInfra(context) {
3
+ const { spec, implType, outputDir } = context;
4
+ if (!spec) {
5
+ throw new Error("Specification is required in template context");
6
+ }
7
+ const config = implType.configuration || {};
8
+ const options = {
9
+ docker: config.docker || {},
10
+ kubernetes: config.kubernetes || {},
11
+ cicd: config.cicd || {}
12
+ };
13
+ const result = generateInfrastructure(spec, outputDir || "./infrastructure", options);
14
+ return JSON.stringify({
15
+ message: "Infrastructure code generated successfully",
16
+ dockerFiles: result.dockerFiles,
17
+ kubernetesFiles: result.kubernetesFiles,
18
+ cicdFiles: result.cicdFiles,
19
+ outputDir: result.outputDir,
20
+ files: result.files
21
+ }, null, 2);
22
+ }
23
+ export {
24
+ generateInfra as default
25
+ };
@@ -0,0 +1,371 @@
1
+ import { pluralize } from "@specverse/types";
2
+ function generatePrismaSchema(context) {
3
+ const { spec, models, implType } = context;
4
+ const allModels = models || spec?.models || [];
5
+ if (allModels.length === 0) {
6
+ throw new Error("No models found in context for schema generation");
7
+ }
8
+ const relationMap = buildRelationMap(allModels);
9
+ const backRefs = buildMissingBackRefs(allModels, relationMap);
10
+ const hasOneTargets = /* @__PURE__ */ new Set();
11
+ for (const m of allModels) {
12
+ const rels = Array.isArray(m.relationships) ? m.relationships : Object.values(m.relationships || {});
13
+ for (const r of rels) {
14
+ if (r.type === "hasOne") {
15
+ hasOneTargets.add(`${m.name}->${r.target}`);
16
+ }
17
+ }
18
+ }
19
+ const header = generateHeader(implType);
20
+ const modelSchemas = allModels.map(
21
+ (model) => generateModelSchema(model, relationMap, backRefs, hasOneTargets, allModels)
22
+ ).join("\n\n");
23
+ return `${header}
24
+
25
+ ${modelSchemas}`;
26
+ }
27
+ function buildRelationMap(allModels) {
28
+ const targetRefs = /* @__PURE__ */ new Map();
29
+ for (const model of allModels) {
30
+ const relationships = Array.isArray(model.relationships) ? model.relationships : Object.values(model.relationships || {});
31
+ for (const rel of relationships) {
32
+ const target = rel.target;
33
+ if (!target) continue;
34
+ const fieldName = rel.name || (rel.type === "hasMany" || rel.type === "manyToMany" ? pluralize(target.toLowerCase()) : target.toLowerCase());
35
+ if (!targetRefs.has(target)) {
36
+ targetRefs.set(target, []);
37
+ }
38
+ targetRefs.get(target).push({
39
+ sourceModel: model.name,
40
+ fieldName,
41
+ relType: rel.type
42
+ });
43
+ }
44
+ }
45
+ const nameMap = /* @__PURE__ */ new Map();
46
+ for (const [target, refs] of targetRefs) {
47
+ for (const ref of refs) {
48
+ const key = `${ref.sourceModel}.${ref.fieldName}`;
49
+ if (ref.relType === "belongsTo") {
50
+ const parentRefs = targetRefs.get(ref.sourceModel) || [];
51
+ const matchingParent = parentRefs.find(
52
+ (p) => p.sourceModel === target && (p.relType === "hasMany" || p.relType === "hasOne")
53
+ );
54
+ if (matchingParent) {
55
+ nameMap.set(key, `${matchingParent.sourceModel}_${matchingParent.fieldName}`);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ return nameMap;
61
+ }
62
+ function buildMissingBackRefs(allModels, relationMap) {
63
+ const existingBelongsTo = /* @__PURE__ */ new Set();
64
+ for (const model of allModels) {
65
+ const relationships = Array.isArray(model.relationships) ? model.relationships : Object.values(model.relationships || {});
66
+ for (const rel of relationships) {
67
+ if (rel.type === "belongsTo") {
68
+ existingBelongsTo.add(`${model.name}->${rel.target}`);
69
+ }
70
+ }
71
+ }
72
+ const backRefs = /* @__PURE__ */ new Map();
73
+ for (const model of allModels) {
74
+ const relationships = Array.isArray(model.relationships) ? model.relationships : Object.values(model.relationships || {});
75
+ for (const rel of relationships) {
76
+ if (rel.type !== "hasMany" && rel.type !== "hasOne") continue;
77
+ const target = rel.target;
78
+ const backKey = `${target}->${model.name}`;
79
+ if (!existingBelongsTo.has(backKey)) {
80
+ const fieldName = rel.name || (rel.type === "hasMany" ? pluralize(target.toLowerCase()) : target.toLowerCase());
81
+ const relName = `${model.name}_${fieldName}`;
82
+ const parentRelsToSameTarget = relationships.filter(
83
+ (r) => r.target === target && (r.type === "hasMany" || r.type === "hasOne")
84
+ );
85
+ const needsFieldInFk = parentRelsToSameTarget.length > 1;
86
+ const fkSuffix = needsFieldInFk ? camelToSnake(fieldName) + "_id" : camelToSnake(model.name.charAt(0).toLowerCase() + model.name.slice(1)) + "_id";
87
+ const fkName = fkSuffix;
88
+ const fkPadding = " ".repeat(Math.max(1, 15 - fkName.length));
89
+ const refFieldName = needsFieldInFk ? fieldName + model.name : model.name.charAt(0).toLowerCase() + model.name.slice(1);
90
+ const refPadding = " ".repeat(Math.max(1, 15 - refFieldName.length));
91
+ let relDef = `${refFieldName}${refPadding}${model.name}`;
92
+ relDef += ` @relation("${relName}", fields: [${fkName}], references: [id])`;
93
+ if (!backRefs.has(target)) {
94
+ backRefs.set(target, []);
95
+ }
96
+ const uniqueModifier = rel.type === "hasOne" ? " @unique" : "";
97
+ backRefs.get(target).push(`${fkName}${fkPadding}String${uniqueModifier}`);
98
+ backRefs.get(target).push(relDef);
99
+ }
100
+ }
101
+ }
102
+ const existingHasRelation = /* @__PURE__ */ new Set();
103
+ for (const model of allModels) {
104
+ const rels = Array.isArray(model.relationships) ? model.relationships : Object.values(model.relationships || {});
105
+ for (const rel of rels) {
106
+ if (rel.type === "hasMany" || rel.type === "hasOne") {
107
+ existingHasRelation.add(`${model.name}->${rel.target}`);
108
+ }
109
+ }
110
+ }
111
+ for (const model of allModels) {
112
+ const relationships = Array.isArray(model.relationships) ? model.relationships : Object.values(model.relationships || {});
113
+ for (const rel of relationships) {
114
+ if (rel.type !== "belongsTo") continue;
115
+ const parent = rel.target;
116
+ const forwardKey = `${parent}->${model.name}`;
117
+ if (!existingHasRelation.has(forwardKey)) {
118
+ const fieldName = rel.name || parent.toLowerCase();
119
+ const relName = getRelationName(model.name, fieldName, parent, relationMap);
120
+ const arrayFieldName = pluralize(model.name.charAt(0).toLowerCase() + model.name.slice(1));
121
+ const padding = " ".repeat(Math.max(1, 15 - arrayFieldName.length));
122
+ if (!backRefs.has(parent)) {
123
+ backRefs.set(parent, []);
124
+ }
125
+ backRefs.get(parent).push(`${arrayFieldName}${padding}${model.name}[] @relation("${relName}")`);
126
+ }
127
+ }
128
+ }
129
+ return backRefs;
130
+ }
131
+ function getRelationName(sourceModel, fieldName, target, relationMap) {
132
+ const mapped = relationMap.get(`${sourceModel}.${fieldName}`);
133
+ if (mapped) return mapped;
134
+ return `${sourceModel}_${fieldName}`;
135
+ }
136
+ function generateHeader(implType) {
137
+ const provider = implType?.configuration?.orm?.provider || "sqlite";
138
+ return `// Generated Prisma schema from SpecVerse specification
139
+ // This is your Prisma schema file
140
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
141
+
142
+ generator client {
143
+ provider = "prisma-client-js"
144
+ }
145
+
146
+ datasource db {
147
+ provider = "${provider}"
148
+ url = ${provider === "sqlite" ? '"file:./dev.db"' : 'env("DATABASE_URL")'}
149
+ }`;
150
+ }
151
+ function generateModelSchema(model, relationMap, backRefs, hasOneTargets, allModels) {
152
+ const modelName = model.name;
153
+ let schema = `model ${modelName} {
154
+ `;
155
+ const attributes = Array.isArray(model.attributes) ? model.attributes : Object.values(model.attributes || {});
156
+ const relationships = Array.isArray(model.relationships) ? model.relationships : Object.values(model.relationships || {});
157
+ attributes.forEach((attr) => {
158
+ schema += ` ${generateField(attr, model)}
159
+ `;
160
+ });
161
+ const rawLifecycles = model.lifecycles || [];
162
+ const lifecycleList = Array.isArray(rawLifecycles) ? rawLifecycles : Object.entries(rawLifecycles).map(([name, lc]) => ({ name, ...typeof lc === "object" ? lc : {} }));
163
+ for (const lifecycle of lifecycleList) {
164
+ const fieldName = lifecycle.name || "status";
165
+ const exists = attributes.some((a) => a.name === fieldName);
166
+ if (!exists && lifecycle.states?.length > 0) {
167
+ const defaultState = lifecycle.states[0];
168
+ const padding = " ".repeat(Math.max(1, 15 - fieldName.length));
169
+ schema += ` ${fieldName}${padding}String @default("${defaultState}")
170
+ `;
171
+ }
172
+ }
173
+ relationships.forEach((rel) => {
174
+ const fields = generateRelationship(rel, model, relationMap, hasOneTargets, allModels);
175
+ fields.forEach((field) => {
176
+ schema += ` ${field}
177
+ `;
178
+ });
179
+ });
180
+ const modelBackRefs = backRefs.get(modelName);
181
+ if (modelBackRefs) {
182
+ for (const line of modelBackRefs) {
183
+ schema += ` ${line}
184
+ `;
185
+ }
186
+ }
187
+ schema += `}`;
188
+ return schema;
189
+ }
190
+ function generateField(attr, model) {
191
+ const name = attr.name;
192
+ const prismaType = mapTypeToPrisma(attr.type, attr.dbMapping?.columnType);
193
+ const isOptional = !(attr.required || attr.constraints?.required);
194
+ const isUnique = attr.unique || attr.constraints?.unique;
195
+ const metadata = model?.metadata || {};
196
+ let modifiers = "";
197
+ let hasDefault = false;
198
+ if (name.toLowerCase() === "id") {
199
+ modifiers += " @id";
200
+ if (metadata.id === "uuid" || metadata.id === "auto" || prismaType === "String") {
201
+ modifiers += " @default(uuid())";
202
+ hasDefault = true;
203
+ } else if (metadata.id === "integer" || prismaType === "Int") {
204
+ modifiers += " @default(autoincrement())";
205
+ hasDefault = true;
206
+ }
207
+ } else if (isUnique) {
208
+ modifiers += " @unique";
209
+ }
210
+ if (name === "updatedAt" || name === "updated_at") {
211
+ modifiers += " @updatedAt";
212
+ hasDefault = true;
213
+ }
214
+ if (attr.auto && !hasDefault) {
215
+ const autoValue = typeof attr.auto === "string" ? attr.auto.toLowerCase() : attr.auto;
216
+ if (autoValue === "now" || autoValue === true) {
217
+ if (prismaType === "DateTime") {
218
+ modifiers += " @default(now())";
219
+ hasDefault = true;
220
+ }
221
+ } else if (autoValue === "uuid" || autoValue === "uuid4") {
222
+ if (prismaType === "String") {
223
+ modifiers += " @default(uuid())";
224
+ hasDefault = true;
225
+ }
226
+ } else if (autoValue === "autoincrement") {
227
+ if (prismaType === "Int") {
228
+ modifiers += " @default(autoincrement())";
229
+ hasDefault = true;
230
+ }
231
+ }
232
+ }
233
+ if (!hasDefault && prismaType === "DateTime") {
234
+ const autoTimestampFields = ["joinedAt", "registeredAt", "enrolledAt", "startedAt", "completedAt", "verifiedAt"];
235
+ if (autoTimestampFields.includes(name)) {
236
+ modifiers += " @default(now())";
237
+ hasDefault = true;
238
+ }
239
+ if ((name === "createdAt" || name === "created_at") && metadata.audit) {
240
+ modifiers += " @default(now())";
241
+ hasDefault = true;
242
+ }
243
+ }
244
+ if (metadata.softDelete && isSoftDeleteField(name)) {
245
+ if (name === "isDeleted" || name === "is_deleted") {
246
+ modifiers += " @default(false)";
247
+ }
248
+ }
249
+ if (metadata.version && isVersionField(name)) {
250
+ modifiers += " @default(0)";
251
+ }
252
+ if (attr.dbMapping?.columnType === "TEXT") {
253
+ modifiers += " @db.Text";
254
+ } else if (attr.dbMapping?.columnType?.startsWith("VARCHAR")) {
255
+ const match = attr.dbMapping.columnType.match(/VARCHAR\((\d+)\)/);
256
+ if (match) {
257
+ modifiers += ` @db.VarChar(${match[1]})`;
258
+ }
259
+ }
260
+ const padding = " ".repeat(Math.max(1, 15 - name.length));
261
+ const typeStr = isOptional ? `${prismaType}?` : prismaType;
262
+ return `${name}${padding}${typeStr}${modifiers}`;
263
+ }
264
+ function generateRelationship(rel, model, relationMap, hasOneTargets, allModels) {
265
+ const fields = [];
266
+ const name = rel.name || rel.target.toLowerCase();
267
+ const padding = " ".repeat(Math.max(1, 15 - name.length));
268
+ const isOptional = rel.optional || false;
269
+ const relName = getRelationName(model.name, name, rel.target, relationMap);
270
+ const relAnnotation = ` @relation("${relName}")`;
271
+ switch (rel.type) {
272
+ case "belongsTo":
273
+ const fkBase = rel.foreignKey || camelToSnake(name) + "_id";
274
+ const fkPadding = " ".repeat(Math.max(1, 15 - fkBase.length));
275
+ const isUniqueFK = hasOneTargets.has(`${rel.target}->${model.name}`);
276
+ let fkType = "String";
277
+ if (allModels) {
278
+ const targetModel = allModels.find((m) => m.name === rel.target);
279
+ if (targetModel) {
280
+ const idAttr = (Array.isArray(targetModel.attributes) ? targetModel.attributes : Object.values(targetModel.attributes || {})).find((a) => a.name === "id");
281
+ if (idAttr) {
282
+ const idType = idAttr.type || "String";
283
+ fkType = mapTypeToPrisma(idType);
284
+ }
285
+ }
286
+ }
287
+ fields.push(`${fkBase}${fkPadding}${fkType}${isOptional ? "?" : ""}${isUniqueFK ? " @unique" : ""}`);
288
+ let relationDef = `${name}${padding}${rel.target}${isOptional ? "?" : ""}`;
289
+ relationDef += ` @relation(`;
290
+ if (relName) {
291
+ relationDef += `"${relName}", `;
292
+ }
293
+ relationDef += `fields: [${fkBase}], references: [id]`;
294
+ if (rel.onDelete) {
295
+ relationDef += `, onDelete: ${rel.onDelete}`;
296
+ }
297
+ if (rel.onUpdate) {
298
+ relationDef += `, onUpdate: ${rel.onUpdate}`;
299
+ }
300
+ relationDef += ")";
301
+ fields.push(relationDef);
302
+ break;
303
+ case "hasOne":
304
+ fields.push(`${name}${padding}${rel.target}?${relAnnotation}`);
305
+ break;
306
+ case "hasMany":
307
+ const pluralName = rel.name || pluralize(rel.target.toLowerCase());
308
+ const manyPadding = " ".repeat(Math.max(1, 15 - pluralName.length));
309
+ fields.push(`${pluralName}${manyPadding}${rel.target}[]${relAnnotation}`);
310
+ break;
311
+ case "manyToMany":
312
+ const manyName = rel.name || pluralize(rel.target.toLowerCase());
313
+ const m2mPadding = " ".repeat(Math.max(1, 15 - manyName.length));
314
+ fields.push(`${manyName}${m2mPadding}${rel.target}[]${relAnnotation}`);
315
+ break;
316
+ }
317
+ return fields;
318
+ }
319
+ function camelToSnake(str) {
320
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
321
+ }
322
+ function mapTypeToPrisma(type, dbType) {
323
+ if (dbType) {
324
+ if (dbType.startsWith("VARCHAR") || dbType === "TEXT") return "String";
325
+ const typeMap = {
326
+ "INTEGER": "Int",
327
+ "BIGINT": "BigInt",
328
+ "DECIMAL": "Decimal",
329
+ "BOOLEAN": "Boolean",
330
+ "DATE": "DateTime",
331
+ "TIMESTAMP": "DateTime",
332
+ "UUID": "String",
333
+ "JSONB": "Json",
334
+ "JSON": "Json",
335
+ "FLOAT": "Float"
336
+ };
337
+ if (typeMap[dbType]) return typeMap[dbType];
338
+ }
339
+ const typeLower = type.toLowerCase();
340
+ if (typeLower.includes("string") || typeLower.includes("text")) return "String";
341
+ if (typeLower.includes("int")) return "Int";
342
+ if (typeLower.includes("bool")) return "Boolean";
343
+ if (typeLower.includes("date") || typeLower.includes("time")) return "DateTime";
344
+ if (typeLower.includes("float") || typeLower.includes("decimal")) return "Float";
345
+ if (typeLower.includes("json")) return "Json";
346
+ return "String";
347
+ }
348
+ function isAuditField(name) {
349
+ const auditFields = [
350
+ "createdAt",
351
+ "updatedAt",
352
+ "createdBy",
353
+ "updatedBy",
354
+ "created_at",
355
+ "updated_at",
356
+ "created_by",
357
+ "updated_by"
358
+ ];
359
+ return auditFields.includes(name);
360
+ }
361
+ function isSoftDeleteField(name) {
362
+ const softDeleteFields = ["deletedAt", "isDeleted", "deleted_at", "is_deleted"];
363
+ return softDeleteFields.includes(name);
364
+ }
365
+ function isVersionField(name) {
366
+ const versionFields = ["version", "versionNumber", "version_number"];
367
+ return versionFields.includes(name);
368
+ }
369
+ export {
370
+ generatePrismaSchema as default
371
+ };