@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,40 @@
1
+ function extractBelongsToTargets(model) {
2
+ const rels = model.relationships ?? {};
3
+ const out = [];
4
+ for (const [name, rawDef] of Object.entries(rels)) {
5
+ const parsed = parseBelongsTo(rawDef);
6
+ if (parsed) out.push({ name, target: parsed });
7
+ }
8
+ return out;
9
+ }
10
+ function parseBelongsTo(def) {
11
+ if (typeof def === "string") {
12
+ const parts = def.trim().split(/\s+/);
13
+ if (parts[0] === "belongsTo" && parts[1]) return parts[1];
14
+ return null;
15
+ }
16
+ if (def && typeof def === "object") {
17
+ const o = def;
18
+ if (o.type === "belongsTo") {
19
+ return o.target || o.to || o.model || o.targetModel || null;
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+ function pluralize(s) {
25
+ if (/[^aeiou]y$/i.test(s)) return s.slice(0, -1) + "ies";
26
+ if (/(s|x|z|ch|sh)$/i.test(s)) return s + "es";
27
+ return s + "s";
28
+ }
29
+ function buildFKMap(model) {
30
+ const map = /* @__PURE__ */ new Map();
31
+ for (const rel of extractBelongsToTargets(model)) {
32
+ map.set(`${rel.name}Id`, rel);
33
+ }
34
+ return map;
35
+ }
36
+ export {
37
+ buildFKMap,
38
+ extractBelongsToTargets,
39
+ pluralize
40
+ };
@@ -0,0 +1,129 @@
1
+ import { METADATA_FIELDS } from "@specverse/runtime/views/core";
2
+ import { buildFKMap } from "./belongs-to.js";
3
+ const METADATA_FIELD_NAMES = new Set(METADATA_FIELDS);
4
+ function composeDashboardBody(context) {
5
+ const modelName = context.model.name;
6
+ const previewColumns = inferPreviewColumns(context.model);
7
+ const enumFields = inferEnumFields(context.model);
8
+ const fkMap = buildFKMap(context.model);
9
+ const lines = [];
10
+ lines.push('<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">');
11
+ lines.push(...renderTotalCard(modelName));
12
+ for (const enumField of enumFields) {
13
+ lines.push(...renderEnumBreakdownCard(enumField));
14
+ }
15
+ if (enumFields.length === 0) {
16
+ lines.push(...renderPlaceholderCard());
17
+ }
18
+ lines.push("</div>");
19
+ lines.push("");
20
+ lines.push("{/* TODO: add aggregation metrics (averages / sums / time series)");
21
+ lines.push(" by adding backend endpoints and per-metric hooks. Wire them in");
22
+ lines.push(" alongside the count cards above. */}");
23
+ lines.push("");
24
+ lines.push('<div className="rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">');
25
+ lines.push(' <div className="border-b border-gray-200 dark:border-gray-700 px-6 py-3">');
26
+ lines.push(' <h3 className="text-sm font-semibold text-gray-700 dark:text-gray-200 uppercase tracking-wider">');
27
+ lines.push(` Recent ${humanize(modelName)}s`);
28
+ lines.push(" </h3>");
29
+ lines.push(" </div>");
30
+ if (previewColumns.length === 0) {
31
+ lines.push(' <div className="px-6 py-4 text-sm text-gray-400">No displayable fields.</div>');
32
+ } else {
33
+ lines.push(' <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">');
34
+ lines.push(" <thead>");
35
+ lines.push(" <tr>");
36
+ for (const col of previewColumns) {
37
+ const fk = fkMap.get(col);
38
+ const headerLabel = humanize(fk ? fk.name : col);
39
+ lines.push(
40
+ ` <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">` + headerLabel + `</th>`
41
+ );
42
+ }
43
+ lines.push(" </tr>");
44
+ lines.push(" </thead>");
45
+ lines.push(' <tbody className="divide-y divide-gray-200 dark:divide-gray-700">');
46
+ lines.push(" {preview.map((item, idx) => (");
47
+ lines.push(" <tr");
48
+ lines.push(" key={idx}");
49
+ lines.push(" onClick={() => onSelect?.(item)}");
50
+ lines.push(' className="hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer"');
51
+ lines.push(" >");
52
+ for (const col of previewColumns) {
53
+ const fk = fkMap.get(col);
54
+ const expr = fk ? `{resolveEntityDisplayName((item as any).${col}, ${fk.name}Options)}` : `{String((item as any).${col} ?? '')}`;
55
+ lines.push(
56
+ ` <td className="px-6 py-4 text-sm text-gray-700 dark:text-gray-300">${expr}</td>`
57
+ );
58
+ }
59
+ lines.push(" </tr>");
60
+ lines.push(" ))}");
61
+ lines.push(" {preview.length === 0 && (");
62
+ lines.push(` <tr><td colSpan={${previewColumns.length}} className="px-6 py-4 text-sm text-gray-400">No records yet.</td></tr>`);
63
+ lines.push(" )}");
64
+ lines.push(" </tbody>");
65
+ lines.push(" </table>");
66
+ }
67
+ lines.push("</div>");
68
+ return lines.join("\n");
69
+ }
70
+ function renderTotalCard(modelName) {
71
+ const pluralLower = humanize(modelName).toLowerCase() + "s";
72
+ return [
73
+ ' <div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-900">',
74
+ ' <p className="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">',
75
+ ` Total ${pluralLower}`,
76
+ " </p>",
77
+ ' <p className="mt-2 text-3xl font-semibold text-gray-900 dark:text-gray-100">',
78
+ " {items.length}",
79
+ " </p>",
80
+ " </div>"
81
+ ];
82
+ }
83
+ function renderEnumBreakdownCard(field) {
84
+ const cards = [];
85
+ for (const value of field.values) {
86
+ cards.push(
87
+ ' <div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-900">',
88
+ ' <p className="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">',
89
+ ` ${humanize(field.name)}: ${humanize(value)}`,
90
+ " </p>",
91
+ ' <p className="mt-2 text-3xl font-semibold text-gray-900 dark:text-gray-100">',
92
+ ` {items.filter((i: any) => i.${field.name} === ${JSON.stringify(value)}).length}`,
93
+ " </p>",
94
+ " </div>"
95
+ );
96
+ }
97
+ return cards;
98
+ }
99
+ function renderPlaceholderCard() {
100
+ return [
101
+ ' <div className="rounded-lg border border-dashed border-gray-300 p-6 text-sm text-gray-400 dark:border-gray-600">',
102
+ " Add a metric here \u2014 e.g. a sum, average, or time-windowed count.",
103
+ " </div>"
104
+ ];
105
+ }
106
+ function inferEnumFields(model) {
107
+ const out = [];
108
+ const attrs = model.attributes ?? {};
109
+ for (const [name, rawDef] of Object.entries(attrs)) {
110
+ const def = rawDef;
111
+ const values = def?.values;
112
+ if (Array.isArray(values) && values.length > 0 && values.length <= 6) {
113
+ out.push({ name, values });
114
+ }
115
+ }
116
+ return out.slice(0, 1);
117
+ }
118
+ function inferPreviewColumns(model) {
119
+ const attrs = model.attributes ?? {};
120
+ const attrCols = Object.keys(attrs).filter((n) => !METADATA_FIELD_NAMES.has(n));
121
+ const fkCols = [...buildFKMap(model).keys()].filter((k) => !attrCols.includes(k));
122
+ return [...fkCols, ...attrCols].slice(0, Math.max(5, fkCols.length + 1));
123
+ }
124
+ function humanize(name) {
125
+ return name.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase()).trim();
126
+ }
127
+ export {
128
+ composeDashboardBody
129
+ };
@@ -0,0 +1,80 @@
1
+ import { METADATA_FIELDS } from "@specverse/runtime/views/core";
2
+ import { extractBelongsToTargets } from "./belongs-to.js";
3
+ const METADATA_FIELD_NAMES = new Set(METADATA_FIELDS);
4
+ function composeDetailBody(context) {
5
+ const belongsTo = extractBelongsToTargets(context.model);
6
+ const fkExcludes = new Set(belongsTo.map((r) => `${r.name}Id`));
7
+ const { business, metadata } = partitionFields(context.model, fkExcludes);
8
+ const lines = [];
9
+ lines.push('<div className="rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-900">');
10
+ if (business.length > 0) {
11
+ lines.push(' <dl className="grid grid-cols-1 gap-4 sm:grid-cols-2">');
12
+ for (const field of business) {
13
+ lines.push(...renderField(field, { muted: false }));
14
+ }
15
+ lines.push(" </dl>");
16
+ } else if (belongsTo.length === 0) {
17
+ lines.push(' <p className="text-sm text-gray-400">No business fields defined for this model.</p>');
18
+ }
19
+ if (belongsTo.length > 0) {
20
+ lines.push("");
21
+ lines.push(' <dl className="mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 border-t border-gray-200 dark:border-gray-700 pt-4">');
22
+ for (const rel of belongsTo) {
23
+ lines.push(...renderRelationshipField(rel));
24
+ }
25
+ lines.push(" </dl>");
26
+ }
27
+ if (metadata.length > 0) {
28
+ lines.push("");
29
+ lines.push(' <dl className="mt-6 grid grid-cols-1 gap-2 sm:grid-cols-2 border-t border-gray-200 dark:border-gray-700 pt-4 text-xs text-gray-500 dark:text-gray-400">');
30
+ for (const field of metadata) {
31
+ lines.push(...renderField(field, { muted: true }));
32
+ }
33
+ lines.push(" </dl>");
34
+ }
35
+ lines.push("</div>");
36
+ return lines.join("\n");
37
+ }
38
+ function partitionFields(model, exclude = /* @__PURE__ */ new Set()) {
39
+ const attrs = Object.keys(model.attributes ?? {});
40
+ const business = [];
41
+ const metadata = [];
42
+ for (const name of attrs) {
43
+ if (exclude.has(name)) continue;
44
+ const field = { name, label: humanize(name) };
45
+ if (METADATA_FIELD_NAMES.has(name)) {
46
+ metadata.push(field);
47
+ } else {
48
+ business.push(field);
49
+ }
50
+ }
51
+ return { business, metadata };
52
+ }
53
+ function renderRelationshipField(rel) {
54
+ const label = humanize(rel.name);
55
+ const fkName = `${rel.name}Id`;
56
+ const optionsVar = `${rel.name}Options`;
57
+ return [
58
+ " <div>",
59
+ ` <dt className="text-sm font-medium text-gray-500 dark:text-gray-400">${label}</dt>`,
60
+ ` <dd className="mt-1 text-sm text-gray-900 dark:text-gray-100 break-words">{resolveEntityDisplayName((item as any).${fkName}, ${optionsVar})}</dd>`,
61
+ " </div>"
62
+ ];
63
+ }
64
+ function renderField(field, opts) {
65
+ const label = field.label ?? humanize(field.name);
66
+ const labelCls = opts.muted ? "font-medium uppercase tracking-wide text-gray-400 dark:text-gray-500" : "text-sm font-medium text-gray-500 dark:text-gray-400";
67
+ const valueCls = opts.muted ? "text-gray-500 dark:text-gray-400" : "mt-1 text-sm text-gray-900 dark:text-gray-100 break-words";
68
+ return [
69
+ " <div>",
70
+ ` <dt className="${labelCls}">${label}</dt>`,
71
+ ` <dd className="${valueCls}">{String((item as any).${field.name} ?? '')}</dd>`,
72
+ " </div>"
73
+ ];
74
+ }
75
+ function humanize(name) {
76
+ return name.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase()).trim();
77
+ }
78
+ export {
79
+ composeDetailBody
80
+ };
@@ -0,0 +1,217 @@
1
+ import { METADATA_FIELDS } from "@specverse/runtime/views/core";
2
+ import { extractBelongsToTargets } from "./belongs-to.js";
3
+ const AUTO_GENERATED_FIELD_NAMES = new Set(METADATA_FIELDS);
4
+ function composeFormBody(context) {
5
+ const belongsTo = extractBelongsToTargets(context.model);
6
+ const shadowedFKs = new Set(belongsTo.map((rel) => `${rel.name}Id`));
7
+ const fields = selectFormFields(context.model, shadowedFKs);
8
+ const lines = [];
9
+ lines.push('<div className="space-y-4">');
10
+ if (fields.length === 0 && belongsTo.length === 0) {
11
+ lines.push(' <p className="text-sm text-gray-400">No editable fields for this model.</p>');
12
+ lines.push("</div>");
13
+ return lines.join("\n");
14
+ }
15
+ for (const field of fields) {
16
+ lines.push(...renderInput(field));
17
+ }
18
+ for (const rel of belongsTo) {
19
+ lines.push(...renderRelationshipSelect(rel));
20
+ }
21
+ lines.push("</div>");
22
+ return lines.join("\n");
23
+ }
24
+ function renderRelationshipSelect(rel) {
25
+ const fkName = `${rel.name}Id`;
26
+ const varName = `${rel.name}Options`;
27
+ const label = humanize(rel.name);
28
+ return [
29
+ " <div>",
30
+ ` <label className="${LABEL_CLS}" htmlFor="${fkName}">${label} *</label>`,
31
+ ` <select`,
32
+ ` id="${fkName}"`,
33
+ ` className="${INPUT_CLS}"`,
34
+ ` value={String((formData as any).${fkName} ?? '')}`,
35
+ ` onChange={e => handleChange('${fkName}', e.target.value)} required`,
36
+ ` >`,
37
+ ` <option value="">\u2014 choose \u2014</option>`,
38
+ ` {${varName}.map((opt: any) => (`,
39
+ ` <option key={opt.id} value={opt.id}>{getEntityDisplayName(opt)}</option>`,
40
+ ` ))}`,
41
+ ` </select>`,
42
+ " </div>"
43
+ ];
44
+ }
45
+ function selectFormFields(model, skip = /* @__PURE__ */ new Set()) {
46
+ const out = [];
47
+ const attrs = model.attributes ?? {};
48
+ const lifecycleStates = extractLifecycleStates(model);
49
+ for (const [name, rawDef] of Object.entries(attrs)) {
50
+ if (AUTO_GENERATED_FIELD_NAMES.has(name)) continue;
51
+ if (skip.has(name)) continue;
52
+ const def = rawDef;
53
+ if (def?.auto) continue;
54
+ const type = def?.type ?? parseTypeFromConvention(def) ?? "String";
55
+ const required = def?.required === true || hasConventionFlag(def, "required");
56
+ const declaredValues = def?.values;
57
+ const lifecycleValues = lifecycleStates.get(name);
58
+ const values = declaredValues ?? lifecycleValues;
59
+ const maxLength = def?.maxLength ?? def?.max;
60
+ const isLongString = typeof maxLength === "number" && maxLength > 100;
61
+ out.push({
62
+ name,
63
+ label: humanize(name),
64
+ type: normalizeType(type),
65
+ required,
66
+ values,
67
+ isLongString
68
+ });
69
+ }
70
+ return out;
71
+ }
72
+ function extractLifecycleStates(model) {
73
+ const out = /* @__PURE__ */ new Map();
74
+ const lifecycles = model.lifecycles ?? {};
75
+ for (const [name, rawDef] of Object.entries(lifecycles)) {
76
+ if (!rawDef || typeof rawDef !== "object") continue;
77
+ const def = rawDef;
78
+ if (Array.isArray(def.states) && def.states.length > 0) {
79
+ const names = def.states.map((s) => typeof s === "string" ? s : s?.name ?? s?.id ?? "").filter(Boolean);
80
+ if (names.length > 0) {
81
+ out.set(name, names);
82
+ continue;
83
+ }
84
+ }
85
+ if (typeof def.flow === "string") {
86
+ const states = def.flow.split(/\s*(?:->|,)\s*/).map((s) => s.trim()).filter(Boolean);
87
+ if (states.length > 0) out.set(name, states);
88
+ }
89
+ }
90
+ return out;
91
+ }
92
+ function parseTypeFromConvention(def) {
93
+ if (typeof def === "string") {
94
+ const first = def.trim().split(/\s+/)[0];
95
+ return first;
96
+ }
97
+ return void 0;
98
+ }
99
+ function hasConventionFlag(def, flag) {
100
+ if (typeof def === "string") {
101
+ return def.split(/\s+/).includes(flag);
102
+ }
103
+ return false;
104
+ }
105
+ function normalizeType(type) {
106
+ return type.replace(/[^A-Za-z].*$/, "");
107
+ }
108
+ const INPUT_CLS = "w-full rounded border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100";
109
+ const LABEL_CLS = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
110
+ function renderInput(field) {
111
+ const requiredMark = field.required ? " *" : "";
112
+ const reqAttr = field.required ? " required" : "";
113
+ if (field.values && field.values.length > 0) {
114
+ const options = field.values.map((v) => ` <option value="${escapeAttr(v)}">${escapeText(v)}</option>`).join("\n");
115
+ return [
116
+ " <div>",
117
+ ` <label className="${LABEL_CLS}" htmlFor="${field.name}">${field.label}${requiredMark}</label>`,
118
+ ` <select`,
119
+ ` id="${field.name}"`,
120
+ ` className="${INPUT_CLS}"`,
121
+ ` value={String((formData as any).${field.name} ?? '')}`,
122
+ ` onChange={e => handleChange('${field.name}', e.target.value)}${reqAttr}`,
123
+ ` >`,
124
+ ` <option value="">\u2014 choose \u2014</option>`,
125
+ options,
126
+ ` </select>`,
127
+ " </div>"
128
+ ];
129
+ }
130
+ if (field.type === "Text" || field.isLongString) {
131
+ return [
132
+ " <div>",
133
+ ` <label className="${LABEL_CLS}" htmlFor="${field.name}">${field.label}${requiredMark}</label>`,
134
+ ` <textarea`,
135
+ ` id="${field.name}"`,
136
+ ` className="${INPUT_CLS}"`,
137
+ ` rows={4}`,
138
+ ` value={String((formData as any).${field.name} ?? '')}`,
139
+ ` onChange={e => handleChange('${field.name}', e.target.value)}${reqAttr}`,
140
+ ` />`,
141
+ " </div>"
142
+ ];
143
+ }
144
+ if (field.type === "Boolean") {
145
+ return [
146
+ " <div>",
147
+ ` <label className="inline-flex items-center gap-2">`,
148
+ ` <input`,
149
+ ` id="${field.name}"`,
150
+ ` type="checkbox"`,
151
+ ` checked={Boolean((formData as any).${field.name})}`,
152
+ ` onChange={e => handleChange('${field.name}', e.target.checked)}`,
153
+ ` />`,
154
+ ` <span className="text-sm text-gray-700 dark:text-gray-300">${field.label}${requiredMark}</span>`,
155
+ ` </label>`,
156
+ " </div>"
157
+ ];
158
+ }
159
+ const inputType = mapInputType(field.type);
160
+ return [
161
+ " <div>",
162
+ ` <label className="${LABEL_CLS}" htmlFor="${field.name}">${field.label}${requiredMark}</label>`,
163
+ ` <input`,
164
+ ` id="${field.name}"`,
165
+ ` type="${inputType}"`,
166
+ ` className="${INPUT_CLS}"`,
167
+ ` value={String((formData as any).${field.name} ?? '')}`,
168
+ ` onChange={e => handleChange('${field.name}', ${coerceOnChange(field.type)})}${reqAttr}`,
169
+ ` />`,
170
+ " </div>"
171
+ ];
172
+ }
173
+ function mapInputType(type) {
174
+ switch (type) {
175
+ case "Integer":
176
+ case "Float":
177
+ case "Number":
178
+ case "Money":
179
+ return "number";
180
+ case "DateTime":
181
+ return "datetime-local";
182
+ case "Date":
183
+ return "date";
184
+ case "Email":
185
+ return "email";
186
+ case "URL":
187
+ return "url";
188
+ case "String":
189
+ case "UUID":
190
+ default:
191
+ return "text";
192
+ }
193
+ }
194
+ function coerceOnChange(type) {
195
+ switch (type) {
196
+ case "Integer":
197
+ case "Number":
198
+ return "e.target.value === '' ? undefined : Number(e.target.value)";
199
+ case "Float":
200
+ case "Money":
201
+ return "e.target.value === '' ? undefined : parseFloat(e.target.value)";
202
+ default:
203
+ return "e.target.value";
204
+ }
205
+ }
206
+ function humanize(name) {
207
+ return name.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase()).trim();
208
+ }
209
+ function escapeAttr(s) {
210
+ return s.replace(/"/g, "&quot;");
211
+ }
212
+ function escapeText(s) {
213
+ return s.replace(/</g, "&lt;").replace(/>/g, "&gt;");
214
+ }
215
+ export {
216
+ composeFormBody
217
+ };
@@ -0,0 +1,51 @@
1
+ function emitEntityDisplay() {
2
+ return `/**
3
+ * Pick the best human-readable label for an entity.
4
+ *
5
+ * Walks a prioritized list of candidate fields. Falls back to a
6
+ * truncated id if none match. Inlined into this project by
7
+ * @specverse/realize (ReactAppStarter); edit freely \u2014 nothing in
8
+ * the factory's regeneration will clobber your edits.
9
+ */
10
+ export function getEntityDisplayName(entity: Record<string, unknown> | null | undefined): string {
11
+ if (!entity) return '';
12
+
13
+ const candidates = ['name', 'title', 'displayName', 'label', 'username', 'email'];
14
+ for (const key of candidates) {
15
+ const value = entity[key];
16
+ if (typeof value === 'string' && value.trim().length > 0) {
17
+ return value;
18
+ }
19
+ }
20
+
21
+ const id = entity.id;
22
+ if (typeof id === 'string') {
23
+ return id.length > 8 ? id.slice(0, 8) + '\u2026' : id;
24
+ }
25
+ return id != null ? String(id) : '';
26
+ }
27
+
28
+ /**
29
+ * Map an entity id to the display name of the record with that id in
30
+ * a provided list. Handy for resolving belongsTo FK columns in
31
+ * list / detail / dashboard views.
32
+ *
33
+ * Typed as \`readonly unknown[]\` so callers can pass arrays of
34
+ * specific model types (e.g. \`User[]\`) without needing to cast; the
35
+ * runtime check on \`.id\` narrows safely.
36
+ */
37
+ export function resolveEntityDisplayName(
38
+ id: unknown,
39
+ records: readonly unknown[]
40
+ ): string {
41
+ if (id == null) return '';
42
+ const match = records.find((r): r is Record<string, unknown> =>
43
+ typeof r === 'object' && r !== null && (r as { id?: unknown }).id === id
44
+ );
45
+ return match ? getEntityDisplayName(match) : String(id);
46
+ }
47
+ `;
48
+ }
49
+ export {
50
+ emitEntityDisplay
51
+ };