@fedify/vocab-tools 2.0.29-dev.2055 → 2.0.29-dev.2068

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.0.29-dev.2055+5e21857f",
3
+ "version": "2.0.29-dev.2068+bb645217",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts"
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.0.29-dev.2055+5e21857f";
11
+ var version = "2.0.29-dev.2068+bb645217";
12
12
  //#endregion
13
13
  //#region src/type.ts
14
14
  const HEURISTICS_CONTEXTS = [
@@ -307,13 +307,16 @@ const scalarTypes = {
307
307
  return `${v}.href`;
308
308
  },
309
309
  dataCheck(v) {
310
- return `typeof ${v} === "object" && "@value" in ${v}
311
- && typeof ${v}["@value"] === "string"
312
- && ${v}["@value"] !== "" && ${v}["@value"] !== "/"`;
310
+ return `typeof ${v} === "object" &&
311
+ ((typeof ${v}["@id"] === "string" && canDecodeIri(${v}["@id"])) ||
312
+ (typeof ${v}["@value"] === "string" && canDecodeIri(${v}["@value"])))`;
313
313
  },
314
314
  decoder(v) {
315
- return `new URL(${v}["@value"])`;
316
- }
315
+ return `decodeIri(
316
+ typeof ${v}["@id"] === "string" ? ${v}["@id"] : ${v}["@value"]
317
+ )`;
318
+ },
319
+ skipUnparsable: true
317
320
  },
318
321
  "fedify:publicKey": {
319
322
  name: "CryptoKey",
@@ -495,6 +498,9 @@ function getDecoder(typeUri, types, variable, optionsVariable, baseUrlVariable)
495
498
  )`;
496
499
  throw new Error(`Unknown type: ${typeUri}`);
497
500
  }
501
+ function skipsUnparsable(typeUri) {
502
+ return scalarTypes[typeUri]?.skipUnparsable ?? false;
503
+ }
498
504
  function getDataCheck(typeUri, types, variable) {
499
505
  if (typeUri in scalarTypes) return scalarTypes[typeUri].dataCheck(variable);
500
506
  if (typeUri in types) {
@@ -1000,15 +1006,22 @@ async function* generateDecoder(typeUri, types) {
1000
1006
  yield `
1001
1007
  const decoded =
1002
1008
  `;
1003
- if (property.range.length == 1) yield getDecoder(property.range[0], types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1004
- else {
1009
+ const lenient = property.range.length == 1 && skipsUnparsable(property.range[0]);
1010
+ if (property.range.length == 1) {
1011
+ if (lenient) {
1012
+ yield getDataCheck(property.range[0], types, "v");
1013
+ yield " ? ";
1014
+ }
1015
+ yield getDecoder(property.range[0], types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1016
+ if (lenient) yield " : undefined";
1017
+ } else {
1005
1018
  const decoders = getDecoders(property.range, types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1006
1019
  for (const code of decoders) yield code;
1007
1020
  }
1008
1021
  yield `
1009
1022
  ;
1010
1023
  `;
1011
- if (property.range.length > 1) yield `
1024
+ if (property.range.length > 1 || lenient) yield `
1012
1025
  if (typeof decoded === "undefined") {
1013
1026
  shouldCacheJsonLd = false;
1014
1027
  continue;
@@ -1888,6 +1901,17 @@ async function* generateClasses(types) {
1888
1901
  isTemporalInstant,
1889
1902
  } from "@fedify/vocab-runtime/temporal";\n`;
