rehype-autolink-headings
Advanced tools
Comparing version
@@ -1,62 +0,2 @@ | ||
/** | ||
* Plugin to automatically add links to headings (h1-h6). | ||
* | ||
* @type {import('unified').Plugin<[Options?]|void[], Root>} | ||
*/ | ||
export default function rehypeAutolinkHeadings( | ||
options?: void | Options | undefined | ||
): | ||
| void | ||
| import('unified').Transformer<import('hast').Root, import('hast').Root> | ||
export type Root = import('hast').Root | ||
export type Parent = import('hast').Parent | ||
export type Element = import('hast').Element | ||
export type ElementChild = Element['children'][number] | ||
export type Properties = import('hast').Properties | ||
export type Test = import('hast-util-is-element').Test | ||
export type Behavior = 'prepend' | 'append' | 'wrap' | 'before' | 'after' | ||
export type Build = (node: Element) => ElementChild | ElementChild[] | ||
/** | ||
* Configuration. | ||
*/ | ||
export type Options = { | ||
/** | ||
* How to create links. | ||
*/ | ||
behavior?: Behavior | undefined | ||
/** | ||
* Please use `behavior` instead | ||
*/ | ||
behaviour?: Behavior | undefined | ||
/** | ||
* Extra properties to set on the link when injecting. | ||
* Defaults to `{ariaHidden: true, tabIndex: -1}` when `'prepend'` or | ||
* `'append'`. | ||
*/ | ||
properties?: import('hast').Properties | undefined | ||
/** | ||
* hast nodes to insert in the link. | ||
*/ | ||
content?: | ||
| import('hast').ElementContent | ||
| import('hast').ElementContent[] | ||
| Build | ||
| undefined | ||
/** | ||
* hast node to wrap the heading and link with, if `behavior` is `'before'` or | ||
* `'after'`. | ||
* There is no default. | ||
*/ | ||
group?: | ||
| import('hast').ElementContent | ||
| import('hast').ElementContent[] | ||
| Build | ||
| undefined | ||
/** | ||
* Test to define which heading elements are linked. | ||
* Any test that can be given to `hast-util-is-element` is supported. | ||
* The default (no test) is to link all headings. | ||
* Can be used to link only h1-h3, or for example all except h1. | ||
*/ | ||
test?: Test | ||
} | ||
export {default} from './lib/index.js' | ||
export type Options = import('./lib/index.js').Options |
170
index.js
/** | ||
* @typedef {import('hast').Root} Root | ||
* @typedef {import('hast').Parent} Parent | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {Element['children'][number]} ElementChild | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('hast-util-is-element').Test} Test | ||
* | ||
* @typedef {'prepend'|'append'|'wrap'|'before'|'after'} Behavior | ||
* | ||
* @callback Build | ||
* @param {Element} node | ||
* @returns {ElementChild|ElementChild[]} | ||
* | ||
* @typedef Options | ||
* Configuration. | ||
* @property {Behavior} [behavior='prepend'] | ||
* How to create links. | ||
* @property {Behavior} [behaviour] | ||
* Please use `behavior` instead | ||
* @property {Properties} [properties] | ||
* Extra properties to set on the link when injecting. | ||
* Defaults to `{ariaHidden: true, tabIndex: -1}` when `'prepend'` or | ||
* `'append'`. | ||
* @property {ElementChild|ElementChild[]|Build} [content={type: 'element', tagName: 'span', properties: {className: ['icon', 'icon-link']}, children: []}] | ||
* hast nodes to insert in the link. | ||
* @property {ElementChild|ElementChild[]|Build} [group] | ||
* hast node to wrap the heading and link with, if `behavior` is `'before'` or | ||
* `'after'`. | ||
* There is no default. | ||
* @property {Test} [test] | ||
* Test to define which heading elements are linked. | ||
* Any test that can be given to `hast-util-is-element` is supported. | ||
* The default (no test) is to link all headings. | ||
* Can be used to link only h1-h3, or for example all except h1. | ||
* @typedef {import('./lib/index.js').Options} Options | ||
*/ | ||
import extend from 'extend' | ||
import {hasProperty} from 'hast-util-has-property' | ||
import {headingRank} from 'hast-util-heading-rank' | ||
import {convertElement} from 'hast-util-is-element' | ||
import {visit, SKIP} from 'unist-util-visit' | ||
/** @type {Element} */ | ||
const contentDefaults = { | ||
type: 'element', | ||
tagName: 'span', | ||
properties: {className: ['icon', 'icon-link']}, | ||
children: [] | ||
} | ||
/** | ||
* Plugin to automatically add links to headings (h1-h6). | ||
* | ||
* @type {import('unified').Plugin<[Options?]|void[], Root>} | ||
*/ | ||
export default function rehypeAutolinkHeadings(options = {}) { | ||
let props = options.properties | ||
const behavior = options.behaviour || options.behavior || 'prepend' | ||
const content = options.content || contentDefaults | ||
const group = options.group | ||
const is = convertElement(options.test) | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
let method | ||
if (behavior === 'wrap') { | ||
method = wrap | ||
} else if (behavior === 'before' || behavior === 'after') { | ||
method = around | ||
} else { | ||
if (!props) { | ||
props = {ariaHidden: 'true', tabIndex: -1} | ||
} | ||
method = inject | ||
} | ||
return (tree) => { | ||
visit(tree, 'element', (node, index, parent) => { | ||
if ( | ||
headingRank(node) && | ||
hasProperty(node, 'id') && | ||
is(node, index, parent) | ||
) { | ||
return method(node, index, parent) | ||
} | ||
}) | ||
} | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
function inject(node) { | ||
node.children[behavior === 'prepend' ? 'unshift' : 'push']( | ||
create(node, extend(true, {}, props), toChildren(content, node)) | ||
) | ||
return [SKIP] | ||
} | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
function around(node, index, parent) { | ||
// Uncommon. | ||
/* c8 ignore next */ | ||
if (typeof index !== 'number' || !parent) return | ||
const link = create( | ||
node, | ||
extend(true, {}, props), | ||
toChildren(content, node) | ||
) | ||
let nodes = behavior === 'before' ? [link, node] : [node, link] | ||
if (group) { | ||
const grouping = toNode(group, node) | ||
if (grouping && !Array.isArray(grouping) && grouping.type === 'element') { | ||
grouping.children = nodes | ||
nodes = [grouping] | ||
} | ||
} | ||
parent.children.splice(index, 1, ...nodes) | ||
return [SKIP, index + nodes.length] | ||
} | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
function wrap(node) { | ||
node.children = [create(node, extend(true, {}, props), node.children)] | ||
return [SKIP] | ||
} | ||
/** | ||
* @param {ElementChild|ElementChild[]|Build} value | ||
* @param {Element} node | ||
* @returns {ElementChild[]} | ||
*/ | ||
function toChildren(value, node) { | ||
const result = toNode(value, node) | ||
return Array.isArray(result) ? result : [result] | ||
} | ||
/** | ||
* @param {ElementChild|ElementChild[]|Build} value | ||
* @param {Element} node | ||
* @returns {ElementChild|ElementChild[]} | ||
*/ | ||
function toNode(value, node) { | ||
if (typeof value === 'function') return value(node) | ||
return extend(true, Array.isArray(value) ? [] : {}, value) | ||
} | ||
/** | ||
* @param {Element} node | ||
* @param {Properties} props | ||
* @param {ElementChild[]} children | ||
* @returns {Element} | ||
*/ | ||
function create(node, props, children) { | ||
return { | ||
type: 'element', | ||
tagName: 'a', | ||
properties: Object.assign({}, props, { | ||
// Fix hast types and make them required. | ||
/* c8 ignore next */ | ||
href: '#' + (node.properties || {}).id | ||
}), | ||
children | ||
} | ||
} | ||
} | ||
export {default} from './lib/index.js' |
{ | ||
"name": "rehype-autolink-headings", | ||
"version": "6.1.0", | ||
"version": "6.1.1", | ||
"description": "rehype plugin to add links to headings", | ||
@@ -30,2 +30,3 @@ "license": "MIT", | ||
"files": [ | ||
"lib/", | ||
"index.d.ts", | ||
@@ -44,3 +45,3 @@ "index.js" | ||
"devDependencies": { | ||
"@types/extend": "^3.0.1", | ||
"@types/extend": "^3.0.0", | ||
"@types/tape": "^4.0.0", | ||
@@ -58,7 +59,7 @@ "bail": "^2.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.44.0" | ||
"typescript": "~4.4.0", | ||
"xo": "^0.47.0" | ||
}, | ||
"scripts": { | ||
"build": "rimraf \"*.d.ts\" \"test/**/*.d.ts\" && tsc && type-coverage", | ||
"build": "rimraf \"lib/**/*.d.ts\" \"test/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
@@ -65,0 +66,0 @@ "test-api": "node --conditions development test/index.js", |
319
readme.md
@@ -11,12 +11,58 @@ # rehype-autolink-headings | ||
[**rehype**][rehype] plugin to automatically add links to headings (h1-h6) that | ||
already have an ID. | ||
**[rehype][]** plugin to add links to headings with `id`s back to themselves. | ||
## Contents | ||
* [What is this?](#what-is-this) | ||
* [When should I use this?](#when-should-i-use-this) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`unified().use(rehypeAutolinkHeadings[, options])`](#unifieduserehypeautolinkheadings-options) | ||
* [Examples](#examples) | ||
* [Example: different behaviors](#example-different-behaviors) | ||
* [Example: content](#example-content) | ||
* [Example: group](#example-group) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Security](#security) | ||
* [Related](#related) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
## What is this? | ||
This package is a [unified][] ([rehype][]) plugin to add links from headings | ||
back to themselves. | ||
It looks for headings (so `<h1>` through `<h6>`), that have `id` attributes, | ||
and injects a link to themselves. | ||
Similar functionality is applied by many places that render markdown. | ||
For example, when browsing this readme on GitHub or npm, an anchor is added | ||
to headings, which you can share to point people to a particular place in a | ||
document. | ||
**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 adds links to headings in the AST. | ||
## When should I use this? | ||
This plugin is useful when you have relatively long documents, where you want | ||
users to be able to link to particular sections, and you already have `id` | ||
attributes set on all (or certain?) headings. | ||
A different plugin, [`rehype-slug`][rehype-slug], adds `id`s to headings. | ||
When a heading doesn’t already have an `id` attribute, it creates a slug from | ||
it, and adds that as the `id` attribute. | ||
When using both plugins together, all headings (whether explicitly with a | ||
certain `id` or automatically with a generate one) will get a link back to | ||
themselves. | ||
## Install | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). | ||
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: | ||
[npm][]: | ||
```sh | ||
@@ -26,9 +72,23 @@ npm install rehype-autolink-headings | ||
In Deno with [Skypack][]: | ||
```js | ||
import rehypeAutolinkHeadings from 'https://cdn.skypack.dev/rehype-autolink-headings@6?dts' | ||
``` | ||
In browsers with [Skypack][]: | ||
```html | ||
<script type="module"> | ||
import rehypeAutolinkHeadings from 'https://cdn.skypack.dev/rehype-autolink-headings@6?min' | ||
</script> | ||
``` | ||
## Use | ||
Say we have the following file, `fragment.html`: | ||
Say we have the following file `example.html`: | ||
```html | ||
<h1>Lorem ipsum 😪</h1> | ||
<h2>dolor—sit—amet</h2> | ||
<h1 id=some-id>Lorem ipsum</h1> | ||
<h2>Dolor sit amet 😪</h2> | ||
<h3>consectetur & adipisicing</h3> | ||
@@ -39,32 +99,37 @@ <h4>elit</h4> | ||
And our script, `example.js`, looks as follows: | ||
And our module `example.js` looks as follows: | ||
```js | ||
import fs from 'node:fs' | ||
import rehype from 'rehype' | ||
import {read} from 'to-vfile' | ||
import {rehype} from 'rehype' | ||
import rehypeSlug from 'rehype-slug' | ||
import rehypeAutolinkHeadings from 'rehype-autolink-headings' | ||
const buf = fs.readFileSync('fragment.html') | ||
main() | ||
rehype() | ||
.data('settings', {fragment: true}) | ||
.use(rehypeSlug) | ||
.use(rehypeAutolinkHeadings) | ||
.process(buf) | ||
.then((file) => { | ||
console.log(String(file)) | ||
}) | ||
async function main() { | ||
const file = await rehype() | ||
.data('settings', {fragment: true}) | ||
.use(rehypeSlug) | ||
.use(rehypeAutolinkHeadings) | ||
.process(await read('example.html')) | ||
console.log(String(file)) | ||
} | ||
``` | ||
Now, running `node example` yields: | ||
Now, running `node example.js` yields: | ||
```html | ||
<h1 id="lorem-ipsum-"><a aria-hidden="true" href="#lorem-ipsum-"><span class="icon icon-link"></span></a>Lorem ipsum 😪</h1> | ||
<h2 id="dolorsitamet"><a aria-hidden="true" href="#dolorsitamet"><span class="icon icon-link"></span></a>dolor—sit—amet</h2> | ||
<h3 id="consectetur--adipisicing"><a aria-hidden="true" href="#consectetur--adipisicing"><span class="icon icon-link"></span></a>consectetur & adipisicing</h3> | ||
<h4 id="elit"><a aria-hidden="true" href="#elit"><span class="icon icon-link"></span></a>elit</h4> | ||
<h5 id="elit-1"><a aria-hidden="true" href="#elit-1"><span class="icon icon-link"></span></a>elit</h5> | ||
<h1 id="some-id"><a aria-hidden="true" tabindex="-1" href="#some-id"><span class="icon icon-link"></span></a>Lorem ipsum</h1> | ||
<h2 id="dolor-sit-amet-"><a aria-hidden="true" tabindex="-1" href="#dolor-sit-amet-"><span class="icon icon-link"></span></a>Dolor sit amet 😪</h2> | ||
<h3 id="consectetur--adipisicing"><a aria-hidden="true" tabindex="-1" href="#consectetur--adipisicing"><span class="icon icon-link"></span></a>consectetur & adipisicing</h3> | ||
<h4 id="elit"><a aria-hidden="true" tabindex="-1" href="#elit"><span class="icon icon-link"></span></a>elit</h4> | ||
<h5 id="elit-1"><a aria-hidden="true" tabindex="-1" href="#elit-1"><span class="icon icon-link"></span></a>elit</h5> | ||
``` | ||
> 👉 **Note**: observe that from the `<h2>` on, automatic `id`s are generated. | ||
> This is done by `rehype-slug`. | ||
> Without `rehype-slug`, those headings would not be linked. | ||
## API | ||
@@ -77,9 +142,11 @@ | ||
Add links to headings (h1-h6) with an `id`. | ||
Add links to headings with `id`s back to themselves. | ||
**Note**: this plugin expects `id`s to already exist on headings. | ||
One way to add those automatically is [`rehype-slug`][slug] (see example). | ||
> 👉 **Note**: this plugin operates on headings that have `id` attributes. | ||
> You can use `rehype-slug` to automatically generate `id`s for headings. | ||
##### `options` | ||
Configuration (optional). | ||
###### `options.behavior` | ||
@@ -95,76 +162,168 @@ | ||
Supplying `wrap` will ignore any value defined by the `content` option. | ||
Supplying `prepend`, `append`, or `wrap` will ignore the `group` option. | ||
> 👉 **Note**: `options.content` is ignored when the behavior is `wrap`, | ||
> `options.group` is ignored when the behavior is `prepend`, `append`, or | ||
> `wrap`. | ||
###### `options.properties` | ||
Extra properties to set on the link (`Object?`). | ||
Attributes to set on the link ([`Properties`][properties], optional). | ||
Defaults to `{ariaHidden: true, tabIndex: -1}` when in `'prepend'` or | ||
`'append'` mode. | ||
`'append'` mode, and `{}` otherwise. | ||
###### `options.content` | ||
[**hast**][hast] nodes to insert in the link (`Function|Node|Children`). | ||
By default, the following is used: | ||
**[hast][]** nodes to insert in the link (`Function|Node|Children`). | ||
By default, a `<span class="icon icon-link"></span>` is used. | ||
When a function is given, it’s called with the current heading (`Element`) and | ||
should return one or more nodes. | ||
> 👉 **Note**: this option is ignored when the behavior is `wrap`. | ||
###### `options.group` | ||
**[hast][]** node to wrap the heading and link with (`Function|Node`, optional). | ||
There is no default. | ||
When a function is given, it’s called with the current heading (`Element`) and | ||
should return a hast node. | ||
> 👉 **Note**: this option is ignored when the behavior is `prepend`, `append`, | ||
> or `wrap` | ||
###### `options.test` | ||
Test to define which heading elements are linked. | ||
Any test that can be given to [`hast-util-is-element`][hast-util-is-element] is | ||
supported. | ||
The default (no test) is to link all headings with an `id` attribute. | ||
Can be used to link only `<h1>` through `<h3>` (with `['h1', 'h2', 'h3']`), or | ||
for example all except `<h1>` (with `['h2', 'h3', 'h4', 'h5', 'h6']`). | ||
A function can be given to do more complex things. | ||
## Examples | ||
### Example: different behaviors | ||
This example shows what each behavior generates by default. | ||
```js | ||
{ | ||
type: 'element', | ||
tagName: 'span', | ||
properties: {className: ['icon', 'icon-link']}, | ||
children: [] | ||
import {rehype} from 'rehype' | ||
import rehypeAutolinkHeadings from 'rehype-autolink-headings' | ||
main() | ||
async function main() { | ||
const behaviors = ['prepend', 'append', 'wrap', 'before', 'after'] | ||
let index = -1 | ||
while (++index < behaviors.length) { | ||
const behavior = behaviors[index] | ||
console.log( | ||
String( | ||
await rehype() | ||
.data('settings', {fragment: true}) | ||
.use(rehypeAutolinkHeadings, {behavior}) | ||
.process('<h1 id="' + behavior + '">' + behavior + '</h1>') | ||
) | ||
) | ||
} | ||
} | ||
``` | ||
If `behavior` is `wrap`, then `content` is ignored. | ||
Yields: | ||
If `content` is a function, it’s called with the current heading (`Element`) and | ||
should return one or more nodes: | ||
```html | ||
<h1 id="prepend"><a aria-hidden="true" tabindex="-1" href="#prepend"><span class="icon icon-link"></span></a>prepend</h1> | ||
<h1 id="append">append<a aria-hidden="true" tabindex="-1" href="#append"><span class="icon icon-link"></span></a></h1> | ||
<h1 id="wrap"><a href="#wrap">wrap</a></h1> | ||
<a href="#before"><span class="icon icon-link"></span></a><h1 id="before">before</h1> | ||
<h1 id="after">after</h1><a href="#after"><span class="icon icon-link"></span></a> | ||
``` | ||
### Example: content | ||
The following example passes `content` as a function, to generate an accessible | ||
description of each link. | ||
```js | ||
import {rehype} from 'rehype' | ||
import rehypeAutolinkHeadings from 'rehype-autolink-headings' | ||
import {toString} from 'hast-util-to-string' | ||
import {h} from 'hastscript' | ||
// … | ||
main() | ||
function content(node) { | ||
return [ | ||
h('span.visually-hidden', 'Read the “', toString(node), '” section'), | ||
h('span.icon.icon-link', {ariaHidden: true}) | ||
] | ||
async function main() { | ||
const file = await rehype() | ||
.data('settings', {fragment: true}) | ||
.use(rehypeAutolinkHeadings, { | ||
content(node) { | ||
return [ | ||
h('span.visually-hidden', 'Read the “', toString(node), '” section'), | ||
h('span.icon.icon-link', {ariaHidden: 'true'}) | ||
] | ||
} | ||
}) | ||
.process('<h1 id="xxx">xxx</h1>') | ||
console.log(String(file)) | ||
} | ||
``` | ||
###### `options.group` | ||
Yields: | ||
[**hast**][hast] node to wrap the heading and link with (`Function|Node`), if | ||
`behavior` is `before` or `after`. | ||
There is no default. | ||
```html | ||
<h1 id="xxx"><a aria-hidden="true" tabindex="-1" href="#xxx"><span class="visually-hidden">Read the “xxx” section</span><span class="icon icon-link" aria-hidden="true"></span></a>xxx</h1> | ||
``` | ||
If `behavior` is `prepend`, `append`, or `wrap`, then `group` is ignored. | ||
### Example: group | ||
If `group` is a function, it’s called with the current heading (`Element`) and | ||
should return a hast node. | ||
The following example passes `group` as a function, to dynamically generate a | ||
differing element that wraps the heading. | ||
```js | ||
import {rehype} from 'rehype' | ||
import rehypeAutolinkHeadings from 'rehype-autolink-headings' | ||
import {h} from 'hastscript' | ||
// … | ||
main() | ||
function group(node) { | ||
return h('.heading-' + node.charAt(1) + '-group') | ||
async function main() { | ||
const file = await rehype() | ||
.data('settings', {fragment: true}) | ||
.use(rehypeAutolinkHeadings, { | ||
behavior: 'before', | ||
group(node) { | ||
return h('.heading-' + node.tagName.charAt(1) + '-group') | ||
} | ||
}) | ||
.process('<h1 id="xxx">xxx</h1>') | ||
console.log(String(file)) | ||
} | ||
``` | ||
###### `options.test` | ||
Yields: | ||
Test to define which heading elements are linked. | ||
Any test that can be given to [`hast-util-is-element`][is] is supported. | ||
The default (no test) is to link all headings. | ||
```html | ||
<div class="heading-1-group"><a href="#xxx"><span class="icon icon-link"></span></a><h1 id="xxx">xxx</h1></div> | ||
``` | ||
Can be used to link only `<h1>` through `<h3>` (with `['h1', 'h2', 'h3']`), or | ||
for example all except `<h1>` (with `['h2', 'h3', 'h4', 'h5', 'h6']`). | ||
## Types | ||
Functions can also be given to do more complex things! | ||
This package is fully typed with [TypeScript][]. | ||
It exports an `Options` type, which specifies the interface of the accepted | ||
options. | ||
## Compatibility | ||
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+. | ||
## Security | ||
@@ -176,12 +335,12 @@ | ||
Always be wary of user input and use [`rehype-sanitize`][sanitize]. | ||
Always be wary of user input and use [`rehype-sanitize`][rehype-sanitize]. | ||
## Related | ||
* [`rehype-slug`][slug] | ||
— Add `id`s to headings | ||
* [`rehype-slug`][rehype-slug] | ||
— add `id`s to headings | ||
* [`rehype-highlight`](https://github.com/rehypejs/rehype-highlight) | ||
— Syntax highlight code blocks | ||
— apply syntax highlighting to code blocks | ||
* [`rehype-toc`](https://github.com/JS-DevTools/rehype-toc) | ||
— Add a table of contents (TOC) | ||
— add a table of contents (TOC) | ||
@@ -232,2 +391,4 @@ ## Contribute | ||
[skypack]: https://www.skypack.dev | ||
[health]: https://github.com/rehypejs/.github | ||
@@ -245,12 +406,18 @@ | ||
[hast]: https://github.com/syntax-tree/hast | ||
[typescript]: https://www.typescriptlang.org | ||
[unified]: https://github.com/unifiedjs/unified | ||
[rehype]: https://github.com/rehypejs/rehype | ||
[hast]: https://github.com/syntax-tree/hast | ||
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting | ||
[sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[slug]: https://github.com/rehypejs/rehype-slug | ||
[rehype-slug]: https://github.com/rehypejs/rehype-slug | ||
[is]: https://github.com/syntax-tree/hast-util-is-element | ||
[hast-util-is-element]: https://github.com/syntax-tree/hast-util-is-element | ||
[properties]: https://github.com/syntax-tree/hast#properties |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
23180
34.33%7
40%220
2.8%416
67.07%1
Infinity%