@dcheglakov/uk-translit 1.0.0 → 1.0.1
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.d.ts +7 -2
- package/dist/index.js +144 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface SlugifyOptions {
|
|
2
|
+
separator?: string;
|
|
3
|
+
lowercase?: boolean;
|
|
4
|
+
}
|
|
5
|
+
declare function transliterate(input: string): string;
|
|
6
|
+
declare function slugify(input: string, options?: SlugifyOptions): string;
|
|
7
|
+
export { transliterate, slugify, SlugifyOptions };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,148 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
var WORD_START_MAP = {
|
|
3
|
+
Є: "Ye",
|
|
4
|
+
Ї: "Yi",
|
|
5
|
+
Й: "Y",
|
|
6
|
+
Ю: "Yu",
|
|
7
|
+
Я: "Ya",
|
|
8
|
+
є: "ye",
|
|
9
|
+
ї: "yi",
|
|
10
|
+
й: "y",
|
|
11
|
+
ю: "yu",
|
|
12
|
+
я: "ya"
|
|
13
|
+
};
|
|
14
|
+
var DEFAULT_MAP = {
|
|
15
|
+
А: "A",
|
|
16
|
+
Б: "B",
|
|
17
|
+
В: "V",
|
|
18
|
+
Г: "H",
|
|
19
|
+
Ґ: "G",
|
|
20
|
+
Д: "D",
|
|
21
|
+
Е: "E",
|
|
22
|
+
Є: "Ie",
|
|
23
|
+
Ж: "Zh",
|
|
24
|
+
З: "Z",
|
|
25
|
+
И: "Y",
|
|
26
|
+
І: "I",
|
|
27
|
+
Ї: "I",
|
|
28
|
+
Й: "I",
|
|
29
|
+
К: "K",
|
|
30
|
+
Л: "L",
|
|
31
|
+
М: "M",
|
|
32
|
+
Н: "N",
|
|
33
|
+
О: "O",
|
|
34
|
+
П: "P",
|
|
35
|
+
Р: "R",
|
|
36
|
+
С: "S",
|
|
37
|
+
Т: "T",
|
|
38
|
+
У: "U",
|
|
39
|
+
Ф: "F",
|
|
40
|
+
Х: "Kh",
|
|
41
|
+
Ц: "Ts",
|
|
42
|
+
Ч: "Ch",
|
|
43
|
+
Ш: "Sh",
|
|
44
|
+
Щ: "Shch",
|
|
45
|
+
Ю: "Iu",
|
|
46
|
+
Я: "Ia",
|
|
47
|
+
а: "a",
|
|
48
|
+
б: "b",
|
|
49
|
+
в: "v",
|
|
50
|
+
г: "h",
|
|
51
|
+
ґ: "g",
|
|
52
|
+
д: "d",
|
|
53
|
+
е: "e",
|
|
54
|
+
є: "ie",
|
|
55
|
+
ж: "zh",
|
|
56
|
+
з: "z",
|
|
57
|
+
и: "y",
|
|
58
|
+
і: "i",
|
|
59
|
+
ї: "i",
|
|
60
|
+
й: "i",
|
|
61
|
+
к: "k",
|
|
62
|
+
л: "l",
|
|
63
|
+
м: "m",
|
|
64
|
+
н: "n",
|
|
65
|
+
о: "o",
|
|
66
|
+
п: "p",
|
|
67
|
+
р: "r",
|
|
68
|
+
с: "s",
|
|
69
|
+
т: "t",
|
|
70
|
+
у: "u",
|
|
71
|
+
ф: "f",
|
|
72
|
+
х: "kh",
|
|
73
|
+
ц: "ts",
|
|
74
|
+
ч: "ch",
|
|
75
|
+
ш: "sh",
|
|
76
|
+
щ: "shch",
|
|
77
|
+
ю: "iu",
|
|
78
|
+
я: "ia",
|
|
79
|
+
Ь: "",
|
|
80
|
+
ь: "",
|
|
81
|
+
"'": "",
|
|
82
|
+
"’": "",
|
|
83
|
+
"ʼ": "",
|
|
84
|
+
"`": ""
|
|
85
|
+
};
|
|
86
|
+
var NON_BOUNDARY_SEPARATORS = new Set(["'", "’", "ʼ", "`", "Ь", "ь"]);
|
|
87
|
+
function isCyrillicLetter(char) {
|
|
88
|
+
return /[А-ЩЬЮЯЄІЇҐа-щьюяєіїґ]/u.test(char);
|
|
89
|
+
}
|
|
90
|
+
function isWordBoundary(char) {
|
|
91
|
+
if (!char) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (NON_BOUNDARY_SEPARATORS.has(char)) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (isCyrillicLetter(char)) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
function isZghSequence(source, index) {
|
|
103
|
+
const current = source[index];
|
|
104
|
+
const next = source[index + 1];
|
|
105
|
+
return (current === "З" || current === "з") && (next === "Г" || next === "г");
|
|
106
|
+
}
|
|
107
|
+
function transliterateZgh(source, index) {
|
|
108
|
+
const current = source[index];
|
|
109
|
+
const next = source[index + 1];
|
|
110
|
+
if (current === "З" && next === "Г") {
|
|
111
|
+
return "ZGH";
|
|
112
|
+
}
|
|
113
|
+
if (current === "З" && next === "г") {
|
|
114
|
+
return "Zgh";
|
|
115
|
+
}
|
|
116
|
+
if (current === "з" && next === "Г") {
|
|
117
|
+
return "zGH";
|
|
118
|
+
}
|
|
119
|
+
return "zgh";
|
|
120
|
+
}
|
|
121
|
+
function transliterate(input) {
|
|
122
|
+
let result = "";
|
|
123
|
+
for (let index = 0;index < input.length; index += 1) {
|
|
124
|
+
const char = input[index] ?? "";
|
|
125
|
+
if (isZghSequence(input, index)) {
|
|
126
|
+
result += transliterateZgh(input, index);
|
|
127
|
+
index += 1;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const previousChar = index > 0 ? input[index - 1] : undefined;
|
|
131
|
+
const isWordStart = isWordBoundary(previousChar);
|
|
132
|
+
const mappedChar = isWordStart ? WORD_START_MAP[char] ?? DEFAULT_MAP[char] : DEFAULT_MAP[char];
|
|
133
|
+
result += mappedChar ?? char;
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
function slugify(input, options = {}) {
|
|
138
|
+
const separator = options.separator ?? "-";
|
|
139
|
+
const lowercase = options.lowercase ?? true;
|
|
140
|
+
const transliterated = transliterate(input);
|
|
141
|
+
const normalized = lowercase ? transliterated.toLowerCase() : transliterated;
|
|
142
|
+
const escapedSeparator = separator.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
143
|
+
return normalized.replace(/[^a-z0-9]+/gi, separator).replace(new RegExp(`${escapedSeparator}{2,}`, "g"), separator).replace(new RegExp(`^${escapedSeparator}|${escapedSeparator}$`, "g"), "");
|
|
4
144
|
}
|
|
5
145
|
export {
|
|
6
|
-
|
|
146
|
+
transliterate,
|
|
147
|
+
slugify
|
|
7
148
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcheglakov/uk-translit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Official Ukrainian transliteration and slug generation for TypeScript, built according to the current rules of the Cabinet of Ministers of Ukraine Resolution No. 55. Designed for headless CMS workflows, with context-aware transliteration, clean slug output, strong test coverage, and a modern release pipeline.",
|
|
5
5
|
"homepage": "https://github.com/dcheglakov/uk-translit#readme",
|
|
6
6
|
"bugs": {
|