diff --git a/package.json b/package.json index ba9067cb..f646b451 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,11 @@ }, "remarkConfig": { "plugins": [ - "remark-preset-wooorm" + "remark-preset-wooorm", + [ + "remark-lint-no-html", + false + ] ] }, "typeCoverage": { diff --git a/packages/rehype-cli/readme.md b/packages/rehype-cli/readme.md index fea13870..f90ba714 100644 --- a/packages/rehype-cli/readme.md +++ b/packages/rehype-cli/readme.md @@ -43,7 +43,7 @@ If not, you can always use [`rehype`][rehype-core] itself manually in a script. ## Install This package is [ESM only][esm]. -In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: +In Node.js (version 16+), install with [npm][]: ```sh npm install rehype-cli @@ -69,31 +69,32 @@ Usage: rehype [options] [path | glob ...] Options: + --[no-]color specify color in report (on by default) + --[no-]config search for configuration files (on by default) + -e --ext specify extensions + --file-path specify path to process as + -f --frail exit with 1 on warnings -h --help output usage information - -v --version output version number + --[no-]ignore search for ignore files (on by default) + -i --ignore-path specify ignore file + --ignore-path-resolve-from cwd|dir resolve patterns in `ignore-path` from its directory or cwd + --ignore-pattern specify ignore patterns + --inspect output formatted syntax tree -o --output [path] specify output location + -q --quiet output only warnings and errors -r --rc-path specify configuration file - -i --ignore-path specify ignore file + --report specify reporter -s --setting specify settings - -e --ext specify extensions - -u --use use plugins - -w --watch watch for changes and reprocess - -q --quiet output only warnings and errors -S --silent output only errors - -f --frail exit with 1 on warnings - -t --tree specify input and output as syntax tree - --report specify reporter - --file-path specify path to process as - --ignore-path-resolve-from dir|cwd resolve patterns in `ignore-path` from its directory or cwd - --ignore-pattern specify ignore patterns --silently-ignore do not fail when given ignored files + --[no-]stdout specify writing to stdout (on by default) + -t --tree specify input and output as syntax tree --tree-in specify input as syntax tree --tree-out output syntax tree - --inspect output formatted syntax tree - --[no-]stdout specify writing to stdout (on by default) - --[no-]color specify color in report (on by default) - --[no-]config search for configuration files (on by default) - --[no-]ignore search for ignore files (on by default) + -u --use use plugins + --verbose report extra info for messages + -v --version output version number + -w --watch watch for changes and reprocess Examples: @@ -107,24 +108,27 @@ Examples: $ rehype . -o ``` -More information on all these options is available at -[`unified-args`][unified-args], which does the work. +More info on all these options is available at [`unified-args`][unified-args], +which does the work. `rehype-cli` is `unified-args` preconfigured to: -* Load `rehype-` plugins -* Search for HTML extensions (`.html`, `.htm`, `.xht`, `.xhtml`) -* Ignore paths found in [`.rehypeignore` files][ignore-file] -* Load configuration from +* load `rehype-` plugins +* search for HTML extensions (`.html`, `.htm`, `.xht`, `.xhtml`) +* ignore paths found in [`.rehypeignore` files][ignore-file] +* load configuration from [`.rehyperc`, `.rehyperc.js`, etc files][config-file] -* Use configuration from +* use configuration from [`rehype` fields in `package.json` files][config-file] ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `rehype-cli@^11`, +compatible with Node.js 12. ## Security @@ -151,8 +155,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
@@ -276,8 +278,8 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize -[config-file]: https://github.com/unifiedjs/unified-engine/blob/main/doc/configure.md +[config-file]: https://github.com/unifiedjs/unified-engine/blob/main/readme.md#config-files -[ignore-file]: https://github.com/unifiedjs/unified-engine/blob/main/doc/ignore.md +[ignore-file]: https://github.com/unifiedjs/unified-engine/blob/main/readme.md#ignore-files [unified-args]: https://github.com/unifiedjs/unified-args#cli diff --git a/packages/rehype-parse/lib/index.js b/packages/rehype-parse/lib/index.js index 6c0125d9..926b4b50 100644 --- a/packages/rehype-parse/lib/index.js +++ b/packages/rehype-parse/lib/index.js @@ -23,6 +23,12 @@ import {fromHtml} from 'hast-util-from-html' /** * Plugin to add support for parsing from HTML. * + * > 👉 **Note**: this is not an XML parser. + * > It supports SVG as embedded in HTML. + * > It does not support the features available in XML. + * > Passing SVG files might break but fragments of modern SVG should be fine. + * > Use [`xast-util-from-xml`][xast-util-from-xml] to parse XML. + * * @param {Options | null | undefined} [options] * Configuration (optional). * @returns {undefined} diff --git a/packages/rehype-parse/readme.md b/packages/rehype-parse/readme.md index 30405d7b..5f89ea46 100644 --- a/packages/rehype-parse/readme.md +++ b/packages/rehype-parse/readme.md @@ -8,7 +8,7 @@ [![Backers][backers-badge]][collective] [![Chat][chat-badge]][chat] -**[rehype][]** plugin to add support for parsing HTML input. +**[rehype][]** plugin to add support for parsing from HTML. ## Contents @@ -18,6 +18,9 @@ * [Use](#use) * [API](#api) * [`unified().use(rehypeParse[, options])`](#unifieduserehypeparse-options) + * [`ErrorCode`](#errorcode) + * [`ErrorSeverity`](#errorseverity) + * [`Options`](#options) * [Examples](#examples) * [Example: fragment versus document](#example-fragment-versus-document) * [Example: whitespace around and inside ``](#example-whitespace-around-and-inside-html) @@ -43,23 +46,24 @@ See [the monorepo readme][rehype] for info on what the rehype ecosystem is. ## When should I use this? This plugin adds support to unified for parsing HTML. -You can alternatively use [`rehype`][rehype-core] instead, which combines -unified, this plugin, and [`rehype-stringify`][rehype-stringify]. +If you also need to serialize HTML, you can alternatively use +[`rehype`][rehype-core], which combines unified, this plugin, and +[`rehype-stringify`][rehype-stringify]. -When you’re in a browser, trust your content, don’t need positional info, and +When you are in a browser, trust your content, don’t need positional info, and value a smaller bundle size, you can use [`rehype-dom-parse`][rehype-dom-parse] instead. -This plugin is built on [`parse5`][parse5] and -[`hast-util-from-parse5`][hast-util-from-parse5], which deal with HTML-compliant -tokenizing, parsing, and creating nodes. +If you don’t use plugins and want to access the syntax tree, you can directly +use [`hast-util-from-html`][hast-util-from-html], which is used inside this +plugin. rehype focusses on making it easier to transform content by abstracting such internals away. ## Install This package is [ESM only][esm]. -In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: +In Node.js (version 16+), install with [npm][]: ```sh npm install rehype-parse @@ -84,22 +88,18 @@ In browsers with [`esm.sh`][esmsh]: Say we have the following module `example.js`: ```js -import {unified} from 'unified' import rehypeParse from 'rehype-parse' import rehypeRemark from 'rehype-remark' import remarkStringify from 'remark-stringify' +import {unified} from 'unified' -main() - -async function main() { - const file = await unified() - .use(rehypeParse) - .use(rehypeRemark) - .use(remarkStringify) - .process('

Hello, world!

') +const file = await unified() + .use(rehypeParse) + .use(rehypeRemark) + .use(remarkStringify) + .process('

Hello, world!

') - console.log(String(file)) -} +console.log(String(file)) ``` …running that with `node example.js` yields: @@ -111,54 +111,136 @@ async function main() { ## API This package exports no identifiers. -The default export is `rehypeParse`. +The default export is [`rehypeParse`][api-rehype-parse]. ### `unified().use(rehypeParse[, options])` -Add support for parsing HTML input. +Plugin to add support for parsing from HTML. + +###### Parameters + +* `options` ([`Options`][api-options], optional) + — configuration + +###### Returns + +Nothing (`undefined`). + +### `ErrorCode` + +Known names of [parse errors][parse-errors] (TypeScript type). + +For a bit more info on each error, see +[`hast-util-from-html`][hast-util-from-html-errors]. + +###### Type + +```ts +type ErrorCode = + | 'abandonedHeadElementChild' + | 'abruptClosingOfEmptyComment' + | 'abruptDoctypePublicIdentifier' + | 'abruptDoctypeSystemIdentifier' + | 'absenceOfDigitsInNumericCharacterReference' + | 'cdataInHtmlContent' + | 'characterReferenceOutsideUnicodeRange' + | 'closingOfElementWithOpenChildElements' + | 'controlCharacterInInputStream' + | 'controlCharacterReference' + | 'disallowedContentInNoscriptInHead' + | 'duplicateAttribute' + | 'endTagWithAttributes' + | 'endTagWithTrailingSolidus' + | 'endTagWithoutMatchingOpenElement' + | 'eofBeforeTagName' + | 'eofInCdata' + | 'eofInComment' + | 'eofInDoctype' + | 'eofInElementThatCanContainOnlyText' + | 'eofInScriptHtmlCommentLikeText' + | 'eofInTag' + | 'incorrectlyClosedComment' + | 'incorrectlyOpenedComment' + | 'invalidCharacterSequenceAfterDoctypeName' + | 'invalidFirstCharacterOfTagName' + | 'misplacedDoctype' + | 'misplacedStartTagForHeadElement' + | 'missingAttributeValue' + | 'missingDoctype' + | 'missingDoctypeName' + | 'missingDoctypePublicIdentifier' + | 'missingDoctypeSystemIdentifier' + | 'missingEndTagName' + | 'missingQuoteBeforeDoctypePublicIdentifier' + | 'missingQuoteBeforeDoctypeSystemIdentifier' + | 'missingSemicolonAfterCharacterReference' + | 'missingWhitespaceAfterDoctypePublicKeyword' + | 'missingWhitespaceAfterDoctypeSystemKeyword' + | 'missingWhitespaceBeforeDoctypeName' + | 'missingWhitespaceBetweenAttributes' + | 'missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers' + | 'nestedComment' + | 'nestedNoscriptInHead' + | 'nonConformingDoctype' + | 'nonVoidHtmlElementStartTagWithTrailingSolidus' + | 'noncharacterCharacterReference' + | 'noncharacterInInputStream' + | 'nullCharacterReference' + | 'openElementsLeftAfterEof' + | 'surrogateCharacterReference' + | 'surrogateInInputStream' + | 'unexpectedCharacterAfterDoctypeSystemIdentifier' + | 'unexpectedCharacterInAttributeName' + | 'unexpectedCharacterInUnquotedAttributeValue' + | 'unexpectedEqualsSignBeforeAttributeName' + | 'unexpectedNullCharacter' + | 'unexpectedQuestionMarkInsteadOfTagName' + | 'unexpectedSolidusInTag' + | 'unknownNamedCharacterReference' +``` -##### `options` +### `ErrorSeverity` -Configuration (optional). +Error severity (TypeScript type). -###### `options.fragment` +* `0` or `false` + — turn the parse error off +* `1` or `true` + — turn the parse error into a warning +* `2` + — turn the parse error into an actual error: processing stops -Specify whether to parse as a fragment (`boolean`, default: `false`). -The default is to expect a whole document. -In document mode, unopened `html`, `head`, and `body` elements are opened. +###### Type -###### `options.space` +```ts +type ErrorSeverity = boolean | 0 | 1 | 2 +``` -Which space the document is in (`'svg'` or `'html'`, default: `'html'`). +### `Options` -When an `` element is found in the HTML space, `rehype-parse` already -automatically switches to and from the SVG space when entering and exiting it. +Configuration (TypeScript type). -> 👉 **Note**: rehype is not an XML parser. +> 👉 **Note**: this is not an XML parser. > It supports SVG as embedded in HTML. > It does not support the features available in XML. > Passing SVG files might break but fragments of modern SVG should be fine. - -> 👉 **Note**: make sure to set `fragment: true` if `space: 'svg'`. - -###### `options.emitParseErrors` - -Emit [HTML parse errors][parse-errors] as warning messages -(`boolean`, default: `false`). - -Specific rules can be turned off by setting their IDs in `options` to `false` -(or `0`). -The default, when `emitParseErrors: true`, is `true` (or `1`), and means that -rules emit as warnings. -Rules can also be configured with `2`, to turn them into fatal errors. - -The list of parse errors: - -To do: remove this. - -###### `options.verbose` - -Add extra positional info (`boolean`, default: `false`). +> Use [`xast-util-from-xml`][xast-util-from-xml] to parse XML. + +###### Fields + +* `fragment` (`boolean`, default: `false`) + — whether to parse as a fragment; by default unopened `html`, `head`, and + `body` elements are opened +* `emitParseErrors` (`boolean`, default: `false`) + — whether to emit [parse errors][parse-errors] while parsing +* `space` (`'html'` or `'svg'`, default: `'html'`) + — which space the document is in +* `verbose` (`boolean`, default: `false`) + — add extra positional info about attributes, start tags, and end tags +* [`[key in ErrorCode]`][api-error-code] + ([`ErrorSeverity`][api-error-severity], default: `1` if + `options.emitParseErrors`, otherwise `0`) + — configure specific [parse errors][parse-errors] ## Examples @@ -168,33 +250,29 @@ The following example shows the difference between parsing as a document and parsing as a fragment: ```js -import {unified} from 'unified' import rehypeParse from 'rehype-parse' import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' -main() - -async function main() { - const doc = 'Hi!

Hello!

' +const doc = 'Hi!

Hello!

' - console.log( - String( - await unified() - .use(rehypeParse, {fragment: true}) - .use(rehypeStringify) - .process(doc) - ) +console.log( + String( + await unified() + .use(rehypeParse, {fragment: true}) + .use(rehypeStringify) + .process(doc) ) - - console.log( - String( - await unified() - .use(rehypeParse, {fragment: false}) - .use(rehypeStringify) - .process(doc) - ) +) + +console.log( + String( + await unified() + .use(rehypeParse, {fragment: false}) + .use(rehypeStringify) + .process(doc) ) -} +) ``` …yields: @@ -216,11 +294,11 @@ The following example shows how whitespace is handled when around and directly inside the `` element: ```js -import {unified} from 'unified' import rehypeParse from 'rehype-parse' import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' -main(` +const doc = ` Hi! @@ -228,13 +306,11 @@ main(`

Hello!

-`) +` -async function main(doc) { - console.log( - String(await unified().use(rehypeParse).use(rehypeStringify).process(doc)) - ) -} +console.log( + String(await unified().use(rehypeParse).use(rehypeStringify).process(doc)) +) ``` …yields (where `␠` represents a space character): @@ -265,34 +341,29 @@ improve the source code. The following example shows how HTML parse errors can be enabled and configured: ```js -import {reporter} from 'vfile-reporter' -import {unified} from 'unified' import rehypeParse from 'rehype-parse' import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' +import {reporter} from 'vfile-reporter' -main() - -async function main() { - const file = await unified() - .use(rehypeParse, { - emitParseErrors: true, // Emit all. - missingWhitespaceBeforeDoctypeName: 2, // Mark one as a fatal error. - nonVoidHtmlElementStartTagWithTrailingSolidus: false // Ignore one. - }) - .use(rehypeStringify) - .process(` +const file = await unified() + .use(rehypeParse, { + emitParseErrors: true, // Emit all. + missingWhitespaceBeforeDoctypeName: 2, // Mark one as a fatal error. + nonVoidHtmlElementStartTagWithTrailingSolidus: false // Ignore one. + }) + .use(rehypeStringify).process(` Hello…

World!

`) - console.log(reporter(file)) -} +console.log(reporter(file)) ``` …yields: ```html - 1:10-1:10 error Missing whitespace before doctype name missing-whitespace-before-doctype-name parse-error - 2:23-2:23 warning Unexpected duplicate attribute duplicate-attribute parse-error +1:10-1:10 error Missing whitespace before doctype name missing-whitespace-before-doctype-name hast-util-from-html +2:23-2:23 warning Unexpected duplicate attribute duplicate-attribute hast-util-from-html 2 messages (✖ 1 error, ⚠ 1 warning) ``` @@ -311,7 +382,7 @@ async function main() { ## Syntax HTML is parsed according to WHATWG HTML (the living standard), which is also -followed by browsers such as Chrome and Firefox. +followed by all browsers. ## Syntax tree @@ -320,18 +391,23 @@ The syntax tree format used in rehype is [hast][]. ## Types This package is fully typed with [TypeScript][]. -The extra types `Options`, `ErrorCode`, and `ErrorSeverity` are exported. +It exports the additional types [`ErrorCode`][api-error-code], +[`ErrorSeverity`][api-error-severity], and +[`Options`][api-options]. ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `rehype-parse@^8`, +compatible with Node.js 12. ## Security -As **rehype** works on HTML, and improper use of HTML can open you up to a +As **rehype** works on HTML and improper use of HTML can open you up to a [cross-site scripting (XSS)][xss] attack, use of rehype can also be unsafe. Use [`rehype-sanitize`][rehype-sanitize] to make the tree safe. @@ -354,8 +430,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
@@ -441,9 +515,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/rehype-parse -[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype-parse.svg +[size-badge]: https://img.shields.io/bundlejs/size/rehype-parse -[size]: https://bundlephobia.com/result?p=rehype-parse +[size]: https://bundlejs.com/?q=rehype-parse [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg @@ -485,18 +559,28 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [typescript]: https://www.typescriptlang.org -[rehype-stringify]: ../rehype-stringify/ +[hast-util-from-html]: https://github.com/syntax-tree/hast-util-from-html -[rehype-core]: ../rehype/ +[hast-util-from-html-errors]: https://github.com/syntax-tree/hast-util-from-html#optionskey-in-errorcode -[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize +[xast-util-from-xml]: https://github.com/syntax-tree/xast-util-from-xml + +[rehype-dom-parse]: https://github.com/rehypejs/rehype-dom/tree/main/packages/rehype-dom-parse -[hast-util-from-parse5]: https://github.com/syntax-tree/hast-util-from-parse5 +[rehype-format]: https://github.com/rehypejs/rehype-format + +[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize [parse-errors]: https://html.spec.whatwg.org/multipage/parsing.html#parse-errors -[rehype-dom-parse]: https://github.com/rehypejs/rehype-dom/tree/main/packages/rehype-dom-parse +[rehype-core]: ../rehype/ -[rehype-format]: https://github.com/rehypejs/rehype-format +[rehype-stringify]: ../rehype-stringify/ + +[api-error-code]: #errorcode + +[api-error-severity]: #errorseverity + +[api-options]: #options -[parse5]: https://github.com/inikulin/parse5 +[api-rehype-parse]: #unifieduserehypeparse-options diff --git a/packages/rehype-stringify/index.d.ts b/packages/rehype-stringify/index.d.ts index 8b14a783..3c1b483a 100644 --- a/packages/rehype-stringify/index.d.ts +++ b/packages/rehype-stringify/index.d.ts @@ -1,8 +1,8 @@ import type {Root} from 'hast' import type {Plugin} from 'unified' -import type {Options} from './lib/index.js' +import type {Options} from 'hast-util-to-html' -export type {Options} from './lib/index.js' +export type {CharacterReferences, Options} from 'hast-util-to-html' /** * Plugin to add support for serializing as HTML. diff --git a/packages/rehype-stringify/readme.md b/packages/rehype-stringify/readme.md index 7e55f07b..4aef3da7 100644 --- a/packages/rehype-stringify/readme.md +++ b/packages/rehype-stringify/readme.md @@ -8,7 +8,7 @@ [![Backers][backers-badge]][collective] [![Chat][chat-badge]][chat] -**[rehype][]** plugin to add support for serializing HTML. +**[rehype][]** plugin to add support for serializing to HTML. ## Contents @@ -18,6 +18,8 @@ * [Use](#use) * [API](#api) * [`unified().use(rehypeStringify[, options])`](#unifieduserehypestringify-options) + * [`CharacterReferences`](#characterreferences) + * [`Options`](#options) * [Syntax](#syntax) * [Syntax tree](#syntax-tree) * [Types](#types) @@ -38,15 +40,16 @@ See [the monorepo readme][rehype] for info on what the rehype ecosystem is. ## When should I use this? This plugin adds support to unified for serializing HTML. -You can alternatively use [`rehype`][rehype-core] instead, which combines -unified, [`rehype-parse`][rehype-parse], and this plugin. +If you also need to parse HTML, you can alternatively use +[`rehype`][rehype-core], which combines unified, +[`rehype-parse`][rehype-parse], and this plugin. -When you’re in a browser, trust your content, don’t need formatting options, and -value a smaller bundle size, you can use +When you are in a browser, trust your content, don’t need formatting options, +and value a smaller bundle size, you can use [`rehype-dom-stringify`][rehype-dom-stringify] instead. -This plugin is built on [`hast-util-to-html`][hast-util-to-html], which turns -[hast][] syntax trees into a string. +If you don’t use plugins and have access to a syntax tree, you can directly use +[`hast-util-to-html`][hast-util-to-html], which is used inside this plugin. rehype focusses on making it easier to transform content by abstracting such internals away. @@ -59,7 +62,7 @@ inverse: minified and mangled HTML. ## Install This package is [ESM only][esm]. -In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: +In Node.js (version 16+), install with [npm][]: ```sh npm install rehype-stringify @@ -84,24 +87,20 @@ In browsers with [`esm.sh`][esmsh]: Say we have the following module `example.js`: ```js -import {unified} from 'unified' -import remarkParse from 'remark-parse' -import remarkGfm from 'remark-gfm' import remarkRehype from 'remark-rehype' import rehypeStringify from 'rehype-stringify' +import remarkGfm from 'remark-gfm' +import remarkParse from 'remark-parse' +import {unified} from 'unified' -main() - -async function main() { - const file = await unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkRehype) - .use(rehypeStringify) - .process('# Hi\n\n*Hello*, world!') +const file = await unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkRehype) + .use(rehypeStringify) + .process('# Hi\n\n*Hello*, world!') - console.log(String(file)) -} +console.log(String(file)) ``` …running that with `node example.js` yields: @@ -114,172 +113,130 @@ async function main() { ## API This package exports no identifiers. -The default export is `rehypeStringify`. +The default export is [`rehypeStringify`][api-rehype-stringify]. ### `unified().use(rehypeStringify[, options])` -Add support for serializing HTML. -Options are passed to [`hast-util-to-html`][hast-util-to-html]. - -##### `options` - -Configuration (optional). - -###### `options.entities` - -Define how to create character references (`Object`, default: `{}`). -Configuration is passed to [`stringify-entities`][stringify-entities]. -You can use the fields `useNamedReferences`, `useShortestReferences`, and -`omitOptionalSemicolons`. -You cannot use the fields `escapeOnly`, `attribute`, or `subset`). - -###### `options.upperDoctype` - -Use a `
  • one
  • two
  • `, both `` closing tags -can be omitted. -The first because it’s followed by another `li`, the last because it’s followed -by nothing. - -Not used in the SVG space. - -###### `options.collapseEmptyAttributes` - -Collapse empty attributes: get `class` instead of `class=""` (`boolean`, -default: `false`). - -Not used in the SVG space. - -> 👉 **Note**: boolean attributes (such as `hidden`) are always collapsed. - -###### `options.closeSelfClosing` - -Close self-closing nodes with an extra slash (`/`): `` instead of -`` (`boolean`, default: `false`). -See `tightSelfClosing` to control whether a space is used before the slash. +Plugin to add support for serializing to HTML. -Not used in the SVG space. +###### Parameters -###### `options.closeEmptyElements` +* `options` ([`Options`][api-options], optional) + — configuration -Close SVG elements without any content with slash (`/`) on the opening tag -instead of an end tag: `` instead of `` (`boolean`, -default: `false`). -See `tightSelfClosing` to control whether a space is used before the slash. +###### Returns -Not used in the HTML space. +Nothing (`undefined`). -###### `options.tightSelfClosing` +### `CharacterReferences` -Do not use an extra space when closing self-closing elements: `` instead -of `` (`boolean`, default: `false`). +How to serialize character references (TypeScript type). -> 👉 **Note**: only used if `closeSelfClosing: true` or -> `closeEmptyElements: true`. +> ⚠️ **Note**: `omitOptionalSemicolons` creates what HTML calls “parse errors” +> but is otherwise still valid HTML — don’t use this except when building a +> minifier. +> Omitting semicolons is possible for certain named and numeric references in +> some cases. -###### `options.tightCommaSeparatedLists` +> ⚠️ **Note**: `useNamedReferences` can be omitted when using +> `useShortestReferences`. -Join known comma-separated attribute values with just a comma (`,`), instead of -padding them on the right as well (`,␠`, where `␠` represents a space) -(`boolean`, default: `false`). +###### Fields -###### `options.tightAttributes` +* `useNamedReferences` (`boolean`, default: `false`) + — prefer named character references (`&`) where possible +* `omitOptionalSemicolons` (`boolean`, default: `false`) + — whether to omit semicolons when possible +* `useShortestReferences` (`boolean`, default: `false`) + — prefer the shortest possible reference, if that results in less bytes -Join attributes together, without whitespace, if possible: get -`class="a b"title="c d"` instead of `class="a b" title="c d"` to save bytes -(`boolean`, default: `false`). +### `Options` -Not used in the SVG space. +Configuration (TypeScript type). -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). +> ⚠️ **Danger**: only set `allowDangerousCharacters` and `allowDangerousHtml` if +> you completely trust the content. -###### `options.tightDoctype` +> 👉 **Note**: `allowParseErrors`, `bogusComments`, `tightAttributes`, and +> `tightDoctype` +> intentionally create parse errors in markup (how parse errors are handled is +> well defined, so this works but isn’t pretty). -Drop unneeded spaces in doctypes: `` instead of `` -to save bytes (`boolean`, default: `false`). - -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). - -###### `options.bogusComments` - -Use “bogus comments” instead of comments to save byes: `` instead of -`` (`boolean`, default: `false`). - -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). - -###### `options.allowParseErrors` - -Do not encode characters which cause parse errors (even though they work), to -save bytes (`boolean`, default: `false`). - -Not used in the SVG space. - -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). - -###### `options.allowDangerousCharacters` - -Do not encode some characters which cause XSS vulnerabilities in older browsers -(`boolean`, default: `false`). - -> ⚠️ **Danger**: only set this if you completely trust the content. - -###### `options.allowDangerousHtml` - -Allow `raw` nodes and insert them as raw HTML. -When falsey, encodes `raw` nodes (`boolean`, default: `false`). - -> ⚠️ **Danger**: only set this if you completely trust the content. - -###### `options.space` - -Which space the document is in (`'svg'` or `'html'`, default: `'html'`). - -When an `` element is found in the HTML space, `rehype-stringify` already -automatically switches to and from the SVG space when entering and exiting it. - -> 👉 **Note**: rehype is not an XML parser. +> 👉 **Note**: this is not an XML serializer. > It supports SVG as embedded in HTML. > It does not support the features available in XML. -> Passing SVG files might break but fragments of modern SVG should be fine. - -###### `options.voids` - -Tag names of elements to serialize without closing tag (`Array`, -default: [`html-void-elements`][html-void-elements]). - -Not used in the SVG space. - -> 👉 **Note**: It’s highly unlikely that you want to pass this. -> It’s only really applicable to the `hast-util-to-html` utility. +> Use [`xast-util-to-xml`][xast-util-to-xml] to serialize XML. + +###### Fields + +* `allowDangerousCharacters` (`boolean`, default: `false`) + — do not encode some characters which cause XSS vulnerabilities in older + browsers +* `allowDangerousHtml` (`boolean`, default: `false`) + — allow [`Raw`][raw] nodes and insert them as raw HTML; when `false`, `Raw` + nodes are encoded +* `allowParseErrors` (`boolean`, default: `false`) + — do not encode characters which cause parse errors (even though they + work), to save bytes; not used in the SVG space. +* `bogusComments` (`boolean`, default: `false`) + — use “bogus comments” instead of comments to save byes: `` + instead of `` +* `characterReferences` ([`CharacterReferences`][api-character-references], + optional) + — configure how to serialize character references +* `closeEmptyElements` (`boolean`, default: `false`) + — close SVG elements without any content with slash (`/`) on the opening + tag instead of an end tag: `` instead of ``; + see `tightSelfClosing` to control whether a space is used before the slash; + not used in the HTML space +* `closeSelfClosing` (`boolean`, default: `false`) + — close self-closing nodes with an extra slash (`/`): `` instead of + ``; see `tightSelfClosing` to control whether a space is used before + the slash; not used in the SVG space. +* `collapseEmptyAttributes` (`boolean`, default: `false`) + — collapse empty attributes: get `class` instead of `class=""`; not used in + the SVG space; boolean attributes (such as `hidden`) are always collapsed +* `omitOptionalTags` (`boolean`, default: `false`) + — omit optional opening and closing tags; to illustrate, in + `
    1. one
    2. two
    `, both `` closing tags can be + omitted, the first because it’s followed by another `li`, the last because + it’s followed by nothing; not used in the SVG space +* `preferUnquoted` (`boolean`, default: `false`) + — leave attributes unquoted if that results in less bytes; not used in the + SVG space +* `quote` (`'"'` or `"'"`, default: `'"'`) + — preferred quote to use +* `quoteSmart` (`boolean`, default: `false`) + — use the other quote if that results in less bytes +* `space` (`'html'` or `'svg'`, default: `'html'`) + — which space the document is in; when an `` element is found in the + HTML space, this package already automatically switches to and from the SVG +* `tightAttributes` (`boolean`, default: `false`) + — join attributes together, without whitespace, if possible: get + `class="a b"title="c d"` instead of `class="a b" title="c d"` to save + bytes; not used in the SVG space +* `tightCommaSeparatedLists` (`boolean`, default: `false`) + — join known comma-separated attribute values with just a comma (`,`), + instead of padding them on the right as well (`,␠`, where `␠` represents a + space) +* `tightDoctype` (`boolean`, default: `false`) + — drop unneeded spaces in doctypes: `` instead of + `` to save bytes +* `tightSelfClosing` (`boolean`, default: `false`). + — do not use an extra space when closing self-closing elements: `` + instead of ``; only used if `closeSelfClosing: true` or + `closeEmptyElements: true` +* `upperDoctype` (`boolean`, default: `false`). + — use a ``, default: + [`html-void-elements`][html-void-elements]) + — tag names of elements to serialize without closing tag; not used in the + SVG space ## Syntax HTML is serialized according to WHATWG HTML (the living standard), which is also -followed by browsers such as Chrome and Firefox. +followed by all browsers. ## Syntax tree @@ -288,14 +245,19 @@ The syntax tree format used in rehype is [hast][]. ## Types This package is fully typed with [TypeScript][]. -The extra types `Options` are exported. +It exports the additional types +[`CharacterReferences`][api-character-references] and +[`Options`][api-options]. ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `rehype-stringify@^9`, +compatible with Node.js 12. ## Security @@ -322,8 +284,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
    @@ -409,9 +369,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/rehype-stringify -[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype-stringify.svg +[size-badge]: https://img.shields.io/bundlejs/size/rehype-stringify -[size]: https://bundlephobia.com/result?p=rehype-stringify +[size]: https://bundlejs.com/?q=rehype-stringify [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg @@ -467,6 +427,16 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [hast-util-to-html]: https://github.com/syntax-tree/hast-util-to-html -[stringify-entities]: https://github.com/wooorm/stringify-entities +[xast-util-to-xml]: https://github.com/syntax-tree/xast-util-to-xml [html-void-elements]: https://github.com/wooorm/html-void-elements + + + +[raw]: https://github.com/syntax-tree/mdast-util-to-hast?tab=readme-ov-file#raw + +[api-character-references]: #characterreferences + +[api-options]: #options + +[api-rehype-stringify]: #unifieduserehypestringify-options diff --git a/packages/rehype/index.js b/packages/rehype/index.js index 0e6e9757..567c588e 100644 --- a/packages/rehype/index.js +++ b/packages/rehype/index.js @@ -3,6 +3,7 @@ import rehypeStringify from 'rehype-stringify' import {unified} from 'unified' /** - * Processor for HTML. + * Create a new unified processor that already uses `rehype-parse` and + * `rehype-stringify`. */ export const rehype = unified().use(rehypeParse).use(rehypeStringify).freeze() diff --git a/packages/rehype/readme.md b/packages/rehype/readme.md index e4317251..2f54910e 100644 --- a/packages/rehype/readme.md +++ b/packages/rehype/readme.md @@ -8,8 +8,8 @@ [![Backers][backers-badge]][collective] [![Chat][chat-badge]][chat] -**[unified][]** processor with support for parsing HTML input and serializing -HTML as output. +**[unified][]** processor to add support for parsing from HTML and serializing +to HTML. ## Contents @@ -32,7 +32,7 @@ HTML as output. ## What is this? -This package is a [unified][] processor with support for parsing HTML input +This package is a [unified][] processor with support for parsing HTML as input and serializing HTML as output by using unified with [`rehype-parse`][rehype-parse] and [`rehype-stringify`][rehype-stringify]. @@ -58,7 +58,7 @@ line, you can use [`rehype-cli`][rehype-cli]. ## Install This package is [ESM only][esm]. -In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: +In Node.js (version 16+), install with [npm][]: ```sh npm install rehype @@ -86,12 +86,7 @@ Say we have the following module `example.js`: import {rehype} from 'rehype' import rehypeFormat from 'rehype-format' -main() - -async function main() { - const file = await rehype() - .use(rehypeFormat) - .process(` +const file = await rehype().use(rehypeFormat).process(` Hi! @@ -101,8 +96,7 @@ async function main() { `) - console.error(String(file)) -} +console.error(String(file)) ``` …running that with `node example.js` yields: @@ -121,13 +115,15 @@ async function main() { ## API -This package exports the following identifier: `rehype`. +This package exports the identifier [`rehype`][api-rehype]. There is no default export. ### `rehype()` -Create a new (unfrozen) unified processor that already uses `rehype-parse` and -`rehype-stringify` and you can add more plugins to. +Create a new unified processor that already uses +[`rehype-parse`][rehype-parse] and [`rehype-stringify`][rehype-stringify]. + +You can add more plugins with `use`. See [`unified`][unified] for more information. ## Examples @@ -135,30 +131,30 @@ See [`unified`][unified] for more information. ### Example: passing options to `rehype-parse`, `rehype-stringify` When you use `rehype-parse` or `rehype-stringify` manually you can pass options -to `use`. +directly to them with `use`. Because both plugins are already used in `rehype`, that’s not possible. To define options for them, you can instead pass options to `data`: ```js -import {reporter} from 'vfile-reporter' import {rehype} from 'rehype' +import {reporter} from 'vfile-reporter' -main() - -async function main() { - const file = await rehype() - .data('settings', {emitParseErrors: true, fragment: true, preferUnquoted: true}) - .process('
    ') +const file = await rehype() + .data('settings', { + emitParseErrors: true, + fragment: true, + preferUnquoted: true + }) + .process('
    ') - console.error(reporter(file)) - console.log(String(file)) -} +console.error(reporter(file)) +console.log(String(file)) ``` …yields: ```txt - 1:21-1:21 warning Unexpected duplicate attribute duplicate-attribute parse-error +1:21-1:21 warning Unexpected duplicate attribute duplicate-attribute hast-util-from-html ⚠ 1 warning ``` @@ -169,8 +165,8 @@ async function main() { ## Syntax -HTML is parsed according to WHATWG HTML (the living standard), which is also -followed by browsers such as Chrome and Firefox. +HTML is parsed and serialized according to WHATWG HTML (the living standard), +which is also followed by all browsers. ## Syntax tree @@ -179,14 +175,17 @@ The syntax tree format used in rehype is [hast][]. ## Types This package is fully typed with [TypeScript][]. -There are no extra types exported. +It exports no additional types. ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line, `rehype@^12`, compatible +with Node.js 12. ## Security @@ -213,8 +212,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
    @@ -300,9 +297,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/rehype -[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype.svg +[size-badge]: https://img.shields.io/bundlejs/size/rehype -[size]: https://bundlephobia.com/result?p=rehype +[size]: https://bundlejs.com/?q=rehype [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg @@ -353,3 +350,5 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize [rehype-dom]: https://github.com/rehypejs/rehype-dom/tree/main/packages/rehype-dom + +[api-rehype]: #rehype-1 diff --git a/readme.md b/readme.md index 4a117b8c..a9914f3b 100644 --- a/readme.md +++ b/readme.md @@ -41,8 +41,7 @@ You can use the many existing plugins or you can make your own. ## What is this? -You can use plugins to format or minify HTML. -**In**: +With this project and a plugin, you can turn this HTML: ```html @@ -58,26 +57,72 @@ You can use plugins to format or minify HTML. ``` -**Out**: +…into the following HTML: ```html Saturn

    Saturn

    Saturn is a gas giant composed predominantly of hydrogen and helium. ``` -You can use plugins to change HTML. -**In**: +

    Show example code + +```js +import rehypeParse from 'rehype-parse' +import rehypePresetMinify from 'rehype-preset-minify' +import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' + +const file = await unified() + .use(rehypeParse) + .use(rehypePresetMinify) + .use(rehypeStringify).process(` + + + + Saturn + + +

    Saturn

    +

    Saturn is a gas giant composed predominantly of hydrogen and helium.

    + +`) + +console.log(String(file)) +``` + +
    + +With another plugin, you can turn this HTML: ```html

    Hi, Saturn!

    ``` -**Plugin**: +…into the following HTML: + +```html +

    Hi, Saturn!

    +``` + +
    Show example code ```js +import rehypeParse from 'rehype-parse' +import rehypeStringify from 'rehype-stringify' +import {unified} from 'unified' import {visit} from 'unist-util-visit' -/** @type {import('unified').Plugin<[], import('hast').Root>} */ +const file = await unified() + .use(rehypeParse, {fragment: true}) + .use(myRehypePluginToIncreaseHeadings) + .use(rehypeStringify) + .process('

    Hi, Saturn!

    ') + +console.log(String(file)) + function myRehypePluginToIncreaseHeadings() { + /** + * @param {import('hast').Root} tree + */ return function (tree) { visit(tree, 'element', function (node) { if (['h1', 'h2', 'h3', 'h4', 'h5'].includes(node.tagName)) { @@ -88,11 +133,7 @@ function myRehypePluginToIncreaseHeadings() { } ``` -**Out**: - -```html -

    Hi, Saturn!

    -``` +
    You can use rehype for many different things. **[unified][]** is the core project that transforms content with ASTs. @@ -148,10 +189,12 @@ Types for hast are available in [`@types/hast`][types-hast]. ## Compatibility -Projects maintained by the unified collective are compatible with all maintained +Projects maintained by the unified collective are compatible with maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, and 16.0+. -Our projects sometimes work with older versions, but this is not guaranteed. + +When we cut a new major release, we drop support for unmaintained versions of +Node. +This means we try to keep the current release line compatible with Node.js 12. ## Security @@ -179,8 +222,6 @@ abide by its terms. Support this effort and give back by sponsoring on [OpenCollective][collective]! - -
    @@ -268,9 +309,9 @@ Support this effort and give back by sponsoring on [OpenCollective][collective]! [downloads]: https://www.npmjs.com/package/rehype -[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype.svg +[size-badge]: https://img.shields.io/bundlejs/size/rehype -[size]: https://bundlephobia.com/result?p=rehype +[size]: https://bundlejs.com/?q=rehype [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg