Technical previewShare feedback

Search

Search documentation

Markdown plugins

Updated Nov 1, 2026

Markdown plugins parse Markdown into mdast, extend its syntax and turn mdast into Markdown, HTML trees or natural-language trees. md.parse and md.stringify are the parser and the compiler; a syntax extension such as md.gfm teaches both, so add it beside either.

md.parse

Parses Markdown into an mdast tree, CommonMark as micromark reads it; add syntax extensions such as md.gfm beside it.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.toHtml())
  .use(html.stringify())
  .processSync("# Hello *world*")
file.value
// <h1>Hello <em>world</em></h1>

Follows remark-parse.

No options.

md.directive

Adds generic directives — :text, ::leaf and :::container — read by md.parse and written by md.stringify.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.directive())
  .use(md.stringify())
  .processSync(":::note{.info}\nRead *this*.\n:::")
file.value
// :::note{.info}
// Read *this*.
// :::

Follows remark-directive.

OptionTypeDefaultDescription
collapseEmptyAttributesbooleantrueWrite an empty attribute as its name alone, {a}, rather than {a=""}.
preferShortcutbooleantrueWrite id and class as #a and .b where they can be.
preferUnquotedbooleanfalseLeave attribute values unquoted where they can be.
quotestring | nullnullThe quote of attribute values: " or '; md.stringify's quote when unset.
quoteSmartbooleanfalseUse the other quote when the preferred one occurs more often in a value.

md.gfm

Adds GitHub Flavored Markdown: tables, task lists, strikethrough, autolink literals and footnotes.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.gfm())
  .use(md.toHtml())
  .use(html.stringify())
  .processSync("~~old~~ www.example.com")
file.value
// <p><del>old</del> <a href="http://www.example.com">www.example.com</a></p>

alerts: true also renders GitHub alerts, a block quote opening with [!NOTE], [!TIP], [!IMPORTANT], [!WARNING] or [!CAUTION], as GitHub does: a <div class="markdown-alert markdown-alert-note"> with a title and its Octicon, as remark-github-blockquote-alert writes it. For an MDX component instead, use md.component's alerts.

Follows remark-gfm.

OptionTypeDefaultDescription
singleTildebooleantrueLet one tilde, ~a~, form strikethrough, as well as two.
tableCellPaddingbooleantruePad table cells with a space on each side when writing Markdown.
tablePipeAlignbooleantrueLine up table pipes when writing Markdown.
firstLineBlankbooleanfalseWrite a footnote definition's first line blank when it holds flow content.
alertsAlerts | nullRender GitHub alerts, a block quote opening with [!NOTE], as GitHub does, as remark-github-blockquote-alert does: true, or its options.

Alerts

md.gfm's alerts: on, or on with remark-github-blockquote-alert's options.

Takes boolean | AlertsOptions.

AlertsOptions

remark-github-blockquote-alert's options.

OptionTypeDefaultDescription
legacyTitlebooleanfalseRead a title after the type, [!NOTE/Read this], in place of the type's name.
tagNamestring"div"The tag name of the alert's element.
classNamesstring""More classes for the alert's element, separated by spaces.

md.definitionList

Adds definition lists: a term, then lines starting with : that define it.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.definitionList())
  .use(md.toHtml())
  .use(html.stringify())
  .processSync("Apple\n: A fruit.")
file.value
// <dl>
// <dt>Apple</dt>
// <dd>A fruit.
// </dd>
// </dl>

Follows remark-definition-list.

No options.

md.math

Adds math: $$ blocks and $ inline, kept as math nodes for a later stage to render.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.math())
  .use(md.toHtml())
  .use(html.stringify())
  .processSync("Euler: $e^{i\\pi} = -1$")
file.value
// <p>Euler: <code class="language-math math-inline">e^{i\pi} = -1</code></p>

Follows remark-math.

OptionTypeDefaultDescription
singleDollarTextMathbooleantrueLet one dollar, $a$, form math in text, as well as two.

md.mdx

Adds MDX syntax — JSX, {expressions} and import/export — and turns off indented code, autolinks and raw HTML, as MDX does.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.mdx())
  .use(md.stringify())
  .processSync("import {Chart} from './chart.js'\n\n# Sales {year}\n\n<Chart  data={rows}/>")
