Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
rehype-highlight
Advanced tools
rehype-highlight is a plugin for the rehype ecosystem that provides syntax highlighting for code blocks in HTML. It uses the popular highlight.js library under the hood to perform the actual highlighting.
Basic Syntax Highlighting
This feature allows you to add syntax highlighting to code blocks in your HTML. The code sample demonstrates how to use rehype-highlight to process an HTML string containing a JavaScript code block.
const rehype = require('rehype');
const rehypeHighlight = require('rehype-highlight');
rehype()
.use(rehypeHighlight)
.process('<pre><code class="language-js">const x = 42;</code></pre>', function (err, file) {
if (err) throw err;
console.log(String(file));
});
Custom Languages
This feature allows you to add custom languages for syntax highlighting. The code sample shows how to include a custom language definition and use it with rehype-highlight.
const rehype = require('rehype');
const rehypeHighlight = require('rehype-highlight');
const customLanguage = require('highlight.js/lib/languages/yourLanguage');
rehype()
.use(rehypeHighlight, { languages: { yourLanguage: customLanguage } })
.process('<pre><code class="language-yourLanguage">your code here</code></pre>', function (err, file) {
if (err) throw err;
console.log(String(file));
});
Custom Highlight.js Configuration
This feature allows you to configure highlight.js options, such as specifying a subset of languages to include. The code sample demonstrates how to limit the languages to JavaScript and Python.
const rehype = require('rehype');
const rehypeHighlight = require('rehype-highlight');
rehype()
.use(rehypeHighlight, { subset: ['javascript', 'python'] })
.process('<pre><code class="language-js">const x = 42;</code></pre>', function (err, file) {
if (err) throw err;
console.log(String(file));
});
Prism is a lightweight, extensible syntax highlighter. It is a popular alternative to highlight.js and offers a wide range of plugins and themes. Unlike rehype-highlight, which is a rehype plugin, Prism can be used directly in the browser or with various build tools.
highlight.js is the underlying library used by rehype-highlight for syntax highlighting. It can be used directly without the rehype ecosystem, offering more control and customization options for users who do not need the additional features provided by rehype.
Shiki is a syntax highlighter that uses TextMate grammar and VS Code themes. It provides high-quality highlighting and is designed to be used in Node.js environments. Shiki offers a different approach to syntax highlighting compared to rehype-highlight, focusing on using VS Code's ecosystem.
rehype plugin to apply syntax highlighting to code with
highlight.js
(through lowlight
).
This package is a unified (rehype) plugin to apply syntax highlighting
to code with highlight.js
.
highlight.js
is pretty fast, relatively small, and a quite good syntax
highlighter which has support for up to 190 different languages.
This package bundles 35 common languages by default and you can
register more.
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, even without a class, all <pre><code>
is highlighted by
automatically detecting which code language it seems to be.
You can prevent that with a no-highlight
or nohighlight
class on the
<code>
or by passing options.subset: false
.
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.
This project is useful when you want to apply 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 lowlight
, 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.
This package is ESM only. In Node.js (version 12.20+, 14.14+, or 16.0+), install with npm:
npm install rehype-highlight
In Deno with Skypack:
import rehypeHighlight from 'https://cdn.skypack.dev/rehype-highlight@5?dts'
In browsers with Skypack:
<script type="module">
import rehypeHighlight from 'https://cdn.skypack.dev/rehype-highlight@5?min'
</script>
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
looks as follows:
import {read} from 'to-vfile'
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
main()
async function main() {
const file = await rehype()
.data('settings', {fragment: true})
.use(rehypeHighlight)
.process(await read('example.html'))
console.log(String(file))
}
Now 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 hljs-language">console</span>.<span class="hljs-title hljs-function">warn</span>(<span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>)</code></pre>
This package exports no identifiers.
The default export is rehypeHighlight
.
unified().use(rehypeHighlight[, options])
Apply syntax highlighting to code with highlight.js
.
options
Configuration (optional).
options.prefix
Prefix to use before classes (string
, default: 'hljs-'
).
options.subset
Scope of languages to check when automatically detecting (boolean
or
Array<string>
, default: all languages).
Pass false
to not highlight code without language classes.
options.plainText
List of plain-text languages (Array<string>
, default: []
).
Pass any languages you would like to be kept as plain-text instead of getting
highlighted.
This is like setting a no-highlight
class assuming txt
was listed, then
language-txt
would be treated as such too.
options.ignoreMissing
Swallow errors for missing languages (boolean
, default: false
).
By default, unregistered syntaxes throw an error when they are used.
Pass true
to swallow those errors and thus ignore code with unknown code
languages.
options.aliases
Register more aliases (Record<string, string|Array<string>>
, default: {}
).
Passed to lowlight.registerAlias
.
options.languages
Register more languages (Record<string, Function>
, default: {}
).
Each key/value pair passed as arguments to
lowlight.registerLanguage
.
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.subset
to false
, which prevents <code>
without a class from being
automatically detected.
For example, with example.html
:
<pre><code>this won’t be highlighted due to `subset: false`</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 {read} from 'to-vfile'
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
main()
async function main() {
const file = await rehype()
.data('settings', {fragment: true})
.use(rehypeHighlight, {subset: false, plainText: ['txt', 'text']})
.process(await read('example.html'))
console.log(String(file))
}
Running that yields the same as example.html
: none of them are highlighted.
rehype-highlight
supports 35 common used languages by default.
This makes it small to load in browsers and Node.js, while supporting most cases
by default.
It’s possible to add support for more languages.
For example, with example.html
:
<pre><code class="language-bnf">a ::= 'a' | 'A'</code></pre>
And example.js
:
import {read} from 'to-vfile'
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
import bnf from 'highlight.js/lib/languages/bnf'
main()
async function main() {
const file = await rehype()
.data('settings', {fragment: true})
.use(rehypeHighlight, {languages: {bnf}})
.process(await read('example.html'))
console.log(String(file))
}
Running that yields:
<pre><code class="hljs language-bnf">a ::= <span class="hljs-string">'a'</span> | <span class="hljs-string">'A'</span></code></pre>
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 {read} from 'to-vfile'
import {rehype} from 'rehype'
import rehypeHighlight from 'rehype-highlight'
main()
async function main() {
const file = await rehype()
.data('settings', {fragment: true})
// 👉 **Note**: the keys are registered and full highlight.js names, and
// the values are the flags that you want to allow as `x` in `language-x`
// classes.
.use(rehypeHighlight, {aliases: {'javascript': 'custom-script'}})
.process(await read('example.html'))
console.log(String(file))
}
Running that yields:
<pre><code class="hljs language-custom-script"><span class="hljs-variable hljs-language">console</span>.<span class="hljs-title hljs-function">log</span>(<span class="hljs-number">1</span>)</code></pre>
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 XSS vulnerabilities.
Working with user input and HTML generally opens you up to XSS vulnerabilities,
so it’s recommend to use sanitation mechanisms, typically
rehype-sanitize
.
Because arbitrary classes are one such opening that rehype-sanitize
takes care
off, using rehype-highlight
with rehype-sanitize
requires some configuration
to make it work.
There are two ways to make it work.
Either by using rehype-sanitize
first while allowing the classes on <code>
and then using rehype-highlight
, or alternatively first using
rehype-highlight
and then using rehype-sanitize
while allowing the classes
on <span>
elements.
Using rehype-sanitize
before rehype-highlight
:
import {unified} from 'unified'
import rehypeParse from 'rehype-parse'
import rehypeHighlight from 'rehype-highlight'
import rehypeSanitize, {defaultSchema} from './index.js'
import rehypeStringify from 'rehype-stringify'
main()
async function main() {
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeSanitize, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
code: [
...(defaultSchema.attributes.code || []),
// List of all allowed languages:
['className', 'language-js', 'language-css', 'language-md']
]
}
})
.use(rehypeHighlight, {subset: false})
.use(rehypeStringify)
.process('<pre><code className="language-js">console.log(1)</code></pre>')
console.log(String(file))
}
Using rehype-highlight
before rehype-sanitize
:
async function main() {
const file = await unified()
.use(rehypeParse, {fragment: true})
+ .use(rehypeHighlight, {subset: false})
.use(rehypeSanitize, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
- code: [
- ...(defaultSchema.attributes.code || []),
- // List of all allowed languages:
- ['className', 'hljs', 'language-js', 'language-css', 'language-md']
+ span: [
+ ...(defaultSchema.attributes.span || []),
+ // List of all allowed tokens:
+ ['className', 'hljs-addition', 'hljs-attr', 'hljs-attribute', 'hljs-built_in', 'hljs-bullet', 'hljs-char', 'hljs-code', 'hljs-comment', 'hljs-deletion', 'hljs-doctag', 'hljs-emphasis', 'hljs-formula', 'hljs-keyword', 'hljs-link', 'hljs-literal', 'hljs-meta', 'hljs-name', 'hljs-number', 'hljs-operator', 'hljs-params', 'hljs-property', 'hljs-punctuation', 'hljs-quote', 'hljs-regexp', 'hljs-section', 'hljs-selector-attr', 'hljs-selector-class', 'hljs-selector-id', 'hljs-selector-pseudo', 'hljs-selector-tag', 'hljs-string', 'hljs-strong', 'hljs-subst', 'hljs-symbol', 'hljs-tag', 'hljs-template-tag', 'hljs-template-variable', 'hljs-title', 'hljs-type', 'hljs-variable'
+ ]
]
}
})
- .use(rehypeHighlight, {subset: false})
.use(rehypeStringify)
.process('<pre><code className="language-js">console.log(1)</code></pre>')
This package is fully typed with TypeScript.
It exports an Options
type, which specifies the interface of the accepted
options.
Projects maintained by the unified collective are compatible with all 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.
This plugin works with rehype-parse
version 1+, rehype-stringify
version 1+,
rehype
version 1+, and unified
version 4+.
Use of rehype-highlight
should be safe to use as highlight.js
and
lowlight
should be safe to use.
When in doubt, use rehype-sanitize
.
rehype-meta
— add metadata to the head of a documentrehype-document
— wrap a fragment in a documentSee contributing.md
in rehypejs/.github
for ways
to get started.
See support.md
for ways to get help.
This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.
FAQs
rehype plugin to highlight code blocks with lowlight (highlight.js)
We found that rehype-highlight demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.