1890
1903
  yield `
1904
+ function canDecodeIri(iri: string): boolean {
1905
+ return URL.canParse(iri) || iri.startsWith("at://");
1906
+ }
1907
+
1908
+ function decodeIri(iri: string): URL {
1909
+ return !URL.canParse(iri) && iri.startsWith("at://")
1910
+ ? new URL("at://" + encodeURIComponent(iri.substring(5)))
1911
+ : new URL(iri);
1912
+ }
1913
+ `;
1914
+ yield `
1891
1915
  function isValidLanguageTag(language: string): boolean {
1892
1916
  try {
1893
1917
  new Intl.Locale(language);
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.0.29-dev.2055+5e21857f";
10
+ var version = "2.0.29-dev.2068+bb645217";
11
11
  //#endregion
12
12
  //#region src/type.ts
13
13
  const HEURISTICS_CONTEXTS = [
@@ -306,13 +306,16 @@ const scalarTypes = {
306
306
  return `${v}.href`;
307
307
  },
308
308
  dataCheck(v) {
309
- return `typeof ${v} === "object" && "@value" in ${v}
310
- && typeof ${v}["@value"] === "string"
311
- && ${v}["@value"] !== "" && ${v}["@value"] !== "/"`;
309
+ return `typeof ${v} === "object" &&
310
+ ((typeof ${v}["@id"] === "string" && canDecodeIri(${v}["@id"])) ||
311
+ (typeof ${v}["@value"] === "string" && canDecodeIri(${v}["@value"])))`;
312
312
  },
313
313
  decoder(v) {
314
- return `new URL(${v}["@value"])`;
315
- }
314
+ return `decodeIri(
315
+ typeof ${v}["@id"] === "string" ? ${v}["@id"] : ${v}["@value"]
316
+ )`;
317
+ },
318
+ skipUnparsable: true
316
319
  },
317
320
  "fedify:publicKey": {
318
321
  name: "CryptoKey",
@@ -494,6 +497,9 @@ function getDecoder(typeUri, types, variable, optionsVariable, baseUrlVariable)
494
497
  )`;
495
498
  throw new Error(`Unknown type: ${typeUri}`);
496
499
  }
