UNPKG

lesetid

Version:

A dead simple read time estimation

79 lines (77 loc) 2.24 kB
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 };