tdk-api-wrapper 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-7KJHYRJZ.mjs → chunk-ZFWZXNGY.mjs} +389 -13
- package/dist/cli.js +394 -14
- package/dist/cli.mjs +6 -2
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +389 -13
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/cli.ts +6 -1
- package/src/morphology.ts +9 -0
- package/src/tdk.ts +441 -40
- package/test/morphology.test.js +11 -0
- package/test/proofread.test.js +28 -0
package/dist/cli.js
CHANGED
|
@@ -560,6 +560,13 @@ function getStemCandidates(word2, minStemLength = 2, maxDepth = 4) {
|
|
|
560
560
|
seen.add(apostropheStem);
|
|
561
561
|
}
|
|
562
562
|
}
|
|
563
|
+
const bareInfinitives = restoreInfinitive(normalized);
|
|
564
|
+
for (const inf of bareInfinitives) {
|
|
565
|
+
if (!seen.has(inf) && inf !== normalized) {
|
|
566
|
+
seen.add(inf);
|
|
567
|
+
candidatesWithWeight.push({ candidate: inf, baseLength: normalized.length });
|
|
568
|
+
}
|
|
569
|
+
}
|
|
563
570
|
let frontier = [normalized];
|
|
564
571
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
565
572
|
const nextFrontier = [];
|
|
@@ -609,6 +616,210 @@ var path = __toESM(require("path"));
|
|
|
609
616
|
var os = __toESM(require("os"));
|
|
610
617
|
var https = __toESM(require("https"));
|
|
611
618
|
var tls = __toESM(require("tls"));
|
|
619
|
+
var COMMON_MISSPELLINGS = {
|
|
620
|
+
// -şey ile biten ve ayrı yazılması zorunlu söz öbekleri
|
|
621
|
+
her\u015Fey: "her \u015Fey",
|
|
622
|
+
hersey: "her \u015Fey",
|
|
623
|
+
bir\u015Fey: "bir \u015Fey",
|
|
624
|
+
birsey: "bir \u015Fey",
|
|
625
|
+
hi\u00E7bir\u015Fey: "hi\xE7bir \u015Fey",
|
|
626
|
+
hicbirsey: "hi\xE7bir \u015Fey",
|
|
627
|
+
\u00E7ok\u015Fey: "\xE7ok \u015Fey",
|
|
628
|
+
coksey: "\xE7ok \u015Fey",
|
|
629
|
+
\u015Feyler: "\u015Feyler",
|
|
630
|
+
seyler: "\u015Feyler",
|
|
631
|
+
herhangibir\u015Fey: "herhangi bir \u015Fey",
|
|
632
|
+
herhangibirsey: "herhangi bir \u015Fey",
|
|
633
|
+
// Sıkça birleşik yazılan ama ayrı yazılması gereken sözler
|
|
634
|
+
herg\u00FCn: "her g\xFCn",
|
|
635
|
+
hergun: "her g\xFCn",
|
|
636
|
+
herzaman: "her zaman",
|
|
637
|
+
heran: "her an",
|
|
638
|
+
heryer: "her yer",
|
|
639
|
+
herbiri: "her biri",
|
|
640
|
+
pek\u00E7ok: "pek \xE7ok",
|
|
641
|
+
pekcok: "pek \xE7ok",
|
|
642
|
+
pekaz: "pek az",
|
|
643
|
+
yada: "ya da",
|
|
644
|
+
tabiki: "tabii ki",
|
|
645
|
+
tabiiki: "tabii ki",
|
|
646
|
+
sa\u011Fol: "sa\u011F ol",
|
|
647
|
+
sagol: "sa\u011F ol",
|
|
648
|
+
sa\u011Folun: "sa\u011F olun",
|
|
649
|
+
sagolun: "sa\u011F olun",
|
|
650
|
+
ho\u015F\u00E7akal: "ho\u015F\xE7a kal",
|
|
651
|
+
hoscakal: "ho\u015F\xE7a kal",
|
|
652
|
+
ho\u015Fgeldin: "ho\u015F geldin",
|
|
653
|
+
hosgeldin: "ho\u015F geldin",
|
|
654
|
+
ho\u015Fgeldiniz: "ho\u015F geldiniz",
|
|
655
|
+
hosgeldiniz: "ho\u015F geldiniz",
|
|
656
|
+
ho\u015Fbulduk: "ho\u015F bulduk",
|
|
657
|
+
hosbulduk: "ho\u015F bulduk",
|
|
658
|
+
yan\u0131s\u0131ra: "yan\u0131 s\u0131ra",
|
|
659
|
+
yanisira: "yan\u0131 s\u0131ra",
|
|
660
|
+
pe\u015Fis\u0131ra: "pe\u015Fi s\u0131ra",
|
|
661
|
+
pesisira: "pe\u015Fi s\u0131ra",
|
|
662
|
+
ard\u0131s\u0131ra: "ard\u0131 s\u0131ra",
|
|
663
|
+
ardisira: "ard\u0131 s\u0131ra",
|
|
664
|
+
artarda: "art arda",
|
|
665
|
+
y\u00FCzy\u00FCze: "y\xFCz y\xFCze",
|
|
666
|
+
yuzyuze: "y\xFCz y\xFCze",
|
|
667
|
+
elele: "el ele",
|
|
668
|
+
g\u00F6zg\u00F6ze: "g\xF6z g\xF6ze",
|
|
669
|
+
ba\u015Fba\u015Fa: "ba\u015F ba\u015Fa",
|
|
670
|
+
basbasa: "ba\u015F ba\u015Fa",
|
|
671
|
+
yanyana: "yan yana",
|
|
672
|
+
i\u00E7i\u00E7e: "i\xE7 i\xE7e",
|
|
673
|
+
icice: "i\xE7 i\xE7e",
|
|
674
|
+
\u00FCst\u00FCste: "\xFCst \xFCste",
|
|
675
|
+
ustuste: "\xFCst \xFCste",
|
|
676
|
+
altalta: "alt alta",
|
|
677
|
+
\u00F6ns\u00F6z: "\xF6n s\xF6z",
|
|
678
|
+
onsoz: "\xF6n s\xF6z",
|
|
679
|
+
\u00F6nyarg\u0131: "\xF6n yarg\u0131",
|
|
680
|
+
onyargi: "\xF6n yarg\u0131",
|
|
681
|
+
farketmek: "fark etmek",
|
|
682
|
+
farketti: "fark etti",
|
|
683
|
+
farkettim: "fark ettim",
|
|
684
|
+
farkeder: "fark eder",
|
|
685
|
+
farketmez: "fark etmez",
|
|
686
|
+
terketmek: "terk etmek",
|
|
687
|
+
terketti: "terk etti",
|
|
688
|
+
ay\u0131rdetmek: "ay\u0131rt etmek",
|
|
689
|
+
ay\u0131rtetmek: "ay\u0131rt etmek",
|
|
690
|
+
arzetmek: "arz etmek",
|
|
691
|
+
arzederim: "arz ederim",
|
|
692
|
+
varolmak: "var olmak",
|
|
693
|
+
yokolmak: "yok olmak",
|
|
694
|
+
haketmek: "hak etmek",
|
|
695
|
+
haketti: "hak etti",
|
|
696
|
+
hakkaten: "hakikaten",
|
|
697
|
+
hi\u00E7kimse: "hi\xE7 kimse",
|
|
698
|
+
hickimse: "hi\xE7 kimse",
|
|
699
|
+
// Ünlü düşmesi yapılmaması gereken yer bildiren sözler (TDK Kural 15)
|
|
700
|
+
burda: "burada",
|
|
701
|
+
burdan: "buradan",
|
|
702
|
+
\u015Furda: "\u015Furada",
|
|
703
|
+
surda: "\u015Furada",
|
|
704
|
+
\u015Furdan: "\u015Furadan",
|
|
705
|
+
surdan: "\u015Furadan",
|
|
706
|
+
orda: "orada",
|
|
707
|
+
ordan: "oradan",
|
|
708
|
+
i\u00E7erde: "i\xE7eride",
|
|
709
|
+
icerde: "i\xE7eride",
|
|
710
|
+
i\u00E7erden: "i\xE7eriden",
|
|
711
|
+
icerden: "i\xE7eriden",
|
|
712
|
+
d\u0131\u015Farda: "d\u0131\u015Far\u0131da",
|
|
713
|
+
disarda: "d\u0131\u015Far\u0131da",
|
|
714
|
+
d\u0131\u015Fardan: "d\u0131\u015Far\u0131dan",
|
|
715
|
+
disardan: "d\u0131\u015Far\u0131dan",
|
|
716
|
+
yukarda: "yukar\u0131da",
|
|
717
|
+
yukardan: "yukar\u0131dan",
|
|
718
|
+
// Sıkça yanlış yazılan sözcükler
|
|
719
|
+
herkez: "herkes",
|
|
720
|
+
yanl\u0131z: "yaln\u0131z",
|
|
721
|
+
yaln\u0131\u015F: "yanl\u0131\u015F",
|
|
722
|
+
orjinal: "orijinal",
|
|
723
|
+
labaratuar: "laboratuvar",
|
|
724
|
+
laboratuar: "laboratuvar",
|
|
725
|
+
\u015F\u00F6f\u00F6r: "\u015Fof\xF6r",
|
|
726
|
+
sofor: "\u015Fof\xF6r",
|
|
727
|
+
egzos: "egzoz",
|
|
728
|
+
eksoz: "egzoz",
|
|
729
|
+
ekzoz: "egzoz",
|
|
730
|
+
kiprik: "kirpik",
|
|
731
|
+
kirbit: "kibrit",
|
|
732
|
+
klavuz: "k\u0131lavuz",
|
|
733
|
+
k\u0131ravat: "kravat",
|
|
734
|
+
s\u00FCpriz: "s\xFCrpriz",
|
|
735
|
+
supriz: "s\xFCrpriz",
|
|
736
|
+
raslant\u0131: "rastlant\u0131",
|
|
737
|
+
hastahane: "hastane",
|
|
738
|
+
pastahane: "pastane",
|
|
739
|
+
postahane: "postane",
|
|
740
|
+
eczahane: "eczane",
|
|
741
|
+
meyva: "meyve",
|
|
742
|
+
sarm\u0131sak: "sar\u0131msak",
|
|
743
|
+
dinazor: "dinozor",
|
|
744
|
+
pantalon: "pantolon",
|
|
745
|
+
tesbih: "tespih",
|
|
746
|
+
ah\u00E7\u0131: "a\u015F\xE7\u0131",
|
|
747
|
+
matba: "matbaa",
|
|
748
|
+
idda: "iddia",
|
|
749
|
+
iddaa: "iddia",
|
|
750
|
+
muhattap: "muhatap",
|
|
751
|
+
tra\u015F: "t\u0131ra\u015F",
|
|
752
|
+
karn\u0131bahar: "karnabahar",
|
|
753
|
+
kareografi: "koreografi",
|
|
754
|
+
poa\u00E7a: "po\u011Fa\xE7a",
|
|
755
|
+
poha\u00E7a: "po\u011Fa\xE7a",
|
|
756
|
+
\u015Farz: "\u015Farj",
|
|
757
|
+
sarj: "\u015Farj",
|
|
758
|
+
makina: "makine",
|
|
759
|
+
m\u00FCsade: "m\xFCsaade",
|
|
760
|
+
entellekt\u00FCel: "entelekt\xFCel",
|
|
761
|
+
inisiyatif: "inisiyatif",
|
|
762
|
+
insiyatif: "inisiyatif",
|
|
763
|
+
sezeryan: "sezaryen",
|
|
764
|
+
dok\u00FCman: "dok\xFCman",
|
|
765
|
+
d\u00F6k\u00FCman: "dok\xFCman",
|
|
766
|
+
erozyon: "erozyon",
|
|
767
|
+
erizyon: "erozyon",
|
|
768
|
+
anane: "anneanne",
|
|
769
|
+
babaanne: "babaanne"
|
|
770
|
+
};
|
|
771
|
+
var SEY_EXCEPTIONS = /* @__PURE__ */ new Set(["d\xFC\u015Fey", "e\u015Fey", "konsey", "jersey", "\u015Fey"]);
|
|
772
|
+
var KEYBOARD_ROWS = [
|
|
773
|
+
["qwertyu\u0131op\u011F\xFC", 0],
|
|
774
|
+
["asdfghjkl\u015Fi", 0.5],
|
|
775
|
+
["zxcvbnm\xF6\xE7", 1]
|
|
776
|
+
];
|
|
777
|
+
var KEYBOARD_COORDS = (() => {
|
|
778
|
+
const coords = {};
|
|
779
|
+
KEYBOARD_ROWS.forEach(([keys, offset], row) => {
|
|
780
|
+
[...keys].forEach((key, col) => {
|
|
781
|
+
coords[key] = [col + offset, row];
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
return coords;
|
|
785
|
+
})();
|
|
786
|
+
var DIACRITIC_SIBLINGS = {
|
|
787
|
+
\u0131: "i",
|
|
788
|
+
i: "\u0131",
|
|
789
|
+
\u00F6: "o",
|
|
790
|
+
o: "\xF6",
|
|
791
|
+
\u00FC: "u",
|
|
792
|
+
u: "\xFC",
|
|
793
|
+
\u015F: "s",
|
|
794
|
+
s: "\u015F",
|
|
795
|
+
\u00E7: "c",
|
|
796
|
+
c: "\xE7",
|
|
797
|
+
\u011F: "g",
|
|
798
|
+
g: "\u011F",
|
|
799
|
+
\u00E2: "a",
|
|
800
|
+
a: "\xE2"
|
|
801
|
+
};
|
|
802
|
+
var KEYBOARD_ROW_SUB_COST = 0.4;
|
|
803
|
+
var KEYBOARD_DIAGONAL_SUB_COST = 0.55;
|
|
804
|
+
var DIACRITIC_SUB_COST = 0.3;
|
|
805
|
+
var TRANSPOSITION_COST = 0.8;
|
|
806
|
+
function keyboardSubCost(a, b) {
|
|
807
|
+
if (a === b)
|
|
808
|
+
return 0;
|
|
809
|
+
if (DIACRITIC_SIBLINGS[a] === b)
|
|
810
|
+
return DIACRITIC_SUB_COST;
|
|
811
|
+
const pa = KEYBOARD_COORDS[a];
|
|
812
|
+
const pb = KEYBOARD_COORDS[b];
|
|
813
|
+
if (!pa || !pb)
|
|
814
|
+
return 1;
|
|
815
|
+
const dx = Math.abs(pa[0] - pb[0]);
|
|
816
|
+
const dy = Math.abs(pa[1] - pb[1]);
|
|
817
|
+
if (dy === 0 && dx <= 1 + 1e-9)
|
|
818
|
+
return KEYBOARD_ROW_SUB_COST;
|
|
819
|
+
if (dy === 1 && dx <= 1 + 1e-9)
|
|
820
|
+
return KEYBOARD_DIAGONAL_SUB_COST;
|
|
821
|
+
return 1;
|
|
822
|
+
}
|
|
612
823
|
var TDK = class {
|
|
613
824
|
static BASE_URL = "https://sozluk.gov.tr";
|
|
614
825
|
static AUDIO_API_HOST = "api.sozluk.gov.tr";
|
|
@@ -1172,25 +1383,45 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
1172
1383
|
* Checks spelling and returns suggestions if wrong.
|
|
1173
1384
|
*/
|
|
1174
1385
|
static async checkSpelling(word2) {
|
|
1386
|
+
if (!word2 || word2.trim() === "") {
|
|
1387
|
+
return { isCorrect: false, word: word2 };
|
|
1388
|
+
}
|
|
1389
|
+
const cleanWord = word2.trim().toLocaleLowerCase("tr-TR");
|
|
1175
1390
|
const results = await this.getWord(word2);
|
|
1176
1391
|
if (results.length > 0) {
|
|
1177
1392
|
return { isCorrect: true, word: word2 };
|
|
1178
1393
|
}
|
|
1394
|
+
if (COMMON_MISSPELLINGS[cleanWord]) {
|
|
1395
|
+
return { isCorrect: false, word: word2, suggestion: COMMON_MISSPELLINGS[cleanWord] };
|
|
1396
|
+
}
|
|
1397
|
+
const seyMatch = cleanWord.match(/^(.+?)(?:şey|sey)([ıiuaeüodekmnl]+)?$/);
|
|
1398
|
+
if (seyMatch && !SEY_EXCEPTIONS.has(cleanWord)) {
|
|
1399
|
+
let prefix = seyMatch[1];
|
|
1400
|
+
const suffix = seyMatch[2] || "";
|
|
1401
|
+
if (prefix === "hicbir")
|
|
1402
|
+
prefix = "hi\xE7bir";
|
|
1403
|
+
if (prefix === "cok")
|
|
1404
|
+
prefix = "\xE7ok";
|
|
1405
|
+
return {
|
|
1406
|
+
isCorrect: false,
|
|
1407
|
+
word: word2,
|
|
1408
|
+
suggestion: `${prefix} \u015Fey${suffix}`
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1179
1411
|
const daily = await this.getDailyContent();
|
|
1180
1412
|
if (daily) {
|
|
1181
|
-
const syydMatch = daily.syyd.find((s) => s.yanliskelime.toLocaleLowerCase("tr-TR") ===
|
|
1413
|
+
const syydMatch = daily.syyd.find((s) => s.yanliskelime.toLocaleLowerCase("tr-TR") === cleanWord);
|
|
1182
1414
|
if (syydMatch) {
|
|
1183
1415
|
return { isCorrect: false, word: word2, suggestion: syydMatch.dogrukelime };
|
|
1184
1416
|
}
|
|
1185
|
-
const mixMatch = daily.karistirma.find((s) => s.yanlis.toLocaleLowerCase("tr-TR") ===
|
|
1417
|
+
const mixMatch = daily.karistirma.find((s) => s.yanlis.toLocaleLowerCase("tr-TR") === cleanWord);
|
|
1186
1418
|
if (mixMatch) {
|
|
1187
1419
|
return { isCorrect: false, word: word2, suggestion: mixMatch.dogru };
|
|
1188
1420
|
}
|
|
1189
1421
|
}
|
|
1190
1422
|
const root = await this.findRoot(word2);
|
|
1191
1423
|
if (root) {
|
|
1192
|
-
const
|
|
1193
|
-
const isInflected = root !== cleanWord2;
|
|
1424
|
+
const isInflected = root !== cleanWord;
|
|
1194
1425
|
return {
|
|
1195
1426
|
isCorrect: true,
|
|
1196
1427
|
word: word2,
|
|
@@ -1201,24 +1432,32 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
1201
1432
|
if (this.autocompleteCache.length === 0) {
|
|
1202
1433
|
this.autocompleteCache = await this.fetchAutocompleteData();
|
|
1203
1434
|
}
|
|
1204
|
-
const
|
|
1435
|
+
for (const candidate of this.autocompleteCache) {
|
|
1436
|
+
if (candidate.includes(" ")) {
|
|
1437
|
+
const candidateNoSpace = candidate.replace(/\s+/g, "").toLocaleLowerCase("tr-TR");
|
|
1438
|
+
if (candidateNoSpace === cleanWord) {
|
|
1439
|
+
return { isCorrect: false, word: word2, suggestion: candidate };
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1205
1443
|
let best = null;
|
|
1206
1444
|
for (const candidate of this.autocompleteCache) {
|
|
1207
1445
|
if (candidate.includes(" ") || candidate !== candidate.toLocaleLowerCase("tr-TR"))
|
|
1208
1446
|
continue;
|
|
1209
1447
|
if (Math.abs(candidate.length - cleanWord.length) > 2)
|
|
1210
1448
|
continue;
|
|
1211
|
-
const
|
|
1212
|
-
if (
|
|
1449
|
+
const rawDist = this.damerauLevenshtein(cleanWord, candidate);
|
|
1450
|
+
if (rawDist === 0 || rawDist > 2)
|
|
1213
1451
|
continue;
|
|
1214
1452
|
const firstMismatch = candidate[0] === cleanWord[0] ? 0 : 1;
|
|
1215
1453
|
const lengthMismatch = candidate.length === cleanWord.length ? 0 : 1;
|
|
1216
|
-
const
|
|
1454
|
+
const score = this.keyboardAwareDistance(cleanWord, candidate) + (firstMismatch > 0 ? 1.2 : 0);
|
|
1455
|
+
const better = !best || score < best.score - 1e-9 || Math.abs(score - best.score) < 1e-9 && firstMismatch < best.firstMismatch || Math.abs(score - best.score) < 1e-9 && firstMismatch === best.firstMismatch && lengthMismatch < best.lengthMismatch;
|
|
1217
1456
|
if (better) {
|
|
1218
|
-
best = { candidate,
|
|
1457
|
+
best = { candidate, score, rawDist, firstMismatch, lengthMismatch };
|
|
1219
1458
|
}
|
|
1220
1459
|
}
|
|
1221
|
-
if (best && best.
|
|
1460
|
+
if (best && best.rawDist <= 2 && (best.firstMismatch === 0 || best.rawDist <= 1)) {
|
|
1222
1461
|
return { isCorrect: false, word: word2, suggestion: best.candidate };
|
|
1223
1462
|
}
|
|
1224
1463
|
return { isCorrect: false, word: word2 };
|
|
@@ -1747,6 +1986,32 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
1747
1986
|
}
|
|
1748
1987
|
return dp[a.length][b.length];
|
|
1749
1988
|
}
|
|
1989
|
+
/**
|
|
1990
|
+
* Keyboard- and diacritic-aware edit distance: same optimal-string-alignment
|
|
1991
|
+
* recurrence as {@link damerauLevenshtein}, but a substitution is charged by
|
|
1992
|
+
* {@link keyboardSubCost} (a fraction of an edit when the two letters are
|
|
1993
|
+
* adjacent on a Turkish Q keyboard or are ASCII/diacritic siblings) and a
|
|
1994
|
+
* transposition costs {@link TRANSPOSITION_COST}. Insertions and deletions
|
|
1995
|
+
* still cost a full 1. Used only to *rank* spelling candidates; the plain
|
|
1996
|
+
* integer distance still gates whether a suggestion is offered at all.
|
|
1997
|
+
*/
|
|
1998
|
+
static keyboardAwareDistance(a, b) {
|
|
1999
|
+
const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
|
|
2000
|
+
for (let i = 0; i <= a.length; i++)
|
|
2001
|
+
dp[i][0] = i;
|
|
2002
|
+
for (let j = 0; j <= b.length; j++)
|
|
2003
|
+
dp[0][j] = j;
|
|
2004
|
+
for (let i = 1; i <= a.length; i++) {
|
|
2005
|
+
for (let j = 1; j <= b.length; j++) {
|
|
2006
|
+
const cost = keyboardSubCost(a[i - 1], b[j - 1]);
|
|
2007
|
+
dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
|
|
2008
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
2009
|
+
dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + TRANSPOSITION_COST);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return dp[a.length][b.length];
|
|
2014
|
+
}
|
|
1750
2015
|
/**
|
|
1751
2016
|
* Fetches multiple words concurrently with a small delay to avoid rate limiting.
|
|
1752
2017
|
*/
|
|
@@ -1971,6 +2236,73 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
1971
2236
|
"me\u011Ferki",
|
|
1972
2237
|
"illaki"
|
|
1973
2238
|
]);
|
|
2239
|
+
const PHRASE_MISTAKES = [
|
|
2240
|
+
{
|
|
2241
|
+
regex: /\bhiç\s+bir\b/gi,
|
|
2242
|
+
suggestion: "hi\xE7bir",
|
|
2243
|
+
message: "'hi\xE7bir' belgisiz s\u0131fat\u0131 biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2244
|
+
type: "spelling"
|
|
2245
|
+
},
|
|
2246
|
+
{
|
|
2247
|
+
regex: /\bbir\s+çok\b/gi,
|
|
2248
|
+
suggestion: "bir\xE7ok",
|
|
2249
|
+
message: "'bir\xE7ok' belgisiz s\u0131fat\u0131/zamiri biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2250
|
+
type: "spelling"
|
|
2251
|
+
},
|
|
2252
|
+
{
|
|
2253
|
+
regex: /\bbir\s+kaç\b/gi,
|
|
2254
|
+
suggestion: "birka\xE7",
|
|
2255
|
+
message: "'birka\xE7' belgisiz s\u0131fat\u0131/zamiri biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2256
|
+
type: "spelling"
|
|
2257
|
+
},
|
|
2258
|
+
{
|
|
2259
|
+
regex: /\bbir\s+az\b/gi,
|
|
2260
|
+
suggestion: "biraz",
|
|
2261
|
+
message: "'biraz' s\xF6zc\xFC\u011F\xFC biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2262
|
+
type: "spelling"
|
|
2263
|
+
},
|
|
2264
|
+
{
|
|
2265
|
+
regex: /\bher\s+hangi\b/gi,
|
|
2266
|
+
suggestion: "herhangi",
|
|
2267
|
+
message: "'herhangi' s\xF6zc\xFC\u011F\xFC biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2268
|
+
type: "spelling"
|
|
2269
|
+
},
|
|
2270
|
+
{
|
|
2271
|
+
regex: /\bgit\s+gide\b/gi,
|
|
2272
|
+
suggestion: "gitgide",
|
|
2273
|
+
message: "'gitgide' zarf\u0131 biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2274
|
+
type: "spelling"
|
|
2275
|
+
},
|
|
2276
|
+
{
|
|
2277
|
+
regex: /\bbirden\s+bire\b/gi,
|
|
2278
|
+
suggestion: "birdenbire",
|
|
2279
|
+
message: "'birdenbire' zarf\u0131 biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2280
|
+
type: "spelling"
|
|
2281
|
+
},
|
|
2282
|
+
{
|
|
2283
|
+
regex: /\brast\s+gele\b/gi,
|
|
2284
|
+
suggestion: "rastgele",
|
|
2285
|
+
message: "'rastgele' zarf\u0131 biti\u015Fik yaz\u0131lmal\u0131d\u0131r.",
|
|
2286
|
+
type: "spelling"
|
|
2287
|
+
}
|
|
2288
|
+
];
|
|
2289
|
+
const coveredRanges = [];
|
|
2290
|
+
for (const pm of PHRASE_MISTAKES) {
|
|
2291
|
+
let pmMatch;
|
|
2292
|
+
while ((pmMatch = pm.regex.exec(text)) !== null) {
|
|
2293
|
+
const start = pmMatch.index;
|
|
2294
|
+
const end = start + pmMatch[0].length;
|
|
2295
|
+
coveredRanges.push({ start, end });
|
|
2296
|
+
issues.push({
|
|
2297
|
+
type: pm.type,
|
|
2298
|
+
word: pmMatch[0],
|
|
2299
|
+
startIndex: start,
|
|
2300
|
+
endIndex: end,
|
|
2301
|
+
suggestion: pm.suggestion,
|
|
2302
|
+
message: pm.message
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
1974
2306
|
const tokenRegex = /[\p{L}0-9'’]+/gu;
|
|
1975
2307
|
let match;
|
|
1976
2308
|
while ((match = tokenRegex.exec(text)) !== null) {
|
|
@@ -1980,6 +2312,8 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
1980
2312
|
const lower = rawWord.toLocaleLowerCase("tr-TR");
|
|
1981
2313
|
if (/^\d+$/.test(lower))
|
|
1982
2314
|
continue;
|
|
2315
|
+
if (coveredRanges.some((r) => startIndex >= r.start && endIndex <= r.end))
|
|
2316
|
+
continue;
|
|
1983
2317
|
let flagged = false;
|
|
1984
2318
|
const questionMatch = lower.match(/^(.+?)(m[ıiuü](?:sin|sın|sun|sün|siniz|sınız|sunuz|sünüz|yiz|yız|yuz|yüz|m|k)?)$/);
|
|
1985
2319
|
if (questionMatch) {
|
|
@@ -2005,7 +2339,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
2005
2339
|
if (!SOMBAHCEMI.has(lower)) {
|
|
2006
2340
|
if (!await this.isHeadword(lower)) {
|
|
2007
2341
|
const root = await this.findRoot(base);
|
|
2008
|
-
const isVerb =
|
|
2342
|
+
const isVerb = (base === "demek" || base === "kald\u0131" || base === "yeter" || base === "bilmem" || VERB_CONJUGATION_REGEX.test(base)) && (root ? root.endsWith("mek") || root.endsWith("mak") : true);
|
|
2009
2343
|
if (isVerb) {
|
|
2010
2344
|
issues.push({
|
|
2011
2345
|
type: "conjunction_ki",
|
|
@@ -2025,7 +2359,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
2025
2359
|
const ending = lower.slice(-2);
|
|
2026
2360
|
if (!await this.isHeadword(lower)) {
|
|
2027
2361
|
const root = await this.findRoot(base);
|
|
2028
|
-
const isVerb =
|
|
2362
|
+
const isVerb = VERB_CONJUGATION_REGEX.test(base) && (root ? root.endsWith("mek") || root.endsWith("mak") : false);
|
|
2029
2363
|
if (isVerb) {
|
|
2030
2364
|
const correctEnding = ending.startsWith("t") ? ending === "te" ? "de" : "da" : ending;
|
|
2031
2365
|
issues.push({
|
|
@@ -2040,6 +2374,47 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
2040
2374
|
}
|
|
2041
2375
|
}
|
|
2042
2376
|
}
|
|
2377
|
+
const seyMatch = lower.match(/^(.+?)(?:şey|sey)([ıiuaeüodekmnl]+)?$/);
|
|
2378
|
+
if (!flagged && seyMatch && !SEY_EXCEPTIONS.has(lower)) {
|
|
2379
|
+
let prefix = seyMatch[1];
|
|
2380
|
+
const suffix = seyMatch[2] || "";
|
|
2381
|
+
if (prefix === "hicbir")
|
|
2382
|
+
prefix = "hi\xE7bir";
|
|
2383
|
+
if (prefix === "cok")
|
|
2384
|
+
prefix = "\xE7ok";
|
|
2385
|
+
issues.push({
|
|
2386
|
+
type: "spelling",
|
|
2387
|
+
word: rawWord,
|
|
2388
|
+
startIndex,
|
|
2389
|
+
endIndex,
|
|
2390
|
+
suggestion: `${prefix} \u015Fey${suffix}`,
|
|
2391
|
+
message: "'\u015Fey' s\xF6zc\xFC\u011F\xFC kendinden \xF6nceki kelimeden ayr\u0131 yaz\u0131lmal\u0131d\u0131r."
|
|
2392
|
+
});
|
|
2393
|
+
flagged = true;
|
|
2394
|
+
}
|
|
2395
|
+
if (!flagged && lower === "yada") {
|
|
2396
|
+
issues.push({
|
|
2397
|
+
type: "spelling",
|
|
2398
|
+
word: rawWord,
|
|
2399
|
+
startIndex,
|
|
2400
|
+
endIndex,
|
|
2401
|
+
suggestion: "ya da",
|
|
2402
|
+
message: "'ya da' ba\u011Flac\u0131 her zaman ayr\u0131 yaz\u0131l\u0131r."
|
|
2403
|
+
});
|
|
2404
|
+
flagged = true;
|
|
2405
|
+
}
|
|
2406
|
+
if (!flagged && (lower === "burda" || lower === "\u015Furda" || lower === "surda" || lower === "orda" || lower === "i\xE7erde" || lower === "icerde" || lower === "d\u0131\u015Farda" || lower === "disarda" || lower === "yukarda")) {
|
|
2407
|
+
const correct = COMMON_MISSPELLINGS[lower] || lower;
|
|
2408
|
+
issues.push({
|
|
2409
|
+
type: "spelling",
|
|
2410
|
+
word: rawWord,
|
|
2411
|
+
startIndex,
|
|
2412
|
+
endIndex,
|
|
2413
|
+
suggestion: correct,
|
|
2414
|
+
message: `'${rawWord}' s\xF6zc\xFC\u011F\xFCnde \xFCnl\xFC d\xFC\u015Fmesi yap\u0131lmaz.`
|
|
2415
|
+
});
|
|
2416
|
+
flagged = true;
|
|
2417
|
+
}
|
|
2043
2418
|
if (!flagged) {
|
|
2044
2419
|
const check = await this.checkSpelling(rawWord);
|
|
2045
2420
|
if (!check.isCorrect) {
|
|
@@ -2049,11 +2424,12 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
|
|
|
2049
2424
|
startIndex,
|
|
2050
2425
|
endIndex,
|
|
2051
2426
|
suggestion: check.suggestion,
|
|
2052
|
-
message: check.suggestion ? `'${rawWord}' yanl\u0131\u015F yaz\u0131lm\u0131\u015F olabilir
|
|
2427
|
+
message: check.suggestion ? `'${rawWord}' yanl\u0131\u015F yaz\u0131lm\u0131\u015F olabilir.` : `'${rawWord}' s\xF6zl\xFCkte bulunamad\u0131.`
|
|
2053
2428
|
});
|
|
2054
2429
|
}
|
|
2055
2430
|
}
|
|
2056
2431
|
}
|
|
2432
|
+
issues.sort((a, b) => a.startIndex - b.startIndex);
|
|
2057
2433
|
return {
|
|
2058
2434
|
text,
|
|
2059
2435
|
issues,
|
|
@@ -2111,7 +2487,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
2111
2487
|
]);
|
|
2112
2488
|
var command = args[0];
|
|
2113
2489
|
var word = args.slice(1).join(" ");
|
|
2114
|
-
if (command && !KNOWN_COMMANDS.has(command) && command !== "--help" && command !== "-h") {
|
|
2490
|
+
if (command && !KNOWN_COMMANDS.has(command) && command !== "--help" && command !== "-h" && command !== "--version" && command !== "-v") {
|
|
2115
2491
|
word = args.join(" ");
|
|
2116
2492
|
command = "anlam";
|
|
2117
2493
|
}
|
|
@@ -2206,6 +2582,10 @@ async function run() {
|
|
|
2206
2582
|
console.log("Not: Komut belirtilmezse do\u011Frudan kelime anlam\u0131 aran\u0131r (\xF6rn: tdk selam)");
|
|
2207
2583
|
process.exit(1);
|
|
2208
2584
|
}
|
|
2585
|
+
if (command === "--version" || command === "-v") {
|
|
2586
|
+
console.log("tdk-api-wrapper v1.5.1");
|
|
2587
|
+
process.exit(0);
|
|
2588
|
+
}
|
|
2209
2589
|
if (command === "--help" || command === "-h") {
|
|
2210
2590
|
console.log("Kullan\u0131m: tdk [komut] <kelime> [--json]");
|
|
2211
2591
|
console.log(
|
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
TDK
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZFWZXNGY.mjs";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
var rawArgs = process.argv.slice(2);
|
|
@@ -52,7 +52,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
52
52
|
]);
|
|
53
53
|
var command = args[0];
|
|
54
54
|
var word = args.slice(1).join(" ");
|
|
55
|
-
if (command && !KNOWN_COMMANDS.has(command) && command !== "--help" && command !== "-h") {
|
|
55
|
+
if (command && !KNOWN_COMMANDS.has(command) && command !== "--help" && command !== "-h" && command !== "--version" && command !== "-v") {
|
|
56
56
|
word = args.join(" ");
|
|
57
57
|
command = "anlam";
|
|
58
58
|
}
|
|
@@ -147,6 +147,10 @@ async function run() {
|
|
|
147
147
|
console.log("Not: Komut belirtilmezse do\u011Frudan kelime anlam\u0131 aran\u0131r (\xF6rn: tdk selam)");
|
|
148
148
|
process.exit(1);
|
|
149
149
|
}
|
|
150
|
+
if (command === "--version" || command === "-v") {
|
|
151
|
+
console.log("tdk-api-wrapper v1.5.1");
|
|
152
|
+
process.exit(0);
|
|
153
|
+
}
|
|
150
154
|
if (command === "--help" || command === "-h") {
|
|
151
155
|
console.log("Kullan\u0131m: tdk [komut] <kelime> [--json]");
|
|
152
156
|
console.log(
|
package/dist/index.d.mts
CHANGED
|
@@ -508,6 +508,16 @@ declare class TDK {
|
|
|
508
508
|
* otherwise misses.
|
|
509
509
|
*/
|
|
510
510
|
private static damerauLevenshtein;
|
|
511
|
+
/**
|
|
512
|
+
* Keyboard- and diacritic-aware edit distance: same optimal-string-alignment
|
|
513
|
+
* recurrence as {@link damerauLevenshtein}, but a substitution is charged by
|
|
514
|
+
* {@link keyboardSubCost} (a fraction of an edit when the two letters are
|
|
515
|
+
* adjacent on a Turkish Q keyboard or are ASCII/diacritic siblings) and a
|
|
516
|
+
* transposition costs {@link TRANSPOSITION_COST}. Insertions and deletions
|
|
517
|
+
* still cost a full 1. Used only to *rank* spelling candidates; the plain
|
|
518
|
+
* integer distance still gates whether a suggestion is offered at all.
|
|
519
|
+
*/
|
|
520
|
+
private static keyboardAwareDistance;
|
|
511
521
|
/**
|
|
512
522
|
* Fetches multiple words concurrently with a small delay to avoid rate limiting.
|
|
513
523
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -508,6 +508,16 @@ declare class TDK {
|
|
|
508
508
|
* otherwise misses.
|
|
509
509
|
*/
|
|
510
510
|
private static damerauLevenshtein;
|
|
511
|
+
/**
|
|
512
|
+
* Keyboard- and diacritic-aware edit distance: same optimal-string-alignment
|
|
513
|
+
* recurrence as {@link damerauLevenshtein}, but a substitution is charged by
|
|
514
|
+
* {@link keyboardSubCost} (a fraction of an edit when the two letters are
|
|
515
|
+
* adjacent on a Turkish Q keyboard or are ASCII/diacritic siblings) and a
|
|
516
|
+
* transposition costs {@link TRANSPOSITION_COST}. Insertions and deletions
|
|
517
|
+
* still cost a full 1. Used only to *rank* spelling candidates; the plain
|
|
518
|
+
* integer distance still gates whether a suggestion is offered at all.
|
|
519
|
+
*/
|
|
520
|
+
private static keyboardAwareDistance;
|
|
511
521
|
/**
|
|
512
522
|
* Fetches multiple words concurrently with a small delay to avoid rate limiting.
|
|
513
523
|
*/
|