yoastseo-dep
Version:
Yoast clientside page analysis
183 lines (153 loc) • 6.03 kB
JavaScript
/** @module stringProcessing/countSyllables */
import getWords from "../word/getWords.js";
import { filter, find, flatMap, forEach, isUndefined, map, memoize, sum } from "lodash-es";
import SyllableCountIterator from "./syllableCountIterator.js";
import DeviationFragment from "./DeviationFragment";
/**
* Counts vowel groups inside a word.
*
* @param {string} word A text with words to count syllables.
* @param {Object} syllables The syllables data for the specific language.
*
* @returns {number} the syllable count.
*/
const countVowelGroups = function( word, syllables ) {
let numberOfSyllables = 0;
const vowelRegex = new RegExp( "[^" + syllables.vowels + "]", "ig" );
const foundVowels = word.split( vowelRegex );
const filteredWords = filter( foundVowels, function( vowel ) {
return vowel !== "";
} );
numberOfSyllables += filteredWords.length;
return numberOfSyllables;
};
/**
* Counts the syllables using vowel exclusions. These are used for groups of vowels that are more or less
* than 1 syllable.
*
* @param {String} word The word to count syllables of.
* @param {Object} syllables The syllables data for the specific language.
*
* @returns {number} The number of syllables found in the given word.
*/
const countVowelDeviations = function( word, syllables ) {
const syllableCountIterator = new SyllableCountIterator( syllables );
return syllableCountIterator.countSyllables( word );
};
/**
* Returns the number of syllables for the word if it is in the list of full word deviations.
*
* @param {String} word The word to retrieve the syllables for.
* @param {Object} syllables The syllables data for the specific language.
*
* @returns {number} The number of syllables found.
*/
const countFullWordDeviations = function( word, syllables ) {
const fullWordDeviations = syllables.deviations.words.full;
const deviation = find( fullWordDeviations, function( fullWordDeviation ) {
return fullWordDeviation.word === word;
} );
if ( ! isUndefined( deviation ) ) {
return deviation.syllables;
}
return 0;
};
/**
* Creates an array of deviation fragments for a certain locale.
*
* @param {Object} syllableConfig Syllable config for a certain locale.
* @returns {DeviationFragment[]} A list of deviation fragments
*/
function createDeviationFragments( syllableConfig ) {
let deviationFragments = [];
const deviations = syllableConfig.deviations;
deviationFragments = flatMap( deviations.words.fragments, function( fragments, fragmentLocation ) {
return map( fragments, function( fragment ) {
fragment.location = fragmentLocation;
return new DeviationFragment( fragment );
} );
} );
return deviationFragments;
}
const createDeviationFragmentsMemoized = memoize( createDeviationFragments );
/**
* Counts syllables in partial exclusions. If these are found, returns the number of syllables found, and the modified word.
* The word is modified so the excluded part isn't counted by the normal syllable counter.
*
* @param {String} word The word to count syllables of.
* @param {Object} syllables The syllables data for the specific language.
*
* @returns {object} The number of syllables found and the modified word.
*/
const countPartialWordDeviations = function( word, syllables ) {
const deviationFragments = createDeviationFragmentsMemoized( syllables );
let remainingParts = word;
let syllableCount = 0;
forEach( deviationFragments, function( deviationFragment ) {
if ( deviationFragment.occursIn( remainingParts ) ) {
remainingParts = deviationFragment.removeFrom( remainingParts );
syllableCount += deviationFragment.getSyllables();
}
} );
return { word: remainingParts, syllableCount: syllableCount };
};
/**
* Count the number of syllables in a word, using vowels and exceptions.
*
* @param {String} word The word to count the number of syllables of.
* @param {Object} syllables The syllables data for the specific language.
*
* @returns {number} The number of syllables found in a word.
*/
const countUsingVowels = function( word, syllables ) {
let syllableCount = 0;
syllableCount += countVowelGroups( word, syllables );
if ( ! isUndefined( syllables.deviations ) && ! isUndefined( syllables.deviations.vowels ) ) {
syllableCount += countVowelDeviations( word, syllables );
}
return syllableCount;
};
/**
* Counts the number of syllables in a word.
*
* @param {string} word The word to count syllables of.
* @param {Object} syllables The syllables data for the specific language.
*
* @returns {number} The syllable count for the word.
*/
const countSyllablesInWord = function( word, syllables ) {
let syllableCount = 0;
if ( ! isUndefined( syllables.deviations ) && ! isUndefined( syllables.deviations.words ) ) {
if ( ! isUndefined( syllables.deviations.words.full ) ) {
const fullWordExclusion = countFullWordDeviations( word, syllables );
if ( fullWordExclusion !== 0 ) {
return fullWordExclusion;
}
}
if ( ! isUndefined( syllables.deviations.words.fragments ) ) {
const partialExclusions = countPartialWordDeviations( word, syllables );
word = partialExclusions.word;
syllableCount += partialExclusions.syllableCount;
}
}
syllableCount += countUsingVowels( word, syllables );
return syllableCount;
};
/**
* Counts the number of syllables in a text per word based on vowels.
* Uses exclusion words for words that cannot be matched with vowel matching.
*
* @param {String} text The text to count the syllables of.
* @param {Object} syllables The syllables data for the specific language.
*
* @returns {int} The total number of syllables found in the text.
*/
const countSyllablesInText = function( text, syllables ) {
text = text.toLocaleLowerCase();
const words = getWords( text );
const syllableCounts = map( words, function( word ) {
return countSyllablesInWord( word, syllables );
} );
return sum( syllableCounts );
};
export default countSyllablesInText;