cizgile 0.3.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.
@@ -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 };
@@ -182,6 +182,8 @@ const symbols = {
182
182
  //#region src/transliterate/core.ts
183
183
  /** The tables every call consults last: `latin`, then `symbols`. */
184
184
  const DEFAULT_TABLES = [latin, symbols];
185
+ /** A table key that starts with this character is a rule: the rest is a regular expression source (flags `gu`) and the value its replacement, `$1` groups allowed. Rules run in table order, before the sequences and the character lookup; the scripts that reorder or contextualise letters (Thai, Lao, Khmer, Myanmar) use them. */
186
+ const RULE_PREFIX = "";
185
187
  const NON_ASCII = /[^\x00-\x7F]/;
186
188
  let tableIds;
187
189
  let nextTableId = 0;
@@ -205,17 +207,20 @@ function tableId(table) {
205
207
  function build(tables) {
206
208
  const map = /* @__PURE__ */ new Map();
207
209
  const multi = [];
210
+ const rules = [];
208
211
  for (const table of tables) for (const key of Object.keys(table)) {
209
212
  if (map.has(key)) continue;
210
213
  const value = table[key] ?? "";
211
214
  map.set(key, value);
212
- if (codePointCount(key) > 1) multi.push([key, value]);
215
+ if (key.startsWith("")) rules.push([new RegExp(key.slice(1), "gu"), value]);
216
+ else if (codePointCount(key) > 1) multi.push([key, value]);
213
217
  }
214
218
  multi.sort((a, b) => b[0].length - a[0].length);
215
219
  const asciiKeys = [...map.keys()].filter((key) => key.length === 1 && (key.codePointAt(0) ?? 0) < 128);
216
220
  return {
217
221
  map,
218
222
  sequences: multi,
223
+ rules,
219
224
  ascii: asciiKeys.length === 0 ? void 0 : new RegExp(`[${asciiKeys.map((k) => k.replace(/[\]\\^-]/g, "\\$&")).join("")}]`, "g"),
220
225
  folded: /* @__PURE__ */ new Map()
221
226
  };
@@ -293,6 +298,7 @@ function fold(input, tables, dropUnknown, foldMarks = true) {
293
298
  const map = compiled.map;
294
299
  let text = input;
295
300
  if (!NON_ASCII.test(text)) return compiled.ascii === void 0 ? text : text.replace(compiled.ascii, (m) => map.get(m) ?? m);
301
+ for (const [pattern, to] of compiled.rules) text = text.replace(pattern, to);
296
302
  if (compiled.sequences.length > 0) {
297
303
  for (const [key, value] of compiled.sequences) if (text.includes(key)) text = text.split(key).join(value);
298
304
  }
@@ -331,7 +337,7 @@ function compatEntries(table) {
331
337
  const cached = compatCache.get(table);
332
338
  if (cached !== void 0) return cached;
333
339
  const out = [];
334
- for (const [key, value] of Object.entries(table)) if (key.normalize("NFKC") !== key) out.push([key, value]);
340
+ for (const [key, value] of Object.entries(table)) if (key.normalize("NFKC") !== key && !key.startsWith("")) out.push([key, value]);
335
341
  compatCache.set(table, out);
336
342
  return out;
337
343
  }
@@ -16,8 +16,8 @@ interface Locale {
16
16
  type LatinLocaleId = "az" | "ca" | "cs" | "da" | "de" | "es" | "et" | "fi" | "fr" | "hr" | "hu" | "is" | "it" | "lt" | "lv" | "nb" | "nl" | "pl" | "pt" | "ro" | "sk" | "sl" | "sv" | "tr" | "vi";
17
17
  /** Locales that carry the Cyrillic table; import the objects from `cizgile/transliterate`. */
18
18
  type CyrillicLocaleId = "be" | "bg" | "kk" | "mk" | "ru" | "sr" | "uk";
19
- /** Locales that carry the Greek, Hebrew, kana or Hangul table; import the objects from `cizgile/transliterate`. */
20
- type OtherLocaleId = "bn" | "el" | "gu" | "he" | "hi" | "ja" | "kn" | "ko" | "ml" | "or" | "pa" | "ta" | "te";
19
+ /** Locales that carry a Greek, Hebrew, Indic, Southeast Asian, kana or Hangul table; import the objects from `cizgile/transliterate`. */
20
+ type OtherLocaleId = "bn" | "el" | "gu" | "he" | "hi" | "ja" | "km" | "kn" | "ko" | "lo" | "ml" | "my" | "or" | "pa" | "si" | "ta" | "te" | "th";
21
21
  /** Every id in the `locales` registry. */
22
22
  type LocaleId = LatinLocaleId | CyrillicLocaleId | OtherLocaleId;
23
23
  //#endregion
@@ -1,4 +1,4 @@
1
- import { a as OtherLocaleId, i as LocaleId, n as LatinLocaleId, o as TransliterationTable, r as Locale, t as CyrillicLocaleId } from "./shared/types-B3EVWvDh.mjs";
1
+ import { a as OtherLocaleId, i as LocaleId, n as LatinLocaleId, o as TransliterationTable, r as Locale, t as CyrillicLocaleId } from "./shared/types-D5P1JMcX.mjs";
2
2
  //#region src/transliterate/core.d.ts
3
3
  /** Options for `transliterate`. */
4
4
  interface TransliterateOptions {
@@ -17,6 +17,7 @@ type Sequences = ReadonlyArray<readonly [string, string]>;
17
17
  interface CompiledTables {
18
18
  readonly map: ReadonlyMap<string, string>;
19
19
  readonly sequences: Sequences;
20
+ readonly rules: ReadonlyArray<readonly [RegExp, string]>;
20
21
  readonly ascii: RegExp | undefined;
21
22
  readonly folded: Map<string, string | null>;
22
23
  }
@@ -94,14 +95,30 @@ export declare const gurmukhi: TransliterationTable;
94
95
  /** Kannada to Latin without diacritics, syllable by syllable like the Devanagari table: inherent `a`, no vowel length, no schwa deletion. */
95
96
  export declare const kannada: TransliterationTable;
96
97
  //#endregion
98
+ //#region src/transliterate/khmer.d.ts
99
+ /** Khmer to Latin in a simple UNGEGN-style scheme: consonants keep one value each, subscript consonants (after the coeng) follow their base, and the vowel signs read as the `a` series (`ក ខ ច ដ ត ប ស ហ អ`...) or the `o` series (`គ ង ជ ទ ន ព ម យ រ ល វ`...) of the base consonant, so `ា` is `a` after `ក` and `ea` after `គ`. A bare consonant after a vowel is read as a final, otherwise it takes its inherent `a` or `o`. There is no dictionary or word segmentation, so `ភ្នំពេញ` is `phnumpenh` and `កម្ពុជា` is `kampuchea`. */
100
+ export declare const khmer: TransliterationTable;
101
+ //#endregion
102
+ //#region src/transliterate/lao.d.ts
103
+ /** Lao to Latin in a simple BGN/PCGN-style scheme, without tone marks: the vowels written before the consonant (`ເ ແ ໂ ໃ ໄ`) are moved after it, a consonant is read as initial or final from its neighbours, and a bare consonant takes `a` or, before the final, `o`. Words are not segmented and there is no dictionary, so `ວຽງຈັນ` is `viangchan` and `ລາວ` is `lao`. */
104
+ export declare const lao: TransliterationTable;
105
+ //#endregion
97
106
  //#region src/transliterate/malayalam.d.ts
98
107
  /** Malayalam to Latin without diacritics, syllable by syllable like the Devanagari table: inherent `a`, no vowel length, no schwa deletion. */
99
108
  export declare const malayalam: TransliterationTable;
100
109
  //#endregion
110
+ //#region src/transliterate/myanmar.d.ts
111
+ /** Myanmar (Burmese) to Latin in a simple BGN/MLC-style scheme without tone marks: consonants carry an inherent `a` unless a vowel sign, the asat or a stacked consonant follows, the medials read `y`, `w` and `h` (`မြန်မာ` is `myanma`, `ရန်ကုန်` is `yankun`). Aspirates are `hs`, `ht`, `hp`; no sound change between syllables is applied. */
112
+ export declare const myanmar: TransliterationTable;
113
+ //#endregion
101
114
  //#region src/transliterate/oriya.d.ts
102
115
  /** Oriya to Latin without diacritics, syllable by syllable like the Devanagari table: inherent `a`, no vowel length, no schwa deletion. */
103
116
  export declare const oriya: TransliterationTable;
104
117
  //#endregion
118
+ //#region src/transliterate/sinhala.d.ts
119
+ /** Sinhala to Latin without diacritics, syllable by syllable like the Devanagari table: inherent `a`, the al-lakuna (virama) removes it, no vowel length is marked and no schwa deletion is applied, so `කොළඹ` is `kolamba`. */
120
+ export declare const sinhala: TransliterationTable;
121
+ //#endregion
105
122
  //#region src/transliterate/tamil.d.ts
106
123
  /** Tamil to Latin without diacritics, syllable by syllable like the Devanagari table: inherent `a`, no vowel length, no schwa deletion. */
107
124
  export declare const tamil: TransliterationTable;
@@ -110,6 +127,10 @@ export declare const tamil: TransliterationTable;
110
127
  /** Telugu to Latin without diacritics, syllable by syllable like the Devanagari table: inherent `a`, no vowel length, no schwa deletion. */
111
128
  export declare const telugu: TransliterationTable;
112
129
  //#endregion
130
+ //#region src/transliterate/thai.d.ts
131
+ /** Thai to Latin after the Royal Thai General System of Transcription, without tone marks and vowel length. The vowels written before the consonant (`เ แ โ ใ ไ`) are moved after it, a consonant is read as initial or final from its neighbours (`ก` is `k` either way, `จ` is `ch` and `t`, `ร` is `r` and `n`), and a bare consonant takes `a` or, before the final, `o`. Words are not segmented and no dictionary is used, so irregular spellings follow those rules: `ไทย` is `thai`, `กรุงเทพ` is `krungthep`. */
132
+ export declare const thai: TransliterationTable;
133
+ //#endregion
113
134
  //#region src/transliterate/dhivehi.d.ts
114
135
  /** Thaana (Dhivehi) to Latin, the sindresorhus/transliterate values. */
115
136
  export declare const dhivehi: TransliterationTable;
@@ -183,6 +204,16 @@ export declare const te: Locale;
183
204
  export declare const kn: Locale;
184
205
  /** Malayalam: the malayalam table, `&` becomes `um`. */
185
206
  export declare const ml: Locale;
207
+ /** Thai: the thai table, `&` becomes `lae`. */
208
+ export declare const th: Locale;
209
+ /** Lao: the lao table, `&` becomes `lae`. */
210
+ export declare const lo: Locale;
211
+ /** Khmer: the khmer table, `&` becomes `ning`. */
212
+ export declare const km: Locale;
213
+ /** Burmese: the myanmar table, `&` becomes `hnin`. */
214
+ export declare const my: Locale;
215
+ /** Sinhala: the sinhala table, `&` becomes `saha`. */
216
+ export declare const si: Locale;
186
217
  /** The locales that carry a non-Latin, non-Cyrillic script table, by id. */
187
218
  export declare const otherLocales: Readonly<Record<OtherLocaleId, Locale>>;
188
219
  //#endregion