UNPKG

yoastseo

Version:

Yoast client-side content analysis

158 lines (147 loc) 6.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = stem; /** * Copyright (c) 2017 Błażej Kubiński * * 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. */ /** * Loops through an array of word endings and returns ending that was matched at the end of the word. * * @param {string} word The word to check. * @param {string[]} endings The word endings to check. * @returns {string} The matched ending. */ const endsInArr = function (word, endings) { const match = endings.find(ending => word.endsWith(ending)); return match ? match : ""; }; /** * Checks if a word is longer than the word length threshold specified for a given suffix group. If the word length does not * meet the threshold, it is not stemmed. * * If it does meet the threshold, checks whether the word ends with one of the endings from the inputted array. If it does, * it removes the suffix from the end of the word. * * The length of the actual suffix is not always equal to the length of the checked ending, so suffix length is a separate * parameter. For example, the word 'rowerek' ends with -erek, one of the endings from the diminutive group. However, for * that ending, the suffix length is defined as 2 so only -ek is stemmed. * * @param {string} word The word to stem. * @param {number} wordLength The length of the word. * @param {string[]} wordEndings The suffix group. * @param {number} suffixLength The length of the suffix. * * @returns {string} The stemmed word. */ const findSuffixInGroupAndStem = function (word, wordLength, wordEndings, suffixLength) { if (word.length > wordLength) { const longestMatchedWordEnding = endsInArr(word, wordEndings); if (longestMatchedWordEnding !== "") { return word.slice(0, -suffixLength); } } }; /** * Goes through all the suffix groups in a given class (i.e., diminutive, noun, verb, adjective/adverb or general) and * stems the word if a suffix is found and should be stemmed. * * @param {string} word The word to stem. * @param {Object} suffixClass The class of suffixes to check. * @returns {string} The stemmed word. */ const findSuffixInClassAndStem = function (word, suffixClass) { const suffixClassArray = Object.entries(suffixClass); for (const suffixGroup of suffixClassArray) { const wordShouldBeLongerThan = suffixGroup[1].wordShouldBeLongerThan; const wordEndings = suffixGroup[1].wordEndings; const suffixLength = suffixGroup[1].suffixLength; const stemmedWord = findSuffixInGroupAndStem(word, wordShouldBeLongerThan, wordEndings, suffixLength); if (stemmedWord) { return stemmedWord; } } }; /** * Stems adjective and adverb suffixes. After stemming the suffixes, looks for the superlative prefix 'naj' and stems it * as well if found. For example, in 'najsilniejsze', first the 'ejsze' is stemmed and then the 'naj'. * * @param {string} word The word to stem. * @param {Object} ruleBasedStemmerData The data for the rule-based stemmer. * * @returns {string} The word with removed adjective/adverb suffixes */ const stemAdjectivesAndAdverbs = function (word, ruleBasedStemmerData) { const stemmedWord = findSuffixInClassAndStem(word, ruleBasedStemmerData.adjectiveAndAdverbSuffixes); if (stemmedWord) { // Remove superlative prefix if found if (word.startsWith(ruleBasedStemmerData.superlativePrefix)) { return stemmedWord.slice(3); } return stemmedWord; } }; /** * Stems Polish words. * * @param {string} word The word to stem. * @param {Object} morphologyData The Polish morphology data file. * * @returns {string} The stemmed word. */ function stem(word, morphologyData) { const ruleBasedStemmerData = morphologyData.externalStemmer; const dictionaryStemmer = morphologyData.dictionary.stems; // Check if the word exists in the dictionary stemmer. If yes, replace the word with the base form of the word specified in the dictionary. let stemmedWord = dictionaryStemmer[word]; if (stemmedWord) { word = stemmedWord; } word.toLowerCase(); // If the word is three characters long or shorter, the stem should be the same as the word. if (word.length < 4) { return word; } /* * Go through diminutive, noun, verb, and adjective stemming steps. If a suffix (and optional prefix in case of adjectives/adverbs) * is found, delete it and stop searching further. */ stemmedWord = findSuffixInClassAndStem(word, ruleBasedStemmerData.diminutiveSuffixes); if (!stemmedWord) { stemmedWord = findSuffixInClassAndStem(word, ruleBasedStemmerData.nounSuffixes); } if (!stemmedWord) { stemmedWord = findSuffixInClassAndStem(word, ruleBasedStemmerData.verbSuffixes); } if (!stemmedWord) { stemmedWord = stemAdjectivesAndAdverbs(word, ruleBasedStemmerData); } // If the word was stemmed in any of the previous steps, replace the word with the stem. if (stemmedWord) { word = stemmedWord; } // Find and stem general suffixes stemmedWord = findSuffixInClassAndStem(word, ruleBasedStemmerData.generalSuffixes); if (stemmedWord) { return stemmedWord; } return word; } //# sourceMappingURL=stem.js.map