rehype-external-links
Advanced tools
Comparing version
@@ -1,67 +0,7 @@ | ||
export default function rehypeExternalLinks( | ||
this: import('unified').Processor<void, import('hast').Root, void, void>, | ||
...settings: [(Options | undefined)?] | void[] | ||
): | ||
| void | ||
| import('unified').Transformer<import('hast').Root, import('hast').Root> | ||
export type Root = import('hast').Root | ||
export type Properties = import('hast').Properties | ||
export type Element = import('hast').Element | ||
export type Test = import('hast-util-is-element').Test | ||
export type ElementChild = Element['children'][number] | ||
export type Target = '_self' | '_blank' | '_parent' | '_top' | ||
export type Rel = Array<string> | string | ||
export type Protocols = Array<string> | ||
export type Content = ElementChild | Array<ElementChild> | ||
export type ContentProperties = Properties | ||
export type TargetCallback = (node: Element) => Target | null | undefined | ||
export type RelCallback = (node: Element) => Rel | null | undefined | ||
export type ProtocolsCallback = (node: Element) => Protocols | null | undefined | ||
export type ContentCallback = (node: Element) => Content | null | undefined | ||
export type ContentPropertiesCallback = ( | ||
node: Element | ||
) => Properties | null | undefined | ||
/** | ||
* Configuration. | ||
*/ | ||
export type Options = { | ||
/** | ||
* How to display referenced documents (`string?`: `_self`, `_blank`, | ||
* `_parent`, or `_top`, default: `_blank`). | ||
* The default (nothing) is to not set `target`s on links. | ||
*/ | ||
target?: Target | TargetCallback | undefined | ||
/** | ||
* Link types to hint about the referenced documents. | ||
* Pass an empty array (`[]`) to not set `rel`s on links. | ||
* | ||
* **Note**: when using a `target`, add `noopener` and `noreferrer` to avoid | ||
* exploitation of the `window.opener` API. | ||
*/ | ||
rel?: Rel | RelCallback | undefined | ||
/** | ||
* Protocols to check, such as `mailto` or `tel`. | ||
*/ | ||
protocols?: Protocols | ProtocolsCallback | undefined | ||
/** | ||
* hast content to insert at the end of external links. | ||
* Will be inserted in a `<span>` element. | ||
* | ||
* Useful for improving accessibility by giving users advanced warning when | ||
* opening a new window. | ||
*/ | ||
content?: Content | ContentCallback | undefined | ||
/** | ||
* hast properties to add to the `span` wrapping `content`, when given. | ||
*/ | ||
contentProperties?: | ||
| import('hast').Properties | ||
| ContentPropertiesCallback | ||
| undefined | ||
/** | ||
* Additional test to define which external link elements are modified. | ||
* Any test that can be given to `hast-util-is-element` is supported. | ||
* The default (no test) is to modify all external links. | ||
*/ | ||
test?: Test | ||
} | ||
export { default } from "./lib/index.js"; | ||
export type CreateContent = import('./lib/index.js').CreateContent; | ||
export type CreateProperties = import('./lib/index.js').CreateProperties; | ||
export type CreateRel = import('./lib/index.js').CreateRel; | ||
export type CreateTarget = import('./lib/index.js').CreateTarget; | ||
export type Options = import('./lib/index.js').Options; | ||
export type Target = import('./lib/index.js').Target; |
148
index.js
/** | ||
* @typedef {import('hast').Root} Root | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast-util-is-element').Test} Test | ||
* | ||
* @typedef {Element['children'][number]} ElementChild | ||
* | ||
* @typedef {'_self'|'_blank'|'_parent'|'_top'} Target | ||
* @typedef {Array<string>|string} Rel | ||
* @typedef {Array<string>} Protocols | ||
* @typedef {ElementChild|Array<ElementChild>} Content | ||
* @typedef {Properties} ContentProperties | ||
* | ||
* @callback TargetCallback | ||
* @param {Element} node | ||
* @returns {Target|null|undefined} | ||
* | ||
* @callback RelCallback | ||
* @param {Element} node | ||
* @returns {Rel|null|undefined} | ||
* | ||
* @callback ProtocolsCallback | ||
* @param {Element} node | ||
* @returns {Protocols|null|undefined} | ||
* | ||
* @callback ContentCallback | ||
* @param {Element} node | ||
* @returns {Content|null|undefined} | ||
* | ||
* @callback ContentPropertiesCallback | ||
* @param {Element} node | ||
* @returns {Properties|null|undefined} | ||
* | ||
* @typedef Options | ||
* Configuration. | ||
* @property {Target|TargetCallback} [target] | ||
* How to display referenced documents (`string?`: `_self`, `_blank`, | ||
* `_parent`, or `_top`, default: `_blank`). | ||
* The default (nothing) is to not set `target`s on links. | ||
* @property {Rel|RelCallback} [rel=['nofollow', 'noopener', 'noreferrer']] | ||
* Link types to hint about the referenced documents. | ||
* Pass an empty array (`[]`) to not set `rel`s on links. | ||
* | ||
* **Note**: when using a `target`, add `noopener` and `noreferrer` to avoid | ||
* exploitation of the `window.opener` API. | ||
* @property {Protocols|ProtocolsCallback} [protocols=['http', 'https']] | ||
* Protocols to check, such as `mailto` or `tel`. | ||
* @property {Content|ContentCallback} [content] | ||
* hast content to insert at the end of external links. | ||
* Will be inserted in a `<span>` element. | ||
* | ||
* Useful for improving accessibility by giving users advanced warning when | ||
* opening a new window. | ||
* @property {ContentProperties|ContentPropertiesCallback} [contentProperties] | ||
* hast properties to add to the `span` wrapping `content`, when given. | ||
* @property {Test} [test] | ||
* Additional test to define which external link elements are modified. | ||
* Any test that can be given to `hast-util-is-element` is supported. | ||
* The default (no test) is to modify all external links. | ||
* @typedef {import('./lib/index.js').CreateContent} CreateContent | ||
* @typedef {import('./lib/index.js').CreateProperties} CreateProperties | ||
* @typedef {import('./lib/index.js').CreateRel} CreateRel | ||
* @typedef {import('./lib/index.js').CreateTarget} CreateTarget | ||
* @typedef {import('./lib/index.js').Options} Options | ||
* @typedef {import('./lib/index.js').Target} Target | ||
*/ | ||
import {visit} from 'unist-util-visit' | ||
import {parse} from 'space-separated-tokens' | ||
import {convertElement} from 'hast-util-is-element' | ||
import isAbsoluteUrl from 'is-absolute-url' | ||
import extend from 'extend' | ||
const defaultRel = ['nofollow'] | ||
const defaultProtocols = ['http', 'https'] | ||
/** | ||
* If this is a value, return that. | ||
* If this is a function instead, call it to get the result. | ||
* | ||
* @template T | ||
* @param {T} value | ||
* @param {Element} node | ||
* @returns {T extends Function ? ReturnType<T> : T} | ||
*/ | ||
function callIfNeeded(value, node) { | ||
return typeof value === 'function' ? value(node) : value | ||
} | ||
/** | ||
* Plugin to automatically add `target` and `rel` attributes to external links. | ||
* | ||
* @type {import('unified').Plugin<[Options?] | Array<void>, Root>} | ||
*/ | ||
export default function rehypeExternalLinks(options = {}) { | ||
const is = convertElement(options.test) | ||
return (tree) => { | ||
visit(tree, 'element', (node, index, parent) => { | ||
if ( | ||
node.tagName === 'a' && | ||
node.properties && | ||
typeof node.properties.href === 'string' && | ||
is(node, index, parent) | ||
) { | ||
const url = node.properties.href | ||
const protocol = url.slice(0, url.indexOf(':')) | ||
const target = callIfNeeded(options.target, node) | ||
const relRaw = callIfNeeded(options.rel, node) || defaultRel | ||
const rel = typeof relRaw === 'string' ? parse(relRaw) : relRaw | ||
const protocols = | ||
callIfNeeded(options.protocols, node) || defaultProtocols | ||
const contentRaw = callIfNeeded(options.content, node) | ||
const content = | ||
contentRaw && !Array.isArray(contentRaw) ? [contentRaw] : contentRaw | ||
const contentProperties = | ||
callIfNeeded(options.contentProperties, node) || {} | ||
if ( | ||
isAbsoluteUrl(url) | ||
? protocols.includes(protocol) | ||
: url.startsWith('//') | ||
) { | ||
if (target) { | ||
node.properties.target = target | ||
} | ||
if (rel.length > 0) { | ||
node.properties.rel = rel.concat() | ||
} | ||
if (content) { | ||
node.children.push({ | ||
type: 'element', | ||
tagName: 'span', | ||
properties: extend(true, contentProperties), | ||
children: extend(true, content) | ||
}) | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
export {default} from './lib/index.js' |
{ | ||
"name": "rehype-external-links", | ||
"version": "2.1.0", | ||
"version": "3.0.0", | ||
"description": "rehype plugin to automatically add `target` and `rel` attributes to external links", | ||
@@ -30,5 +30,5 @@ "license": "MIT", | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"exports": "./index.js", | ||
"files": [ | ||
"lib/", | ||
"index.d.ts", | ||
@@ -38,44 +38,40 @@ "index.js" | ||
"dependencies": { | ||
"@types/hast": "^2.0.0", | ||
"extend": "^3.0.0", | ||
"hast-util-is-element": "^2.0.0", | ||
"@types/hast": "^3.0.0", | ||
"@ungap/structured-clone": "^1.0.0", | ||
"hast-util-is-element": "^3.0.0", | ||
"is-absolute-url": "^4.0.0", | ||
"space-separated-tokens": "^2.0.0", | ||
"unified": "^10.0.0", | ||
"unist-util-visit": "^4.0.0" | ||
"unist-util-visit": "^5.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/tape": "^4.0.0", | ||
"c8": "^7.0.0", | ||
"prettier": "^2.0.0", | ||
"rehype": "^12.0.0", | ||
"@types/node": "^20.0.0", | ||
"@types/ungap__structured-clone": "^0.3.0", | ||
"c8": "^8.0.0", | ||
"prettier": "^3.0.0", | ||
"rehype": "^13.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^5.0.0", | ||
"xo": "^0.54.0" | ||
"xo": "^0.56.0" | ||
}, | ||
"scripts": { | ||
"build": "rimraf \"*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"build": "tsc --build --clean && tsc --build && type-coverage", | ||
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix", | ||
"prepack": "npm run build && npm run format", | ||
"test": "npm run build && npm run format && npm run test-coverage", | ||
"test-api": "node --conditions development test.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov npm run test-api", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
"test-coverage": "c8 --100 --check-coverage --reporter lcov npm run test-api" | ||
}, | ||
"prettier": { | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"bracketSpacing": false, | ||
"singleQuote": true, | ||
"bracketSpacing": false, | ||
"semi": false, | ||
"trailingComma": "none" | ||
"tabWidth": 2, | ||
"trailingComma": "none", | ||
"useTabs": false | ||
}, | ||
"xo": { | ||
"prettier": true | ||
}, | ||
"remarkConfig": { | ||
"plugins": [ | ||
"preset-wooorm" | ||
"remark-preset-wooorm" | ||
] | ||
@@ -86,5 +82,8 @@ }, | ||
"detail": true, | ||
"strict": true, | ||
"ignoreCatch": true | ||
"ignoreCatch": true, | ||
"strict": true | ||
}, | ||
"xo": { | ||
"prettier": true | ||
} | ||
} |
238
readme.md
@@ -21,4 +21,8 @@ # rehype-external-links | ||
* [`unified().use(rehypeExternalLinks[, options])`](#unifieduserehypeexternallinks-options) | ||
* [Examples](#examples) | ||
* [Example: dynamic options](#example-dynamic-options) | ||
* [`CreateContent`](#createcontent) | ||
* [`CreateProperties`](#createproperties) | ||
* [`CreateRel`](#createrel) | ||
* [`CreateTarget`](#createtarget) | ||
* [`Options`](#options) | ||
* [`Target`](#target) | ||
* [Types](#types) | ||
@@ -55,4 +59,4 @@ * [Compatibility](#compatibility) | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). | ||
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: | ||
This package is [ESM only][esm]. | ||
In Node.js (version 16+), install with [npm][]: | ||
@@ -66,3 +70,3 @@ ```sh | ||
```js | ||
import rehypeExternalLinks from 'https://esm.sh/rehype-external-links@1' | ||
import rehypeExternalLinks from 'https://esm.sh/rehype-external-links@3' | ||
``` | ||
@@ -74,3 +78,3 @@ | ||
<script type="module"> | ||
import rehypeExternalLinks from 'https://esm.sh/rehype-external-links@1?bundle' | ||
import rehypeExternalLinks from 'https://esm.sh/rehype-external-links@3?bundle' | ||
</script> | ||
@@ -81,10 +85,10 @@ ``` | ||
Say our module `example.js` looks as follows: | ||
Say our module `example.js` contains: | ||
```js | ||
import {unified} from 'unified' | ||
import rehypeExternalLinks from 'rehype-external-links' | ||
import remarkParse from 'remark-parse' | ||
import remarkRehype from 'remark-rehype' | ||
import rehypeExternalLinks from 'rehype-external-links' | ||
import rehypeStringify from 'rehype-stringify' | ||
import {unified} from 'unified' | ||
@@ -101,3 +105,3 @@ const file = await unified() | ||
Now running `node example.js` yields: | ||
…then running `node example.js` yields: | ||
@@ -111,113 +115,143 @@ ```html | ||
This package exports no identifiers. | ||
The default export is `rehypeExternalLinks`. | ||
The default export is [`rehypeExternalLinks`][api-rehype-external-links]. | ||
### `unified().use(rehypeExternalLinks[, options])` | ||
Add `rel` (and `target`) to external links. | ||
Automatically add `rel` (and `target`?) to external links. | ||
##### `options` | ||
###### Parameters | ||
Configuration (optional). | ||
* `options` ([`Options`][api-options], optional) | ||
— configuration | ||
###### `options.target` | ||
###### Returns | ||
How to open external documents (`string?`: `_self`, `_blank`, `_parent`, | ||
or `_top`, default: `undefined`). | ||
Can also be a function called with the current element to get `target` | ||
dynamically. | ||
The default (nothing) is to not set `target`s on links. | ||
Transform ([`Transformer`][unified-transformer]). | ||
> 👉 **Note**: [you should likely not configure this][css-tricks]. | ||
###### Notes | ||
###### `options.rel` | ||
You should [likely not configure `target`][css-tricks]. | ||
[Link types][mdn-rel] to hint about the referenced documents (`Array<string>` | ||
or `string`, default: `['nofollow']`). | ||
Can also be a function called with the current element to get `rel` dynamically. | ||
Pass an empty array (`[]`) to not set `rel`s on links. | ||
You should at least set `rel` to `['nofollow']`. | ||
When using a `target`, add `noopener` and `noreferrer` to avoid exploitation | ||
of the `window.opener` API. | ||
> 👉 **Note**: you should at least set `['nofollow']`. | ||
When using a `target`, you should set `content` to adhere to accessibility | ||
guidelines by [giving users advanced warning when opening a new window][g201]. | ||
> ⚠️ **Danger**: when using a `target`, add [`noopener` and `noreferrer`][mdn-a] | ||
> to avoid exploitation of the `window.opener` API. | ||
### `CreateContent` | ||
###### `options.protocols` | ||
Create a target for the element (TypeScript type). | ||
Protocols to see as external, such as `mailto` or `tel` (`Array<string>`, | ||
default: `['http', 'https']`). | ||
Can also be a function called with the current element to get `protocols` | ||
dynamically. | ||
###### Parameters | ||
###### `options.content` | ||
* `element` ([`Element`][hast-element]) | ||
— element to check | ||
**[hast][]** content to insert at the end of external links ([`Node`][node] or | ||
[`Children`][children], optional). | ||
Can also be a function called with the current element to get `content` | ||
dynamically. | ||
The content will be inserted in a `<span>` element. | ||
###### Returns | ||
> 👉 **Note**: you should set this when using `target` to adhere to | ||
> accessibility guidelines by [giving users advanced warning when opening a new | ||
> window][g201]. | ||
Content to add (`Array<Node>` or `Node`, optional). | ||
###### `options.contentProperties` | ||
### `CreateProperties` | ||
Attributes to add to the `<span>`s wrapping `options.content` | ||
([`Properties`][properties], optional). | ||
Can also be a function called with the current element to get | ||
`contentProperties` dynamically. | ||
Create properties for an element (TypeScript type). | ||
###### `options.test` | ||
###### Parameters | ||
Additional test to define which external link elements are modified. | ||
Any test that can be given to [hast-util-is-element](https://github.com/syntax-tree/hast-util-is-element) | ||
is supported. The default (no test) is to modify all external links. | ||
* `element` ([`Element`][hast-element]) | ||
— element to check | ||
> 👉 **Note**: in this case it only makes sense to provide a test function | ||
> since this plugin will only consider `a` tags. | ||
###### Returns | ||
## Examples | ||
Properties to add ([`Properties`][hast-properties], optional). | ||
### Example: dynamic options | ||
### `CreateRel` | ||
This example shows how to define options dynamically. | ||
That means that you can choose per element what to generate. | ||
Create a `rel` for the element (TypeScript type). | ||
Each option can be a function which is called with the current element | ||
(`Element`) and returns the corresponding value. | ||
###### Parameters | ||
Taking the above `example.js` and applying the following diff: | ||
* `element` ([`Element`][hast-element]) | ||
— element to check | ||
```diff | ||
const file = await unified() | ||
.use(remarkParse) | ||
.use(remarkRehype) | ||
- .use(rehypeExternalLinks, {rel: ['nofollow']}) | ||
+ .use(rehypeExternalLinks, { | ||
+ target(element) { | ||
+ return element.properties && element.properties.id === '5' | ||
+ ? '_blank' | ||
+ : undefined | ||
+ }, | ||
+ rel: ['nofollow'] | ||
+ }) | ||
.use(rehypeStringify) | ||
.process('[rehype](https://github.com/rehypejs/rehype)') | ||
###### Returns | ||
`rel` to use (`Array<string>`, optional). | ||
### `CreateTarget` | ||
Create a `target` for the element (TypeScript type). | ||
###### Parameters | ||
* `element` ([`Element`][hast-element]) | ||
— element to check | ||
###### Returns | ||
`target` to use ([`Target`][api-target], optional). | ||
### `Options` | ||
Configuration (TypeScript type). | ||
###### Fields | ||
* `content` (`Array<Node>`, [`CreateContent`][api-create-content], or `Node`, | ||
optional) | ||
— content to insert at the end of external links; will be inserted in a | ||
`<span>` element; useful for improving accessibility by giving users | ||
advanced warning when opening a new window | ||
* `contentProperties` ([`CreateProperties`][api-create-properties] or | ||
[`Properties`][hast-properties], optional) | ||
— properties to add to the `span` wrapping `content` | ||
* `properties` ([`CreateProperties`][api-create-properties] or | ||
[`Properties`][hast-properties], optional) | ||
— properties to add to the link itself | ||
* `protocols` (`Array<string>`, default: `['http', 'https']`) | ||
— protocols to see as external, such as `mailto` or `tel` | ||
* `rel` (`Array<string>`, [`CreateRel`][api-create-rel], or `string`, | ||
default: `['nofollow']`) | ||
— [link types][mdn-rel] to hint about the referenced documents; pass an | ||
empty array (`[]`) to not set `rel`s on links; when using a `target`, add `noopener` | ||
and `noreferrer` to avoid exploitation of the `window.opener` API | ||
* `target` ([`CreateTarget`][api-create-target] or [`Target`][api-target], | ||
optional) | ||
— how to display referenced documents; the default (nothing) is to not set | ||
`target`s on links | ||
* `test` ([`Test`][is-test], optional) | ||
— extra test to define which external link elements are modified; any test | ||
that can be given to `hast-util-is-element` is supported | ||
### `Target` | ||
Target (TypeScript type). | ||
###### Type | ||
```ts | ||
type Target = '_blank' | '_parent' | '_self' | '_top' | ||
``` | ||
Changes to apply `target="_blank"` on the element with an `id="5"`. | ||
## Types | ||
This package is fully typed with [TypeScript][]. | ||
It exports an `Options` type, which specifies the interface of the accepted | ||
options. | ||
It exports the additional types | ||
[`CreateContent`][api-create-content], | ||
[`CreateProperties`][api-create-properties], | ||
[`CreateRel`][api-create-rel], | ||
[`CreateTarget`][api-create-target], | ||
[`Options`][api-options], and | ||
[`Target`][api-target]. | ||
## Compatibility | ||
Projects maintained by the unified collective are compatible with all maintained | ||
Projects maintained by the unified collective are compatible with maintained | ||
versions of Node.js. | ||
As of now, that is Node.js 12.20+, 14.14+, and 16.0+. | ||
Our projects sometimes work with older versions, but this is not guaranteed. | ||
When we cut a new major release, we drop support for unmaintained versions of | ||
Node. | ||
This means we try to keep the current release line, `rehype-external-links@^3`, | ||
compatible with Node.js 16. | ||
This plugin works with `rehype-parse` version 3+, `rehype-stringify` version 3+, | ||
@@ -262,5 +296,5 @@ `rehype` version 4+, and `unified` version 6+. | ||
[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype-external-links.svg | ||
[size-badge]: https://img.shields.io/bundlejs/size/rehype-external-links | ||
[size]: https://bundlephobia.com/result?p=rehype-external-links | ||
[size]: https://bundlejs.com/?q=rehype-external-links | ||
@@ -279,2 +313,4 @@ [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg | ||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[esmsh]: https://esm.sh | ||
@@ -294,2 +330,12 @@ | ||
[hast-properties]: https://github.com/syntax-tree/hast#properties | ||
[is-test]: https://github.com/syntax-tree/hast-util-is-element#test | ||
[mdn-rel]: https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types | ||
[rehype]: https://github.com/rehypejs/rehype | ||
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[typescript]: https://www.typescriptlang.org | ||
@@ -299,22 +345,24 @@ | ||
[rehype]: https://github.com/rehypejs/rehype | ||
[unified-transformer]: https://github.com/unifiedjs/unified#transformer | ||
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting | ||
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[hast-element]: https://github.com/syntax-tree/hast#element | ||
[mdn-rel]: https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types | ||
[g201]: https://www.w3.org/WAI/WCAG21/Techniques/general/G201 | ||
[mdn-a]: https://developer.mozilla.org/en/docs/Web/HTML/Element/a | ||
[css-tricks]: https://css-tricks.com/use-target_blank/ | ||
[hast]: https://github.com/syntax-tree/hast | ||
[api-create-content]: #createcontent | ||
[properties]: https://github.com/syntax-tree/hast#properties | ||
[api-create-properties]: #createproperties | ||
[node]: https://github.com/syntax-tree/hast#nodes | ||
[api-create-rel]: #createrel | ||
[children]: https://github.com/syntax-tree/unist#child | ||
[api-create-target]: #createtarget | ||
[g201]: https://www.w3.org/WAI/WCAG21/Techniques/general/G201 | ||
[api-options]: #options | ||
[css-tricks]: https://css-tricks.com/use-target_blank/ | ||
[api-target]: #target | ||
[api-rehype-external-links]: #unifieduserehypeexternallinks-options |
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
23309
17.32%6
-14.29%10
-9.09%7
40%269
35.86%358
15.48%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated