@fedify/vocab-tools 2.5.0-dev.2332 → 2.5.0-dev.2355
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 +14 -4
- package/deno.json +1 -1
- package/dist/mod.cjs +73 -4
- package/dist/mod.js +73 -4
- package/package.json +2 -2
- package/src/__snapshots__/class.test.ts.deno.snap +2121 -158
- package/src/__snapshots__/class.test.ts.node.snap +2121 -158
- package/src/__snapshots__/class.test.ts.snap +2121 -158
- package/src/class.ts +55 -3
- package/src/codec.test.ts +71 -1
- package/src/codec.ts +21 -5
- package/src/type.ts +19 -0
package/README.md
CHANGED
|
@@ -52,10 +52,20 @@ Conditional contexts and metadata trust
|
|
|
52
52
|
---------------------------------------
|
|
53
53
|
|
|
54
54
|
A property schema can set `extraContext` to a context URL. The generated
|
|
55
|
-
serializer adds it to its default context when the property
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
serializer adds it to its default context when the property is populated,
|
|
56
|
+
including inside nested objects, even if the default context already defines a
|
|
57
|
+
prefix that could abbreviate the property's IRI. A nested object kept in its
|
|
58
|
+
received form is recognized by the context URL or the full property IRI it
|
|
59
|
+
uses. A caller-provided context takes precedence. When populated, such a
|
|
60
|
+
property uses the JSON-LD processor so context container rules, including
|
|
61
|
+
`@set`, are respected.
|
|
62
|
+
|
|
63
|
+
The `fedify:absoluteIri` range is a `URL` written as an IRI reference
|
|
64
|
+
(`@id`). When reading, it also accepts plain string literals and literals
|
|
65
|
+
typed as `xsd:string` or `xsd:anyURI`, because publishers do not always coerce
|
|
66
|
+
the property's term to an IRI. The decoder never resolves a value against the
|
|
67
|
+
object's ID or a base URL, so a value must already be absolute after JSON-LD
|
|
68
|
+
expansion; values that are not are skipped.
|
|
59
69
|
|
|
60
70
|
A type schema can set `trustEmbeddedObjects: false` when its identifier is
|
|
61
71
|
metadata rather than a resource that establishes an origin. Its own
|
package/deno.json
CHANGED
package/dist/mod.cjs
CHANGED
|
@@ -8,7 +8,7 @@ let yaml = require("yaml");
|
|
|
8
8
|
let es_toolkit = require("es-toolkit");
|
|
9
9
|
//#region deno.json
|
|
10
10
|
var name = "@fedify/vocab-tools";
|
|
11
|
-
var version = "2.5.0-dev.
|
|
11
|
+
var version = "2.5.0-dev.2355+c92a1cb1";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/type.ts
|
|
14
14
|
const HEURISTICS_CONTEXTS = [
|
|
@@ -327,6 +327,25 @@ const scalarTypes = {
|
|
|
327
327
|
},
|
|
328
328
|
skipUnparsable: true
|
|
329
329
|
},
|
|
330
|
+
"fedify:absoluteIri": {
|
|
331
|
+
name: "URL",
|
|
332
|
+
typeGuard(v) {
|
|
333
|
+
return `${v} instanceof URL`;
|
|
334
|
+
},
|
|
335
|
+
encoder(v) {
|
|
336
|
+
return `{ "@id": formatIri(${v}) }`;
|
|
337
|
+
},
|
|
338
|
+
compactEncoder(v) {
|
|
339
|
+
return `formatIri(${v})`;
|
|
340
|
+
},
|
|
341
|
+
dataCheck(v) {
|
|
342
|
+
return `isAbsoluteIriValue(${v})`;
|
|
343
|
+
},
|
|
344
|
+
decoder(v) {
|
|
345
|
+
return `decodeIri(getAbsoluteIriValue(${v})!)`;
|
|
346
|
+
},
|
|
347
|
+
skipUnparsable: true
|
|
348
|
+
},
|
|
330
349
|
"fedify:gatewayUrl": {
|
|
331
350
|
name: "URL",
|
|
332
351
|
typeGuard(v) {
|
|
@@ -940,13 +959,27 @@ async function* generateEncoder(typeUri, types) {
|
|
|
940
959
|
}
|
|
941
960
|
let docContext: Parameters<typeof jsonld.compact>[1] = options.context ??
|
|
942
961
|
${JSON.stringify(type.defaultContext)};
|
|
962
|
+
`;
|
|
963
|
+
const hasExtraContexts = Object.values(types).some((t) => t.properties.some((p) => p.extraContext != null));
|
|
964
|
+
if (hasExtraContexts) yield `
|
|
965
|
+
if (options.context == null) {
|
|
966
|
+
const currentContexts = Array.isArray(docContext) ? docContext : [docContext];
|
|
967
|
+
const additionalContexts = getExtraContexts(values).filter(
|
|
968
|
+
context => !currentContexts.includes(context)
|
|
969
|
+
);
|
|
970
|
+
if (additionalContexts.length > 0) {
|
|
971
|
+
docContext = [...currentContexts, ...additionalContexts];
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
`;
|
|
975
|
+
yield `
|
|
943
976
|
let compacted = await jsonld.compact(
|
|
944
977
|
values,
|
|
945
978
|
docContext,
|
|
946
979
|
{ documentLoader: options.contextLoader },
|
|
947
980
|
);
|
|
948
981
|
`;
|
|
949
|
-
if (
|
|
982
|
+
if (hasExtraContexts) yield `
|
|
950
983
|
if (options.context == null) {
|
|
951
984
|
const currentContexts = Array.isArray(docContext) ? docContext : [docContext];
|
|
952
985
|
const additionalContexts = getExtraContexts(compacted).filter(
|
|
@@ -2294,6 +2327,7 @@ async function* generateProperties(typeUri, types, moduleVarNames) {
|
|
|
2294
2327
|
//#region src/class.ts
|
|
2295
2328
|
const XSD_ANY_URI = "http://www.w3.org/2001/XMLSchema#anyURI";
|
|
2296
2329
|
const FEDIFY_URL = "fedify:url";
|
|
2330
|
+
const FEDIFY_ABSOLUTE_IRI = "fedify:absoluteIri";
|
|
2297
2331
|
const INTERNAL_RUNTIME_IMPORTS = [
|
|
2298
2332
|
"compactJsonLdCache",
|
|
2299
2333
|
"createScopedContextLoader",
|
|
@@ -2502,7 +2536,7 @@ export function getEntityTypeById(id: string | URL): $EntityType | undefined {
|
|
|
2502
2536
|
`;
|
|
2503
2537
|
}
|
|
2504
2538
|
function canContainIriValue(property, types) {
|
|
2505
|
-
return property.range.some((typeUri) => typeUri === XSD_ANY_URI || typeUri === FEDIFY_URL || types[typeUri]?.entity);
|
|
2539
|
+
return property.range.some((typeUri) => typeUri === XSD_ANY_URI || typeUri === FEDIFY_URL || typeUri === FEDIFY_ABSOLUTE_IRI || types[typeUri]?.entity);
|
|
2506
2540
|
}
|
|
2507
2541
|
function addKeys(keys, property) {
|
|
2508
2542
|
keys.add(property.uri);
|
|
@@ -2560,12 +2594,38 @@ function isValidLanguageTag(language: string): boolean {
|
|
|
2560
2594
|
throw error;
|
|
2561
2595
|
}
|
|
2562
2596
|
}
|
|
2597
|
+
`;
|
|
2598
|
+
if (Object.values(types).some((type) => type.properties.some((property) => property.range.includes(FEDIFY_ABSOLUTE_IRI)))) yield `
|
|
2599
|
+
function getAbsoluteIriValue(value: unknown): string | undefined {
|
|
2600
|
+
if (value == null || typeof value !== "object") return undefined;
|
|
2601
|
+
const node = value as Record<string, unknown>;
|
|
2602
|
+
if (typeof node["@id"] === "string") {
|
|
2603
|
+
return node["@id"].startsWith("_:") ? undefined : node["@id"];
|
|
2604
|
+
}
|
|
2605
|
+
// A language tag can come from a context's default language, so it does
|
|
2606
|
+
// not make a literal any less of an IRI:
|
|
2607
|
+
if (typeof node["@value"] !== "string") return undefined;
|
|
2608
|
+
const type = node["@type"];
|
|
2609
|
+
return type == null ||
|
|
2610
|
+
type === "http://www.w3.org/2001/XMLSchema#string" ||
|
|
2611
|
+
type === "http://www.w3.org/2001/XMLSchema#anyURI"
|
|
2612
|
+
? node["@value"]
|
|
2613
|
+
: undefined;
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
function isAbsoluteIriValue(value: unknown): boolean {
|
|
2617
|
+
const iri = getAbsoluteIriValue(value);
|
|
2618
|
+
return iri != null && canDecodeIri(iri);
|
|
2619
|
+
}
|
|
2563
2620
|
`;
|
|
2564
2621
|
const extraContexts = Object.fromEntries(Object.values(types).flatMap((type) => type.properties.flatMap((property) => property.extraContext == null ? [] : [[property.uri, property.extraContext]])));
|
|
2565
2622
|
if (Object.keys(extraContexts).length > 0) yield `
|
|
2566
2623
|
const extraPropertyContexts: Readonly<Record<string, string>> =
|
|
2567
2624
|
${JSON.stringify(extraContexts)};
|
|
2568
2625
|
|
|
2626
|
+
const extraContextUrls: readonly string[] =
|
|
2627
|
+
${JSON.stringify([...new Set(Object.values(extraContexts))])};
|
|
2628
|
+
|
|
2569
2629
|
function getExtraContexts(document: unknown): string[] {
|
|
2570
2630
|
const contexts = new Set<string>();
|
|
2571
2631
|
const pending: unknown[] = [document];
|
|
@@ -2578,7 +2638,16 @@ function getExtraContexts(document: unknown): string[] {
|
|
|
2578
2638
|
}
|
|
2579
2639
|
if ("@value" in value) continue;
|
|
2580
2640
|
for (const [key, child] of globalThis.Object.entries(value)) {
|
|
2581
|
-
if (key === "@context")
|
|
2641
|
+
if (key === "@context") {
|
|
2642
|
+
for (const context of Array.isArray(child) ? child : [child]) {
|
|
2643
|
+
if (
|
|
2644
|
+
typeof context === "string" && extraContextUrls.includes(context)
|
|
2645
|
+
) {
|
|
2646
|
+
contexts.add(context);
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
continue;
|
|
2650
|
+
}
|
|
2582
2651
|
if (globalThis.Object.hasOwn(extraPropertyContexts, key)) {
|
|
2583
2652
|
contexts.add(extraPropertyContexts[key]);
|
|
2584
2653
|
}
|
package/dist/mod.js
CHANGED
|
@@ -7,7 +7,7 @@ import { parse } from "yaml";
|
|
|
7
7
|
import { pascalCase } from "es-toolkit";
|
|
8
8
|
//#region deno.json
|
|
9
9
|
var name = "@fedify/vocab-tools";
|
|
10
|
-
var version = "2.5.0-dev.
|
|
10
|
+
var version = "2.5.0-dev.2355+c92a1cb1";
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/type.ts
|
|
13
13
|
const HEURISTICS_CONTEXTS = [
|
|
@@ -326,6 +326,25 @@ const scalarTypes = {
|
|
|
326
326
|
},
|
|
327
327
|
skipUnparsable: true
|
|
328
328
|
},
|
|
329
|
+
"fedify:absoluteIri": {
|
|
330
|
+
name: "URL",
|
|
331
|
+
typeGuard(v) {
|
|
332
|
+
return `${v} instanceof URL`;
|
|
333
|
+
},
|
|
334
|
+
encoder(v) {
|
|
335
|
+
return `{ "@id": formatIri(${v}) }`;
|
|
336
|
+
},
|
|
337
|
+
compactEncoder(v) {
|
|
338
|
+
return `formatIri(${v})`;
|
|
339
|
+
},
|
|
340
|
+
dataCheck(v) {
|
|
341
|
+
return `isAbsoluteIriValue(${v})`;
|
|
342
|
+
},
|
|
343
|
+
decoder(v) {
|
|
344
|
+
return `decodeIri(getAbsoluteIriValue(${v})!)`;
|
|
345
|
+
},
|
|
346
|
+
skipUnparsable: true
|
|
347
|
+
},
|
|
329
348
|
"fedify:gatewayUrl": {
|
|
330
349
|
name: "URL",
|
|
331
350
|
typeGuard(v) {
|
|
@@ -939,13 +958,27 @@ async function* generateEncoder(typeUri, types) {
|
|
|
939
958
|
}
|
|
940
959
|
let docContext: Parameters<typeof jsonld.compact>[1] = options.context ??
|
|
941
960
|
${JSON.stringify(type.defaultContext)};
|
|
961
|
+
`;
|
|
962
|
+
const hasExtraContexts = Object.values(types).some((t) => t.properties.some((p) => p.extraContext != null));
|
|
963
|
+
if (hasExtraContexts) yield `
|
|
964
|
+
if (options.context == null) {
|
|
965
|
+
const currentContexts = Array.isArray(docContext) ? docContext : [docContext];
|
|
966
|
+
const additionalContexts = getExtraContexts(values).filter(
|
|
967
|
+
context => !currentContexts.includes(context)
|
|
968
|
+
);
|
|
969
|
+
if (additionalContexts.length > 0) {
|
|
970
|
+
docContext = [...currentContexts, ...additionalContexts];
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
`;
|
|
974
|
+
yield `
|
|
942
975
|
let compacted = await jsonld.compact(
|
|
943
976
|
values,
|
|
944
977
|
docContext,
|
|
945
978
|
{ documentLoader: options.contextLoader },
|
|
946
979
|
);
|
|
947
980
|
`;
|
|
948
|
-
if (
|
|
981
|
+
if (hasExtraContexts) yield `
|
|
949
982
|
if (options.context == null) {
|
|
950
983
|
const currentContexts = Array.isArray(docContext) ? docContext : [docContext];
|
|
951
984
|
const additionalContexts = getExtraContexts(compacted).filter(
|
|
@@ -2293,6 +2326,7 @@ async function* generateProperties(typeUri, types, moduleVarNames) {
|
|
|
2293
2326
|
//#region src/class.ts
|
|
2294
2327
|
const XSD_ANY_URI = "http://www.w3.org/2001/XMLSchema#anyURI";
|
|
2295
2328
|
const FEDIFY_URL = "fedify:url";
|
|
2329
|
+
const FEDIFY_ABSOLUTE_IRI = "fedify:absoluteIri";
|
|
2296
2330
|
const INTERNAL_RUNTIME_IMPORTS = [
|
|
2297
2331
|
"compactJsonLdCache",
|
|
2298
2332
|
"createScopedContextLoader",
|
|
@@ -2501,7 +2535,7 @@ export function getEntityTypeById(id: string | URL): $EntityType | undefined {
|
|
|
2501
2535
|
`;
|
|
2502
2536
|
}
|
|
2503
2537
|
function canContainIriValue(property, types) {
|
|
2504
|
-
return property.range.some((typeUri) => typeUri === XSD_ANY_URI || typeUri === FEDIFY_URL || types[typeUri]?.entity);
|
|
2538
|
+
return property.range.some((typeUri) => typeUri === XSD_ANY_URI || typeUri === FEDIFY_URL || typeUri === FEDIFY_ABSOLUTE_IRI || types[typeUri]?.entity);
|
|
2505
2539
|
}
|
|
2506
2540
|
function addKeys(keys, property) {
|
|
2507
2541
|
keys.add(property.uri);
|
|
@@ -2559,12 +2593,38 @@ function isValidLanguageTag(language: string): boolean {
|
|
|
2559
2593
|
throw error;
|
|
2560
2594
|
}
|
|
2561
2595
|
}
|
|
2596
|
+
`;
|
|
2597
|
+
if (Object.values(types).some((type) => type.properties.some((property) => property.range.includes(FEDIFY_ABSOLUTE_IRI)))) yield `
|
|
2598
|
+
function getAbsoluteIriValue(value: unknown): string | undefined {
|
|
2599
|
+
if (value == null || typeof value !== "object") return undefined;
|
|
2600
|
+
const node = value as Record<string, unknown>;
|
|
2601
|
+
if (typeof node["@id"] === "string") {
|
|
2602
|
+
return node["@id"].startsWith("_:") ? undefined : node["@id"];
|
|
2603
|
+
}
|
|
2604
|
+
// A language tag can come from a context's default language, so it does
|
|
2605
|
+
// not make a literal any less of an IRI:
|
|
2606
|
+
if (typeof node["@value"] !== "string") return undefined;
|
|
2607
|
+
const type = node["@type"];
|
|
2608
|
+
return type == null ||
|
|
2609
|
+
type === "http://www.w3.org/2001/XMLSchema#string" ||
|
|
2610
|
+
type === "http://www.w3.org/2001/XMLSchema#anyURI"
|
|
2611
|
+
? node["@value"]
|
|
2612
|
+
: undefined;
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
function isAbsoluteIriValue(value: unknown): boolean {
|
|
2616
|
+
const iri = getAbsoluteIriValue(value);
|
|
2617
|
+
return iri != null && canDecodeIri(iri);
|
|
2618
|
+
}
|
|
2562
2619
|
`;
|
|
2563
2620
|
const extraContexts = Object.fromEntries(Object.values(types).flatMap((type) => type.properties.flatMap((property) => property.extraContext == null ? [] : [[property.uri, property.extraContext]])));
|
|
2564
2621
|
if (Object.keys(extraContexts).length > 0) yield `
|
|
2565
2622
|
const extraPropertyContexts: Readonly<Record<string, string>> =
|
|
2566
2623
|
${JSON.stringify(extraContexts)};
|
|
2567
2624
|
|
|
2625
|
+
const extraContextUrls: readonly string[] =
|
|
2626
|
+
${JSON.stringify([...new Set(Object.values(extraContexts))])};
|
|
2627
|
+
|
|
2568
2628
|
function getExtraContexts(document: unknown): string[] {
|
|
2569
2629
|
const contexts = new Set<string>();
|
|
2570
2630
|
const pending: unknown[] = [document];
|
|
@@ -2577,7 +2637,16 @@ function getExtraContexts(document: unknown): string[] {
|
|
|
2577
2637
|
}
|
|
2578
2638
|
if ("@value" in value) continue;
|
|
2579
2639
|
for (const [key, child] of globalThis.Object.entries(value)) {
|
|
2580
|
-
if (key === "@context")
|
|
2640
|
+
if (key === "@context") {
|
|
2641
|
+
for (const context of Array.isArray(child) ? child : [child]) {
|
|
2642
|
+
if (
|
|
2643
|
+
typeof context === "string" && extraContextUrls.includes(context)
|
|
2644
|
+
) {
|
|
2645
|
+
contexts.add(context);
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
continue;
|
|
2649
|
+
}
|
|
2581
2650
|
if (globalThis.Object.hasOwn(extraPropertyContexts, key)) {
|
|
2582
2651
|
contexts.add(extraPropertyContexts[key]);
|
|
2583
2652
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/vocab-tools",
|
|
3
|
-
"version": "2.5.0-dev.
|
|
3
|
+
"version": "2.5.0-dev.2355+c92a1cb1",
|
|
4
4
|
"description": "Code generator for Activity Vocabulary APIs",
|
|
5
5
|
"homepage": "https://fedify.dev/",
|
|
6
6
|
"repository": {
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@types/node": "^24.12.2",
|
|
52
52
|
"tsdown": "^0.22.0",
|
|
53
53
|
"typescript": "^6.0.0",
|
|
54
|
-
"@fedify/vocab-runtime": "^2.5.0-dev.
|
|
54
|
+
"@fedify/vocab-runtime": "^2.5.0-dev.2355+c92a1cb1"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@cfworker/json-schema": "^4.1.1",
|