astro-ghostcms/.pnpm-store/v3/files/bf/536bee2b2c2b1fc9b595fbdb4ad...

1451 lines
40 KiB
Plaintext
Raw Permalink 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.

# [![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.
Its 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.
Its used in about 700k projects on GitHub and has about 35m downloads each
month on npm: youre 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 its 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 youre using a compiler doesnt 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 its 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 youre 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 youre 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.
Its 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 its 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