@metaobjectsdev/metadata 1.0.13 → 1.1.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/README.md +2 -0
- package/dist/attr-schema-validate.d.ts.map +1 -1
- package/dist/attr-schema-validate.js +9 -12
- package/dist/attr-schema-validate.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/core/attr/meta-attr-filter.d.ts.map +1 -1
- package/dist/core/attr/meta-attr-filter.js +8 -2
- package/dist/core/attr/meta-attr-filter.js.map +1 -1
- package/dist/core/attr/meta-attr.d.ts +14 -0
- package/dist/core/attr/meta-attr.d.ts.map +1 -1
- package/dist/core/attr/meta-attr.js +23 -1
- package/dist/core/attr/meta-attr.js.map +1 -1
- package/dist/core/field/shared-enum.d.ts +21 -0
- package/dist/core/field/shared-enum.d.ts.map +1 -0
- package/dist/core/field/shared-enum.js +49 -0
- package/dist/core/field/shared-enum.js.map +1 -0
- package/dist/core/identity/meta-identity.d.ts +1 -1
- package/dist/core/identity/meta-identity.d.ts.map +1 -1
- package/dist/core/identity/meta-identity.js +8 -13
- package/dist/core/identity/meta-identity.js.map +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/object/object-constants.d.ts +14 -1
- package/dist/core/object/object-constants.d.ts.map +1 -1
- package/dist/core/object/object-constants.js +18 -0
- package/dist/core/object/object-constants.js.map +1 -1
- package/dist/core/object/object-definition.embedded.d.ts.map +1 -1
- package/dist/core/object/object-definition.embedded.js +80 -0
- package/dist/core/object/object-definition.embedded.js.map +1 -1
- package/dist/core/relationship/derive-m2m-fields.d.ts +1 -1
- package/dist/core/relationship/derive-m2m-fields.d.ts.map +1 -1
- package/dist/core/relationship/derive-m2m-fields.js +15 -44
- package/dist/core/relationship/derive-m2m-fields.js.map +1 -1
- package/dist/core/relationship/find-reference.d.ts.map +1 -1
- package/dist/core/relationship/find-reference.js +4 -2
- package/dist/core/relationship/find-reference.js.map +1 -1
- package/dist/core/relationship/resolve-relationship-reference.d.ts +6 -5
- package/dist/core/relationship/resolve-relationship-reference.d.ts.map +1 -1
- package/dist/core/relationship/resolve-relationship-reference.js +9 -7
- package/dist/core/relationship/resolve-relationship-reference.js.map +1 -1
- package/dist/core/reporting/meta-dimension.d.ts +13 -0
- package/dist/core/reporting/meta-dimension.d.ts.map +1 -0
- package/dist/core/reporting/meta-dimension.js +30 -0
- package/dist/core/reporting/meta-dimension.js.map +1 -0
- package/dist/core/reporting/meta-measure.d.ts +24 -0
- package/dist/core/reporting/meta-measure.d.ts.map +1 -0
- package/dist/core/reporting/meta-measure.js +54 -0
- package/dist/core/reporting/meta-measure.js.map +1 -0
- package/dist/core/reporting/meta-segment.d.ts +6 -0
- package/dist/core/reporting/meta-segment.d.ts.map +1 -0
- package/dist/core/reporting/meta-segment.js +13 -0
- package/dist/core/reporting/meta-segment.js.map +1 -0
- package/dist/core/reporting/report-accessors.d.ts +27 -0
- package/dist/core/reporting/report-accessors.d.ts.map +1 -0
- package/dist/core/reporting/report-accessors.js +56 -0
- package/dist/core/reporting/report-accessors.js.map +1 -0
- package/dist/core/reporting/report-describe.d.ts +59 -0
- package/dist/core/reporting/report-describe.d.ts.map +1 -0
- package/dist/core/reporting/report-describe.js +182 -0
- package/dist/core/reporting/report-describe.js.map +1 -0
- package/dist/core/reporting/report-read-model.d.ts +34 -0
- package/dist/core/reporting/report-read-model.d.ts.map +1 -0
- package/dist/core/reporting/report-read-model.js +165 -0
- package/dist/core/reporting/report-read-model.js.map +1 -0
- package/dist/core/reporting/report-shape.d.ts +103 -0
- package/dist/core/reporting/report-shape.d.ts.map +1 -0
- package/dist/core/reporting/report-shape.js +398 -0
- package/dist/core/reporting/report-shape.js.map +1 -0
- package/dist/core/reporting/reporting-constants.d.ts +65 -0
- package/dist/core/reporting/reporting-constants.d.ts.map +1 -0
- package/dist/core/reporting/reporting-constants.js +84 -0
- package/dist/core/reporting/reporting-constants.js.map +1 -0
- package/dist/core/reporting/reporting-definition.embedded.d.ts +3 -0
- package/dist/core/reporting/reporting-definition.embedded.d.ts.map +1 -0
- package/dist/core/reporting/reporting-definition.embedded.js +185 -0
- package/dist/core/reporting/reporting-definition.embedded.js.map +1 -0
- package/dist/core/requirement/resolve-claim.d.ts +8 -0
- package/dist/core/requirement/resolve-claim.d.ts.map +1 -1
- package/dist/core/requirement/resolve-claim.js +21 -0
- package/dist/core/requirement/resolve-claim.js.map +1 -1
- package/dist/core/yaml-desugar.d.ts.map +1 -1
- package/dist/core/yaml-desugar.js +12 -82
- package/dist/core/yaml-desugar.js.map +1 -1
- package/dist/core-types.d.ts.map +1 -1
- package/dist/core-types.js +28 -1
- package/dist/core-types.js.map +1 -1
- package/dist/docs-ref.d.ts +19 -0
- package/dist/docs-ref.d.ts.map +1 -0
- package/dist/docs-ref.js +37 -0
- package/dist/docs-ref.js.map +1 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +17 -6
- package/dist/errors.js.map +1 -1
- package/dist/fmt.d.ts.map +1 -1
- package/dist/fmt.js +3 -1
- package/dist/fmt.js.map +1 -1
- package/dist/index.d.ts +15 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/dist/loader/declared-duplicate-fields.d.ts +19 -0
- package/dist/loader/declared-duplicate-fields.d.ts.map +1 -0
- package/dist/loader/declared-duplicate-fields.js +97 -0
- package/dist/loader/declared-duplicate-fields.js.map +1 -0
- package/dist/loader/meta-data-loader.d.ts.map +1 -1
- package/dist/loader/meta-data-loader.js +18 -1
- package/dist/loader/meta-data-loader.js.map +1 -1
- package/dist/loader/reporting-validation.d.ts +11 -0
- package/dist/loader/reporting-validation.d.ts.map +1 -0
- package/dist/loader/reporting-validation.js +883 -0
- package/dist/loader/reporting-validation.js.map +1 -0
- package/dist/loader/resolve-references.d.ts +8 -0
- package/dist/loader/resolve-references.d.ts.map +1 -0
- package/dist/loader/resolve-references.js +132 -0
- package/dist/loader/resolve-references.js.map +1 -0
- package/dist/loader/validation-passes.d.ts.map +1 -1
- package/dist/loader/validation-passes.js +14 -9
- 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 +33 -10
- package/dist/loader/validation-registry.js.map +1 -1
- package/dist/metamodel-docs/index.js +3 -3
- package/dist/metamodel-docs/index.js.map +1 -1
- package/dist/metamodel-docs/render.js +4 -4
- package/dist/metamodel-docs/render.js.map +1 -1
- package/dist/naming-refs.d.ts +102 -50
- package/dist/naming-refs.d.ts.map +1 -1
- package/dist/naming-refs.js +223 -97
- package/dist/naming-refs.js.map +1 -1
- package/dist/naming.d.ts +42 -7
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +43 -5
- package/dist/naming.js.map +1 -1
- package/dist/object-serializer.d.ts.map +1 -1
- package/dist/object-serializer.js +6 -9
- package/dist/object-serializer.js.map +1 -1
- package/dist/parser-core.d.ts.map +1 -1
- package/dist/parser-core.js +18 -48
- package/dist/parser-core.js.map +1 -1
- package/dist/persistence/db/db-definition.embedded.js +2 -2
- package/dist/persistence/db/db-definition.embedded.js.map +1 -1
- package/dist/persistence/source/meta-source.d.ts +5 -3
- package/dist/persistence/source/meta-source.d.ts.map +1 -1
- package/dist/persistence/source/meta-source.js +8 -6
- package/dist/persistence/source/meta-source.js.map +1 -1
- package/dist/registry-manifest-exclusions.js +2 -2
- package/dist/registry-manifest-exclusions.js.map +1 -1
- package/dist/registry-manifest.d.ts +1 -1
- package/dist/registry-manifest.js +1 -1
- package/dist/release-docs.d.ts +11 -0
- package/dist/release-docs.d.ts.map +1 -0
- package/dist/release-docs.js +48 -0
- package/dist/release-docs.js.map +1 -0
- package/dist/serializer-json.d.ts +15 -1
- package/dist/serializer-json.d.ts.map +1 -1
- package/dist/serializer-json.js +55 -17
- package/dist/serializer-json.js.map +1 -1
- package/dist/shared/base-types.d.ts +7 -1
- package/dist/shared/base-types.d.ts.map +1 -1
- package/dist/shared/base-types.js +9 -0
- package/dist/shared/base-types.js.map +1 -1
- package/dist/shared/meta-data.d.ts +10 -0
- package/dist/shared/meta-data.d.ts.map +1 -1
- package/dist/shared/meta-data.js +22 -1
- package/dist/shared/meta-data.js.map +1 -1
- package/dist/shared/meta-root.d.ts +13 -1
- package/dist/shared/meta-root.d.ts.map +1 -1
- package/dist/shared/meta-root.js +19 -1
- package/dist/shared/meta-root.js.map +1 -1
- package/dist/super-resolve.d.ts +4 -1
- package/dist/super-resolve.d.ts.map +1 -1
- package/dist/super-resolve.js +44 -65
- package/dist/super-resolve.js.map +1 -1
- package/dist/vocabulary-catalog.js +2 -2
- package/dist/vocabulary-catalog.js.map +1 -1
- package/package.json +6 -1
- package/src/attr-schema-validate.ts +9 -13
- package/src/constants.ts +1 -0
- package/src/core/attr/meta-attr-filter.ts +8 -1
- package/src/core/attr/meta-attr.ts +24 -1
- package/src/core/field/shared-enum.ts +53 -0
- package/src/core/identity/meta-identity.ts +9 -12
- package/src/core/index.ts +5 -0
- package/src/core/object/object-constants.ts +19 -0
- package/src/core/object/object-definition.embedded.ts +80 -0
- package/src/core/relationship/derive-m2m-fields.ts +15 -48
- package/src/core/relationship/find-reference.ts +4 -2
- package/src/core/relationship/resolve-relationship-reference.ts +11 -9
- package/src/core/reporting/meta-dimension.ts +41 -0
- package/src/core/reporting/meta-measure.ts +75 -0
- package/src/core/reporting/meta-segment.ts +14 -0
- package/src/core/reporting/report-accessors.ts +73 -0
- package/src/core/reporting/report-describe.ts +206 -0
- package/src/core/reporting/report-read-model.ts +177 -0
- package/src/core/reporting/report-shape.ts +493 -0
- package/src/core/reporting/reporting-constants.ts +104 -0
- package/src/core/reporting/reporting-definition.embedded.ts +192 -0
- package/src/core/requirement/resolve-claim.ts +20 -0
- package/src/core/yaml-desugar.ts +9 -89
- package/src/core-types.ts +41 -0
- package/src/docs-ref.ts +41 -0
- package/src/errors.ts +17 -6
- package/src/fmt.ts +3 -1
- package/src/index.ts +72 -4
- package/src/loader/declared-duplicate-fields.ts +114 -0
- package/src/loader/meta-data-loader.ts +25 -1
- package/src/loader/reporting-validation.ts +1137 -0
- package/src/loader/resolve-references.ts +144 -0
- package/src/loader/validation-passes.ts +13 -9
- package/src/loader/validation-registry.ts +37 -9
- package/src/metamodel-docs/index.ts +3 -3
- package/src/metamodel-docs/render.ts +4 -4
- package/src/naming-refs.ts +237 -94
- package/src/naming.ts +75 -11
- package/src/object-serializer.ts +7 -9
- package/src/parser-core.ts +19 -56
- package/src/persistence/db/db-definition.embedded.ts +2 -2
- package/src/persistence/source/meta-source.ts +8 -6
- package/src/registry-manifest-exclusions.ts +2 -2
- package/src/registry-manifest.ts +1 -1
- package/src/release-docs.ts +48 -0
- package/src/serializer-json.ts +79 -12
- package/src/shared/base-types.ts +9 -0
- package/src/shared/meta-data.ts +22 -1
- package/src/shared/meta-root.ts +20 -1
- package/src/super-resolve.ts +49 -63
- package/src/vocabulary-catalog.ts +2 -2
package/src/parser-core.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
extendsTargetCompatible,
|
|
40
40
|
EXTENDS_TARGET_MISMATCH_RULE,
|
|
41
41
|
} from "./super-resolve.js";
|
|
42
|
+
import { RefOverDropError } from "./naming-refs.js";
|
|
42
43
|
import { JsonPathBuilder, type Segment as JsonPathSegment } from "./json-path.js";
|
|
43
44
|
import { getYamlPosition, type YamlPosition } from "./core/yaml-positions.js";
|
|
44
45
|
import {
|
|
@@ -66,7 +67,6 @@ import {
|
|
|
66
67
|
import { ATTR_SUBTYPE_PROPERTIES, ATTR_SUBTYPE_STRINGARRAY } from "./core/attr/attr-constants.js";
|
|
67
68
|
import { attrClassFor } from "./attr-class-map.js";
|
|
68
69
|
import type { AttrValue } from "./shared/meta-data.js";
|
|
69
|
-
import { isRelativeRef, REF_BEARING_ATTR_NAMES } from "./naming-refs.js";
|
|
70
70
|
|
|
71
71
|
// ---------------------------------------------------------------------------
|
|
72
72
|
// Public API
|
|
@@ -234,44 +234,6 @@ function reportProblem(
|
|
|
234
234
|
warnings.push(msg);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
// ---------------------------------------------------------------------------
|
|
238
|
-
// FR-032 (ADR-0032) — canonical-JSON ref guard.
|
|
239
|
-
//
|
|
240
|
-
// Canonical JSON is the self-contained interchange form: every ref-bearing attr
|
|
241
|
-
// MUST be fully-qualified. A relative authoring form (leading `::` or `..::`)
|
|
242
|
-
// surviving into canonical JSON is `ERR_RELATIVE_REF_IN_CANONICAL`. The guard
|
|
243
|
-
// fires ONLY for JSON-format input — YAML-format input has already been
|
|
244
|
-
// desugar-expanded via expandRef (so any `::`/`..::` there is correct authoring
|
|
245
|
-
// that was lowered to FQN before buildTree sees it). Like ERR_RESERVED_ATTR,
|
|
246
|
-
// this is a hard error routed through the loader's error sink even in lax mode.
|
|
247
|
-
// ---------------------------------------------------------------------------
|
|
248
|
-
|
|
249
|
-
function guardRelativeRefInCanonical(
|
|
250
|
-
refLabel: string,
|
|
251
|
-
rawValue: unknown,
|
|
252
|
-
strict: boolean,
|
|
253
|
-
warnings: string[],
|
|
254
|
-
path: string,
|
|
255
|
-
): void {
|
|
256
|
-
if (_currentFormat !== "json") return;
|
|
257
|
-
if (typeof rawValue !== "string") return;
|
|
258
|
-
if (!isRelativeRef(rawValue)) return;
|
|
259
|
-
const msg =
|
|
260
|
-
`Relative reference '${rawValue}' on ${refLabel} at ${path} is not allowed in ` +
|
|
261
|
-
`canonical JSON — canonical JSON must be fully-qualified. Relative forms ` +
|
|
262
|
-
`(leading '::' or '..::') are YAML-authoring sugar that the desugar expands.`;
|
|
263
|
-
if (strict) {
|
|
264
|
-
throw new ParseError(msg, { code: "ERR_RELATIVE_REF_IN_CANONICAL", source: errSource() });
|
|
265
|
-
}
|
|
266
|
-
if (_currentErrors !== undefined) {
|
|
267
|
-
_currentErrors.push(
|
|
268
|
-
new ParseError(msg, { code: "ERR_RELATIVE_REF_IN_CANONICAL", source: errSource() }),
|
|
269
|
-
);
|
|
270
|
-
} else {
|
|
271
|
-
warnings.push(msg);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
237
|
// ---------------------------------------------------------------------------
|
|
276
238
|
// The one message for an authored `<type>.base`, so both doors say the same thing.
|
|
277
239
|
//
|
|
@@ -701,10 +663,11 @@ export function buildTree(parsed: unknown, opts: ParseOptions): ParseResult {
|
|
|
701
663
|
if (opts.intoRoot !== undefined) {
|
|
702
664
|
// --- Merge mode: parse root's attrs/children into the existing root ---
|
|
703
665
|
// The JSON root's own package/super/reserved-keys are not re-applied to the
|
|
704
|
-
// existing root.
|
|
705
|
-
//
|
|
666
|
+
// existing root. Children from the NEW document take the NEW document's
|
|
667
|
+
// package — and a document with no `package` declares root-level nodes,
|
|
668
|
+
// whatever was loaded before it (ADR-0059 R10: the default package is per file).
|
|
706
669
|
const newRootPkg = rootDataObj[RESERVED_KEY_PACKAGE];
|
|
707
|
-
const contextPkg =
|
|
670
|
+
const contextPkg = typeof newRootPkg === "string" ? newRootPkg : "";
|
|
708
671
|
parseNodeInto(
|
|
709
672
|
rootDataObj,
|
|
710
673
|
opts.intoRoot,
|
|
@@ -825,9 +788,9 @@ function parseNodeFresh(
|
|
|
825
788
|
// this node by its effective qualified key regardless of post-merge tree
|
|
826
789
|
// shape or load order. This does NOT touch the node's `package` or `fqn()`
|
|
827
790
|
// (objects stay bare per FR5d). Mirrors Java's parse-time getDefaultPackageName().
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
791
|
+
// Recorded even when empty: "" says the file declares no package (ADR-0059
|
|
792
|
+
// R10), which is not the same as a node built in code with no file at all.
|
|
793
|
+
model.setFileDefaultPackage(inheritedContextPkg);
|
|
831
794
|
|
|
832
795
|
// --- Apply reserved keys (package, extends, abstract, isArray) ---
|
|
833
796
|
applyReservedKeys(model, nodeData, strict, source, path, warnings, inheritedContextPkg);
|
|
@@ -861,7 +824,17 @@ function parseNodeFresh(
|
|
|
861
824
|
if (model.superRef !== undefined && accumRoot !== undefined && !_deferSuperResolution) {
|
|
862
825
|
// FR-024: thread the referrer's type so dotted `Entity.child` refs resolve
|
|
863
826
|
// type-scoped — kept consistent with the deferred path (super-resolve.ts).
|
|
864
|
-
|
|
827
|
+
let superModel: MetaData | undefined;
|
|
828
|
+
try {
|
|
829
|
+
superModel = resolveSuperRef(model.superRef, effectivePkg, accumRoot, { type: model.type });
|
|
830
|
+
} catch (e) {
|
|
831
|
+
if (!(e instanceof RefOverDropError)) throw e;
|
|
832
|
+
// ADR-0059 R2 — `..::` dropped more segments than the package has.
|
|
833
|
+
throw new ParseError(
|
|
834
|
+
`the extends ref '${model.superRef}' on ${model.fqn()} climbs above the root package — each '..::' drops one segment of the declaring package`,
|
|
835
|
+
{ code: "ERR_BAD_ATTR_VALUE", source: resolvedSource(errSource(), model.fqn(), model.superRef) },
|
|
836
|
+
);
|
|
837
|
+
}
|
|
865
838
|
if (superModel !== undefined) {
|
|
866
839
|
// FR-024 — a dotted child-targeting ref must resolve to a node of the
|
|
867
840
|
// SAME type and subtype as the extending node. Dotted-only check; the
|
|
@@ -1458,9 +1431,6 @@ function applyReservedKeys(
|
|
|
1458
1431
|
if (typeof rawExtends !== "string") {
|
|
1459
1432
|
reportProblem(`"${RESERVED_KEY_EXTENDS}" must be a string at ${path}`, strict, warnings, "ERR_UNRESOLVED_SUPER");
|
|
1460
1433
|
} else {
|
|
1461
|
-
// FR-032: canonical JSON `extends` must be FQN; reject a surviving
|
|
1462
|
-
// relative form (no-op for YAML-format input, which was desugar-expanded).
|
|
1463
|
-
guardRelativeRefInCanonical(`"${RESERVED_KEY_EXTENDS}"`, rawExtends, strict, warnings, path);
|
|
1464
1434
|
model.setSuper(rawExtends);
|
|
1465
1435
|
}
|
|
1466
1436
|
}
|
|
@@ -1548,13 +1518,6 @@ function applyInlineAttrsAndUnknownKeys(
|
|
|
1548
1518
|
|
|
1549
1519
|
const rawVal = nodeData[key];
|
|
1550
1520
|
|
|
1551
|
-
// FR-032: a ref-bearing inline attr (@objectRef/@references/@from/@of/@via/
|
|
1552
|
-
// @parameterRef/@payloadRef/@responseRef) in canonical JSON must be FQN —
|
|
1553
|
-
// reject a surviving relative form. No-op for YAML-format input.
|
|
1554
|
-
if (REF_BEARING_ATTR_NAMES.has(attrName)) {
|
|
1555
|
-
guardRelativeRefInCanonical(`${ATTR_PREFIX}${attrName}`, rawVal, strict, warnings, path);
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
1521
|
try {
|
|
1559
1522
|
const attr = materializeAttr(model, attrName, rawVal, registry);
|
|
1560
1523
|
model.setMetaAttr(attr);
|
|
@@ -19,7 +19,7 @@ export const DB_DEFINITION: ProviderDefinition = {
|
|
|
19
19
|
"name": "column",
|
|
20
20
|
"min": 0,
|
|
21
21
|
"max": 1,
|
|
22
|
-
"description": "Physical column name for this field on an rdb source. Defaults to the field name
|
|
22
|
+
"description": "Physical column name for this field on an rdb source. Defaults to the field name under the project's naming.columns rule (the \"naming\" setting in .metaobjects/config.json)."
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"type": "attr",
|
|
@@ -108,7 +108,7 @@ export const DB_DEFINITION: ProviderDefinition = {
|
|
|
108
108
|
"name": "table",
|
|
109
109
|
"min": 0,
|
|
110
110
|
"max": 1,
|
|
111
|
-
"description": "Physical SQL table name for source.rdb @kind: \"table\" (default). FR-016: Defaults from the source's bare structural `name`
|
|
111
|
+
"description": "Physical SQL table name for source.rdb @kind: \"table\" (default). FR-016: Defaults from the source's bare structural `name` under the project's naming.tables rule (the \"naming\" setting in .metaobjects/config.json) when omitted, then from the owning entity's name. Pre-1.0 legacy spelling for view/materializedView/storedProc/tableFunction kinds during the transition; canonical-serializer rewrites to the kind-matching alias."
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
114
|
"type": "attr",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Extends MetaData directly: no model wrapper, no metaOf() indirection.
|
|
7
7
|
|
|
8
8
|
import { MetaData } from "../../shared/meta-data.js";
|
|
9
|
-
import {
|
|
9
|
+
import { applyTableNamingRule, physicalNamingOf, pluralizeTableNameLegacy } from "../../naming.js";
|
|
10
10
|
import {
|
|
11
11
|
SOURCE_ATTR_TABLE,
|
|
12
12
|
SOURCE_ATTR_VIEW,
|
|
@@ -100,9 +100,11 @@ export class MetaSource extends MetaData {
|
|
|
100
100
|
* four-step rule:
|
|
101
101
|
* 1. Kind-matching alias (e.g. @proc when @kind: "storedProc").
|
|
102
102
|
* 2. Legacy @table for non-table kind (pre-1.0 fallback).
|
|
103
|
-
* 3. Source's bare structural `name
|
|
104
|
-
* 4. Owning entity's name
|
|
105
|
-
* see pluralizeTableNameLegacy's doc for why it is frozen.
|
|
103
|
+
* 3. Source's bare structural `name`, cased by the project's table rule.
|
|
104
|
+
* 4. Owning entity's name, cased by the project's table rule, through the frozen
|
|
105
|
+
* legacy pluralizer — see pluralizeTableNameLegacy's doc for why it is frozen.
|
|
106
|
+
* The table rule is `naming.tables` in `.metaobjects/config.json` (ADR-0058), carried by
|
|
107
|
+
* the loaded root; default `snake_case`.
|
|
106
108
|
*
|
|
107
109
|
* Callers needing the legacy raw @table slot only should use `tableName`;
|
|
108
110
|
* codegen / migrate / runtime should use `physicalName`.
|
|
@@ -128,7 +130,7 @@ export class MetaSource extends MetaData {
|
|
|
128
130
|
// Step 3: source's structural `name` via snake_case (no pluralization —
|
|
129
131
|
// the source's name IS the logical name).
|
|
130
132
|
if (this.name !== "") {
|
|
131
|
-
return
|
|
133
|
+
return applyTableNamingRule(this.name, physicalNamingOf(this).tables);
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
// Step 4: owning entity's name via pluralize(snake_case). The MetaData
|
|
@@ -136,7 +138,7 @@ export class MetaSource extends MetaData {
|
|
|
136
138
|
// rule — this is a DEFAULT PHYSICAL name, not an API-surface name.
|
|
137
139
|
const owner = this.parent;
|
|
138
140
|
if (owner !== undefined && owner.name !== "") {
|
|
139
|
-
return pluralizeTableNameLegacy(
|
|
141
|
+
return pluralizeTableNameLegacy(applyTableNamingRule(owner.name, physicalNamingOf(this).tables));
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
return "";
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
// — a TS-web presentation facet (TS web client + TS
|
|
39
39
|
// form codegen consume them; zero backend/codegen/
|
|
40
40
|
// render consumers in any port), like the TS-only `D1`
|
|
41
|
-
// dialect.
|
|
42
|
-
//
|
|
41
|
+
// dialect. REGISTERED in every port, for LOADING
|
|
42
|
+
// only; EXCLUDED from the manifest everywhere.
|
|
43
43
|
//
|
|
44
44
|
// The boundary is now an EXPLICIT classification (not a silent default): the
|
|
45
45
|
// port-private set is enumerated WITH a reason category, and a TRIPWIRE
|
package/src/registry-manifest.ts
CHANGED
|
@@ -112,7 +112,7 @@ export interface ManifestType {
|
|
|
112
112
|
* constant read `"0.10"`). Bump with that script — never by hand — so the manifest and
|
|
113
113
|
* all four port constants move together.
|
|
114
114
|
*/
|
|
115
|
-
export const METAMODEL_VERSION = "1.
|
|
115
|
+
export const METAMODEL_VERSION = "1.1";
|
|
116
116
|
|
|
117
117
|
/** The full canonical manifest. All collections are sorted for byte-stability. */
|
|
118
118
|
interface RegistryManifest {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// release-docs.ts — guide URLs pinned to the release this toolchain belongs to.
|
|
2
|
+
//
|
|
3
|
+
// Node-only (reads package.json), so it sits behind its own subpath
|
|
4
|
+
// (`@metaobjectsdev/metadata/release-docs`) and is never reachable from the root entry,
|
|
5
|
+
// which must stay browser-safe. The pure rule (`docsRefForVersion`) is in `docs-ref.ts`.
|
|
6
|
+
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { docsBlobUrl, docsRefForVersion } from "./docs-ref.js";
|
|
11
|
+
import { PHYSICAL_NAMING_MIGRATION_GUIDE_PATH } from "./naming.js";
|
|
12
|
+
|
|
13
|
+
let cachedVersion: string | undefined;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The version of this package, read from its own package.json (walking up from this
|
|
17
|
+
* module). All `@metaobjectsdev/*` npm packages release in lockstep, so it is also the
|
|
18
|
+
* version of the toolchain a message is printed by. "0.0.0" when not found.
|
|
19
|
+
*/
|
|
20
|
+
export function metadataPackageVersion(): string {
|
|
21
|
+
if (cachedVersion !== undefined) return cachedVersion;
|
|
22
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
for (let i = 0; i < 6; i++) {
|
|
24
|
+
const candidate = join(dir, "package.json");
|
|
25
|
+
if (existsSync(candidate)) {
|
|
26
|
+
try {
|
|
27
|
+
const pkg = JSON.parse(readFileSync(candidate, "utf8")) as { name?: string; version?: string };
|
|
28
|
+
if (pkg.name === "@metaobjectsdev/metadata" && pkg.version) return (cachedVersion = pkg.version);
|
|
29
|
+
} catch {
|
|
30
|
+
// not our manifest / unreadable — keep walking up
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const parent = dirname(dir);
|
|
34
|
+
if (parent === dir) break;
|
|
35
|
+
dir = parent;
|
|
36
|
+
}
|
|
37
|
+
return (cachedVersion = "0.0.0");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** A guide URL pinned to the release this package belongs to. */
|
|
41
|
+
export function guideUrl(repoRelativePath: string): string {
|
|
42
|
+
return docsBlobUrl(repoRelativePath, docsRefForVersion(metadataPackageVersion()));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The physical-naming migration guide, pinned: what `physicalNamingRemovedMessage` is given. */
|
|
46
|
+
export function physicalNamingGuideUrl(): string {
|
|
47
|
+
return guideUrl(PHYSICAL_NAMING_MIGRATION_GUIDE_PATH);
|
|
48
|
+
}
|
package/src/serializer-json.ts
CHANGED
|
@@ -41,15 +41,28 @@ const SOURCE_RDB_FUSED_KEY = `${TYPE_SOURCE}${TYPE_SUBTYPE_SEPARATOR}${SOURCE_SU
|
|
|
41
41
|
// Public API
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* How references are written (ADR-0059 R8).
|
|
46
|
+
* - "canonical" (default): each reference as the loader resolved it — `pkg::Name`,
|
|
47
|
+
* `::Name` for a root-level target from a packaged referrer — and the document
|
|
48
|
+
* package rule below. The output loads back to the same model from any source.
|
|
49
|
+
* - "authored": each reference, `extends` included, exactly as written, and every
|
|
50
|
+
* `package` where it was written. Only `meta fmt` uses it, so formatting never
|
|
51
|
+
* rewrites what an author wrote (ADR-0059, C2).
|
|
52
|
+
*/
|
|
53
|
+
export type RefSpelling = "canonical" | "authored";
|
|
54
|
+
|
|
44
55
|
export interface SerializeOptions {
|
|
45
56
|
/** Pretty-print indent. 0 = no whitespace. Default 2. */
|
|
46
57
|
indent?: number;
|
|
58
|
+
/** Reference spelling; default "canonical". */
|
|
59
|
+
refs?: RefSpelling;
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
export function serializeJson(model: MetaData, opts?: SerializeOptions): string {
|
|
50
63
|
const indent = opts?.indent ?? 2;
|
|
51
64
|
|
|
52
|
-
const nodeObj = serializeNode(model, false);
|
|
65
|
+
const nodeObj = serializeNode(model, false, opts?.refs ?? "canonical", undefined);
|
|
53
66
|
return JSON.stringify(nodeObj, null, indent === 0 ? undefined : indent);
|
|
54
67
|
}
|
|
55
68
|
|
|
@@ -82,17 +95,57 @@ function fusedKey(type: string, subType: string): string {
|
|
|
82
95
|
// Serialize a single node — returns { "<type>.<subType>": { ...body } }
|
|
83
96
|
// ---------------------------------------------------------------------------
|
|
84
97
|
|
|
98
|
+
/**
|
|
99
|
+
* How a node's `package` key is written. `undefined`: the node's own `package`, as
|
|
100
|
+
* authored. Otherwise the package the document rule (ADR-0059 R8) assigns it; ""
|
|
101
|
+
* writes none.
|
|
102
|
+
*/
|
|
103
|
+
type PackageSlot = string | undefined;
|
|
104
|
+
|
|
85
105
|
function serializeNode(
|
|
86
106
|
model: MetaData,
|
|
87
107
|
effective: boolean,
|
|
108
|
+
refs: RefSpelling,
|
|
109
|
+
pkgSlot: PackageSlot,
|
|
88
110
|
): Record<string, unknown> {
|
|
89
|
-
const inner = serializeNodeInner(model, effective);
|
|
111
|
+
const inner = serializeNodeInner(model, effective, refs, pkgSlot);
|
|
90
112
|
return { [fusedKey(model.type, model.subType)]: inner };
|
|
91
113
|
}
|
|
92
114
|
|
|
115
|
+
/** Effective package of a top-level node (ADR-0059 R10): own, else its file's. A
|
|
116
|
+
* node built in code has no file, so it takes the root's package, as re-loading the
|
|
117
|
+
* output would give it. */
|
|
118
|
+
function topLevelPackage(node: MetaData, root: MetaData): string {
|
|
119
|
+
return node.package ?? node.fileDefaultPackage ?? root.package ?? "";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* ADR-0059 R8 document package rule, for a `metadata.root` in canonical mode.
|
|
124
|
+
* Every top-level node in one non-empty package P: the root carries P (a node keeps
|
|
125
|
+
* a package it carries itself, as before). Otherwise the root carries none and each packaged top-level node
|
|
126
|
+
* carries its own. A root with no named top-level node keeps its own package.
|
|
127
|
+
*/
|
|
128
|
+
function documentPackages(root: MetaData): { rootPkg: string | undefined; perNode: boolean } {
|
|
129
|
+
// ADR-0039: own — the serializer writes the declared layer; the root has no super.
|
|
130
|
+
const named = root.ownChildren().filter((c) => c.name !== "");
|
|
131
|
+
if (named.length === 0) return { rootPkg: root.package, perNode: false };
|
|
132
|
+
const pkgs = new Set(named.map((c) => topLevelPackage(c, root)));
|
|
133
|
+
if (pkgs.size === 1) {
|
|
134
|
+
const only = [...pkgs][0]!;
|
|
135
|
+
// When every node already names P itself and the root names none, the
|
|
136
|
+
// document is already complete as written; adding a root package would only
|
|
137
|
+
// repeat it.
|
|
138
|
+
const selfNamed = root.package === undefined && named.every((c) => c.package === only);
|
|
139
|
+
if (only !== "") return { rootPkg: selfNamed ? undefined : only, perNode: false };
|
|
140
|
+
}
|
|
141
|
+
return { rootPkg: undefined, perNode: true };
|
|
142
|
+
}
|
|
143
|
+
|
|
93
144
|
function serializeNodeInner(
|
|
94
145
|
model: MetaData,
|
|
95
146
|
effective: boolean,
|
|
147
|
+
refs: RefSpelling,
|
|
148
|
+
pkgSlot: PackageSlot,
|
|
96
149
|
): Record<string, unknown> {
|
|
97
150
|
// Canonical body-key order:
|
|
98
151
|
// 1. name 2. package 3. extends 4. abstract
|
|
@@ -104,12 +157,19 @@ function serializeNodeInner(
|
|
|
104
157
|
obj[RESERVED_KEY_NAME] = model.name;
|
|
105
158
|
}
|
|
106
159
|
|
|
107
|
-
|
|
108
|
-
|
|
160
|
+
const isDocRoot = model.type === TYPE_METADATA && model.subType === SUBTYPE_ROOT;
|
|
161
|
+
const doc = isDocRoot && refs === "canonical" ? documentPackages(model) : undefined;
|
|
162
|
+
|
|
163
|
+
const pkg = doc !== undefined ? doc.rootPkg : pkgSlot !== undefined ? pkgSlot : model.package;
|
|
164
|
+
if (pkg !== undefined && pkg !== "") {
|
|
165
|
+
obj[RESERVED_KEY_PACKAGE] = pkg;
|
|
109
166
|
}
|
|
110
167
|
|
|
111
|
-
|
|
112
|
-
|
|
168
|
+
// After the loader's resolveReferences pass `superRef` is canonical (ADR-0059 R5);
|
|
169
|
+
// the authored spelling is kept beside it for `meta fmt`.
|
|
170
|
+
const superRef = refs === "authored" ? (model.authoredSuperRef ?? model.superRef) : model.superRef;
|
|
171
|
+
if (superRef !== undefined) {
|
|
172
|
+
obj[RESERVED_KEY_EXTENDS] = superRef;
|
|
113
173
|
}
|
|
114
174
|
|
|
115
175
|
if (model.isAbstract === true) {
|
|
@@ -141,13 +201,20 @@ function serializeNodeInner(
|
|
|
141
201
|
|
|
142
202
|
const serializedChildren: Record<string, unknown>[] = [];
|
|
143
203
|
for (const child of childList) {
|
|
144
|
-
// Attrs never appear in children(); only structural nodes recurse.
|
|
145
|
-
|
|
204
|
+
// Attrs never appear in children(); only structural nodes recurse. A top-level
|
|
205
|
+
// node's package follows the document rule; deeper nodes keep their own.
|
|
206
|
+
// In a one-package document a node keeps any package it carries itself (the parser
|
|
207
|
+
// gives a root-level field its file's package), so single-package output is unchanged.
|
|
208
|
+
const childSlot: PackageSlot =
|
|
209
|
+
doc === undefined || !doc.perNode ? undefined : child.name !== "" ? topLevelPackage(child, model) : "";
|
|
210
|
+
serializedChildren.push(serializeNode(child, effective, refs, childSlot));
|
|
146
211
|
}
|
|
147
212
|
|
|
148
213
|
// Attrs ALWAYS emit inline @name (D5 — attrs have no children, one canonical form).
|
|
149
214
|
for (const [attrName, attrValue] of attrMap) {
|
|
150
|
-
|
|
215
|
+
// ADR-0039: own — the authored value lives on the declaring attr node.
|
|
216
|
+
const authored = refs === "authored" && !effective ? model.ownMetaAttr(attrName)?.authoredValue : undefined;
|
|
217
|
+
obj[`${ATTR_PREFIX}${attrName}`] = authored ?? attrValue;
|
|
151
218
|
}
|
|
152
219
|
|
|
153
220
|
if (serializedChildren.length > 0) {
|
|
@@ -167,8 +234,8 @@ function serializeNodeInner(
|
|
|
167
234
|
// byte-identical output from the same input metamodel.
|
|
168
235
|
// ---------------------------------------------------------------------------
|
|
169
236
|
|
|
170
|
-
export function canonicalSerialize(model: MetaData): string {
|
|
171
|
-
const raw = serializeJson(model, { indent: 2 });
|
|
237
|
+
export function canonicalSerialize(model: MetaData, opts?: { refs?: RefSpelling }): string {
|
|
238
|
+
const raw = serializeJson(model, { indent: 2, refs: opts?.refs ?? "canonical" });
|
|
172
239
|
|
|
173
240
|
const parsed = JSON.parse(raw) as unknown;
|
|
174
241
|
// FR-016 / ADR-0018: rewrite legacy @table → kind-matching alias on source.rdb
|
|
@@ -188,7 +255,7 @@ export function canonicalSerialize(model: MetaData): string {
|
|
|
188
255
|
* Used by the conformance harness's expected-effective fixtures.
|
|
189
256
|
*/
|
|
190
257
|
export function canonicalSerializeEffective(model: MetaData): string {
|
|
191
|
-
const nodeObj = serializeNode(model, true);
|
|
258
|
+
const nodeObj = serializeNode(model, true, "canonical", undefined);
|
|
192
259
|
const raw = JSON.stringify(nodeObj, null, 2);
|
|
193
260
|
|
|
194
261
|
const parsed = JSON.parse(raw) as unknown;
|
package/src/shared/base-types.ts
CHANGED
|
@@ -22,6 +22,12 @@ export const TYPE_INDEX = "index";
|
|
|
22
22
|
/** Capability / requirement records — `requirement.functional` (existence check)
|
|
23
23
|
* and `requirement.architectural` (universality check). Ruling amendment 3. */
|
|
24
24
|
export const TYPE_REQUIREMENT = "requirement";
|
|
25
|
+
/** FR-044 reporting vocabulary — a named group-by attribute (`dimension.attribute`,
|
|
26
|
+
* `dimension.time`), a named aggregate (`measure.aggregate`, `measure.ratio`) and a
|
|
27
|
+
* named row filter (`segment.filter`), all declared on an `object.entity`. */
|
|
28
|
+
export const TYPE_DIMENSION = "dimension";
|
|
29
|
+
export const TYPE_MEASURE = "measure";
|
|
30
|
+
export const TYPE_SEGMENT = "segment";
|
|
25
31
|
|
|
26
32
|
export const BASE_TYPES = [
|
|
27
33
|
TYPE_METADATA,
|
|
@@ -38,6 +44,9 @@ export const BASE_TYPES = [
|
|
|
38
44
|
TYPE_TEMPLATE,
|
|
39
45
|
TYPE_INDEX,
|
|
40
46
|
TYPE_REQUIREMENT,
|
|
47
|
+
TYPE_DIMENSION,
|
|
48
|
+
TYPE_MEASURE,
|
|
49
|
+
TYPE_SEGMENT,
|
|
41
50
|
] as const;
|
|
42
51
|
export type BaseType = (typeof BASE_TYPES)[number];
|
|
43
52
|
|
package/src/shared/meta-data.ts
CHANGED
|
@@ -34,7 +34,10 @@ export abstract class MetaData {
|
|
|
34
34
|
// order and post-merge tree shape. Mirrors Java's BaseMetaDataParser, which
|
|
35
35
|
// folds getDefaultPackageName() into the registered name at parse time.
|
|
36
36
|
fileDefaultPackage?: string;
|
|
37
|
-
superRef?: string; //
|
|
37
|
+
superRef?: string; // super reference string; canonical after the loader's resolveReferences pass
|
|
38
|
+
/** ADR-0059 R5 — the `extends` value exactly as authored, kept when the loader's
|
|
39
|
+
* `resolveReferences` pass rewrites `superRef` to its canonical spelling. */
|
|
40
|
+
authoredSuperRef?: string;
|
|
38
41
|
private _superData?: MetaData; // post-resolution pointer; set by setSuperResolved() after parsing
|
|
39
42
|
isAbstract: boolean = false;
|
|
40
43
|
|
|
@@ -384,6 +387,24 @@ export abstract class MetaData {
|
|
|
384
387
|
return this.attrs().get(name);
|
|
385
388
|
}
|
|
386
389
|
|
|
390
|
+
/**
|
|
391
|
+
* ADR-0059 — effective attr value for `name` as the author WROTE it: for a
|
|
392
|
+
* reference the loader rewrote to its canonical spelling, the authored string;
|
|
393
|
+
* for every other attr, the value. For human-facing text (descriptions) only —
|
|
394
|
+
* code that binds a reference reads `attr()`.
|
|
395
|
+
*/
|
|
396
|
+
authoredAttr(name: string): AttrValue | undefined {
|
|
397
|
+
assertNotStructuralKeyword(name, "authoredAttr");
|
|
398
|
+
const seen = new Set<MetaData>();
|
|
399
|
+
for (let n: MetaData | undefined = this; n !== undefined && !seen.has(n); n = n._superData) {
|
|
400
|
+
seen.add(n);
|
|
401
|
+
// ADR-0039: own — locating the layer that declares the attr, walking the super chain.
|
|
402
|
+
const node = n._attrNodes.get(name);
|
|
403
|
+
if (node !== undefined) return node.authoredValue ?? node.value;
|
|
404
|
+
}
|
|
405
|
+
return undefined;
|
|
406
|
+
}
|
|
407
|
+
|
|
387
408
|
/** True if `name` resolves to an effective attr (own or inherited). */
|
|
388
409
|
hasAttr(name: string): boolean {
|
|
389
410
|
assertNotStructuralKeyword(name, "hasAttr");
|
package/src/shared/meta-root.ts
CHANGED
|
@@ -7,8 +7,18 @@ import { MetaData } from "./meta-data.js";
|
|
|
7
7
|
import { TYPE_OBJECT, TYPE_FIELD } from "./base-types.js";
|
|
8
8
|
import type { MetaObject } from "../core/object/meta-object.js";
|
|
9
9
|
import type { MetaField } from "../core/field/meta-field.js";
|
|
10
|
+
import { DEFAULT_PHYSICAL_NAMING, type PhysicalNaming } from "../naming.js";
|
|
11
|
+
import { PACKAGE_SEPARATOR } from "./structural.js";
|
|
12
|
+
import { lookupCanonical } from "../naming-refs.js";
|
|
10
13
|
|
|
11
14
|
export class MetaRoot extends MetaData {
|
|
15
|
+
/**
|
|
16
|
+
* The project's physical-naming rules (`naming` in `.metaobjects/config.json`, ADR-0058).
|
|
17
|
+
* Set by the project-aware load (`loadMemory`, `resolveCollection`), read by every name
|
|
18
|
+
* resolver through `physicalNamingOf`. A tree loaded with no project has the default.
|
|
19
|
+
*/
|
|
20
|
+
physicalNaming: PhysicalNaming = DEFAULT_PHYSICAL_NAMING;
|
|
21
|
+
|
|
12
22
|
/** Object entities defined at this root level. */
|
|
13
23
|
objects(): MetaObject[] {
|
|
14
24
|
return this.cached("objects", () =>
|
|
@@ -26,9 +36,18 @@ export class MetaRoot extends MetaData {
|
|
|
26
36
|
);
|
|
27
37
|
}
|
|
28
38
|
|
|
29
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Find an object by name, or by a canonical reference (ADR-0059): a value with a
|
|
41
|
+
* package separator (`acme::Program`, `::Program`) binds the object whose resolution
|
|
42
|
+
* key matches exactly, so a reference the loader rewrote to canonical form still finds
|
|
43
|
+
* its target. A bare name matches a root-level child by name, as before.
|
|
44
|
+
*/
|
|
30
45
|
findObject(name: string): MetaObject | undefined {
|
|
31
46
|
return this.cached(`findObject:${name}`, () => {
|
|
47
|
+
if (name.includes(PACKAGE_SEPARATOR)) {
|
|
48
|
+
const node = lookupCanonical(this, name, { ownerType: TYPE_OBJECT });
|
|
49
|
+
return node !== undefined && node.type === TYPE_OBJECT ? (node as MetaObject) : undefined;
|
|
50
|
+
}
|
|
32
51
|
// ADR-0039: own — the metadata root has no super chain (it never `extends`).
|
|
33
52
|
const child = this.ownChildByTypeAndName(TYPE_OBJECT, name);
|
|
34
53
|
return child !== undefined ? (child as MetaObject) : undefined;
|