tdk-api-wrapper 1.5.0 → 1.5.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/src/tdk.ts CHANGED
@@ -25,6 +25,168 @@ import * as os from "node:os";
25
25
  import * as https from "node:https";
26
26
  import * as tls from "node:tls";
27
27
 
28
+ /**
29
+ * Known frequent Turkish misspellings, erroneously joined compound words,
30
+ * and words where vowel dropping is prohibited by TDK (Yazım Kılavuzu).
31
+ */
32
+ export const COMMON_MISSPELLINGS: Record<string, string> = {
33
+ // -şey ile biten ve ayrı yazılması zorunlu söz öbekleri
34
+ herşey: "her şey",
35
+ hersey: "her şey",
36
+ birşey: "bir şey",
37
+ birsey: "bir şey",
38
+ hiçbirşey: "hiçbir şey",
39
+ hicbirsey: "hiçbir şey",
40
+ çokşey: "çok şey",
41
+ coksey: "çok şey",
42
+ şeyler: "şeyler",
43
+ seyler: "şeyler",
44
+ herhangibirşey: "herhangi bir şey",
45
+ herhangibirsey: "herhangi bir şey",
46
+
47
+ // Sıkça birleşik yazılan ama ayrı yazılması gereken sözler
48
+ hergün: "her gün",
49
+ hergun: "her gün",
50
+ herzaman: "her zaman",
51
+ heran: "her an",
52
+ heryer: "her yer",
53
+ herbiri: "her biri",
54
+ pekçok: "pek çok",
55
+ pekcok: "pek çok",
56
+ pekaz: "pek az",
57
+ yada: "ya da",
58
+ tabiki: "tabii ki",
59
+ tabiiki: "tabii ki",
60
+ sağol: "sağ ol",
61
+ sagol: "sağ ol",
62
+ sağolun: "sağ olun",
63
+ sagolun: "sağ olun",
64
+ hoşçakal: "hoşça kal",
65
+ hoscakal: "hoşça kal",
66
+ hoşgeldin: "hoş geldin",
67
+ hosgeldin: "hoş geldin",
68
+ hoşgeldiniz: "hoş geldiniz",
69
+ hosgeldiniz: "hoş geldiniz",
70
+ hoşbulduk: "hoş bulduk",
71
+ hosbulduk: "hoş bulduk",
72
+ yanısıra: "yanı sıra",
73
+ yanisira: "yanı sıra",
74
+ peşisıra: "peşi sıra",
75
+ pesisira: "peşi sıra",
76
+ ardısıra: "ardı sıra",
77
+ ardisira: "ardı sıra",
78
+ artarda: "art arda",
79
+ yüzyüze: "yüz yüze",
80
+ yuzyuze: "yüz yüze",
81
+ elele: "el ele",
82
+ gözgöze: "göz göze",
83
+ başbaşa: "baş başa",
84
+ basbasa: "baş başa",
85
+ yanyana: "yan yana",
86
+ içiçe: "iç içe",
87
+ icice: "iç içe",
88
+ üstüste: "üst üste",
89
+ ustuste: "üst üste",
90
+ altalta: "alt alta",
91
+ önsöz: "ön söz",
92
+ onsoz: "ön söz",
93
+ önyargı: "ön yargı",
94
+ onyargi: "ön yargı",
95
+ farketmek: "fark etmek",
96
+ farketti: "fark etti",
97
+ farkettim: "fark ettim",
98
+ farkeder: "fark eder",
99
+ farketmez: "fark etmez",
100
+ terketmek: "terk etmek",
101
+ terketti: "terk etti",
102
+ ayırdetmek: "ayırt etmek",
103
+ ayırtetmek: "ayırt etmek",
104
+ arzetmek: "arz etmek",
105
+ arzederim: "arz ederim",
106
+ varolmak: "var olmak",
107
+ yokolmak: "yok olmak",
108
+ haketmek: "hak etmek",
109
+ haketti: "hak etti",
110
+ hakkaten: "hakikaten",
111
+ hiçkimse: "hiç kimse",
112
+ hickimse: "hiç kimse",
113
+
114
+ // Ünlü düşmesi yapılmaması gereken yer bildiren sözler (TDK Kural 15)
115
+ burda: "burada",
116
+ burdan: "buradan",
117
+ şurda: "şurada",
118
+ surda: "şurada",
119
+ şurdan: "şuradan",
120
+ surdan: "şuradan",
121
+ orda: "orada",
122
+ ordan: "oradan",
123
+ içerde: "içeride",
124
+ icerde: "içeride",
125
+ içerden: "içeriden",
126
+ icerden: "içeriden",
127
+ dışarda: "dışarıda",
128
+ disarda: "dışarıda",
129
+ dışardan: "dışarıdan",
130
+ disardan: "dışarıdan",
131
+ yukarda: "yukarıda",
132
+ yukardan: "yukarıdan",
133
+
134
+ // Sıkça yanlış yazılan sözcükler
135
+ herkez: "herkes",
136
+ yanlız: "yalnız",
137
+ yalnış: "yanlış",
138
+ orjinal: "orijinal",
139
+ labaratuar: "laboratuvar",
140
+ laboratuar: "laboratuvar",
141
+ şöför: "şoför",
142
+ sofor: "şoför",
143
+ egzos: "egzoz",
144
+ eksoz: "egzoz",
145
+ ekzoz: "egzoz",
146
+ kiprik: "kirpik",
147
+ kirbit: "kibrit",
148
+ klavuz: "kılavuz",
149
+ kıravat: "kravat",
150
+ süpriz: "sürpriz",
151
+ supriz: "sürpriz",
152
+ raslantı: "rastlantı",
153
+ hastahane: "hastane",
154
+ pastahane: "pastane",
155
+ postahane: "postane",
156
+ eczahane: "eczane",
157
+ meyva: "meyve",
158
+ sarmısak: "sarımsak",
159
+ dinazor: "dinozor",
160
+ pantalon: "pantolon",
161
+ tesbih: "tespih",
162
+ ahçı: "aşçı",
163
+ matba: "matbaa",
164
+ idda: "iddia",
165
+ iddaa: "iddia",
166
+ muhattap: "muhatap",
167
+ traş: "tıraş",
168
+ karnıbahar: "karnabahar",
169
+ kareografi: "koreografi",
170
+ poaça: "poğaça",
171
+ pohaça: "poğaça",
172
+ şarz: "şarj",
173
+ sarj: "şarj",
174
+ makina: "makine",
175
+ müsade: "müsaade",
176
+ entellektüel: "entelektüel",
177
+ inisiyatif: "inisiyatif",
178
+ insiyatif: "inisiyatif",
179
+ sezeryan: "sezaryen",
180
+ doküman: "doküman",
181
+ döküman: "doküman",
182
+ erozyon: "erozyon",
183
+ erizyon: "erozyon",
184
+ anane: "anneanne",
185
+ babaanne: "babaanne",
186
+ };
187
+
188
+ export const SEY_EXCEPTIONS = new Set(["düşey", "eşey", "konsey", "jersey", "şey"]);
189
+
28
190
  /**
29
191
  * TDK (Türk Dil Kurumu) API Wrapper
30
192
  */
