yoastseo
Version:
Yoast client-side content analysis
635 lines (602 loc) • 29.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = stem;
/**
* Copyright (c) 2015 Mouaffak A. Sarhan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Tries to match a word with a regex. If matched, modifies the string according to the indicated pattern.
*
* @param {string} word The word to check.
* @param {string[]} regexAndReplacement The regex to match the word with and what the word should be replaced with if it is matched.
*
* @returns {string} The modified word or the original word if it was not matched.
*/
const matchWithRegexAndReplace = function (word, regexAndReplacement) {
return word.replace(new RegExp(regexAndReplacement[0]), regexAndReplacement[1]);
};
/**
* Check if the word is on the list of three-letter roots which had the last weak letter removed (so are now two letters long).
* If the word is on the list, add back the removed last letter and return the three-letter root.
* Examples: طر -> طري (word with last weak letter ي (yeh) removed) , حص -> حصا (word with last weak letter ا (alef) removed)
*
* @param {string} word The two-letter word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string|null} The word with the last weak letter added back or null if the word was not found on a list.
*/
const checkWordsWithRemovedLastLetter = function (word, morphologyData) {
const externalStemmer = morphologyData.externalStemmer;
const characters = externalStemmer.characters;
if (externalStemmer.wordsWithLastAlefRemoved.includes(word)) {
return word + characters.alef;
}
if (externalStemmer.wordsWithLastHamzaRemoved.includes(word)) {
return word + characters.alef_hamza_above;
}
if (externalStemmer.wordsWithLastMaksoraRemoved.includes(word)) {
return word + characters.yeh_maksorah;
}
if (externalStemmer.wordsWithLastYehRemoved.includes(word)) {
return word + characters.yeh;
}
};
/**
* Check if the word is on the list of three-letter roots which had the first weak letter removed (so are now two letters long).
* If the word is on the list, add back the removed first letter and return the three-letter root.
* Examples: مض -> ومض (word with first weak letter و (waw) removed) , سن -> يسن (word with first weak letter ي (yeh) removed)
*
* @param {string} word The two-letter word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string|null} The word with the first weak letter added back or null if the word was not found on any list.
*/
const checkWordsWithRemovedFirstLetter = function (word, morphologyData) {
const externalStemmer = morphologyData.externalStemmer;
const characters = externalStemmer.characters;
if (externalStemmer.wordsWithFirstWawRemoved.includes(word)) {
return characters.waw + word;
}
if (externalStemmer.wordsWithFirstYehRemoved.includes(word)) {
return characters.yeh + word;
}
};
/**
* Check if the word is on the list of three-letter roots which had the middle weak letter removed (so are now two letters long).
* If the word is on the list, add back the removed middle letter and return the three-letter root.
* Examples: غز -> غوز (word with middle weak letter و (waw) removed), لن -> لين (word with middle weak letter ي (yeh) removed)
*
* @param {string} word The two-letter word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string|null} The word with the middle weak letter added back or null if the word was not found on a list.
*/
const checkWordsWithRemovedMiddleLetter = function (word, morphologyData) {
const externalStemmer = morphologyData.externalStemmer;
const characters = externalStemmer.characters;
if (externalStemmer.wordsWithMiddleWawRemoved.includes(word)) {
return word[0] + characters.waw + word[1];
}
if (externalStemmer.wordsWithMiddleYehRemoved.includes(word)) {
return word[0] + characters.yeh + word[1];
}
};
/**
* Find the root of two-letter words. Two-letter words usually come from three-letter roots for which a letter was deleted
* as it is a duplicated last letter or a weak letter.
*
* @param {string} word The two-letter word to process.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string} The three-letter root or the input word if no root was found.
*/
const processTwoLetterWords = function (word, morphologyData) {
// Check whether the word is on the list of words with removed duplicate last letter. If it is, add back the removed letter to get the root.
if (morphologyData.externalStemmer.wordsWithRemovedDuplicateLetter.includes(word)) {
return word + word.substring(1);
}
// Check whether the word is on one of the lists of words with removed weak letter or hamza.
const wordAfterLastLetterCheck = checkWordsWithRemovedLastLetter(word, morphologyData);
if (wordAfterLastLetterCheck) {
return wordAfterLastLetterCheck;
}
const wordAfterFirstLetterCheck = checkWordsWithRemovedFirstLetter(word, morphologyData);
if (wordAfterFirstLetterCheck) {
return wordAfterFirstLetterCheck;
}
const wordAfterMiddleLetterCheck = checkWordsWithRemovedMiddleLetter(word, morphologyData);
if (wordAfterMiddleLetterCheck) {
return wordAfterMiddleLetterCheck;
}
return word;
};
/**
* Remove the middle/last weak letter or hamza in a three letter word. Find its root by checking the appropriate exception lists
* (words with middle letter removed or words with last letter removed) and attaching the removed letter back.
* Example: بدء -> بد -> بدأ (three letter word with (ء) hamza ending,
* which is found on the list of words with last letter removed after removing the suffix)
*
* @param {string} word The three-letter word to check.
* @param {Object} morphologyData The Arabic morphology data.
* @param {string[]} replacementPattern The regex to find and remove middle or last weak letter/hamza in three letter words
* @param {function} functionToRunToGetRoot The function that checks lists of words with either middle or last letter removed
* and attaches it back.
*
* @returns {string|null} The root or null if no root was found.
*/
const processThreeLetterWordsWithWeakLetterOrHamza = function (word, morphologyData, replacementPattern, functionToRunToGetRoot) {
// Find and remove middle or last weak letter or hamza
const wordAfterRemovingWeakLetterOrHamza = word.replace(new RegExp(replacementPattern[0]), replacementPattern[1]);
if (wordAfterRemovingWeakLetterOrHamza !== word) {
/*
* If the weak letter or hamza was removed, get the root by checking lists of words with middle/last weak letter
* or hamza removed and attaching it back.
*/
return functionToRunToGetRoot(wordAfterRemovingWeakLetterOrHamza, morphologyData);
}
};
/**
* Get the root of three letter words.
* Examples: ؤكد -> أكد (three letter word with ؤ (waw_hamza) beginning, قدّ -> قدد (three letter word which has a shadda on the second letter)
*
* @param {string} word The three-letter word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string|null} The root or the original input word (which may already be the root).
*/
const processThreeLetterWords = function (word, morphologyData) {
const characters = morphologyData.externalStemmer.characters;
// If the word exists on the list of three letter roots, return the word.
if (morphologyData.externalStemmer.threeLetterRoots.includes(word)) {
return word;
}
// If the first letter is ا/ ؤ/ ئ (yeh_hamza/waw_hamza/alef), change it to أ (alef_hamza_above).
if (word[0] === characters.alef || word[0] === characters.waw_hamza || word[0] === characters.yeh_hamza) {
word = characters.alef_hamza_above + word.slice(1);
}
// If the last letter is a weak letter or a hamza, check if the word is a root that may get the last weak letter/hamza removed.
const wordAfterLastWeakLetterOrHamzaCheck = processThreeLetterWordsWithWeakLetterOrHamza(word, morphologyData, morphologyData.externalStemmer.regexRemoveLastWeakLetterOrHamza, checkWordsWithRemovedLastLetter);
if (wordAfterLastWeakLetterOrHamzaCheck) {
return wordAfterLastWeakLetterOrHamzaCheck;
}
// If the middle letter is a waw, yeh, alef or a yeh_hamza, check if the word is a root that may get the middle weak letter/hamza removed..
const wordAfterMiddleWeakLetterOrHamzaCheck = processThreeLetterWordsWithWeakLetterOrHamza(word, morphologyData, morphologyData.externalStemmer.regexRemoveMiddleWeakLetterOrHamza, checkWordsWithRemovedMiddleLetter);
if (wordAfterMiddleWeakLetterOrHamzaCheck) {
return wordAfterMiddleWeakLetterOrHamzaCheck;
}
const regexReplaceMiddleLetterWithAlef = morphologyData.externalStemmer.regexReplaceMiddleLetterWithAlef;
const regexReplaceMiddleLetterWithAlefWithHamza = morphologyData.externalStemmer.regexReplaceMiddleLetterWithAlefWithHamza;
// If the word has ئ/ؤ (yeh_hamza/waw_hamza) as the second letter and ends in ر/ز/ن (noon/zai/reh), change ئ/ؤ (yeh_hamza/waw_hamza) to ا (alef).
const wordAfterReplacingMiddleLetterWithAlef = word.replace(new RegExp(regexReplaceMiddleLetterWithAlef[0]), regexReplaceMiddleLetterWithAlef[1]);
if (wordAfterReplacingMiddleLetterWithAlef === word) {
// If the second letter is a ئ/ؤ (yeh_hamza/waw_hamza) and it doesn't end in noon/zai/reh, change ئ/ؤ d to أ (alef_hamza_above).
word = word.replace(new RegExp(regexReplaceMiddleLetterWithAlefWithHamza[0]), regexReplaceMiddleLetterWithAlefWithHamza[1]);
} else {
word = wordAfterReplacingMiddleLetterWithAlef;
}
// If the last letter is a shadda, remove it and duplicate the last letter.
const regexRemoveShaddaAndDuplicateLastLetter = morphologyData.externalStemmer.regexRemoveShaddaAndDuplicateLastLetter;
word = word.replace(new RegExp(regexRemoveShaddaAndDuplicateLastLetter[0]), regexRemoveShaddaAndDuplicateLastLetter[1]);
return word;
};
/**
* Check whether the word matches the pattern (it is a 6 letter-word, the fourth and sixth letter are the same, and the pattern
* and the word share two same letters at the same index). If it does, remove the first character and the two last characters and
* get the root.
* Example: احولال -> حول (the stem is the 2nd to 4th character)
*
* @param {string} word The word to check.
* @param {number} numberSameLetters The number of letters the word and the pattern share at the same index.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string} The root or the original word if word was not matched by the pattern.
*/
const checkFirstPatternAndGetRoot = function (word, numberSameLetters, morphologyData) {
if (word.length === 6 && word[3] === word[5] && numberSameLetters === 2) {
return processThreeLetterWords(word.substring(1, 4), morphologyData);
}
return word;
};
/**
* Checks whether the word matches the pattern (the word shares three characters with the pattern) and get the root if it does.
* Example: استكتب -> كتب (A word that matches pattern (استفعل))
*
* @param {string} word The word to check.
* @param {string} pattern The pattern to check.
* @param {number} numberSameLetters The number of letters the word and the pattern share at the same index.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string} The root or the original word if no root was found.
*/
const checkSecondPatternAndGetRoot = function (word, pattern, numberSameLetters, morphologyData) {
const characters = morphologyData.externalStemmer.characters;
// If the word length minus three is equal to or less than the number of same letters found in the checkPatterns function.
if (word.length - 3 <= numberSameLetters) {
let root = "";
for (let i = 0; i < word.length; i++) {
if (pattern[i] === characters.feh || pattern[i] === characters.aen || pattern[i] === characters.lam) {
root = root.concat(word[i]);
}
}
return processThreeLetterWords(root, morphologyData);
}
return word;
};
/**
* Count the number of letters the word and the pattern to match with share at the same index.
*
* @param {string} word The word to check.
* @param {string} pattern The pattern to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {number} The number of shared letters between the word and the pattern at the same index.
*/
const countSharedLettersBetweenWordAndPattern = function (word, pattern, morphologyData) {
const characters = morphologyData.externalStemmer.characters;
let numberSameLetters = 0;
for (let i = 0; i < word.length; i++) {
if (pattern[i] === word[i] && pattern[i] !== characters.feh && pattern[i] !== characters.aen && pattern[i] !== characters.lam) {
numberSameLetters++;
}
}
return numberSameLetters;
};
/**
* Check if a word matches a specific pattern of letters, and if it does, modify the word to get the root.
*
* @param {string} word The word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {Object|null} An object with either the root or the modified word and the information whether the root was found,
* or null if the word was not modified and the root was not found.
*/
const checkPatterns = function (word, morphologyData) {
// If the first letter is an alef_madda, alef_hamza_above, or alef_hamza_below (أ/إ/آ), change it to an alef (ا)
const wordAfterModification = matchWithRegexAndReplace(word, morphologyData.externalStemmer.regexReplaceFirstHamzaWithAlef);
// Try and find a pattern that matches the word
for (const pattern of morphologyData.externalStemmer.patterns) {
if (pattern.length === wordAfterModification.length) {
// Count the number of letters the word and the pattern share at the same index.
const numberSameLetters = countSharedLettersBetweenWordAndPattern(wordAfterModification, pattern, morphologyData);
const wordAfterCheckingFirstPattern = checkFirstPatternAndGetRoot(wordAfterModification, numberSameLetters, morphologyData);
if (wordAfterCheckingFirstPattern !== wordAfterModification) {
return {
word: wordAfterCheckingFirstPattern,
rootFound: true
};
}
const wordAfterCheckingSecondPattern = checkSecondPatternAndGetRoot(wordAfterModification, pattern, numberSameLetters, morphologyData);
if (wordAfterCheckingSecondPattern !== wordAfterModification) {
return {
word: wordAfterCheckingSecondPattern,
rootFound: true
};
}
}
}
// If a pattern was not matched but the word was modified, return the modified word.
if (wordAfterModification !== word) {
return {
word: wordAfterModification,
rootFound: false
};
}
};
/**
* Tries to find the root of two-, three- and four-letter words by checking lists and/or applying modifications to the word.
*
* Example: the word أبطر is on the list of four-letter roots.
*
* @param {string} word The word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string|null} The root or null if the root was not found.
*/
const checkIfWordIsRoot = function (word, morphologyData) {
// Check if the word consists of two letters and find its root.
if (word.length === 2) {
return processTwoLetterWords(word, morphologyData);
}
// Check if the word consists of three letters.
if (word.length === 3) {
return processThreeLetterWords(word, morphologyData);
}
// If the word consists of four letters, check if it is on the list of four-letter roots.
if (word.length === 4) {
if (morphologyData.externalStemmer.fourLetterRoots.includes(word)) {
return word;
}
}
};
/**
* Checks whether the word ends in a suffix, and removes it if it does.
*
* @param {string} word The word to check.
* @param {string[]} suffixes The suffixes to check.
*
* @returns {string} The word with the suffix removed or the input word if no suffix was found.
*/
const removeSuffix = function (word, suffixes) {
for (const suffix of suffixes) {
if (word.endsWith(suffix)) {
return word.slice(0, -suffix.length);
}
}
return word;
};
/**
* Checks whether the word starts with a prefix, and removes it if it does.
*
* @param {string} word The word to check.
* @param {string[]} prefixes The prefixes to check.
*
* @returns {string} The word with the prefix removed or the input word if no prefix was found.
*/
const removePrefix = function (word, prefixes) {
for (const prefix of prefixes) {
if (word.startsWith(prefix)) {
return word.substring(prefix.length, word.length);
}
}
return word;
};
/**
* Searches for a suffix, removes it if found, and tries to find the root of the stemmed word. If the root is not found, the
* function returns null, with one exception: it is possible that in the checkPatterns function that is ran inside of this one,
* the word is modified but no root is found. In this case, the function returns the modified word.
*
* Example: جمعكم -> جمع (word with suffix كم which is found on the list of three-letter roots after removing the suffix).
*
* @param {string} word The word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {Object|null} An object with the root/modified word and information about whether the root was found, or null if
* the word is not modified and no root is found.
*/
const processWordWithSuffix = function (word, morphologyData) {
// Find and remove suffix.
const wordAfterRemovingSuffix = removeSuffix(word, morphologyData.externalStemmer.suffixes);
if (wordAfterRemovingSuffix !== word) {
// If suffix was removed, check if the stemmed word is a root.
const root = checkIfWordIsRoot(wordAfterRemovingSuffix, morphologyData);
if (root) {
return {
word: root,
rootFound: true
};
}
// If no root was found, try to get the root by matching with a pattern.
const outputAfterCheckingPatterns = checkPatterns(wordAfterRemovingSuffix, morphologyData);
if (outputAfterCheckingPatterns) {
return outputAfterCheckingPatterns;
}
}
};
/**
* Searches for a prefix (other than the definite article), removes it if found, and tries to find the root of the stemmed
* word. If the root is not found, the function returns null, with one exception: it is possible that in the checkPatterns
* function that is ran inside of this one, the word is modified but no root is found. In this case, the function returns
* the modified word.
*
* Example: للزهور -> زهر (word with prefix لل that gets its root by matching with a pattern after removing the prefix).
*
* @param {string} word The word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {Object|null} An object with the root/modified word and information about whether the root was found, or null if
* the word is not modified and no root is found.
*/
const processWordWithPrefix = function (word, morphologyData) {
// Find and remove prefix.
let wordAfterRemovingPrefix = removePrefix(word, morphologyData.externalStemmer.prefixes);
if (wordAfterRemovingPrefix !== word) {
// If prefix was removed, check if the stemmed word is a root.
const root = checkIfWordIsRoot(wordAfterRemovingPrefix, morphologyData);
if (root) {
return {
word: root,
rootFound: true
};
}
// If no root was found, try to get the root by matching with a pattern.
const outputAfterCheckingPatterns = checkPatterns(wordAfterRemovingPrefix, morphologyData);
if (outputAfterCheckingPatterns) {
if (outputAfterCheckingPatterns.rootFound === true) {
return outputAfterCheckingPatterns;
}
wordAfterRemovingPrefix = outputAfterCheckingPatterns.word;
}
// If the root was still not found, try to find and remove suffixes and find the root again.
const outputAfterCheckingForSuffixes = processWordWithSuffix(wordAfterRemovingPrefix, morphologyData);
if (outputAfterCheckingForSuffixes) {
return outputAfterCheckingForSuffixes;
}
}
};
/**
* Checks if the word is a root. If root is not found, checks whether the root can be derived using a pattern. If the root is
* still not found, removes affixes and tries to find the root again. If the root is not found, the function returns null,
* with one exception: it is possible that in the checkPatterns function that is ran inside of this one, the word is modified
* but no root is found. In this case, the function returns the modified word.
*
* @param {string} word The word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {Object|null} An object with the root/modified word and information about whether the root was found, or null if
* the word is not modified and no root is found.
*/
const findRoot = function (word, morphologyData) {
// Check if the word is a root.
const root = checkIfWordIsRoot(word, morphologyData);
if (root) {
return {
word: root,
rootFound: true
};
}
// Check if the root can be derived by matching a pattern. إعدجص
const outputAfterCheckingPatterns = checkPatterns(word, morphologyData);
let stemmedWord = word;
if (outputAfterCheckingPatterns) {
if (outputAfterCheckingPatterns.rootFound === true) {
return outputAfterCheckingPatterns;
}
// Word: اعدجص
stemmedWord = outputAfterCheckingPatterns.word;
}
// Remove affixes and check if the stemmed word is a root
const outputAfterProcessingSuffix = processWordWithSuffix(stemmedWord, morphologyData);
if (outputAfterProcessingSuffix) {
return outputAfterProcessingSuffix;
}
const outputAfterRemovingPrefix = processWordWithPrefix(stemmedWord, morphologyData);
if (outputAfterRemovingPrefix) {
return outputAfterRemovingPrefix;
}
if (stemmedWord !== word) {
return {
word: stemmedWord,
rootFound: false
};
}
};
/**
* Search for and remove a definite article and try to get the root of the word. If the root was not found, but the word
* was modified inside the checkPatterns function, returns the modified word. If the definite article was removed and the
* stemmed word is longer than three letters, but the root was not found, returns the stemmed word. Otherwise, if the root
* was not found, returns null.
*
* Example: الجدولين -> جدول (word with definite article ال and suffix ين ).
*
* @param {string} word The word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {Object|null} An object with the root/modified word and information about whether the root was found, or null if
* the word is not modified and no root is found.
*/
const processWordWithDefiniteArticle = function (word, morphologyData) {
// Search for and remove the definite article.
const wordAfterRemovingDefiniteArticle = removePrefix(word, morphologyData.externalStemmer.definiteArticles);
// If a definite article was removed, try to find the root.
if (wordAfterRemovingDefiniteArticle !== word) {
/**
* If definite article was removed, try to find root by checking whether the word is a root, matching with a pattern, and/or
* searching for and removing prefixes.
*/
const outputAfterTryingToFindRoot = findRoot(wordAfterRemovingDefiniteArticle, morphologyData);
if (outputAfterTryingToFindRoot) {
return outputAfterTryingToFindRoot;
}
// Return it even if no root was found.
return {
word: wordAfterRemovingDefiniteArticle,
rootFound: false
};
}
};
/**
* Searches for prefix waw (و) and removes it if found, then tries to find the root. If the root is still not found, removes
* affixes and tries to find the root again. If the root is not found, the function returns null, with one exception: it
* is possible that in the checkPatterns function that is ran inside of this one, the word is modified but no root is found.
* In this case, the function returns the modified word.
*
* Example: وتمثّل -> مثل (word with prefix waw which matches a pattern after removing the prefix).
*
* @param {string} word The word to check.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {Object|null} An object with the root/modified word and information about whether the root was found, or null if
* the word is not modified and no root is found.
*/
const processWordWithPrefixWaw = function (word, morphologyData) {
let wordAfterRemovingWaw = "";
if (word.length > 3 && word.startsWith(morphologyData.externalStemmer.characters.waw)) {
wordAfterRemovingWaw = word.substring(1);
/*
* If the prefix waw was removed, try to find the root by checking whether the word is a root, matching with a pattern,
* and/or searching for and removing prefixes.
*/
const outputAfterTryingToFindRoot = findRoot(wordAfterRemovingWaw, morphologyData);
if (outputAfterTryingToFindRoot) {
return outputAfterTryingToFindRoot;
}
}
};
/**
* Stems Arabic words.
*
* @param {string} word The word to stem.
* @param {Object} morphologyData The Arabic morphology data.
*
* @returns {string} The stemmed word.
*/
function stem(word, morphologyData) {
// Remove diacritics that serve as phonetic guides and are not usually used in regular writing.
const regexRemovingDiacritics = morphologyData.externalStemmer.regexRemovingDiacritics;
word.replace(new RegExp(regexRemovingDiacritics), "");
const root = checkIfWordIsRoot(word, morphologyData);
if (root) {
return root;
}
// If the root still hasn't been found, check if the word matches a pattern and get its root if it does.
const outputAfterCheckingPatterns = checkPatterns(word, morphologyData);
if (outputAfterCheckingPatterns) {
// Return the root if it was found in the checkPatterns function
if (outputAfterCheckingPatterns.rootFound === true) {
return outputAfterCheckingPatterns.word;
}
// If the checkPatterns function modified the word but did not find the root, replace the word with the modified word.
word = outputAfterCheckingPatterns.word;
}
// If the root still hasn't been found, remove the definite article and try to find the root.
const outputAfterProcessingDefiniteArticle = processWordWithDefiniteArticle(word, morphologyData);
if (outputAfterProcessingDefiniteArticle) {
// Return the root if it was found after removing the definite article.
if (outputAfterProcessingDefiniteArticle.rootFound === true) {
return outputAfterProcessingDefiniteArticle.word;
}
// If the definite article was removed but the root was not found, replace the word with the stemmed word.
word = outputAfterProcessingDefiniteArticle.word;
}
// If the root still hasn't been found, remove the prefix waw and try to find the root.
const outputAfterProcessingPrefixWaw = processWordWithPrefixWaw(word, morphologyData);
if (outputAfterProcessingPrefixWaw) {
if (outputAfterProcessingPrefixWaw.rootFound === true) {
return outputAfterProcessingPrefixWaw.word;
}
// If the checkPatterns function modified the word but did not find the root, replace the word with the modified word.
word = outputAfterProcessingPrefixWaw.word;
}
// If the root still hasn't been found, remove a suffix and try to find the root.
const outputAfterProcessingSuffix = processWordWithSuffix(word, morphologyData);
if (outputAfterProcessingSuffix) {
return outputAfterProcessingSuffix.word;
}
// If the root still hasn't been found, remove a prefix and try to find the root.
const wordAfterProcessingPrefix = processWordWithPrefix(word, morphologyData);
if (wordAfterProcessingPrefix) {
return wordAfterProcessingPrefix.word;
}
return word;
}
//# sourceMappingURL=stem.js.map