@metaobjectsdev/metadata 0.5.0 → 0.6.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 (168) hide show
  1. package/dist/attr-schema-validate.d.ts.map +1 -1
  2. package/dist/attr-schema-validate.js +66 -11
  3. package/dist/attr-schema-validate.js.map +1 -1
  4. package/dist/core/documentation/doc-constants.d.ts +11 -0
  5. package/dist/core/documentation/doc-constants.d.ts.map +1 -0
  6. package/dist/core/documentation/doc-constants.js +20 -0
  7. package/dist/core/documentation/doc-constants.js.map +1 -0
  8. package/dist/core/documentation/doc-provider.d.ts +3 -0
  9. package/dist/core/documentation/doc-provider.d.ts.map +1 -0
  10. package/dist/core/documentation/doc-provider.js +10 -0
  11. package/dist/core/documentation/doc-provider.js.map +1 -0
  12. package/dist/core/documentation/doc-schema.d.ts +8 -0
  13. package/dist/core/documentation/doc-schema.d.ts.map +1 -0
  14. package/dist/core/documentation/doc-schema.js +53 -0
  15. package/dist/core/documentation/doc-schema.js.map +1 -0
  16. package/dist/core/field/field-constants.d.ts +25 -1
  17. package/dist/core/field/field-constants.d.ts.map +1 -1
  18. package/dist/core/field/field-constants.js +32 -1
  19. package/dist/core/field/field-constants.js.map +1 -1
  20. package/dist/core/field/field-schema.d.ts +2 -0
  21. package/dist/core/field/field-schema.d.ts.map +1 -1
  22. package/dist/core/field/field-schema.js +20 -2
  23. package/dist/core/field/field-schema.js.map +1 -1
  24. package/dist/core/field/meta-field.d.ts +2 -1
  25. package/dist/core/field/meta-field.d.ts.map +1 -1
  26. package/dist/core/field/meta-field.js +6 -4
  27. package/dist/core/field/meta-field.js.map +1 -1
  28. package/dist/core/object/meta-object.d.ts.map +1 -1
  29. package/dist/core/object/meta-object.js +6 -5
  30. package/dist/core/object/meta-object.js.map +1 -1
  31. package/dist/core/parser-yaml.d.ts.map +1 -1
  32. package/dist/core/parser-yaml.js +9 -2
  33. package/dist/core/parser-yaml.js.map +1 -1
  34. package/dist/core/relationship/meta-relationship.d.ts +4 -0
  35. package/dist/core/relationship/meta-relationship.d.ts.map +1 -1
  36. package/dist/core/relationship/meta-relationship.js +11 -1
  37. package/dist/core/relationship/meta-relationship.js.map +1 -1
  38. package/dist/core/relationship/relationship-constants.d.ts +9 -0
  39. package/dist/core/relationship/relationship-constants.d.ts.map +1 -1
  40. package/dist/core/relationship/relationship-constants.js +15 -0
  41. package/dist/core/relationship/relationship-constants.js.map +1 -1
  42. package/dist/core/relationship/relationship-schema.d.ts.map +1 -1
  43. package/dist/core/relationship/relationship-schema.js +15 -1
  44. package/dist/core/relationship/relationship-schema.js.map +1 -1
  45. package/dist/core/yaml-desugar.d.ts +8 -1
  46. package/dist/core/yaml-desugar.d.ts.map +1 -1
  47. package/dist/core/yaml-desugar.js +166 -15
  48. package/dist/core/yaml-desugar.js.map +1 -1
  49. package/dist/core-types.d.ts.map +1 -1
  50. package/dist/core-types.js +28 -11
  51. package/dist/core-types.js.map +1 -1
  52. package/dist/errors.d.ts +1 -1
  53. package/dist/errors.d.ts.map +1 -1
  54. package/dist/errors.js +21 -0
  55. package/dist/errors.js.map +1 -1
  56. package/dist/index.d.ts +6 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +7 -1
  59. package/dist/index.js.map +1 -1
  60. package/dist/loader/meta-data-loader.d.ts.map +1 -1
  61. package/dist/loader/meta-data-loader.js +12 -1
  62. package/dist/loader/meta-data-loader.js.map +1 -1
  63. package/dist/loader/validation-passes.d.ts +2 -0
  64. package/dist/loader/validation-passes.d.ts.map +1 -1
  65. package/dist/loader/validation-passes.js +69 -3
  66. package/dist/loader/validation-passes.js.map +1 -1
  67. package/dist/naming.d.ts +3 -2
  68. package/dist/naming.d.ts.map +1 -1
  69. package/dist/naming.js +14 -12
  70. package/dist/naming.js.map +1 -1
  71. package/dist/parser-core.d.ts.map +1 -1
  72. package/dist/parser-core.js +91 -48
  73. package/dist/parser-core.js.map +1 -1
  74. package/dist/persistence/db/db-constants.d.ts +2 -2
  75. package/dist/persistence/db/db-constants.d.ts.map +1 -1
  76. package/dist/persistence/db/db-constants.js +2 -2
  77. package/dist/persistence/db/db-constants.js.map +1 -1
  78. package/dist/persistence/db/db-provider.d.ts.map +1 -1
  79. package/dist/persistence/db/db-provider.js +10 -13
  80. package/dist/persistence/db/db-provider.js.map +1 -1
  81. package/dist/persistence/db/db-schema.d.ts +2 -4
  82. package/dist/persistence/db/db-schema.d.ts.map +1 -1
  83. package/dist/persistence/db/db-schema.js +5 -13
  84. package/dist/persistence/db/db-schema.js.map +1 -1
  85. package/dist/persistence/origin/meta-origin.d.ts +10 -0
  86. package/dist/persistence/origin/meta-origin.d.ts.map +1 -1
  87. package/dist/persistence/origin/meta-origin.js +14 -1
  88. package/dist/persistence/origin/meta-origin.js.map +1 -1
  89. package/dist/persistence/origin/origin-constants.d.ts +3 -1
  90. package/dist/persistence/origin/origin-constants.d.ts.map +1 -1
  91. package/dist/persistence/origin/origin-constants.js +6 -0
  92. package/dist/persistence/origin/origin-constants.js.map +1 -1
  93. package/dist/persistence/origin/origin-schema.d.ts +1 -1
  94. package/dist/persistence/origin/origin-schema.d.ts.map +1 -1
  95. package/dist/persistence/origin/origin-schema.js +12 -2
  96. package/dist/persistence/origin/origin-schema.js.map +1 -1
  97. package/dist/persistence/source/meta-source.d.ts +11 -9
  98. package/dist/persistence/source/meta-source.d.ts.map +1 -1
  99. package/dist/persistence/source/meta-source.js +23 -15
  100. package/dist/persistence/source/meta-source.js.map +1 -1
  101. package/dist/persistence/source/source-constants.d.ts +32 -11
  102. package/dist/persistence/source/source-constants.d.ts.map +1 -1
  103. package/dist/persistence/source/source-constants.js +55 -16
  104. package/dist/persistence/source/source-constants.js.map +1 -1
  105. package/dist/persistence/source/source-schema.d.ts +4 -0
  106. package/dist/persistence/source/source-schema.d.ts.map +1 -0
  107. package/dist/persistence/source/source-schema.js +37 -0
  108. package/dist/persistence/source/source-schema.js.map +1 -0
  109. package/dist/persistence/source/validate-source-roles.d.ts +12 -0
  110. package/dist/persistence/source/validate-source-roles.d.ts.map +1 -0
  111. package/dist/persistence/source/validate-source-roles.js +38 -0
  112. package/dist/persistence/source/validate-source-roles.js.map +1 -0
  113. package/dist/registry.d.ts +13 -0
  114. package/dist/registry.d.ts.map +1 -1
  115. package/dist/registry.js +26 -0
  116. package/dist/registry.js.map +1 -1
  117. package/dist/shared/base-types.d.ts +2 -1
  118. package/dist/shared/base-types.d.ts.map +1 -1
  119. package/dist/shared/base-types.js +5 -2
  120. package/dist/shared/base-types.js.map +1 -1
  121. package/dist/template/meta-template.d.ts +13 -0
  122. package/dist/template/meta-template.d.ts.map +1 -0
  123. package/dist/template/meta-template.js +13 -0
  124. package/dist/template/meta-template.js.map +1 -0
  125. package/dist/template/template-constants.d.ts +17 -0
  126. package/dist/template/template-constants.d.ts.map +1 -0
  127. package/dist/template/template-constants.js +46 -0
  128. package/dist/template/template-constants.js.map +1 -0
  129. package/dist/template/template-schema.d.ts +3 -0
  130. package/dist/template/template-schema.d.ts.map +1 -0
  131. package/dist/template/template-schema.js +84 -0
  132. package/dist/template/template-schema.js.map +1 -0
  133. package/package.json +1 -1
  134. package/src/attr-schema-validate.ts +89 -9
  135. package/src/core/documentation/doc-constants.ts +22 -0
  136. package/src/core/documentation/doc-provider.ts +12 -0
  137. package/src/core/documentation/doc-schema.ts +64 -0
  138. package/src/core/field/field-constants.ts +41 -1
  139. package/src/core/field/field-schema.ts +25 -0
  140. package/src/core/field/meta-field.ts +6 -3
  141. package/src/core/object/meta-object.ts +6 -6
  142. package/src/core/parser-yaml.ts +11 -3
  143. package/src/core/relationship/meta-relationship.ts +14 -0
  144. package/src/core/relationship/relationship-constants.ts +20 -0
  145. package/src/core/relationship/relationship-schema.ts +18 -0
  146. package/src/core/yaml-desugar.ts +206 -24
  147. package/src/core-types.ts +31 -9
  148. package/src/errors.ts +21 -0
  149. package/src/index.ts +7 -0
  150. package/src/loader/meta-data-loader.ts +15 -1
  151. package/src/loader/validation-passes.ts +98 -1
  152. package/src/naming.ts +15 -13
  153. package/src/parser-core.ts +119 -73
  154. package/src/persistence/db/db-constants.ts +2 -2
  155. package/src/persistence/db/db-provider.ts +10 -16
  156. package/src/persistence/db/db-schema.ts +5 -15
  157. package/src/persistence/origin/meta-origin.ts +15 -0
  158. package/src/persistence/origin/origin-constants.ts +7 -0
  159. package/src/persistence/origin/origin-schema.ts +15 -1
  160. package/src/persistence/source/meta-source.ts +30 -17
  161. package/src/persistence/source/source-constants.ts +66 -17
  162. package/src/persistence/source/source-schema.ts +54 -0
  163. package/src/persistence/source/validate-source-roles.ts +53 -0
  164. package/src/registry.ts +31 -0
  165. package/src/shared/base-types.ts +5 -2
  166. package/src/template/meta-template.ts +12 -0
  167. package/src/template/template-constants.ts +53 -0
  168. package/src/template/template-schema.ts +106 -0
