@metaobjectsdev/codegen-ts 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/README.md +1 -1
  2. package/dist/column-mapper.d.ts.map +1 -1
  3. package/dist/column-mapper.js +24 -8
  4. package/dist/column-mapper.js.map +1 -1
  5. package/dist/constants.d.ts +8 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +16 -0
  8. package/dist/constants.js.map +1 -1
  9. package/dist/docs-paths.d.ts +58 -0
  10. package/dist/docs-paths.d.ts.map +1 -0
  11. package/dist/docs-paths.js +89 -0
  12. package/dist/docs-paths.js.map +1 -0
  13. package/dist/enum-import.d.ts +14 -0
  14. package/dist/enum-import.d.ts.map +1 -0
  15. package/dist/enum-import.js +35 -0
  16. package/dist/enum-import.js.map +1 -0
  17. package/dist/enum-shared.d.ts +32 -0
  18. package/dist/enum-shared.d.ts.map +1 -0
  19. package/dist/enum-shared.js +83 -0
  20. package/dist/enum-shared.js.map +1 -0
  21. package/dist/generator-registry.d.ts +22 -0
  22. package/dist/generator-registry.d.ts.map +1 -0
  23. package/dist/generator-registry.js +161 -0
  24. package/dist/generator-registry.js.map +1 -0
  25. package/dist/generator.d.ts +6 -0
  26. package/dist/generator.d.ts.map +1 -1
  27. package/dist/generator.js.map +1 -1
  28. package/dist/generators/api-doc-render.d.ts +17 -0
  29. package/dist/generators/api-doc-render.d.ts.map +1 -0
  30. package/dist/generators/api-doc-render.js +431 -0
  31. package/dist/generators/api-doc-render.js.map +1 -0
  32. package/dist/generators/api-docs-file.d.ts +21 -0
  33. package/dist/generators/api-docs-file.d.ts.map +1 -0
  34. package/dist/generators/api-docs-file.js +112 -0
  35. package/dist/generators/api-docs-file.js.map +1 -0
  36. package/dist/generators/api-field-shape.d.ts +39 -0
  37. package/dist/generators/api-field-shape.d.ts.map +1 -0
  38. package/dist/generators/api-field-shape.js +92 -0
  39. package/dist/generators/api-field-shape.js.map +1 -0
  40. package/dist/generators/api-label.d.ts +3 -0
  41. package/dist/generators/api-label.d.ts.map +1 -0
  42. package/dist/generators/api-label.js +8 -0
  43. package/dist/generators/api-label.js.map +1 -0
  44. package/dist/generators/api-model.d.ts +122 -0
  45. package/dist/generators/api-model.d.ts.map +1 -0
  46. package/dist/generators/api-model.js +809 -0
  47. package/dist/generators/api-model.js.map +1 -0
  48. package/dist/generators/docs-data-builder.d.ts +26 -4
  49. package/dist/generators/docs-data-builder.d.ts.map +1 -1
  50. package/dist/generators/docs-data-builder.js +436 -164
  51. package/dist/generators/docs-data-builder.js.map +1 -1
  52. package/dist/generators/docs-data.d.ts +136 -27
  53. package/dist/generators/docs-data.d.ts.map +1 -1
  54. package/dist/generators/docs-data.js +1 -1
  55. package/dist/generators/docs-data.js.map +1 -1
  56. package/dist/generators/docs-file.d.ts +19 -0
  57. package/dist/generators/docs-file.d.ts.map +1 -1
  58. package/dist/generators/docs-file.js +154 -27
  59. package/dist/generators/docs-file.js.map +1 -1
  60. package/dist/generators/entity-file.d.ts.map +1 -1
  61. package/dist/generators/entity-file.js +29 -14
  62. package/dist/generators/entity-file.js.map +1 -1
  63. package/dist/generators/extractor-file.d.ts.map +1 -1
  64. package/dist/generators/extractor-file.js +2 -1
  65. package/dist/generators/extractor-file.js.map +1 -1
  66. package/dist/generators/field-anchor.d.ts +7 -0
  67. package/dist/generators/field-anchor.d.ts.map +1 -0
  68. package/dist/generators/field-anchor.js +23 -0
  69. package/dist/generators/field-anchor.js.map +1 -0
  70. package/dist/generators/index.d.ts +8 -1
  71. package/dist/generators/index.d.ts.map +1 -1
  72. package/dist/generators/index.js +6 -0
  73. package/dist/generators/index.js.map +1 -1
  74. package/dist/generators/mermaid-er.d.ts +14 -0
  75. package/dist/generators/mermaid-er.d.ts.map +1 -1
  76. package/dist/generators/mermaid-er.js +14 -0
  77. package/dist/generators/mermaid-er.js.map +1 -1
  78. package/dist/generators/output-parser-file.d.ts.map +1 -1
  79. package/dist/generators/output-parser-file.js +3 -4
  80. package/dist/generators/output-parser-file.js.map +1 -1
  81. package/dist/generators/output-prompt-file.d.ts.map +1 -1
  82. package/dist/generators/output-prompt-file.js +2 -2
  83. package/dist/generators/output-prompt-file.js.map +1 -1
  84. package/dist/generators/prompt-render-file.d.ts.map +1 -1
  85. package/dist/generators/prompt-render-file.js +3 -4
  86. package/dist/generators/prompt-render-file.js.map +1 -1
  87. package/dist/generators/queries-file.d.ts.map +1 -1
  88. package/dist/generators/queries-file.js +8 -3
  89. package/dist/generators/queries-file.js.map +1 -1
  90. package/dist/generators/render-helper-file.d.ts.map +1 -1
  91. package/dist/generators/render-helper-file.js +2 -2
  92. package/dist/generators/render-helper-file.js.map +1 -1
  93. package/dist/generators/routes-file-hono.d.ts.map +1 -1
  94. package/dist/generators/routes-file-hono.js +5 -1
  95. package/dist/generators/routes-file-hono.js.map +1 -1
  96. package/dist/generators/routes-file.d.ts +3 -0
  97. package/dist/generators/routes-file.d.ts.map +1 -1
  98. package/dist/generators/routes-file.js +6 -1
  99. package/dist/generators/routes-file.js.map +1 -1
  100. package/dist/generators/template-doc-builder.d.ts +19 -0
  101. package/dist/generators/template-doc-builder.d.ts.map +1 -0
  102. package/dist/generators/template-doc-builder.js +220 -0
  103. package/dist/generators/template-doc-builder.js.map +1 -0
  104. package/dist/generators/template-doc-data.d.ts +62 -0
  105. package/dist/generators/template-doc-data.d.ts.map +1 -0
  106. package/dist/generators/template-doc-data.js +16 -0
  107. package/dist/generators/template-doc-data.js.map +1 -0
  108. package/dist/generators/template-payload-tree.d.ts +15 -0
  109. package/dist/generators/template-payload-tree.d.ts.map +1 -0
  110. package/dist/generators/template-payload-tree.js +61 -0
  111. package/dist/generators/template-payload-tree.js.map +1 -0
  112. package/dist/generators/template-source-annotate.d.ts +74 -0
  113. package/dist/generators/template-source-annotate.d.ts.map +1 -0
  114. package/dist/generators/template-source-annotate.js +184 -0
  115. package/dist/generators/template-source-annotate.js.map +1 -0
  116. package/dist/generators/template-source-render.d.ts +24 -0
  117. package/dist/generators/template-source-render.d.ts.map +1 -0
  118. package/dist/generators/template-source-render.js +175 -0
  119. package/dist/generators/template-source-render.js.map +1 -0
  120. package/dist/generators/trace-helper-file.d.ts +9 -0
  121. package/dist/generators/trace-helper-file.d.ts.map +1 -0
  122. package/dist/generators/trace-helper-file.js +196 -0
  123. package/dist/generators/trace-helper-file.js.map +1 -0
  124. package/dist/index.d.ts +29 -4
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +28 -2
  127. package/dist/index.js.map +1 -1
  128. package/dist/metaobjects-config.d.ts +75 -2
  129. package/dist/metaobjects-config.d.ts.map +1 -1
  130. package/dist/metaobjects-config.js +43 -0
  131. package/dist/metaobjects-config.js.map +1 -1
  132. package/dist/naming.d.ts +19 -0
  133. package/dist/naming.d.ts.map +1 -1
  134. package/dist/naming.js +41 -0
  135. package/dist/naming.js.map +1 -1
  136. package/dist/payload-codegen.d.ts.map +1 -1
  137. package/dist/payload-codegen.js +12 -4
  138. package/dist/payload-codegen.js.map +1 -1
  139. package/dist/projection/extract-view-spec.d.ts.map +1 -1
  140. package/dist/projection/extract-view-spec.js +51 -25
  141. package/dist/projection/extract-view-spec.js.map +1 -1
  142. package/dist/relation-resolver.d.ts +16 -0
  143. package/dist/relation-resolver.d.ts.map +1 -1
  144. package/dist/relation-resolver.js +82 -1
  145. package/dist/relation-resolver.js.map +1 -1
  146. package/dist/render-context.d.ts +4 -0
  147. package/dist/render-context.d.ts.map +1 -1
  148. package/dist/render-context.js.map +1 -1
  149. package/dist/render-engine/embedded-templates.generated.d.ts +2 -0
  150. package/dist/render-engine/embedded-templates.generated.d.ts.map +1 -0
  151. package/dist/render-engine/embedded-templates.generated.js +15 -0
  152. package/dist/render-engine/embedded-templates.generated.js.map +1 -0
  153. package/dist/render-engine/framework-provider.d.ts.map +1 -1
  154. package/dist/render-engine/framework-provider.js +26 -13
  155. package/dist/render-engine/framework-provider.js.map +1 -1
  156. package/dist/runner.d.ts.map +1 -1
  157. package/dist/runner.js +17 -0
  158. package/dist/runner.js.map +1 -1
  159. package/dist/templates/docs-file.d.ts +2 -6
  160. package/dist/templates/docs-file.d.ts.map +1 -1
  161. package/dist/templates/docs-file.js +2 -5
  162. package/dist/templates/docs-file.js.map +1 -1
  163. package/dist/templates/drizzle-schema.d.ts.map +1 -1
  164. package/dist/templates/drizzle-schema.js +30 -2
  165. package/dist/templates/drizzle-schema.js.map +1 -1
  166. package/dist/templates/entity-constants.d.ts +7 -0
  167. package/dist/templates/entity-constants.d.ts.map +1 -1
  168. package/dist/templates/entity-constants.js +1 -1
  169. package/dist/templates/entity-constants.js.map +1 -1
  170. package/dist/templates/entity-file.d.ts.map +1 -1
  171. package/dist/templates/entity-file.js +16 -5
  172. package/dist/templates/entity-file.js.map +1 -1
  173. package/dist/templates/enums-file.d.ts +11 -0
  174. package/dist/templates/enums-file.d.ts.map +1 -0
  175. package/dist/templates/enums-file.js +44 -0
  176. package/dist/templates/enums-file.js.map +1 -0
  177. package/dist/templates/extract-delegate-emitter.d.ts.map +1 -1
  178. package/dist/templates/extract-delegate-emitter.js +5 -7
  179. package/dist/templates/extract-delegate-emitter.js.map +1 -1
  180. package/dist/templates/extract-schema-emitter.d.ts.map +1 -1
  181. package/dist/templates/extract-schema-emitter.js +5 -1
  182. package/dist/templates/extract-schema-emitter.js.map +1 -1
  183. package/dist/templates/extractor.d.ts.map +1 -1
  184. package/dist/templates/extractor.js +56 -39
  185. package/dist/templates/extractor.js.map +1 -1
  186. package/dist/templates/field-meta.d.ts.map +1 -1
  187. package/dist/templates/field-meta.js +1 -5
  188. package/dist/templates/field-meta.js.map +1 -1
  189. package/dist/templates/filter-allowlist.d.ts +7 -2
  190. package/dist/templates/filter-allowlist.d.ts.map +1 -1
  191. package/dist/templates/filter-allowlist.js +17 -9
  192. package/dist/templates/filter-allowlist.js.map +1 -1
  193. package/dist/templates/filter-type.d.ts +7 -1
  194. package/dist/templates/filter-type.d.ts.map +1 -1
  195. package/dist/templates/filter-type.js +9 -5
  196. package/dist/templates/filter-type.js.map +1 -1
  197. package/dist/templates/find-templates.d.ts +4 -0
  198. package/dist/templates/find-templates.d.ts.map +1 -0
  199. package/dist/templates/find-templates.js +15 -0
  200. package/dist/templates/find-templates.js.map +1 -0
  201. package/dist/templates/fr010-field-mapping.d.ts +2 -0
  202. package/dist/templates/fr010-field-mapping.d.ts.map +1 -1
  203. package/dist/templates/fr010-field-mapping.js +10 -6
  204. package/dist/templates/fr010-field-mapping.js.map +1 -1
  205. package/dist/templates/inferred-types.d.ts +44 -7
  206. package/dist/templates/inferred-types.d.ts.map +1 -1
  207. package/dist/templates/inferred-types.js +107 -16
  208. package/dist/templates/inferred-types.js.map +1 -1
  209. package/dist/templates/mermaid-er.d.ts +35 -2
  210. package/dist/templates/mermaid-er.d.ts.map +1 -1
  211. package/dist/templates/mermaid-er.js +174 -7
  212. package/dist/templates/mermaid-er.js.map +1 -1
  213. package/dist/templates/output-parser.d.ts.map +1 -1
  214. package/dist/templates/output-parser.js +30 -79
  215. package/dist/templates/output-parser.js.map +1 -1
  216. package/dist/templates/output-prompt.d.ts.map +1 -1
  217. package/dist/templates/output-prompt.js +2 -2
  218. package/dist/templates/output-prompt.js.map +1 -1
  219. package/dist/templates/queries-file.d.ts.map +1 -1
  220. package/dist/templates/queries-file.js +112 -4
  221. package/dist/templates/queries-file.js.map +1 -1
  222. package/dist/templates/queries.d.ts +5 -0
  223. package/dist/templates/queries.d.ts.map +1 -1
  224. package/dist/templates/queries.js +7 -7
  225. package/dist/templates/queries.js.map +1 -1
  226. package/dist/templates/recover-schema-emitter.d.ts +8 -0
  227. package/dist/templates/recover-schema-emitter.d.ts.map +1 -0
  228. package/dist/templates/recover-schema-emitter.js +64 -0
  229. package/dist/templates/recover-schema-emitter.js.map +1 -0
  230. package/dist/templates/relations-block.js +10 -0
  231. package/dist/templates/relations-block.js.map +1 -1
  232. package/dist/templates/render-helper.d.ts.map +1 -1
  233. package/dist/templates/render-helper.js +4 -4
  234. package/dist/templates/render-helper.js.map +1 -1
  235. package/dist/templates/routes-file.d.ts.map +1 -1
  236. package/dist/templates/routes-file.js +183 -6
  237. package/dist/templates/routes-file.js.map +1 -1
  238. package/dist/templates/tph-discriminator.d.ts +56 -0
  239. package/dist/templates/tph-discriminator.d.ts.map +1 -0
  240. package/dist/templates/tph-discriminator.js +180 -0
  241. package/dist/templates/tph-discriminator.js.map +1 -0
  242. package/dist/templates/value-object-file.d.ts +2 -1
  243. package/dist/templates/value-object-file.d.ts.map +1 -1
  244. package/dist/templates/value-object-file.js +32 -4
  245. package/dist/templates/value-object-file.js.map +1 -1
  246. package/dist/templates/zod-validators.d.ts +64 -1
  247. package/dist/templates/zod-validators.d.ts.map +1 -1
  248. package/dist/templates/zod-validators.js +181 -8
  249. package/dist/templates/zod-validators.js.map +1 -1
  250. package/package.json +103 -34
  251. package/src/column-mapper.ts +25 -8
  252. package/src/constants.ts +18 -0
  253. package/src/docs-paths.ts +128 -0
  254. package/src/enum-import.ts +43 -0
  255. package/src/enum-shared.ts +95 -0
  256. package/src/generator-registry.ts +204 -0
  257. package/src/generator.ts +6 -0
  258. package/src/generators/api-doc-render.ts +572 -0
  259. package/src/generators/api-docs-file.ts +146 -0
  260. package/src/generators/api-field-shape.ts +114 -0
  261. package/src/generators/api-label.ts +7 -0
  262. package/src/generators/api-model.ts +1067 -0
  263. package/src/generators/docs-data-builder.ts +479 -185
  264. package/src/generators/docs-data.ts +139 -28
  265. package/src/generators/docs-file.ts +205 -39
  266. package/src/generators/entity-file.ts +31 -15
  267. package/src/generators/extractor-file.ts +2 -1
  268. package/src/generators/field-anchor.ts +24 -0
  269. package/src/generators/index.ts +8 -1
  270. package/src/generators/mermaid-er.ts +14 -0
  271. package/src/generators/output-parser-file.ts +3 -4
  272. package/src/generators/output-prompt-file.ts +2 -1
  273. package/src/generators/prompt-render-file.ts +3 -4
  274. package/src/generators/queries-file.ts +9 -3
  275. package/src/generators/render-helper-file.ts +2 -1
  276. package/src/generators/routes-file-hono.ts +5 -1
  277. package/src/generators/routes-file.ts +7 -1
  278. package/src/generators/template-doc-builder.ts +306 -0
  279. package/src/generators/template-doc-data.ts +85 -0
  280. package/src/generators/template-payload-tree.ts +71 -0
  281. package/src/generators/template-source-annotate.ts +290 -0
  282. package/src/generators/template-source-render.ts +203 -0
  283. package/src/generators/trace-helper-file.ts +301 -0
  284. package/src/index.ts +55 -4
  285. package/src/metaobjects-config.ts +117 -2
  286. package/src/naming.ts +48 -0
  287. package/src/payload-codegen.ts +14 -3
  288. package/src/projection/extract-view-spec.ts +49 -30
  289. package/src/relation-resolver.ts +103 -1
  290. package/src/render-context.ts +4 -0
  291. package/src/render-engine/embedded-templates.generated.ts +14 -0
  292. package/src/render-engine/framework-provider.ts +25 -11
  293. package/src/runner.ts +21 -0
  294. package/src/templates/docs-file.ts +2 -9
  295. package/src/templates/drizzle-schema.ts +31 -1
  296. package/src/templates/entity-constants.ts +1 -1
  297. package/src/templates/entity-file.ts +16 -5
  298. package/src/templates/enums-file.ts +50 -0
  299. package/src/templates/extract-delegate-emitter.ts +5 -6
  300. package/src/templates/extractor.ts +68 -38
  301. package/src/templates/field-meta.ts +0 -6
  302. package/src/templates/filter-allowlist.ts +17 -10
  303. package/src/templates/filter-type.ts +8 -6
  304. package/src/templates/find-templates.ts +15 -0
  305. package/src/templates/fr010-field-mapping.ts +10 -8
  306. package/src/templates/inferred-types.ts +108 -18
  307. package/src/templates/mermaid-er.ts +176 -8
  308. package/src/templates/output-parser.ts +30 -79
  309. package/src/templates/output-prompt.ts +2 -1
  310. package/src/templates/queries-file.ts +132 -3
  311. package/src/templates/queries.ts +15 -7
  312. package/src/templates/relations-block.ts +17 -0
  313. package/src/templates/render-helper.ts +4 -3
  314. package/src/templates/routes-file.ts +233 -6
  315. package/src/templates/tph-discriminator.ts +232 -0
  316. package/src/templates/value-object-file.ts +38 -4
  317. package/src/templates/zod-validators.ts +204 -7
  318. package/templates/api/agent-api.md.mustache +30 -0
  319. package/templates/api/entity-api.md.mustache +69 -0
  320. package/templates/api/index.md.mustache +21 -0
  321. package/templates/docs/entity-page.md.mustache +33 -21
  322. package/templates/docs/template-page.md.mustache +56 -0
  323. package/src/templates/extract-schema-emitter.ts +0 -111
