@metaobjectsdev/metadata 0.14.2 → 0.15.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.
- package/dist/attr-schema-validate.js +22 -1
- package/dist/attr-schema-validate.js.map +1 -1
- package/dist/core/attr/meta-attr.d.ts.map +1 -1
- package/dist/core/attr/meta-attr.js +2 -0
- package/dist/core/attr/meta-attr.js.map +1 -1
- package/dist/core/field/field-constants.d.ts +26 -1
- package/dist/core/field/field-constants.d.ts.map +1 -1
- package/dist/core/field/field-constants.js +29 -0
- package/dist/core/field/field-constants.js.map +1 -1
- package/dist/core/field/field-definition.embedded.d.ts.map +1 -1
- package/dist/core/field/field-definition.embedded.js +28 -0
- package/dist/core/field/field-definition.embedded.js.map +1 -1
- package/dist/core/field/meta-field.d.ts +12 -3
- package/dist/core/field/meta-field.d.ts.map +1 -1
- package/dist/core/field/meta-field.js +33 -15
- package/dist/core/field/meta-field.js.map +1 -1
- package/dist/core/field/validate-field-readonly.d.ts.map +1 -1
- package/dist/core/field/validate-field-readonly.js +15 -3
- package/dist/core/field/validate-field-readonly.js.map +1 -1
- package/dist/core/identity/meta-identity.d.ts +2 -0
- package/dist/core/identity/meta-identity.d.ts.map +1 -1
- package/dist/core/identity/meta-identity.js +16 -8
- package/dist/core/identity/meta-identity.js.map +1 -1
- package/dist/core/identity/validate-identity-passthrough.d.ts.map +1 -1
- package/dist/core/identity/validate-identity-passthrough.js +9 -1
- package/dist/core/identity/validate-identity-passthrough.js.map +1 -1
- package/dist/core/object/meta-object.d.ts.map +1 -1
- package/dist/core/object/meta-object.js +15 -5
- package/dist/core/object/meta-object.js.map +1 -1
- package/dist/core/object/validate-discriminator.d.ts.map +1 -1
- package/dist/core/object/validate-discriminator.js +17 -2
- package/dist/core/object/validate-discriminator.js.map +1 -1
- package/dist/core/query/query-constants.d.ts.map +1 -1
- package/dist/core/query/query-constants.js +7 -1
- package/dist/core/query/query-constants.js.map +1 -1
- package/dist/core/relationship/meta-relationship.d.ts.map +1 -1
- package/dist/core/relationship/meta-relationship.js +9 -7
- package/dist/core/relationship/meta-relationship.js.map +1 -1
- package/dist/core/validator/meta-validator.d.ts.map +1 -1
- package/dist/core/validator/meta-validator.js +6 -3
- package/dist/core/validator/meta-validator.js.map +1 -1
- package/dist/core-types.js +2 -2
- package/dist/core-types.js.map +1 -1
- package/dist/loader/meta-data-loader.d.ts.map +1 -1
- package/dist/loader/meta-data-loader.js +4 -0
- package/dist/loader/meta-data-loader.js.map +1 -1
- package/dist/loader/validation-passes.d.ts.map +1 -1
- package/dist/loader/validation-passes.js +97 -39
- package/dist/loader/validation-passes.js.map +1 -1
- package/dist/loader/validation-registry.d.ts.map +1 -1
- package/dist/loader/validation-registry.js +7 -2
- package/dist/loader/validation-registry.js.map +1 -1
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +6 -3
- package/dist/naming.js.map +1 -1
- package/dist/object-serializer.d.ts.map +1 -1
- package/dist/object-serializer.js +6 -2
- package/dist/object-serializer.js.map +1 -1
- package/dist/parser-core.js +5 -0
- package/dist/parser-core.js.map +1 -1
- package/dist/persistence/db/db-constants.d.ts +20 -9
- package/dist/persistence/db/db-constants.d.ts.map +1 -1
- package/dist/persistence/db/db-constants.js +20 -15
- package/dist/persistence/db/db-constants.js.map +1 -1
- package/dist/persistence/db/db-definition.embedded.d.ts.map +1 -1
- package/dist/persistence/db/db-definition.embedded.js +19 -1
- package/dist/persistence/db/db-definition.embedded.js.map +1 -1
- package/dist/persistence/origin/meta-origin.d.ts.map +1 -1
- package/dist/persistence/origin/meta-origin.js +6 -0
- package/dist/persistence/origin/meta-origin.js.map +1 -1
- package/dist/persistence/source/meta-source.d.ts.map +1 -1
- package/dist/persistence/source/meta-source.js +11 -5
- package/dist/persistence/source/meta-source.js.map +1 -1
- package/dist/persistence/source/validate-source-parameter-ref.d.ts.map +1 -1
- package/dist/persistence/source/validate-source-parameter-ref.js +14 -5
- package/dist/persistence/source/validate-source-parameter-ref.js.map +1 -1
- package/dist/persistence/source/validate-source-physical-names.d.ts.map +1 -1
- package/dist/persistence/source/validate-source-physical-names.js +9 -1
- package/dist/persistence/source/validate-source-physical-names.js.map +1 -1
- package/dist/persistence/source/validate-source-roles.d.ts.map +1 -1
- package/dist/persistence/source/validate-source-roles.js +5 -1
- package/dist/persistence/source/validate-source-roles.js.map +1 -1
- package/dist/presentation/layout/meta-layout.d.ts.map +1 -1
- package/dist/presentation/layout/meta-layout.js +12 -6
- package/dist/presentation/layout/meta-layout.js.map +1 -1
- package/dist/registry-manifest.d.ts +12 -2
- package/dist/registry-manifest.d.ts.map +1 -1
- package/dist/registry-manifest.js +20 -8
- package/dist/registry-manifest.js.map +1 -1
- package/dist/serializer-json.d.ts.map +1 -1
- package/dist/serializer-json.js +8 -1
- package/dist/serializer-json.js.map +1 -1
- package/dist/shared/meta-data.d.ts +14 -0
- package/dist/shared/meta-data.d.ts.map +1 -1
- package/dist/shared/meta-data.js +30 -0
- package/dist/shared/meta-data.js.map +1 -1
- package/dist/shared/meta-root.d.ts.map +1 -1
- package/dist/shared/meta-root.js +8 -2
- package/dist/shared/meta-root.js.map +1 -1
- package/dist/subtype-rules.js +4 -3
- package/dist/subtype-rules.js.map +1 -1
- package/dist/super-resolve.d.ts.map +1 -1
- package/dist/super-resolve.js +3 -0
- package/dist/super-resolve.js.map +1 -1
- package/dist/validate-max-occurs.js +5 -0
- package/dist/validate-max-occurs.js.map +1 -1
- package/package.json +1 -1
- package/src/attr-schema-validate.ts +24 -1
- package/src/core/attr/meta-attr.ts +2 -0
- package/src/core/field/field-constants.ts +34 -0
- package/src/core/field/field-definition.embedded.ts +28 -0
- package/src/core/field/meta-field.ts +30 -12
- package/src/core/field/validate-field-readonly.ts +15 -3
- package/src/core/identity/meta-identity.ts +16 -8
- package/src/core/identity/validate-identity-passthrough.ts +9 -1
- package/src/core/object/meta-object.ts +5 -0
- package/src/core/object/validate-discriminator.ts +17 -2
- package/src/core/query/query-constants.ts +7 -1
- package/src/core/relationship/meta-relationship.ts +9 -7
- package/src/core/validator/meta-validator.ts +6 -3
- package/src/core-types.ts +2 -2
- package/src/loader/meta-data-loader.ts +4 -0
- package/src/loader/validation-passes.ts +97 -39
- package/src/loader/validation-registry.ts +7 -2
- package/src/naming.ts +6 -3
- package/src/object-serializer.ts +6 -2
- package/src/parser-core.ts +5 -0
- package/src/persistence/db/db-constants.ts +20 -15
- package/src/persistence/db/db-definition.embedded.ts +19 -1
- package/src/persistence/origin/meta-origin.ts +6 -0
- package/src/persistence/source/meta-source.ts +11 -5
- package/src/persistence/source/validate-source-parameter-ref.ts +14 -5
- package/src/persistence/source/validate-source-physical-names.ts +9 -1
- package/src/persistence/source/validate-source-roles.ts +5 -1
- package/src/presentation/layout/meta-layout.ts +12 -6
- package/src/registry-manifest.ts +28 -8
- package/src/serializer-json.ts +8 -1
- package/src/shared/meta-data.ts +30 -0
- package/src/shared/meta-root.ts +4 -0
- package/src/subtype-rules.ts +4 -3
- package/src/super-resolve.ts +3 -0
- 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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
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
|
-
.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|