yoastseo
Version:
Yoast client-side content analysis
183 lines (167 loc) • 9.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _quotes = require("../helpers/sanitize/quotes");
var _buildTopicStems = require("../helpers/morphology/buildTopicStems");
var _lodash = require("lodash");
var _getAllWordsFromPaper = _interopRequireDefault(require("../helpers/morphology/getAllWordsFromPaper"));
var _parseSynonyms = _interopRequireDefault(require("../helpers/sanitize/parseSynonyms"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* A stem with accompanying forms.
*
* @param {string} stem The word stem.
* @param {string[]} forms The word forms for the stem.
*
* @constructor
*/
function StemWithForms(stem, forms) {
this.stem = stem;
this.forms = forms;
}
/**
* A result for all topic forms.
*
* @param {Array[]} keyphraseForms All keyphrase forms.
* @param {Array[]} synonymsForms All synonym forms.
* @constructor
*/
function Result(keyphraseForms = [], synonymsForms = []) {
this.keyphraseForms = keyphraseForms;
this.synonymsForms = synonymsForms;
}
/**
* Takes a stem-original pair and returns the accompanying forms for the stem that were found in the paper. Additionally
* adds a sanitized version of the original word and (for specific languages) creates basic word forms.
*
* @param {StemOriginalPair} stemOriginalPair The stem-original pair for which to get forms.
* @param {StemWithForms[]} paperWordsGroupedByStems All word forms in the paper grouped by stem.
* @param {Function|null} createBasicWordForms A function to create basic word forms (if available).
*
* @returns {string[]} All forms found in the paper for the given stem, plus a sanitized version of the original word.
*/
function replaceStemWithForms(stemOriginalPair, paperWordsGroupedByStems, createBasicWordForms) {
const matchingStemFormPair = paperWordsGroupedByStems.find(element => element.stem === stemOriginalPair.stem);
const originalSanitized = (0, _quotes.normalizeSingle)((0, _lodash.escapeRegExp)(stemOriginalPair.original));
const forms = matchingStemFormPair ? [originalSanitized, ...matchingStemFormPair.forms] : [originalSanitized];
// Add extra forms for languages for which we have basic word form support.
if (createBasicWordForms) {
forms.push(...createBasicWordForms(stemOriginalPair.original));
}
/*
* Return original and found or created forms.
* Only return original if no matching forms were found in the text and no forms could be created.
*/
return [...new Set(forms)];
}
/**
* Extracts the stems from all keyphrase and synonym stems.
*
* @param {TopicPhrase} keyphrase A topic phrase.
* @param {TopicPhrase[]} synonyms An array of topic phrases.
*
* @returns {string[]} All word stems of they keyphrase and synonyms.
*/
function extractStems(keyphrase, synonyms) {
const keyphraseStemsOnly = keyphrase.stemOriginalPairs.length === 0 ? [] : keyphrase.getStems();
const synonymsStemsOnly = synonyms.length === 0 ? [] : synonyms.map(topicPhrase => topicPhrase.getStems());
return [...keyphraseStemsOnly, ...(0, _lodash.flattenDeep)(synonymsStemsOnly)];
}
/**
* Constructs the result with forms for a topic phrase (i.e., a keyphrase or a synonym).
*
* @param {TopicPhrase} topicPhrase The topic phrase for which to construct the result.
* @param {StemWithForms[]} paperWordsGroupedByStems All word forms in the paper grouped by stem.
* @param {Function|null} createBasicWordForms A function to create basic word forms (if available).
*
* @returns {Array.<string[]>} The word forms for a given topic phrase, grouped by original topic phrase word.
*/
function constructTopicPhraseResult(topicPhrase, paperWordsGroupedByStems, createBasicWordForms) {
// Empty result for an empty topic phrase.
if (topicPhrase.stemOriginalPairs.length === 0) {
return [];
}
if (topicPhrase.exactMatch) {
return [[topicPhrase.stemOriginalPairs[0].stem]];
}
return topicPhrase.stemOriginalPairs.map(function (stemOriginalPair) {
return replaceStemWithForms(stemOriginalPair, paperWordsGroupedByStems, createBasicWordForms);
});
}
/**
* Gets all matching word forms for the keyphrase and synonyms. Stems are either collected from
* the paper or, for specific languages, directly created.
*
* @param {string} keyphrase The keyphrase.
* @param {string[]} synonyms The synonyms.
* @param {string[]} allWordsFromPaper All words found in the paper.
* @param {string[]} functionWords The function words for a given language (if available).
* @param {Function|null} stemmer A stemmer (if available).
* @param {Function|null} createBasicWordForms A function to create basic word forms (if available).
* @param {boolean} areHyphensWordBoundaries Whether hyphens should be treated as word boundaries.
* @returns {Object} Object with an array of keyphrase forms and an array of arrays of synonyms forms, based on the forms
* found in the text or created forms.
*/
function getWordForms(keyphrase, synonyms, allWordsFromPaper, functionWords, stemmer, createBasicWordForms, areHyphensWordBoundaries) {
const topicPhrases = (0, _buildTopicStems.collectStems)(keyphrase, synonyms, stemmer, functionWords, areHyphensWordBoundaries);
const keyphraseStemmed = topicPhrases.keyphraseStems;
const synonymsStemmed = topicPhrases.synonymsStems;
// Return an empty result when no keyphrase and synonyms have been set.
if (keyphraseStemmed.stemOriginalPairs.length === 0 && synonymsStemmed.length === 0) {
return new Result();
}
// Return exact match if all topic phrases contain exact match. Forms don't need to be built in that case.
const allTopicPhrases = [keyphraseStemmed, ...synonymsStemmed];
if (allTopicPhrases.every(topicPhrase => topicPhrase.exactMatch === true)) {
return new Result([[keyphraseStemmed.stemOriginalPairs[0].stem]], synonymsStemmed.map(synonym => [[synonym.stemOriginalPairs[0].stem]]));
}
// Get all stems from the keyphrase and synonyms.
const topicStemsFlat = [...new Set(extractStems(keyphraseStemmed, synonymsStemmed))];
/*
* Get all words from the paper text, title, meta description and slug.
* Filter duplicates and function words.
*/
const paperWords = [...new Set(allWordsFromPaper.filter(word => !functionWords.includes(word)))];
// Add stems to words from the paper, filter out all forms that aren't in the keyphrase or synonyms and order alphabetically.
const paperWordsWithStems = paperWords.map(word => new _buildTopicStems.StemOriginalPair(stemmer(word), word)).filter(stemOriginalPair => topicStemsFlat.includes(stemOriginalPair.stem)).sort((a, b) => a.stem.localeCompare(b.stem));
// Group word-stem pairs from the paper by stems.
const paperWordsGroupedByStems = paperWordsWithStems.reduce(function (accumulator, stemOriginalPair) {
const lastItem = accumulator[accumulator.length - 1];
if (accumulator.length === 0 || lastItem.stem !== stemOriginalPair.stem) {
accumulator.push(new StemWithForms(stemOriginalPair.stem, [stemOriginalPair.original]));
} else {
lastItem.forms.push(stemOriginalPair.original);
}
return accumulator;
}, []);
return new Result(constructTopicPhraseResult(keyphraseStemmed, paperWordsGroupedByStems, createBasicWordForms), synonymsStemmed.map(synonym => constructTopicPhraseResult(synonym, paperWordsGroupedByStems, createBasicWordForms)));
}
/**
* Gets all matching word forms for the keyphrase and synonyms.
*
* @param {Paper} paper The paper.
* @param {Researcher} researcher The researcher.
*
* @returns {Object} Object with an array of keyphrase forms and an array of arrays of synonyms forms, based on the forms
* found in the text or created forms.
*/
function _default(paper, researcher) {
const functionWords = researcher.getConfig("functionWords");
const stemmer = researcher.getHelper("getStemmer")(researcher);
const createBasicWordForms = researcher.getHelper("createBasicWordForms");
const language = researcher.getConfig("language");
/*
* Whether we want to split words on hyphens depends on the language.
* In all languages apart from Indonesian, we consider hyphens as word boundaries. But in Indonesian, hyphens are used
* to form plural forms of nouns, e.g. 'buku' is the singular form for 'book' and 'buku-buku' is the plural form.
* This is why we don't split words on hyphens in Indonesian and we consider 'buku-buku' as one word rather than two.
*/
const areHyphensWordBoundaries = researcher.getConfig("areHyphensWordBoundaries");
const allWordsFromPaper = (0, _getAllWordsFromPaper.default)(paper, areHyphensWordBoundaries).map(word => word.toLocaleLowerCase(language));
const keyphrase = paper.getKeyword().toLocaleLowerCase(language).trim();
const synonyms = (0, _parseSynonyms.default)(paper.getSynonyms().toLocaleLowerCase(language).trim());
return getWordForms(keyphrase, synonyms, allWordsFromPaper, functionWords, stemmer, createBasicWordForms, areHyphensWordBoundaries);
}
//# sourceMappingURL=getWordForms.js.map