@fedify/vocab-tools 2.4.0-dev.2155 → 2.4.0-dev.2159
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/deno.json +1 -1
- package/dist/mod.cjs +61 -37
- package/dist/mod.js +61 -37
- package/package.json +1 -1
- package/src/__snapshots__/class.test.ts.deno.snap +2771 -1818
- package/src/__snapshots__/class.test.ts.node.snap +2771 -1818
- package/src/__snapshots__/class.test.ts.snap +2771 -1818
- package/src/class.ts +11 -0
- package/src/codec.ts +9 -0
- package/src/property.ts +31 -23
- package/src/type.ts +15 -4
package/src/class.ts
CHANGED
|
@@ -304,6 +304,17 @@ export async function* generateClasses(
|
|
|
304
304
|
isTemporalInstant,
|
|
305
305
|
} from "@fedify/vocab-runtime/temporal";\n`;
|
|
306
306
|
yield `
|
|
307
|
+
function canDecodeIri(iri: string): boolean {
|
|
308
|
+
try { parseIri(iri); return true; } catch { return iri.startsWith("at://"); }
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function decodeIri(iri: string): URL {
|
|
312
|
+
return !URL.canParse(iri) && iri.startsWith("at://")
|
|
313
|
+
? new URL("at://" + encodeURIComponent(iri.substring(5)))
|
|
314
|
+
: parseIri(iri);
|
|
315
|
+
}
|
|
316
|
+
`;
|
|
317
|
+
yield `
|
|
307
318
|
function isValidLanguageTag(language: string): boolean {
|
|
308
319
|
try {
|
|
309
320
|
new Intl.Locale(language);
|
package/src/codec.ts
CHANGED
|
@@ -6,12 +6,14 @@ import {
|
|
|
6
6
|
areAllScalarTypes,
|
|
7
7
|
emitOverride,
|
|
8
8
|
getAllProperties,
|
|
9
|
+
getDataCheck,
|
|
9
10
|
getDecoder,
|
|
10
11
|
getDecoders,
|
|
11
12
|
getEncoders,
|
|
12
13
|
getSubtypes,
|
|
13
14
|
getTypeNames,
|
|
14
15
|
isCompactableType,
|
|
16
|
+
skipsUnparsable,
|
|
15
17
|
} from "./type.ts";
|
|
16
18
|
|
|
17
19
|
function* generatePreprocessorBlock(
|
|
@@ -591,7 +593,13 @@ export async function* generateDecoder(
|
|
|
591
593
|
yield `
|
|
592
594
|
const decoded =
|
|
593
595
|
`;
|
|
596
|
+
const lenient = property.range.length == 1 &&
|
|
597
|
+
skipsUnparsable(property.range[0]);
|
|
594
598
|
if (property.range.length == 1) {
|
|
599
|
+
if (lenient) {
|
|
600
|
+
yield getDataCheck(property.range[0], types, "v");
|
|
601
|
+
yield " ? ";
|
|
602
|
+
}
|
|
595
603
|
yield getDecoder(
|
|
596
604
|
property.range[0],
|
|
597
605
|
types,
|
|
@@ -599,6 +607,7 @@ export async function* generateDecoder(
|
|
|
599
607
|
"options",
|
|
600
608
|
propertyBaseUrl,
|
|
601
609
|
);
|
|
610
|
+
if (lenient) yield " : undefined";
|
|
602
611
|
} else {
|
|
603
612
|
const decoders = getDecoders(
|
|
604
613
|
property.range,
|
package/src/property.ts
CHANGED
|
@@ -477,18 +477,21 @@ async function* generateProperty(
|
|
|
477
477
|
${JSON.stringify(property.compactName)}];
|
|
478
478
|
const doc = Array.isArray(prop) ? prop[0] : prop;
|
|
479
479
|
if (doc != null && typeof doc === "object" && "@context" in doc) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
480
|
+
try {
|
|
481
|
+
v = await this.#${property.singularName}_fromJsonLd(doc, {
|
|
482
|
+
...options,
|
|
483
|
+
// Keep the parent default for embedded objects.
|
|
484
|
+
verifyPortableObject: this._verifyPortableObject,
|
|
485
|
+
baseUrl: ${cachedPropertyBaseUrl},
|
|
486
|
+
});
|
|
487
|
+
} catch (error) {
|
|
488
|
+
if (!options.suppressError) throw error;
|
|
489
|
+
getLogger(["fedify", "vocab"]).debug(
|
|
490
|
+
"Failed to parse embedded value of {property}: {error}",
|
|
491
|
+
{ property: ${JSON.stringify(property.uri)}, error },
|
|
492
|
+
);
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
492
495
|
}
|
|
493
496
|
}
|
|
494
497
|
`;
|
|
@@ -647,18 +650,23 @@ async function* generateProperty(
|
|
|
647
650
|
${JSON.stringify(property.compactName)}];
|
|
648
651
|
const obj = Array.isArray(prop) ? prop[i] : prop;
|
|
649
652
|
if (obj != null && typeof obj === "object" && "@context" in obj) {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
// Embedded objects get this object's own default, whether or
|
|
655
|
-
// not they carry their own @context, as when this object was
|
|
656
|
-
// parsed:
|
|
653
|
+
try {
|
|
654
|
+
v = await this.#${property.singularName}_fromJsonLd(obj, {
|
|
655
|
+
...options,
|
|
656
|
+
// Keep the parent default for embedded objects.
|
|
657
657
|
verifyPortableObject: this._verifyPortableObject,
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
658
|
+
baseUrl: ${cachedPropertyBaseUrl},
|
|
659
|
+
});
|
|
660
|
+
} catch (error) {
|
|
661
|
+
if (!options.suppressError) throw error;
|
|
662
|
+
getLogger(["fedify", "vocab"]).debug(
|
|
663
|
+
"Failed to parse embedded value of {property} at index {index}: {error}",
|
|
664
|
+
{ property: ${
|
|
665
|
+
JSON.stringify(property.uri)
|
|
666
|
+
}, index: i, error },
|
|
667
|
+
);
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
662
670
|
}
|
|
663
671
|
}
|
|
664
672
|
`;
|
package/src/type.ts
CHANGED
|
@@ -19,6 +19,12 @@ interface ScalarType {
|
|
|
19
19
|
compactEncoder?: (variable: string) => string;
|
|
20
20
|
dataCheck(variable: string): string;
|
|
21
21
|
decoder(variable: string, baseUrlVar: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether a value that fails `dataCheck()` should be skipped instead of
|
|
24
|
+
* being handed to `decoder()`. Set this for types decoded from untrusted
|
|
25
|
+
* remote input, where one malformed value must not fail the whole object.
|
|
26
|
+
*/
|
|
27
|
+
skipUnparsable?: boolean;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
const scalarTypes: Record<string, ScalarType> = {
|
|
@@ -319,13 +325,14 @@ const scalarTypes: Record<string, ScalarType> = {
|
|
|
319
325
|
return `formatIri(${v})`;
|
|
320
326
|
},
|
|
321
327
|
dataCheck(v) {
|
|
322
|
-
return `typeof ${v} === "object" &&
|
|
323
|
-
|
|
324
|
-
|
|
328
|
+
return `typeof ${v} === "object" &&
|
|
329
|
+
((typeof ${v}["@id"] === "string" && canDecodeIri(${v}["@id"])) ||
|
|
330
|
+
(typeof ${v}["@value"] === "string" && canDecodeIri(${v}["@value"])))`;
|
|
325
331
|
},
|
|
326
332
|
decoder(v) {
|
|
327
|
-
return `
|
|
333
|
+
return `decodeIri(typeof ${v}["@id"] === "string" ? ${v}["@id"] : ${v}["@value"])`;
|
|
328
334
|
},
|
|
335
|
+
skipUnparsable: true,
|
|
329
336
|
},
|
|
330
337
|
"fedify:gatewayUrl": {
|
|
331
338
|
name: "URL",
|
|
@@ -658,6 +665,10 @@ export function getDecoder(
|
|
|
658
665
|
throw new Error(`Unknown type: ${typeUri}`);
|
|
659
666
|
}
|
|
660
667
|
|
|
668
|
+
export function skipsUnparsable(typeUri: string): boolean {
|
|
669
|
+
return scalarTypes[typeUri]?.skipUnparsable ?? false;
|
|
670
|
+
}
|
|
671
|
+
|
|
661
672
|
export function getDataCheck(
|
|
662
673
|
typeUri: string,
|
|
663
674
|
types: Record<string, TypeSchema>,
|