@specverse/engines 4.1.30 → 4.2.1

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 (285) 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/assets/templates/default/specs/main.specly +65 -0
  5. package/dist/inference/comprehensive-engine.d.ts.map +1 -1
  6. package/dist/inference/comprehensive-engine.js +3 -19
  7. package/dist/inference/comprehensive-engine.js.map +1 -1
  8. package/dist/inference/core/rule-engine.d.ts +31 -0
  9. package/dist/inference/core/rule-engine.d.ts.map +1 -1
  10. package/dist/inference/core/rule-engine.js +117 -33
  11. package/dist/inference/core/rule-engine.js.map +1 -1
  12. package/dist/inference/core/rule-file-types.d.ts +0 -2
  13. package/dist/inference/core/rule-file-types.d.ts.map +1 -1
  14. package/dist/inference/core/rule-file-types.js +3 -6
  15. package/dist/inference/core/rule-file-types.js.map +1 -1
  16. package/dist/inference/core/rule-loader.d.ts +5 -15
  17. package/dist/inference/core/rule-loader.d.ts.map +1 -1
  18. package/dist/inference/core/rule-loader.js +43 -132
  19. package/dist/inference/core/rule-loader.js.map +1 -1
  20. package/dist/inference/core/types.d.ts +0 -6
  21. package/dist/inference/core/types.d.ts.map +1 -1
  22. package/dist/inference/core/types.js +0 -4
  23. package/dist/inference/core/types.js.map +1 -1
  24. package/dist/inference/logical/generators/component-type-resolver.d.ts +0 -26
  25. package/dist/inference/logical/generators/component-type-resolver.d.ts.map +1 -1
  26. package/dist/inference/logical/generators/component-type-resolver.js +0 -19
  27. package/dist/inference/logical/generators/component-type-resolver.js.map +1 -1
  28. package/dist/inference/logical/generators/specialist-view-expander.d.ts +1 -17
  29. package/dist/inference/logical/generators/specialist-view-expander.d.ts.map +1 -1
  30. package/dist/inference/logical/generators/specialist-view-expander.js +0 -15
  31. package/dist/inference/logical/generators/specialist-view-expander.js.map +1 -1
  32. package/dist/inference/logical/generators/view-generator.d.ts +4 -14
  33. package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
  34. package/dist/inference/logical/generators/view-generator.js +6 -26
  35. package/dist/inference/logical/generators/view-generator.js.map +1 -1
  36. package/dist/inference/logical/index.d.ts +2 -2
  37. package/dist/inference/logical/index.d.ts.map +1 -1
  38. package/dist/inference/logical/logical-engine.d.ts.map +1 -1
  39. package/dist/inference/logical/logical-engine.js +17 -80
  40. package/dist/inference/logical/logical-engine.js.map +1 -1
  41. package/dist/inference/quint-transpiler.d.ts +5 -3
  42. package/dist/inference/quint-transpiler.d.ts.map +1 -1
  43. package/dist/inference/quint-transpiler.js +11 -6
  44. package/dist/inference/quint-transpiler.js.map +1 -1
  45. package/dist/libs/instance-factories/CURVED-INTERFACE.md +278 -0
  46. package/dist/libs/instance-factories/README.md +73 -0
  47. package/dist/libs/instance-factories/applications/README.md +51 -0
  48. package/dist/libs/instance-factories/applications/generic-app.yaml +52 -0
  49. package/{libs/instance-factories/applications/react-app.yaml → dist/libs/instance-factories/applications/react-app-runtime.yaml} +30 -77
  50. package/dist/libs/instance-factories/applications/react-app-starter.yaml +143 -0
  51. package/dist/libs/instance-factories/applications/templates/react/env-example-generator.js +24 -2
  52. package/dist/libs/instance-factories/applications/templates/react/vite-config-generator.js +54 -33
  53. package/dist/libs/instance-factories/applications/templates/react-starter/README.md +211 -0
  54. package/dist/libs/instance-factories/applications/templates/react-starter/api-types-starter-generator.js +69 -0
  55. package/dist/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.js +110 -0
  56. package/dist/libs/instance-factories/applications/templates/react-starter/belongs-to.js +40 -0
  57. package/dist/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.js +129 -0
  58. package/dist/libs/instance-factories/applications/templates/react-starter/detail-body-composer.js +80 -0
  59. package/dist/libs/instance-factories/applications/templates/react-starter/form-body-composer.js +217 -0
  60. package/dist/libs/instance-factories/applications/templates/react-starter/helpers-emitter.js +51 -0
  61. package/dist/libs/instance-factories/applications/templates/react-starter/html-to-jsx.js +192 -0
  62. package/dist/libs/instance-factories/applications/templates/react-starter/list-body-composer.js +56 -0
  63. package/dist/libs/instance-factories/applications/templates/react-starter/orchestrator.js +41 -0
  64. package/dist/libs/instance-factories/applications/templates/react-starter/package-json-generator.js +38 -0
  65. package/dist/libs/instance-factories/applications/templates/react-starter/regen-safety.js +89 -0
  66. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/dashboard.tsx.template +49 -0
  67. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/detail.tsx.template +96 -0
  68. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/form.tsx.template +116 -0
  69. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/list.tsx.template +74 -0
  70. package/dist/libs/instance-factories/applications/templates/react-starter/use-api-hooks-starter-generator.js +95 -0
  71. package/dist/libs/instance-factories/applications/templates/react-starter/view-emitter.js +81 -0
  72. package/dist/libs/instance-factories/applications/templates/react-starter/views-generator.js +66 -0
  73. package/dist/libs/instance-factories/archived/fastify-prisma.yaml +104 -0
  74. package/dist/libs/instance-factories/cli/README.md +43 -0
  75. package/dist/libs/instance-factories/cli/commander-js.yaml +55 -0
  76. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +63 -12
  77. package/dist/libs/instance-factories/communication/README.md +47 -0
  78. package/dist/libs/instance-factories/communication/event-emitter.yaml +60 -0
  79. package/dist/libs/instance-factories/communication/rabbitmq-events.yaml +87 -0
  80. package/dist/libs/instance-factories/controllers/README.md +42 -0
  81. package/dist/libs/instance-factories/controllers/fastify.yaml +139 -0
  82. package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +29 -2
  83. package/dist/libs/instance-factories/infrastructure/README.md +29 -0
  84. package/dist/libs/instance-factories/infrastructure/docker-k8s.yaml +61 -0
  85. package/dist/libs/instance-factories/orms/README.md +54 -0
  86. package/dist/libs/instance-factories/orms/prisma.yaml +89 -0
  87. package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +2 -2
  88. package/dist/libs/instance-factories/scaffolding/README.md +49 -0
  89. package/dist/libs/instance-factories/scaffolding/generic-scaffold.yaml +65 -0
  90. package/dist/libs/instance-factories/sdks/README.md +28 -0
  91. package/dist/libs/instance-factories/sdks/python-sdk.yaml +66 -0
  92. package/dist/libs/instance-factories/sdks/typescript-sdk.yaml +59 -0
  93. package/dist/libs/instance-factories/services/README.md +55 -0
  94. package/dist/libs/instance-factories/services/prisma-services.yaml +71 -0
  95. package/dist/libs/instance-factories/storage/README.md +34 -0
  96. package/dist/libs/instance-factories/storage/mongodb.yaml +79 -0
  97. package/dist/libs/instance-factories/storage/postgresql.yaml +75 -0
  98. package/dist/libs/instance-factories/storage/redis.yaml +79 -0
  99. package/dist/libs/instance-factories/testing/README.md +40 -0
  100. package/dist/libs/instance-factories/testing/vitest-tests.yaml +63 -0
  101. package/dist/libs/instance-factories/tools/README.md +70 -0
  102. package/dist/libs/instance-factories/tools/mcp.yaml +36 -0
  103. package/dist/libs/instance-factories/tools/vscode.yaml +35 -0
  104. package/dist/libs/instance-factories/validation/README.md +38 -0
  105. package/dist/libs/instance-factories/validation/zod.yaml +56 -0
  106. package/dist/realize/engines/code-generator.d.ts.map +1 -1
  107. package/dist/realize/engines/code-generator.js +3 -0
  108. package/dist/realize/engines/code-generator.js.map +1 -1
  109. package/dist/realize/index.d.ts.map +1 -1
  110. package/dist/realize/index.js +15 -22
  111. package/dist/realize/index.js.map +1 -1
  112. package/dist/registry/utils/manifest-adapter.d.ts +8 -1
  113. package/dist/registry/utils/manifest-adapter.d.ts.map +1 -1
  114. package/dist/registry/utils/manifest-adapter.js +8 -1
  115. package/dist/registry/utils/manifest-adapter.js.map +1 -1
  116. package/libs/instance-factories/applications/react-app-starter.yaml +143 -0
  117. package/libs/instance-factories/applications/templates/react/env-example-generator.ts +24 -2
  118. package/libs/instance-factories/applications/templates/react/vite-config-generator.ts +54 -33
  119. package/libs/instance-factories/applications/templates/react-starter/README.md +211 -0
  120. package/libs/instance-factories/applications/templates/react-starter/__tests__/dashboard-body-composer.test.ts +153 -0
  121. package/libs/instance-factories/applications/templates/react-starter/__tests__/detail-body-composer.test.ts +146 -0
  122. package/libs/instance-factories/applications/templates/react-starter/__tests__/form-body-composer.test.ts +188 -0
  123. package/libs/instance-factories/applications/templates/react-starter/__tests__/helpers-emitter.test.ts +55 -0
  124. package/libs/instance-factories/applications/templates/react-starter/__tests__/html-to-jsx.test.ts +140 -0
  125. package/libs/instance-factories/applications/templates/react-starter/__tests__/list-body-composer.test.ts +146 -0
  126. package/libs/instance-factories/applications/templates/react-starter/__tests__/orchestrator.test.ts +184 -0
  127. package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p2-factory-imports.test.ts +116 -0
  128. package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p3-rendered-output.test.ts +183 -0
  129. package/libs/instance-factories/applications/templates/react-starter/__tests__/regen-safety.test.ts +144 -0
  130. package/libs/instance-factories/applications/templates/react-starter/__tests__/starter-generators.test.ts +114 -0
  131. package/libs/instance-factories/applications/templates/react-starter/__tests__/view-emitter.test.ts +107 -0
  132. package/libs/instance-factories/applications/templates/react-starter/__tests__/views-generator.test.ts +139 -0
  133. package/libs/instance-factories/applications/templates/react-starter/api-types-starter-generator.ts +98 -0
  134. package/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.ts +141 -0
  135. package/libs/instance-factories/applications/templates/react-starter/belongs-to.ts +82 -0
  136. package/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.ts +189 -0
  137. package/libs/instance-factories/applications/templates/react-starter/detail-body-composer.ts +135 -0
  138. package/libs/instance-factories/applications/templates/react-starter/form-body-composer.ts +383 -0
  139. package/libs/instance-factories/applications/templates/react-starter/helpers-emitter.ts +66 -0
  140. package/libs/instance-factories/applications/templates/react-starter/html-to-jsx.ts +334 -0
  141. package/libs/instance-factories/applications/templates/react-starter/list-body-composer.ts +146 -0
  142. package/libs/instance-factories/applications/templates/react-starter/orchestrator.ts +95 -0
  143. package/libs/instance-factories/applications/templates/react-starter/package-json-generator.ts +57 -0
  144. package/libs/instance-factories/applications/templates/react-starter/regen-safety.ts +157 -0
  145. package/libs/instance-factories/applications/templates/react-starter/skeletons/dashboard.tsx.template +49 -0
  146. package/libs/instance-factories/applications/templates/react-starter/skeletons/detail.tsx.template +96 -0
  147. package/libs/instance-factories/applications/templates/react-starter/skeletons/form.tsx.template +116 -0
  148. package/libs/instance-factories/applications/templates/react-starter/skeletons/list.tsx.template +74 -0
  149. package/libs/instance-factories/applications/templates/react-starter/use-api-hooks-starter-generator.ts +124 -0
  150. package/libs/instance-factories/applications/templates/react-starter/view-emitter.ts +209 -0
  151. package/libs/instance-factories/applications/templates/react-starter/views-generator.ts +137 -0
  152. package/libs/instance-factories/cli/templates/commander/command-generator.ts +63 -12
  153. package/libs/instance-factories/controllers/fastify.yaml +7 -0
  154. package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +36 -2
  155. package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +11 -4
  156. package/package.json +3 -3
  157. package/dist/libs/instance-factories/applications/templates/react/_view-components-source.js +0 -530
  158. package/dist/libs/instance-factories/applications/templates/react/app-tsx-generator.js +0 -73
  159. package/dist/libs/instance-factories/applications/templates/react/field-helpers-generator.js +0 -99
  160. package/dist/libs/instance-factories/applications/templates/react/package-json-generator.js +0 -49
  161. package/dist/libs/instance-factories/applications/templates/react/pattern-adapter-generator.js +0 -156
  162. package/dist/libs/instance-factories/applications/templates/react/react-pattern-adapter.js +0 -935
  163. package/dist/libs/instance-factories/applications/templates/react/relationship-field-generator.js +0 -143
  164. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.js +0 -646
  165. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.js +0 -65
  166. package/dist/libs/instance-factories/applications/templates/react/view-dashboard-generator.js +0 -143
  167. package/dist/libs/instance-factories/applications/templates/react/view-detail-generator.js +0 -143
  168. package/dist/libs/instance-factories/applications/templates/react/view-form-generator.js +0 -355
  169. package/dist/libs/instance-factories/applications/templates/react/view-list-generator.js +0 -91
  170. package/dist/libs/instance-factories/applications/templates/react/view-router-generator.js +0 -79
  171. package/dist/libs/instance-factories/views/index.js +0 -48
  172. package/dist/libs/instance-factories/views/templates/react/adapters/antd-adapter.js +0 -742
  173. package/dist/libs/instance-factories/views/templates/react/adapters/mui-adapter.js +0 -824
  174. package/dist/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.js +0 -719
  175. package/dist/libs/instance-factories/views/templates/react/app-generator.js +0 -45
  176. package/dist/libs/instance-factories/views/templates/react/components-generator.js +0 -820
  177. package/dist/libs/instance-factories/views/templates/react/forms-generator.js +0 -275
  178. package/dist/libs/instance-factories/views/templates/react/frontend-package-json-generator.js +0 -46
  179. package/dist/libs/instance-factories/views/templates/react/hooks-generator.js +0 -81
  180. package/dist/libs/instance-factories/views/templates/react/index-css-generator.js +0 -9
  181. package/dist/libs/instance-factories/views/templates/react/index-html-generator.js +0 -23
  182. package/dist/libs/instance-factories/views/templates/react/main-tsx-generator.js +0 -21
  183. package/dist/libs/instance-factories/views/templates/react/react-component-generator.js +0 -299
  184. package/dist/libs/instance-factories/views/templates/react/router-generator.js +0 -136
  185. package/dist/libs/instance-factories/views/templates/react/router-generic-generator.js +0 -107
  186. package/dist/libs/instance-factories/views/templates/react/shared-utils-generator.js +0 -187
  187. package/dist/libs/instance-factories/views/templates/react/spec-json-generator.js +0 -7
  188. package/dist/libs/instance-factories/views/templates/react/types-generator.js +0 -56
  189. package/dist/libs/instance-factories/views/templates/react/views-metadata-generator.js +0 -27
  190. package/dist/libs/instance-factories/views/templates/react/vite-config-generator.js +0 -29
  191. package/dist/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js +0 -261
  192. package/dist/libs/instance-factories/views/templates/shared/adapter-types.js +0 -34
  193. package/dist/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -800
  194. package/dist/libs/instance-factories/views/templates/shared/base-generator.js +0 -305
  195. package/dist/libs/instance-factories/views/templates/shared/component-metadata.js +0 -517
  196. package/dist/libs/instance-factories/views/templates/shared/composite-pattern-types.js +0 -0
  197. package/dist/libs/instance-factories/views/templates/shared/composite-patterns.js +0 -445
  198. package/dist/libs/instance-factories/views/templates/shared/index.js +0 -80
  199. package/dist/libs/instance-factories/views/templates/shared/pattern-validator.js +0 -210
  200. package/dist/libs/instance-factories/views/templates/shared/property-mapper.js +0 -492
  201. package/dist/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -321
  202. package/dist/realize/index.js.bak +0 -758
  203. package/libs/instance-factories/applications/templates/react/_view-components-source.ts +0 -555
  204. package/libs/instance-factories/applications/templates/react/app-tsx-generator.ts +0 -94
  205. package/libs/instance-factories/applications/templates/react/field-helpers-generator.ts +0 -106
  206. package/libs/instance-factories/applications/templates/react/package-json-generator.ts +0 -57
  207. package/libs/instance-factories/applications/templates/react/pattern-adapter-generator.ts +0 -179
  208. package/libs/instance-factories/applications/templates/react/react-pattern-adapter.tsx +0 -1347
  209. package/libs/instance-factories/applications/templates/react/relationship-field-generator.ts +0 -150
  210. package/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.ts +0 -704
  211. package/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.ts +0 -84
  212. package/libs/instance-factories/applications/templates/react/view-dashboard-generator.ts +0 -150
  213. package/libs/instance-factories/applications/templates/react/view-detail-generator.ts +0 -150
  214. package/libs/instance-factories/applications/templates/react/view-form-generator.ts +0 -362
  215. package/libs/instance-factories/applications/templates/react/view-list-generator.ts +0 -98
  216. package/libs/instance-factories/applications/templates/react/view-router-generator.ts +0 -89
  217. package/libs/instance-factories/views/README.md +0 -62
  218. package/libs/instance-factories/views/index.d.ts +0 -13
  219. package/libs/instance-factories/views/index.d.ts.map +0 -1
  220. package/libs/instance-factories/views/index.js +0 -18
  221. package/libs/instance-factories/views/index.js.map +0 -1
  222. package/libs/instance-factories/views/index.ts +0 -45
  223. package/libs/instance-factories/views/react-components.yaml +0 -129
  224. package/libs/instance-factories/views/templates/ARCHITECTURE.md +0 -198
  225. package/libs/instance-factories/views/templates/react/adapters/antd-adapter.ts +0 -869
  226. package/libs/instance-factories/views/templates/react/adapters/mui-adapter.ts +0 -953
  227. package/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.ts +0 -806
  228. package/libs/instance-factories/views/templates/react/app-generator.ts +0 -55
  229. package/libs/instance-factories/views/templates/react/components-generator.ts +0 -938
  230. package/libs/instance-factories/views/templates/react/forms-generator.ts +0 -325
  231. package/libs/instance-factories/views/templates/react/frontend-package-json-generator.ts +0 -57
  232. package/libs/instance-factories/views/templates/react/hooks-generator.ts +0 -106
  233. package/libs/instance-factories/views/templates/react/index-css-generator.ts +0 -14
  234. package/libs/instance-factories/views/templates/react/index-html-generator.ts +0 -34
  235. package/libs/instance-factories/views/templates/react/main-tsx-generator.ts +0 -29
  236. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts +0 -152
  237. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts.map +0 -1
  238. package/libs/instance-factories/views/templates/react/react-component-generator.js +0 -398
  239. package/libs/instance-factories/views/templates/react/react-component-generator.js.map +0 -1
  240. package/libs/instance-factories/views/templates/react/react-component-generator.ts +0 -533
  241. package/libs/instance-factories/views/templates/react/router-generator.ts +0 -197
  242. package/libs/instance-factories/views/templates/react/router-generic-generator.ts +0 -132
  243. package/libs/instance-factories/views/templates/react/shared-utils-generator.ts +0 -196
  244. package/libs/instance-factories/views/templates/react/spec-json-generator.ts +0 -17
  245. package/libs/instance-factories/views/templates/react/types-generator.ts +0 -76
  246. package/libs/instance-factories/views/templates/react/views-metadata-generator.ts +0 -42
  247. package/libs/instance-factories/views/templates/react/vite-config-generator.ts +0 -38
  248. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.d.ts.map +0 -1
  249. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js.map +0 -1
  250. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.ts +0 -474
  251. package/libs/instance-factories/views/templates/shared/__tests__/composite-patterns.test.ts +0 -242
  252. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts +0 -77
  253. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts.map +0 -1
  254. package/libs/instance-factories/views/templates/shared/adapter-types.js +0 -47
  255. package/libs/instance-factories/views/templates/shared/adapter-types.js.map +0 -1
  256. package/libs/instance-factories/views/templates/shared/adapter-types.ts +0 -142
  257. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts +0 -63
  258. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts.map +0 -1
  259. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -822
  260. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js.map +0 -1
  261. package/libs/instance-factories/views/templates/shared/atomic-components-registry.ts +0 -908
  262. package/libs/instance-factories/views/templates/shared/base-generator.d.ts +0 -247
  263. package/libs/instance-factories/views/templates/shared/base-generator.d.ts.map +0 -1
  264. package/libs/instance-factories/views/templates/shared/base-generator.js +0 -363
  265. package/libs/instance-factories/views/templates/shared/base-generator.js.map +0 -1
  266. package/libs/instance-factories/views/templates/shared/base-generator.ts +0 -608
  267. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts +0 -254
  268. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts.map +0 -1
  269. package/libs/instance-factories/views/templates/shared/component-metadata.js +0 -602
  270. package/libs/instance-factories/views/templates/shared/component-metadata.js.map +0 -1
  271. package/libs/instance-factories/views/templates/shared/component-metadata.ts +0 -803
  272. package/libs/instance-factories/views/templates/shared/composite-pattern-types.ts +0 -250
  273. package/libs/instance-factories/views/templates/shared/composite-patterns.ts +0 -535
  274. package/libs/instance-factories/views/templates/shared/index.ts +0 -68
  275. package/libs/instance-factories/views/templates/shared/pattern-validator.ts +0 -279
  276. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts +0 -149
  277. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts.map +0 -1
  278. package/libs/instance-factories/views/templates/shared/property-mapper.js +0 -580
  279. package/libs/instance-factories/views/templates/shared/property-mapper.js.map +0 -1
  280. package/libs/instance-factories/views/templates/shared/property-mapper.ts +0 -700
  281. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts +0 -143
  282. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts.map +0 -1
  283. package/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -420
  284. package/libs/instance-factories/views/templates/shared/syntax-mapper.js.map +0 -1
  285. package/libs/instance-factories/views/templates/shared/syntax-mapper.ts +0 -539
