@metaobjectsdev/metadata 0.7.0-rc.1 → 0.7.0-rc.11
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/core/parser-yaml.d.ts.map +1 -1
- package/dist/core/parser-yaml.js +24 -8
- package/dist/core/parser-yaml.js.map +1 -1
- package/dist/core/yaml-desugar.d.ts.map +1 -1
- package/dist/core/yaml-desugar.js +54 -5
- package/dist/core/yaml-desugar.js.map +1 -1
- package/dist/core/yaml-positions-walker.d.ts +21 -0
- package/dist/core/yaml-positions-walker.d.ts.map +1 -0
- package/dist/core/yaml-positions-walker.js +75 -0
- package/dist/core/yaml-positions-walker.js.map +1 -0
- package/dist/core/yaml-positions.d.ts +19 -0
- package/dist/core/yaml-positions.d.ts.map +1 -0
- package/dist/core/yaml-positions.js +60 -0
- package/dist/core/yaml-positions.js.map +1 -0
- package/dist/core-types.d.ts.map +1 -1
- package/dist/core-types.js +7 -4
- package/dist/core-types.js.map +1 -1
- package/dist/errors.d.ts +4 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -1
- package/dist/loader/meta-data-loader.d.ts.map +1 -1
- package/dist/loader/meta-data-loader.js +26 -6
- 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 +81 -17
- package/dist/loader/validation-passes.js.map +1 -1
- package/dist/parser-core.d.ts +16 -1
- package/dist/parser-core.d.ts.map +1 -1
- package/dist/parser-core.js +266 -8
- package/dist/parser-core.js.map +1 -1
- package/dist/source.d.ts +29 -1
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +25 -0
- package/dist/source.js.map +1 -1
- package/dist/template/template-constants.d.ts +3 -1
- package/dist/template/template-constants.d.ts.map +1 -1
- package/dist/template/template-constants.js +22 -6
- package/dist/template/template-constants.js.map +1 -1
- package/dist/template/template-schema.d.ts.map +1 -1
- package/dist/template/template-schema.js +41 -1
- package/dist/template/template-schema.js.map +1 -1
- package/package.json +1 -1
- package/src/core/parser-yaml.ts +24 -8
- package/src/core/yaml-desugar.ts +58 -4
- package/src/core/yaml-positions-walker.ts +101 -0
- package/src/core/yaml-positions.ts +80 -0
- package/src/core-types.ts +7 -4
- package/src/errors.ts +15 -0
- package/src/loader/meta-data-loader.ts +26 -6
- package/src/loader/validation-passes.ts +83 -20
- package/src/parser-core.ts +306 -10
- package/src/source.ts +40 -2
- package/src/template/template-constants.ts +23 -6
- package/src/template/template-schema.ts +43 -0
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import type { MetaData } from "../shared/meta-data.js";
|
|
13
13
|
import { ParseError } from "../errors.js";
|
|
14
|
-
import type
|
|
14
|
+
import { resolvedSource, type ErrorSource } from "../source.js";
|
|
15
15
|
import {
|
|
16
16
|
TYPE_OBJECT,
|
|
17
17
|
TYPE_FIELD,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
TEMPLATE_ATTR_PAYLOAD_REF,
|
|
26
26
|
TEMPLATE_ATTR_REQUIRED_SLOTS,
|
|
27
27
|
} from "../template/template-constants.js";
|
|
28
|
+
import { OBJECT_SUBTYPE_VALUE } from "../core/object/object-constants.js";
|
|
28
29
|
import {
|
|
29
30
|
LAYOUT_SUBTYPE_DATA_GRID,
|
|
30
31
|
LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD,
|
|
@@ -99,11 +100,16 @@ export function validateTemplatePayloadRefs(root: MetaData): ParseError[] {
|
|
|
99
100
|
const payloadRef = tmpl.ownAttr(TEMPLATE_ATTR_PAYLOAD_REF);
|
|
100
101
|
if (typeof payloadRef !== "string") continue; // absence handled by the required-attr schema check
|
|
101
102
|
const payload = root.ownChildren().find((c) => c.type === TYPE_OBJECT && c.name === payloadRef);
|
|
102
|
-
if (!payload) {
|
|
103
|
+
if (!payload || payload.subType !== OBJECT_SUBTYPE_VALUE) {
|
|
104
|
+
// FR5d — @payloadRef is a reference; emit format=resolved with
|
|
105
|
+
// referrer=template FQN, target=the unresolved payloadRef string.
|
|
103
106
|
errors.push(
|
|
104
107
|
new ParseError(
|
|
105
|
-
`template "${tmpl.name}" @payloadRef "${payloadRef}" does not resolve to
|
|
106
|
-
{
|
|
108
|
+
`template "${tmpl.name}" @payloadRef "${payloadRef}" does not resolve to an object.value at root`,
|
|
109
|
+
{
|
|
110
|
+
code: "ERR_INVALID_TEMPLATE",
|
|
111
|
+
source: resolvedSource(tmpl.source, tmpl.fqn(), payloadRef),
|
|
112
|
+
},
|
|
107
113
|
),
|
|
108
114
|
);
|
|
109
115
|
continue;
|
|
@@ -115,11 +121,17 @@ export function validateTemplatePayloadRefs(root: MetaData): ParseError[] {
|
|
|
115
121
|
const slotList = Array.isArray(slots) ? slots : typeof slots === "string" ? [slots] : [];
|
|
116
122
|
for (const slot of slotList) {
|
|
117
123
|
if (typeof slot === "string" && !fieldNames.has(slot)) {
|
|
124
|
+
// FR5d — @requiredSlots is a field-on-payload reference; emit
|
|
125
|
+
// format=resolved with referrer=template FQN, target=`payloadRef.slot`
|
|
126
|
+
// (the dotted ref that did not resolve to a payload field).
|
|
118
127
|
errors.push(
|
|
119
128
|
new ParseError(
|
|
120
129
|
`template "${tmpl.name}" @requiredSlots "${slot}" is not a field on payload "${payloadRef}". ` +
|
|
121
130
|
`Available fields: ${[...fieldNames].join(", ")}`,
|
|
122
|
-
{
|
|
131
|
+
{
|
|
132
|
+
code: "ERR_INVALID_TEMPLATE",
|
|
133
|
+
source: resolvedSource(tmpl.source, tmpl.fqn(), `${payloadRef}.${slot}`),
|
|
134
|
+
},
|
|
123
135
|
),
|
|
124
136
|
);
|
|
125
137
|
}
|
|
@@ -195,18 +207,28 @@ function _findRelationship(obj: MetaData, name: string): MetaData | undefined {
|
|
|
195
207
|
function _validateFromPath(
|
|
196
208
|
fromAttr: string,
|
|
197
209
|
root: MetaData,
|
|
198
|
-
|
|
210
|
+
projection: MetaData,
|
|
199
211
|
fieldName: string,
|
|
200
212
|
originSource: ErrorSource,
|
|
201
213
|
errors: ParseError[],
|
|
202
214
|
label: string = "origin.passthrough.@from",
|
|
203
215
|
): void {
|
|
216
|
+
const projectionName = projection.name;
|
|
217
|
+
// FR5d — referrer is `<projection-FQN>::<fieldName>` (the canonical
|
|
218
|
+
// "where the broken reference lives" identifier).
|
|
219
|
+
const referrer = `${projection.fqn()}::${fieldName}`;
|
|
204
220
|
const dotIdx = fromAttr.indexOf(".");
|
|
205
221
|
if (dotIdx < 1 || dotIdx === fromAttr.length - 1) {
|
|
222
|
+
// Malformed shape (not "Entity.field") — not a reference resolution
|
|
223
|
+
// failure per se, but emit format=resolved with target=the bad string
|
|
224
|
+
// so consumers see the same envelope shape across all FR5d sites.
|
|
206
225
|
errors.push(
|
|
207
226
|
new ParseError(
|
|
208
227
|
`${label} "${fromAttr}" on ${projectionName}.${fieldName}: must be of form "Entity.field".`,
|
|
209
|
-
{
|
|
228
|
+
{
|
|
229
|
+
code: "ERR_INVALID_ORIGIN",
|
|
230
|
+
source: resolvedSource(originSource, referrer, fromAttr),
|
|
231
|
+
},
|
|
210
232
|
),
|
|
211
233
|
);
|
|
212
234
|
return;
|
|
@@ -215,20 +237,28 @@ function _validateFromPath(
|
|
|
215
237
|
const targetFieldName = fromAttr.slice(dotIdx + 1);
|
|
216
238
|
const sourceObj = _findObject(root, entityName);
|
|
217
239
|
if (!sourceObj) {
|
|
240
|
+
// FR5d — entity half of the ref didn't resolve. target = full ref.
|
|
218
241
|
errors.push(
|
|
219
242
|
new ParseError(
|
|
220
243
|
`${label} "${fromAttr}" on ${projectionName}.${fieldName}: no such entity "${entityName}".`,
|
|
221
|
-
{
|
|
244
|
+
{
|
|
245
|
+
code: "ERR_INVALID_ORIGIN",
|
|
246
|
+
source: resolvedSource(originSource, referrer, fromAttr),
|
|
247
|
+
},
|
|
222
248
|
),
|
|
223
249
|
);
|
|
224
250
|
return;
|
|
225
251
|
}
|
|
226
252
|
const sourceField = _findField(sourceObj, targetFieldName);
|
|
227
253
|
if (!sourceField) {
|
|
254
|
+
// FR5d — entity resolved, field on it did not. target = full ref.
|
|
228
255
|
errors.push(
|
|
229
256
|
new ParseError(
|
|
230
257
|
`${label} "${fromAttr}" on ${projectionName}.${fieldName}: no such field "${targetFieldName}" on ${entityName}.`,
|
|
231
|
-
{
|
|
258
|
+
{
|
|
259
|
+
code: "ERR_INVALID_ORIGIN",
|
|
260
|
+
source: resolvedSource(originSource, referrer, fromAttr),
|
|
261
|
+
},
|
|
232
262
|
),
|
|
233
263
|
);
|
|
234
264
|
}
|
|
@@ -237,17 +267,23 @@ function _validateFromPath(
|
|
|
237
267
|
function _validateViaPath(
|
|
238
268
|
viaAttr: string,
|
|
239
269
|
root: MetaData,
|
|
240
|
-
|
|
270
|
+
projection: MetaData,
|
|
241
271
|
fieldName: string,
|
|
242
272
|
originSource: ErrorSource,
|
|
243
273
|
errors: ParseError[],
|
|
244
274
|
): void {
|
|
275
|
+
const projectionName = projection.name;
|
|
276
|
+
// FR5d — referrer is `<projection-FQN>::<fieldName>`.
|
|
277
|
+
const referrer = `${projection.fqn()}::${fieldName}`;
|
|
245
278
|
const segments = viaAttr.split(".");
|
|
246
279
|
if (segments.length < 2) {
|
|
247
280
|
errors.push(
|
|
248
281
|
new ParseError(
|
|
249
282
|
`origin.@via "${viaAttr}" on ${projectionName}.${fieldName}: must be of form "Entity.relationship[.relationship...]".`,
|
|
250
|
-
{
|
|
283
|
+
{
|
|
284
|
+
code: "ERR_INVALID_ORIGIN",
|
|
285
|
+
source: resolvedSource(originSource, referrer, viaAttr),
|
|
286
|
+
},
|
|
251
287
|
),
|
|
252
288
|
);
|
|
253
289
|
return;
|
|
@@ -258,18 +294,32 @@ function _validateViaPath(
|
|
|
258
294
|
errors.push(
|
|
259
295
|
new ParseError(
|
|
260
296
|
`origin.@via "${viaAttr}" on ${projectionName}.${fieldName}: no such entity "${entityName}".`,
|
|
261
|
-
{
|
|
297
|
+
{
|
|
298
|
+
code: "ERR_INVALID_ORIGIN",
|
|
299
|
+
source: resolvedSource(originSource, referrer, viaAttr),
|
|
300
|
+
},
|
|
262
301
|
),
|
|
263
302
|
);
|
|
264
303
|
return;
|
|
265
304
|
}
|
|
305
|
+
// FR5d — track the deepest-valid-prefix as we walk. The prefix grows
|
|
306
|
+
// segment-by-segment; on a hop failure the error message names the prefix
|
|
307
|
+
// that DID resolve, so authors can fix multi-hop typos quickly.
|
|
308
|
+
// After the entity lookup above, the deepest valid prefix is just the
|
|
309
|
+
// entity name; each successful relationship hop appends a segment.
|
|
310
|
+
const validSegments: string[] = [entityName];
|
|
266
311
|
for (const relName of relSegments) {
|
|
267
312
|
const rel = _findRelationship(currentObj, relName);
|
|
268
313
|
if (!rel) {
|
|
314
|
+
const prefix = validSegments.join(".");
|
|
269
315
|
errors.push(
|
|
270
316
|
new ParseError(
|
|
271
|
-
`origin.@via "${viaAttr}" on ${projectionName}.${fieldName}: no such relationship "${relName}" on ${currentObj.name}
|
|
272
|
-
|
|
317
|
+
`origin.@via "${viaAttr}" on ${projectionName}.${fieldName}: no such relationship "${relName}" on ${currentObj.name}. ` +
|
|
318
|
+
`Deepest valid prefix was "${prefix}".`,
|
|
319
|
+
{
|
|
320
|
+
code: "ERR_INVALID_ORIGIN",
|
|
321
|
+
source: resolvedSource(originSource, referrer, viaAttr),
|
|
322
|
+
},
|
|
273
323
|
),
|
|
274
324
|
);
|
|
275
325
|
return;
|
|
@@ -279,21 +329,32 @@ function _validateViaPath(
|
|
|
279
329
|
errors.push(
|
|
280
330
|
new ParseError(
|
|
281
331
|
`origin.@via "${viaAttr}" on ${projectionName}.${fieldName}: relationship "${relName}" on ${currentObj.name} is missing @objectRef.`,
|
|
282
|
-
{
|
|
332
|
+
{
|
|
333
|
+
code: "ERR_INVALID_ORIGIN",
|
|
334
|
+
source: resolvedSource(originSource, referrer, viaAttr),
|
|
335
|
+
},
|
|
283
336
|
),
|
|
284
337
|
);
|
|
285
338
|
return;
|
|
286
339
|
}
|
|
287
340
|
const nextObj = _findObject(root, refTarget);
|
|
288
341
|
if (!nextObj) {
|
|
342
|
+
// FR5d — relationship's @objectRef points at a missing entity. This
|
|
343
|
+
// is the @objectRef-resolution edge of the via-path walk (the "5th
|
|
344
|
+
// site" in FR5d's scope list for @objectRef references encountered
|
|
345
|
+
// transitively).
|
|
289
346
|
errors.push(
|
|
290
347
|
new ParseError(
|
|
291
348
|
`origin.@via "${viaAttr}" on ${projectionName}.${fieldName}: relationship "${relName}" points to non-existent entity "${refTarget}".`,
|
|
292
|
-
{
|
|
349
|
+
{
|
|
350
|
+
code: "ERR_INVALID_ORIGIN",
|
|
351
|
+
source: resolvedSource(originSource, referrer, refTarget),
|
|
352
|
+
},
|
|
293
353
|
),
|
|
294
354
|
);
|
|
295
355
|
return;
|
|
296
356
|
}
|
|
357
|
+
validSegments.push(relName);
|
|
297
358
|
currentObj = nextObj;
|
|
298
359
|
}
|
|
299
360
|
}
|
|
@@ -306,6 +367,8 @@ export function validateOriginPaths(root: MetaData): ParseError[] {
|
|
|
306
367
|
if (origin.subType === ORIGIN_SUBTYPE_PASSTHROUGH) {
|
|
307
368
|
const from = origin.ownAttr(ORIGIN_PASSTHROUGH_ATTR_FROM);
|
|
308
369
|
if (typeof from !== "string" || from === "") {
|
|
370
|
+
// Missing-attr (not a reference resolution failure) — keep the
|
|
371
|
+
// node's own source envelope (json/yaml/merged).
|
|
309
372
|
errors.push(
|
|
310
373
|
new ParseError(
|
|
311
374
|
`origin.passthrough on ${obj.name}.${field.name}: missing @from.`,
|
|
@@ -314,10 +377,10 @@ export function validateOriginPaths(root: MetaData): ParseError[] {
|
|
|
314
377
|
);
|
|
315
378
|
continue;
|
|
316
379
|
}
|
|
317
|
-
_validateFromPath(from, root, obj
|
|
380
|
+
_validateFromPath(from, root, obj, field.name, origin.source, errors);
|
|
318
381
|
const via = origin.ownAttr(ORIGIN_PASSTHROUGH_ATTR_VIA);
|
|
319
382
|
if (typeof via === "string" && via !== "") {
|
|
320
|
-
_validateViaPath(via, root, obj
|
|
383
|
+
_validateViaPath(via, root, obj, field.name, origin.source, errors);
|
|
321
384
|
}
|
|
322
385
|
} else if (origin.subType === ORIGIN_SUBTYPE_AGGREGATE) {
|
|
323
386
|
const of_ = origin.ownAttr(ORIGIN_AGGREGATE_ATTR_OF);
|
|
@@ -330,7 +393,7 @@ export function validateOriginPaths(root: MetaData): ParseError[] {
|
|
|
330
393
|
);
|
|
331
394
|
continue;
|
|
332
395
|
}
|
|
333
|
-
_validateFromPath(of_, root, obj
|
|
396
|
+
_validateFromPath(of_, root, obj, field.name, origin.source, errors, "origin.aggregate.@of");
|
|
334
397
|
const via = origin.ownAttr(ORIGIN_AGGREGATE_ATTR_VIA);
|
|
335
398
|
if (typeof via !== "string" || via === "") {
|
|
336
399
|
errors.push(
|
|
@@ -341,7 +404,7 @@ export function validateOriginPaths(root: MetaData): ParseError[] {
|
|
|
341
404
|
);
|
|
342
405
|
continue;
|
|
343
406
|
}
|
|
344
|
-
_validateViaPath(via, root, obj
|
|
407
|
+
_validateViaPath(via, root, obj, field.name, origin.source, errors);
|
|
345
408
|
}
|
|
346
409
|
}
|
|
347
410
|
}
|