UNPKG

15.6 kBMarkdownView Raw
1# rehype-stringify
2
3[![Build][build-badge]][build]
4[![Coverage][coverage-badge]][coverage]
5[![Downloads][downloads-badge]][downloads]
6[![Size][size-badge]][size]
7[![Sponsors][sponsors-badge]][collective]
8[![Backers][backers-badge]][collective]
9[![Chat][chat-badge]][chat]
10
11**[rehype][]** plugin to add support for serializing to HTML.
12
13## Contents
14
15* [What is this?](#what-is-this)
16* [When should I use this?](#when-should-i-use-this)
17* [Install](#install)
18* [Use](#use)
19* [API](#api)
20 * [`unified().use(rehypeStringify[, options])`](#unifieduserehypestringify-options)
21 * [`CharacterReferences`](#characterreferences)
22 * [`Options`](#options)
23* [Syntax](#syntax)
24* [Syntax tree](#syntax-tree)
25* [Types](#types)
26* [Compatibility](#compatibility)
27* [Security](#security)
28* [Contribute](#contribute)
29* [Sponsor](#sponsor)
30* [License](#license)
31
32## What is this?
33
34This package is a [unified][] ([rehype][]) plugin that defines how to take a
35syntax tree as input and turn it into serialized HTML.
36When it’s used, HTML is serialized as the final result.
37
38See [the monorepo readme][rehype] for info on what the rehype ecosystem is.
39
40## When should I use this?
41
42This plugin adds support to unified for serializing HTML.
43If you also need to parse HTML, you can alternatively use
44[`rehype`][rehype-core], which combines unified,
45[`rehype-parse`][rehype-parse], and this plugin.
46
47When you are in a browser, trust your content, don’t need formatting options,
48and value a smaller bundle size, you can use
49[`rehype-dom-stringify`][rehype-dom-stringify] instead.
50
51If you don’t use plugins and have access to a syntax tree, you can directly use
52[`hast-util-to-html`][hast-util-to-html], which is used inside this plugin.
53rehype focusses on making it easier to transform content by abstracting such
54internals away.
55
56A different plugin, [`rehype-format`][rehype-format], improves the readability
57of HTML source code as it adds insignificant but pretty whitespace between
58elements.
59There is also the preset [`rehype-minify`][rehype-minify] for when you want the
60inverse: minified and mangled HTML.
61
62## Install
63
64This package is [ESM only][esm].
65In Node.js (version 16+), install with [npm][]:
66
67```sh
68npm install rehype-stringify
69```
70
71In Deno with [`esm.sh`][esmsh]:
72
73```js
74import rehypeStringify from 'https://esm.sh/rehype-stringify@10'
75```
76
77In browsers with [`esm.sh`][esmsh]:
78
79```html
80<script type="module">
81 import rehypeStringify from 'https://esm.sh/rehype-stringify@10?bundle'
82</script>
83```
84
85## Use
86
87Say we have the following module `example.js`:
88
89```js
90import remarkRehype from 'remark-rehype'
91import rehypeStringify from 'rehype-stringify'
92import remarkGfm from 'remark-gfm'
93import remarkParse from 'remark-parse'
94import {unified} from 'unified'
95
96const file = await unified()
97 .use(remarkParse)
98 .use(remarkGfm)
99 .use(remarkRehype)
100 .use(rehypeStringify)
101 .process('# Hi\n\n*Hello*, world!')
102
103console.log(String(file))
104```
105
106…running that with `node example.js` yields:
107
108```html
109<h1>Hi</h1>
110<p><em>Hello</em>, world!</p>
111```
112
113## API
114
115This package exports no identifiers.
116The default export is [`rehypeStringify`][api-rehype-stringify].
117
118### `unified().use(rehypeStringify[, options])`
119
120Plugin to add support for serializing to HTML.
121
122###### Parameters
123
124* `options` ([`Options`][api-options], optional)
125 — configuration
126
127###### Returns
128
129Nothing (`undefined`).
130
131### `CharacterReferences`
132
133How to serialize character references (TypeScript type).
134
135> ⚠️ **Note**: `omitOptionalSemicolons` creates what HTML calls “parse errors”
136> but is otherwise still valid HTML — don’t use this except when building a
137> minifier.
138> Omitting semicolons is possible for certain named and numeric references in
139> some cases.
140
141> ⚠️ **Note**: `useNamedReferences` can be omitted when using
142> `useShortestReferences`.
143
144###### Fields
145
146* `useNamedReferences` (`boolean`, default: `false`)
147 — prefer named character references (`&amp;`) where possible
148* `omitOptionalSemicolons` (`boolean`, default: `false`)
149 — whether to omit semicolons when possible
150* `useShortestReferences` (`boolean`, default: `false`)
151 — prefer the shortest possible reference, if that results in less bytes
152
153### `Options`
154
155Configuration (TypeScript type).
156
157> ⚠️ **Danger**: only set `allowDangerousCharacters` and `allowDangerousHtml` if
158> you completely trust the content.
159
160> 👉 **Note**: `allowParseErrors`, `bogusComments`, `tightAttributes`, and
161> `tightDoctype`
162> intentionally create parse errors in markup (how parse errors are handled is
163> well defined, so this works but isn’t pretty).
164
165> 👉 **Note**: this is not an XML serializer.
166> It supports SVG as embedded in HTML.
167> It does not support the features available in XML.
168> Use [`xast-util-to-xml`][xast-util-to-xml] to serialize XML.
169
170###### Fields
171
172* `allowDangerousCharacters` (`boolean`, default: `false`)
173 — do not encode some characters which cause XSS vulnerabilities in older
174 browsers
175* `allowDangerousHtml` (`boolean`, default: `false`)
176 — allow [`Raw`][raw] nodes and insert them as raw HTML; when `false`, `Raw`
177 nodes are encoded
178* `allowParseErrors` (`boolean`, default: `false`)
179 — do not encode characters which cause parse errors (even though they
180 work), to save bytes; not used in the SVG space.
181* `bogusComments` (`boolean`, default: `false`)
182 — use “bogus comments” instead of comments to save byes: `<?charlie>`
183 instead of `<!--charlie-->`
184* `characterReferences` ([`CharacterReferences`][api-character-references],
185 optional)
186 — configure how to serialize character references
187* `closeEmptyElements` (`boolean`, default: `false`)
188 — close SVG elements without any content with slash (`/`) on the opening
189 tag instead of an end tag: `<circle />` instead of `<circle></circle>`;
190 see `tightSelfClosing` to control whether a space is used before the slash;
191 not used in the HTML space
192* `closeSelfClosing` (`boolean`, default: `false`)
193 — close self-closing nodes with an extra slash (`/`): `<img />` instead of
194 `<img>`; see `tightSelfClosing` to control whether a space is used before
195 the slash; not used in the SVG space.
196* `collapseEmptyAttributes` (`boolean`, default: `false`)
197 — collapse empty attributes: get `class` instead of `class=""`; not used in
198 the SVG space; boolean attributes (such as `hidden`) are always collapsed
199* `omitOptionalTags` (`boolean`, default: `false`)
200 — omit optional opening and closing tags; to illustrate, in
201 `<ol><li>one</li><li>two</li></ol>`, both `</li>` closing tags can be
202 omitted, the first because it’s followed by another `li`, the last because
203 it’s followed by nothing; not used in the SVG space
204* `preferUnquoted` (`boolean`, default: `false`)
205 — leave attributes unquoted if that results in less bytes; not used in the
206 SVG space
207* `quote` (`'"'` or `"'"`, default: `'"'`)
208 — preferred quote to use
209* `quoteSmart` (`boolean`, default: `false`)
210 — use the other quote if that results in less bytes
211* `space` (`'html'` or `'svg'`, default: `'html'`)
212 — which space the document is in; when an `<svg>` element is found in the
213 HTML space, this package already automatically switches to and from the SVG
214* `tightAttributes` (`boolean`, default: `false`)
215 — join attributes together, without whitespace, if possible: get
216 `class="a b"title="c d"` instead of `class="a b" title="c d"` to save
217 bytes; not used in the SVG space
218* `tightCommaSeparatedLists` (`boolean`, default: `false`)
219 — join known comma-separated attribute values with just a comma (`,`),
220 instead of padding them on the right as well (`,␠`, where `␠` represents a
221 space)
222* `tightDoctype` (`boolean`, default: `false`)
223 — drop unneeded spaces in doctypes: `<!doctypehtml>` instead of
224 `<!doctype html>` to save bytes
225* `tightSelfClosing` (`boolean`, default: `false`).
226 — do not use an extra space when closing self-closing elements: `<img/>`
227 instead of `<img />`; only used if `closeSelfClosing: true` or
228 `closeEmptyElements: true`
229* `upperDoctype` (`boolean`, default: `false`).
230 — use a `<!DOCTYPE…` instead of `<!doctype…`; useless except for XHTML
231* `voids` (`Array<string>`, default:
232 [`html-void-elements`][html-void-elements])
233 — tag names of elements to serialize without closing tag; not used in the
234 SVG space
235
236## Syntax
237
238HTML is serialized according to WHATWG HTML (the living standard), which is also
239followed by all browsers.
240
241## Syntax tree
242
243The syntax tree format used in rehype is [hast][].
244
245## Types
246
247This package is fully typed with [TypeScript][].
248It exports the additional types
249[`CharacterReferences`][api-character-references] and
250[`Options`][api-options].
251
252## Compatibility
253
254Projects maintained by the unified collective are compatible with maintained
255versions of Node.js.
256
257When we cut a new major release, we drop support for unmaintained versions of
258Node.
259This means we try to keep the current release line, `rehype-stringify@^10`,
260compatible with Node.js 16.
261
262## Security
263
264As **rehype** works on HTML, and improper use of HTML can open you up to a
265[cross-site scripting (XSS)][xss] attack, use of rehype can also be unsafe.
266Use [`rehype-sanitize`][rehype-sanitize] to make the tree safe.
267
268Use of rehype plugins could also open you up to other attacks.
269Carefully assess each plugin and the risks involved in using them.
270
271For info on how to submit a report, see our [security policy][security].
272
273## Contribute
274
275See [`contributing.md`][contributing] in [`rehypejs/.github`][health] for ways
276to get started.
277See [`support.md`][support] for ways to get help.
278
279This project has a [code of conduct][coc].
280By interacting with this repository, organization, or community you agree to
281abide by its terms.
282
283## Sponsor
284
285Support this effort and give back by sponsoring on [OpenCollective][collective]!
286
287<table>
288<tr valign="middle">
289<td width="20%" align="center" rowspan="2" colspan="2">
290 <a href="https://vercel.com">Vercel</a><br><br>
291 <a href="https://vercel.com"><img src="https://avatars1.githubusercontent.com/u/14985020?s=256&v=4" width="128"></a>
292</td>
293<td width="20%" align="center" rowspan="2" colspan="2">
294 <a href="https://motif.land">Motif</a><br><br>
295 <a href="https://motif.land"><img src="https://avatars1.githubusercontent.com/u/74457950?s=256&v=4" width="128"></a>
296</td>
297<td width="20%" align="center" rowspan="2" colspan="2">
298 <a href="https://www.hashicorp.com">HashiCorp</a><br><br>
299 <a href="https://www.hashicorp.com"><img src="https://avatars1.githubusercontent.com/u/761456?s=256&v=4" width="128"></a>
300</td>
301<td width="20%" align="center" rowspan="2" colspan="2">
302 <a href="https://www.gitbook.com">GitBook</a><br><br>
303 <a href="https://www.gitbook.com"><img src="https://avatars1.githubusercontent.com/u/7111340?s=256&v=4" width="128"></a>
304</td>
305<td width="20%" align="center" rowspan="2" colspan="2">
306 <a href="https://www.gatsbyjs.org">Gatsby</a><br><br>
307 <a href="https://www.gatsbyjs.org"><img src="https://avatars1.githubusercontent.com/u/12551863?s=256&v=4" width="128"></a>
308</td>
309</tr>
310<tr valign="middle">
311</tr>
312<tr valign="middle">
313<td width="20%" align="center" rowspan="2" colspan="2">
314 <a href="https://www.netlify.com">Netlify</a><br><br>
315 <!--OC has a sharper image-->
316 <a href="https://www.netlify.com"><img src="https://images.opencollective.com/netlify/4087de2/logo/256.png" width="128"></a>
317</td>
318<td width="10%" align="center">
319 <a href="https://www.coinbase.com">Coinbase</a><br><br>
320 <a href="https://www.coinbase.com"><img src="https://avatars1.githubusercontent.com/u/1885080?s=256&v=4" width="64"></a>
321</td>
322<td width="10%" align="center">
323 <a href="https://themeisle.com">ThemeIsle</a><br><br>
324 <a href="https://themeisle.com"><img src="https://avatars1.githubusercontent.com/u/58979018?s=128&v=4" width="64"></a>
325</td>
326<td width="10%" align="center">
327 <a href="https://expo.io">Expo</a><br><br>
328 <a href="https://expo.io"><img src="https://avatars1.githubusercontent.com/u/12504344?s=128&v=4" width="64"></a>
329</td>
330<td width="10%" align="center">
331 <a href="https://boostnote.io">Boost Note</a><br><br>
332 <a href="https://boostnote.io"><img src="https://images.opencollective.com/boosthub/6318083/logo/128.png" width="64"></a>
333</td>
334<td width="10%" align="center">
335 <a href="https://markdown.space">Markdown Space</a><br><br>
336 <a href="https://markdown.space"><img src="https://images.opencollective.com/markdown-space/e1038ed/logo/128.png" width="64"></a>
337</td>
338<td width="10%" align="center">
339 <a href="https://www.holloway.com">Holloway</a><br><br>
340 <a href="https://www.holloway.com"><img src="https://avatars1.githubusercontent.com/u/35904294?s=128&v=4" width="64"></a>
341</td>
342<td width="10%"></td>
343<td width="10%"></td>
344</tr>
345<tr valign="middle">
346<td width="100%" align="center" colspan="8">
347 <br>
348 <a href="https://opencollective.com/unified"><strong>You?</strong></a>
349 <br><br>
350</td>
351</tr>
352</table>
353
354## License
355
356[MIT][license] © [Titus Wormer][author]
357
358<!-- Definitions -->
359
360[build-badge]: https://github.com/rehypejs/rehype/workflows/main/badge.svg
361
362[build]: https://github.com/rehypejs/rehype/actions
363
364[coverage-badge]: https://img.shields.io/codecov/c/github/rehypejs/rehype.svg
365
366[coverage]: https://codecov.io/github/rehypejs/rehype
367
368[downloads-badge]: https://img.shields.io/npm/dm/rehype-stringify.svg
369
370[downloads]: https://www.npmjs.com/package/rehype-stringify
371
372[size-badge]: https://img.shields.io/bundlejs/size/rehype-stringify
373
374[size]: https://bundlejs.com/?q=rehype-stringify
375
376[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
377
378[backers-badge]: https://opencollective.com/unified/backers/badge.svg
379
380[collective]: https://opencollective.com/unified
381
382[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
383
384[chat]: https://github.com/rehypejs/rehype/discussions
385
386[health]: https://github.com/rehypejs/.github
387
388[security]: https://github.com/rehypejs/.github/blob/main/security.md
389
390[contributing]: https://github.com/rehypejs/.github/blob/main/contributing.md
391
392[support]: https://github.com/rehypejs/.github/blob/main/support.md
393
394[coc]: https://github.com/rehypejs/.github/blob/main/code-of-conduct.md
395
396[license]: https://github.com/rehypejs/rehype/blob/main/license
397
398[author]: https://wooorm.com
399
400[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
401
402[npm]: https://docs.npmjs.com/cli/install
403
404[esmsh]: https://esm.sh
405
406[unified]: https://github.com/unifiedjs/unified
407
408[rehype]: https://github.com/rehypejs/rehype
409
410[hast]: https://github.com/syntax-tree/hast
411
412[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
413
414[typescript]: https://www.typescriptlang.org
415
416[rehype-parse]: ../rehype-parse/
417
418[rehype-core]: ../rehype/
419
420[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize
421
422[rehype-format]: https://github.com/rehypejs/rehype-format
423
424[rehype-minify]: https://github.com/rehypejs/rehype-minify
425
426[rehype-dom-stringify]: https://github.com/rehypejs/rehype-dom/tree/main/packages/rehype-dom-stringify
427
428[hast-util-to-html]: https://github.com/syntax-tree/hast-util-to-html
429
430[xast-util-to-xml]: https://github.com/syntax-tree/xast-util-to-xml
431
432[html-void-elements]: https://github.com/wooorm/html-void-elements
433
434<!-- To do: use `remark-rehype` link if that’s released? -->
435
436[raw]: https://github.com/syntax-tree/mdast-util-to-hast?tab=readme-ov-file#raw
437
438[api-character-references]: #characterreferences
439
440[api-options]: #options
441
442[api-rehype-stringify]: #unifieduserehypestringify-options