rehype-highlight
Advanced tools
Comparing version 5.0.1 to 5.0.2
@@ -1,52 +0,2 @@ | ||
/** | ||
* Plugin to highlight the syntax of code with lowlight (`highlight.js`). | ||
* | ||
* @type {import('unified').Plugin<[Options?] | void[], Root>} | ||
*/ | ||
export default function rehypeHighlight( | ||
options?: void | Options | undefined | ||
): | ||
| void | ||
| import('unified').Transformer<import('hast').Root, import('hast').Root> | ||
export type LowlightRoot = import('lowlight').Root | ||
export type HighlightSyntax = import('lowlight/lib/core.js').HighlightSyntax | ||
export type Root = import('hast').Root | ||
export type Element = import('hast').Element | ||
export type Node = Root | Root['children'][number] | ||
/** | ||
* Configuration. | ||
*/ | ||
export type Options = { | ||
/** | ||
* Prefix to use before classes. | ||
*/ | ||
prefix?: string | undefined | ||
/** | ||
* Scope of languages to check when auto-detecting (default: all languages). | ||
* Pass `false` to not highlight code without language classes. | ||
*/ | ||
subset?: boolean | string[] | undefined | ||
/** | ||
* Swallow errors for missing languages. | ||
* 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. | ||
*/ | ||
ignoreMissing?: boolean | undefined | ||
/** | ||
* List of plain-text languages. | ||
* Pass any languages you would like to be kept as plain-text instead of | ||
* getting highlighted. | ||
*/ | ||
plainText?: string[] | undefined | ||
/** | ||
* Register more aliases. | ||
* Passed to `lowlight.registerAlias`. | ||
*/ | ||
aliases?: Record<string, string | string[]> | undefined | ||
/** | ||
* Register more languages. | ||
* Each key/value pair passed as arguments to `lowlight.registerLanguage`. | ||
*/ | ||
languages?: Record<string, import('highlight.js').LanguageFn> | undefined | ||
} | ||
export {default} from './lib/index.js' | ||
export type Options = import('./lib/index.js').Options |
156
index.js
/** | ||
* @typedef {import('lowlight').Root} LowlightRoot | ||
* @typedef {import('lowlight/lib/core.js').HighlightSyntax} HighlightSyntax | ||
* @typedef {import('hast').Root} Root | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {Root|Root['children'][number]} Node | ||
* | ||
* @typedef Options | ||
* Configuration. | ||
* @property {string} [prefix='hljs-'] | ||
* Prefix to use before classes. | ||
* @property {boolean|string[]} [subset] | ||
* Scope of languages to check when auto-detecting (default: all languages). | ||
* Pass `false` to not highlight code without language classes. | ||
* @property {boolean} [ignoreMissing=false] | ||
* Swallow errors for missing languages. | ||
* 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. | ||
* @property {string[]} [plainText=[]] | ||
* List of plain-text languages. | ||
* Pass any languages you would like to be kept as plain-text instead of | ||
* getting highlighted. | ||
* @property {Record<string, string|string[]>} [aliases={}] | ||
* Register more aliases. | ||
* Passed to `lowlight.registerAlias`. | ||
* @property {Record<string, HighlightSyntax>} [languages={}] | ||
* Register more languages. | ||
* Each key/value pair passed as arguments to `lowlight.registerLanguage`. | ||
* @typedef {import('./lib/index.js').Options} Options | ||
*/ | ||
import {lowlight} from 'lowlight' | ||
import {toText} from 'hast-util-to-text' | ||
import {visit} from 'unist-util-visit' | ||
const own = {}.hasOwnProperty | ||
/** | ||
* Plugin to highlight the syntax of code with lowlight (`highlight.js`). | ||
* | ||
* @type {import('unified').Plugin<[Options?] | void[], Root>} | ||
*/ | ||
export default function rehypeHighlight(options = {}) { | ||
const {aliases, languages, prefix, plainText, ignoreMissing, subset} = options | ||
let name = 'hljs' | ||
if (aliases) { | ||
lowlight.registerAlias(aliases) | ||
} | ||
if (languages) { | ||
/** @type {string} */ | ||
let key | ||
for (key in languages) { | ||
if (own.call(languages, key)) { | ||
lowlight.registerLanguage(key, languages[key]) | ||
} | ||
} | ||
} | ||
if (prefix) { | ||
const pos = prefix.indexOf('-') | ||
name = pos > -1 ? prefix.slice(0, pos) : prefix | ||
} | ||
return (tree) => { | ||
// eslint-disable-next-line complexity | ||
visit(tree, 'element', (node, _, givenParent) => { | ||
const parent = /** @type {Node?} */ (givenParent) | ||
if ( | ||
!parent || | ||
!('tagName' in parent) || | ||
parent.tagName !== 'pre' || | ||
node.tagName !== 'code' || | ||
!node.properties | ||
) { | ||
return | ||
} | ||
const lang = language(node) | ||
if ( | ||
lang === false || | ||
(!lang && subset === false) || | ||
(lang && plainText && plainText.includes(lang)) | ||
) { | ||
return | ||
} | ||
if (!Array.isArray(node.properties.className)) { | ||
node.properties.className = [] | ||
} | ||
if (!node.properties.className.includes(name)) { | ||
node.properties.className.unshift(name) | ||
} | ||
/** @type {LowlightRoot} */ | ||
let result | ||
try { | ||
result = lang | ||
? lowlight.highlight(lang, toText(parent), {prefix}) | ||
: // @ts-expect-error: we checked that `subset` is not a boolean. | ||
lowlight.highlightAuto(toText(parent), {prefix, subset}) | ||
} catch (error) { | ||
const exception = /** @type {Error} */ (error) | ||
if (!ignoreMissing || !/Unknown language/.test(exception.message)) { | ||
throw error | ||
} | ||
return | ||
} | ||
if (!lang && result.data.language) { | ||
node.properties.className.push('language-' + result.data.language) | ||
} | ||
if (Array.isArray(result.children) && result.children.length > 0) { | ||
node.children = result.children | ||
} | ||
}) | ||
} | ||
} | ||
/** | ||
* Get the programming language of `node`. | ||
* | ||
* @param {Element} node | ||
* @returns {false|string|undefined} | ||
*/ | ||
function language(node) { | ||
const className = node.properties && node.properties.className | ||
let index = -1 | ||
if (!Array.isArray(className)) { | ||
return | ||
} | ||
while (++index < className.length) { | ||
const value = String(className[index]) | ||
if (value === 'no-highlight' || value === 'nohighlight') { | ||
return false | ||
} | ||
if (value.slice(0, 5) === 'lang-') { | ||
return value.slice(5) | ||
} | ||
if (value.slice(0, 9) === 'language-') { | ||
return value.slice(9) | ||
} | ||
} | ||
} | ||
export {default} from './lib/index.js' |
{ | ||
"name": "rehype-highlight", | ||
"version": "5.0.1", | ||
"version": "5.0.2", | ||
"description": "rehype plugin to highlight code blocks with lowlight (highlight.js)", | ||
@@ -32,2 +32,3 @@ "license": "MIT", | ||
"files": [ | ||
"lib/", | ||
"index.d.ts", | ||
@@ -57,3 +58,3 @@ "index.js" | ||
"scripts": { | ||
"build": "rimraf \"*.d.ts\" && tsc && type-coverage", | ||
"build": "rimraf \"lib/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
@@ -60,0 +61,0 @@ "test-api": "node --conditions development test.js", |
390
readme.md
@@ -11,17 +11,71 @@ # rehype-highlight | ||
[**rehype**][rehype] plugin to highlight the syntax of code with | ||
[**lowlight**][lowlight] ([`highlight.js`][highlight-js]). | ||
**[rehype][]** plugin to apply syntax highlighting to code with | ||
[`highlight.js`][highlight-js] (through [`lowlight`][lowlight]). | ||
`rehype-highlight` is built to work with all syntaxes supported by | ||
[`highlight.js`][highlight-js]. | ||
It starts off with 35 [common languages][common] registered. | ||
You can add up to 191 languages. | ||
## 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(rehypeHighlight[, options])`](#unifieduserehypehighlight-options) | ||
* [Example](#example) | ||
* [Example: ignoring](#example-ignoring) | ||
* [Example: registering](#example-registering) | ||
* [Example: aliases](#example-aliases) | ||
* [Example: sanitation](#example-sanitation) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Security](#security) | ||
* [Related](#related) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
## What is this? | ||
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][common] 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. | ||
## When should I use this? | ||
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`][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. | ||
## 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 | ||
@@ -31,5 +85,19 @@ npm install rehype-highlight | ||
In Deno with [Skypack][]: | ||
```js | ||
import rehypeHighlight from 'https://cdn.skypack.dev/rehype-highlight@5?dts' | ||
``` | ||
In browsers with [Skypack][]: | ||
```html | ||
<script type="module"> | ||
import rehypeHighlight from 'https://cdn.skypack.dev/rehype-highlight@5?min' | ||
</script> | ||
``` | ||
## Use | ||
Say `example.html` looks as follows: | ||
Say we have the following file `example.html`: | ||
@@ -43,30 +111,28 @@ ```html | ||
…and `example.js` like this: | ||
And our module `example.js` looks as follows: | ||
```js | ||
import {readSync} from 'to-vfile' | ||
import {reporter} from 'vfile-reporter' | ||
import {read} from 'to-vfile' | ||
import {rehype} from 'rehype' | ||
import rehypeHighlight from 'rehype-highlight' | ||
const file = readSync('example.html') | ||
main() | ||
rehype() | ||
.data('settings', {fragment: true}) | ||
.use(rehypeHighlight) | ||
.process(file) | ||
.then((file) => { | ||
console.error(reporter(file)) | ||
console.log(String(file)) | ||
}) | ||
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` yields: | ||
Now running `node example.js` yields: | ||
```html | ||
example.html: no issues found | ||
<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-built_in">console</span>.warn(<span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>)</code></pre> | ||
<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> | ||
``` | ||
@@ -81,17 +147,8 @@ | ||
Syntax highlight `pre > code`. | ||
Uses [**lowlight**][lowlight] under the hood, which is a virtual version of | ||
[`highlight.js`][highlight-js]. | ||
Apply syntax highlighting to code with `highlight.js`. | ||
Configure the language by using a `lang-js` or `language-js` class. | ||
Ignore `code` with a `no-highlight` or `nohighlight` class. | ||
Will auto-detect the syntax language otherwise. | ||
##### `options` | ||
`rehype-highlight` is built to work with all syntaxes supported by | ||
`highlight.js`. | ||
It starts off with 35 [common languages][common] registered. | ||
You can add up to 191 languages. | ||
Configuration (optional). | ||
##### `options` | ||
###### `options.prefix` | ||
@@ -103,6 +160,14 @@ | ||
Scope of languages to check when auto-detecting (`boolean` or `Array.<string>`, | ||
default: all languages). | ||
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` | ||
@@ -115,11 +180,5 @@ | ||
###### `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. | ||
###### `options.aliases` | ||
Register more aliases (`Object<string | Array.<string>>`, default: `{}`). | ||
Register more aliases (`Record<string, string|Array<string>>`, default: `{}`). | ||
Passed to [`lowlight.registerAlias`][register-alias]. | ||
@@ -133,13 +192,228 @@ | ||
`rehype-highlight` is built to work with all syntaxes supported by | ||
`highlight.js`. | ||
It starts off with 35 [common languages][common] registered. | ||
You can add up to 191 languages. | ||
## 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.subset` to `false`, which prevents `<code>` without a class from being | ||
automatically detected. | ||
For example, with `example.html`: | ||
```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`: | ||
```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. | ||
### Example: registering | ||
`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`: | ||
```html | ||
<pre><code class="language-bnf">a ::= 'a' | 'A'</code></pre> | ||
``` | ||
And `example.js`: | ||
```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: | ||
```html | ||
<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`: | ||
```html | ||
<pre><code class="language-custom-script">console.log(1)</code></pre> | ||
``` | ||
And `example.js`: | ||
```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: | ||
```html | ||
<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> | ||
``` | ||
### 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 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`][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`: | ||
```js | ||
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`: | ||
```diff | ||
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>') | ||
``` | ||
## Types | ||
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 | ||
Use of `rehype-highlight` *should* be safe to use as `lowlight` *should* be safe | ||
to use. | ||
When in doubt, use [`rehype-sanitize`][sanitize]. | ||
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-sanitize]. | ||
## Related | ||
* [`rehype-meta`](https://github.com/rehypejs/rehype-meta) | ||
— add metadata to the head of a document | ||
* [`rehype-document`](https://github.com/rehypejs/rehype-document) | ||
— wrap a fragment in a document | ||
## Contribute | ||
@@ -189,2 +463,4 @@ | ||
[skypack]: https://www.skypack.dev | ||
[health]: https://github.com/rehypejs/.github | ||
@@ -202,2 +478,6 @@ | ||
[typescript]: https://www.typescriptlang.org | ||
[unified]: https://github.com/unifiedjs/unified | ||
[rehype]: https://github.com/rehypejs/rehype | ||
@@ -213,4 +493,4 @@ | ||
[sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize | ||
[common]: https://github.com/wooorm/lowlight#syntaxes |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24642
7
192
487
1