fullfiller
Version:
Feature-rich filler text generator.
117 lines (92 loc) • 3.84 kB
text/typescript
import { freqMapType, languageType } from 'fullfiller-common/src/types';
import {
capitalize,
getRandomArrayElement,
last,
isNumeric,
} from 'fullfiller-common/src/utils';
import { isStopword as isStopwordBase } from 'stopwords-utils/src';
import weightedRandomness from 'weighted-randomness/src';
function capitalizeSentence(sentenceArray: string[]) {
return [capitalize(sentenceArray[0]), ...sentenceArray.slice(1)];
}
function getRandomPunctuation(location: 'end' | 'mid') {
const freqMap: freqMapType =
location === 'end'
? { 1: ['...'], 3: ['!', '?'], 16: ['.'] }
: { 1: ['[]'], 2: [';', ':'], 4: ['""', '()', '— —'], 8: [','] }; // mid punctuation will be enclosing (quotes, parentheses, brackets, em dash) 1/3 of the time
const punctuation = weightedRandomness(freqMap)();
return punctuation;
}
function addEndSentencePunctuation(arr: string[]) {
const sentenceArray = [...arr];
if (!last(sentenceArray).endsWith('.')) {
sentenceArray[sentenceArray.length - 1] += getRandomPunctuation('end');
}
return sentenceArray;
}
function addMidSentencePunctuation(arr: string[], language: languageType) {
const isStopword = (word: string) => isStopwordBase(word, language);
const sentenceArray = [...arr];
if (sentenceArray.length > 8 && Math.random() < 0.8) {
// punctuation will be placed at a minimum the fourth word
// and at a maximum at the fourth to last word
const subarray = sentenceArray.slice(3, sentenceArray.length - 3);
const randomPunctuation = getRandomPunctuation('mid');
if (/,|:|;/.test(randomPunctuation)) {
// simple punctuation won't be placed between stopwords or numbers
const filtered = subarray.filter((word) => {
const nextWord = sentenceArray[sentenceArray.indexOf(word) + 1];
return [word, nextWord].every((w) => !isStopword(w) && !isNumeric(w));
});
if (filtered.length > 0) {
const randomWord = getRandomArrayElement(filtered);
sentenceArray[sentenceArray.indexOf(randomWord)] += randomPunctuation;
}
} else {
// enclosing punctuation won't be placed between stopwords
const punctuationStartIndex = sentenceArray.indexOf(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
subarray.find((word) => {
const previousWord = sentenceArray[sentenceArray.indexOf(word) - 1];
return !isStopword(previousWord) && !isStopword(word);
})!
);
const punctuationEndIndex =
punctuationStartIndex === -1
? -1
: sentenceArray.indexOf(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
[...subarray]
.slice(subarray.indexOf(sentenceArray[punctuationStartIndex]))
.reverse()
.find((word) => {
const nextWord =
sentenceArray[sentenceArray.indexOf(word) + 1];
return !isStopword(word) && !isStopword(nextWord);
})!
);
if (punctuationStartIndex !== -1 && punctuationEndIndex !== -1) {
const [, openingPunctuation, closingPunctuation] =
/(\(|\[|"|—\s)(\)|]|"|\s—)/.exec(randomPunctuation) || [];
sentenceArray[
punctuationStartIndex
] = `${openingPunctuation}${sentenceArray[punctuationStartIndex]}`;
sentenceArray[punctuationEndIndex] += closingPunctuation;
}
}
}
return sentenceArray;
}
function capitalizeAndPunctuateSentence(
arr: string[],
language: languageType
): string[] {
const sentenceArray = [...arr];
return capitalizeSentence(
addEndSentencePunctuation(
addMidSentencePunctuation(sentenceArray, language)
)
);
}
export default capitalizeAndPunctuateSentence;