500
+ function skipsUnparsable(typeUri) {
501
+ return scalarTypes[typeUri]?.skipUnparsable ?? false;
502
+ }
497
503
  function getDataCheck(typeUri, types, variable) {
498
504
  if (typeUri in scalarTypes) return scalarTypes[typeUri].dataCheck(variable);
499
505
  if (typeUri in types) {
@@ -999,15 +1005,22 @@ async function* generateDecoder(typeUri, types) {
999
1005
  yield `
1000
1006
  const decoded =
1001
1007
  `;
1002
- if (property.range.length == 1) yield getDecoder(property.range[0], types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1003
- else {
1008
+ const lenient = property.range.length == 1 && skipsUnparsable(property.range[0]);
1009
+ if (property.range.length == 1) {
1010
+ if (lenient) {
1011
+ yield getDataCheck(property.range[0], types, "v");
1012
+ yield " ? ";
1013
+ }
1014
+ yield getDecoder(property.range[0], types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1015
+ if (lenient) yield " : undefined";
1016
+ } else {
1004
1017
  const decoders = getDecoders(property.range, types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1005
1018
  for (const code of decoders) yield code;
1006
1019
  }
1007
1020
  yield `
1008
1021
  ;
1009
1022
  `;
1010
- if (property.range.length > 1) yield `
1023
+ if (property.range.length > 1 || lenient) yield `
1011
1024
  if (typeof decoded === "undefined") {
1012
1025
  shouldCacheJsonLd = false;
1013
1026
  continue;
@@ -1887,6 +1900,17 @@ async function* generateClasses(types) {
1887
1900
  isTemporalInstant,
1888
1901
  } from "@fedify/vocab-runtime/temporal";\n`;
1889
1902
  yield `
1903
+ function canDecodeIri(iri: string): boolean {
1904
+ return URL.canParse(iri) || iri.startsWith("at://");
1905
+ }
1906
+
1907
+ function decodeIri(iri: string): URL {
1908
+ return !URL.canParse(iri) && iri.startsWith("at://")
1909
+ ? new URL("at://" + encodeURIComponent(iri.substring(5)))
1910
+ : new URL(iri);
1911
+ }
1912
+ `;
1913
+ yield `
1890
1914
  function isValidLanguageTag(language: string): boolean {
1891
1915
  try {
1892
1916
  new Intl.Locale(language);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-tools",
3
- "version": "2.0.29-dev.2055+5e21857f",
3
+ "version": "2.0.29-dev.2068+bb645217",
4
4
  "description": "Code generator for Activity Vocabulary APIs",
5
5
  "homepage": "https://fedify.dev/",
6
6
  "repository": {
@@ -23,6 +23,16 @@ import {
23
23
  isTemporalInstant,
24
24
  } from \\"@fedify/vocab-runtime/temporal\\";
25
25
 
26
+ function canDecodeIri(iri: string): boolean {
27
+ return URL.canParse(iri) || iri.startsWith(\\"at://\\");
28
+ }
29
+
30
+ function decodeIri(iri: string): URL {
31
+ return !URL.canParse(iri) && iri.startsWith(\\"at://\\")
32
+ ? new URL(\\"at://\\" + encodeURIComponent(iri.substring(5)))
33
+ : new URL(iri);
34
+ }
35
+
26
36
  function isValidLanguageTag(language: string): boolean {
27
37
  try {
28
38
  new Intl.Locale(language);
@@ -12236,9 +12246,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
12236
12246
  if (v == null) continue;
12237
12247
 
12238
12248
  const decoded =
12239
- new URL(v[\\"@value\\"])
12249
+ typeof v === \\"object\\" &&
12250
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
12251
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
12252
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
12253
+ ) : undefined
12240
12254
  ;
12241
12255
 
12256
+ if (typeof decoded === \\"undefined\\") {
12257
+ shouldCacheJsonLd = false;
12258
+ continue;
12259
+ }
12260
+
12242
12261
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
12243
12262
  shouldCacheJsonLd = false;
12244
12263
  }
@@ -29346,9 +29365,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
29346
29365
  if (v == null) continue;
29347
29366
 
29348
29367
  const decoded =
29349
- new URL(v[\\"@value\\"])
29368
+ typeof v === \\"object\\" &&
29369
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
29370
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
29371
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
29372
+ ) : undefined
29350
29373
  ;
29351
29374
 
29375
+ if (typeof decoded === \\"undefined\\") {
29376
+ shouldCacheJsonLd = false;
29377
+ continue;
29378
+ }
29379
+
29352
29380
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
29353
29381
  shouldCacheJsonLd = false;
29354
29382
  }
@@ -52519,9 +52547,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
52519
52547
  if (v == null) continue;
52520
52548
 
52521
52549
  const decoded =
52522
- new URL(v[\\"@value\\"])
52550
+ typeof v === \\"object\\" &&
52551
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
52552
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
52553
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
52554
+ ) : undefined
52523
52555
  ;
52524
52556
 
52557
+ if (typeof decoded === \\"undefined\\") {
52558
+ shouldCacheJsonLd = false;
52559
+ continue;
52560
+ }
52561
+
52525
52562
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
52526
52563
  shouldCacheJsonLd = false;
52527
52564
  }
@@ -71062,9 +71099,18 @@ instruments?: (Object | URL)[];exclusiveOptions?: (Object | URL)[];inclusiveOpti
71062
71099
  if (v == null) continue;
71063
71100
 
71064
71101
  const decoded =
71065
- new URL(v[\\"@value\\"])
71102
+ typeof v === \\"object\\" &&
71103
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
71104
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
71105
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
71106
+ ) : undefined
71066
71107
  ;
71067
71108
 
71109
+ if (typeof decoded === \\"undefined\\") {
71110
+ shouldCacheJsonLd = false;
71111
+ continue;
71112
+ }
71113
+
71068
71114
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
71069
71115
  shouldCacheJsonLd = false;
71070
71116
  }
@@ -21,6 +21,16 @@ import {
21
21
  isTemporalInstant,
22
22
  } from \\"@fedify/vocab-runtime/temporal\\";
23
23
 
24
+ function canDecodeIri(iri: string): boolean {
25
+ return URL.canParse(iri) || iri.startsWith(\\"at://\\");
26
+ }
27
+
28
+ function decodeIri(iri: string): URL {
29
+ return !URL.canParse(iri) && iri.startsWith(\\"at://\\")
30
+ ? new URL(\\"at://\\" + encodeURIComponent(iri.substring(5)))
31
+ : new URL(iri);
32
+ }
33
+
24
34
  function isValidLanguageTag(language: string): boolean {
25
35
  try {
26
36
  new Intl.Locale(language);
@@ -12234,9 +12244,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
12234
12244
  if (v == null) continue;
12235
12245
 
12236
12246
  const decoded =
12237
- new URL(v[\\"@value\\"])
12247
+ typeof v === \\"object\\" &&
12248
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
12249
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
12250
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
12251
+ ) : undefined
12238
12252
  ;
12239
12253
 
12254
+ if (typeof decoded === \\"undefined\\") {
12255
+ shouldCacheJsonLd = false;
12256
+ continue;
12257
+ }
12258
+
12240
12259
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
12241
12260
  shouldCacheJsonLd = false;
12242
12261
  }
@@ -29344,9 +29363,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
29344
29363
  if (v == null) continue;
29345
29364
 
29346
29365
  const decoded =
29347
- new URL(v[\\"@value\\"])
29366
+ typeof v === \\"object\\" &&
29367
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
29368
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
29369
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
29370
+ ) : undefined
29348
29371
  ;
29349
29372
 
29373
+ if (typeof decoded === \\"undefined\\") {
29374
+ shouldCacheJsonLd = false;
29375
+ continue;
29376
+ }
29377
+
29350
29378
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
29351
29379
  shouldCacheJsonLd = false;
29352
29380
  }
@@ -52517,9 +52545,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
52517
52545
  if (v == null) continue;
52518
52546
 
52519
52547
  const decoded =
52520
- new URL(v[\\"@value\\"])
52548
+ typeof v === \\"object\\" &&
52549
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
52550
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
52551
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
52552
+ ) : undefined
52521
52553
  ;
52522
52554
 
52555
+ if (typeof decoded === \\"undefined\\") {
52556
+ shouldCacheJsonLd = false;
52557
+ continue;
52558
+ }
52559
+
52523
52560
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
52524
52561
  shouldCacheJsonLd = false;
52525
52562
  }
@@ -71060,9 +71097,18 @@ instruments?: (Object | URL)[];exclusiveOptions?: (Object | URL)[];inclusiveOpti
71060
71097
  if (v == null) continue;
71061
71098
 
71062
71099
  const decoded =
71063
- new URL(v[\\"@value\\"])
71100
+ typeof v === \\"object\\" &&
71101
+ ((typeof v[\\"@id\\"] === \\"string\\" && canDecodeIri(v[\\"@id\\"])) ||
71102
+ (typeof v[\\"@value\\"] === \\"string\\" && canDecodeIri(v[\\"@value\\"]))) ? decodeIri(
71103
+ typeof v[\\"@id\\"] === \\"string\\" ? v[\\"@id\\"] : v[\\"@value\\"]
71104
+ ) : undefined
71064
71105
  ;
71065
71106
 
71107
+ if (typeof decoded === \\"undefined\\") {
71108
+ shouldCacheJsonLd = false;
71109
+ continue;
71110
+ }
71111
+
71066
71112
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
71067
71113
  shouldCacheJsonLd = false;
71068
71114
  }
