1450 lines
40 KiB
Markdown
1450 lines
40 KiB
Markdown
# [![unified][logo]][site]
|
||
|
||
[![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]
|
||
|
||
**unified** is an interface for processing text using syntax trees.
|
||
It’s what powers [**remark**][remark] (Markdown), [**retext**][retext] (natural
|
||
language), and [**rehype**][rehype] (HTML), and allows for processing between
|
||
formats.
|
||
|
||
## Intro
|
||
|
||
**unified** enables new exciting projects like [Gatsby][] to pull in Markdown,
|
||
[MDX][] to embed [JSX][], and [Prettier][] to format it.
|
||
It’s used in about 700k projects on GitHub and has about 35m downloads each
|
||
month on npm: you’re probably using it.
|
||
Some notable users are [Node.js][], [Vercel][], [Netlify][], [GitHub][],
|
||
[Mozilla][], [WordPress][], [Adobe][], [Facebook][], [Google][], and many more.
|
||
|
||
* To read about what we are up to, follow us [Twitter][]
|
||
* For a less technical and more practical introduction to unified, visit
|
||
[`unifiedjs.com`][site] and peruse its [Learn][] section
|
||
* Browse [awesome unified][awesome] to find out more about the ecosystem
|
||
* Questions?
|
||
Get help on [Discussions][chat]!
|
||
* Check out [Contribute][] below to find out how to help out, or become a
|
||
backer or sponsor on [OpenCollective][collective]
|
||
|
||
## Sponsors
|
||
|
||
Support this effort and give back by sponsoring on [OpenCollective][collective]!
|
||
|
||
<!--lint ignore no-html-->
|
||
|
||
<table>
|
||
<tr valign="middle">
|
||
<td width="20%" align="center" rowspan="2" colspan="2">
|
||
<a href="https://vercel.com">Vercel</a><br><br>
|
||
<a href="https://vercel.com"><img src="https://avatars1.githubusercontent.com/u/14985020?s=256&v=4" width="128"></a>
|
||
</td>
|
||
<td width="20%" align="center" rowspan="2" colspan="2">
|
||
<a href="https://motif.land">Motif</a><br><br>
|
||
<a href="https://motif.land"><img src="https://avatars1.githubusercontent.com/u/74457950?s=256&v=4" width="128"></a>
|
||
</td>
|
||
<td width="20%" align="center" rowspan="2" colspan="2">
|
||
<a href="https://www.hashicorp.com">HashiCorp</a><br><br>
|
||
<a href="https://www.hashicorp.com"><img src="https://avatars1.githubusercontent.com/u/761456?s=256&v=4" width="128"></a>
|
||
</td>
|
||
<td width="20%" align="center" rowspan="2" colspan="2">
|
||
<a href="https://americanexpress.io">American Express</a><br><br>
|
||
<a href="https://americanexpress.io"><img src="https://avatars1.githubusercontent.com/u/3853301?s=256&v=4" width="128"></a>
|
||
</td>
|
||
<td width="20%" align="center" rowspan="2" colspan="2">
|
||
<a href="https://www.gitbook.com">GitBook</a><br><br>
|
||
<a href="https://www.gitbook.com"><img src="https://avatars1.githubusercontent.com/u/7111340?s=256&v=4" width="128"></a>
|
||
</td>
|
||
</tr>
|
||
<tr valign="middle">
|
||
</tr>
|
||
<tr valign="middle">
|
||
<td width="20%" align="center" rowspan="2" colspan="2">
|
||
<a href="https://www.gatsbyjs.org">Gatsby</a><br><br>
|
||
<a href="https://www.gatsbyjs.org"><img src="https://avatars1.githubusercontent.com/u/12551863?s=256&v=4" width="128"></a>
|
||
</td>
|
||
<td width="20%" align="center" rowspan="2" colspan="2">
|
||
<a href="https://www.netlify.com">Netlify</a><br><br>
|
||
<!--OC has a sharper image-->
|
||
<a href="https://www.netlify.com"><img src="https://images.opencollective.com/netlify/4087de2/logo/256.png" width="128"></a>
|
||
</td>
|
||
<td width="10%" align="center">
|
||
<a href="https://www.coinbase.com">Coinbase</a><br><br>
|
||
<a href="https://www.coinbase.com"><img src="https://avatars1.githubusercontent.com/u/1885080?s=256&v=4" width="64"></a>
|
||
</td>
|
||
<td width="10%" align="center">
|
||
<a href="https://themeisle.com">ThemeIsle</a><br><br>
|
||
<a href="https://themeisle.com"><img src="https://avatars1.githubusercontent.com/u/58979018?s=128&v=4" width="64"></a>
|
||
</td>
|
||
<td width="10%" align="center">
|
||
<a href="https://expo.io">Expo</a><br><br>
|
||
<a href="https://expo.io"><img src="https://avatars1.githubusercontent.com/u/12504344?s=128&v=4" width="64"></a>
|
||
</td>
|
||
<td width="10%" align="center">
|
||
<a href="https://boostnote.io">Boost Note</a><br><br>
|
||
<a href="https://boostnote.io"><img src="https://images.opencollective.com/boosthub/6318083/logo/128.png" width="64"></a>
|
||
</td>
|
||
<td width="10%" align="center">
|
||
<a href="https://www.holloway.com">Holloway</a><br><br>
|
||
<a href="https://www.holloway.com"><img src="https://avatars1.githubusercontent.com/u/35904294?s=128&v=4" width="64"></a>
|
||
</td>
|
||
<td width="10%"></td>
|
||
</tr>
|
||
<tr valign="middle">
|
||
<td width="100%" align="center" colspan="6">
|
||
<br>
|
||
<a href="https://opencollective.com/unified"><strong>You?</strong></a>
|
||
<br><br>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
## Install
|
||
|
||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c):
|
||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d.
|
||
|
||
[npm][]:
|
||
|
||
```sh
|
||
npm install unified
|
||
```
|
||
|
||
## Use
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'remark-parse'
|
||
import remarkRehype from 'remark-rehype'
|
||
import rehypeDocument from 'rehype-document'
|
||
import rehypeFormat from 'rehype-format'
|
||
import rehypeStringify from 'rehype-stringify'
|
||
import {reporter} from 'vfile-reporter'
|
||
|
||
unified()
|
||
.use(remarkParse)
|
||
.use(remarkRehype)
|
||
.use(rehypeDocument, {title: '👋🌍'})
|
||
.use(rehypeFormat)
|
||
.use(rehypeStringify)
|
||
.process('# Hello world!')
|
||
.then(
|
||
(file) => {
|
||
console.error(reporter(file))
|
||
console.log(String(file))
|
||
},
|
||
(error) => {
|
||
// Handle your error here!
|
||
throw error
|
||
}
|
||
)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```txt
|
||
no issues found
|
||
```
|
||
|
||
```html
|
||
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>👋🌍</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
</head>
|
||
<body>
|
||
<h1>Hello world!</h1>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
## Contents
|
||
|
||
* [Description](#description)
|
||
* [API](#api)
|
||
* [`processor()`](#processor)
|
||
* [`processor.use(plugin[, options])`](#processoruseplugin-options)
|
||
* [`processor.parse(file)`](#processorparsefile)
|
||
* [`processor.stringify(node[, file])`](#processorstringifynode-file)
|
||
* [`processor.run(node[, file][, done])`](#processorrunnode-file-done)
|
||
* [`processor.runSync(node[, file])`](#processorrunsyncnode-file)
|
||
* [`processor.process(file[, done])`](#processorprocessfile-done)
|
||
* [`processor.processSync(file|value)`](#processorprocesssyncfilevalue)
|
||
* [`processor.data([key[, value]])`](#processordatakey-value)
|
||
* [`processor.freeze()`](#processorfreeze)
|
||
* [`Plugin`](#plugin)
|
||
* [`function attacher([options])`](#function-attacheroptions)
|
||
* [`function transformer(node, file[, next])`](#function-transformernode-file-next)
|
||
* [`Preset`](#preset)
|
||
* [Contribute](#contribute)
|
||
* [Acknowledgments](#acknowledgments)
|
||
* [License](#license)
|
||
|
||
## Description
|
||
|
||
**unified** is an interface for processing text using syntax trees.
|
||
Syntax trees are a representation of text understandable to programs.
|
||
Those programs, called [*plugin*][plugin]s, take these trees and inspect and
|
||
modify them.
|
||
To get to the syntax tree from text, there is a [*parser*][parser].
|
||
To get from that back to text, there is a [*compiler*][compiler].
|
||
This is the [*process*][process] of a *processor*.
|
||
|
||
```ascii
|
||
| ........................ process ........................... |
|
||
| .......... parse ... | ... run ... | ... stringify ..........|
|
||
|
||
+--------+ +----------+
|
||
Input ->- | Parser | ->- Syntax Tree ->- | Compiler | ->- Output
|
||
+--------+ | +----------+
|
||
X
|
||
|
|
||
+--------------+
|
||
| Transformers |
|
||
+--------------+
|
||
```
|
||
|
||
###### Processors
|
||
|
||
Every **processor** implements another processor.
|
||
To create a processor, call another processor.
|
||
The new processor is configured to work the same as its ancestor.
|
||
But when the descendant processor is configured in the future it does not affect
|
||
the ancestral processor.
|
||
|
||
When processors are exposed from a module (for example, `unified` itself) they
|
||
should not be configured directly, as that would change their behavior for all
|
||
module users.
|
||
Those processors are [*frozen*][freeze] and they should be called to create a
|
||
new processor before they are used.
|
||
|
||
###### Syntax trees
|
||
|
||
The **syntax trees** used in **unified** are [**unist**][unist] nodes.
|
||
A [**node**][node] is a plain JavaScript objects with a `type` field.
|
||
The semantics of nodes and format of syntax trees is defined by other projects.
|
||
|
||
There are several [*utilities*][unist-utilities] for working with nodes.
|
||
|
||
* [**esast**][esast] — JS
|
||
* [**hast**][hast] — HTML
|
||
* [**mdast**][mdast] — Markdown
|
||
* [**nlcst**][nlcst] — Natural language
|
||
* [**xast**][xast] — XML
|
||
|
||
###### List of processors
|
||
|
||
The following projects process different [*syntax tree*][syntax-tree] formats.
|
||
They parse text to a syntax tree and compile that back to text.
|
||
These processors can be used as is, or their parser and compiler can be mixed
|
||
and matched with **unified** and plugins to process between different syntaxes.
|
||
|
||
* [**rehype**][rehype] ([*hast*][hast]) — HTML
|
||
* [**remark**][remark] ([*mdast*][mdast]) — Markdown
|
||
* [**retext**][retext] ([*nlcst*][nlcst]) — Natural language
|
||
|
||
###### List of plugins
|
||
|
||
The below [**plugins**][plugin] work with **unified**, on all [*syntax
|
||
tree*][syntax-tree] formats:
|
||
|
||
* [`unified-diff`](https://github.com/unifiedjs/unified-diff)
|
||
— Ignore messages for unchanged lines in Travis
|
||
* [`unified-message-control`](https://github.com/unifiedjs/unified-message-control)
|
||
— Enable, disable, and ignore messages
|
||
|
||
See [**remark**][remark-plugins], [**rehype**][rehype-plugins], and
|
||
[**retext**][retext-plugins] for their lists of plugins.
|
||
|
||
###### File
|
||
|
||
When processing a document, **metadata** is often gathered about that document.
|
||
[**vfile**][vfile] is a virtual file format that stores data, metadata, and
|
||
messages about files for **unified** and its plugins.
|
||
|
||
There are several [*utilities*][vfile-utilities] for working with these files.
|
||
|
||
###### Configuration
|
||
|
||
[*Processors*][processors] are configured with [*plugin*][plugin]s or
|
||
with the [`data`][data] method.
|
||
|
||
###### Integrations
|
||
|
||
**unified** can integrate with the file system with [`unified-engine`][engine].
|
||
CLI apps can be created with [`unified-args`][args], Gulp plugins with
|
||
[`unified-engine-gulp`][gulp], and Atom Linters with
|
||
[`unified-engine-atom`][atom].
|
||
|
||
[`unified-stream`][stream] provides a streaming interface.
|
||
|
||
###### Programming interface
|
||
|
||
The API provided by **unified** allows multiple files to be processed and gives
|
||
access to *metadata* (such as lint messages):
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'remark-parse'
|
||
import remarkPresetLintMarkdownStyleGuide from 'remark-preset-lint-markdown-style-guide'
|
||
import remarkRetext from 'remark-retext'
|
||
import retextEnglish from 'retext-english'
|
||
import retextEquality from 'retext-equality'
|
||
import remarkRehype from 'remark-rehype'
|
||
import rehypeStringify from 'rehype-stringify'
|
||
import {reporter} from 'vfile-reporter'
|
||
|
||
unified()
|
||
.use(remarkParse)
|
||
.use(remarkPresetLintMarkdownStyleGuide)
|
||
.use(remarkRetext, unified().use(retextEnglish).use(retextEquality))
|
||
.use(remarkRehype)
|
||
.use(rehypeStringify)
|
||
.process('*Emphasis* and _stress_, you guys!')
|
||
.then(
|
||
(file) => {
|
||
console.error(reporter(file))
|
||
console.log(String(file))
|
||
},
|
||
(error) => {
|
||
// Handle your error here!
|
||
throw error
|
||
}
|
||
)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```txt
|
||
1:16-1:24 warning Emphasis should use `*` as a marker emphasis-marker remark-lint
|
||
1:30-1:34 warning `guys` may be insensitive, use `people`, `persons`, `folks` instead gals-man retext-equality
|
||
|
||
⚠ 2 warnings
|
||
```
|
||
|
||
```html
|
||
<p><em>Emphasis</em> and <em>stress</em>, you guys!</p>
|
||
```
|
||
|
||
###### Processing between syntaxes
|
||
|
||
[*Processors*][processors] can be combined in two modes.
|
||
|
||
**Bridge** mode transforms the [*syntax tree*][syntax-tree] from one format
|
||
(*origin*) to another (*destination*).
|
||
Another processor runs on the destination tree.
|
||
Finally, the original processor continues transforming the origin tree.
|
||
|
||
**Mutate** mode also transforms the syntax tree from one format to another.
|
||
But the original processor continues transforming the destination tree.
|
||
|
||
In the previous example (“Programming interface”), `remark-retext` is used in
|
||
*bridge* mode: the origin syntax tree is kept after [**retext**][retext] is
|
||
done; whereas `remark-rehype` is used in *mutate* mode: it sets a new syntax
|
||
tree and discards the origin tree.
|
||
|
||
* [`remark-retext`][remark-retext]
|
||
* [`remark-rehype`][remark-rehype]
|
||
* [`rehype-retext`][rehype-retext]
|
||
* [`rehype-remark`][rehype-remark]
|
||
|
||
## API
|
||
|
||
This package exports the following identifiers: `unified`.
|
||
There is no default export.
|
||
|
||
### `processor()`
|
||
|
||
[*Processor*][processors] describing how to *process* text.
|
||
|
||
###### Returns
|
||
|
||
`Function` — New [*unfrozen*][freeze] processor that is configured to work the
|
||
same as its ancestor.
|
||
When the descendant processor is configured in the future it does not affect the
|
||
ancestral processor.
|
||
|
||
###### Example
|
||
|
||
The following example shows how a new processor can be created (from the remark
|
||
processor) and linked to **stdin**(4) and **stdout**(4).
|
||
|
||
```js
|
||
import {remark} from 'remark'
|
||
import concatStream from 'concat-stream'
|
||
|
||
process.stdin.pipe(
|
||
concatStream((buf) => {
|
||
process.stdout.write(remark().processSync(buf).toString())
|
||
})
|
||
)
|
||
```
|
||
|
||
### `processor.use(plugin[, options])`
|
||
|
||
[*Configure*][configuration] the processor to use a [*plugin*][plugin] and
|
||
optionally configure that plugin with options.
|
||
|
||
If the processor is already using this plugin, the previous plugin configuration
|
||
is changed based on the options that are passed in.
|
||
The plugin is not added a second time.
|
||
|
||
###### Signatures
|
||
|
||
* `processor.use(plugin[, options])`
|
||
* `processor.use(preset)`
|
||
* `processor.use(list)`
|
||
|
||
###### Parameters
|
||
|
||
* `plugin` ([`Attacher`][plugin])
|
||
* `options` (`*`, optional) — Configuration for `plugin`
|
||
* `preset` (`Object`) — Object with an optional `plugins` (set to `list`),
|
||
and/or an optional `settings` object
|
||
* `list` (`Array`) — List of plugins, presets, and pairs (`plugin` and
|
||
`options` in an array)
|
||
|
||
###### Returns
|
||
|
||
`processor` — The processor that `use` was called on.
|
||
|
||
###### Note
|
||
|
||
`use` cannot be called on [*frozen*][freeze] processors.
|
||
Call the processor first to create a new unfrozen processor.
|
||
|
||
###### Example
|
||
|
||
There are many ways to pass plugins to `.use()`.
|
||
The below example gives an overview.
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
|
||
unified()
|
||
// Plugin with options:
|
||
.use(pluginA, {x: true, y: true})
|
||
// Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
|
||
.use(pluginA, {y: false, z: true})
|
||
// Plugins:
|
||
.use([pluginB, pluginC])
|
||
// Two plugins, the second with options:
|
||
.use([pluginD, [pluginE, {}]])
|
||
// Preset with plugins and settings:
|
||
.use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
|
||
// Settings only:
|
||
.use({settings: {position: false}})
|
||
```
|
||
|
||
### `processor.parse(file)`
|
||
|
||
Parse text to a [*syntax tree*][syntax-tree].
|
||
|
||
###### Parameters
|
||
|
||
* `file` ([`VFile`][vfile]) — [*File*][file], any value accepted by `vfile()`
|
||
|
||
###### Returns
|
||
|
||
[`Node`][node] — Parsed [*syntax tree*][syntax-tree] representing `file`.
|
||
|
||
###### Note
|
||
|
||
`parse` freezes the processor if not already [*frozen*][freeze].
|
||
|
||
`parse` performs the [*parse phase*][description], not the *run phase* or other
|
||
phases.
|
||
|
||
###### Example
|
||
|
||
The below example shows how `parse` can be used to create a syntax tree from a
|
||
file.
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'remark-parse'
|
||
|
||
const tree = unified().use(remarkParse).parse('# Hello world!')
|
||
|
||
console.log(tree)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```js
|
||
{
|
||
type: 'root',
|
||
children: [
|
||
{type: 'heading', depth: 1, children: [Array], position: [Position]}
|
||
],
|
||
position: {
|
||
start: {line: 1, column: 1, offset: 0},
|
||
end: {line: 1, column: 15, offset: 14}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `processor.Parser`
|
||
|
||
A **parser** handles the parsing of text to a [*syntax tree*][syntax-tree].
|
||
Used in the [*parse phase*][description] and called with a `string` and
|
||
[`VFile`][vfile] representation of the text to parse.
|
||
|
||
`Parser` can be a function, in which case it must return a [`Node`][node]: the
|
||
syntax tree representation of the given file.
|
||
|
||
`Parser` can also be a constructor function (a function with a `parse` field, or
|
||
other fields, in its `prototype`), in which case it’s constructed with `new`.
|
||
Instances must have a `parse` method that is called without arguments and must
|
||
return a [`Node`][node].
|
||
|
||
### `processor.stringify(node[, file])`
|
||
|
||
Compile a [*syntax tree*][syntax-tree].
|
||
|
||
###### Parameters
|
||
|
||
* `node` ([`Node`][node]) — [*Syntax tree*][syntax-tree] to compile
|
||
* `file` ([`VFile`][vfile], optional) — [*File*][file], any value accepted by
|
||
`vfile()`
|
||
|
||
###### Returns
|
||
|
||
`string` or `Buffer` (see notes) — Textual representation of the [*syntax
|
||
tree*][syntax-tree]
|
||
|
||
###### Note
|
||
|
||
`stringify` freezes the processor if not already [*frozen*][freeze].
|
||
|
||
`stringify` performs the [*stringify phase*][description], not the *run phase*
|
||
or other phases.
|
||
|
||
unified typically compiles by serializing: most [*compiler*][compiler]s return
|
||
`string` (or `Buffer`).
|
||
Some compilers, such as the one configured with [`rehype-react`][rehype-react],
|
||
return other values (in this case, a React tree).
|
||
If you’re using a compiler doesn’t serialize, expect different result values.
|
||
When using TypeScript, cast the type on your side.
|
||
|
||
###### Example
|
||
|
||
The below example shows how `stringify` can be used to serialize a syntax tree.
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import rehypeStringify from 'rehype-stringify'
|
||
import {h} from 'hastscript'
|
||
|
||
const tree = h('h1', 'Hello world!')
|
||
|
||
const doc = unified().use(rehypeStringify).stringify(tree)
|
||
|
||
console.log(doc)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```html
|
||
<h1>Hello world!</h1>
|
||
```
|
||
|
||
#### `processor.Compiler`
|
||
|
||
A **compiler** handles the compiling of a [*syntax tree*][syntax-tree] to text.
|
||
Used in the [*stringify phase*][description] and called with a [`Node`][node]
|
||
and [`VFile`][file] representation of syntax tree to compile.
|
||
|
||
`Compiler` can be a function, in which case it should return a `string`: the
|
||
textual representation of the syntax tree.
|
||
|
||
`Compiler` can also be a constructor function (a function with a `compile`
|
||
field, or other fields, in its `prototype`), in which case it’s constructed with
|
||
`new`.
|
||
Instances must have a `compile` method that is called without arguments and
|
||
should return a `string`.
|
||
|
||
### `processor.run(node[, file][, done])`
|
||
|
||
Run [*transformers*][transformer] on a [*syntax tree*][syntax-tree].
|
||
|
||
###### Parameters
|
||
|
||
* `node` ([`Node`][node]) — [*Syntax tree*][syntax-tree] to run on
|
||
* `file` ([`VFile`][vfile], optional) — [*File*][file], any value accepted by
|
||
`vfile()`
|
||
* `done` ([`Function`][run-done], optional) — Callback
|
||
|
||
###### Returns
|
||
|
||
[`Promise`][promise] if `done` is not given.
|
||
The returned promise is rejected with a fatal error, or resolved with the
|
||
transformed [*syntax tree*][syntax-tree].
|
||
|
||
###### Note
|
||
|
||
`run` freezes the processor if not already [*frozen*][freeze].
|
||
|
||
`run` performs the [*run phase*][description], not other phases.
|
||
|
||
#### `function done(err[, node, file])`
|
||
|
||
Callback called when [*transformers*][transformer] are done.
|
||
Called with either an error or results.
|
||
|
||
###### Parameters
|
||
|
||
* `err` (`Error`, optional) — Fatal error
|
||
* `node` ([`Node`][node], optional) — Transformed [*syntax tree*][syntax-tree]
|
||
* `file` ([`VFile`][vfile], optional) — [*File*][file]
|
||
|
||
###### Example
|
||
|
||
The below example shows how `run` can be used to transform a syntax tree.
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkReferenceLinks from 'remark-reference-links'
|
||
import {u} from 'unist-builder'
|
||
|
||
const tree = u('root', [
|
||
u('paragraph', [
|
||
u('link', {href: 'https://example.com'}, [u('text', 'Example Domain')])
|
||
])
|
||
])
|
||
|
||
unified()
|
||
.use(remarkReferenceLinks)
|
||
.run(tree)
|
||
.then(
|
||
(changedTree) => console.log(changedTree),
|
||
(error) => {
|
||
// Handle your error here!
|
||
throw error
|
||
}
|
||
)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```js
|
||
{
|
||
type: 'root',
|
||
children: [
|
||
{type: 'paragraph', children: [Array]},
|
||
{type: 'definition', identifier: '1', title: undefined, url: undefined}
|
||
]
|
||
}
|
||
```
|
||
|
||
### `processor.runSync(node[, file])`
|
||
|
||
Run [*transformers*][transformer] on a [*syntax tree*][syntax-tree].
|
||
|
||
An error is thrown if asynchronous [*plugin*][plugin]s are configured.
|
||
|
||
###### Parameters
|
||
|
||
* `node` ([`Node`][node]) — [*Syntax tree*][syntax-tree] to run on
|
||
* `file` ([`VFile`][vfile], optional) — [*File*][file], any value accepted by
|
||
`vfile()`
|
||
|
||
###### Returns
|
||
|
||
[`Node`][node] — Transformed [*syntax tree*][syntax-tree].
|
||
|
||
###### Note
|
||
|
||
`runSync` freezes the processor if not already [*frozen*][freeze].
|
||
|
||
`runSync` performs the [*run phase*][description], not other phases.
|
||
|
||
### `processor.process(file[, done])`
|
||
|
||
[*Process*][description] the given [*file*][file] as configured on the
|
||
processor.
|
||
|
||
###### Parameters
|
||
|
||
* `file` ([`VFile`][vfile]) — [*File*][file], any value accepted by `vfile()`
|
||
* `done` ([`Function`][process-done], optional) — Callback
|
||
|
||
###### Returns
|
||
|
||
[`Promise`][promise] if `done` is not given.
|
||
The returned promise is rejected with a fatal error, or resolved with the
|
||
processed [*file*][file].
|
||
|
||
The parsed, transformed, and compiled value is exposed on
|
||
[`file.value`][vfile-value] or `file.result` (see notes).
|
||
|
||
###### Note
|
||
|
||
`process` freezes the processor if not already [*frozen*][freeze].
|
||
|
||
`process` performs the [*parse*, *run*, and *stringify* phases][description].
|
||
|
||
unified typically compiles by serializing: most [*compiler*][compiler]s return
|
||
`string` (or `Buffer`).
|
||
Some compilers, such as the one configured with [`rehype-react`][rehype-react],
|
||
return other values (in this case, a React tree).
|
||
If you’re using a compiler that serializes, the result is available at
|
||
`file.value`.
|
||
Otherwise, the result is available at `file.result`.
|
||
|
||
###### Example
|
||
|
||
The below example shows how `process` can be used to process a file, whether
|
||
transformers are asynchronous or not, with promises.
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'remark-parse'
|
||
import remarkRehype from 'remark-rehype'
|
||
import rehypeDocument from 'rehype-document'
|
||
import rehypeFormat from 'rehype-format'
|
||
import rehypeStringify from 'rehype-stringify'
|
||
|
||
unified()
|
||
.use(remarkParse)
|
||
.use(remarkRehype)
|
||
.use(rehypeDocument, {title: '👋🌍'})
|
||
.use(rehypeFormat)
|
||
.use(rehypeStringify)
|
||
.process('# Hello world!')
|
||
.then(
|
||
(file) => console.log(String(file)),
|
||
(error) => {
|
||
// Handle your error here!
|
||
throw error
|
||
}
|
||
)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```html
|
||
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>👋🌍</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
</head>
|
||
<body>
|
||
<h1>Hello world!</h1>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
#### `function done(err, file)`
|
||
|
||
Callback called when the [*process*][description] is done.
|
||
Called with a fatal error, if any, and a [*file*][file].
|
||
|
||
###### Parameters
|
||
|
||
* `err` (`Error`, optional) — Fatal error
|
||
* `file` ([`VFile`][vfile]) — Processed [*file*][file]
|
||
|
||
###### Example
|
||
|
||
The below example shows how `process` can be used to process a file, whether
|
||
transformers are asynchronous or not, with a callback.
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'remark-parse'
|
||
import remarkGithub from 'remark-github'
|
||
import remarkStringify from 'remark-stringify'
|
||
import {reporter} from 'vfile-reporter'
|
||
|
||
unified()
|
||
.use(remarkParse)
|
||
.use(remarkGithub)
|
||
.use(remarkStringify)
|
||
.process('@unifiedjs')
|
||
.then(
|
||
(file) => {
|
||
console.error(reporter(file))
|
||
console.log(String(file))
|
||
},
|
||
(error) => {
|
||
// Handle your error here!
|
||
throw error
|
||
}
|
||
)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```txt
|
||
no issues found
|
||
```
|
||
|
||
```markdown
|
||
[**@unifiedjs**](https://github.com/unifiedjs)
|
||
```
|
||
|
||
### `processor.processSync(file|value)`
|
||
|
||
[*Process*][description] the given [*file*][file] as configured on the
|
||
processor.
|
||
|
||
An error is thrown if asynchronous [*plugin*][plugin]s are configured.
|
||
|
||
###### Parameters
|
||
|
||
* `file` ([`VFile`][vfile]) — [*File*][file], any value accepted by `vfile()`
|
||
|
||
###### Returns
|
||
|
||
([`VFile`][vfile]) — Processed [*file*][file]
|
||
|
||
The parsed, transformed, and compiled value is exposed on
|
||
[`file.value`][vfile-value] or `file.result` (see notes).
|
||
|
||
###### Note
|
||
|
||
`processSync` freezes the processor if not already [*frozen*][freeze].
|
||
|
||
`processSync` performs the [*parse*, *run*, and *stringify*
|
||
phases][description].
|
||
|
||
unified typically compiles by serializing: most [*compiler*][compiler]s return
|
||
`string` (or `Buffer`).
|
||
Some compilers, such as the one configured with [`rehype-react`][rehype-react],
|
||
return other values (in this case, a React tree).
|
||
If you’re using a compiler that serializes, the result is available at
|
||
`file.value`.
|
||
Otherwise, the result is available at `file.result`.
|
||
|
||
###### Example
|
||
|
||
The below example shows how `processSync` can be used to process a file, if all
|
||
transformers are synchronous.
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'remark-parse'
|
||
import remarkRehype from 'remark-rehype'
|
||
import rehypeDocument from 'rehype-document'
|
||
import rehypeFormat from 'rehype-format'
|
||
import rehypeStringify from 'rehype-stringify'
|
||
|
||
const processor = unified()
|
||
.use(remarkParse)
|
||
.use(remarkRehype)
|
||
.use(rehypeDocument, {title: '👋🌍'})
|
||
.use(rehypeFormat)
|
||
.use(rehypeStringify)
|
||
|
||
console.log(processor.processSync('# Hello world!').toString())
|
||
```
|
||
|
||
Yields:
|
||
|
||
```html
|
||
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>👋🌍</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
</head>
|
||
<body>
|
||
<h1>Hello world!</h1>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
### `processor.data([key[, value]])`
|
||
|
||
[*Configure*][configuration] the processor with information available to all
|
||
[*plugin*][plugin]s.
|
||
Information is stored in an in-memory key-value store.
|
||
|
||
Typically, options can be given to a specific plugin, but sometimes it makes
|
||
sense to have information shared with several plugins.
|
||
For example, a list of HTML elements that are self-closing, which is needed
|
||
during all [*phases*][description] of the *process*.
|
||
|
||
###### Signatures
|
||
|
||
* `processor = processor.data(key, value)`
|
||
* `processor = processor.data(values)`
|
||
* `value = processor.data(key)`
|
||
* `info = processor.data()`
|
||
|
||
###### Parameters
|
||
|
||
* `key` (`string`, optional) — Identifier
|
||
* `value` (`*`, optional) — Value to set
|
||
* `values` (`Object`, optional) — Values to set
|
||
|
||
###### Returns
|
||
|
||
* `processor` — If setting, the processor that `data` is called on
|
||
* `value` (`*`) — If getting, the value at `key`
|
||
* `info` (`Object`) — Without arguments, the key-value store
|
||
|
||
###### Note
|
||
|
||
Setting information cannot occur on [*frozen*][freeze] processors.
|
||
Call the processor first to create a new unfrozen processor.
|
||
|
||
###### Example
|
||
|
||
The following example show how to get and set information:
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
|
||
const processor = unified().data('alpha', 'bravo')
|
||
|
||
processor.data('alpha') // => 'bravo'
|
||
|
||
processor.data() // => {alpha: 'bravo'}
|
||
|
||
processor.data({charlie: 'delta'})
|
||
|
||
processor.data() // => {charlie: 'delta'}
|
||
```
|
||
|
||
### `processor.freeze()`
|
||
|
||
**Freeze** a processor.
|
||
*Frozen* processors are meant to be extended and not to be configured directly.
|
||
|
||
Once a processor is frozen it cannot be *unfrozen*.
|
||
New processors working the same way can be created by calling the processor.
|
||
|
||
It’s possible to freeze processors explicitly by calling `.freeze()`.
|
||
Processors freeze implicitly when [`.parse()`][parse], [`.run()`][run],
|
||
[`.runSync()`][run-sync], [`.stringify()`][stringify], [`.process()`][process],
|
||
or [`.processSync()`][process-sync] are called.
|
||
|
||
###### Returns
|
||
|
||
`processor` — The processor that `freeze` was called on.
|
||
|
||
###### Example
|
||
|
||
The following example, `index.js`, shows how rehype prevents extensions to
|
||
itself:
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'rehype-parse'
|
||
import remarkStringify from 'rehype-stringify'
|
||
|
||
export const rehype = unified().use(remarkParse).use(remarkStringify).freeze()
|
||
```
|
||
|
||
The below example, `a.js`, shows how that processor can be used and configured.
|
||
|
||
```js
|
||
import {rehype} from 'rehype'
|
||
import rehypeFormat from 'rehype-format'
|
||
// …
|
||
|
||
rehype()
|
||
.use(rehypeFormat)
|
||
// …
|
||
```
|
||
|
||
The below example, `b.js`, shows a similar looking example that operates on the
|
||
frozen rehype interface because it does not call `rehype`.
|
||
If this behavior was allowed it would result in unexpected behavior so an
|
||
error is thrown.
|
||
**This is invalid**:
|
||
|
||
```js
|
||
import {rehype} from 'rehype'
|
||
import rehypeFormat from 'rehype-format'
|
||
// …
|
||
|
||
rehype
|
||
.use(rehypeFormat)
|
||
// …
|
||
```
|
||
|
||
Yields:
|
||
|
||
```txt
|
||
~/node_modules/unified/index.js:426
|
||
throw new Error(
|
||
^
|
||
|
||
Error: Cannot call `use` on a frozen processor.
|
||
Create a new processor first, by calling it: use `processor()` instead of `processor`.
|
||
at assertUnfrozen (~/node_modules/unified/index.js:426:11)
|
||
at Function.use (~/node_modules/unified/index.js:165:5)
|
||
at ~/b.js:6:4
|
||
```
|
||
|
||
## `Plugin`
|
||
|
||
**Plugins** [*configure*][configuration] the processors they are applied on in
|
||
the following ways:
|
||
|
||
* They change the processor: such as the [*parser*][parser], the
|
||
[*compiler*][compiler], or configuring [*data*][data]
|
||
* They specify how to handle [*syntax trees*][syntax-tree] and [*files*][file]
|
||
|
||
Plugins are a concept.
|
||
They materialize as [`attacher`][attacher]s.
|
||
|
||
###### Example
|
||
|
||
`move.js`:
|
||
|
||
```js
|
||
export function move(options = {}) {
|
||
const {extname} = options
|
||
|
||
if (!extname) {
|
||
throw new Error('Missing `extname` in options')
|
||
}
|
||
|
||
return transformer
|
||
|
||
function transformer(tree, file) {
|
||
if (file.extname && file.extname !== extname) {
|
||
file.extname = extname
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
`index.md`:
|
||
|
||
```markdown
|
||
# Hello, world!
|
||
```
|
||
|
||
`index.js`:
|
||
|
||
```js
|
||
import {unified} from 'unified'
|
||
import remarkParse from 'remark-parse'
|
||
import remarkRehype from 'remark-rehype'
|
||
import rehypeStringify from 'rehype-stringify'
|
||
import {toVFile} from 'to-vfile'
|
||
import {reporter} from 'vfile-reporter'
|
||
import {move} from './move.js'
|
||
|
||
unified()
|
||
.use(remarkParse)
|
||
.use(remarkRehype)
|
||
.use(move, {extname: '.html'})
|
||
.use(rehypeStringify)
|
||
.process(toVFile.readSync('index.md'))
|
||
.then(
|
||
(file) => {
|
||
console.error(reporter(file))
|
||
toVFile.writeSync(file) // Written to `index.html`.
|
||
},
|
||
(error) => {
|
||
// Handle your error here!
|
||
throw error
|
||
}
|
||
)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```txt
|
||
index.md: no issues found
|
||
```
|
||
|
||
…and in `index.html`:
|
||
|
||
```html
|
||
<h1>Hello, world!</h1>
|
||
```
|
||
|
||
### `function attacher([options])`
|
||
|
||
**Attachers** are materialized [*plugin*][plugin]s.
|
||
An attacher is a function that can receive options and
|
||
[*configures*][configuration] the processor.
|
||
|
||
Attachers change the processor, such as the [*parser*][parser], the
|
||
[*compiler*][compiler], configuring [*data*][data], or by specifying how the
|
||
[*syntax tree*][syntax-tree] or [*file*][file] are handled.
|
||
|
||
###### Context
|
||
|
||
The context object (`this`) is set to the processor the attacher is applied on.
|
||
|
||
###### Parameters
|
||
|
||
* `options` (`*`, optional) — Configuration
|
||
|
||
###### Returns
|
||
|
||
[`transformer`][transformer] — Optional.
|
||
|
||
###### Note
|
||
|
||
Attachers are called when the processor is [*frozen*][freeze], not when they are
|
||
applied.
|
||
|
||
### `function transformer(node, file[, next])`
|
||
|
||
**Transformers** handle [*syntax tree*][syntax-tree]s and [*file*][file]s.
|
||
A transformer is a function that is called each time a syntax tree and file are
|
||
passed through the [*run phase*][description].
|
||
If an error occurs (either because it’s thrown, returned, rejected, or passed to
|
||
[`next`][next]), the process stops.
|
||
|
||
The *run phase* is handled by [`trough`][trough], see its documentation for the
|
||
exact semantics of these functions.
|
||
|
||
###### Parameters
|
||
|
||
* `node` ([`Node`][node]) — [*Syntax tree*][syntax-tree] to handle
|
||
* `file` ([`VFile`][vfile]) — [*File*][file] to handle
|
||
* `next` ([`Function`][next], optional)
|
||
|
||
###### Returns
|
||
|
||
* `void` — If nothing is returned, the next transformer keeps using same tree.
|
||
* `Error` — Fatal error to stop the process
|
||
* `node` ([`Node`][node]) — New [*syntax tree*][syntax-tree].
|
||
If returned, the next transformer is given this new tree
|
||
* `Promise` — Returned to perform an asynchronous operation.
|
||
The promise **must** be resolved (optionally with a [`Node`][node]) or
|
||
rejected (optionally with an `Error`)
|
||
|
||
#### `function next(err[, tree[, file]])`
|
||
|
||
If the signature of a [*transformer*][transformer] includes `next` (the third
|
||
argument), the transformer **may** perform asynchronous operations, and **must**
|
||
call `next()`.
|
||
|
||
###### Parameters
|
||
|
||
* `err` (`Error`, optional) — Fatal error to stop the process
|
||
* `node` ([`Node`][node], optional) — New [*syntax tree*][syntax-tree].
|
||
If given, the next transformer is given this new tree
|
||
* `file` ([`VFile`][vfile], optional) — New [*file*][file].
|
||
If given, the next transformer is given this new file
|
||
|
||
## `Preset`
|
||
|
||
**Presets** are sharable [*configuration*][configuration].
|
||
They can contain [*plugins*][plugin] and settings.
|
||
|
||
###### Example
|
||
|
||
`preset.js`:
|
||
|
||
```js
|
||
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
|
||
import remarkPresetLintConsistent from 'remark-preset-lint-consistent'
|
||
import remarkCommentConfig from 'remark-comment-config'
|
||
import remarkToc from 'remark-toc'
|
||
import remarkLicense from 'remark-license'
|
||
|
||
export const preset = {
|
||
settings: {bullet: '*', emphasis: '*', fences: true},
|
||
plugins: [
|
||
remarkPresetLintRecommended,
|
||
remarkPresetLintConsistent,
|
||
remarkCommentConfig,
|
||
[remarkToc, {maxDepth: 3, tight: true}],
|
||
remarkLicense
|
||
]
|
||
}
|
||
```
|
||
|
||
`example.md`:
|
||
|
||
```markdown
|
||
# Hello, world!
|
||
|
||
_Emphasis_ and **importance**.
|
||
|
||
## Table of contents
|
||
|
||
## API
|
||
|
||
## License
|
||
```
|
||
|
||
`index.js`:
|
||
|
||
```js
|
||
import {remark} from 'remark'
|
||
import {toVFile} from 'to-vfile'
|
||
import {reporter} from 'vfile-reporter'
|
||
import {preset} from './preset.js'
|
||
|
||
remark()
|
||
.use(preset)
|
||
.process(toVFile.readSync('example.md'))
|
||
.then(
|
||
(file) => {
|
||
console.error(reporter(file))
|
||
toVFile.writeSync(file)
|
||
},
|
||
(error) => {
|
||
// Handle your error here!
|
||
throw error
|
||
}
|
||
)
|
||
```
|
||
|
||
Yields:
|
||
|
||
```txt
|
||
example.md: no issues found
|
||
```
|
||
|
||
`example.md` now contains:
|
||
|
||
```markdown
|
||
# Hello, world!
|
||
|
||
*Emphasis* and **importance**.
|
||
|
||
## Table of contents
|
||
|
||
* [API](#api)
|
||
* [License](#license)
|
||
|
||
## API
|
||
|
||
## License
|
||
|
||
[MIT](license) © [Titus Wormer](https://wooorm.com)
|
||
```
|
||
|
||
## Contribute
|
||
|
||
See [`contributing.md`][contributing] in [`unifiedjs/.github`][health] for ways
|
||
to get started.
|
||
See [`support.md`][support] for ways to get help.
|
||
Ideas for new plugins and tools can be posted in [`unifiedjs/ideas`][ideas].
|
||
|
||
A curated list of awesome unified resources can be found in [**awesome
|
||
unified**][awesome].
|
||
|
||
This project has a [code of conduct][coc].
|
||
By interacting with this repository, organization, or community you agree to
|
||
abide by its terms.
|
||
|
||
## Acknowledgments
|
||
|
||
Preliminary work for unified was done [in 2014][preliminary] for
|
||
[**retext**][retext] and inspired by [`ware`][ware].
|
||
Further incubation happened in [**remark**][remark].
|
||
The project was finally [externalised][] in 2015 and [published][] as `unified`.
|
||
The project was authored by [**@wooorm**](https://github.com/wooorm).
|
||
|
||
Although `unified` since moved its plugin architecture to [`trough`][trough],
|
||
thanks to [**@calvinfo**](https://github.com/calvinfo),
|
||
[**@ianstormtaylor**](https://github.com/ianstormtaylor), and others for their
|
||
work on [`ware`][ware], as it was a huge initial inspiration.
|
||
|
||
## License
|
||
|
||
[MIT][license] © [Titus Wormer][author]
|
||
|
||
<!-- Definitions -->
|
||
|
||
[logo]: https://raw.githubusercontent.com/unifiedjs/unified/93862e5/logo.svg?sanitize=true
|
||
|
||
[build-badge]: https://github.com/unifiedjs/unified/workflows/main/badge.svg
|
||
|
||
[build]: https://github.com/unifiedjs/unified/actions
|
||
|
||
[coverage-badge]: https://img.shields.io/codecov/c/github/unifiedjs/unified.svg
|
||
|
||
[coverage]: https://codecov.io/github/unifiedjs/unified
|
||
|
||
[downloads-badge]: https://img.shields.io/npm/dm/unified.svg
|
||
|
||
[downloads]: https://www.npmjs.com/package/unified
|
||
|
||
[size-badge]: https://img.shields.io/bundlephobia/minzip/unified.svg
|
||
|
||
[size]: https://bundlephobia.com/result?p=unified
|
||
|
||
[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/unifiedjs/unified/discussions
|
||
|
||
[health]: https://github.com/unifiedjs/.github
|
||
|
||
[contributing]: https://github.com/unifiedjs/.github/blob/HEAD/contributing.md
|
||
|
||
[support]: https://github.com/unifiedjs/.github/blob/HEAD/support.md
|
||
|
||
[coc]: https://github.com/unifiedjs/.github/blob/HEAD/code-of-conduct.md
|
||
|
||
[awesome]: https://github.com/unifiedjs/awesome-unified
|
||
|
||
[license]: license
|
||
|
||
[author]: https://wooorm.com
|
||
|
||
[npm]: https://docs.npmjs.com/cli/install
|
||
|
||
[site]: https://unifiedjs.com
|
||
|
||
[twitter]: https://twitter.com/unifiedjs
|
||
|
||
[learn]: https://unifiedjs.com/learn/
|
||
|
||
[rehype]: https://github.com/rehypejs/rehype
|
||
|
||
[remark]: https://github.com/remarkjs/remark
|
||
|
||
[retext]: https://github.com/retextjs/retext
|
||
|
||
[esast]: https://github.com/syntax-tree/esast
|
||
|
||
[hast]: https://github.com/syntax-tree/hast
|
||
|
||
[mdast]: https://github.com/syntax-tree/mdast
|
||
|
||
[nlcst]: https://github.com/syntax-tree/nlcst
|
||
|
||
[xast]: https://github.com/syntax-tree/xast
|
||
|
||
[unist]: https://github.com/syntax-tree/unist
|
||
|
||
[engine]: https://github.com/unifiedjs/unified-engine
|
||
|
||
[args]: https://github.com/unifiedjs/unified-args
|
||
|
||
[gulp]: https://github.com/unifiedjs/unified-engine-gulp
|
||
|
||
[atom]: https://github.com/unifiedjs/unified-engine-atom
|
||
|
||
[remark-rehype]: https://github.com/remarkjs/remark-rehype
|
||
|
||
[remark-retext]: https://github.com/remarkjs/remark-retext
|
||
|
||
[rehype-retext]: https://github.com/rehypejs/rehype-retext
|
||
|
||
[rehype-remark]: https://github.com/rehypejs/rehype-remark
|
||
|
||
[unist-utilities]: https://github.com/syntax-tree/unist#list-of-utilities
|
||
|
||
[vfile]: https://github.com/vfile/vfile
|
||
|
||
[vfile-value]: https://github.com/vfile/vfile#vfilevalue
|
||
|
||
[vfile-utilities]: https://github.com/vfile/vfile#list-of-utilities
|
||
|
||
[node]: https://github.com/syntax-tree/unist#node
|
||
|
||
[description]: #description
|
||
|
||
[syntax-tree]: #syntax-trees
|
||
|
||
[configuration]: #configuration
|
||
|
||
[file]: #file
|
||
|
||
[processors]: #processors
|
||
|
||
[process]: #processorprocessfile-done
|
||
|
||
[process-sync]: #processorprocesssyncfilevalue
|
||
|
||
[parse]: #processorparsefile
|
||
|
||
[parser]: #processorparser
|
||
|
||
[stringify]: #processorstringifynode-file
|
||
|
||
[run]: #processorrunnode-file-done
|
||
|
||
[run-sync]: #processorrunsyncnode-file
|
||
|
||
[compiler]: #processorcompiler
|
||
|
||
[data]: #processordatakey-value
|
||
|
||
[attacher]: #function-attacheroptions
|
||
|
||
[transformer]: #function-transformernode-file-next
|
||
|
||
[next]: #function-nexterr-tree-file
|
||
|
||
[freeze]: #processorfreeze
|
||
|
||
[plugin]: #plugin
|
||
|
||
[run-done]: #function-doneerr-node-file
|
||
|
||
[process-done]: #function-doneerr-file
|
||
|
||
[contribute]: #contribute
|
||
|
||
[rehype-react]: https://github.com/rehypejs/rehype-react
|
||
|
||
[trough]: https://github.com/wooorm/trough#function-fninput-next
|
||
|
||
[promise]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
||
|
||
[remark-plugins]: https://github.com/remarkjs/remark/blob/HEAD/doc/plugins.md#list-of-plugins
|
||
|
||
[rehype-plugins]: https://github.com/rehypejs/rehype/blob/HEAD/doc/plugins.md#list-of-plugins
|
||
|
||
[retext-plugins]: https://github.com/retextjs/retext/blob/HEAD/doc/plugins.md#list-of-plugins
|
||
|
||
[stream]: https://github.com/unifiedjs/unified-stream
|
||
|
||
[ideas]: https://github.com/unifiedjs/ideas
|
||
|
||
[preliminary]: https://github.com/retextjs/retext/commit/8fcb1f#diff-168726dbe96b3ce427e7fedce31bb0bc
|
||
|
||
[externalised]: https://github.com/remarkjs/remark/commit/9892ec#diff-168726dbe96b3ce427e7fedce31bb0bc
|
||
|
||
[published]: https://github.com/unifiedjs/unified/commit/2ba1cf
|
||
|
||
[ware]: https://github.com/segmentio/ware
|
||
|
||
[gatsby]: https://www.gatsbyjs.org
|
||
|
||
[mdx]: https://mdxjs.com
|
||
|
||
[jsx]: https://reactjs.org/docs/jsx-in-depth.html
|
||
|
||
[prettier]: https://prettier.io
|
||
|
||
[node.js]: https://nodejs.org
|
||
|
||
[vercel]: https://vercel.com
|
||
|
||
[netlify]: https://www.netlify.com
|
||
|
||
[github]: https://github.com
|
||
|
||
[mozilla]: https://www.mozilla.org
|
||
|
||
[wordpress]: https://wordpress.com
|
||
|
||
[adobe]: https://www.adobe.com
|
||
|
||
[facebook]: https://www.facebook.com
|
||
|
||
[google]: https://www.google.com
|