unified

Learn/Recipe/HTML and remark

HTML and remark

remark is a markdown compiler. It’s focus is markdown. It’s concerned with HTML in two ways:

  1. markdown is often turned into HTML
  2. markdown sometimes has embedded HTML

When dealing with HTML and markdown, both remark and rehype are used. This article shows some examples of how to do that.

Contents

How to turn markdown into HTML

remark handles markdown: it can parse and serialize it. But it’s not for HTML. That’s what rehype does, which exists to parse and serialize HTML.

To turn markdown into HTML, we need remark-parse, remark-rehype, and rehype-stringify:

import rehypeStringify from 'rehype-stringify'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'

const file = await unified()
  .use(remarkParse) // Parse markdown content to a syntax tree
  .use(remarkRehype) // Turn markdown syntax tree to HTML syntax tree, ignoring embedded HTML
  .use(rehypeStringify) // Serialize HTML syntax tree
  .process('*emphasis* and **strong**')

console.log(String(file))
(alias) const rehypeStringify: Plugin<[(Options | null | undefined)?], Root, string>
import rehypeStringify

Plugin to add support for serializing as HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) const remarkParse: Plugin<[(Readonly<Options> | null | undefined)?], string, Root>
import remarkParse

Add support for parsing from markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) function remarkRehype(processor: Processor, options?: Readonly<Options> | null | undefined): TransformBridge (+1 overload)
import remarkRehype

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:

<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
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(alias) const unified: Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
const file: VFile
(alias) unified(): Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
(method) Processor<undefined, undefined, undefined, undefined, undefined>.use<[], string, Root>(plugin: Plugin<[], string, Root>, ...parameters: [] | [boolean]): Processor<Root, undefined, undefined, undefined, undefined> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const remarkParse: Plugin<[(Readonly<Options> | null | undefined)?], string, Root>
import remarkParse

Add support for parsing from markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(method) Processor<Root, undefined, undefined, undefined, undefined>.use<[], Root, Root>(plugin: Plugin<[], Root, Root>, ...parameters: [] | [boolean]): Processor<Root, Root, Root, undefined, undefined> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) function remarkRehype(processor: Processor, options?: Readonly<Options> | null | undefined): TransformBridge (+1 overload)
import remarkRehype

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:

<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
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(method) Processor<Root, Root, Root, undefined, undefined>.use<[], Root, string>(plugin: Plugin<[], Root, string>, ...parameters: [] | [boolean]): Processor<Root, Root, Root, Root, string> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const rehypeStringify: Plugin<[(Options | null | undefined)?], Root, string>
import rehypeStringify

Plugin to add support for serializing as HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(method) Processor<Root, Root, Root, Root, string>.process(file?: Compatible | undefined): Promise<VFile> (+1 overload)

Process the given file as configured on the processor.

Note: process freezes the processor if not already frozen.

Note: process performs the parse, run, and stringify phases.

  • @overload
  • @overload
  • @param file File (optional); typically string or VFile]; any value accepted as x in new VFile(x).
  • @param done Callback (optional).
  • @returns Nothing if done is given. Otherwise a promise, rejected with a fatal error or resolved with the processed file. The parsed, transformed, and compiled value is available at file.value (see note).

    Note: unified typically compiles by serializing: most compilers return string (or Uint8Array). Some compilers, such as the one configured with rehype-react, return other values (in this case, a React tree). If you’re using a compiler that doesn’t serialize, expect different result values.

    To register custom results in TypeScript, add them to {@linkcode CompileResultMap}.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
var String: StringConstructor
(value?: any) => string

Allows manipulation and formatting of text strings and determination and location of substrings within strings.

const file: VFile

This turns *emphasis* and **strong** into <em>emphasis</em> and <strong>strong</strong>, but it does not support HTML embedded inside markdown (such as *emphasis* and <strong>strong</strong>).

This solution is safe: content you don’t trust cannot cause an XSS vulnerability.

How to turn HTML into markdown

We can also do the inverse. To turn HTML into markdown, we need rehype-parse, rehype-remark, and remark-stringify:

import rehypeParse from 'rehype-parse'
import rehypeRemark from 'rehype-remark'
import remarkStringify from 'remark-stringify'
import {unified} from 'unified'

const file = await unified()
  .use(rehypeParse) // Parse HTML to a syntax tree
  .use(rehypeRemark) // Turn HTML syntax tree to markdown syntax tree
  .use(remarkStringify) // Serialize HTML syntax tree
  .process('<em>emphasis</em> and <strong>strong</strong>')