@@ -0,0 +1,46 @@
1
+ // template.* subtype vocabulary + reserved attribute names (FR-004, R1).
2
+ //
3
+ // `template` is the fourth-pillar base type: a renderable text artifact bound to
4
+ // a typed payload. Two subtypes (by audience/structure, NOT by format):
5
+ // - prompt: LLM-targeted; carries the prompt-overlay attrs and is the home for
6
+ // future structured-prompt (role/turn/tool) divergence.
7
+ // - output: every other rendered artifact (email, export, docs, config).
8
+ //
9
+ // Format is the @format ATTRIBUTE (closed set below), never a subtype — the
10
+ // render engine keys its escaper off @format, so a new format costs one escaper
11
+ // + one enum value, not a new subtype + cross-language port.
12
+ import { SUBTYPE_BASE } from "../shared/base-types.js";
13
+ export const TEMPLATE_SUBTYPE_PROMPT = "prompt";
14
+ export const TEMPLATE_SUBTYPE_OUTPUT = "output";
15
+ export const TEMPLATE_SUBTYPES = [
16
+ SUBTYPE_BASE,
17
+ TEMPLATE_SUBTYPE_PROMPT,
18
+ TEMPLATE_SUBTYPE_OUTPUT,
19
+ ];
20
+ // Generic reserved attrs (both subtypes). The "@" is applied at wire time.
21
+ export const TEMPLATE_ATTR_PAYLOAD_REF = "payloadRef";
22
+ export const TEMPLATE_ATTR_TEXT_REF = "textRef";
23
+ export const TEMPLATE_ATTR_FORMAT = "format";
24
+ export const TEMPLATE_ATTR_MAX_CHARS = "maxChars";
25
+ export const TEMPLATE_ATTR_OWNER = "owner";
26
+ export const TEMPLATE_ATTR_SINCE = "since";
27
+ // Output tags the rendered text must contain (drives the verify output-tag check).
28
+ // Generic — not prompt-only: any rendered artifact (email, export, prompt) can
29
+ // carry a tag contract a downstream parser depends on.
30
+ export const TEMPLATE_ATTR_REQUIRED_TAGS = "requiredTags";
31
+ // Prompt-overlay attrs (template.prompt only).
32
+ export const TEMPLATE_ATTR_MAX_TOKENS = "maxTokens";
33
+ export const TEMPLATE_ATTR_REQUIRED_SLOTS = "requiredSlots";
34
+ export const TEMPLATE_ATTR_MODEL = "model";
35
+ // Closed format set — escaping/whitespace behavior is keyed off this in the
36
+ // render engine's escaper registry (FR-004 R7).
37
+ export const TEMPLATE_FORMATS = [
38
+ "text",
39
+ "html",
40
+ "xml",
41
+ "csv",
42
+ "json",
43
+ "markdown",
44
+ "spreadsheet",
45
+ ];
46
+ //# sourceMappingURL=template-constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-constants.js","sourceRoot":"","sources":["../../src/template/template-constants.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,iFAAiF;AACjF,wEAAwE;AACxE,iFAAiF;AACjF,4DAA4D;AAC5D,2EAA2E;AAC3E,EAAE;AACF,4EAA4E;AAC5E,gFAAgF;AAChF,6DAA6D;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAChD,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAEhD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,YAAY;IACZ,uBAAuB;IACvB,uBAAuB;CACf,CAAC;AAGX,2EAA2E;AAC3E,MAAM,CAAC,MAAM,yBAAyB,GAAG,YAAY,CAAC;AACtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC;AAChD,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAC7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;AAClD,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAC3C,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAC3C,mFAAmF;AACnF,+EAA+E;AAC/E,uDAAuD;AACvD,MAAM,CAAC,MAAM,2BAA2B,GAAG,cAAc,CAAC;AAE1D,+CAA+C;AAC/C,MAAM,CAAC,MAAM,wBAAwB,GAAG,WAAW,CAAC;AACpD,MAAM,CAAC,MAAM,4BAA4B,GAAG,eAAe,CAAC;AAC5D,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAE3C,4EAA4E;AAC5E,gDAAgD;AAChD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,UAAU;IACV,aAAa;CACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AttrSchema } from "../registry.js";
2
+ export declare const TEMPLATE_ATTRS_MAP: Map<string, AttrSchema[]>;
3
+ //# sourceMappingURL=template-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-schema.d.ts","sourceRoot":"","sources":["../../src/template/template-schema.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AA6FjD,eAAO,MAAM,kBAAkB,2BAI7B,CAAC"}
@@ -0,0 +1,84 @@
1
+ // Reserved-attribute schemas per template subtype (FR-004, R1).
2
+ //
3
+ // Both subtypes share the generic attrs; @format is a closed enum (allowedValues)
4
+ // that the render engine keys its escaper off. template.prompt additionally
5
+ // carries the LLM-overlay attrs. References (@payloadRef, @textRef) are plain
6
+ // strings here — resolution against a real payload / text source is render-time
7
+ // `verify` scope (Plan #3), not load-time validation.
8
+ import { ATTR_SUBTYPE_STRING, ATTR_SUBTYPE_INT, ATTR_SUBTYPE_STRINGARRAY, } from "../core/attr/attr-constants.js";
9
+ import { SUBTYPE_BASE } from "../shared/base-types.js";
10
+ import { TEMPLATE_SUBTYPE_PROMPT, TEMPLATE_SUBTYPE_OUTPUT, TEMPLATE_ATTR_PAYLOAD_REF, TEMPLATE_ATTR_TEXT_REF, TEMPLATE_ATTR_FORMAT, TEMPLATE_ATTR_MAX_CHARS, TEMPLATE_ATTR_OWNER, TEMPLATE_ATTR_SINCE, TEMPLATE_ATTR_REQUIRED_TAGS, TEMPLATE_ATTR_MAX_TOKENS, TEMPLATE_ATTR_REQUIRED_SLOTS, TEMPLATE_ATTR_MODEL, TEMPLATE_FORMATS, } from "./template-constants.js";
11
+ // Generic attrs shared by template.prompt and template.output.
12
+ const genericAttrs = [
13
+ {
14
+ name: TEMPLATE_ATTR_PAYLOAD_REF,
15
+ valueType: ATTR_SUBTYPE_STRING,
16
+ required: true,
17
+ description: "Reference to the payload (a view-object / projection) this template renders against.",
18
+ },
19
+ {
20
+ name: TEMPLATE_ATTR_TEXT_REF,
21
+ valueType: ATTR_SUBTYPE_STRING,
22
+ required: true,
23
+ description: "2-layer logical reference (group/source) to the body text, resolved by a provider at render time.",
24
+ },
25
+ {
26
+ name: TEMPLATE_ATTR_FORMAT,
27
+ valueType: ATTR_SUBTYPE_STRING,
28
+ required: false,
29
+ default: "text",
30
+ allowedValues: [...TEMPLATE_FORMATS],
31
+ description: "Output format; drives the render engine's escaping/whitespace behavior.",
32
+ },
33
+ {
34
+ name: TEMPLATE_ATTR_MAX_CHARS,
35
+ valueType: ATTR_SUBTYPE_INT,
36
+ required: false,
37
+ description: "Size budget for the rendered output, in characters.",
38
+ },
39
+ {
40
+ name: TEMPLATE_ATTR_OWNER,
41
+ valueType: ATTR_SUBTYPE_STRING,
42
+ required: false,
43
+ description: "Governance: the owner of this template.",
44
+ },
45
+ {
46
+ name: TEMPLATE_ATTR_SINCE,
47
+ valueType: ATTR_SUBTYPE_STRING,
48
+ required: false,
49
+ description: "Governance: the version this template was introduced in.",
50
+ },
51
+ {
52
+ name: TEMPLATE_ATTR_REQUIRED_TAGS,
53
+ valueType: ATTR_SUBTYPE_STRINGARRAY,
54
+ required: false,
55
+ description: "Output tags the rendered text must contain (drives the verify output-tag check).",
56
+ },
57
+ ];
58
+ // LLM-overlay attrs (template.prompt only).
59
+ const promptOverlayAttrs = [
60
+ {
61
+ name: TEMPLATE_ATTR_MAX_TOKENS,
62
+ valueType: ATTR_SUBTYPE_INT,
63
+ required: false,
64
+ description: "Token budget for the rendered prompt (LLM-specific).",
65
+ },
66
+ {
67
+ name: TEMPLATE_ATTR_REQUIRED_SLOTS,
68
+ valueType: ATTR_SUBTYPE_STRINGARRAY,
69
+ required: false,
70
+ description: "Slots that must resolve at render time (drives the verify check).",
71
+ },
72
+ {
73
+ name: TEMPLATE_ATTR_MODEL,
74
+ valueType: ATTR_SUBTYPE_STRING,
75
+ required: false,
76
+ description: "Target model id (LLM-specific).",
77
+ },
78
+ ];
79
+ export const TEMPLATE_ATTRS_MAP = new Map([
80
+ [SUBTYPE_BASE, []],
81
+ [TEMPLATE_SUBTYPE_PROMPT, [...genericAttrs, ...promptOverlayAttrs]],
82
+ [TEMPLATE_SUBTYPE_OUTPUT, [...genericAttrs]],
83
+ ]);
84
+ //# sourceMappingURL=template-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-schema.js","sourceRoot":"","sources":["../../src/template/template-schema.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,kFAAkF;AAClF,4EAA4E;AAC5E,8EAA8E;AAC9E,gFAAgF;AAChF,sDAAsD;AAGtD,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,2BAA2B,EAC3B,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,+DAA+D;AAC/D,MAAM,YAAY,GAAiB;IACjC;QACE,IAAI,EAAE,yBAAyB;QAC/B,SAAS,EAAE,mBAAmB;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,sFAAsF;KACpG;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,SAAS,EAAE,mBAAmB;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,mGAAmG;KACjH;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,SAAS,EAAE,mBAAmB;QAC9B,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,CAAC,GAAG,gBAAgB,CAAC;QACpC,WAAW,EAAE,yEAAyE;KACvF;IACD;QACE,IAAI,EAAE,uBAAuB;QAC7B,SAAS,EAAE,gBAAgB;QAC3B,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,qDAAqD;KACnE;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,SAAS,EAAE,mBAAmB;QAC9B,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,yCAAyC;KACvD;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,SAAS,EAAE,mBAAmB;QAC9B,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,0DAA0D;KACxE;IACD;QACE,IAAI,EAAE,2BAA2B;QACjC,SAAS,EAAE,wBAAwB;QACnC,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,kFAAkF;KAChG;CACF,CAAC;AAEF,4CAA4C;AAC5C,MAAM,kBAAkB,GAAiB;IACvC;QACE,IAAI,EAAE,wBAAwB;QAC9B,SAAS,EAAE,gBAAgB;QAC3B,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,sDAAsD;KACpE;IACD;QACE,IAAI,EAAE,4BAA4B;QAClC,SAAS,EAAE,wBAAwB;QACnC,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,mEAAmE;KACjF;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,SAAS,EAAE,mBAAmB;QAC9B,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,iCAAiC;KAC/C;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAuB;IAC9D,CAAC,YAAY,EAAE,EAAE,CAAC;IAClB,CAAC,uBAAuB,EAAE,CAAC,GAAG,YAAY,EAAE,GAAG,kBAAkB,CAAC,CAAC;IACnE,CAAC,uBAAuB,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC;CAC7C,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaobjectsdev/metadata",
3
- "version": "0.5.0",
3
+ "version": "0.6.0-rc.1",
4
4
  "description": "Metamodel loader, types, and constants for the MetaObjects standard.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,6 +30,12 @@
