@fedify/vocab 2.5.0-dev.2513 → 2.5.0-dev.2532
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.json +1 -1
- package/dist/mod.cjs +13426 -2215
- package/dist/mod.d.cts +9001 -782
- package/dist/mod.d.ts +9001 -782
- package/dist/mod.js +13427 -2216
- package/dist-tests/{actor-DIiC1MSh.mjs → actor-Dw7TDsLQ.mjs} +2 -2
- package/dist-tests/actor.test.mjs +2 -2
- package/dist-tests/deep-clone.test.mjs +292 -0
- package/dist-tests/gateway.test.mjs +71 -4
- package/dist-tests/license.test.mjs +2 -2
- package/dist-tests/{lookup-B0Rs8ySI.mjs → lookup-DO37fRpY.mjs} +2 -2
- package/dist-tests/lookup.test.mjs +2 -2
- package/dist-tests/portable-lookup.test.mjs +3 -3
- package/dist-tests/signed-representation.test.mjs +15 -1
- package/dist-tests/sparse-arrays.test.mjs +459 -0
- package/dist-tests/{src-DblV5ccz.mjs → src-BU0YVUfA.mjs} +3 -3
- package/dist-tests/translation.test.mjs +2 -2
- package/dist-tests/type.test.mjs +1 -1
- package/dist-tests/{vocab-Dwwwbub3.mjs → vocab-HbQozX9F.mjs} +13427 -2216
- package/dist-tests/vocab.test.mjs +2 -2
- package/package.json +4 -4
- package/src/deep-clone.test.ts +347 -0
- package/src/gateway.test.ts +81 -5
- package/src/signed-representation.test.ts +21 -0
- package/src/sparse-arrays.test.ts +507 -0
- package/src/vocab.bench.ts +63 -1
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
globalThis.addEventListener = () => {};
|
|
3
|
+
import { A as Note, q as Translation, u as Create } from "./vocab-HbQozX9F.mjs";
|
|
4
|
+
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
5
|
+
import { deepStrictEqual, notStrictEqual, ok, strictEqual, throws } from "node:assert/strict";
|
|
6
|
+
//#region src/sparse-arrays.test.ts
|
|
7
|
+
const sparseLength = 8192;
|
|
8
|
+
test("sparse scalar copies preserve own indices and omit metadata", () => {
|
|
9
|
+
const names = new Array(sparseLength);
|
|
10
|
+
globalThis.Object.defineProperty(names, 2, { value: "hidden" });
|
|
11
|
+
names[6e3] = "visible";
|
|
12
|
+
globalThis.Object.assign(names, {
|
|
13
|
+
"01": "metadata",
|
|
14
|
+
"-1": "metadata",
|
|
15
|
+
"4294967295": "metadata",
|
|
16
|
+
extra: "metadata",
|
|
17
|
+
[Symbol("metadata")]: "metadata"
|
|
18
|
+
});
|
|
19
|
+
const before = globalThis.Object.getOwnPropertyDescriptors(names);
|
|
20
|
+
const source = new Note({ names });
|
|
21
|
+
for (const copy of [
|
|
22
|
+
source,
|
|
23
|
+
source.clone(),
|
|
24
|
+
source.deepClone()
|
|
25
|
+
]) {
|
|
26
|
+
strictEqual(copy.names.length, sparseLength);
|
|
27
|
+
deepStrictEqual(Reflect.ownKeys(copy.names), [
|
|
28
|
+
"2",
|
|
29
|
+
"6000",
|
|
30
|
+
"length"
|
|
31
|
+
]);
|
|
32
|
+
deepStrictEqual(globalThis.Object.getOwnPropertyDescriptor(copy.names, 2), {
|
|
33
|
+
value: "hidden",
|
|
34
|
+
writable: true,
|
|
35
|
+
enumerable: true,
|
|
36
|
+
configurable: true
|
|
37
|
+
});
|
|
38
|
+
strictEqual(copy.names[6e3], "visible");
|
|
39
|
+
strictEqual(0 in copy.names, false);
|
|
40
|
+
strictEqual(sparseLength - 1 in copy.names, false);
|
|
41
|
+
notStrictEqual(copy.names, names);
|
|
42
|
+
}
|
|
43
|
+
deepStrictEqual(globalThis.Object.getOwnPropertyDescriptors(names), before);
|
|
44
|
+
});
|
|
45
|
+
test("sparse copies preserve empty and trailing-hole arrays", () => {
|
|
46
|
+
for (const index of [
|
|
47
|
+
void 0,
|
|
48
|
+
0,
|
|
49
|
+
sparseLength - 1
|
|
50
|
+
]) {
|
|
51
|
+
const names = new Array(sparseLength);
|
|
52
|
+
if (index != null) names[index] = "kept";
|
|
53
|
+
const source = new Note({ names });
|
|
54
|
+
for (const copy of [
|
|
55
|
+
source,
|
|
56
|
+
source.clone(),
|
|
57
|
+
source.deepClone()
|
|
58
|
+
]) {
|
|
59
|
+
strictEqual(copy.names.length, sparseLength);
|
|
60
|
+
deepStrictEqual(globalThis.Object.getOwnPropertyNames(copy.names), index == null ? ["length"] : [String(index), "length"]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
test("sparse inputs distinguish holes from explicit undefined", () => {
|
|
65
|
+
const names = new Array(sparseLength);
|
|
66
|
+
new Note({ names });
|
|
67
|
+
globalThis.Object.defineProperty(names, 100, { value: void 0 });
|
|
68
|
+
throws(() => new Note({ names }), TypeError);
|
|
69
|
+
throws(() => new Note({}).clone({ names }), TypeError);
|
|
70
|
+
});
|
|
71
|
+
test("sparse URL copies preserve aliases and isolate mutable leaves", () => {
|
|
72
|
+
const url = new URL("https://example.com/license");
|
|
73
|
+
const licenses = new Array(sparseLength);
|
|
74
|
+
licenses[0] = licenses[6e3] = url;
|
|
75
|
+
globalThis.Object.freeze(licenses);
|
|
76
|
+
const source = new Note({ licenses });
|
|
77
|
+
const shallow = source.clone();
|
|
78
|
+
const deep = source.deepClone();
|
|
79
|
+
const replaced = new Note({}).deepClone({ licenses });
|
|
80
|
+
for (const copy of [
|
|
81
|
+
source,
|
|
82
|
+
shallow,
|
|
83
|
+
deep,
|
|
84
|
+
replaced
|
|
85
|
+
]) {
|
|
86
|
+
strictEqual(copy.licenses.length, sparseLength);
|
|
87
|
+
deepStrictEqual(globalThis.Object.keys(copy.licenses), ["0", "6000"]);
|
|
88
|
+
notStrictEqual(copy.licenses, licenses);
|
|
89
|
+
strictEqual(copy.licenses[0], copy.licenses[6e3]);
|
|
90
|
+
copy.licenses[1] = new URL("https://example.com/copy-only");
|
|
91
|
+
}
|
|
92
|
+
strictEqual(shallow.licenses[0], url);
|
|
93
|
+
notStrictEqual(deep.licenses[0], url);
|
|
94
|
+
notStrictEqual(replaced.licenses[0], url);
|
|
95
|
+
deep.licenses[0].pathname = "/deep-only";
|
|
96
|
+
strictEqual(url.pathname, "/license");
|
|
97
|
+
strictEqual(replaced.licenses[0].pathname, "/license");
|
|
98
|
+
strictEqual(1 in licenses, false);
|
|
99
|
+
});
|
|
100
|
+
test("sparse non-entity arrays deep-copy aliases and nested URLs", () => {
|
|
101
|
+
const url = new URL("https://example.com/original");
|
|
102
|
+
const translation = new Translation({
|
|
103
|
+
original: url,
|
|
104
|
+
basis: url
|
|
105
|
+
});
|
|
106
|
+
const translations = new Array(sparseLength);
|
|
107
|
+
globalThis.Object.defineProperty(translations, 0, { value: translation });
|
|
108
|
+
translations[6e3] = translation;
|
|
109
|
+
const source = new Note({ translations });
|
|
110
|
+
const shallow = source.clone();
|
|
111
|
+
const copy = source.deepClone();
|
|
112
|
+
const replacement = source.deepClone({ translations });
|
|
113
|
+
strictEqual(shallow.translations[0], translation);
|
|
114
|
+
for (const deep of [copy, replacement]) {
|
|
115
|
+
strictEqual(deep.translations.length, sparseLength);
|
|
116
|
+
deepStrictEqual(globalThis.Object.keys(deep.translations), ["0", "6000"]);
|
|
117
|
+
strictEqual(deep.translations[0], deep.translations[6e3]);
|
|
118
|
+
notStrictEqual(deep.translations[0], translation);
|
|
119
|
+
strictEqual(deep.translations[0].original, deep.translations[0].basis);
|
|
120
|
+
notStrictEqual(deep.translations[0].original, url);
|
|
121
|
+
}
|
|
122
|
+
copy.translations[0].original.pathname = "/copy-only";
|
|
123
|
+
strictEqual(url.pathname, "/original");
|
|
124
|
+
strictEqual(replacement.translations[0].original.pathname, "/original");
|
|
125
|
+
copy.translations.length = 1;
|
|
126
|
+
strictEqual(source.translations.length, sparseLength);
|
|
127
|
+
});
|
|
128
|
+
test("sparse object arrays copy embedded graphs without fetching holes", async () => {
|
|
129
|
+
const child = new Note({ content: "child" });
|
|
130
|
+
const objects = new Array(sparseLength);
|
|
131
|
+
objects[0] = child;
|
|
132
|
+
objects[6e3] = child;
|
|
133
|
+
const source = new Create({
|
|
134
|
+
objects,
|
|
135
|
+
attachments: [child]
|
|
136
|
+
});
|
|
137
|
+
const shallow = source.clone();
|
|
138
|
+
const copy = source.deepClone();
|
|
139
|
+
const copiedChild = await copy.getObject();
|
|
140
|
+
ok(copiedChild instanceof Note);
|
|
141
|
+
notStrictEqual(copiedChild, child);
|
|
142
|
+
strictEqual(await shallow.getObject(), child);
|
|
143
|
+
strictEqual((await Array.fromAsync(copy.getAttachments()))[0], copiedChild);
|
|
144
|
+
const iterator = copy.getObjects()[Symbol.asyncIterator]();
|
|
145
|
+
strictEqual((await iterator.next()).value, copiedChild);
|
|
146
|
+
strictEqual((await iterator.next()).value, void 0);
|
|
147
|
+
await iterator.return?.();
|
|
148
|
+
});
|
|
149
|
+
test("exposed scalar arrays recheck accessors, prototypes, and freezing", () => {
|
|
150
|
+
const source = new Note({ names: new Array(sparseLength) });
|
|
151
|
+
let reads = 0;
|
|
152
|
+
globalThis.Object.defineProperty(source.names, 2, {
|
|
153
|
+
get() {
|
|
154
|
+
reads++;
|
|
155
|
+
return "getter";
|
|
156
|
+
},
|
|
157
|
+
configurable: true
|
|
158
|
+
});
|
|
159
|
+
strictEqual(source.clone().names[2], "getter");
|
|
160
|
+
strictEqual(reads, 1);
|
|
161
|
+
globalThis.Object.defineProperty(source.names, 2, {
|
|
162
|
+
value: "own",
|
|
163
|
+
writable: true,
|
|
164
|
+
configurable: true
|
|
165
|
+
});
|
|
166
|
+
const prototype = globalThis.Object.create(Array.prototype, { 1: {
|
|
167
|
+
get: () => "inherited",
|
|
168
|
+
configurable: true
|
|
169
|
+
} });
|
|
170
|
+
globalThis.Object.setPrototypeOf(source.names, prototype);
|
|
171
|
+
const inheritedCopy = source.clone();
|
|
172
|
+
strictEqual(inheritedCopy.names[1], "inherited");
|
|
173
|
+
strictEqual(globalThis.Object.hasOwn(inheritedCopy.names, 1), true);
|
|
174
|
+
globalThis.Object.setPrototypeOf(source.names, Array.prototype);
|
|
175
|
+
globalThis.Object.freeze(source.names);
|
|
176
|
+
const frozenCopy = source.deepClone();
|
|
177
|
+
frozenCopy.names[2] = "changed";
|
|
178
|
+
strictEqual(source.names[2], "own");
|
|
179
|
+
});
|
|
180
|
+
test("source shallow copies retain scalar getter mutations", () => {
|
|
181
|
+
const source = new Note({ names: new Array(sparseLength) });
|
|
182
|
+
globalThis.Object.defineProperty(source.names, 2, { get: () => 123 });
|
|
183
|
+
strictEqual(source.clone().names[2], 123);
|
|
184
|
+
strictEqual(source.deepClone().names[2], 123);
|
|
185
|
+
throws(() => new Note({ names: source.names }), TypeError);
|
|
186
|
+
});
|
|
187
|
+
test("array subclasses, species, and own methods retain native fallback", () => {
|
|
188
|
+
class Names extends Array {
|
|
189
|
+
static get [Symbol.species]() {
|
|
190
|
+
return Array;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const names = new Names(sparseLength);
|
|
194
|
+
names[2] = "kept";
|
|
195
|
+
const source = new Note({ names });
|
|
196
|
+
strictEqual(globalThis.Object.getPrototypeOf(source.names), Array.prototype);
|
|
197
|
+
strictEqual(source.names[2], "kept");
|
|
198
|
+
strictEqual(source.names.length, sparseLength);
|
|
199
|
+
let everyCalls = 0;
|
|
200
|
+
let sliceCalls = 0;
|
|
201
|
+
const custom = new Array(sparseLength);
|
|
202
|
+
custom[2] = "kept";
|
|
203
|
+
globalThis.Object.defineProperty(custom, "every", {
|
|
204
|
+
value(callback, thisArg) {
|
|
205
|
+
everyCalls++;
|
|
206
|
+
return Array.prototype.every.call(this, callback, thisArg);
|
|
207
|
+
},
|
|
208
|
+
configurable: true,
|
|
209
|
+
writable: true
|
|
210
|
+
});
|
|
211
|
+
custom.slice = function(start, end) {
|
|
212
|
+
sliceCalls++;
|
|
213
|
+
return Array.prototype.slice.call(this, start, end);
|
|
214
|
+
};
|
|
215
|
+
strictEqual(new Note({ names: custom }).names[2], "kept");
|
|
216
|
+
strictEqual(everyCalls, 1);
|
|
217
|
+
strictEqual(sliceCalls, 1);
|
|
218
|
+
});
|
|
219
|
+
test("sparse validation rejects invalid keys injected by element proxies", () => {
|
|
220
|
+
for (const replace of [false, true]) {
|
|
221
|
+
const licenses = new Array(sparseLength);
|
|
222
|
+
licenses[0] = new Proxy(new URL("https://example.com/license"), { getPrototypeOf(target) {
|
|
223
|
+
licenses[6e3] = 123;
|
|
224
|
+
return Reflect.getPrototypeOf(target);
|
|
225
|
+
} });
|
|
226
|
+
throws(() => replace ? new Note({}).clone({ licenses }) : new Note({ licenses }), TypeError);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
test("sparse validation rejects keys injected by Symbol.hasInstance", () => {
|
|
230
|
+
const translations = new Array(sparseLength);
|
|
231
|
+
translations[0] = new Translation({});
|
|
232
|
+
const previous = globalThis.Object.getOwnPropertyDescriptor(Translation, Symbol.hasInstance);
|
|
233
|
+
globalThis.Object.defineProperty(Translation, Symbol.hasInstance, {
|
|
234
|
+
configurable: true,
|
|
235
|
+
value(value) {
|
|
236
|
+
translations[6e3] = 123;
|
|
237
|
+
return Function.prototype[Symbol.hasInstance].call(Translation, value);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
try {
|
|
241
|
+
throws(() => new Note({ translations }), TypeError);
|
|
242
|
+
} finally {
|
|
243
|
+
if (previous == null) Reflect.deleteProperty(Translation, Symbol.hasInstance);
|
|
244
|
+
else globalThis.Object.defineProperty(Translation, Symbol.hasInstance, previous);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
test("sparse validation rechecks inputs that switch to native copying", () => {
|
|
248
|
+
for (const transition of ["density", "accessor"]) {
|
|
249
|
+
const licenses = new Array(sparseLength);
|
|
250
|
+
const url = new URL("https://example.com/license");
|
|
251
|
+
licenses[0] = new Proxy(url, { getPrototypeOf(target) {
|
|
252
|
+
if (transition === "density") {
|
|
253
|
+
licenses.fill(url, 1, 4097);
|
|
254
|
+
licenses[6e3] = 123;
|
|
255
|
+
} else globalThis.Object.defineProperty(licenses, 6e3, {
|
|
256
|
+
get: () => 123,
|
|
257
|
+
configurable: true
|
|
258
|
+
});
|
|
259
|
+
return Reflect.getPrototypeOf(target);
|
|
260
|
+
} });
|
|
261
|
+
throws(() => new Note({ licenses }), TypeError);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
test("sparse copying omits invalid keys injected after its snapshot", () => {
|
|
265
|
+
const licenses = new Array(sparseLength);
|
|
266
|
+
let checks = 0;
|
|
267
|
+
licenses[0] = new Proxy(new URL("https://example.com/license"), { getPrototypeOf(target) {
|
|
268
|
+
if (++checks === 2) licenses[6e3] = 123;
|
|
269
|
+
return Reflect.getPrototypeOf(target);
|
|
270
|
+
} });
|
|
271
|
+
const source = new Note({ licenses });
|
|
272
|
+
strictEqual(licenses[6e3], 123);
|
|
273
|
+
strictEqual(6e3 in source.licenses, false);
|
|
274
|
+
strictEqual(source.licenses[0], licenses[0]);
|
|
275
|
+
});
|
|
276
|
+
test("sparse validation propagates element reflection errors", () => {
|
|
277
|
+
const failure = /* @__PURE__ */ new Error("element reflection failed");
|
|
278
|
+
const licenses = new Array(sparseLength);
|
|
279
|
+
licenses[0] = new Proxy(new URL("https://example.com/license"), { getPrototypeOf() {
|
|
280
|
+
throw failure;
|
|
281
|
+
} });
|
|
282
|
+
throws(() => new Note({ licenses }), (error) => error === failure);
|
|
283
|
+
});
|
|
284
|
+
test("sparse deep traversal snapshots keys and reads later current values", () => {
|
|
285
|
+
let destination;
|
|
286
|
+
const added = new Translation({ original: new URL("https://example.com/new") });
|
|
287
|
+
const updated = new Translation({ original: new URL("https://example.com/updated") });
|
|
288
|
+
class CapturesCopy extends Note {
|
|
289
|
+
clone() {
|
|
290
|
+
return destination = super.clone();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
class ChangesLaterEntries extends Translation {
|
|
294
|
+
clone() {
|
|
295
|
+
destination.translations[100] = added;
|
|
296
|
+
delete destination.translations[6e3];
|
|
297
|
+
destination.translations[7e3] = updated;
|
|
298
|
+
return super.clone();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const translations = new Array(sparseLength);
|
|
302
|
+
translations[0] = new ChangesLaterEntries({});
|
|
303
|
+
translations[6e3] = new Translation({});
|
|
304
|
+
translations[7e3] = new Translation({});
|
|
305
|
+
const source = new CapturesCopy({ translations });
|
|
306
|
+
const copy = source.deepClone();
|
|
307
|
+
strictEqual(copy.translations.length, sparseLength);
|
|
308
|
+
strictEqual(copy.translations[100], added);
|
|
309
|
+
strictEqual(6e3 in copy.translations, false);
|
|
310
|
+
notStrictEqual(copy.translations[7e3], updated);
|
|
311
|
+
notStrictEqual(copy.translations[7e3].original, updated.original);
|
|
312
|
+
strictEqual(copy.translations[7e3].original.href, updated.original.href);
|
|
313
|
+
strictEqual(100 in source.translations, false);
|
|
314
|
+
strictEqual(source.translations[6e3], translations[6e3]);
|
|
315
|
+
strictEqual(source.translations[7e3], translations[7e3]);
|
|
316
|
+
});
|
|
317
|
+
test("plural getters establish trust for the array actually stored", async () => {
|
|
318
|
+
let reads = 0;
|
|
319
|
+
const first = new Array(2);
|
|
320
|
+
const stored = new Array(3);
|
|
321
|
+
stored[2] = new Note({ content: "stored" });
|
|
322
|
+
const source = new Create({ get objects() {
|
|
323
|
+
reads++;
|
|
324
|
+
return reads < 4 ? first : stored;
|
|
325
|
+
} });
|
|
326
|
+
strictEqual(reads, 4);
|
|
327
|
+
for (const copy of [
|
|
328
|
+
source,
|
|
329
|
+
source.clone(),
|
|
330
|
+
source.deepClone()
|
|
331
|
+
]) {
|
|
332
|
+
const values = await Array.fromAsync(copy.getObjects());
|
|
333
|
+
strictEqual(values.length, 3);
|
|
334
|
+
strictEqual(values[0], void 0);
|
|
335
|
+
strictEqual(values[1], void 0);
|
|
336
|
+
strictEqual(values[2].content, "stored");
|
|
337
|
+
}
|
|
338
|
+
strictEqual(reads, 4);
|
|
339
|
+
});
|
|
340
|
+
test("small sparse object replacements retain trusted holes", async () => {
|
|
341
|
+
const child = new Note({ content: "trusted" });
|
|
342
|
+
const objects = new Array(3);
|
|
343
|
+
objects[1] = child;
|
|
344
|
+
const source = new Create({ objects });
|
|
345
|
+
for (const copy of [
|
|
346
|
+
source,
|
|
347
|
+
source.clone(),
|
|
348
|
+
source.clone({ objects }),
|
|
349
|
+
source.deepClone({ objects })
|
|
350
|
+
]) deepStrictEqual((await Array.fromAsync(copy.getObjects())).map((value) => value?.content), [
|
|
351
|
+
void 0,
|
|
352
|
+
"trusted",
|
|
353
|
+
void 0
|
|
354
|
+
]);
|
|
355
|
+
deepStrictEqual(await Array.fromAsync(source.clone({ object: child }).getObjects()), [child]);
|
|
356
|
+
deepStrictEqual(await Array.fromAsync(source.clone({ objects: [] }).getObjects()), []);
|
|
357
|
+
});
|
|
358
|
+
test("decoded and warmed object trust stays local across clones", async () => {
|
|
359
|
+
let fetches = 0;
|
|
360
|
+
const original = await Create.fromJsonLd({
|
|
361
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
362
|
+
id: "https://a.example/create",
|
|
363
|
+
type: "Create",
|
|
364
|
+
object: {
|
|
365
|
+
id: "https://b.example/note",
|
|
366
|
+
type: "Note",
|
|
367
|
+
content: "embedded"
|
|
368
|
+
}
|
|
369
|
+
}, { contextLoader: mockDocumentLoader });
|
|
370
|
+
const documentLoader = async (url) => {
|
|
371
|
+
fetches++;
|
|
372
|
+
return {
|
|
373
|
+
contextUrl: null,
|
|
374
|
+
documentUrl: url,
|
|
375
|
+
document: {
|
|
376
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
377
|
+
id: url,
|
|
378
|
+
type: "Note",
|
|
379
|
+
content: "fetched"
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
};
|
|
383
|
+
const options = {
|
|
384
|
+
documentLoader,
|
|
385
|
+
contextLoader: mockDocumentLoader
|
|
386
|
+
};
|
|
387
|
+
const cold = original.clone();
|
|
388
|
+
const fetched = await original.getObject(options);
|
|
389
|
+
strictEqual(fetched?.content, "fetched");
|
|
390
|
+
const warmed = original.clone();
|
|
391
|
+
strictEqual(await warmed.getObject(options), fetched);
|
|
392
|
+
strictEqual(fetches, 1);
|
|
393
|
+
strictEqual((await cold.getObject(options))?.content, "fetched");
|
|
394
|
+
strictEqual(fetches, 2);
|
|
395
|
+
const replacement = new Note({
|
|
396
|
+
id: new URL("https://c.example/note"),
|
|
397
|
+
content: "replacement"
|
|
398
|
+
});
|
|
399
|
+
strictEqual(await warmed.clone({ objects: [replacement] }).getObject(options), replacement);
|
|
400
|
+
strictEqual(fetches, 2);
|
|
401
|
+
});
|
|
402
|
+
for (const defaultKind of ["singular", "plural"]) test(`clone trust replaces ${defaultKind} subclass constructor defaults`, async () => {
|
|
403
|
+
let enableDefaults = false;
|
|
404
|
+
const defaultObject = new Note({
|
|
405
|
+
id: new URL("https://c.example/default"),
|
|
406
|
+
content: "constructor default"
|
|
407
|
+
});
|
|
408
|
+
class StatefulCreate extends Create {
|
|
409
|
+
constructor(values, options = {}) {
|
|
410
|
+
const defaults = enableDefaults && values.object == null && values.objects == null ? defaultKind === "singular" ? { object: defaultObject } : { objects: [defaultObject] } : {};
|
|
411
|
+
super({
|
|
412
|
+
...defaults,
|
|
413
|
+
...values
|
|
414
|
+
}, options);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const original = await StatefulCreate.fromJsonLd({
|
|
418
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
419
|
+
id: "https://a.example/create",
|
|
420
|
+
type: "Create",
|
|
421
|
+
object: {
|
|
422
|
+
id: "https://b.example/note",
|
|
423
|
+
type: "Note",
|
|
424
|
+
content: "untrusted embedded"
|
|
425
|
+
}
|
|
426
|
+
}, { contextLoader: mockDocumentLoader });
|
|
427
|
+
ok(original instanceof StatefulCreate);
|
|
428
|
+
enableDefaults = true;
|
|
429
|
+
strictEqual(await new StatefulCreate({}).getObject(), defaultObject);
|
|
430
|
+
const copies = [
|
|
431
|
+
original,
|
|
432
|
+
original.clone(),
|
|
433
|
+
original.deepClone()
|
|
434
|
+
];
|
|
435
|
+
let fetches = 0;
|
|
436
|
+
const documentLoader = async (url) => {
|
|
437
|
+
fetches++;
|
|
438
|
+
return {
|
|
439
|
+
contextUrl: null,
|
|
440
|
+
documentUrl: url,
|
|
441
|
+
document: {
|
|
442
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
443
|
+
id: url,
|
|
444
|
+
type: "Note",
|
|
445
|
+
content: "fetched"
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
for (const copy of copies) {
|
|
450
|
+
ok(copy instanceof StatefulCreate);
|
|
451
|
+
strictEqual((await copy.getObject({
|
|
452
|
+
documentLoader,
|
|
453
|
+
contextLoader: mockDocumentLoader
|
|
454
|
+
}))?.content, "fetched");
|
|
455
|
+
}
|
|
456
|
+
strictEqual(fetches, 3);
|
|
457
|
+
});
|
|
458
|
+
//#endregion
|
|
459
|
+
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
globalThis.addEventListener = () => {};
|
|
3
|
-
import "./actor-
|
|
4
|
-
import "./vocab-
|
|
5
|
-
import "./lookup-
|
|
3
|
+
import "./actor-Dw7TDsLQ.mjs";
|
|
4
|
+
import "./vocab-HbQozX9F.mjs";
|
|
5
|
+
import "./lookup-DO37fRpY.mjs";
|
|
6
6
|
import { LanguageString as LanguageString$1 } from "@fedify/vocab-runtime";
|
|
7
7
|
new URL("https://www.w3.org/ns/activitystreams#Public");
|
|
8
8
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
globalThis.addEventListener = () => {};
|
|
3
|
-
import { A as
|
|
4
|
-
import { t as LanguageString$1 } from "./src-
|
|
3
|
+
import { A as Note, D as Link, F as Organization, I as Person, J as Update, R as PropertyValue, W as Service, a as Application, j as Object$1, o as Article, q as Translation, s as Collection, u as Create, x as Group } from "./vocab-HbQozX9F.mjs";
|
|
4
|
+
import { t as LanguageString$1 } from "./src-BU0YVUfA.mjs";
|
|
5
5
|
import { test } from "@fedify/fixture";
|
|
6
6
|
import { deepStrictEqual, ok, rejects } from "node:assert/strict";
|
|
7
7
|
import { getDocumentLoader, preloadedContexts } from "@fedify/vocab-runtime";
|
package/dist-tests/type.test.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
globalThis.addEventListener = () => {};
|
|
3
3
|
import { t as getTypeId } from "./type-BMdjm4Eg.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { D as Link, I as Person, X as getEntityTypeById, Z as isEntityType } from "./vocab-HbQozX9F.mjs";
|
|
5
5
|
import { test } from "@fedify/fixture";
|
|
6
6
|
import { deepStrictEqual } from "node:assert/strict";
|
|
7
7
|
//#region src/type.test.ts
|