@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.
@@ -1,12 +1,12 @@
1
- import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-JVGlYdPG.mjs";
2
- import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-CGeu_wlY.mjs";
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.test("ok", async () => {
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.test("Link header", async () => {
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.test("Link header relative url", async () => {
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.test("wrong Link header syntax", async () => {
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.test("HTML <link>", async () => {
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.test("XHTML <link>", async () => {
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.test("HTML <a>", async () => {
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.test("Wrong Content-Type", async () => {
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.test("not ok", async () => {
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.test("preloaded contexts", async () => {
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.test("preloaded CID v1 context", async () => {
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.test("preloaded FEP-ef61 context", async () => {
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.test("preloaded FEP-7aa9 context", async () => {
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.test("preloaded FEP-6757 context", async () => {
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.test("preloaded FEP-22cd context", async () => {
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.test("deny non-HTTP/HTTPS", async () => {
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.test("allowPrivateAddress: false", async () => {
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.test("allowPrivateAddress: true", async () => {
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.test("too many redirects", async () => {
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.test("redirect loop", async () => {
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.test("redirect loop with relative location", async () => {
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.test("ReDoS resistance (CVE-2025-68475)", async () => {
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.test(result, async () => {
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.test(`${mode}: ${hops} hops`, async () => {
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.test(`${mode}: cycle`, async () => {
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.test("alternate followed by 20 redirects shares the limit", async () => {
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.test("relative alternate after redirect and isolated calls", async () => {
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.test(html ? "HTML" : "Link header", async () => {
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, node_test.test)("multibase.encode and decode", async (t) => {
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.test(`Encoding/Decoding ${name} with ${input}`, () => {
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.test("should allow base32pad full alphabet", () => {
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, node_test.test)("constants", async (t) => {
330
- await t.test("constants indexed by name", () => {
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.test("constants indexed by code", () => {
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.test(`Encoding/Decoding ${name} with ${input}`, () => {
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.test("should allow base32pad full alphabet", () => {
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.test("constants indexed by name", () => {
329
+ await t.step("constants indexed by name", () => {
330
330
  deepStrictEqual(Object.keys(names).length, 23);
331
331
  });
332
- await t.test("constants indexed by code", () => {
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.2306+e775cf8c";
6
+ var version = "2.0.31-dev.2310+e604de57";
7
7
  //#endregion
8
8
  //#region src/request.ts
9
9
  /**
@@ -1,7 +1,7 @@
1
1
  import process from "node:process";
2
2
  //#region deno.json
3
3
  var name = "@fedify/vocab-runtime";
4
- var version = "2.0.31-dev.2306+e775cf8c";
4
+ var version = "2.0.31-dev.2310+e604de57";
5
5
  //#endregion
6
6
  //#region src/request.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Do9eywBl.cjs");
2
- const require_request = require("./request-75RoXeN4.cjs");
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-JVGlYdPG.mjs";
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";