console.log(String(file))
(alias) const rehypeParse: Plugin<[(Options | null | undefined)?], string, Root>
import rehypeParse

Plugin to add support for parsing from HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) function rehypeRemark(processor: Processor, options?: Options | null | undefined): TransformBridge (+1 overload)
import rehypeRemark

Turn HTML into markdown.

Notes
  • if a processor is given, runs the (remark) plugins used on it with an mdast tree, then discards the result (bridge mode)
  • otherwise, returns an mdast tree, the plugins used after rehypeRemark are remark plugins (mutate mode)

👉 Note: It’s highly unlikely that you want to pass a processor.

  • @overload
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(alias) const remarkStringify: Plugin<[(Readonly<Options> | null | undefined)?], Root, string>
import remarkStringify

Add support for serializing to markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) const unified: Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
const file: VFile
(alias) unified(): Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
(method) Processor<undefined, undefined, undefined, undefined, undefined>.use<[], string, Root>(plugin: Plugin<[], string, Root>, ...parameters: [] | [boolean]): Processor<Root, undefined, undefined, undefined, undefined> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const rehypeParse: Plugin<[(Options | null | undefined)?], string, Root>
import rehypeParse

Plugin to add support for parsing from HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(method) Processor<Root, undefined, undefined, undefined, undefined>.use<[], Root, Root>(plugin: Plugin<[], Root, Root>, ...parameters: [] | [boolean]): Processor<Root, Root, Root, undefined, undefined> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) function rehypeRemark(processor: Processor, options?: Options | null | undefined): TransformBridge (+1 overload)
import rehypeRemark

Turn HTML into markdown.

Notes
  • if a processor is given, runs the (remark) plugins used on it with an mdast tree, then discards the result (bridge mode)
  • otherwise, returns an mdast tree, the plugins used after rehypeRemark are remark plugins (mutate mode)

👉 Note: It’s highly unlikely that you want to pass a processor.

  • @overload
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(method) Processor<Root, Root, Root, undefined, undefined>.use<[], Root, string>(plugin: Plugin<[], Root, string>, ...parameters: [] | [boolean]): Processor<Root, Root, Root, Root, string> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const remarkStringify: Plugin<[(Readonly<Options> | null | undefined)?], Root, string>
import remarkStringify

Add support for serializing to markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(method) Processor<Root, Root, Root, Root, string>.process(file?: Compatible | undefined): Promise<VFile> (+1 overload)

Process the given file as configured on the processor.

Note: process freezes the processor if not already frozen.

Note: process performs the parse, run, and stringify phases.

  • @overload
  • @overload
  • @param file File (optional); typically string or VFile]; any value accepted as x in new VFile(x).
  • @param done Callback (optional).
  • @returns Nothing if done is given. Otherwise a promise, rejected with a fatal error or resolved with the processed file. The parsed, transformed, and compiled value is available at file.value (see note).

    Note: unified typically compiles by serializing: most compilers return string (or Uint8Array). Some compilers, such as the one configured with rehype-react, return other values (in this case, a React tree). If you’re using a compiler that doesn’t serialize, expect different result values.

    To register custom results in TypeScript, add them to {@linkcode CompileResultMap}.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
var String: StringConstructor
(value?: any) => string

Allows manipulation and formatting of text strings and determination and location of substrings within strings.

const file: VFile

This turns <em>emphasis</em> and <strong>strong</strong> into *emphasis* and **strong**.

How to allow HTML embedded in markdown

Markdown is a content format that’s great for the more basic things: it’s nicer to write *emphasis* than <em>emphasis</em>. But, it’s limited: only a couple things are supported with its terse syntax. Luckily, for more complex things, markdown allows HTML inside it. A common example of this is to include a <details> element.

HTML embedded in markdown can be allowed when going from markdown to HTML by configuring remark-rehype and rehype-stringify:

import rehypeStringify from 'rehype-stringify'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'

const file = await unified()
  .use(remarkParse)
  .use(remarkRehype, {allowDangerousHtml: true}) // Pass raw HTML strings through.
  .use(rehypeStringify, {allowDangerousHtml: true}) // Serialize the raw HTML strings
  .process('*emphasis* and <strong>strong</strong>')

console.log(String(file))
(alias) const rehypeStringify: Plugin<[(Options | null | undefined)?], Root, string>
import rehypeStringify

Plugin to add support for serializing as HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) const remarkParse: Plugin<[(Readonly<Options> | null | undefined)?], string, Root>
import remarkParse

