@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
|
@@ -36,7 +36,9 @@ export class MetaSource extends MetaData {
|
|
|
36
36
|
* back-compat accessor that reads ONLY the @table slot — callers should
|
|
37
37
|
* use physicalName for the FR-016 four-step rule. */
|
|
38
38
|
get tableName(): string | undefined {
|
|
39
|
-
|
|
39
|
+
// ADR-0039: resolving — a source may be inherited via extends (an entity
|
|
40
|
+
// extending BaseEntity inherits its source.rdb); @table can live on the super.
|
|
41
|
+
const v = this.attr(SOURCE_ATTR_TABLE);
|
|
40
42
|
return typeof v === "string" && v !== "" ? v : undefined;
|
|
41
43
|
}
|
|
42
44
|
|
|
@@ -45,13 +47,15 @@ export class MetaSource extends MetaData {
|
|
|
45
47
|
* `"table"` when omitted (ADR-0007 Rule 3 — per-paradigm default).
|
|
46
48
|
*/
|
|
47
49
|
get effectiveKind(): string {
|
|
48
|
-
|
|
50
|
+
// ADR-0039: resolving — an inherited source's @kind lives on the super node.
|
|
51
|
+
const v = this.attr(SOURCE_ATTR_KIND);
|
|
49
52
|
return typeof v === "string" && v !== "" ? v : DEFAULT_SOURCE_KIND;
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
/** The multi-source role for this source (defaults to "primary" when omitted). */
|
|
53
56
|
get role(): string {
|
|
54
|
-
|
|
57
|
+
// ADR-0039: resolving — an inherited source's @role lives on the super node.
|
|
58
|
+
const v = this.attr(SOURCE_ATTR_ROLE);
|
|
55
59
|
return typeof v === "string" && v !== "" ? v : DEFAULT_SOURCE_ROLE;
|
|
56
60
|
}
|
|
57
61
|
|
|
@@ -85,13 +89,15 @@ export class MetaSource extends MetaData {
|
|
|
85
89
|
// Step 1: kind-matching alias.
|
|
86
90
|
const canonicalAttr = PHYSICAL_NAME_ATTR_BY_KIND.get(kind);
|
|
87
91
|
if (canonicalAttr !== undefined) {
|
|
88
|
-
|
|
92
|
+
// ADR-0039: resolving — an inherited source's physical-name alias lives on the super.
|
|
93
|
+
const v = this.attr(canonicalAttr);
|
|
89
94
|
if (typeof v === "string" && v !== "") return v;
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
// Step 2: legacy @table for non-table kind.
|
|
93
98
|
if (canonicalAttr !== SOURCE_ATTR_TABLE) {
|
|
94
|
-
|
|
99
|
+
// ADR-0039: resolving — inherited @table lives on the super node.
|
|
100
|
+
const legacy = this.attr(SOURCE_ATTR_TABLE);
|
|
95
101
|
if (typeof legacy === "string" && legacy !== "") return legacy;
|
|
96
102
|
}
|
|
97
103
|
|
|
@@ -55,7 +55,8 @@ export function validateSourceParameterRef(root: MetaData): ParseError[] {
|
|
|
55
55
|
// matches via resolutionKey() (these fixtures declare package at metadata.root
|
|
56
56
|
// only, so obj.package is undefined and the file-default must be folded in).
|
|
57
57
|
const objectIndex = new Map<string, MetaData>();
|
|
58
|
-
|
|
58
|
+
// ADR-0039: root has no super; children()==ownChildren() but resolving is the default.
|
|
59
|
+
for (const obj of root.children().filter((c) => c.type === TYPE_OBJECT)) {
|
|
59
60
|
objectIndex.set(obj.name, obj);
|
|
60
61
|
const fqn = obj.package !== undefined && obj.package !== ""
|
|
61
62
|
? `${obj.package}${PACKAGE_SEPARATOR}${obj.name}`
|
|
@@ -64,12 +65,15 @@ export function validateSourceParameterRef(root: MetaData): ParseError[] {
|
|
|
64
65
|
objectIndex.set(obj.resolutionKey(), obj);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
// ADR-0039: root has no super; children()==ownChildren() but resolving is the default.
|
|
69
|
+
for (const obj of root.children().filter((c) => c.type === TYPE_OBJECT)) {
|
|
70
|
+
// ADR-0039: own — declaration-layer source iteration (mirrors validateSourceRoles).
|
|
68
71
|
for (const source of obj.ownChildren().filter(
|
|
69
72
|
(c): c is MetaSource =>
|
|
70
73
|
c.type === TYPE_SOURCE && c.subType === SOURCE_SUBTYPE_RDB && c instanceof MetaSource,
|
|
71
74
|
)) {
|
|
72
|
-
|
|
75
|
+
// ADR-0039: resolving — a source may inherit @parameterRef via extends.
|
|
76
|
+
const ref = source.attr(SOURCE_ATTR_PARAMETER_REF);
|
|
73
77
|
if (typeof ref !== "string" || ref === "") continue;
|
|
74
78
|
|
|
75
79
|
// ERR_PARAMETER_REF_ON_NON_CALLABLE_KIND — checked even before resolution
|
|
@@ -114,11 +118,15 @@ export function validateSourceParameterRef(root: MetaData): ParseError[] {
|
|
|
114
118
|
// with origin.passthrough must have a subtype matching the referenced
|
|
115
119
|
// field. The origin path validation pass checks the from-path resolves;
|
|
116
120
|
// here we just check the subtype alignment.
|
|
117
|
-
|
|
121
|
+
// ADR-0039: resolving — the parameter value-object's fields may be inherited.
|
|
122
|
+
for (const paramField of target.children().filter((c) => c.type === TYPE_FIELD)) {
|
|
123
|
+
// ADR-0039: own — origin.* never inherits (ADR-0029); the origin child and
|
|
124
|
+
// its @from are read own.
|
|
118
125
|
const passthrough = paramField.ownChildren().find(
|
|
119
126
|
(c) => c.type === TYPE_ORIGIN && c.subType === ORIGIN_SUBTYPE_PASSTHROUGH,
|
|
120
127
|
);
|
|
121
128
|
if (passthrough === undefined) continue;
|
|
129
|
+
// ADR-0039: own — origin.* never inherits (ADR-0029).
|
|
122
130
|
const from = passthrough.ownAttr(ORIGIN_PASSTHROUGH_ATTR_FROM);
|
|
123
131
|
if (typeof from !== "string" || from === "") continue;
|
|
124
132
|
const dot = from.indexOf(".");
|
|
@@ -127,7 +135,8 @@ export function validateSourceParameterRef(root: MetaData): ParseError[] {
|
|
|
127
135
|
const targetFieldName = from.slice(dot + 1);
|
|
128
136
|
const targetEntity = objectIndex.get(targetEntityName);
|
|
129
137
|
if (targetEntity === undefined) continue; // origin-paths pass surfaces this
|
|
130
|
-
|
|
138
|
+
// ADR-0039: resolving — the referenced entity's field may be inherited via extends.
|
|
139
|
+
const targetField = targetEntity.children().find(
|
|
131
140
|
(c) => c.type === TYPE_FIELD && c.name === targetFieldName,
|
|
132
141
|
);
|
|
133
142
|
if (targetField === undefined) continue;
|
|
@@ -42,7 +42,11 @@ export function validateSourcePhysicalNames(root: MetaData): PhysicalNameValidat
|
|
|
42
42
|
const errors: ParseError[] = [];
|
|
43
43
|
const warnings: LoaderWarning[] = [];
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
// ADR-0039: root has no super; children()==ownChildren() but resolving is the default.
|
|
46
|
+
for (const obj of root.children().filter((c) => c.type === TYPE_OBJECT)) {
|
|
47
|
+
// ADR-0039: own — validates the physical-name aliases DECLARED on this object's
|
|
48
|
+
// own sources (declaration-layer, mirrors validateSourceRoles); an inherited
|
|
49
|
+
// source's aliases were validated on the object that declares it.
|
|
46
50
|
const sources = obj
|
|
47
51
|
.ownChildren()
|
|
48
52
|
.filter(
|
|
@@ -54,6 +58,9 @@ export function validateSourcePhysicalNames(root: MetaData): PhysicalNameValidat
|
|
|
54
58
|
// Empty-string check first — explicit "" is meaningless and an
|
|
55
59
|
// authoring error regardless of which alias was used.
|
|
56
60
|
for (const attr of ALL_PHYSICAL_NAME_ALIASES) {
|
|
61
|
+
// ADR-0039: own — the "exactly one alias, non-empty" rule is a per-source
|
|
62
|
+
// OWN-declaration constraint (resolving would conflate an inherited alias
|
|
63
|
+
// with an own one and falsely trip ERR_PHYSICAL_NAME_MULTIPLE).
|
|
57
64
|
const v = source.ownAttr(attr);
|
|
58
65
|
if (typeof v === "string" && v === "") {
|
|
59
66
|
errors.push(
|
|
@@ -66,6 +73,7 @@ export function validateSourcePhysicalNames(root: MetaData): PhysicalNameValidat
|
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
const setAliases = ALL_PHYSICAL_NAME_ALIASES.filter((attr) => {
|
|
76
|
+
// ADR-0039: own — per-source own-declaration constraint (see above).
|
|
69
77
|
const v = source.ownAttr(attr);
|
|
70
78
|
return typeof v === "string" && v !== "";
|
|
71
79
|
});
|
|
@@ -23,7 +23,11 @@ import { OBJECT_SUBTYPE_ENTITY } from "../../core/object/object-constants.js";
|
|
|
23
23
|
export function validateSourceRoles(root: MetaData): ParseError[] {
|
|
24
24
|
const errors: ParseError[] = [];
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// ADR-0039: root has no super; children()==ownChildren() but resolving is the default.
|
|
27
|
+
for (const obj of root.children().filter((c) => c.type === TYPE_OBJECT)) {
|
|
28
|
+
// ADR-0039: own — the one-primary rule is a DECLARATION-layer check (cross-port
|
|
29
|
+
// parity: Java uses getSources(false)); it counts sources declared on THIS object,
|
|
30
|
+
// not inherited ones. The role/kind reads below resolve via MetaSource getters.
|
|
27
31
|
const sources = obj
|
|
28
32
|
.ownChildren()
|
|
29
33
|
.filter((c) => c.type === TYPE_SOURCE)
|
|
@@ -18,13 +18,15 @@ import type { SortOrderValue } from "../../core/query/query-constants.js";
|
|
|
18
18
|
export class MetaLayout extends MetaData {
|
|
19
19
|
/** The number of rows per page for the dataGrid layout. */
|
|
20
20
|
get pageSize(): number | undefined {
|
|
21
|
-
|
|
21
|
+
// ADR-0039: resolving — a layout may inherit its grid attrs via extends.
|
|
22
|
+
const v = this.attr(LAYOUT_DATA_GRID_ATTR_PAGE_SIZE);
|
|
22
23
|
return typeof v === "number" ? v : undefined;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/** The field name to sort by default in the dataGrid layout. */
|
|
26
27
|
get defaultSortField(): string | undefined {
|
|
27
|
-
|
|
28
|
+
// ADR-0039: resolving — a layout may inherit its grid attrs via extends.
|
|
29
|
+
const v = this.attr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD);
|
|
28
30
|
return typeof v === "string" ? v : undefined;
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -33,7 +35,8 @@ export class MetaLayout extends MetaData {
|
|
|
33
35
|
* Returns `undefined` when the attr is absent.
|
|
34
36
|
*/
|
|
35
37
|
get defaultSortOrder(): SortOrderValue | undefined {
|
|
36
|
-
|
|
38
|
+
// ADR-0039: resolving — a layout may inherit its grid attrs via extends.
|
|
39
|
+
const v = this.attr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER);
|
|
37
40
|
return typeof v === "string" ? (v as SortOrderValue) : undefined;
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -42,12 +45,14 @@ export class MetaLayout extends MetaData {
|
|
|
42
45
|
* Defaults to `false` when the attr is absent.
|
|
43
46
|
*/
|
|
44
47
|
get filterable(): boolean {
|
|
45
|
-
|
|
48
|
+
// ADR-0039: resolving — a layout may inherit @filterable via extends.
|
|
49
|
+
return this.attr(LAYOUT_DATA_GRID_ATTR_FILTERABLE) === true;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
/** The desugared preset filter object for the dataGrid layout, or undefined. */
|
|
49
53
|
get filter(): Record<string, unknown> | undefined {
|
|
50
|
-
|
|
54
|
+
// ADR-0039: resolving — a layout may inherit its grid attrs via extends.
|
|
55
|
+
const v = this.attr(LAYOUT_DATA_GRID_ATTR_FILTER);
|
|
51
56
|
return typeof v === "object" && v !== null && !Array.isArray(v)
|
|
52
57
|
? (v as Record<string, unknown>)
|
|
53
58
|
: undefined;
|
|
@@ -55,7 +60,8 @@ export class MetaLayout extends MetaData {
|
|
|
55
60
|
|
|
56
61
|
/** The ordered list of field names to display as columns in the dataGrid layout. */
|
|
57
62
|
get columns(): string[] {
|
|
58
|
-
|
|
63
|
+
// ADR-0039: resolving — a layout may inherit its grid attrs via extends.
|
|
64
|
+
const c = this.attr(LAYOUT_DATA_GRID_ATTR_COLUMNS);
|
|
59
65
|
return Array.isArray(c) ? (c as string[]) : [];
|
|
60
66
|
}
|
|
61
67
|
}
|
package/src/registry-manifest.ts
CHANGED
|
@@ -9,12 +9,15 @@
|
|
|
9
9
|
//
|
|
10
10
|
// The IN/OUT boundary is documented in fixtures/registry-conformance/README.md.
|
|
11
11
|
// In short, the manifest emits: type.subType + per-type/per-attr `description`
|
|
12
|
-
// (FR-033) + attrs[{name, valueType, isArray, required,
|
|
13
|
-
// example?, whenToUse?}] + the structural constraint graph
|
|
14
|
-
// cardinality, FR-033) + commonAttrs + defaultSubTypes.
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
12
|
+
// (FR-033) + attrs[{name, valueType, isArray, required, allowedValues?,
|
|
13
|
+
// description, rules?, example?, whenToUse?}] + the structural constraint graph
|
|
14
|
+
// (children / parents / cardinality, FR-033) + commonAttrs + defaultSubTypes.
|
|
15
|
+
// `allowedValues` (ADR-0036 Wave 1, decision 5) is the closed value-set of a
|
|
16
|
+
// closed-enum attr — emitted ONLY when the attr declares one, OMITTED for open /
|
|
17
|
+
// format-validated attrs (@currency, @locale). It byte-gates closed vocabularies
|
|
18
|
+
// cross-port (the gate that catches a value-set silently drifting between ports).
|
|
19
|
+
// EXCLUDED (per-port-physical or not-universally-tracked-on-the-registry):
|
|
20
|
+
// factories/native bindings; AttrSchema.default.
|
|
18
21
|
//
|
|
19
22
|
// FR-033 Task 5 GREW the manifest: it now also emits the documentation surface
|
|
20
23
|
// (every type/attr carries a required, non-empty `description`; optional `rules`/
|
|
@@ -41,6 +44,14 @@ interface ManifestAttr {
|
|
|
41
44
|
/** True for an array-valued attr (a list of the scalar `valueType`); the orthogonal array axis. */
|
|
42
45
|
isArray: boolean;
|
|
43
46
|
required: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The closed value-set of a closed-enum attr (ADR-0036 Wave 1, decision 5).
|
|
49
|
+
* Emitted ONLY when the attr declares a non-empty `allowedValues` set; OMITTED
|
|
50
|
+
* for open / format-validated attrs (e.g. @currency ISO-4217, @locale BCP-47).
|
|
51
|
+
* This byte-gates closed-enum vocabularies cross-port — the gate that catches a
|
|
52
|
+
* value-set drifting between ports (the failure mode the dbColumnType slim hit).
|
|
53
|
+
*/
|
|
54
|
+
allowedValues?: readonly string[];
|
|
44
55
|
/** FR-033 — human/AI-facing description of the attribute (required, non-empty). */
|
|
45
56
|
description: string;
|
|
46
57
|
/** FR-033 — prose documenting the complex rules enforced in code. Emitted only when present. */
|
|
@@ -119,11 +130,18 @@ function toManifestAttr(attr: AttrSchema): ManifestAttr {
|
|
|
119
130
|
// FR-033: the documentation surface (`description` required + non-empty;
|
|
120
131
|
// `rules`/`example`/`whenToUse` emitted ONLY when present) follows the
|
|
121
132
|
// existing facets, preserving key order for byte-stability.
|
|
133
|
+
// The closed value-set, emitted only when present + non-empty (decision 5).
|
|
134
|
+
// AttrValue is string | number | boolean | array; a closed enum is always a set
|
|
135
|
+
// of scalar string members, so stringify each for a stable cross-port surface.
|
|
136
|
+
// Spread BEFORE `description` so the JSON key order is name → valueType →
|
|
137
|
+
// isArray → required → (allowedValues?) → description → (rules?/example?/whenToUse?).
|
|
138
|
+
const hasAllowed = attr.allowedValues !== undefined && attr.allowedValues.length > 0;
|
|
122
139
|
const out: ManifestAttr = {
|
|
123
140
|
name: attr.name,
|
|
124
141
|
valueType,
|
|
125
142
|
isArray,
|
|
126
143
|
required: attr.required,
|
|
144
|
+
...(hasAllowed ? { allowedValues: attr.allowedValues!.map((v) => String(v)) } : {}),
|
|
127
145
|
description: attr.description,
|
|
128
146
|
};
|
|
129
147
|
if (attr.rules !== undefined) out.rules = attr.rules;
|
|
@@ -309,8 +327,10 @@ export function buildRegistryManifest(registry: TypeRegistry): RegistryManifest
|
|
|
309
327
|
* - 2-space indentation (JSON.stringify(_, _, 2)).
|
|
310
328
|
* - Object keys in a fixed order (JSON.stringify preserves insertion order):
|
|
311
329
|
* the manifest is built with `types`, `commonAttrs`, `defaultSubTypes`.
|
|
312
|
-
* - Each attr: `name`, `valueType`, `isArray`, `required`,
|
|
313
|
-
*
|
|
330
|
+
* - Each attr: `name`, `valueType`, `isArray`, `required`, then optional
|
|
331
|
+
* `allowedValues` (omitted unless the attr declares a non-empty closed set —
|
|
332
|
+
* decision 5), then `description`, then optional `rules`, `example`,
|
|
333
|
+
* `whenToUse` (each omitted when absent).
|
|
314
334
|
* - Each type: `type`, `subType`, `description`, then optional `rules`,
|
|
315
335
|
* `example`, `whenToUse` (omitted when absent), then `attrs`, `children`,
|
|
316
336
|
* then optional `parents` (omitted when absent/empty).
|
package/src/serializer-json.ts
CHANGED
|
@@ -122,12 +122,19 @@ function serializeNodeInner(
|
|
|
122
122
|
// (re-parsing would seek a non-existent node to merge into). So it is
|
|
123
123
|
// deliberately NOT serialized.
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
// ADR-0039: effective mode resolves array-ness through the super chain (a
|
|
126
|
+
// concrete field that extends an abstract array field is itself an array);
|
|
127
|
+
// own mode (canonicalSerialize) emits only the authored `isArray` so the
|
|
128
|
+
// round-trip reconstructs the same extends tree.
|
|
129
|
+
const isArrayForMode = effective ? model.resolvedIsArray() : model.isArray === true;
|
|
130
|
+
if (isArrayForMode) {
|
|
126
131
|
obj[RESERVED_KEY_IS_ARRAY] = true;
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
// In effective mode use children()/attrs() (own + inherited via super chain);
|
|
130
135
|
// in own mode use ownChildren()/ownAttrs() (declared on this node only).
|
|
136
|
+
// ADR-0039: own-mode canonical serializer — round-trips the AUTHORED form so
|
|
137
|
+
// re-loading reconstructs the same extends tree (the effective branch resolves).
|
|
131
138
|
const childList = effective ? model.children() : model.ownChildren();
|
|
132
139
|
const attrMap = effective ? model.attrs() : model.ownAttrs();
|
|
133
140
|
|
package/src/shared/meta-data.ts
CHANGED
|
@@ -204,6 +204,32 @@ export abstract class MetaData {
|
|
|
204
204
|
this.isArray = val;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Effective array-ness — the RESOLVING accessor for the native `isArray` flag
|
|
209
|
+
* (ADR-0039). `isArray` is a native boolean property, NOT an attr, so it has no
|
|
210
|
+
* resolving path through attrs()/attr(); a concrete node that `extends` an
|
|
211
|
+
* abstract array node inherits its array-ness only through the super chain.
|
|
212
|
+
* Reading the bare `isArray` field is OWN-ONLY and silently drops inherited
|
|
213
|
+
* array-ness — every codegen/runtime/effective-serializer read of a node's
|
|
214
|
+
* effective array-ness MUST route through this method instead.
|
|
215
|
+
*
|
|
216
|
+
* Returns the node's own `isArray` if set true, else walks the super chain.
|
|
217
|
+
* (Own `true` always wins; a node can only widen to array, never narrow — an
|
|
218
|
+
* abstract array base extended by a concrete node stays an array.)
|
|
219
|
+
*/
|
|
220
|
+
resolvedIsArray(): boolean {
|
|
221
|
+
return this.cached("resolvedIsArray", () => {
|
|
222
|
+
let node: MetaData | undefined = this;
|
|
223
|
+
const visited = new Set<MetaData>();
|
|
224
|
+
while (node !== undefined && !visited.has(node)) {
|
|
225
|
+
if (node.isArray === true) return true;
|
|
226
|
+
visited.add(node);
|
|
227
|
+
node = node._superData;
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
207
233
|
// ---------------------------------------------------------------------------
|
|
208
234
|
// dataType
|
|
209
235
|
// ---------------------------------------------------------------------------
|
|
@@ -383,21 +409,25 @@ export abstract class MetaData {
|
|
|
383
409
|
|
|
384
410
|
/** Own children whose type matches — excludes inherited. */
|
|
385
411
|
ownChildrenOfType(type: string): MetaData[] {
|
|
412
|
+
// ADR-0039: own-accessor definition — delegates to ownChildren() by contract.
|
|
386
413
|
return this.ownChildren().filter((c) => c.type === type);
|
|
387
414
|
}
|
|
388
415
|
|
|
389
416
|
/** Own children matching both type and subType — excludes inherited. */
|
|
390
417
|
ownChildrenOfSubType(type: string, subType: string): MetaData[] {
|
|
418
|
+
// ADR-0039: own-accessor definition — delegates to ownChildren() by contract.
|
|
391
419
|
return this.ownChildren().filter((c) => c.type === type && c.subType === subType);
|
|
392
420
|
}
|
|
393
421
|
|
|
394
422
|
/** First own child with matching name, or undefined — excludes inherited. */
|
|
395
423
|
ownChildByName(name: string): MetaData | undefined {
|
|
424
|
+
// ADR-0039: own-accessor definition — delegates to ownChildren() by contract.
|
|
396
425
|
return this.ownChildren().find((c) => c.name === name);
|
|
397
426
|
}
|
|
398
427
|
|
|
399
428
|
/** First own child matching both type and name, or undefined — excludes inherited. */
|
|
400
429
|
ownChildByTypeAndName(type: string, name: string): MetaData | undefined {
|
|
430
|
+
// ADR-0039: own-accessor definition — delegates to ownChildren() by contract.
|
|
401
431
|
return this.ownChildren().find((c) => c.type === type && c.name === name);
|
|
402
432
|
}
|
|
403
433
|
|
package/src/shared/meta-root.ts
CHANGED
|
@@ -12,6 +12,8 @@ export class MetaRoot extends MetaData {
|
|
|
12
12
|
/** Object entities defined at this root level. */
|
|
13
13
|
objects(): MetaObject[] {
|
|
14
14
|
return this.cached("objects", () =>
|
|
15
|
+
// ADR-0039: own — the metadata root has no super chain (it never `extends`),
|
|
16
|
+
// so own children ARE its effective children.
|
|
15
17
|
this.ownChildren().filter((c): c is MetaObject => c.type === TYPE_OBJECT),
|
|
16
18
|
);
|
|
17
19
|
}
|
|
@@ -19,6 +21,7 @@ export class MetaRoot extends MetaData {
|
|
|
19
21
|
/** Abstract / package-level fields defined at root (rare; e.g. shared id fields). */
|
|
20
22
|
fields(): MetaField[] {
|
|
21
23
|
return this.cached("fields", () =>
|
|
24
|
+
// ADR-0039: own — the metadata root has no super chain (it never `extends`).
|
|
22
25
|
this.ownChildren().filter((c): c is MetaField => c.type === TYPE_FIELD),
|
|
23
26
|
);
|
|
24
27
|
}
|
|
@@ -26,6 +29,7 @@ export class MetaRoot extends MetaData {
|
|
|
26
29
|
/** Find an object by name. */
|
|
27
30
|
findObject(name: string): MetaObject | undefined {
|
|
28
31
|
return this.cached(`findObject:${name}`, () => {
|
|
32
|
+
// ADR-0039: own — the metadata root has no super chain (it never `extends`).
|
|
29
33
|
const child = this.ownChildByTypeAndName(TYPE_OBJECT, name);
|
|
30
34
|
return child !== undefined ? (child as MetaObject) : undefined;
|
|
31
35
|
});
|
package/src/subtype-rules.ts
CHANGED
|
@@ -78,6 +78,7 @@ function walk(model: MetaData, errors: ParseError[], warnings: string[]): void {
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
// ADR-0039: own — structural walk visiting every physical node once at its site.
|
|
81
82
|
for (const child of model.ownChildren()) {
|
|
82
83
|
walk(child, errors, warnings);
|
|
83
84
|
}
|
|
@@ -151,9 +152,9 @@ function validateProjectionLicensing(
|
|
|
151
152
|
);
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
// OWN sources only: an inherited source is validated on the
|
|
155
|
-
// object that declares it; an inherited source from a non-projection
|
|
156
|
-
// is unreachable without first tripping the extends rule above.
|
|
155
|
+
// ADR-0039: own — OWN sources only: an inherited source is validated on the
|
|
156
|
+
// (projection) object that declares it; an inherited source from a non-projection
|
|
157
|
+
// super is unreachable without first tripping the extends rule above.
|
|
157
158
|
for (const child of model.ownChildren()) {
|
|
158
159
|
if (child.type !== TYPE_SOURCE) continue;
|
|
159
160
|
const kind =
|
package/src/super-resolve.ts
CHANGED
|
@@ -49,6 +49,8 @@ function findInTree(root: MetaData, fqn: string): MetaData | undefined {
|
|
|
49
49
|
if (root.package === undefined && root.name !== "" && root.resolutionKey() === fqn) {
|
|
50
50
|
return root;
|
|
51
51
|
}
|
|
52
|
+
// ADR-0039: own — super-resolution walk over the PHYSICAL declaration tree;
|
|
53
|
+
// resolving accessors would be circular while the super chain is being wired.
|
|
52
54
|
for (const child of root.ownChildren()) {
|
|
53
55
|
const found = findInTree(child, fqn);
|
|
54
56
|
if (found !== undefined) return found;
|
|
@@ -266,6 +268,7 @@ export function resolveDeferredSupers(root: MetaData): DeferredSuperFailure[] {
|
|
|
266
268
|
|
|
267
269
|
function walk(node: MetaData, visit: (n: MetaData) => void): void {
|
|
268
270
|
visit(node);
|
|
271
|
+
// ADR-0039: own — super-resolution walk over the PHYSICAL declaration tree.
|
|
269
272
|
for (const child of node.ownChildren()) {
|
|
270
273
|
walk(child, visit);
|
|
271
274
|
}
|
|
@@ -16,6 +16,9 @@ export function validateMaxOccurs(root: MetaData, registry: TypeRegistry): Parse
|
|
|
16
16
|
|
|
17
17
|
function walk(node: MetaData, registry: TypeRegistry, errors: ParseError[]): void {
|
|
18
18
|
const counts = new Map<string, MetaData[]>();
|
|
19
|
+
// ADR-0039: own — maxOccurs constrains the AUTHORED declaration layer (how many
|
|
20
|
+
// children a node may DECLARE); inherited children were counted at their
|
|
21
|
+
// declaring parent, so only own children count against this node's limit.
|
|
19
22
|
for (const child of node.ownChildren()) {
|
|
20
23
|
const key = `${child.type}.${child.subType}`;
|
|
21
24
|
const list = counts.get(key);
|
|
@@ -35,5 +38,7 @@ function walk(node: MetaData, registry: TypeRegistry, errors: ParseError[]): voi
|
|
|
35
38
|
);
|
|
36
39
|
}
|
|
37
40
|
}
|
|
41
|
+
// ADR-0039: own — structural walk over the physical declaration tree (each
|
|
42
|
+
// declared node is visited once at its declaration site).
|
|
38
43
|
for (const child of node.ownChildren()) walk(child, registry, errors);
|
|
39
44
|
}
|