@specverse/engines 4.1.28 → 4.2.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 (237) hide show
  1. package/assets/examples/manifests/frontend-only.yaml +3 -6
  2. package/assets/examples/manifests/fullstack-app.yaml +5 -7
  3. package/assets/examples/manifests/fullstack-monorepo.yaml +3 -6
  4. package/dist/inference/comprehensive-engine.d.ts.map +1 -1
  5. package/dist/inference/comprehensive-engine.js +3 -19
  6. package/dist/inference/comprehensive-engine.js.map +1 -1
  7. package/dist/inference/core/rule-engine.d.ts +31 -0
  8. package/dist/inference/core/rule-engine.d.ts.map +1 -1
  9. package/dist/inference/core/rule-engine.js +117 -33
  10. package/dist/inference/core/rule-engine.js.map +1 -1
  11. package/dist/inference/core/rule-file-types.d.ts +0 -2
  12. package/dist/inference/core/rule-file-types.d.ts.map +1 -1
  13. package/dist/inference/core/rule-file-types.js +3 -6
  14. package/dist/inference/core/rule-file-types.js.map +1 -1
  15. package/dist/inference/core/rule-loader.d.ts +5 -15
  16. package/dist/inference/core/rule-loader.d.ts.map +1 -1
  17. package/dist/inference/core/rule-loader.js +43 -132
  18. package/dist/inference/core/rule-loader.js.map +1 -1
  19. package/dist/inference/core/types.d.ts +0 -6
  20. package/dist/inference/core/types.d.ts.map +1 -1
  21. package/dist/inference/core/types.js +0 -4
  22. package/dist/inference/core/types.js.map +1 -1
  23. package/dist/inference/logical/generators/component-type-resolver.d.ts +0 -26
  24. package/dist/inference/logical/generators/component-type-resolver.d.ts.map +1 -1
  25. package/dist/inference/logical/generators/component-type-resolver.js +0 -19
  26. package/dist/inference/logical/generators/component-type-resolver.js.map +1 -1
  27. package/dist/inference/logical/generators/specialist-view-expander.d.ts +1 -17
  28. package/dist/inference/logical/generators/specialist-view-expander.d.ts.map +1 -1
  29. package/dist/inference/logical/generators/specialist-view-expander.js +0 -15
  30. package/dist/inference/logical/generators/specialist-view-expander.js.map +1 -1
  31. package/dist/inference/logical/generators/view-generator.d.ts +4 -14
  32. package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
  33. package/dist/inference/logical/generators/view-generator.js +6 -26
  34. package/dist/inference/logical/generators/view-generator.js.map +1 -1
  35. package/dist/inference/logical/index.d.ts +2 -2
  36. package/dist/inference/logical/index.d.ts.map +1 -1
  37. package/dist/inference/logical/logical-engine.d.ts.map +1 -1
  38. package/dist/inference/logical/logical-engine.js +17 -80
  39. package/dist/inference/logical/logical-engine.js.map +1 -1
  40. package/dist/inference/quint-transpiler.d.ts +5 -3
  41. package/dist/inference/quint-transpiler.d.ts.map +1 -1
  42. package/dist/inference/quint-transpiler.js +11 -6
  43. package/dist/inference/quint-transpiler.js.map +1 -1
  44. package/dist/libs/instance-factories/applications/templates/generic/main-generator.js +3 -3
  45. package/dist/libs/instance-factories/applications/templates/react/api-client-generator.js +16 -6
  46. package/dist/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.js +110 -0
  47. package/dist/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.js +121 -0
  48. package/dist/libs/instance-factories/applications/templates/react-starter/detail-body-composer.js +78 -0
  49. package/dist/libs/instance-factories/applications/templates/react-starter/form-body-composer.js +190 -0
  50. package/dist/libs/instance-factories/applications/templates/react-starter/helpers-emitter.js +45 -0
  51. package/dist/libs/instance-factories/applications/templates/react-starter/html-to-jsx.js +192 -0
  52. package/dist/libs/instance-factories/applications/templates/react-starter/list-body-composer.js +46 -0
  53. package/dist/libs/instance-factories/applications/templates/react-starter/orchestrator.js +30 -0
  54. package/dist/libs/instance-factories/applications/templates/react-starter/package-json-generator.js +38 -0
  55. package/dist/libs/instance-factories/applications/templates/react-starter/regen-safety.js +89 -0
  56. package/dist/libs/instance-factories/applications/templates/react-starter/view-emitter.js +56 -0
  57. package/dist/libs/instance-factories/applications/templates/react-starter/views-generator.js +66 -0
  58. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +14 -11
  59. package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +11 -3
  60. package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +27 -17
  61. package/dist/libs/instance-factories/shared/path-resolver.js +1 -1
  62. package/dist/realize/index.d.ts.map +1 -1
  63. package/dist/realize/index.js +15 -22
  64. package/dist/realize/index.js.map +1 -1
  65. package/dist/registry/utils/manifest-adapter.d.ts +8 -1
  66. package/dist/registry/utils/manifest-adapter.d.ts.map +1 -1
  67. package/dist/registry/utils/manifest-adapter.js +8 -1
  68. package/dist/registry/utils/manifest-adapter.js.map +1 -1
  69. package/libs/instance-factories/applications/react-app-starter.yaml +150 -0
  70. package/libs/instance-factories/applications/templates/generic/main-generator.ts +3 -3
  71. package/libs/instance-factories/applications/templates/react/api-client-generator.ts +16 -6
  72. package/libs/instance-factories/applications/templates/react-starter/README.md +211 -0
  73. package/libs/instance-factories/applications/templates/react-starter/__tests__/dashboard-body-composer.test.ts +153 -0
  74. package/libs/instance-factories/applications/templates/react-starter/__tests__/detail-body-composer.test.ts +145 -0
  75. package/libs/instance-factories/applications/templates/react-starter/__tests__/form-body-composer.test.ts +175 -0
  76. package/libs/instance-factories/applications/templates/react-starter/__tests__/helpers-emitter.test.ts +55 -0
  77. package/libs/instance-factories/applications/templates/react-starter/__tests__/html-to-jsx.test.ts +140 -0
  78. package/libs/instance-factories/applications/templates/react-starter/__tests__/list-body-composer.test.ts +146 -0
  79. package/libs/instance-factories/applications/templates/react-starter/__tests__/orchestrator.test.ts +163 -0
  80. package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p2-factory-imports.test.ts +116 -0
  81. package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p3-rendered-output.test.ts +183 -0
  82. package/libs/instance-factories/applications/templates/react-starter/__tests__/regen-safety.test.ts +144 -0
  83. package/libs/instance-factories/applications/templates/react-starter/__tests__/starter-generators.test.ts +114 -0
  84. package/libs/instance-factories/applications/templates/react-starter/__tests__/view-emitter.test.ts +107 -0
  85. package/libs/instance-factories/applications/templates/react-starter/__tests__/views-generator.test.ts +139 -0
  86. package/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.ts +141 -0
  87. package/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.ts +174 -0
  88. package/libs/instance-factories/applications/templates/react-starter/detail-body-composer.ts +135 -0
  89. package/libs/instance-factories/applications/templates/react-starter/form-body-composer.ts +306 -0
  90. package/libs/instance-factories/applications/templates/react-starter/helpers-emitter.ts +60 -0
  91. package/libs/instance-factories/applications/templates/react-starter/html-to-jsx.ts +334 -0
  92. package/libs/instance-factories/applications/templates/react-starter/list-body-composer.ts +120 -0
  93. package/libs/instance-factories/applications/templates/react-starter/orchestrator.ts +80 -0
  94. package/libs/instance-factories/applications/templates/react-starter/package-json-generator.ts +57 -0
  95. package/libs/instance-factories/applications/templates/react-starter/regen-safety.ts +157 -0
  96. package/libs/instance-factories/applications/templates/react-starter/skeletons/dashboard.tsx.template +47 -0
  97. package/libs/instance-factories/applications/templates/react-starter/skeletons/detail.tsx.template +94 -0
  98. package/libs/instance-factories/applications/templates/react-starter/skeletons/form.tsx.template +114 -0
  99. package/libs/instance-factories/applications/templates/react-starter/skeletons/list.tsx.template +72 -0
  100. package/libs/instance-factories/applications/templates/react-starter/view-emitter.ts +151 -0
  101. package/libs/instance-factories/applications/templates/react-starter/views-generator.ts +137 -0
  102. package/libs/instance-factories/cli/templates/commander/command-generator.ts +14 -11
  103. package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +11 -3
  104. package/libs/instance-factories/services/templates/prisma/controller-generator.ts +27 -17
  105. package/libs/instance-factories/shared/path-resolver.ts +8 -2
  106. package/package.json +3 -3
  107. package/dist/libs/instance-factories/applications/templates/react/_view-components-source.js +0 -530
  108. package/dist/libs/instance-factories/applications/templates/react/app-tsx-generator.js +0 -73
  109. package/dist/libs/instance-factories/applications/templates/react/field-helpers-generator.js +0 -99
  110. package/dist/libs/instance-factories/applications/templates/react/package-json-generator.js +0 -49
  111. package/dist/libs/instance-factories/applications/templates/react/pattern-adapter-generator.js +0 -156
  112. package/dist/libs/instance-factories/applications/templates/react/react-pattern-adapter.js +0 -935
  113. package/dist/libs/instance-factories/applications/templates/react/relationship-field-generator.js +0 -143
  114. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.js +0 -646
  115. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.js +0 -65
  116. package/dist/libs/instance-factories/applications/templates/react/view-dashboard-generator.js +0 -143
  117. package/dist/libs/instance-factories/applications/templates/react/view-detail-generator.js +0 -143
  118. package/dist/libs/instance-factories/applications/templates/react/view-form-generator.js +0 -355
  119. package/dist/libs/instance-factories/applications/templates/react/view-list-generator.js +0 -91
  120. package/dist/libs/instance-factories/applications/templates/react/view-router-generator.js +0 -79
  121. package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js.bak +0 -244
  122. package/dist/libs/instance-factories/views/index.js +0 -48
  123. package/dist/libs/instance-factories/views/templates/react/adapters/antd-adapter.js +0 -742
  124. package/dist/libs/instance-factories/views/templates/react/adapters/mui-adapter.js +0 -824
  125. package/dist/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.js +0 -719
  126. package/dist/libs/instance-factories/views/templates/react/app-generator.js +0 -45
  127. package/dist/libs/instance-factories/views/templates/react/components-generator.js +0 -820
  128. package/dist/libs/instance-factories/views/templates/react/forms-generator.js +0 -275
  129. package/dist/libs/instance-factories/views/templates/react/frontend-package-json-generator.js +0 -46
  130. package/dist/libs/instance-factories/views/templates/react/hooks-generator.js +0 -81
  131. package/dist/libs/instance-factories/views/templates/react/index-css-generator.js +0 -9
  132. package/dist/libs/instance-factories/views/templates/react/index-html-generator.js +0 -23
  133. package/dist/libs/instance-factories/views/templates/react/main-tsx-generator.js +0 -21
  134. package/dist/libs/instance-factories/views/templates/react/react-component-generator.js +0 -299
  135. package/dist/libs/instance-factories/views/templates/react/router-generator.js +0 -136
  136. package/dist/libs/instance-factories/views/templates/react/router-generic-generator.js +0 -107
  137. package/dist/libs/instance-factories/views/templates/react/shared-utils-generator.js +0 -187
  138. package/dist/libs/instance-factories/views/templates/react/spec-json-generator.js +0 -7
  139. package/dist/libs/instance-factories/views/templates/react/types-generator.js +0 -56
  140. package/dist/libs/instance-factories/views/templates/react/views-metadata-generator.js +0 -27
  141. package/dist/libs/instance-factories/views/templates/react/vite-config-generator.js +0 -29
  142. package/dist/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js +0 -261
  143. package/dist/libs/instance-factories/views/templates/shared/adapter-types.js +0 -34
  144. package/dist/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -800
  145. package/dist/libs/instance-factories/views/templates/shared/base-generator.js +0 -305
  146. package/dist/libs/instance-factories/views/templates/shared/component-metadata.js +0 -517
  147. package/dist/libs/instance-factories/views/templates/shared/composite-pattern-types.js +0 -0
  148. package/dist/libs/instance-factories/views/templates/shared/composite-patterns.js +0 -445
  149. package/dist/libs/instance-factories/views/templates/shared/index.js +0 -80
  150. package/dist/libs/instance-factories/views/templates/shared/pattern-validator.js +0 -210
  151. package/dist/libs/instance-factories/views/templates/shared/property-mapper.js +0 -492
  152. package/dist/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -321
  153. package/dist/realize/index.js.bak +0 -758
  154. package/libs/instance-factories/applications/react-app.yaml +0 -186
  155. package/libs/instance-factories/applications/templates/react/_view-components-source.ts +0 -555
  156. package/libs/instance-factories/applications/templates/react/app-tsx-generator.ts +0 -94
  157. package/libs/instance-factories/applications/templates/react/field-helpers-generator.ts +0 -106
  158. package/libs/instance-factories/applications/templates/react/package-json-generator.ts +0 -57
  159. package/libs/instance-factories/applications/templates/react/pattern-adapter-generator.ts +0 -179
  160. package/libs/instance-factories/applications/templates/react/react-pattern-adapter.tsx +0 -1347
  161. package/libs/instance-factories/applications/templates/react/relationship-field-generator.ts +0 -150
  162. package/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.ts +0 -704
  163. package/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.ts +0 -84
  164. package/libs/instance-factories/applications/templates/react/view-dashboard-generator.ts +0 -150
  165. package/libs/instance-factories/applications/templates/react/view-detail-generator.ts +0 -150
  166. package/libs/instance-factories/applications/templates/react/view-form-generator.ts +0 -362
  167. package/libs/instance-factories/applications/templates/react/view-list-generator.ts +0 -98
  168. package/libs/instance-factories/applications/templates/react/view-router-generator.ts +0 -89
  169. package/libs/instance-factories/views/README.md +0 -62
  170. package/libs/instance-factories/views/index.d.ts +0 -13
  171. package/libs/instance-factories/views/index.d.ts.map +0 -1
  172. package/libs/instance-factories/views/index.js +0 -18
  173. package/libs/instance-factories/views/index.js.map +0 -1
  174. package/libs/instance-factories/views/index.ts +0 -45
  175. package/libs/instance-factories/views/react-components.yaml +0 -129
  176. package/libs/instance-factories/views/templates/ARCHITECTURE.md +0 -198
  177. package/libs/instance-factories/views/templates/react/adapters/antd-adapter.ts +0 -869
  178. package/libs/instance-factories/views/templates/react/adapters/mui-adapter.ts +0 -953
  179. package/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.ts +0 -806
  180. package/libs/instance-factories/views/templates/react/app-generator.ts +0 -55
  181. package/libs/instance-factories/views/templates/react/components-generator.ts +0 -938
  182. package/libs/instance-factories/views/templates/react/forms-generator.ts +0 -325
  183. package/libs/instance-factories/views/templates/react/frontend-package-json-generator.ts +0 -57
  184. package/libs/instance-factories/views/templates/react/hooks-generator.ts +0 -106
  185. package/libs/instance-factories/views/templates/react/index-css-generator.ts +0 -14
  186. package/libs/instance-factories/views/templates/react/index-html-generator.ts +0 -34
  187. package/libs/instance-factories/views/templates/react/main-tsx-generator.ts +0 -29
  188. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts +0 -152
  189. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts.map +0 -1
  190. package/libs/instance-factories/views/templates/react/react-component-generator.js +0 -398
  191. package/libs/instance-factories/views/templates/react/react-component-generator.js.map +0 -1
  192. package/libs/instance-factories/views/templates/react/react-component-generator.ts +0 -533
  193. package/libs/instance-factories/views/templates/react/router-generator.ts +0 -197
  194. package/libs/instance-factories/views/templates/react/router-generic-generator.ts +0 -132
  195. package/libs/instance-factories/views/templates/react/shared-utils-generator.ts +0 -196
  196. package/libs/instance-factories/views/templates/react/spec-json-generator.ts +0 -17
  197. package/libs/instance-factories/views/templates/react/types-generator.ts +0 -76
  198. package/libs/instance-factories/views/templates/react/views-metadata-generator.ts +0 -42
  199. package/libs/instance-factories/views/templates/react/vite-config-generator.ts +0 -38
  200. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.d.ts.map +0 -1
  201. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js.map +0 -1
  202. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.ts +0 -474
  203. package/libs/instance-factories/views/templates/shared/__tests__/composite-patterns.test.ts +0 -242
  204. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts +0 -77
  205. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts.map +0 -1
  206. package/libs/instance-factories/views/templates/shared/adapter-types.js +0 -47
  207. package/libs/instance-factories/views/templates/shared/adapter-types.js.map +0 -1
  208. package/libs/instance-factories/views/templates/shared/adapter-types.ts +0 -142
  209. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts +0 -63
  210. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts.map +0 -1
  211. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -822
  212. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js.map +0 -1
  213. package/libs/instance-factories/views/templates/shared/atomic-components-registry.ts +0 -908
  214. package/libs/instance-factories/views/templates/shared/base-generator.d.ts +0 -247
  215. package/libs/instance-factories/views/templates/shared/base-generator.d.ts.map +0 -1
  216. package/libs/instance-factories/views/templates/shared/base-generator.js +0 -363
  217. package/libs/instance-factories/views/templates/shared/base-generator.js.map +0 -1
  218. package/libs/instance-factories/views/templates/shared/base-generator.ts +0 -608
  219. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts +0 -254
  220. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts.map +0 -1
  221. package/libs/instance-factories/views/templates/shared/component-metadata.js +0 -602
  222. package/libs/instance-factories/views/templates/shared/component-metadata.js.map +0 -1
  223. package/libs/instance-factories/views/templates/shared/component-metadata.ts +0 -803
  224. package/libs/instance-factories/views/templates/shared/composite-pattern-types.ts +0 -250
  225. package/libs/instance-factories/views/templates/shared/composite-patterns.ts +0 -535
  226. package/libs/instance-factories/views/templates/shared/index.ts +0 -68
  227. package/libs/instance-factories/views/templates/shared/pattern-validator.ts +0 -279
  228. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts +0 -149
  229. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts.map +0 -1
  230. package/libs/instance-factories/views/templates/shared/property-mapper.js +0 -580
  231. package/libs/instance-factories/views/templates/shared/property-mapper.js.map +0 -1
  232. package/libs/instance-factories/views/templates/shared/property-mapper.ts +0 -700
  233. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts +0 -143
  234. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts.map +0 -1
  235. package/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -420
  236. package/libs/instance-factories/views/templates/shared/syntax-mapper.js.map +0 -1
  237. package/libs/instance-factories/views/templates/shared/syntax-mapper.ts +0 -539