file.value
// import {Chart} from './chart.js'
//
// # Sales {year}
//
// <Chart data={rows} />

Follows remark-mdx.

OptionTypeDefaultDescription
quotestring | nullnullThe quote of JSX attribute values: " (when unset) or '.
quoteSmartbooleanfalseUse the other quote when the preferred one occurs more often in a value.
tightSelfClosingbooleanfalseWrite self-closing tags without a space before the slash, <a/>.
printWidthnumber | nullnullThe width past which a flow element's attributes go on lines of their own.

md.frontmatter

Reads frontmatter — YAML by default, TOML or your own fences by option — into a node of its own.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.frontmatter(["yaml", "toml"]))
  .use(md.stringify())
  .processSync('+++\ntitle = "Hi"\n+++\n\n# Hi')
file.value
// +++
// title = "Hi"
// +++
//
// # Hi

With data: true it also parses the YAML a document starts with into the file's data.matter, as vfile-matter does ({} when there is none; YAML 1.2's core schema, as the yaml package reads it), and strip: true drops that node from the tree. Invalid YAML fails with invalid-frontmatter. To combine them with other matters, pass { matters, data, strip }.

const withData = textlane()
  .use(md.parse())
  .use(md.frontmatter({ data: true }))
  .use(md.stringify())
  .processSync("---\ntitle: Hello\ntags: [a, b]\n---\n\n# Hello")
withData.data.matter
// { title: "Hello", tags: ["a", "b"] }

Follows remark-frontmatter.

The kinds of matter to recognize, as remark-frontmatter takes them (a preset, a matter, or a list of them; yaml when unset), or textlane's options object.

Takes "yaml" | "toml" | Matter | ("yaml" | "toml" | Matter)[] | FrontmatterSettings.

Matter

One kind of frontmatter: the node type it becomes and its fences, a marker repeated three times or a whole fence.

OptionTypeDefaultDescription
typestring
markerFence
fenceFence
anywhereboolean

FrontmatterSettings

textlane's options: the matters, and what to do with YAML frontmatter.

OptionTypeDefaultDescription
matters"yaml" | "toml" | Matter | ("yaml" | "toml" | Matter)[]The kinds of matter to recognize, as remark-frontmatter takes them; yaml when unset.
databooleanParse the YAML frontmatter a document starts with into file.data.matter, {} when there is none, as vfile-matter does.
stripbooleanRemove the YAML frontmatter a document starts with from the tree.

Fence

A fence, or its opening and closing ones.

Takes string | FencePair.

FencePair

Different opening and closing fences.

OptionTypeDefaultDescription
openstring
closestring

md.cjkFriendly

Lets *, _ and, with md.gfm, ~ emphasize text next to Chinese, Japanese and Korean characters and punctuation, as remark-cjk-friendly and remark-cjk-friendly-gfm-strikethrough parse it: **これは強調。**です is strong, where CommonMark leaves the asterisks. Text without CJK parses as before. md.stringify does not yet escape emphasis the CJK-friendly way, so Markdown written back may not parse to the same tree.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.cjkFriendly())
  .use(md.toHtml())
  .use(html.stringify())
  .processSync("**これは強調。**です")
file.value
// <p><strong>これは強調。</strong>です</p>

Follows remark-cjk-friendly.

No options.

md.gemoji

Turns gemoji shortcodes such as :tada: into the emoji they name.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.gemoji())
  .use(md.stringify())
  .processSync("Shipped :tada:")
file.value
// Shipped 🎉

emoticon: true also turns emoticons such as :) and :-( into emoji, accessible: true wraps an emoji in <span role="img" aria-label="…"> and padSpaceAfter: true puts a space after each, as remark-emoji's options do. Shortcodes stay gemoji's names, where remark-emoji reads node-emoji's, which name a few emoji differently.

Follows remark-gemoji.

OptionTypeDefaultDescription
emoticonbooleanfalseAlso turn emoticons such as :) and :-( into emoji, as remark-emoji does.
accessiblebooleanfalseWrap each emoji in <span role="img" aria-label="…">, labelled with its name.
padSpaceAfterbooleanfalsePut a space after each emoji.

md.smartypants

Turns straight quotes, dashes, dots and backticks in Markdown text into their typographic forms, pairing quotes across links and emphasis, as remark-smartypants does. Code is left alone.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.smartypants())
  .use(md.stringify())
  .processSync(`"Hello" -- it's *done*...`)