@@ -630,32 +792,56 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
630
792
  * Checks spelling and returns suggestions if wrong.
631
793
  */
632
794
  public static async checkSpelling(word: string): Promise<SpellCheckResult> {
633
- // 1. Check if word exists
795
+ if (!word || word.trim() === "") {
796
+ return { isCorrect: false, word };
797
+ }
798
+
799
+ const cleanWord = word.trim().toLocaleLowerCase("tr-TR");
800
+
801
+ // 1. Check if word exists in TDK dictionary
634
802
  const results = await this.getWord(word);
635
803
  if (results.length > 0) {
636
804
  return { isCorrect: true, word };
637
805
  }
638
806
 
639
- // 2. If not, check "sıkça yapılan yanlışlar" from DailyContent — an exact
640
- // match here is TDK explicitly saying "X is often confused with Y", so
641
- // it's authoritative when it hits (but only 2-3 rotating entries per call).
807
+ // 2. Common Turkish misspellings, erroneously joined compounds, and vowel drop errors
808
+ if (COMMON_MISSPELLINGS[cleanWord]) {
809
+ return { isCorrect: false, word, suggestion: COMMON_MISSPELLINGS[cleanWord] };
810
+ }
811
+
812
+ // 3. Dynamic -şey / -sey attached check:
813
+ // In Turkish, 'şey' is an indefinite pronoun and is ALWAYS written separately from the preceding word
814
+ // (e.g. her şey, bir şey, hiçbir şey, çok şey, her şeyi, bir şeyler).
815
+ const seyMatch = cleanWord.match(/^(.+?)(?:şey|sey)([ıiuaeüodekmnl]+)?$/);
816
+ if (seyMatch && !SEY_EXCEPTIONS.has(cleanWord)) {
817
+ let prefix = seyMatch[1];
818
+ const suffix = seyMatch[2] || "";
819
+ if (prefix === "hicbir") prefix = "hiçbir";
820
+ if (prefix === "cok") prefix = "çok";
821
+ return {
822
+ isCorrect: false,
823
+ word,
824
+ suggestion: `${prefix} şey${suffix}`,
825
+ };
826
+ }
827
+
828
+ // 4. "Sıkça yapılan yanlışlar" from DailyContent
642
829
  const daily = await this.getDailyContent();
643
830
  if (daily) {
644
- const syydMatch = daily.syyd.find(s => s.yanliskelime.toLocaleLowerCase("tr-TR") === word.toLocaleLowerCase("tr-TR"));
831
+ const syydMatch = daily.syyd.find((s) => s.yanliskelime.toLocaleLowerCase("tr-TR") === cleanWord);
645
832
  if (syydMatch) {
646
833
  return { isCorrect: false, word, suggestion: syydMatch.dogrukelime };
647
834
  }
648
- const mixMatch = daily.karistirma.find(s => s.yanlis.toLocaleLowerCase("tr-TR") === word.toLocaleLowerCase("tr-TR"));
835
+ const mixMatch = daily.karistirma.find((s) => s.yanlis.toLocaleLowerCase("tr-TR") === cleanWord);
649
836
  if (mixMatch) {
650
837
  return { isCorrect: false, word, suggestion: mixMatch.dogru };
651
838
  }
652
839
  }
653
840
 
654
- // 3. Morphology Fallback: Check if the word is an inflected form of a known headword
655
- // (e.g., "halılarımızın" -> "halı", "kitabımız" -> "kitap", "çocuğa" -> "çocuk")
841
+ // 5. Morphology Fallback: Check if the word is an inflected form or bare verb imperative of a known headword
842
+ // (e.g., "halılarımızın" -> "halı", "kitabımız" -> "kitap", "çocuğa" -> "çocuk", "söyle" -> "söylemek")
656
843
  const root = await this.findRoot(word);
657
844
  if (root) {
658
- const cleanWord = word.trim().toLocaleLowerCase("tr-TR");
659
845
  const isInflected = root !== cleanWord;
660
846
  return {
661
847
  isCorrect: true,
@@ -665,42 +851,44 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
665
851
  };
666
852
  }
667
853
 
668
- // 4. No exact match or morphology root: fall back to the closest
669
- // headword (by edit distance) across TDK's full ~81k-word list (the same
670
- // data `getSuggestions()` uses). Restricted to single-token, lowercase
671
- // headwords so it doesn't suggest compounds/phrases or proper nouns.
672
- // Candidates whose length differs too much are skipped before running
673
- // the O(n*m) distance calculation, both for speed and because a huge
674
- // length gap can't be within the distance threshold anyway. Ties (same
675
- // distance) prefer a matching first letter, then a matching length —
676
- // typos rarely change the first letter, and this avoids picking
677
- // whatever happens to sort alphabetically first. There's no word
678
- // frequency data available, so a genuine tie can still land on a
679
- // technically-correct but less commonly intended word.
854
+ // 6. Check if headwords with spaces match when space is removed (e.g. "ön yargı" for "önyargı")
680
855
  if (this.autocompleteCache.length === 0) {
681
856
  this.autocompleteCache = await this.fetchAutocompleteData();
682
857
  }
683
- const cleanWord = word.trim().toLocaleLowerCase("tr-TR");
684
- let best: { candidate: string; distance: number; firstMismatch: number; lengthMismatch: number } | null = null;
858
+ for (const candidate of this.autocompleteCache) {
859
+ if (candidate.includes(" ")) {
860
+ const candidateNoSpace = candidate.replace(/\s+/g, "").toLocaleLowerCase("tr-TR");
861
+ if (candidateNoSpace === cleanWord) {
862
+ return { isCorrect: false, word, suggestion: candidate };
863
+ }
864
+ }
865
+ }
866
+
867
+ // 7. No exact match or morphology root: fall back to closest headword by edit distance.
868
+ // Ties prefer matching first letter, and initial character mismatches are penalized
869
+ // so irrelevant foreign loanwords (like 'jersey') do not beat Turkish roots.
870
+ let best: { candidate: string; distance: number; rawDist: number; firstMismatch: number; lengthMismatch: number } | null = null;
685
871
  for (const candidate of this.autocompleteCache) {
686
872
  if (candidate.includes(" ") || candidate !== candidate.toLocaleLowerCase("tr-TR")) continue;
687
873
  if (Math.abs(candidate.length - cleanWord.length) > 2) continue;
688
874
 
689
- const distance = this.damerauLevenshtein(cleanWord, candidate);
690
- if (distance === 0) continue;
875
+ const rawDist = this.damerauLevenshtein(cleanWord, candidate);
876
+ if (rawDist === 0) continue;
691
877
 
692
878
  const firstMismatch = candidate[0] === cleanWord[0] ? 0 : 1;
693
879
  const lengthMismatch = candidate.length === cleanWord.length ? 0 : 1;
880
+ const distance = rawDist + (firstMismatch > 0 ? 1.2 : 0);
881
+
694
882
  const better =
695
883
  !best ||
696
884
  distance < best.distance ||
697
885
  (distance === best.distance && firstMismatch < best.firstMismatch) ||
698
886
  (distance === best.distance && firstMismatch === best.firstMismatch && lengthMismatch < best.lengthMismatch);
699
887
  if (better) {
700
- best = { candidate, distance, firstMismatch, lengthMismatch };
888
+ best = { candidate, distance, rawDist, firstMismatch, lengthMismatch };
701
889
  }
702
890
  }
703
- if (best && best.distance <= 2) {
891
+ if (best && best.rawDist <= 2 && (best.firstMismatch === 0 || best.rawDist <= 1)) {
704
892
  return { isCorrect: false, word, suggestion: best.candidate };
705
893
  }
706
894
  return { isCorrect: false, word };
@@ -1477,6 +1665,81 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1477
1665
  "sanki", "oysaki", "mademki", "belki", "halbuki", "çünkü", "meğerki", "illaki"
1478
1666
  ]);