Add support for parsing from markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) function remarkRehype(processor: Processor, options?: Readonly<Options> | null | undefined): TransformBridge (+1 overload)
import remarkRehype

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:

<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
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(alias) const unified: Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
const file: VFile
(alias) unified(): Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
(method) Processor<undefined, undefined, undefined, undefined, undefined>.use<[], string, Root>(plugin: Plugin<[], string, Root>, ...parameters: [] | [boolean]): Processor<Root, undefined, undefined, undefined, undefined> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const remarkParse: Plugin<[(Readonly<Options> | null | undefined)?], string, Root>
import remarkParse

Add support for parsing from markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(method) Processor<Root, undefined, undefined, undefined, undefined>.use<[{
    allowDangerousHtml: boolean;
}], Root, Root>(plugin: Plugin<[{
    allowDangerousHtml: boolean;
}], Root, Root>, ...parameters: [boolean] | [...]): Processor<...> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) function remarkRehype(processor: Processor, options?: Readonly<Options> | null | undefined): TransformBridge (+1 overload)
import remarkRehype

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:

<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
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(property) allowDangerousHtml: boolean
(method) Processor<Root, Root, Root, undefined, undefined>.use<[{
    allowDangerousHtml: boolean;
}], Root, string>(plugin: Plugin<[{
    allowDangerousHtml: boolean;
}], Root, string>, ...parameters: [boolean] | [{
    allowDangerousHtml: boolean;
}]): Processor<...> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const rehypeStringify: Plugin<[(Options | null | undefined)?], Root, string>
import rehypeStringify

Plugin to add support for serializing as HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(property) allowDangerousHtml: boolean
(method) Processor<Root, Root, Root, Root, string>.process(file?: Compatible | undefined): Promise<VFile> (+1 overload)

Process the given file as configured on the processor.

Note: process freezes the processor if not already frozen.

Note: process performs the parse, run, and stringify phases.

  • @overload
  • @overload
  • @param file File (optional); typically string or VFile]; any value accepted as x in new VFile(x).
  • @param done Callback (optional).
  • @returns Nothing if done is given. Otherwise a promise, rejected with a fatal error or resolved with the processed file. The parsed, transformed, and compiled value is available at file.value (see note).

    Note: unified typically compiles by serializing: most compilers return string (or Uint8Array). Some compilers, such as the one configured with rehype-react, return other values (in this case, a React tree). If you’re using a compiler that doesn’t serialize, expect different result values.

    To register custom results in TypeScript, add them to {@linkcode CompileResultMap}.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
var String: StringConstructor
(value?: any) => string

Allows manipulation and formatting of text strings and determination and location of substrings within strings.

const file: VFile

This solution is not safe: content you don’t trust can cause XSS vulnerabilities.

How to properly support HTML inside markdown

To properly support HTML embedded inside markdown, we need another plugin: rehype-raw. This plugin will take the strings of HTML embedded in markdown and parse them with an actual HTML parser.

import rehypeRaw from 'rehype-raw'
import rehypeStringify from 'rehype-stringify'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'

const file = await unified()
  .use(remarkParse)
  .use(remarkRehype, {allowDangerousHtml: true})
  .use(rehypeRaw) // *Parse* the raw HTML strings embedded in the tree
  .use(rehypeStringify)
  .process('*emphasis* and <strong>strong</strong>')

console.log(String(file))
(alias) function rehypeRaw(options?: Options | null | undefined): (tree: Root, file: VFile) => Root
import rehypeRaw

Parse the tree (and raw nodes) again, keeping positional info okay.

  • @param options Configuration (optional).
  • @returns Transform.
(alias) const rehypeStringify: Plugin<[(Options | null | undefined)?], Root, string>
import rehypeStringify

Plugin to add support for serializing as HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) const remarkParse: Plugin<[(Readonly<Options> | null | undefined)?], string, Root>
import remarkParse

Add support for parsing from markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(alias) function remarkRehype(processor: Processor, options?: Readonly<Options> | null | undefined): TransformBridge (+1 overload)
import remarkRehype

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:

<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
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(alias) const unified: Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
const file: VFile
(alias) unified(): Processor<undefined, undefined, undefined, undefined, undefined>
import unified

Create a new processor.

  • @example This example shows how a new processor can be created (from remark) and linked to stdin(4) and stdout(4).
    import process from 'node:process'
    import concatStream from 'concat-stream'
    import {remark} from 'remark'
    
    process.stdin.pipe(
      concatStream(function (buf) {
        process.stdout.write(String(remark().processSync(buf)))
      })
    )
    
  • @returns New unfrozen processor (processor). This processor is configured to work the same as its ancestor. When the descendant processor is configured in the future it does not affect the ancestral processor.