@@ -1,530 +0,0 @@
1
- async function generate(context) {
2
- const files = {};
3
- files["FormView.tsx"] = generateFormView();
4
- files["ListView.tsx"] = generateListView();
5
- files["DetailView.tsx"] = generateDetailView();
6
- files["DashboardView.tsx"] = generateDashboardView();
7
- return files;
8
- }
9
- function generateFormView() {
10
- return `/**
11
- * StandardFormView - Controller-Based Form View Component
12
- *
13
- * LOCAL VERSION - Uses local hooks with instance-factory-specific API client
14
- *
15
- * Supports both Create and Edit modes with:
16
- * - Controller-driven form generation
17
- * - Smart input types (text, number, boolean, relationship selectors)
18
- * - Auto-generated field detection
19
- * - Validation and error handling
20
- * - Lifecycle management (Edit/Evolve tabs)
21
- * - Foreign key relationship fields
22
- * - Two-panel layout (form + entity list)
23
- */
24
-
25
- import { useState, useEffect, useMemo } from 'react';
26
- import { useAppStore } from '../../stores/appStore';
27
- import { useEntitiesQuery, useModelSchemaQuery, useExecuteOperationMutation, useAvailableTransitionsQuery, useTransitionStateMutation } from '../../hooks/useApi';
28
- import { isAutoGeneratedField, isFieldRequired, initializeFormData } from '../../utils/field-helpers';
29
- import { RelationshipField } from '../../components/RelationshipField';
30
- import type { View, Entity } from '../../types/api';
31
-
32
- type FormMode = 'create' | 'update';
33
- type ActiveTab = 'edit' | 'evolve';
34
-
35
- interface StandardFormViewProps {
36
- view: View;
37
- spec?: any; // Full spec for controller access
38
- }
39
-
40
- export function FormView({ view, spec }: StandardFormViewProps) {
41
- // Determine controller and model
42
- let controllerName: string;
43
- let modelName: string;
44
-
45
- if (view.controller && spec) {
46
- // New: Controller-based
47
- controllerName = view.controller;
48
- const controller = spec.controllers[view.controller];
49
- modelName = controller.model;
50
- } else {
51
- // Legacy: Model-based
52
- modelName = view.model as string;
53
- controllerName = \`\${modelName}Controller\`;
54
- }
55
-
56
- const [selectedEntity, setSelectedEntity] = useState<Entity | null>(null);
57
- const [formMode, setFormMode] = useState<FormMode>('create');
58
- const [activeTab, setActiveTab] = useState<ActiveTab>('edit');
59
- const [formData, setFormData] = useState<Record<string, any>>({});
60
- const [errors, setErrors] = useState<Record<string, string>>({});
61
- const [selectedLifecycleStates, setSelectedLifecycleStates] = useState<Record<string, string>>({});
62
-
63
- // Fetch entities and schema - USES LOCAL HOOKS
64
- const { data: entities = [], isLoading: entitiesLoading } = useEntitiesQuery(controllerName, modelName);
65
- const { data: schema } = useModelSchemaQuery(modelName);
66
- const { mutate: executeOperation, isPending } = useExecuteOperationMutation();
67
- const { mutate: transitionState, isPending: isTransitioning } = useTransitionStateMutation();
68
-
69
- const attributes = schema?.attributes || {};
70
- const relationships = schema?.relationships || {};
71
- const lifecycles = schema?.lifecycles || {};
72
-
73
- // Get entities store for relationship resolution
74
- const entitiesStore = useAppStore((state) => state.entities);
75
-
76
- // Sync selected entity with updated entities list
77
- useEffect(() => {
78
- if (selectedEntity && entities.length > 0) {
79
- const updatedEntity = entities.find((e) => e.id === selectedEntity.id);
80
- if (updatedEntity) {
81
- const oldStates = JSON.stringify(selectedEntity.metadata?.lifecycleStates || {});
82
- const newStates = JSON.stringify(updatedEntity.metadata?.lifecycleStates || {});
83
-
84
- if (oldStates !== newStates) {
85
- setSelectedEntity(updatedEntity);
86
- setSelectedLifecycleStates({ ...(updatedEntity.metadata?.lifecycleStates || {}) });
87
- }
88
- }
89
- }
90
- }, [entities, selectedEntity?.id]);
91
-
92
- // Initialize form data when schema changes or when switching modes
93
- useEffect(() => {
94
- if (selectedEntity && formMode === 'update') {
95
- setFormData({ ...selectedEntity.data });
96
- const currentStates = selectedEntity.metadata?.lifecycleStates || {};
97
- setSelectedLifecycleStates({ ...currentStates });
98
- } else if (schema?.attributes) {
99
- setFormData(initializeFormData(schema.attributes, { includeAutoGenerated: false }));
100
- setSelectedLifecycleStates({});
101
- }
102
- }, [selectedEntity, formMode, schema]);
103
-
104
- // Check if field should be shown
105
- const shouldShowField = (attrName: string, attrDef: any): boolean => {
106
- const isAuto = isAutoGeneratedField(attrName, attrDef);
107
- // In create mode, hide auto-generated fields
108
- if (formMode === 'create' && isAuto) {
109
- return false;
110
- }
111
- // In update mode, show all fields
112
- return true;
113
- };
114
-
115
- // Handle form submission
116
- const handleSubmit = async (e: React.FormEvent) => {
117
- e.preventDefault();
118
- setErrors({});
119
-
120
- const operation = formMode === 'create' ? 'create' : 'update';
121
- const params = formMode === 'update' && selectedEntity
122
- ? { ...formData, id: selectedEntity.id }
123
- : formData;
124
-
125
- executeOperation(
126
- { controllerName, operationName: operation, params },
127
- {
128
- onSuccess: () => {
129
- if (formMode === 'create') {
130
- setFormData(initializeFormData(schema.attributes, { includeAutoGenerated: false }));
131
- }
132
- setFormMode('create');
133
- setSelectedEntity(null);
134
- },
135
- onError: (error: any) => {
136
- setErrors({ _form: error.message || 'Operation failed' });
137
- }
138
- }
139
- );
140
- };
141
-
142
- // Handle entity selection for editing
143
- const handleEntitySelect = (entity: Entity) => {
144
- setSelectedEntity(entity);
145
- setFormMode('update');
146
- setActiveTab('edit');
147
- };
148
-
149
- // Handle lifecycle state transition
150
- const handleLifecycleTransition = (lifecycleName: string, toState: string) => {
151
- if (!selectedEntity) return;
152
-
153
- transitionState(
154
- { modelName, entityId: selectedEntity.id, toState, lifecycleName },
155
- {
156
- onSuccess: () => {
157
- setSelectedLifecycleStates((prev) => ({ ...prev, [lifecycleName]: toState }));
158
- },
159
- onError: (error: any) => {
160
- setErrors({ _lifecycle: error.message || 'Transition failed' });
161
- }
162
- }
163
- );
164
- };
165
-
166
- // Render field input
167
- const renderFieldInput = (attrName: string, attrDef: any) => {
168
- const value = formData[attrName] ?? '';
169
- const isRequired = isFieldRequired(attrDef);
170
-
171
- const handleChange = (newValue: any) => {
172
- setFormData((prev) => ({ ...prev, [attrName]: newValue }));
173
- };
174
-
175
- // Boolean field
176
- if (attrDef.type === 'Boolean') {
177
- return (
178
- <input
179
- type="checkbox"
180
- checked={!!value}
181
- onChange={(e) => handleChange(e.target.checked)}
182
- className="h-4 w-4 rounded border-gray-300"
183
- />
184
- );
185
- }
186
-
187
- // Number field
188
- if (attrDef.type === 'Integer' || attrDef.type === 'Float' || attrDef.type === 'Decimal') {
189
- return (
190
- <input
191
- type="number"
192
- value={value}
193
- onChange={(e) => handleChange(e.target.value ? Number(e.target.value) : '')}
194
- required={isRequired}
195
- className="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
196
- />
197
- );
198
- }
199
-
200
- // Text field (default)
201
- return (
202
- <input
203
- type="text"
204
- value={value}
205
- onChange={(e) => handleChange(e.target.value)}
206
- required={isRequired}
207
- className="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
208
- />
209
- );
210
- };
211
-
212
- return (
213
- <div className="flex gap-4 h-full">
214
- {/* Form Panel */}
215
- <div className="flex-1 bg-white dark:bg-gray-800 rounded-lg shadow p-6">
216
- <h2 className="text-2xl font-bold mb-4 text-gray-800 dark:text-white">
217
- {formMode === 'create' ? \`Create \${modelName}\` : \`Edit \${modelName}\`}
218
- </h2>
219
-
220
- {/* Tabs for Edit/Evolve modes */}
221
- {formMode === 'update' && Object.keys(lifecycles).length > 0 && (
222
- <div className="flex gap-2 mb-4 border-b border-gray-200">
223
- <button
224
- onClick={() => setActiveTab('edit')}
225
- className={\`px-4 py-2 font-medium \${activeTab === 'edit' ? 'border-b-2 border-blue-500 text-blue-600' : 'text-gray-500'}\`}
226
- >
227
- Edit Data
228
- </button>
229
- <button
230
- onClick={() => setActiveTab('evolve')}
231
- className={\`px-4 py-2 font-medium \${activeTab === 'evolve' ? 'border-b-2 border-blue-500 text-blue-600' : 'text-gray-500'}\`}
232
- >
233
- Lifecycle
234
- </button>
235
- </div>
236
- )}
237
-
238
- {activeTab === 'edit' ? (
239
- <form onSubmit={handleSubmit} className="space-y-4">
240
- {errors._form && (
241
- <div className="p-3 bg-red-100 text-red-700 rounded-md">{errors._form}</div>
242
- )}
243
-
244
- {/* Attributes */}
245
- {Object.entries(attributes).map(([attrName, attrDef]: [string, any]) => {
246
- if (!shouldShowField(attrName, attrDef)) return null;
247
-
248
- return (
249
- <div key={attrName}>
250
- <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
251
- {attrName}
252
- {isFieldRequired(attrDef) && <span className="text-red-500">*</span>}
253
- </label>
254
- {renderFieldInput(attrName, attrDef)}
255
- </div>
256
- );
257
- })}
258
-
259
- {/* Relationships */}
260
- {Object.entries(relationships).map(([relName, relDef]: [string, any]) => (
261
- <RelationshipField
262
- key={relName}
263
- name={relName}
264
- definition={relDef}
265
- value={formData[relName]}
266
- onChange={(value) => setFormData((prev) => ({ ...prev, [relName]: value }))}
267
- entities={entitiesStore}
268
- />
269
- ))}
270
-
271
- <div className="flex gap-2 pt-4">
272
- <button
273
- type="submit"
274
- disabled={isPending}
275
- className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
276
- >
277
- {isPending ? 'Saving...' : formMode === 'create' ? 'Create' : 'Update'}
278
- </button>
279
- {formMode === 'update' && (
280
- <button
281
- type="button"
282
- onClick={() => {
283
- setFormMode('create');
284
- setSelectedEntity(null);
285
- setFormData(initializeFormData(schema.attributes, { includeAutoGenerated: false }));
286
- }}
287
- className="px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600"
288
- >
289
- Cancel
290
- </button>
291
- )}
292
- </div>
293
- </form>
294
- ) : (
295
- /* Lifecycle Tab */
296
- <div className="space-y-4">
297
- {errors._lifecycle && (
298
- <div className="p-3 bg-red-100 text-red-700 rounded-md">{errors._lifecycle}</div>
299
- )}
300
-
301
- {Object.entries(lifecycles).map(([lifecycleName, lifecycle]: [string, any]) => {
302
- const currentState = selectedLifecycleStates[lifecycleName] || lifecycle.initial;
303
-
304
- return (
305
- <div key={lifecycleName} className="border border-gray-200 rounded-lg p-4">
306
- <h3 className="font-semibold text-lg mb-2">{lifecycleName}</h3>
307
- <p className="text-sm text-gray-600 mb-3">Current: {currentState}</p>
308
-
309
- <div className="flex flex-wrap gap-2">
310
- {Object.keys(lifecycle.states || {}).map((state) => (
311
- <button
312
- key={state}
313
- onClick={() => handleLifecycleTransition(lifecycleName, state)}
314
- disabled={isTransitioning || state === currentState}
315
- className={\`px-3 py-1 rounded-md \${state === currentState ? 'bg-blue-600 text-white' : 'bg-gray-200 text-gray-700 hover:bg-gray-300'} disabled:opacity-50\`}
316
- >
317
- {state}
318
- </button>
319
- ))}
320
- </div>
321
- </div>
322
- );
323
- })}
324
- </div>
325
- )}
326
- </div>
327
-
328
- {/* Entity List Panel */}
329
- <div className="w-80 bg-white dark:bg-gray-800 rounded-lg shadow p-4">
330
- <h3 className="text-lg font-semibold mb-3 text-gray-800 dark:text-white">
331
- {modelName} List
332
- </h3>
333
-
334
- {entitiesLoading ? (
335
- <p className="text-gray-500">Loading...</p>
336
- ) : entities.length === 0 ? (
337
- <p className="text-gray-500 italic">No entities yet</p>
338
- ) : (
339
- <div className="space-y-2">
340
- {entities.map((entity) => (
341
- <div
342
- key={entity.id}
343
- onClick={() => handleEntitySelect(entity)}
344
- className={\`p-3 rounded-md cursor-pointer \${selectedEntity?.id === entity.id ? 'bg-blue-100 border-blue-500' : 'bg-gray-50 hover:bg-gray-100'} border\`}
345
- >
346
- <p className="font-medium text-sm">{entity.id}</p>
347
- {Object.entries(entity.data).slice(0, 2).map(([key, value]) => (
348
- <p key={key} className="text-xs text-gray-600">
349
- {key}: {String(value)}
350
- </p>
351
- ))}
352
- </div>
353
- ))}
354
- </div>
355
- )}
356
- </div>
357
- </div>
358
- );
359
- }
360
-
361
- export default FormView;
362
- `;
363
- }
364
- function generateListView() {
365
- return `/**
366
- * StandardListView - Controller-Based List View Component
367
- *
368
- * LOCAL VERSION - Uses local hooks with instance-factory-specific API client
369
- */
370
-
371
- import { useEntitiesQuery, useModelSchemaQuery } from '../../hooks/useApi';
372
- import type { View } from '../../types/api';
373
-
374
- interface StandardListViewProps {
375
- view: View;
376
- spec?: any;
377
- }
378
-
379
- export function ListView({ view, spec }: StandardListViewProps) {
380
- let controllerName: string;
381
- let modelName: string;
382
-
383
- if (view.controller && spec) {
384
- controllerName = view.controller;
385
- const controller = spec.controllers[view.controller];
386
- modelName = controller.model;
387
- } else {
388
- modelName = view.model as string;
389
- controllerName = \`\${modelName}Controller\`;
390
- }
391
-
392
- const { data: entities = [], isLoading } = useEntitiesQuery(controllerName, modelName);
393
- const { data: schema } = useModelSchemaQuery(modelName);
394
-
395
- if (isLoading) {
396
- return <div className="p-4">Loading...</div>;
397
- }
398
-
399
- return (
400
- <div className="p-6">
401
- <h2 className="text-2xl font-bold mb-4">{modelName} List</h2>
402
- <div className="overflow-x-auto">
403
- <table className="min-w-full bg-white border border-gray-200">
404
- <thead className="bg-gray-50">
405
- <tr>
406
- <th className="px-4 py-2 border-b">ID</th>
407
- {schema && Object.keys(schema.attributes || {}).map((attr) => (
408
- <th key={attr} className="px-4 py-2 border-b">{attr}</th>
409
- ))}
410
- </tr>
411
- </thead>
412
- <tbody>
413
- {entities.map((entity) => (
414
- <tr key={entity.id} className="hover:bg-gray-50">
415
- <td className="px-4 py-2 border-b">{entity.id}</td>
416
- {schema && Object.keys(schema.attributes || {}).map((attr) => (
417
- <td key={attr} className="px-4 py-2 border-b">
418
- {String(entity.data[attr] ?? '')}
419
- </td>
420
- ))}
421
- </tr>
422
- ))}
423
- </tbody>
424
- </table>
425
- </div>
426
- </div>
427
- );
428
- }
429
-
430
- export default ListView;
431
- `;
432
- }
433
- function generateDetailView() {
434
- return `/**
435
- * StandardDetailView - Controller-Based Detail View Component
436
- *
437
- * LOCAL VERSION - Uses local hooks with instance-factory-specific API client
438
- */
439
-
440
- import { useEntitiesQuery, useModelSchemaQuery } from '../../hooks/useApi';
441
- import type { View } from '../../types/api';
442
-
443
- interface StandardDetailViewProps {
444
- view: View;
445
- spec?: any;
446
- }
447
-
448
- export function DetailView({ view, spec }: StandardDetailViewProps) {
449
- let controllerName: string;
450
- let modelName: string;
451
-
452
- if (view.controller && spec) {
453
- controllerName = view.controller;
454
- const controller = spec.controllers[view.controller];
455
- modelName = controller.model;
456
- } else {
457
- modelName = view.model as string;
458
- controllerName = \`\${modelName}Controller\`;
459
- }
460
-
461
- const { data: entities = [] } = useEntitiesQuery(controllerName, modelName);
462
- const { data: schema } = useModelSchemaQuery(modelName);
463
- const entity = entities[0];
464
-
465
- if (!entity) {
466
- return <div className="p-4">No entity selected</div>;
467
- }
468
-
469
- return (
470
- <div className="p-6">
471
- <h2 className="text-2xl font-bold mb-4">{modelName} Detail</h2>
472
- <div className="space-y-2">
473
- <div>
474
- <span className="font-semibold">ID:</span> {entity.id}
475
- </div>
476
- {schema && Object.entries(schema.attributes || {}).map(([attr, def]: [string, any]) => (
477
- <div key={attr}>
478
- <span className="font-semibold">{attr}:</span> {String(entity.data[attr] ?? '')}
479
- </div>
480
- ))}
481
- </div>
482
- </div>
483
- );
484
- }
485
-
486
- export default DetailView;
487
- `;
488
- }
489
- function generateDashboardView() {
490
- return `/**
491
- * StandardDashboardView - Controller-Based Dashboard View Component
492
- *
493
- * LOCAL VERSION - Uses local hooks with instance-factory-specific API client
494
- */
495
-
496
- import type { View } from '../../types/api';
497
-
498
- interface StandardDashboardViewProps {
499
- view: View;
500
- spec?: any;
501
- }
502
-
503
- export function DashboardView({ view, spec }: StandardDashboardViewProps) {
504
- return (
505
- <div className="p-6">
506
- <h2 className="text-2xl font-bold mb-4">Dashboard</h2>
507
- <div className="grid grid-cols-3 gap-4">
508
- <div className="bg-white p-4 rounded-lg shadow">
509
- <h3 className="text-lg font-semibold">Card 1</h3>
510
- <p>Content here</p>
511
- </div>
512
- <div className="bg-white p-4 rounded-lg shadow">
513
- <h3 className="text-lg font-semibold">Card 2</h3>
514
- <p>Content here</p>
515
- </div>
516
- <div className="bg-white p-4 rounded-lg shadow">
517
- <h3 className="text-lg font-semibold">Card 3</h3>
518
- <p>Content here</p>
519
- </div>
520
- </div>
521
- </div>
522
- );
523
- }
524
-
525
- export default DashboardView;
526
- `;
527
- }
528
- export {
529
- generate
530
- };
@@ -1,73 +0,0 @@
1
- function generateAppTsx(context) {
2
- const { spec } = context;
3
- let viewList = [];
4
- if (spec.views) {
5
- viewList = Array.isArray(spec.views) ? spec.views : Object.entries(spec.views).map(([name, def]) => ({ name, ...def }));
6
- }
7
- const modelViews = /* @__PURE__ */ new Map();
8
- const dashboardView = viewList.find((v) => v.type === "dashboard")?.name || null;
9
- for (const view of viewList) {
10
- const model = Array.isArray(view.model) ? view.model[0] : view.model || view.primaryModel;
11
- if (!model) continue;
12
- if (!modelViews.has(model)) modelViews.set(model, { other: [] });
13
- const entry = modelViews.get(model);
14
- const type = view.type || "list";
15
- if (type === "list") entry.list = view.name;
16
- else if (type === "detail") entry.detail = view.name;
17
- else if (type === "form") entry.form = view.name;
18
- else if (type !== "dashboard") entry.other.push(view.name);
19
- }
20
- const imports = viewList.map((v) => `import ${v.name} from './components/${v.name}';`).join("\n");
21
- const routes = viewList.map((v) => {
22
- const path = `/${v.name.toLowerCase().replace("view", "")}`;
23
- return ` <Route path="${path}" element={<${v.name} />} />`;
24
- }).join("\n");
25
- const defaultView = dashboardView || viewList[0]?.name || "div";
26
- const defaultElement = defaultView === "div" ? '<div className="p-8">Welcome</div>' : `<${defaultView} />`;
27
- const navGroups = Array.from(modelViews.entries()).map(([model, views]) => {
28
- const lower = model.charAt(0).toLowerCase() + model.slice(1);
29
- const listPath = views.list ? `/${views.list.toLowerCase().replace("view", "")}` : "";
30
- const formPath = views.form ? `/${views.form.toLowerCase().replace("view", "")}` : "";
31
- return ` <div>
32
- <h3 className="px-3 text-xs font-semibold text-gray-400 uppercase tracking-wider mb-1">${model}s</h3>
33
- ${listPath ? ` <a href="${listPath}" className="block px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100 rounded">Browse</a>` : ""}
34
- ${formPath ? ` <a href="${formPath}" className="block px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100 rounded">+ New</a>` : ""}
35
- </div>`;
36
- }).join("\n");
37
- return `import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
38
- ${imports}
39
-
40
- function App() {
41
- return (
42
- <Router>
43
- <div className="flex min-h-screen bg-gray-50">
44
- {/* Sidebar */}
45
- <aside className="w-56 bg-white border-r border-gray-200 p-4 space-y-5">
46
- <div>
47
- <h1 className="text-lg font-bold text-gray-900">SpecVerse App</h1>
48
- <p className="text-xs text-gray-400">Generated from specification</p>
49
- </div>
50
- ${dashboardView ? ` <a href="/dashboard" className="block px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 rounded">Dashboard</a>` : ""}
51
- ${navGroups}
52
- </aside>
53
-
54
- {/* Main content */}
55
- <main className="flex-1 overflow-auto">
56
- <Routes>
57
- <Route path="/" element={${defaultElement}} />
58
- ${dashboardView ? ` <Route path="/dashboard" element={<${dashboardView} />} />` : ""}
59
- ${routes}
60
- <Route path="*" element={<div className="p-8"><h1 className="text-2xl">404 - Not Found</h1></div>} />
61
- </Routes>
62
- </main>
63
- </div>
64
- </Router>
65
- );
66
- }
67
-
68
- export default App;
69
- `;
70
- }
71
- export {
72
- generateAppTsx as default
73
- };
@@ -1,99 +0,0 @@
1
- async function generate(context) {
2
- return `/**
3
- * Utility functions for form field handling
4
- */
5
-
6
- /**
7
- * Check if a field should be hidden because it's auto-generated
8
- */
9
- export function isAutoGeneratedField(attrName: string, attrDef: any): boolean {
10
- const typeStr = typeof attrDef === 'string' ? attrDef : attrDef?.type || '';
11
-
12
- // Hide UUID id field
13
- if (attrName === 'id' && typeStr.includes('UUID')) return true;
14
-
15
- // Hide auto-generated DateTime fields
16
- const autoDateFields = ['createdAt', 'updatedAt', 'joinedAt', 'publishedAt'];
17
- if (autoDateFields.includes(attrName) && typeStr.includes('DateTime')) return true;
18
-
19
- return false;
20
- }
21
-
22
- /**
23
- * Check if a field is required
24
- */
25
- export function isFieldRequired(attrDef: any): boolean {
26
- if (!attrDef) return false;
27
- if (typeof attrDef === 'string') {
28
- return attrDef.toLowerCase().includes('required');
29
- }
30
- return attrDef.required === true;
31
- }
32
-
33
- /**
34
- * Get default value for a field based on its type
35
- */
36
- export function getFieldDefaultValue(attrDef: any): any {
37
- if (!attrDef) return '';
38
-
39
- const typeStr = typeof attrDef === 'string' ? attrDef : attrDef?.type || '';
40
-
41
- // Check if schema has a default value
42
- if (attrDef && typeof attrDef === 'object' && attrDef.default !== undefined) {
43
- const defaultVal = attrDef.default;
44
- // Parse string defaults to proper types
45
- if (typeStr.toLowerCase().includes('bool')) {
46
- return defaultVal === 'true' || defaultVal === true;
47
- } else if (
48
- typeStr.toLowerCase().includes('int') ||
49
- typeStr.toLowerCase().includes('number')
50
- ) {
51
- return typeof defaultVal === 'number' ? defaultVal : parseInt(defaultVal) || 0;
52
- } else if (typeStr.toLowerCase().includes('string')) {
53
- // Remove surrounding quotes if present
54
- return typeof defaultVal === 'string'
55
- ? defaultVal.replace(/^"|"$/g, '')
56
- : defaultVal;
57
- } else {
58
- return defaultVal;
59
- }
60
- }
61
-
62
- // Otherwise use type-based defaults
63
- if (typeStr.toLowerCase().includes('bool')) {
64
- return false;
65
- } else if (
66
- typeStr.toLowerCase().includes('int') ||
67
- typeStr.toLowerCase().includes('number')
68
- ) {
69
- return 0;
70
- } else {
71
- return '';
72
- }
73
- }
74
-
75
- /**
76
- * Initialize form data from schema attributes
77
- */
78
- export function initializeFormData(
79
- attributes: Record<string, any>,
80
- options: { includeAutoGenerated?: boolean } = {}
81
- ): Record<string, any> {
82
- const data: Record<string, any> = {};
83
-
84
- Object.entries(attributes).forEach(([attrName, attrDef]) => {
85
- // Skip auto-generated fields unless explicitly included
86
- if (!options.includeAutoGenerated && isAutoGeneratedField(attrName, attrDef)) {
87
- return;
88
- }
89
-
90
- data[attrName] = getFieldDefaultValue(attrDef);
91
- });
92
-
93
- return data;
94
- }
95
- `;
96
- }
97
- export {
98
- generate
99
- };