remark-rehype
Advanced tools
Comparing version 10.1.0 to 11.0.0
@@ -1,4 +0,3 @@ | ||
export {default} from './lib/index.js' | ||
export type Options = import('./lib/index.js').Options | ||
export type Processor = import('./lib/index.js').Processor | ||
export {defaultHandlers, all, one} from 'mdast-util-to-hast' | ||
export { default } from "./lib/index.js"; | ||
export type Options = import('./lib/index.js').Options; | ||
export { defaultFootnoteBackContent, defaultFootnoteBackLabel, defaultHandlers } from "mdast-util-to-hast"; |
/** | ||
* @typedef {import('./lib/index.js').Options} Options | ||
* @typedef {import('./lib/index.js').Processor} Processor | ||
*/ | ||
export {defaultHandlers, all, one} from 'mdast-util-to-hast' | ||
export { | ||
defaultFootnoteBackContent, | ||
defaultFootnoteBackLabel, | ||
defaultHandlers | ||
} from 'mdast-util-to-hast' | ||
export {default} from './lib/index.js' |
@@ -1,40 +0,210 @@ | ||
export default remarkRehype | ||
export type HastRoot = import('hast').Root | ||
export type MdastRoot = import('mdast').Root | ||
export type Options = import('mdast-util-to-hast').Options | ||
export type Processor = import('unified').Processor<any, any, any, any> | ||
export type DoNotTouchAsThisImportIncludesRawInTree = | ||
typeof import('mdast-util-to-hast') | ||
/** | ||
* Plugin that turns markdown into HTML to support rehype. | ||
* Turn markdown into HTML. | ||
* | ||
* * If a destination processor is given, that processor runs with a new HTML | ||
* (hast) tree (bridge-mode). | ||
* As the given processor runs with a hast tree, and rehype plugins support | ||
* hast, that means rehype plugins can be used with the given processor. | ||
* The hast tree is discarded in the end. | ||
* It’s highly unlikely that you want to do this. | ||
* * The common case is to not pass a destination processor, in which case the | ||
* current processor continues running with a new HTML (hast) tree | ||
* (mutate-mode). | ||
* As the current processor continues with a hast tree, and rehype plugins | ||
* support hast, that means rehype plugins can be used after | ||
* `remark-rehype`. | ||
* It’s likely that this is what you want to do. | ||
* ##### Notes | ||
* | ||
* @param destination | ||
* Optional unified processor. | ||
* @param options | ||
* Options passed to `mdast-util-to-hast`. | ||
* ###### Signature | ||
* | ||
* * if a processor is given, runs the (rehype) plugins used on it with a | ||
* hast tree, then discards the result (*bridge mode*) | ||
* * otherwise, returns a hast tree, the plugins used after `remarkRehype` | ||
* are rehype plugins (*mutate mode*) | ||
* | ||
* > 👉 **Note**: It’s highly unlikely that you want to pass a `processor`. | ||
* | ||
* ###### HTML | ||
* | ||
* Raw HTML is available in mdast as `html` nodes and can be embedded in hast | ||
* as semistandard `raw` nodes. | ||
* Most plugins ignore `raw` nodes but two notable ones don’t: | ||
* | ||
* * `rehype-stringify` also has an option `allowDangerousHtml` which will | ||
* output the raw HTML. | ||
* This is typically discouraged as noted by the option name but is useful if | ||
* you completely trust authors | ||
* * `rehype-raw` can handle the raw embedded HTML strings by parsing them | ||
* into standard hast nodes (`element`, `text`, etc). | ||
* This is a heavy task as it needs a full HTML parser, but it is the only way | ||
* to support untrusted content | ||
* | ||
* ###### Footnotes | ||
* | ||
* Many options supported here relate to footnotes. | ||
* Footnotes are not specified by CommonMark, which we follow by default. | ||
* They are supported by GitHub, so footnotes can be enabled in markdown with | ||
* `remark-gfm`. | ||
* | ||
* The options `footnoteBackLabel` and `footnoteLabel` define natural language | ||
* that explains footnotes, which is hidden for sighted users but shown to | ||
* assistive technology. | ||
* When your page is not in English, you must define translated values. | ||
* | ||
* Back references use ARIA attributes, but the section label itself uses a | ||
* heading that is hidden with an `sr-only` class. | ||
* To show it to sighted users, define different attributes in | ||
* `footnoteLabelProperties`. | ||
* | ||
* ###### Clobbering | ||
* | ||
* Footnotes introduces a problem, as it links footnote calls to footnote | ||
* definitions on the page through `id` attributes generated from user content, | ||
* which results in DOM clobbering. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id=x></p> | ||
* <script>alert(x) // `x` now refers to the DOM `p#x` element</script> | ||
* ``` | ||
* | ||
* Elements by their ID are made available by browsers on the `window` object, | ||
* which is a security risk. | ||
* Using a prefix solves this problem. | ||
* | ||
* More information on how to handle clobbering and the prefix is explained in | ||
* *Example: headings (DOM clobbering)* in `rehype-sanitize`. | ||
* | ||
* ###### Unknown nodes | ||
* | ||
* Unknown nodes are nodes with a type that isn’t in `handlers` or `passThrough`. | ||
* The default behavior for unknown nodes is: | ||
* | ||
* * when the node has a `value` (and doesn’t have `data.hName`, | ||
* `data.hProperties`, or `data.hChildren`, see later), create a hast `text` | ||
* node | ||
* * otherwise, create a `<div>` element (which could be changed with | ||
* `data.hName`), with its children mapped from mdast to hast as well | ||
* | ||
* This behavior can be changed by passing an `unknownHandler`. | ||
* | ||
* @overload | ||
* @param {Processor} processor | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* @returns {TransformBridge} | ||
* | ||
* @overload | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* @returns {TransformMutate} | ||
* | ||
* @param {Readonly<Options> | Processor | null | undefined} [destination] | ||
* Processor or configuration (optional). | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* When a processor was given, configuration (optional). | ||
* @returns {TransformBridge | TransformMutate} | ||
* Transform. | ||
*/ | ||
declare const remarkRehype: import('unified').Plugin< | ||
| [ | ||
import('unified').Processor<any, any, any, any>, | ||
(import('mdast-util-to-hast/lib').Options | undefined)? | ||
] | ||
| [null | undefined, (import('mdast-util-to-hast/lib').Options | undefined)?] | ||
| [import('mdast-util-to-hast/lib').Options] | ||
| [], | ||
import('mdast').Root, | ||
import('mdast').Root | ||
> | ||
export default function remarkRehype(processor: Processor, options?: Readonly<Options> | null | undefined): TransformBridge; | ||
/** | ||
* Turn markdown into HTML. | ||
* | ||
* ##### Notes | ||
* | ||
* ###### Signature | ||
* | ||
* * if a processor is given, runs the (rehype) plugins used on it with a | ||
* hast tree, then discards the result (*bridge mode*) | ||
* * otherwise, returns a hast tree, the plugins used after `remarkRehype` | ||
* are rehype plugins (*mutate mode*) | ||
* | ||
* > 👉 **Note**: It’s highly unlikely that you want to pass a `processor`. | ||
* | ||
* ###### HTML | ||
* | ||
* Raw HTML is available in mdast as `html` nodes and can be embedded in hast | ||
* as semistandard `raw` nodes. | ||
* Most plugins ignore `raw` nodes but two notable ones don’t: | ||
* | ||
* * `rehype-stringify` also has an option `allowDangerousHtml` which will | ||
* output the raw HTML. | ||
* This is typically discouraged as noted by the option name but is useful if | ||
* you completely trust authors | ||
* * `rehype-raw` can handle the raw embedded HTML strings by parsing them | ||
* into standard hast nodes (`element`, `text`, etc). | ||
* This is a heavy task as it needs a full HTML parser, but it is the only way | ||
* to support untrusted content | ||
* | ||
* ###### Footnotes | ||
* | ||
* Many options supported here relate to footnotes. | ||
* Footnotes are not specified by CommonMark, which we follow by default. | ||
* They are supported by GitHub, so footnotes can be enabled in markdown with | ||
* `remark-gfm`. | ||
* | ||
* The options `footnoteBackLabel` and `footnoteLabel` define natural language | ||
* that explains footnotes, which is hidden for sighted users but shown to | ||
* assistive technology. | ||
* When your page is not in English, you must define translated values. | ||
* | ||
* Back references use ARIA attributes, but the section label itself uses a | ||
* heading that is hidden with an `sr-only` class. | ||
* To show it to sighted users, define different attributes in | ||
* `footnoteLabelProperties`. | ||
* | ||
* ###### Clobbering | ||
* | ||
* Footnotes introduces a problem, as it links footnote calls to footnote | ||
* definitions on the page through `id` attributes generated from user content, | ||
* which results in DOM clobbering. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id=x></p> | ||
* <script>alert(x) // `x` now refers to the DOM `p#x` element</script> | ||
* ``` | ||
* | ||
* Elements by their ID are made available by browsers on the `window` object, | ||
* which is a security risk. | ||
* Using a prefix solves this problem. | ||
* | ||
* More information on how to handle clobbering and the prefix is explained in | ||
* *Example: headings (DOM clobbering)* in `rehype-sanitize`. | ||
* | ||
* ###### Unknown nodes | ||
* | ||
* Unknown nodes are nodes with a type that isn’t in `handlers` or `passThrough`. | ||
* The default behavior for unknown nodes is: | ||
* | ||
* * when the node has a `value` (and doesn’t have `data.hName`, | ||
* `data.hProperties`, or `data.hChildren`, see later), create a hast `text` | ||
* node | ||
* * otherwise, create a `<div>` element (which could be changed with | ||
* `data.hName`), with its children mapped from mdast to hast as well | ||
* | ||
* This behavior can be changed by passing an `unknownHandler`. | ||
* | ||
* @overload | ||
* @param {Processor} processor | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* @returns {TransformBridge} | ||
* | ||
* @overload | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* @returns {TransformMutate} | ||
* | ||
* @param {Readonly<Options> | Processor | null | undefined} [destination] | ||
* Processor or configuration (optional). | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* When a processor was given, configuration (optional). | ||
* @returns {TransformBridge | TransformMutate} | ||
* Transform. | ||
*/ | ||
export default function remarkRehype(options?: Readonly<Options> | null | undefined): TransformMutate; | ||
export type HastRoot = import('hast').Root; | ||
export type MdastRoot = import('mdast').Root; | ||
export type Options = import('mdast-util-to-hast').Options; | ||
export type Processor = import('unified').Processor; | ||
export type VFile = import('vfile').VFile; | ||
/** | ||
* Bridge-mode. | ||
* | ||
* Runs the destination with the new hast tree. | ||
* Discards result. | ||
*/ | ||
export type TransformBridge = (tree: MdastRoot, file: VFile) => Promise<undefined>; | ||
/** | ||
* Mutate-mode. | ||
* | ||
* Further transformers run on the hast tree. | ||
*/ | ||
export type TransformMutate = (tree: MdastRoot, file: VFile) => HastRoot; |
188
lib/index.js
@@ -0,1 +1,4 @@ | ||
// Include `data` fields in mdast and `raw` nodes in hast. | ||
/// <reference types="mdast-util-to-hast" /> | ||
/** | ||
@@ -5,68 +8,147 @@ * @typedef {import('hast').Root} HastRoot | ||
* @typedef {import('mdast-util-to-hast').Options} Options | ||
* @typedef {import('unified').Processor<any, any, any, any>} Processor | ||
* | ||
* @typedef {import('mdast-util-to-hast')} DoNotTouchAsThisImportIncludesRawInTree | ||
* @typedef {import('unified').Processor} Processor | ||
* @typedef {import('vfile').VFile} VFile | ||
*/ | ||
import {toHast} from 'mdast-util-to-hast' | ||
// Note: the `<MdastRoot, HastRoot>` overload doesn’t seem to work :'( | ||
/** | ||
* Plugin that turns markdown into HTML to support rehype. | ||
* @callback TransformBridge | ||
* Bridge-mode. | ||
* | ||
* * If a destination processor is given, that processor runs with a new HTML | ||
* (hast) tree (bridge-mode). | ||
* As the given processor runs with a hast tree, and rehype plugins support | ||
* hast, that means rehype plugins can be used with the given processor. | ||
* The hast tree is discarded in the end. | ||
* It’s highly unlikely that you want to do this. | ||
* * The common case is to not pass a destination processor, in which case the | ||
* current processor continues running with a new HTML (hast) tree | ||
* (mutate-mode). | ||
* As the current processor continues with a hast tree, and rehype plugins | ||
* support hast, that means rehype plugins can be used after | ||
* `remark-rehype`. | ||
* It’s likely that this is what you want to do. | ||
* Runs the destination with the new hast tree. | ||
* Discards result. | ||
* @param {MdastRoot} tree | ||
* Tree. | ||
* @param {VFile} file | ||
* File. | ||
* @returns {Promise<undefined>} | ||
* Nothing. | ||
* | ||
* @param destination | ||
* Optional unified processor. | ||
* @param options | ||
* Options passed to `mdast-util-to-hast`. | ||
* @callback TransformMutate | ||
* Mutate-mode. | ||
* | ||
* Further transformers run on the hast tree. | ||
* @param {MdastRoot} tree | ||
* Tree. | ||
* @param {VFile} file | ||
* File. | ||
* @returns {HastRoot} | ||
* Tree (hast). | ||
*/ | ||
const remarkRehype = | ||
/** @type {(import('unified').Plugin<[Processor, Options?]|[null|undefined, Options?]|[Options]|[], MdastRoot>)} */ | ||
( | ||
function (destination, options) { | ||
return destination && 'run' in destination | ||
? bridge(destination, options) | ||
: mutate(destination || options) | ||
} | ||
) | ||
export default remarkRehype | ||
import {toHast} from 'mdast-util-to-hast' | ||
/** | ||
* Bridge-mode. | ||
* Runs the destination with the new hast tree. | ||
* Turn markdown into HTML. | ||
* | ||
* @type {import('unified').Plugin<[Processor, Options?], MdastRoot>} | ||
* ##### Notes | ||
* | ||
* ###### Signature | ||
* | ||
* * if a processor is given, runs the (rehype) plugins used on it with a | ||
* hast tree, then discards the result (*bridge mode*) | ||
* * otherwise, returns a hast tree, the plugins used after `remarkRehype` | ||
* are rehype plugins (*mutate mode*) | ||
* | ||
* > 👉 **Note**: It’s highly unlikely that you want to pass a `processor`. | ||
* | ||
* ###### HTML | ||
* | ||
* Raw HTML is available in mdast as `html` nodes and can be embedded in hast | ||
* as semistandard `raw` nodes. | ||
* Most plugins ignore `raw` nodes but two notable ones don’t: | ||
* | ||
* * `rehype-stringify` also has an option `allowDangerousHtml` which will | ||
* output the raw HTML. | ||
* This is typically discouraged as noted by the option name but is useful if | ||
* you completely trust authors | ||
* * `rehype-raw` can handle the raw embedded HTML strings by parsing them | ||
* into standard hast nodes (`element`, `text`, etc). | ||
* This is a heavy task as it needs a full HTML parser, but it is the only way | ||
* to support untrusted content | ||
* | ||
* ###### Footnotes | ||
* | ||
* Many options supported here relate to footnotes. | ||
* Footnotes are not specified by CommonMark, which we follow by default. | ||
* They are supported by GitHub, so footnotes can be enabled in markdown with | ||
* `remark-gfm`. | ||
* | ||
* The options `footnoteBackLabel` and `footnoteLabel` define natural language | ||
* that explains footnotes, which is hidden for sighted users but shown to | ||
* assistive technology. | ||
* When your page is not in English, you must define translated values. | ||
* | ||
* Back references use ARIA attributes, but the section label itself uses a | ||
* heading that is hidden with an `sr-only` class. | ||
* To show it to sighted users, define different attributes in | ||
* `footnoteLabelProperties`. | ||
* | ||
* ###### Clobbering | ||
* | ||
* Footnotes introduces a problem, as it links footnote calls to footnote | ||
* definitions on the page through `id` attributes generated from user content, | ||
* which results in DOM clobbering. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id=x></p> | ||
* <script>alert(x) // `x` now refers to the DOM `p#x` element</script> | ||
* ``` | ||
* | ||
* Elements by their ID are made available by browsers on the `window` object, | ||
* which is a security risk. | ||
* Using a prefix solves this problem. | ||
* | ||
* More information on how to handle clobbering and the prefix is explained in | ||
* *Example: headings (DOM clobbering)* in `rehype-sanitize`. | ||
* | ||
* ###### Unknown nodes | ||
* | ||
* Unknown nodes are nodes with a type that isn’t in `handlers` or `passThrough`. | ||
* The default behavior for unknown nodes is: | ||
* | ||
* * when the node has a `value` (and doesn’t have `data.hName`, | ||
* `data.hProperties`, or `data.hChildren`, see later), create a hast `text` | ||
* node | ||
* * otherwise, create a `<div>` element (which could be changed with | ||
* `data.hName`), with its children mapped from mdast to hast as well | ||
* | ||
* This behavior can be changed by passing an `unknownHandler`. | ||
* | ||
* @overload | ||
* @param {Processor} processor | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* @returns {TransformBridge} | ||
* | ||
* @overload | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* @returns {TransformMutate} | ||
* | ||
* @param {Readonly<Options> | Processor | null | undefined} [destination] | ||
* Processor or configuration (optional). | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* When a processor was given, configuration (optional). | ||
* @returns {TransformBridge | TransformMutate} | ||
* Transform. | ||
*/ | ||
function bridge(destination, options) { | ||
return (node, file, next) => { | ||
destination.run(toHast(node, options), file, (error) => { | ||
next(error) | ||
}) | ||
export default function remarkRehype(destination, options) { | ||
if (destination && 'run' in destination) { | ||
/** | ||
* @type {TransformBridge} | ||
*/ | ||
return async function (tree, file) { | ||
// Cast because root in -> root out. | ||
const hastTree = /** @type {HastRoot} */ (toHast(tree, options)) | ||
await destination.run(hastTree, file) | ||
} | ||
} | ||
} | ||
/** | ||
* Mutate-mode. | ||
* Further plugins run on the hast tree. | ||
* | ||
* @type {import('unified').Plugin<[Options?]|void[], MdastRoot, HastRoot>} | ||
*/ | ||
function mutate(options) { | ||
// @ts-expect-error: assume a corresponding node is returned by `toHast`. | ||
return (node) => toHast(node, options) | ||
/** | ||
* @type {TransformMutate} | ||
*/ | ||
return function (tree) { | ||
// Cast because root in -> root out. | ||
return /** @type {HastRoot} */ (toHast(tree, options || destination)) | ||
} | ||
} |
{ | ||
"name": "remark-rehype", | ||
"version": "10.1.0", | ||
"version": "11.0.0", | ||
"description": "remark plugin that turns markdown into HTML to support rehype", | ||
"license": "MIT", | ||
"keywords": [ | ||
"unified", | ||
"hast", | ||
"html", | ||
"markdown", | ||
"mdast", | ||
"plugin", | ||
"rehype", | ||
"rehype-plugin", | ||
"remark", | ||
"rehype", | ||
"remark-plugin", | ||
"rehype-plugin", | ||
"plugin", | ||
"html", | ||
"hast", | ||
"mdast", | ||
"markdown" | ||
"unified" | ||
], | ||
@@ -31,4 +31,3 @@ "repository": "remarkjs/remark-rehype", | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"exports": "./index.js", | ||
"files": [ | ||
@@ -40,44 +39,40 @@ "lib/", | ||
"dependencies": { | ||
"@types/hast": "^2.0.0", | ||
"@types/mdast": "^3.0.0", | ||
"mdast-util-to-hast": "^12.1.0", | ||
"unified": "^10.0.0" | ||
"@types/hast": "^3.0.0", | ||
"@types/mdast": "^4.0.0", | ||
"mdast-util-to-hast": "^13.0.0", | ||
"unified": "^11.0.0", | ||
"vfile": "^6.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/tape": "^4.0.0", | ||
"c8": "^7.0.0", | ||
"prettier": "^2.0.0", | ||
"rehype-stringify": "^9.0.0", | ||
"remark-cli": "^10.0.0", | ||
"remark-parse": "^10.0.0", | ||
"@types/node": "^20.0.0", | ||
"c8": "^8.0.0", | ||
"prettier": "^3.0.0", | ||
"rehype-stringify": "^10.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-parse": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"remark-stringify": "^10.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"remark-stringify": "^11.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.47.0" | ||
"typescript": "^5.0.0", | ||
"xo": "^0.56.0" | ||
}, | ||
"scripts": { | ||
"build": "rimraf \"lib/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"build": "tsc --build --clean && tsc --build && type-coverage", | ||
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix", | ||
"prepack": "npm run build && npm run format", | ||
"test": "npm run build && npm run format && npm run test-coverage", | ||
"test-api": "node --conditions development test.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov npm run test-api", | ||
"test-types": "dtslint types", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
"test-coverage": "c8 --100 --reporter lcov npm run test-api" | ||
}, | ||
"prettier": { | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"bracketSpacing": false, | ||
"singleQuote": true, | ||
"bracketSpacing": false, | ||
"semi": false, | ||
"trailingComma": "none" | ||
"tabWidth": 2, | ||
"trailingComma": "none", | ||
"useTabs": false | ||
}, | ||
"xo": { | ||
"prettier": true | ||
}, | ||
"remarkConfig": { | ||
"plugins": [ | ||
"preset-wooorm" | ||
"remark-preset-wooorm" | ||
] | ||
@@ -88,11 +83,8 @@ }, | ||
"detail": true, | ||
"strict": true, | ||
"ignoreCatch": true, | ||
"#": "needed `any`s", | ||
"ignoreFiles": [ | ||
"lib/index.d.ts", | ||
"lib/index.js", | ||
"index.d.ts" | ||
] | ||
"strict": true | ||
}, | ||
"xo": { | ||
"prettier": true | ||
} | ||
} |
645
readme.md
@@ -20,6 +20,7 @@ # remark-rehype | ||
* [API](#api) | ||
* [`defaultFootnoteBackContent(referenceIndex, rereferenceIndex)`](#defaultfootnotebackcontentreferenceindex-rereferenceindex) | ||
* [`defaultFootnoteBackLabel(referenceIndex, rereferenceIndex)`](#defaultfootnotebacklabelreferenceindex-rereferenceindex) | ||
* [`defaultHandlers`](#defaulthandlers) | ||
* [`unified().use(remarkRehype[, destination][, options])`](#unifieduseremarkrehype-destination-options) | ||
* [`defaultHandlers`](#defaulthandlers) | ||
* [`all`](#all) | ||
* [`one`](#one) | ||
* [`Options`](#options) | ||
* [Examples](#examples) | ||
@@ -29,4 +30,5 @@ * [Example: supporting HTML in markdown naïvely](#example-supporting-html-in-markdown-naïvely) | ||
* [Example: footnotes in languages other than English](#example-footnotes-in-languages-other-than-english) | ||
* [HTML](#html-1) | ||
* [CSS](#css) | ||
* [Syntax tree](#syntax-tree) | ||
* [CSS](#css) | ||
* [Types](#types) | ||
@@ -64,10 +66,2 @@ * [Compatibility](#compatibility) | ||
**unified** is a project that transforms content with abstract syntax trees | ||
(ASTs). | ||
**remark** adds support for markdown to unified. | ||
**rehype** adds support for HTML to unified. | ||
**mdast** is the markdown AST that remark uses. | ||
**hast** is the markdown AST that rehype uses. | ||
This is a remark plugin that transforms mdast into hast to support rehype. | ||
## When should I use this? | ||
@@ -85,5 +79,5 @@ | ||
This is a separate plugin because supporting HTML inside markdown is a heavy | ||
task and not always needed. | ||
task (performance and bundle size) and not always needed. | ||
To use both together, you also have to configure `remark-rehype` with | ||
`allowDangerousHtml: true`. | ||
`allowDangerousHtml: true` and then use `rehype-raw`. | ||
@@ -94,6 +88,9 @@ The rehype plugin [`rehype-remark`][rehype-remark] does the inverse of this | ||
If you don’t use plugins and want to access syntax trees, you can use | ||
[`mdast-util-to-hast`][mdast-util-to-hast]. | ||
## Install | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). | ||
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: | ||
This package is [ESM only][esm]. | ||
In Node.js (version 16+), install with [npm][]: | ||
@@ -104,13 +101,13 @@ ```sh | ||
In Deno with [Skypack][]: | ||
In Deno with [`esm.sh`][esmsh]: | ||
```js | ||
import remarkRehype from 'https://cdn.skypack.dev/remark-rehype@10?dts' | ||
import remarkRehype from 'https://esm.sh/remark-rehype@11' | ||
``` | ||
In browsers with [Skypack][]: | ||
In browsers with [`esm.sh`][esmsh]: | ||
```html | ||
<script type="module"> | ||
import remarkRehype from 'https://cdn.skypack.dev/remark-rehype@10?min' | ||
import remarkRehype from 'https://esm.sh/remark-rehype@11?bundle' | ||
</script> | ||
@@ -121,41 +118,37 @@ ``` | ||
Say we have the following file `example.md`: | ||
Say our document `example.md` contains: | ||
```markdown | ||
# Hello world | ||
# Pluto | ||
> Block quote. | ||
Some _emphasis_, **importance**, and `code`. | ||
**Pluto** (minor-planet designation: **134340 Pluto**) is a | ||
[dwarf planet](https://en.wikipedia.org/wiki/Dwarf_planet) in the | ||
[Kuiper belt](https://en.wikipedia.org/wiki/Kuiper_belt). | ||
``` | ||
And our module `example.js` looks as follows: | ||
…and our module `example.js` contains: | ||
```js | ||
import {read} from 'to-vfile' | ||
import {reporter} from 'vfile-reporter' | ||
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 remarkParse from 'remark-parse' | ||
import remarkRehype from 'remark-rehype' | ||
import {read} from 'to-vfile' | ||
import {unified} from 'unified' | ||
import {reporter} from 'vfile-reporter' | ||
main() | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkRehype) | ||
.use(rehypeDocument) | ||
.use(rehypeFormat) | ||
.use(rehypeStringify) | ||
.process(await read('example.md')) | ||
async function main() { | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkRehype) | ||
.use(rehypeDocument) | ||
.use(rehypeFormat) | ||
.use(rehypeStringify) | ||
.process(await read('example.md')) | ||
console.error(reporter(file)) | ||
console.log(String(file)) | ||
} | ||
console.error(reporter(file)) | ||
console.log(String(file)) | ||
``` | ||
Now, running `node example.js` yields: | ||
…then running `node example.js` yields: | ||
@@ -172,10 +165,11 @@ ```txt | ||
<title>example</title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<meta content="width=device-width, initial-scale=1" name="viewport"> | ||
</head> | ||
<body> | ||
<h1>Hello world</h1> | ||
<blockquote> | ||
<p>Block quote.</p> | ||
</blockquote> | ||
<p>Some <em>emphasis</em>, <strong>importance</strong>, and <code>code</code>.</p> | ||
<h1>Pluto</h1> | ||
<p> | ||
<strong>Pluto</strong> (minor-planet designation: <strong>134340 Pluto</strong>) is a | ||
<a href="https://en.wikipedia.org/wiki/Dwarf_planet">dwarf planet</a> in the | ||
<a href="https://en.wikipedia.org/wiki/Kuiper_belt">Kuiper belt</a>. | ||
</p> | ||
</body> | ||
@@ -187,44 +181,88 @@ </html> | ||
This package exports `defaultHandlers`, `all`, and `one`. | ||
The default export is `remarkRehype`. | ||
This package exports the identifiers | ||
[`defaultFootnoteBackContent`][api-default-footnote-back-content], | ||
[`defaultFootnoteBackLabel`][api-default-footnote-back-label], and | ||
[`defaultHandlers`][api-default-handlers]. | ||
The default export is [`remarkRehype`][api-remark-rehype]. | ||
### `defaultFootnoteBackContent(referenceIndex, rereferenceIndex)` | ||
See [`defaultFootnoteBackContent` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-default-footnote-back-content] | ||
### `defaultFootnoteBackLabel(referenceIndex, rereferenceIndex)` | ||
See [`defaultFootnoteBackLabel` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-default-footnote-back-label] | ||
### `defaultHandlers` | ||
See [`defaultHandlers` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-default-handlers] | ||
### `unified().use(remarkRehype[, destination][, options])` | ||
Plugin that turns markdown into HTML to support rehype. | ||
Turn markdown into HTML. | ||
##### `destination` | ||
###### Parameters | ||
If a [`Unified`][processor] destination processor is given, that processor runs | ||
with a new HTML (hast) tree (bridge-mode). | ||
As the given processor runs with a hast tree, and rehype plugins support | ||
hast, that means rehype plugins can be used with the given processor. | ||
The hast tree is discarded in the end. | ||
* `destination` ([`Processor`][unified-processor], optional) | ||
— processor | ||
* `options` ([`Options`][api-options], optional) | ||
— configuration | ||
> 👉 **Note**: It’s highly unlikely that you want to do this. | ||
###### Returns | ||
##### `options` | ||
Transform ([`Transformer`][unified-transformer]). | ||
Configuration (optional). | ||
##### Notes | ||
###### `options.allowDangerousHtml` | ||
###### Signature | ||
Whether to persist raw HTML in markdown in the hast tree (`boolean`, default: | ||
`false`). | ||
Raw HTML is available in the markdown (mdast) tree as [`html`][mdast-html] nodes | ||
and can be embedded in the HTML (hast) tree as semistandard `raw` nodes. | ||
Most rehype plugins ignore `raw` nodes, but two notable plugins don’t: | ||
* if a [processor][unified-processor] is given, runs the (rehype) plugins | ||
used on it with a hast tree, then discards the result | ||
([*bridge mode*][unified-mode]) | ||
* otherwise, returns a hast tree, the plugins used after `remarkRehype` | ||
are rehype plugins ([*mutate mode*][unified-mode]) | ||
> 👉 **Note**: It’s highly unlikely that you want to pass a `processor`. | ||
###### HTML | ||
Raw HTML is available in mdast as [`html`][mdast-html] nodes and can be embedded | ||
in hast as semistandard `raw` nodes. | ||
Most plugins ignore `raw` nodes but two notable ones don’t: | ||
* [`rehype-stringify`][rehype-stringify] also has an option | ||
`allowDangerousHtml` which will output the raw HTML. | ||
This is typically discouraged as noted by the option name but is useful if | ||
you completely trust who authors the markdown | ||
* [`rehype-raw`][rehype-raw] can handle the raw embedded HTML strings in hast | ||
trees by parsing them into standard hast nodes (element, text, etc). | ||
you completely trust authors | ||
* [`rehype-raw`][rehype-raw] can handle the raw embedded HTML strings by | ||
parsing them into standard hast nodes (`element`, `text`, etc). | ||
This is a heavy task as it needs a full HTML parser, but it is the only way | ||
to support untrusted content | ||
###### `options.clobberPrefix` | ||
###### Footnotes | ||
Prefix to use before the `id` attribute on footnotes to prevent it from | ||
*clobbering* (`string`, default: `'user-content-'`). | ||
Many options supported here relate to footnotes. | ||
Footnotes are not specified by CommonMark, which we follow by default. | ||
They are supported by GitHub, so footnotes can be enabled in markdown with | ||
[`remark-gfm`][remark-gfm]. | ||
The options `footnoteBackLabel` and `footnoteLabel` define natural language | ||
that explains footnotes, which is hidden for sighted users but shown to | ||
assistive technology. | ||
When your page is not in English, you must define translated values. | ||
Back references use ARIA attributes, but the section label itself uses a | ||
heading that is hidden with an `sr-only` class. | ||
To show it to sighted users, define different attributes in | ||
`footnoteLabelProperties`. | ||
###### Clobbering | ||
Footnotes introduces a problem, as it links footnote calls to footnote | ||
definitions on the page through `id` attributes generated from user content, | ||
which results in DOM clobbering. | ||
DOM clobbering is this: | ||
@@ -241,63 +279,64 @@ | ||
> 👉 **Note**: this option affects footnotes. | ||
> Footnotes are not specified by CommonMark so they’re not supported in remark | ||
> by default. | ||
> They are supported by GitHub, so they can be enabled by using the remark | ||
> plugin [`remark-gfm`][remark-gfm]. | ||
More information on how to handle clobbering and the prefix is explained in | ||
[*Example: headings (DOM clobbering)* in | ||
`rehype-sanitize`][rehype-sanitize-clobber]. | ||
###### `options.footnoteLabel` | ||
###### Unknown nodes | ||
Label to use for the footnotes section (`string`, default: `'Footnotes'`). | ||
Affects screen readers. | ||
Change it when the markdown is not in English. | ||
Unknown nodes are nodes with a type that isn’t in `handlers` or `passThrough`. | ||
The default behavior for unknown nodes is: | ||
> 👉 **Note**: this option affects footnotes. | ||
> Footnotes are not specified by CommonMark so they’re not supported in remark | ||
> by default. | ||
> They are supported by GitHub, so they can be enabled by using the remark | ||
> plugin [`remark-gfm`][remark-gfm]. | ||
* when the node has a `value` (and doesn’t have `data.hName`, | ||
`data.hProperties`, or `data.hChildren`, see later), create a hast `text` | ||
node | ||
* otherwise, create a `<div>` element (which could be changed with | ||
`data.hName`), with its children mapped from mdast to hast as well | ||
###### `options.footnoteBackLabel` | ||
This behavior can be changed by passing an `unknownHandler`. | ||
Label to use from backreferences back to their footnote call (`string`, default: | ||
`'Back to content'`). | ||
Affects screen readers. | ||
Change it when the markdown is not in English. | ||
### `Options` | ||
> 👉 **Note**: this option affects footnotes. | ||
> Footnotes are not specified by CommonMark so they’re not supported in remark | ||
> by default. | ||
> They are supported by GitHub, so they can be enabled by using the remark | ||
> plugin [`remark-gfm`][remark-gfm]. | ||
Configuration (TypeScript type). | ||
###### `options.handlers` | ||
###### Fields | ||
This option is a bit advanced as it requires knowledge of ASTs, so we defer | ||
to the documentation available in [`mdast-util-to-hast`][mdast-util-to-hast]. | ||
* `allowDangerousHtml` (`boolean`, default: `false`) | ||
— whether to persist raw HTML in markdown in the hast tree | ||
* `clobberPrefix` (`string`, default: `'user-content-'`) | ||
— prefix to use before the `id` property on footnotes to prevent them from | ||
*clobbering* | ||
* `footnoteBackContent` | ||
([`FootnoteBackContentTemplate` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-footnote-back-content-template] | ||
or `string`, default: | ||
[`defaultFootnoteBackContent` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-default-footnote-back-content]) | ||
— content of the backreference back to references | ||
* `footnoteBackLabel` | ||
([`FootnoteBackLabelTemplate` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-footnote-back-label-template] | ||
or `string`, default: | ||
[`defaultFootnoteBackLabel` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-default-footnote-back-label]) | ||
— label to describe the backreference back to references | ||
* `footnoteLabel` (`string`, default: `'Footnotes'`) | ||
— label to use for the footnotes section (affects screen readers) | ||
* `footnoteLabelProperties` | ||
([`Properties` from `@types/hast`][hast-properties], default: | ||
`{className: ['sr-only']}`) | ||
— properties to use on the footnote label | ||
(note that `id: 'footnote-label'` is always added as footnote calls use it | ||
with `aria-describedby` to provide an accessible label) | ||
* `footnoteLabelTagName` (`string`, default: `h2`) | ||
— tag name to use for the footnote label | ||
* `handlers` ([`Handlers` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-handlers], optional) | ||
— extra handlers for nodes | ||
* `passThrough` (`Array<Nodes['type']>`, optional) | ||
— list of custom mdast node types to pass through (keep) in hast (note that | ||
the node itself is passed, but eventual children are transformed) | ||
* `unknownHandler` ([`Handler` from | ||
`mdast-util-to-hast`][mdast-util-to-hast-handler], optional) | ||
— handle all unknown nodes | ||
###### `options.passThrough` | ||
This option is a bit advanced as it requires knowledge of ASTs, so we defer | ||
to the documentation available in [`mdast-util-to-hast`][mdast-util-to-hast]. | ||
###### `options.unknownHandler` | ||
This option is a bit advanced as it requires knowledge of ASTs, so we defer | ||
to the documentation available in [`mdast-util-to-hast`][mdast-util-to-hast]. | ||
### `defaultHandlers` | ||
The `defaultHandlers` export from [`mdast-util-to-hast`][mdast-util-to-hast], | ||
useful when passing in your own handlers. | ||
### `all` | ||
The `all` export from [`mdast-util-to-hast`][mdast-util-to-hast], | ||
useful when passing in your own handlers. | ||
### `one` | ||
The `one` export from [`mdast-util-to-hast`][mdast-util-to-hast], | ||
useful when passing in your own handlers. | ||
## Examples | ||
@@ -308,32 +347,27 @@ | ||
If you completely trust the authors of the input markdown and want to allow them | ||
to write HTML inside markdown, you can pass `allowDangerousHtml` to this plugin | ||
(`remark-rehype`) and `rehype-stringify`: | ||
to write HTML inside markdown, you can pass `allowDangerousHtml` to | ||
`remark-rehype` and `rehype-stringify`: | ||
```js | ||
import {unified} from 'unified' | ||
import rehypeStringify from 'rehype-stringify' | ||
import remarkParse from 'remark-parse' | ||
import remarkRehype from 'remark-rehype' | ||
import rehypeStringify from 'rehype-stringify' | ||
import {unified} from 'unified' | ||
main() | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkRehype, {allowDangerousHtml: true}) | ||
.use(rehypeStringify, {allowDangerousHtml: true}) | ||
.process('<a href="/wiki/Dysnomia_(moon)" onclick="alert(1)">Dysnomia</a>') | ||
async function main() { | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkRehype, {allowDangerousHtml: true}) | ||
.use(rehypeStringify, {allowDangerousHtml: true}) | ||
.process('It <i>works</i>! <img onerror="alert(1)">') | ||
console.log(String(file)) | ||
} | ||
console.log(String(file)) | ||
``` | ||
Running that code yields: | ||
Yields: | ||
```html | ||
<p>It <i>works</i>! <img onerror="alert(1)"></p> | ||
<p><a href="/wiki/Dysnomia_(moon)" onclick="alert(1)">Dysnomia</a></p> | ||
``` | ||
> ⚠️ **Danger**: Observe that the XSS attack through the `onerror` attribute | ||
> is still present. | ||
> ⚠️ **Danger**: observe that the XSS attack through `onclick` is present. | ||
@@ -345,28 +379,24 @@ ### Example: supporting HTML in markdown properly | ||
[`rehype-raw`][rehype-raw]. | ||
The following example passes `allowDangerousHtml` to this plugin | ||
(`remark-rehype`), then turns the raw embedded HTML into proper HTML nodes | ||
(`rehype-raw`), and finally sanitizes the HTML by only allowing safe things | ||
(`rehype-sanitize`): | ||
The following example passes `allowDangerousHtml` to `remark-rehype`, then | ||
turns the raw embedded HTML into proper HTML nodes with `rehype-raw`, and | ||
finally sanitizes the HTML by only allowing safe things with | ||
`rehype-sanitize`: | ||
```js | ||
import {unified} from 'unified' | ||
import rehypeSanitize from 'rehype-sanitize' | ||
import rehypeStringify from 'rehype-stringify' | ||
import rehypeRaw from 'rehype-raw' | ||
import remarkParse from 'remark-parse' | ||
import remarkRehype from 'remark-rehype' | ||
import rehypeRaw from 'rehype-raw' | ||
import rehypeSanitize from 'rehype-sanitize' | ||
import rehypeStringify from 'rehype-stringify' | ||
import {unified} from 'unified' | ||
main() | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkRehype, {allowDangerousHtml: true}) | ||
.use(rehypeRaw) | ||
.use(rehypeSanitize) | ||
.use(rehypeStringify) | ||
.process('<a href="/wiki/Dysnomia_(moon)" onclick="alert(1)">Dysnomia</a>') | ||
async function main() { | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkRehype, {allowDangerousHtml: true}) | ||
.use(rehypeRaw) | ||
.use(rehypeSanitize) | ||
.use(rehypeStringify) | ||
.process('It <i>works</i>! <img onerror="alert(1)">') | ||
console.log(String(file)) | ||
} | ||
console.log(String(file)) | ||
``` | ||
@@ -377,7 +407,7 @@ | ||
```html | ||
<p>It <i>works</i>! <img></p> | ||
<p><a href="/wiki/Dysnomia_(moon)">Dysnomia</a></p> | ||
``` | ||
> 👉 **Note**: Observe that the XSS attack through the `onerror` attribute | ||
> is no longer present. | ||
> ⚠️ **Danger**: observe that the XSS attack through `onclick` is **not** | ||
> present. | ||
@@ -400,24 +430,36 @@ ### Example: footnotes in languages other than English | ||
main() | ||
const doc = ` | ||
Ceres ist nach der römischen Göttin des Ackerbaus benannt; | ||
ihr astronomisches Symbol ist daher eine stilisierte Sichel: ⚳.[^nasa-2015] | ||
async function main() { | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkGfm) | ||
.use(remarkRehype) | ||
.use(rehypeStringify) | ||
.process('Hallo[^1]\n\n[^1]: Wereld!') | ||
[^nasa-2015]: JPL/NASA: | ||
[*What is a Dwarf Planet?*](https://www.jpl.nasa.gov/infographics/what-is-a-dwarf-planet) | ||
In: Jet Propulsion Laboratory. | ||
22. April 2015, | ||
abgerufen am 19. Januar 2022 (englisch). | ||
` | ||
console.log(String(file)) | ||
} | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkGfm) | ||
.use(remarkRehype) | ||
.use(rehypeStringify) | ||
.process(doc) | ||
console.log(String(file)) | ||
``` | ||
Running that code yields: | ||
Yields: | ||
```html | ||
<p>Hallo<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p> | ||
<section data-footnotes class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes</h2> | ||
<p>Ceres ist nach der römischen Göttin des Ackerbaus benannt; | ||
ihr astronomisches Symbol ist daher eine stilisierte Sichel: ⚳.<sup><a href="#user-content-fn-nasa-2015" id="user-content-fnref-nasa-2015" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p> | ||
<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2> | ||
<ol> | ||
<li id="user-content-fn-1"> | ||
<p>Wereld! <a href="#user-content-fnref-1" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p> | ||
<li id="user-content-fn-nasa-2015"> | ||
<p>JPL/NASA: | ||
<a href="https://www.jpl.nasa.gov/infographics/what-is-a-dwarf-planet"><em>What is a Dwarf Planet?</em></a> | ||
In: Jet Propulsion Laboratory. | ||
22. April 2015, | ||
abgerufen am 19. Januar 2022 (englisch). <a href="#user-content-fnref-nasa-2015" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p> | ||
</li> | ||
@@ -428,4 +470,5 @@ </ol> | ||
This is a mix of English and Dutch that screen readers can’t handle nicely. | ||
Let’s say our program does know that the markdown is in Dutch. | ||
This is a mix of English and German that isn’t very accessible, such as that | ||
screen readers can’t handle it nicely. | ||
Let’s say our program *does* know that the markdown is in German. | ||
In that case, it’s important to translate and define the labels relating to | ||
@@ -435,10 +478,19 @@ footnotes so that screen reader users can properly pronounce the page: | ||
```diff | ||
@@ -10,7 +10,7 @@ async function main() { | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkGfm) | ||
- .use(remarkRehype) | ||
+ .use(remarkRehype, {footnoteLabel: 'Voetnoten', footnoteBackLabel: 'Terug'}) | ||
.use(rehypeStringify) | ||
.process('Hallo[^1]\n\n[^1]: Wereld!') | ||
@@ -18,7 +18,16 @@ ihr astronomisches Symbol ist daher eine stilisierte Sichel: ⚳.[^nasa-2015] | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkGfm) | ||
- .use(remarkRehype) | ||
+ .use(remarkRehype, { | ||
+ footnoteBackLabel(referenceIndex, rereferenceIndex) { | ||
+ return ( | ||
+ 'Hochspringen nach: ' + | ||
+ (referenceIndex + 1) + | ||
+ (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
+ ) | ||
+ }, | ||
+ footnoteLabel: 'Fußnoten' | ||
+ }) | ||
.use(rehypeStringify) | ||
.process(doc) | ||
``` | ||
@@ -449,10 +501,15 @@ | ||
```diff | ||
@@ -1,8 +1,8 @@ | ||
<p>Hallo<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p> | ||
-<section data-footnotes class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes</h2> | ||
+<section data-footnotes class="footnotes"><h2 id="footnote-label" class="sr-only">Voetnoten</h2> | ||
@@ -1,13 +1,13 @@ | ||
<p>Ceres ist nach der römischen Göttin des Ackerbaus benannt; | ||
ihr astronomisches Symbol ist daher eine stilisierte Sichel: ⚳.<sup><a href="#user-content-fn-nasa-2015" id="user-content-fnref-nasa-2015" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p> | ||
-<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2> | ||
+<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Fußnoten</h2> | ||
<ol> | ||
<li id="user-content-fn-1"> | ||
-<p>Wereld! <a href="#user-content-fnref-1" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p> | ||
+<p>Wereld! <a href="#user-content-fnref-1" data-footnote-backref class="data-footnote-backref" aria-label="Terug">↩</a></p> | ||
<li id="user-content-fn-nasa-2015"> | ||
<p>JPL/NASA: | ||
<a href="https://www.jpl.nasa.gov/infographics/what-is-a-dwarf-planet"><em>What is a Dwarf Planet?</em></a> | ||
In: Jet Propulsion Laboratory. | ||
22. April 2015, | ||
-abgerufen am 19. Januar 2022 (englisch). <a href="#user-content-fnref-nasa-2015" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p> | ||
+abgerufen am 19. Januar 2022 (englisch). <a href="#user-content-fnref-nasa-2015" data-footnote-backref="" aria-label="Hochspringen nach: 1" class="data-footnote-backref">↩</a></p> | ||
</li> | ||
@@ -463,30 +520,17 @@ </ol> | ||
## Syntax tree | ||
## HTML | ||
A frequent problem arises when having to turn one syntax tree into another. | ||
As the original tree (in this case, mdast for markdown) is in some cases | ||
limited compared to the destination (in this case, hast for HTML) tree, | ||
is it possible to provide more info in the original to define what the | ||
result will be in the destination? | ||
This is possible by defining data on mdast nodes, which this plugin will read | ||
as instructions on what hast nodes to create. | ||
See [*Algorithm* in | ||
`mdast-util-to-hast`](https://github.com/syntax-tree/mdast-util-to-hast#algorithm) | ||
for info on how mdast (markdown) nodes are transformed to hast (HTML). | ||
An example is `remark-math`, which defines semistandard math nodes that this | ||
plugin doesn’t understand. | ||
To solve this, `remark-math` defines instructions on mdast nodes that this | ||
plugin does understand because they define a certain hast structure. | ||
As these instructions are somewhat advanced in that they requires knowledge of | ||
ASTs, we defer to the documentation available in the low level utility we use: | ||
[`mdast-util-to-hast`][mdast-util-to-hast]. | ||
## CSS | ||
Assuming you know how to use (semantic) HTML and CSS, then it should generally | ||
be straight forward to style the HTML produced by this plugin. | ||
be straightforward to style the HTML produced by this plugin. | ||
With CSS, you can get creative and style the results as you please. | ||
Some semistandard features, notably [`remark-gfm`][remark-gfm]s tasklists and | ||
footnotes, generate HTML that be unintuitive, as it matches exactly what GitHub | ||
produces for their website. | ||
Some semistandard features, notably GFMs tasklists and footnotes, generate HTML | ||
that be unintuitive, as it matches exactly what GitHub produces for their | ||
website. | ||
There is a project, [`sindresorhus/github-markdown-css`][github-markdown-css], | ||
@@ -497,15 +541,84 @@ that exposes the stylesheet that GitHub uses for rendered markdown, which might | ||
The following CSS is needed to make footnotes look a bit like GitHub: | ||
```css | ||
/* Style the footnotes section. */ | ||
.footnotes { | ||
font-size: smaller; | ||
color: #8b949e; | ||
border-top: 1px solid #30363d; | ||
} | ||
/* Hide the section label for visual users. */ | ||
.sr-only { | ||
position: absolute; | ||
width: 1px; | ||
height: 1px; | ||
padding: 0; | ||
overflow: hidden; | ||
clip: rect(0, 0, 0, 0); | ||
word-wrap: normal; | ||
border: 0; | ||
} | ||
/* Place `[` and `]` around footnote calls. */ | ||
[data-footnote-ref]::before { | ||
content: '['; | ||
} | ||
[data-footnote-ref]::after { | ||
content: ']'; | ||
} | ||
``` | ||
## Syntax tree | ||
This projects turns [mdast][] (markdown) into [hast][] (HTML). | ||
It extends mdast by supporting `data` fields on mdast nodes to specify how they | ||
should be transformed. | ||
See [*Fields on nodes* in | ||
`mdast-util-to-hast`](https://github.com/syntax-tree/mdast-util-to-hast#fields-on-nodes) | ||
for info on how these fields work. | ||
It extends hast by using a semistandard raw nodes for raw HTML. | ||
See the [*HTML* note above](#html) for more info. | ||
## Types | ||
This package is fully typed with [TypeScript][]. | ||
It exports `Options` and `Processor` types, which specify the interfaces of the | ||
accepted options. | ||
It exports the types | ||
[`Options`][api-options]. | ||
The types of `mdast-util-to-hast` can be referenced to register data fields | ||
with `@types/mdast` and `Raw` nodes with `@types/hast`. | ||
```js | ||
// Include `data` fields in mdast and `raw` nodes in hast. | ||
/// <reference types="mdast-util-to-hast" /> | ||
import {visit} from 'unist-util-visit' | ||
/** @type {import('mdast').Root} */ | ||
const mdastNode = {/* … */} | ||
console.log(mdastNode.data?.hName) // Typed as `string | undefined`. | ||
/** @type {import('hast').Root} */ | ||
const hastNode = {/* … */} | ||
visit(hastNode, function (node) { | ||
// `node` can now be `raw`. | ||
}) | ||
``` | ||
## 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, `remark-rehype@^11`, | ||
compatible with Node.js 16. | ||
This plugin works with `unified` version 6+, `remark-parse` version 3+ (used in | ||
@@ -517,4 +630,4 @@ `remark` version 7), and `rehype-stringify` version 3+ (used in `rehype` | ||
Use of `remark-rehype` can open you up to a [cross-site scripting (XSS)][xss] | ||
attack. | ||
Use of `remark-rehype` can open you up to a | ||
[cross-site scripting (XSS)][wiki-xss] attack. | ||
Embedded **[hast][]** properties (`hName`, `hProperties`, `hChildren`) in | ||
@@ -566,5 +679,5 @@ [mdast][], custom handlers, and the `allowDangerousHtml` option all provide | ||
[size-badge]: https://img.shields.io/bundlephobia/minzip/remark-rehype.svg | ||
[size-badge]: https://img.shields.io/bundlejs/size/remark-rehype | ||
[size]: https://bundlephobia.com/result?p=remark-rehype | ||
[size]: https://bundlejs.com/?q=remark-rehype | ||
@@ -583,11 +696,13 @@ [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg | ||
[skypack]: https://www.skypack.dev | ||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[esmsh]: https://esm.sh | ||
[health]: https://github.com/remarkjs/.github | ||
[contributing]: https://github.com/remarkjs/.github/blob/HEAD/contributing.md | ||
[contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md | ||
[support]: https://github.com/remarkjs/.github/blob/HEAD/support.md | ||
[support]: https://github.com/remarkjs/.github/blob/main/support.md | ||
[coc]: https://github.com/remarkjs/.github/blob/HEAD/code-of-conduct.md | ||
[coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md | ||
@@ -598,20 +713,32 @@ [license]: license | ||
[processor]: https://github.com/unifiedjs/unified#processor | ||
[github-markdown-css]: https://github.com/sindresorhus/github-markdown-css | ||
[remark]: https://github.com/remarkjs/remark | ||
[hast]: https://github.com/syntax-tree/hast | ||
[rehype]: https://github.com/rehypejs/rehype | ||
[hast-properties]: https://github.com/syntax-tree/hast#properties | ||
[unified]: https://github.com/unifiedjs/unified | ||
[mdast]: https://github.com/syntax-tree/mdast | ||
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting | ||
[mdast-html]: https://github.com/syntax-tree/mdast#html | ||
[typescript]: https://www.typescriptlang.org | ||
[mdast-util-to-hast]: https://github.com/syntax-tree/mdast-util-to-hast | ||
[rehype-minify]: https://github.com/rehypejs/rehype-minify | ||
[mdast-util-to-hast-default-footnote-back-content]: https://github.com/syntax-tree/mdast-util-to-hast#defaultfootnotebackcontentreferenceindex-rereferenceindex | ||
[mdast-util-to-hast-default-footnote-back-label]: https://github.com/syntax-tree/mdast-util-to-hast#defaultfootnotebacklabelreferenceindex-rereferenceindex | ||
[mdast-util-to-hast-footnote-back-content-template]: https://github.com/syntax-tree/mdast-util-to-hast#footnotebackcontenttemplate | ||
[mdast-util-to-hast-footnote-back-label-template]: https://github.com/syntax-tree/mdast-util-to-hast#footnotebacklabeltemplate | ||
[mdast-util-to-hast-default-handlers]: https://github.com/syntax-tree/mdast-util-to-hast#defaulthandlers | ||
[mdast-util-to-hast-handlers]: https://github.com/syntax-tree/mdast-util-to-hast#handlers | ||
[mdast-util-to-hast-handler]: https://github.com/syntax-tree/mdast-util-to-hast#handler | ||
[rehype]: https://github.com/rehypejs/rehype | ||
[rehype-format]: https://github.com/rehypejs/rehype-format | ||
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[rehype-highlight]: https://github.com/rehypejs/rehype-highlight | ||
@@ -621,18 +748,38 @@ | ||
[rehype-minify]: https://github.com/rehypejs/rehype-minify | ||
[rehype-raw]: https://github.com/rehypejs/rehype-raw | ||
[rehype-remark]: https://github.com/rehypejs/rehype-remark | ||
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[rehype-sanitize-clobber]: https://github.com/rehypejs/rehype-sanitize#example-headings-dom-clobbering | ||
[rehype-stringify]: https://github.com/rehypejs/rehype/tree/main/packages/rehype-stringify | ||
[mdast-html]: https://github.com/syntax-tree/mdast#html | ||
[rehype-remark]: https://github.com/rehypejs/rehype-remark | ||
[remark]: https://github.com/remarkjs/remark | ||
[remark-gfm]: https://github.com/remarkjs/remark-gfm | ||
[mdast-util-to-hast]: https://github.com/syntax-tree/mdast-util-to-hast | ||
[typescript]: https://www.typescriptlang.org | ||
[mdast]: https://github.com/syntax-tree/mdast | ||
[unified]: https://github.com/unifiedjs/unified | ||
[hast]: https://github.com/syntax-tree/hast | ||
[unified-mode]: https://github.com/unifiedjs/unified#transforming-between-ecosystems | ||
[github-markdown-css]: https://github.com/sindresorhus/github-markdown-css | ||
[unified-processor]: https://github.com/unifiedjs/unified#processor | ||
[unified-transformer]: https://github.com/unifiedjs/unified#transformer | ||
[wiki-xss]: https://en.wikipedia.org/wiki/Cross-site_scripting | ||
[api-default-footnote-back-content]: #defaultfootnotebackcontentreferenceindex-rereferenceindex | ||
[api-default-footnote-back-label]: #defaultfootnotebacklabelreferenceindex-rereferenceindex | ||
[api-default-handlers]: #defaulthandlers | ||
[api-options]: #options | ||
[api-remark-rehype]: #unifieduseremarkrehype-destination-options |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42377
11
370
762
5
1
+ Addedvfile@^6.0.0
+ Added@types/hast@3.0.4(transitive)
+ Added@types/mdast@4.0.4(transitive)
+ Added@types/unist@3.0.3(transitive)
+ Added@ungap/structured-clone@1.2.0(transitive)
+ Addeddequal@2.0.3(transitive)
+ Addeddevlop@1.1.0(transitive)
+ Addedmdast-util-to-hast@13.2.0(transitive)
+ Addedmicromark-util-character@2.1.0(transitive)
+ Addedmicromark-util-encode@2.0.0(transitive)
+ Addedmicromark-util-sanitize-uri@2.0.0(transitive)
+ Addedmicromark-util-symbol@2.0.0(transitive)
+ Addedmicromark-util-types@2.0.0(transitive)
+ Addedunified@11.0.5(transitive)
+ Addedunist-util-is@6.0.0(transitive)
+ Addedunist-util-position@5.0.0(transitive)
+ Addedunist-util-stringify-position@4.0.0(transitive)
+ Addedunist-util-visit@5.0.0(transitive)
+ Addedunist-util-visit-parents@6.0.1(transitive)
+ Addedvfile@6.0.3(transitive)
+ Addedvfile-message@4.0.2(transitive)
- Removed@types/hast@2.3.10(transitive)
- Removed@types/mdast@3.0.15(transitive)
- Removed@types/unist@2.0.11(transitive)
- Removedis-buffer@2.0.5(transitive)
- Removedmdast-util-definitions@5.1.2(transitive)
- Removedmdast-util-to-hast@12.3.0(transitive)
- Removedmicromark-util-character@1.2.0(transitive)
- Removedmicromark-util-encode@1.1.0(transitive)
- Removedmicromark-util-sanitize-uri@1.2.0(transitive)
- Removedmicromark-util-symbol@1.1.0(transitive)
- Removedmicromark-util-types@1.1.0(transitive)
- Removedunified@10.1.2(transitive)
- Removedunist-util-generated@2.0.1(transitive)
- Removedunist-util-is@5.2.1(transitive)
- Removedunist-util-position@4.0.4(transitive)
- Removedunist-util-stringify-position@3.0.3(transitive)
- Removedunist-util-visit@4.1.2(transitive)
- Removedunist-util-visit-parents@5.1.3(transitive)
- Removedvfile@5.3.7(transitive)
- Removedvfile-message@3.1.4(transitive)
Updated@types/hast@^3.0.0
Updated@types/mdast@^4.0.0
Updatedmdast-util-to-hast@^13.0.0
Updatedunified@^11.0.0