@fedify/vocab-tools 2.4.0-dev.1962 → 2.4.0-dev.1964
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 +18 -0
- package/deno.json +1 -1
- package/dist/mod.cjs +56 -12
- package/dist/mod.d.cts +14 -0
- package/dist/mod.d.ts +14 -0
- package/dist/mod.js +56 -12
- package/dist/schema.yaml +15 -0
- package/package.json +1 -1
- package/src/__snapshots__/class.test.ts.deno.snap +3440 -318
- package/src/__snapshots__/class.test.ts.node.snap +3440 -318
- package/src/__snapshots__/class.test.ts.snap +3440 -318
- package/src/class.ts +38 -0
- package/src/codec.ts +28 -3
- package/src/property.ts +29 -8
- package/src/schema.ts +16 -0
- package/src/schema.yaml +15 -0
package/README.md
CHANGED
|
@@ -46,3 +46,21 @@ mise run test:update_snapshots
|
|
|
46
46
|
|
|
47
47
|
Review and commit every changed snapshot file. Updating only one runtime
|
|
48
48
|
leaves the other test suites with stale expectations.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
Conditional contexts and metadata trust
|
|
52
|
+
---------------------------------------
|
|
53
|
+
|
|
54
|
+
A property schema can set `extraContext` to a context URL. The generated
|
|
55
|
+
serializer adds it to its default context when the property's expanded IRI
|
|
56
|
+
appears after compaction, including inside nested objects. A caller-provided
|
|
57
|
+
context takes precedence. When populated, such a property uses the JSON-LD
|
|
58
|
+
processor so context container rules, including `@set`, are respected.
|
|
59
|
+
|
|
60
|
+
A type schema can set `trustEmbeddedObjects: false` when its identifier is
|
|
61
|
+
metadata rather than a resource that establishes an origin. Its own
|
|
62
|
+
entity-valued accessors then fetch embedded objects with identifiers instead
|
|
63
|
+
of trusting a matching origin. Locally constructed values, previously fetched
|
|
64
|
+
values, and the explicit `crossOrigin: "trust"` option retain their usual
|
|
65
|
+
behavior. This does not verify id-less embedded objects or establish publishing
|
|
66
|
+
authority.
|
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.4.0-dev.
|
|
11
|
+
var version = "2.4.0-dev.1964+1d28dc03";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/type.ts
|
|
14
14
|
const HEURISTICS_CONTEXTS = [
|
|
@@ -916,13 +916,29 @@ async function* generateEncoder(typeUri, types) {
|
|
|
916
916
|
},
|
|
917
917
|
);
|
|
918
918
|
}
|
|
919
|
-
|
|
919
|
+
let docContext: Parameters<typeof jsonld.compact>[1] = options.context ??
|
|
920
920
|
${JSON.stringify(type.defaultContext)};
|
|
921
|
-
|
|
921
|
+
let compacted = await jsonld.compact(
|
|
922
922
|
values,
|
|
923
923
|
docContext,
|
|
924
924
|
{ documentLoader: options.contextLoader },
|
|
925
925
|
);
|
|
926
|
+
`;
|
|
927
|
+
if (Object.values(types).some((t) => t.properties.some((p) => p.extraContext != null))) yield `
|
|
928
|
+
if (options.context == null) {
|
|
929
|
+
const currentContexts = Array.isArray(docContext) ? docContext : [docContext];
|
|
930
|
+
const additionalContexts = getExtraContexts(compacted).filter(
|
|
931
|
+
context => !currentContexts.includes(context)
|
|
932
|
+
);
|
|
933
|
+
if (additionalContexts.length > 0) {
|
|
934
|
+
docContext = [...currentContexts, ...additionalContexts];
|
|
935
|
+
compacted = await jsonld.compact(values, docContext, {
|
|
936
|
+
documentLoader: options.contextLoader,
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
`;
|
|
941
|
+
yield `
|
|
926
942
|
if (docContext != null) {
|
|
927
943
|
// Embed context
|
|
928
944
|
`;
|
|
@@ -951,7 +967,7 @@ async function* generateEncoder(typeUri, types) {
|
|
|
951
967
|
|
|
952
968
|
protected ${emitOverride$1(typeUri, types)} isCompactable(): boolean {
|
|
953
969
|
`;
|
|
954
|
-
for (const property of type.properties) if (!property.range.every((r) => isCompactableType(r, types))) yield `
|
|
970
|
+
for (const property of type.properties) if (property.extraContext != null || !property.range.every((r) => isCompactableType(r, types))) yield `
|
|
955
971
|
if (
|
|
956
972
|
this.${await getFieldName(property.uri)} != null &&
|
|
957
973
|
this.${await getFieldName(property.uri)}.length > 0
|
|
@@ -1577,6 +1593,7 @@ function emitOverride(typeUri, types, property) {
|
|
|
1577
1593
|
}
|
|
1578
1594
|
async function* generateProperty(type, property, types, moduleVarNames) {
|
|
1579
1595
|
const override = emitOverride(type.uri, types, property);
|
|
1596
|
+
const trustOwner = type.trustEmbeddedObjects === false ? "null" : "this.id";
|
|
1580
1597
|
const doc = `\n/** ${property.description.replaceAll("\n", "\n * ")}\n */\n`;
|
|
1581
1598
|
const cachedPropertyBaseUrl = `(options as { baseUrl?: URL }).baseUrl ??
|
|
1582
1599
|
this._baseUrl ??
|
|
@@ -1807,7 +1824,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1807
1824
|
let v = this.${await getFieldName(property.uri)}[0];
|
|
1808
1825
|
if (!(v instanceof URL) &&
|
|
1809
1826
|
v.id != null &&
|
|
1810
|
-
!isTrustedIriOrigin(options, v.id,
|
|
1827
|
+
!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1811
1828
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1812
1829
|
v = v.id;
|
|
1813
1830
|
}
|
|
@@ -1847,12 +1864,12 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1847
1864
|
}
|
|
1848
1865
|
yield `
|
|
1849
1866
|
if (v?.id != null &&
|
|
1850
|
-
this.id != null && !isTrustedIriOrigin(options, v.id,
|
|
1867
|
+
${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1851
1868
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1852
1869
|
if (options.crossOrigin === "throw") {
|
|
1853
1870
|
throw new Error(
|
|
1854
1871
|
"The property object's @id (" + v.id.href + ") has a different " +
|
|
1855
|
-
"origin than the property owner's @id (" + this.id.href + "); " +
|
|
1872
|
+
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} + "); " +
|
|
1856
1873
|
"refusing to return the object. If you want to bypass this " +
|
|
1857
1874
|
"check and are aware of the security implications, set the " +
|
|
1858
1875
|
'crossOrigin option to "trust".'
|
|
@@ -1864,7 +1881,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1864
1881
|
"return the object. If you want to bypass this check and are " +
|
|
1865
1882
|
"aware of the security implications, set the crossOrigin option " +
|
|
1866
1883
|
'to "trust".',
|
|
1867
|
-
{ objectId: v.id.href, parentObjectId: this.id.href },
|
|
1884
|
+
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} },
|
|
1868
1885
|
);
|
|
1869
1886
|
return null;
|
|
1870
1887
|
}
|
|
@@ -1913,7 +1930,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1913
1930
|
let v = vs[i];
|
|
1914
1931
|
if (!(v instanceof URL) &&
|
|
1915
1932
|
v.id != null &&
|
|
1916
|
-
!isTrustedIriOrigin(options, v.id,
|
|
1933
|
+
!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1917
1934
|
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
1918
1935
|
v = v.id;
|
|
1919
1936
|
}
|
|
@@ -1954,12 +1971,12 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1954
1971
|
}
|
|
1955
1972
|
yield `
|
|
1956
1973
|
if (v?.id != null &&
|
|
1957
|
-
this.id != null && !isTrustedIriOrigin(options, v.id,
|
|
1974
|
+
${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1958
1975
|
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
1959
1976
|
if (options.crossOrigin === "throw") {
|
|
1960
1977
|
throw new Error(
|
|
1961
1978
|
"The property object's @id (" + v.id.href + ") has a different " +
|
|
1962
|
-
"origin than the property owner's @id (" + this.id.href + "); " +
|
|
1979
|
+
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} + "); " +
|
|
1963
1980
|
"refusing to return the object. If you want to bypass this " +
|
|
1964
1981
|
"check and are aware of the security implications, set the " +
|
|
1965
1982
|
'crossOrigin option to "trust".'
|
|
@@ -1971,7 +1988,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1971
1988
|
"return the object. If you want to bypass this check and are " +
|
|
1972
1989
|
"aware of the security implications, set the crossOrigin " +
|
|
1973
1990
|
'option to "trust".',
|
|
1974
|
-
{ objectId: v.id.href, parentObjectId: this.id.href },
|
|
1991
|
+
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} },
|
|
1975
1992
|
);
|
|
1976
1993
|
continue;
|
|
1977
1994
|
}
|
|
@@ -2205,6 +2222,33 @@ function isValidLanguageTag(language: string): boolean {
|
|
|
2205
2222
|
throw error;
|
|
2206
2223
|
}
|
|
2207
2224
|
}
|
|
2225
|
+
`;
|
|
2226
|
+
const extraContexts = Object.fromEntries(Object.values(types).flatMap((type) => type.properties.flatMap((property) => property.extraContext == null ? [] : [[property.uri, property.extraContext]])));
|
|
2227
|
+
if (Object.keys(extraContexts).length > 0) yield `
|
|
2228
|
+
const extraPropertyContexts: Readonly<Record<string, string>> =
|
|
2229
|
+
${JSON.stringify(extraContexts)};
|
|
2230
|
+
|
|
2231
|
+
function getExtraContexts(document: unknown): string[] {
|
|
2232
|
+
const contexts = new Set<string>();
|
|
2233
|
+
const pending: unknown[] = [document];
|
|
2234
|
+
while (pending.length > 0) {
|
|
2235
|
+
const value = pending.pop();
|
|
2236
|
+
if (value == null || typeof value !== "object") continue;
|
|
2237
|
+
if (Array.isArray(value)) {
|
|
2238
|
+
for (const item of value) pending.push(item);
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2241
|
+
if ("@value" in value) continue;
|
|
2242
|
+
for (const [key, child] of globalThis.Object.entries(value)) {
|
|
2243
|
+
if (key === "@context") continue;
|
|
2244
|
+
if (globalThis.Object.hasOwn(extraPropertyContexts, key)) {
|
|
2245
|
+
contexts.add(extraPropertyContexts[key]);
|
|
2246
|
+
}
|
|
2247
|
+
pending.push(child);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
return [...contexts];
|
|
2251
|
+
}
|
|
2208
2252
|
`;
|
|
2209
2253
|
yield "\n\n";
|
|
2210
2254
|
const portableIriKeys = /* @__PURE__ */ new Set(["@id", "id"]);
|
package/dist/mod.d.cts
CHANGED
|
@@ -36,6 +36,13 @@ interface TypeSchema {
|
|
|
36
36
|
*/
|
|
37
37
|
entity: boolean;
|
|
38
38
|
/**
|
|
39
|
+
* Whether this type's id can establish same-origin trust for its own
|
|
40
|
+
* embedded entity-valued properties. Defaults to true. Set to false for
|
|
41
|
+
* metadata whose id does not identify an independently fetched resource.
|
|
42
|
+
* Locally constructed and explicitly trusted values remain trusted.
|
|
43
|
+
*/
|
|
44
|
+
trustEmbeddedObjects?: boolean;
|
|
45
|
+
/**
|
|
39
46
|
* Whether the type omits `@type` in JSON-LD serialization. When `true`,
|
|
40
47
|
* the generated `toJsonLd()` method will not emit `@type` (or `type` in
|
|
41
48
|
* compact form) in the serialized JSON-LD. The generated `fromJsonLd()`
|
|
@@ -61,6 +68,13 @@ interface TypeSchema {
|
|
|
61
68
|
defaultContext: Context;
|
|
62
69
|
}
|
|
63
70
|
interface PropertySchemaBase {
|
|
71
|
+
/**
|
|
72
|
+
* A context URL added to the default serialization context when this
|
|
73
|
+
* property's expanded IRI appears in the compacted document. Explicit
|
|
74
|
+
* caller contexts are unchanged. Populated properties with this option
|
|
75
|
+
* use the JSON-LD processor instead of compact serialization heuristics.
|
|
76
|
+
*/
|
|
77
|
+
extraContext?: string;
|
|
64
78
|
/**
|
|
65
79
|
* The singular form of the property name. It is used as the name of the
|
|
66
80
|
* generated property accessors.
|
package/dist/mod.d.ts
CHANGED
|
@@ -36,6 +36,13 @@ interface TypeSchema {
|
|
|
36
36
|
*/
|
|
37
37
|
entity: boolean;
|
|
38
38
|
/**
|
|
39
|
+
* Whether this type's id can establish same-origin trust for its own
|
|
40
|
+
* embedded entity-valued properties. Defaults to true. Set to false for
|
|
41
|
+
* metadata whose id does not identify an independently fetched resource.
|
|
42
|
+
* Locally constructed and explicitly trusted values remain trusted.
|
|
43
|
+
*/
|
|
44
|
+
trustEmbeddedObjects?: boolean;
|
|
45
|
+
/**
|
|
39
46
|
* Whether the type omits `@type` in JSON-LD serialization. When `true`,
|
|
40
47
|
* the generated `toJsonLd()` method will not emit `@type` (or `type` in
|
|
41
48
|
* compact form) in the serialized JSON-LD. The generated `fromJsonLd()`
|
|
@@ -61,6 +68,13 @@ interface TypeSchema {
|
|
|
61
68
|
defaultContext: Context;
|
|
62
69
|
}
|
|
63
70
|
interface PropertySchemaBase {
|
|
71
|
+
/**
|
|
72
|
+
* A context URL added to the default serialization context when this
|
|
73
|
+
* property's expanded IRI appears in the compacted document. Explicit
|
|
74
|
+
* caller contexts are unchanged. Populated properties with this option
|
|
75
|
+
* use the JSON-LD processor instead of compact serialization heuristics.
|
|
76
|
+
*/
|
|
77
|
+
extraContext?: string;
|
|
64
78
|
/**
|
|
65
79
|
* The singular form of the property name. It is used as the name of the
|
|
66
80
|
* generated property accessors.
|
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.4.0-dev.
|
|
10
|
+
var version = "2.4.0-dev.1964+1d28dc03";
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/type.ts
|
|
13
13
|
const HEURISTICS_CONTEXTS = [
|
|
@@ -915,13 +915,29 @@ async function* generateEncoder(typeUri, types) {
|
|
|
915
915
|
},
|
|
916
916
|
);
|
|
917
917
|
}
|
|
918
|
-
|
|
918
|
+
let docContext: Parameters<typeof jsonld.compact>[1] = options.context ??
|
|
919
919
|
${JSON.stringify(type.defaultContext)};
|
|
920
|
-
|
|
920
|
+
let compacted = await jsonld.compact(
|
|
921
921
|
values,
|
|
922
922
|
docContext,
|
|
923
923
|
{ documentLoader: options.contextLoader },
|
|
924
924
|
);
|
|
925
|
+
`;
|
|
926
|
+
if (Object.values(types).some((t) => t.properties.some((p) => p.extraContext != null))) yield `
|
|
927
|
+
if (options.context == null) {
|
|
928
|
+
const currentContexts = Array.isArray(docContext) ? docContext : [docContext];
|
|
929
|
+
const additionalContexts = getExtraContexts(compacted).filter(
|
|
930
|
+
context => !currentContexts.includes(context)
|
|
931
|
+
);
|
|
932
|
+
if (additionalContexts.length > 0) {
|
|
933
|
+
docContext = [...currentContexts, ...additionalContexts];
|
|
934
|
+
compacted = await jsonld.compact(values, docContext, {
|
|
935
|
+
documentLoader: options.contextLoader,
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
`;
|
|
940
|
+
yield `
|
|
925
941
|
if (docContext != null) {
|
|
926
942
|
// Embed context
|
|
927
943
|
`;
|
|
@@ -950,7 +966,7 @@ async function* generateEncoder(typeUri, types) {
|
|
|
950
966
|
|
|
951
967
|
protected ${emitOverride$1(typeUri, types)} isCompactable(): boolean {
|
|
952
968
|
`;
|
|
953
|
-
for (const property of type.properties) if (!property.range.every((r) => isCompactableType(r, types))) yield `
|
|
969
|
+
for (const property of type.properties) if (property.extraContext != null || !property.range.every((r) => isCompactableType(r, types))) yield `
|
|
954
970
|
if (
|
|
955
971
|
this.${await getFieldName(property.uri)} != null &&
|
|
956
972
|
this.${await getFieldName(property.uri)}.length > 0
|
|
@@ -1576,6 +1592,7 @@ function emitOverride(typeUri, types, property) {
|
|
|
1576
1592
|
}
|
|
1577
1593
|
async function* generateProperty(type, property, types, moduleVarNames) {
|
|
1578
1594
|
const override = emitOverride(type.uri, types, property);
|
|
1595
|
+
const trustOwner = type.trustEmbeddedObjects === false ? "null" : "this.id";
|
|
1579
1596
|
const doc = `\n/** ${property.description.replaceAll("\n", "\n * ")}\n */\n`;
|
|
1580
1597
|
const cachedPropertyBaseUrl = `(options as { baseUrl?: URL }).baseUrl ??
|
|
1581
1598
|
this._baseUrl ??
|
|
@@ -1806,7 +1823,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1806
1823
|
let v = this.${await getFieldName(property.uri)}[0];
|
|
1807
1824
|
if (!(v instanceof URL) &&
|
|
1808
1825
|
v.id != null &&
|
|
1809
|
-
!isTrustedIriOrigin(options, v.id,
|
|
1826
|
+
!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1810
1827
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1811
1828
|
v = v.id;
|
|
1812
1829
|
}
|
|
@@ -1846,12 +1863,12 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1846
1863
|
}
|
|
1847
1864
|
yield `
|
|
1848
1865
|
if (v?.id != null &&
|
|
1849
|
-
this.id != null && !isTrustedIriOrigin(options, v.id,
|
|
1866
|
+
${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1850
1867
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1851
1868
|
if (options.crossOrigin === "throw") {
|
|
1852
1869
|
throw new Error(
|
|
1853
1870
|
"The property object's @id (" + v.id.href + ") has a different " +
|
|
1854
|
-
"origin than the property owner's @id (" + this.id.href + "); " +
|
|
1871
|
+
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} + "); " +
|
|
1855
1872
|
"refusing to return the object. If you want to bypass this " +
|
|
1856
1873
|
"check and are aware of the security implications, set the " +
|
|
1857
1874
|
'crossOrigin option to "trust".'
|
|
@@ -1863,7 +1880,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1863
1880
|
"return the object. If you want to bypass this check and are " +
|
|
1864
1881
|
"aware of the security implications, set the crossOrigin option " +
|
|
1865
1882
|
'to "trust".',
|
|
1866
|
-
{ objectId: v.id.href, parentObjectId: this.id.href },
|
|
1883
|
+
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} },
|
|
1867
1884
|
);
|
|
1868
1885
|
return null;
|
|
1869
1886
|
}
|
|
@@ -1912,7 +1929,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1912
1929
|
let v = vs[i];
|
|
1913
1930
|
if (!(v instanceof URL) &&
|
|
1914
1931
|
v.id != null &&
|
|
1915
|
-
!isTrustedIriOrigin(options, v.id,
|
|
1932
|
+
!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1916
1933
|
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
1917
1934
|
v = v.id;
|
|
1918
1935
|
}
|
|
@@ -1953,12 +1970,12 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1953
1970
|
}
|
|
1954
1971
|
yield `
|
|
1955
1972
|
if (v?.id != null &&
|
|
1956
|
-
this.id != null && !isTrustedIriOrigin(options, v.id,
|
|
1973
|
+
${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1957
1974
|
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
1958
1975
|
if (options.crossOrigin === "throw") {
|
|
1959
1976
|
throw new Error(
|
|
1960
1977
|
"The property object's @id (" + v.id.href + ") has a different " +
|
|
1961
|
-
"origin than the property owner's @id (" + this.id.href + "); " +
|
|
1978
|
+
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} + "); " +
|
|
1962
1979
|
"refusing to return the object. If you want to bypass this " +
|
|
1963
1980
|
"check and are aware of the security implications, set the " +
|
|
1964
1981
|
'crossOrigin option to "trust".'
|
|
@@ -1970,7 +1987,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1970
1987
|
"return the object. If you want to bypass this check and are " +
|
|
1971
1988
|
"aware of the security implications, set the crossOrigin " +
|
|
1972
1989
|
'option to "trust".',
|
|
1973
|
-
{ objectId: v.id.href, parentObjectId: this.id.href },
|
|
1990
|
+
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id.href"} },
|
|
1974
1991
|
);
|
|
1975
1992
|
continue;
|
|
1976
1993
|
}
|
|
@@ -2204,6 +2221,33 @@ function isValidLanguageTag(language: string): boolean {
|
|
|
2204
2221
|
throw error;
|
|
2205
2222
|
}
|
|
2206
2223
|
}
|
|
2224
|
+
`;
|
|
2225
|
+
const extraContexts = Object.fromEntries(Object.values(types).flatMap((type) => type.properties.flatMap((property) => property.extraContext == null ? [] : [[property.uri, property.extraContext]])));
|
|
2226
|
+
if (Object.keys(extraContexts).length > 0) yield `
|
|
2227
|
+
const extraPropertyContexts: Readonly<Record<string, string>> =
|
|
2228
|
+
${JSON.stringify(extraContexts)};
|
|
2229
|
+
|
|
2230
|
+
function getExtraContexts(document: unknown): string[] {
|
|
2231
|
+
const contexts = new Set<string>();
|
|
2232
|
+
const pending: unknown[] = [document];
|
|
2233
|
+
while (pending.length > 0) {
|
|
2234
|
+
const value = pending.pop();
|
|
2235
|
+
if (value == null || typeof value !== "object") continue;
|
|
2236
|
+
if (Array.isArray(value)) {
|
|
2237
|
+
for (const item of value) pending.push(item);
|
|
2238
|
+
continue;
|
|
2239
|
+
}
|
|
2240
|
+
if ("@value" in value) continue;
|
|
2241
|
+
for (const [key, child] of globalThis.Object.entries(value)) {
|
|
2242
|
+
if (key === "@context") continue;
|
|
2243
|
+
if (globalThis.Object.hasOwn(extraPropertyContexts, key)) {
|
|
2244
|
+
contexts.add(extraPropertyContexts[key]);
|
|
2245
|
+
}
|
|
2246
|
+
pending.push(child);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
return [...contexts];
|
|
2250
|
+
}
|
|
2207
2251
|
`;
|
|
2208
2252
|
yield "\n\n";
|
|
2209
2253
|
const portableIriKeys = /* @__PURE__ */ new Set(["@id", "id"]);
|
package/dist/schema.yaml
CHANGED
|
@@ -72,6 +72,14 @@ $defs:
|
|
|
72
72
|
property-base:
|
|
73
73
|
type: object
|
|
74
74
|
properties:
|
|
75
|
+
extraContext:
|
|
76
|
+
description: >-
|
|
77
|
+
A context URL added to default serialization when this property's
|
|
78
|
+
expanded IRI appears in the compacted document. Explicit caller
|
|
79
|
+
contexts are unchanged. Populated properties use the JSON-LD
|
|
80
|
+
processor instead of compact serialization heuristics.
|
|
81
|
+
type: string
|
|
82
|
+
format: uri
|
|
75
83
|
singularName:
|
|
76
84
|
description: >-
|
|
77
85
|
The singular form of the property name. It is used as the name of the
|
|
@@ -250,6 +258,13 @@ properties:
|
|
|
250
258
|
|
|
251
259
|
The extended subtypes must have the consistent value of this flag.
|
|
252
260
|
type: boolean
|
|
261
|
+
trustEmbeddedObjects:
|
|
262
|
+
description: >-
|
|
263
|
+
Whether this type's id establishes same-origin trust for its own
|
|
264
|
+
embedded entity-valued properties. Defaults to true. Set to false
|
|
265
|
+
for metadata ids that do not identify independently fetched resources.
|
|
266
|
+
Locally constructed and explicitly trusted values remain trusted.
|
|
267
|
+
type: boolean
|
|
253
268
|
typeless:
|
|
254
269
|
description: >-
|
|
255
270
|
Whether the type omits @type in JSON-LD serialization. When true,
|