@fedify/vocab-runtime 2.0.31-dev.2306 → 2.0.31-dev.2310
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 +2 -2
- package/dist/mod.cjs +50 -3
- package/dist/mod.d.cts +28 -2
- package/dist/mod.d.ts +28 -2
- package/dist/mod.js +50 -4
- package/dist/tests/{body-CGeu_wlY.mjs → body-DhJNq-PQ.mjs} +1 -1
- package/dist/tests/{body-KqP1lgFZ.cjs → body-N4Kc5pwz.cjs} +1 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/docloader.test.cjs +41 -44
- package/dist/tests/docloader.test.mjs +32 -35
- package/dist/tests/langstr.test.cjs +12 -2
- package/dist/tests/langstr.test.mjs +13 -3
- package/dist/tests/langtag-Bm8oKhIO.cjs +50 -0
- package/dist/tests/langtag-QZZgy903.mjs +45 -0
- package/dist/tests/langtag.test.cjs +46 -0
- package/dist/tests/langtag.test.d.cts +1 -0
- package/dist/tests/langtag.test.d.mts +1 -0
- package/dist/tests/langtag.test.mjs +46 -0
- package/dist/tests/multibase/multibase.test.cjs +7 -7
- package/dist/tests/multibase/multibase.test.mjs +5 -5
- package/dist/tests/{request-75RoXeN4.cjs → request-CFKB-Yqd.cjs} +1 -1
- package/dist/tests/{request-JVGlYdPG.mjs → request-DDAEJJqw.mjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/package.json +6 -3
- package/scripts/test-bun.mjs +18 -0
- package/src/docloader.test.ts +75 -68
- package/src/langstr.test.ts +18 -1
- package/src/langstr.ts +6 -2
- package/src/langtag.test.ts +53 -0
- package/src/langtag.ts +76 -0
- package/src/mod.ts +1 -0
- package/src/multibase/multibase.test.ts +5 -5
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-
|
|
2
|
-
import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-
|
|
1
|
+
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-DDAEJJqw.mjs";
|
|
2
|
+
import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-DhJNq-PQ.mjs";
|
|
3
3
|
import { t as HttpHeaderLink } from "./link-NUUWCdnK.mjs";
|
|
4
4
|
import { o as validatePublicUrl, t as UrlError } from "./url-DzlMS01z.mjs";
|
|
5
|
-
import { test } from "node:test";
|
|
6
5
|
import { gzipSync } from "node:zlib";
|
|
7
6
|
import { configure, getLogger, reset } from "@logtape/logtape";
|
|
8
7
|
import { deepStrictEqual, ok, rejects } from "node:assert";
|
|
9
8
|
import dns from "node:dns/promises";
|
|
9
|
+
import { test } from "@fedify/fixture";
|
|
10
10
|
import { createServer } from "node:http";
|
|
11
11
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
12
12
|
import jsonld from "jsonld/dist/jsonld.esm.js";
|
|
@@ -5941,7 +5941,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
5941
5941
|
name: "Fetched object",
|
|
5942
5942
|
type: "Object"
|
|
5943
5943
|
} });
|
|
5944
|
-
await t.
|
|
5944
|
+
await t.step("ok", async () => {
|
|
5945
5945
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/object"), {
|
|
5946
5946
|
contextUrl: null,
|
|
5947
5947
|
documentUrl: "https://example.com/object",
|
|
@@ -5984,7 +5984,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
5984
5984
|
Link: "<https://example.com/object>; rel=\"alternate\"; type=\"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"\""
|
|
5985
5985
|
}
|
|
5986
5986
|
});
|
|
5987
|
-
await t.
|
|
5987
|
+
await t.step("Link header", async () => {
|
|
5988
5988
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/link-ctx"), {
|
|
5989
5989
|
contextUrl: "https://www.w3.org/ns/activitystreams",
|
|
5990
5990
|
documentUrl: "https://example.com/link-ctx",
|
|
@@ -6005,7 +6005,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6005
6005
|
}
|
|
6006
6006
|
});
|
|
6007
6007
|
});
|
|
6008
|
-
await t.
|
|
6008
|
+
await t.step("Link header relative url", async () => {
|
|
6009
6009
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/link-ctx"), {
|
|
6010
6010
|
contextUrl: "https://www.w3.org/ns/activitystreams",
|
|
6011
6011
|
documentUrl: "https://example.com/link-ctx",
|
|
@@ -6026,7 +6026,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6026
6026
|
}
|
|
6027
6027
|
});
|
|
6028
6028
|
});
|
|
6029
|
-
await t.
|
|
6029
|
+
await t.step("wrong Link header syntax", async () => {
|
|
6030
6030
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/obj-w-wrong-link"), {
|
|
6031
6031
|
contextUrl: null,
|
|
6032
6032
|
documentUrl: "https://example.com/obj-w-wrong-link",
|
|
@@ -6050,7 +6050,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6050
6050
|
</html>`,
|
|
6051
6051
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
6052
6052
|
});
|
|
6053
|
-
await t.
|
|
6053
|
+
await t.step("HTML <link>", async () => {
|
|
6054
6054
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/html-link"), {
|
|
6055
6055
|
contextUrl: null,
|
|
6056
6056
|
documentUrl: "https://example.com/object",
|
|
@@ -6074,7 +6074,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6074
6074
|
</html>`,
|
|
6075
6075
|
headers: { "Content-Type": "application/xhtml+xml; charset=utf-8" }
|
|
6076
6076
|
});
|
|
6077
|
-
await t.
|
|
6077
|
+
await t.step("XHTML <link>", async () => {
|
|
6078
6078
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/xhtml-link"), {
|
|
6079
6079
|
contextUrl: null,
|
|
6080
6080
|
documentUrl: "https://example.com/object",
|
|
@@ -6100,7 +6100,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6100
6100
|
</html>`,
|
|
6101
6101
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
6102
6102
|
});
|
|
6103
|
-
await t.
|
|
6103
|
+
await t.step("HTML <a>", async () => {
|
|
6104
6104
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/html-a"), {
|
|
6105
6105
|
contextUrl: null,
|
|
6106
6106
|
documentUrl: "https://example.com/object",
|
|
@@ -6121,7 +6121,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6121
6121
|
},
|
|
6122
6122
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
6123
6123
|
});
|
|
6124
|
-
await t.
|
|
6124
|
+
await t.step("Wrong Content-Type", async () => {
|
|
6125
6125
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/wrong-content-type"), {
|
|
6126
6126
|
contextUrl: null,
|
|
6127
6127
|
documentUrl: "https://example.com/wrong-content-type",
|
|
@@ -6134,10 +6134,10 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6134
6134
|
});
|
|
6135
6135
|
});
|
|
6136
6136
|
esm_default.get("https://example.com/404", { status: 404 });
|
|
6137
|
-
await t.
|
|
6137
|
+
await t.step("not ok", async () => {
|
|
6138
6138
|
await rejects(() => fetchDocumentLoader("https://example.com/404"), FetchError, "HTTP 404: https://example.com/404");
|
|
6139
6139
|
});
|
|
6140
|
-
await t.
|
|
6140
|
+
await t.step("preloaded contexts", async () => {
|
|
6141
6141
|
for (const [url, document] of Object.entries(preloadedContexts)) deepStrictEqual(await fetchDocumentLoader(url), {
|
|
6142
6142
|
contextUrl: null,
|
|
6143
6143
|
documentUrl: url,
|
|
@@ -6145,7 +6145,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6145
6145
|
});
|
|
6146
6146
|
});
|
|
6147
6147
|
esm_default.get("https://www.w3.org/ns/cid/v1", { status: 503 });
|
|
6148
|
-
await t.
|
|
6148
|
+
await t.step("preloaded CID v1 context", async () => {
|
|
6149
6149
|
const url = "https://www.w3.org/ns/cid/v1";
|
|
6150
6150
|
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
6151
6151
|
contextUrl: null,
|
|
@@ -6153,7 +6153,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6153
6153
|
document: cid_v1_default
|
|
6154
6154
|
});
|
|
6155
6155
|
});
|
|
6156
|
-
await t.
|
|
6156
|
+
await t.step("preloaded FEP-ef61 context", async () => {
|
|
6157
6157
|
const url = "https://w3id.org/fep/ef61";
|
|
6158
6158
|
ok(url in preloadedContexts);
|
|
6159
6159
|
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
@@ -6170,7 +6170,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6170
6170
|
});
|
|
6171
6171
|
});
|
|
6172
6172
|
esm_default.get("https://w3id.org/fep/7aa9", { status: 502 });
|
|
6173
|
-
await t.
|
|
6173
|
+
await t.step("preloaded FEP-7aa9 context", async () => {
|
|
6174
6174
|
const url = "https://w3id.org/fep/7aa9";
|
|
6175
6175
|
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
6176
6176
|
contextUrl: null,
|
|
@@ -6201,7 +6201,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6201
6201
|
deepStrictEqual(esm_default.callHistory.calls(url).length, 0);
|
|
6202
6202
|
});
|
|
6203
6203
|
esm_default.get("https://w3id.org/fep/6757", { status: 502 });
|
|
6204
|
-
await t.
|
|
6204
|
+
await t.step("preloaded FEP-6757 context", async () => {
|
|
6205
6205
|
const url = "https://w3id.org/fep/6757";
|
|
6206
6206
|
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
6207
6207
|
contextUrl: null,
|
|
@@ -6230,7 +6230,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6230
6230
|
deepStrictEqual(esm_default.callHistory.calls(url).length, 0);
|
|
6231
6231
|
});
|
|
6232
6232
|
esm_default.get("https://w3id.org/fep/22cd", { status: 502 });
|
|
6233
|
-
await t.
|
|
6233
|
+
await t.step("preloaded FEP-22cd context", async () => {
|
|
6234
6234
|
const url = "https://w3id.org/fep/22cd";
|
|
6235
6235
|
const articleId = "https://example.com/articles/1";
|
|
6236
6236
|
const translatorId = "https://example.com/users/alice";
|
|
@@ -6308,7 +6308,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6308
6308
|
deepStrictEqual(esm_default.callHistory.calls(url).length, 0);
|
|
6309
6309
|
deepStrictEqual(esm_default.callHistory.calls("https://www.w3.org/ns/activitystreams").length, 0);
|
|
6310
6310
|
});
|
|
6311
|
-
await t.
|
|
6311
|
+
await t.step("deny non-HTTP/HTTPS", async () => {
|
|
6312
6312
|
await rejects(() => fetchDocumentLoader("ftp://localhost"), UrlError);
|
|
6313
6313
|
});
|
|
6314
6314
|
esm_default.get("https://example.com/localhost-redirect", {
|
|
@@ -6333,13 +6333,13 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6333
6333
|
name: "Fetched object",
|
|
6334
6334
|
type: "Object"
|
|
6335
6335
|
} });
|
|
6336
|
-
await t.
|
|
6336
|
+
await t.step("allowPrivateAddress: false", async () => {
|
|
6337
6337
|
await rejects(() => fetchDocumentLoader("https://localhost/object"), UrlError);
|
|
6338
6338
|
await rejects(() => fetchDocumentLoader("https://example.com/localhost-redirect"), UrlError);
|
|
6339
6339
|
await rejects(() => fetchDocumentLoader("https://example.com/localhost-link"), UrlError);
|
|
6340
6340
|
});
|
|
6341
6341
|
const fetchDocumentLoader2 = getDocumentLoader({ allowPrivateAddress: true });
|
|
6342
|
-
await t.
|
|
6342
|
+
await t.step("allowPrivateAddress: true", async () => {
|
|
6343
6343
|
const expected = {
|
|
6344
6344
|
contextUrl: null,
|
|
6345
6345
|
documentUrl: "https://localhost/object",
|
|
@@ -6362,7 +6362,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6362
6362
|
headers: { Location: `https://example.com/too-many-redirects/${Number(cl.url.split("/").at(-1)) + 1}` }
|
|
6363
6363
|
};
|
|
6364
6364
|
});
|
|
6365
|
-
await t.
|
|
6365
|
+
await t.step("too many redirects", async () => {
|
|
6366
6366
|
redirectAttempts = 0;
|
|
6367
6367
|
await rejects(() => fetchDocumentLoader("https://example.com/too-many-redirects/0"), FetchError, "Too many redirections");
|
|
6368
6368
|
deepStrictEqual(redirectAttempts, 21);
|
|
@@ -6382,7 +6382,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6382
6382
|
headers: { Location: "https://example.com/redirect-loop-a" }
|
|
6383
6383
|
};
|
|
6384
6384
|
});
|
|
6385
|
-
await t.
|
|
6385
|
+
await t.step("redirect loop", async () => {
|
|
6386
6386
|
loopAttempts = 0;
|
|
6387
6387
|
await rejects(() => fetchDocumentLoader("https://example.com/redirect-loop-a"), FetchError, "Redirect loop detected");
|
|
6388
6388
|
deepStrictEqual(loopAttempts, 2);
|
|
@@ -6395,7 +6395,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6395
6395
|
headers: { Location: "/redirect-loop-relative" }
|
|
6396
6396
|
};
|
|
6397
6397
|
});
|
|
6398
|
-
await t.
|
|
6398
|
+
await t.step("redirect loop with relative location", async () => {
|
|
6399
6399
|
relativeLoopAttempts = 0;
|
|
6400
6400
|
await rejects(() => fetchDocumentLoader("https://example.com/redirect-loop-relative"), FetchError, "Redirect loop detected");
|
|
6401
6401
|
deepStrictEqual(relativeLoopAttempts, 1);
|
|
@@ -6405,7 +6405,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
6405
6405
|
body: maliciousPayload,
|
|
6406
6406
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
6407
6407
|
});
|
|
6408
|
-
await t.
|
|
6408
|
+
await t.step("ReDoS resistance (CVE-2025-68475)", async () => {
|
|
6409
6409
|
const start = performance.now();
|
|
6410
6410
|
await rejects(() => fetchDocumentLoader("https://example.com/redos"), SyntaxError);
|
|
6411
6411
|
const elapsed = performance.now() - start;
|
|
@@ -6491,16 +6491,13 @@ test("getRemoteDocument() bounds JSON by default", async () => {
|
|
|
6491
6491
|
deepStrictEqual(pulls, 257);
|
|
6492
6492
|
});
|
|
6493
6493
|
test("getDocumentLoader() logs DNS failures as such", async (t) => {
|
|
6494
|
-
if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted")
|
|
6495
|
-
t.skip("requires the net permission");
|
|
6496
|
-
return;
|
|
6497
|
-
}
|
|
6494
|
+
if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted") throw new Error("This DNS test requires Deno network permission (--allow-net).");
|
|
6498
6495
|
const loader = getDocumentLoader();
|
|
6499
6496
|
for (const result of [
|
|
6500
6497
|
"throws",
|
|
6501
6498
|
"empty",
|
|
6502
6499
|
"private"
|
|
6503
|
-
]) await t.
|
|
6500
|
+
]) await t.step(result, async () => {
|
|
6504
6501
|
const originalLookup = dns.lookup;
|
|
6505
6502
|
dns.lookup = (() => result === "throws" ? Promise.reject(/* @__PURE__ */ new Error("Resolver unavailable")) : Promise.resolve(result === "empty" ? [] : [{
|
|
6506
6503
|
address: "127.0.0.1",
|
|
@@ -6555,7 +6552,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
6555
6552
|
"header",
|
|
6556
6553
|
"html",
|
|
6557
6554
|
"mixed"
|
|
6558
|
-
]) for (const hops of [20, 21]) await t.
|
|
6555
|
+
]) for (const hops of [20, 21]) await t.step(`${mode}: ${hops} hops`, async () => {
|
|
6559
6556
|
esm_default.mockGlobal();
|
|
6560
6557
|
let requests = 0;
|
|
6561
6558
|
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
@@ -6584,7 +6581,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
6584
6581
|
"alternate-redirect",
|
|
6585
6582
|
"redirect-alternate",
|
|
6586
6583
|
"redirect-intermediate"
|
|
6587
|
-
]) await t.
|
|
6584
|
+
]) await t.step(`${mode}: cycle`, async () => {
|
|
6588
6585
|
esm_default.mockGlobal();
|
|
6589
6586
|
let requests = 0;
|
|
6590
6587
|
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
@@ -6606,7 +6603,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
6606
6603
|
esm_default.hardReset();
|
|
6607
6604
|
}
|
|
6608
6605
|
});
|
|
6609
|
-
await t.
|
|
6606
|
+
await t.step("alternate followed by 20 redirects shares the limit", async () => {
|
|
6610
6607
|
esm_default.mockGlobal();
|
|
6611
6608
|
let requests = 0;
|
|
6612
6609
|
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
@@ -6626,7 +6623,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
6626
6623
|
esm_default.hardReset();
|
|
6627
6624
|
}
|
|
6628
6625
|
});
|
|
6629
|
-
await t.
|
|
6626
|
+
await t.step("relative alternate after redirect and isolated calls", async () => {
|
|
6630
6627
|
esm_default.mockGlobal();
|
|
6631
6628
|
esm_default.get(`${base}start`, Response.redirect(`${base}html`, 302));
|
|
6632
6629
|
esm_default.get(`${base}html`, alternate("./document", true));
|
|
@@ -6653,7 +6650,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
6653
6650
|
test("getDocumentLoader() preserves cancellation across alternates", async (t) => {
|
|
6654
6651
|
const base = "https://example.com/alternate-abort/";
|
|
6655
6652
|
const loader = getDocumentLoader({ allowPrivateAddress: true });
|
|
6656
|
-
for (const html of [false, true]) await t.
|
|
6653
|
+
for (const html of [false, true]) await t.step(html ? "HTML" : "Link header", async () => {
|
|
6657
6654
|
esm_default.mockGlobal();
|
|
6658
6655
|
const controller = new AbortController();
|
|
6659
6656
|
let requests = 0;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Do9eywBl.cjs");
|
|
2
|
+
const require_langtag = require("./langtag-Bm8oKhIO.cjs");
|
|
2
3
|
let node_test = require("node:test");
|
|
3
4
|
let node_assert = require("node:assert");
|
|
4
5
|
let node_util = require("node:util");
|
|
@@ -17,11 +18,13 @@ var LanguageString = class extends String {
|
|
|
17
18
|
* Constructs a new `LanguageString`.
|
|
18
19
|
* @param value A string value written in the given language.
|
|
19
20
|
* @param language The language of the string. If a string is given, it will
|
|
20
|
-
* be parsed as a `Intl.Locale` object.
|
|
21
|
+
* be parsed as a `Intl.Locale` object. Extended language
|
|
22
|
+
* subtags are normalized first, e.g., `zh-yue` is parsed as
|
|
23
|
+
* `yue`.
|
|
21
24
|
*/
|
|
22
25
|
constructor(value, language) {
|
|
23
26
|
super(value);
|
|
24
|
-
this.locale = typeof language === "string" ? new Intl.Locale(language) : language;
|
|
27
|
+
this.locale = typeof language === "string" ? new Intl.Locale(require_langtag.normalizeLanguageTag(language)) : language;
|
|
25
28
|
}
|
|
26
29
|
};
|
|
27
30
|
LanguageString.prototype[Symbol.for("Deno.customInspect")] = function(inspect, options) {
|
|
@@ -38,6 +41,13 @@ LanguageString.prototype[Symbol.for("nodejs.util.inspect.custom")] = function(_d
|
|
|
38
41
|
(0, node_assert.deepStrictEqual)(langStr.locale, new Intl.Locale("en"));
|
|
39
42
|
(0, node_assert.deepStrictEqual)(new LanguageString("Hello", new Intl.Locale("en")), langStr);
|
|
40
43
|
});
|
|
44
|
+
(0, node_test.test)("new LanguageString() with extlang tags", () => {
|
|
45
|
+
(0, node_assert.deepStrictEqual)(new LanguageString("你好", "zh-YUE").locale.baseName, "yue");
|
|
46
|
+
(0, node_assert.deepStrictEqual)(new LanguageString("你好", "zh-yue-HK").locale.baseName, "yue-HK");
|
|
47
|
+
(0, node_assert.deepStrictEqual)(new LanguageString("你好", "zh-cmn-Hant").locale.baseName, new Intl.Locale("cmn-Hant").baseName);
|
|
48
|
+
(0, node_assert.throws)(() => new LanguageString("Hello", "en-USA"), RangeError);
|
|
49
|
+
(0, node_assert.throws)(() => new LanguageString("你好", "zh-yue-"), RangeError);
|
|
50
|
+
});
|
|
41
51
|
(0, node_test.test)("Deno.inspect(LanguageString)", () => {
|
|
42
52
|
const langStr = new LanguageString("Hello, 'world'", "en");
|
|
43
53
|
(0, node_assert.deepStrictEqual)(node_util.default.inspect(langStr, { colors: false }), "<en> \"Hello, 'world'\"");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { t as normalizeLanguageTag } from "./langtag-QZZgy903.mjs";
|
|
1
2
|
import { test } from "node:test";
|
|
2
|
-
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { deepStrictEqual, throws } from "node:assert";
|
|
3
4
|
import util from "node:util";
|
|
4
5
|
//#region src/langstr.ts
|
|
5
6
|
/**
|
|
@@ -15,11 +16,13 @@ var LanguageString = class extends String {
|
|
|
15
16
|
* Constructs a new `LanguageString`.
|
|
16
17
|
* @param value A string value written in the given language.
|
|
17
18
|
* @param language The language of the string. If a string is given, it will
|
|
18
|
-
* be parsed as a `Intl.Locale` object.
|
|
19
|
+
* be parsed as a `Intl.Locale` object. Extended language
|
|
20
|
+
* subtags are normalized first, e.g., `zh-yue` is parsed as
|
|
21
|
+
* `yue`.
|
|
19
22
|
*/
|
|
20
23
|
constructor(value, language) {
|
|
21
24
|
super(value);
|
|
22
|
-
this.locale = typeof language === "string" ? new Intl.Locale(language) : language;
|
|
25
|
+
this.locale = typeof language === "string" ? new Intl.Locale(normalizeLanguageTag(language)) : language;
|
|
23
26
|
}
|
|
24
27
|
};
|
|
25
28
|
LanguageString.prototype[Symbol.for("Deno.customInspect")] = function(inspect, options) {
|
|
@@ -36,6 +39,13 @@ test("new LanguageString()", () => {
|
|
|
36
39
|
deepStrictEqual(langStr.locale, new Intl.Locale("en"));
|
|
37
40
|
deepStrictEqual(new LanguageString("Hello", new Intl.Locale("en")), langStr);
|
|
38
41
|
});
|
|
42
|
+
test("new LanguageString() with extlang tags", () => {
|
|
43
|
+
deepStrictEqual(new LanguageString("你好", "zh-YUE").locale.baseName, "yue");
|
|
44
|
+
deepStrictEqual(new LanguageString("你好", "zh-yue-HK").locale.baseName, "yue-HK");
|
|
45
|
+
deepStrictEqual(new LanguageString("你好", "zh-cmn-Hant").locale.baseName, new Intl.Locale("cmn-Hant").baseName);
|
|
46
|
+
throws(() => new LanguageString("Hello", "en-USA"), RangeError);
|
|
47
|
+
throws(() => new LanguageString("你好", "zh-yue-"), RangeError);
|
|
48
|
+
});
|
|
39
49
|
test("Deno.inspect(LanguageString)", () => {
|
|
40
50
|
const langStr = new LanguageString("Hello, 'world'", "en");
|
|
41
51
|
deepStrictEqual(util.inspect(langStr, { colors: false }), "<en> \"Hello, 'world'\"");
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/langtag.ts
|
|
2
|
+
const EXTLANG_PAIRS = new Set(Object.entries({
|
|
3
|
+
ar: "aao abh abv acm acq acw acx acy adf aeb aec afb ajp apc apd arb arq ars ary arz auz avl ayh ayl ayn ayp bbz pga shu ssh",
|
|
4
|
+
kok: "gom knn",
|
|
5
|
+
lv: "ltg lvs",
|
|
6
|
+
ms: "bjn btj bve bvu coa dup hji jak jax kvb kvr kxd lce lcf liw max meo mfa mfb min mqg msi mui orn ors pel pse tmw urk vkk vkt xmm zlm zmi zsm",
|
|
7
|
+
sgn: "ads aed aen afg ajs ase asf asp asq asw bfi bfk bog bqn bqy bvl bzs cds csc csd cse csf csg csl csn csq csr csx doq dse dsl dsz dyl ecs ehs esl esn eso eth fcs fse fsl fss gds gse gsg gsm gss gus hab haf hds hks hos hps hsh hsl icl iks ils inl ins ise isg isr jcs jhs jks jls jos jsl jus kgi kvk lbs lgs lls lsb lsc lsg lsl lsn lso lsp lst lsv lsw lsy lws mdl mfs mre msd msr mzc mzg mzy nbs ncs nsi nsl nsp nsr nzs okl pgz pks prl prz psc psd psg psl pso psp psr pys rib rms rnb rsi rsl rsm rsn sdl sfb sfs sgg sgx slf sls sqk sqs sqx ssp ssr svk swl syy szs tse tsm tsq tss tsy tza ugn ugy ukl uks vgt vsi vsl vsv wbs xki xml xms yds ygs yhs ysl ysm zhk zib zsl",
|
|
8
|
+
sw: "swc swh",
|
|
9
|
+
uz: "uzn uzs",
|
|
10
|
+
zh: "cdo cjy cmn cnp cpx csp czh czo gan hak hnm hsn luh lzh mnp nan sjc wuu yue"
|
|
11
|
+
}).flatMap(([prefix, extlangs]) => extlangs.split(" ").map((extlang) => `${prefix}-${extlang}`)));
|
|
12
|
+
const PREFIX_PATTERN = /^[A-Za-z]{2,3}$/;
|
|
13
|
+
const EXTLANG_PATTERN = /^[A-Za-z]{3}$/;
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes a BCP 47 language tag that has an extended language subtag
|
|
16
|
+
* (extlang), such as `zh-yue`, into its canonical form, such as `yue`, as
|
|
17
|
+
* described in [RFC 5646, Section 4.5][1]. `Intl.Locale` rejects extlang
|
|
18
|
+
* tags, so tags should be normalized before being passed to it.
|
|
19
|
+
*
|
|
20
|
+
* Only registered extlangs that follow their registered prefix are removed;
|
|
21
|
+
* any other tag is returned unchanged, so the result still needs to be
|
|
22
|
+
* validated, e.g., by `Intl.Locale`.
|
|
23
|
+
*
|
|
24
|
+
* NOTE: This function is marked as internal in the 2.0.x–2.4.x patch
|
|
25
|
+
* releases. When merging it into the *main* branch, remove the `@internal`
|
|
26
|
+
* tag, formalize it as a public API (`@since 2.5.0`), and add it to
|
|
27
|
+
* the changelog fragment.
|
|
28
|
+
*
|
|
29
|
+
* [1]: https://www.rfc-editor.org/rfc/rfc5646.html#section-4.5
|
|
30
|
+
*
|
|
31
|
+
* @param tag The BCP 47 language tag to normalize.
|
|
32
|
+
* @returns The normalized language tag.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
function normalizeLanguageTag(tag) {
|
|
36
|
+
const subtags = tag.split("-");
|
|
37
|
+
if (subtags.length < 2) return tag;
|
|
38
|
+
const [prefix, extlang, ...rest] = subtags;
|
|
39
|
+
if (!PREFIX_PATTERN.test(prefix) || !EXTLANG_PATTERN.test(extlang)) return tag;
|
|
40
|
+
const language = extlang.toLowerCase();
|
|
41
|
+
if (!EXTLANG_PAIRS.has(`${prefix.toLowerCase()}-${language}`)) return tag;
|
|
42
|
+
return [language, ...rest].join("-");
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
Object.defineProperty(exports, "normalizeLanguageTag", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function() {
|
|
48
|
+
return normalizeLanguageTag;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/langtag.ts
|
|
2
|
+
const EXTLANG_PAIRS = new Set(Object.entries({
|
|
3
|
+
ar: "aao abh abv acm acq acw acx acy adf aeb aec afb ajp apc apd arb arq ars ary arz auz avl ayh ayl ayn ayp bbz pga shu ssh",
|
|
4
|
+
kok: "gom knn",
|
|
5
|
+
lv: "ltg lvs",
|
|
6
|
+
ms: "bjn btj bve bvu coa dup hji jak jax kvb kvr kxd lce lcf liw max meo mfa mfb min mqg msi mui orn ors pel pse tmw urk vkk vkt xmm zlm zmi zsm",
|
|
7
|
+
sgn: "ads aed aen afg ajs ase asf asp asq asw bfi bfk bog bqn bqy bvl bzs cds csc csd cse csf csg csl csn csq csr csx doq dse dsl dsz dyl ecs ehs esl esn eso eth fcs fse fsl fss gds gse gsg gsm gss gus hab haf hds hks hos hps hsh hsl icl iks ils inl ins ise isg isr jcs jhs jks jls jos jsl jus kgi kvk lbs lgs lls lsb lsc lsg lsl lsn lso lsp lst lsv lsw lsy lws mdl mfs mre msd msr mzc mzg mzy nbs ncs nsi nsl nsp nsr nzs okl pgz pks prl prz psc psd psg psl pso psp psr pys rib rms rnb rsi rsl rsm rsn sdl sfb sfs sgg sgx slf sls sqk sqs sqx ssp ssr svk swl syy szs tse tsm tsq tss tsy tza ugn ugy ukl uks vgt vsi vsl vsv wbs xki xml xms yds ygs yhs ysl ysm zhk zib zsl",
|
|
8
|
+
sw: "swc swh",
|
|
9
|
+
uz: "uzn uzs",
|
|
10
|
+
zh: "cdo cjy cmn cnp cpx csp czh czo gan hak hnm hsn luh lzh mnp nan sjc wuu yue"
|
|
11
|
+
}).flatMap(([prefix, extlangs]) => extlangs.split(" ").map((extlang) => `${prefix}-${extlang}`)));
|
|
12
|
+
const PREFIX_PATTERN = /^[A-Za-z]{2,3}$/;
|
|
13
|
+
const EXTLANG_PATTERN = /^[A-Za-z]{3}$/;
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes a BCP 47 language tag that has an extended language subtag
|
|
16
|
+
* (extlang), such as `zh-yue`, into its canonical form, such as `yue`, as
|
|
17
|
+
* described in [RFC 5646, Section 4.5][1]. `Intl.Locale` rejects extlang
|
|
18
|
+
* tags, so tags should be normalized before being passed to it.
|
|
19
|
+
*
|
|
20
|
+
* Only registered extlangs that follow their registered prefix are removed;
|
|
21
|
+
* any other tag is returned unchanged, so the result still needs to be
|
|
22
|
+
* validated, e.g., by `Intl.Locale`.
|
|
23
|
+
*
|
|
24
|
+
* NOTE: This function is marked as internal in the 2.0.x–2.4.x patch
|
|
25
|
+
* releases. When merging it into the *main* branch, remove the `@internal`
|
|
26
|
+
* tag, formalize it as a public API (`@since 2.5.0`), and add it to
|
|
27
|
+
* the changelog fragment.
|
|
28
|
+
*
|
|
29
|
+
* [1]: https://www.rfc-editor.org/rfc/rfc5646.html#section-4.5
|
|
30
|
+
*
|
|
31
|
+
* @param tag The BCP 47 language tag to normalize.
|
|
32
|
+
* @returns The normalized language tag.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
function normalizeLanguageTag(tag) {
|
|
36
|
+
const subtags = tag.split("-");
|
|
37
|
+
if (subtags.length < 2) return tag;
|
|
38
|
+
const [prefix, extlang, ...rest] = subtags;
|
|
39
|
+
if (!PREFIX_PATTERN.test(prefix) || !EXTLANG_PATTERN.test(extlang)) return tag;
|
|
40
|
+
const language = extlang.toLowerCase();
|
|
41
|
+
if (!EXTLANG_PAIRS.has(`${prefix.toLowerCase()}-${language}`)) return tag;
|
|
42
|
+
return [language, ...rest].join("-");
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { normalizeLanguageTag as t };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require("./chunk-Do9eywBl.cjs");
|
|
2
|
+
const require_langtag = require("./langtag-Bm8oKhIO.cjs");
|
|
3
|
+
let node_test = require("node:test");
|
|
4
|
+
let node_assert = require("node:assert");
|
|
5
|
+
//#region src/langtag.test.ts
|
|
6
|
+
(0, node_test.test)("normalizeLanguageTag() removes extlang subtags", () => {
|
|
7
|
+
for (const [input, expected] of [
|
|
8
|
+
["zh-yue", "yue"],
|
|
9
|
+
["zh-YUE", "yue"],
|
|
10
|
+
["ZH-Yue-hk", "yue-hk"],
|
|
11
|
+
["zh-yue-HK", "yue-HK"],
|
|
12
|
+
["zh-cmn-Hant", "cmn-Hant"],
|
|
13
|
+
["zh-yue-u-nu-hanidec", "yue-u-nu-hanidec"],
|
|
14
|
+
["sgn-ase", "ase"],
|
|
15
|
+
["ar-arz", "arz"],
|
|
16
|
+
["ms-zlm", "zlm"],
|
|
17
|
+
["kok-gom", "gom"],
|
|
18
|
+
["koK-gom", "gom"],
|
|
19
|
+
["lv-ltg", "ltg"],
|
|
20
|
+
["sw-swc", "swc"],
|
|
21
|
+
["uz-uzs", "uzs"],
|
|
22
|
+
["zh-yue-cmn", "yue-cmn"],
|
|
23
|
+
["zh-yue-", "yue-"]
|
|
24
|
+
]) (0, node_assert.deepStrictEqual)(require_langtag.normalizeLanguageTag(input), expected, input);
|
|
25
|
+
});
|
|
26
|
+
(0, node_test.test)("normalizeLanguageTag() leaves other tags unchanged", () => {
|
|
27
|
+
for (const tag of [
|
|
28
|
+
"",
|
|
29
|
+
"en",
|
|
30
|
+
"en-US",
|
|
31
|
+
"en-USA",
|
|
32
|
+
"en-yue",
|
|
33
|
+
"zh",
|
|
34
|
+
"zh-Hant-TW",
|
|
35
|
+
"yue",
|
|
36
|
+
"yue-HK",
|
|
37
|
+
"x-private",
|
|
38
|
+
"i-klingon",
|
|
39
|
+
"zh-min-nan",
|
|
40
|
+
"koK-gom",
|
|
41
|
+
"zh-yuK",
|
|
42
|
+
"constructor-yue",
|
|
43
|
+
"toString-yue"
|
|
44
|
+
]) (0, node_assert.deepStrictEqual)(require_langtag.normalizeLanguageTag(tag), tag, tag);
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { t as normalizeLanguageTag } from "./langtag-QZZgy903.mjs";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { deepStrictEqual } from "node:assert";
|
|
4
|
+
//#region src/langtag.test.ts
|
|
5
|
+
test("normalizeLanguageTag() removes extlang subtags", () => {
|
|
6
|
+
for (const [input, expected] of [
|
|
7
|
+
["zh-yue", "yue"],
|
|
8
|
+
["zh-YUE", "yue"],
|
|
9
|
+
["ZH-Yue-hk", "yue-hk"],
|
|
10
|
+
["zh-yue-HK", "yue-HK"],
|
|
11
|
+
["zh-cmn-Hant", "cmn-Hant"],
|
|
12
|
+
["zh-yue-u-nu-hanidec", "yue-u-nu-hanidec"],
|
|
13
|
+
["sgn-ase", "ase"],
|
|
14
|
+
["ar-arz", "arz"],
|
|
15
|
+
["ms-zlm", "zlm"],
|
|
16
|
+
["kok-gom", "gom"],
|
|
17
|
+
["koK-gom", "gom"],
|
|
18
|
+
["lv-ltg", "ltg"],
|
|
19
|
+
["sw-swc", "swc"],
|
|
20
|
+
["uz-uzs", "uzs"],
|
|
21
|
+
["zh-yue-cmn", "yue-cmn"],
|
|
22
|
+
["zh-yue-", "yue-"]
|
|
23
|
+
]) deepStrictEqual(normalizeLanguageTag(input), expected, input);
|
|
24
|
+
});
|
|
25
|
+
test("normalizeLanguageTag() leaves other tags unchanged", () => {
|
|
26
|
+
for (const tag of [
|
|
27
|
+
"",
|
|
28
|
+
"en",
|
|
29
|
+
"en-US",
|
|
30
|
+
"en-USA",
|
|
31
|
+
"en-yue",
|
|
32
|
+
"zh",
|
|
33
|
+
"zh-Hant-TW",
|
|
34
|
+
"yue",
|
|
35
|
+
"yue-HK",
|
|
36
|
+
"x-private",
|
|
37
|
+
"i-klingon",
|
|
38
|
+
"zh-min-nan",
|
|
39
|
+
"koK-gom",
|
|
40
|
+
"zh-yuK",
|
|
41
|
+
"constructor-yue",
|
|
42
|
+
"toString-yue"
|
|
43
|
+
]) deepStrictEqual(normalizeLanguageTag(tag), tag, tag);
|
|
44
|
+
});
|
|
45
|
+
//#endregion
|
|
46
|
+
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require("../chunk-Do9eywBl.cjs");
|
|
2
2
|
const require_multibase = require("../multibase-CnmModw0.cjs");
|
|
3
|
-
let node_test = require("node:test");
|
|
4
3
|
let node_assert = require("node:assert");
|
|
4
|
+
let _fedify_fixture = require("@fedify/fixture");
|
|
5
5
|
//#region src/multibase/multibase.test.ts
|
|
6
|
-
(0,
|
|
6
|
+
(0, _fedify_fixture.test)("multibase.encode and decode", async (t) => {
|
|
7
7
|
const testCases = [
|
|
8
8
|
[
|
|
9
9
|
"base16",
|
|
@@ -316,22 +316,22 @@ let node_assert = require("node:assert");
|
|
|
316
316
|
"Uw7fDr8O_8J-lsMO3w6_Dv_CfmI7wn6W28J-krw=="
|
|
317
317
|
]
|
|
318
318
|
];
|
|
319
|
-
for (const [name, input, expectedOutput] of testCases) await t.
|
|
319
|
+
for (const [name, input, expectedOutput] of testCases) await t.step(`Encoding/Decoding ${name} with ${input}`, () => {
|
|
320
320
|
(0, node_assert.deepStrictEqual)(require_multibase.decodeText(require_multibase.encodeMultibase(name, require_multibase.encodeText(input))), expectedOutput, `Encoding ${name} failed`);
|
|
321
321
|
(0, node_assert.deepStrictEqual)(require_multibase.decodeMultibase(expectedOutput), require_multibase.encodeText(input), `Decoding ${name} failed`);
|
|
322
322
|
(0, node_assert.deepStrictEqual)(require_multibase.decodeMultibase(require_multibase.encodeText(expectedOutput)), require_multibase.encodeText(input), `Decoding buffer of ${name} failed`);
|
|
323
323
|
});
|
|
324
|
-
await t.
|
|
324
|
+
await t.step("should allow base32pad full alphabet", () => {
|
|
325
325
|
const decoded = require_multibase.decodeMultibase("ctimaq4ygg2iegci7");
|
|
326
326
|
(0, node_assert.deepStrictEqual)(require_multibase.decodeMultibase(require_multibase.encodeMultibase("c", decoded)), decoded);
|
|
327
327
|
});
|
|
328
328
|
});
|
|
329
|
-
(0,
|
|
330
|
-
await t.
|
|
329
|
+
(0, _fedify_fixture.test)("constants", async (t) => {
|
|
330
|
+
await t.step("constants indexed by name", () => {
|
|
331
331
|
const names$1 = require_multibase.names;
|
|
332
332
|
(0, node_assert.deepStrictEqual)(Object.keys(names$1).length, 23);
|
|
333
333
|
});
|
|
334
|
-
await t.
|
|
334
|
+
await t.step("constants indexed by code", () => {
|
|
335
335
|
const codes$1 = require_multibase.codes;
|
|
336
336
|
(0, node_assert.deepStrictEqual)(Object.keys(codes$1).length, 23);
|
|
337
337
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as decodeText, i as names, n as encodeMultibase, o as encodeText, r as codes, t as decodeMultibase } from "../multibase-DLBufb99.mjs";
|
|
2
|
-
import { test } from "node:test";
|
|
3
2
|
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { test } from "@fedify/fixture";
|
|
4
4
|
//#region src/multibase/multibase.test.ts
|
|
5
5
|
test("multibase.encode and decode", async (t) => {
|
|
6
6
|
const testCases = [
|
|
@@ -315,21 +315,21 @@ test("multibase.encode and decode", async (t) => {
|
|
|
315
315
|
"Uw7fDr8O_8J-lsMO3w6_Dv_CfmI7wn6W28J-krw=="
|
|
316
316
|
]
|
|
317
317
|
];
|
|
318
|
-
for (const [name, input, expectedOutput] of testCases) await t.
|
|
318
|
+
for (const [name, input, expectedOutput] of testCases) await t.step(`Encoding/Decoding ${name} with ${input}`, () => {
|
|
319
319
|
deepStrictEqual(decodeText(encodeMultibase(name, encodeText(input))), expectedOutput, `Encoding ${name} failed`);
|
|
320
320
|
deepStrictEqual(decodeMultibase(expectedOutput), encodeText(input), `Decoding ${name} failed`);
|
|
321
321
|
deepStrictEqual(decodeMultibase(encodeText(expectedOutput)), encodeText(input), `Decoding buffer of ${name} failed`);
|
|
322
322
|
});
|
|
323
|
-
await t.
|
|
323
|
+
await t.step("should allow base32pad full alphabet", () => {
|
|
324
324
|
const decoded = decodeMultibase("ctimaq4ygg2iegci7");
|
|
325
325
|
deepStrictEqual(decodeMultibase(encodeMultibase("c", decoded)), decoded);
|
|
326
326
|
});
|
|
327
327
|
});
|
|
328
328
|
test("constants", async (t) => {
|
|
329
|
-
await t.
|
|
329
|
+
await t.step("constants indexed by name", () => {
|
|
330
330
|
deepStrictEqual(Object.keys(names).length, 23);
|
|
331
331
|
});
|
|
332
|
-
await t.
|
|
332
|
+
await t.step("constants indexed by code", () => {
|
|
333
333
|
deepStrictEqual(Object.keys(codes).length, 23);
|
|
334
334
|
});
|
|
335
335
|
});
|
|
@@ -3,7 +3,7 @@ let node_process = require("node:process");
|
|
|
3
3
|
node_process = require_chunk.__toESM(node_process);
|
|
4
4
|
//#region deno.json
|
|
5
5
|
var name = "@fedify/vocab-runtime";
|
|
6
|
-
var version = "2.0.31-dev.
|
|
6
|
+
var version = "2.0.31-dev.2310+e604de57";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/request.ts
|
|
9
9
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Do9eywBl.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-CFKB-Yqd.cjs");
|
|
3
3
|
let node_test = require("node:test");
|
|
4
4
|
let node_process = require("node:process");
|
|
5
5
|
node_process = require_chunk.__toESM(node_process);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as version, r as getUserAgent } from "./request-
|
|
1
|
+
import { o as version, r as getUserAgent } from "./request-DDAEJJqw.mjs";
|
|
2
2
|
import { test } from "node:test";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { deepStrictEqual } from "node:assert";
|