lesetid
Version:
A dead simple read time estimation
79 lines (77 loc) • 2.24 kB
JavaScript
import { isAnsi, isCJK, isPunctuation } from "./utils-CnJJfLNX.js";
//#region src/index.ts
const DEFAULT_OPTIONS = {
wordsPerMinute: 200,
charsPerMinute: 500,
isWord: isAnsi
};
/**
* Counts the number of words and characters in the given text.
*
* @param {string?} text - the text to count words and characters in.
* @param {Options} [options] - the options to use.
* @returns {CountResult} the result of words and characters.
*/
function count(text, options = DEFAULT_OPTIONS) {
if (!text) return {
words: 0,
chars: 0
};
let words = 0;
let chars = 0;
let start = 0;
let end = text.length - 1;
while (!isPunctuationOrWord(text[start], options.isWord || isAnsi)) start++;
while (!isPunctuationOrWord(text[end], options.isWord || isAnsi)) end--;
const normalizedText = `${text}\n`;
for (let i = start; i <= end; i++) {
const char = normalizedText[i];
let nextChar = normalizedText[i + 1];
if (isCJK(char)) {
chars++;
while (i <= end && !isPunctuationOrWord(nextChar, options.isWord || isAnsi)) {
i++;
nextChar = normalizedText[i + 1];
}
} else if (isPunctuationOrWord(char, options.isWord || isAnsi) && (!isPunctuationOrWord(nextChar, options.isWord || isAnsi) || isCJK(nextChar))) words++;
}
return {
words,
chars
};
}
function isPunctuationOrWord(char = "", isWordFn) {
return !char || !(isPunctuation(char) || isWordFn(char));
}
/**
* Estimate a text's reading time.
*
* @param {string} text - the text to estimate.
* @param {Options} [options] - the options to use.
* @returns {Estimation} the estimation result.
*/
function estimate(text, options = DEFAULT_OPTIONS) {
if (!text) return {
minutes: 0,
time: 0,
words: 0,
chars: 0,
text: "0 min read"
};
const { words, chars } = count(text);
const { wordsPerMinute = 200, charsPerMinute = 500 } = options;
const charMinutes = chars / charsPerMinute;
const wordMinutes = words / wordsPerMinute;
const totalMinutes = charMinutes + wordMinutes;
const time = Math.round(totalMinutes * 60 * 1e3);
const displayed = Math.ceil(Number.parseFloat(totalMinutes.toFixed(2)));
return {
minutes: displayed,
time,
words,
chars,
text: `${displayed} min read`
};
}
//#endregion
export { DEFAULT_OPTIONS, count, estimate };