@@ -23,6 +23,16 @@ import {
23
23
  isTemporalInstant,
24
24
  } from "@fedify/vocab-runtime/temporal";
25
25
 
26
+ function canDecodeIri(iri: string): boolean {
27
+ return URL.canParse(iri) || iri.startsWith("at://");
28
+ }
29
+
30
+ function decodeIri(iri: string): URL {
31
+ return !URL.canParse(iri) && iri.startsWith("at://")
32
+ ? new URL("at://" + encodeURIComponent(iri.substring(5)))
33
+ : new URL(iri);
34
+ }
35
+
26
36
  function isValidLanguageTag(language: string): boolean {
27
37
  try {
28
38
  new Intl.Locale(language);
@@ -12236,9 +12246,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
12236
12246
  if (v == null) continue;
12237
12247
 
12238
12248
  const decoded =
12239
- new URL(v["@value"])
12249
+ typeof v === "object" &&
12250
+ ((typeof v["@id"] === "string" && canDecodeIri(v["@id"])) ||
12251
+ (typeof v["@value"] === "string" && canDecodeIri(v["@value"]))) ? decodeIri(
12252
+ typeof v["@id"] === "string" ? v["@id"] : v["@value"]
12253
+ ) : undefined
12240
12254
  ;
12241
12255
 
12256
+ if (typeof decoded === "undefined") {
12257
+ shouldCacheJsonLd = false;
12258
+ continue;
12259
+ }
12260
+
12242
12261
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
12243
12262
  shouldCacheJsonLd = false;
12244
12263
  }
@@ -29346,9 +29365,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
29346
29365
  if (v == null) continue;
29347
29366
 
29348
29367
  const decoded =
29349
- new URL(v["@value"])
29368
+ typeof v === "object" &&
29369
+ ((typeof v["@id"] === "string" && canDecodeIri(v["@id"])) ||
29370
+ (typeof v["@value"] === "string" && canDecodeIri(v["@value"]))) ? decodeIri(
29371
+ typeof v["@id"] === "string" ? v["@id"] : v["@value"]
29372
+ ) : undefined
29350
29373
  ;
29351
29374
 
29375
+ if (typeof decoded === "undefined") {
29376
+ shouldCacheJsonLd = false;
29377
+ continue;
29378
+ }
29379
+
29352
29380
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
29353
29381
  shouldCacheJsonLd = false;
29354
29382
  }
