small, safe, and great commonmark (optionally gfm, mdx) compliant markdown parser
small, safe, and great commonmark (optionally gfm, mdx) compliant markdown parser
[![Build][build-badge]][build] [![Coverage][coverage-badge]][coverage] [![Downloads][downloads-badge]][downloads] [![Size][bundle-size-badge]][bundle-size] [![Sponsors][sponsors-badge]][opencollective] [![Backers][backers-badge]][opencollective] [![Chat][chat-badge]][chat]
The smallest CommonMark compliant markdown parser. With positional info and concrete tokens.
See [§ Comparison][comparison] for more info
micromark is an open source markdown parser written in JavaScript.
It’s implemented as a state machine that emits concrete tokens, so that every
byte is accounted for, with positional info.
It then compiles those tokens directly to HTML, but other tools can take the
data and for example build an AST which is easier to work with
([mdast-util-to-markdown][mdast-util-to-markdown]).
While most markdown parsers work towards compliancy with CommonMark (or GFM),
this project goes further by following how the reference parsers (cmark,
cmark-gfm) work, which is confirmed with thousands of extra tests.
Other than CommonMark and GFM, micromark also supports common extensions to markdown such as MDX, math, and frontmatter.
These npm packages have a sibling project in Rust:
[markdown-rs][markdown-rs].
unifiedjs.com][site]This package is [ESM only][esm]. In Node.js (version 16+), install with [npm][]:
npm install micromarkIn Deno with [esm.sh][esmsh]:
import {micromark} from 'https://esm.sh/micromark@3'In browsers with [esm.sh][esmsh]:
<script type="module">
import {micromark} from 'https://esm.sh/micromark@3?bundle'
</script>Typical use (buffering):
import {micromark} from 'micromark'
console.log(micromark('## Hello, *world*!'))Yields:
<h2>Hello, <em>world</em>!</h2>You can pass extensions (in this case [micromark-extension-gfm][gfm]):
import {micromark} from 'micromark'
import {gfmHtml, gfm} from 'micromark-extension-gfm'
const value = '* [x] [email protected] ~~strikethrough~~'
const result = micromark(value, {
extensions: [gfm()],
htmlExtensions: [gfmHtml()]
})
console.log(result)Yields:
<ul>
<li><input checked="" disabled="" type="checkbox"> <a href="mailto:[email protected]">[email protected]</a> <del>strikethrough</del></li>
</ul>Streaming interface:
import {createReadStream} from 'node:fs'
import {stream} from 'micromark/stream'
createReadStream('example.md')
.on('error', handleError)
.pipe(stream())
.pipe(process.stdout)
function handleError(error) {
// Handle your error here!
throw error
}See [§ API][api] in the micromark readme.
micromark supports extensions.
There are two types of extensions for micromark:
[SyntaxExtension][syntax-extension],
which change how markdown is parsed, and [HtmlExtension][html-extension],
which change how it compiles.
They can be passed in [options.extensions][api-option-extensions] or
[options.htmlExtensions][api-option-htmlextensions], respectively.
As a user of extensions, refer to each extension’s readme for more on how to use them. As a (potential) author of extensions, refer to [§ Extending markdown][extending-markdown] and [§ Creating a micromark extension][create-extension].
micromark/micromark-extension-directive][directives]
— support directives (generic extensions)micromark/micromark-extension-frontmatter][frontmatter]
— support frontmatter (YAML, TOML, etc)micromark/micromark-extension-gfm][gfm]
— support GFM (GitHub Flavored Markdown)micromark/micromark-extension-gfm-autolink-literal
— support GFM autolink literalsmicromark/micromark-extension-gfm-footnote
— support GFM footnotesmicromark/micromark-extension-gfm-strikethrough
— support GFM strikethroughmicromark/micromark-extension-gfm-table
— support GFM tablesmicromark/micromark-extension-gfm-tagfilter
— support GFM tagfiltermicromark/micromark-extension-gfm-task-list-item
— support GFM tasklistsmicromark/micromark-extension-math][math]
— support mathmicromark/micromark-extension-mdx
— support MDXmicromark/micromark-extension-mdxjs][mdxjs]
— support MDX.jsmicromark/micromark-extension-mdx-expression][mdx-expression]
— support MDX (or MDX.js) expressionsmicromark/micromark-extension-mdx-jsx
— support MDX (or MDX.js) JSXmicromark/micromark-extension-mdx-md
— support misc MDX changesmicromark/micromark-extension-mdxjs-esm
— support MDX.js import/exportswataru-chocola/micromark-extension-definition-list
— support definition listsSyntaxExtensionA syntax extension is an object whose fields are typically the names of hooks, referring to where constructs “hook” into. The fields at such objects are character codes, mapping to constructs as values.
The built in [constructs][] are an example. See it and [existing extensions][extensions] for inspiration.
HtmlExtensionAn HTML extension is an object whose fields are typically enter or exit
(reflecting whether a token is entered or exited).
The values at such objects are names of tokens mapping to handlers.
See [existing extensions][extensions] for inspiration.
micromark lets you change markdown syntax, yes, but there are alternatives. The alternatives are often better.
Over the years, many micromark and remark users have asked about their unique goals for markdown. Some exemplary goals are:
rel="nofollow" to external linksThese can be solved in different ways and which solution is best is both subjective and dependent on unique needs. Often, there is already a solution in the form of an existing remark or rehype plugin. Respectively, their solutions are:
remark-external-linksrehype-autolink-headingsremark-breaksrehype-katex
but integrating abcjsremark-directive][remark-directive]
and a custom plugin or with
rehype-attrremark-directive][remark-directive]
combined with a custom pluginmdx-js/mdx][mdx] or
xdmLooking at these from a higher level, they can be categorized:
Changing the output by transforming syntax trees (1 and 2)
This category is nice as the format remains plain markdown that authors are already familiar with and which will work with existing tools and platforms.
Implementations will deal with the syntax tree
([mdast][mdast]) and the ecosystems
[remark][] and [rehype][].
There are many existing
[utilities for working with that tree][utilities].
Many [remark plugins][remark-plugins] and
[rehype plugins][rehype-plugins] also exist.
Using and abusing markdown to add new meaning (3, 4, potentially 5)
This category is similar to Changing the output by transforming syntax trees, but adds a new meaning to certain things which already have semantics in markdown.
Some examples in pseudocode:
* **A list item with the first paragraph bold**
And then more content, is turned into `<dl>` / `<dt>` / `<dd>` elements
Or, the title attributes on links or images is [overloaded](/url 'rel:nofollow')
with a new meaning.
```csv
fenced,code,can,include,data
which,is,turned,into,a,graph
```
```js data can="be" passed=true
// after the code language name
```
HTML, especially comments, could be used as **markers**Arbitrary extension mechanism (potentially 5; 6)
This category is nice when content should contain embedded “components”. Often this means it’s required for authors to have some programming experience. There are three good ways to solve arbitrary extensions.
HTML: Markdown already has an arbitrary extension syntax. It works in most places and authors are already familiar with the syntax, but it’s reasonably hard to implement securely. Certain platforms will remove HTML completely, others sanitize it to varying degrees. HTML also supports custom elements. These could be used and enhanced by client side JavaScript or enhanced when transforming the syntax tree.
Generic directives: although [a proposal][directive-proposal] and not supported on most platforms, directives do work with many tools already. They’re not the easiest to author compared to, say, a heading, but sometimes that’s okay. They do have potential: they nicely solve the need for an infinite number of potential extensions to markdown in a single
No open issues yet, or sync has not completed.