@metaobjectsdev/codegen-ts 0.7.0 → 0.8.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 (67) hide show
  1. package/dist/generators/entity-file.d.ts.map +1 -1
  2. package/dist/generators/entity-file.js +7 -0
  3. package/dist/generators/entity-file.js.map +1 -1
  4. package/dist/generators/index.d.ts +1 -0
  5. package/dist/generators/index.d.ts.map +1 -1
  6. package/dist/generators/index.js +1 -0
  7. package/dist/generators/index.js.map +1 -1
  8. package/dist/generators/output-prompt-file.d.ts +9 -0
  9. package/dist/generators/output-prompt-file.d.ts.map +1 -0
  10. package/dist/generators/output-prompt-file.js +51 -0
  11. package/dist/generators/output-prompt-file.js.map +1 -0
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/instance-artifacts.d.ts +29 -0
  17. package/dist/instance-artifacts.d.ts.map +1 -0
  18. package/dist/instance-artifacts.js +57 -0
  19. package/dist/instance-artifacts.js.map +1 -0
  20. package/dist/metaobjects-config.d.ts +10 -0
  21. package/dist/metaobjects-config.d.ts.map +1 -1
  22. package/dist/metaobjects-config.js +1 -0
  23. package/dist/metaobjects-config.js.map +1 -1
  24. package/dist/render-context.d.ts +4 -1
  25. package/dist/render-context.d.ts.map +1 -1
  26. package/dist/render-context.js +1 -0
  27. package/dist/render-context.js.map +1 -1
  28. package/dist/runner.d.ts.map +1 -1
  29. package/dist/runner.js +1 -0
  30. package/dist/runner.js.map +1 -1
  31. package/dist/templates/entity-file.d.ts.map +1 -1
  32. package/dist/templates/entity-file.js +12 -0
  33. package/dist/templates/entity-file.js.map +1 -1
  34. package/dist/templates/fr010-field-mapping.d.ts +28 -0
  35. package/dist/templates/fr010-field-mapping.d.ts.map +1 -0
  36. package/dist/templates/fr010-field-mapping.js +170 -0
  37. package/dist/templates/fr010-field-mapping.js.map +1 -0
  38. package/dist/templates/output-format-spec-emitter.d.ts +4 -0
  39. package/dist/templates/output-format-spec-emitter.d.ts.map +1 -0
  40. package/dist/templates/output-format-spec-emitter.js +60 -0
  41. package/dist/templates/output-format-spec-emitter.js.map +1 -0
  42. package/dist/templates/output-parser.d.ts.map +1 -1
  43. package/dist/templates/output-parser.js +69 -4
  44. package/dist/templates/output-parser.js.map +1 -1
  45. package/dist/templates/output-prompt.d.ts +10 -0
  46. package/dist/templates/output-prompt.d.ts.map +1 -0
  47. package/dist/templates/output-prompt.js +75 -0
  48. package/dist/templates/output-prompt.js.map +1 -0
  49. package/dist/templates/recover-schema-emitter.d.ts +8 -0
  50. package/dist/templates/recover-schema-emitter.d.ts.map +1 -0
  51. package/dist/templates/recover-schema-emitter.js +64 -0
  52. package/dist/templates/recover-schema-emitter.js.map +1 -0
  53. package/package.json +4 -4
  54. package/src/generators/entity-file.ts +7 -0
  55. package/src/generators/index.ts +1 -0
  56. package/src/generators/output-prompt-file.ts +66 -0
  57. package/src/index.ts +1 -0
  58. package/src/instance-artifacts.ts +61 -0
  59. package/src/metaobjects-config.ts +11 -0
  60. package/src/render-context.ts +5 -1
  61. package/src/runner.ts +1 -0
  62. package/src/templates/entity-file.ts +13 -0
  63. package/src/templates/fr010-field-mapping.ts +191 -0
  64. package/src/templates/output-format-spec-emitter.ts +97 -0
  65. package/src/templates/output-parser.ts +77 -2
  66. package/src/templates/output-prompt.ts +88 -0
  67. package/src/templates/recover-schema-emitter.ts +91 -0