file.value
// “Hello” — it’s *done*…

Follows remark-smartypants.

OptionTypeDefaultDescription
backticksBackticksTurn double backticks and double straight single quotes into double quotes; all turns single ones into single quotes too.
closingQuotesQuoteCharacters | nullThe closing quotes to use: ” and ’ by default.
dashesDashesTurn two dashes into an em dash; oldschool and inverted treat three too.
ellipsesEllipsesTurn three dots into an ellipsis, with spaces between them or without.
openingQuotesQuoteCharacters | nullThe opening quotes to use: “ and ‘ by default.
quotesboolean | nulltrueTurn straight quotes into smart ones.

Backticks

Takes boolean | "all".

QuoteCharacters

The quote characters to use for double and single quotes.

OptionTypeDefaultDescription
doublestring
singlestring

Dashes

Takes boolean | "oldschool" | "inverted".

Ellipses

Takes boolean | "spaced" | "unspaced".

md.smartypants

Turns straight quotes, dashes, dots and backticks in Markdown text into their typographic forms, pairing quotes across links and emphasis, as remark-smartypants does. Code is left alone.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.smartypants())
  .use(md.stringify())
  .processSync(`"Hello" -- it's *done*...`)
file.value
// “Hello” — it’s *done*…

Follows remark-smartypants.

OptionTypeDefaultDescription
backticksBackticksTurn double backticks and double straight single quotes into double quotes; all turns single ones into single quotes too.
closingQuotesQuoteCharacters | nullThe closing quotes to use: ” and ’ by default.
dashesDashesTurn two dashes into an em dash; oldschool and inverted treat three too.
ellipsesEllipsesTurn three dots into an ellipsis, with spaces between them or without.
openingQuotesQuoteCharacters | nullThe opening quotes to use: “ and ‘ by default.
quotesboolean | nulltrueTurn straight quotes into smart ones.

Backticks

Takes boolean | "all".

QuoteCharacters

The quote characters to use for double and single quotes.

OptionTypeDefaultDescription
doublestring
singlestring

Dashes

Takes boolean | "oldschool" | "inverted".

Ellipses

Takes boolean | "spaced" | "unspaced".

md.component

Turns directives, GitHub alerts and other nodes into MDX JSX elements, the components an MDX runtime renders, by declarative rules, so a site's :::note or ::button needs no JavaScript plugin. Each directive rule names the directive and the component, where its name and label go, which attributes it keeps, what it requires and whether adjacent elements are grouped, as livemark's cards and tabs are. Code rules (codes) do the same for fenced code: a block becomes a component by its language or a meta key="value", or adjacent blocks are wrapped together, as tabbed code is. A container rule's treeAs reads its lists as a file tree, as Starlight's <FileTree> reads one, into a JSON attribute of items { name, type, comment?, highlighted?, children? }: a name ending in / or holding a list is a directory, a bold name is highlighted, text after the name is its comment and … stands for more files. Run it after md.directive and before md.toHtml and mdx.compile, which compile the elements to component calls.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.directive())
  .use(md.mdx())
  .use(
    md.component({
      directives: [{ name: "note", component: "Callout", nameAs: "type", labelAs: "title" }],
    }),
  )
  .use(md.stringify())
  .processSync(":::note[Heads up]\nRead *this*.\n:::")
file.value
// <Callout type="note" title="Heads up">
//   Read *this*.
// </Callout>
OptionTypeDefaultDescription
directivesDirectiveRule[]Rules for directives; the first that matches a directive converts it.
alertsAlertRule | nullGitHub alerts, > [!NOTE], into a component.
nodesRecord<string, string>{}Node types, such as defList, into components keeping their children.
unknownDirectivesUnknownDirectivesWhat becomes of a directive no rule converts.
codesCodeRule[]Rules for fenced code; the first that matches a block applies.

