@metaobjectsdev/codegen-ts 0.24.5 → 1.0.0-rc.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 (237) hide show
  1. package/README.md +37 -12
  2. package/dist/api-surface.d.ts +29 -0
  3. package/dist/api-surface.d.ts.map +1 -1
  4. package/dist/api-surface.js +47 -0
  5. package/dist/api-surface.js.map +1 -1
  6. package/dist/column-mapper.d.ts +12 -0
  7. package/dist/column-mapper.d.ts.map +1 -1
  8. package/dist/column-mapper.js +1 -0
  9. package/dist/column-mapper.js.map +1 -1
  10. package/dist/constants.d.ts +24 -11
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +54 -19
  13. package/dist/constants.js.map +1 -1
  14. package/dist/db-emitting.d.ts +6 -0
  15. package/dist/db-emitting.d.ts.map +1 -0
  16. package/dist/db-emitting.js +26 -0
  17. package/dist/db-emitting.js.map +1 -0
  18. package/dist/generator-registry.d.ts.map +1 -1
  19. package/dist/generator-registry.js +14 -1
  20. package/dist/generator-registry.js.map +1 -1
  21. package/dist/generator.d.ts +5 -0
  22. package/dist/generator.d.ts.map +1 -1
  23. package/dist/generator.js.map +1 -1
  24. package/dist/generators/agent-docs-file.d.ts +19 -0
  25. package/dist/generators/agent-docs-file.d.ts.map +1 -0
  26. package/dist/generators/agent-docs-file.js +257 -0
  27. package/dist/generators/agent-docs-file.js.map +1 -0
  28. package/dist/generators/agent-requirements-page.d.ts +22 -0
  29. package/dist/generators/agent-requirements-page.d.ts.map +1 -0
  30. package/dist/generators/agent-requirements-page.js +175 -0
  31. package/dist/generators/agent-requirements-page.js.map +1 -0
  32. package/dist/generators/agent-schema-input.d.ts +69 -0
  33. package/dist/generators/agent-schema-input.d.ts.map +1 -0
  34. package/dist/generators/agent-schema-input.js +23 -0
  35. package/dist/generators/agent-schema-input.js.map +1 -0
  36. package/dist/generators/agent-schema-page.d.ts +21 -0
  37. package/dist/generators/agent-schema-page.d.ts.map +1 -0
  38. package/dist/generators/agent-schema-page.js +241 -0
  39. package/dist/generators/agent-schema-page.js.map +1 -0
  40. package/dist/generators/agent-ui-page.d.ts +22 -0
  41. package/dist/generators/agent-ui-page.d.ts.map +1 -0
  42. package/dist/generators/agent-ui-page.js +253 -0
  43. package/dist/generators/agent-ui-page.js.map +1 -0
  44. package/dist/generators/api-docs-file.d.ts.map +1 -1
  45. package/dist/generators/api-docs-file.js +13 -6
  46. package/dist/generators/api-docs-file.js.map +1 -1
  47. package/dist/generators/api-model.d.ts +6 -0
  48. package/dist/generators/api-model.d.ts.map +1 -1
  49. package/dist/generators/api-model.js +54 -35
  50. package/dist/generators/api-model.js.map +1 -1
  51. package/dist/generators/callable-file.js +1 -1
  52. package/dist/generators/callable-file.js.map +1 -1
  53. package/dist/generators/docs-data-builder.d.ts.map +1 -1
  54. package/dist/generators/docs-data-builder.js +47 -2
  55. package/dist/generators/docs-data-builder.js.map +1 -1
  56. package/dist/generators/docs-data.d.ts +6 -2
  57. package/dist/generators/docs-data.d.ts.map +1 -1
  58. package/dist/generators/index.d.ts +3 -8
  59. package/dist/generators/index.d.ts.map +1 -1
  60. package/dist/generators/index.js +19 -14
  61. package/dist/generators/index.js.map +1 -1
  62. package/dist/generators/names-file.d.ts +17 -0
  63. package/dist/generators/names-file.d.ts.map +1 -0
  64. package/dist/generators/names-file.js +95 -0
  65. package/dist/generators/names-file.js.map +1 -0
  66. package/dist/generators/requirements-markdown.d.ts +18 -1
  67. package/dist/generators/requirements-markdown.d.ts.map +1 -1
  68. package/dist/generators/requirements-markdown.js +11 -9
  69. package/dist/generators/requirements-markdown.js.map +1 -1
  70. package/dist/generators/routes-file-hono.d.ts +17 -2
  71. package/dist/generators/routes-file-hono.d.ts.map +1 -1
  72. package/dist/generators/routes-file-hono.js +9 -11
  73. package/dist/generators/routes-file-hono.js.map +1 -1
  74. package/dist/generators/routes-file.d.ts +17 -2
  75. package/dist/generators/routes-file.d.ts.map +1 -1
  76. package/dist/generators/routes-file.js +10 -8
  77. package/dist/generators/routes-file.js.map +1 -1
  78. package/dist/generators/template-generator.d.ts.map +1 -1
  79. package/dist/generators/template-generator.js +20 -6
  80. package/dist/generators/template-generator.js.map +1 -1
  81. package/dist/index.d.ts +20 -5
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +43 -4
  84. package/dist/index.js.map +1 -1
  85. package/dist/metaobjects-config.d.ts +38 -1
  86. package/dist/metaobjects-config.d.ts.map +1 -1
  87. package/dist/metaobjects-config.js +9 -1
  88. package/dist/metaobjects-config.js.map +1 -1
  89. package/dist/names.d.ts +275 -0
  90. package/dist/names.d.ts.map +1 -0
  91. package/dist/names.js +433 -0
  92. package/dist/names.js.map +1 -0
  93. package/dist/overwrite-policy.d.ts.map +1 -1
  94. package/dist/overwrite-policy.js +15 -3
  95. package/dist/overwrite-policy.js.map +1 -1
  96. package/dist/projection/extract-view-spec.d.ts +25 -1
  97. package/dist/projection/extract-view-spec.d.ts.map +1 -1
  98. package/dist/projection/extract-view-spec.js +79 -6
  99. package/dist/projection/extract-view-spec.js.map +1 -1
  100. package/dist/reference-templates.d.ts +1 -1
  101. package/dist/reference-templates.d.ts.map +1 -1
  102. package/dist/reference-templates.js +1 -1
  103. package/dist/reference-templates.js.map +1 -1
  104. package/dist/render-context.d.ts +12 -1
  105. package/dist/render-context.d.ts.map +1 -1
  106. package/dist/render-context.js +1 -0
  107. package/dist/render-context.js.map +1 -1
  108. package/dist/retired-codegen-attrs.d.ts +32 -0
  109. package/dist/retired-codegen-attrs.d.ts.map +1 -0
  110. package/dist/retired-codegen-attrs.js +47 -0
  111. package/dist/retired-codegen-attrs.js.map +1 -0
  112. package/dist/routes-expose.d.ts +63 -0
  113. package/dist/routes-expose.d.ts.map +1 -0
  114. package/dist/routes-expose.js +57 -0
  115. package/dist/routes-expose.js.map +1 -0
  116. package/dist/runner.d.ts +18 -0
  117. package/dist/runner.d.ts.map +1 -1
  118. package/dist/runner.js +109 -7
  119. package/dist/runner.js.map +1 -1
  120. package/dist/templates/callable-file.d.ts +7 -2
  121. package/dist/templates/callable-file.d.ts.map +1 -1
  122. package/dist/templates/callable-file.js +54 -9
  123. package/dist/templates/callable-file.js.map +1 -1
  124. package/dist/templates/drizzle-schema.d.ts.map +1 -1
  125. package/dist/templates/drizzle-schema.js +236 -65
  126. package/dist/templates/drizzle-schema.js.map +1 -1
  127. package/dist/templates/entity-constants.d.ts +15 -6
  128. package/dist/templates/entity-constants.d.ts.map +1 -1
  129. package/dist/templates/entity-constants.js +85 -161
  130. package/dist/templates/entity-constants.js.map +1 -1
  131. package/dist/templates/entity-file.d.ts.map +1 -1
  132. package/dist/templates/entity-file.js +38 -4
  133. package/dist/templates/entity-file.js.map +1 -1
  134. package/dist/templates/entity-meta-file.d.ts +15 -1
  135. package/dist/templates/entity-meta-file.d.ts.map +1 -1
  136. package/dist/templates/entity-meta-file.js +12 -2
  137. package/dist/templates/entity-meta-file.js.map +1 -1
  138. package/dist/templates/entity-ui-descriptor.d.ts +112 -0
  139. package/dist/templates/entity-ui-descriptor.d.ts.map +1 -0
  140. package/dist/templates/entity-ui-descriptor.js +238 -0
  141. package/dist/templates/entity-ui-descriptor.js.map +1 -0
  142. package/dist/templates/field-meta.d.ts +46 -9
  143. package/dist/templates/field-meta.d.ts.map +1 -1
  144. package/dist/templates/field-meta.js +95 -21
  145. package/dist/templates/field-meta.js.map +1 -1
  146. package/dist/templates/names-decl.d.ts +38 -0
  147. package/dist/templates/names-decl.d.ts.map +1 -0
  148. package/dist/templates/names-decl.js +104 -0
  149. package/dist/templates/names-decl.js.map +1 -0
  150. package/dist/templates/projection-decl.d.ts +21 -0
  151. package/dist/templates/projection-decl.d.ts.map +1 -1
  152. package/dist/templates/projection-decl.js +53 -29
  153. package/dist/templates/projection-decl.js.map +1 -1
  154. package/dist/templates/queries-file.d.ts.map +1 -1
  155. package/dist/templates/queries-file.js +17 -2
  156. package/dist/templates/queries-file.js.map +1 -1
  157. package/dist/templates/requirement-test.d.ts.map +1 -1
  158. package/dist/templates/requirement-test.js +13 -2
  159. package/dist/templates/requirement-test.js.map +1 -1
  160. package/dist/templates/routes-file-hono.d.ts +2 -1
  161. package/dist/templates/routes-file-hono.d.ts.map +1 -1
  162. package/dist/templates/routes-file-hono.js +11 -2
  163. package/dist/templates/routes-file-hono.js.map +1 -1
  164. package/dist/templates/routes-file.d.ts +2 -1
  165. package/dist/templates/routes-file.d.ts.map +1 -1
  166. package/dist/templates/routes-file.js +54 -21
  167. package/dist/templates/routes-file.js.map +1 -1
  168. package/dist/templates/value-object-file.d.ts.map +1 -1
  169. package/dist/templates/value-object-file.js +15 -1
  170. package/dist/templates/value-object-file.js.map +1 -1
  171. package/dist/templates/view-decl.d.ts +37 -1
  172. package/dist/templates/view-decl.d.ts.map +1 -1
  173. package/dist/templates/view-decl.js +27 -3
  174. package/dist/templates/view-decl.js.map +1 -1
  175. package/dist/templates/zod-validators.d.ts +21 -0
  176. package/dist/templates/zod-validators.d.ts.map +1 -1
  177. package/dist/templates/zod-validators.js +40 -5
  178. package/dist/templates/zod-validators.js.map +1 -1
  179. package/dist/view-context.d.ts +24 -0
  180. package/dist/view-context.d.ts.map +1 -0
  181. package/dist/view-context.js +81 -0
  182. package/dist/view-context.js.map +1 -0
  183. package/package.json +6 -6
  184. package/src/api-surface.ts +53 -0
  185. package/src/column-mapper.ts +13 -0
  186. package/src/constants.ts +91 -16
  187. package/src/db-emitting.ts +31 -0
  188. package/src/generator-registry.ts +14 -4
  189. package/src/generator.ts +5 -0
  190. package/src/generators/agent-docs-file.ts +297 -0
  191. package/src/generators/agent-requirements-page.ts +199 -0
  192. package/src/generators/agent-schema-input.ts +88 -0
  193. package/src/generators/agent-schema-page.ts +297 -0
  194. package/src/generators/agent-ui-page.ts +290 -0
  195. package/src/generators/api-docs-file.ts +13 -6
  196. package/src/generators/api-model.ts +63 -34
  197. package/src/generators/callable-file.ts +1 -1
  198. package/src/generators/docs-data-builder.ts +46 -2
  199. package/src/generators/docs-data.ts +6 -2
  200. package/src/generators/index.ts +25 -14
  201. package/src/generators/names-file.ts +98 -0
  202. package/src/generators/requirements-markdown.ts +36 -2
  203. package/src/generators/routes-file-hono.ts +19 -10
  204. package/src/generators/routes-file.ts +20 -7
  205. package/src/generators/template-generator.ts +20 -6
  206. package/src/index.ts +64 -4
  207. package/src/metaobjects-config.ts +48 -2
  208. package/src/names.ts +629 -0
  209. package/src/overwrite-policy.ts +15 -3
  210. package/src/projection/extract-view-spec.ts +85 -6
  211. package/src/reference/entity.ts +21 -2
  212. package/src/reference/names.ts +125 -0
  213. package/src/reference/queries.ts +19 -3
  214. package/src/reference/routes-hono.ts +19 -9
  215. package/src/reference/routes.ts +25 -9
  216. package/src/reference-templates.ts +1 -1
  217. package/src/render-context.ts +13 -1
  218. package/src/retired-codegen-attrs.ts +52 -0
  219. package/src/routes-expose.ts +86 -0
  220. package/src/runner.ts +122 -11
  221. package/src/templates/callable-file.ts +60 -8
  222. package/src/templates/drizzle-schema.ts +248 -60
  223. package/src/templates/entity-constants.ts +95 -184
  224. package/src/templates/entity-file.ts +46 -4
  225. package/src/templates/entity-meta-file.ts +16 -3
  226. package/src/templates/entity-ui-descriptor.ts +305 -0
  227. package/src/templates/field-meta.ts +100 -19
  228. package/src/templates/names-decl.ts +165 -0
  229. package/src/templates/projection-decl.ts +72 -31
  230. package/src/templates/queries-file.ts +17 -2
  231. package/src/templates/requirement-test.ts +13 -2
  232. package/src/templates/routes-file-hono.ts +14 -2
  233. package/src/templates/routes-file.ts +69 -24
  234. package/src/templates/value-object-file.ts +15 -1
  235. package/src/templates/view-decl.ts +53 -3
  236. package/src/templates/zod-validators.ts +41 -5
  237. package/src/view-context.ts +88 -0