@@ -0,0 +1,184 @@
1
+ // Annotated-template IR (linked-template-source-docs, Task 1).
2
+ //
3
+ // annotateTemplate parses a Mustache template into an ordered TplToken[] where
4
+ // every {{variable}} / {{#section}} is resolved to the payload field it
5
+ // references plus that field's doc link. It tokenizes with the SAME parser
6
+ // verify walks (`parseTemplate` from @metaobjectsdev/render) and resolves each
7
+ // path with verify's EXPORTED `resolveTemplateVariable` — so the annotator and
8
+ // the build-time drift gate share ONE resolution and can never disagree (a
9
+ // later conformance gate asserts exactly that).
10
+ //
11
+ // Reuse, not reimplementation:
12
+ // • parseTemplate — the render verify engine's Mustache.parse.
13
+ // • resolveTemplateVariable — verify's context-stack walk (sections push the
14
+ // nested subtree; dotted paths descend). Generic
15
+ // over the node, so an ENRICHED tree (carrying
16
+ // owner/type/required) resolves identically.
17
+ //
18
+ // The annotator is a pure function over an enriched payload tree + the source —
19
+ // no metadata import, no I/O — so it is unit-testable and golden-pinnable.
20
+ import { parseTemplate, resolveTemplateVariable, } from "@metaobjectsdev/render";
21
+ import { fieldAnchorSlug } from "./field-anchor.js";
22
+ /** The doc-page href for a resolved field: `./<OwnerVO>.md#field-<name>`. The
23
+ * anchor slug comes from the SHARED `fieldAnchorSlug()` (prefixed — avoids
24
+ * colliding with other page anchors), the SAME helper the entity page uses to
25
+ * emit its per-field `<a id="field-<name>">` anchor, so the link and the anchor
26
+ * can never drift. */
27
+ function fieldHref(owner, name) {
28
+ return `./${owner}.md#${fieldAnchorSlug(name)}`;
29
+ }
30
+ function toResolvedField(f) {
31
+ return { owner: f.owner, name: f.name, type: f.type, required: f.required };
32
+ }
33
+ /**
34
+ * Parse `source` into an annotated IR, resolving each variable/section against
35
+ * the enriched `payload` tree using verify's shared resolution.
36
+ */
37
+ export function annotateTemplate(source, payload, opts) {
38
+ const root = payload;
39
+ const out = [];
40
+ let cursor = 0;
41
+ // How a resolved field's href is built: the injected layout-aware resolver
42
+ // when provided, else the flat default (byte-identical to today's output).
43
+ const buildFieldHref = opts.fieldHref ?? fieldHref;
44
+ // Emit verbatim source between `cursor` and `to` as a text token, advancing
45
+ // the cursor. This recovers literal text AND any span Mustache trimmed as
46
+ // standalone (e.g. the newline after a standalone partial/section), so the
47
+ // concatenated tokens reproduce the source byte-for-byte.
48
+ function emitTextUpTo(to) {
49
+ if (to > cursor) {
50
+ out.push({ kind: "text", text: source.slice(cursor, to) });
51
+ cursor = to;
52
+ }
53
+ }
54
+ function resolveAt(stack, path) {
55
+ const hit = resolveTemplateVariable(stack, path);
56
+ if (!hit)
57
+ return undefined;
58
+ const field = toResolvedField(hit);
59
+ return { field, href: buildFieldHref(field.owner, field.name) };
60
+ }
61
+ // Build a variable token ({{x}} or {{&x}}/{{{x}}}). The implicit iterator
62
+ // `.` is always valid against the current context; any other path resolves
63
+ // against the enriched tree (carrying field + href when found).
64
+ function makeVarToken(kind, raw, value, stack) {
65
+ if (value === ".")
66
+ return { kind, raw, path: value, valid: true };
67
+ const r = resolveAt(stack, value);
68
+ return r
69
+ ? { kind, raw, path: value, field: r.field, href: r.href, valid: true }
70
+ : { kind, raw, path: value, valid: false };
71
+ }
72
+ function walk(tokens, stack) {
73
+ for (const tok of tokens) {
74
+ const type = tok[0];
75
+ const value = tok[1];
76
+ const start = tok[2];
77
+ const end = tok[3];
78
+ // Recover any source between the previous token and this tag (literal
79
+ // text, or trimmed standalone whitespace).
80
+ emitTextUpTo(start);
81
+ switch (type) {
82
+ case "text": {
83
+ out.push({ kind: "text", text: source.slice(start, end) });
84
+ cursor = end;
85
+ break;
86
+ }
87
+ case "name": {
88
+ // {{x}} — escaped variable.
89
+ const raw = source.slice(start, end);
90
+ cursor = end;
91
+ out.push(makeVarToken("var", raw, value, stack));
92
+ break;
93
+ }
94
+ case "&":
95
+ case "{": {
96
+ // {{&x}} / {{{x}}} — unescaped variable (mustache.js emits "&" for both).
97
+ const raw = source.slice(start, end);
98
+ cursor = end;
99
+ out.push(makeVarToken("unescaped", raw, value, stack));
100
+ break;
101
+ }
102
+ case "#":
103
+ case "^": {
104
+ // {{#x}}…{{/x}} (section) / {{^x}}…{{/x}} (inverted). `end` is the end
105
+ // of the OPENING tag; subTokens at [4]; [5] is where the closing tag
106
+ // begins. Emit the open tag, recurse the body in the pushed context,
107
+ // then emit the close tag.
108
+ const sub = Array.isArray(tok[4]) ? tok[4] : [];
109
+ const closeStart = tok[5];
110
+ const openRaw = source.slice(start, end);
111
+ cursor = end;
112
+ const isImplicit = value === ".";
113
+ const r = isImplicit ? undefined : resolveAt(stack, value);
114
+ const kind = type === "#" ? "section" : "inverted";
115
+ out.push(r
116
+ ? {
117
+ kind,
118
+ raw: openRaw,
119
+ path: value,
120
+ field: r.field,
121
+ href: r.href,
122
+ }
123
+ : { kind, raw: openRaw, path: value });
124
+ // `#` over a container pushes its element fields; `^` (and `#` over a
125
+ // scalar conditional) keep the current context — EXACTLY verify's rule.
126
+ const hit = isImplicit
127
+ ? undefined
128
+ : resolveTemplateVariable(stack, value);
129
+ const nested = type === "#" ? hit?.fields : undefined;
130
+ const childStack = nested !== undefined ? [...stack, nested] : stack;
131
+ walk(sub, childStack);
132
+ // The closing tag `{{/value}}` runs from closeStart to the end of the
133
+ // section. Recover any body remainder Mustache trimmed, then emit close.
134
+ emitTextUpTo(closeStart);
135
+ // The close tag's exact end isn't in the token; derive it from the
136
+ // literal `{{/…}}` form starting at closeStart so the raw is verbatim.
137
+ const closeRaw = readCloseTag(source, closeStart, value);
138
+ out.push({ kind: "close", raw: closeRaw, path: value });
139
+ cursor = closeStart + closeRaw.length;
140
+ break;
141
+ }
142
+ case ">": {
143
+ // {{>ref}} — partial.
144
+ const raw = source.slice(start, end);
145
+ cursor = end;
146
+ const href = opts.resolvePartialHref?.(value);
147
+ out.push(href !== undefined
148
+ ? { kind: "partial", raw, ref: value, href }
149
+ : { kind: "partial", raw, ref: value });
150
+ break;
151
+ }
152
+ case "!": {
153
+ // {{! comment }}.
154
+ out.push({ kind: "comment", raw: source.slice(start, end) });
155
+ cursor = end;
156
+ break;
157
+ }
158
+ default: {
159
+ // set-delimiter (=) or any other: preserve verbatim as text.
160
+ if (Number.isFinite(end) && end > start) {
161
+ out.push({ kind: "text", text: source.slice(start, end) });
162
+ cursor = end;
163
+ }
164
+ break;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ walk(parseTemplate(source), [root]);
170
+ // Any trailing source after the last token (e.g. a standalone-trimmed final
171
+ // newline) is recovered as text.
172
+ emitTextUpTo(source.length);
173
+ return out;
174
+ }
175
+ // Read the verbatim closing tag `{{/name}}` (with any inner whitespace the
176
+ // author wrote) starting at `from`. Mustache only gives the close-tag start, so
177
+ // we locate the terminating `}}` from there to recover the exact source span.
178
+ function readCloseTag(source, from, _name) {
179
+ const close = source.indexOf("}}", from);
180
+ if (close === -1)
181
+ return source.slice(from);
182
+ return source.slice(from, close + 2);
183
+ }
184
+ //# sourceMappingURL=template-source-annotate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-source-annotate.js","sourceRoot":"","sources":["../../src/generators/template-source-annotate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { TplToken } from "./template-source-annotate.js";
2
+ /**
3
+ * Reconstruct the verbatim template source from the tokens and wrap it in a
4
+ * ```mustache fenced block. Concatenating `text` (text tokens) / `raw` (tag
5
+ * tokens) round-trips the original source byte-for-byte (the annotator pins
6
+ * this), so the fence body is the clean, highlightable source.
7
+ */
8
+ export declare function renderSourceBlock(tokens: TplToken[]): string;
9
+ /**
10
+ * A Markdown table of the unique referenced variables. Resolved variables link
11
+ * to their field doc (`[owner.name](href)`); unresolved ones are em-dashed and
12
+ * carry a "not on payload" note in the Type cell. Returns "" when there are no
13
+ * variables (keeps the page clean).
14
+ */
15
+ export declare function renderVariablesTable(tokens: TplToken[]): string;
16
+ /**
17
+ * The collapsed <details> "Linked view": a <pre> reproducing the template where
18
+ * each token is an inline-styled <span> (color by kind) and each resolved
19
+ * variable/section is additionally wrapped in a clickable <a href>. Whitespace
20
+ * and newlines are preserved inside the <pre>. Collapsed by default (no `open`)
21
+ * so the plain/agent view stays clean; a human expands it for the clickable vars.
22
+ */
23
+ export declare function renderRichLinkedHtml(tokens: TplToken[]): string;
24
+ //# sourceMappingURL=template-source-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-source-render.d.ts","sourceRoot":"","sources":["../../src/generators/template-source-render.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAI9D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAG5D;AAoDD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAsB/D;AAsCD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAyC/D"}
@@ -0,0 +1,175 @@
1
+ // Template-source renderers (linked-template-source-docs, Task 3).
2
+ //
3
+ // ONE annotated IR (the TplToken[] from annotateTemplate), THREE doc forms — no
4
+ // re-derivation, no second parse. All three are pure functions over the tokens:
5
+ //
6
+ // • renderSourceBlock — the verbatim template inside a ```mustache fence.
7
+ // The annotator round-trips the source via text/raw,
8
+ // so the fenced body equals the original byte-for-byte
9
+ // and any viewer/site highlighter colors it.
10
+ // • renderVariablesTable — a Markdown table of the UNIQUE referenced variables
11
+ // (vars + sections that resolve to a field), each a
12
+ // Markdown-native `[owner.name](href)` link (or flagged
13
+ // "not on payload" when unresolved). Agent-clean.
14
+ // • renderRichLinkedHtml — a collapsed <details> whose <pre> reproduces the
15
+ // template with each token in a SELF-CONTAINED
16
+ // inline-styled <span> (color per kind) and each
17
+ // resolved variable/section wrapped in a clickable
18
+ // <a href>. Inline styles only (no external CSS) so it
19
+ // renders identically on GitHub and a static site.
20
+ //
21
+ // Color (block + rich view), links (table + rich view), agent-cleanliness (block
22
+ // + table) — all from the same source of truth.
23
+ // ── 1. Source block ────────────────────────────────────────────────────────
24
+ /**
25
+ * Reconstruct the verbatim template source from the tokens and wrap it in a
26
+ * ```mustache fenced block. Concatenating `text` (text tokens) / `raw` (tag
27
+ * tokens) round-trips the original source byte-for-byte (the annotator pins
28
+ * this), so the fence body is the clean, highlightable source.
29
+ */
30
+ export function renderSourceBlock(tokens) {
31
+ const source = reconstructSource(tokens);
32
+ return "```mustache\n" + source + "\n```";
33
+ }
34
+ /** Concatenate the verbatim span of every token (text or tag raw). */
35
+ function reconstructSource(tokens) {
36
+ let out = "";
37
+ for (const t of tokens)
38
+ out += t.kind === "text" ? t.text : t.raw;
39
+ return out;
40
+ }
41
+ /** Collect the unique referenced variables (vars/unescaped + sections/inverted
42
+ * that carry a path), deduped by path, in first-seen order. Implicit-iterator
43
+ * `.` tokens and close tokens are not "variables" and are skipped. */
44
+ function collectVarRows(tokens) {
45
+ const seen = new Set();
46
+ const rows = [];
47
+ for (const t of tokens) {
48
+ const isRef = t.kind === "var" ||
49
+ t.kind === "unescaped" ||
50
+ t.kind === "section" ||
51
+ t.kind === "inverted";
52
+ if (!isRef)
53
+ continue;
54
+ if (t.path === "." || seen.has(t.path))
55
+ continue;
56
+ seen.add(t.path);
57
+ rows.push({
58
+ path: t.path,
59
+ owner: t.field?.owner,
60
+ name: t.field?.name,
61
+ type: t.field?.type,
62
+ required: t.field?.required,
63
+ href: t.href,
64
+ });
65
+ }
66
+ return rows;
67
+ }
68
+ /** Markdown-escape a table cell whose text may contain a `|`. */
69
+ function mdCell(text) {
70
+ return text.replace(/\|/g, "\\|");
71
+ }
72
+ /**
73
+ * A Markdown table of the unique referenced variables. Resolved variables link
74
+ * to their field doc (`[owner.name](href)`); unresolved ones are em-dashed and
75
+ * carry a "not on payload" note in the Type cell. Returns "" when there are no
76
+ * variables (keeps the page clean).
77
+ */
78
+ export function renderVariablesTable(tokens) {
79
+ const rows = collectVarRows(tokens);
80
+ if (rows.length === 0)
81
+ return "";
82
+ const lines = [
83
+ "| Variable | Field | Type | Required |",
84
+ "| --- | --- | --- | --- |",
85
+ ];
86
+ for (const r of rows) {
87
+ const variable = `\`{{${mdCell(r.path)}}}\``;
88
+ if (r.href && r.owner && r.name) {
89
+ const field = `[${r.owner}.${r.name}](${r.href})`;
90
+ const type = r.type ? mdCell(r.type) : "—";
91
+ const required = r.required ? "yes" : "no";
92
+ lines.push(`| ${variable} | ${field} | ${type} | ${required} |`);
93
+ }
94
+ else {
95
+ // Unresolved: no field/type/required. Keep the 4-column shape; flag it
96
+ // "not on payload" in the Field cell, em-dash the rest.
97
+ lines.push(`| ${variable} | — (not on payload) | — | — |`);
98
+ }
99
+ }
100
+ return lines.join("\n");
101
+ }
102
+ // ── 3. Rich linked HTML ────────────────────────────────────────────────────
103
+ // Per-kind inline color (self-contained — no external CSS, no classes). Chosen
104
+ // for legibility on both GitHub's light/dark Markdown and a generic docs site.
105
+ const STYLE_VAR = "color:#0969da"; // blue — escaped/unescaped variable
106
+ const STYLE_SECTION = "color:#8250df"; // purple — section / inverted / close
107
+ const STYLE_PARTIAL = "color:#1a7f7a"; // teal — partial reference
108
+ const STYLE_COMMENT = "color:#6e7781;font-style:italic"; // gray italic — comment
109
+ /** HTML-escape literal text so `<`, `>`, `&`, `"` in the template don't break
110
+ * the surrounding HTML. Quotes are escaped too so token raw is safe in any
111
+ * attribute-adjacent position. */
112
+ function escapeHtml(s) {
113
+ return s
114
+ .replace(/&/g, "&amp;")
115
+ .replace(/</g, "&lt;")
116
+ .replace(/>/g, "&gt;")
117
+ .replace(/"/g, "&quot;");
118
+ }
119
+ /** An inline-styled span for a token kind, escaping the inner verbatim text. */
120
+ function styledSpan(style, inner) {
121
+ return `<span style="${style}">${inner}</span>`;
122
+ }
123
+ /** A styled span for a token kind, wrapped in a clickable `<a href>` when the
124
+ * token resolved to a link (else the bare span). The raw text is HTML-escaped. */
125
+ function linkSpan(style, raw, href) {
126
+ const span = styledSpan(style, escapeHtml(raw));
127
+ return href ? `<a href="${escapeHtml(href)}">${span}</a>` : span;
128
+ }
129
+ /**
130
+ * The collapsed <details> "Linked view": a <pre> reproducing the template where
131
+ * each token is an inline-styled <span> (color by kind) and each resolved
132
+ * variable/section is additionally wrapped in a clickable <a href>. Whitespace
133
+ * and newlines are preserved inside the <pre>. Collapsed by default (no `open`)
134
+ * so the plain/agent view stays clean; a human expands it for the clickable vars.
135
+ */
136
+ export function renderRichLinkedHtml(tokens) {
137
+ let pre = "";
138
+ for (const t of tokens) {
139
+ switch (t.kind) {
140
+ case "text": {
141
+ // Default color; escape literal text verbatim (preserves newlines).
142
+ pre += escapeHtml(t.text);
143
+ break;
144
+ }
145
+ case "var":
146
+ case "unescaped": {
147
+ pre += linkSpan(STYLE_VAR, t.raw, t.href);
148
+ break;
149
+ }
150
+ case "section":
151
+ case "inverted":
152
+ case "close": {
153
+ // Only open tags (section/inverted) carry an href; close tags don't.
154
+ const href = "href" in t ? t.href : undefined;
155
+ pre += linkSpan(STYLE_SECTION, t.raw, href);
156
+ break;
157
+ }
158
+ case "partial": {
159
+ pre += linkSpan(STYLE_PARTIAL, t.raw, t.href);
160
+ break;
161
+ }
162
+ case "comment": {
163
+ pre += styledSpan(STYLE_COMMENT, escapeHtml(t.raw));
164
+ break;
165
+ }
166
+ }
167
+ }
168
+ return ("<details>\n" +
169
+ "<summary>Linked view</summary>\n\n" +
170
+ '<pre style="white-space:pre-wrap;word-break:break-word">' +
171
+ pre +
172
+ "</pre>\n\n" +
173
+ "</details>");
174
+ }
175
+ //# sourceMappingURL=template-source-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-source-render.js","sourceRoot":"","sources":["../../src/generators/template-source-render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type GeneratorFactory } from "../generator.js";
2
+ export interface TraceHelperOpts {
3
+ /** Output directory prefix relative to the target's outDir. Default: "" (root). */
4
+ outDir?: string;
5
+ /** Optional named output target (registry key). Defaults to "default". */
6
+ target?: string;
7
+ }
8
+ export declare const traceHelperFile: GeneratorFactory<TraceHelperOpts>;
9
+ //# sourceMappingURL=trace-helper-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-helper-file.d.ts","sourceRoot":"","sources":["../../src/generators/trace-helper-file.ts"],"names":[],"mappings":"AA6BA,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAQzB,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAiBD,eAAO,MAAM,eAAe,EA4OvB,gBAAgB,CAAC,eAAe,CAAC,CAAC"}
@@ -0,0 +1,196 @@
1
+ // server/typescript/packages/codegen-ts/src/generators/trace-helper-file.ts
2
+ //
3
+ // Stock generator that emits one <Entity>.trace.ts helper file for each concrete
4
+ // entity that (a) extends LlmCallBase (directly or transitively) and (b) nests a
5
+ // template.prompt with @payloadRef and/or @responseRef.
6
+ //
7
+ // The emitted helper exports an async function `record<Entity>(om, responseMo, input)`
8
+ // that EXTRACTS the typed response VO itself and persists ONE row = base envelope +
9
+ // raw I/O (via buildLlmCallRow) PLUS the typed voRequest/voResponse columns. The
10
+ // helper is typed against the generated payload interfaces (request + response VOs)
11
+ // so call-sites get compile-time checks.
12
+ //
13
+ // NOTE: ObjectManager does not expose its loaded metadata root, so the caller must
14
+ // pass the resolved `responseMo: MetaObject` explicitly. The generated helper
15
+ // documents this in its JSDoc.
16
+ //
17
+ // Consumer wiring (metaobjects.config.ts):
18
+ // generators: [..., entityFile(), queriesFile(), traceHelperFile(), barrel()]
19
+ import { TYPE_OBJECT, TYPE_TEMPLATE, TEMPLATE_SUBTYPE_PROMPT, TEMPLATE_ATTR_PAYLOAD_REF, TEMPLATE_ATTR_RESPONSE_REF, TEMPLATE_ATTR_FORMAT, TEMPLATE_ATTR_TEXT_REF, } from "@metaobjectsdev/metadata";
20
+ import { perEntity, } from "../generator.js";
21
+ import { generatePayloadInterfacesBatch } from "../payload-codegen.js";
22
+ import { GENERATED_HEADER } from "../constants.js";
23
+ import { tphDiscriminatorPin } from "../templates/zod-validators.js";
24
+ /** Short name of the shipped abstract base every trace entity extends. */
25
+ const LLM_CALL_BASE = "LlmCallBase";
26
+ /** Walk the super chain looking for a node named LLM_CALL_BASE. */
27
+ function extendsBase(obj) {
28
+ let cur = obj.superResolved;
29
+ while (cur !== undefined) {
30
+ if (cur.name === LLM_CALL_BASE)
31
+ return true;
32
+ cur = cur.superResolved;
33
+ }
34
+ return false;
35
+ }
36
+ /** Capitalise the first character. */
37
+ function pascal(s) {
38
+ return s.length > 0 ? s[0].toUpperCase() + s.slice(1) : s;
39
+ }
40
+ export const traceHelperFile = function traceHelperFile(opts) {
41
+ const dirPrefix = opts?.outDir ? `${opts.outDir.replace(/\/$/, "")}/` : "";
42
+ const generator = {
43
+ name: "trace-helper",
44
+ generate: perEntity((entity, ctx) => {
45
+ // Only concrete entities derived from LlmCallBase.
46
+ if (entity.isAbstract)
47
+ return [];
48
+ if (!extendsBase(entity))
49
+ return [];
50
+ // Find the nested template.prompt.
51
+ const prompt = entity.ownChildren().find((c) => c.type === TYPE_TEMPLATE && c.subType === TEMPLATE_SUBTYPE_PROMPT);
52
+ if (prompt === undefined)
53
+ return [];
54
+ const payloadRef = prompt.ownAttr(TEMPLATE_ATTR_PAYLOAD_REF);
55
+ const responseRef = prompt.ownAttr(TEMPLATE_ATTR_RESPONSE_REF);
56
+ // @responseRef types the result; @payloadRef types the request. Both gate
57
+ // the helper: the entity must declare voRequest/voResponse field.object
58
+ // columns (authored) for these writes to land, and the prompt's refs name
59
+ // the VOs to render/extract into.
60
+ if (typeof responseRef !== "string")
61
+ return [];
62
+ if (typeof payloadRef !== "string")
63
+ return [];
64
+ const entityName = entity.name;
65
+ const fnName = `record${pascal(entityName)}`;
66
+ // STI: a trace entity that is a TPH subtype stamps its declared
67
+ // discriminator value as callType and drops callType from the caller input
68
+ // (industry-standard STI — the discriminator is framework-managed).
69
+ const tphPin = tphDiscriminatorPin(entity);
70
+ const sti = tphPin !== undefined;
71
+ const callTypeValue = sti ? tphPin.value : entityName;
72
+ // Emitted record<Entity> fragments. The caller never supplies the derived
73
+ // status/errorDetail (the helper computes them from extraction), and an STI
74
+ // subtype additionally drops the framework-managed callType discriminator.
75
+ const recordInputOmit = sti
76
+ ? `"llmRequest" | "status" | "errorDetail" | "callType"`
77
+ : `"llmRequest" | "status" | "errorDetail"`;
78
+ // The object spread passed to buildLlmCallRow: STI subtypes stamp their
79
+ // discriminator value, all helpers fold in the derived status/errorDetail.
80
+ const recordBuildArg = sti
81
+ ? `{ ...input, callType: ${JSON.stringify(callTypeValue)}, status, errorDetail }`
82
+ : `{ ...input, status, errorDetail }`;
83
+ // Derive the parse format from the prompt's @format attr.
84
+ // "xml" → Format.XML; absent or any other value → Format.JSON.
85
+ const promptFormat = prompt.ownAttr(TEMPLATE_ATTR_FORMAT);
86
+ const formatLiteral = typeof promptFormat === "string" && promptFormat.toLowerCase() === "xml"
87
+ ? "Format.XML"
88
+ : "Format.JSON";
89
+ // Collect VO names for interface emission (dedupe via batch emitter).
90
+ // Both refs are guaranteed strings by the guards above.
91
+ const interfaces = generatePayloadInterfacesBatch(ctx.loadedRoot, [payloadRef, responseRef]);
92
+ const requestType = payloadRef;
93
+ // A renderable prompt (carries @textRef) gets an additional call<Entity> helper
94
+ // that renders the prompt text, calls the LLM, then parses + persists a trace row.
95
+ const textRef = prompt.ownAttr(TEMPLATE_ATTR_TEXT_REF);
96
+ const renderable = typeof textRef === "string";
97
+ // Same @format attr, two intentionally different shapes: extract() takes the
98
+ // Format enum (formatLiteral, above → Format.XML/Format.JSON), render() takes the
99
+ // raw format string (renderFormat, here → e.g. "json"/"xml", default "text").
100
+ const renderFormat = typeof promptFormat === "string" ? promptFormat : "text";
101
+ // Build the import block — all imports MUST stay at the top of the emitted file.
102
+ // `extract` + `render` both live in @metaobjectsdev/render: import them together
103
+ // (one de-duplicated statement) when the prompt is renderable, else import only
104
+ // `extract`.
105
+ const importLines = [
106
+ `import type { ObjectManager } from "@metaobjectsdev/runtime-ts";`,
107
+ `import {`,
108
+ ` LlmCallDbRecorder,`,
109
+ ` buildLlmCallRow,`,
110
+ ` persistLlmCallRow,`,
111
+ ` extractSchemaFor,`,
112
+ ` Format,`,
113
+ ` type LlmCallInput,`,
114
+ ` type LlmCallRow,`,
115
+ `} from "@metaobjectsdev/runtime-ts";`,
116
+ renderable
117
+ ? `import { extract, render, type Provider } from "@metaobjectsdev/render";`
118
+ : `import { extract } from "@metaobjectsdev/render";`,
119
+ `import type { MetaObject } from "@metaobjectsdev/metadata";`,
120
+ ];
121
+ if (renderable) {
122
+ importLines.push(`import {`, ` runLlmCall,`, ` type RunLlmCallInput,`, ` type RunLlmCallDeps,`, ` type LlmClient,`, ` type LlmRequest,`, ` type CostFn,`, ` type Clock,`, ` type IdGen,`, `} from "@metaobjectsdev/ai-runtime";`);
123
+ }
124
+ const lines = [
125
+ `// ${GENERATED_HEADER} — DO NOT EDIT.`,
126
+ ``,
127
+ ...importLines,
128
+ ``,
129
+ `// ---- Payload interfaces (inlined) ------------------------------------------`,
130
+ ``,
131
+ interfaces.trimEnd(),
132
+ ``,
133
+ `// ---- Typed result -----------------------------------------------------------`,
134
+ ``,
135
+ `export interface ${entityName}TraceResult {`,
136
+ ` status: "ok" | "error";`,
137
+ ` errorDetail: string | null;`,
138
+ ` /** Parsed response VO, or null when extraction reported a lost-required field. */`,
139
+ ` /** Note: voResponse is the plain extracted record typed as the response shape (structural, not an instance). */`,
140
+ ` voResponse: ${responseRef} | null;`,
141
+ `}`,
142
+ ``,
143
+ `// ---- Record helper ----------------------------------------------------------`,
144
+ ``,
145
+ `/**`,
146
+ ` * Record a single ${entityName} LLM call: extract the response VO and persist a`,
147
+ ` * trace row via ObjectManager regardless of whether extraction succeeded.`,
148
+ ` *`,
149
+ ` * @param om - ObjectManager wired to the application database.`,
150
+ ` * @param responseMo - MetaObject for \`${responseRef}\` (resolve via the loaded`,
151
+ ` * metadata root: \`root.findObject("${responseRef}")\`).`,
152
+ ` * Passed explicitly because ObjectManager does not expose`,
153
+ ` * its loaded metadata root.`,
154
+ ` * @param input - LLM call inputs; type \`llmRequest\` as \`${requestType}\`.`,
155
+ ` * @param opts - Optional \`redact\` hook applied to the row before persist`,
156
+ ` * (scrub PII/secrets on the typed path, same as the generic`,
157
+ ` * recordLlmCall/callLlm helpers).`,
158
+ ` */`,
159
+ `export async function ${fnName}(`,
160
+ ` om: ObjectManager,`,
161
+ ` responseMo: MetaObject,`,
162
+ ` input: Omit<LlmCallInput, ${recordInputOmit}> & { llmRequest: ${requestType} },`,
163
+ ` opts?: { redact?: (row: LlmCallRow) => LlmCallRow },`,
164
+ `): Promise<${entityName}TraceResult> {`,
165
+ ` const schema = extractSchemaFor(responseMo, ${formatLiteral});`,
166
+ ` const outcome = extract(input.llmResponseText, schema);`,
167
+ ` const failed = outcome.report.hasLostRequired();`,
168
+ ` const status = failed ? ("error" as const) : ("ok" as const);`,
169
+ ' const errorDetail = failed ? `lost required: ${outcome.report.lostRequired().join(", ")}` : null;',
170
+ ` const base = buildLlmCallRow(${recordBuildArg});`,
171
+ ` const row = { ...base, voRequest: input.llmRequest, voResponse: failed ? null : outcome.data };`,
172
+ ` await persistLlmCallRow(new LlmCallDbRecorder(om, "${entityName}"), row, opts?.redact ? { redact: opts.redact } : undefined);`,
173
+ ` return { status, errorDetail, voResponse: failed ? null : (outcome.data as ${responseRef}) };`,
174
+ `}`,
175
+ ``,
176
+ ];
177
+ if (renderable) {
178
+ const callFn = `call${pascal(entityName)}`;
179
+ lines.push(``, `// ---- Call helper (GENERATE -> CALL -> record) -------------------------------`, ``, `export interface ${entityName}CallDeps {`, ` om: ObjectManager;`, ` responseMo: MetaObject;`, ` client: LlmClient;`, ` /** Prompt-TEXT resolver for render() (NOT the LLM client). */`, ` provider: Provider;`, ` model: string;`, ` system?: string;`, ` params?: Record<string, unknown>;`, ` cost?: CostFn;`, ` clock?: Clock;`, ` ids?: IdGen;`, ` traceId?: string;`, ` parentSpanId?: string;`, ` sessionId?: string;`, ` /** Optional row-redaction hook applied before persist (scrub PII/secrets). */`, ` redact?: (row: LlmCallRow) => LlmCallRow;`, `}`, ``, `/**`, ` * Render the ${entityName} prompt, call the LLM, then parse + persist a trace`, ` * row (finally-style: a call/parse failure still writes a row).`, ` */`, `export async function ${callFn}(`, ` payload: ${requestType},`, ` deps: ${entityName}CallDeps,`, `): Promise<${entityName}TraceResult> {`, ` const prompt = render({ ref: ${JSON.stringify(textRef)}, payload, format: ${JSON.stringify(renderFormat)}, provider: deps.provider });`,
180
+ // Build request/input/deps conditionally so that an absent optional (T |
181
+ // undefined) is never assigned to an optional T? property — required for
182
+ // exactOptionalPropertyTypes-strict consumer projects.
183
+ ` const request: LlmRequest = { prompt, model: deps.model };`, ` if (deps.system !== undefined) request.system = deps.system;`, ` if (deps.params !== undefined) request.params = deps.params;`, ` const runInput: RunLlmCallInput = { callType: ${JSON.stringify(callTypeValue)}, request };`, ` if (deps.traceId !== undefined) runInput.traceId = deps.traceId;`, ` if (deps.parentSpanId !== undefined) runInput.parentSpanId = deps.parentSpanId;`, ` if (deps.sessionId !== undefined) runInput.sessionId = deps.sessionId;`, ` const runDeps: RunLlmCallDeps = { client: deps.client };`, ` if (deps.cost !== undefined) runDeps.cost = deps.cost;`, ` if (deps.clock !== undefined) runDeps.clock = deps.clock;`, ` if (deps.ids !== undefined) runDeps.ids = deps.ids;`, ` const { input: recInput, completion } = await runLlmCall(runInput, runDeps);`, ` let voResponse: ${responseRef} | null = null;`, ` let status = recInput.status;`, ` let errorDetail = recInput.errorDetail;`, ` if (completion !== undefined) {`, ` const outcome = extract(completion.body, extractSchemaFor(deps.responseMo, ${formatLiteral}));`, ` if (outcome.report.hasLostRequired()) {`, ` status = "error";`, ' errorDetail = `lost required: ${outcome.report.lostRequired().join(", ")}`;', ` } else {`, ` voResponse = outcome.data as ${responseRef};`, ` }`, ` }`, ` const row = { ...buildLlmCallRow({ ...recInput, status, errorDetail }), voRequest: payload, voResponse };`, ` await persistLlmCallRow(new LlmCallDbRecorder(deps.om, ${JSON.stringify(entityName)}), row, deps.redact ? { redact: deps.redact } : undefined);`, ` return { status, errorDetail, voResponse };`, `}`);
184
+ }
185
+ return [{
186
+ path: `${dirPrefix}${entityName}.trace.ts`,
187
+ content: lines.join("\n"),
188
+ }];
189
+ }),
190
+ };
191
+ if (opts?.target) {
192
+ generator.target = opts.target;
193
+ }
194
+ return generator;
195
+ };
196
+ //# sourceMappingURL=trace-helper-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-helper-file.js","sourceRoot":"","sources":["../../src/generators/trace-helper-file.ts"],"names":[],"mappings":"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"}