DirectiveRule

How md.component turns matching directives into one component.

OptionTypeDefaultDescription
nameNamesThe directive's name, or several.
kindDirectiveKind | nullThe kind of directive: text, leaf or container; any when left out.
whereRecord<string, string>{}Attribute values the directive must have.
componentstringThe component: a text element for a text directive, else a flow element; {name} in it stands for the directive's name, so one rule can cover a family of them.
nameAsstring | nullnullThe attribute that gets the directive's name.
labelAsstring | nullnullThe attribute that gets the label's text: a container's label paragraph or a text or leaf directive's content, which is then dropped.
labelDefaultstring | nullnullThe label's text when there is none.
attributesAttributeRule[] | nullThe attributes to keep, in order; every one, as written, when left out.
requiredstring[][]Attributes without which the directive is left to unknownDirectives.
groupGroupRule | nullWrap runs of adjacent siblings this rule converted in another component.
treeAsstring | nullnullThe attribute that gets the lists of a container directive as a file tree, JSON items {name, type, comment?, highlighted?, children?}; the lists leave its content.

AlertRule

How md.component turns GitHub alerts, a block quote opening with [!TYPE], into a component.

OptionTypeDefaultDescription
componentstringThe component an alert becomes.
typeAsstringThe attribute that gets the alert's type.
typesRecord<string, string>Each alert type, as written, to the value of typeAs; other types stay block quotes.

UnknownDirectives

What md.component does with a directive no rule converts.

Takes "keep" | "source" | "error".

CodeRule

How md.component turns matching code blocks into a component, or groups them.

OptionTypeDefaultDescription
langNames | nullThe block's language, or several; any when left out.
metastring | nullnullA key="value" the block's meta must hold.
componentstring | nullnullThe component the block becomes; left out, the block stays code and only groups.
valueAsstring | nullnullThe attribute that gets the code; left out, the code is the component's text.
attributesAttributeRule[]Meta key="value" pairs to keep as attributes, in order.
groupCodeGroupRule | nullWrap runs of adjacent blocks this rule matched in another component.

Names

One name or several.

Takes string | string[].

DirectiveKind

A directive's kind, by how many colons open it.

Takes "text" | "leaf" | "container".

AttributeRule

An attribute to keep: its name, or its name with what to call it and a default.

Takes string | { name: string; rename?: string | null; default?: string | null }.

GroupRule

The component wrapping a run of adjacent siblings one rule converted.

OptionTypeDefaultDescription
componentstringThe wrapping component.
minnumber | nullnullThe shortest run wrapped; 2 when left out.
inheritstring[][]Attributes the wrapper copies from the run's first element.

CodeGroupRule

The component wrapping a run of adjacent code blocks one rule matched; the meta keys it reads are taken out of each block's meta.

OptionTypeDefaultDescription
componentstringThe wrapping component.
minnumber | nullnullThe shortest run wrapped; 2 when left out.
collectstring | nullnullThe attribute that gets the run's values of the rule's meta key, as a JSON list.
inheritstring[][]Meta keys the wrapper copies from the run's first block as attributes.

md.packageCommand

Turns a fenced block of package-manager commands into one MDX JSX element with the commands converted for each manager, as @docusaurus/remark-plugin-npm2yarn does, so a site's install tabs need no JavaScript plugin. The block's language names the ecosystem: npm converts as the npm-to-yarn package does, for pnpm, yarn, bun, deno and nub; pip for uv, poetry and pdm; cargo for cargo-binstall. Each manager becomes a string attribute named after it, in the order ecosystems lists them, and each line converts on its own; a line a manager has no equivalent for stays as written. Run it before md.toHtml and mdx.compile.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.mdx())
  .use(md.packageCommand())
  .use(md.stringify())
  .processSync("```npm\nnpm install textlane\n```")
file.value
// <PackageTabs npm="npm install textlane" pnpm="pnpm add textlane" yarn="yarn add textlane" bun="bun add textlane" />

Follows npm-to-yarn.

OptionTypeDefaultDescription
componentstring"PackageTabs"The component a block becomes; one string attribute per manager.
ecosystemsEcosystemsEach ecosystem's managers, in attribute order; an empty list leaves its blocks code.

