cizgile 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as fold, D as DEFAULT_TABLES, F as symbols, O as applyCompat, k as compileTables, m as latinLocales } from "./shared/locales-latin-Bm94HAeL.mjs";
1
+ import { M as applyCompat, N as compileTables, P as fold, j as DEFAULT_TABLES, n as registeredLocale, r as registryVersion, v as latinLocales, z as symbols } from "./shared/registry-D787niCh.mjs";
2
2
  import { h as isSegmentNzNc, r as percentEncode } from "./shared/percent-DG-pZhJI.mjs";
3
3
 
4
4
  //#region src/slug/bidi.ts
@@ -168,14 +168,15 @@ let cache$1;
168
168
  function resolveLocale(locale) {
169
169
  if (locale === void 0) return void 0;
170
170
  if (typeof locale === "string") {
171
- const found = latinLocales[locale];
172
- if (found === void 0) throw new TypeError(`slugify: unknown locale "${locale}"; pass a Locale object exported by cizgile/transliterate`);
171
+ const found = latinLocales[locale] ?? registeredLocale(locale);
172
+ if (found === void 0) throw new TypeError(`slugify: unknown locale "${locale}"; pass a Locale object exported by cizgile/transliterate, or register it with registerLocale()`);
173
173
  return found;
174
174
  }
175
175
  return locale;
176
176
  }
