turkce-utils 0.0.0-stage → 0.1.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +234 -2
  3. package/dist/case.d.ts +12 -0
  4. package/dist/case.d.ts.map +1 -0
  5. package/dist/case.js +18 -0
  6. package/dist/case.js.map +1 -0
  7. package/dist/cli.d.ts +10 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +119 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/index.d.ts +17 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +13 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/initials.d.ts +12 -0
  16. package/dist/initials.d.ts.map +1 -0
  17. package/dist/initials.js +16 -0
  18. package/dist/initials.js.map +1 -0
  19. package/dist/normalize.d.ts +14 -0
  20. package/dist/normalize.d.ts.map +1 -0
  21. package/dist/normalize.js +27 -0
  22. package/dist/normalize.js.map +1 -0
  23. package/dist/numbers.d.ts +11 -0
  24. package/dist/numbers.d.ts.map +1 -0
  25. package/dist/numbers.js +76 -0
  26. package/dist/numbers.js.map +1 -0
  27. package/dist/ordinal.d.ts +11 -0
  28. package/dist/ordinal.d.ts.map +1 -0
  29. package/dist/ordinal.js +43 -0
  30. package/dist/ordinal.js.map +1 -0
  31. package/dist/readability.d.ts +24 -0
  32. package/dist/readability.d.ts.map +1 -0
  33. package/dist/readability.js +50 -0
  34. package/dist/readability.js.map +1 -0
  35. package/dist/slug.d.ts +18 -0
  36. package/dist/slug.d.ts.map +1 -0
  37. package/dist/slug.js +47 -0
  38. package/dist/slug.js.map +1 -0
  39. package/dist/sort.d.ts +12 -0
  40. package/dist/sort.d.ts.map +1 -0
  41. package/dist/sort.js +17 -0
  42. package/dist/sort.js.map +1 -0
  43. package/dist/syllables.d.ts +9 -0
  44. package/dist/syllables.d.ts.map +1 -0
  45. package/dist/syllables.js +12 -0
  46. package/dist/syllables.js.map +1 -0
  47. package/dist/title.d.ts +6 -0
  48. package/dist/title.d.ts.map +1 -0
  49. package/dist/title.js +14 -0
  50. package/dist/title.js.map +1 -0
  51. package/dist/truncate.d.ts +6 -0
  52. package/dist/truncate.d.ts.map +1 -0
  53. package/dist/truncate.js +18 -0
  54. package/dist/truncate.js.map +1 -0
  55. package/package.json +64 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mehmet Fatih Doğan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,235 @@