Ecosystems

The managers md.packageCommand converts each ecosystem's commands for.

OptionTypeDefaultDescription
npmNpmManager[]Managers for npm blocks, converted as npm-to-yarn converts; npm, pnpm, yarn and bun by default.
pipPipManager[]Managers for pip blocks; pip, uv, poetry and pdm by default.
cargoCargoManager[]Managers for cargo blocks; cargo and cargo-binstall by default.

NpmManager

A JavaScript package manager an npm command converts to.

Takes "npm" | "pnpm" | "yarn" | "bun" | "deno" | "nub".

PipManager

A Python package manager a pip command converts to.

Takes "pip" | "uv" | "poetry" | "pdm".

CargoManager

A Rust installer a cargo command converts to.

Takes "cargo" | "cargo-binstall".

md.headingId

Reads {#id} at the end of a heading, after a space, as its id, as remark-heading-id does; md.toHtml puts it on the heading. remark-heading-id's defaults is not ported: html.slug gives the other headings ids. With attributes: true it reads a whole attribute list instead, as md.directive reads one: ## API {#api .wide data-step=2} gives the heading an id, classes and a data-step. Only the last braces are read, event handlers (on…) and invalid names are dropped, and on untrusted input the result still belongs behind html.sanitize. markers turns literal heading suffixes into attributes and strips them, before or after an attribute list: {"[step]": {"data-step": true}, "[!toc]": {"data-toc-hidden": true}} reads ## Install [step] as <h2 data-step>Install</h2>.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.headingId())
  .use(md.toHtml())
  .use(html.stringify())
  .processSync("# Install {#setup}")
file.value
// <h1 id="setup">Install</h1>

Follows remark-heading-id.

OptionTypeDefaultDescription
attributesbooleanfalseRead a whole attribute list, {#id .class key=value key="v w"}, as directives write theirs: classes become className and other keys properties.
markersRecord<string, Record<string, MarkerValue>>Literal suffixes, such as [step], stripped from a heading's end for the attributes each names, a value or true for a bare one: {"[step]": {"data-step": true}}.

MarkerValue

An attribute a heading marker sets: its value, or true for the bare attribute.

Takes boolean | string.

md.pathRewrite

Rewrites the URLs of images, links and definitions as a site serves them, from where the document lives: a relative URL is resolved against the file's path and made relative to root, every root-relative URL gets base once, and a link to a Markdown file becomes its page's URL, from pages or by markdownLinks (keep, directory or html). URLs with a scheme, protocol-relative ones and fragments stay as they are. Pass the document's path with the text.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.pathRewrite({ root: "/repo/docs", base: "/site", markdownLinks: "directory" }))
  .use(md.toHtml())
  .use(html.stringify())
  .processSync({
    value: "![logo](../logo.png) and [next](./next.md)",
    path: "/repo/docs/guide/intro.md",
  })
file.value
// <p><img src="/site/logo.png" alt="logo"> and <a href="/site/guide/next/">next</a></p>
OptionTypeDefaultDescription
rootstring | nullnullThe directory URLs count from, as the file's path spells it; the path's own starting point when left out.
basestring | nullnullThe URL the site is served at, such as /docs, put before every root-relative URL once.
nodesUrlNode[] | nullThe nodes whose URLs are rewritten; images, links and definitions when left out.
pagesRecord<string, string>{}Markdown files, relative to root, to the URL of their page; a link to one of them takes it, before markdownLinks applies.
markdownLinksMarkdownLinksHow a link to a Markdown file no page names becomes a URL.

UrlNode

A node with a URL.

Takes "image" | "link" | "definition".

MarkdownLinks

How a link to a Markdown file becomes a URL.

Takes "keep" | "directory" | "html".

md.shiftHeading

Moves every heading's depth by shift, kept within 1 to 6, as rehype-shift-heading does for hast: -1 makes each h2 an h1. dropTitle first drops the document's first node when it is an h1, looking past frontmatter and ESM, which suits a page whose title is rendered on its own; dropping before shifting keeps a document that opens on an h2.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.shiftHeading({ shift: -1, dropTitle: true }))
  .use(md.stringify())
  .processSync("# 0.2.0\n\n### Features\n\n- a")
file.value
// ## Features
//
// * a

Follows rehype-shift-heading.

OptionTypeDefaultDescription
shiftnumber0The levels added to each heading's depth: -1 makes an h2 an h1, 1 an h1 an h2.
dropTitlebooleanfalseDrop the document's first node when it is an h1, looking past frontmatter and ESM.

md.strip

Strips mdast down to its text, as strip-markdown does: code, HTML, tables and definitions go, headings become paragraphs and formatting gives way to its content, which suits search indexes and plain-text summaries. keep leaves node types as they are and remove drops more.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.strip())
  .use(md.stringify())
  .processSync("# Hello *world*\n\nSee [the docs](/docs).")
