rehype-highlight

rehype plugin to highlight code blocks with lowlight (highlight.js)

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
rehype-highlight
7.0.07 months ago8 years agoMinified + gzip package size for rehype-highlight in KB

Readme

rehype-highlight
!Buildbuild-badgebuild !Coveragecoverage-badgecoverage !Downloadsdownloads-badgedownloads !Sizesize-badgesize !Sponsorssponsors-badgecollective !Backersbackers-badgecollective !Chatchat-badgechat
rehype plugin to apply syntax highlighting to code with lowlightlowlight.

Contents

*   [`unified().use(rehypeHighlight[, options])`](#unifieduserehypehighlight-options)
*   [`Options`](#options)
*   [Example: ignoring](#example-ignoring)
*   [Example: registering](#example-registering)
*   [Example: aliases](#example-aliases)
*   [Example: sanitation](#example-sanitation)

What is this?

This package is a unified (rehype) plugin to perform syntax highlighting. It uses highlight.js through lowlight, which is pretty fast, relatively small, and quite good. This package bundles 37 common languageslowlight-common by default and you can register more (190 with alllowlight-all).
It looks for <code> elements (when directly in <pre> elements) and changes them. You can specify the code language (such as Python) with a language-* or lang-* class, where the * can be for example js (so language-js), md, css, etc. By default, code without such a language class is not highlighted. Pass detect: true to detect their programming language and highlight the code anyway. You can prevent specific blocks from being highlighted with a no-highlight or nohighlight class on the <code>.
unified is a project that transforms content with abstract syntax trees (ASTs). rehype adds support for HTML to unified. hast is the HTML AST that rehype uses. This is a rehype plugin that applies syntax highlighting to the AST.

When should I use this?

This project is useful when you want to perform syntax highlighting in rehype. One reason to do that is that it typically means the highlighting happens once at build time instead of every time at run time.
There are several other community plugins that apply syntax highlighting. Some of them are great choices but some are broken. As anyone can make rehype plugins, make sure to carefully assess the quality of rehype plugins.
This plugin is built on lowlightlowlight, which is a virtual version of highlight.js. You can make a plugin based on this one with lowlight when you want to do things differently.

Install

This package is ESM onlyesm. In Node.js (version 16+), install with npm:
npm install rehype-highlight

In Deno with esm.shesmsh:
import rehypeHighlight from 'https://esm.sh/rehype-highlight@66'

In browsers with esm.shesmsh:
<script type="module">
  import rehypeHighlight from 'https://esm.sh/rehype-highlight@6?bundle'
</script>

Use

Say we have the following file example.html:
<h1>Hello World!</h1>

<pre><code class="language-js">var name = "World";
console.warn("Hello, " + name + "!")</code></pre>

…and our module example.js contains:
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
import {read} from 'to-vfile'

const file = await rehype()
  .data('settings', {fragment: true})
  .use(rehypeHighlight)
  .process(await read('example.html'))

console.log(String(file))

…then running node example.js yields:
<h1>Hello World!</h1>

<pre><code class="hljs language-js"><span class="hljs-keyword">var</span> name = <span class="hljs-string">"World"</span>;
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">warn</span>(<span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>)</code></pre>

API

This package exports no identifiers. The default export is rehypeHighlightapi-rehype-highlight.

unified().use(rehypeHighlight[, options])

Apply syntax highlighting.
Parameters
— configuration
Returns
Transform (Transformerunified-transformer).

Options

Configuration (TypeScript type).
Fields
  • aliases (Record<string, Array<string> | string>, optional)
— register more aliases;
passed to [`lowlight.registerAlias`][lowlight-register-alias]
  • detect (boolean, default: false)
— highlight code without language classes by guessing its programming
language
  • languages (Record<string, LanguageFn>, default:
[`common`][lowlight-common])
— register languages; passed to [`lowlight.register`][lowlight-register]
  • plainText (Array<string>, optional)
— list of language names to not highlight;
note you can also add `no-highlight` classes
  • prefix (string, default: 'hljs-')
— class prefix
languages)
— names of languages to check when detecting

Example

Example: ignoring

There are three ways to not apply syntax highlighting to code blocks. They can be ignored with an explicit class of no-highlight (or nohighlight), an explicit language name that’s listed in options.plainText, or by setting options.detect to false (default), which prevents <code> without a class from being automatically detected.
For example, with example.html:
<pre><code>this won’t be highlighted due to `detect: false` (default)</code></pre>

<pre><code class="no-highlight">this won’t be highlighted due to its class</code></pre>

<pre><code class="language-txt">this won’t be highlighted due to `plainText: ['txt']`</code></pre>

…and example.js:
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
import {read} from 'to-vfile'

const file = await rehype()
  .data('settings', {fragment: true})
  .use(rehypeHighlight, {plainText: ['txt', 'text']})
  .process(await read('example.html'))

console.log(String(file))

…then running that yields the same as example.html: none of them are highlighted.

Example: registering

rehype-highlight supports 37 commonly used languages by default. This makes it small to load in browsers and Node.js, while supporting enough default cases. You can add more languages.
For example, with example.html:
<pre><code class="language-bnf">a ::= 'a' | 'A'</code></pre>

…and example.js:
import bnf from 'highlight.js/lib/languages/bnf'
import {common} from 'lowlight'
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
import {read} from 'to-vfile'

const file = await rehype()
  .data('settings', {fragment: true})
  .use(rehypeHighlight, {languages: {...common, bnf}})
  .process(await read('example.html'))

console.log(String(file))

…then running that yields:
<pre><code class="hljs language-bnf">a ::= <span class="hljs-string">'a'</span> | <span class="hljs-string">'A'</span></code></pre>

Example: aliases

You can map your own language flags to highlight.js languages.
For example, with example.html:
<pre><code class="language-custom-script">console.log(1)</code></pre>

…and example.js:
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
import {read} from 'to-vfile'

const file = await rehype()
  .data('settings', {fragment: true})
  // 👉 **Note**: the keys are language names, values are the aliases that you
  // want to also allow as `x` in `language-x` classes.
  .use(rehypeHighlight, {aliases: {'javascript': 'custom-script'}})
  .process(await read('example.html'))

console.log(String(file))

…then running that yields:
<pre><code class="hljs language-custom-script"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-number">1</span>)</code></pre>

Example: sanitation

Applying syntax highlighting in rehype operates on <code> elements with certain classes and it injects many <span> elements with classes. Allowing arbitrary classes is an opening for security vulnerabilities.
To make HTML safe in rehype, use rehype-sanitizerehype-sanitize. It specifically allows /^language-./ class names on <code> elements. Which we also use. So you can use rehype-highlight after rehype-sanitize:
import {unified} from 'unified'
import rehypeHighlight from './index.js'
import rehypeParse from 'rehype-parse'
import rehypeSanitize, {defaultSchema} from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'

const file = await unified()
  .use(rehypeParse, {fragment: true})
  .use(rehypeSanitize)
  .use(rehypeHighlight)
  .use(rehypeStringify)
  .process('<pre><code className="language-js">console.log(1)</code></pre>')

console.log(String(file))

…yields:
<pre><code class="hljs language-js"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-number">1</span>)</code></pre>

Using plugins after rehype-sanitize, like we just did, is safe assuming you trust those plugins. If you do not trust rehype-highlight, you can use it before. But then you need to configure rehype-sanitize to keep the classes you allow:
import {unified} from 'unified'
import rehypeHighlight from './index.js'
import rehypeParse from 'rehype-parse'
import rehypeSanitize, {defaultSchema} from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'

const file = await unified()
  .use(rehypeParse, {fragment: true})
  .use(rehypeHighlight)
  .use(rehypeSanitize, {
    ...defaultSchema,
    attributes: {
      ...defaultSchema.attributes,
      span: [
        ...(defaultSchema.attributes?.span || []),
        // Allow all class names starting with `hljs-`.
        ['className', /^hljs-./]
        // Alternatively, to allow only certain class names:
        // ['className', 'hljs-number', 'hljs-title', 'hljs-variable']
      ]
    },
    tagNames: [...(defaultSchema.tagNames || []), 'span']
  })
  .use(rehypeStringify)
  .process('<pre><code className="language-js">console.log(1)</code></pre>')

console.log(String(file))

Types

This package is fully typed with TypeScript. It exports the additional type Optionsapi-options.

Compatibility

Projects maintained by the unified collective are compatible with maintained versions of Node.js.
When we cut a new major release, we drop support for unmaintained versions of Node. This means we try to keep the current release line, rehype-highlight@^7, compatible with Node.js 16.
This plugin works with rehype-parse version 1+, rehype-stringify version 1+, rehype version 1+, and unified version 4+.

Security

Use of rehype-highlight should be safe to use as highlight.js and lowlight should be safe to use. When in doubt, use rehype-sanitizerehype-sanitize.

Related

— add metadata to the head of a document
— wrap a fragment in a document

Contribute

See contributing.mdcontributing in rehypejs/.githubhealth for ways to get started. See support.mdsupport for ways to get help.
This project has a code of conductcoc. By interacting with this repository, organization, or community you agree to abide by its terms.

License

MITlicense © Titus Wormerauthor