@@ -0,0 +1,24 @@
1
+ import type { MetaField, MetaView } from "@metaobjectsdev/metadata";
2
+ /**
3
+ * The surface a generated artifact renders, and therefore the `name` its
4
+ * emitter looks for among a field's views.
5
+ *
6
+ * These are the only two surfaces the packaged generators render. An owned
7
+ * generator (FR-040) targeting a third may pass its own name — `viewForContext`
8
+ * takes any string — but it then owns telling its authors what to name.
9
+ */
10
+ export declare const VIEW_CONTEXT_FORM = "form";
11
+ /** Both grid tiers (TanStack and Angular) render the same surface, so both ask for this. */
12
+ export declare const VIEW_CONTEXT_GRID = "grid";
13
+ /**
14
+ * The view a field declares for `context`, or `undefined` when it declares none
15
+ * at all (the caller's existing "no view" path — an inferred default — applies).
16
+ *
17
+ * Uses the RESOLVING accessor (ADR-0039): a view inherited through `extends` is
18
+ * as much the field's view as one declared on it.
19
+ *
20
+ * @throws CodegenError when the field declares several views and none is named
21
+ * for `context`. The remedy is in the message: name one of them.
22
+ */
23
+ export declare function viewForContext(field: MetaField, context: string): MetaView | undefined;
24
+ //# sourceMappingURL=view-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-context.d.ts","sourceRoot":"","sources":["../src/view-context.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpE;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,4FAA4F;AAC5F,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAexC;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAiBtF"}
@@ -0,0 +1,81 @@
1
+ // Selecting a field's view by the SURFACE that renders it (#356).
2
+ //
3
+ // A field may legally declare more than one `view.*` child and every one of them
4
+ // survives the load, so an emitter reading `field.views()[0]` let DECLARATION
5
+ // ORDER decide its output — and because several emitters read that same list,
6
+ // one declaration drove three unrelated surfaces at once. Declaring a
7
+ // `view.text` so a grid cell rendered as text silently degraded the generated
8
+ // FORM to an `<input>`, and swapping two lines of JSON with no semantic change
9
+ // flipped the form's `<select>` back. That is not a modelling mistake; it is the
10
+ // only possible outcome when one declaration serves three readers.
11
+ //
12
+ // The selector is the view's `name` — a reserved structural key already legal on
13
+ // every node — so this needs no new attribute, no provider and no
14
+ // `metamodelVersion` move (ADR-0037 step 0: the vocabulary existed, only the
15
+ // read was wrong). The same shape as #353's resolution.
16
+ //
17
+ // Two rules, and the second is the load-bearing one:
18
+ //
19
+ // 1. A field declaring ONE view keeps its exact current behaviour: that view
20
+ // applies to every surface, whatever it is named (or unnamed). Existing
21
+ // models are untouched by construction — a `name` is how a view is
22
+ // ADDRESSED by `extends` (ADR-0029 `Customer.priceCents.display`), and
23
+ // re-reading those names as surface names would break addressing.
24
+ //
25
+ // 2. A field declaring SEVERAL views must name one for the surface being
26
+ // rendered. No match is a hard error, not a fallback: falling back to
27
+ // `views()[0]` reinstates the positional read for exactly the multi-view
28
+ // case this exists to fix, and falling back to the inferred default turns a
29
+ // `name` typo ("forms") into a silently degraded control. A field cannot
30
+ // declare two views with the SAME name — the loader merges same-(type,
31
+ // name) siblings into one node — so a match is never ambiguous.
32
+ import { CodegenError } from "./errors.js";
33
+ /**
34
+ * The surface a generated artifact renders, and therefore the `name` its
35
+ * emitter looks for among a field's views.
36
+ *
37
+ * These are the only two surfaces the packaged generators render. An owned
38
+ * generator (FR-040) targeting a third may pass its own name — `viewForContext`
39
+ * takes any string — but it then owns telling its authors what to name.
40
+ */
41
+ export const VIEW_CONTEXT_FORM = "form";
42
+ /** Both grid tiers (TanStack and Angular) render the same surface, so both ask for this. */
43
+ export const VIEW_CONTEXT_GRID = "grid";
44
+ /** Render `view.dropdown name="form"` / `view.text (no name)` for a diagnostic. */
45
+ function describe(view) {
46
+ return view.name.length > 0
47
+ ? `view.${view.subType} name="${view.name}"`
48
+ : `view.${view.subType} (no name)`;
49
+ }
50
+ /** `Entity.field`, or just the field name when the field has no parent object. */
51
+ function fieldPath(field) {
52
+ const owner = field.parent?.name;
53
+ return owner !== undefined && owner.length > 0 ? `${owner}.${field.name}` : field.name;
54
+ }
55
+ /**
56
+ * The view a field declares for `context`, or `undefined` when it declares none
57
+ * at all (the caller's existing "no view" path — an inferred default — applies).
58
+ *
59
+ * Uses the RESOLVING accessor (ADR-0039): a view inherited through `extends` is
60
+ * as much the field's view as one declared on it.
61
+ *
62
+ * @throws CodegenError when the field declares several views and none is named
63
+ * for `context`. The remedy is in the message: name one of them.
64
+ */
65
+ export function viewForContext(field, context) {
66
+ const declared = field.views();
67
+ // One view (or none) is unambiguous: it applies to every surface, exactly as
68
+ // it did before this selector existed.
69
+ if (declared.length <= 1)
70
+ return declared[0];
71
+ const match = declared.find((v) => v.name === context);
72
+ if (match !== undefined)
73
+ return match;
74
+ throw new CodegenError(`Field "${fieldPath(field)}" declares ${declared.length} views ` +
75
+ `(${declared.map(describe).join(", ")}) and none is named "${context}", so codegen ` +
76
+ `cannot tell which one renders the ${context}. Name one of them "${context}" — a ` +
77
+ `view's \`name\` selects the surface it renders ("${VIEW_CONTEXT_FORM}" or ` +
78
+ `"${VIEW_CONTEXT_GRID}"). A field declaring a SINGLE view needs no name: that view ` +
79
+ `applies to every surface.`);
80
+ }
81
+ //# sourceMappingURL=view-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-context.js","sourceRoot":"","sources":["../src/view-context.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,iFAAiF;AACjF,8EAA8E;AAC9E,8EAA8E;AAC9E,sEAAsE;AACtE,8EAA8E;AAC9E,+EAA+E;AAC/E,iFAAiF;AACjF,mEAAmE;AACnE,EAAE;AACF,iFAAiF;AACjF,kEAAkE;AAClE,6EAA6E;AAC7E,wDAAwD;AACxD,EAAE;AACF,qDAAqD;AACrD,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,uEAAuE;AACvE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,8EAA8E;AAC9E,iFAAiF;AACjF,8EAA8E;AAC9E,4EAA4E;AAC5E,qEAAqE;AAGrE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACxC,4FAA4F;AAC5F,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAExC,mFAAmF;AACnF,SAAS,QAAQ,CAAC,IAAc;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QACzB,CAAC,CAAC,QAAQ,IAAI,CAAC,OAAO,UAAU,IAAI,CAAC,IAAI,GAAG;QAC5C,CAAC,CAAC,QAAQ,IAAI,CAAC,OAAO,YAAY,CAAC;AACvC,CAAC;AAED,kFAAkF;AAClF,SAAS,SAAS,CAAC,KAAgB;IACjC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;IACjC,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACzF,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,KAAgB,EAAE,OAAe;IAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;IAC/B,6EAA6E;IAC7E,uCAAuC;IACvC,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE7C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IACvD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,IAAI,YAAY,CACpB,UAAU,SAAS,CAAC,KAAK,CAAC,cAAc,QAAQ,CAAC,MAAM,SAAS;QAC9D,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,OAAO,gBAAgB;QACpF,qCAAqC,OAAO,uBAAuB,OAAO,QAAQ;QAClF,oDAAoD,iBAAiB,OAAO;QAC5E,IAAI,iBAAiB,+DAA+D;QACpF,2BAA2B,CAC9B,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaobjectsdev/codegen-ts",
3
- "version": "0.24.5",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "TypeScript codegen engine for MetaObjects — emits Drizzle, Zod, and Fastify artifacts.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -111,8 +111,8 @@
111
111
  "access": "public"
