site/node_modules/mdast-util-to-hast/readme.md
2024-10-14 08:09:33 +02:00

1723 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# mdast-util-to-hast
[![Build][build-badge]][build]
[![Coverage][coverage-badge]][coverage]
[![Downloads][downloads-badge]][downloads]
[![Size][size-badge]][size]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat]
[mdast][] utility to transform to [hast][].
## Contents
* [What is this?](#what-is-this)
* [When should I use this?](#when-should-i-use-this)
* [Install](#install)
* [Use](#use)
* [API](#api)
* [`defaultFootnoteBackContent(referenceIndex, rereferenceIndex)`](#defaultfootnotebackcontentreferenceindex-rereferenceindex)
* [`defaultFootnoteBackLabel(referenceIndex, rereferenceIndex)`](#defaultfootnotebacklabelreferenceindex-rereferenceindex)
* [`defaultHandlers`](#defaulthandlers)
* [`toHast(tree[, options])`](#tohasttree-options)
* [`FootnoteBackContentTemplate`](#footnotebackcontenttemplate)
* [`FootnoteBackLabelTemplate`](#footnotebacklabeltemplate)
* [`Handler`](#handler)
* [`Handlers`](#handlers)
* [`Options`](#options)
* [`Raw`](#raw)
* [`State`](#state)
* [Examples](#examples)
* [Example: supporting HTML in markdown naïvely](#example-supporting-html-in-markdown-naïvely)
* [Example: supporting HTML in markdown properly](#example-supporting-html-in-markdown-properly)
* [Example: footnotes in languages other than English](#example-footnotes-in-languages-other-than-english)
* [Example: supporting custom nodes](#example-supporting-custom-nodes)
* [Algorithm](#algorithm)
* [Default handling](#default-handling)
* [Fields on nodes](#fields-on-nodes)
* [CSS](#css)
* [Syntax tree](#syntax-tree)
* [Nodes](#nodes)
* [Types](#types)
* [Compatibility](#compatibility)
* [Security](#security)
* [Related](#related)
* [Contribute](#contribute)
* [License](#license)
## What is this?
This package is a utility that takes an [mdast][] (markdown) syntax tree as
input and turns it into a [hast][] (HTML) syntax tree.
## When should I use this?
This project is useful when you want to deal with ASTs and turn markdown to
HTML.
The hast utility [`hast-util-to-mdast`][hast-util-to-mdast] does the inverse of
this utility.
It turns HTML into markdown.
The remark plugin [`remark-rehype`][remark-rehype] wraps this utility to also
turn markdown to HTML at a higher-level (easier) abstraction.
## Install
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:
```sh
npm install mdast-util-to-hast
```
In Deno with [`esm.sh`][esmsh]:
```js
import {toHast} from 'https://esm.sh/mdast-util-to-hast@13'
```
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import {toHast} from 'https://esm.sh/mdast-util-to-hast@13?bundle'
</script>
```
## Use
Say we have the following `example.md`:
```markdown
## Hello **World**!
```
…and next to it a module `example.js`:
```js
import {fs} from 'node:fs/promises'
import {toHtml} from 'hast-util-to-html'
import {fromMarkdown} from 'mdast-util-from-markdown'
import {toHast} from 'mdast-util-to-hast'
const markdown = String(await fs.readFile('example.md'))
const mdast = fromMarkdown(markdown)
const hast = toHast(mdast)
const html = toHtml(hast)
console.log(html)
```
…now running `node example.js` yields:
```html
<h2>Hello <strong>World</strong>!</h2>
```
## API
This package exports the identifiers
[`defaultFootnoteBackContent`][api-default-footnote-back-content],
[`defaultFootnoteBackLabel`][api-default-footnote-back-label],
[`defaultHandlers`][api-default-handlers], and
[`toHast`][api-to-hast].
There is no default export.
### `defaultFootnoteBackContent(referenceIndex, rereferenceIndex)`
Generate the default content that GitHub uses on backreferences.
###### Parameters
* `referenceIndex` (`number`)
— index of the definition in the order that they are first referenced,
0-indexed
* `rereferenceIndex` (`number`)
— index of calls to the same definition, 0-indexed
###### Returns
Content (`Array<ElementContent>`).
### `defaultFootnoteBackLabel(referenceIndex, rereferenceIndex)`
Generate the default label that GitHub uses on backreferences.
###### Parameters
* `referenceIndex` (`number`)
— index of the definition in the order that they are first referenced,
0-indexed
* `rereferenceIndex` (`number`)
— index of calls to the same definition, 0-indexed
###### Returns
Label (`string`).
### `defaultHandlers`
Default handlers for nodes ([`Handlers`][api-handlers]).
### `toHast(tree[, options])`
Transform mdast to hast.
###### Parameters
* `tree` ([`MdastNode`][mdast-node])
— mdast tree
* `options` ([`Options`][api-options], optional)
— configuration
###### Returns
hast tree ([`HastNode`][hast-node]).
##### Notes
###### HTML
Raw HTML is available in mdast as [`html`][mdast-html] nodes and can be embedded
in hast as semistandard `raw` nodes.
Most utilities ignore `raw` nodes but two notable ones dont:
* [`hast-util-to-html`][hast-util-to-html] also has an option
`allowDangerousHtml` which will output the raw HTML.
This is typically discouraged as noted by the option name but is useful if
you completely trust authors
* [`hast-util-raw`][hast-util-raw] can handle the raw embedded HTML strings by
parsing them into standard hast nodes (`element`, `text`, etc).
This is a heavy task as it needs a full HTML parser, but it is the only way
to support untrusted content
###### Footnotes
Many options supported here relate to footnotes.
Footnotes are not specified by CommonMark, which we follow by default.
They are supported by GitHub, so footnotes can be enabled in markdown with
[`mdast-util-gfm`][mdast-util-gfm].
The options `footnoteBackLabel` and `footnoteLabel` define natural language
that explains footnotes, which is hidden for sighted users but shown to
assistive technology.
When your page is not in English, you must define translated values.
Back references use ARIA attributes, but the section label itself uses a
heading that is hidden with an `sr-only` class.
To show it to sighted users, define different attributes in
`footnoteLabelProperties`.
###### Clobbering
Footnotes introduces a problem, as it links footnote calls to footnote
definitions on the page through `id` attributes generated from user content,
which results in DOM clobbering.
DOM clobbering is this:
```html
<p id=x></p>
<script>alert(x) // `x` now refers to the DOM `p#x` element</script>
```
Elements by their ID are made available by browsers on the `window` object,
which is a security risk.
Using a prefix solves this problem.
More information on how to handle clobbering and the prefix is explained in
[Example: headings (DOM clobbering) in `rehype-sanitize`][clobber-example].
###### Unknown nodes
Unknown nodes are nodes with a type that isnt in `handlers` or `passThrough`.
The default behavior for unknown nodes is:
* when the node has a `value` (and doesnt have `data.hName`,
`data.hProperties`, or `data.hChildren`, see later), create a hast `text`
node
* otherwise, create a `<div>` element (which could be changed with
`data.hName`), with its children mapped from mdast to hast as well
This behavior can be changed by passing an `unknownHandler`.
### `FootnoteBackContentTemplate`
Generate content for the backreference dynamically.
For the following markdown:
```markdown
Alpha[^micromark], bravo[^micromark], and charlie[^remark].
[^remark]: things about remark
[^micromark]: things about micromark
```
This function will be called with:
* `0` and `0` for the backreference from `things about micromark` to
`alpha`, as it is the first used definition, and the first call to it
* `0` and `1` for the backreference from `things about micromark` to
`bravo`, as it is the first used definition, and the second call to it
* `1` and `0` for the backreference from `things about remark` to
`charlie`, as it is the second used definition
###### Parameters
* `referenceIndex` (`number`)
— index of the definition in the order that they are first referenced,
0-indexed
* `rereferenceIndex` (`number`)
— index of calls to the same definition, 0-indexed
###### Returns
Content for the backreference when linking back from definitions to their
reference (`Array<ElementContent>`, `ElementContent`, or `string`).
### `FootnoteBackLabelTemplate`
Generate a back label dynamically.
For the following markdown:
```markdown
Alpha[^micromark], bravo[^micromark], and charlie[^remark].
[^remark]: things about remark
[^micromark]: things about micromark
```
This function will be called with:
* `0` and `0` for the backreference from `things about micromark` to
`alpha`, as it is the first used definition, and the first call to it
* `0` and `1` for the backreference from `things about micromark` to
`bravo`, as it is the first used definition, and the second call to it
* `1` and `0` for the backreference from `things about remark` to
`charlie`, as it is the second used definition
###### Parameters
* `referenceIndex` (`number`)
— index of the definition in the order that they are first referenced,
0-indexed
* `rereferenceIndex` (`number`)
— index of calls to the same definition, 0-indexed
###### Returns
Back label to use when linking back from definitions to their reference
(`string`).
### `Handler`
Handle a node (TypeScript type).
###### Parameters
* `state` ([`State`][api-state])
— info passed around
* `node` ([`MdastNode`][mdast-node])
— node to handle
* `parent` ([`MdastNode | undefined`][mdast-node])
— parent of `node`
###### Returns
Result ([`Array<HastNode> | HastNode | undefined`][hast-node]).
### `Handlers`
Handle nodes (TypeScript type).
###### Type
```ts
type Handlers = Partial<Record<Nodes['type'], Handler>>
```
### `Options`
Configuration (TypeScript type).
###### Fields
* `allowDangerousHtml` (`boolean`, default: `false`)
— whether to persist raw HTML in markdown in the hast tree
* `clobberPrefix` (`string`, default: `'user-content-'`)
— prefix to use before the `id` property on footnotes to prevent them from
*clobbering*
* `file` ([`VFile`][vfile], optional)
— corresponding virtual file representing the input document
* `footnoteBackContent`
([`FootnoteBackContentTemplate`][api-footnote-back-content-template]
or `string`, default:
[`defaultFootnoteBackContent`][api-default-footnote-back-content])
— content of the backreference back to references
* `footnoteBackLabel`
([`FootnoteBackLabelTemplate`][api-footnote-back-label-template]
or `string`, default:
[`defaultFootnoteBackLabel`][api-default-footnote-back-label])
— label to describe the backreference back to references
* `footnoteLabel` (`string`, default: `'Footnotes'`)
— label to use for the footnotes section (affects screen readers)
* `footnoteLabelProperties`
([`Properties`][properties], default: `{className: ['sr-only']}`)
— properties to use on the footnote label
(note that `id: 'footnote-label'` is always added as footnote calls use it
with `aria-describedby` to provide an accessible label)
* `footnoteLabelTagName` (`string`, default: `h2`)
— tag name to use for the footnote label
* `handlers` ([`Handlers`][api-handlers], optional)
— extra handlers for nodes
* `passThrough` (`Array<Nodes['type']>`, optional)
— list of custom mdast node types to pass through (keep) in hast (note that
the node itself is passed, but eventual children are transformed)
* `unknownHandler` ([`Handler`][api-handler], optional)
— handle all unknown nodes
### `Raw`
Raw string of HTML embedded into HTML AST (TypeScript type).
###### Type
```ts
import type {Data, Literal} from 'hast'
interface Raw extends Literal {
type: 'raw'
data?: RawData | undefined
}
interface RawData extends Data {}
```
### `State`
Info passed around about the current state (TypeScript type).
###### Fields
* `all` (`(node: MdastNode) => Array<HastNode>`)
— transform the children of an mdast parent to hast
* `applyData` (`<Type extends HastNode>(from: MdastNode, to: Type) => Type | HastElement`)
— honor the `data` of `from` and maybe generate an element instead of `to`
* `definitionById` (`Map<string, Definition>`)
— definitions by their uppercased identifier
* `footnoteById` (`Map<string, FootnoteDefinition>`)
— footnote definitions by their uppercased identifier
* `footnoteCounts` (`Map<string, number>`)
— counts for how often the same footnote was called
* `footnoteOrder` (`Array<string>`)
— identifiers of order when footnote calls first appear in tree order
* `handlers` ([`Handlers`][api-handlers])
— applied node handlers
* `one` (`(node: MdastNode, parent: MdastNode | undefined) => HastNode | Array<HastNode> | undefined`)
— transform an mdast node to hast
* `options` ([`Options`][api-options])
— configuration
* `patch` (`(from: MdastNode, to: HastNode) => undefined`)
* `wrap` (`<Type extends HastNode>(nodes: Array<Type>, loose?: boolean) => Array<Type | HastText>`)
— wrap `nodes` with line endings between each node, adds initial/final line
endings when `loose`
## Examples
### Example: supporting HTML in markdown naïvely
If you completely trust authors (or plugins) and want to allow them to HTML *in*
markdown, and the last utility has an `allowDangerousHtml` option as well (such
as `hast-util-to-html`) you can pass `allowDangerousHtml` to this utility
(`mdast-util-to-hast`):
```js
import {fromMarkdown} from 'mdast-util-from-markdown'
import {toHast} from 'mdast-util-to-hast'
import {toHtml} from 'hast-util-to-html'
const markdown = 'It <i>works</i>! <img onerror="alert(1)">'
const mdast = fromMarkdown(markdown)
const hast = toHast(mdast, {allowDangerousHtml: true})
const html = toHtml(hast, {allowDangerousHtml: true})
console.log(html)
```
…now running `node example.js` yields:
```html
<p>It <i>works</i>! <img onerror="alert(1)"></p>
```
> ⚠️ **Danger**: observe that the XSS attack through the `onerror` attribute
> is still present.
### Example: supporting HTML in markdown properly
If you do not trust the authors of the input markdown, or if you want to make
sure that further utilities can see HTML embedded in markdown, use
[`hast-util-raw`][hast-util-raw].
The following example passes `allowDangerousHtml` to this utility
(`mdast-util-to-hast`), then turns the raw embedded HTML into proper HTML nodes
(`hast-util-raw`), and finally sanitizes the HTML by only allowing safe things
(`hast-util-sanitize`):
```js
import {raw} from 'hast-util-raw'
import {sanitize} from 'hast-util-sanitize'
import {toHtml} from 'hast-util-to-html'
import {fromMarkdown} from 'mdast-util-from-markdown'
import {toHast} from 'mdast-util-to-hast'
const markdown = 'It <i>works</i>! <img onerror="alert(1)">'
const mdast = fromMarkdown(markdown)
const hast = raw(toHast(mdast, {allowDangerousHtml: true}))
const safeHast = sanitize(hast)
const html = toHtml(safeHast)
console.log(html)
```
…now running `node example.js` yields:
```html
<p>It <i>works</i>! <img></p>
```
> 👉 **Note**: observe that the XSS attack through the `onerror` attribute
> is no longer present.
### Example: footnotes in languages other than English
If you know that the markdown is authored in a language other than English,
and youre using `micromark-extension-gfm` and `mdast-util-gfm` to match how
GitHub renders markdown, and you know that footnotes are (or can?) be used, you
should translate the labels associated with them.
Lets first set the stage:
```js
import {toHtml} from 'hast-util-to-html'
import {gfm} from 'micromark-extension-gfm'
import {fromMarkdown} from 'mdast-util-from-markdown'
import {gfmFromMarkdown} from 'mdast-util-gfm'
import {toHast} from 'mdast-util-to-hast'
const markdown = 'Bonjour[^1]\n\n[^1]: Monde!'
const mdast = fromMarkdown(markdown, {
extensions: [gfm()],
mdastExtensions: [gfmFromMarkdown()]
})
const hast = toHast(mdast)
const html = toHtml(hast)
console.log(html)
```
…now running `node example.js` yields:
```html
<p>Bonjour<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p>
<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a></p>
</li>
</ol>
</section>
```
This is a mix of English and French that screen readers cant handle nicely.
Lets say our program does know that the markdown is in French.
In that case, its important to translate and define the labels relating to
footnotes so that screen reader users can properly pronounce the page:
```diff
@@ -9,7 +9,16 @@ const mdast = fromMarkdown(markdown, {
extensions: [gfm()],
mdastExtensions: [gfmFromMarkdown()]
})
-const hast = toHast(mdast)
+const hast = toHast(mdast, {
+ footnoteLabel: 'Notes de bas de page',
+ footnoteBackLabel(referenceIndex, rereferenceIndex) {
+ return (
+ 'Retour à la référence ' +
+ (referenceIndex + 1) +
+ (rereferenceIndex > 1 ? '-' + rereferenceIndex : '')
+ )
+ }
+})
const html = toHtml(hast)
console.log(html)
```
…now running `node example.js` with the above patch applied yields:
```diff
@@ -1,8 +1,8 @@
<p>Bonjour<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p>
-<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
+<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Notes de bas de page</h2>
<ol>
<li id="user-content-fn-1">
-<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
+<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Retour à la référence 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>
```
### Example: supporting custom nodes
This project supports CommonMark and the GFM constructs (footnotes,
strikethrough, tables) and the frontmatter constructs YAML and TOML.
Support can be extended to other constructs in two ways: a) with handlers, b)
through fields on nodes.
For example, when we represent a mark element in markdown and want to turn it
into a `<mark>` element in HTML, we can use a handler:
```js
import {toHtml} from 'hast-util-to-html'
import {toHast} from 'mdast-util-to-hast'
const mdast = {
type: 'paragraph',
children: [{type: 'mark', children: [{type: 'text', value: 'x'}]}]
}
const hast = toHast(mdast, {
handlers: {
mark(state, node) {
return {
type: 'element',
tagName: 'mark',
properties: {},
children: state.all(node)
}
}
}
})
console.log(toHtml(hast))
```
We can do the same through certain fields on nodes:
```js
import {toHtml} from 'hast-util-to-html'
import {toHast} from 'mdast-util-to-hast'
const mdast = {
type: 'paragraph',
children: [
{
type: 'mark',
children: [{type: 'text', value: 'x'}],
data: {hName: 'mark'}
}
]
}
console.log(toHtml(toHast(mdast)))
```
## Algorithm
This project by default handles CommonMark, GFM (footnotes, strikethrough,
tables) and common frontmatter (YAML, TOML).
Existing handlers can be overwritten and handlers for more nodes can be added.
Its also possible to define how mdast is turned into hast through fields on
nodes.
### Default handling
The following table gives insight into what input turns into what output:
<table>
<thead>
<tr>
<th scope="col">mdast node</th>
<th scope="col">markdown example</th>
<th scope="col">hast node</th>
<th scope="col">html example</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
[`blockquote`](https://github.com/syntax-tree/mdast#blockquote)
</th>
<td>
```markdown
> A greater than…
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`blockquote`)
</td>
<td>
```html
<blockquote>
<p>A greater than…</p>
</blockquote>
```
</td>
</tr>
<tr>
<th scope="row">
[`break`](https://github.com/syntax-tree/mdast#break)
</th>
<td>
```markdown
A backslash\
before a line break…
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`br`)
</td>
<td>
```html
<p>A backslash<br>
before a line break…</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`code`](https://github.com/syntax-tree/mdast#code)
</th>
<td>
````markdown
```js
backtick.fences('for blocks')
```
````
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`pre` and `code`)
</td>
<td>
```html
<pre><code className="language-js">backtick.fences('for blocks')
</code></pre>
```
</td>
</tr>
<tr>
<th scope="row">
[`delete`](https://github.com/syntax-tree/mdast#delete) (GFM)
</th>
<td>
```markdown
Two ~~tildes~~ for delete.
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`del`)
</td>
<td>
```html
<p>Two <del>tildes</del> for delete.</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`emphasis`](https://github.com/syntax-tree/mdast#emphasis)
</th>
<td>
```markdown
Some *asterisks* for emphasis.
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`em`)
</td>
<td>
```html
<p>Some <em>asterisks</em> for emphasis.</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`footnoteReference`](https://github.com/syntax-tree/mdast#footnotereference),
[`footnoteDefinition`](https://github.com/syntax-tree/mdast#footnotedefinition)
(GFM)
</th>
<td>
```markdown
With a [^caret].
[^caret]: Stuff
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`section`, `sup`, `a`)
</td>
<td>
```html
<p>With a <sup><a href="#fn-caret" >1</a></sup>.</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`heading`](https://github.com/syntax-tree/mdast#heading)
</th>
<td>
```markdown
# One number sign…
###### Six number signs…
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`h1`…`h6`)
</td>
<td>
```html
<h1>One number sign…</h1>
<h6>Six number signs…</h6>
```
</td>
</tr>
<tr>
<th scope="row">
[`html`](https://github.com/syntax-tree/mdast#html)
</th>
<td>
```html
<kbd>CMD+S</kbd>
```
</td>
<td>
Nothing (default), `raw` (when `allowDangerousHtml: true`)
</td>
<td>
n/a
</td>
</tr>
<tr>
<th scope="row">
[`image`](https://github.com/syntax-tree/mdast#image)
</th>
<td>
```markdown
![Alt text](/logo.png "title")
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`img`)
</td>
<td>
```html
<p><img src="/logo.png" alt="Alt text" title="title"></p>
```
</td>
</tr>
<tr>
<th scope="row">
[`imageReference`](https://github.com/syntax-tree/mdast#imagereference),
[`definition`](https://github.com/syntax-tree/mdast#definition)
</th>
<td>
```markdown
![Alt text][logo]
[logo]: /logo.png "title"
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`img`)
</td>
<td>
```html
<p><img src="/logo.png" alt="Alt text" title="title"></p>
```
</td>
</tr>
<tr>
<th scope="row">
[`inlineCode`](https://github.com/syntax-tree/mdast#inlinecode)
</th>
<td>
```markdown
Some `backticks` for inline code.
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`code`)
</td>
<td>
```html
<p>Some <code>backticks</code> for inline code.</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`link`](https://github.com/syntax-tree/mdast#link)
</th>
<td>
```markdown
[Example](https://example.com "title")
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`a`)
</td>
<td>
```html
<p><a href="https://example.com" title="title">Example</a></p>
```
</td>
</tr>
<tr>
<th scope="row">
[`linkReference`](https://github.com/syntax-tree/mdast#linkreference),
[`definition`](https://github.com/syntax-tree/mdast#definition)
</th>
<td>
```markdown
[Example][]
[example]: https://example.com "title"
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`a`)
</td>
<td>
```html
<p><a href="https://example.com" title="title">Example</a></p>
```
</td>
</tr>
<tr>
<th scope="row">
[`list`](https://github.com/syntax-tree/mdast#list),
[`listItem`](https://github.com/syntax-tree/mdast#listitem)
</th>
<td>
```markdown
* asterisks for unordered items
1. decimals and a dot for ordered items
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`li` and `ol` or `ul`)
</td>
<td>
```html
<ul>
<li>asterisks for unordered items</li>
</ul>
<ol>
<li>decimals and a dot for ordered items</li>
</ol>
```
</td>
</tr>
<tr>
<th scope="row">
[`paragraph`](https://github.com/syntax-tree/mdast#paragraph)
</th>
<td>
```markdown
Just some text…
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`p`)
</td>
<td>
```html
<p>Just some text…</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`root`](https://github.com/syntax-tree/mdast#root)
</th>
<td>
```markdown
Anything!
```
</td>
<td>
[`root`](https://github.com/syntax-tree/hast#root)
</td>
<td>
```html
<p>Anything!</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`strong`](https://github.com/syntax-tree/mdast#strong)
</th>
<td>
```markdown
Two **asterisks** for strong.
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`strong`)
</td>
<td>
```html
<p>Two <strong>asterisks</strong> for strong.</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`text`](https://github.com/syntax-tree/mdast#text)
</th>
<td>
```markdown
Anything!
```
</td>
<td>
[`text`](https://github.com/syntax-tree/hast#text)
</td>
<td>
```html
<p>Anything!</p>
```
</td>
</tr>
<tr>
<th scope="row">
[`table`](https://github.com/syntax-tree/mdast#table),
[`tableRow`](https://github.com/syntax-tree/mdast#tablerow),
[`tableCell`](https://github.com/syntax-tree/mdast#tablecell)
</th>
<td>
```markdown
| Pipes |
| ----- |
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`table`, `thead`, `tbody`, `tr`, `td`, `th`)
</td>
<td>
```html
<table>
<thead>
<tr>
<th>Pipes</th>
</tr>
</thead>
</table>
```
</td>
</tr>
<tr>
<th scope="row">
[`thematicBreak`](https://github.com/syntax-tree/mdast#thematicbreak)
</th>
<td>
```markdown
Three asterisks for a thematic break:
***
```
</td>
<td>
[`element`](https://github.com/syntax-tree/hast#element) (`hr`)
</td>
<td>
```html
<p>Three asterisks for a thematic break:</p>
<hr>
```
</td>
</tr>
<tr>
<th scope="row">
`toml` (frontmatter)
</th>
<td>
```markdown
+++
fenced = true
+++
```
</td>
<td>
Nothing
</td>
<td>
n/a
</td>
</tr>
<tr>
<th scope="row">
[`yaml`](https://github.com/syntax-tree/mdast#yaml) (frontmatter)
</th>
<td>
```markdown
---
fenced: yes
---
```
</td>
<td>
Nothing
</td>
<td>
n/a
</td>
</tr>
</tbody>
</table>
> 👉 **Note**: GFM prescribes that the obsolete `align` attribute on `td` and
> `th` elements is used.
> To use `style` attributes instead of obsolete features, combine this utility
> with [`@mapbox/hast-util-table-cell-style`][hast-util-table-cell-style].
> 🧑‍🏫 **Info**: this project is concerned with turning one syntax tree into
> another.
> It does not deal with markdown syntax or HTML syntax.
> The preceding examples are illustrative rather than authoritative or
> exhaustive.
### Fields on nodes
A frequent problem arises when having to turn one syntax tree into another.
As the original tree (in this case, mdast for markdown) is in some cases
limited compared to the destination (in this case, hast for HTML) tree,
is it possible to provide more info in the original to define what the
result will be in the destination?
This is possible by defining data on mdast nodes, which this utility will read
as instructions on what hast nodes to create.
An example is math, which is a nonstandard markdown extension, that this utility
doesnt understand.
To solve this, `mdast-util-math` defines instructions on mdast nodes that this
plugin does understand because they define a certain hast structure.
The following fields can be used:
* `node.data.hName` — define the elements tag name
* `node.data.hProperties` — define extra properties to use
* `node.data.hChildren` — define hast children to use
###### `hName`
`node.data.hName` sets the tag name of an element.
The following [mdast][]:
```js
{
type: 'strong',
data: {hName: 'b'},
children: [{type: 'text', value: 'Alpha'}]
}
```
…yields ([hast][]):
```js
{
type: 'element',
tagName: 'b',
properties: {},
children: [{type: 'text', value: 'Alpha'}]
}
```
###### `hProperties`
`node.data.hProperties` sets the properties of an element.
The following [mdast][]:
```js
{
type: 'image',
src: 'circle.svg',
alt: 'Big red circle on a black background',
data: {hProperties: {className: ['responsive']}}
}
```
…yields ([hast][]):
```js
{
type: 'element',
tagName: 'img',
properties: {
src: 'circle.svg',
alt: 'Big red circle on a black background',
className: ['responsive']
},
children: []
}
```
###### `hChildren`
`node.data.hChildren` sets the children of an element.
The following [mdast][]:
```js
{
type: 'code',
lang: 'js',
data: {
hChildren: [
{
type: 'element',
tagName: 'span',
properties: {className: ['hljs-meta']},
children: [{type: 'text', value: '"use strict"'}]
},
{type: 'text', value: ';'}
]
},
value: '"use strict";'
}
```
…yields ([hast][]):
```js
{
type: 'element',
tagName: 'pre',
properties: {},
children: [{
type: 'element',
tagName: 'code',
properties: {className: ['language-js']},
children: [
{
type: 'element',
tagName: 'span',
properties: {className: ['hljs-meta']},
children: [{type: 'text', value: '"use strict"'}]
},
{type: 'text', value: ';'}
]
}]
}
```
> 👉 **Note**: the `pre` and `language-js` class are normal `mdast-util-to-hast`
> functionality.
## CSS
Assuming you know how to use (semantic) HTML and CSS, then it should generally
be straightforward to style the HTML produced by this plugin.
With CSS, you can get creative and style the results as you please.
Some semistandard features, notably GFMs tasklists and footnotes, generate HTML
that be unintuitive, as it matches exactly what GitHub produces for their
website.
There is a project, [`sindresorhus/github-markdown-css`][github-markdown-css],
that exposes the stylesheet that GitHub uses for rendered markdown, which might
either be inspirational for more complex features, or can be used as-is to
exactly match how GitHub styles rendered markdown.
The following CSS is needed to make footnotes look a bit like GitHub:
```css
/* Style the footnotes section. */
.footnotes {
font-size: smaller;
color: #8b949e;
border-top: 1px solid #30363d;
}
/* Hide the section label for visual users. */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
word-wrap: normal;
border: 0;
}
/* Place `[` and `]` around footnote calls. */
[data-footnote-ref]::before {
content: '[';
}
[data-footnote-ref]::after {
content: ']';
}
```
## Syntax tree
The following interfaces are added to **[hast][]** by this utility.
### Nodes
#### `Raw`
```idl
interface Raw <: Literal {
type: 'raw'
}
```
**Raw** (**[Literal][dfn-literal]**) represents a string if raw HTML inside
hast.
Raw nodes are typically ignored but are handled by
[`hast-util-to-html`][hast-util-to-html] and [`hast-util-raw`][hast-util-raw].
## Types
This package is fully typed with [TypeScript][].
It exports the
[`FootnoteBackContentTemplate`][api-footnote-back-content-template],
[`FootnoteBackLabelTemplate`][api-footnote-back-label-template],
[`Handler`][api-handler],
[`Handlers`][api-handlers],
[`Options`][api-options],
[`Raw`][api-raw], and
[`State`][api-state] types.
It also registers the `Raw` node type with `@types/hast`.
If youre working with the syntax tree (and you pass
`allowDangerousHtml: true`), make sure to import this utility somewhere in your
types, as that registers the new node type in the tree.
```js
/**
* @typedef {import('mdast-util-to-hast')}
*/
import {visit} from 'unist-util-visit'
/** @type {import('hast').Root} */
const tree = { /* … */ }
visit(tree, function (node) {
// `node` can now be `raw`.
})
```
Finally, it also registers the `hChildren`, `hName`, and `hProperties` fields
on `Data` of `@types/mdast`.
If youre working with the syntax tree, make sure to import this utility
somewhere in your types, as that registers the data fields in the tree.
```js
/**
* @typedef {import('mdast-util-to-hast')}
*/
import {visit} from 'unist-util-visit'
/** @type {import('hast').Root} */
const tree = { /* … */ }
console.log(tree.data?.hName) // Types as `string | undefined`.
```
## Compatibility
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
When we cut a new major release, we drop support for unmaintained versions of
Node.
This means we try to keep the current release line, `mdast-util-to-hast@^13`,
compatible with Node.js 16.
## Security
Use of `mdast-util-to-hast` can open you up to a
[cross-site scripting (XSS)][xss] attack.
Embedded hast properties (`hName`, `hProperties`, `hChildren`), custom handlers,
and the `allowDangerousHtml` option all provide openings.
The following example shows how a script is injected where a benign code block
is expected with embedded hast properties:
```js
const code = {type: 'code', value: 'alert(1)'}
code.data = {hName: 'script'}
```
Yields:
```html
<script>alert(1)</script>
```
The following example shows how an image is changed to fail loading and
therefore run code in a browser.
```js
const image = {type: 'image', url: 'existing.png'}
image.data = {hProperties: {src: 'missing', onError: 'alert(2)'}}
```
Yields:
```html
<img src="missing" onerror="alert(2)">
```
The following example shows the default handling of embedded HTML:
```markdown
# Hello
<script>alert(3)</script>
```
Yields:
```html
<h1>Hello</h1>
```
Passing `allowDangerousHtml: true` to `mdast-util-to-hast` is typically still
not enough to run unsafe code:
```html
<h1>Hello</h1>
&#x3C;script>alert(3)&#x3C;/script>
```
If `allowDangerousHtml: true` is also given to `hast-util-to-html` (or
`rehype-stringify`), the unsafe code runs:
```html
<h1>Hello</h1>
<script>alert(3)</script>
```
Use [`hast-util-sanitize`][hast-util-sanitize] to make the hast tree safe.
## Related
* [`hast-util-to-mdast`](https://github.com/syntax-tree/hast-util-to-mdast)
— transform hast to mdast
* [`hast-util-to-xast`](https://github.com/syntax-tree/hast-util-to-xast)
— transform hast to xast
* [`hast-util-sanitize`](https://github.com/syntax-tree/hast-util-sanitize)
— sanitize hast nodes
## Contribute
See [`contributing.md` in `syntax-tree/.github`][contributing] for ways to get
started.
See [`support.md`][support] for ways to get help.
This project has a [code of conduct][coc].
By interacting with this repository, organization, or community you agree to
abide by its terms.
## License
[MIT][license] © [Titus Wormer][author]
<!-- Definitions -->
[build-badge]: https://github.com/syntax-tree/mdast-util-to-hast/workflows/main/badge.svg
[build]: https://github.com/syntax-tree/mdast-util-to-hast/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/syntax-tree/mdast-util-to-hast.svg
[coverage]: https://codecov.io/github/syntax-tree/mdast-util-to-hast
[downloads-badge]: https://img.shields.io/npm/dm/mdast-util-to-hast.svg
[downloads]: https://www.npmjs.com/package/mdast-util-to-hast
[size-badge]: https://img.shields.io/badge/dynamic/json?label=minzipped%20size&query=$.size.compressedSize&url=https://deno.bundlejs.com/?q=mdast-util-to-hast
[size]: https://bundlejs.com/?q=mdast-util-to-hast
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
[collective]: https://opencollective.com/unified
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
[chat]: https://github.com/syntax-tree/unist/discussions
[npm]: https://docs.npmjs.com/cli/install
[license]: license
[author]: https://wooorm.com
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[typescript]: https://www.typescriptlang.org
[contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md
[support]: https://github.com/syntax-tree/.github/blob/main/support.md
[coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md
[mdast]: https://github.com/syntax-tree/mdast
[mdast-node]: https://github.com/syntax-tree/mdast#nodes
[mdast-html]: https://github.com/syntax-tree/mdast#html
[mdast-util-gfm]: https://github.com/syntax-tree/mdast-util-gfm
[hast]: https://github.com/syntax-tree/hast
[hast-node]: https://github.com/syntax-tree/hast#nodes
[properties]: https://github.com/syntax-tree/hast#properties
[hast-util-table-cell-style]: https://github.com/mapbox/hast-util-table-cell-style
[hast-util-to-mdast]: https://github.com/syntax-tree/hast-util-to-mdast
[hast-util-to-html]: https://github.com/syntax-tree/hast-util-to-html
[hast-util-raw]: https://github.com/syntax-tree/hast-util-raw
[hast-util-sanitize]: https://github.com/syntax-tree/hast-util-sanitize
[remark-rehype]: https://github.com/remarkjs/remark-rehype
[vfile]: https://github.com/vfile/vfile
[clobber-example]: https://github.com/rehypejs/rehype-sanitize#example-headings-dom-clobbering
[github-markdown-css]: https://github.com/sindresorhus/github-markdown-css
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
[dfn-literal]: https://github.com/syntax-tree/hast#literal
[api-default-footnote-back-content]: #defaultfootnotebackcontentreferenceindex-rereferenceindex
[api-default-footnote-back-label]: #defaultfootnotebacklabelreferenceindex-rereferenceindex
[api-default-handlers]: #defaulthandlers
[api-footnote-back-content-template]: #footnotebackcontenttemplate
[api-footnote-back-label-template]: #footnotebacklabeltemplate
[api-handler]: #handler
[api-handlers]: #handlers
[api-options]: #options
[api-raw]: #raw
[api-state]: #state
[api-to-hast]: #tohasttree-options