file.value
// Hello world
//
// See the docs.

Follows strip-markdown.

OptionTypeDefaultDescription
keepstring[][]Node types to leave as they are, such as inlineCode.
removestring[][]Node types to drop, besides those strip-markdown drops.

md.toc

Generates a table of contents, as remark-toc does: under the first heading matching heading (Contents, Table of contents or TOC by default), it replaces whatever sat before the next heading as deep or shallower with a list linking to every heading after, by the ids github-slugger makes from their text, or the ids md.headingId stored. heading and skip are JavaScript regular expression sources matched against a heading's whole text, case-insensitively, run by Rust's regex: lookaround and back references are refused, and case folding is Unicode's rather than JavaScript's. parents takes unist-util-is tests written as JSON (a type, an object of fields, a list), not functions.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.toc())
  .use(md.stringify())
  .processSync("# Guide\n\n## Contents\n\n## Install\n\n### From npm\n\n## Use")
file.value
// # Guide
//
// ## Contents
//
// * [Install](#install)
//   * [From npm](#from-npm)
// * [Use](#use)
//
// ## Install
//
// ### From npm
//
// ## Use

Follows remark-toc.

OptionTypeDefaultDescription
headingstring | nullnullThe heading to put the table under, as JavaScript regular expression source matched against its whole text, case-insensitively; (table[ -]of[ -])?contents?|toc when unset.
maxDepthnumber | nullnullThe deepest heading rank to list, 1 to 6.
minDepthnumber | nullnullThe shallowest heading rank to list, 1 to 6.
skipstring | nullnullHeadings to leave out, as JavaScript regular expression source matched against their whole text, case-insensitively.
tightboolean | nullnullKeep the list compact, without blank lines between items; true when unset.
orderedboolean | nullnullNumber the list instead of bulleting it.
prefixstring | nullnullWhat each link's fragment starts with, such as user-content-.
parentsParentTest | nullThe parents whose headings are listed, as a unist-util-is test: a node type, an object of fields a parent must equal, or a list of these; only the root when unset.

ParentTest

A unist-util-is test of a node, written as JSON: one check, or a list any of which passes.

Takes ParentCheck | ParentCheck[].

ParentCheck

One unist-util-is check: a node type, or fields a node must equal.

Takes string | Record<string, unknown>.

md.stringify

Serializes mdast back into Markdown; its options pick the markers and spacing it writes.

import { textlane } from "textlane"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.stringify({ bullet: "-", emphasis: "_" }))
  .processSync("* *one*\n* two")
file.value
// - _one_
// - two

Follows remark-stringify.

