@metaobjectsdev/metadata 0.14.1 → 0.15.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 (142) hide show
  1. package/dist/attr-schema-validate.js +22 -1
  2. package/dist/attr-schema-validate.js.map +1 -1
  3. package/dist/core/attr/meta-attr.d.ts.map +1 -1
  4. package/dist/core/attr/meta-attr.js +2 -0
  5. package/dist/core/attr/meta-attr.js.map +1 -1
  6. package/dist/core/field/field-constants.d.ts +26 -1
  7. package/dist/core/field/field-constants.d.ts.map +1 -1
  8. package/dist/core/field/field-constants.js +29 -0
  9. package/dist/core/field/field-constants.js.map +1 -1
  10. package/dist/core/field/field-definition.embedded.d.ts.map +1 -1
  11. package/dist/core/field/field-definition.embedded.js +28 -0
  12. package/dist/core/field/field-definition.embedded.js.map +1 -1
  13. package/dist/core/field/meta-field.d.ts +12 -3
  14. package/dist/core/field/meta-field.d.ts.map +1 -1
  15. package/dist/core/field/meta-field.js +33 -15
  16. package/dist/core/field/meta-field.js.map +1 -1
  17. package/dist/core/field/validate-field-readonly.d.ts.map +1 -1
  18. package/dist/core/field/validate-field-readonly.js +15 -3
  19. package/dist/core/field/validate-field-readonly.js.map +1 -1
  20. package/dist/core/identity/meta-identity.d.ts +2 -0
  21. package/dist/core/identity/meta-identity.d.ts.map +1 -1
  22. package/dist/core/identity/meta-identity.js +16 -8
  23. package/dist/core/identity/meta-identity.js.map +1 -1
  24. package/dist/core/identity/validate-identity-passthrough.d.ts.map +1 -1
  25. package/dist/core/identity/validate-identity-passthrough.js +9 -1
  26. package/dist/core/identity/validate-identity-passthrough.js.map +1 -1
  27. package/dist/core/object/meta-object.d.ts.map +1 -1
  28. package/dist/core/object/meta-object.js +15 -5
  29. package/dist/core/object/meta-object.js.map +1 -1
  30. package/dist/core/object/validate-discriminator.d.ts.map +1 -1
  31. package/dist/core/object/validate-discriminator.js +17 -2
  32. package/dist/core/object/validate-discriminator.js.map +1 -1
  33. package/dist/core/query/query-constants.d.ts.map +1 -1
  34. package/dist/core/query/query-constants.js +7 -1
  35. package/dist/core/query/query-constants.js.map +1 -1
  36. package/dist/core/relationship/meta-relationship.d.ts.map +1 -1
  37. package/dist/core/relationship/meta-relationship.js +9 -7
  38. package/dist/core/relationship/meta-relationship.js.map +1 -1
  39. package/dist/core/validator/meta-validator.d.ts.map +1 -1
  40. package/dist/core/validator/meta-validator.js +6 -3
  41. package/dist/core/validator/meta-validator.js.map +1 -1
  42. package/dist/core-types.js +2 -2
  43. package/dist/core-types.js.map +1 -1
  44. package/dist/loader/meta-data-loader.d.ts.map +1 -1
  45. package/dist/loader/meta-data-loader.js +4 -0
  46. package/dist/loader/meta-data-loader.js.map +1 -1
  47. package/dist/loader/validation-passes.d.ts.map +1 -1
  48. package/dist/loader/validation-passes.js +97 -39
  49. package/dist/loader/validation-passes.js.map +1 -1
  50. package/dist/loader/validation-registry.d.ts.map +1 -1
  51. package/dist/loader/validation-registry.js +7 -2
  52. package/dist/loader/validation-registry.js.map +1 -1
  53. package/dist/naming.d.ts.map +1 -1
  54. package/dist/naming.js +6 -3
  55. package/dist/naming.js.map +1 -1
  56. package/dist/object-serializer.d.ts.map +1 -1
  57. package/dist/object-serializer.js +6 -2
  58. package/dist/object-serializer.js.map +1 -1
  59. package/dist/parser-core.js +5 -0
  60. package/dist/parser-core.js.map +1 -1
  61. package/dist/persistence/db/db-constants.d.ts +20 -9
  62. package/dist/persistence/db/db-constants.d.ts.map +1 -1
  63. package/dist/persistence/db/db-constants.js +20 -15
  64. package/dist/persistence/db/db-constants.js.map +1 -1
  65. package/dist/persistence/db/db-definition.embedded.d.ts.map +1 -1
  66. package/dist/persistence/db/db-definition.embedded.js +19 -1
  67. package/dist/persistence/db/db-definition.embedded.js.map +1 -1
  68. package/dist/persistence/origin/meta-origin.d.ts.map +1 -1
  69. package/dist/persistence/origin/meta-origin.js +6 -0
  70. package/dist/persistence/origin/meta-origin.js.map +1 -1
  71. package/dist/persistence/source/meta-source.d.ts.map +1 -1
  72. package/dist/persistence/source/meta-source.js +11 -5
  73. package/dist/persistence/source/meta-source.js.map +1 -1
  74. package/dist/persistence/source/validate-source-parameter-ref.d.ts.map +1 -1
  75. package/dist/persistence/source/validate-source-parameter-ref.js +14 -5
  76. package/dist/persistence/source/validate-source-parameter-ref.js.map +1 -1
  77. package/dist/persistence/source/validate-source-physical-names.d.ts.map +1 -1
  78. package/dist/persistence/source/validate-source-physical-names.js +9 -1
  79. package/dist/persistence/source/validate-source-physical-names.js.map +1 -1
  80. package/dist/persistence/source/validate-source-roles.d.ts.map +1 -1
  81. package/dist/persistence/source/validate-source-roles.js +5 -1
  82. package/dist/persistence/source/validate-source-roles.js.map +1 -1
  83. package/dist/presentation/layout/meta-layout.d.ts.map +1 -1
  84. package/dist/presentation/layout/meta-layout.js +12 -6
  85. package/dist/presentation/layout/meta-layout.js.map +1 -1
  86. package/dist/registry-manifest.d.ts +12 -2
  87. package/dist/registry-manifest.d.ts.map +1 -1
  88. package/dist/registry-manifest.js +20 -8
  89. package/dist/registry-manifest.js.map +1 -1
  90. package/dist/serializer-json.d.ts.map +1 -1
  91. package/dist/serializer-json.js +8 -1
  92. package/dist/serializer-json.js.map +1 -1
  93. package/dist/shared/meta-data.d.ts +14 -0
  94. package/dist/shared/meta-data.d.ts.map +1 -1
  95. package/dist/shared/meta-data.js +30 -0
  96. package/dist/shared/meta-data.js.map +1 -1
  97. package/dist/shared/meta-root.d.ts.map +1 -1
  98. package/dist/shared/meta-root.js +8 -2
  99. package/dist/shared/meta-root.js.map +1 -1
  100. package/dist/subtype-rules.js +4 -3
  101. package/dist/subtype-rules.js.map +1 -1
  102. package/dist/super-resolve.d.ts.map +1 -1
  103. package/dist/super-resolve.js +3 -0
  104. package/dist/super-resolve.js.map +1 -1
  105. package/dist/validate-max-occurs.js +5 -0
  106. package/dist/validate-max-occurs.js.map +1 -1
  107. package/package.json +1 -1
  108. package/src/attr-schema-validate.ts +24 -1
  109. package/src/core/attr/meta-attr.ts +2 -0
  110. package/src/core/field/field-constants.ts +34 -0
  111. package/src/core/field/field-definition.embedded.ts +28 -0
  112. package/src/core/field/meta-field.ts +30 -12
  113. package/src/core/field/validate-field-readonly.ts +15 -3
  114. package/src/core/identity/meta-identity.ts +16 -8
  115. package/src/core/identity/validate-identity-passthrough.ts +9 -1
  116. package/src/core/object/meta-object.ts +5 -0
  117. package/src/core/object/validate-discriminator.ts +17 -2
  118. package/src/core/query/query-constants.ts +7 -1
  119. package/src/core/relationship/meta-relationship.ts +9 -7
  120. package/src/core/validator/meta-validator.ts +6 -3
  121. package/src/core-types.ts +2 -2
  122. package/src/loader/meta-data-loader.ts +4 -0
  123. package/src/loader/validation-passes.ts +97 -39
  124. package/src/loader/validation-registry.ts +7 -2
  125. package/src/naming.ts +6 -3
  126. package/src/object-serializer.ts +6 -2
  127. package/src/parser-core.ts +5 -0
  128. package/src/persistence/db/db-constants.ts +20 -15
  129. package/src/persistence/db/db-definition.embedded.ts +19 -1
  130. package/src/persistence/origin/meta-origin.ts +6 -0
  131. package/src/persistence/source/meta-source.ts +11 -5
  132. package/src/persistence/source/validate-source-parameter-ref.ts +14 -5
  133. package/src/persistence/source/validate-source-physical-names.ts +9 -1
  134. package/src/persistence/source/validate-source-roles.ts +5 -1
  135. package/src/presentation/layout/meta-layout.ts +12 -6
  136. package/src/registry-manifest.ts +28 -8
  137. package/src/serializer-json.ts +8 -1
  138. package/src/shared/meta-data.ts +30 -0
  139. package/src/shared/meta-root.ts +4 -0
  140. package/src/subtype-rules.ts +4 -3
  141. package/src/super-resolve.ts +3 -0
  142. package/src/validate-max-occurs.ts +5 -0