30
30
  import type { MetaData } from "./shared/meta-data.js";
31
31
  import { ParseError } from "./errors.js";
32
32
  import type { AttrSchema, TypeRegistry } from "./registry.js";
33
+ import { TYPE_FIELD } from "./shared/base-types.js";
34
+ import {
35
+ FIELD_SUBTYPE_ENUM,
36
+ FIELD_ATTR_VALUES,
37
+ ENUM_MEMBER_PATTERN,
38
+ } from "./core/field/field-constants.js";
33
39
 
34
40
  export interface AttrSchemaValidationResult {
35
41
  errors: ParseError[];
@@ -45,7 +51,11 @@ export function validateAttrSchema(
45
51
  registry: TypeRegistry,
46
52
  ): AttrSchemaValidationResult {
47
53
  const errors: ParseError[] = [];
48
- walk(root, registry, errors);
54
+ // Tracks (type.subType) pairs for which ERR_PROVIDER_ATTR_CONFLICT has already
55
+ // been emitted. The conflict is a registry-state condition, not a per-node
56
+ // condition — emit it once per (type, subType), not once per node instance.
57
+ const reportedConflicts = new Set<string>();
58
+ walk(root, registry, errors, reportedConflicts);
49
59
  return { errors, warnings: [] };
50
60
  }
51
61
 
@@ -53,10 +63,11 @@ function walk(
53
63
  node: MetaData,
54
64
  registry: TypeRegistry,
55
65
  errors: ParseError[],
66
+ reportedConflicts: Set<string>,
56
67
  ): void {
57
- validateNode(node, registry, errors);
68
+ validateNode(node, registry, errors, reportedConflicts);
58
69
  for (const child of node.ownChildren()) {
59
- walk(child, registry, errors);
70
+ walk(child, registry, errors, reportedConflicts);
60
71
  }
61
72
  }
62
73
 
@@ -70,13 +81,36 @@ function validateNode(
70
81
  node: MetaData,
71
82
  registry: TypeRegistry,
72
83
  errors: ParseError[],
84
+ reportedConflicts: Set<string>,
73
85
  ): void {
74
- const schema = registry.attrsOf(node.type, node.subType);
75
- if (schema.length === 0) return;
76
-
77
- // Index the schema by attr name for the declared-attr checks below.
86
+ // Build the effective schema in a single pass: per-type attrs win on name
87
+ // collision; common attrs fill in for unclaimed names. Surface common-vs-per-type
88
+ // collisions in the same pass — a name in both lists means a provider tried to
89
+ // overload a declared attr. The conflict is registry-state (not per-node), so
90
+ // emit ONE error per (type, subType), tracked via `reportedConflicts`.
91
+ // Even when a conflict exists, the per-type attr still wins (the common attr
92
+ // for that name is suppressed) so type-checking proceeds normally for everything else.
78
93
  const byName = new Map<string, AttrSchema>();
79
- for (const spec of schema) byName.set(spec.name, spec);
94
+ for (const spec of registry.attrsOf(node.type, node.subType)) byName.set(spec.name, spec);
95
+
96
+ const typeKey = `${node.type}.${node.subType}`;
97
+ for (const ca of registry.getCommonAttrs()) {
98
+ if (byName.has(ca.name)) {
99
+ if (!reportedConflicts.has(typeKey)) {
100
+ errors.push(
101
+ new ParseError(
102
+ `Common attr '${ca.name}' conflicts with per-type attr on ${typeKey}`,
103
+ { code: "ERR_PROVIDER_ATTR_CONFLICT" },
104
+ ),
105
+ );
106
+ reportedConflicts.add(typeKey);
107
+ }
108
+ continue; // per-type wins
109
+ }
110
+ byName.set(ca.name, ca);
111
+ }
112
+
113
+ if (byName.size === 0) return;
80
114
 
81
115
  // --- Check 1: required attrs present ---
82
116
  //
@@ -87,7 +121,7 @@ function validateNode(
87
121
  // were already validated on the node that declared them, so re-checking would
88
122
  // double-report. This mirrors the effective-vs-own split in subtype-rules.ts.
89
123
  const effective = node.attrs();
90
- for (const spec of schema) {
124
+ for (const spec of byName.values()) {
91
125
  if (spec.required && !effective.has(spec.name)) {
92
126
  errors.push(
93
127
  new ParseError(
@@ -131,4 +165,50 @@ function validateNode(
131
165
  }
132
166
  }
133
167
  }
168
+
169
+ // --- Check 4: field.enum @values content rules ---
170
+ //
171
+ // Only for field.enum nodes that carry an own @values attr (concrete or
172
+ // abstract). Concrete fields that extend an abstract enum inherit @values
173
+ // from the super; the super was already validated when it was declared, so
174
+ // only own @values need checking here (mirrors the own-attrs-only policy of
175
+ // Checks 2+3 above — inherited attrs were validated on the declaring node).
176
+ if (node.type === TYPE_FIELD && node.subType === FIELD_SUBTYPE_ENUM) {
177
+ const rawValues = node.ownAttrs().get(FIELD_ATTR_VALUES);
178
+ if (Array.isArray(rawValues)) {
179
+ if (rawValues.length === 0) {
180
+ errors.push(
181
+ new ParseError(
182
+ `${nodeLabel(node)} must declare at least one value in '@${FIELD_ATTR_VALUES}'.`,
183
+ { code: "ERR_BAD_ATTR_VALUE" },
184
+ ),
185
+ );
186
+ } else {
187
+ // rawValues is the only array variant of AttrValue, so each member is a
188
+ // string (StringArrayAttr.coerce stringifies every element on load).
189
+ const seen = new Set<string>();
190
+ for (const member of rawValues) {
191
+ if (!ENUM_MEMBER_PATTERN.test(member)) {
192
+ errors.push(
193
+ new ParseError(
194
+ `${nodeLabel(node)} attribute '@${FIELD_ATTR_VALUES}' member '${member}' ` +
195
+ `is not a valid identifier (must match ${ENUM_MEMBER_PATTERN.source}). ` +
196
+ `Non-identifier-safe member strings require a symbol↔value mapping (deferred).`,
197
+ { code: "ERR_BAD_ATTR_VALUE" },
198
+ ),
199
+ );
200
+ } else if (seen.has(member)) {
201
+ errors.push(
202
+ new ParseError(
203
+ `${nodeLabel(node)} attribute '@${FIELD_ATTR_VALUES}' has duplicate member '${member}'.`,
204
+ { code: "ERR_BAD_ATTR_VALUE" },
205
+ ),
206
+ );
207
+ } else {
208
+ seen.add(member);
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
134
214
  }
@@ -0,0 +1,22 @@
1
+ // Documentation common-attr constants. Bare names — the @-prefix is added by
2
+ // the serializer per ADR-0006.
3
+
4
+ export const DOC_ATTR_DESCRIPTION = "description";
5
+ export const DOC_ATTR_TITLE = "title";
6
+ export const DOC_ATTR_NOTES = "notes";
7
+ export const DOC_ATTR_DEPRECATED = "deprecated";
8
+ export const DOC_ATTR_REPLACED_BY = "replacedBy";
9
+ export const DOC_ATTR_SEE_ALSO = "seeAlso";
10
+ export const DOC_ATTR_ALIASES = "aliases";
11
+
12
+ /** All 7 documentation common-attr names in declaration order. */
13
+ export const DOC_ATTR_NAMES = [
14
+ DOC_ATTR_DESCRIPTION,
15
+ DOC_ATTR_TITLE,
16
+ DOC_ATTR_NOTES,
17
+ DOC_ATTR_DEPRECATED,
18
+ DOC_ATTR_REPLACED_BY,
19
+ DOC_ATTR_SEE_ALSO,
20
+ DOC_ATTR_ALIASES,
21
+ ] as const;
22
+ export type DocAttrName = (typeof DOC_ATTR_NAMES)[number];
@@ -0,0 +1,12 @@
1
+ import type { MetaDataTypeProvider } from "../../provider.js";
2
+ import type { TypeRegistry } from "../../registry.js";
3
+ import { commonDocAttrs } from "./doc-schema.js";
4
+
5
+ export const docProvider: MetaDataTypeProvider = {
6
+ id: "metaobjects-documentation",
7
+ dependencies: ["metaobjects-core-types"],
8
+ description: "Universal documentation common attrs (description / title / notes / deprecated / replacedBy / seeAlso / aliases) accepted on every metatype.",
9
+ registerTypes(registry: TypeRegistry): void {
10
+ registry.registerCommonAttrs(commonDocAttrs);
11
+ },
12
+ };
@@ -0,0 +1,64 @@
1
+ import { type AttrSchema } from "../../registry.js";
2
+ import {
3
+ ATTR_SUBTYPE_STRING,
4
+ ATTR_SUBTYPE_STRINGARRAY,
5
+ } from "../attr/attr-constants.js";
6
+ import {
7
+ DOC_ATTR_ALIASES,
8
+ DOC_ATTR_DEPRECATED,
9
+ DOC_ATTR_DESCRIPTION,
10
+ DOC_ATTR_NOTES,
11
+ DOC_ATTR_REPLACED_BY,
12
+ DOC_ATTR_SEE_ALSO,
13
+ DOC_ATTR_TITLE,
14
+ } from "./doc-constants.js";
15
+
16
+ /**
17
+ * The 7 universal documentation common attrs. Registered via the
18
+ * registry.registerCommonAttrs() hook by the documentation provider.
19
+ * Per ADR-0006, attr names are bare here; the serializer prefixes with @.
20
+ */
21
+ export const commonDocAttrs: AttrSchema[] = [
22
+ {
23
+ name: DOC_ATTR_DESCRIPTION,
24
+ valueType: ATTR_SUBTYPE_STRING,
25
+ required: false,
26
+ description: "Free-form user-facing prose. Markdown allowed, multi-line via YAML '|' block scalar. Flows into doc-gen surfaces (JSDoc / XML-doc / Postgres COMMENT / Mermaid prose).",
27
+ },
28
+ {
29
+ name: DOC_ATTR_TITLE,
30
+ valueType: ATTR_SUBTYPE_STRING,
31
+ required: false,
32
+ description: "Short single-line human label (e.g. 'Email' for a `field.string email`). Optional supplement to description.",
33
+ },
34
+ {
35
+ name: DOC_ATTR_NOTES,
36
+ valueType: ATTR_SUBTYPE_STRING,
37
+ required: false,
38
+ description: "Internal-only rationale. Stays in metadata; never emitted to user-facing docs.",
39
+ },
40
+ {
41
+ name: DOC_ATTR_DEPRECATED,
42
+ valueType: ATTR_SUBTYPE_STRING,
43
+ required: false,
44
+ description: "Text reason for deprecation. Presence ⇒ deprecated. Codegen emits @deprecated / [Obsolete] with this reason.",
45
+ },
46
+ {
47
+ name: DOC_ATTR_REPLACED_BY,
48
+ valueType: ATTR_SUBTYPE_STRING,
49
+ required: false,
50
+ description: "FQN reference to the replacement element. Only meaningful with `deprecated`. Codegen appends 'Replaced by <ref>' to deprecation messages.",
51
+ },
52
+ {
53
+ name: DOC_ATTR_SEE_ALSO,
54
+ valueType: ATTR_SUBTYPE_STRINGARRAY,
55
+ required: false,
56
+ description: "External documentation URLs. Codegen emits @see / <seealso href=...>.",
57
+ },
58
+ {
59
+ name: DOC_ATTR_ALIASES,
60
+ valueType: ATTR_SUBTYPE_STRINGARRAY,
61
+ required: false,
62
+ description: "Alternate names for this element. Aids AI authoring disambiguation, search, migration.",
63
+ },
64
+ ];
@@ -3,7 +3,7 @@
3
3
  import { SUBTYPE_BASE } from "../../shared/base-types.js";
4
4
 
5
5
  // ---------------------------------------------------------------------------
6
- // Field subtypes (15)
6
+ // Field subtypes (16)
7
7
  // ---------------------------------------------------------------------------
8
8
 
9
9
  export const FIELD_SUBTYPE_STRING = "string";
@@ -21,6 +21,7 @@ export const FIELD_SUBTYPE_TIMESTAMP = "timestamp";
21
21
  export const FIELD_SUBTYPE_OBJECT = "object";
22
22
  export const FIELD_SUBTYPE_CLASS = "class";
23
23
  export const FIELD_SUBTYPE_CURRENCY = "currency";
24
+ export const FIELD_SUBTYPE_ENUM = "enum";
24
25
 
25
26
  export const FIELD_SUBTYPES = [
26
27
  SUBTYPE_BASE,
@@ -39,6 +40,7 @@ export const FIELD_SUBTYPES = [
39
40
  FIELD_SUBTYPE_OBJECT,
40
41
  FIELD_SUBTYPE_CLASS,
41
42
  FIELD_SUBTYPE_CURRENCY,
43
+ FIELD_SUBTYPE_ENUM,
42
44
  ] as const;
43
45
  export type FieldSubType = (typeof FIELD_SUBTYPES)[number];
44
46
 
@@ -63,6 +65,30 @@ export const FIELD_ATTR_AUTO_SET = "autoSet";
63
65
  * spelling as the relationship `@objectRef` — Java's single ATTR_OBJECT_REF. */
64
66
  export const FIELD_ATTR_OBJECT_REF = "objectRef";
65
67
 
68
+ /** Storage strategy for an object-typed field. Meaningful only when @objectRef is set.
69
+ * Cross-language metamodel attr — every port must accept and round-trip it. */
70
+ export const FIELD_ATTR_STORAGE = "storage";
71
+
72
+ /** @storage "flattened" — nested object's columns expand into the parent table,
73
+ * each prefixed by the parent field's DB name (EF OwnsOne pattern). Requires
74
+ * the parent field.object to have isArray=false; arrays-of-values must use jsonb. */
75
+ export const STORAGE_FLATTENED = "flattened";
76
+
77
+ /** @storage "jsonb" — the nested value (or array of values when isArray=true) lives
78
+ * in a single jsonb column. The structure is typed by metadata; storage is opaque. */
79
+ export const STORAGE_JSONB = "jsonb";
80
+
81
+ /** @storage "subdocument" — document-store-native nested document. No Postgres
82
+ * column is emitted for this; codegen targets like Mongo render it inline. */
83
+ export const STORAGE_SUBDOCUMENT = "subdocument";
84
+
85
+ export const STORAGE_VALUES = [
86
+ STORAGE_FLATTENED,
87
+ STORAGE_JSONB,
88
+ STORAGE_SUBDOCUMENT,
89
+ ] as const;
90
+ export type StorageValue = (typeof STORAGE_VALUES)[number];
91
+
66
92
  export const AUTO_SET_ON_CREATE = "onCreate";
67
93
  export const AUTO_SET_ON_UPDATE = "onUpdate";
68
94
 
@@ -77,3 +103,17 @@ export type AutoSetValue = (typeof AUTO_SET_VALUES)[number];
77
103
  export const FIELD_ATTR_CURRENCY = "currency";
78
104
  /** Default ISO 4217 currency code when @currency is omitted on a currency field. */
79
105
  export const FIELD_ATTR_CURRENCY_DEFAULT = "USD";
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Enum attrs (on enum-subtype fields)
109
+ // ---------------------------------------------------------------------------
110
+
111
+ /** Member symbols of an enum-subtype field. Required, string array. */
112
+ export const FIELD_ATTR_VALUES = "values";
113
+
114
+ /**
115
+ * Pattern every enum member must satisfy: a legal identifier in all target
116
+ * languages (TS union member, Java/C#/Python enum member). Ensures symbol ==
117
+ * stored string with no name↔value divergence.
118
+ */
119
+ export const ENUM_MEMBER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -6,10 +6,13 @@ import {
6
6
  ATTR_SUBTYPE_STRING,
7
7
  ATTR_SUBTYPE_INT,
8
8
  ATTR_SUBTYPE_BOOLEAN,
9
+ ATTR_SUBTYPE_STRINGARRAY,
9
10
  } from "../attr/attr-constants.js";
10
11
  import { SORT_ORDER_VALUES } from "../query/query-constants.js";
11
12
  import {
12
13
  FIELD_ATTR_OBJECT_REF,
14
+ FIELD_ATTR_STORAGE,
15
+ STORAGE_VALUES,
13
16
  FIELD_ATTR_REQUIRED,
14
17
  FIELD_ATTR_UNIQUE,
15
18
  FIELD_ATTR_DEFAULT,
@@ -23,6 +26,7 @@ import {
23
26
  FIELD_ATTR_CURRENCY_DEFAULT,
24
27
  FIELD_ATTR_AUTO_SET,
25
28
  AUTO_SET_VALUES,
29
+ FIELD_ATTR_VALUES,
26
30
  } from "./field-constants.js";
27
31
 
28
32
  /** Attrs common to every field subtype (codegen-ts column mapper + Project D filter/sort). */
@@ -34,6 +38,18 @@ export const commonFieldAttrs: AttrSchema[] = [
34
38
  description:
35
39
  "Name (or FQN) of the target object an object-typed field nests — drives nested-object (de)serialization.",
36
40
  },
41
+ {
42
+ name: FIELD_ATTR_STORAGE,
43
+ valueType: ATTR_SUBTYPE_STRING,
44
+ required: false,
45
+ allowedValues: [...STORAGE_VALUES],
46
+ description:
47
+ "Storage strategy for an object-typed field (set with @objectRef). " +
48
+ "\"flattened\" expands the nested value into prefixed columns on the parent " +
49
+ "table. \"jsonb\" stores the structured value in a single jsonb column " +
50
+ "(supports isArray=true for arrays of values). \"subdocument\" is a hint for " +
51
+ "document-store codegen targets and emits no Postgres column.",
52
+ },
37
53
  {
38
54
  name: FIELD_ATTR_REQUIRED,
39
55
  valueType: ATTR_SUBTYPE_BOOLEAN,
@@ -119,3 +135,12 @@ export const currencyFieldAttr: AttrSchema = {
119
135
  description:
120
136
  "ISO 4217 currency code for a currency-subtype field. Storage is integer minor units; defaults to 'USD' when omitted.",
121
137
  };
138
+
139
+ /** The @values attr — only on field.enum. Required string array. */
140
+ export const enumFieldAttr: AttrSchema = {
141
+ name: FIELD_ATTR_VALUES,
142
+ valueType: ATTR_SUBTYPE_STRINGARRAY,
143
+ required: true,
144
+ description:
145
+ "Member symbols of an enum-subtype field. Declaration order is significant; each is a legal identifier and its own stored string.",
146
+ };
@@ -33,6 +33,7 @@ import {
33
33
  FIELD_SUBTYPE_TIME,
34
34
  FIELD_SUBTYPE_TIMESTAMP,
35
35
  FIELD_SUBTYPE_OBJECT,
36
+ FIELD_SUBTYPE_ENUM,
36
37
  FIELD_ATTR_REQUIRED,
37
38
  FIELD_ATTR_UNIQUE,
38
39
  FIELD_ATTR_DEFAULT,
@@ -41,7 +42,7 @@ import {
41
42
  FIELD_ATTR_SCALE,
42
43
  FIELD_ATTR_OBJECT_REF,
43
44
  } from "./field-constants.js";
44
- import { FIELD_ATTR_DB_COLUMN } from "../../persistence/db/db-constants.js";
45
+ import { FIELD_ATTR_COLUMN } from "../../persistence/db/db-constants.js";
45
46
  import { VALIDATOR_SUBTYPE_REQUIRED } from "../validator/validator-constants.js";
46
47
  import type { MetaValidator } from "../validator/meta-validator.js";
47
48
  import type { MetaView } from "../../presentation/view/meta-view.js";
@@ -57,6 +58,7 @@ const FIELD_DATA_TYPE: Readonly<Record<string, DataType>> = {
57
58
  [FIELD_SUBTYPE_BYTE]: DATA_TYPE_INT,
58
59
  [FIELD_SUBTYPE_LONG]: DATA_TYPE_LONG,
59
60
  [FIELD_SUBTYPE_CURRENCY]: DATA_TYPE_LONG,
61
+ [FIELD_SUBTYPE_ENUM]: DATA_TYPE_STRING,
60
62
  [FIELD_SUBTYPE_DOUBLE]: DATA_TYPE_DOUBLE,
61
63
  [FIELD_SUBTYPE_FLOAT]: DATA_TYPE_DOUBLE,
62
64
  [FIELD_SUBTYPE_DECIMAL]: DATA_TYPE_DOUBLE,
@@ -84,8 +86,9 @@ export class MetaField extends MetaData implements DataTypeAware {
84
86
  return typeof v === "string" ? v : undefined;
85
87
  }
86
88
 
87
- get dbColumn(): string | undefined {
88
- const v = this.ownAttr(FIELD_ATTR_DB_COLUMN);
89
+ /** Physical column name override (`@column` attr). */
90
+ get column(): string | undefined {
91
+ const v = this.ownAttr(FIELD_ATTR_COLUMN);
89
92
  return typeof v === "string" ? v : undefined;
90
93
  }
91
94
 
@@ -9,13 +9,12 @@ import {
9
9
  TYPE_IDENTITY,
10
10
  TYPE_RELATIONSHIP,
11
11
  TYPE_VALIDATOR,
12
- TYPE_SOURCE,
13
12
  TYPE_LAYOUT,
14
13
  } from "../../shared/base-types.js";
15
14
  import {
16
- SOURCE_SUBTYPE_DB_TABLE,
17
- SOURCE_DB_TABLE_ATTR_NAME,
15
+ SOURCE_ROLE_PRIMARY,
18
16
  } from "../../persistence/source/source-constants.js";
17
+ import { MetaSource } from "../../persistence/source/meta-source.js";
19
18
  import {
20
19
  OBJECT_SUBTYPE_ENTITY,
21
20
  OBJECT_SUBTYPE_VALUE,
@@ -34,11 +33,12 @@ import type { MetaValidator } from "../validator/meta-validator.js";
34
33
  export class MetaObject extends MetaData {
35
34
  get dbTable(): string | undefined {
36
35
  return this.cached("dbTable", () => {
36
+ // The primary writable source carries the physical table name (@table).
37
37
  const source = this.children().find(
38
- (c) => c.type === TYPE_SOURCE && c.subType === SOURCE_SUBTYPE_DB_TABLE,
38
+ (c): c is MetaSource =>
39
+ c instanceof MetaSource && c.isWritable() && c.role === SOURCE_ROLE_PRIMARY,
39
40
  );
40
- const name = source?.ownAttr(SOURCE_DB_TABLE_ATTR_NAME);
41
- return typeof name === "string" && name !== "" ? name : undefined;
41
+ return source?.tableName;
42
42
  });
43
43
  }
44
44
 
@@ -34,17 +34,25 @@ export function parseYaml(content: string, opts: ParseOptions): ParseResult {
34
34
  // If the desugar could not produce a usable document at all, surface the
35
35
  // first desugar error as a throw — parallels parseJson's top-level throws.
36
36
  if (Object.keys(canonical).length === 0) {
37
+ const first = desugarErrors[0]!;
37
38
  throw new ParseError(
38
- desugarErrors[0]!,
39
- { ...errOpts(opts.sourceName), code: "ERR_MALFORMED_YAML" },
39
+ first.message,
40
+ { ...errOpts(opts.sourceName), code: first.code ?? "ERR_MALFORMED_YAML" },
40
41
  );
41
42
  }
42
43
 
43
44
  const result = buildTree(canonical, opts);
44
45
 
45
46
  // Merge collected desugar errors ahead of buildTree's own collected errors.
47
+ // Each CollectedError carries its own stable code when set (e.g.
48
+ // ERR_YAML_COERCION from the D2 type-coercion guard); the malformed-document
49
+ // shape errors fall back to ERR_MALFORMED_YAML.
46
50
  const desugarParseErrors = desugarErrors.map(
47
- (msg) => new ParseError(msg, { ...errOpts(opts.sourceName), code: "ERR_MALFORMED_YAML" }),
51
+ (e) =>
52
+ new ParseError(e.message, {
53
+ ...errOpts(opts.sourceName),
54
+ code: e.code ?? "ERR_MALFORMED_YAML",
55
+ }),
48
56
  );
49
57
  return {
50
58
  root: result.root,
@@ -8,6 +8,8 @@ import {
8
8
  RELATIONSHIP_ATTR_OBJECT_REF,
9
9
  RELATIONSHIP_ATTR_JOIN_ENTITY,
10
10
  RELATIONSHIP_ATTR_JOIN_FIELDS,
11
+ RELATIONSHIP_ATTR_ON_DELETE,
12
+ RELATIONSHIP_ATTR_ON_UPDATE,
11
13
  } from "./relationship-constants.js";
12
14
 
13
15
  export class MetaRelationship extends MetaData {
@@ -33,4 +35,16 @@ export class MetaRelationship extends MetaData {
33
35
  const f = this.ownAttr(RELATIONSHIP_ATTR_JOIN_FIELDS);
34
36
  return Array.isArray(f) ? (f as string[]) : [];
35
37
  }
38
+
39
+ /** Referential action on parent delete. Undefined when not explicitly set (default derives from subtype). */
40
+ get onDelete(): string | undefined {
41
+ const v = this.ownAttr(RELATIONSHIP_ATTR_ON_DELETE);
42
+ return typeof v === "string" && v !== "" ? v : undefined;
43
+ }
44
+
45
+ /** Referential action on key update. Undefined when not explicitly set (default: cascade). */
46
+ get onUpdate(): string | undefined {
47
+ const v = this.ownAttr(RELATIONSHIP_ATTR_ON_UPDATE);
48
+ return typeof v === "string" && v !== "" ? v : undefined;
49
+ }
36
50
  }