@metaobjectsdev/metadata 1.0.2 → 1.0.4-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/core/parser-yaml.d.ts.map +1 -1
  2. package/dist/core/parser-yaml.js +4 -0
  3. package/dist/core/parser-yaml.js.map +1 -1
  4. package/dist/core/relationship/derive-m2m-fields.d.ts +3 -1
  5. package/dist/core/relationship/derive-m2m-fields.d.ts.map +1 -1
  6. package/dist/core/relationship/derive-m2m-fields.js +110 -15
  7. package/dist/core/relationship/derive-m2m-fields.js.map +1 -1
  8. package/dist/core/relationship/find-reference.d.ts +21 -5
  9. package/dist/core/relationship/find-reference.d.ts.map +1 -1
  10. package/dist/core/relationship/find-reference.js +29 -10
  11. package/dist/core/relationship/find-reference.js.map +1 -1
  12. package/dist/core/relationship/relationship-definition.embedded.js +8 -8
  13. package/dist/core/relationship/relationship-definition.embedded.js.map +1 -1
  14. package/dist/core/relationship/resolve-relationship-reference.d.ts +27 -0
  15. package/dist/core/relationship/resolve-relationship-reference.d.ts.map +1 -0
  16. package/dist/core/relationship/resolve-relationship-reference.js +84 -0
  17. package/dist/core/relationship/resolve-relationship-reference.js.map +1 -0
  18. package/dist/errors.d.ts +1 -1
  19. package/dist/errors.d.ts.map +1 -1
  20. package/dist/errors.js +31 -0
  21. package/dist/errors.js.map +1 -1
  22. package/dist/index.d.ts +8 -5
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +9 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/json-path.d.ts +14 -0
  27. package/dist/json-path.d.ts.map +1 -1
  28. package/dist/json-path.js +13 -0
  29. package/dist/json-path.js.map +1 -1
  30. package/dist/library/embedded-library.generated.d.ts +2 -0
  31. package/dist/library/embedded-library.generated.d.ts.map +1 -1
  32. package/dist/library/embedded-library.generated.js +11 -1
  33. package/dist/library/embedded-library.generated.js.map +1 -1
  34. package/dist/library/index.d.ts +2 -0
  35. package/dist/library/index.d.ts.map +1 -0
  36. package/dist/library/index.js +24 -0
  37. package/dist/library/index.js.map +1 -0
  38. package/dist/library/library-sources.d.ts +99 -6
  39. package/dist/library/library-sources.d.ts.map +1 -1
  40. package/dist/library/library-sources.js +165 -43
  41. package/dist/library/library-sources.js.map +1 -1
  42. package/dist/loader/meta-data-loader.d.ts +44 -21
  43. package/dist/loader/meta-data-loader.d.ts.map +1 -1
  44. package/dist/loader/meta-data-loader.js +118 -88
  45. package/dist/loader/meta-data-loader.js.map +1 -1
  46. package/dist/loader/sources/file-source.d.ts +7 -1
  47. package/dist/loader/sources/file-source.d.ts.map +1 -1
  48. package/dist/loader/sources/file-source.js +3 -2
  49. package/dist/loader/sources/file-source.js.map +1 -1
  50. package/dist/loader/validation-passes.d.ts +2 -0
  51. package/dist/loader/validation-passes.d.ts.map +1 -1
  52. package/dist/loader/validation-passes.js +162 -22
  53. package/dist/loader/validation-passes.js.map +1 -1
  54. package/dist/naming.d.ts +7 -0
  55. package/dist/naming.d.ts.map +1 -1
  56. package/dist/naming.js +10 -0
  57. package/dist/naming.js.map +1 -1
  58. package/dist/parser-core.d.ts +103 -0
  59. package/dist/parser-core.d.ts.map +1 -1
  60. package/dist/parser-core.js +202 -18
  61. package/dist/parser-core.js.map +1 -1
  62. package/dist/scope.d.ts +16 -0
  63. package/dist/scope.d.ts.map +1 -0
  64. package/dist/scope.js +78 -0
  65. package/dist/scope.js.map +1 -0
  66. package/dist/serializer-json.d.ts +1 -0
  67. package/dist/serializer-json.d.ts.map +1 -1
  68. package/dist/serializer-json.js +43 -1
  69. package/dist/serializer-json.js.map +1 -1
  70. package/dist/vocabulary-rewrite-yaml.d.ts +2 -0
  71. package/dist/vocabulary-rewrite-yaml.d.ts.map +1 -0
  72. package/dist/vocabulary-rewrite-yaml.js +22 -0
  73. package/dist/vocabulary-rewrite-yaml.js.map +1 -0
  74. package/package.json +7 -7
  75. package/src/core/parser-yaml.ts +4 -0
  76. package/src/core/relationship/derive-m2m-fields.ts +115 -15
  77. package/src/core/relationship/find-reference.ts +34 -11
  78. package/src/core/relationship/relationship-definition.embedded.ts +8 -8
  79. package/src/core/relationship/resolve-relationship-reference.ts +99 -0
  80. package/src/errors.ts +31 -0
  81. package/src/index.ts +18 -5
  82. package/src/json-path.ts +16 -1
  83. package/src/library/embedded-library.generated.ts +12 -1
  84. package/src/library/index.ts +23 -0
  85. package/src/library/library-sources.ts +197 -47
  86. package/src/loader/meta-data-loader.ts +154 -102
  87. package/src/loader/sources/file-source.ts +10 -2
  88. package/src/loader/validation-passes.ts +181 -23
  89. package/src/naming.ts +11 -0
  90. package/src/parser-core.ts +319 -22
  91. package/src/scope.ts +97 -0
  92. package/src/serializer-json.ts +46 -1
  93. package/src/vocabulary-rewrite-yaml.ts +21 -0
