@fedify/vocab-tools 2.3.0-dev.994 → 2.3.0-pr.809.37

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-tools",
3
- "version": "2.3.0-dev.994+9071ca0a",
3
+ "version": "2.3.0-pr.809.37+0574ba5c",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts"
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "imports": {
14
14
  "@cfworker/json-schema": "npm:@cfworker/json-schema@^4.1.1",
15
- "yaml": "npm:yaml@^2.8.1"
15
+ "yaml": "npm:yaml@^2.9.0"
16
16
  },
17
17
  "exclude": [
18
18
  "dist",
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.3.0-dev.994+9071ca0a";
11
+ var version = "2.3.0-pr.809.37+0574ba5c";
12
12
  //#endregion
13
13
  //#region src/type.ts
14
14
  const HEURISTICS_CONTEXTS = [
@@ -208,7 +208,7 @@ const scalarTypes = {
208
208
  "http://www.w3.org/2001/XMLSchema#dateTime": {
209
209
  name: "Temporal.Instant",
210
210
  typeGuard(v) {
211
- return `${v} instanceof Temporal.Instant`;
211
+ return `isTemporalInstant(${v})`;
212
212
  },
213
213
  encoder(v) {
214
214
  return `{
@@ -238,7 +238,7 @@ const scalarTypes = {
238
238
  "http://www.w3.org/2001/XMLSchema#duration": {
239
239
  name: "Temporal.Duration",
240
240
  typeGuard(v) {
241
- return `${v} instanceof Temporal.Duration`;
241
+ return `isTemporalDuration(${v})`;
242
242
  },
243
243
  encoder(v) {
244
244
  return `{
@@ -712,6 +712,38 @@ async function loadSchemaFiles(dir) {
712
712
  }
713
713
  //#endregion
714
714
  //#region src/codec.ts
715
+ function* generatePreprocessorBlock(property, rangeTypeName, variable, baseUrlExpr, moduleVarNames) {
716
+ if (property.preprocessors == null || property.preprocessors.length === 0) return;
717
+ yield `
718
+ {
719
+ let _handled: ${rangeTypeName} | undefined;
720
+ `;
721
+ for (const pp of property.preprocessors) {
722
+ const varName = moduleVarNames.get(pp.module);
723
+ if (varName == null) throw new Error(`Preprocessor module "${pp.module}" is not registered in the generated imports. Ensure all preprocessor modules used in property schemas are available.`);
724
+ yield `
725
+ if (_handled === undefined) {
726
+ const _result = await ${varName}[${JSON.stringify(pp.function)}](v, {
727
+ documentLoader: options.documentLoader,
728
+ contextLoader: options.contextLoader,
729
+ tracerProvider: options.tracerProvider,
730
+ baseUrl: ${baseUrlExpr},
731
+ });
732
+ if (_result instanceof Error) throw _result;
733
+ if (_result !== undefined) {
734
+ _handled = _result as ${rangeTypeName};
735
+ }
736
+ }
737
+ `;
738
+ }
739
+ yield `
740
+ if (_handled !== undefined) {
741
+ ${variable}.push(_handled);
742
+ continue;
743
+ }
744
+ }
745
+ `;
746
+ }
715
747
  async function* generateEncoder(typeUri, types) {
716
748
  const type = types[typeUri];
717
749
  yield `
@@ -912,7 +944,7 @@ async function* generateEncoder(typeUri, types) {
912
944
  }
913
945
  `;
914
946
  }
915
- async function* generateDecoder(typeUri, types) {
947
+ async function* generateDecoder(typeUri, types, moduleVarNames) {
916
948
  const type = types[typeUri];
917
949
  yield `
918
950
  /**
@@ -996,7 +1028,10 @@ async function* generateDecoder(typeUri, types) {
996
1028
  // deno-lint-ignore no-explicit-any
997
1029
  (expanded[0] ?? {}) as (Record<string, any[]> & { "@id"?: string });
998
1030
  }
999
- if (options.baseUrl == null && values["@id"] != null) {
1031
+ if (values["@id"] != null && !values["@id"].startsWith("_:") && !URL.canParse(values["@id"], options.baseUrl)) {
1032
+ throw new TypeError("Invalid @id: " + values["@id"]);
1033
+ }
1034
+ if (options.baseUrl == null && values["@id"] != null && !values["@id"].startsWith("_:") && URL.canParse(values["@id"])) {
1000
1035
  options = { ...options, baseUrl: new URL(values["@id"]) };
1001
1036
  }
1002
1037
  `;
@@ -1021,7 +1056,7 @@ async function* generateDecoder(typeUri, types) {
1021
1056
  `;
1022
1057
  if (type.extends == null) yield `
1023
1058
  const instance = new this(
1024
- { id: "@id" in values ? new URL(values["@id"] as string) : undefined },
1059
+ { id: values["@id"] != null && !values["@id"].startsWith("_:") && URL.canParse(values["@id"], options.baseUrl) ? new URL(values["@id"], options.baseUrl) : undefined },
1025
1060
  options,
1026
1061
  );
1027
1062
  `;
@@ -1058,26 +1093,29 @@ async function* generateDecoder(typeUri, types) {
1058
1093
  ) {
1059
1094
  if (v == null) continue;
1060
1095
  `;
1096
+ const propertyBaseUrl = "options.baseUrl";
1097
+ yield* generatePreprocessorBlock(property, getTypeNames(property.range, types), variable, propertyBaseUrl, moduleVarNames);
1061
1098
  if (!areAllScalarTypes(property.range, types)) yield `
1062
1099
  if (typeof v === "object" && "@id" in v && !("@type" in v)
1063
1100
  && globalThis.Object.keys(v).length === 1) {
1101
+ if (v["@id"].startsWith("_:")) continue;
1064
1102
  ${variable}.push(
1065
- !URL.canParse(v["@id"]) && v["@id"].startsWith("at://")
1103
+ !URL.canParse(v["@id"], ${propertyBaseUrl}) && v["@id"].startsWith("at://")
1066
1104
  ? new URL("at://" + encodeURIComponent(v["@id"].substring(5)))
1067
- : new URL(v["@id"])
1105
+ : new URL(v["@id"], ${propertyBaseUrl})
1068
1106
  );
1069
1107
  continue;
1070
1108
  }
1071
1109
  `;
1072
1110
  if (property.range.length == 1) yield `
1073
- const decoded = ${getDecoder(property.range[0], types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`)};
1111
+ const decoded = ${getDecoder(property.range[0], types, "v", "options", propertyBaseUrl)};
1074
1112
  if (typeof decoded === "undefined") continue;
1075
1113
  ${variable}.push(decoded);`;
1076
1114
  else {
1077
1115
  yield `
1078
1116
  const decoded =
1079
1117
  `;
1080
- const decoders = getDecoders(property.range, types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1118
+ const decoders = getDecoders(property.range, types, "v", "options", propertyBaseUrl);
1081
1119
  for (const code of decoders) yield code;
1082
1120
  yield `
1083
1121
  ;
@@ -1152,6 +1190,8 @@ async function* generateConstructor(typeUri, types) {
1152
1190
  this.#documentLoader = options.documentLoader;
1153
1191
  this.#contextLoader = options.contextLoader;
1154
1192
  this.#tracerProvider = options.tracerProvider;
1193
+ const baseUrl = (options as { baseUrl?: URL }).baseUrl;
1194
+ this.#_baseUrl = baseUrl == null ? undefined : new URL(baseUrl.href);
1155
1195
  if ("$warning" in options) {
1156
1196
  this.#warning = options.$warning as unknown as {
1157
1197
  category: string[];
@@ -1463,9 +1503,16 @@ function emitOverride(typeUri, types, property) {
1463
1503
  }
1464
1504
  return "";
1465
1505
  }
1466
- async function* generateProperty(type, property, types) {
1506
+ async function* generateProperty(type, property, types, moduleVarNames) {
1467
1507
  const override = emitOverride(type.uri, types, property);
1468
1508
  const doc = `\n/** ${property.description.replaceAll("\n", "\n * ")}\n */\n`;
1509
+ const cachedPropertyBaseUrl = `(options as { baseUrl?: URL }).baseUrl ??
1510
+ this._baseUrl ??
1511
+ (this.id != null &&
1512
+ (this.id.protocol === "http:" ||
1513
+ this.id.protocol === "https:")
1514
+ ? this.id
1515
+ : undefined)`;
1469
1516
  if (areAllScalarTypes(property.range, types)) {
1470
1517
  if (hasSingularAccessor(property)) {
1471
1518
  yield doc;
@@ -1598,6 +1645,36 @@ async function* generateProperty(type, property, types) {
1598
1645
  this._tracerProvider ?? trace.getTracerProvider();
1599
1646
  const baseUrl = options.baseUrl;
1600
1647
  `;
1648
+ if (property.preprocessors != null && property.preprocessors.length > 0) {
1649
+ yield `
1650
+ if (jsonLd != null && typeof jsonLd === "object") {
1651
+ const _expanded = await jsonld.expand(jsonLd, {
1652
+ documentLoader: contextLoader,
1653
+ keepFreeFloatingNodes: true,
1654
+ });
1655
+ for (const _pp_obj of _expanded) {
1656
+ `;
1657
+ for (const pp of property.preprocessors) {
1658
+ const varName = moduleVarNames.get(pp.module);
1659
+ if (varName == null) throw new Error(`Preprocessor module "${pp.module}" is not registered in the generated imports. Ensure all preprocessor modules used in property schemas are available.`);
1660
+ yield `
1661
+ {
1662
+ const _result = await ${varName}[${JSON.stringify(pp.function)}](_pp_obj, {
1663
+ documentLoader,
1664
+ contextLoader,
1665
+ tracerProvider,
1666
+ baseUrl,
1667
+ });
1668
+ if (_result instanceof Error) throw _result;
1669
+ if (_result !== undefined) return _result as ${getTypeNames(property.range, types)};
1670
+ }
1671
+ `;
1672
+ }
1673
+ yield `
1674
+ }
1675
+ }
1676
+ `;
1677
+ }
1601
1678
  for (const range of property.range) {
1602
1679
  if (!(range in types)) continue;
1603
1680
  yield `
@@ -1671,7 +1748,8 @@ async function* generateProperty(type, property, types) {
1671
1748
  return fetched;
1672
1749
  }
1673
1750
  `;
1674
- if (property.compactName != null) yield `
1751
+ if (property.compactName != null) {
1752
+ yield `
1675
1753
  if (
1676
1754
  this._cachedJsonLd != null &&
1677
1755
  typeof this._cachedJsonLd === "object" &&
@@ -1682,10 +1760,18 @@ async function* generateProperty(type, property, types) {
1682
1760
  ${JSON.stringify(property.compactName)}];
1683
1761
  const doc = Array.isArray(prop) ? prop[0] : prop;
1684
1762
  if (doc != null && typeof doc === "object" && "@context" in doc) {
1685
- v = await this.#${property.singularName}_fromJsonLd(doc, options);
1763
+ `;
1764
+ yield `
1765
+ v = await this.#${property.singularName}_fromJsonLd(doc, {
1766
+ ...options,
1767
+ baseUrl: ${cachedPropertyBaseUrl},
1768
+ });
1769
+ `;
1770
+ yield `
1686
1771
  }
1687
1772
  }
1688
1773
  `;
1774
+ }
1689
1775
  yield `
1690
1776
  if (options.crossOrigin !== "trust" && v?.id != null &&
1691
1777
  this.id != null && v.id.origin !== this.id.origin &&
@@ -1768,7 +1854,8 @@ async function* generateProperty(type, property, types) {
1768
1854
  continue;
1769
1855
  }
1770
1856
  `;
1771
- if (property.compactName != null) yield `
1857
+ if (property.compactName != null) {
1858
+ yield `
1772
1859
  if (
1773
1860
  this._cachedJsonLd != null &&
1774
1861
  typeof this._cachedJsonLd === "object" &&
@@ -1779,10 +1866,18 @@ async function* generateProperty(type, property, types) {
1779
1866
  ${JSON.stringify(property.compactName)}];
1780
1867
  const obj = Array.isArray(prop) ? prop[i] : prop;
1781
1868
  if (obj != null && typeof obj === "object" && "@context" in obj) {
1782
- v = await this.#${property.singularName}_fromJsonLd(obj, options);
1869
+ `;
1870
+ yield `
1871
+ v = await this.#${property.singularName}_fromJsonLd(obj, {
1872
+ ...options,
1873
+ baseUrl: ${cachedPropertyBaseUrl},
1874
+ });
1875
+ `;
1876
+ yield `
1783
1877
  }
1784
1878
  }
1785
1879
  `;
1880
+ }
1786
1881
  yield `
1787
1882
  if (options.crossOrigin !== "trust" && v?.id != null &&
1788
1883
  this.id != null && v.id.origin !== this.id.origin &&
@@ -1813,9 +1908,9 @@ async function* generateProperty(type, property, types) {
1813
1908
  }
1814
1909
  }
1815
1910
  }
1816
- async function* generateProperties(typeUri, types) {
1911
+ async function* generateProperties(typeUri, types, moduleVarNames) {
1817
1912
  const type = types[typeUri];
1818
- for (const property of type.properties) yield* generateProperty(type, property, types);
1913
+ for (const property of type.properties) yield* generateProperty(type, property, types, moduleVarNames);
1819
1914
  }
1820
1915
  //#endregion
1821
1916
  //#region src/class.ts
@@ -1841,7 +1936,7 @@ function sortTopologically(types) {
1841
1936
  sorted.push(node.uri);
1842
1937
  }
1843
1938
  }
1844
- async function* generateClass(typeUri, types) {
1939
+ async function* generateClass(typeUri, types, moduleVarNames) {
1845
1940
  const type = types[typeUri];
1846
1941
  yield `/** ${type.description.replaceAll("\n", "\n * ")}\n */\n`;
1847
1942
  if (type.extends) {
@@ -1858,6 +1953,7 @@ async function* generateClass(typeUri, types) {
1858
1953
  values?: Record<string, unknown>;
1859
1954
  };
1860
1955
  #cachedJsonLd?: unknown;
1956
+ readonly #_baseUrl?: URL;
1861
1957
  readonly id: URL | null;
1862
1958
 
1863
1959
  protected get _documentLoader(): DocumentLoader | undefined {
@@ -1887,6 +1983,10 @@ async function* generateClass(typeUri, types) {
1887
1983
  protected set _cachedJsonLd(value: unknown | undefined) {
1888
1984
  this.#cachedJsonLd = value;
1889
1985
  }
1986
+
1987
+ protected get _baseUrl(): URL | undefined {
1988
+ return this.#_baseUrl;
1989
+ }
1890
1990
  `;
1891
1991
  yield `
1892
1992
  /**
@@ -1899,9 +1999,9 @@ async function* generateClass(typeUri, types) {
1899
1999
  for await (const code of generateFields(typeUri, types)) yield code;
1900
2000
  for await (const code of generateConstructor(typeUri, types)) yield code;
1901
2001
  for await (const code of generateCloner(typeUri, types)) yield code;
1902
- for await (const code of generateProperties(typeUri, types)) yield code;
2002
+ for await (const code of generateProperties(typeUri, types, moduleVarNames)) yield code;
1903
2003
  for await (const code of generateEncoder(typeUri, types)) yield code;
1904
- for await (const code of generateDecoder(typeUri, types)) yield code;
2004
+ for await (const code of generateDecoder(typeUri, types, moduleVarNames)) yield code;
1905
2005
  for await (const code of generateInspector(typeUri, types)) yield code;
1906
2006
  yield "}\n\n";
1907
2007
  for await (const code of generateInspectorPostClass(typeUri, types)) yield code;
@@ -1970,15 +2070,29 @@ async function* generateClasses(types) {
1970
2070
  "parseDecimal",
1971
2071
  "type RemoteDocument"
1972
2072
  ];
1973
- yield "// deno-lint-ignore-file ban-unused-ignore no-unused-vars prefer-const verbatim-module-syntax\n";
2073
+ yield "// deno-lint-ignore-file ban-unused-ignore no-explicit-any no-unused-vars prefer-const verbatim-module-syntax\n";
1974
2074
  yield "import jsonld from \"@fedify/vocab-runtime/jsonld\";\n";
1975
2075
  yield "import { getLogger } from \"@logtape/logtape\";\n";
1976
2076
  yield `import { type Span, SpanStatusCode, type TracerProvider, trace }
1977
2077
  from "@opentelemetry/api";\n`;
1978
2078
  yield `import {\n ${runtimeImports.join(",\n ")}\n} from "@fedify/vocab-runtime";\n`;
2079
+ yield `import {
2080
+ isTemporalDuration,
2081
+ isTemporalInstant,
2082
+ } from "@fedify/vocab-runtime/temporal";\n`;
1979
2083
  yield "\n\n";
2084
+ const moduleVarNames = /* @__PURE__ */ new Map();
1980
2085
  const sorted = sortTopologically(types);
1981
- for (const typeUri of sorted) for await (const code of generateClass(typeUri, types)) yield code;
2086
+ for (const typeUri of sorted) for (const property of types[typeUri].properties) {
2087
+ if (property.preprocessors == null) continue;
2088
+ for (const pp of property.preprocessors) if (!moduleVarNames.has(pp.module)) {
2089
+ const name = `_ppM${moduleVarNames.size}`;
2090
+ moduleVarNames.set(pp.module, name);
2091
+ }
2092
+ }
2093
+ for (const [modulePath, varName] of moduleVarNames) yield `import * as ${varName} from ${JSON.stringify(modulePath)};\n`;
2094
+ if (moduleVarNames.size > 0) yield "\n";
2095
+ for (const typeUri of sorted) for await (const code of generateClass(typeUri, types, moduleVarNames)) yield code;
1982
2096
  for (const code of generateEntityTypeHelpers(sorted, types)) yield code;
1983
2097
  }
1984
2098
  //#endregion
package/dist/mod.d.cts CHANGED
@@ -100,6 +100,30 @@ interface PropertySchemaBase {
100
100
  */
101
101
  inherit: true;
102
102
  };
103
+ /**
104
+ * Preprocessors for this property. Each preprocessor receives an expanded
105
+ * JSON-LD property value and may return a vocabulary object matching the
106
+ * property's declared range, `undefined` when it did not handle the value,
107
+ * or an `Error` when it recognized the value but failed while converting it.
108
+ *
109
+ * `module` is resolved from the generated vocabulary source file
110
+ * and imported statically at the top of the generated file.
111
+ */
112
+ preprocessors?: PropertyPreprocessorSchema[];
113
+ }
114
+ /**
115
+ * A schema for a property preprocessor that normalizes wire-level values
116
+ * before the generated range decoder runs.
117
+ */
118
+ interface PropertyPreprocessorSchema {
119
+ /**
120
+ * Module specifier resolved from the generated vocabulary source file.
121
+ */
122
+ module: string;
123
+ /**
124
+ * The name of the exported function in the module.
125
+ */
126
+ function: string;
103
127
  }
104
128
  type PropertySchemaTyping = {
105
129
  /**
@@ -196,4 +220,4 @@ declare function loadSchemaFiles(dir: string): Promise<Record<string, TypeSchema
196
220
  //#region src/type.d.ts
197
221
  declare function areAllScalarTypes(typeUris: string[], types: Record<string, TypeSchema>): boolean;
198
222
  //#endregion
199
- export { type PropertySchema, type TypeSchema, areAllScalarTypes, generateVocab, loadSchemaFiles };
223
+ export { type PropertyPreprocessorSchema, type PropertySchema, type TypeSchema, areAllScalarTypes, generateVocab, loadSchemaFiles };
package/dist/mod.d.ts CHANGED
@@ -100,6 +100,30 @@ interface PropertySchemaBase {
100
100
  */
101
101
  inherit: true;
102
102
  };
103
+ /**
104
+ * Preprocessors for this property. Each preprocessor receives an expanded
105
+ * JSON-LD property value and may return a vocabulary object matching the
106
+ * property's declared range, `undefined` when it did not handle the value,
107
+ * or an `Error` when it recognized the value but failed while converting it.
108
+ *
109
+ * `module` is resolved from the generated vocabulary source file
110
+ * and imported statically at the top of the generated file.
111
+ */
112
+ preprocessors?: PropertyPreprocessorSchema[];
113
+ }
114
+ /**
115
+ * A schema for a property preprocessor that normalizes wire-level values
116
+ * before the generated range decoder runs.
117
+ */
118
+ interface PropertyPreprocessorSchema {
119
+ /**
120
+ * Module specifier resolved from the generated vocabulary source file.
121
+ */
122
+ module: string;
123
+ /**
124
+ * The name of the exported function in the module.
125
+ */
126
+ function: string;
103
127
  }
104
128
  type PropertySchemaTyping = {
105
129
  /**
@@ -196,4 +220,4 @@ declare function loadSchemaFiles(dir: string): Promise<Record<string, TypeSchema
196
220
  //#region src/type.d.ts
197
221
  declare function areAllScalarTypes(typeUris: string[], types: Record<string, TypeSchema>): boolean;
198
222
  //#endregion
199
- export { type PropertySchema, type TypeSchema, areAllScalarTypes, generateVocab, loadSchemaFiles };
223
+ export { type PropertyPreprocessorSchema, type PropertySchema, type TypeSchema, areAllScalarTypes, generateVocab, loadSchemaFiles };