UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

51 lines (50 loc) 2.64 kB
import { MARKUP_PARSER } from "../markup/MarkupParser.js"; import { getElementText, walkElements } from "../util/element.js"; import { FileExtractor } from "./FileExtractor.js"; /** * File extractor for Markdown files. * - Stores the markdown text as `content`; rendering happens at output time via `<Markup>`. * - Sets `title` from the first `# h1` heading if one is present — otherwise leaves it undefined * (a confident title only). * - When a `title` is found, strips the leading `# h1` from `content` so renderers (which show * `title` separately) don't display the heading twice. * - Sets `description` to the first prose paragraph as a plain-text summary (used for card listings and `<meta>`). */ export class MarkupExtractor extends FileExtractor { extractProps(name, text) { const { title, description } = extractMarkdownProps(text); // The title `# h1` is surfaced separately as `title`, so strip it from the body to avoid rendering it twice. return { name, title, description, content: title ? _stripTitle(text) : text }; } } /** * Parse a markdown source string once and derive its `title` and `description` in a single pass. * - `title` — plain text of the first `# h1` heading, or `undefined` if there is none. * - `description` — plain-text summary of the first prose paragraph, or `undefined` if there is none. * - Both query the parsed markup tree, so inline syntax (`` `code` ``, `*emphasis*`, links) resolves to clean plain text. * * @param text The markdown source string (a markdown file's text, or a JSDoc description). * @returns An object whose `title` and `description` are each a plain string, or `undefined` when absent. */ export function extractMarkdownProps(text) { let title; let description; // Walk the top-level block elements once, claiming the first `h1` as the title and the first `p` as the description. for (const element of walkElements(MARKUP_PARSER.parse(text))) { if (!title && element.type === "h1") title = _plain(element); else if (!description && element.type === "p") description = _plain(element); if (title && description) break; } return { title, description }; } /** Flatten an element to a single-line plain-text summary, or `undefined` if it has no text. */ function _plain(element) { return getElementText(element).replace(/\s+/g, " ").trim() || undefined; } /** Strip a leading `# h1` heading (and any blank lines after it) from markdown text. */ function _stripTitle(text) { return text.replace(/^\s*#[^\n\S]+\S[^\n]*(?:\n+|$)/, ""); }