@@ -52519,9 +52547,18 @@ proofs?: (DataIntegrityProof | URL)[];quoteUrl?: URL | null;}
52519
52547
  if (v == null) continue;
52520
52548
 
52521
52549
  const decoded =
52522
- new URL(v["@value"])
52550
+ typeof v === "object" &&
52551
+ ((typeof v["@id"] === "string" && canDecodeIri(v["@id"])) ||
52552
+ (typeof v["@value"] === "string" && canDecodeIri(v["@value"]))) ? decodeIri(
52553
+ typeof v["@id"] === "string" ? v["@id"] : v["@value"]
52554
+ ) : undefined
52523
52555
  ;
52524
52556
 
52557
+ if (typeof decoded === "undefined") {
52558
+ shouldCacheJsonLd = false;
52559
+ continue;
52560
+ }
52561
+
52525
52562
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
52526
52563
  shouldCacheJsonLd = false;
52527
52564
  }
@@ -71062,9 +71099,18 @@ instruments?: (Object | URL)[];exclusiveOptions?: (Object | URL)[];inclusiveOpti
71062
71099
  if (v == null) continue;
71063
71100
 
71064
71101
  const decoded =
71065
- new URL(v["@value"])
71102
+ typeof v === "object" &&
71103
+ ((typeof v["@id"] === "string" && canDecodeIri(v["@id"])) ||
71104
+ (typeof v["@value"] === "string" && canDecodeIri(v["@value"]))) ? decodeIri(
71105
+ typeof v["@id"] === "string" ? v["@id"] : v["@value"]
71106
+ ) : undefined
71066
71107
  ;
71067
71108
 
71109
+ if (typeof decoded === "undefined") {
71110
+ shouldCacheJsonLd = false;
71111
+ continue;
71112
+ }
71113
+
71068
71114
  if (!this._shouldCacheDecodedJsonLd(decoded)) {
71069
71115
  shouldCacheJsonLd = false;
71070
71116
  }
package/src/class.ts CHANGED
@@ -154,6 +154,17 @@ export async function* generateClasses(
154
154
  isTemporalInstant,
155
155
  } from "@fedify/vocab-runtime/temporal";\n`;
156
156
  yield `