@@ -9,19 +9,30 @@ import { join, dirname } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { FileSource } from "../loader/sources/file-source.js";
11
11
  import { InMemoryStringSource } from "../loader/meta-data-source.js";
12
- import { EMBEDDED_LIBRARY } from "./embedded-library.generated.js";
13
- // Package ordered refs, derived from the generated embedded module so adding a
14
- // library file (which regenerates EMBEDDED_LIBRARY) needs no edit here.
15
- const REFS_BY_PACKAGE = (() => {
16
- const map = {};
17
- for (const ref of Object.keys(EMBEDDED_LIBRARY).sort()) {
18
- const pkg = ref.split("/")[0];
19
- if (pkg === undefined || pkg === "")
20
- continue;
21
- (map[pkg] ??= []).push(ref);
12
+ import { EMBEDDED_LIBRARY, EMBEDDED_LIBRARY_MANIFESTS } from "./embedded-library.generated.js";
13
+ const MANIFESTS = (() => {
14
+ const out = {};
15
+ for (const [name, text] of Object.entries(EMBEDDED_LIBRARY_MANIFESTS)) {
16
+ out[name] = JSON.parse(text);
22
17
  }
23
- return map;
18
+ return out;
24
19
  })();
20
+ /** Every shipped library's parsed manifest, keyed by name. */
21
+ export function libraryManifests() {
22
+ return MANIFESTS;
23
+ }
24
+ /**
25
+ * Split a selection token into `[library, layer]` — `"iam"` → `["iam", ""]`,
26
+ * `"iam/db"` → `["iam", "db"]`.
27
+ *
28
+ * Path-like, so `libraries` stays `string[]` and no config schema moves. Only ONE
29
+ * separator is meaningful; anything after a second is part of the layer token, which
30
+ * keeps a typo failing loudly rather than resolving to a prefix.
31
+ */
32
+ export function splitLayerToken(token) {
33
+ const i = token.indexOf("/");
34
+ return i === -1 ? [token, ""] : [token.slice(0, i), token.slice(i + 1)];
35
+ }
25
36
  /**
26
37
  * Locate the repo-root `library/` directory by walking up from this module's
27
38
  * location until a directory contains BOTH `library/` and `server/` (the two
@@ -57,45 +68,156 @@ function getLibraryDir() {
57
68
  * available (Python's `project_config` draws the same line, in the same place).
58
69
  */
59
70
  export function knownLibraryPackages() {
60
- return Object.keys(REFS_BY_PACKAGE).sort();
71
+ return Object.keys(MANIFESTS).sort();
61
72
  }
62
73
  /**
63
- * Returns a list of `MetaDataSource` instances for the requested library packages.
74
+ * Every package name a shipped library OWNS, across every library and layer.
64
75
  *
65
- * - Recognized packages: `"ai"` (others contribute no sources).
66
- * - Per ref: if the on-disk `library/<ref>.yaml` exists, returns a `FileSource`;
67
- * otherwise falls back to an `InMemoryStringSource` built from the embedded content.
76
+ * The provenance key for FR-043 §5.4 object coverage activates on adopter-authored
77
+ * requirements only, and "adopter-authored" means "declared outside every library
78
+ * package". It reads the manifests rather than node source ids deliberately: `packages`
79
+ * is a manifest fact the standalone gate resolves against the library loaded alone,
80
+ * while a source id differs between the on-disk dev layout (an absolute path) and the
81
+ * embedded one (`library:<ref>.yaml`), so a rule keyed on that would hold here and stop
82
+ * holding in an installed build.
83
+ */
84
+ /**
85
+ * The source id a library file loads under, in EVERY build — `library:iam/model.yaml`.
68
86
  *
69
- * @param packages - Package names to include (e.g. `["ai"]`).
87
+ * Stable rather than path-derived so a library node's ADR-0009 provenance envelope reads
88
+ * the same from a checkout and from an installed package, carries no absolute path, and
89
+ * cannot be confused with an adopter file that happens to share a basename. The
90
+ * `library:` prefix is the discriminator {@link isLibraryFileId} reads.
70
91
  */
71
- export function librarySources(packages) {
72
- const dir = getLibraryDir();
92
+ export function libraryFileId(ref) {
93
+ return `${LIBRARY_FILE_ID_PREFIX}${ref}.yaml`;
94
+ }
95
+ /** The prefix every library source id carries. */
96
+ export const LIBRARY_FILE_ID_PREFIX = "library:";
97
+ /** True when a source id names a file a shipped library contributed. */
98
+ export function isLibraryFileId(id) {
99
+ return id.startsWith(LIBRARY_FILE_ID_PREFIX);
100
+ }
101
+ export function libraryPackages() {
102
+ const out = new Set();
103
+ for (const manifest of Object.values(MANIFESTS)) {
104
+ for (const pkg of manifest.packages ?? [])
105
+ out.add(pkg);
106
+ }
107
+ return out;
108
+ }
109
+ /**
110
+ * Every selection token this build accepts, sorted — `["ai", "ai/db", "iam", "iam/db"]`.
111
+ *
112
+ * What a config error message should print, so an adopter who typed `iam/database` is
113
+ * shown the layer they meant rather than only the library they got right.
114
+ */
115
+ export function knownLibraryTokens() {
73
116
  const out = [];
74
- for (const pkg of packages) {
75
- const refs = REFS_BY_PACKAGE[pkg];
76
- if (refs === undefined)
77
- continue; // unknown package — no sources
78
- for (const ref of refs) {
79
- if (dir !== undefined) {
80
- const path = join(dir, `${ref}.yaml`);
81
- if (existsSync(path)) {
82
- out.push(new FileSource(path));
83
- continue;
84
- }
85
- }
86
- const embedded = EMBEDDED_LIBRARY[ref];
87
- if (embedded !== undefined) {
88
- out.push(new InMemoryStringSource(embedded, {
89
- id: `library:${ref}.yaml`,
90
- format: "yaml",
91
- }));
92
- }
93
- else {
94
- throw new Error(`library ref "${ref}" (package "${pkg}") has no on-disk file and no embedded entry — ` +
95
- `the embedded library module is stale; run scripts/generate-embedded-library.ts`);
96
- }
117
+ for (const [name, manifest] of Object.entries(MANIFESTS)) {
118
+ for (const layer of Object.keys(manifest.layers ?? { "": { refs: [] } })) {
119
+ out.push(layer === "" ? name : `${name}/${layer}`);
97
120
  }
98
121
  }
99
- return out;
122
+ return out.sort();
123
+ }
124
+ /**
125
+ * `MetaDataSource` instances for the requested library selection.
126
+ *
127
+ * **Layer-granular.** A token is `<library>` or `<library>/<layer>`; the CORE layer is
128
+ * the bare name. This used to be package-granular — every ref under a library came back
129
+ * for a bare `"iam"` — which under the layered design would have handed an adopter the
130
+ * db and ui layers they did not ask for, and with them a migration proposing nine tables.
131
+ *
132
+ * **`"iam/db"` IMPLIES `"iam"`**, and the implication is not a convenience: a db layer is
133
+ * nothing but `overlay: true` redeclarations, and an overlay whose target was never
134
+ * declared is `ERR_OVERLAY_NO_TARGET`. Resolving the layer without its core would produce
135
+ * exactly that error, so implying it is the only coherent reading.
136
+ *
137
+ * Refs are de-duplicated and returned in a stable order — core first, then each requested
138
+ * layer in the manifest's own order — because an overlay must be parsed after its base
139
+ * even though ADR-0055 applies overlays in a deferred pass.
140
+ *
141
+ * An unrecognised token contributes nothing and is skipped silently: that is right for a
142
+ * programmatic caller asking for something a given version may not ship. A name a HUMAN
143
+ * typed is a different case and is refused by the config readers, which call
144
+ * {@link knownLibraryTokens} to say what is available.
145
+ *
146
+ * @param selection - Tokens, e.g. `["iam", "iam/db"]`.
147
+ */
148
+ export function librarySources(selection) {
149
+ const refs = [];
150
+ const seen = new Set();
151
+ const add = (ref) => {
152
+ if (seen.has(ref))
153
+ return;
154
+ seen.add(ref);
155
+ refs.push(ref);
156
+ };
157
+ // Core layers first, across every requested library, so a db layer named before its
158
+ // core in the config still parses after it.
159
+ //
160
+ // A token whose LAYER is unknown is dropped whole, not reduced to its core. The core is
161
+ // implied by a VALID layer token; implying it from an invalid one would answer a
162
+ // mistyped `iam/database` with an inert core and no tables — "I asked for the db layer
163
+ // and got nothing" with no diagnostic, which is the worst of the available outcomes.
164
+ const wanted = selection
165
+ .map(splitLayerToken)
166
+ .filter(([lib, layer]) => lib in MANIFESTS && (MANIFESTS[lib].layers ?? {})[layer] !== undefined);
167
+ for (const [lib] of wanted) {
168
+ for (const ref of MANIFESTS[lib].layers?.[""]?.refs ?? [])
169
+ add(ref);
170
+ }
171
+ for (const [lib, layer] of wanted) {
172
+ if (layer === "")
173
+ continue;
174
+ for (const ref of MANIFESTS[lib].layers?.[layer]?.refs ?? [])
175
+ add(ref);
176
+ }
177
+ return refs.map(libraryRefSource);
178
+ }
179
+ /**
180
+ * One library ref as a source — on-disk first, embedded otherwise.
181
+ *
182
+ * Factored out of {@link librarySources} because `meta eject <library>` needs the TEXT
183
+ * of one ref and must resolve it exactly the way a load does: an adopter ejecting from a
184
+ * checkout must get the file they can see, and from an installed package the embedded
185
+ * copy, with no third rule to keep in step.
186
+ */
187
+ export function libraryRefSource(ref) {
188
+ const dir = getLibraryDir();
189
+ if (dir !== undefined) {
190
+ const path = join(dir, `${ref}.yaml`);
191
+ if (existsSync(path)) {
192
+ // The SAME id the embedded branch below uses, deliberately. A `FileSource`
193
+ // defaults its id to the file's BASENAME, which would make a library node's error
194
+ // envelope read `model.yaml` in a checkout and `library:iam/model.yaml` in an
195
+ // installed build — and would collide outright with an adopter file of that name.
196
+ // One stable id makes the two builds report identically and gives anything asking
197
+ // "did a library declare this node" an unambiguous answer.
198
+ return new FileSource(path, { id: libraryFileId(ref) });
199
+ }
200
+ }
201
+ const embedded = EMBEDDED_LIBRARY[ref];
202
+ if (embedded === undefined) {
203
+ throw new Error(`library ref "${ref}" has no on-disk file and no embedded entry — ` +
204
+ `the embedded library module is stale; run scripts/generate-embedded-library.ts`);
205
+ }
206
+ return new InMemoryStringSource(embedded, { id: libraryFileId(ref), format: "yaml" });
207
+ }
208
+ /** Every ref one library contributes, core layer first — what `meta eject` copies. */
209
+ export function libraryRefs(name) {
210
+ const layers = MANIFESTS[name]?.layers ?? {};
211
+ const refs = [];
212
+ const seen = new Set();
213
+ for (const token of ["", ...Object.keys(layers).filter((k) => k !== "")]) {
214
+ for (const ref of layers[token]?.refs ?? []) {
215
+ if (seen.has(ref))
216
+ continue;
217
+ seen.add(ref);
218
+ refs.push(ref);
219
+ }
220
+ }
221
+ return refs;
100
222
  }
101
223
  //# sourceMappingURL=library-sources.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"library-sources.js","sourceRoot":"","sources":["../../src/library/library-sources.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"library-sources.js","sourceRoot":"","sources":["../../src/library/library-sources.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,50 @@ export interface LoadResult {
38
38
  warnings: LoaderWarning[];
39
39
  errors: Error[];
40
40
  }
41
+ /** One root-level declaration as `declaredTopLevelKeys` structurally scans it —
42
+ * before registry-driven parsing, super resolution, or merge. */
43
+ export interface DeclaredTopLevelKey {
44
+ /** The wrapper key's TYPE segment (e.g. "object" for "object.entity"). A bare
45
+ * wrapper key with no "." is its own type — this walk never consults the
46
+ * registry for a default subType, because it never needs the subType. */
47
+ type: string;
48
+ /** The resolution key the declaration would carry once parsed: the child's
49
+ * own `package` if set (expanded against the root's `package` via
50
+ * `expandPackageForPath` when it's a relative, `::`-prefixed path — e.g.
51
+ * root `acme` + own `::garage` → `acme::garage`), else the root's
52
+ * `package` verbatim, then `::`, then its `name`. Exactly
53
+ * `rootChildResolutionKey` (parser-core.ts) — including the relative-path
54
+ * expansion, reusing `expandPackageForPath` rather than reimplementing it,
55
+ * because a second copy is exactly how this walk and the real parser
56
+ * silently disagreed on a relative package (task 17 fix-round-1: this
57
+ * function used to return `::garage::Garage` for a fixture the real
58
+ * loader resolves to `acme::garage::Garage`). */
59
+ key: string;
60
+ /** Whether the declaration's body carries `overlay: true`. */
61
+ overlay: boolean;
62
+ }
63
+ /**
64
+ * Structurally scan a source's raw content (JSON via `JSON.parse`; sigil-free
65
+ * authoring YAML via the raw YAML walker — `overlay: true` is a bare key
66
+ * before desugar) and report every top-level declaration under
67
+ * `metadata.root.children`: its type, the resolution key it would carry once
68
+ * parsed, and whether it carries `overlay: true`.
69
+ *
70
+ * A declaration with no (string, non-empty) `name` is skipped — a resolution
71
+ * key can't be computed for it, and the real parser will report it as a
72
+ * loader error rather than silently reusing or creating a node. Malformed
73
+ * root shapes (root missing, not an object, `children` absent or not an
74
+ * array) return `[]` rather than throwing — the real parse loop is where a
75
+ * genuine structural error surfaces; this walk must never crash a caller
76
+ * that is only trying to answer "what does this file declare".
77
+ *
78
+ * Written for the #160 overlay-only source partition, which ADR-0055 retired —
79
+ * overlays are now applied in a post-parse pass, so no ordering decision needs
80
+ * this walk. Its remaining caller is the `meta verify` overlay authoring lint,
81
+ * which needs per-file declaration provenance precisely because the MERGED tree
82
+ * has already lost which file contributed which declaration.
83
+ */
84
+ export declare function declaredTopLevelKeys(content: string, format: MetaDataFormat): Promise<ReadonlyArray<DeclaredTopLevelKey>>;
41
85
  export declare class MetaDataLoader {
42
86
  private readonly _registry;
43
87
  private readonly _freeze;
@@ -120,27 +164,6 @@ export declare class MetaDataLoader {
120
164
  protected parseSource(content: string, source: MetaDataSource, parseOpts: ParseOptions): ParseResult;
121
165
  private static _yamlParser;
122
166
  private static _ensureYamlParser;
123
- /**
124
- * Stable-partition `sources` so that "overlay-only" sources — every top-level
125
- * object declaration carries `overlay: true`, i.e. the source declares no base
126
- * objects of its own and only re-opens objects declared elsewhere — are parsed
127
- * LAST. Preserves original order within each group.
128
- *
129
- * A source whose content can't be read or structurally scanned stays in the
130
- * base group (never overlay-only) — this partition must never crash the loader;
131
- * any genuine read/parse failure surfaces later, in the real parse loop.
132
- */
133
- private static _partitionOverlayLast;
134
- /**
135
- * Structurally scan a source's raw content (JSON via JSON.parse; sigil-free
136
- * authoring YAML via the raw YAML walker — `overlay: true` is a bare key
137
- * before desugar) and report whether every top-level object declaration under
138
- * `metadata.root.children` carries `overlay: true` (and there is at least one).
139
- */
140
- private static _isOverlayOnlySource;
141
- /** True when the structurally-parsed root has ≥1 child and every top-level
142
- * child node carries `overlay: true` (declares no base objects). */
143
- private static _rootIsOverlayOnly;
144
167
  /**
145
168
  * Load metadata from one or more MetaDataSource instances. Sources are read
146
169
  * in order; each source's content is parsed and merged into the accumulating
@@ -1 +1 @@
1
- {"version":3,"file":"meta-data-loader.d.ts","sourceRoot":"","sources":["../../src/loader/meta-data-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"meta-data-loader.d.ts","sourceRoot":"","sources":["../../src/loader/meta-data-loader.ts"],"names":[],"mappings":"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"}
@@ -11,11 +11,11 @@ import { TypeId, TypeRegistry } from "../registry.js";
11
11
  import { coreProviders } from "../core-types.js";
12
12
  import { composeRegistry } from "../provider.js";
13
13
  import { TYPE_METADATA, SUBTYPE_ROOT } from "../shared/base-types.js";
14
- import { RESERVED_KEY_CHILDREN, RESERVED_KEY_OVERLAY } from "../shared/structural.js";
14
+ import { PACKAGE_SEPARATOR, RESERVED_KEY_CHILDREN, RESERVED_KEY_NAME, RESERVED_KEY_OVERLAY, RESERVED_KEY_PACKAGE, TYPE_SUBTYPE_SEPARATOR, } from "../shared/structural.js";
15
15
  import { ParseError } from "../errors.js";
16
16
  import { codeSource, resolvedSource } from "../source.js";
17
17
  import { parseJson } from "../parser-json.js";
18
- import { validateDataGridSortFields, validateFilterableHasIndex, validateFilterableHasSupportedOps, validateSortableHasSupportedSubtype, validateOriginPaths, validateDerivedFieldProvidability, validateDataGridFilterValues, validateFieldObjectStorage, validateFieldMap, validateTemplatePayloadRefs, validateFieldDefaults, validateRelationships, validateIndexLookupFields, validateProjectionFilter, validateRetiredRequirementLinks } from "./validation-passes.js";
18
+ import { validateDataGridSortFields, validateFilterableHasIndex, validateFilterableHasSupportedOps, validateSortableHasSupportedSubtype, validateOriginPaths, validateDerivedFieldProvidability, validateDataGridFilterValues, validateFieldObjectStorage, validateFieldMap, validateTemplatePayloadRefs, validateFieldDefaults, validateRelationships, validateOneSideReferenceResolution, validateIndexLookupFields, validateProjectionFilter, validateRetiredRequirementLinks } from "./validation-passes.js";
19
19
  import { runRegisteredValidation } from "./validation-registry.js";
20
20
  import { validateSourceRoles } from "../persistence/source/validate-source-roles.js";
21
21
  import { validateSourceEscapes } from "../persistence/source/validate-source-escapes.js";
@@ -30,12 +30,94 @@ import { validateMaxOccurs } from "../validate-max-occurs.js";
30
30
  import { validateIdentityPassthrough } from "../core/identity/validate-identity-passthrough.js";
31
31
  import { validateAttrSchema } from "../attr-schema-validate.js";
32
32
  import { InMemoryStringSource } from "./meta-data-source.js";
33
+ import { expandPackageForPath, applyPendingOverlays } from "../parser-core.js";
33
34
  // ---------------------------------------------------------------------------
34
35
  // Synthetic empty root (used when all sources fail to parse)
35
36
  // ---------------------------------------------------------------------------
36
37
  function makeSyntheticRoot() {
37
38
  return new MetaRoot(new TypeId(TYPE_METADATA, SUBTYPE_ROOT), "");
38
39
  }
40
+ /**
41
+ * Structurally scan a source's raw content (JSON via `JSON.parse`; sigil-free
42
+ * authoring YAML via the raw YAML walker — `overlay: true` is a bare key
43
+ * before desugar) and report every top-level declaration under
44
+ * `metadata.root.children`: its type, the resolution key it would carry once
45
+ * parsed, and whether it carries `overlay: true`.
46
+ *
47
+ * A declaration with no (string, non-empty) `name` is skipped — a resolution
48
+ * key can't be computed for it, and the real parser will report it as a
49
+ * loader error rather than silently reusing or creating a node. Malformed
50
+ * root shapes (root missing, not an object, `children` absent or not an
51
+ * array) return `[]` rather than throwing — the real parse loop is where a
52
+ * genuine structural error surfaces; this walk must never crash a caller
53
+ * that is only trying to answer "what does this file declare".
54
+ *
55
+ * Written for the #160 overlay-only source partition, which ADR-0055 retired —
56
+ * overlays are now applied in a post-parse pass, so no ordering decision needs
57
+ * this walk. Its remaining caller is the `meta verify` overlay authoring lint,
58
+ * which needs per-file declaration provenance precisely because the MERGED tree
59
+ * has already lost which file contributed which declaration.
60
+ */
61
+ export async function declaredTopLevelKeys(content, format) {
62
+ // Strip UTF-8 BOM if present (mirrors parseJson / parseYaml).
63
+ const normalized = content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;
64
+ let parsed;
65
+ if (format === "json") {
66
+ parsed = JSON.parse(normalized);
67
+ }
68
+ else if (format === "yaml") {
69
+ const { parseYamlWithPositions } = await import("../core/yaml-positions-walker.js");
70
+ parsed = parseYamlWithPositions(normalized).value;
71
+ }
72
+ else {
73
+ return [];
74
+ }
75
+ return declaredTopLevelKeysFromParsedRoot(parsed);
76
+ }
77
+ /** The structural walk `declaredTopLevelKeys` performs once content is
78
+ * structurally parsed — split out so it takes no format/BOM concerns. */
79
+ function declaredTopLevelKeysFromParsedRoot(parsed) {
80
+ if (typeof parsed !== "object" || parsed === null)
81
+ return [];
82
+ const parsedRecord = parsed;
83
+ // Canonical JSON always fuses the subType onto the root wrapper key
84
+ // ("metadata.root"); sigil-free YAML authoring writes the bare type
85
+ // ("metadata") and leaves the default subType to the registry — this
86
+ // structural walk runs BEFORE desugar/registry resolution, so it must
87
+ // accept both spellings rather than only ever matching JSON's.
88
+ const explicitRootKey = `${TYPE_METADATA}${TYPE_SUBTYPE_SEPARATOR}${SUBTYPE_ROOT}`; // "metadata.root"
89
+ const rootBody = parsedRecord[explicitRootKey] ?? parsedRecord[TYPE_METADATA];
90
+ if (typeof rootBody !== "object" || rootBody === null)
91
+ return [];
92
+ const rawRootPkg = rootBody[RESERVED_KEY_PACKAGE];
93
+ const rootPkg = typeof rawRootPkg === "string" ? rawRootPkg : "";
94
+ const children = rootBody[RESERVED_KEY_CHILDREN];
95
+ if (!Array.isArray(children))
96
+ return [];
97
+ const declared = [];
98
+ for (const child of children) {
99
+ if (typeof child !== "object" || child === null)
100
+ continue;
101
+ // Each child is a single-key wrapper: { "object.entity": { ... } }.
102
+ for (const [wrapperKey, body] of Object.entries(child)) {
103
+ if (typeof body !== "object" || body === null)
104
+ continue;
105
+ const bodyRecord = body;
106
+ const name = bodyRecord[RESERVED_KEY_NAME];
107
+ if (typeof name !== "string" || name === "")
108
+ continue;
109
+ const dotIdx = wrapperKey.indexOf(TYPE_SUBTYPE_SEPARATOR);
110
+ const type = dotIdx < 0 ? wrapperKey : wrapperKey.slice(0, dotIdx);
111
+ const rawOwnPkg = bodyRecord[RESERVED_KEY_PACKAGE];
112
+ const pkg = typeof rawOwnPkg === "string" && rawOwnPkg !== ""
113
+ ? expandPackageForPath(rootPkg, rawOwnPkg)
114
+ : rootPkg;
115
+ const key = pkg !== "" ? `${pkg}${PACKAGE_SEPARATOR}${name}` : name;
116
+ declared.push({ type, key, overlay: bodyRecord[RESERVED_KEY_OVERLAY] === true });
117
+ }
118
+ }
119
+ return declared;
120
+ }
39
121
  // ---------------------------------------------------------------------------
40
122
  // MetaDataLoader class
41
123
  // ---------------------------------------------------------------------------
@@ -230,80 +312,6 @@ export class MetaDataLoader {
230
312
  MetaDataLoader._yamlParser = mod.parseYaml;
231
313
  }
232
314
  // ---------------------------------------------------------------------------
233
- // #160 — overlay-only source partition (stable, overlay-only sources last)
234
- // ---------------------------------------------------------------------------
235
- /**
236
- * Stable-partition `sources` so that "overlay-only" sources — every top-level
237
- * object declaration carries `overlay: true`, i.e. the source declares no base
238
- * objects of its own and only re-opens objects declared elsewhere — are parsed
239
- * LAST. Preserves original order within each group.
240
- *
241
- * A source whose content can't be read or structurally scanned stays in the
242
- * base group (never overlay-only) — this partition must never crash the loader;
243
- * any genuine read/parse failure surfaces later, in the real parse loop.
244
- */
245
- static async _partitionOverlayLast(sources) {
246
- const base = [];
247
- const overlayOnly = [];
248
- for (const source of sources) {
249
- let isOverlayOnly = false;
250
- try {
251
- const content = await source.read();
252
- isOverlayOnly = await MetaDataLoader._isOverlayOnlySource(content, source.format);
253
- }
254
- catch {
255
- isOverlayOnly = false;
256
- }
257
- (isOverlayOnly ? overlayOnly : base).push(source);
258
- }
259
- return [...base, ...overlayOnly];
260
- }
261
- /**
262
- * Structurally scan a source's raw content (JSON via JSON.parse; sigil-free
263
- * authoring YAML via the raw YAML walker — `overlay: true` is a bare key
264
- * before desugar) and report whether every top-level object declaration under
265
- * `metadata.root.children` carries `overlay: true` (and there is at least one).
266
- */
267
- static async _isOverlayOnlySource(content, format) {
268
- // Strip UTF-8 BOM if present (mirrors parseJson / parseYaml).
269
- const normalized = content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;
270
- let parsed;
271
- if (format === "json") {
272
- parsed = JSON.parse(normalized);
273
- }
274
- else if (format === "yaml") {
275
- const { parseYamlWithPositions } = await import("../core/yaml-positions-walker.js");
276
- parsed = parseYamlWithPositions(normalized).value;
277
- }
278
- else {
279
- return false;
280
- }
281
- return MetaDataLoader._rootIsOverlayOnly(parsed);
282
- }
283
- /** True when the structurally-parsed root has ≥1 child and every top-level
284
- * child node carries `overlay: true` (declares no base objects). */
285
- static _rootIsOverlayOnly(parsed) {
286
- if (typeof parsed !== "object" || parsed === null)
287
- return false;
288
- const rootKey = `${TYPE_METADATA}.${SUBTYPE_ROOT}`; // "metadata.root"
289
- const rootBody = parsed[rootKey];
290
- if (typeof rootBody !== "object" || rootBody === null)
291
- return false;
292
- const children = rootBody[RESERVED_KEY_CHILDREN];
293
- if (!Array.isArray(children) || children.length === 0)
294
- return false;
295
- return children.every((child) => {
296
- if (typeof child !== "object" || child === null)
297
- return false;
298
- // Each child is a single-key wrapper: { "object.projection": { ... } }.
299
- const bodies = Object.values(child);
300
- return (bodies.length > 0 &&
301
- bodies.every((body) => typeof body === "object" &&
302
- body !== null &&
303
- body[RESERVED_KEY_OVERLAY] === true));
304
- });
305
- }
306
- // ---------------------------------------------------------------------------
307
315
  // load — async pipeline over MetaDataSource[]
308
316
  // ---------------------------------------------------------------------------
309
317
  /**
@@ -338,19 +346,17 @@ export class MetaDataLoader {
338
346
  if (sources.some((s) => s.format === "yaml")) {
339
347
  await MetaDataLoader._ensureYamlParser();
340
348
  }
341
- // #160this loader merges DURING parse (each source is streamed into the
342
- // accumulating `root` via parseOpts.intoRoot). A source that ONLY re-opens
343
- // objects declared elsewhere (every top-level object carries `overlay: true`)
344
- // must therefore be parsed AFTER the sources that declare those base objects,
345
- // or the overlaid node lands ahead of its base entities — leaving a projection
346
- // before its base so order-dependent super-resolution can't resolve its
347
- // `extends`/`@via`, and the streaming merge errors ERR_OVERLAY_NO_TARGET.
348
- // Directory discovery order is not guaranteed to present base files first
349
- // (basename sort can put an overlay-only file first), so stable-partition
350
- // overlay-only sources to the END here, making the merge order-independent.
351
- // Stable within each group preserves last-writer-wins overlay semantics.
352
- sources = await MetaDataLoader._partitionOverlayLast(sources);
349
+ // ADR-0055sources are parsed in the order given. Overlays are not applied
350
+ // during the walk: each parse QUEUES its `overlay: true` declarations and the
351
+ // loader applies them below, once every base exists. That retired the #160
352
+ // overlay-only source partition, whose file-level predicate could not rescue a
353
+ // MIXED file (plain + overlay declarations together) and therefore left the
354
+ // load order-dependent and divergent across ports, since every port's
355
+ // directory walk orders files differently.
353
356
  let root;
357
+ // ADR-0055 — every source's queue, concatenated in parse order, which is
358
+ // already "source order, then declaration order within a source" (G2).
359
+ const pendingOverlays = [];
354
360
  // Parse all sources with super resolution DEFERRED so cross-file super
355
361
  // refs work — one source may declare a super target that's defined in a
356
362
  // source parsed later. A second pass (resolveDeferredSupers) resolves
@@ -372,6 +378,10 @@ export class MetaDataLoader {
372
378
  registry: this._registry,
373
379
  strict: this._strict,
374
380
  deferSuperResolution: true,
381
+ // ADR-0055 — queue overlays; this loader drains them after every source
382
+ // is parsed. Without it each document would drain its own queue and an
383
+ // overlay could still not reach a base declared in a later source.
384
+ deferOverlays: true,
375
385
  sourceName: source.id,
376
386
  };
377
387
  if (root !== undefined)
@@ -384,6 +394,7 @@ export class MetaDataLoader {
384
394
  // source). The legacy `warnings` channel still flows into the
385
395
  // WARN_LEGACY-wrapping path below for unchanged behavior.
386
396
  envelopeWarnings.push(...parseResult.envelopeWarnings);
397
+ pendingOverlays.push(...parseResult.pendingOverlays);
387
398
  root = parseResult.root;
388
399
  }
389
400
  catch (err) {
@@ -392,6 +403,20 @@ export class MetaDataLoader {
392
403
  : new Error(`Parse error in "${source.id}": ${String(err)}`));
393
404
  }
394
405
  }
406
+ // ADR-0055 — apply every queued overlay now: all plain declarations from all
407
+ // sources are in the tree (G1), so a base/overlay relation no longer depends
408
+ // on file order (G4). This runs BEFORE super resolution so a node an overlay
409
+ // contributes is visible to every `extends` (G5) — the ordering #160's
410
+ // partition was reaching for, now guaranteed rather than approximated.
411
+ if (root !== undefined && pendingOverlays.length > 0) {
412
+ const applied = applyPendingOverlays(pendingOverlays, {
413
+ registry: this._registry,
414
+ strict: this._strict,
415
+ });
416
+ warnings.push(...applied.warnings);
417
+ errors.push(...applied.errors);
418
+ envelopeWarnings.push(...applied.envelopeWarnings);
419
+ }
395
420
  // Second pass: resolve every deferred super ref against the full tree.
396
421
  // Unresolved refs are always errors (matches the original eager-throw
397
422
  // behavior — broken metadata is broken regardless of strict mode).
@@ -458,6 +483,11 @@ export class MetaDataLoader {
458
483
  // @symmetric is self-join-only + mutually exclusive with @sourceRefField; M:N attrs
459
484
  // are invalid on a 1:N relationship.
460
485
  errors.push(...validateRelationships(root));
486
+ // Rule (e) — #368: a `@cardinality: one` relationship must resolve to
487
+ // exactly one identity.reference when its declaring entity holds more
488
+ // than one onto the same target; an unresolvable case is a load error
489
+ // naming the candidates (ADR-0029 §5).
490
+ errors.push(...validateOneSideReferenceResolution(root));
461
491
  // index.lookup @fields resolution — each index.lookup must name ≥1 field,
462
492
  // and every field must exist in the entity's effective (resolved) field set
463
493
  // (ADR-0039: resolving accessor, so inherited fields via extends are visible).