UNPKG

rehype-infer-reading-time-meta

Version:

rehype plugin to infer reading time as file metadata from the document

88 lines (79 loc) 2.56 kB
/** * @typedef {import('hast').Root} Root * @typedef {import('vfile').VFile} VFile */ /** * @typedef Options * Configuration. * @property {[number, number] | [number] | number | null | undefined} [age=[16, 18]] * Target age group (default: `[16, 18]`); this is the age your target * audience was still in school; so, set it to `18` if you expect all readers * to have finished high school, `21` if you expect your readers to be * college graduates, etc; can be two numbers in an array to get two * estimates. * @property {string | null | undefined} [mainSelector] * CSS selector to body of content (optional, example: `'main'`); useful to * exclude other things, such as the head, ads, styles, scripts, and other * random stuff, by focussing all strategies in one element. */ import {readingTime} from 'hast-util-reading-time' import {select} from 'hast-util-select' /** @type {Options} */ const emptyOptions = {} const defaultAge = [14, 18] /** * Infer the estimated reading time from a document as file metadata. * * The reading time is inferred not just on words per minute, but also takes * readability into account. * The result is stored on `file.data.meta.readingTime`. * * @param {Readonly<Options> | null | undefined} [options] * Configuration (optional). * @returns * Transform. */ export default function rehypeInferReadingTimeMeta(options) { const settings = options || emptyOptions const age = settings.age || defaultAge const mainSelector = settings.mainSelector || undefined /** * Transform. * * @param {Root} tree * Tree. * @param {VFile} file * File * @returns {undefined} * Nothing. */ return function (tree, file) { const main = mainSelector ? select(mainSelector, tree) : tree /** @type {[number, number] | [number] | number | undefined} */ let time if (main) { if (Array.isArray(age)) { // @ts-expect-error: `age` is not empty so `time` won’t be either. time = age .slice(0, 2) .map(function (age) { return readingTime(main, {age}) }) .sort(function (a, b) { return a - b }) } else { time = readingTime(main, {age}) } } if (time) { const matter = /** @type {Record<string, unknown>} */ ( file.data.matter || {} ) const meta = file.data.meta || (file.data.meta = {}) if (!matter.readingTime && !meta.readingTime) { meta.readingTime = time } } } }