@@ -0,0 +1,88 @@
1
+ // server/typescript/packages/codegen-ts/src/templates/output-prompt.ts
2
+ //
3
+ // Per-template renderer for the FR-010 artifact-1 output-format prompt fragment
4
+ // ("produce your answer like this"). For each json/xml `template.output` whose
5
+ // @payloadRef resolves to a value-object, emits a `<TemplateName>.prompt.ts` file
6
+ // exporting `render<TemplateName>Format(overrides?)` backed by the render engine's
7
+ // renderOutputFormat(). The baked OutputFormatSpec's rootName is the payload name,
8
+ // so the prompt fragment and the recover() codegen agree on the root name.
9
+ //
10
+ // Mirrors the C# OutputPromptGenerator + OutputFormatSpecEmitter (split into a
11
+ // generator factory + this pure renderer, matching the TS output-parser shape).
12
+
13
+ import {
14
+ type MetaData,
15
+ TYPE_OBJECT,
16
+ TYPE_TEMPLATE,
17
+ TEMPLATE_SUBTYPE_OUTPUT,
18
+ TEMPLATE_ATTR_PAYLOAD_REF,
19
+ TEMPLATE_ATTR_FORMAT,
20
+ } from "@metaobjectsdev/metadata";
21
+ import { specLiteral } from "./output-format-spec-emitter.js";
22
+
23
+ function findObject(root: MetaData, name: string): MetaData | undefined {
24
+ return root.ownChildren().find((c) => c.type === TYPE_OBJECT && c.name === name);
25
+ }
26
+
27
+ function findTemplate(root: MetaData, name: string): MetaData | undefined {
28
+ return root.ownChildren().find((c) => c.type === TYPE_TEMPLATE && c.name === name);
29
+ }
30
+
31
+ /** True iff the template.output's @format is json or xml (the renderable structured formats). */
32
+ export function templateSupportsPrompt(tmpl: MetaData): boolean {
33
+ const f = ((tmpl.ownAttr(TEMPLATE_ATTR_FORMAT) as string | undefined) ?? "text").toLowerCase();
34
+ return f === "json" || f === "xml";
35
+ }
36
+
37
+ /**
38
+ * Render the full output-prompt file for one json/xml `template.output` node.
39
+ * Throws if the template isn't found, isn't a template.output, isn't json/xml,
40
+ * or its @payloadRef doesn't resolve to an object.value.
41
+ */
42
+ export function renderOutputPrompt(root: MetaData, templateName: string): string {
43
+ const tmpl = findTemplate(root, templateName);
44
+ if (!tmpl) {
45
+ throw new Error(`template "${templateName}" not found in metadata root`);
46
+ }
47
+ if (tmpl.subType !== TEMPLATE_SUBTYPE_OUTPUT) {
48
+ throw new Error(`template "${templateName}" is not a template.output (got subtype "${tmpl.subType}")`);
49
+ }
50
+ if (!templateSupportsPrompt(tmpl)) {
51
+ throw new Error(`template "${templateName}" @format is not json/xml — no prompt fragment`);
52
+ }
53
+ const payloadRef = tmpl.ownAttr(TEMPLATE_ATTR_PAYLOAD_REF);
54
+ if (typeof payloadRef !== "string") {
55
+ throw new Error(`template "${templateName}" missing @payloadRef`);
56
+ }
57
+ const vo = findObject(root, payloadRef);
58
+ if (!vo) {
59
+ throw new Error(`template "${templateName}" @payloadRef "${payloadRef}" not found in metadata root`);
60
+ }
61
+
62
+ // rootName == payload name so the prompt fragment and recover() agree.
63
+ const spec = specLiteral(vo, tmpl, payloadRef);
64
+ const specName = `${templateName}FormatSpec`;
65
+ const fnName = `render${templateName}Format`;
66
+
67
+ return `import {
68
+ renderOutputFormat,
69
+ Format,
70
+ FieldKind,
71
+ PromptStyle,
72
+ type OutputFormatSpec,
73
+ type PromptOverrides,
74
+ } from "@metaobjectsdev/render";
75
+
76
+ const ${specName}: OutputFormatSpec = ${spec};
77
+
78
+ /**
79
+ * The output-format instruction fragment for the ${templateName} template.output
80
+ * ("produce your answer like this"). Comment-free — guidance lives in prose /
81
+ * inline placeholders / a filled skeleton. Pass \`overrides\` to override the style
82
+ * or per-field example/instruction at render time.
83
+ */
84
+ export function ${fnName}(overrides?: PromptOverrides): string {
85
+ return renderOutputFormat(${specName}, overrides ?? {});
86
+ }
87
+ `;
88
+ }
@@ -0,0 +1,91 @@
1
+ // server/typescript/packages/codegen-ts/src/templates/recover-schema-emitter.ts
2
+ //
3
+ // Turns a payload value-object into TS source fragments for the FR-010 recover codegen:
4
+ // • schemaLiteral — a `recoverSchema(Format.JSON, "root", [ … ])` baked descriptor
5
+ // built from FieldSpec factories (scalar / enumField).
6
+ // • mirrorInterface — an all-nullable mirror interface `<Payload>Recovered` (each
7
+ // component `T | null`); recover returns this nullable twin rather
8
+ // than the strict payload (same reasoning as the Java/C#/Kotlin ports).
9
+ // • mirrorInitializer — `{ prop: asString(d, "prop"), … }` building the mirror from the
10
+ // forgiving outcome map `d`.
11
+ //
12
+ // Mirrors the C# RecoverSchemaEmitter (adapted to TS syntax + the `| null` nullable mirror).
13
+ // Bounded scope: scalar / enum / scalar-array. Nested object + array-of-enum deferred.
14
+
15
+ import {
16
+ type MetaData,
17
+ FIELD_SUBTYPE_ENUM,
18
+ FIELD_SUBTYPE_OBJECT,
19
+ FIELD_ATTR_ENUM_ALIAS,
20
+ } from "@metaobjectsdev/metadata";
21
+ import {
22
+ fields,
23
+ isRequired,
24
+ isArray,
25
+ scalarKind,
26
+ mirrorType,
27
+ recoverMapCall,
28
+ enumValues,
29
+ jsonStringLiteral,
30
+ stringArrayLiteral,
31
+ propertiesMapLiteral,
32
+ } from "./fr010-field-mapping.js";
33
+
34
+ /** Emit `recoverSchema(Format.X, "rootName", [ … ])`. */
35
+ export function schemaLiteral(vo: MetaData, format: string, rootName: string): string {
36
+ const formatEnum = format.toLowerCase() === "xml" ? "Format.XML" : "Format.JSON";
37
+ const specs = fields(vo).map(fieldSpecLiteral);
38
+ return `recoverSchema(${formatEnum}, ${jsonStringLiteral(rootName)}, [${specs.join(", ")}])`;
39
+ }
40
+
41
+ function fieldSpecLiteral(field: MetaData): string {
42
+ const name = jsonStringLiteral(field.name);
43
+ const required = isRequired(field);
44
+
45
+ if (field.subType === FIELD_SUBTYPE_ENUM) {
46
+ const valuesLit = stringArrayLiteral(enumValues(field));
47
+ const aliasLit = propertiesMapLiteral(field.ownAttr(FIELD_ATTR_ENUM_ALIAS));
48
+ // enumField() sets array:false; enum-array is a bounded deferral (parity with Java/C#).
49
+ return `enumField(${name}, ${required}, ${valuesLit}, ${aliasLit})`;
50
+ }
51
+
52
+ if (field.subType === FIELD_SUBTYPE_OBJECT) {
53
+ // FR-010: nested recover deferred — treat as an opaque required/optional string slot.
54
+ return `scalar(${name}, FieldKind.STRING, ${required}) /* FR-010: nested recover deferred */`;
55
+ }
56
+
57
+ const kind = scalarKind(field.subType) ?? "STRING";
58
+ // Scalar-array: the scalar() factory only builds singular specs (array:false), so emit a
59
+ // FieldSpec object literal with array:true. Tier-2 win over the Roslyn proof: the emitted
60
+ // recover() actually populates the array at runtime (RecoverMap.asStringList).
61
+ if (isArray(field)) {
62
+ return (
63
+ `{ name: ${name}, kind: FieldKind.${kind}, required: ${required}, array: true, ` +
64
+ `enumValues: null, enumAlias: null, min: null, max: null, nested: null }`
65
+ );
66
+ }
67
+ return `scalar(${name}, FieldKind.${kind}, ${required})`;
68
+ }
69
+
70
+ /** Emit the all-nullable mirror interface declaration. */
71
+ export function mirrorInterface(vo: MetaData, interfaceName: string): string {
72
+ const base = interfaceName.endsWith("Recovered")
73
+ ? interfaceName.slice(0, -"Recovered".length)
74
+ : interfaceName;
75
+ const lines: string[] = [];
76
+ lines.push(
77
+ `/** Best-effort recovered twin of \`${base}\` — every field nullable (null where lost/malformed). */`,
78
+ );
79
+ lines.push(`export interface ${interfaceName} {`);
80
+ for (const f of fields(vo)) {
81
+ lines.push(` ${f.name}: ${mirrorType(f)};`);
82
+ }
83
+ lines.push("}");
84
+ return lines.join("\n");
85
+ }
86
+
87
+ /** Emit `{ prop: asString(d, "prop"), … }` building the mirror from the forgiving map `d`. */
88
+ export function mirrorInitializer(vo: MetaData): string {
89
+ const assigns = fields(vo).map((f) => `${f.name}: ${recoverMapCall(f)}`);
90
+ return `{ ${assigns.join(", ")} }`;
91
+ }