1
- # Temporary Holding Version
1
+ # turkce-utils
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![CI](https://github.com/fatihdogann/turkce-utils/actions/workflows/ci.yml/badge.svg)](https://github.com/fatihdogann/turkce-utils/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
+ [![Runtime dependencies: 0](https://img.shields.io/badge/runtime_dependencies-0-brightgreen.svg)](#development)
6
+
7
+ Zero-dependency TypeScript helpers for Turkish text — and a `turkce` CLI.
8
+
9
+ Turkish is not English with a few accents: `I` lowercases to `ı`, `i`
10
+ uppercases to `İ`, the alphabet puts `ç`, `ğ`, `ı`, `ö`, `ş`, `ü` in their own
11
+ places, and reading difficulty needs its own formula. `turkce-utils` packages
12
+ those rules into small, tested, dependency-free functions.
13
+
14
+ ```ts
15
+ import { slugify, upperTr, sortTr } from "turkce-utils";
16
+
17
+ slugify("Çılgın Şöför İĞÜ"); // "cilgin-sofor-igu"
18
+ upperTr("istanbul ışık"); // "İSTANBUL IŞIK"
19
+ sortTr(["üzüm", "armut", "çilek"]); // ["armut", "çilek", "üzüm"]
20
+ ```
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ npm install turkce-utils
26
+ ```
27
+
28
+ Requires Node.js 20 or later. The published package is compiled ESM with type
29
+ declarations and **zero runtime dependencies**.
30
+
31
+ Working on the library itself? Node.js 22.18+ can run the TypeScript sources
32
+ directly — see [Development](#development).
33
+
34
+ ## Modules
35
+
36
+ | Module | What it does |
37
+ | --- | --- |
38
+ | `slug` | Turkish-aware slug generation |
39
+ | `case` | Turkish letter casing (i/İ, ı/I) |
40
+ | `sort` | Turkish alphabet collation |
41
+ | `title` | Turkish title casing |
42
+ | `normalize` | Normalise typographic punctuation and whitespace |
43
+ | `numbers` | Spell out numbers in Turkish |
44
+ | `ordinal` | Turkish ordinal numbers |
45
+ | `syllables` | Count syllables |
46
+ | `readability` | Ateşman readability score |
47
+ | `truncate` | Truncate on a word boundary |
48
+ | `initials` | Initials from a full name |
49
+ | `cli` | `turkce` command line interface |
50
+
51
+ ## API
52
+
53
+ ### `slugify(input, options?)`
54
+
55
+ Turkish-aware slug: `ç → c`, `ğ → g`, `ı → i`, `İ → i`, `ö → o`, `ş → s`, `ü → u`.
56
+ Remaining diacritics are folded, punctuation is dropped.
57
+
58
+ ```ts
59
+ import { slugify } from "turkce-utils";
60
+
61
+ slugify("Çılgın Şöför İĞÜ"); // "cilgin-sofor-igu"
62
+ slugify("Türkçe Metin", { separator: "_" }); // "turkce_metin"
63
+ slugify("kahve falı bakıyoruz", { maxLength: 10 }); // "kahve"
64
+ ```
65
+
66
+ Options: `separator` (default `"-"`), `lowercase` (default `true`), `maxLength`.
67
+
68
+ ### `lowerTr(input)` / `upperTr(input)`
69
+
70
+ Turkish letter casing. JavaScript maps `I → i` and `i → I`; Turkish pairs the
71
+ dotless `ı` with `I` and the dotted `i` with `İ`.
72
+
73
+ ```ts
74
+ import { lowerTr, upperTr } from "turkce-utils";
75
+
76
+ lowerTr("İSTANBUL"); // "istanbul"
77
+ lowerTr("IŞIK"); // "ışık"
78
+ upperTr("istanbul ışık"); // "İSTANBUL IŞIK"
79
+ ```
80
+
81
+ ### `sortTr(items)` / `compareTr(a, b)`
82
+
83
+ Sort by the Turkish alphabet — `ç` after `c`, `ğ` after `g`, `ı` before `i`,
84
+ `ö`, `ş`, `ü` in place — backed by `Intl.Collator("tr")`.
85
+
86
+ ```ts
87
+ import { sortTr } from "turkce-utils";
88
+
89
+ sortTr(["zeytin", "armut", "üzüm", "çilek", "ıspanak", "incir"]);
90
+ // ["armut", "çilek", "ıspanak", "incir", "üzüm", "zeytin"]
91
+ ```
92
+
93
+ ### `titleCaseTr(input)`
94
+
95
+ Title-case with Turkish rules; the suffix after an apostrophe stays lowercase.
96
+
97
+ ```ts
98
+ import { titleCaseTr } from "turkce-utils";
99
+
100
+ titleCaseTr("çılgın şöför istanbul'da"); // "Çılgın Şöför İstanbul'da"
101
+ titleCaseTr("TÜRKÇE METİN IŞIK"); // "Türkçe Metin Işık"
102
+ ```
103
+
104
+ ### `normalizeTr(input, options?)`
105
+
106
+ NFC normalisation plus typographic fixes: smart quotes → `"`/`'`, en/em dashes →
107
+ `-`, `…` → `...`, non-breaking and zero-width spaces handled, whitespace collapsed.
108
+
109
+ ```ts
110
+ import { normalizeTr } from "turkce-utils";
111
+
112
+ normalizeTr("“Merhaba” —dünya…"); // '"Merhaba" -dünya...'
113
+ normalizeTr(" bir iki "); // "bir iki"
114
+ ```
115
+
116
+ ### `numberToWordsTr(value)` / `integerToWordsTr(value)`
117
+
118
+ Spell out numbers in Turkish, including negatives and decimals.
119
+
120
+ ```ts
121
+ import { numberToWordsTr } from "turkce-utils";
122
+
123
+ numberToWordsTr(1234); // "bin iki yüz otuz dört"
124
+ numberToWordsTr(1000000); // "bir milyon"
125
+ numberToWordsTr(-5); // "eksi beş"
126
+ numberToWordsTr(3.5); // "üç virgül beş"
127
+ ```
128
+
129
+ `1000` is spoken as `bin`, never `bir bin`.
130
+
131
+ ### `ordinalTr(value)` / `ordinalWordTr(value)`
132
+
133
+ ```ts
134
+ import { ordinalTr, ordinalWordTr } from "turkce-utils";
135
+
136
+ ordinalTr(3); // "3."
137
+ ordinalWordTr(3); // "üçüncü"
138
+ ordinalWordTr(4); // "dördüncü"
139
+ ordinalWordTr(121); // "yüz yirmi birinci"
140
+ ```
141
+
142
+ Suffixes follow Turkish vowel harmony.
143
+
144
+ ### `syllablesTr(input)`
145
+
146
+ Turkish is one vowel per syllable, so the count is the number of vowel groups.
147
+
148
+ ```ts
149
+ import { syllablesTr } from "turkce-utils";
150
+
151
+ syllablesTr("Türkçe"); // 2
152
+ syllablesTr("yapıyoruz"); // 4
153
+ ```
154
+
155
+ ### `atestmanScore(text)` / `atestmanGrade(score)`
156
+
157
+ Ateşman readability score for Turkish (Ateşman, 1997):
158
+
159
+ ```text
160
+ score = 198.43 − 40.175 × (syllables / words) − 2.610 × (words / sentences)
161
+ ```
162
+
163
+ ```ts
164
+ import { atestmanScore } from "turkce-utils";
165
+
166
+ atestmanScore("Merhaba dünya. Nasılsın?");
167
+ // { score: 87.38, grade: "kolay", syllables: 8, words: 3, sentences: 2 }
168
+ ```
169
+
170
+ Grades: `çok kolay` (90+), `kolay` (70+), `orta` (50+), `zor` (30+), `çok zor`.
171
+
172
+ ### `truncateTr(text, maxLength, ellipsis?)`
173
+
174
+ Shorten text on the last word boundary, never exceeding `maxLength`.
175
+
176
+ ```ts
177
+ import { truncateTr } from "turkce-utils";
178
+
179
+ truncateTr("kahve falı bakıyoruz", 12); // "kahve falı…"
180
+ truncateTr("abcdef", 4, "..."); // "a..."
181
+ ```
182
+
183
+ ### `initialsTr(input, options?)`
184
+
185
+ Initials from a full name, uppercased with Turkish rules.
186
+
187
+ ```ts
188
+ import { initialsTr } from "turkce-utils";
189
+
190
+ initialsTr("Mehmet Fatih Doğan"); // "MFD"
191
+ initialsTr("ışık inci"); // "Iİ"
192
+ initialsTr("Mehmet Fatih Doğan", { separator: "." }); // "M.F.D"
193
+ ```
194
+
195
+ ### CLI
196
+
197
+ The package ships a `turkce` command covering every helper:
198
+
199
+ ```console
200
+ $ turkce slug "Çılgın Şöför"
201
+ cilgin-sofor
202
+
203
+ $ turkce words 1234
204
+ bin iki yüz otuz dört
205
+
206
+ $ printf 'üzüm\narmut\nçilek\n' | turkce sort
207
+ armut
208
+ çilek
209
+ üzüm
210
+ ```
211
+
212
+ Run `turkce --help` for the full command list.
213
+
214
+ ## Development
215
+
216
+ Node.js 22.18+ runs the TypeScript sources directly (native type stripping),
217
+ so no build step is needed for tests:
218
+
219
+ ```bash
220
+ npm test # node --test
221
+ npm run typecheck # tsc --noEmit
222
+ npm run build # tsc -> dist/
223
+ ```
224
+
225
+ Every module has a matching test in `test/`. The library has **zero runtime
226
+ dependencies**.
227
+
228
+ ## Developer
229
+
230
+ **Mehmet Fatih Doğan** — Software Developer.
231
+
232
+ - 🌐 Portfolio & Contact: [mehmetfatihdogan.com.tr](https://mehmetfatihdogan.com.tr)
233
+ - 💻 GitHub: [@fatihdogann](https://github.com/fatihdogann)
234
+
235
+ For questions, bug reports, or feedback about this project, feel free to contact me through [my website](https://mehmetfatihdogan.com.tr).
package/dist/case.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Turkish-aware letter casing.
3
+ *
4
+ * JavaScript's `toLowerCase`/`toUpperCase` follow the Unicode default, which
5
+ * maps `I` to `i` and `i` to `I`. Turkish is different: the dotless `ı` pairs
6
+ * with `I`, and the dotted `i` pairs with `İ`.
7
+ */
8
+ /** Lowercase a string using Turkish rules (`I` → `ı`, `İ` → `i`). */
9
+ export declare function lowerTr(input: string): string;
10
+ /** Uppercase a string using Turkish rules (`i` → `İ`, `ı` → `I`). */
11
+ export declare function upperTr(input: string): string;
12
+ //# sourceMappingURL=case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"case.d.ts","sourceRoot":"","sources":["../src/case.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,qEAAqE;AACrE,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,qEAAqE;AACrE,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C"}
package/dist/case.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Turkish-aware letter casing.
3
+ *
4
+ * JavaScript's `toLowerCase`/`toUpperCase` follow the Unicode default, which
5
+ * maps `I` to `i` and `i` to `I`. Turkish is different: the dotless `ı` pairs
6
+ * with `I`, and the dotted `i` pairs with `İ`.
7
+ */
8
+ const LOWER = { I: "ı", İ: "i" };
9
+ const UPPER = { i: "İ", ı: "I" };
10
+ /** Lowercase a string using Turkish rules (`I` → `ı`, `İ` → `i`). */
11
+ export function lowerTr(input) {
12
+ return input.replace(/[Iİ]/g, (char) => LOWER[char] ?? char).toLowerCase();
13
+ }
14
+ /** Uppercase a string using Turkish rules (`i` → `İ`, `ı` → `I`). */
15
+ export function upperTr(input) {
16
+ return input.replace(/[iı]/g, (char) => UPPER[char] ?? char).toUpperCase();
17
+ }
18
+ //# sourceMappingURL=case.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"case.js","sourceRoot":"","sources":["../src/case.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,KAAK,GAAqC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;AACnE,MAAM,KAAK,GAAqC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;AAEnE,qEAAqE;AACrE,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AAC7E,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AAC7E,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `turkce` — a small CLI over the turkce-utils helpers.
4
+ *
5
+ * Usage: `turkce <command> [text...]`, or pipe text on stdin.
6
+ */
7
+ export declare const HELP = "turkce \u2014 Turkish text helpers\n\nUsage:\n turkce <command> [text...] text can also be piped on stdin\n\nCommands:\n slug URL-safe slug (\u00E7 -> c, \u011F -> g, ...)\n upper Turkish uppercase (i -> \u0130, \u0131 -> I)\n lower Turkish lowercase (I -> \u0131, \u0130 -> i)\n title Turkish title case\n normalize normalise quotes, dashes, whitespace\n words spell out a number (1234 -> \"bin iki y\u00FCz otuz d\u00F6rt\")\n ordinal spill out an ordinal (3 -> \"\u00FC\u00E7\u00FCnc\u00FC\")\n syllables count syllables\n readability Ate\u015Fman readability score\n initials initials from a full name\n truncate shorten text (max 80 chars)\n sort sort lines by the Turkish alphabet\n\nOptions:\n -h, --help show this help\n";
8
+ /** Run a command against `input` and return the text to print. */
9
+ export declare function runCommand(command: string, input: string): string;
10
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAgBH,eAAO,MAAM,IAAI,kzBAqBhB,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA+BjE"}
package/dist/cli.js ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `turkce` — a small CLI over the turkce-utils helpers.
4
+ *
5
+ * Usage: `turkce <command> [text...]`, or pipe text on stdin.
6
+ */
7
+ import { slugify } from "./slug.js";
8
+ import { lowerTr, upperTr } from "./case.js";
9
+ import { sortTr } from "./sort.js";
10
+ import { titleCaseTr } from "./title.js";
11
+ import { normalizeTr } from "./normalize.js";
12
+ import { numberToWordsTr } from "./numbers.js";
13
+ import { ordinalWordTr } from "./ordinal.js";
14
+ import { syllablesTr } from "./syllables.js";
15
+ import { atestmanScore } from "./readability.js";
16
+ import { truncateTr } from "./truncate.js";
17
+ import { initialsTr } from "./initials.js";
18
+ import { realpathSync } from "node:fs";
19
+ import { fileURLToPath } from "node:url";
20
+ export const HELP = `turkce — Turkish text helpers
21
+
22
+ Usage:
23
+ turkce <command> [text...] text can also be piped on stdin
24
+
25
+ Commands:
26
+ slug URL-safe slug (ç -> c, ğ -> g, ...)
27
+ upper Turkish uppercase (i -> İ, ı -> I)
28
+ lower Turkish lowercase (I -> ı, İ -> i)
29
+ title Turkish title case
30
+ normalize normalise quotes, dashes, whitespace
31
+ words spell out a number (1234 -> "bin iki yüz otuz dört")
32
+ ordinal spill out an ordinal (3 -> "üçüncü")
33
+ syllables count syllables
34
+ readability Ateşman readability score
35
+ initials initials from a full name
36
+ truncate shorten text (max 80 chars)
37
+ sort sort lines by the Turkish alphabet
38
+
39
+ Options:
40
+ -h, --help show this help
41
+ `;
42
+ /** Run a command against `input` and return the text to print. */
43
+ export function runCommand(command, input) {
44
+ switch (command) {
45
+ case "slug":
46
+ return slugify(input);
47
+ case "upper":
48
+ return upperTr(input);
49
+ case "lower":
50
+ return lowerTr(input);
51
+ case "title":
52
+ return titleCaseTr(input);
53
+ case "normalize":
54
+ return normalizeTr(input);
55
+ case "words":
56
+ return numberToWordsTr(Number(input.trim()));
57
+ case "ordinal":
58
+ return ordinalWordTr(Number(input.trim()));
59
+ case "syllables":
60
+ return String(syllablesTr(input));
61
+ case "initials":
62
+ return initialsTr(input);
63
+ case "truncate":
64
+ return truncateTr(input, 80);
65
+ case "sort":
66
+ return sortTr(input.split("\n").filter((line) => line.length > 0)).join("\n");
67
+ case "readability": {
68
+ const result = atestmanScore(input);
69
+ return `${result.score} (${result.grade}) — ${result.words} kelime, ${result.sentences} cümle`;
70
+ }
71
+ default:
72
+ throw new Error(`unknown command: ${command}`);
73
+ }
74
+ }
75
+ async function readStdin() {
76
+ const chunks = [];
77
+ for await (const chunk of process.stdin)
78
+ chunks.push(chunk);
79
+ return Buffer.concat(chunks).toString("utf8");
80
+ }
81
+ async function main(argv) {
82
+ const [command, ...rest] = argv;
83
+ if (!command || command === "-h" || command === "--help" || command === "help") {
84
+ process.stdout.write(HELP);
85
+ return command ? 0 : 1;
86
+ }
87
+ const input = rest.length > 0 ? rest.join(" ") : (await readStdin()).replace(/\n$/, "");
88
+ try {
89
+ process.stdout.write(runCommand(command, input) + "\n");
90
+ return 0;
91
+ }
92
+ catch (error) {
93
+ process.stderr.write(`turkce: ${error.message}\n`);
94
+ return 1;
95
+ }
96
+ }
97
+ /**
98
+ * True when this file is the process entry point.
99
+ *
100
+ * `process.argv[1]` can be a symlink — npm links `node_modules/.bin/turkce`
101
+ * to `dist/cli.js` — so both sides are resolved to their real path first.
102
+ */
103
+ function isEntryPoint() {
104
+ const invoked = process.argv[1];
105
+ if (!invoked)
106
+ return false;
107
+ try {
108
+ return realpathSync(invoked) === realpathSync(fileURLToPath(import.meta.url));
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ }
114
+ if (isEntryPoint()) {
115
+ main(process.argv.slice(2)).then((code) => {
116
+ process.exitCode = code;
117
+ });
118
+ }
119
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export { slugify } from "./slug.ts";
2
+ export type { SlugifyOptions } from "./slug.ts";
3
+ export { lowerTr, upperTr } from "./case.ts";
4
+ export { compareTr, sortTr } from "./sort.ts";
5
+ export { titleCaseTr } from "./title.ts";
6
+ export { normalizeTr } from "./normalize.ts";
7
+ export type { NormalizeTrOptions } from "./normalize.ts";
8
+ export { numberToWordsTr, integerToWordsTr } from "./numbers.ts";
9
+ export { ordinalTr, ordinalWordTr } from "./ordinal.ts";
10
+ export { syllablesTr } from "./syllables.ts";
11
+ export { atestmanScore, atestmanGrade } from "./readability.ts";
12
+ export type { ReadabilityResult, AtestmanGrade } from "./readability.ts";
13
+ export { truncateTr } from "./truncate.ts";
14
+ export { initialsTr } from "./initials.ts";
15
+ export type { InitialsTrOptions } from "./initials.ts";
16
+ export { runCommand, HELP } from "./cli.ts";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAChE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ export { slugify } from "./slug.js";
2
+ export { lowerTr, upperTr } from "./case.js";
3
+ export { compareTr, sortTr } from "./sort.js";
4
+ export { titleCaseTr } from "./title.js";
5
+ export { normalizeTr } from "./normalize.js";
6
+ export { numberToWordsTr, integerToWordsTr } from "./numbers.js";
7
+ export { ordinalTr, ordinalWordTr } from "./ordinal.js";
8
+ export { syllablesTr } from "./syllables.js";
9
+ export { atestmanScore, atestmanGrade } from "./readability.js";
10
+ export { truncateTr } from "./truncate.js";
11
+ export { initialsTr } from "./initials.js";
12
+ export { runCommand, HELP } from "./cli.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Initials from Turkish names.
3
+ */
4
+ export interface InitialsTrOptions {
5
+ /** Keep only the first N initials. */
6
+ limit?: number;
7
+ /** String placed between initials. Defaults to `""`. */
8
+ separator?: string;
9
+ }
10
+ /** Build uppercase initials from a full name: "Mehmet Fatih Doğan" → "MFD". */
11
+ export declare function initialsTr(input: string, options?: InitialsTrOptions): string;
12
+ //# sourceMappingURL=initials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initials.d.ts","sourceRoot":"","sources":["../src/initials.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAWjF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Initials from Turkish names.
3
+ */
4
+ import { upperTr } from "./case.js";
5
+ /** Build uppercase initials from a full name: "Mehmet Fatih Doğan" → "MFD". */
6
+ export function initialsTr(input, options = {}) {
7
+ const separator = options.separator ?? "";
8
+ const initials = input
9
+ .trim()
10
+ .split(/\s+/)
11
+ .filter((word) => word.length > 0)
12
+ .map((word) => upperTr(word[0] ?? ""));
13
+ const limited = options.limit !== undefined && options.limit >= 0 ? initials.slice(0, options.limit) : initials;
14
+ return limited.join(separator);
15
+ }
16
+ //# sourceMappingURL=initials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initials.js","sourceRoot":"","sources":["../src/initials.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,UAA6B,EAAE;IACvE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,KAAK;SACnB,IAAI,EAAE;SACN,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEzC,MAAM,OAAO,GACX,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAClG,OAAO,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Normalise Turkish text for storage and comparison.
3
+ *
4
+ * Applies NFC, replaces typographic punctuation (smart quotes, en/em dashes,
5
+ * ellipsis, non-breaking spaces) with plain ASCII equivalents and collapses
6
+ * repeated whitespace.
7
+ */
8
+ export interface NormalizeTrOptions {
9
+ /** Collapse runs of whitespace and trim the result. Defaults to `true`. */
10
+ collapseWhitespace?: boolean;
11
+ }
12
+ /** Return a normalised copy of `input`. */
13
+ export declare function normalizeTr(input: string, options?: NormalizeTrOptions): string;
14
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAWD,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,CASnF"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Normalise Turkish text for storage and comparison.
3
+ *
4
+ * Applies NFC, replaces typographic punctuation (smart quotes, en/em dashes,
5
+ * ellipsis, non-breaking spaces) with plain ASCII equivalents and collapses
6
+ * repeated whitespace.
7
+ */
8
+ const REPLACEMENTS = [
9
+ [/[\u2018\u2019\u201A\u201B\u2032]/g, "'"],
10
+ [/[\u201C\u201D\u201E\u201F\u2033]/g, '"'],
11
+ [/[\u2013\u2014\u2015]/g, "-"],
12
+ [/\u2026/g, "..."],
13
+ [/\u00A0|\u2007|\u202F/g, " "],
14
+ [/\u200B|\u200C|\u200D|\uFEFF/g, ""],
15
+ ];
16
+ /** Return a normalised copy of `input`. */
17
+ export function normalizeTr(input, options = {}) {
18
+ let out = input.normalize("NFC");
19
+ for (const [pattern, replacement] of REPLACEMENTS) {
20
+ out = out.replace(pattern, replacement);
21
+ }
22
+ if (options.collapseWhitespace ?? true) {
23
+ out = out.replace(/\s+/g, " ").trim();
24
+ }
25
+ return out;
26
+ }
27
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,MAAM,YAAY,GAA6C;IAC7D,CAAC,mCAAmC,EAAE,GAAG,CAAC;IAC1C,CAAC,mCAAmC,EAAE,GAAG,CAAC;IAC1C,CAAC,uBAAuB,EAAE,GAAG,CAAC;IAC9B,CAAC,SAAS,EAAE,KAAK,CAAC;IAClB,CAAC,uBAAuB,EAAE,GAAG,CAAC;IAC9B,CAAC,8BAA8B,EAAE,EAAE,CAAC;CACrC,CAAC;AAEF,2CAA2C;AAC3C,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,UAA8B,EAAE;IACzE,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACjC,KAAK,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,YAAY,EAAE,CAAC;QAClD,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,OAAO,CAAC,kBAAkB,IAAI,IAAI,EAAE,CAAC;QACvC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Spell out numbers in Turkish.
3
+ *
4
+ * Supports integers up to the trillions, negatives and simple decimals
5
+ * (separated with the Turkish decimal comma word, `virgül`).
6
+ */
7
+ /** Spell out an integer in Turkish. */
8
+ export declare function integerToWordsTr(value: number): string;
9
+ /** Spell out a number in Turkish, including negatives and decimals. */
10
+ export declare function numberToWordsTr(value: number): string;
11
+ //# sourceMappingURL=numbers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numbers.d.ts","sourceRoot":"","sources":["../src/numbers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2BH,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA6BtD;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAcrD"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Spell out numbers in Turkish.
3
+ *
4
+ * Supports integers up to the trillions, negatives and simple decimals
5
+ * (separated with the Turkish decimal comma word, `virgül`).
6
+ */
7
+ const UNITS = [
8
+ "sıfır", "bir", "iki", "üç", "dört", "beş", "altı", "yedi", "sekiz", "dokuz",
9
+ ];
10
+ const TENS = [
11
+ "", "on", "yirmi", "otuz", "kırk", "elli", "altmış", "yetmiş", "seksen", "doksan",
12
+ ];
13
+ const SCALES = ["", "bin", "milyon", "milyar", "trilyon"];
14
+ function belowThousand(value) {
15
+ const words = [];
16
+ const hundreds = Math.floor(value / 100);
17
+ const tens = Math.floor((value % 100) / 10);
18
+ const units = value % 10;
19
+ if (hundreds > 0) {
20
+ if (hundreds > 1)
21
+ words.push(UNITS[hundreds]);
22
+ words.push("yüz");
23
+ }
24
+ if (tens > 0)
25
+ words.push(TENS[tens]);
26
+ if (units > 0)
27
+ words.push(UNITS[units]);
28
+ return words;
29
+ }
30
+ /** Spell out an integer in Turkish. */
31
+ export function integerToWordsTr(value) {
32
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
33
+ throw new RangeError("integerToWordsTr: expected a finite integer");
34
+ }
35
+ if (value === 0)
36
+ return "sıfır";
37
+ const negative = value < 0;
38
+ let remaining = Math.abs(value);
39
+ const groups = [];
40
+ while (remaining > 0) {
41
+ groups.push(remaining % 1000);
42
+ remaining = Math.floor(remaining / 1000);
43
+ }
44
+ const words = [];
45
+ for (let i = groups.length - 1; i >= 0; i--) {
46
+ const group = groups[i];
47
+ if (group === 0)
48
+ continue;
49
+ // "1000" is spoken as "bin", never "bir bin".
50
+ if (i === 1 && group === 1) {
51
+ words.push("bin");
52
+ continue;
53
+ }
54
+ words.push(...belowThousand(group));
55
+ if (i > 0)
56
+ words.push(SCALES[i]);
57
+ }
58
+ return (negative ? "eksi " : "") + words.join(" ");
59
+ }
60
+ /** Spell out a number in Turkish, including negatives and decimals. */
61
+ export function numberToWordsTr(value) {
62
+ const sign = value < 0 ? "eksi " : "";
63
+ const absolute = Math.abs(value);
64
+ const integerPart = Math.trunc(absolute);
65
+ const fraction = absolute - integerPart;
66
+ if (fraction === 0)
67
+ return integerToWordsTr(value);
68
+ const fractionDigits = fraction.toFixed(10).slice(2).replace(/0+$/, "");
69
+ const head = integerPart === 0 ? "sıfır" : integerToWordsTr(integerPart);
70
+ const tail = fractionDigits
71
+ .split("")
72
+ .map((digit) => UNITS[Number(digit)])
73
+ .join(" ");
74
+ return `${sign}${head} virgül ${tail}`;
75
+ }
76
+ //# sourceMappingURL=numbers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numbers.js","sourceRoot":"","sources":["../src/numbers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Turkish ordinal numbers.
3
+ *
4
+ * `ordinalTr` returns the numeric form with a trailing dot ("3."), while
5
+ * `ordinalWordTr` spells the ordinal out ("üçüncü") using Turkish vowel harmony.
6
+ */
7
+ /** Numeric ordinal: 3 → "3.". */
8
+ export declare function ordinalTr(value: number): string;
9
+ /** Spelled-out ordinal: 3 → "üçüncü", 21 → "yirmi birinci". */
10
+ export declare function ordinalWordTr(value: number): string;
11
+ //# sourceMappingURL=ordinal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ordinal.d.ts","sourceRoot":"","sources":["../src/ordinal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA6BH,iCAAiC;AACjC,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKnD"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Turkish ordinal numbers.
3
+ *
4
+ * `ordinalTr` returns the numeric form with a trailing dot ("3."), while
5
+ * `ordinalWordTr` spells the ordinal out ("üçüncü") using Turkish vowel harmony.
6
+ */
7
+ import { integerToWordsTr } from "./numbers.js";
8
+ const HARMONY = {
9
+ a: "ı", ı: "ı",
10
+ e: "i", i: "i",
11
+ o: "u", u: "u",
12
+ ö: "ü", ü: "ü",
13
+ };
14
+ const VOWELS = "aeıioöuüâîû";
15
+ const IRREGULAR = { dört: "dörd" };
16
+ function lastVowel(word) {
17
+ for (let i = word.length - 1; i >= 0; i--) {
18
+ const char = word[i];
19
+ if (VOWELS.includes(char))
20
+ return HARMONY[char] ?? "i";
21
+ }
22
+ return "i";
23
+ }
24
+ function ordinaliseWord(word) {
25
+ const base = IRREGULAR[word] ?? word;
26
+ const vowel = lastVowel(word);
27
+ const endsWithVowel = VOWELS.includes(word[word.length - 1]);
28
+ return endsWithVowel ? `${base}nc${vowel}` : `${base}${vowel}nc${vowel}`;
29
+ }
30
+ /** Numeric ordinal: 3 → "3.". */
31
+ export function ordinalTr(value) {
32
+ if (!Number.isInteger(value))
33
+ throw new RangeError("ordinalTr: expected an integer");
34
+ return `${value}.`;
35
+ }
36
+ /** Spelled-out ordinal: 3 → "üçüncü", 21 → "yirmi birinci". */
37
+ export function ordinalWordTr(value) {
38
+ const words = integerToWordsTr(value).split(" ");
39
+ const last = words.pop();
40
+ words.push(ordinaliseWord(last));
41
+ return words.join(" ");
42
+ }
43
+ //# sourceMappingURL=ordinal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ordinal.js","sourceRoot":"","sources":["../src/ordinal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,OAAO,GAAqC;IAChD,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;CACf,CAAC;AAEF,MAAM,MAAM,GAAG,aAAa,CAAC;AAC7B,MAAM,SAAS,GAAqC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAErE,SAAS,SAAS,CAAC,IAAY;IAC7B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACtB,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;IACzD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACrC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,CAAC;IAC9D,OAAO,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,KAAK,KAAK,EAAE,CAAC;AAC3E,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,gCAAgC,CAAC,CAAC;IACrF,OAAO,GAAG,KAAK,GAAG,CAAC;AACrB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;IAC1B,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Ateşman readability score for Turkish text (Ateşman, 1997).
3
+ *
4
+ * ```text
5
+ * score = 198.43 − 40.175 × (syllables / words) − 2.610 × (words / sentences)
6
+ * ```
7
+ *
8
+ * Higher scores mean easier text. The score is clamped to the 0–100 range.
9
+ */
10
+ export interface ReadabilityResult {
11
+ /** Ateşman score, clamped to 0–100. */
12
+ score: number;
13
+ /** Qualitative band for the score. */
14
+ grade: AtestmanGrade;
15
+ syllables: number;
16
+ words: number;
17
+ sentences: number;
18
+ }
19
+ export type AtestmanGrade = "çok kolay" | "kolay" | "orta" | "zor" | "çok zor";
20
+ /** Map an Ateşman score to its qualitative band. */
21
+ export declare function atestmanGrade(score: number): AtestmanGrade;
22
+ /** Compute the Ateşman readability score for Turkish text. */
23
+ export declare function atestmanScore(text: string): ReadabilityResult;
24
+ //# sourceMappingURL=readability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readability.d.ts","sourceRoot":"","sources":["../src/readability.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAW/E,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAM1D;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAkB7D"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Ateşman readability score for Turkish text (Ateşman, 1997).
3
+ *
4
+ * ```text
5
+ * score = 198.43 − 40.175 × (syllables / words) − 2.610 × (words / sentences)
6
+ * ```
7
+ *
8
+ * Higher scores mean easier text. The score is clamped to the 0–100 range.
9
+ */
10
+ import { syllablesTr } from "./syllables.js";
11
+ const WORD = /[\p{L}\p{N}]+/gu;
12
+ function tokenize(text) {
13
+ const words = text.match(WORD) ?? [];
14
+ const trimmed = text.trim();
15
+ if (trimmed === "")
16
+ return { words, sentences: 1 };
17
+ const ends = trimmed.match(/[.!?…]+/g)?.length ?? 0;
18
+ const trailing = /[.!?…]$/.test(trimmed) ? 0 : 1;
19
+ return { words, sentences: Math.max(1, ends + trailing) };
20
+ }
21
+ /** Map an Ateşman score to its qualitative band. */
22
+ export function atestmanGrade(score) {
23
+ if (score >= 90)
24
+ return "çok kolay";
25
+ if (score >= 70)
26
+ return "kolay";
27
+ if (score >= 50)
28
+ return "orta";
29
+ if (score >= 30)
30
+ return "zor";
31
+ return "çok zor";
32
+ }
33
+ /** Compute the Ateşman readability score for Turkish text. */
34
+ export function atestmanScore(text) {
35
+ const { words, sentences } = tokenize(text);
36
+ const wordCount = words.length;
37
+ const syllableCount = words.reduce((total, word) => total + syllablesTr(word), 0);
38
+ const score = wordCount === 0
39
+ ? 0
40
+ : 198.43 - 40.175 * (syllableCount / wordCount) - 2.61 * (wordCount / sentences);
41
+ const clamped = Math.max(0, Math.min(100, Math.round(score * 100) / 100));
42
+ return {
43
+ score: clamped,
44
+ grade: atestmanGrade(clamped),
45
+ syllables: syllableCount,
46
+ words: wordCount,
47
+ sentences,
48
+ };
49
+ }
50
+ //# sourceMappingURL=readability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readability.js","sourceRoot":"","sources":["../src/readability.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,IAAI,GAAG,iBAAiB,CAAC;AAc/B,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IACnD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,WAAW,CAAC;IACpC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,OAAO,CAAC;IAChC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,MAAM,CAAC;IAC/B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;IAC/B,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAElF,MAAM,KAAK,GACT,SAAS,KAAK,CAAC;QACb,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,aAAa,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IACrF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAE1E,OAAO;QACL,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC;QAC7B,SAAS,EAAE,aAAa;QACxB,KAAK,EAAE,SAAS;QAChB,SAAS;KACV,CAAC;AACJ,CAAC"}
package/dist/slug.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Turkish-aware slug generation.
3
+ *
4
+ * `slugify` transliterates Turkish letters to their ASCII counterparts
5
+ * (ç→c, ğ→g, ı→i, İ→i, ö→o, ş→s, ü→u), folds remaining diacritics,
6
+ * drops punctuation and produces a URL-safe, separator-joined string.
7
+ */
8
+ export interface SlugifyOptions {
9
+ /** Separator between words. Defaults to `"-"`. */
10
+ separator?: string;
11
+ /** Lowercase the result. Defaults to `true`. */
12
+ lowercase?: boolean;
13
+ /** Hard limit for the returned slug length. Truncation happens on a word boundary. */
14
+ maxLength?: number;
15
+ }
16
+ /** Convert arbitrary text into a URL-safe slug, respecting Turkish letters. */
17
+ export declare function slugify(input: string, options?: SlugifyOptions): string;
18
+ //# sourceMappingURL=slug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../src/slug.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,+EAA+E;AAC/E,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CA8B3E"}
package/dist/slug.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Turkish-aware slug generation.
3
+ *
4
+ * `slugify` transliterates Turkish letters to their ASCII counterparts
5
+ * (ç→c, ğ→g, ı→i, İ→i, ö→o, ş→s, ü→u), folds remaining diacritics,
6
+ * drops punctuation and produces a URL-safe, separator-joined string.
7
+ */
8
+ const TURKISH = {
9
+ ç: "c", Ç: "c",
10
+ ğ: "g", Ğ: "g",
11
+ ı: "i", I: "i",
12
+ İ: "i", i: "i",
13
+ ö: "o", Ö: "o",
14
+ ş: "s", Ş: "s",
15
+ ü: "u", Ü: "u",
16
+ â: "a", Â: "a",
17
+ î: "i", Î: "i",
18
+ û: "u", Û: "u",
19
+ };
20
+ /** Convert arbitrary text into a URL-safe slug, respecting Turkish letters. */
21
+ export function slugify(input, options = {}) {
22
+ const separator = options.separator ?? "-";
23
+ const lowercase = options.lowercase ?? true;
24
+ if (separator === "")
25
+ throw new RangeError("slugify: separator must not be empty");
26
+ let out = "";
27
+ for (const char of input.normalize("NFC")) {
28
+ const mapped = TURKISH[char];
29
+ if (mapped !== undefined) {
30
+ out += mapped;
31
+ continue;
32
+ }
33
+ out += char.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
34
+ }
35
+ out = out.replace(/[^a-zA-Z0-9]+/g, separator);
36
+ const escaped = separator.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
37
+ out = out.replace(new RegExp(`^(${escaped})+|(${escaped})+$`, "g"), "");
38
+ if (lowercase)
39
+ out = out.toLowerCase();
40
+ if (options.maxLength !== undefined && out.length > options.maxLength) {
41
+ const cut = out.slice(0, options.maxLength);
42
+ const lastSep = cut.lastIndexOf(separator);
43
+ out = (lastSep > 0 ? cut.slice(0, lastSep) : cut).replace(new RegExp(`(${escaped})+$`), "");
44
+ }
45
+ return out;
46
+ }
47
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.js","sourceRoot":"","sources":["../src/slug.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,OAAO,GAAqC;IAChD,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IACd,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;CACf,CAAC;AAWF,+EAA+E;AAC/E,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,UAA0B,EAAE;IACjE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;IAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAC5C,IAAI,SAAS,KAAK,EAAE;QAAE,MAAM,IAAI,UAAU,CAAC,sCAAsC,CAAC,CAAC;IAEnF,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,GAAG,IAAI,MAAM,CAAC;YACd,SAAS;QACX,CAAC;QACD,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IACjE,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,OAAO,OAAO,OAAO,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IACxE,IAAI,SAAS;QAAE,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAEvC,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;QACtE,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAC3C,GAAG,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CACvD,IAAI,MAAM,CAAC,IAAI,OAAO,KAAK,CAAC,EAC5B,EAAE,CACH,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/sort.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Turkish-aware collation.
3
+ *
4
+ * Sorts using the Turkish alphabet, where ç follows c, ğ follows g, ı comes
5
+ * before i, ö follows o, ş follows s and ü follows u. Backed by `Intl.Collator`
6
+ * so no lookup tables are needed.
7
+ */
8
+ /** Compare two strings by the Turkish alphabet. Returns a negative, zero or positive number. */
9
+ export declare function compareTr(a: string, b: string): number;
10
+ /** Return a new array sorted by the Turkish alphabet. */
11
+ export declare function sortTr<T extends string>(items: readonly T[]): T[];
12
+ //# sourceMappingURL=sort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../src/sort.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,gGAAgG;AAChG,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,yDAAyD;AACzD,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAEjE"}
package/dist/sort.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Turkish-aware collation.
3
+ *
4
+ * Sorts using the Turkish alphabet, where ç follows c, ğ follows g, ı comes
5
+ * before i, ö follows o, ş follows s and ü follows u. Backed by `Intl.Collator`
6
+ * so no lookup tables are needed.
7
+ */
8
+ const collator = new Intl.Collator("tr", { sensitivity: "variant", numeric: false });
9
+ /** Compare two strings by the Turkish alphabet. Returns a negative, zero or positive number. */
10
+ export function compareTr(a, b) {
11
+ return collator.compare(a, b);
12
+ }
13
+ /** Return a new array sorted by the Turkish alphabet. */
14
+ export function sortTr(items) {
15
+ return [...items].sort(compareTr);
16
+ }
17
+ //# sourceMappingURL=sort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.js","sourceRoot":"","sources":["../src/sort.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AAErF,gGAAgG;AAChG,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,CAAS;IAC5C,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,MAAM,CAAmB,KAAmB;IAC1D,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Count syllables in Turkish words.
3
+ *
4
+ * Turkish is written as one vowel per syllable, so the syllable count is the
5
+ * number of vowel groups.
6
+ */
7
+ /** Count the syllables in a word or sentence. */
8
+ export declare function syllablesTr(input: string): number;
9
+ //# sourceMappingURL=syllables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syllables.d.ts","sourceRoot":"","sources":["../src/syllables.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Count syllables in Turkish words.
3
+ *
4
+ * Turkish is written as one vowel per syllable, so the syllable count is the
5
+ * number of vowel groups.
6
+ */
7
+ const VOWEL_GROUP = /[aeıioöuüâîû]+/g;
8
+ /** Count the syllables in a word or sentence. */
9
+ export function syllablesTr(input) {
10
+ return input.toLowerCase().match(VOWEL_GROUP)?.length ?? 0;
11
+ }
12
+ //# sourceMappingURL=syllables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syllables.js","sourceRoot":"","sources":["../src/syllables.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAEtC,iDAAiD;AACjD,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Turkish-aware title casing.
3
+ */
4
+ /** Title-case a string, capitalising the first letter of each word with Turkish rules. */
5
+ export declare function titleCaseTr(input: string): string;
6
+ //# sourceMappingURL=title.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"title.d.ts","sourceRoot":"","sources":["../src/title.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
package/dist/title.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Turkish-aware title casing.
3
+ */
4
+ import { lowerTr, upperTr } from "./case.js";
5
+ // Word separators: whitespace and opening punctuation, but never an apostrophe
6
+ // (so "istanbul'da" keeps its lowercase suffix).
7
+ const WORD_START = /(^|[\s([{"«»""\-–—/|]+)(\p{L})/gu;
8
+ /** Title-case a string, capitalising the first letter of each word with Turkish rules. */
9
+ export function titleCaseTr(input) {
10
+ return lowerTr(input).replace(WORD_START, (_match, separator, letter) => {
11
+ return separator + upperTr(letter);
12
+ });
13
+ }
14
+ //# sourceMappingURL=title.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"title.js","sourceRoot":"","sources":["../src/title.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,+EAA+E;AAC/E,iDAAiD;AACjD,MAAM,UAAU,GAAG,kCAAkC,CAAC;AAEtD,0FAA0F;AAC1F,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,SAAiB,EAAE,MAAc,EAAE,EAAE;QACtF,OAAO,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Truncate Turkish text on a word boundary.
3
+ */
4
+ /** Shorten `text` to at most `maxLength` characters, appending an ellipsis. */
5
+ export declare function truncateTr(text: string, maxLength: number, ellipsis?: string): string;
6
+ //# sourceMappingURL=truncate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../src/truncate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAWlF"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Truncate Turkish text on a word boundary.
3
+ */
4
+ /** Shorten `text` to at most `maxLength` characters, appending an ellipsis. */
5
+ export function truncateTr(text, maxLength, ellipsis = "…") {
6
+ if (maxLength <= 0)
7
+ return "";
8
+ if (text.length <= maxLength)
9
+ return text;
10
+ const budget = maxLength - ellipsis.length;
11
+ if (budget <= 0)
12
+ return ellipsis.slice(0, maxLength);
13
+ const slice = text.slice(0, budget + 1);
14
+ const lastSpace = slice.lastIndexOf(" ");
15
+ const cut = lastSpace > 0 ? slice.slice(0, lastSpace) : text.slice(0, budget);
16
+ return cut.replace(/\s+$/, "") + ellipsis;
17
+ }
18
+ //# sourceMappingURL=truncate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../src/truncate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,SAAiB,EAAE,QAAQ,GAAG,GAAG;IACxE,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9B,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC3C,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAErD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC9E,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC;AAC5C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "turkce-utils",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Zero-dependency TypeScript helpers for Turkish text: slugify, Turkish-aware case & sort, title case, number-to-words, syllables and Ateşman readability — plus a CLI.",
5
+ "keywords": [
6
+ "turkish",
7
+ "türkçe",
8
+ "turkce",
9
+ "turkish-language",
10
+ "slugify",
11
+ "slug",
12
+ "text",
13
+ "text-utils",
14
+ "string",
15
+ "i18n",
16
+ "locale",
17
+ "collation",
18
+ "readability",
19
+ "atestman",
20
+ "okunabilirlik",
21
+ "number-to-words",
22
+ "syllables",
23
+ "cli"
24
+ ],
25
+ "license": "MIT",
26
+ "author": "Mehmet Fatih Doğan",
27
+ "type": "module",
28
+ "engines": {
29
+ "node": ">=20.0.0"
30
+ },
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ }
38
+ },
39
+ "bin": {
40
+ "turkce": "./dist/cli.js"
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "README.md",
45
+ "LICENSE"
46
+ ],
47
+ "scripts": {
48
+ "test": "node --test",
49
+ "typecheck": "tsc --noEmit",
50
+ "build": "tsc",
51
+ "prepare": "npm run build",
52
+ "prepublishOnly": "npm run build"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^24.0.0",
56
+ "typescript": "^5.7.2"
57
+ },
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "git+https://github.com/fatihdogann/turkce-utils.git"
61
+ },
62
+ "bugs": {
63
+ "url": "https://github.com/fatihdogann/turkce-utils/issues"
64
+ },
65
+ "homepage": "https://github.com/fatihdogann/turkce-utils#readme"
66
+ }