@@ -0,0 +1,143 @@
1
+ name: ReactAppStarter
2
+ version: "1.0.0"
3
+ category: view
4
+ description: "Fully standalone React starter kit — pre-rendered view components the user can fork and extend. No @specverse/runtime dependency."
5
+
6
+ metadata:
7
+ author: "SpecVerse Team"
8
+ license: "MIT"
9
+ tags: [react, vite, spa, frontend, starter, editable]
10
+ mode: starter
11
+
12
+ compatibility:
13
+ specverse: ">=4.0.0"
14
+ node: ">=18.0.0"
15
+
16
+ capabilities:
17
+ provides:
18
+ - "app.frontend"
19
+ - "ui.scaffolding"
20
+ - "ui.router"
21
+ - "ui.staticviews"
22
+ - "ui.staticforms"
23
+ - "ui.staticcomponents"
24
+ requires: []
25
+
26
+ technology:
27
+ runtime: "browser"
28
+ language: "typescript"
29
+ framework: "react"
30
+ bundler: "vite"
31
+ version: "^18.2.0"
32
+
33
+ dependencies:
34
+ # Runtime deps baked into the generated package.json.
35
+ # Deliberately no @specverse/runtime — the starter kit is
36
+ # standalone by design.
37
+ runtime:
38
+ - name: "react"
39
+ version: "^18.2.0"
40
+ - name: "react-dom"
41
+ version: "^18.2.0"
42
+ - name: "@tanstack/react-query"
43
+ version: "^5.0.0"
44
+
45
+ dev:
46
+ - name: "@types/react"
47
+ version: "^18.2.0"
48
+ - name: "@types/react-dom"
49
+ version: "^18.2.0"
50
+ - name: "typescript"
51
+ version: "^5.2.0"
52
+ - name: "vite"
53
+ version: "^6.0.0"
54
+ - name: "@vitejs/plugin-react"
55
+ version: "^4.2.0"
56
+ - name: "tailwindcss"
57
+ version: "^3.4.13"
58
+ - name: "postcss"
59
+ version: "^8.4.47"
60
+ - name: "autoprefixer"
61
+ version: "^10.4.20"
62
+
63
+ codeTemplates:
64
+ # === Infrastructure reused from ReactAppRuntime ===
65
+ # Safe to share because these files don't embed any runtime-specific
66
+ # logic — just build config + entry points.
67
+ index-html:
68
+ engine: typescript
69
+ generator: "libs/instance-factories/applications/templates/react/index-html-generator.ts"
70
+ outputPattern: "{frontendDir}/index.html"
71
+
72
+ main-tsx:
73
+ engine: typescript
74
+ generator: "libs/instance-factories/applications/templates/react/main-tsx-generator.ts"
75
+ outputPattern: "{frontendDir}/src/main.tsx"
76
+
77
+ vite-config:
78
+ engine: typescript
79
+ generator: "libs/instance-factories/applications/templates/react/vite-config-generator.ts"
80
+ outputPattern: "{frontendDir}/vite.config.ts"
81
+
82
+ tsconfig:
83
+ engine: typescript
84
+ generator: "libs/instance-factories/applications/templates/react/tsconfig-generator.ts"
85
+ outputPattern: "{frontendDir}/tsconfig.json"
86
+
87
+ index-css:
88
+ engine: typescript
89
+ generator: "libs/instance-factories/applications/templates/react/index-css-generator.ts"
90
+ outputPattern: "{frontendDir}/src/index.css"
91
+
92
+ gitignore:
93
+ engine: typescript
94
+ generator: "libs/instance-factories/applications/templates/react/gitignore-generator.ts"
95
+ outputPattern: "{frontendDir}/.gitignore"
96
+
97
+ env-example:
98
+ engine: typescript
99
+ generator: "libs/instance-factories/applications/templates/react/env-example-generator.ts"
100
+ outputPattern: "{frontendDir}/.env.example"
101
+
102
+ # API wiring — starter-specific. The starter's hooks inline their
103
+ # own fetch transport so there is NO apiClient.ts (the runtime
104
+ # apiClient imports runtime-only types that this factory doesn't
105
+ # emit). Users wanting a shared transport layer can add one by
106
+ # hand; the hooks file is intentionally small enough to edit.
107
+ use-api-hooks:
108
+ engine: typescript
109
+ generator: "libs/instance-factories/applications/templates/react-starter/use-api-hooks-starter-generator.ts"
110
+ outputPattern: "{frontendDir}/src/hooks/useApi.ts"
111
+
112
+ api-types:
113
+ engine: typescript
114
+ generator: "libs/instance-factories/applications/templates/react-starter/api-types-starter-generator.ts"
115
+ outputPattern: "{frontendDir}/src/types/api.ts"
116
+
117
+ # === Starter-specific: emitted view components + helpers + App + package.json ===
118
+ # The orchestrator returns a map of {relativePath: content} covering:
119
+ # src/views/*.tsx one per (model, view-type) pair
120
+ # src/lib/entity-display.ts FK→name helper (standalone source)
121
+ # src/App.tsx simple internal-routing shell
122
+ # package.json no @specverse/runtime dep
123
+ # .specverse-gen/hashes.json content hashes for regeneration safety
124
+ #
125
+ # Regeneration safety is internal to the orchestrator: user-edited
126
+ # files are omitted from the returned map (so realize never sees
127
+ # them), and the hash manifest's per-file entries are preserved for
128
+ # those skipped files so a later un-edit restores regenerability.
129
+ starter-output:
130
+ engine: typescript
131
+ generator: "libs/instance-factories/applications/templates/react-starter/orchestrator.ts"
132
+ outputPattern: "{frontendDir}/"
133
+
134
+ configuration:
135
+ projectStructure: "monorepo"
136
+ frontendDir: "frontend"
137
+ backendDir: "backend"
138
+
139
+ vite:
140
+ port: 5173
141
+ host: "localhost"
142
+ proxy:
143
+ "/api": "http://localhost:3000"
@@ -2,8 +2,30 @@ import { getApiBaseUrl, getPathConfig } from "../../../shared/path-resolver.js";
2
2
  function generateEnvExample(context) {
3
3
  const pathConfig = getPathConfig(context);
4
4
  const defaultApiUrl = getApiBaseUrl(pathConfig);
5
- return `# API Configuration
6
- # Base URL for backend API
5
+ return `# \u2500\u2500\u2500 Ports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
6
+ # Running more than one SpecVerse project at once? Each project reads
7
+ # its own .env \u2014 copy this file to .env and bump the numbers so the
8
+ # projects don't collide.
9
+ #
10
+ # Suggested ranges (shared across the ecosystem):
11
+ # 3000-3049 : generated project backends (one per project)
12
+ # 3050-3099 : app-demo per-spec runtime backends
13
+ # 5173-5199 : vite frontends (one per project)
14
+ # 9000+ : app-demo Server Manager
15
+
16
+ # Backend (Fastify) port \u2014 read by \`npm run dev:backend\`.
17
+ PORT=3000
18
+
19
+ # Frontend (vite) port \u2014 read by \`npm run dev:frontend\`.
20
+ VITE_PORT=5173
21
+
22
+ # Frontend host \u2014 '0.0.0.0' if you want LAN access.
23
+ VITE_HOST=localhost
24
+
25
+ # \u2500\u2500\u2500 API wiring \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
26
+ # Base URL for backend API. Used by the generated apiClient AND by
27
+ # vite's dev-server proxy (so /api and /ws requests from the browser
28
+ # are forwarded to your backend). Keep this in sync with PORT.
7
29
  VITE_API_BASE_URL=${defaultApiUrl}
8
30
 
9
31
  # API Path Prefix
@@ -6,45 +6,66 @@ function generateViteConfig(context) {
6
6
  const viteHost = configuration?.vite?.host || "localhost";
7
7
  const apiBaseUrl = getApiBaseUrl(pathConfig);
8
8
  const apiProxy = configuration?.vite?.proxy?.["/api"] || apiBaseUrl;
9
- return `import { defineConfig } from 'vite';
9
+ return `import { defineConfig, loadEnv } from 'vite';
10
10
  import react from '@vitejs/plugin-react';
11
11
  import path from 'path';
12
12
 
13
- // https://vitejs.dev/config/
14
- export default defineConfig({
15
- plugins: [react()],
16
- server: {
17
- port: ${vitePort},
18
- host: '${viteHost}',
19
- proxy: {
20
- '/api': {
21
- target: '${apiProxy}',
22
- changeOrigin: true,
23
- },
24
- // WebSocket proxy \u2014 the runtime's useEntitySync hook opens
25
- // ws://<host>/ws to receive entity mutation events from the
26
- // backend event bus. Without this proxy the socket tries to
27
- // connect to the vite dev server on /ws and fails, forcing
28
- // state-sync to fall back to React Query's refetchInterval
29
- // polling (usable but slow).
30
- '/ws': {
31
- target: '${apiProxy.replace(/^http/, "ws")}',
32
- ws: true,
33
- changeOrigin: true,
13
+ /**
14
+ * Ports and proxy targets are env-overridable via this project's
15
+ * .env (and .env.local). Lets you run several SpecVerse projects
16
+ * side-by-side without port collisions:
17
+ *
18
+ * # project-a/.env
19
+ * PORT=3001
20
+ * VITE_PORT=5174
21
+ * VITE_API_BASE_URL=http://localhost:3001
22
+ *
23
+ * # project-b/.env
24
+ * PORT=3002
25
+ * VITE_PORT=5175
26
+ * VITE_API_BASE_URL=http://localhost:3002
27
+ */
28
+ export default defineConfig(({ mode }) => {
29
+ const env = loadEnv(mode, process.cwd(), '');
30
+ const port = Number(env.VITE_PORT ?? ${vitePort});
31
+ const host = env.VITE_HOST ?? '${viteHost}';
32
+ const apiTarget = env.VITE_API_BASE_URL ?? '${apiProxy}';
33
+
34
+ return {
35
+ plugins: [react()],
36
+ server: {
37
+ port,
38
+ host,
39
+ proxy: {
40
+ '/api': {
41
+ target: apiTarget,
42
+ changeOrigin: true,
43
+ },
44
+ // WebSocket proxy \u2014 the runtime's useEntitySync hook opens
45
+ // ws://<host>/ws to receive entity mutation events from the
46
+ // backend event bus. Without this proxy the socket tries to
47
+ // connect to the vite dev server on /ws and fails, forcing
48
+ // state-sync to fall back to React Query's refetchInterval
49
+ // polling (usable but slow).
50
+ '/ws': {
51
+ target: apiTarget.replace(/^http/, 'ws'),
52
+ ws: true,
53
+ changeOrigin: true,
54
+ },
34
55
  },
35
56
  },
36
- },
37
- build: {
38
- outDir: 'dist',
39
- sourcemap: true,
40
- },
41
- resolve: {
42
- alias: {
43
- '@': path.resolve(__dirname, './src'),
57
+ build: {
58
+ outDir: 'dist',
59
+ sourcemap: true,
60
+ },
61
+ resolve: {
62
+ alias: {
63
+ '@': path.resolve(__dirname, './src'),
64
+ },
65
+ // Prevent React duplication when using local packages
66
+ dedupe: ['react', 'react-dom'],
44
67
  },
45
- // Prevent React duplication when using local packages
46
- dedupe: ['react', 'react-dom'],
47
- },
68
+ };
48
69
  });
49
70
  `;
50
71
  }
@@ -0,0 +1,211 @@
1
+ # ReactAppStarter — Emitter Architecture
2
+
3
+ **Audience**: anyone touching the view emitter for Factory B (the "starter-kit" React factory).
4
+
5
+ **Companion docs**:
6
+ - `specverse-self/docs/guides/VIEW-RENDERING-ARCHITECTURE.md` (the "one pattern library, three consumers" design)
7
+ - `specverse-self/docs/plans/2026-04-17-UNIFIED-VIEW-RENDERING.md` (the migration plan)
8
+
9
+ ---
10
+
11
+ ## The problem this solves
12
+
13
+ Factory B emits a standalone React codebase. For every view in the inferred spec (dev defaults + user-defined views), it writes a `.tsx` file the user can read, fork, and edit. The generated code:
14
+
15
+ - Has no `@specverse/runtime` dependency (fully standalone).
16
+ - Is idiomatic React with typed props, hooks, event handlers — not a big static HTML blob.
17
+ - Renders the **same** visual output as `@specverse/runtime` renders for the same spec (verified by Phase 3 parity test P3).
18
+
19
+ The tension: "idiomatic React structure" wants hand-crafted JSX. "Same visual output as runtime" wants a single rendering authority. Strategy 3 resolves this by splitting *structure* (hand-written skeleton templates) from *interior* (canonical Tailwind adapter rendering).
20
+
21
+ ## The three pieces
22
+
23
+ ```
24
+ ┌─────────────────────────────────────────────────────────────┐
25
+ │ 1. view-emitter.ts — orchestrator │
26
+ │ Takes (viewSpec, modelSpec, expandedSpec) → .tsx string │
27
+ └──────────────┬───────────────────────────────┬──────────────┘
28
+ │ │
29
+ ▼ ▼
30
+ ┌──────────────────────────────┐ ┌─────────────────────────────────┐
31
+ │ 2. skeletons/*.tsx.template │ │ 3. html-to-jsx.ts — transformer│
32
+ │ One per view type: │ │ │
33
+ │ list.tsx.template │ │ Converts Tailwind-HTML │
34
+ │ detail.tsx.template │ │ strings from the runtime │
35
+ │ form.tsx.template │ │ adapter into JSX-safe source │
36
+ │ dashboard.tsx.template │ │ (class→className, self-close,│
37
+ │ + specialist types │ │ brace escape, attribute map) │
38
+ │ │ │ │
39
+ │ Each has a {{BODY}} │ │ ~50-150 LoC, bounded scope │
40
+ │ placeholder the emitter │ │ │
41
+ │ fills with transformed │ │ │
42
+ │ JSX. │ │ │
43
+ └──────────────────────────────┘ └─────────────────────────────────┘
44
+
45
+
46
+ │ renders body as HTML
47
+
48
+ ┌─────────────────────┴──────────────────────┐
49
+ │ @specverse/runtime/views/tailwind │
50
+ │ createUniversalTailwindAdapter() │
51
+ │ (the canonical build-time renderer — │
52
+ │ same code app-demo and Factory A │
53
+ │ transitively rely on at runtime) │
54
+ └────────────────────────────────────────────┘
55
+ ```
56
+
57
+ ## Data flow for ONE view
58
+
59
+ Given an inferred `PostListView` in the expanded spec:
60
+
61
+ 1. **view-emitter.ts** receives `(view, model, expandedSpec)`.
62
+ 2. Picks the correct skeleton based on `view.type`: `skeletons/list.tsx.template`.
63
+ 3. Builds a render context for the pattern: `{ primaryModel: 'Post', modelSchemas: {...}, viewSpec: view, modelData: [] }` (empty data — structure only).
64
+ 4. Calls `createUniversalTailwindAdapter()` and renders the composite pattern's interior → HTML string.
65
+ Example output: `<table class="w-full ..."><thead><tr><th class="...">Title</th>...`.
66
+ 5. Passes that HTML through **html-to-jsx.ts** → JSX-safe source.
67
+ Example: `<table className="w-full ..."><thead><tr><th className="...">{/* data.map */}Title</th>...`.
68
+ 6. Substitutes `{{BODY}}` in the skeleton with the transformed JSX.
69
+ 7. Substitutes skeleton placeholders like `{{MODEL_NAME}}`, `{{PLURAL}}`, `{{PROPS_INTERFACE}}` with model-specific values.
70
+ 8. Returns the complete `.tsx` source string.
71
+
72
+ The factory's realize pass calls this once per view, writes each to `frontend/src/views/{ViewName}.tsx`, updates `.specverse-gen/hashes.json`.
73
+
74
+ ## Why this split works
75
+
76
+ - **Idiomatic outer structure** — skeletons are hand-written `.tsx.template` files, tweaked by the humans who maintain the factory. They define imports, props interfaces, hook placement, event wiring, loading states, empty states. Exactly what a human React author would write.
77
+ - **Pattern-driven interior** — the actual markup (table header cells, row templates, form fields, badge styling) comes from the canonical Tailwind adapter. When runtime improves the pattern rendering, Factory B inherits the fix automatically — because the adapter is the single source.
78
+ - **No full re-implementation** — we don't build a second renderer. The adapter already works for runtime; we reuse it at build time.
79
+
80
+ ## The html-to-jsx transformer — scope
81
+
82
+ Input: HTML string with Tailwind classes. Single root element (always — the adapter always produces a containing element).
83
+
84
+ Output: A JSX-safe source string that can be dropped between JSX tags.
85
+
86
+ What it does:
87
+ 1. `class="..."` → `className="..."`
88
+ 2. Self-closing tags: `<img src="...">` → `<img src="..." />`
89
+ 3. Escape `{` and `}` in text content by wrapping in `{'{'}` / `{'}'}` when they appear outside attribute values.
90
+ 4. Convert `style="color: red"` to `style={{ color: 'red' }}`.
91
+ 5. Convert `for="..."` to `htmlFor="..."`.
92
+ 6. Strip any attributes that aren't valid in JSX.
93
+
94
+ What it explicitly does NOT do:
95
+ - Parse JavaScript inside the HTML (the adapter produces static HTML — no JS expressions).
96
+ - Insert React hooks or event handlers — those live in the skeleton, not the interior.
97
+ - Handle SVG / MathML nuances — only HTML+Tailwind.
98
+
99
+ Test coverage target: feed the transformer 50 pre-captured HTML snippets from the canonical adapter output, assert the JSX output parses as valid TSX via `typescript.transpileModule`.
100
+
101
+ ## Skeleton template format
102
+
103
+ A skeleton is a `.tsx.template` file — syntactically valid TypeScript with substitution markers. Example (sketch for `list.tsx.template`):
104
+
105
+ ```tsx
106
+ /**
107
+ * {{MODEL_NAME}}ListView — generated by @specverse/realize (ReactAppStarter)
108
+ *
109
+ * Safe to edit. Edits are preserved across regeneration (content-hashed).
110
+ * Regenerate with `spv realize` or, if this file was edited, delete the
111
+ * file first to opt back into regeneration.
112
+ */
113
+ import { useState, useMemo } from 'react';
114
+ import { use{{PLURAL_MODEL}}Query, useDelete{{MODEL_NAME}}Mutation } from '../hooks/useApi';
115
+ import type { {{MODEL_NAME}} } from '../types/api';
116
+
117
+ interface {{MODEL_NAME}}ListViewProps {
118
+ onSelect?: (item: {{MODEL_NAME}}) => void;
119
+ onCreate?: () => void;
120
+ }
121
+
122
+ export function {{MODEL_NAME}}ListView({ onSelect, onCreate }: {{MODEL_NAME}}ListViewProps) {
123
+ const { data: items = [], isLoading, error } = use{{PLURAL_MODEL}}Query();
124
+ const deleteItem = useDelete{{MODEL_NAME}}Mutation();
125
+ const [searchTerm, setSearchTerm] = useState('');
126
+
127
+ const filtered = useMemo(
128
+ () => items.filter(item =>
129
+ Object.values(item).some(v => String(v).toLowerCase().includes(searchTerm.toLowerCase()))
130
+ ),
131
+ [items, searchTerm]
132
+ );
133
+
134
+ if (isLoading) return <div className="p-4 text-gray-500">Loading…</div>;
135
+ if (error) return <div className="p-4 text-red-600">Error loading {{PLURAL_LOWER}}: {String(error)}</div>;
136
+
137
+ return (
138
+ <div className="p-6 space-y-4">
139
+ <div className="flex justify-between items-center">
140
+ <input
141
+ type="search"
142
+ placeholder="Search {{PLURAL_LOWER}}…"
143
+ value={searchTerm}
144
+ onChange={e => setSearchTerm(e.target.value)}
145
+ className="rounded border px-3 py-2 w-64"
146
+ />
147
+ <button
148
+ onClick={onCreate}
149
+ className="rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700"
150
+ >
151
+ + New {{MODEL_NAME}}
152
+ </button>
153
+ </div>
154
+
155
+ {/* {{BODY}} — pattern-rendered table interior, JSX-transformed */}
156
+ {{BODY}}
157
+
158
+ {filtered.length === 0 && (
159
+ <div className="p-8 text-center text-gray-400">No {{PLURAL_LOWER}} yet.</div>
160
+ )}
161
+ </div>
162
+ );
163
+ }
164
+ ```
165
+
166
+ Substitution contract:
167
+ - `{{MODEL_NAME}}` — PascalCase model name (e.g., `Post`).
168
+ - `{{PLURAL_MODEL}}` — PascalCase plural (e.g., `Posts`).
169
+ - `{{PLURAL_LOWER}}` — lowercase plural (e.g., `posts`).
170
+ - `{{BODY}}` — exactly one substitution per skeleton, where the pattern-rendered interior goes.
171
+
172
+ Substitution is plain string replacement — no template expression evaluation.
173
+
174
+ ## File placement
175
+
176
+ ```
177
+ engines/libs/instance-factories/applications/templates/react-starter/
178
+ ├── README.md # this file
179
+ ├── view-emitter.ts # orchestrator (step 1)
180
+ ├── html-to-jsx.ts # transformer (step 3)
181
+ ├── skeletons/
182
+ │ ├── list.tsx.template # list view
183
+ │ ├── detail.tsx.template # detail view
184
+ │ ├── form.tsx.template # form view (Phase 2e)
185
+ │ ├── dashboard.tsx.template # dashboard (Phase 2e)
186
+ │ └── specialist-*.tsx.template # board/timeline/calendar (Phase 2e)
187
+ └── __tests__/
188
+ ├── html-to-jsx.test.ts # transformer unit tests
189
+ └── view-emitter.test.ts # end-to-end: (spec, view) → valid TSX
190
+ ```
191
+
192
+ ## Build order (Phase 2a in the migration plan)
193
+
194
+ 1. Implement `html-to-jsx.ts` first (smallest, most testable, standalone).
195
+ 2. Write `list.tsx.template` (one view type; production-quality).
196
+ 3. Implement `view-emitter.ts` — orchestrator that wires html-to-jsx + canonical Tailwind adapter + skeleton.
197
+ 4. Integration test: take a reference spec with one model + its list view, emit, assert the `.tsx` source parses and its JSX matches the expected shape.
198
+ 5. Only after list works end-to-end: template out to detail + form + dashboard.
199
+
200
+ ## Open questions (inside Phase 2a)
201
+
202
+ 1. **Where do per-model hooks come from?** `use{{PLURAL_MODEL}}Query` and `useDelete{{MODEL_NAME}}Mutation` in the skeleton presume a generated hooks file (`src/hooks/useApi.ts`) that provides them. `ReactAppRuntime` already generates this file via `use-api-hooks-generator.ts` — Factory B should reuse that generator (shared between both factories as called out in the migration plan).
203
+ 2. **How does the skeleton address auto-generated fields (id, createdAt, etc.)?** The view should skip them in the table/form. `isAutoGeneratedField()` logic needs to be available in the generated output. Plan: emit a `src/lib/field-helpers.ts` alongside the views (inlined from the pattern library's logic, same way the runtime has it).
204
+ 3. **What happens when the view spec has `uiComponents` that the pattern library doesn't recognize?** Runtime gracefully falls back to a default table. Factory B should do the same — same fallback logic, same output.
205
+ 4. **Should the skeleton expose a slot for user-added React nodes (e.g. `<Children />` or a `prepend` prop)?** Useful for extensibility without forcing users to edit the generated file. Defer to v2 of the emitter — start with fixed skeletons.
206
+
207
+ ## Non-goals
208
+
209
+ - No JSX AST parsing or manipulation. `html-to-jsx.ts` is a string transformer, not a compiler.
210
+ - No server-side rendering of the React components. The emitter outputs source files; the user's Vite build bundles them.
211
+ - No runtime customization of skeletons. A project that wants different skeletons forks the factory or the generated code.
@@ -0,0 +1,69 @@
1
+ function mapAttrType(attr) {
2
+ const t = typeof attr === "string" ? attr.split(/\s+/)[0] : attr?.type;
3
+ const values = attr?.values;
4
+ if (Array.isArray(values) && values.length > 0) {
5
+ return values.map((v) => JSON.stringify(v)).join(" | ");
6
+ }
7
+ switch ((t || "").toLowerCase()) {
8
+ case "string":
9
+ case "text":
10
+ case "uuid":
11
+ case "email":
12
+ case "url":
13
+ return "string";
14
+ case "int":
15
+ case "integer":
16
+ case "float":
17
+ case "number":
18
+ case "decimal":
19
+ return "number";
20
+ case "boolean":
21
+ case "bool":
22
+ return "boolean";
23
+ case "datetime":
24
+ case "date":
25
+ case "time":
26
+ case "timestamp":
27
+ return "string";
28
+ case "json":
29
+ return "Record<string, unknown>";
30
+ default:
31
+ return "unknown";
32
+ }
33
+ }
34
+ function isRequired(attr) {
35
+ if (typeof attr === "string") return /\brequired\b/.test(attr);
36
+ return !!attr?.required;
37
+ }
38
+ async function generate(context) {
39
+ const models = context.spec.models ?? {};
40
+ const modelNames = Object.keys(models);
41
+ const header = `/**
42
+ * API types (ReactAppStarter)
43
+ *
44
+ * Per-model interfaces generated from the spec's model definitions.
45
+ * Safe to edit \u2014 extend these when your UI needs more than the spec
46
+ * describes (e.g. optimistic fields, denormalized joins).
47
+ */
48
+ `;
49
+ const interfaces = modelNames.map((name) => {
50
+ const model = models[name] || {};
51
+ const attrs = model.attributes || {};
52
+ const attrKeys = Object.keys(attrs);
53
+ const fields = attrKeys.map((attrName) => {
54
+ const attr = attrs[attrName];
55
+ const tsType = mapAttrType(attr);
56
+ const optional = isRequired(attr) ? "" : "?";
57
+ return ` ${attrName}${optional}: ${tsType};`;
58
+ }).join("\n");
59
+ return `export interface ${name} {
60
+ ${fields || " [key: string]: unknown;"}
61
+ }`;
62
+ }).join("\n\n");
63
+ return header + "\n" + interfaces + "\n";
64
+ }
65
+ var stdin_default = generate;
66
+ export {
67
+ stdin_default as default,
68
+ generate
69
+ };
@@ -0,0 +1,110 @@
1
+ async function generate(context) {
2
+ const models = Object.keys(context.spec.models ?? {});
3
+ const imports = buildImports(models);
4
+ const navEntries = buildNavEntries(models);
5
+ const viewSwitch = buildViewSwitch(models);
6
+ return `/**
7
+ * App.tsx \u2014 generated by @specverse/realize (ReactAppStarter)
8
+ *
9
+ * Safe to edit. Edits are preserved across regeneration via content
10
+ * hashing. This is a minimal shell: a sidebar listing every
11
+ * (model, view-type) plus a main area that renders the selection.
12
+ * Swap in react-router or your preferred routing library when the
13
+ * app needs URL-driven navigation.
14
+ */
15
+ import { useState } from 'react';
16
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
17
+ ${imports}
18
+
19
+ const queryClient = new QueryClient({
20
+ defaultOptions: {
21
+ queries: { staleTime: 5 * 60 * 1000, retry: 1 },
22
+ },
23
+ });
24
+
25
+ type Selection = {
26
+ model: string;
27
+ view: 'list' | 'detail' | 'form' | 'dashboard';
28
+ entityId?: string | number;
29
+ };
30
+
31
+ function Inner() {
32
+ const [selection, setSelection] = useState<Selection>(${models.length > 0 ? `{ model: '${models[0]}', view: 'list' }` : `{ model: '', view: 'list' }`});
33
+
34
+ const select = (model: string, view: Selection['view']) =>
35
+ setSelection({ model, view });
36
+
37
+ return (
38
+ <div className="min-h-screen flex bg-gray-50 dark:bg-gray-950">
39
+ <aside className="w-64 shrink-0 border-r border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900">
40
+ <div className="p-4 border-b border-gray-200 dark:border-gray-800">
41
+ <h1 className="text-lg font-semibold text-gray-900 dark:text-gray-100">App</h1>
42
+ </div>
43
+ <nav className="p-2 space-y-4">
44
+ ${navEntries}
45
+ </nav>
46
+ </aside>
47
+
48
+ <main className="flex-1 overflow-auto">
49
+ ${viewSwitch}
50
+ </main>
51
+ </div>
52
+ );
53
+ }
54
+
55
+ export default function App() {
56
+ return (
57
+ <QueryClientProvider client={queryClient}>
58
+ <Inner />
59
+ </QueryClientProvider>
60
+ );
61
+ }
62
+ `;
63
+ }
64
+ function buildImports(models) {
65
+ return models.flatMap((m) => [
66
+ `import { ${m}ListView } from './views/${m}ListView';`,
67
+ `import { ${m}DetailView } from './views/${m}DetailView';`,
68
+ `import { ${m}FormView } from './views/${m}FormView';`,
69
+ `import { ${m}DashboardView } from './views/${m}DashboardView';`
70
+ ]).join("\n");
71
+ }
72
+ function buildNavEntries(models) {
73
+ if (models.length === 0) {
74
+ return ' <p className="text-sm text-gray-400 px-2">No models in this spec.</p>';
75
+ }
76
+ return models.map((m) => ` <div>
77
+ <div className="px-2 pb-1 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">
78
+ ${m}
79
+ </div>
80
+ <button type="button" onClick={() => select('${m}', 'list')} className="${navButtonCls("list")}">List</button>
81
+ <button type="button" onClick={() => select('${m}', 'dashboard')} className="${navButtonCls("dashboard")}">Dashboard</button>
82
+ <button type="button" onClick={() => select('${m}', 'form')} className="${navButtonCls("form")}">Form</button>
83
+ </div>`).join("\n");
84
+ }
85
+ function navButtonCls(_view) {
86
+ return "block w-full text-left rounded px-2 py-1 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800";
87
+ }
88
+ function buildViewSwitch(models) {
89
+ if (models.length === 0) {
90
+ return ' <p className="p-6 text-sm text-gray-400">No models \u2014 add one to your .specly file and run <code>spv realize</code>.</p>';
91
+ }
92
+ const branches = models.flatMap((m) => [
93
+ ` {selection.model === '${m}' && selection.view === 'list' && (
94
+ <${m}ListView onSelect={item => setSelection({ model: '${m}', view: 'detail', entityId: (item as any).id })} onCreate={() => setSelection({ model: '${m}', view: 'form' })} />
95
+ )}`,
96
+ ` {selection.model === '${m}' && selection.view === 'detail' && selection.entityId !== undefined && (
97
+ <${m}DetailView entityId={selection.entityId} onEdit={item => setSelection({ model: '${m}', view: 'form', entityId: (item as any).id })} onBack={() => setSelection({ model: '${m}', view: 'list' })} onDeleted={() => setSelection({ model: '${m}', view: 'list' })} />
98
+ )}`,
99
+ ` {selection.model === '${m}' && selection.view === 'form' && (
100
+ <${m}FormView mode={selection.entityId ? 'update' : 'create'} entityId={selection.entityId} onSuccess={() => setSelection({ model: '${m}', view: 'list' })} onCancel={() => setSelection({ model: '${m}', view: 'list' })} />
101
+ )}`,
102
+ ` {selection.model === '${m}' && selection.view === 'dashboard' && (
103
+ <${m}DashboardView onSelect={item => setSelection({ model: '${m}', view: 'detail', entityId: (item as any).id })} />
104
+ )}`
105
+ ]);
106
+ return branches.join("\n");
107
+ }
108
+ export {
109
+ generate
110
+ };