177
177
  function resolveTables(option, unicode, locale) {
178
178
  if (unicode) return void 0;
179
+ if (option === "none") return (locale === void 0 ? [symbols] : [locale.table, symbols]).map(symbolEntries);
179
180
  const out = [];
180
181
  if (locale !== void 0) {
181
182
  out.push(locale.table);
@@ -207,6 +208,15 @@ function build(options) {
207
208
  }
208
209
  const maxLength = options.maxLength;
209
210
  if (maxLength !== void 0 && (!Number.isInteger(maxLength) || maxLength < 0)) throw new RangeError("slugify: maxLength must be a non-negative integer");
211
+ const maxLengthUnit = options.maxLengthUnit ?? "units";
212
+ if (![
213
+ "units",
214
+ "code-points",
215
+ "graphemes",
216
+ "bytes"
217
+ ].includes(maxLengthUnit)) throw new TypeError(`slugify: unknown maxLengthUnit ${JSON.stringify(maxLengthUnit)}`);
218
+ const fallback = options.fallback;
219
+ if (fallback !== void 0 && typeof fallback !== "string" && typeof fallback !== "function") throw new TypeError("slugify: fallback must be a string or a function");
210
220
  const wordExtra = preserveCharacters.map(escapeClassChar).join("");
211
221
  const wordClass = unicode ? `\\p{L}\\p{N}\\p{M}${wordExtra}` : `a-z0-9${lowercase ? "" : "A-Z"}${wordExtra}`;
212
222
  const allowedClass = wordClass + separatorChars.map(escapeClassChar).join("");
@@ -227,6 +237,8 @@ function build(options) {
227
237
  preserveLeadingUnderscore: options.preserveLeadingUnderscore ?? false,
228
238
  preserveTrailingSeparator: options.preserveTrailingSeparator ?? false,
229
239
  maxLength,
240
+ maxLengthUnit,
241
+ fallback,
230
242
  scripts: options.scripts ?? "any",
231
243
  bidi: options.bidi ?? "allow",
232
244
  allowedClass,
@@ -257,6 +269,7 @@ function optionsKey(options) {
257
269
  const locale = options.locale;
258
270
  const transliterate = options.transliterate;
259
271
  const remove = options.remove;
272
+ const fallback = options.fallback;
260
273
  return JSON.stringify([
261
274
  options.separator,
262
275
  options.lowercase,
@@ -270,60 +283,31 @@ function optionsKey(options) {
270
283
  options.preserveLeadingUnderscore,
271
284
  options.preserveTrailingSeparator,
272
285
  options.maxLength,
286
+ options.maxLengthUnit,
287
+ typeof fallback === "function" ? `#${objectId(fallback)}` : fallback,
273
288
  options.scripts,
274
289
  options.bidi
275
290
  ]);
276
291
  }
277
292
  function resolveOptions(options = DEFAULT_OPTIONS$1) {
278
293
  cache$1 ??= /* @__PURE__ */ new WeakMap();
279
- const cached = cache$1.get(options);
280
- if (cached !== void 0) return cached;
294
+ const registered = typeof options.locale === "string" && !(options.locale in latinLocales);
295
+ if (!registered) {
296
+ const cached = cache$1.get(options);
297
+ if (cached !== void 0) return cached;
298
+ }
281
299
  byKey ??= /* @__PURE__ */ new Map();
282
- const key = optionsKey(options);
300
+ const key = registered ? `${registryVersion()}:${optionsKey(options)}` : optionsKey(options);
283
301
  let resolved = byKey.get(key);
284
302
  if (resolved === void 0) {
285
303
  resolved = build(options);
286
304
  if (byKey.size > 512) byKey.clear();
287
305
  byKey.set(key, resolved);
288
306
  }
289
- cache$1.set(options, resolved);
307
+ if (!registered) cache$1.set(options, resolved);
290
308
  return resolved;
291
309
  }
292
310
 
293
- //#endregion
294
- //#region src/slug/is-slug.ts
295
- let cache;
296
- function patternFor(options) {
297
- cache ??= /* @__PURE__ */ new WeakMap();
298
- const cached = cache.get(options);
299
- if (cached !== void 0) return cached;
300
- const o = resolveOptions(options);
301
- const char = `[${o.wordClass}]`;
302
- const separator = escapeRegExp$1(o.separator);
303
- const lead = o.preserveLeadingUnderscore ? "_?" : "";
304
- const word = o.unicode ? `(?!\\p{M})${char}+` : `${char}+`;
305
- const body = o.separator === "" ? word : `${word}(?:${separator}${word})*`;
306
- const tail = o.preserveTrailingSeparator && o.separator !== "" ? `(?:${separator})?` : "";
307
- const pattern = new RegExp(`^${lead}${body}${tail}$`, "u");
308
- cache.set(options, pattern);
309
- return pattern;
310
- }
311
- const DEFAULT_OPTIONS = {};
312
- /** Whether `input` is exactly what `slugify` would produce under the same options. */
313
- function isSlug(input, options = DEFAULT_OPTIONS) {
314
- if (typeof input !== "string" || input === "" || input === "." || input === "..") return false;
315
- const o = resolveOptions(options);
316
- if (o.maxLength !== void 0 && input.length > o.maxLength) return false;
317
- if (o.separator !== "" && input.includes(o.separator + o.separator)) return false;
318
- if (o.unicode) {
319
- if (input !== input.normalize("NFKC")) return false;
320
- if (o.lowercase && input !== lowercaseOf(input, o)) return false;
321
- if (o.scripts !== "any" && !checkScripts(input, o.scripts).ok) return false;
322
- if (o.bidi !== "allow" && !isBidiSafeComponent(input)) return false;
323
- }
324
- return patternFor(options).test(input);
325
- }
326
-
327
311
  //#endregion
328
312
  //#region src/slug/truncate.ts
329
313
  let segmenter;
@@ -339,6 +323,53 @@ function isJoinerBefore(text, index) {
339
323
  function isClusterExtender(cp) {
340
324
  return cp >= 56320 && cp <= 57343 || cp === 8205 || cp >= 65024 && cp <= 65039 || cp >= 127995 && cp <= 127999 || cp >= 4448 && cp <= 4607 || cp >= 917536 && cp <= 917631 || /\p{M}/u.test(String.fromCodePoint(cp));
341
325
  }
326
+ function utf8Length(cp) {
327
+ return cp < 128 ? 1 : cp < 2048 ? 2 : cp < 65536 ? 3 : 4;
328
+ }
329
+ /** The length of `text` in the given unit. */
330
+ function measure(text, unit = "units") {
331
+ if (unit === "units") return text.length;
332
+ let count = 0;
333
+ if (unit === "graphemes") {
334
+ const seg = graphemeSegmenter();
335
+ if (seg !== void 0) {
336
+ for (const _ of seg.segment(text)) count += 1;
337
+ return count;
338
+ }
339
+ let index = 0;
340
+ for (const ch of text) {
341
+ if (!(isClusterExtender(ch.codePointAt(0) ?? 0) || isJoinerBefore(text, index)) || index === 0) count += 1;
342
+ index += ch.length;
343
+ }
344
+ return count;
345
+ }
346
+ for (const ch of text) count += unit === "bytes" ? utf8Length(ch.codePointAt(0) ?? 0) : 1;
347
+ return count;
348
+ }
349
+ function prefixEnd(text, limit, unit) {
350
+ if (unit === "units") return Math.min(limit, text.length);
351
+ let used = 0;
352
+ if (unit === "graphemes") {
353
+ const seg = graphemeSegmenter();
354
+ if (seg !== void 0) {
355
+ let end = 0;
356
+ for (const { index, segment } of seg.segment(text)) {
357
+ if (used === limit) break;
358
+ used += 1;
359
+ end = index + segment.length;
360
+ }
361
+ return end;
362
+ }
363
+ }
364
+ let end = 0;
365
+ for (const ch of text) {
366
+ const cost = unit === "bytes" ? utf8Length(ch.codePointAt(0) ?? 0) : 1;
367
+ if (used + cost > limit) break;
368
+ used += cost;
369
+ end += ch.length;
370
+ }
371
+ return unit === "graphemes" ? graphemeBoundary(text, end, { fallback: true }) : end;
372
+ }
342
373
  function graphemeBoundary(text, limit, options = {}) {
343
374
  const seg = options.fallback === true ? void 0 : graphemeSegmenter();
344
375
  if (seg !== void 0) {
@@ -361,13 +392,14 @@ function stripTrailingSeparator(text, separator) {
361
392
  for (let k = separator.length - 1; k > 0; k--) if (out.endsWith(separator.slice(0, k))) return out.slice(0, -k);
362
393
  return out;
363
394
  }
364
- /** Cuts `slug` to at most `maxLength` UTF-16 code units at a `separator` boundary, never inside a grapheme cluster. */
365
- function truncateSlug(slug, maxLength, separator = "-") {
395
+ /** Cuts `slug` to at most `maxLength` in the given `unit` (UTF-16 code units by default) at a `separator` boundary, never inside a grapheme cluster. */
396
+ function truncateSlug(slug, maxLength, separator = "-", unit = "units") {
366
397
  if (!Number.isInteger(maxLength) || maxLength < 0) throw new RangeError("truncateSlug: maxLength must be a non-negative integer");
367
- if (slug.length <= maxLength) return slug;
398
+ if (measure(slug, unit) <= maxLength) return slug;
368
399
  if (maxLength === 0) return "";
369
- let cut = slug.slice(0, maxLength);
370
- if (separator !== "" && !slug.startsWith(separator, maxLength)) {
400
+ const limit = prefixEnd(slug, maxLength, unit);
401
+ let cut = slug.slice(0, limit);
402
+ if (separator !== "" && !slug.startsWith(separator, limit)) {
371
403
  const last = cut.lastIndexOf(separator);
372
404
  if (last > 0) cut = cut.slice(0, last);
373
405
  }
@@ -375,6 +407,40 @@ function truncateSlug(slug, maxLength, separator = "-") {
375
407
  return stripTrailingSeparator(cut, separator);
376
408
  }
377
409
 
410
+ //#endregion
411
+ //#region src/slug/is-slug.ts
412
+ let cache;
413
+ function patternFor(options) {
414
+ cache ??= /* @__PURE__ */ new WeakMap();
415
+ const cached = cache.get(options);
416
+ if (cached !== void 0) return cached;
417
+ const o = resolveOptions(options);
418
+ const char = `[${o.wordClass}]`;
419
+ const separator = escapeRegExp$1(o.separator);
420
+ const lead = o.preserveLeadingUnderscore ? "_?" : "";
421
+ const word = o.unicode ? `(?!\\p{M})${char}+` : `${char}+`;
422
+ const body = o.separator === "" ? word : `${word}(?:${separator}${word})*`;
423
+ const tail = o.preserveTrailingSeparator && o.separator !== "" ? `(?:${separator})?` : "";
424
+ const pattern = new RegExp(`^${lead}${body}${tail}$`, "u");
425
+ cache.set(options, pattern);
426
+ return pattern;
427
+ }
428
+ const DEFAULT_OPTIONS = {};
429
+ /** Whether `input` is exactly what `slugify` would produce under the same options. */
430
+ function isSlug(input, options = DEFAULT_OPTIONS) {
431
+ if (typeof input !== "string" || input === "" || input === "." || input === "..") return false;
432
+ const o = resolveOptions(options);
433
+ if (o.maxLength !== void 0 && measure(input, o.maxLengthUnit) > o.maxLength) return false;
434
+ if (o.separator !== "" && input.includes(o.separator + o.separator)) return false;
435
+ if (o.unicode) {
436
+ if (input !== input.normalize("NFKC")) return false;
437
+ if (o.lowercase && input !== lowercaseOf(input, o)) return false;
438
+ if (o.scripts !== "any" && !checkScripts(input, o.scripts).ok) return false;
439
+ if (o.bidi !== "allow" && !isBidiSafeComponent(input)) return false;
440
+ }
441
+ return patternFor(options).test(input);
442
+ }
443
+
378
444
  //#endregion
379
445
  //#region src/slug/slugify.ts
380
446
  const NON_ASCII = /[^\x00-\x7F]/;
@@ -414,10 +480,15 @@ function slugify(input, options) {
414
480
  if (o.leadingMarks !== void 0 && !ascii) s = s.replace(o.leadingMarks, "$1");
415
481
  const hadTrailingSeparator = o.separator !== "" && s.endsWith(o.separator);
416
482
  s = collapse(s, o);
417
- if (o.maxLength !== void 0) s = truncateSlug(s, o.maxLength, o.separator);
483
+ if (o.maxLength !== void 0) s = truncateSlug(s, o.maxLength, o.separator, o.maxLengthUnit);
418
484
  if (s === "." || s === "..") s = "";
419
485
  if (o.preserveLeadingUnderscore && hadLeadingUnderscore && s !== "" && !s.startsWith("_")) s = "_" + s;
420
486
  if (o.preserveTrailingSeparator && hadTrailingSeparator && s !== "") s += o.separator;
487
+ if (s === "" && o.fallback !== void 0) {
488
+ const text = typeof o.fallback === "string" ? o.fallback : o.fallback(input);
489
+ const { fallback: _fallback, ...rest } = options ?? {};
490
+ return slugify(text, rest);
491
+ }
421
492
  if (o.unicode && s !== "") {
422
493
  if (o.scripts !== "any") {
423
494
  const check = checkScripts(s, o.scripts);
@@ -433,11 +504,11 @@ function slugify(input, options) {
433
504
 
434
505
  //#endregion
435
506
  //#region src/slug/slugger.ts
436
- function withSuffix(base, separator, n, maxLength) {
507
+ function withSuffix(base, separator, n, maxLength, unit) {
437
508
  const suffix = separator + String(n);
438
- if (maxLength === void 0 || base.length + suffix.length <= maxLength) return base + suffix;
439
- const room = maxLength - suffix.length;
440
- const head = room > 0 ? truncateSlug(base, room, separator) : "";
509
+ if (maxLength === void 0 || measure(base + suffix, unit) <= maxLength) return base + suffix;
510
+ const room = maxLength - measure(suffix, unit);
511
+ const head = room > 0 ? truncateSlug(base, room, separator, unit) : "";
441
512
  return head === "" ? String(n).slice(0, maxLength) : head + suffix;
442
513
  }
443
514
  /** A slugger that never repeats a slug: the second `"Hello"` becomes `"hello-2"`. `defaults` apply to every call. */
@@ -460,7 +531,7 @@ function createSlugger(defaults = {}) {
460
531
  let candidate;
461
532
  do {
462
533
  n += 1;
463
- candidate = withSuffix(base, separator, n, merged.maxLength);
534
+ candidate = withSuffix(base, separator, n, merged.maxLength, merged.maxLengthUnit ?? "units");
464
535
  } while (issued.has(candidate));
465
536
  counters.set(base, n);
466
537
  issued.add(candidate);
@@ -483,4 +554,4 @@ function createSlugger(defaults = {}) {
483
554
  const slugifyWithCounter = createSlugger;
484
555
 
485
556
  //#endregion
486
- export { checkScripts, createSlugger, decamelize, detectScripts, isBidiSafeComponent, isSlug, slugify, slugifyWithCounter, truncateSlug };
557
+ export { checkScripts, createSlugger, decamelize, detectScripts, isBidiSafeComponent, isSlug, measure, slugify, slugifyWithCounter, truncateSlug };
@@ -0,0 +1,180 @@
1
+ //#region src/uri/punycode.ts
2
+ const BASE = 36;
3
+ const T_MIN = 1;
4
+ const T_MAX = 26;
5
+ const SKEW = 38;
6
+ const DAMP = 700;
7
+ const INITIAL_BIAS = 72;
8
+ const INITIAL_N = 128;
9
+ const DELIMITER = "-";
10
+ const PREFIX = "xn--";
11
+ const MAX_INT = 2147483647;
12
+ const LABEL_SEPARATORS = /[.\u3002\uFF0E\uFF61]/;
13
+ function adapt(delta, numPoints, firstTime) {
14
+ let d = firstTime ? Math.floor(delta / DAMP) : delta >> 1;
15
+ d += Math.floor(d / numPoints);
16
+ let k = 0;
17
+ while (d > 455) {
18
+ d = Math.floor(d / 35);
19
+ k += BASE;
20
+ }
21
+ return k + Math.floor(36 * d / (d + SKEW));
22
+ }
23
+ function digit(value) {
24
+ return String.fromCodePoint(value + (value < 26 ? 97 : 22));
25
+ }
26
+ function digitValue(cp) {
27
+ if (cp >= 48 && cp <= 57) return cp - 22;
28
+ if (cp >= 65 && cp <= 90) return cp - 65;
29
+ if (cp >= 97 && cp <= 122) return cp - 97;
30
+ return -1;
31
+ }
32
+ /** RFC 3492 Punycode encoding of one label, without the `xn--` prefix. */
33
+ function punycodeEncode(input) {
34
+ const points = Array.from(input, (ch) => ch.codePointAt(0) ?? 0);
35
+ let out = "";
36
+ for (const cp of points) if (cp < 128) out += String.fromCodePoint(cp);
37
+ const basicCount = out.length;
38
+ let handled = basicCount;
39
+ if (basicCount > 0) out += DELIMITER;
40
+ let n = INITIAL_N;
41
+ let delta = 0;
42
+ let bias = INITIAL_BIAS;
43
+ while (handled < points.length) {
44
+ let m = 1114112;
45
+ for (const cp of points) if (cp >= n && cp < m) m = cp;
46
+ delta += (m - n) * (handled + 1);
47
+ n = m;
48
+ for (const cp of points) {
49
+ if (cp < n) delta += 1;
50
+ if (cp === n) {
51
+ let q = delta;
52
+ for (let k = BASE;; k += BASE) {
53
+ const t = k <= bias ? T_MIN : k >= bias + T_MAX ? T_MAX : k - bias;
54
+ if (q < t) break;
55
+ out += digit(t + (q - t) % (BASE - t));
56
+ q = Math.floor((q - t) / (BASE - t));
57
+ }
58
+ out += digit(q);
59
+ bias = adapt(delta, handled + 1, handled === basicCount);
60
+ delta = 0;
61
+ handled += 1;
62
+ }
63
+ }
64
+ delta += 1;
65
+ n += 1;
66
+ }
67
+ return out;
68
+ }
69
+ /**
70
+ * RFC 3492 Punycode decoding of one label, without the `xn--` prefix.
71
+ * @throws {RangeError} on malformed input.
72
+ */
73
+ function punycodeDecode(input) {
74
+ const output = [];
75
+ const last = input.lastIndexOf(DELIMITER);
76
+ const basicEnd = last > 0 ? last : 0;
77
+ for (let i = 0; i < basicEnd; i++) {
78
+ const cp = input.codePointAt(i) ?? 0;
79
+ if (cp >= 128) throw new RangeError("punycodeDecode: invalid basic code point");
80
+ output.push(cp);
81
+ }
82
+ let n = INITIAL_N;
83
+ let bias = INITIAL_BIAS;
84
+ let i = 0;
85
+ let index = basicEnd > 0 ? basicEnd + 1 : 0;
86
+ while (index < input.length) {
87
+ const oldI = i;
88
+ let w = 1;
89
+ for (let k = BASE;; k += BASE) {
90
+ if (index >= input.length) throw new RangeError("punycodeDecode: truncated input");
91
+ const d = digitValue(input.codePointAt(index) ?? 0);
92
+ index += 1;
93
+ if (d < 0) throw new RangeError("punycodeDecode: invalid digit");
94
+ i += d * w;
95
+ if (i > MAX_INT) throw new RangeError("punycodeDecode: overflow");
96
+ const t = k <= bias ? T_MIN : k >= bias + T_MAX ? T_MAX : k - bias;
97
+ if (d < t) break;
98
+ w *= BASE - t;
99
+ }
100
+ const count = output.length + 1;
101
+ bias = adapt(i - oldI, count, oldI === 0);
102
+ n += Math.floor(i / count);
103
+ i %= count;
104
+ if (n > 1114111) throw new RangeError("punycodeDecode: code point out of range");
105
+ output.splice(i, 0, n);
106
+ i += 1;
107
+ }
108
+ return String.fromCodePoint(...output);
109
+ }
110
+ function isAsciiLabel(label) {
111
+ for (const ch of label) if ((ch.codePointAt(0) ?? 0) >= 128) return false;
112
+ return true;
113
+ }
114
+ function lowercaseCodePoints(text) {
115
+ let out = "";
116
+ for (const ch of text) out += ch.toLowerCase();
117
+ return out;
118
+ }
119
+ function mapLabel(label) {
120
+ return lowercaseCodePoints(label.replace(/\p{Cf}/gu, "").normalize("NFKC")).normalize("NFC");
121
+ }
122
+ function invalid(fn, label, reason) {
123
+ return /* @__PURE__ */ new RangeError(`${fn}: label ${JSON.stringify(label)} ${reason}`);
124
+ }
125
+ function decodeLabel(fn, label) {
126
+ let decoded;
127
+ try {
128
+ decoded = punycodeDecode(label.slice(4));
129
+ } catch {
130
+ throw invalid(fn, label, "is not valid Punycode");
131
+ }
132
+ if (decoded === "" || isAsciiLabel(decoded) || /[\p{C}\p{Z}]/u.test(decoded) || mapLabel(decoded) !== decoded || PREFIX + punycodeEncode(decoded) !== label) throw invalid(fn, label, "is not a valid A-label");
133
+ return decoded;
134
+ }
135
+ function checkAsciiLabel(fn, label, original) {
136
+ if (label.length > 63) throw invalid(fn, original, "exceeds 63 octets");
137
+ if (!/^[a-z0-9-]*$/.test(label)) throw invalid(fn, original, "contains characters outside letters, digits and hyphen");
138
+ if (label.startsWith("-") || label.endsWith("-")) throw invalid(fn, original, "may not start or end with a hyphen");
139
+ if (label.startsWith(PREFIX)) decodeLabel(fn, label);
140
+ else if (label.slice(2, 4) === "--") throw invalid(fn, original, "has hyphens in positions 3 and 4");
141
+ return label;
142
+ }
143
+ function checkDomain(fn, labels, host) {
144
+ if (labels.length > 1 && labels[labels.length - 1] === "") labels = labels.slice(0, -1);
145
+ for (const label of labels) if (label === "") throw invalid(fn, host, "contains an empty label");
146
+ const out = labels.join(".");
147
+ if (out.length > 253) throw new RangeError(`${fn}: ${JSON.stringify(host)} exceeds 253 octets`);
148
+ return out;
149
+ }
150
+ /**
151
+ * Converts a domain to its A-label form: maps and lowercases each label the way UTS #46 does, punycodes the non-ASCII ones, and validates lengths, hyphens and existing `xn--` labels. IP literals pass through.
152
+ * @throws {RangeError} when a label or the domain is not valid.
153
+ */
154
+ function domainToAscii(host) {
155
+ if (host === "" || host.startsWith("[")) return host;
156
+ const out = checkDomain("domainToAscii", host.split(LABEL_SEPARATORS).flatMap((label) => {
157
+ if (isAsciiLabel(label)) return [checkAsciiLabel("domainToAscii", label.toLowerCase(), label)];
158
+ const mapped = mapLabel(label);
159
+ if (mapped.includes(".")) return domainToAscii(mapped).split(".");
160
+ if (isAsciiLabel(mapped)) return [checkAsciiLabel("domainToAscii", mapped, label)];
161
+ return [checkAsciiLabel("domainToAscii", PREFIX + punycodeEncode(mapped), label)];
162
+ }), host);
163
+ return host.endsWith(".") && out !== "" ? `${out}.` : out;
164
+ }
165
+ /**
166
+ * Converts the `xn--` labels of a domain back to Unicode and lowercases the rest.
167
+ * @throws {RangeError} when an `xn--` label does not decode to a valid U-label.
168
+ */
169
+ function domainToUnicode(host) {
170
+ if (host === "" || host.startsWith("[")) return host;
171
+ const out = checkDomain("domainToUnicode", host.split(".").map((label) => {
172
+ const lower = label.toLowerCase();
173
+ if (!isAsciiLabel(lower)) return lower;
174
+ return lower.startsWith(PREFIX) ? decodeLabel("domainToUnicode", lower) : lower;
175
+ }), host);
176
+ return host.endsWith(".") && out !== "" ? `${out}.` : out;
177
+ }
178
+
179
+ //#endregion
180
+ export { punycodeEncode as i, domainToUnicode as n, punycodeDecode as r, domainToAscii as t };