comrak
Version:
Comrak is an efficient, extensible, and highly configurable Markdown parser and renderer, written in Rust and compiled to WebAssembly. Portable and agnostic, it works seamlessly in any WebAssembly-friendly JS runtime.
196 lines (195 loc) • 7.18 kB
TypeScript
/**
* This module provides types and interfaces for adapters used in the Comrak
* markdown processing library.
*
* @module adapters
*/
import type { Sourcepos } from "./nodes.js";
/**
* Metadata about a heading element, which is passed to the `enter` and `exit`
* methods of the {@linkcode HeadingAdapter} API for custom heading rendering.
*
* @remarks
* This object is not created by users directly, but rather is provided by the
* Comrak library when invoking the `enter` and `exit` methods of a custom
* {@linkcode HeadingAdapter} implementation.
*
* @category Adapters
* @tags plugins, headings
*/
export interface HeadingMeta {
/** The level of the heading (1-6). */
level: number;
/** The textual content of the heading. */
content: string;
}
/**
* The `HeadingAdapter` API allows you to customize how headings are rendered
* by Comrak (`h1`, `h2`, ...) via custom `enter` and `exit` methods.
*
* The `enter` and `exit` methods define what is rendered before and after the
* heading content, respectively. Both receive {@linkcode HeadingMeta} objects
* for their contextual `this` binding and first argument, which provide them
* with the heading level and content. The actual AST content of the heading
* remains unchanged.
*
* ## Methods
*
* ### `enter`
*
* The `enter` method is called **once** for each heading immediately before
* rendering its content, and as such, should render the opening tag and any
* attributes it has.
*
* ### `exit`
*
* The `exit` method - also called **once** - is invoked immediately _after_
* the heading content has been rendered, and should render the closing tag.
*
* ---
*
* ## Example
*
* Here's a brief demo of a `HeadingAdapter` that adds `id` attributes to
* headings based on their content, as well as `data-sourcepos` attributes if
* source position tracking is enabled:
*
* @example
* ```ts
* import { markdownToHTML, Options } from "@nick/comrak";
* import assert from "node:assert";
*
* const options = Options.default();
*
* options.render.sourcepos = true;
*
* options.plugins.render.headingAdapter = {
* enter: ({ level, content }, sourcepos) => {
* // rudimentary slugification example. don't actually use this!
* const id = content.trim()
* .replace(/[^a-z0-9-]+|-+/gi, "-")
* .replace(/^-+|-+$/g, "")
* .toLowerCase();
* let attrs = ` id="${id}"`;
* if (sourcepos) {
* const { start, end } = sourcepos;
* const { line: l1, column: c1 } = start;
* const { line: l2, column: c2 } = end;
* attrs += ` data-sourcepos="${l1}:${c1}-${l2}:${c2}"`;
* }
* return `<h${level}${attrs}>`
* },
* exit: ({ level }) => `</h${level}>`,
* };
*
* const md = '# Hello!\n\n## Subheading\n\nBye!\n';
*
* const html = markdownToHTML(md, options);
* assert.strictEqual(html,
* '<h1 id="hello" data-sourcepos="1:1-1:8">Hello!</h1>\n' +
* '<h2 id="subheading" data-sourcepos="3:1-3:13">Subheading</h2>\n' +
* '<p data-sourcepos="5:1-5:4">Bye!</p>\n'
* );
* ```
* @category Adapters
* @tags plugins, headings
*/
export interface HeadingAdapter {
/**
* Called when entering a heading element during rendering.
*
* @param heading Metadata about the heading being entered.
* @param location Optional source position information for the heading.
* @returns The HTML string to insert at the start of the heading.
*/
enter(heading: HeadingMeta, location?: Sourcepos): string;
/**
* Called when exiting a heading element during rendering.
*
* @param heading Metadata about the heading being exited.
* @returns The HTML string to insert at the end of the heading.
*/
exit(heading: HeadingMeta): string;
}
/**
* The `SyntaxHighlighterAdapter` API allows you to customize how code
* fences/blocks are rendered by Comrak via custom `highlight`, `pre`, and
* `code` methods.
*
* ## Methods
*
* ### `highlight`
*
* The `highlight` method is called to perform syntax highlighting on the raw
* code content of a code block. It receives the code string and an optional
* language identifier, and should return the highlighted HTML string. The HTML
* returned by this method will be inserted inside the `<code>` element, and so
* should not include any `<pre>` or `<code>` tags.
*
* **Note**: The returned HTML should *never* include a `</code>` or `</pre>`
* tag, as those are added automatically by Comrak. However, if you wish to
* inherit the opening `<pre>` and/or `<code>` tags from your highlighter's
* output, you can do so by returning everything up to (but not including) the
* closing `</code>` tag, as shown in the Shiki example file.
*
* If this is the route you take, be sure that your `pre` and `code` methods
* both return empty strings to avoid duplicate tags.
*
* ### `pre`
*
* The `pre` method is called to render the `<pre>` element that wraps the code
* block. It receives a single argument: an object mapping attribute names to
* their values (e.g., `class`, `data-lang`, etc.). It should return the
* opening `<pre>` tag with any necessary attributes included.
*
* ### `code`
*
* The `code` method is called to render the `<code>` element that contains the
* highlighted code. It receives a single argument: an object mapping attribute
* names to their values. It should return the opening `<code>` tag with any
* necessary attributes included.
*
* ---
*
* ## Examples
*
* See the README.md file for examples of how to integrate external syntax
* highlighters like Shiki or Prism with Comrak using this adapter. There are
* also real-world sample scripts in the `examples/` directory of the repo.
*
* @category Adapters
* @tags plugins, syntax-highlighting
*/
export interface SyntaxHighlighterAdapter {
/**
* Invoked with the raw `code` content and `lang` string (if one was given).
* Should return the highlighted HTML to be inserted inside the `<code>` tag.
*
* @param code The raw code content.
* @param [lang] The optional language identifier.
* @returns The highlighted HTML string.
*/
highlight(code: string, lang?: string | null): string;
/**
* Called to render the `<pre>` element that wraps the code block.
*
* @remarks
* If not provided, a default implementation will be used that renders a
* simple `<pre>` tag with its attributes serialized as standard HTML.
*
* @param attrs An object mapping attribute names to their values.
* @returns The opening `<pre>` tag with any necessary attributes included.
*/
pre?(attrs: Record<string, string>): string;
/**
* Called to render the `<code>` element that contains the highlighted code.
*
* @remarks
* If not provided, a default implementation will be used that renders a
* simple `<code>` tag with its attributes serialized as standard HTML.
*
* @param attrs An object mapping attribute names to their values.
* @returns The opening `<code>` tag with any necessary attributes included.
*/
code?(attrs: Record<string, string>): string;
}