@fedify/vocab-tools 2.0.0-pr.458.1785

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/dist/mod.cjs ADDED
@@ -0,0 +1,1941 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ const node_fs_promises = __toESM(require("node:fs/promises"));
25
+ const byte_encodings_base58 = __toESM(require("byte-encodings/base58"));
26
+ const __cfworker_json_schema = __toESM(require("@cfworker/json-schema"));
27
+ const node_path = __toESM(require("node:path"));
28
+ const node_url = __toESM(require("node:url"));
29
+ const yaml = __toESM(require("yaml"));
30
+ const es_toolkit = __toESM(require("es-toolkit"));
31
+
32
+ //#region deno.json
33
+ var name = "@fedify/vocab-tools";
34
+ var version = "2.0.0-pr.458.1785+f5e97597";
35
+ var license = "MIT";
36
+ var exports$1 = { ".": "./src/mod.ts" };
37
+ var author = {
38
+ "name": "Hong Minhee",
39
+ "email": "hong@minhee.org",
40
+ "url": "https://hongminhee.org/"
41
+ };
42
+ var imports = {
43
+ "@cfworker/json-schema": "npm:@cfworker/json-schema@^4.1.1",
44
+ "byte-encodings": "npm:byte-encodings@^1.0.11",
45
+ "es-toolkit": "npm:es-toolkit@^1.39.10",
46
+ "yaml": "npm:yaml@^2.8.1"
47
+ };
48
+ var exclude = [
49
+ "dist",
50
+ "node_modules",
51
+ "src/schema.yaml"
52
+ ];
53
+ var tasks = {
54
+ "check": "deno fmt --check && deno lint && deno check src/*.ts",
55
+ "test": "deno test -A"
56
+ };
57
+ var deno_default = {
58
+ name,
59
+ version,
60
+ license,
61
+ exports: exports$1,
62
+ author,
63
+ imports,
64
+ exclude,
65
+ tasks
66
+ };
67
+
68
+ //#endregion
69
+ //#region src/type.ts
70
+ const HEURISTICS_CONTEXTS = [
71
+ "https://www.w3.org/ns/activitystreams",
72
+ "https://w3id.org/security/v1",
73
+ "https://w3id.org/security/data-integrity/v1",
74
+ "https://www.w3.org/ns/did/v1",
75
+ "https://w3id.org/security/multikey/v1"
76
+ ];
77
+ const scalarTypes = {
78
+ "http://www.w3.org/2001/XMLSchema#boolean": {
79
+ name: "boolean",
80
+ typeGuard(v) {
81
+ return `typeof ${v} === "boolean"`;
82
+ },
83
+ encoder(v) {
84
+ return `{ "@value": ${v} }`;
85
+ },
86
+ compactEncoder(v) {
87
+ return v;
88
+ },
89
+ dataCheck(v) {
90
+ return `typeof ${v} === "object" && "@value" in ${v}
91
+ && typeof ${v}["@value"] === "boolean"`;
92
+ },
93
+ decoder(v) {
94
+ return `${v}["@value"]`;
95
+ }
96
+ },
97
+ "http://www.w3.org/2001/XMLSchema#integer": {
98
+ name: "number",
99
+ typeGuard(v) {
100
+ return `typeof ${v} === "number" && Number.isInteger(${v})`;
101
+ },
102
+ encoder(v) {
103
+ return `{
104
+ "@type": "http://www.w3.org/2001/XMLSchema#integer",
105
+ "@value": ${v},
106
+ }`;
107
+ },
108
+ compactEncoder(v) {
109
+ return v;
110
+ },
111
+ dataCheck(v) {
112
+ return `typeof ${v} === "object" && "@type" in ${v}
113
+ && ${v}["@type"] === "http://www.w3.org/2001/XMLSchema#integer"
114
+ && "@value" in ${v} && typeof ${v}["@value"] === "number"`;
115
+ },
116
+ decoder(v) {
117
+ return `${v}["@value"] as number`;
118
+ }
119
+ },
120
+ "http://www.w3.org/2001/XMLSchema#nonNegativeInteger": {
121
+ name: "number",
122
+ typeGuard(v) {
123
+ return `typeof ${v} === "number" && Number.isInteger(${v}) && ${v} >= 0`;
124
+ },
125
+ encoder(v) {
126
+ return `{
127
+ "@type": "http://www.w3.org/2001/XMLSchema#nonNegativeInteger",
128
+ "@value": ${v},
129
+ }`;
130
+ },
131
+ compactEncoder(v) {
132
+ return v;
133
+ },
134
+ dataCheck(v) {
135
+ return `typeof ${v} === "object" && "@type" in ${v}
136
+ && ${v}["@type"] === "http://www.w3.org/2001/XMLSchema#nonNegativeInteger"
137
+ && "@value" in ${v} && typeof ${v}["@value"] === "number"`;
138
+ },
139
+ decoder(v) {
140
+ return `${v}["@value"]`;
141
+ }
142
+ },
143
+ "http://www.w3.org/2001/XMLSchema#float": {
144
+ name: "number",
145
+ typeGuard(v) {
146
+ return `typeof ${v} === "number" && !Number.isNaN(${v})`;
147
+ },
148
+ encoder(v) {
149
+ return `{
150
+ "@type": "http://www.w3.org/2001/XMLSchema#float",
151
+ "@value": ${v},
152
+ }`;
153
+ },
154
+ compactEncoder(v) {
155
+ return v;
156
+ },
157
+ dataCheck(v) {
158
+ return `typeof ${v} === "object" && "@type" in ${v}
159
+ && ${v}["@type"] === "http://www.w3.org/2001/XMLSchema#float"
160
+ && "@value" in ${v} && typeof ${v}["@value"] === "number"`;
161
+ },
162
+ decoder(v) {
163
+ return `${v}["@value"]`;
164
+ }
165
+ },
166
+ "http://www.w3.org/2001/XMLSchema#string": {
167
+ name: "string",
168
+ typeGuard(v) {
169
+ return `typeof ${v} === "string"`;
170
+ },
171
+ encoder(v) {
172
+ return `{ "@value": ${v} }`;
173
+ },
174
+ compactEncoder(v) {
175
+ return v;
176
+ },
177
+ dataCheck(v) {
178
+ return `typeof ${v} === "object" && "@value" in ${v}
179
+ && typeof ${v}["@value"] === "string" && !("@language" in ${v})`;
180
+ },
181
+ decoder(v) {
182
+ return `${v}["@value"]`;
183
+ }
184
+ },
185
+ "http://www.w3.org/2001/XMLSchema#anyURI": {
186
+ name: "URL",
187
+ typeGuard(v) {
188
+ return `${v} instanceof URL`;
189
+ },
190
+ encoder(v) {
191
+ return `{ "@id": ${v}.href }`;
192
+ },
193
+ compactEncoder(v) {
194
+ return `${v}.href`;
195
+ },
196
+ dataCheck(v) {
197
+ return `typeof ${v} === "object" && "@id" in ${v}
198
+ && typeof ${v}["@id"] === "string"
199
+ && ${v}["@id"] !== ""`;
200
+ },
201
+ decoder(v, baseUrlVar) {
202
+ return `${v}["@id"].startsWith("at://")
203
+ ? new URL("at://" +
204
+ encodeURIComponent(
205
+ ${v}["@id"].includes("/", 5)
206
+ ? ${v}["@id"].slice(5, ${v}["@id"].indexOf("/", 5))
207
+ : ${v}["@id"].slice(5)
208
+ ) +
209
+ (
210
+ ${v}["@id"].includes("/", 5)
211
+ ? ${v}["@id"].slice(${v}["@id"].indexOf("/", 5))
212
+ : ""
213
+ )
214
+ )
215
+ : URL.canParse(${v}["@id"]) && ${baseUrlVar}
216
+ ? new URL(${v}["@id"])
217
+ : new URL(${v}["@id"], ${baseUrlVar})`;
218
+ }
219
+ },
220
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString": {
221
+ name: "LanguageString",
222
+ typeGuard(v) {
223
+ return `${v} instanceof LanguageString`;
224
+ },
225
+ encoder(v) {
226
+ return `{
227
+ "@value": ${v}.toString(),
228
+ "@language": ${v}.locale.baseName,
229
+ }`;
230
+ },
231
+ dataCheck(v) {
232
+ return `typeof ${v} === "object" && "@language" in ${v} && "@value" in ${v}
233
+ && typeof ${v}["@language"] === "string"
234
+ && typeof ${v}["@value"] === "string"`;
235
+ },
236
+ decoder(v) {
237
+ return `new LanguageString(${v}["@value"], ${v}["@language"])`;
238
+ }
239
+ },
240
+ "http://www.w3.org/2001/XMLSchema#dateTime": {
241
+ name: "Temporal.Instant",
242
+ typeGuard(v) {
243
+ return `${v} instanceof Temporal.Instant`;
244
+ },
245
+ encoder(v) {
246
+ return `{
247
+ "@type": "http://www.w3.org/2001/XMLSchema#dateTime",
248
+ "@value": ${v}.toString(),
249
+ }`;
250
+ },
251
+ compactEncoder(v) {
252
+ return `${v}.toString()`;
253
+ },
254
+ dataCheck(v) {
255
+ return `typeof ${v} === "object" && "@type" in ${v}
256
+ && "@value" in ${v} && typeof ${v}["@value"] === "string"
257
+ && ${v}["@type"] === "http://www.w3.org/2001/XMLSchema#dateTime"
258
+ // Check if the value is a valid RFC 3339 date-time string
259
+ && new Date(${v}["@value"]).toString() !== "Invalid Date"
260
+ `;
261
+ },
262
+ decoder(v) {
263
+ return `Temporal.Instant.from(
264
+ ${v}["@value"].substring(19).match(/[Z+-]/)
265
+ ? ${v}["@value"]
266
+ : ${v}["@value"] + "Z"
267
+ )`;
268
+ }
269
+ },
270
+ "http://www.w3.org/2001/XMLSchema#duration": {
271
+ name: "Temporal.Duration",
272
+ typeGuard(v) {
273
+ return `${v} instanceof Temporal.Duration`;
274
+ },
275
+ encoder(v) {
276
+ return `{
277
+ "@type": "http://www.w3.org/2001/XMLSchema#duration",
278
+ "@value": ${v}.toString(),
279
+ }`;
280
+ },
281
+ compactEncoder(v) {
282
+ return `${v}.toString()`;
283
+ },
284
+ dataCheck(v) {
285
+ return `typeof ${v} === "object" && "@type" in ${v}
286
+ && "@value" in ${v} && typeof ${v}["@value"] === "string"
287
+ && ${v}["@type"] === "http://www.w3.org/2001/XMLSchema#duration"`;
288
+ },
289
+ decoder(v) {
290
+ return `Temporal.Duration.from(${v}["@value"])`;
291
+ }
292
+ },
293
+ "https://w3id.org/security#cryptosuiteString": {
294
+ name: "\"eddsa-jcs-2022\"",
295
+ typeGuard(v) {
296
+ return `${v} == "eddsa-jcs-2022"`;
297
+ },
298
+ encoder(v) {
299
+ return `{ "@value": ${v} }`;
300
+ },
301
+ compactEncoder(v) {
302
+ return v;
303
+ },
304
+ dataCheck(v) {
305
+ return `typeof ${v} === "object" && "@value" in ${v}
306
+ && !("@language" in ${v}) && ${v}["@value"] === "eddsa-jcs-2022"`;
307
+ },
308
+ decoder(v) {
309
+ return `${v}["@value"]`;
310
+ }
311
+ },
312
+ "https://w3id.org/security#multibase": {
313
+ name: "Uint8Array",
314
+ typeGuard(v) {
315
+ return `${v} instanceof Uint8Array`;
316
+ },
317
+ encoder(v) {
318
+ return `{
319
+ "@type": "https://w3id.org/security#multibase",
320
+ "@value": new TextDecoder().decode(encodeMultibase("base58btc", ${v})),
321
+ }`;
322
+ },
323
+ compactEncoder(v) {
324
+ return `new TextDecoder().decode(encodeMultibase("base58btc", ${v}))`;
325
+ },
326
+ dataCheck(v) {
327
+ return `typeof ${v} === "object" && "@value" in ${v}
328
+ && typeof ${v}["@value"] === "string"`;
329
+ },
330
+ decoder(v) {
331
+ return `decodeMultibase(${v}["@value"])`;
332
+ }
333
+ },
334
+ "fedify:langTag": {
335
+ name: "Intl.Locale",
336
+ typeGuard(v) {
337
+ return `${v} instanceof Intl.Locale`;
338
+ },
339
+ encoder(v) {
340
+ return `{ "@value": ${v}.baseName }`;
341
+ },
342
+ compactEncoder(v) {
343
+ return `${v}.baseName`;
344
+ },
345
+ dataCheck(v) {
346
+ return `typeof ${v} === "object" && "@value" in ${v}
347
+ && typeof ${v}["@value"] === "string" && !("@language" in ${v})`;
348
+ },
349
+ decoder(v) {
350
+ return `new Intl.Locale(${v}["@value"])`;
351
+ }
352
+ },
353
+ "fedify:url": {
354
+ name: "URL",
355
+ typeGuard(v) {
356
+ return `${v} instanceof URL`;
357
+ },
358
+ encoder(v) {
359
+ return `{ "@value": ${v}.href }`;
360
+ },
361
+ compactEncoder(v) {
362
+ return `${v}.href`;
363
+ },
364
+ dataCheck(v) {
365
+ return `typeof ${v} === "object" && "@value" in ${v}
366
+ && typeof ${v}["@value"] === "string"
367
+ && ${v}["@value"] !== "" && ${v}["@value"] !== "/"`;
368
+ },
369
+ decoder(v) {
370
+ return `new URL(${v}["@value"])`;
371
+ }
372
+ },
373
+ "fedify:publicKey": {
374
+ name: "CryptoKey",
375
+ typeGuard(v) {
376
+ return `
377
+ // @ts-ignore: CryptoKey exists in the global scope.
378
+ ${v} instanceof CryptoKey
379
+ `;
380
+ },
381
+ encoder(v) {
382
+ return `{ "@value": await exportSpki(${v}) }`;
383
+ },
384
+ compactEncoder(v) {
385
+ return `await exportSpki(${v})`;
386
+ },
387
+ dataCheck(v) {
388
+ return `typeof ${v} === "object" && "@value" in ${v}
389
+ && typeof ${v}["@value"] === "string"`;
390
+ },
391
+ decoder(v) {
392
+ return `await importPem(${v}["@value"])`;
393
+ }
394
+ },
395
+ "fedify:multibaseKey": {
396
+ name: "CryptoKey",
397
+ typeGuard(v) {
398
+ return `
399
+ // @ts-ignore: CryptoKey exists in the global scope.
400
+ ${v} instanceof CryptoKey
401
+ `;
402
+ },
403
+ encoder(v) {
404
+ return `{
405
+ "@type": "https://w3id.org/security#multibase",
406
+ "@value": await exportMultibaseKey(${v}),
407
+ }`;
408
+ },
409
+ compactEncoder(v) {
410
+ return `await exportMultibaseKey(${v})`;
411
+ },
412
+ dataCheck(v) {
413
+ return `typeof ${v} === "object" && "@value" in ${v}
414
+ && typeof ${v}["@value"] === "string"`;
415
+ },
416
+ decoder(v) {
417
+ return `await importMultibaseKey(${v}["@value"])`;
418
+ }
419
+ },
420
+ "fedify:proofPurpose": {
421
+ name: "\"assertionMethod\" | \"authentication\" | \"capabilityInvocation\" | \"capabilityDelegation\" | \"keyAgreement\"",
422
+ typeGuard(v) {
423
+ return `${v} === "assertionMethod" || ${v} === "authentication" ||
424
+ ${v} === "capabilityInvocation" || ${v} === "capabilityDelegation" ||
425
+ ${v} === "keyAgreement"`;
426
+ },
427
+ encoder(v) {
428
+ return `{
429
+ "@id": "https://w3id.org/security#" + ${v},
430
+ }`;
431
+ },
432
+ compactEncoder(v) {
433
+ return v;
434
+ },
435
+ dataCheck(v) {
436
+ return `typeof ${v} === "object" && "@id" in ${v}
437
+ && typeof ${v}["@id"] === "string"
438
+ && ${v}["@id"].startsWith("https://w3id.org/security#")
439
+ && [
440
+ "assertionMethod", "authentication", "capabilityInvocation",
441
+ "capabilityDelegation", "keyAgreement",
442
+ ].includes(${v}["@id"].substring(26))`;
443
+ },
444
+ decoder(v) {
445
+ return `${v}["@id"].substring(26)`;
446
+ }
447
+ },
448
+ "fedify:units": {
449
+ name: "\"cm\" | \"feet\" | \"inches\" | \"km\" | \"m\" | \"miles\"",
450
+ typeGuard(v) {
451
+ return `${v} == "cm" || ${v} == "feet" || ${v} == "inches" || ${v} == "km" || ${v} == "m" || ${v} == "miles"`;
452
+ },
453
+ encoder(v) {
454
+ return `{ "@value": ${v} }`;
455
+ },
456
+ compactEncoder(v) {
457
+ return v;
458
+ },
459
+ dataCheck(v) {
460
+ return `typeof ${v} === "object" && "@value" in ${v}
461
+ && (${v}["@value"] == "cm" || ${v}["@value"] == "feet" || ${v}["@value"] == "inches" || ${v}["@value"] == "km" || ${v}["@value"] == "m" || ${v}["@value"] == "miles")`;
462
+ },
463
+ decoder(v) {
464
+ return `${v}["@value"]`;
465
+ }
466
+ }
467
+ };
468
+ function getTypeName(typeUri, types) {
469
+ if (typeUri in types) return types[typeUri].name;
470
+ if (typeUri in scalarTypes) return scalarTypes[typeUri].name;
471
+ throw new Error(`Unknown type: ${typeUri}`);
472
+ }
473
+ function getTypeNames(typeUris, types, parentheses = false) {
474
+ if (typeUris.length < 1) return "never";
475
+ else if (typeUris.length === 1) return getTypeName(typeUris[0], types);
476
+ let typeNames = typeUris.map((typeUri) => getTypeName(typeUri, types));
477
+ typeNames = typeNames.filter((t$1, i) => typeNames.indexOf(t$1) === i);
478
+ const t = typeNames.join(" | ");
479
+ return parentheses && typeNames.length > 1 ? `(${t})` : t;
480
+ }
481
+ function isScalarType(typeUri, types) {
482
+ if (typeUri in scalarTypes) return true;
483
+ else if (typeUri in types) return !types[typeUri].entity;
484
+ throw new Error(`Unknown type: ${typeUri}`);
485
+ }
486
+ function areAllScalarTypes(typeUris, types) {
487
+ return typeUris.every((typeUri) => isScalarType(typeUri, types));
488
+ }
489
+ function isCompactableType(typeUri, types) {
490
+ if (typeUri in scalarTypes) return scalarTypes[typeUri].compactEncoder != null;
491
+ else if (typeUri in types) {
492
+ const type = types[typeUri];
493
+ if (type.compactName == null) return false;
494
+ else if (type.extends != null && !isCompactableType(type.extends, types)) return false;
495
+ const defaultContext = type.defaultContext;
496
+ return defaultContext != null && HEURISTICS_CONTEXTS.includes(defaultContext) || Array.isArray(defaultContext) && defaultContext.some(HEURISTICS_CONTEXTS.includes.bind(HEURISTICS_CONTEXTS));
497
+ }
498
+ throw new Error(`Unknown type: ${typeUri}`);
499
+ }
500
+ function getSubtypes(typeUri, types, excludeSelf = false) {
501
+ const subtypes = excludeSelf ? [] : [typeUri];
502
+ for (const uri in types) {
503
+ const type = types[uri];
504
+ if (type.extends === typeUri) subtypes.push(...getSubtypes(uri, types));
505
+ }
506
+ return subtypes.filter((t, i) => subtypes.indexOf(t) === i);
507
+ }
508
+ function getSupertypes(typeUri, types, excludeSelf = false) {
509
+ const supertypes = excludeSelf ? [] : [typeUri];
510
+ const type = types[typeUri];
511
+ if (type.extends) supertypes.push(...getSupertypes(type.extends, types));
512
+ return supertypes;
513
+ }
514
+ function* getAllProperties(typeUri, types, excludeSelf = false) {
515
+ for (const t of getSupertypes(typeUri, types, excludeSelf)) {
516
+ if (!(t in types)) continue;
517
+ for (const prop of types[t].properties) yield prop;
518
+ }
519
+ }
520
+ function getEncoder(typeUri, types, variable, optionsVariable, compact = false) {
521
+ if (typeUri in scalarTypes) return compact ? scalarTypes[typeUri].compactEncoder?.(variable) ?? scalarTypes[typeUri].encoder(variable) : scalarTypes[typeUri].encoder(variable);
522
+ if (typeUri in types) return compact ? `await ${variable}.toJsonLd({
523
+ ...(${optionsVariable}),
524
+ format: undefined,
525
+ context: undefined,
526
+ })` : `await ${variable}.toJsonLd(${optionsVariable})`;
527
+ throw new Error(`Unknown type: ${typeUri}`);
528
+ }
529
+ function getTypeGuard(typeUri, types, variable) {
530
+ if (typeUri in scalarTypes) return scalarTypes[typeUri].typeGuard(variable);
531
+ if (typeUri in types) return `${variable} instanceof ${types[typeUri].name}`;
532
+ throw new Error(`Unknown type: ${typeUri}`);
533
+ }
534
+ function getTypeGuards(typeUris, types, variable) {
535
+ return typeUris.map((t) => getTypeGuard(t, types, variable)).join(" || ");
536
+ }
537
+ function* getEncoders(typeUris, types, variable, optionsVariable, compact = false) {
538
+ let i = typeUris.length;
539
+ for (const typeUri of typeUris) {
540
+ if (--i > 0) {
541
+ yield getTypeGuard(typeUri, types, variable);
542
+ yield " ? ";
543
+ }
544
+ yield getEncoder(typeUri, types, variable, optionsVariable, compact);
545
+ if (i > 0) yield " : ";
546
+ }
547
+ }
548
+ function getDecoder(typeUri, types, variable, optionsVariable, baseUrlVariable) {
549
+ if (typeUri in scalarTypes) return scalarTypes[typeUri].decoder(variable, baseUrlVariable);
550
+ if (typeUri in types) return `await ${types[typeUri].name}.fromJsonLd(
551
+ ${variable},
552
+ { ...${optionsVariable}, baseUrl: ${baseUrlVariable} }
553
+ )`;
554
+ throw new Error(`Unknown type: ${typeUri}`);
555
+ }
556
+ function getDataCheck(typeUri, types, variable) {
557
+ if (typeUri in scalarTypes) return scalarTypes[typeUri].dataCheck(variable);
558
+ if (typeUri in types) {
559
+ const subtypes = getSubtypes(typeUri, types);
560
+ return `typeof ${variable} === "object" && "@type" in ${variable}
561
+ && Array.isArray(${variable}["@type"])` + (subtypes.length > 1 ? `&& ${JSON.stringify(subtypes)}.some(
562
+ t => ${variable}["@type"].includes(t))` : `&& ${variable}["@type"].includes(${JSON.stringify(typeUri)})`);
563
+ }
564
+ throw new Error(`Unknown type: ${typeUri}`);
565
+ }
566
+ function* getDecoders(typeUris, types, variable, optionsVariable, baseUrlVariable) {
567
+ for (const typeUri of typeUris) {
568
+ yield getDataCheck(typeUri, types, variable);
569
+ yield " ? ";
570
+ yield getDecoder(typeUri, types, variable, optionsVariable, baseUrlVariable);
571
+ yield " : ";
572
+ }
573
+ yield "undefined";
574
+ }
575
+ function emitOverride(typeUri, types) {
576
+ if (types[typeUri].extends == null) return "";
577
+ return "override";
578
+ }
579
+
580
+ //#endregion
581
+ //#region src/field.ts
582
+ async function getFieldName(propertyUri, prefix = "#") {
583
+ const hashedUri = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(propertyUri));
584
+ const match = propertyUri.match(/#([A-Za-z0-9_]+)$/);
585
+ const suffix = match == null ? "" : `_${match[1]}`;
586
+ return `${prefix}_${(0, byte_encodings_base58.encodeBase58)(hashedUri)}${suffix}`;
587
+ }
588
+ async function generateField(property, types, prefix = "#") {
589
+ const fieldName = await getFieldName(property.uri, prefix);
590
+ if (areAllScalarTypes(property.range, types)) return `${fieldName}: (${getTypeNames(property.range, types, true)})[] = [];\n`;
591
+ else {
592
+ const typeNames = getTypeNames(property.range, types);
593
+ const trustFieldName = await getFieldName(property.uri, `${prefix}_trust`);
594
+ return `
595
+ ${fieldName}: (${typeNames} | URL)[] = [];
596
+ ${trustFieldName}: Set<number> = new Set();
597
+ `;
598
+ }
599
+ }
600
+ async function* generateFields(typeUri, types) {
601
+ const type = types[typeUri];
602
+ for (const property of type.properties) yield await generateField(property, types);
603
+ }
604
+
605
+ //#endregion
606
+ //#region src/fs.ts
607
+ /**
608
+ * Recursively read a directory, yielding the paths of all files. File paths
609
+ * are relative to the directory, and directories are not yielded.
610
+ * @param dir The directory to read.
611
+ * @returns An async iterable of file paths.
612
+ */
613
+ async function* readDirRecursive(dir) {
614
+ for (const entry of await (0, node_fs_promises.readdir)(dir, { withFileTypes: true })) if (entry.isDirectory()) {
615
+ const path = (0, node_path.join)(dir, entry.name);
616
+ for await (const subentry of readDirRecursive(path)) yield (0, node_path.join)(entry.name, subentry);
617
+ } else yield entry.name;
618
+ }
619
+
620
+ //#endregion
621
+ //#region src/schema.ts
622
+ /**
623
+ * Type guard to check if a property is not functional (has pluralName).
624
+ */
625
+ function isNonFunctionalProperty(property) {
626
+ return property.functional !== true;
627
+ }
628
+ /**
629
+ * Type guard to check if a property has singular accessor.
630
+ */
631
+ function hasSingularAccessor(property) {
632
+ if (property.functional === true) return true;
633
+ return isNonFunctionalProperty(property) && property.singularAccessor === true;
634
+ }
635
+ /**
636
+ * An error that occurred while loading a schema file.
637
+ */
638
+ var SchemaError = class extends Error {
639
+ /**
640
+ * The path of the schema file.
641
+ */
642
+ path;
643
+ /**
644
+ * Constructs a new `SchemaError`.
645
+ * @param path The path of the schema file.
646
+ * @param message The error message.
647
+ */
648
+ constructor(path, message) {
649
+ super(message);
650
+ this.path = path;
651
+ }
652
+ };
653
+ async function loadSchemaValidator() {
654
+ const thisFile = require("url").pathToFileURL(__filename).href;
655
+ const schemaFile = new URL(node_path.posix.join(node_path.posix.dirname(thisFile), "schema.yaml"));
656
+ let content;
657
+ if (schemaFile.protocol !== "file:") {
658
+ const response = await fetch(schemaFile);
659
+ content = await response.text();
660
+ } else content = await (0, node_fs_promises.readFile)((0, node_url.fileURLToPath)(schemaFile), { encoding: "utf-8" });
661
+ const schemaObject = (0, yaml.parse)(content);
662
+ return new __cfworker_json_schema.Validator(schemaObject);
663
+ }
664
+ let schemaValidator = void 0;
665
+ async function loadSchema(path) {
666
+ const content = await (0, node_fs_promises.readFile)(path, { encoding: "utf-8" });
667
+ const schema = (0, yaml.parse)(content);
668
+ if (schemaValidator == null) schemaValidator = await loadSchemaValidator();
669
+ const result = schemaValidator.validate(schema);
670
+ const errors = [];
671
+ if (result.valid) return schema;
672
+ for (const e of result.errors) errors.push(new SchemaError(path, `${path}:${e.instanceLocation}: ${e.error}`));
673
+ throw new AggregateError(errors);
674
+ }
675
+ /**
676
+ * Loads all schema files in the directory.
677
+ * @param dir The path of the directory to load schema files from.
678
+ * @returns A map from the qualified URI of a type to its {@link SchemaFile}.
679
+ * @throws {@link AggregateError} if any schema file is invalid. It contains
680
+ * all {@link SchemaError}s of the invalid schema files.
681
+ */
682
+ async function loadSchemaFiles(dir) {
683
+ if (typeof dir !== "string") throw new TypeError("Expected a directory path in string");
684
+ const result = {};
685
+ const errors = [];
686
+ for await (const relPath of readDirRecursive(dir)) {
687
+ if (!relPath.match(/\.ya?ml$/i)) continue;
688
+ if (relPath.match(/(^|[/\\])schema.yaml$/i)) continue;
689
+ const path = (0, node_path.join)(dir, relPath);
690
+ let schema;
691
+ try {
692
+ schema = await loadSchema(path);
693
+ } catch (e) {
694
+ if (e instanceof AggregateError && e.errors.length > 0 && e.errors[0] instanceof SchemaError) {
695
+ errors.push(...e.errors);
696
+ continue;
697
+ }
698
+ throw e;
699
+ }
700
+ result[schema.uri] = schema;
701
+ }
702
+ if (errors.length > 0) throw new AggregateError(errors);
703
+ const entries = Object.entries(result);
704
+ entries.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
705
+ return Object.fromEntries(entries);
706
+ }
707
+
708
+ //#endregion
709
+ //#region src/codec.ts
710
+ async function* generateEncoder(typeUri, types) {
711
+ const type = types[typeUri];
712
+ yield `
713
+ /**
714
+ * Converts this object to a JSON-LD structure.
715
+ * @param options The options to use.
716
+ * - \`format\`: The format of the output: \`compact\` or
717
+ \`expand\`.
718
+ * - \`contextLoader\`: The loader for remote JSON-LD contexts.
719
+ * - \`context\`: The JSON-LD context to use. Not applicable
720
+ when \`format\` is set to \`'expand'\`.
721
+ * @returns The JSON-LD representation of this object.
722
+ */
723
+ ${emitOverride(typeUri, types)} async toJsonLd(options: {
724
+ format?: "compact" | "expand",
725
+ contextLoader?: DocumentLoader,
726
+ context?: string | Record<string, string> | (string | Record<string, string>)[],
727
+ } = {}): Promise<unknown> {
728
+ if (options.format == null && this._cachedJsonLd != null) {
729
+ return this._cachedJsonLd;
730
+ }
731
+ if (options.format !== "compact" && options.context != null) {
732
+ throw new TypeError(
733
+ "The context option can only be used when the format option is set " +
734
+ "to 'compact'."
735
+ );
736
+ }
737
+ options = {
738
+ ...options,
739
+ contextLoader: options.contextLoader ?? getDocumentLoader(),
740
+ };
741
+ `;
742
+ if (isCompactableType(typeUri, types)) {
743
+ yield `
744
+ if (options.format == null && this.isCompactable()) {
745
+ `;
746
+ if (type.extends == null) yield "const result: Record<string, unknown> = {};";
747
+ else {
748
+ yield `
749
+ const result = await super.toJsonLd({
750
+ ...options,
751
+ format: undefined,
752
+ context: undefined,
753
+ }) as Record<string, unknown>;
754
+ `;
755
+ const selfProperties = type.properties.map((p) => p.uri);
756
+ for (const property of getAllProperties(typeUri, types, true)) {
757
+ if (!selfProperties.includes(property.uri)) continue;
758
+ yield `delete result[${JSON.stringify(property.compactName)}];`;
759
+ }
760
+ }
761
+ yield `
762
+ // deno-lint-ignore no-unused-vars
763
+ let compactItems: unknown[];
764
+ `;
765
+ for (const property of type.properties) {
766
+ yield `
767
+ compactItems = [];
768
+ for (const v of this.${await getFieldName(property.uri)}) {
769
+ const item = (
770
+ `;
771
+ if (!areAllScalarTypes(property.range, types)) yield "v instanceof URL ? v.href : ";
772
+ const encoders = getEncoders(property.range, types, "v", "options", true);
773
+ for (const code of encoders) yield code;
774
+ yield `
775
+ );
776
+ compactItems.push(item);
777
+ }
778
+ if (compactItems.length > 0) {
779
+ `;
780
+ if (property.functional || isNonFunctionalProperty(property) && property.container !== "list") {
781
+ yield `
782
+ result[${JSON.stringify(property.compactName)}]
783
+ = compactItems.length > 1
784
+ ? compactItems
785
+ : compactItems[0];
786
+ `;
787
+ if (property.functional && property.redundantProperties != null) for (const prop of property.redundantProperties) yield `
788
+ result[${JSON.stringify(prop.compactName)}]
789
+ = compactItems.length > 1
790
+ ? compactItems
791
+ : compactItems[0];
792
+ `;
793
+ } else yield `
794
+ result[${JSON.stringify(property.compactName)}] = compactItems;
795
+ `;
796
+ yield `
797
+ }
798
+ `;
799
+ }
800
+ yield `
801
+ result["type"] = ${JSON.stringify(type.compactName ?? type.uri)};
802
+ if (this.id != null) result["id"] = this.id.href;
803
+ result["@context"] = ${JSON.stringify(type.defaultContext)};
804
+ return result;
805
+ }
806
+ `;
807
+ }
808
+ yield `
809
+ // deno-lint-ignore no-unused-vars prefer-const
810
+ let array: unknown[];
811
+ `;
812
+ if (type.extends == null) yield "const values: Record<string, unknown[] | string> = {};";
813
+ else yield `
814
+ const baseValues = await super.toJsonLd({
815
+ ...options,
816
+ format: "expand",
817
+ context: undefined,
818
+ }) as unknown[];
819
+ const values = baseValues[0] as Record<
820
+ string,
821
+ unknown[] | { "@list": unknown[] } | string
822
+ >;
823
+ `;
824
+ for (const property of type.properties) {
825
+ yield `
826
+ array = [];
827
+ for (const v of this.${await getFieldName(property.uri)}) {
828
+ const element = (
829
+ `;
830
+ if (!areAllScalarTypes(property.range, types)) yield "v instanceof URL ? { \"@id\": v.href } : ";
831
+ for (const code of getEncoders(property.range, types, "v", "options")) yield code;
832
+ yield `
833
+ );
834
+ `;
835
+ if (isNonFunctionalProperty(property) && property.container === "graph") yield `array.push({ "@graph": element });`;
836
+ else yield `array.push(element);`;
837
+ yield `;
838
+ }
839
+ if (array.length > 0) {
840
+ const propValue = (
841
+ `;
842
+ if (isNonFunctionalProperty(property) && property.container === "list") yield `{ "@list": array }`;
843
+ else yield `array`;
844
+ yield `
845
+ );
846
+ values[${JSON.stringify(property.uri)}] = propValue;
847
+ `;
848
+ if (property.functional && property.redundantProperties != null) for (const prop of property.redundantProperties) yield `
849
+ values[${JSON.stringify(prop.uri)}] = propValue;
850
+ `;
851
+ yield `
852
+ }
853
+ `;
854
+ }
855
+ yield `
856
+ values["@type"] = [${JSON.stringify(type.uri)}];
857
+ if (this.id != null) values["@id"] = this.id.href;
858
+ if (options.format === "expand") {
859
+ return await jsonld.expand(
860
+ values,
861
+ { documentLoader: options.contextLoader },
862
+ );
863
+ }
864
+ const docContext = options.context ??
865
+ ${JSON.stringify(type.defaultContext)};
866
+ const compacted = await jsonld.compact(
867
+ values,
868
+ docContext,
869
+ { documentLoader: options.contextLoader },
870
+ );
871
+ if (docContext != null) {
872
+ // Embed context
873
+ `;
874
+ const supertypes = [];
875
+ for (let uri = typeUri; uri != null; uri = types[uri].extends) supertypes.push(uri);
876
+ for (const supertype of supertypes) for (const property of types[supertype].properties) {
877
+ if (property.embedContext == null) continue;
878
+ const compactName = property.embedContext.compactName;
879
+ yield `
880
+ if (${JSON.stringify(compactName)} in compacted &&
881
+ compacted.${compactName} != null) {
882
+ if (Array.isArray(compacted.${compactName})) {
883
+ for (const element of compacted.${compactName}) {
884
+ element["@context"] = docContext;
885
+ }
886
+ } else {
887
+ compacted.${compactName}["@context"] = docContext;
888
+ }
889
+ }
890
+ `;
891
+ }
892
+ yield `
893
+ }
894
+ return compacted;
895
+ }
896
+
897
+ protected ${emitOverride(typeUri, types)} isCompactable(): boolean {
898
+ `;
899
+ for (const property of type.properties) if (!property.range.every((r) => isCompactableType(r, types))) yield `
900
+ if (
901
+ this.${await getFieldName(property.uri)} != null &&
902
+ this.${await getFieldName(property.uri)}.length > 0
903
+ ) return false;
904
+ `;
905
+ yield `
906
+ return ${type.extends == null ? "true" : "super.isCompactable()"};
907
+ }
908
+ `;
909
+ }
910
+ async function* generateDecoder(typeUri, types) {
911
+ const type = types[typeUri];
912
+ yield `
913
+ /**
914
+ * Converts a JSON-LD structure to an object of this type.
915
+ * @param json The JSON-LD structure to convert.
916
+ * @param options The options to use.
917
+ * - \`documentLoader\`: The loader for remote JSON-LD documents.
918
+ * - \`contextLoader\`: The loader for remote JSON-LD contexts.
919
+ * - \`tracerProvider\`: The OpenTelemetry tracer provider to use.
920
+ * If omitted, the global tracer provider is used.
921
+ * @returns The object of this type.
922
+ * @throws {TypeError} If the given \`json\` is invalid.
923
+ */
924
+ static ${emitOverride(typeUri, types)} async fromJsonLd(
925
+ json: unknown,
926
+ options: {
927
+ documentLoader?: DocumentLoader,
928
+ contextLoader?: DocumentLoader,
929
+ tracerProvider?: TracerProvider,
930
+ baseUrl?: URL,
931
+ } = {},
932
+ ): Promise<${type.name}> {
933
+ const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
934
+ const tracer = tracerProvider.getTracer(
935
+ ${JSON.stringify(deno_default.name)},
936
+ ${JSON.stringify(deno_default.version)},
937
+ );
938
+ return await tracer.startActiveSpan(
939
+ "activitypub.parse_object",
940
+ async (span) => {
941
+ try {
942
+ const object = await this.__fromJsonLd__${type.name}__(
943
+ json, span, options);
944
+ if (object.id != null) {
945
+ span.setAttribute("activitypub.object.id", object.id.href);
946
+ }
947
+ return object;
948
+ } catch (error) {
949
+ span.setStatus({
950
+ code: SpanStatusCode.ERROR,
951
+ message: String(error),
952
+ });
953
+ throw error;
954
+ } finally {
955
+ span.end();
956
+ }
957
+ },
958
+ );
959
+ }
960
+
961
+ protected static async __fromJsonLd__${type.name}__(
962
+ json: unknown,
963
+ span: Span,
964
+ options: {
965
+ documentLoader?: DocumentLoader,
966
+ contextLoader?: DocumentLoader,
967
+ tracerProvider?: TracerProvider,
968
+ baseUrl?: URL,
969
+ } = {},
970
+ ): Promise<${type.name}> {
971
+ if (typeof json === "undefined") {
972
+ throw new TypeError("Invalid JSON-LD: undefined.");
973
+ }
974
+ else if (json === null) throw new TypeError("Invalid JSON-LD: null.");
975
+ options = {
976
+ ...options,
977
+ documentLoader: options.documentLoader ?? getDocumentLoader(),
978
+ contextLoader: options.contextLoader ?? getDocumentLoader(),
979
+ tracerProvider: options.tracerProvider ?? trace.getTracerProvider(),
980
+ };
981
+ // deno-lint-ignore no-explicit-any
982
+ let values: Record<string, any[]> & { "@id"?: string };
983
+ if (globalThis.Object.keys(json).length == 0) {
984
+ values = {};
985
+ } else {
986
+ const expanded = await jsonld.expand(json, {
987
+ documentLoader: options.contextLoader,
988
+ keepFreeFloatingNodes: true,
989
+ });
990
+ values =
991
+ // deno-lint-ignore no-explicit-any
992
+ (expanded[0] ?? {}) as (Record<string, any[]> & { "@id"?: string });
993
+ }
994
+ if (options.baseUrl == null && values["@id"] != null) {
995
+ options = { ...options, baseUrl: new URL(values["@id"]) };
996
+ }
997
+ `;
998
+ const subtypes = getSubtypes(typeUri, types, true);
999
+ yield `
1000
+ if ("@type" in values) {
1001
+ span.setAttribute("activitypub.object.type", values["@type"]);
1002
+ }
1003
+ if ("@type" in values &&
1004
+ !values["@type"].every(t => t.startsWith("_:"))) {
1005
+ `;
1006
+ for (const subtypeUri of subtypes) yield `
1007
+ if (values["@type"].includes(${JSON.stringify(subtypeUri)})) {
1008
+ return await ${types[subtypeUri].name}.fromJsonLd(json, options);
1009
+ }
1010
+ `;
1011
+ yield `
1012
+ if (!values["@type"].includes(${JSON.stringify(typeUri)})) {
1013
+ throw new TypeError("Invalid type: " + values["@type"]);
1014
+ }
1015
+ }
1016
+ `;
1017
+ if (type.extends == null) yield `
1018
+ const instance = new this(
1019
+ { id: "@id" in values ? new URL(values["@id"] as string) : undefined },
1020
+ options,
1021
+ );
1022
+ `;
1023
+ else yield `
1024
+ delete values["@type"];
1025
+ const instance = await super.fromJsonLd(values, {
1026
+ ...options,
1027
+ // @ts-ignore: an internal option
1028
+ _fromSubclass: true,
1029
+ });
1030
+ if (!(instance instanceof ${type.name})) {
1031
+ throw new TypeError("Unexpected type: " + instance.constructor.name);
1032
+ }
1033
+ `;
1034
+ for (const property of type.properties) {
1035
+ const variable = await getFieldName(property.uri, "");
1036
+ yield await generateField(property, types, "const ");
1037
+ const arrayVariable = `${variable}__array`;
1038
+ yield `
1039
+ let ${arrayVariable} = values[${JSON.stringify(property.uri)}];
1040
+ `;
1041
+ if (property.functional && property.redundantProperties != null) for (const prop of property.redundantProperties) yield `
1042
+ if (${arrayVariable} == null || ${arrayVariable}.length < 1) {
1043
+ ${arrayVariable} = values[${JSON.stringify(prop.uri)}];
1044
+ }
1045
+ `;
1046
+ yield `
1047
+ for (
1048
+ const v of ${arrayVariable} == null
1049
+ ? []
1050
+ : ${arrayVariable}.length === 1 && "@list" in ${arrayVariable}[0]
1051
+ ? ${arrayVariable}[0]["@list"]
1052
+ : ${arrayVariable}
1053
+ ) {
1054
+ if (v == null) continue;
1055
+ `;
1056
+ if (!areAllScalarTypes(property.range, types)) yield `
1057
+ if (typeof v === "object" && "@id" in v && !("@type" in v)
1058
+ && globalThis.Object.keys(v).length === 1) {
1059
+ ${variable}.push(
1060
+ !URL.canParse(v["@id"]) && v["@id"].startsWith("at://")
1061
+ ? new URL("at://" + encodeURIComponent(v["@id"].substring(5)))
1062
+ : new URL(v["@id"])
1063
+ );
1064
+ continue;
1065
+ }
1066
+ `;
1067
+ if (property.range.length == 1) yield `${variable}.push(${getDecoder(property.range[0], types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`)})`;
1068
+ else {
1069
+ yield `
1070
+ const decoded =
1071
+ `;
1072
+ const decoders = getDecoders(property.range, types, "v", "options", `(values["@id"] == null ? options.baseUrl : new URL(values["@id"]))`);
1073
+ for (const code of decoders) yield code;
1074
+ yield `
1075
+ ;
1076
+ if (typeof decoded === "undefined") continue;
1077
+ ${variable}.push(decoded);
1078
+ `;
1079
+ }
1080
+ yield `
1081
+ }
1082
+ instance.${await getFieldName(property.uri)} = ${variable};
1083
+ `;
1084
+ }
1085
+ yield `
1086
+ if (!("_fromSubclass" in options) || !options._fromSubclass) {
1087
+ try {
1088
+ instance._cachedJsonLd = structuredClone(json);
1089
+ } catch {
1090
+ getLogger(["fedify", "vocab"]).warn(
1091
+ "Failed to cache JSON-LD: {json}",
1092
+ { json },
1093
+ );
1094
+ }
1095
+ }
1096
+ return instance;
1097
+ }
1098
+ `;
1099
+ }
1100
+
1101
+ //#endregion
1102
+ //#region src/constructor.ts
1103
+ function generateParameterType(property, types) {
1104
+ const range = property.range;
1105
+ const scalar = areAllScalarTypes(range, types);
1106
+ const code = [];
1107
+ if (hasSingularAccessor(property)) if (scalar) code.push(`${property.singularName}?: ${getTypeNames(range, types)} | null;`);
1108
+ else code.push(`${property.singularName}?: ${getTypeNames(range, types)} | URL | null;`);
1109
+ if (isNonFunctionalProperty(property)) if (scalar) code.push(`${property.pluralName}?: (${getTypeNames(range, types, true)})[];`);
1110
+ else code.push(`${property.pluralName}?: (${getTypeNames(range, types)} | URL)[];`);
1111
+ return code.join("\n");
1112
+ }
1113
+ async function* generateParametersType(typeUri, types, parentheses = true, excludeProperties = []) {
1114
+ const type = types[typeUri];
1115
+ if (parentheses) yield "{\n";
1116
+ if (type.extends == null) yield `id?: URL | null;\n`;
1117
+ else for await (const code of generateParametersType(type.extends, types, false, [...excludeProperties, ...type.properties.map((p) => p.singularName)])) yield code;
1118
+ for (const property of type.properties) {
1119
+ if (excludeProperties.includes(property.singularName)) continue;
1120
+ yield generateParameterType(property, types);
1121
+ }
1122
+ if (parentheses) yield "}\n";
1123
+ }
1124
+ async function* generateConstructor(typeUri, types) {
1125
+ const type = types[typeUri];
1126
+ yield `
1127
+ /**
1128
+ * Constructs a new instance of ${type.name} with the given values.
1129
+ * @param values The values to initialize the instance with.
1130
+ * @param options The options to use for initialization.
1131
+ */
1132
+ constructor(
1133
+ values:
1134
+ `;
1135
+ for await (const code of generateParametersType(typeUri, types)) yield code;
1136
+ yield `,
1137
+ options: {
1138
+ documentLoader?: DocumentLoader,
1139
+ contextLoader?: DocumentLoader,
1140
+ tracerProvider?: TracerProvider,
1141
+ } = {},
1142
+ ) {
1143
+ `;
1144
+ if (type.extends == null) yield `
1145
+ this.#documentLoader = options.documentLoader;
1146
+ this.#contextLoader = options.contextLoader;
1147
+ this.#tracerProvider = options.tracerProvider;
1148
+ if ("$warning" in options) {
1149
+ this.#warning = options.$warning as unknown as {
1150
+ category: string[];
1151
+ message: string;
1152
+ values?: Record<string, unknown>;
1153
+ };
1154
+ }
1155
+ if (values.id == null || values.id instanceof URL) {
1156
+ this.id = values.id ?? null;
1157
+ } else {
1158
+ throw new TypeError("The id must be a URL.");
1159
+ }
1160
+ `;
1161
+ else yield "super(values, options);";
1162
+ for (const property of type.properties) {
1163
+ const fieldName = await getFieldName(property.uri);
1164
+ const trustFieldName = await getFieldName(property.uri, "#_trust");
1165
+ const allScalarTypes = areAllScalarTypes(property.range, types);
1166
+ if (hasSingularAccessor(property)) {
1167
+ let typeGuards = getTypeGuards(property.range, types, `values.${property.singularName}`);
1168
+ let typeNames = getTypeNames(property.range, types);
1169
+ const scalar = areAllScalarTypes(property.range, types);
1170
+ if (!scalar) {
1171
+ typeGuards = `${typeGuards} || values.${property.singularName} instanceof URL`;
1172
+ typeNames = `${typeNames} | URL`;
1173
+ }
1174
+ yield `
1175
+ if ("${property.singularName}" in values && \
1176
+ values.${property.singularName} != null) {
1177
+ if (${typeGuards}) {
1178
+ // @ts-ignore: type is checked above.
1179
+ this.${fieldName} = [values.${property.singularName}];
1180
+ `;
1181
+ if (!allScalarTypes) yield `this.${trustFieldName}.add(0);`;
1182
+ yield `
1183
+ } else {
1184
+ throw new TypeError(
1185
+ "The ${property.singularName} must be of type " +
1186
+ ${JSON.stringify(typeNames)} + ".",
1187
+ );
1188
+ }
1189
+ }
1190
+ `;
1191
+ }
1192
+ if (isNonFunctionalProperty(property)) {
1193
+ let typeGuards = getTypeGuards(property.range, types, `v`);
1194
+ let typeNames = getTypeNames(property.range, types);
1195
+ const scalar = areAllScalarTypes(property.range, types);
1196
+ if (!scalar) {
1197
+ typeGuards = `${typeGuards} || v instanceof URL`;
1198
+ typeNames = `${typeNames} | URL`;
1199
+ }
1200
+ yield `
1201
+ if ("${property.pluralName}" in values && \
1202
+ values.${property.pluralName} != null) {
1203
+ `;
1204
+ if (property && property.singularAccessor) yield `
1205
+ if ("${property.singularName}" in values &&
1206
+ values.${property.singularName} != null) {
1207
+ throw new TypeError(
1208
+ "Cannot initialize both ${property.singularName} and " +
1209
+ "${property.pluralName} at the same time.",
1210
+ );
1211
+ }
1212
+ `;
1213
+ yield `
1214
+ if (Array.isArray(values.${property.pluralName}) &&
1215
+ values.${property.pluralName}.every(v => ${typeGuards})) {
1216
+ // @ts-ignore: type is checked above.
1217
+ this.${fieldName} = values.${property.pluralName};
1218
+ `;
1219
+ if (!allScalarTypes) yield `
1220
+ for (let i = 0; i < values.${property.pluralName}.length; i++) {
1221
+ this.${trustFieldName}.add(i);
1222
+ }
1223
+ `;
1224
+ yield `
1225
+ } else {
1226
+ throw new TypeError(
1227
+ "The ${property.pluralName} must be an array of type " +
1228
+ ${JSON.stringify(typeNames)} + ".",
1229
+ );
1230
+ }
1231
+ }
1232
+ `;
1233
+ }
1234
+ }
1235
+ yield "}\n";
1236
+ }
1237
+ async function* generateCloner(typeUri, types) {
1238
+ const type = types[typeUri];
1239
+ yield `
1240
+ /**
1241
+ * Clones this instance, optionally updating it with the given values.
1242
+ * @param values The values to update the clone with.
1243
+ * @options The options to use for cloning.
1244
+ * @returns The cloned instance.
1245
+ */
1246
+ ${emitOverride(typeUri, types)} clone(
1247
+ values:
1248
+ `;
1249
+ for await (const code of generateParametersType(typeUri, types)) yield code;
1250
+ yield `
1251
+ = {},
1252
+ options: {
1253
+ documentLoader?: DocumentLoader,
1254
+ contextLoader?: DocumentLoader,
1255
+ } = {}
1256
+ ): ${type.name} {
1257
+ if (this._warning != null) {
1258
+ getLogger(this._warning.category).warn(
1259
+ this._warning.message,
1260
+ this._warning.values
1261
+ );
1262
+ // @ts-ignore: $warning is not recognized as a property, but it is.
1263
+ options = { ...options, $warning: this._warning };
1264
+ }
1265
+ `;
1266
+ if (type.extends == null) yield `
1267
+ // @ts-ignore: this.constructor is not recognized as a constructor, but it is.
1268
+ const clone: ${type.name} = new this.constructor(
1269
+ { id: values.id ?? this.id },
1270
+ options
1271
+ );
1272
+ `;
1273
+ else yield `const clone = super.clone(values, options) as unknown as ${type.name};`;
1274
+ for (const property of type.properties) {
1275
+ const fieldName = await getFieldName(property.uri);
1276
+ const trustFieldName = await getFieldName(property.uri, "#_trust");
1277
+ const allScalarTypes = areAllScalarTypes(property.range, types);
1278
+ yield `clone.${fieldName} = this.${fieldName};`;
1279
+ if (!allScalarTypes) yield `clone.${trustFieldName} = new Set(this.${trustFieldName});`;
1280
+ if (hasSingularAccessor(property)) {
1281
+ let typeGuards = getTypeGuards(property.range, types, `values.${property.singularName}`);
1282
+ let typeNames = getTypeNames(property.range, types);
1283
+ const scalar = areAllScalarTypes(property.range, types);
1284
+ if (!scalar) {
1285
+ typeGuards = `${typeGuards} || values.${property.singularName} instanceof URL`;
1286
+ typeNames = `${typeNames} | URL`;
1287
+ }
1288
+ yield `
1289
+ if ("${property.singularName}" in values && \
1290
+ values.${property.singularName} != null) {
1291
+ if (${typeGuards}) {
1292
+ // @ts-ignore: type is checked above.
1293
+ clone.${fieldName} = [values.${property.singularName}];
1294
+ `;
1295
+ if (!allScalarTypes) yield `clone.${trustFieldName} = new Set([0]);`;
1296
+ yield `
1297
+ } else {
1298
+ throw new TypeError(
1299
+ "The ${property.singularName} must be of type " +
1300
+ ${JSON.stringify(typeNames)} + ".",
1301
+ );
1302
+ }
1303
+ }
1304
+ `;
1305
+ }
1306
+ if (isNonFunctionalProperty(property)) {
1307
+ let typeGuards = getTypeGuards(property.range, types, `v`);
1308
+ let typeNames = getTypeNames(property.range, types);
1309
+ const scalar = areAllScalarTypes(property.range, types);
1310
+ if (!scalar) {
1311
+ typeGuards = `${typeGuards} || v instanceof URL`;
1312
+ typeNames = `${typeNames} | URL`;
1313
+ }
1314
+ yield `
1315
+ if ("${property.pluralName}" in values && \
1316
+ values.${property.pluralName} != null) {
1317
+ `;
1318
+ if (property.singularAccessor) yield `
1319
+ if ("${property.singularName}" in values &&
1320
+ values.${property.singularName} != null) {
1321
+ throw new TypeError(
1322
+ "Cannot update both ${property.singularName} and " +
1323
+ "${property.pluralName} at the same time.",
1324
+ );
1325
+ }
1326
+ `;
1327
+ yield `
1328
+ if (Array.isArray(values.${property.pluralName}) &&
1329
+ values.${property.pluralName}.every(v => ${typeGuards})) {
1330
+ // @ts-ignore: type is checked above.
1331
+ clone.${fieldName} = values.${property.pluralName};
1332
+ `;
1333
+ if (!allScalarTypes) yield `
1334
+ clone.${trustFieldName} = new Set();
1335
+ for (let i = 0; i < values.${property.pluralName}.length; i++) {
1336
+ clone.${trustFieldName}.add(i);
1337
+ }
1338
+ `;
1339
+ yield `
1340
+ } else {
1341
+ throw new TypeError(
1342
+ "The ${property.pluralName} must be an array of type " +
1343
+ ${JSON.stringify(typeNames)} + ".",
1344
+ );
1345
+ }
1346
+ }
1347
+ `;
1348
+ }
1349
+ }
1350
+ yield `
1351
+ return clone;
1352
+ }
1353
+ `;
1354
+ }
1355
+
1356
+ //#endregion
1357
+ //#region src/inspector.ts
1358
+ async function* generateInspector(typeUri, types) {
1359
+ const type = types[typeUri];
1360
+ yield `
1361
+ protected ${emitOverride(typeUri, types)} _getCustomInspectProxy(): Record<string, unknown> {
1362
+ `;
1363
+ if (type.extends == null) yield `
1364
+ const proxy: Record<string, unknown> = {};
1365
+ if (this.id != null) {
1366
+ proxy.id = {
1367
+ [Symbol.for("Deno.customInspect")]: (
1368
+ inspect: typeof Deno.inspect,
1369
+ options: Deno.InspectOptions,
1370
+ ): string => "URL " + inspect(this.id!.href, options),
1371
+ [Symbol.for("nodejs.util.inspect.custom")]: (
1372
+ _depth: number,
1373
+ options: unknown,
1374
+ inspect: (value: unknown, options: unknown) => string,
1375
+ ): string => "URL " + inspect(this.id!.href, options),
1376
+ };
1377
+ }
1378
+ `;
1379
+ else yield "const proxy: Record<string, unknown> = super._getCustomInspectProxy();";
1380
+ for (const property of type.properties) {
1381
+ const fieldName = await getFieldName(property.uri);
1382
+ const localName = await getFieldName(property.uri, "");
1383
+ yield `
1384
+ const ${localName} = this.${fieldName}
1385
+ // deno-lint-ignore no-explicit-any
1386
+ .map((v: any) => v instanceof URL
1387
+ ? {
1388
+ [Symbol.for("Deno.customInspect")]: (
1389
+ inspect: typeof Deno.inspect,
1390
+ options: Deno.InspectOptions,
1391
+ ): string => "URL " + inspect(v.href, options),
1392
+ [Symbol.for("nodejs.util.inspect.custom")]: (
1393
+ _depth: number,
1394
+ options: unknown,
1395
+ inspect: (value: unknown, options: unknown) => string,
1396
+ ): string => "URL " + inspect(v.href, options),
1397
+ }
1398
+ : v);
1399
+ `;
1400
+ if (hasSingularAccessor(property)) yield `
1401
+ if (${localName}.length == 1) {
1402
+ proxy.${property.singularName} = ${localName}[0];
1403
+ }
1404
+ `;
1405
+ if (isNonFunctionalProperty(property)) yield `
1406
+ if (${localName}.length > 1
1407
+ || !(${JSON.stringify(property.singularName)} in proxy)
1408
+ && ${localName}.length > 0) {
1409
+ proxy.${property.pluralName} = ${localName};
1410
+ }
1411
+ `;
1412
+ }
1413
+ yield `
1414
+ return proxy;
1415
+ }
1416
+
1417
+ // @ts-ignore: suppressing TS4127
1418
+ ${emitOverride(typeUri, types)} [Symbol.for("Deno.customInspect")](
1419
+ inspect: typeof Deno.inspect,
1420
+ options: Deno.InspectOptions,
1421
+ ): string {
1422
+ const proxy = this._getCustomInspectProxy();
1423
+ return ${JSON.stringify(type.name + " ")} + inspect(proxy, options);
1424
+ }
1425
+
1426
+ // @ts-ignore: suppressing TS4127
1427
+ ${emitOverride(typeUri, types)} [Symbol.for("nodejs.util.inspect.custom")](
1428
+ _depth: number,
1429
+ options: unknown,
1430
+ inspect: (value: unknown, options: unknown) => string,
1431
+ ): string {
1432
+ const proxy = this._getCustomInspectProxy();
1433
+ return ${JSON.stringify(type.name + " ")} + inspect(proxy, options);
1434
+ }
1435
+ `;
1436
+ }
1437
+
1438
+ //#endregion
1439
+ //#region src/property.ts
1440
+ function emitOverride$1(typeUri, types, property) {
1441
+ const type = types[typeUri];
1442
+ let supertypeUri = type.extends;
1443
+ while (supertypeUri != null) {
1444
+ const st = types[supertypeUri];
1445
+ if (st.properties.find((p) => p.singularName === property.singularName)) return "override";
1446
+ supertypeUri = st.extends;
1447
+ }
1448
+ return "";
1449
+ }
1450
+ async function* generateProperty(type, property, types) {
1451
+ const override = emitOverride$1(type.uri, types, property);
1452
+ const doc = `\n/** ${property.description.replaceAll("\n", "\n * ")}\n */\n`;
1453
+ if (areAllScalarTypes(property.range, types)) {
1454
+ if (hasSingularAccessor(property)) {
1455
+ yield doc;
1456
+ yield `${override} get ${property.singularName}(): (${getTypeNames(property.range, types)} | null) {
1457
+ if (this._warning != null) {
1458
+ getLogger(this._warning.category).warn(
1459
+ this._warning.message,
1460
+ this._warning.values
1461
+ );
1462
+ }
1463
+ if (this.${await getFieldName(property.uri)}.length < 1) return null;
1464
+ return this.${await getFieldName(property.uri)}[0];
1465
+ }
1466
+ `;
1467
+ }
1468
+ if (isNonFunctionalProperty(property)) {
1469
+ yield doc;
1470
+ yield `get ${property.pluralName}(): (${getTypeNames(property.range, types, true)})[] {
1471
+ return this.${await getFieldName(property.uri)};
1472
+ }
1473
+ `;
1474
+ }
1475
+ } else {
1476
+ yield `
1477
+ async #fetch${(0, es_toolkit.pascalCase)(property.singularName)}(
1478
+ url: URL,
1479
+ options: {
1480
+ documentLoader?: DocumentLoader,
1481
+ contextLoader?: DocumentLoader,
1482
+ suppressError?: boolean,
1483
+ tracerProvider?: TracerProvider,
1484
+ crossOrigin?: "ignore" | "throw" | "trust";
1485
+ } = {},
1486
+ ): Promise<${getTypeNames(property.range, types)} | null> {
1487
+ const documentLoader =
1488
+ options.documentLoader ?? this._documentLoader ?? getDocumentLoader();
1489
+ const contextLoader =
1490
+ options.contextLoader ?? this._contextLoader ?? getDocumentLoader();
1491
+ const tracerProvider = options.tracerProvider ??
1492
+ this._tracerProvider ?? trace.getTracerProvider();
1493
+ const tracer = tracerProvider.getTracer(
1494
+ ${JSON.stringify(deno_default.name)},
1495
+ ${JSON.stringify(deno_default.version)},
1496
+ );
1497
+ return await tracer.startActiveSpan("activitypub.lookup_object", async (span) => {
1498
+ let fetchResult: RemoteDocument;
1499
+ try {
1500
+ fetchResult = await documentLoader(url.href);
1501
+ } catch (error) {
1502
+ span.setStatus({
1503
+ code: SpanStatusCode.ERROR,
1504
+ message: String(error),
1505
+ });
1506
+ span.end();
1507
+ if (options.suppressError) {
1508
+ getLogger(["fedify", "vocab"]).error(
1509
+ "Failed to fetch {url}: {error}",
1510
+ { error, url: url.href }
1511
+ );
1512
+ return null;
1513
+ }
1514
+ throw error;
1515
+ }
1516
+ const { document, documentUrl } = fetchResult;
1517
+ const baseUrl = new URL(documentUrl);
1518
+ try {
1519
+ const obj = await this.#${property.singularName}_fromJsonLd(
1520
+ document,
1521
+ { documentLoader, contextLoader, tracerProvider, baseUrl }
1522
+ );
1523
+ if (options.crossOrigin !== "trust" && obj?.id != null &&
1524
+ obj.id.origin !== baseUrl.origin) {
1525
+ if (options.crossOrigin === "throw") {
1526
+ throw new Error(
1527
+ "The object's @id (" + obj.id.href + ") has a different origin " +
1528
+ "than the document URL (" + baseUrl.href + "); refusing to return " +
1529
+ "the object. If you want to bypass this check and are aware of" +
1530
+ 'the security implications, set the crossOrigin option to "trust".'
1531
+ );
1532
+ }
1533
+ getLogger(["fedify", "vocab"]).warn(
1534
+ "The object's @id ({objectId}) has a different origin than the document " +
1535
+ "URL ({documentUrl}); refusing to return the object. If you want to " +
1536
+ "bypass this check and are aware of the security implications, " +
1537
+ 'set the crossOrigin option to "trust".',
1538
+ { ...fetchResult, objectId: obj.id.href },
1539
+ );
1540
+ return null;
1541
+ }
1542
+ span.setAttribute("activitypub.object.id", (obj.id ?? url).href);
1543
+ span.setAttribute(
1544
+ "activitypub.object.type",
1545
+ // @ts-ignore: obj.constructor always has a typeId.
1546
+ obj.constructor.typeId.href
1547
+ );
1548
+ return obj;
1549
+ } catch (e) {
1550
+ if (options.suppressError) {
1551
+ getLogger(["fedify", "vocab"]).error(
1552
+ "Failed to parse {url}: {error}",
1553
+ { error: e, url: url.href }
1554
+ );
1555
+ return null;
1556
+ }
1557
+ span.setStatus({
1558
+ code: SpanStatusCode.ERROR,
1559
+ message: String(e),
1560
+ });
1561
+ throw e;
1562
+ } finally {
1563
+ span.end();
1564
+ }
1565
+ });
1566
+ }
1567
+
1568
+ async #${property.singularName}_fromJsonLd(
1569
+ jsonLd: unknown,
1570
+ options: {
1571
+ documentLoader?: DocumentLoader,
1572
+ contextLoader?: DocumentLoader,
1573
+ tracerProvider?: TracerProvider,
1574
+ baseUrl?: URL
1575
+ }
1576
+ ): Promise<${getTypeNames(property.range, types)}> {
1577
+ const documentLoader =
1578
+ options.documentLoader ?? this._documentLoader ?? getDocumentLoader();
1579
+ const contextLoader =
1580
+ options.contextLoader ?? this._contextLoader ?? getDocumentLoader();
1581
+ const tracerProvider = options.tracerProvider ??
1582
+ this._tracerProvider ?? trace.getTracerProvider();
1583
+ const baseUrl = options.baseUrl;
1584
+ `;
1585
+ for (const range of property.range) {
1586
+ if (!(range in types)) continue;
1587
+ const rangeType = types[range];
1588
+ yield `
1589
+ try {
1590
+ return await ${rangeType.name}.fromJsonLd(
1591
+ jsonLd,
1592
+ { documentLoader, contextLoader, tracerProvider, baseUrl },
1593
+ );
1594
+ } catch (e) {
1595
+ if (!(e instanceof TypeError)) throw e;
1596
+ }
1597
+ `;
1598
+ }
1599
+ yield `
1600
+ throw new TypeError("Expected an object of any type of: " +
1601
+ ${JSON.stringify(property.range)}.join(", "));
1602
+ }
1603
+
1604
+ `;
1605
+ if (hasSingularAccessor(property)) {
1606
+ yield `
1607
+ /**
1608
+ * Similar to
1609
+ * {@link ${type.name}.get${(0, es_toolkit.pascalCase)(property.singularName)}},
1610
+ * but returns its \`@id\` URL instead of the object itself.
1611
+ */
1612
+ ${override} get ${property.singularName}Id(): URL | null {
1613
+ if (this._warning != null) {
1614
+ getLogger(this._warning.category).warn(
1615
+ this._warning.message,
1616
+ this._warning.values
1617
+ );
1618
+ }
1619
+ if (this.${await getFieldName(property.uri)}.length < 1) return null;
1620
+ const v = this.${await getFieldName(property.uri)}[0];
1621
+ if (v instanceof URL) return v;
1622
+ return v.id;
1623
+ }
1624
+ `;
1625
+ yield doc;
1626
+ yield `
1627
+ ${override} async get${(0, es_toolkit.pascalCase)(property.singularName)}(
1628
+ options: {
1629
+ documentLoader?: DocumentLoader,
1630
+ contextLoader?: DocumentLoader,
1631
+ suppressError?: boolean,
1632
+ tracerProvider?: TracerProvider,
1633
+ crossOrigin?: "ignore" | "throw" | "trust";
1634
+ } = {}
1635
+ ): Promise<${getTypeNames(property.range, types)} | null> {
1636
+ if (this._warning != null) {
1637
+ getLogger(this._warning.category).warn(
1638
+ this._warning.message,
1639
+ this._warning.values
1640
+ );
1641
+ }
1642
+ if (this.${await getFieldName(property.uri)}.length < 1) return null;
1643
+ let v = this.${await getFieldName(property.uri)}[0];
1644
+ if (options.crossOrigin !== "trust" && !(v instanceof URL) &&
1645
+ v.id != null && v.id.origin !== this.id?.origin &&
1646
+ !this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
1647
+ v = v.id;
1648
+ }
1649
+ if (v instanceof URL) {
1650
+ const fetched =
1651
+ await this.#fetch${(0, es_toolkit.pascalCase)(property.singularName)}(v, options);
1652
+ if (fetched == null) return null;
1653
+ this.${await getFieldName(property.uri)}[0] = fetched;
1654
+ this.${await getFieldName(property.uri, "#_trust")}.add(0);
1655
+ this._cachedJsonLd = undefined;
1656
+ return fetched;
1657
+ }
1658
+ `;
1659
+ if (property.compactName != null) yield `
1660
+ if (
1661
+ this._cachedJsonLd != null &&
1662
+ typeof this._cachedJsonLd === "object" &&
1663
+ "@context" in this._cachedJsonLd &&
1664
+ ${JSON.stringify(property.compactName)} in this._cachedJsonLd
1665
+ ) {
1666
+ const prop = this._cachedJsonLd[
1667
+ ${JSON.stringify(property.compactName)}];
1668
+ const doc = Array.isArray(prop) ? prop[0] : prop;
1669
+ if (doc != null && typeof doc === "object" && "@context" in doc) {
1670
+ v = await this.#${property.singularName}_fromJsonLd(doc, options);
1671
+ }
1672
+ }
1673
+ `;
1674
+ yield `
1675
+ if (options.crossOrigin !== "trust" && v?.id != null &&
1676
+ this.id != null && v.id.origin !== this.id.origin &&
1677
+ !this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
1678
+ if (options.crossOrigin === "throw") {
1679
+ throw new Error(
1680
+ "The property object's @id (" + v.id.href + ") has a different " +
1681
+ "origin than the property owner's @id (" + this.id.href + "); " +
1682
+ "refusing to return the object. If you want to bypass this " +
1683
+ "check and are aware of the security implications, set the " +
1684
+ 'crossOrigin option to "trust".'
1685
+ );
1686
+ }
1687
+ getLogger(["fedify", "vocab"]).warn(
1688
+ "The property object's @id ({objectId}) has a different origin " +
1689
+ "than the property owner's @id ({parentObjectId}); refusing to " +
1690
+ "return the object. If you want to bypass this check and are " +
1691
+ "aware of the security implications, set the crossOrigin option " +
1692
+ 'to "trust".',
1693
+ { objectId: v.id.href, parentObjectId: this.id.href },
1694
+ );
1695
+ return null;
1696
+ }
1697
+ return v;
1698
+ }
1699
+ `;
1700
+ }
1701
+ if (isNonFunctionalProperty(property)) {
1702
+ yield `
1703
+ /**
1704
+ * Similar to
1705
+ * {@link ${type.name}.get${(0, es_toolkit.pascalCase)(property.pluralName)}},
1706
+ * but returns their \`@id\`s instead of the objects themselves.
1707
+ */
1708
+ ${override} get ${property.singularName}Ids(): URL[] {
1709
+ if (this._warning != null) {
1710
+ getLogger(this._warning.category).warn(
1711
+ this._warning.message,
1712
+ this._warning.values
1713
+ );
1714
+ }
1715
+ return this.${await getFieldName(property.uri)}.map((v) =>
1716
+ v instanceof URL ? v : v.id!
1717
+ ).filter(id => id !== null);
1718
+ }
1719
+ `;
1720
+ yield doc;
1721
+ yield `
1722
+ ${override} async* get${(0, es_toolkit.pascalCase)(property.pluralName)}(
1723
+ options: {
1724
+ documentLoader?: DocumentLoader,
1725
+ contextLoader?: DocumentLoader,
1726
+ suppressError?: boolean,
1727
+ tracerProvider?: TracerProvider,
1728
+ crossOrigin?: "ignore" | "throw" | "trust";
1729
+ } = {}
1730
+ ): AsyncIterable<${getTypeNames(property.range, types)}> {
1731
+ if (this._warning != null) {
1732
+ getLogger(this._warning.category).warn(
1733
+ this._warning.message,
1734
+ this._warning.values
1735
+ );
1736
+ }
1737
+ const vs = this.${await getFieldName(property.uri)};
1738
+ for (let i = 0; i < vs.length; i++) {
1739
+ let v = vs[i];
1740
+ if (options.crossOrigin !== "trust" && !(v instanceof URL) &&
1741
+ v.id != null && v.id.origin !== this.id?.origin &&
1742
+ !this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
1743
+ v = v.id;
1744
+ }
1745
+ if (v instanceof URL) {
1746
+ const fetched =
1747
+ await this.#fetch${(0, es_toolkit.pascalCase)(property.singularName)}(v, options);
1748
+ if (fetched == null) continue;
1749
+ vs[i] = fetched;
1750
+ this.${await getFieldName(property.uri, "#_trust")}.add(i);
1751
+ this._cachedJsonLd = undefined;
1752
+ yield fetched;
1753
+ continue;
1754
+ }
1755
+ `;
1756
+ if (property.compactName != null) yield `
1757
+ if (
1758
+ this._cachedJsonLd != null &&
1759
+ typeof this._cachedJsonLd === "object" &&
1760
+ "@context" in this._cachedJsonLd &&
1761
+ ${JSON.stringify(property.compactName)} in this._cachedJsonLd
1762
+ ) {
1763
+ const prop = this._cachedJsonLd[
1764
+ ${JSON.stringify(property.compactName)}];
1765
+ const obj = Array.isArray(prop) ? prop[i] : prop;
1766
+ if (obj != null && typeof obj === "object" && "@context" in obj) {
1767
+ v = await this.#${property.singularName}_fromJsonLd(obj, options);
1768
+ }
1769
+ }
1770
+ `;
1771
+ yield `
1772
+ if (options.crossOrigin !== "trust" && v?.id != null &&
1773
+ this.id != null && v.id.origin !== this.id.origin &&
1774
+ !this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
1775
+ if (options.crossOrigin === "throw") {
1776
+ throw new Error(
1777
+ "The property object's @id (" + v.id.href + ") has a different " +
1778
+ "origin than the property owner's @id (" + this.id.href + "); " +
1779
+ "refusing to return the object. If you want to bypass this " +
1780
+ "check and are aware of the security implications, set the " +
1781
+ 'crossOrigin option to "trust".'
1782
+ );
1783
+ }
1784
+ getLogger(["fedify", "vocab"]).warn(
1785
+ "The property object's @id ({objectId}) has a different origin " +
1786
+ "than the property owner's @id ({parentObjectId}); refusing to " +
1787
+ "return the object. If you want to bypass this check and are " +
1788
+ "aware of the security implications, set the crossOrigin " +
1789
+ 'option to "trust".',
1790
+ { objectId: v.id.href, parentObjectId: this.id.href },
1791
+ );
1792
+ continue;
1793
+ }
1794
+ yield v;
1795
+ }
1796
+ }
1797
+ `;
1798
+ }
1799
+ }
1800
+ }
1801
+ async function* generateProperties(typeUri, types) {
1802
+ const type = types[typeUri];
1803
+ for (const property of type.properties) yield* generateProperty(type, property, types);
1804
+ }
1805
+
1806
+ //#endregion
1807
+ //#region src/class.ts
1808
+ /**
1809
+ * Sorts the given types topologically so that the base types come before the
1810
+ * extended types.
1811
+ * @param types The types to sort.
1812
+ * @returns The sorted type URIs.
1813
+ */
1814
+ function sortTopologically(types) {
1815
+ const sorted = [];
1816
+ const visited = /* @__PURE__ */ new Set();
1817
+ const visiting = /* @__PURE__ */ new Set();
1818
+ for (const node of Object.values(types)) visit(node);
1819
+ return sorted;
1820
+ function visit(node) {
1821
+ if (visited.has(node.uri)) return;
1822
+ if (visiting.has(node.uri)) throw new Error(`Detected cyclic inheritance: ${node.uri}`);
1823
+ visiting.add(node.uri);
1824
+ if (node.extends) visit(types[node.extends]);
1825
+ visiting.delete(node.uri);
1826
+ visited.add(node.uri);
1827
+ sorted.push(node.uri);
1828
+ }
1829
+ }
1830
+ async function* generateClass(typeUri, types) {
1831
+ const type = types[typeUri];
1832
+ yield `/** ${type.description.replaceAll("\n", "\n * ")}\n */\n`;
1833
+ if (type.extends) {
1834
+ const baseType = types[type.extends];
1835
+ yield `export class ${type.name} extends ${baseType.name} {\n`;
1836
+ } else yield `export class ${type.name} {\n`;
1837
+ if (type.extends == null) yield `
1838
+ readonly #documentLoader?: DocumentLoader;
1839
+ readonly #contextLoader?: DocumentLoader;
1840
+ readonly #tracerProvider?: TracerProvider;
1841
+ readonly #warning?: {
1842
+ category: string[];
1843
+ message: string;
1844
+ values?: Record<string, unknown>;
1845
+ };
1846
+ #cachedJsonLd?: unknown;
1847
+ readonly id: URL | null;
1848
+
1849
+ protected get _documentLoader(): DocumentLoader | undefined {
1850
+ return this.#documentLoader;
1851
+ }
1852
+
1853
+ protected get _contextLoader(): DocumentLoader | undefined {
1854
+ return this.#contextLoader;
1855
+ }
1856
+
1857
+ protected get _tracerProvider(): TracerProvider | undefined {
1858
+ return this.#tracerProvider;
1859
+ }
1860
+
1861
+ protected get _warning(): {
1862
+ category: string[];
1863
+ message: string;
1864
+ values?: Record<string, unknown>;
1865
+ } | undefined {
1866
+ return this.#warning;
1867
+ }
1868
+
1869
+ protected get _cachedJsonLd(): unknown | undefined {
1870
+ return this.#cachedJsonLd;
1871
+ }
1872
+
1873
+ protected set _cachedJsonLd(value: unknown | undefined) {
1874
+ this.#cachedJsonLd = value;
1875
+ }
1876
+ `;
1877
+ yield `
1878
+ /**
1879
+ * The type URI of {@link ${type.name}}: \`${typeUri}\`.
1880
+ */
1881
+ static ${emitOverride(typeUri, types)} get typeId(): URL {
1882
+ return new URL(${JSON.stringify(typeUri)});
1883
+ }
1884
+ `;
1885
+ for await (const code of generateFields(typeUri, types)) yield code;
1886
+ for await (const code of generateConstructor(typeUri, types)) yield code;
1887
+ for await (const code of generateCloner(typeUri, types)) yield code;
1888
+ for await (const code of generateProperties(typeUri, types)) yield code;
1889
+ for await (const code of generateEncoder(typeUri, types)) yield code;
1890
+ for await (const code of generateDecoder(typeUri, types)) yield code;
1891
+ for await (const code of generateInspector(typeUri, types)) yield code;
1892
+ yield "}\n\n";
1893
+ }
1894
+ /**
1895
+ * Generates the TypeScript classes from the given types.
1896
+ * @param types The types to generate classes from.
1897
+ * @returns The source code of the generated classes.
1898
+ */
1899
+ async function* generateClasses(types) {
1900
+ yield "// deno-lint-ignore-file ban-unused-ignore prefer-const\n";
1901
+ yield "// @ts-ignore TS7016\n";
1902
+ yield "import jsonld from \"jsonld\";\n";
1903
+ yield "import { getLogger } from \"@logtape/logtape\";\n";
1904
+ yield `import { type Span, SpanStatusCode, type TracerProvider, trace }
1905
+ from "@opentelemetry/api";\n`;
1906
+ yield `import {
1907
+ decodeMultibase,
1908
+ type DocumentLoader,
1909
+ encodeMultibase,
1910
+ exportMultibaseKey,
1911
+ exportSpki,
1912
+ getDocumentLoader,
1913
+ importMultibaseKey,
1914
+ importPem,
1915
+ LanguageString,
1916
+ type RemoteDocument,
1917
+ } from "@fedify/vocab-runtime";\n`;
1918
+ yield "\n\n";
1919
+ const sorted = sortTopologically(types);
1920
+ for (const typeUri of sorted) for await (const code of generateClass(typeUri, types)) yield code;
1921
+ }
1922
+
1923
+ //#endregion
1924
+ //#region src/generate.ts
1925
+ async function generateVocab(schemaDir, generatedPath) {
1926
+ const types = await loadSchemaFiles(schemaDir);
1927
+ const encoder = new TextEncoder();
1928
+ const file = await (0, node_fs_promises.open)(generatedPath, "w");
1929
+ const writer = file.createWriteStream();
1930
+ for await (const code of generateClasses(types)) writer.write(encoder.encode(code));
1931
+ await new Promise((resolve, reject) => {
1932
+ writer.once("finish", () => file.close().then(resolve, reject));
1933
+ writer.once("error", reject);
1934
+ writer.end();
1935
+ });
1936
+ }
1937
+
1938
+ //#endregion
1939
+ exports.areAllScalarTypes = areAllScalarTypes;
1940
+ exports.generateVocab = generateVocab;
1941
+ exports.loadSchemaFiles = loadSchemaFiles;