/** * A small Markdown reader, written for text that is still arriving. * * No parser library. What a chat answer actually contains is headings, * paragraphs, lists, fenced code, blockquotes, tables, rules and a handful of * inline marks — and every general-purpose parser worth using assumes it has * been handed the whole document. That assumption is the one thing that is * never true here. * * ## Half-arrived markdown * * A token stream shows you every prefix of the final text, so the reader sees * `**bo`, then `**bol`, then `**bold**`. Treated naively that is three * documents: two with literal asterisks in them and one with a bolded word. The * text would flash between styles on nearly every frame, which is worse than no * formatting at all — the eye tracks the flicker instead of the words. * * So an unterminated construct at the very end of the input is *completed * speculatively* rather than escaped: an open fence becomes a code block that * is still filling, an open `**` becomes bold text that is still being written. * Anything unterminated anywhere else is literal, because a document that has * stopped arriving means what it says. * * The two rules that follow from this: * * - **Only the tail is speculative.** An asterisk in the middle of a finished * paragraph is an asterisk. * - **A speculative construct never removes visible text.** The characters that * opened it are hidden, and everything after them stays on screen. Otherwise * the last word of the answer disappears and reappears as its delimiter * arrives. */ export type Align = 'left' | 'center' | 'right'; export interface InlineToken { kind: 'text' | 'code' | 'link' | 'image'; value: string; /** For links and images. */ href?: string; bold?: boolean; italic?: boolean; strike?: boolean; } export type Block = { type: 'heading'; level: 1 | 2 | 3 | 4 | 5 | 6; inline: InlineToken[]; } | { type: 'paragraph'; inline: InlineToken[]; } | { type: 'code'; code: string; language?: string; open: boolean; } | { type: 'quote'; blocks: Block[]; } | { type: 'list'; ordered: boolean; start: number; items: Block[][]; } | { type: 'table'; head: InlineToken[][]; rows: InlineToken[][][]; align: (Align | null)[]; } | { type: 'rule'; }; /** * Splits a document into blocks. * * `streaming` is what turns speculative completion on. With it off — a stored * answer, a message that has finished — an unterminated fence is just a * paragraph starting with three backticks, which is what it literally is. */ export declare function parseMarkdown(source: string, streaming?: boolean): Block[]; /** * Splits a run of text into styled spans. * * `tail` says this run is the end of a stream, which is what licenses closing * an open delimiter speculatively. It is deliberately narrow: only the *last* * unterminated opener on the line is completed, and only when nothing after it * could still turn out to be the closer. */ export declare function parseInline(source: string, tail: boolean): InlineToken[]; //# sourceMappingURL=markdown.d.ts.map