@fedify/vocab-runtime 2.3.11-dev.2296 → 2.3.11
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 +91 -4
- package/dist/mod.d.cts +30 -2
- package/dist/mod.d.ts +30 -2
- package/dist/mod.js +91 -5
- package/dist/tests/{body-B4vYiUPw.mjs → body-Cfk4XwBC.mjs} +1 -1
- package/dist/tests/{body-E_Ip3EI_.cjs → body-kujxx7yw.cjs} +1 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/decimal.test.cjs +3 -2
- package/dist/tests/decimal.test.mjs +3 -2
- package/dist/tests/{docloader-DBzA04Tp.mjs → docloader-BeuDl5a0.mjs} +43 -3
- package/dist/tests/{docloader-zA5iGORs.cjs → docloader-Bx_LR9xG.cjs} +43 -3
- package/dist/tests/docloader.test.cjs +168 -43
- package/dist/tests/docloader.test.mjs +158 -34
- package/dist/tests/{langstr-DDLc4833.mjs → langstr-ABdAOKlF.mjs} +5 -2
- package/dist/tests/{langstr-BOQHfJDr.cjs → langstr-BsqFJupv.cjs} +5 -2
- package/dist/tests/langstr.test.cjs +8 -1
- package/dist/tests/langstr.test.mjs +9 -2
- package/dist/tests/langtag-DgySESmk.cjs +50 -0
- package/dist/tests/langtag-LDBqlxHv.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-CzD6ie9f.mjs → request-D6bjY2cF.mjs} +1 -1
- package/dist/tests/{request-DfDR4M7o.cjs → request-DPh7-Q1i.cjs} +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/contexts/fep-22cd.json +14 -0
- package/src/contexts/fep-6757.json +12 -0
- package/src/contexts/joinmastodon.json +1 -1
- package/src/contexts.ts +16 -0
- package/src/docloader.test.ts +222 -67
- package/src/docloader.ts +2 -0
- 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,13 @@
|
|
|
1
|
-
import { t as FetchError } from "./request-
|
|
2
|
-
import { i as cid_v1_default, n as getRemoteDocument, r as preloadedContexts, t as getDocumentLoader } from "./docloader-
|
|
1
|
+
import { t as FetchError } from "./request-D6bjY2cF.mjs";
|
|
2
|
+
import { i as cid_v1_default, n as getRemoteDocument, r as preloadedContexts, t as getDocumentLoader } from "./docloader-BeuDl5a0.mjs";
|
|
3
3
|
import { t as UrlError } from "./url-3fyJuqC0.mjs";
|
|
4
|
-
import { test } from "node:test";
|
|
5
4
|
import { gzipSync } from "node:zlib";
|
|
6
5
|
import { configure, reset } from "@logtape/logtape";
|
|
7
6
|
import { deepStrictEqual, ok, rejects } from "node:assert";
|
|
8
7
|
import dns from "node:dns/promises";
|
|
8
|
+
import { test } from "@fedify/fixture";
|
|
9
9
|
import { createServer } from "node:http";
|
|
10
|
+
import jsonld from "jsonld/dist/jsonld.esm.js";
|
|
10
11
|
//#region \0rolldown/runtime.js
|
|
11
12
|
var __create = Object.create;
|
|
12
13
|
var __defProp = Object.defineProperty;
|
|
@@ -1228,6 +1229,9 @@ var esm_default = new class FetchMock {
|
|
|
1228
1229
|
}
|
|
1229
1230
|
}({ ...defaultFetchMockConfig });
|
|
1230
1231
|
//#endregion
|
|
1232
|
+
//#region src/jsonld.ts
|
|
1233
|
+
var jsonld_default = jsonld;
|
|
1234
|
+
//#endregion
|
|
1231
1235
|
//#region src/docloader.test.ts
|
|
1232
1236
|
test("new FetchError()", () => {
|
|
1233
1237
|
const e = new FetchError("https://example.com/", "An error message.");
|
|
@@ -1251,7 +1255,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1251
1255
|
name: "Fetched object",
|
|
1252
1256
|
type: "Object"
|
|
1253
1257
|
} });
|
|
1254
|
-
await t.
|
|
1258
|
+
await t.step("ok", async () => {
|
|
1255
1259
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/object"), {
|
|
1256
1260
|
contextUrl: null,
|
|
1257
1261
|
documentUrl: "https://example.com/object",
|
|
@@ -1294,7 +1298,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1294
1298
|
Link: "<https://example.com/object>; rel=\"alternate\"; type=\"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"\""
|
|
1295
1299
|
}
|
|
1296
1300
|
});
|
|
1297
|
-
await t.
|
|
1301
|
+
await t.step("Link header", async () => {
|
|
1298
1302
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/link-ctx"), {
|
|
1299
1303
|
contextUrl: "https://www.w3.org/ns/activitystreams",
|
|
1300
1304
|
documentUrl: "https://example.com/link-ctx",
|
|
@@ -1315,7 +1319,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1315
1319
|
}
|
|
1316
1320
|
});
|
|
1317
1321
|
});
|
|
1318
|
-
await t.
|
|
1322
|
+
await t.step("Link header relative url", async () => {
|
|
1319
1323
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/link-ctx"), {
|
|
1320
1324
|
contextUrl: "https://www.w3.org/ns/activitystreams",
|
|
1321
1325
|
documentUrl: "https://example.com/link-ctx",
|
|
@@ -1336,7 +1340,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1336
1340
|
}
|
|
1337
1341
|
});
|
|
1338
1342
|
});
|
|
1339
|
-
await t.
|
|
1343
|
+
await t.step("wrong Link header syntax", async () => {
|
|
1340
1344
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/obj-w-wrong-link"), {
|
|
1341
1345
|
contextUrl: null,
|
|
1342
1346
|
documentUrl: "https://example.com/obj-w-wrong-link",
|
|
@@ -1360,7 +1364,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1360
1364
|
</html>`,
|
|
1361
1365
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
1362
1366
|
});
|
|
1363
|
-
await t.
|
|
1367
|
+
await t.step("HTML <link>", async () => {
|
|
1364
1368
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/html-link"), {
|
|
1365
1369
|
contextUrl: null,
|
|
1366
1370
|
documentUrl: "https://example.com/object",
|
|
@@ -1384,7 +1388,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1384
1388
|
</html>`,
|
|
1385
1389
|
headers: { "Content-Type": "application/xhtml+xml; charset=utf-8" }
|
|
1386
1390
|
});
|
|
1387
|
-
await t.
|
|
1391
|
+
await t.step("XHTML <link>", async () => {
|
|
1388
1392
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/xhtml-link"), {
|
|
1389
1393
|
contextUrl: null,
|
|
1390
1394
|
documentUrl: "https://example.com/object",
|
|
@@ -1410,7 +1414,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1410
1414
|
</html>`,
|
|
1411
1415
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
1412
1416
|
});
|
|
1413
|
-
await t.
|
|
1417
|
+
await t.step("HTML <a>", async () => {
|
|
1414
1418
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/html-a"), {
|
|
1415
1419
|
contextUrl: null,
|
|
1416
1420
|
documentUrl: "https://example.com/object",
|
|
@@ -1431,7 +1435,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1431
1435
|
},
|
|
1432
1436
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
1433
1437
|
});
|
|
1434
|
-
await t.
|
|
1438
|
+
await t.step("Wrong Content-Type", async () => {
|
|
1435
1439
|
deepStrictEqual(await fetchDocumentLoader("https://example.com/wrong-content-type"), {
|
|
1436
1440
|
contextUrl: null,
|
|
1437
1441
|
documentUrl: "https://example.com/wrong-content-type",
|
|
@@ -1444,18 +1448,33 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1444
1448
|
});
|
|
1445
1449
|
});
|
|
1446
1450
|
esm_default.get("https://example.com/404", { status: 404 });
|
|
1447
|
-
await t.
|
|
1451
|
+
await t.step("not ok", async () => {
|
|
1448
1452
|
await rejects(() => fetchDocumentLoader("https://example.com/404"), FetchError, "HTTP 404: https://example.com/404");
|
|
1449
1453
|
});
|
|
1450
|
-
await t.
|
|
1454
|
+
await t.step("preloaded contexts", async () => {
|
|
1451
1455
|
for (const [url, document] of Object.entries(preloadedContexts)) deepStrictEqual(await fetchDocumentLoader(url), {
|
|
1452
1456
|
contextUrl: null,
|
|
1453
1457
|
documentUrl: url,
|
|
1454
1458
|
document
|
|
1455
1459
|
});
|
|
1456
1460
|
});
|
|
1461
|
+
await t.step("preloaded Mastodon attribution domains", async () => {
|
|
1462
|
+
const context = ["https://www.w3.org/ns/activitystreams", "http://joinmastodon.org/ns"];
|
|
1463
|
+
const expanded = await jsonld_default.expand({
|
|
1464
|
+
"@context": context,
|
|
1465
|
+
id: "https://social.example/users/alice",
|
|
1466
|
+
type: "Person",
|
|
1467
|
+
attributionDomains: ["blog.example"]
|
|
1468
|
+
}, { documentLoader: fetchDocumentLoader });
|
|
1469
|
+
deepStrictEqual(expanded, [{
|
|
1470
|
+
"@id": "https://social.example/users/alice",
|
|
1471
|
+
"@type": ["https://www.w3.org/ns/activitystreams#Person"],
|
|
1472
|
+
"http://joinmastodon.org/ns#attributionDomains": [{ "@value": "blog.example" }]
|
|
1473
|
+
}]);
|
|
1474
|
+
deepStrictEqual((await jsonld_default.compact(expanded, context, { documentLoader: fetchDocumentLoader })).attributionDomains, ["blog.example"]);
|
|
1475
|
+
});
|
|
1457
1476
|
esm_default.get("https://www.w3.org/ns/cid/v1", { status: 503 });
|
|
1458
|
-
await t.
|
|
1477
|
+
await t.step("preloaded CID v1 context", async () => {
|
|
1459
1478
|
const url = "https://www.w3.org/ns/cid/v1";
|
|
1460
1479
|
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
1461
1480
|
contextUrl: null,
|
|
@@ -1463,7 +1482,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1463
1482
|
document: cid_v1_default
|
|
1464
1483
|
});
|
|
1465
1484
|
});
|
|
1466
|
-
await t.
|
|
1485
|
+
await t.step("preloaded FEP-ef61 context", async () => {
|
|
1467
1486
|
const url = "https://w3id.org/fep/ef61";
|
|
1468
1487
|
ok(url in preloadedContexts);
|
|
1469
1488
|
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
@@ -1480,7 +1499,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1480
1499
|
});
|
|
1481
1500
|
});
|
|
1482
1501
|
esm_default.get("https://w3id.org/fep/7aa9", { status: 502 });
|
|
1483
|
-
await t.
|
|
1502
|
+
await t.step("preloaded FEP-7aa9 context", async () => {
|
|
1484
1503
|
const url = "https://w3id.org/fep/7aa9";
|
|
1485
1504
|
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
1486
1505
|
contextUrl: null,
|
|
@@ -1510,7 +1529,115 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1510
1529
|
});
|
|
1511
1530
|
deepStrictEqual(esm_default.callHistory.calls(url).length, 0);
|
|
1512
1531
|
});
|
|
1513
|
-
|
|
1532
|
+
esm_default.get("https://w3id.org/fep/6757", { status: 502 });
|
|
1533
|
+
await t.step("preloaded FEP-6757 context", async () => {
|
|
1534
|
+
const url = "https://w3id.org/fep/6757";
|
|
1535
|
+
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
1536
|
+
contextUrl: null,
|
|
1537
|
+
documentUrl: url,
|
|
1538
|
+
document: { "@context": {
|
|
1539
|
+
license: {
|
|
1540
|
+
"@id": "http://purl.org/dc/terms/license",
|
|
1541
|
+
"@type": "@id"
|
|
1542
|
+
},
|
|
1543
|
+
preferredLicense: {
|
|
1544
|
+
"@id": "https://w3id.org/fep/6757#preferredLicense",
|
|
1545
|
+
"@type": "@id"
|
|
1546
|
+
}
|
|
1547
|
+
} }
|
|
1548
|
+
});
|
|
1549
|
+
deepStrictEqual(await jsonld_default.expand({
|
|
1550
|
+
"@context": ["https://www.w3.org/ns/activitystreams", url],
|
|
1551
|
+
type: "Person",
|
|
1552
|
+
license: "https://creativecommons.org/licenses/by/4.0/",
|
|
1553
|
+
preferredLicense: "https://creativecommons.org/licenses/by-nc/4.0/"
|
|
1554
|
+
}, { documentLoader: fetchDocumentLoader }), [{
|
|
1555
|
+
"@type": ["https://www.w3.org/ns/activitystreams#Person"],
|
|
1556
|
+
"http://purl.org/dc/terms/license": [{ "@id": "https://creativecommons.org/licenses/by/4.0/" }],
|
|
1557
|
+
"https://w3id.org/fep/6757#preferredLicense": [{ "@id": "https://creativecommons.org/licenses/by-nc/4.0/" }]
|
|
1558
|
+
}]);
|
|
1559
|
+
deepStrictEqual(esm_default.callHistory.calls(url).length, 0);
|
|
1560
|
+
});
|
|
1561
|
+
esm_default.get("https://w3id.org/fep/22cd", { status: 502 });
|
|
1562
|
+
await t.step("preloaded FEP-22cd context", async () => {
|
|
1563
|
+
const url = "https://w3id.org/fep/22cd";
|
|
1564
|
+
const articleId = "https://example.com/articles/1";
|
|
1565
|
+
const translatorId = "https://example.com/users/alice";
|
|
1566
|
+
const revisionId = "https://example.com/articles/1/revisions/1";
|
|
1567
|
+
deepStrictEqual(await fetchDocumentLoader(url), {
|
|
1568
|
+
contextUrl: null,
|
|
1569
|
+
documentUrl: url,
|
|
1570
|
+
document: { "@context": {
|
|
1571
|
+
"fep-22cd": "https://w3id.org/fep/22cd#",
|
|
1572
|
+
schema: "https://schema.org/",
|
|
1573
|
+
xsd: "http://www.w3.org/2001/XMLSchema#",
|
|
1574
|
+
translations: {
|
|
1575
|
+
"@id": "fep-22cd:translations",
|
|
1576
|
+
"@container": "@set"
|
|
1577
|
+
},
|
|
1578
|
+
Translation: "fep-22cd:Translation",
|
|
1579
|
+
sourceUpdated: {
|
|
1580
|
+
"@id": "fep-22cd:sourceUpdated",
|
|
1581
|
+
"@type": "xsd:dateTime"
|
|
1582
|
+
},
|
|
1583
|
+
translator: {
|
|
1584
|
+
"@id": "schema:translator",
|
|
1585
|
+
"@type": "@id",
|
|
1586
|
+
"@container": "@set"
|
|
1587
|
+
},
|
|
1588
|
+
inLanguage: "schema:inLanguage",
|
|
1589
|
+
translationOfWork: {
|
|
1590
|
+
"@id": "schema:translationOfWork",
|
|
1591
|
+
"@type": "@id"
|
|
1592
|
+
},
|
|
1593
|
+
isBasedOn: {
|
|
1594
|
+
"@id": "schema:isBasedOn",
|
|
1595
|
+
"@type": "@id"
|
|
1596
|
+
}
|
|
1597
|
+
} }
|
|
1598
|
+
});
|
|
1599
|
+
deepStrictEqual(await jsonld_default.expand({
|
|
1600
|
+
"@context": ["https://www.w3.org/ns/activitystreams", url],
|
|
1601
|
+
id: articleId,
|
|
1602
|
+
type: "Article",
|
|
1603
|
+
contentMap: {
|
|
1604
|
+
en: "Original",
|
|
1605
|
+
ko: "Translation"
|
|
1606
|
+
},
|
|
1607
|
+
translations: [{
|
|
1608
|
+
type: "Translation",
|
|
1609
|
+
inLanguage: "ko",
|
|
1610
|
+
translator: [translatorId],
|
|
1611
|
+
translationOfWork: articleId,
|
|
1612
|
+
sourceUpdated: "2026-09-01T00:00:00Z",
|
|
1613
|
+
isBasedOn: revisionId
|
|
1614
|
+
}]
|
|
1615
|
+
}, { documentLoader: fetchDocumentLoader }), [{
|
|
1616
|
+
"@id": articleId,
|
|
1617
|
+
"@type": ["https://www.w3.org/ns/activitystreams#Article"],
|
|
1618
|
+
"https://www.w3.org/ns/activitystreams#content": [{
|
|
1619
|
+
"@language": "en",
|
|
1620
|
+
"@value": "Original"
|
|
1621
|
+
}, {
|
|
1622
|
+
"@language": "ko",
|
|
1623
|
+
"@value": "Translation"
|
|
1624
|
+
}],
|
|
1625
|
+
"https://w3id.org/fep/22cd#translations": [{
|
|
1626
|
+
"@type": ["https://w3id.org/fep/22cd#Translation"],
|
|
1627
|
+
"https://schema.org/inLanguage": [{ "@value": "ko" }],
|
|
1628
|
+
"https://schema.org/translator": [{ "@id": translatorId }],
|
|
1629
|
+
"https://schema.org/translationOfWork": [{ "@id": articleId }],
|
|
1630
|
+
"https://w3id.org/fep/22cd#sourceUpdated": [{
|
|
1631
|
+
"@type": "http://www.w3.org/2001/XMLSchema#dateTime",
|
|
1632
|
+
"@value": "2026-09-01T00:00:00Z"
|
|
1633
|
+
}],
|
|
1634
|
+
"https://schema.org/isBasedOn": [{ "@id": revisionId }]
|
|
1635
|
+
}]
|
|
1636
|
+
}]);
|
|
1637
|
+
deepStrictEqual(esm_default.callHistory.calls(url).length, 0);
|
|
1638
|
+
deepStrictEqual(esm_default.callHistory.calls("https://www.w3.org/ns/activitystreams").length, 0);
|
|
1639
|
+
});
|
|
1640
|
+
await t.step("deny non-HTTP/HTTPS", async () => {
|
|
1514
1641
|
await rejects(() => fetchDocumentLoader("ftp://localhost"), UrlError);
|
|
1515
1642
|
});
|
|
1516
1643
|
esm_default.get("https://example.com/localhost-redirect", {
|
|
@@ -1535,13 +1662,13 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1535
1662
|
name: "Fetched object",
|
|
1536
1663
|
type: "Object"
|
|
1537
1664
|
} });
|
|
1538
|
-
await t.
|
|
1665
|
+
await t.step("allowPrivateAddress: false", async () => {
|
|
1539
1666
|
await rejects(() => fetchDocumentLoader("https://localhost/object"), UrlError);
|
|
1540
1667
|
await rejects(() => fetchDocumentLoader("https://example.com/localhost-redirect"), UrlError);
|
|
1541
1668
|
await rejects(() => fetchDocumentLoader("https://example.com/localhost-link"), UrlError);
|
|
1542
1669
|
});
|
|
1543
1670
|
const fetchDocumentLoader2 = getDocumentLoader({ allowPrivateAddress: true });
|
|
1544
|
-
await t.
|
|
1671
|
+
await t.step("allowPrivateAddress: true", async () => {
|
|
1545
1672
|
const expected = {
|
|
1546
1673
|
contextUrl: null,
|
|
1547
1674
|
documentUrl: "https://localhost/object",
|
|
@@ -1564,12 +1691,12 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1564
1691
|
headers: { Location: `https://example.com/too-many-redirects/${Number(cl.url.split("/").at(-1)) + 1}` }
|
|
1565
1692
|
};
|
|
1566
1693
|
});
|
|
1567
|
-
await t.
|
|
1694
|
+
await t.step("too many redirects", async () => {
|
|
1568
1695
|
redirectAttempts = 0;
|
|
1569
1696
|
await rejects(() => fetchDocumentLoader("https://example.com/too-many-redirects/0"), FetchError, "Too many redirections");
|
|
1570
1697
|
deepStrictEqual(redirectAttempts, 21);
|
|
1571
1698
|
});
|
|
1572
|
-
await t.
|
|
1699
|
+
await t.step("custom max redirection", async () => {
|
|
1573
1700
|
redirectAttempts = 0;
|
|
1574
1701
|
const loader = getDocumentLoader({ maxRedirection: 1 });
|
|
1575
1702
|
await rejects(() => loader("https://example.com/too-many-redirects/0"), FetchError, "Too many redirections");
|
|
@@ -1590,7 +1717,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1590
1717
|
headers: { Location: "https://example.com/redirect-loop-a" }
|
|
1591
1718
|
};
|
|
1592
1719
|
});
|
|
1593
|
-
await t.
|
|
1720
|
+
await t.step("redirect loop", async () => {
|
|
1594
1721
|
loopAttempts = 0;
|
|
1595
1722
|
await rejects(() => fetchDocumentLoader("https://example.com/redirect-loop-a"), FetchError, "Redirect loop detected");
|
|
1596
1723
|
deepStrictEqual(loopAttempts, 2);
|
|
@@ -1603,7 +1730,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1603
1730
|
headers: { Location: "/redirect-loop-relative" }
|
|
1604
1731
|
};
|
|
1605
1732
|
});
|
|
1606
|
-
await t.
|
|
1733
|
+
await t.step("redirect loop with relative location", async () => {
|
|
1607
1734
|
relativeLoopAttempts = 0;
|
|
1608
1735
|
await rejects(() => fetchDocumentLoader("https://example.com/redirect-loop-relative"), FetchError, "Redirect loop detected");
|
|
1609
1736
|
deepStrictEqual(relativeLoopAttempts, 1);
|
|
@@ -1613,7 +1740,7 @@ test("getDocumentLoader()", async (t) => {
|
|
|
1613
1740
|
body: maliciousPayload,
|
|
1614
1741
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
1615
1742
|
});
|
|
1616
|
-
await t.
|
|
1743
|
+
await t.step("ReDoS resistance (CVE-2025-68475)", async () => {
|
|
1617
1744
|
const start = performance.now();
|
|
1618
1745
|
await rejects(() => fetchDocumentLoader("https://example.com/redos"), SyntaxError);
|
|
1619
1746
|
const elapsed = performance.now() - start;
|
|
@@ -1699,16 +1826,13 @@ test("getRemoteDocument() bounds JSON by default", async () => {
|
|
|
1699
1826
|
deepStrictEqual(pulls, 257);
|
|
1700
1827
|
});
|
|
1701
1828
|
test("getDocumentLoader() logs DNS failures as such", async (t) => {
|
|
1702
|
-
if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted")
|
|
1703
|
-
t.skip("requires the net permission");
|
|
1704
|
-
return;
|
|
1705
|
-
}
|
|
1829
|
+
if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted") throw new Error("This DNS test requires Deno network permission (--allow-net).");
|
|
1706
1830
|
const loader = getDocumentLoader();
|
|
1707
1831
|
for (const result of [
|
|
1708
1832
|
"throws",
|
|
1709
1833
|
"empty",
|
|
1710
1834
|
"private"
|
|
1711
|
-
]) await t.
|
|
1835
|
+
]) await t.step(result, async () => {
|
|
1712
1836
|
const originalLookup = dns.lookup;
|
|
1713
1837
|
dns.lookup = (() => result === "throws" ? Promise.reject(/* @__PURE__ */ new Error("Resolver unavailable")) : Promise.resolve(result === "empty" ? [] : [{
|
|
1714
1838
|
address: "127.0.0.1",
|
|
@@ -1763,7 +1887,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
1763
1887
|
"header",
|
|
1764
1888
|
"html",
|
|
1765
1889
|
"mixed"
|
|
1766
|
-
]) for (const hops of [20, 21]) await t.
|
|
1890
|
+
]) for (const hops of [20, 21]) await t.step(`${mode}: ${hops} hops`, async () => {
|
|
1767
1891
|
esm_default.mockGlobal();
|
|
1768
1892
|
let requests = 0;
|
|
1769
1893
|
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
@@ -1792,7 +1916,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
1792
1916
|
"alternate-redirect",
|
|
1793
1917
|
"redirect-alternate",
|
|
1794
1918
|
"redirect-intermediate"
|
|
1795
|
-
]) await t.
|
|
1919
|
+
]) await t.step(`${mode}: cycle`, async () => {
|
|
1796
1920
|
esm_default.mockGlobal();
|
|
1797
1921
|
let requests = 0;
|
|
1798
1922
|
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
@@ -1814,7 +1938,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
1814
1938
|
esm_default.hardReset();
|
|
1815
1939
|
}
|
|
1816
1940
|
});
|
|
1817
|
-
await t.
|
|
1941
|
+
await t.step("alternate followed by 20 redirects shares the limit", async () => {
|
|
1818
1942
|
esm_default.mockGlobal();
|
|
1819
1943
|
let requests = 0;
|
|
1820
1944
|
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
@@ -1834,7 +1958,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
1834
1958
|
esm_default.hardReset();
|
|
1835
1959
|
}
|
|
1836
1960
|
});
|
|
1837
|
-
await t.
|
|
1961
|
+
await t.step("relative alternate after redirect and isolated calls", async () => {
|
|
1838
1962
|
esm_default.mockGlobal();
|
|
1839
1963
|
esm_default.get(`${base}start`, Response.redirect(`${base}html`, 302));
|
|
1840
1964
|
esm_default.get(`${base}html`, alternate("./document", true));
|
|
@@ -1861,7 +1985,7 @@ test("getDocumentLoader() bounds alternate document chains", async (t) => {
|
|
|
1861
1985
|
test("getDocumentLoader() preserves cancellation across alternates", async (t) => {
|
|
1862
1986
|
const base = "https://example.com/alternate-abort/";
|
|
1863
1987
|
const loader = getDocumentLoader({ allowPrivateAddress: true });
|
|
1864
|
-
for (const html of [false, true]) await t.
|
|
1988
|
+
for (const html of [false, true]) await t.step(html ? "HTML" : "Link header", async () => {
|
|
1865
1989
|
esm_default.mockGlobal();
|
|
1866
1990
|
const controller = new AbortController();
|
|
1867
1991
|
let requests = 0;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as normalizeLanguageTag } from "./langtag-LDBqlxHv.mjs";
|
|
1
2
|
//#region src/langstr.ts
|
|
2
3
|
/**
|
|
3
4
|
* A language-tagged string which corresponds to the `rdf:langString` type.
|
|
@@ -12,11 +13,13 @@ var LanguageString = class extends String {
|
|
|
12
13
|
* Constructs a new `LanguageString`.
|
|
13
14
|
* @param value A string value written in the given language.
|
|
14
15
|
* @param language The language of the string. If a string is given, it will
|
|
15
|
-
* be parsed as a `Intl.Locale` object.
|
|
16
|
+
* be parsed as a `Intl.Locale` object. Extended language
|
|
17
|
+
* subtags are normalized first, e.g., `zh-yue` is parsed as
|
|
18
|
+
* `yue`.
|
|
16
19
|
*/
|
|
17
20
|
constructor(value, language) {
|
|
18
21
|
super(value);
|
|
19
|
-
this.locale = typeof language === "string" ? new Intl.Locale(language) : language;
|
|
22
|
+
this.locale = typeof language === "string" ? new Intl.Locale(normalizeLanguageTag(language)) : language;
|
|
20
23
|
}
|
|
21
24
|
};
|
|
22
25
|
LanguageString.prototype[Symbol.for("Deno.customInspect")] = function(inspect, options) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const require_langtag = require("./langtag-DgySESmk.cjs");
|
|
1
2
|
//#region src/langstr.ts
|
|
2
3
|
/**
|
|
3
4
|
* A language-tagged string which corresponds to the `rdf:langString` type.
|
|
@@ -12,11 +13,13 @@ var LanguageString = class extends String {
|
|
|
12
13
|
* Constructs a new `LanguageString`.
|
|
13
14
|
* @param value A string value written in the given language.
|
|
14
15
|
* @param language The language of the string. If a string is given, it will
|
|
15
|
-
* be parsed as a `Intl.Locale` object.
|
|
16
|
+
* be parsed as a `Intl.Locale` object. Extended language
|
|
17
|
+
* subtags are normalized first, e.g., `zh-yue` is parsed as
|
|
18
|
+
* `yue`.
|
|
16
19
|
*/
|
|
17
20
|
constructor(value, language) {
|
|
18
21
|
super(value);
|
|
19
|
-
this.locale = typeof language === "string" ? new Intl.Locale(language) : language;
|
|
22
|
+
this.locale = typeof language === "string" ? new Intl.Locale(require_langtag.normalizeLanguageTag(language)) : language;
|
|
20
23
|
}
|
|
21
24
|
};
|
|
22
25
|
LanguageString.prototype[Symbol.for("Deno.customInspect")] = function(inspect, options) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-C2EiDwsr.cjs");
|
|
2
|
-
const require_langstr = require("./langstr-
|
|
2
|
+
const require_langstr = require("./langstr-BsqFJupv.cjs");
|
|
3
3
|
let node_test = require("node:test");
|
|
4
4
|
let node_assert = require("node:assert");
|
|
5
5
|
let node_util = require("node:util");
|
|
@@ -11,6 +11,13 @@ node_util = require_chunk.__toESM(node_util, 1);
|
|
|
11
11
|
(0, node_assert.deepStrictEqual)(langStr.locale, new Intl.Locale("en"));
|
|
12
12
|
(0, node_assert.deepStrictEqual)(new require_langstr.LanguageString("Hello", new Intl.Locale("en")), langStr);
|
|
13
13
|
});
|
|
14
|
+
(0, node_test.test)("new LanguageString() with extlang tags", () => {
|
|
15
|
+
(0, node_assert.deepStrictEqual)(new require_langstr.LanguageString("你好", "zh-YUE").locale.baseName, "yue");
|
|
16
|
+
(0, node_assert.deepStrictEqual)(new require_langstr.LanguageString("你好", "zh-yue-HK").locale.baseName, "yue-HK");
|
|
17
|
+
(0, node_assert.deepStrictEqual)(new require_langstr.LanguageString("你好", "zh-cmn-Hant").locale.baseName, new Intl.Locale("cmn-Hant").baseName);
|
|
18
|
+
(0, node_assert.throws)(() => new require_langstr.LanguageString("Hello", "en-USA"), RangeError);
|
|
19
|
+
(0, node_assert.throws)(() => new require_langstr.LanguageString("你好", "zh-yue-"), RangeError);
|
|
20
|
+
});
|
|
14
21
|
(0, node_test.test)("Deno.inspect(LanguageString)", () => {
|
|
15
22
|
const langStr = new require_langstr.LanguageString("Hello, 'world'", "en");
|
|
16
23
|
(0, node_assert.deepStrictEqual)(node_util.default.inspect(langStr, { colors: false }), "<en> \"Hello, 'world'\"");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as LanguageString } from "./langstr-
|
|
1
|
+
import { t as LanguageString } from "./langstr-ABdAOKlF.mjs";
|
|
2
2
|
import { test } from "node:test";
|
|
3
|
-
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { deepStrictEqual, throws } from "node:assert";
|
|
4
4
|
import util from "node:util";
|
|
5
5
|
//#region src/langstr.test.ts
|
|
6
6
|
test("new LanguageString()", () => {
|
|
@@ -9,6 +9,13 @@ test("new LanguageString()", () => {
|
|
|
9
9
|
deepStrictEqual(langStr.locale, new Intl.Locale("en"));
|
|
10
10
|
deepStrictEqual(new LanguageString("Hello", new Intl.Locale("en")), langStr);
|
|
11
11
|
});
|
|
12
|
+
test("new LanguageString() with extlang tags", () => {
|
|
13
|
+
deepStrictEqual(new LanguageString("你好", "zh-YUE").locale.baseName, "yue");
|
|
14
|
+
deepStrictEqual(new LanguageString("你好", "zh-yue-HK").locale.baseName, "yue-HK");
|
|
15
|
+
deepStrictEqual(new LanguageString("你好", "zh-cmn-Hant").locale.baseName, new Intl.Locale("cmn-Hant").baseName);
|
|
16
|
+
throws(() => new LanguageString("Hello", "en-USA"), RangeError);
|
|
17
|
+
throws(() => new LanguageString("你好", "zh-yue-"), RangeError);
|
|
18
|
+
});
|
|
12
19
|
test("Deno.inspect(LanguageString)", () => {
|
|
13
20
|
const langStr = new LanguageString("Hello, 'world'", "en");
|
|
14
21
|
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-C2EiDwsr.cjs");
|
|
2
|
+
const require_langtag = require("./langtag-DgySESmk.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 { };
|