@@ -32,6 +32,8 @@ import {
32
32
  FIELD_SUBTYPE_OBJECT,
33
33
  FIELD_SUBTYPE_ENUM,
34
34
  FIELD_SUBTYPE_UUID,
35
+ FIELD_SUBTYPE_URI,
36
+ FIELD_SUBTYPE_INET,
35
37
  FIELD_ATTR_REQUIRED,
36
38
  FIELD_ATTR_UNIQUE,
37
39
  FIELD_ATTR_DEFAULT,
@@ -53,6 +55,10 @@ const FIELD_DATA_TYPE: Readonly<Record<string, DataType>> = {
53
55
  [FIELD_SUBTYPE_STRING]: DATA_TYPE_STRING,
54
56
  // field.uuid binds to TS `string` (no native UUID type) — DATA_TYPE_STRING.
55
57
  [FIELD_SUBTYPE_UUID]: DATA_TYPE_STRING,
58
+ // ADR-0036/0037 Wave 3: field.uri / field.inet bind to TS `string` (no native
59
+ // URI/IP type in TS). Other ports bind to their native URI/IP type.
60
+ [FIELD_SUBTYPE_URI]: DATA_TYPE_STRING,
61
+ [FIELD_SUBTYPE_INET]: DATA_TYPE_STRING,
56
62
  [FIELD_SUBTYPE_INT]: DATA_TYPE_INT,
57
63
  [FIELD_SUBTYPE_LONG]: DATA_TYPE_LONG,
58
64
  [FIELD_SUBTYPE_CURRENCY]: DATA_TYPE_LONG,
@@ -83,20 +89,23 @@ export class MetaField extends MetaData implements DataTypeAware {
83
89
  return convertToDataType(this.dataType, raw);
84
90
  }
85
91
 
86
- /** The target object name for an object-typed field (the `@objectRef` attr). */
92
+ /** The target object name for an object-typed field (the `@objectRef` attr).
93
+ * ADR-0039: resolving — a concrete field.object may inherit @objectRef via extends. */
87
94
  get objectRef(): string | undefined {
88
- const v = this.ownAttr(FIELD_ATTR_OBJECT_REF);
95
+ const v = this.attr(FIELD_ATTR_OBJECT_REF);
89
96
  return typeof v === "string" ? v : undefined;
90
97
  }
91
98
 
92
- /** Physical column name override (`@column` attr). */
99
+ /** Physical column name override (`@column` attr).
100
+ * ADR-0039: resolving — inheritable via extends. */
93
101
  get column(): string | undefined {
94
- const v = this.ownAttr(FIELD_ATTR_COLUMN);
102
+ const v = this.attr(FIELD_ATTR_COLUMN);
95
103
  return typeof v === "string" ? v : undefined;
96
104
  }
97
105
 
106
+ /** ADR-0039: resolving — a concrete field may inherit @default from an abstract base. */
98
107
  get default(): unknown {
99
- return this.ownAttr(FIELD_ATTR_DEFAULT);
108
+ return this.attr(FIELD_ATTR_DEFAULT);
100
109
  }
101
110
 
102
111
  /**
@@ -113,30 +122,35 @@ export class MetaField extends MetaData implements DataTypeAware {
113
122
  */
114
123
  defaultValue(): AttrValue | undefined {
115
124
  return this.cached("defaultValue", () => {
116
- const raw = this.ownAttr(FIELD_ATTR_DEFAULT);
125
+ // ADR-0039: resolving — inherit @default from an abstract base via extends.
126
+ const raw = this.attr(FIELD_ATTR_DEFAULT);
117
127
  if (raw === undefined) return undefined;
118
128
  return this.coerce(raw);
119
129
  });
120
130
  }
121
131
 
132
+ /** ADR-0039: resolving — a concrete field inherits @maxLength from an abstract base. */
122
133
  get maxLength(): number | undefined {
123
- const v = this.ownAttr(FIELD_ATTR_MAX_LENGTH);
134
+ const v = this.attr(FIELD_ATTR_MAX_LENGTH);
124
135
  return typeof v === "number" ? v : undefined;
125
136
  }
126
137
 
138
+ /** ADR-0039: resolving — inheritable via extends (abstract decimal base). */
127
139
  get precision(): number | undefined {
128
- const v = this.ownAttr(FIELD_ATTR_PRECISION);
140
+ const v = this.attr(FIELD_ATTR_PRECISION);
129
141
  return typeof v === "number" ? v : undefined;
130
142
  }
131
143
 
144
+ /** ADR-0039: resolving — inheritable via extends (abstract decimal base). */
132
145
  get scale(): number | undefined {
133
- const v = this.ownAttr(FIELD_ATTR_SCALE);
146
+ const v = this.attr(FIELD_ATTR_SCALE);
134
147
  return typeof v === "number" ? v : undefined;
135
148
  }
136
149
 
137
- /** True if `@unique: true` is set on the field itself (column-level unique). */
150
+ /** True if `@unique: true` is the effective value on the field (column-level unique).
151
+ * ADR-0039: resolving — inheritable via extends. */
138
152
  get unique(): boolean {
139
- return this.ownAttr(FIELD_ATTR_UNIQUE) === true;
153
+ return this.attr(FIELD_ATTR_UNIQUE) === true;
140
154
  }
141
155
 
142
156
  /**
@@ -144,9 +158,11 @@ export class MetaField extends MetaData implements DataTypeAware {
144
158
  *
145
159
  * Checks both `@required: true` attr and `validator.required` children —
146
160
  * matches the codegen-ts isRequired() semantics.
161
+ * ADR-0039: resolving — both the @required attr and the validator set are the
162
+ * effective (own + inherited) forms.
147
163
  */
148
164
  get isRequired(): boolean {
149
- if (this.ownAttr(FIELD_ATTR_REQUIRED) === true) return true;
165
+ if (this.attr(FIELD_ATTR_REQUIRED) === true) return true;
150
166
  return this.validators().some((v) => v.subType === VALIDATOR_SUBTYPE_REQUIRED);
151
167
  }
152
168
 
@@ -160,6 +176,7 @@ export class MetaField extends MetaData implements DataTypeAware {
160
176
  /** Own validators only — excludes validators inherited via extends. Java parity: getChildren(Class, false). */
161
177
  ownValidators(): MetaValidator[] {
162
178
  return this.cached("ownValidators", () =>
179
+ // ADR-0039: own-accessor definition — the deliberate own-only API twin of validators().
163
180
  this.ownChildren().filter((c): c is MetaValidator => c.type === TYPE_VALIDATOR),
164
181
  );
165
182
  }
@@ -174,6 +191,7 @@ export class MetaField extends MetaData implements DataTypeAware {
174
191
  /** Own views only — excludes views inherited via extends. */
175
192
  ownViews(): MetaView[] {
176
193
  return this.cached("ownViews", () =>
194
+ // ADR-0039: own-accessor definition — the deliberate own-only API twin of views().
177
195
  this.ownChildren().filter((c): c is MetaView => c.type === TYPE_VIEW),
178
196
  );
179
197
  }
@@ -38,11 +38,15 @@ export function validateFieldReadOnly(root: MetaData): FieldReadOnlyValidationRe
38
38
  const errors: ParseError[] = [];
39
39
  const warnings: LoaderWarning[] = [];
40
40
 
41
- for (const obj of root.ownChildren().filter((c) => c.type === TYPE_OBJECT)) {
41
+ // ADR-0039: root has no super; children()==ownChildren() but resolving is the default.
42
+ for (const obj of root.children().filter((c) => c.type === TYPE_OBJECT)) {
42
43
  const isValueObject = obj.subType === OBJECT_SUBTYPE_VALUE;
43
44
 
44
45
  // 1) WARN_READONLY_VALUE_OBJECT — any @readOnly field child of an object.value.
45
46
  if (isValueObject) {
47
+ // ADR-0039: own — warns on @readOnly DECLARED on this value's own fields
48
+ // (readOnlyFlag reads the explicit own flag; the FR-013 read-only checks
49
+ // are own-vs-super comparisons by design).
46
50
  for (const child of obj.ownChildren()) {
47
51
  if (child.type === TYPE_FIELD && readOnlyFlag(child) === true) {
48
52
  warnings.push({
@@ -60,6 +64,8 @@ export function validateFieldReadOnly(root: MetaData): FieldReadOnlyValidationRe
60
64
 
61
65
  // 2) ERR_READONLY_DOWNGRADE — read-only-ness can only be upgraded across
62
66
  // extends. Compare own field vs. inherited field's effective @readOnly.
67
+ // ADR-0039: own — the downgrade check compares this object's OWN explicit
68
+ // @readOnly:false against the inherited effective value (own-vs-super by design).
63
69
  for (const ownField of obj.ownChildren().filter((c) => c.type === TYPE_FIELD)) {
64
70
  const ownVal = readOnlyFlag(ownField);
65
71
  if (ownVal !== false) continue; // only the explicit downgrade case matters
@@ -103,6 +109,9 @@ export function validateFieldReadOnly(root: MetaData): FieldReadOnlyValidationRe
103
109
  /** Read the explicit @readOnly value from a field's own attrs. Returns
104
110
  * true / false when explicitly set, undefined when absent. */
105
111
  function readOnlyFlag(field: MetaData): boolean | undefined {
112
+ // ADR-0039: own — the FR-013 downgrade rule needs the EXPLICIT own @readOnly on
113
+ // THIS node (detecting an own :false against an inherited :true); resolving would
114
+ // mask the downgrade. Deliberate own-vs-super comparison.
106
115
  const v = field.ownAttr(FIELD_ATTR_READ_ONLY);
107
116
  if (typeof v === "boolean") return v;
108
117
  return undefined;
@@ -113,6 +122,8 @@ function readOnlyFlag(field: MetaData): boolean | undefined {
113
122
  function inheritedField(obj: MetaData, name: string): MetaData | undefined {
114
123
  let cursor = obj.superResolved;
115
124
  while (cursor !== undefined) {
125
+ // ADR-0039: own — super-chain walk reading each level's OWN fields to find the
126
+ // declaring node (the FR-013 comparison needs the declaring node's own flag).
116
127
  const f = cursor.ownChildren().find((c) => c.type === TYPE_FIELD && c.name === name);
117
128
  if (f !== undefined) return f;
118
129
  cursor = cursor.superResolved;
@@ -127,9 +138,10 @@ function primaryAssignedFieldNames(obj: MetaData): Set<string> {
127
138
  for (const id of obj.children()) {
128
139
  if (id.type !== TYPE_IDENTITY) continue;
129
140
  if (id.subType !== IDENTITY_SUBTYPE_PRIMARY) continue;
130
- const gen = id.ownAttr(IDENTITY_ATTR_GENERATION);
141
+ // ADR-0039: resolving — an identity may inherit @generation / @fields via extends.
142
+ const gen = id.attr(IDENTITY_ATTR_GENERATION);
131
143
  if (gen !== GENERATION_ASSIGNED) continue;
132
- const fields = id.ownAttr(IDENTITY_ATTR_FIELDS);
144
+ const fields = id.attr(IDENTITY_ATTR_FIELDS);
133
145
  if (Array.isArray(fields)) {
134
146
  for (const fName of fields) {
135
147
  if (typeof fName === "string") out.add(fName);
@@ -22,17 +22,19 @@ import type { MetaRoot } from "../../shared/meta-root.js";
22
22
  export type IdentityGeneration = "increment" | "uuid" | "assigned";
23
23
 
24
24
  export class MetaIdentity extends MetaData {
25
+ /** ADR-0039: resolving — @fields may be inherited via extends. */
25
26
  get fields(): string[] {
26
- const f = this.ownAttr(IDENTITY_ATTR_FIELDS);
27
+ const f = this.attr(IDENTITY_ATTR_FIELDS);
27
28
  return Array.isArray(f) ? (f as string[]) : [];
28
29
  }
29
30
 
30
31
  /**
31
32
  * Whether the identity enforces uniqueness.
32
33
  * Defaults to true; explicit `@unique: false` makes it a non-unique index.
34
+ * ADR-0039: resolving.
33
35
  */
34
36
  get unique(): boolean {
35
- return this.ownAttr(IDENTITY_ATTR_UNIQUE) !== false;
37
+ return this.attr(IDENTITY_ATTR_UNIQUE) !== false;
36
38
  }
37
39
 
38
40
  isPrimary(): boolean {
@@ -58,7 +60,8 @@ export class MetaIdentity extends MetaData {
58
60
  */
59
61
  export class MetaPrimaryIdentity extends MetaIdentity {
60
62
  get generation(): IdentityGeneration | undefined {
61
- const v = this.ownAttr(IDENTITY_ATTR_GENERATION);
63
+ // ADR-0039: resolving — @generation may be inherited via extends.
64
+ const v = this.attr(IDENTITY_ATTR_GENERATION);
62
65
  return typeof v === "string" ? (v as IdentityGeneration) : undefined;
63
66
  }
64
67
  }
@@ -83,7 +86,8 @@ export class MetaSecondaryIdentity extends MetaIdentity {}
83
86
  export class MetaReferenceIdentity extends MetaIdentity {
84
87
  /** Raw `@references` attr value, unparsed. */
85
88
  get referencesRaw(): string | undefined {
86
- const v = this.ownAttr(IDENTITY_REFERENCE_ATTR_REFERENCES);
89
+ // ADR-0039: resolving — @references may be inherited via extends.
90
+ const v = this.attr(IDENTITY_REFERENCE_ATTR_REFERENCES);
87
91
  return typeof v === "string" ? v : undefined;
88
92
  }
89
93
 
@@ -103,7 +107,8 @@ export class MetaReferenceIdentity extends MetaIdentity {
103
107
  * block and projection JOIN inference are unaffected.
104
108
  */
105
109
  get enforce(): boolean {
106
- return this.ownAttr(IDENTITY_REFERENCE_ATTR_ENFORCE) !== false;
110
+ // ADR-0039: resolving — @enforce may be inherited via extends.
111
+ return this.attr(IDENTITY_REFERENCE_ATTR_ENFORCE) !== false;
107
112
  }
108
113
 
109
114
  /**
@@ -114,13 +119,15 @@ export class MetaReferenceIdentity extends MetaIdentity {
114
119
  * declared here too rather than only on a sibling relationship node.
115
120
  */
116
121
  get onDelete(): string | undefined {
117
- const v = this.ownAttr(IDENTITY_REFERENCE_ATTR_ON_DELETE);
122
+ // ADR-0039: resolving — @onDelete may be inherited via extends.
123
+ const v = this.attr(IDENTITY_REFERENCE_ATTR_ON_DELETE);
118
124
  return typeof v === "string" && v !== "" ? v : undefined;
119
125
  }
120
126
 
121
127
  /** Referential action on key update, declared directly on the reference. Undefined when not set. */
122
128
  get onUpdate(): string | undefined {
123
- const v = this.ownAttr(IDENTITY_REFERENCE_ATTR_ON_UPDATE);
129
+ // ADR-0039: resolving — @onUpdate may be inherited via extends.
130
+ const v = this.attr(IDENTITY_REFERENCE_ATTR_ON_UPDATE);
124
131
  return typeof v === "string" && v !== "" ? v : undefined;
125
132
  }
126
133
 
@@ -167,7 +174,8 @@ export class MetaReferenceIdentity extends MetaIdentity {
167
174
  if (!targetObj) return undefined;
168
175
 
169
176
  const primary = targetObj.primaryIdentity();
170
- const fields = primary?.ownAttr(IDENTITY_ATTR_FIELDS) as string | string[] | undefined;
177
+ // ADR-0039: resolving the target's @fields may be inherited via extends.
178
+ const fields = primary?.attr(IDENTITY_ATTR_FIELDS) as string | string[] | undefined;
171
179
  if (typeof fields === "string") return fields.split(",")[0]!.trim();
172
180
  if (Array.isArray(fields) && fields.length > 0) return String(fields[0]).trim();
173
181
  return "id";
@@ -30,6 +30,9 @@ import { IDENTITY_ATTR_FIELDS } from "./identity-constants.js";
30
30
  * undefined when the identity declares no own @fields (the pass-through case).
31
31
  */
32
32
  export function identityOwnFields(identity: MetaData): string[] | undefined {
33
+ // ADR-0039: own — the OWN @fields is read deliberately (paired with
34
+ // identityEffectiveFields below) to detect an explicit author-declared @fields
35
+ // that disagrees with the computed pass-through key.
33
36
  return normalizeFields(identity.ownAttr(IDENTITY_ATTR_FIELDS));
34
37
  }
35
38
 
@@ -92,6 +95,8 @@ export function resolveIdentityPassthrough(
92
95
  continue;
93
96
  }
94
97
  const local = owner
98
+ // ADR-0039: own — a pass-through field must be LOCALLY declared on the
99
+ // projection (it carries the extends ref reaching the entity field).
95
100
  .ownChildren()
96
101
  .find((c) => c.type === TYPE_FIELD && extendsChainReaches(c, entityField));
97
102
  if (local === undefined) {
@@ -134,11 +139,14 @@ function arraysEqual(a: readonly string[], b: readonly string[]): boolean {
134
139
  export function validateIdentityPassthrough(root: MetaData): ParseError[] {
135
140
  const errors: ParseError[] = [];
136
141
 
142
+ // ADR-0039: root has no super; children()==ownChildren() but resolving is the default.
137
143
  for (const obj of root
138
- .ownChildren()
144
+ .children()
139
145
  .filter(
140
146
  (c) => c.type === TYPE_OBJECT && c.subType === OBJECT_SUBTYPE_PROJECTION,
141
147
  )) {
148
+ // ADR-0039: own — validates the projection's OWN-declared identities (the
149
+ // pass-through subjects; an inherited identity was validated on its declarer).
142
150
  for (const identity of obj
143
151
  .ownChildren()
144
152
  .filter((c) => c.type === TYPE_IDENTITY)) {
@@ -71,6 +71,7 @@ export class MetaObject extends MetaData {
71
71
  /** Own fields only — excludes fields inherited via extends. Java parity: getMetaFields(false). */
72
72
  ownFields(): MetaField[] {
73
73
  return this.cached("ownFields", () =>
74
+ // ADR-0039: own-accessor definition — the deliberate own-only API twin of fields().
74
75
  this.ownChildren().filter((c): c is MetaField => c.type === TYPE_FIELD),
75
76
  );
76
77
  }
@@ -85,6 +86,7 @@ export class MetaObject extends MetaData {
85
86
  /** Own identities only — excludes inherited. */
86
87
  ownIdentities(): MetaIdentity[] {
87
88
  return this.cached("ownIdentities", () =>
89
+ // ADR-0039: own-accessor definition — the deliberate own-only API twin of identities().
88
90
  this.ownChildren().filter((c): c is MetaIdentity => c.type === TYPE_IDENTITY),
89
91
  );
90
92
  }
@@ -122,6 +124,7 @@ export class MetaObject extends MetaData {
122
124
  /** Own relationships only — excludes inherited. */
123
125
  ownRelationships(): MetaRelationship[] {
124
126
  return this.cached("ownRelationships", () =>
127
+ // ADR-0039: own-accessor definition — the deliberate own-only API twin of relationships().
125
128
  this.ownChildren().filter((c): c is MetaRelationship => c.type === TYPE_RELATIONSHIP),
126
129
  );
127
130
  }
@@ -136,6 +139,7 @@ export class MetaObject extends MetaData {
136
139
  /** Own validators only — excludes validators inherited via extends. Java parity: getChildren(Class, false). */
137
140
  ownValidators(): MetaValidator[] {
138
141
  return this.cached("ownValidators", () =>
142
+ // ADR-0039: own-accessor definition — the deliberate own-only API twin of validators().
139
143
  this.ownChildren().filter((c): c is MetaValidator => c.type === TYPE_VALIDATOR),
140
144
  );
141
145
  }
@@ -150,6 +154,7 @@ export class MetaObject extends MetaData {
150
154
  /** Own layouts only — excludes inherited. */
151
155
  ownLayouts(): MetaLayout[] {
152
156
  return this.cached("ownLayouts", () =>
157
+ // ADR-0039: own-accessor definition — the deliberate own-only API twin of layouts().
153
158
  this.ownChildren().filter((c): c is MetaLayout => c.type === TYPE_LAYOUT),
154
159
  );
155
160
  }
@@ -40,12 +40,16 @@ const NUMERIC_DISCRIMINATOR_SUBTYPES = new Set<string>([
40
40
  export function validateDiscriminator(root: MetaData): ParseError[] {
41
41
  const errors: ParseError[] = [];
42
42
 
43
+ // ADR-0039: root has no super; children()==ownChildren() but resolving is the default.
43
44
  const entities = root
44
- .ownChildren()
45
+ .children()
45
46
  .filter((c) => c.type === TYPE_OBJECT && c.subType === OBJECT_SUBTYPE_ENTITY);
46
47
 
47
48
  // Pass 1: @discriminator on bases — name resolution (own + inherited fields).
48
49
  for (const obj of entities) {
50
+ // ADR-0039: own — @discriminator is declared on the HIERARCHY ROOT only; reading
51
+ // it own distinguishes a root from a subtype (a subtype inherits it, but here we
52
+ // want the entity that DECLARES it). findDiscriminatorRoot walks up separately.
49
53
  const disc = obj.ownAttr(OBJECT_ATTR_DISCRIMINATOR);
50
54
  if (typeof disc !== "string" || disc === "") continue;
51
55
 
@@ -72,6 +76,8 @@ export function validateDiscriminator(root: MetaData): ParseError[] {
72
76
  const bindingsByRoot = new Map<MetaData, SubtypeBinding[]>();
73
77
 
74
78
  for (const obj of entities) {
79
+ // ADR-0039: own — @discriminatorValue is per-subtype; each concrete entity
80
+ // declares its OWN. Reading own detects THIS subtype's declared value.
75
81
  const value = obj.ownAttr(OBJECT_ATTR_DISCRIMINATOR_VALUE);
76
82
  if (typeof value !== "string" || value === "") continue;
77
83
 
@@ -83,7 +89,9 @@ export function validateDiscriminator(root: MetaData): ParseError[] {
83
89
 
84
90
  // Type-match check.
85
91
  if (field.subType === FIELD_SUBTYPE_ENUM) {
86
- const enumValues = field.ownAttr(FIELD_ATTR_VALUES);
92
+ // ADR-0039: resolving — the discriminator field may inherit @values from an
93
+ // abstract enum via extends.
94
+ const enumValues = field.attr(FIELD_ATTR_VALUES);
87
95
  const list = Array.isArray(enumValues) ? enumValues.map(String) : [];
88
96
  if (!list.includes(value)) {
89
97
  errors.push(
@@ -140,6 +148,8 @@ export function validateDiscriminator(root: MetaData): ParseError[] {
140
148
  // entity that extends a @discriminator-bearing root must declare a value.
141
149
  for (const obj of entities) {
142
150
  if (obj.isAbstract === true) continue;
151
+ // ADR-0039: own — checks whether THIS entity declares its OWN value / its OWN
152
+ // @discriminator (a root). Resolving would inherit a parent's and mis-classify.
143
153
  if (typeof obj.ownAttr(OBJECT_ATTR_DISCRIMINATOR_VALUE) === "string") continue;
144
154
  if (typeof obj.ownAttr(OBJECT_ATTR_DISCRIMINATOR) === "string") continue; // a root, not a subtype
145
155
  const { root: discRoot } = findDiscriminatorRoot(obj);
@@ -160,11 +170,14 @@ export function validateDiscriminator(root: MetaData): ParseError[] {
160
170
  /** Find a field with the given name on `entity` — own first, then via the
161
171
  * resolved extends chain. Returns the declaring field node (own attrs intact). */
162
172
  function findFieldOnEntity(entity: MetaData, name: string): MetaData | undefined {
173
+ // ADR-0039: own — extends-chain walk returning the DECLARING field node (own
174
+ // children at each level), so callers can read that node's own/effective attrs.
163
175
  for (const child of entity.ownChildren()) {
164
176
  if (child.type === TYPE_FIELD && child.name === name) return child;
165
177
  }
166
178
  let cursor = entity.superResolved;
167
179
  while (cursor !== undefined) {
180
+ // ADR-0039: own — super-chain walk reading each level's OWN fields.
168
181
  for (const child of cursor.ownChildren()) {
169
182
  if (child.type === TYPE_FIELD && child.name === name) return child;
170
183
  }
@@ -181,6 +194,8 @@ function findDiscriminatorRoot(
181
194
  ): { root: MetaData | undefined; fieldName: string | undefined } {
182
195
  let cursor: MetaData | undefined = entity;
183
196
  while (cursor !== undefined) {
197
+ // ADR-0039: own — walks up to find the ancestor that DECLARES @discriminator
198
+ // (the hierarchy root); must read own to locate the physical declaration site.
184
199
  const v = cursor.ownAttr(OBJECT_ATTR_DISCRIMINATOR);
185
200
  if (typeof v === "string" && v !== "") {
186
201
  return { root: cursor, fieldName: v };
@@ -1,4 +1,4 @@
1
- import { FIELD_SUBTYPE_UUID, FIELD_SUBTYPE_CURRENCY, FIELD_SUBTYPE_ENUM } from "../field/field-constants.js";
1
+ import { FIELD_SUBTYPE_UUID, FIELD_SUBTYPE_CURRENCY, FIELD_SUBTYPE_ENUM, FIELD_SUBTYPE_URI, FIELD_SUBTYPE_INET } from "../field/field-constants.js";
2
2
 
3
3
  // Query concern constants — filter operators, sort order values.
4
4
  //
@@ -55,6 +55,12 @@ export const OPS_BY_SUBTYPE: Readonly<Record<string, readonly FilterOp[]>> = {
55
55
  // uuid: identity-comparison ops only — no `like` (not free-text) and no
56
56
  // ordering (`gt`/`lt` are meaningless on a UUID).
57
57
  [FIELD_SUBTYPE_UUID]: [FILTER_OP_EQ, FILTER_OP_NE, FILTER_OP_IN, FILTER_OP_IS_NULL],
58
+ // uri: a URI string — free-text-comparable. Same op band as string (prefix
59
+ // matching with `like` is meaningful for URLs).
60
+ [FIELD_SUBTYPE_URI]: [FILTER_OP_EQ, FILTER_OP_NE, FILTER_OP_IN, FILTER_OP_LIKE, FILTER_OP_IS_NULL],
61
+ // inet: an IP address — identity-comparison ops only (no `like`; ordering
62
+ // gt/lt is not exposed). Same op band as uuid.
63
+ [FIELD_SUBTYPE_INET]: [FILTER_OP_EQ, FILTER_OP_NE, FILTER_OP_IN, FILTER_OP_IS_NULL],
58
64
  } as const;
59
65
 
60
66
  export function opsForSubType(subType: string): readonly FilterOp[] {
@@ -13,44 +13,46 @@ import {
13
13
  RELATIONSHIP_ATTR_ON_UPDATE,
14
14
  } from "./relationship-constants.js";
15
15
 
16
+ // ADR-0039: every getter below uses the RESOLVING attr() accessor — a relationship
17
+ // attr may be inherited from an abstract base via extends.
16
18
  export class MetaRelationship extends MetaData {
17
19
  get cardinality(): string | undefined {
18
- const v = this.ownAttr(RELATIONSHIP_ATTR_CARDINALITY);
20
+ const v = this.attr(RELATIONSHIP_ATTR_CARDINALITY);
19
21
  return typeof v === "string" ? v : undefined;
20
22
  }
21
23
 
22
24
  /** FQN of the target object (e.g., "acme::vehicle::Car"). */
23
25
  get objectRef(): string | undefined {
24
- const v = this.ownAttr(RELATIONSHIP_ATTR_OBJECT_REF);
26
+ const v = this.attr(RELATIONSHIP_ATTR_OBJECT_REF);
25
27
  return typeof v === "string" ? v : undefined;
26
28
  }
27
29
 
28
30
  /** Junction (through) entity name for M:N relationships. */
29
31
  get through(): string | undefined {
30
- const v = this.ownAttr(RELATIONSHIP_ATTR_THROUGH);
32
+ const v = this.attr(RELATIONSHIP_ATTR_THROUGH);
31
33
  return typeof v === "string" ? v : undefined;
32
34
  }
33
35
 
34
36
  /** Source-side FK field on the junction (directed self-join disambiguator). */
35
37
  get sourceRefField(): string | undefined {
36
- const v = this.ownAttr(RELATIONSHIP_ATTR_SOURCE_REF_FIELD);
38
+ const v = this.attr(RELATIONSHIP_ATTR_SOURCE_REF_FIELD);
37
39
  return typeof v === "string" ? v : undefined;
38
40
  }
39
41
 
40
42
  /** Whether this M:N relationship is an undirected (symmetric) self-join. */
41
43
  get symmetric(): boolean {
42
- return this.ownAttr(RELATIONSHIP_ATTR_SYMMETRIC) === true;
44
+ return this.attr(RELATIONSHIP_ATTR_SYMMETRIC) === true;
43
45
  }
44
46
 
45
47
  /** Referential action on parent delete. Undefined when not explicitly set (default derives from subtype). */
46
48
  get onDelete(): string | undefined {
47
- const v = this.ownAttr(RELATIONSHIP_ATTR_ON_DELETE);
49
+ const v = this.attr(RELATIONSHIP_ATTR_ON_DELETE);
48
50
  return typeof v === "string" && v !== "" ? v : undefined;
49
51
  }
50
52
 
51
53
  /** Referential action on key update. Undefined when not explicitly set (default: cascade). */
52
54
  get onUpdate(): string | undefined {
53
- const v = this.ownAttr(RELATIONSHIP_ATTR_ON_UPDATE);
55
+ const v = this.attr(RELATIONSHIP_ATTR_ON_UPDATE);
54
56
  return typeof v === "string" && v !== "" ? v : undefined;
55
57
  }
56
58
  }
@@ -19,12 +19,14 @@ export class MetaValidator extends MetaData {
19
19
  * (Pattern moves to MetaRegexValidator; required validators have no extra attrs.)
20
20
  */
21
21
  get min(): number | undefined {
22
- const v = this.ownAttr(VALIDATOR_ATTR_MIN);
22
+ // ADR-0039: resolving — effective bound; a validator may inherit @min via extends.
23
+ const v = this.attr(VALIDATOR_ATTR_MIN);
23
24
  return typeof v === "number" ? v : undefined;
24
25
  }
25
26
 
26
27
  get max(): number | undefined {
27
- const v = this.ownAttr(VALIDATOR_ATTR_MAX);
28
+ // ADR-0039: resolving — effective bound; a validator may inherit @max via extends.
29
+ const v = this.attr(VALIDATOR_ATTR_MAX);
28
30
  return typeof v === "number" ? v : undefined;
29
31
  }
30
32
 
@@ -50,7 +52,8 @@ export class MetaLengthValidator extends MetaValidator {}
50
52
  /** Regex validator: carries the pattern. */
51
53
  export class MetaRegexValidator extends MetaValidator {
52
54
  get pattern(): string | undefined {
53
- const v = this.ownAttr(VALIDATOR_ATTR_PATTERN);
55
+ // ADR-0039: resolving — effective @pattern; a validator may inherit it via extends.
56
+ const v = this.attr(VALIDATOR_ATTR_PATTERN);
54
57
  return typeof v === "string" ? v : undefined;
55
58
  }
56
59
  }
package/src/core-types.ts CHANGED
@@ -266,8 +266,8 @@ function registerCoreTypeDefs(registry: TypeRegistry): void {
266
266
  // childRules EMPTY. The named attrs still enforce strictly via attr-schema-
267
267
  // validate (ERR_UNKNOWN_ATTR); a misplaced STRUCTURAL child is now
268
268
  // ERR_CHILD_NOT_ALLOWED. Attr schemas: base + length/numeric/array read @min/@max
269
- // via this.ownAttr(VALIDATOR_ATTR_MIN/MAX); regex also reads @pattern; required
270
- // has no extra attrs.
269
+ // via this.attr(VALIDATOR_ATTR_MIN/MAX) (ADR-0039 resolving); regex also reads
270
+ // @pattern; required has no extra attrs.
271
271
  const VALIDATOR_FACTORIES: FactoryMap = Object.fromEntries(
272
272
  VALIDATOR_SUBTYPES.map((subType) => [
273
273
  `${TYPE_VALIDATOR}.${subType}`,
@@ -249,6 +249,8 @@ export class MetaDataLoader {
249
249
  */
250
250
  findByName(name: string): MetaData | undefined {
251
251
  this._checkStateForRead();
252
+ // ADR-0039: own — the tree root has no super chain (never `extends`),
253
+ // so its own children ARE its effective children.
252
254
  return this._root!.ownChildByName(name);
253
255
  }
254
256
 
@@ -258,6 +260,7 @@ export class MetaDataLoader {
258
260
  */
259
261
  findByTypeAndName(type: string, name: string): MetaData | undefined {
260
262
  this._checkStateForRead();
263
+ // ADR-0039: own — the tree root has no super chain (never `extends`).
261
264
  return this._root!.ownChildByTypeAndName(type, name);
262
265
  }
263
266
 
@@ -267,6 +270,7 @@ export class MetaDataLoader {
267
270
  */
268
271
  childrenOfType(type: string): MetaData[] {
269
272
  this._checkStateForRead();
273
+ // ADR-0039: own — the tree root has no super chain (never `extends`).
270
274
  return this._root!.ownChildrenOfType(type);
271
275
  }
272
276