1479
1667
 
1668
+ // 1. Detect multi-word phrases that should be written as single compound words
1669
+ const PHRASE_MISTAKES: {
1670
+ regex: RegExp;
1671
+ suggestion: string;
1672
+ message: string;
1673
+ type: ProofreadIssue["type"];
1674
+ }[] = [
1675
+ {
1676
+ regex: /\bhiç\s+bir\b/gi,
1677
+ suggestion: "hiçbir",
1678
+ message: "'hiçbir' belgisiz sıfatı bitişik yazılmalıdır.",
1679
+ type: "spelling",
1680
+ },
1681
+ {
1682
+ regex: /\bbir\s+çok\b/gi,
1683
+ suggestion: "birçok",
1684
+ message: "'birçok' belgisiz sıfatı/zamiri bitişik yazılmalıdır.",
1685
+ type: "spelling",
1686
+ },
1687
+ {
1688
+ regex: /\bbir\s+kaç\b/gi,
1689
+ suggestion: "birkaç",
1690
+ message: "'birkaç' belgisiz sıfatı/zamiri bitişik yazılmalıdır.",
1691
+ type: "spelling",
1692
+ },
1693
+ {
1694
+ regex: /\bbir\s+az\b/gi,
1695
+ suggestion: "biraz",
1696
+ message: "'biraz' sözcüğü bitişik yazılmalıdır.",
1697
+ type: "spelling",
1698
+ },
1699
+ {
1700
+ regex: /\bher\s+hangi\b/gi,
1701
+ suggestion: "herhangi",
1702
+ message: "'herhangi' sözcüğü bitişik yazılmalıdır.",
1703
+ type: "spelling",
1704
+ },
1705
+ {
1706
+ regex: /\bgit\s+gide\b/gi,
1707
+ suggestion: "gitgide",
1708
+ message: "'gitgide' zarfı bitişik yazılmalıdır.",
1709
+ type: "spelling",
1710
+ },
1711
+ {
1712
+ regex: /\bbirden\s+bire\b/gi,
1713
+ suggestion: "birdenbire",
1714
+ message: "'birdenbire' zarfı bitişik yazılmalıdır.",
1715
+ type: "spelling",
1716
+ },
1717
+ {
1718
+ regex: /\brast\s+gele\b/gi,
1719
+ suggestion: "rastgele",
1720
+ message: "'rastgele' zarfı bitişik yazılmalıdır.",
1721
+ type: "spelling",
1722
+ },
1723
+ ];
1724
+
1725
+ const coveredRanges: { start: number; end: number }[] = [];
1726
+ for (const pm of PHRASE_MISTAKES) {
1727
+ let pmMatch: RegExpExecArray | null;
1728
+ while ((pmMatch = pm.regex.exec(text)) !== null) {
1729
+ const start = pmMatch.index;
1730
+ const end = start + pmMatch[0].length;
1731
+ coveredRanges.push({ start, end });
1732
+ issues.push({
1733
+ type: pm.type,
1734
+ word: pmMatch[0],
1735
+ startIndex: start,
1736
+ endIndex: end,
1737
+ suggestion: pm.suggestion,
1738
+ message: pm.message,
1739
+ });
1740
+ }
1741
+ }
1742
+
1480
1743
  const tokenRegex = /[\p{L}0-9'’]+/gu;
1481
1744
  let match: RegExpExecArray | null;
1482
1745
 
@@ -1487,6 +1750,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1487
1750
  const lower = rawWord.toLocaleLowerCase("tr-TR");
1488
1751
 
1489
1752
  if (/^\d+$/.test(lower)) continue;
1753
+ if (coveredRanges.some((r) => startIndex >= r.start && endIndex <= r.end)) continue;
1490
1754
 
1491
1755
  let flagged = false;
1492
1756
 
@@ -1520,12 +1784,8 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1520
1784
  if (!(await this.isHeadword(lower))) {
1521
1785
  const root = await this.findRoot(base);
1522
1786
  const isVerb =
1523
- (root && (root.endsWith("mek") || root.endsWith("mak"))) ||
1524
- base === "demek" ||
1525
- base === "kaldı" ||
1526
- base === "yeter" ||
1527
- base === "bilmem" ||
1528
- VERB_CONJUGATION_REGEX.test(base);
1787
+ (base === "demek" || base === "kaldı" || base === "yeter" || base === "bilmem" || VERB_CONJUGATION_REGEX.test(base)) &&
1788
+ (root ? root.endsWith("mek") || root.endsWith("mak") : true);
1529
1789
 
1530
1790
  if (isVerb) {
1531
1791
  issues.push({
@@ -1549,8 +1809,8 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1549
1809
  if (!(await this.isHeadword(lower))) {
1550
1810
  const root = await this.findRoot(base);
1551
1811
  const isVerb =
1552
- (root && (root.endsWith("mek") || root.endsWith("mak"))) ||
1553
- VERB_CONJUGATION_REGEX.test(base);
1812
+ VERB_CONJUGATION_REGEX.test(base) &&
1813
+ (root ? root.endsWith("mek") || root.endsWith("mak") : false);
1554
1814
 
1555
1815
  if (isVerb) {
1556
1816
  const correctEnding = ending.startsWith("t") ? (ending === "te" ? "de" : "da") : ending;
@@ -1567,7 +1827,52 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1567
1827
  }
1568
1828
  }
1569
1829
 
1570
- // 4. General Spell Check
1830
+ // 4. Check -şey / -sey erroneously attached to preceding word
1831
+ const seyMatch = lower.match(/^(.+?)(?:şey|sey)([ıiuaeüodekmnl]+)?$/);
1832
+ if (!flagged && seyMatch && !SEY_EXCEPTIONS.has(lower)) {
1833
+ let prefix = seyMatch[1];
1834
+ const suffix = seyMatch[2] || "";
1835
+ if (prefix === "hicbir") prefix = "hiçbir";
1836
+ if (prefix === "cok") prefix = "çok";
1837
+ issues.push({
1838
+ type: "spelling",
1839
+ word: rawWord,
1840
+ startIndex,
1841
+ endIndex,
1842
+ suggestion: `${prefix} şey${suffix}`,
1843
+ message: "'şey' sözcüğü kendinden önceki kelimeden ayrı yazılmalıdır.",
1844
+ });
1845
+ flagged = true;
1846
+ }
1847
+
1848
+ // 5. Check 'yada' conjunction mistake
1849
+ if (!flagged && lower === "yada") {
1850
+ issues.push({
1851
+ type: "spelling",
1852
+ word: rawWord,
1853
+ startIndex,
1854
+ endIndex,
1855
+ suggestion: "ya da",
1856
+ message: "'ya da' bağlacı her zaman ayrı yazılır.",
1857
+ });
1858
+ flagged = true;
1859
+ }
1860
+
1861
+ // 6. Check common vowel drop mistakes: burda, şurda, orda, vb. (TDK Kural 15)
1862
+ if (!flagged && (lower === "burda" || lower === "şurda" || lower === "surda" || lower === "orda" || lower === "içerde" || lower === "icerde" || lower === "dışarda" || lower === "disarda" || lower === "yukarda")) {
1863
+ const correct = COMMON_MISSPELLINGS[lower] || lower;
1864
+ issues.push({
1865
+ type: "spelling",
1866
+ word: rawWord,
1867
+ startIndex,
1868
+ endIndex,
1869
+ suggestion: correct,
1870
+ message: `'${rawWord}' sözcüğünde ünlü düşmesi yapılmaz.`,
1871
+ });
1872
+ flagged = true;
1873
+ }
1874
+
1875
+ // 7. General Spell Check
1571
1876
  if (!flagged) {
1572
1877
  const check = await this.checkSpelling(rawWord);
1573
1878
  if (!check.isCorrect) {
@@ -1578,13 +1883,15 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1578
1883
  endIndex,
1579
1884
  suggestion: check.suggestion,
1580
1885
  message: check.suggestion
1581
- ? `'${rawWord}' yanlış yazılmış olabilir. Öneri: '${check.suggestion}'`
1886
+ ? `'${rawWord}' yanlış yazılmış olabilir.`
1582
1887
  : `'${rawWord}' sözlükte bulunamadı.`,
1583
1888
  });
1584
1889
  }
1585
1890
  }
1586
1891
  }
1587
1892
 
1893
+ issues.sort((a, b) => a.startIndex - b.startIndex);
1894
+
1588
1895
  return {
1589
1896
  text,
1590
1897
  issues,
@@ -51,6 +51,34 @@ async function runTests() {
51
51
  assert.strictEqual(combo.issues.some((i) => i.type === "question_particle"), true);
52
52
  console.log(" ✓ Combined proofread passed.");
53
53
 
54
+ // 5. Şey detachment check (herşey, hersey, birşeyler -> her şey, bir şeyler)
55
+ console.log("5. Testing -şey detachment...");
56
+ const s1 = await TDK.proofread("burda herşey yolunda");
57
+ assert.strictEqual(s1.isCorrect, false);
58
+ assert.strictEqual(s1.issues.length, 2);
59
+ assert.strictEqual(s1.issues[0].word, "burda");
60
+ assert.strictEqual(s1.issues[0].suggestion, "burada");
61
+ assert.strictEqual(s1.issues[1].word, "herşey");
62
+ assert.strictEqual(s1.issues[1].suggestion, "her şey");
63
+
64
+ const s2 = await TDK.proofread("hersey çok güzel");
65
+ assert.strictEqual(s2.isCorrect, false);
66
+ assert.strictEqual(s2.issues[0].word, "hersey");
67
+ assert.strictEqual(s2.issues[0].suggestion, "her şey");
68
+ console.log(" ✓ -şey detachment passed.");
69
+
70
+ // 6. Erroneously separated compound phrases (hiç bir, bir çok, git gide)
71
+ console.log("6. Testing compound phrases...");
72
+ const p1 = await TDK.proofread("hiç bir şey bilmiyor");
73
+ assert.strictEqual(p1.isCorrect, false);
74
+ assert.strictEqual(p1.issues[0].word, "hiç bir");
75
+ assert.strictEqual(p1.issues[0].suggestion, "hiçbir");
76
+
77
+ const p2 = await TDK.proofread("yada gelme");
78
+ assert.strictEqual(p2.isCorrect, false);
79
+ assert.strictEqual(p2.issues[0].suggestion, "ya da");
80
+ console.log(" ✓ Compound phrases passed.");
81
+
54
82
  console.log("\n All proofread tests passed successfully!");
55
83
  }
56
84