112
112
  },
113
113
  "dependencies": {
114
- "@metaobjectsdev/metadata": "0.24.5",
115
- "@metaobjectsdev/render": "0.24.5",
114
+ "@metaobjectsdev/metadata": "1.0.0-rc.1",
115
+ "@metaobjectsdev/render": "1.0.0-rc.1",
116
116
  "@biomejs/js-api": "^0.7.0",
117
117
  "@biomejs/wasm-nodejs": "^1.9.4",
118
118
  "@toon-format/toon": "^2.3.0",
@@ -124,9 +124,9 @@
124
124
  },
125
125
  "devDependencies": {
126
126
  "@biomejs/biome": "^1.9.0",
127
- "@metaobjectsdev/codegen-ts-react": "0.24.5",
128
- "@metaobjectsdev/migrate-ts": "0.24.5",
129
- "@metaobjectsdev/runtime-ts": "0.24.5",
127
+ "@metaobjectsdev/codegen-ts-react": "1.0.0-rc.1",
128
+ "@metaobjectsdev/migrate-ts": "1.0.0-rc.1",
129
+ "@metaobjectsdev/runtime-ts": "1.0.0-rc.1",
130
130
  "bun-types": "latest",
131
131
  "drizzle-orm": "^0.38.0",
132
132
  "hono": "^4.6.0",
@@ -20,7 +20,16 @@
20
20
 
21
21
  import type { MetaObject } from "@metaobjectsdev/metadata";
22
22
  import { isAbstract } from "./instance-artifacts.js";
23
+ import { isProjection } from "./projection/projection-detector.js";
23
24
  import { hasAnyRdbSource, hasWritableRdbSource } from "./source-detect.js";
25
+ import { resourcePath, restPath } from "./templates/entity-ui-descriptor.js";
26
+ import {
27
+ declaresTphDiscriminator,
28
+ isTphSubtype,
29
+ tphDiscriminatorBase,
30
+ tphDiscriminatorPin,
31
+ } from "./templates/zod-validators.js";
32
+ import { tphRouteSegment } from "./templates/tph-discriminator.js";
24
33
 
25
34
  /**
26
35
  * True when the object is served by a generated READ endpoint — so a hook has
@@ -43,3 +52,47 @@ export function servesReadApi(entity: MetaObject): boolean {
43
52
  export function servesWriteApi(entity: MetaObject): boolean {
44
53
  return !isAbstract(entity) && hasWritableRdbSource(entity);
45
54
  }
55
+
56
+ // `restPath` MOVED to templates/entity-ui-descriptor.ts, beside `resourcePath` and the
57
+ // descriptor that emits `$path` from it. Re-exported here because this module is where
58
+ // the package barrel and `generators/agent-ui-page.ts` import it from, and neither should
59
+ // have to care that the composition moved.
60
+ export { restPath } from "./templates/entity-ui-descriptor.js";
61
+
62
+ /**
63
+ * The address the generated routes actually SERVE an object at: the mount prefix plus the
64
+ * object's REST path.
65
+ *
66
+ * One function, because getting this wrong is the defect it exists to prevent, twice over.
67
+ * `agent/ui.md` documented `/authors` for routes mounted at `/api/authors`; the API
68
+ * reference did the same, separately, in two more places — three doors composing one
69
+ * address, each free to drift from the others. `templates/routes-file-hono.ts` and
70
+ * `routes-file.ts` compose the same thing into GENERATED code and remain the runtime
71
+ * authority; this is the documentation side mirroring them.
72
+ */
73
+ export function servedPath(entity: MetaObject, apiPrefix: string): string {
74
+ return `${apiPrefix}${restPath(entity)}`;
75
+ }
76
+
77
+ /**
78
+ * True when a FORM is generated for this object.
79
+ *
80
+ * `servesWriteApi` is NOT the same question, and the difference is a TPH hierarchy. The
81
+ * discriminator BASE has a writable SOURCE — which is all `servesWriteApi` asks — but no
82
+ * write ENDPOINT: `routes-file.ts` mounts it with `expose: ["list", "get"]`, because the
83
+ * discriminated union has no single writable shape. So it gets no form, and there would be
84
+ * nowhere to submit one. Each concrete SUBTYPE gets a form, even though it owns no writable
85
+ * source of its own. A read-only projection gets none: it is instantiable for read, never
86
+ * for write.
87
+ *
88
+ * This is the form generator's own filter, hoisted so `agent/ui.md` can say "there is
89
+ * deliberately no form here" for the same set of objects the generator skips. Asking
90
+ * `servesWriteApi` on the page instead announced a form for every discriminator base.
91
+ */
92
+ export function hasGeneratedForm(entity: MetaObject): boolean {
93
+ if (isTphSubtype(entity)) return true; // per-subtype form
94
+ // A discriminator base is never form-rendered directly; `entity` is already known not
95
+ // to be a subtype.
96
+ if (declaresTphDiscriminator(entity)) return false;
97
+ return servesWriteApi(entity) && !isProjection(entity);
98
+ }
@@ -264,6 +264,18 @@ export interface ColumnSpec {
264
264
  leadingComment?: string;
265
265
  /** Optional CHECK constraint expression for the column (e.g., `status IN ('A', 'B')`). */
266
266
  checkConstraint?: string;
267
+ /**
268
+ * The member list of {@link checkConstraint}, without the leading column name — e.g.
269
+ * `'A', 'B'` or `0, 5, 9`.
270
+ *
271
+ * Carried separately so the RENDERER can compose the constraint against the column's
272
+ * `<Entity>Names` constant instead of the literal `dbName` baked in above. Splitting it
273
+ * here rather than re-deriving it there keeps ONE builder for the member list, which is
274
+ * the half that must match `migrate-ts`'s `buildChecks` exactly or `meta verify` reports
275
+ * permanent drift. `checkConstraint` stays the composed literal, for the documented arm
276
+ * where no names artifact is in the run.
277
+ */
278
+ checkConstraintValues?: string;
267
279
  /**
268
280
  * Optional `.$type<...>()` chain target. Renderer (drizzle-schema.ts) emits
269
281
  * it ahead of the modifiers chain, using ts-poet `imp()` for objectRef
@@ -799,6 +811,7 @@ export function mapColumnType(
799
811
  list = values.map((v) => `'${v.replace(/'/g, "''")}'`).join(", ");
800
812
  }
801
813
  result.checkConstraint = `${dbName} IN (${list})`;
814
+ result.checkConstraintValues = list;
802
815
  }
803
816
  }
804
817
 
package/src/constants.ts CHANGED
@@ -1,28 +1,103 @@
1
1
  // Local constants for codegen-ts.
2
2
 
3
- /** The marker that says "codegen owns this file" — drives the overwrite policy. */
3
+ /**
4
+ * The header line every emitter puts at the top of a generated file.
5
+ *
6
+ * Informational ON THIS PORT. It used to be documented here as the thing that "drives
7
+ * the overwrite policy", and it does not: `overwrite-policy.ts` decides from the
8
+ * `.gen-state` snapshot body and the committed hash manifest and never reads this
9
+ * string (grep it — no non-template module imports it). Deleting the header from a
10
+ * generated file does not take ownership of it here; it just changes the content, so
11
+ * the hash stops matching and the file is refused like any other edit.
12
+ *
13
+ * The JVM ports are the opposite: there the marker IS the decision
14
+ * (`GeneratedFileWriter`), and deleting it is exactly how you take ownership. Both
15
+ * behaviours are stated in `docs/features/own-your-codegen.md` — do not collapse them
16
+ * into one sentence, because the gesture that protects a file differs per port.
17
+ */
4
18
  export const GENERATED_HEADER = "@generated by @metaobjectsdev/codegen-ts";
5
19
 
6
- /** Suffix for sibling user extension files (codegen never touches these). */
7
- export const EXTRA_SUFFIX = ".extra";
20
+ // `EXTRA_SUFFIX = ".extra"` was removed here. It was a public export of this package
21
+ // wired to nothing: no generator, orphan sweep or write path ever compared a path
22
+ // against it, so its presence implied tool support for a name that is pure convention.
23
+ // A `<Entity>.extra.ts` sibling is safe because codegen only writes the paths it
24
+ // records in `.gen-state/.hashes.json` — not because of its name — and the generated
25
+ // barrel is built from the model, so it does not re-export it. Say that in prose;
26
+ // do not re-add a constant that suggests the engine knows the name.
8
27
 
9
28
  /** Default outDir used by tests + as a sane default for generate(). */
10
29
  export const DEFAULT_OUT_DIR = "./src/db/entities";
11
30
 
12
31
  // ---------------------------------------------------------------------------
13
- // Codegen-control attributes.
32
+ // Retired codegen-control attributes.
14
33
  //
15
- // These are per-entity opt-in/opt-out flags read by generators (NOT metamodel
16
- // vocabulary they tune codegen, not the model). Named here so the literals
17
- // aren't scattered as magic strings across the generator packages (compile-time
18
- // typo safety), matching the metadata package's constants discipline.
34
+ // `@emitRoutes` / `@emitTanstack` / `@emitForm` / `@emitGrid` / `@emitAngular`
35
+ // were read off metadata by generator filters and were NEVER registered
36
+ // metamodel vocabulary. The strict loader rejects every one of them with
37
+ // ERR_UNKNOWN_ATTR and `meta verify` loads strict — while `meta gen` loads
38
+ // non-strict and honoured them. So an adopter who authored the documented
39
+ // per-entity opt-out got the behaviour AND a red `meta verify`: half-working,
40
+ // which is worse than either half, and exactly the class ADR-0023 §2 names.
41
+ //
42
+ // Registering them was refused. That moves `metamodelVersion` and forces a
43
+ // four-registry publish for a TypeScript-only generator kill switch that four
44
+ // of five ports would never read. The replacement already exists and is
45
+ // verified end to end: decide per generator what you consume — wire only the
46
+ // generators whose output you actually import, and narrow one with its
47
+ // `filter` option. The one clause that was opt-IN rather than opt-out (a TPH
48
+ // subtype's own per-subtype grid) cannot be a `filter`, since a filter is
49
+ // ANDed with the built-in gates and can only NARROW; it is the
50
+ // `tphSubtypeGrids` option on tanstackGrid()/tanstackGridHook() instead.
51
+ //
52
+ // No generator reads any of these names now. They survive HERE and nowhere
53
+ // else, so `meta gen` can recognise a stale one still sitting in an adopter's
54
+ // metadata and say what replaced it (see retired-codegen-attrs.ts). Keeping
55
+ // the name and its replacement in ONE record is the point: a warning whose
56
+ // text lives apart from the list it is warning about drifts from it.
19
57
  // ---------------------------------------------------------------------------
20
58
 
21
- /** `@emitTanstack: false` skip the TanStack hooks + grid generators for an entity. */
22
- export const CODEGEN_ATTR_EMIT_TANSTACK = "emitTanstack";
23
- /** `@emitGrid: true` opt a TPH subtype IN to its own per-subtype grid (default: the polymorphic base grid is the single source). */
24
- export const CODEGEN_ATTR_EMIT_GRID = "emitGrid";
25
- /** `@emitForm: false` skip the React form generator for an entity. */
26
- export const CODEGEN_ATTR_EMIT_FORM = "emitForm";
27
- /** `@emitRoutes: false` — skip the Fastify routes generator for an entity. */
28
- export const CODEGEN_ATTR_EMIT_ROUTES = "emitRoutes";
59
+ /** One retired codegen-control attribute, paired with what an adopter does instead. */
60
+ export interface RetiredCodegenAttr {
61
+ /** The bare attribute name, as it appears in metadata (no `@` sigil). */
62
+ readonly name: string;
63
+ /** What to do instead, phrased as an instruction and naming a real API. */
64
+ readonly replacement: string;
65
+ }
66
+
67
+ /** Every retired codegen-control attribute. Read ONLY by the `meta gen` warning. */
68
+ export const RETIRED_CODEGEN_ATTRS: readonly RetiredCodegenAttr[] = [
69
+ {
70
+ name: "emitRoutes",
71
+ replacement:
72
+ 'drop routesFile() / routesFileHono() from `generators` in metaobjects.config.ts if ' +
73
+ 'you do not consume REST routes, or narrow it — routesFile({ filter: (e) => e.name !== "Ledger" })',
74
+ },
75
+ {
76
+ name: "emitTanstack",
77
+ replacement:
78
+ 'drop tanstackQuery() / tanstackGrid() / tanstackGridHook() from `generators` in ' +
79
+ 'metaobjects.config.ts if you do not consume their output, or narrow one — ' +
80
+ 'tanstackQuery({ filter: (e) => e.name !== "InternalAudit" })',
81
+ },
82
+ {
83
+ name: "emitForm",
84
+ replacement:
85
+ 'drop formFile() from `generators` in metaobjects.config.ts if you do not consume ' +
86
+ 'generated forms, or narrow it — formFile({ filter: (e) => e.name !== "InternalAudit" })',
87
+ },
88
+ {
89
+ name: "emitGrid",
90
+ replacement:
91
+ 'pass the `tphSubtypeGrids` option — tanstackGrid({ tphSubtypeGrids: (e) => e.name === ' +
92
+ '"CopayAuth" }) — and pass the SAME predicate to tanstackGridHook(), or the emitted ' +
93
+ '<Sub>.grid.ts has no <Sub>.columns.tsx to import. This one is an opt-IN, so a `filter` ' +
94
+ 'cannot express it: a filter is ANDed with the built-in gates and can only narrow',
95
+ },
96
+ {
97
+ name: "emitAngular",
98
+ replacement:
99
+ 'drop angularServiceFile() / angularFormFile() / angularGridFile() from `generators` in ' +
100
+ 'metaobjects.config.ts if you do not consume Angular output, or narrow one — ' +
101
+ 'angularServiceFile({ filter: (e) => e.name !== "InternalAudit" })',
102
+ },
103
+ ] as const;
@@ -0,0 +1,31 @@
1
+ // Which objects make a project a DATABASE project — and therefore require a `dialect`.
2
+ //
3
+ // THIS IS THE ONE ANSWER, and it is hoisted here because two commands need it and a second
4
+ // copy would be a second answer. `runGen` throws when a model emits database code and the
5
+ // config declares no dialect (see `missingDialectMessage`), and it throws BEFORE
6
+ // `normalizeConfig` fills its defaults on purpose: `DEFAULT_DIALECT` is INERT, existing
7
+ // only so a value-object-only project need not name one. A DB project that forgot it gets
8
+ // a named error rather than silently-defaulted output — "a Postgres project quietly
9
+ // emitting sqlite", as the runner's own comment puts it.
10
+ //
11
+ // `meta docs` needs the same answer for `agent/schema.md`. Reading `?? DEFAULT_DIALECT`
12
+ // there instead would document a sqlite schema for a project `meta gen` refuses to build
13
+ // — asserting an answer the toolchain never gave.
14
+
15
+ import type { MetaObject } from "@metaobjectsdev/metadata";
16
+ import { hasAnyRdbSource } from "./source-detect.js";
17
+
18
+ /** The concrete objects a run would emit database code for. Empty ⇒ no dialect needed. */
19
+ export function dbEmittingObjects(entities: readonly MetaObject[]): MetaObject[] {
20
+ return entities.filter((e) => !e.isAbstract && hasAnyRdbSource(e));
21
+ }
22
+
23
+ /** The one wording for "this model needs a dialect and the config has none". */
24
+ export function missingDialectMessage(dbEmitting: readonly MetaObject[]): string {
25
+ const names = dbEmitting.map((e) => e.name).join(", ");
26
+ return (
27
+ `codegen config is missing dialect — required because this model ` +
28
+ `generates database code for: ${names}. Set dialect in ` +
29
+ `metaobjects.config.ts. (A model of only value objects and/or sourceless projections may omit it.)`
30
+ );
31
+ }
@@ -18,13 +18,17 @@
18
18
  // door for documentation is `meta docs` (D1).
19
19
 
20
20
  import type { Generator } from "./generator.js";
21
+ // The four ADR-0034 ownable generators are no longer exported from ./generators/index.js
22
+ // (1.0 removed them — see that file's header). They remain the engine's internal composers
23
+ // and the stable-name registry still constructs them, so import them from their own modules.
24
+ import { entityFile } from "./generators/entity-file.js";
25
+ import { queriesFile } from "./generators/queries-file.js";
26
+ import { routesFile } from "./generators/routes-file.js";
27
+ import { barrel } from "./generators/barrel.js";
21
28
  import {
22
- entityFile,
23
- queriesFile,
24
29
  callableFile,
25
- routesFile,
26
30
  routesFileHono,
27
- barrel,
31
+ namesFile,
28
32
  mermaidErDiagram,
29
33
  promptRender,
30
34
  outputParser,
@@ -111,6 +115,12 @@ export const generatorRegistry: Record<string, GeneratorRegistryEntry> = {
111
115
  factory: () => barrel(),
112
116
  options: "target?",
113
117
  },
118
+ names: {
119
+ name: "names",
120
+ description: "Per-entity physical database name constants (table/view, schema, columns).",
121
+ tier: "native",
122
+ factory: () => namesFile(),
123
+ },
114
124
  "prompt-render": {
115
125
  name: "prompt-render",
116
126
  description: "Per-template prompt-render helper over the render engine.",
package/src/generator.ts CHANGED
@@ -63,6 +63,11 @@ export interface Generator {
63
63
  * that Hono routes are actually being emitted and document them — rather than
64
64
  * silently omitting the Hono CRUD registrars whenever the variant is wired. */
65
65
  emitsHonoRoutes?: boolean;
66
+ /** §A6 — marks the generator that emits the <Entity>Names artifact. The runner
67
+ * aggregates this across the suite into ResolvedGenConfig.includeNames, which the
68
+ * entity generator reads to decide whether it may reference those constants.
69
+ * Same mechanism as emitsHonoRoutes/includeHonoRoutes. */
70
+ emitsNames?: boolean;
66
71
  }
67
72
 
68
73
  export type GeneratorFactory<TOpts = void> = TOpts extends void