@fedify/vocab-tools 2.4.0-dev.1570 → 2.4.0-dev.1571
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 +108 -72
- package/dist/mod.js +108 -72
- package/package.json +1 -1
- package/src/__snapshots__/class.test.ts.deno.snap +34561 -28340
- package/src/__snapshots__/class.test.ts.node.snap +34561 -28340
- package/src/__snapshots__/class.test.ts.snap +34561 -28340
- package/src/class.ts +79 -21
- package/src/codec.ts +39 -17
- package/src/property.ts +17 -15
- package/src/type.ts +6 -21
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.1571+31e2786b";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/type.ts
|
|
14
14
|
const HEURISTICS_CONTEXTS = [
|
|
@@ -156,10 +156,10 @@ const scalarTypes = {
|
|
|
156
156
|
return `${v} instanceof URL`;
|
|
157
157
|
},
|
|
158
158
|
encoder(v) {
|
|
159
|
-
return `{ "@id": ${v}
|
|
159
|
+
return `{ "@id": formatIri(${v}) }`;
|
|
160
160
|
},
|
|
161
161
|
compactEncoder(v) {
|
|
162
|
-
return
|
|
162
|
+
return `formatIri(${v})`;
|
|
163
163
|
},
|
|
164
164
|
dataCheck(v) {
|
|
165
165
|
return `${v} != null && typeof ${v} === "object" && "@id" in ${v}
|
|
@@ -167,22 +167,7 @@ const scalarTypes = {
|
|
|
167
167
|
&& ${v}["@id"] !== ""`;
|
|
168
168
|
},
|
|
169
169
|
decoder(v, baseUrlVar) {
|
|
170
|
-
return
|
|
171
|
-
? new URL("at://" +
|
|
172
|
-
encodeURIComponent(
|
|
173
|
-
${v}["@id"].includes("/", 5)
|
|
174
|
-
? ${v}["@id"].slice(5, ${v}["@id"].indexOf("/", 5))
|
|
175
|
-
: ${v}["@id"].slice(5)
|
|
176
|
-
) +
|
|
177
|
-
(
|
|
178
|
-
${v}["@id"].includes("/", 5)
|
|
179
|
-
? ${v}["@id"].slice(${v}["@id"].indexOf("/", 5))
|
|
180
|
-
: ""
|
|
181
|
-
)
|
|
182
|
-
)
|
|
183
|
-
: URL.canParse(${v}["@id"]) && ${baseUrlVar}
|
|
184
|
-
? new URL(${v}["@id"])
|
|
185
|
-
: new URL(${v}["@id"], ${baseUrlVar})`;
|
|
170
|
+
return `parseIri(${v}["@id"], ${baseUrlVar})`;
|
|
186
171
|
}
|
|
187
172
|
},
|
|
188
173
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString": {
|
|
@@ -324,10 +309,10 @@ const scalarTypes = {
|
|
|
324
309
|
return `${v} instanceof URL`;
|
|
325
310
|
},
|
|
326
311
|
encoder(v) {
|
|
327
|
-
return `{ "@value": ${v}
|
|
312
|
+
return `{ "@value": formatIri(${v}) }`;
|
|
328
313
|
},
|
|
329
314
|
compactEncoder(v) {
|
|
330
|
-
return
|
|
315
|
+
return `formatIri(${v})`;
|
|
331
316
|
},
|
|
332
317
|
dataCheck(v) {
|
|
333
318
|
return `typeof ${v} === "object" && "@value" in ${v}
|
|
@@ -335,7 +320,7 @@ const scalarTypes = {
|
|
|
335
320
|
&& ${v}["@value"] !== "" && ${v}["@value"] !== "/"`;
|
|
336
321
|
},
|
|
337
322
|
decoder(v) {
|
|
338
|
-
return `
|
|
323
|
+
return `parseIri(${v}["@value"])`;
|
|
339
324
|
}
|
|
340
325
|
},
|
|
341
326
|
"fedify:publicKey": {
|
|
@@ -805,7 +790,7 @@ async function* generateEncoder(typeUri, types) {
|
|
|
805
790
|
for (const v of this.${await getFieldName(property.uri)}) {
|
|
806
791
|
const item = (
|
|
807
792
|
`;
|
|
808
|
-
if (!areAllScalarTypes(property.range, types)) yield "v instanceof URL ? v
|
|
793
|
+
if (!areAllScalarTypes(property.range, types)) yield "v instanceof URL ? formatIri(v) : ";
|
|
809
794
|
const encoders = getEncoders(property.range, types, "v", "options", true);
|
|
810
795
|
for (const code of encoders) yield code;
|
|
811
796
|
yield `
|
|
@@ -836,7 +821,7 @@ async function* generateEncoder(typeUri, types) {
|
|
|
836
821
|
}
|
|
837
822
|
yield `
|
|
838
823
|
${type.typeless ? "" : `result["type"] = ${JSON.stringify(type.compactName ?? type.uri)};`}
|
|
839
|
-
if (this.id != null) result["id"] = this.id
|
|
824
|
+
if (this.id != null) result["id"] = formatIri(this.id);
|
|
840
825
|
result["@context"] = ${JSON.stringify(type.defaultContext)};
|
|
841
826
|
return result;
|
|
842
827
|
}
|
|
@@ -864,7 +849,7 @@ async function* generateEncoder(typeUri, types) {
|
|
|
864
849
|
for (const v of this.${await getFieldName(property.uri)}) {
|
|
865
850
|
const element = (
|
|
866
851
|
`;
|
|
867
|
-
if (!areAllScalarTypes(property.range, types)) yield "v instanceof URL ? { \"@id\": v
|
|
852
|
+
if (!areAllScalarTypes(property.range, types)) yield "v instanceof URL ? { \"@id\": formatIri(v) } : ";
|
|
868
853
|
for (const code of getEncoders(property.range, types, "v", "options")) yield code;
|
|
869
854
|
yield `
|
|
870
855
|
);
|
|
@@ -891,7 +876,7 @@ async function* generateEncoder(typeUri, types) {
|
|
|
891
876
|
}
|
|
892
877
|
yield `
|
|
893
878
|
${type.typeless ? "" : `values["@type"] = [${JSON.stringify(type.uri)}];`}
|
|
894
|
-
if (this.id != null) values["@id"] = this.id
|
|
879
|
+
if (this.id != null) values["@id"] = formatIri(this.id);
|
|
895
880
|
if (options.format === "expand") {
|
|
896
881
|
return await jsonld.expand(
|
|
897
882
|
values,
|
|
@@ -1017,10 +1002,12 @@ async function* generateDecoder(typeUri, types, moduleVarNames) {
|
|
|
1017
1002
|
};
|
|
1018
1003
|
// deno-lint-ignore no-explicit-any
|
|
1019
1004
|
let values: Record<string, any[]> & { "@id"?: string };
|
|
1005
|
+
let expanded: unknown[];
|
|
1020
1006
|
if (globalThis.Object.keys(json).length == 0) {
|
|
1021
1007
|
values = {};
|
|
1008
|
+
expanded = [values];
|
|
1022
1009
|
} else {
|
|
1023
|
-
|
|
1010
|
+
expanded = await jsonld.expand(json, {
|
|
1024
1011
|
documentLoader: options.contextLoader,
|
|
1025
1012
|
keepFreeFloatingNodes: true,
|
|
1026
1013
|
});
|
|
@@ -1028,11 +1015,9 @@ async function* generateDecoder(typeUri, types, moduleVarNames) {
|
|
|
1028
1015
|
// deno-lint-ignore no-explicit-any
|
|
1029
1016
|
(expanded[0] ?? {}) as (Record<string, any[]> & { "@id"?: string });
|
|
1030
1017
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
if (options.baseUrl == null && values["@id"] != null && !values["@id"].startsWith("_:") && URL.canParse(values["@id"])) {
|
|
1035
|
-
options = { ...options, baseUrl: new URL(values["@id"]) };
|
|
1018
|
+
const id = parseJsonLdId(values["@id"], options.baseUrl);
|
|
1019
|
+
if (id != null && options.baseUrl == null) {
|
|
1020
|
+
options = { ...options, baseUrl: id };
|
|
1036
1021
|
}
|
|
1037
1022
|
`;
|
|
1038
1023
|
const subtypes = getSubtypes(typeUri, types, true);
|
|
@@ -1053,10 +1038,24 @@ async function* generateDecoder(typeUri, types, moduleVarNames) {
|
|
|
1053
1038
|
throw new TypeError("Invalid type: " + values["@type"]);
|
|
1054
1039
|
}
|
|
1055
1040
|
}
|
|
1041
|
+
`;
|
|
1042
|
+
yield `
|
|
1043
|
+
let cacheJsonLd = !("_fromSubclass" in options) || !options._fromSubclass
|
|
1044
|
+
? normalizeJsonLdIris(
|
|
1045
|
+
expanded,
|
|
1046
|
+
PORTABLE_IRI_KEYS,
|
|
1047
|
+
PORTABLE_IRI_PATTERN,
|
|
1048
|
+
)
|
|
1049
|
+
: undefined;
|
|
1050
|
+
if (cacheJsonLd != null && cacheJsonLd !== expanded) {
|
|
1051
|
+
cacheJsonLd = structuredClone(cacheJsonLd);
|
|
1052
|
+
}
|
|
1056
1053
|
`;
|
|
1057
1054
|
if (type.extends == null) yield `
|
|
1058
1055
|
const instance = new this(
|
|
1059
|
-
{
|
|
1056
|
+
{
|
|
1057
|
+
id
|
|
1058
|
+
},
|
|
1060
1059
|
options,
|
|
1061
1060
|
);
|
|
1062
1061
|
`;
|
|
@@ -1099,11 +1098,7 @@ async function* generateDecoder(typeUri, types, moduleVarNames) {
|
|
|
1099
1098
|
if (typeof v === "object" && "@id" in v && !("@type" in v)
|
|
1100
1099
|
&& globalThis.Object.keys(v).length === 1) {
|
|
1101
1100
|
if (v["@id"].startsWith("_:")) continue;
|
|
1102
|
-
${variable}.push(
|
|
1103
|
-
!URL.canParse(v["@id"], ${propertyBaseUrl}) && v["@id"].startsWith("at://")
|
|
1104
|
-
? new URL("at://" + encodeURIComponent(v["@id"].substring(5)))
|
|
1105
|
-
: new URL(v["@id"], ${propertyBaseUrl})
|
|
1106
|
-
);
|
|
1101
|
+
${variable}.push(parseIri(v["@id"], ${propertyBaseUrl}));
|
|
1107
1102
|
continue;
|
|
1108
1103
|
}
|
|
1109
1104
|
`;
|
|
@@ -1131,7 +1126,19 @@ async function* generateDecoder(typeUri, types, moduleVarNames) {
|
|
|
1131
1126
|
yield `
|
|
1132
1127
|
if (!("_fromSubclass" in options) || !options._fromSubclass) {
|
|
1133
1128
|
try {
|
|
1134
|
-
|
|
1129
|
+
if (cacheJsonLd != null && cacheJsonLd !== expanded) {
|
|
1130
|
+
const compactArray = Array.isArray(json) && json.length === 1;
|
|
1131
|
+
const jsonLd = compactArray ? json[0] : json;
|
|
1132
|
+
const normalized = cacheJsonLd;
|
|
1133
|
+
const cachedJsonLd = await compactJsonLdCache(
|
|
1134
|
+
normalized,
|
|
1135
|
+
jsonLd,
|
|
1136
|
+
options.contextLoader,
|
|
1137
|
+
);
|
|
1138
|
+
instance._cachedJsonLd = compactArray ? [cachedJsonLd] : cachedJsonLd;
|
|
1139
|
+
} else {
|
|
1140
|
+
instance._cachedJsonLd = structuredClone(json);
|
|
1141
|
+
}
|
|
1135
1142
|
} catch {
|
|
1136
1143
|
getLogger(["fedify", "vocab"]).warn(
|
|
1137
1144
|
"Failed to cache JSON-LD: {json}",
|
|
@@ -1558,9 +1565,10 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1558
1565
|
${JSON.stringify(version)},
|
|
1559
1566
|
);
|
|
1560
1567
|
return await tracer.startActiveSpan("activitypub.lookup_object", async (span) => {
|
|
1568
|
+
const lookupUrl = formatIri(url);
|
|
1561
1569
|
let fetchResult: RemoteDocument;
|
|
1562
1570
|
try {
|
|
1563
|
-
fetchResult = await documentLoader(
|
|
1571
|
+
fetchResult = await documentLoader(lookupUrl);
|
|
1564
1572
|
} catch (error) {
|
|
1565
1573
|
span.setStatus({
|
|
1566
1574
|
code: SpanStatusCode.ERROR,
|
|
@@ -1570,21 +1578,20 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1570
1578
|
if (options.suppressError) {
|
|
1571
1579
|
getLogger(["fedify", "vocab"]).error(
|
|
1572
1580
|
"Failed to fetch {url}: {error}",
|
|
1573
|
-
{ error, url:
|
|
1581
|
+
{ error, url: lookupUrl }
|
|
1574
1582
|
);
|
|
1575
1583
|
return null;
|
|
1576
1584
|
}
|
|
1577
1585
|
throw error;
|
|
1578
1586
|
}
|
|
1579
1587
|
const { document, documentUrl } = fetchResult;
|
|
1580
|
-
const baseUrl =
|
|
1588
|
+
const baseUrl = parseIri(documentUrl);
|
|
1581
1589
|
try {
|
|
1582
1590
|
const obj = await this.#${property.singularName}_fromJsonLd(
|
|
1583
1591
|
document,
|
|
1584
1592
|
{ documentLoader, contextLoader, tracerProvider, baseUrl }
|
|
1585
1593
|
);
|
|
1586
|
-
if (
|
|
1587
|
-
obj.id.origin !== baseUrl.origin) {
|
|
1594
|
+
if (obj?.id != null && !isTrustedIriOrigin(options, obj.id, baseUrl)) {
|
|
1588
1595
|
if (options.crossOrigin === "throw") {
|
|
1589
1596
|
throw new Error(
|
|
1590
1597
|
"The object's @id (" + obj.id.href + ") has a different origin " +
|
|
@@ -1613,7 +1620,7 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1613
1620
|
if (options.suppressError) {
|
|
1614
1621
|
getLogger(["fedify", "vocab"]).error(
|
|
1615
1622
|
"Failed to parse {url}: {error}",
|
|
1616
|
-
{ error: e, url:
|
|
1623
|
+
{ error: e, url: lookupUrl }
|
|
1617
1624
|
);
|
|
1618
1625
|
return null;
|
|
1619
1626
|
}
|
|
@@ -1733,8 +1740,9 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1733
1740
|
}
|
|
1734
1741
|
if (this.${await getFieldName(property.uri)}.length < 1) return null;
|
|
1735
1742
|
let v = this.${await getFieldName(property.uri)}[0];
|
|
1736
|
-
if (
|
|
1737
|
-
v.id != null &&
|
|
1743
|
+
if (!(v instanceof URL) &&
|
|
1744
|
+
v.id != null &&
|
|
1745
|
+
!isTrustedIriOrigin(options, v.id, this.id) &&
|
|
1738
1746
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1739
1747
|
v = v.id;
|
|
1740
1748
|
}
|
|
@@ -1773,8 +1781,8 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1773
1781
|
`;
|
|
1774
1782
|
}
|
|
1775
1783
|
yield `
|
|
1776
|
-
if (
|
|
1777
|
-
this.id != null && v.id
|
|
1784
|
+
if (v?.id != null &&
|
|
1785
|
+
this.id != null && !isTrustedIriOrigin(options, v.id, this.id) &&
|
|
1778
1786
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1779
1787
|
if (options.crossOrigin === "throw") {
|
|
1780
1788
|
throw new Error(
|
|
@@ -1838,8 +1846,9 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1838
1846
|
const vs = this.${await getFieldName(property.uri)};
|
|
1839
1847
|
for (let i = 0; i < vs.length; i++) {
|
|
1840
1848
|
let v = vs[i];
|
|
1841
|
-
if (
|
|
1842
|
-
v.id != null &&
|
|
1849
|
+
if (!(v instanceof URL) &&
|
|
1850
|
+
v.id != null &&
|
|
1851
|
+
!isTrustedIriOrigin(options, v.id, this.id) &&
|
|
1843
1852
|
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
1844
1853
|
v = v.id;
|
|
1845
1854
|
}
|
|
@@ -1879,9 +1888,9 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1879
1888
|
`;
|
|
1880
1889
|
}
|
|
1881
1890
|
yield `
|
|
1882
|
-
if (
|
|
1883
|
-
this.id != null && v.id
|
|
1884
|
-
!this.${await getFieldName(property.uri, "#_trust")}.has(
|
|
1891
|
+
if (v?.id != null &&
|
|
1892
|
+
this.id != null && !isTrustedIriOrigin(options, v.id, this.id) &&
|
|
1893
|
+
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
1885
1894
|
if (options.crossOrigin === "throw") {
|
|
1886
1895
|
throw new Error(
|
|
1887
1896
|
"The property object's @id (" + v.id.href + ") has a different " +
|
|
@@ -1914,6 +1923,33 @@ async function* generateProperties(typeUri, types, moduleVarNames) {
|
|
|
1914
1923
|
}
|
|
1915
1924
|
//#endregion
|
|
1916
1925
|
//#region src/class.ts
|
|
1926
|
+
const XSD_ANY_URI = "http://www.w3.org/2001/XMLSchema#anyURI";
|
|
1927
|
+
const FEDIFY_URL = "fedify:url";
|
|
1928
|
+
const INTERNAL_RUNTIME_IMPORTS = [
|
|
1929
|
+
"compactJsonLdCache",
|
|
1930
|
+
"getJsonLdContext",
|
|
1931
|
+
"isTrustedIriOrigin",
|
|
1932
|
+
"normalizeJsonLdIris"
|
|
1933
|
+
].join(",\n ");
|
|
1934
|
+
const RUNTIME_IMPORTS = [
|
|
1935
|
+
"canParseDecimal",
|
|
1936
|
+
"decodeMultibase",
|
|
1937
|
+
"type Decimal",
|
|
1938
|
+
"type DocumentLoader",
|
|
1939
|
+
"encodeMultibase",
|
|
1940
|
+
"exportMultibaseKey",
|
|
1941
|
+
"exportSpki",
|
|
1942
|
+
"formatIri",
|
|
1943
|
+
"getDocumentLoader",
|
|
1944
|
+
"importMultibaseKey",
|
|
1945
|
+
"importPem",
|
|
1946
|
+
"isDecimal",
|
|
1947
|
+
"LanguageString",
|
|
1948
|
+
"parseDecimal",
|
|
1949
|
+
"parseIri",
|
|
1950
|
+
"parseJsonLdId",
|
|
1951
|
+
"type RemoteDocument"
|
|
1952
|
+
].join(",\n ");
|
|
1917
1953
|
/**
|
|
1918
1954
|
* Sorts the given types topologically so that the base types come before the
|
|
1919
1955
|
* extended types.
|
|
@@ -2047,6 +2083,18 @@ export function getEntityTypeById(id: string | URL): $EntityType | undefined {
|
|
|
2047
2083
|
|
|
2048
2084
|
`;
|
|
2049
2085
|
}
|
|
2086
|
+
function canContainIriValue(property, types) {
|
|
2087
|
+
return property.range.some((typeUri) => typeUri === XSD_ANY_URI || typeUri === FEDIFY_URL || types[typeUri]?.entity);
|
|
2088
|
+
}
|
|
2089
|
+
function addKeys(keys, property) {
|
|
2090
|
+
keys.add(property.uri);
|
|
2091
|
+
if (property.compactName != null) keys.add(property.compactName);
|
|
2092
|
+
}
|
|
2093
|
+
function addPortableIriKeys(keys, property, types) {
|
|
2094
|
+
if (!canContainIriValue(property, types)) return;
|
|
2095
|
+
addKeys(keys, property);
|
|
2096
|
+
if ("redundantProperties" in property && property.redundantProperties != null) for (const redundantProperty of property.redundantProperties) addKeys(keys, redundantProperty);
|
|
2097
|
+
}
|
|
2050
2098
|
/**
|
|
2051
2099
|
* Generates the TypeScript classes from the given types.
|
|
2052
2100
|
* @param types The types to generate classes from.
|
|
@@ -2054,33 +2102,21 @@ export function getEntityTypeById(id: string | URL): $EntityType | undefined {
|
|
|
2054
2102
|
*/
|
|
2055
2103
|
async function* generateClasses(types) {
|
|
2056
2104
|
validateTypeSchemas(types);
|
|
2057
|
-
const runtimeImports = [
|
|
2058
|
-
"canParseDecimal",
|
|
2059
|
-
"decodeMultibase",
|
|
2060
|
-
"type Decimal",
|
|
2061
|
-
"type DocumentLoader",
|
|
2062
|
-
"encodeMultibase",
|
|
2063
|
-
"exportMultibaseKey",
|
|
2064
|
-
"exportSpki",
|
|
2065
|
-
"getDocumentLoader",
|
|
2066
|
-
"importMultibaseKey",
|
|
2067
|
-
"importPem",
|
|
2068
|
-
"isDecimal",
|
|
2069
|
-
"LanguageString",
|
|
2070
|
-
"parseDecimal",
|
|
2071
|
-
"type RemoteDocument"
|
|
2072
|
-
];
|
|
2073
2105
|
yield "// deno-lint-ignore-file ban-unused-ignore no-explicit-any no-unused-vars prefer-const verbatim-module-syntax\n";
|
|
2074
2106
|
yield "import jsonld from \"@fedify/vocab-runtime/jsonld\";\n";
|
|
2075
2107
|
yield "import { getLogger } from \"@logtape/logtape\";\n";
|
|
2076
2108
|
yield `import { type Span, SpanStatusCode, type TracerProvider, trace }
|
|
2077
2109
|
from "@opentelemetry/api";\n`;
|
|
2078
|
-
yield `import {\n ${
|
|
2110
|
+
yield `import {\n ${RUNTIME_IMPORTS}\n} from "@fedify/vocab-runtime";\n`;
|
|
2111
|
+
yield `import {\n ${INTERNAL_RUNTIME_IMPORTS}\n} from "@fedify/vocab-runtime/internal/jsonld-cache";\n`;
|
|
2079
2112
|
yield `import {
|
|
2080
2113
|
isTemporalDuration,
|
|
2081
2114
|
isTemporalInstant,
|
|
2082
2115
|
} from "@fedify/vocab-runtime/temporal";\n`;
|
|
2083
|
-
|
|
2116
|
+
const portableIriKeys = new Set(["@id", "id"]);
|
|
2117
|
+
for (const type of Object.values(types)) for (const property of type.properties) addPortableIriKeys(portableIriKeys, property, types);
|
|
2118
|
+
yield "const PORTABLE_IRI_PATTERN = /^ap(?:\\+ef61)?:\\/\\//i;\n";
|
|
2119
|
+
yield `const PORTABLE_IRI_KEYS: ReadonlySet<string> = new Set(${JSON.stringify([...portableIriKeys].sort())});\n\n`;
|
|
2084
2120
|
const moduleVarNames = /* @__PURE__ */ new Map();
|
|
2085
2121
|
const sorted = sortTopologically(types);
|
|
2086
2122
|
for (const typeUri of sorted) for (const property of types[typeUri].properties) {
|