157
+ function canDecodeIri(iri: string): boolean {
158
+ return URL.canParse(iri) || iri.startsWith("at://");
159
+ }
160
+
161
+ function decodeIri(iri: string): URL {
162
+ return !URL.canParse(iri) && iri.startsWith("at://")
163
+ ? new URL("at://" + encodeURIComponent(iri.substring(5)))
164
+ : new URL(iri);
165
+ }
166
+ `;
167
+ yield `
157
168
  function isValidLanguageTag(language: string): boolean {
158
169
  try {
159
170
  new Intl.Locale(language);
package/src/codec.ts CHANGED
@@ -6,11 +6,13 @@ 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
  isCompactableType,
15
+ skipsUnparsable,
14
16
  } from "./type.ts";
15
17
 
16
18
  export async function* generateEncoder(
@@ -441,7 +443,13 @@ export async function* generateDecoder(
441
443
  yield `
442
444
  const decoded =
443
445
  `;
446
+ const lenient = property.range.length == 1 &&
447
+ skipsUnparsable(property.range[0]);
444
448
  if (property.range.length == 1) {
449
+ if (lenient) {
450
+ yield getDataCheck(property.range[0], types, "v");
451
+ yield " ? ";
452
+ }
445
453
  yield getDecoder(
446
454
  property.range[0],
447
455
  types,
@@ -449,6 +457,7 @@ export async function* generateDecoder(
449
457
  "options",
450
458
  `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`,
451
459
  );
460
+ if (lenient) yield " : undefined";
452
461
  } else {
453
462
  const decoders = getDecoders(
454
463
  property.range,
@@ -462,7 +471,7 @@ export async function* generateDecoder(
462
471
  yield `
463
472
  ;
464
473
  `;
465
- if (property.range.length > 1) {
474
+ if (property.range.length > 1 || lenient) {
466
475
  yield `
467
476
  if (typeof decoded === "undefined") {
468
477
  shouldCacheJsonLd = false;
package/src/type.ts CHANGED
@@ -17,6 +17,12 @@ interface ScalarType {
17
17
  compactEncoder?: (variable: string) => string;
18
18
  dataCheck(variable: string): string;
19
19
  decoder(variable: string, baseUrlVar: string): string;
20
+ /**
21
+ * Whether a value that fails `dataCheck()` should be skipped instead of
22
+ * being handed to `decoder()`. Set this for types decoded from untrusted
23
+ * remote input, where one malformed value must not fail the whole object.
24
+ */
25
+ skipUnparsable?: boolean;
20
26
  }
21
27
 
22
28
  const scalarTypes: Record<string, ScalarType> = {
@@ -308,13 +314,16 @@ const scalarTypes: Record<string, ScalarType> = {
308
314
  return `${v}.href`;
309
315
  },
310
316
  dataCheck(v) {
311
- return `typeof ${v} === "object" && "@value" in ${v}
312
- && typeof ${v}["@value"] === "string"
313
- && ${v}["@value"] !== "" && ${v}["@value"] !== "/"`;
317
+ return `typeof ${v} === "object" &&
318
+ ((typeof ${v}["@id"] === "string" && canDecodeIri(${v}["@id"])) ||
319
+ (typeof ${v}["@value"] === "string" && canDecodeIri(${v}["@value"])))`;
314
320
  },
315
321
  decoder(v) {
316
- return `new URL(${v}["@value"])`;
322
+ return `decodeIri(
323
+ typeof ${v}["@id"] === "string" ? ${v}["@id"] : ${v}["@value"]
324
+ )`;
317
325
  },
326
+ skipUnparsable: true,
318
327
  },
319
328
  "fedify:publicKey": {
320
329
  name: "CryptoKey",
@@ -595,6 +604,10 @@ export function getDecoder(
595
604
  throw new Error(`Unknown type: ${typeUri}`);
596
605
  }
597
606
 
607
+ export function skipsUnparsable(typeUri: string): boolean {
608
+ return scalarTypes[typeUri]?.skipUnparsable ?? false;
609
+ }
610
+
598
611
  export function getDataCheck(
599
612
  typeUri: string,
600
613
  types: Record<string, TypeSchema>,