@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,285 @@
1
+ function generateReactForm(context) {
2
+ const { model, spec } = context;
3
+ if (!model) {
4
+ throw new Error("Model is required in template context");
5
+ }
6
+ const modelName = model.name;
7
+ const formName = `${modelName}Form`;
8
+ return `/**
9
+ * ${formName}
10
+ * Form component for creating/editing ${modelName}
11
+ */
12
+
13
+ import { useForm } from 'react-hook-form';
14
+ import { zodResolver } from '@hookform/resolvers/zod';
15
+ import { z } from 'zod';
16
+ import { useEffect } from 'react';
17
+ import type { ${modelName} } from '../../types/${modelName}';
18
+
19
+ // Zod schema for form validation
20
+ const ${modelName.toLowerCase()}Schema = z.object({
21
+ ${generateSchemaFields(model)}
22
+ });
23
+
24
+ type ${modelName}FormData = z.infer<typeof ${modelName.toLowerCase()}Schema>;
25
+
26
+ interface ${formName}Props {
27
+ ${modelName.toLowerCase()}?: ${modelName};
28
+ onSubmit: (data: ${modelName}FormData) => void;
29
+ onValidate?: (data: ${modelName}FormData) => void;
30
+ onDelete?: () => void;
31
+ onCancel?: () => void;
32
+ isDeleting?: boolean;
33
+ isValidating?: boolean;
34
+ }
35
+
36
+ /**
37
+ * ${formName} Component
38
+ */
39
+ export function ${formName}({ ${modelName.toLowerCase()}, onSubmit, onValidate, onDelete, onCancel, isDeleting, isValidating }: ${formName}Props) {
40
+ const {
41
+ register,
42
+ handleSubmit,
43
+ getValues,
44
+ reset,
45
+ formState: { errors, isSubmitting },
46
+ } = useForm<${modelName}FormData>({
47
+ resolver: zodResolver(${modelName.toLowerCase()}Schema),
48
+ defaultValues: ${modelName.toLowerCase()} || {},
49
+ });
50
+
51
+ // Reset form when ${modelName.toLowerCase()} changes
52
+ useEffect(() => {
53
+ if (${modelName.toLowerCase()}) {
54
+ reset(${modelName.toLowerCase()});
55
+ } else {
56
+ reset({});
57
+ }
58
+ }, [${modelName.toLowerCase()}, reset]);
59
+
60
+ const handleValidateClick = () => {
61
+ if (onValidate) {
62
+ const data = getValues();
63
+ onValidate(data);
64
+ }
65
+ };
66
+
67
+ return (
68
+ <form onSubmit={handleSubmit(onSubmit)} className="${modelName.toLowerCase()}-form space-y-4" autoComplete="off" data-lpignore="true" data-form-type="other">
69
+ {/* Hidden fake fields to trick password managers */}
70
+ <input type="text" name="fake-username" style={{ display: 'none' }} tabIndex={-1} autoComplete="off" aria-hidden="true" />
71
+ <input type="password" name="fake-password" style={{ display: 'none' }} tabIndex={-1} autoComplete="new-password" aria-hidden="true" />
72
+
73
+ ${generateFormFields(model)}
74
+
75
+ <div className="form-actions flex flex-wrap gap-2 pt-4">
76
+ <button
77
+ type="submit"
78
+ disabled={isSubmitting}
79
+ className="px-6 py-2 bg-blue-600 text-white font-medium rounded hover:bg-blue-700 disabled:bg-slate-600 disabled:cursor-not-allowed transition-colors"
80
+ >
81
+ {isSubmitting ? 'Saving...' : 'Save'}
82
+ </button>
83
+
84
+ {onValidate && (
85
+ <button
86
+ type="button"
87
+ onClick={handleValidateClick}
88
+ disabled={isValidating}
89
+ className="px-6 py-2 bg-green-600 text-white font-medium rounded hover:bg-green-700 disabled:bg-slate-600 disabled:cursor-not-allowed transition-colors"
90
+ >
91
+ {isValidating ? 'Validating...' : 'Validate'}
92
+ </button>
93
+ )}
94
+
95
+ {onDelete && (
96
+ <button
97
+ type="button"
98
+ onClick={onDelete}
99
+ disabled={isDeleting}
100
+ className="px-6 py-2 bg-red-600 text-white font-medium rounded hover:bg-red-700 disabled:bg-slate-600 disabled:cursor-not-allowed transition-colors"
101
+ >
102
+ {isDeleting ? 'Deleting...' : 'Delete'}
103
+ </button>
104
+ )}
105
+
106
+ {onCancel && (
107
+ <button
108
+ type="button"
109
+ onClick={onCancel}
110
+ className="px-6 py-2 bg-slate-600 text-gray-200 font-medium rounded hover:bg-slate-500 transition-colors"
111
+ >
112
+ Cancel
113
+ </button>
114
+ )}
115
+ </div>
116
+ </form>
117
+ );
118
+ }
119
+ `;
120
+ }
121
+ function generateSchemaFields(model) {
122
+ let attributes = model.attributes || {};
123
+ if (Array.isArray(attributes)) {
124
+ const obj = {};
125
+ attributes.forEach((attr, index) => {
126
+ if (attr && typeof attr === "object" && attr.name) {
127
+ obj[attr.name] = attr;
128
+ } else if (Array.isArray(attr) && attr.length >= 2) {
129
+ obj[attr[0]] = attr[1];
130
+ } else {
131
+ obj[index.toString()] = attr;
132
+ }
133
+ });
134
+ attributes = obj;
135
+ }
136
+ const fields = [];
137
+ for (const [name, config] of Object.entries(attributes)) {
138
+ if (name === "id" || name === "createdAt" || name === "updatedAt") continue;
139
+ const attr = config;
140
+ if (attr.auto || attr.autoGenerate) continue;
141
+ const autoTimestampFields = ["joinedAt", "registeredAt", "enrolledAt", "startedAt", "completedAt", "verifiedAt"];
142
+ if (autoTimestampFields.includes(name) && (attr.type === "DateTime" || attr.type === "Timestamp")) {
143
+ continue;
144
+ }
145
+ const type = attr.type || "String";
146
+ let zodType = "z.string()";
147
+ if (type === "Integer" || type === "Number") zodType = "z.number()";
148
+ if (type === "Boolean") zodType = "z.boolean()";
149
+ if (type === "Email") zodType = "z.string().email()";
150
+ if (type === "DateTime") zodType = "z.string()";
151
+ if (type === "UUID") zodType = "z.string().uuid()";
152
+ if (attr.required) {
153
+ } else {
154
+ zodType += ".optional()";
155
+ }
156
+ if (attr.min && type === "String") {
157
+ zodType = zodType.replace(")", `.min(${attr.min})`);
158
+ }
159
+ if (attr.max && type === "String") {
160
+ zodType = zodType.replace(")", `.max(${attr.max})`);
161
+ }
162
+ fields.push(` ${name}: ${zodType},`);
163
+ }
164
+ return fields.join("\n");
165
+ }
166
+ function generateFormFields(model) {
167
+ let attributes = model.attributes || {};
168
+ if (Array.isArray(attributes)) {
169
+ const obj = {};
170
+ attributes.forEach((attr, index) => {
171
+ if (attr && typeof attr === "object" && attr.name) {
172
+ obj[attr.name] = attr;
173
+ } else if (Array.isArray(attr) && attr.length >= 2) {
174
+ obj[attr[0]] = attr[1];
175
+ } else {
176
+ obj[index.toString()] = attr;
177
+ }
178
+ });
179
+ attributes = obj;
180
+ }
181
+ const fields = [];
182
+ const regularFields = [];
183
+ const textAreaFields = [];
184
+ for (const [name, config] of Object.entries(attributes)) {
185
+ if (name === "id" || name === "createdAt" || name === "updatedAt") continue;
186
+ const attr = config;
187
+ if (attr.auto || attr.autoGenerate) continue;
188
+ const autoTimestampFields = ["joinedAt", "registeredAt", "enrolledAt", "startedAt", "completedAt", "verifiedAt"];
189
+ if (autoTimestampFields.includes(name) && (attr.type === "DateTime" || attr.type === "Timestamp")) {
190
+ continue;
191
+ }
192
+ const type = attr.type || "String";
193
+ const label = name.charAt(0).toUpperCase() + name.slice(1);
194
+ const isRequired = attr.required;
195
+ let inputType = "text";
196
+ if (type === "Email") inputType = "email";
197
+ if (type === "Number" || type === "Integer") inputType = "number";
198
+ if (type === "Boolean") inputType = "checkbox";
199
+ if (type === "DateTime") inputType = "datetime-local";
200
+ if (type === "Text") inputType = "textarea";
201
+ const field = inputType === "textarea" ? ` <div className="form-field">
202
+ <label htmlFor="${name}" className="block text-sm font-medium text-gray-300 mb-1">
203
+ ${name}${isRequired ? ' <span className="text-red-400">*</span>' : ""}
204
+ </label>
205
+ <textarea
206
+ id="${name}"
207
+ {...register('${name}')}
208
+ rows={2}
209
+ className={\`w-full px-3 py-2 rounded bg-slate-700 border transition-colors text-gray-200
210
+ \${errors['${name}']
211
+ ? 'border-red-500 focus:border-red-400'
212
+ : 'border-slate-600 focus:border-blue-500'
213
+ } focus:outline-none focus:ring-0 resize-none\`}
214
+ placeholder="Enter ${name}"
215
+ autoComplete="off"
216
+ data-lpignore="true"
217
+ data-form-type="other"
218
+ readOnly
219
+ onFocus={(e) => e.target.removeAttribute('readonly')}
220
+ />
221
+ {errors['${name}'] && (
222
+ <p className="mt-1 text-xs text-red-400">{errors['${name}']?.message}</p>
223
+ )}
224
+ </div>` : inputType === "checkbox" ? ` <div className="form-field">
225
+ <label htmlFor="${name}" className="flex items-center text-sm font-medium text-gray-300">
226
+ <input
227
+ id="${name}"
228
+ type="checkbox"
229
+ {...register('${name}')}
230
+ className="mr-2"
231
+ autoComplete="off"
232
+ data-lpignore="true"
233
+ />
234
+ ${name}${isRequired ? ' <span className="ml-1 text-red-400">*</span>' : ""}
235
+ </label>
236
+ {errors['${name}'] && (
237
+ <p className="mt-1 text-xs text-red-400">{errors['${name}']?.message}</p>
238
+ )}
239
+ </div>` : ` <div className="form-field">
240
+ <label htmlFor="${name}" className="block text-sm font-medium text-gray-300 mb-1">
241
+ ${name}${isRequired ? ' <span className="text-red-400">*</span>' : ""}
242
+ </label>
243
+ <input
244
+ id="${name}"
245
+ type="${inputType}"
246
+ {...register('${name}')}
247
+ className={\`w-full px-3 py-2 rounded bg-slate-700 border transition-colors text-gray-200
248
+ \${errors['${name}']
249
+ ? 'border-red-500 focus:border-red-400'
250
+ : 'border-slate-600 focus:border-blue-500'
251
+ } focus:outline-none focus:ring-0\`}
252
+ placeholder="Enter ${name}"
253
+ autoComplete="off"
254
+ data-lpignore="true"
255
+ data-form-type="other"
256
+ readOnly
257
+ onFocus={(e) => e.target.removeAttribute('readonly')}
258
+ />
259
+ {errors['${name}'] && (
260
+ <p className="mt-1 text-xs text-red-400">{errors['${name}']?.message}</p>
261
+ )}
262
+ </div>`;
263
+ if (inputType === "textarea") {
264
+ textAreaFields.push(field);
265
+ } else {
266
+ regularFields.push(field);
267
+ }
268
+ }
269
+ let output = "";
270
+ if (regularFields.length > 0) {
271
+ output += ` <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
272
+ `;
273
+ output += regularFields.join("\n\n");
274
+ output += `
275
+ </div>`;
276
+ }
277
+ if (textAreaFields.length > 0) {
278
+ if (output) output += "\n\n";
279
+ output += textAreaFields.join("\n\n");
280
+ }
281
+ return output;
282
+ }
283
+ export {
284
+ generateReactForm as default
285
+ };
@@ -0,0 +1,46 @@
1
+ function generateFrontendPackageJson(context) {
2
+ const { spec } = context;
3
+ const componentName = spec?.name || "app";
4
+ const packageName = `${componentName.toLowerCase()}-frontend`;
5
+ const packageJson = {
6
+ name: packageName,
7
+ version: "1.0.0",
8
+ description: `Frontend for ${spec?.description || componentName}`,
9
+ private: true,
10
+ type: "module",
11
+ scripts: {
12
+ dev: "vite",
13
+ build: "tsc && vite build",
14
+ preview: "vite preview",
15
+ lint: "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
16
+ "type-check": "tsc --noEmit"
17
+ },
18
+ dependencies: {
19
+ "react": "^18.3.1",
20
+ "react-dom": "^18.3.1",
21
+ "react-router-dom": "^6.26.2",
22
+ "@tanstack/react-query": "^5.56.2",
23
+ "zustand": "^4.5.5",
24
+ "axios": "^1.7.7"
25
+ },
26
+ devDependencies: {
27
+ "@types/react": "^18.3.9",
28
+ "@types/react-dom": "^18.3.0",
29
+ "@typescript-eslint/eslint-plugin": "^8.7.0",
30
+ "@typescript-eslint/parser": "^8.7.0",
31
+ "@vitejs/plugin-react": "^4.3.1",
32
+ "autoprefixer": "^10.4.20",
33
+ "eslint": "^9.11.1",
34
+ "eslint-plugin-react-hooks": "^5.1.0-rc.0",
35
+ "eslint-plugin-react-refresh": "^0.4.12",
36
+ "postcss": "^8.4.47",
37
+ "tailwindcss": "^3.4.13",
38
+ "typescript": "^5.6.2",
39
+ "vite": "^5.4.8"
40
+ }
41
+ };
42
+ return JSON.stringify(packageJson, null, 2);
43
+ }
44
+ export {
45
+ generateFrontendPackageJson as default
46
+ };
@@ -0,0 +1,111 @@
1
+ function generateReactHook(context) {
2
+ const { model, controller, spec } = context;
3
+ if (!model) {
4
+ throw new Error("Model is required in template context");
5
+ }
6
+ const modelName = model.name;
7
+ const hookName = `use${modelName}`;
8
+ const controllerName = `${modelName}Controller`;
9
+ return `/**
10
+ * ${hookName}
11
+ * Custom React hook for ${modelName} data fetching and mutations
12
+ */
13
+
14
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
15
+ import { executeOperation } from '../lib/apiClient';
16
+ import type { ${modelName} } from '../types/${modelName}';
17
+
18
+ interface Use${modelName}Options {
19
+ id?: string;
20
+ list?: boolean;
21
+ filters?: Record<string, any>;
22
+ }
23
+
24
+ /**
25
+ * ${hookName} - Fetch and mutate ${modelName} data
26
+ */
27
+ export function ${hookName}(options: Use${modelName}Options = {}) {
28
+ const queryClient = useQueryClient();
29
+ const { id, list, filters } = options;
30
+
31
+ // Fetch single ${modelName}
32
+ const { data: ${modelName.toLowerCase()}, isLoading: singleLoading, error: singleError } = useQuery({
33
+ queryKey: ['${modelName.toLowerCase()}', id],
34
+ queryFn: async () => {
35
+ if (!id) return null;
36
+ return await executeOperation('${controllerName}', 'retrieve', { id });
37
+ },
38
+ enabled: !!id && !list,
39
+ });
40
+
41
+ // Fetch list of ${modelName}s
42
+ const { data: ${modelName.toLowerCase()}s, isLoading: listLoading, error: listError } = useQuery({
43
+ queryKey: ['${modelName.toLowerCase()}s', filters],
44
+ queryFn: async () => {
45
+ return await executeOperation('${controllerName}', 'list', filters || {});
46
+ },
47
+ enabled: list,
48
+ });
49
+
50
+ const isLoading = list ? listLoading : singleLoading;
51
+ const error = list ? listError : singleError;
52
+
53
+ // Create mutation
54
+ const createMutation = useMutation({
55
+ mutationFn: async (data: Partial<${modelName}>) => {
56
+ return await executeOperation('${controllerName}', 'create', data);
57
+ },
58
+ onSuccess: () => {
59
+ queryClient.invalidateQueries({ queryKey: ['${modelName.toLowerCase()}s'] });
60
+ },
61
+ });
62
+
63
+ // Update mutation
64
+ const updateMutation = useMutation({
65
+ mutationFn: async ({ id, data }: { id: string; data: Partial<${modelName}> }) => {
66
+ return await executeOperation('${controllerName}', 'update', { id, ...data });
67
+ },
68
+ onSuccess: (_, variables) => {
69
+ queryClient.invalidateQueries({ queryKey: ['${modelName.toLowerCase()}', variables.id] });
70
+ queryClient.invalidateQueries({ queryKey: ['${modelName.toLowerCase()}s'] });
71
+ },
72
+ });
73
+
74
+ // Delete mutation
75
+ const deleteMutation = useMutation({
76
+ mutationFn: async (id: string) => {
77
+ return await executeOperation('${controllerName}', 'delete', { id });
78
+ },
79
+ onSuccess: () => {
80
+ queryClient.invalidateQueries({ queryKey: ['${modelName.toLowerCase()}s'] });
81
+ },
82
+ });
83
+
84
+ // Refetch functions
85
+ const refetch = () => {
86
+ if (list) {
87
+ queryClient.invalidateQueries({ queryKey: ['${modelName.toLowerCase()}s'] });
88
+ } else if (id) {
89
+ queryClient.invalidateQueries({ queryKey: ['${modelName.toLowerCase()}', id] });
90
+ }
91
+ };
92
+
93
+ return {
94
+ ${modelName.toLowerCase()},
95
+ ${modelName.toLowerCase()}s,
96
+ isLoading,
97
+ error,
98
+ refetch,
99
+ create: createMutation.mutateAsync,
100
+ update: updateMutation.mutateAsync,
101
+ delete: deleteMutation.mutateAsync,
102
+ isCreating: createMutation.isPending,
103
+ isUpdating: updateMutation.isPending,
104
+ isDeleting: deleteMutation.isPending,
105
+ };
106
+ }
107
+ `;
108
+ }
109
+ export {
110
+ generateReactHook as default
111
+ };
@@ -0,0 +1,9 @@
1
+ function generateIndexCss(context) {
2
+ return `@tailwind base;
3
+ @tailwind components;
4
+ @tailwind utilities;
5
+ `;
6
+ }
7
+ export {
8
+ generateIndexCss as default
9
+ };
@@ -0,0 +1,23 @@
1
+ function generateIndexHtml(context) {
2
+ const { spec } = context;
3
+ const componentName = spec?.metadata?.component || spec?.component?.name || "App";
4
+ const description = spec?.metadata?.description || spec?.component?.description || "Generated by SpecVerse";
5
+ return `<!DOCTYPE html>
6
+ <html lang="en">
7
+ <head>
8
+ <meta charset="UTF-8" />
9
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
10
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11
+ <meta name="description" content="${description}" />
12
+ <title>${componentName}</title>
13
+ </head>
14
+ <body>
15
+ <div id="root"></div>
16
+ <script type="module" src="/src/main.tsx"></script>
17
+ </body>
18
+ </html>
19
+ `;
20
+ }
21
+ export {
22
+ generateIndexHtml as default
23
+ };
@@ -0,0 +1,21 @@
1
+ function generateMainTsx(context) {
2
+ return `/**
3
+ * React Application Entry Point
4
+ * Auto-generated by SpecVerse
5
+ */
6
+
7
+ import React from 'react';
8
+ import ReactDOM from 'react-dom/client';
9
+ import App from './App';
10
+ import './index.css';
11
+
12
+ ReactDOM.createRoot(document.getElementById('root')!).render(
13
+ <React.StrictMode>
14
+ <App />
15
+ </React.StrictMode>
16
+ );
17
+ `;
18
+ }
19
+ export {
20
+ generateMainTsx as default
21
+ };