affixi
Version:
Affixi is a helper library for Turkish suffixes for nouns and proper nouns written in typescript.
729 lines (728 loc) • 26.3 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.AffixiWord = exports.makeCompound = exports.getCompoundSuffix = exports.makeCase = exports.getCaseSuffix = exports.makePossesive = exports.getPossesiveSuffix = exports.makeEqual = exports.getEqualitySuffix = exports.makePlural = exports.getPluralSuffix = exports.alterToVowelDrop = exports.alterToVoicedConsonant = exports.getVoicedConsonant = exports.exceptions = exports.sounds = exports.util = exports.Compound = exports.Case = exports.Pronoun = void 0;
var tslib_1 = require("tslib");
var Pronoun;
(function (Pronoun) {
/** Birinci Tekil Şahıs */
Pronoun[Pronoun["SingularFirst"] = 0] = "SingularFirst";
/** İkinci Tekil Şahıs */
Pronoun[Pronoun["SingularSecond"] = 1] = "SingularSecond";
/** Üçüncü Tekil Şahıs */
Pronoun[Pronoun["SingularThird"] = 2] = "SingularThird";
/** Birinci Çoğul Şahıs */
Pronoun[Pronoun["PluralFirst"] = 3] = "PluralFirst";
/** İkinci Çoğul Şahıs */
Pronoun[Pronoun["PluralSecond"] = 4] = "PluralSecond";
/** Üçüncü Çoğul Şahıs */
Pronoun[Pronoun["PluralThird"] = 5] = "PluralThird";
})(Pronoun = exports.Pronoun || (exports.Pronoun = {}));
var Case;
(function (Case) {
/** İsmin Yalın Hâli - */
Case[Case["Absolute"] = 0] = "Absolute";
/** İsmin Belirtme Hâli -i */
Case[Case["Accusative"] = 1] = "Accusative";
/** İsmin Ayrılma Hâli -den */
Case[Case["Ablative"] = 2] = "Ablative";
/** İsmin Bulunma Hâli -de */
Case[Case["Locative"] = 3] = "Locative";
/** İsmin Vasıta Hâli -ile */
Case[Case["Instrumental"] = 4] = "Instrumental";
/** İsmin Yönelme Hâli -e */
Case[Case["Dative"] = 5] = "Dative";
})(Case = exports.Case || (exports.Case = {}));
var Compound;
(function (Compound) {
/** Tamlayan */
Compound[Compound["Compounder"] = 0] = "Compounder";
/** Tamlanan */
Compound[Compound["Compoundee"] = 1] = "Compoundee";
})(Compound = exports.Compound || (exports.Compound = {}));
exports.util = {
duplicateToUppercase: function (list) {
var copy = (0, tslib_1.__spreadArray)([], list, true);
return (0, tslib_1.__spreadArray)((0, tslib_1.__spreadArray)([], list, true), copy.map(function (item) { return item.toLocaleUpperCase('tr'); }), true);
},
getComponents: function (base) {
var input = base.split('').reverse().join('');
var index = 0;
var letter = input[0].toLocaleLowerCase('tr');
var vowel = input[index].toLocaleLowerCase('tr');
while (!exports.sounds.vowels.includes(vowel)) {
index++;
vowel = input[index].toLocaleLowerCase('tr');
}
return { letter: letter, vowel: vowel };
},
getSyllableCount: function (base) {
var count = 0;
var input = base.split('');
input.forEach(function (letter) {
if (exports.sounds.vowels.includes(letter))
count++;
});
return count;
},
getNumberText: function (value) {
var numberString = value.toString();
var map = ['sıfır', 'bir', 'iki', 'üç', 'dört', 'beş', 'altı', 'yedi', 'sekiz', 'dokuz'];
var tensMap = [null, 'on', 'yirmi', 'otuz', 'kırk', 'elli', 'altmış', 'yetmiş', 'seksen', 'doksan'];
var lastDigit = value % 10;
if (value === 0) {
return map[0];
}
if (lastDigit !== 0) {
return map[lastDigit];
}
var coefficientIndex = 0;
var currentValue = '0';
while (currentValue === '0') {
coefficientIndex++;
currentValue = numberString.split('').reverse()[coefficientIndex];
}
if (coefficientIndex === 1) {
var tensDigit = value.toString().split('').reverse()[1];
return tensMap[parseInt(tensDigit, 10)];
}
if (coefficientIndex === 2) {
return 'yüz';
}
if (coefficientIndex >= 3 && coefficientIndex < 6) {
return 'bin';
}
if (coefficientIndex >= 6 && coefficientIndex < 9) {
return 'milyon';
}
if (coefficientIndex >= 9 && coefficientIndex < 12) {
return 'milyar';
}
if ((coefficientIndex >= 12 && coefficientIndex < 15) || (coefficientIndex >= 15 && coefficientIndex < 18)) {
return 'trilyon';
}
return 'a';
}
};
exports.sounds = {
unvoicedStoppingConsonants: exports.util.duplicateToUppercase(['p', 'ç', 't', 'k']),
unvoicedContinuousConsonants: exports.util.duplicateToUppercase(['f', 's', 'ş', 'h']),
voicedStoppingConsonants: exports.util.duplicateToUppercase(['b', 'c', 'd', 'ğ']),
concatentorConsonants: exports.util.duplicateToUppercase(['y', 'ş', 's', 'n']),
unvoicedConsonants: exports.util.duplicateToUppercase(['f', 's', 'ş', 'h', 'p', 'ç', 't', 'k']),
roundedVowels: exports.util.duplicateToUppercase(['o', 'u', 'ö', 'ü']),
unRoundedVowels: exports.util.duplicateToUppercase(['a', 'ı', 'e', 'i']),
backVowels: exports.util.duplicateToUppercase(['e', 'i', 'ö', 'ü']),
frontVowels: exports.util.duplicateToUppercase(['a', 'ı', 'o', 'u']),
acuteVowels: exports.util.duplicateToUppercase(['ı', 'i', 'u', 'ü']),
wideVowels: exports.util.duplicateToUppercase(['a', 'e', 'o', 'ö']),
vowels: exports.util.duplicateToUppercase(['a', 'e', 'ı', 'i', 'o', 'ö', 'u', 'ü'])
};
exports.exceptions = {
/** Unvoiced exceptions that does not soften with a vowel suffix immediately after */
unvoiced: ['hukuk', 'bilet', 'tabiat', 'devlet', 'bisiklet', 'millet', 'ahret', 'ahiret', 'merak'],
/** Unvoiced single syllable exceptions that does soften with a vowel suffix immediately after */
unvoicedSingleSyllable: ['uç'],
/** Exceptions that need to be filled when made plural */
plural: ['o'],
/** Limited list of words that drop their vowe upon a cretain condition */
vowelDrop: [
'ağız',
'akıl',
'alın',
'bağır',
'beyin',
'boyun',
'burun',
'çevir',
'devir',
'emir',
'fikir',
'göğüs',
'gönül',
'hapis',
'isim',
'karın',
'kayıp',
'nehir',
'oğul',
'ömür',
'sabır',
'seyir',
'şehir',
'şekil',
'zulüm',
]
};
function transformBase(_base) {
if (typeof _base === 'number') {
return exports.util.getNumberText(_base);
}
return _base;
}
/** Some words that end with an unvoiced consonants (p,ç,t,k) may be converted into their voiced counterparts (b,c,d,ğ).
* If extist, this function returns the voiced consonant. If not returns undefined -
* Eğer kelime sert ünsüz ile bitiyorsa, ünsüzün yumuşak halini, bitmiyorsa undefined döndürür
*/
var getVoicedConsonant = function (_base, isProperNoun) {
if (isProperNoun === void 0) { isProperNoun = false; }
var base = transformBase(_base);
var letter = exports.util.getComponents(base).letter;
if (exports.sounds.unvoicedStoppingConsonants.includes(letter) &&
!isProperNoun &&
!exports.exceptions.unvoiced.includes(base.toLocaleLowerCase('tr'))) {
var i = exports.sounds.unvoicedStoppingConsonants.indexOf(base[base.length - 1]);
var voicedCounterPart = void 0;
var isNK = base
.split('')
.slice(base.length - 2, base.length)
.join('') === 'nk';
if (isNK) {
voicedCounterPart = 'g';
}
else {
if (exports.util.getSyllableCount(base) > 1 || exports.exceptions.unvoicedSingleSyllable.includes(base.toLocaleLowerCase('tr'))) {
voicedCounterPart = exports.sounds.voicedStoppingConsonants[i];
}
}
return voicedCounterPart;
}
return;
};
exports.getVoicedConsonant = getVoicedConsonant;
/** This function returns the mutated version of a word with its voiced consonant. If base does not have a voiced counterpart, the base itself is returned -
* Kelimenin sonunda sert ünsüz varsa, sert ünsüzü yumuşak haliyle değiştirir, yoksa kelimenin kendisini döndürür
* 'Renk' -> 'Reng'
* 'Akıl' -> 'Akıl'
*/
var alterToVoicedConsonant = function (_base, isProperNoun) {
if (isProperNoun === void 0) { isProperNoun = false; }
var base = transformBase(_base);
var voicedCounterPart = (0, exports.getVoicedConsonant)(base, isProperNoun);
if (voicedCounterPart) {
var result = base
.split('')
.splice(0, base.length - 1)
.join('') + voicedCounterPart;
return result;
}
return base;
};
exports.alterToVoicedConsonant = alterToVoicedConsonant;
/** Alter given word to its vowel dropped version. If no vowel is supposed to drop, the word itself is returned -
* Verilen kelimenin hecesi düşmüş versiyonunu döndürür. Eğer kelimede ünlü düşmesi yoksa, kelimenin kendisi döndürülür
* e.g 'Akıl' -> 'Akl',
* e.g 'Bebek' -> 'Bebek'
*/
var alterToVowelDrop = function (_base) {
var base = transformBase(_base);
var vowel = exports.util.getComponents(base).vowel;
var word = base.trim();
if (exports.util.getSyllableCount(base) === 2 &&
exports.sounds.acuteVowels.includes(vowel) &&
exports.exceptions.vowelDrop.includes(word.toLocaleLowerCase('tr'))) {
// Remove the last vowel e.g 'Akıl' -> 'Akl'
var result = word.split('').reverse().join('').replace(vowel, '').split('').reverse().join('');
return result;
}
return word;
};
exports.alterToVowelDrop = alterToVowelDrop;
/** Returns the plural suffix for a given word -
* Verilen kelimenin çoğul ekini dödürür
*/
var getPluralSuffix = function (_base) {
var base = transformBase(_base);
var vowel = exports.util.getComponents(base).vowel;
var result;
var infix = '';
if (exports.sounds.frontVowels.includes(vowel)) {
result = 'lar';
}
else if (exports.sounds.backVowels.includes(vowel)) {
result = 'ler';
}
else {
throw Error('Unknown vowel');
}
if (exports.exceptions.plural.includes(base.toLocaleLowerCase('tr'))) {
infix = 'n';
}
return infix + result;
};
exports.getPluralSuffix = getPluralSuffix;
/** Transforms a given word into plural form -
* Verilen kelimeyi çoğul hale getirir
*/
var makePlural = function (_base) {
var base = transformBase(_base);
return "".concat(base).concat((0, exports.getPluralSuffix)(base));
};
exports.makePlural = makePlural;
/** Returns the equality suffix for a given word -
* Verilen kelimenin eşitlik ekini dödürür; e.g 'Çocuk' -> 'ça'
*/
var getEqualitySuffix = function (_base) {
var base = transformBase(_base);
var _a = exports.util.getComponents(base), vowel = _a.vowel, letter = _a.letter;
var result = '';
if (exports.sounds.unvoicedConsonants.includes(letter)) {
result += 'ç';
}
else {
result += 'c';
}
if (exports.sounds.frontVowels.includes(vowel)) {
result += 'a';
}
else if (exports.sounds.backVowels.includes(vowel)) {
result += 'e';
}
else {
throw Error('Unknown vowel');
}
return result;
};
exports.getEqualitySuffix = getEqualitySuffix;
/** Transforms a given word into equal form -
* Verilen kelimeye eşitlik ekini ekler; e.g 'Çocuk' -> 'Çocukça'
*/
var makeEqual = function (_base) {
var base = transformBase(_base);
return "".concat(base).concat((0, exports.getEqualitySuffix)(base));
};
exports.makeEqual = makeEqual;
/** Returns the possesive suffix for a given word and pronoun -
* Verilen kelimeye ve zamire uygun iyelik ekini döndürür
*/
var getPossesiveSuffix = function (_base, pronoun) {
var base = transformBase(_base);
var _a = exports.util.getComponents(base), vowel = _a.vowel, letter = _a.letter;
var result = '';
var infix = '';
var vowelSuffix;
if (exports.sounds.vowels.includes(letter)) {
if (pronoun === Pronoun.SingularThird) {
infix = 's';
if (exports.sounds.frontVowels.includes(vowel)) {
if (exports.sounds.roundedVowels.includes(vowel)) {
result += 'u';
vowelSuffix = 'u';
}
else {
result += 'ı';
vowelSuffix = 'ı';
}
}
else {
if (exports.sounds.roundedVowels.includes(vowel)) {
result += 'ü';
vowelSuffix = 'ü';
}
else {
result += 'i';
vowelSuffix = 'i';
}
}
}
else {
vowelSuffix = '';
}
}
else {
if (pronoun !== Pronoun.PluralThird) {
if (exports.sounds.frontVowels.includes(vowel)) {
if (exports.sounds.roundedVowels.includes(vowel)) {
result += 'u';
vowelSuffix = 'u';
}
else {
result += 'ı';
vowelSuffix = 'ı';
}
}
else {
if (exports.sounds.roundedVowels.includes(vowel)) {
result += 'ü';
vowelSuffix = 'ü';
}
else {
result += 'i';
vowelSuffix = 'i';
}
}
}
else {
vowelSuffix = '';
}
}
switch (pronoun) {
case Pronoun.SingularFirst:
result += 'm';
break;
case Pronoun.SingularSecond:
result += 'n';
break;
case Pronoun.SingularThird:
break;
case Pronoun.PluralFirst:
switch (vowelSuffix) {
case 'u':
result += 'muz';
break;
case 'ı':
result += 'mız';
break;
case 'ü':
result += 'müz';
break;
case 'i':
result += 'miz';
break;
}
break;
case Pronoun.PluralSecond:
switch (vowelSuffix) {
case 'u':
result += 'nuz';
break;
case 'ı':
result += 'nız';
break;
case 'ü':
result += 'nüz';
break;
case 'i':
result += 'niz';
break;
}
break;
case Pronoun.PluralThird:
var targetVowel = vowelSuffix !== '' ? vowelSuffix : vowel;
if (exports.sounds.backVowels.includes(targetVowel)) {
result += 'leri';
}
else {
result += 'ları';
}
break;
}
return infix + result;
};
exports.getPossesiveSuffix = getPossesiveSuffix;
/** Concatenates the word with the possesive suffix for a given base and pronoun -
* Verilen kelimeye ve zamire uygun iyelik ekini ekler
*/
var makePossesive = function (_base, pronoun, isProperNoun) {
if (isProperNoun === void 0) { isProperNoun = false; }
var base = transformBase(_base);
var suffix = (0, exports.getPossesiveSuffix)(base, pronoun);
var firstLetter = suffix[0];
var root;
var word = (0, exports.alterToVowelDrop)(base);
if (exports.sounds.vowels.includes(firstLetter)) {
root = (0, exports.alterToVoicedConsonant)(word);
}
else {
root = word;
}
var punctuation = isProperNoun ? "'" : '';
return root + punctuation + suffix;
};
exports.makePossesive = makePossesive;
/** Returns the appropriate case suffix for a given base word and a case -
* Verilen kelimeye ve hâle uygun hâl ekini döndürür.
*/
var getCaseSuffix = function (_base, _case, isCompound) {
if (isCompound === void 0) { isCompound = false; }
var base = transformBase(_base);
var _a = exports.util.getComponents(base), vowel = _a.vowel, letter = _a.letter;
var result;
var infix = '';
switch (_case) {
case Case.Absolute:
result = '';
break;
case Case.Accusative:
if (exports.sounds.vowels.includes(letter)) {
infix = 'n';
}
if (exports.sounds.frontVowels.includes(vowel)) {
if (exports.sounds.roundedVowels.includes(vowel)) {
result = 'u';
}
else {
result = 'ı';
}
}
else {
if (exports.sounds.roundedVowels.includes(vowel)) {
result = 'ü';
}
else {
result = 'i';
}
}
break;
case Case.Ablative:
if (exports.sounds.vowels.includes(letter) && isCompound) {
infix = 'n';
}
if (exports.sounds.unvoicedConsonants.includes(letter)) {
result = 't';
}
else {
result = 'd';
}
if (exports.sounds.frontVowels.includes(vowel)) {
result += 'an';
}
else {
result += 'en';
}
break;
case Case.Locative:
if (exports.sounds.vowels.includes(letter) && isCompound) {
infix = 'n';
}
if (exports.sounds.unvoicedConsonants.includes(letter)) {
result = 't';
}
else {
result = 'd';
}
if (exports.sounds.frontVowels.includes(vowel)) {
result += 'a';
}
else {
result += 'e';
}
break;
case Case.Instrumental:
if (exports.sounds.vowels.includes(letter)) {
infix = 'y';
}
if (exports.sounds.frontVowels.includes(vowel)) {
result = 'la';
}
else {
result = 'le';
}
break;
case Case.Dative:
if (exports.sounds.vowels.includes(letter)) {
if (isCompound) {
infix = 'n';
}
else {
infix = 'y';
}
}
if (exports.sounds.frontVowels.includes(vowel)) {
result = 'a';
}
else {
result = 'e';
}
break;
}
return infix + result;
};
exports.getCaseSuffix = getCaseSuffix;
/** Returns the word base concatenated with the appropriate case suffix for a given base word and a case
* Verilen kelimeye ve hâle uygun hâl ekini ekler
*/
var makeCase = function (_base, _case, isProperNoun, isCompound) {
if (isProperNoun === void 0) { isProperNoun = false; }
if (isCompound === void 0) { isCompound = false; }
var base = transformBase(_base);
var suffix = (0, exports.getCaseSuffix)(base, _case, isCompound);
var punctuation = isProperNoun ? "'" : '';
var word = _case === Case.Absolute ? base : (0, exports.alterToVoicedConsonant)(base);
var firstLetter = suffix[0];
if (exports.sounds.vowels.includes(firstLetter)) {
word = (0, exports.alterToVowelDrop)(word);
}
return word + punctuation + suffix;
};
exports.makeCase = makeCase;
/** Returns the appropriate compounder suffix for a given base word -
* Verilen kelimeye uygun tamlayan ekini döndürür.
*/
var getCompounderSuffix = function (_base) {
var base = transformBase(_base);
var _a = exports.util.getComponents(base), vowel = _a.vowel, letter = _a.letter;
var infix = '';
var result = '';
if (exports.sounds.vowels.includes(letter)) {
infix += 'n';
}
if (exports.sounds.unRoundedVowels.includes(vowel)) {
if (exports.sounds.frontVowels.includes(vowel)) {
result += 'ın';
}
else {
result += 'in';
}
}
else {
if (exports.sounds.frontVowels.includes(vowel)) {
result += 'un';
}
else {
result += 'ün';
}
}
return infix + result;
};
/** Returns the appropriate compoundee suffix for a given base word -
* Verilen kelimeye uygun tamlanan ekini döndürür.
*/
var getCompoundeeSuffix = function (_base) {
var base = transformBase(_base);
var _a = exports.util.getComponents(base), vowel = _a.vowel, letter = _a.letter;
var infix = '';
var result = '';
if (exports.sounds.vowels.includes(letter)) {
infix += 's';
}
if (exports.sounds.unRoundedVowels.includes(vowel)) {
if (exports.sounds.frontVowels.includes(vowel)) {
result += 'ı';
}
else {
result += 'i';
}
}
else {
if (exports.sounds.frontVowels.includes(vowel)) {
result += 'u';
}
else {
result += 'ü';
}
}
return infix + result;
};
/** Returns the appropriate case suffix for a given base word and a compound type -
* Verilen kelimeye ve tamlama tipine uygun tamlama ekini döndürür.
*/
var getCompoundSuffix = function (_base, type) {
var base = transformBase(_base);
switch (type) {
case Compound.Compoundee:
return getCompoundeeSuffix(base);
case Compound.Compounder:
return getCompounderSuffix(base);
}
};
exports.getCompoundSuffix = getCompoundSuffix;
/** Returns the word base concatenated with the appropriate compound suffix for a given base word and a compound type
* Verilen kelimeye ve tamlama tipine uygun tamlama ekini ekler
*/
var makeCompound = function (_base, type, isProperNoun) {
if (isProperNoun === void 0) { isProperNoun = false; }
var base = transformBase(_base);
var suffix;
var firstLetter;
var word = (0, exports.alterToVoicedConsonant)(base);
var punctuation = isProperNoun ? "'" : '';
switch (type) {
case Compound.Compoundee:
suffix = getCompoundeeSuffix(base);
firstLetter = suffix[0];
if (exports.sounds.vowels.includes(firstLetter)) {
word = (0, exports.alterToVowelDrop)(word);
}
return word + punctuation + suffix;
case Compound.Compounder:
suffix = getCompounderSuffix(base);
firstLetter = suffix[0];
if (exports.sounds.vowels.includes(firstLetter)) {
word = (0, exports.alterToVowelDrop)(word);
}
return word + punctuation + suffix;
}
};
exports.makeCompound = makeCompound;
/** AffixiWord is a construct that makes it easier to handle nouns in a complex manner.
* It holds a state that can be undone and handles aspects like compoundness in itslef.
* It has a toString method that returns the resulting word and can be used with String(word).
* All its methods apart from toString return the instance itself so they are chainable.
*/
var AffixiWord = /** @class */ (function () {
function AffixiWord(base, isProperNoun) {
if (isProperNoun === void 0) { isProperNoun = false; }
this.base = base;
this.isProperNoun = isProperNoun;
this.isCompound = false;
this.history = [];
this.word = transformBase(this.base);
}
/** Concatenates the word with the appropriate compound suffix for a given compound type -
* Kelimeye verilen tamlama tipine uygun tamlama ekini ekler
*/
AffixiWord.prototype.makeCompound = function (type) {
this.commit();
this.word = (0, exports.makeCompound)(this.word, type, this.isProperNoun);
this.isCompound = true;
return this;
};
/** Concatenates the word with the appropriate case suffix for a given case -
* Kelimeye verilen hâle uygun hâl ekini ekler
*/
AffixiWord.prototype.makeCase = function (_case) {
this.commit();
this.word = (0, exports.makeCase)(this.word, _case, this.isProperNoun, this.isCompound);
return this;
};
/** Concatenates the word with the possesive suffix for a given pronoun -
* Kelimeye verilen zamire uygun iyelik ekini ekler
*/
AffixiWord.prototype.makePossesive = function (pronoun) {
this.commit();
this.word = (0, exports.makePossesive)(this.word, pronoun, this.isProperNoun);
this.isCompound = true;
return this;
};
/** Transforms the word into equal form -
* Kelimeye eşitlik ekini ekler; e.g 'Çocuk' -> 'Çocukça'
*/
AffixiWord.prototype.makeEqual = function () {
this.commit();
this.word = (0, exports.makeEqual)(this.word);
return this;
};
/** Transforms the word into plural form -
* Kelimeyi çoğul hale getirir
*/
AffixiWord.prototype.makePlural = function () {
this.commit();
this.word = (0, exports.makePlural)(this.word);
return this;
};
AffixiWord.prototype.commit = function () {
if (this.history.length >= 20) {
this.history.shift();
}
this.history.push({
word: this.word,
isCompound: this.isCompound,
isProperNoun: this.isProperNoun
});
};
/** Undoes the last operation */
AffixiWord.prototype.undo = function () {
var oldState = this.history.pop();
if (oldState) {
this.word = oldState.word;
this.isCompound = oldState.isCompound;
this.isProperNoun = oldState.isProperNoun;
}
return this;
};
AffixiWord.prototype.toString = function () {
return this.word;
};
return AffixiWord;
}());
exports.AffixiWord = AffixiWord;