(method) Processor<undefined, undefined, undefined, undefined, undefined>.use<[], string, Root>(plugin: Plugin<[], string, Root>, ...parameters: [] | [boolean]): Processor<Root, undefined, undefined, undefined, undefined> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const remarkParse: Plugin<[(Readonly<Options> | null | undefined)?], string, Root>
import remarkParse

Add support for parsing from markdown.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(method) Processor<Root, undefined, undefined, undefined, undefined>.use<[{
    allowDangerousHtml: boolean;
}], Root, Root>(plugin: Plugin<[{
    allowDangerousHtml: boolean;
}], Root, Root>, ...parameters: [boolean] | [...]): Processor<...> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) function remarkRehype(processor: Processor, options?: Readonly<Options> | null | undefined): TransformBridge (+1 overload)
import remarkRehype

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:

<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
  • @overload
  • @param destination Processor or configuration (optional).
  • @param options When a processor was given, configuration (optional).
  • @returns Transform.
(property) allowDangerousHtml: boolean
(method) Processor<Root, Root, Root, undefined, undefined>.use<[], Root, Root>(plugin: Plugin<[], Root, Root>, ...parameters: [] | [boolean]): Processor<Root, Root, Root, undefined, undefined> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) function rehypeRaw(options?: Options | null | undefined): (tree: Root, file: VFile) => Root
import rehypeRaw

Parse the tree (and raw nodes) again, keeping positional info okay.

  • @param options Configuration (optional).
  • @returns Transform.
(method) Processor<Root, Root, Root, undefined, undefined>.use<[], Root, string>(plugin: Plugin<[], Root, string>, ...parameters: [] | [boolean]): Processor<Root, Root, Root, Root, string> (+2 overloads)

Configure the processor to use a plugin, a list of usable values, or a preset.

If the processor is already using a plugin, the previous plugin configuration is changed based on the options that are passed in. In other words, the plugin is not added a second time.

Note: use cannot be called on frozen processors. Call the processor first to create a new unfrozen processor.

  • @example There are many ways to pass plugins to .use(). This example gives an overview:
    import {unified} from 'unified'
    
    unified()
      // Plugin with options:
      .use(pluginA, {x: true, y: true})
      // Passing the same plugin again merges configuration (to `{x: true, y: false, z: true}`):
      .use(pluginA, {y: false, z: true})
      // Plugins:
      .use([pluginB, pluginC])
      // Two plugins, the second with options:
      .use([pluginD, [pluginE, {}]])
      // Preset with plugins and settings:
      .use({plugins: [pluginF, [pluginG, {}]], settings: {position: false}})
      // Settings only:
      .use({settings: {position: false}})
    
  • @template {Array} [Parameters=[]]
  • @template {Node | string | undefined} [Input=undefined]
  • @template [Output=Input]
  • @overload
  • @overload
  • @overload
  • @param value Usable value.
  • @param parameters Parameters, when a plugin is given as a usable value.
  • @returns Current processor.
(alias) const rehypeStringify: Plugin<[(Options | null | undefined)?], Root, string>
import rehypeStringify

Plugin to add support for serializing as HTML.

  • @this processor.
  • @param Configuration (optional).
  • @returns Nothing.
(method) Processor<Root, Root, Root, Root, string>.process(file?: Compatible | undefined): Promise<VFile> (+1 overload)

Process the given file as configured on the processor.

Note: process freezes the processor if not already frozen.

Note: process performs the parse, run, and stringify phases.

  • @overload
  • @overload
  • @param file File (optional); typically string or VFile]; any value accepted as x in new VFile(x).
  • @param done Callback (optional).
  • @returns Nothing if done is given. Otherwise a promise, rejected with a fatal error or resolved with the processed file. The parsed, transformed, and compiled value is available at file.value (see note).

    Note: unified typically compiles by serializing: most compilers return string (or Uint8Array). Some compilers, such as the one configured with rehype-react, return other values (in this case, a React tree). If you’re using a compiler that doesn’t serialize, expect different result values.

    To register custom results in TypeScript, add them to {@linkcode CompileResultMap}.

namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
var String: StringConstructor
(value?: any) => string

Allows manipulation and formatting of text strings and determination and location of substrings within strings.

const file: VFile

This solution is not safe: content you don’t trust can cause XSS vulnerabilities.

But because we now have a complete HTML syntax tree, we can sanitize that tree. For a safe solution, add rehype-sanitize right before rehype-stringify.