OptionTypeDefaultDescription
bulletstring | nullnullThe marker of unordered list items: *, + or -.
bulletOrderedstring | nullnullThe marker of ordered list items: . or ).
bulletOtherstring | nullnullThe marker of a list right after a list with bullet.
closeAtxbooleanfalseClose ATX headings with as many # as they open with.
emphasisstring | nullnullThe marker of emphasis: * or _.
fencestring | nullnullThe marker of fenced code: ` or ~.
fencesbooleantrueFence code; false indents it where it can.
incrementListMarkerbooleantrueNumber ordered list items up from start.
listItemIndentstring | nullnullHow list item content is indented: one, tab or mixed.
quotestring | nullnullThe marker of titles: " or '.
resourceLinkbooleanfalseWrite links as resources even where an autolink would do.
rulestring | nullnullThe marker of thematic breaks: *, - or _.
ruleRepetitionnumber | nullnullHow many markers a thematic break has, 3 or more.
ruleSpacesbooleanfalsePut spaces between the markers of a thematic break.
setextbooleanfalseWrite headings of rank 1 and 2 as setext headings.
strongstring | nullnullThe marker of strong: * or _.
tightDefinitionsbooleanfalseJoin definitions with no blank line between them.
unsafeUnsafePattern[]Extra patterns of characters to escape.

UnsafePattern

A character to escape where it would otherwise start or end syntax.

OptionTypeDefaultDescription
characterstring""The character, escaped as a regular expression would need it.
beforestring | nullnullA regular expression that must match right before the character.
afterstring | nullnullA regular expression that must match right after the character.
atBreakbooleanfalseOnly at the start of a line, after any indent.
inConstructNames | nullOnly inside one of these constructs.
notInConstructNames | nullNever inside one of these constructs.
beforeNodeNames | nullOnly at the start of a node right after one of these node types.
afterNodeNames | nullOnly at the end of a node right before one of these node types.
unicodebooleanfalseRead before and after with Unicode classes such as \p{L}.

Names

One name or several.

Takes string | string[].

md.toHtml

Turns mdast into hast, the HTML tree, so HTML plugins and html.stringify can follow.

import { textlane } from "textlane"
import * as html from "textlane/html"
import * as md from "textlane/md"

const file = textlane()
  .use(md.parse())
  .use(md.toHtml({ allowDangerousHtml: true }))
  .use(html.stringify({ allowDangerousHtml: true }))
  .processSync("Hi <kbd>Ctrl</kbd>")
file.value
// <p>Hi <kbd>Ctrl</kbd></p>

taskListLabels: { checked, unchecked } gives each GFM task-list checkbox an aria-label, so screen readers name it; remark-rehype writes none, so it is off by default.

breaks: true turns each line ending in text into a <br>, as remark-breaks does, so a single newline breaks the line as in GitHub comments.

Follows remark-rehype.

OptionTypeDefaultDescription
allowDangerousHtmlbooleanfalseKeep raw HTML in the tree instead of dropping it.
breaksbooleanfalseTurn each line ending in text into a <br>, as remark-breaks does.
clobberPrefixstring | nullnullWhat footnote ids start with, so they cannot clobber the page's; user-content- when unset.
footnoteBackContentstring | nullnullThe text of each footnote's back reference; ↩, numbered from the second, when unset.
footnoteBackLabelstring | nullnullThe aria-label of each footnote's back reference; Back to reference 1 and so on when unset.
footnoteLabelstring | nullnullThe heading of the footnotes section; Footnotes when unset.
footnoteLabelTagNamestring | nullnullThe tag name of the footnotes section's heading; h2 when unset.
passThroughstring[][]Node types without a handler to copy into hast as they are, their children converted.
taskListLabelsTaskListLabels | nullAn aria-label for each task-list checkbox, so screen readers name it; none when left out, as remark-rehype writes none.
jsxElementsbooleanfalseTurn MDX JSX elements, such as md.component and md.packageCommand make, into the plain HTML elements they name, literal attributes kept, for a pipeline that ends in HTML rather than MDX.

TaskListLabels

The labels of task-list checkboxes.

OptionTypeDefaultDescription
checkedstringThe label of a checked box, such as Completed task.
uncheckedstringThe label of an unchecked box, such as Task.

md.toNaturalLanguage

Turns mdast into nlcst, the natural-language tree, so nl.* plugins can check the prose of a Markdown document.

import { textlane } from "textlane"
import * as md from "textlane/md"
import * as nl from "textlane/nl"

const file = textlane()
  .use(md.parse())
  .use(md.toNaturalLanguage())
  .use(nl.repeatedWords())
  .use(nl.stringify())
  .processSync("It is *the the* best.")
file.messages[0].reason
// Unexpected repeated `the`, remove one occurrence

Follows remark-retext.

OptionTypeDefaultDescription
ignorestring[][]Node types to leave out, besides table, tableRow and tableCell.
sourcestring[][]Node types to keep as one SourceNode of their source text, besides inlineCode.

Created with ❤ and Livemark