remark-lint-no-undefined-references
Advanced tools
Comparing version 4.2.1 to 5.0.0
@@ -1,41 +0,22 @@ | ||
export default remarkLintNoUndefinedReferences | ||
export type Heading = import('mdast').Heading | ||
export type Paragraph = import('mdast').Paragraph | ||
export type Root = import('mdast').Root | ||
export default remarkLintNoUndefinedReferences; | ||
export type Nodes = import('mdast').Nodes; | ||
export type Root = import('mdast').Root; | ||
/** | ||
* Configuration. | ||
*/ | ||
export type Options = { | ||
/** | ||
* Text or regex that you want to be allowed between `[` and `]` even though | ||
* it’s `undefined` (default: `[]`). | ||
* | ||
* Regex is provided via a `RegExp` object or via a `{source: string}` object | ||
* where `source` is the source text of a case-insensitive regex. | ||
*/ | ||
allow?: | ||
| Array< | ||
| string | ||
| RegExp | ||
| { | ||
source: string | ||
} | ||
> | ||
| null | ||
| undefined | ||
} | ||
export type Range = Array<number> | ||
declare const remarkLintNoUndefinedReferences: import('unified').Plugin< | ||
| void[] | ||
| [ | ||
| Options | ||
| [ | ||
( | ||
| boolean | ||
| import('unified-lint-rule/lib/index.js').Label | ||
| import('unified-lint-rule/lib/index.js').Severity | ||
), | ||
(Options | undefined)? | ||
] | ||
| undefined | ||
], | ||
import('mdast').Root, | ||
import('mdast').Root | ||
> | ||
/** | ||
* List of values to allow between `[` and `]` (optional) | ||
*/ | ||
allow?: ReadonlyArray<RegExp | string> | null | undefined; | ||
/** | ||
* Allow shortcut references, which are just brackets such as `[text]` | ||
* (`boolean`, default: `false`) | ||
*/ | ||
allowShortcutLink?: boolean | null | undefined; | ||
}; | ||
declare const remarkLintNoUndefinedReferences: { | ||
(config?: import("../../node_modules/unified-lint-rule/lib/index.js").Label | import("../../node_modules/unified-lint-rule/lib/index.js").Severity | Readonly<Options> | [level: import("../../node_modules/unified-lint-rule/lib/index.js").Label | import("../../node_modules/unified-lint-rule/lib/index.js").Severity, option?: Readonly<Options> | null | undefined] | null | undefined): ((tree: import("mdast").Root, file: import("vfile").VFile, next: import("unified").TransformCallback<import("mdast").Root>) => undefined) | undefined; | ||
readonly name: string; | ||
}; | ||
//# sourceMappingURL=index.d.ts.map |
561
index.js
/** | ||
* remark-lint rule to warn when undefined definitions are referenced. | ||
* | ||
* ## What is this? | ||
* | ||
* This package checks that referenced definitions are defined. | ||
* | ||
* ## When should I use this? | ||
* | ||
* You can use this package to check that referenced definitions are defined. | ||
* You can use this package to check for broken references. | ||
* | ||
* ## API | ||
* | ||
* The following options (default: `undefined`) are accepted: | ||
* ### `unified().use(remarkLintNoUndefinedReferences[, options])` | ||
* | ||
* * `Object` with the following fields: | ||
* * `allow` (`Array<string | RegExp | { source: string }>`, | ||
* default: `[]`) | ||
* — text or regex that you want to be allowed between `[` and `]` | ||
* even though it’s undefined; regex is provided via a `RegExp` object | ||
* or via a `{source: string}` object where `source` is the source | ||
* text of a case-insensitive regex | ||
* Warn when undefined definitions are referenced. | ||
* | ||
* ###### Parameters | ||
* | ||
* * `options` ([`Options`][api-options], optional) | ||
* — configuration | ||
* | ||
* ###### Returns | ||
* | ||
* Transform ([`Transformer` from `unified`][github-unified-transformer]). | ||
* | ||
* ### `Options` | ||
* | ||
* Configuration (TypeScript type). | ||
* | ||
* ###### Fields | ||
* | ||
* * `allow` (`Array<RegExp | string>`, optional) | ||
* — list of values to allow between `[` and `]` | ||
* * `allowShortcutLink` (`boolean`, default: `false`) | ||
* — allow shortcut references, which are just brackets such as `[text]` | ||
* | ||
* ## Recommendation | ||
@@ -22,4 +42,5 @@ * | ||
* text. | ||
* For example, it is reasonable to expect an author adding `[…]` to abbreviate | ||
* some text somewhere in a document: | ||
* To illustrate, | ||
* it is reasonable to expect an author adding `[…]` to abbreviate some text | ||
* somewhere in a document: | ||
* | ||
@@ -30,99 +51,121 @@ * ```markdown | ||
* | ||
* This isn’t a problem, but it might become one when an author later adds a | ||
* definition: | ||
* This isn’t a problem, | ||
* but it might become one when an author later adds a definition: | ||
* | ||
* ```markdown | ||
* Some text. […][] | ||
* Some new text […][]. | ||
* | ||
* […] #read-more "Read more" | ||
* […]: #read-more | ||
* ``` | ||
* | ||
* The second author might expect only their newly added text to form a link, | ||
* but their changes also result in a link for the first author’s text. | ||
* but their changes also result in a link for the text by the first author. | ||
* | ||
* [api-options]: #options | ||
* [api-remark-lint-no-undefined-references]: #unifieduseremarklintnoundefinedreferences-options | ||
* [github-unified-transformer]: https://github.com/unifiedjs/unified#transformer | ||
* | ||
* @module no-undefined-references | ||
* @summary | ||
* remark-lint rule to warn when undefined definitions are referenced. | ||
* @author Titus Wormer | ||
* @copyright 2016 Titus Wormer | ||
* @license MIT | ||
* | ||
* @example | ||
* {"name": "ok.md"} | ||
* | ||
* [foo][] | ||
* [Mercury][] is the first planet from the Sun and the smallest in the Solar | ||
* System. | ||
* | ||
* Just a [ bracket. | ||
* Venus is the second planet from the [Sun. | ||
* | ||
* Typically, you’d want to use escapes (with a backslash: \\) to escape what | ||
* could turn into a \[reference otherwise]. | ||
* Earth is the third planet from the \[Sun] and the only astronomical object | ||
* known to harbor life\. | ||
* | ||
* Just two braces can’t link: []. | ||
* Mars is the fourth planet from the Sun: []. | ||
* | ||
* [foo]: https://example.com | ||
* [mercury]: https://example.com/mercury/ | ||
* | ||
* @example | ||
* {"name": "ok-allow.md", "config": {"allow": ["...", "…"]}} | ||
* {"label": "input", "name": "not-ok.md"} | ||
* | ||
* > Eliding a portion of a quoted passage […] is acceptable. | ||
* [Mercury] is the first planet from the Sun and the smallest in the Solar | ||
* System. | ||
* | ||
* @example | ||
* {"name": "ok-allow.md", "config": {"allow": ["a", {"source": "^b\\."}]}} | ||
* [Venus][] is the second planet from the Sun. | ||
* | ||
* [foo][b.c] | ||
* [Earth][earth] is the third planet from the Sun and the only astronomical | ||
* object known to harbor life. | ||
* | ||
* [bar][a] | ||
* ![Mars] is the fourth planet from the Sun in the [Solar | ||
* System]. | ||
* | ||
* Matching is case-insensitive: [bar][B.C] | ||
* > Jupiter is the fifth planet from the Sun and the largest in the [Solar | ||
* > System][]. | ||
* | ||
* [Saturn][ is the sixth planet from the Sun and the second-largest | ||
* in the Solar System, after Jupiter. | ||
* | ||
* [*Uranus*][] is the seventh planet from the Sun. | ||
* | ||
* [Neptune][neptune][more] is the eighth and farthest planet from the Sun. | ||
* @example | ||
* {"name": "not-ok.md", "label": "input"} | ||
* {"label": "output", "name": "not-ok.md"} | ||
* | ||
* [bar] | ||
* 1:1-1:10: Unexpected reference to undefined definition, expected corresponding definition (`mercury`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 4:1-4:10: Unexpected reference to undefined definition, expected corresponding definition (`venus`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 6:1-6:15: Unexpected reference to undefined definition, expected corresponding definition (`earth`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 9:2-9:8: Unexpected reference to undefined definition, expected corresponding definition (`mars`) for an image or escaped opening bracket (`\[`) for regular text | ||
* 9:50-10:8: Unexpected reference to undefined definition, expected corresponding definition (`solar system`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 12:67-13:12: Unexpected reference to undefined definition, expected corresponding definition (`solar > system`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 15:1-15:9: Unexpected reference to undefined definition, expected corresponding definition (`saturn`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 18:1-18:13: Unexpected reference to undefined definition, expected corresponding definition (`*uranus*`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 20:1-20:19: Unexpected reference to undefined definition, expected corresponding definition (`neptune`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 20:19-20:25: Unexpected reference to undefined definition, expected corresponding definition (`more`) for a link or escaped opening bracket (`\[`) for regular text | ||
* | ||
* [baz][] | ||
* @example | ||
* {"config": {"allow": ["…"]}, "name": "ok-allow.md"} | ||
* | ||
* [text][qux] | ||
* Mercury is the first planet from the Sun and the smallest in the Solar | ||
* System. […] | ||
* | ||
* Spread [over | ||
* lines][] | ||
* @example | ||
* {"config": {"allow": [{"source": "^mer"}, "venus"]}, "name": "source.md"} | ||
* | ||
* > in [a | ||
* > block quote][] | ||
* [Mercury][] is the first planet from the Sun and the smallest in the Solar | ||
* System. | ||
* | ||
* [asd][a | ||
* [Venus][] is the second planet from the Sun. | ||
* | ||
* Can include [*emphasis*]. | ||
* @example | ||
* {"gfm": true, "label": "input", "name": "gfm.md"} | ||
* | ||
* Multiple pairs: [a][b][c]. | ||
* Mercury[^mercury] is the first planet from the Sun and the smallest in the | ||
* Solar System. | ||
* | ||
* [^venus]: | ||
* **Venus** is the second planet from the Sun. | ||
* @example | ||
* {"name": "not-ok.md", "label": "output"} | ||
* {"gfm": true, "label": "output", "name": "gfm.md"} | ||
* | ||
* 1:1-1:6: Found reference to undefined definition | ||
* 3:1-3:8: Found reference to undefined definition | ||
* 5:1-5:12: Found reference to undefined definition | ||
* 7:8-8:9: Found reference to undefined definition | ||
* 10:6-11:17: Found reference to undefined definition | ||
* 13:1-13:6: Found reference to undefined definition | ||
* 15:13-15:25: Found reference to undefined definition | ||
* 17:17-17:23: Found reference to undefined definition | ||
* 17:23-17:26: Found reference to undefined definition | ||
* 1:8-1:18: Unexpected reference to undefined definition, expected corresponding definition (`mercury`) for a footnote or escaped opening bracket (`\[`) for regular text | ||
* | ||
* @example | ||
* {"name": "not-ok.md", "label": "input", "config": {"allow": ["a", {"source": "^b\\."}]}} | ||
* {"config": {"allowShortcutLink": true}, "label": "input", "name": "allow-shortcut-link.md"} | ||
* | ||
* [foo][a.c] | ||
* [Mercury] is the first planet from the Sun and the smallest in the Solar | ||
* System. | ||
* | ||
* [bar][b] | ||
* [Venus][] is the second planet from the Sun. | ||
* | ||
* [Earth][earth] is the third planet from the Sun and the only astronomical object | ||
* known to harbor life. | ||
* @example | ||
* {"name": "not-ok.md", "label": "output", "config": {"allow": ["a", {"source": "^b\\."}]}} | ||
* {"config": {"allowShortcutLink": true}, "label": "output", "name": "allow-shortcut-link.md"} | ||
* | ||
* 1:1-1:11: Found reference to undefined definition | ||
* 3:1-3:9: Found reference to undefined definition | ||
* 4:1-4:10: Unexpected reference to undefined definition, expected corresponding definition (`venus`) for a link or escaped opening bracket (`\[`) for regular text | ||
* 6:1-6:15: Unexpected reference to undefined definition, expected corresponding definition (`earth`) for a link or escaped opening bracket (`\[`) for regular text | ||
*/ | ||
/** | ||
* @typedef {import('mdast').Heading} Heading | ||
* @typedef {import('mdast').Paragraph} Paragraph | ||
* @typedef {import('mdast').Nodes} Nodes | ||
* @typedef {import('mdast').Root} Root | ||
@@ -133,19 +176,25 @@ */ | ||
* @typedef Options | ||
* @property {Array<string | RegExp | {source: string}> | null | undefined} [allow] | ||
* Text or regex that you want to be allowed between `[` and `]` even though | ||
* it’s `undefined` (default: `[]`). | ||
* | ||
* Regex is provided via a `RegExp` object or via a `{source: string}` object | ||
* where `source` is the source text of a case-insensitive regex. | ||
* | ||
* @typedef {Array<number>} Range | ||
* Configuration. | ||
* @property {ReadonlyArray<RegExp | string> | null | undefined} [allow] | ||
* List of values to allow between `[` and `]` (optional) | ||
* @property {boolean | null | undefined} [allowShortcutLink] | ||
* Allow shortcut references, which are just brackets such as `[text]` | ||
* (`boolean`, default: `false`) | ||
*/ | ||
import {collapseWhiteSpace} from 'collapse-white-space' | ||
import {ok as assert} from 'devlop' | ||
import {normalizeIdentifier} from 'micromark-util-normalize-identifier' | ||
import {lintRule} from 'unified-lint-rule' | ||
import {pointEnd, pointStart} from 'unist-util-position' | ||
import {visitParents} from 'unist-util-visit-parents' | ||
import {location} from 'vfile-location' | ||
import {lintRule} from 'unified-lint-rule' | ||
import {generated} from 'unist-util-generated' | ||
import {pointStart, pointEnd} from 'unist-util-position' | ||
import {visit, SKIP, EXIT} from 'unist-util-visit' | ||
/** @type {Readonly<Options>} */ | ||
const emptyOptions = {} | ||
/** @type {ReadonlyArray<RegExp | string>} */ | ||
const emptyAllow = [] | ||
const lineEndingExpression = /(\r?\n|\r)[\t ]*(>[\t ]*)*/g | ||
const remarkLintNoUndefinedReferences = lintRule( | ||
@@ -156,11 +205,20 @@ { | ||
}, | ||
/** @type {import('unified-lint-rule').Rule<Root, Options>} */ | ||
(tree, file, option = {}) => { | ||
const contents = String(file) | ||
const loc = location(file) | ||
const lineEnding = /(\r?\n|\r)[\t ]*(>[\t ]*)*/g | ||
/** @type {Record<string, boolean>} */ | ||
const map = Object.create(null) | ||
const allow = option.allow || [] | ||
/** | ||
* @param {Root} tree | ||
* Tree. | ||
* @param {Readonly<Options> | null | undefined} [options] | ||
* Configuration (optional). | ||
* @returns {undefined} | ||
* Nothing. | ||
*/ | ||
function (tree, file, options) { | ||
const settings = options || emptyOptions | ||
const allow = settings.allow || emptyAllow | ||
const allowShortcutLink = settings.allowShortcutLink || false | ||
const value = String(file) | ||
const toPoint = location(file).toPoint | ||
/** @type {Set<string>} */ | ||
const definitionIdentifiers = new Set() | ||
/** @type {Set<string>} */ | ||
const footnoteDefinitionIdentifiers = new Set() | ||
/** @type {Array<RegExp>} */ | ||
@@ -170,2 +228,4 @@ const regexes = [] | ||
const strings = new Set() | ||
/** @type {Array<Array<Nodes>>} */ | ||
const phrasingStacks = [] | ||
@@ -176,205 +236,228 @@ let index = -1 | ||
const value = allow[index] | ||
if (typeof value === 'string') { | ||
strings.add(normalizeIdentifier(value)) | ||
} else if (value instanceof RegExp) { | ||
regexes.push(value) | ||
} else { | ||
regexes.push(new RegExp(value.source, 'i')) | ||
} else if (typeof value === 'object' && 'source' in value) { | ||
regexes.push(new RegExp(value.source, value.flags ?? 'i')) | ||
} | ||
} | ||
visit(tree, (node) => { | ||
if ( | ||
(node.type === 'definition' || node.type === 'footnoteDefinition') && | ||
!generated(node) | ||
) { | ||
map[normalizeIdentifier(node.identifier)] = true | ||
visitParents(tree, function (node, parents) { | ||
if (node.type === 'definition') { | ||
definitionIdentifiers.add(normalizeIdentifier(node.identifier)) | ||
} | ||
}) | ||
visit(tree, (node) => { | ||
// CM specifiers that references only form when defined. | ||
// Still, they could be added by plugins, so let’s keep it. | ||
/* c8 ignore next 10 */ | ||
if ( | ||
(node.type === 'imageReference' || | ||
node.type === 'linkReference' || | ||
node.type === 'footnoteReference') && | ||
!generated(node) && | ||
!(normalizeIdentifier(node.identifier) in map) && | ||
!isAllowed(node.identifier) | ||
) { | ||
file.message('Found reference to undefined definition', node) | ||
if (node.type === 'footnoteDefinition') { | ||
footnoteDefinitionIdentifiers.add(normalizeIdentifier(node.identifier)) | ||
} | ||
if (node.type === 'paragraph' || node.type === 'heading') { | ||
findInPhrasing(node) | ||
if (node.type === 'heading' || node.type === 'paragraph') { | ||
phrasingStacks.push([...parents, node]) | ||
} | ||
}) | ||
for (const ancestors of phrasingStacks) { | ||
findInPhrasingContainer(ancestors) | ||
} | ||
/** | ||
* @param {Heading | Paragraph} node | ||
* @param {Array<Nodes>} ancestors | ||
* Ancestors, the last of which a parent of phrasing nodes. | ||
* @returns {undefined} | ||
* Nothing. | ||
*/ | ||
function findInPhrasing(node) { | ||
/** @type {Array<Range>} */ | ||
let ranges = [] | ||
function findInPhrasingContainer(ancestors) { | ||
/** @type {Array<[ancestors: Array<Nodes>, brackets: Array<number>]>} */ | ||
const bracketRanges = [] | ||
const node = ancestors.at(-1) | ||
assert(node) // Always defined. | ||
assert('children' in node) // Always defined. | ||
visit(node, (child) => { | ||
// Ignore the node itself. | ||
if (child === node) return | ||
// Can’t have links in links, so reset ranges. | ||
if (child.type === 'link' || child.type === 'linkReference') { | ||
ranges = [] | ||
return SKIP | ||
for (const child of node.children) { | ||
if (child.type === 'text') { | ||
findRangesInText(bracketRanges, [...ancestors, child]) | ||
} else if ('children' in child) { | ||
findInPhrasingContainer([...ancestors, child]) | ||
} | ||
} | ||
// Enter non-text. | ||
if (child.type !== 'text') return | ||
// Remaining ranges. | ||
for (const range of bracketRanges) { | ||
handleRange(range) | ||
} | ||
} | ||
const start = pointStart(child).offset | ||
const end = pointEnd(child).offset | ||
/** | ||
* @param {Array<[ancestors: Array<Nodes>, brackets: Array<number>]>} ranges | ||
* @param {Array<Nodes>} ancestors | ||
*/ | ||
function findRangesInText(ranges, ancestors) { | ||
const node = ancestors.at(-1) | ||
assert(node) // Always defined. | ||
const end = pointEnd(node) | ||
const start = pointStart(node) | ||
// Bail if there’s no positional info. | ||
if (typeof start !== 'number' || typeof end !== 'number') { | ||
return EXIT | ||
} | ||
// Bail if there’s no positional info. | ||
if ( | ||
!end || | ||
!start || | ||
typeof start.offset !== 'number' || | ||
typeof end.offset !== 'number' | ||
) { | ||
return | ||
} | ||
const source = contents.slice(start, end) | ||
/** @type {Array<[number, string]>} */ | ||
const lines = [[start, '']] | ||
let last = 0 | ||
const source = value.slice(start.offset, end.offset) | ||
/** @type {Array<[number, string]>} */ | ||
const lines = [[start.offset, '']] | ||
let last = 0 | ||
lineEnding.lastIndex = 0 | ||
let match = lineEnding.exec(source) | ||
lineEndingExpression.lastIndex = 0 | ||
let match = lineEndingExpression.exec(source) | ||
while (match) { | ||
const index = match.index | ||
lines[lines.length - 1][1] = source.slice(last, index) | ||
last = index + match[0].length | ||
lines.push([start + last, '']) | ||
match = lineEnding.exec(source) | ||
} | ||
while (match) { | ||
const index = match.index | ||
const lineTuple = lines.at(-1) | ||
assert(lineTuple) // Always defined. | ||
lineTuple[1] = source.slice(last, index) | ||
lines[lines.length - 1][1] = source.slice(last) | ||
let lineIndex = -1 | ||
last = index + match[0].length | ||
lines.push([start.offset + last, '']) | ||
match = lineEndingExpression.exec(source) | ||
} | ||
while (++lineIndex < lines.length) { | ||
const line = lines[lineIndex][1] | ||
let index = 0 | ||
const lineTuple = lines.at(-1) | ||
assert(lineTuple) // Always defined. | ||
lineTuple[1] = source.slice(last) | ||
while (index < line.length) { | ||
const code = line.charCodeAt(index) | ||
for (const lineTuple of lines) { | ||
const [lineStart, line] = lineTuple | ||
let index = 0 | ||
// Skip past escaped brackets. | ||
if (code === 92) { | ||
const next = line.charCodeAt(index + 1) | ||
while (index < line.length) { | ||
const code = line.charCodeAt(index) | ||
// Opening bracket. | ||
if (code === 91 /* `[` */) { | ||
ranges.push([ancestors, [lineStart + index]]) | ||
index++ | ||
} | ||
// Skip escaped brackets. | ||
else if (code === 92 /* `\` */) { | ||
const next = line.charCodeAt(index + 1) | ||
index++ | ||
if (next === 91 /* `[` */ || next === 93 /* `]` */) { | ||
index++ | ||
} | ||
} | ||
// Close bracket. | ||
else if (code === 93 /* `]` */) { | ||
const bracketInfo = ranges.at(-1) | ||
if (next === 91 || next === 93) { | ||
index++ | ||
} | ||
// No opening, ignore. | ||
if (!bracketInfo) { | ||
index++ | ||
} | ||
// Opening bracket. | ||
else if (code === 91) { | ||
ranges.push([lines[lineIndex][0] + index]) | ||
// `][`. | ||
else if ( | ||
line.charCodeAt(index + 1) === 91 /* `[` */ && | ||
// That would be the end of a reference already. | ||
bracketInfo[1].length !== 3 | ||
) { | ||
index++ | ||
bracketInfo[1].push(lineStart + index, lineStart + index) | ||
index++ | ||
} | ||
// Close bracket. | ||
else if (code === 93) { | ||
// No opening. | ||
if (ranges.length === 0) { | ||
index++ | ||
} else if (line.charCodeAt(index + 1) === 91) { | ||
index++ | ||
// Collapsed or full. | ||
let range = ranges.pop() | ||
// Range should always exist. | ||
// eslint-disable-next-line max-depth | ||
if (range) { | ||
range.push(lines[lineIndex][0] + index) | ||
// This is the end of a reference already. | ||
// eslint-disable-next-line max-depth | ||
if (range.length === 4) { | ||
handleRange(range) | ||
range = [] | ||
} | ||
range.push(lines[lineIndex][0] + index) | ||
ranges.push(range) | ||
index++ | ||
} | ||
} else { | ||
index++ | ||
// Shortcut or typical end of a reference. | ||
const range = ranges.pop() | ||
// Range should always exist. | ||
// eslint-disable-next-line max-depth | ||
if (range) { | ||
range.push(lines[lineIndex][0] + index) | ||
handleRange(range) | ||
} | ||
} | ||
} | ||
// Anything else. | ||
// `]` with earlier `[`. | ||
else { | ||
index++ | ||
bracketInfo[1].push(lineStart + index) | ||
handleRange(bracketInfo) | ||
ranges.pop() | ||
} | ||
} | ||
// Anything else. | ||
else { | ||
index++ | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
let index = -1 | ||
/** | ||
* @param {[ancestors: Array<Nodes>, brackets: Array<number>]} bracketRange | ||
* Info. | ||
* @returns {undefined} | ||
* Nothing. | ||
*/ | ||
function handleRange(bracketRange) { | ||
const [ancestors, range] = bracketRange | ||
while (++index < ranges.length) { | ||
handleRange(ranges[index]) | ||
} | ||
// `[`. | ||
if (range.length === 1) return | ||
return SKIP | ||
// `[x][`. | ||
if (range.length === 3) range.length = 2 | ||
/** | ||
* @param {Range} range | ||
*/ | ||
function handleRange(range) { | ||
if (range.length === 1) return | ||
if (range.length === 3) range.length = 2 | ||
// No need to warn for just `[]`. | ||
if (range.length === 2 && range[0] + 2 === range[1]) return | ||
// No need to warn for just `[]`. | ||
if (range.length === 2 && range[0] + 2 === range[1]) return | ||
const label = | ||
value.charCodeAt(range[0] - 1) === 33 /* `!` */ | ||
? 'image' | ||
: value.charCodeAt(range[0] + 1) === 94 /* `^` */ | ||
? 'footnote' | ||
: 'link' | ||
const offset = range.length === 4 && range[2] + 2 !== range[3] ? 2 : 0 | ||
const id = contents | ||
.slice(range[0 + offset] + 1, range[1 + offset] - 1) | ||
.replace(lineEnding, ' ') | ||
const pos = { | ||
start: loc.toPoint(range[0]), | ||
end: loc.toPoint(range[range.length - 1]) | ||
} | ||
const offset = range.length === 4 && range[2] + 2 !== range[3] ? 2 : 0 | ||
if ( | ||
!generated({position: pos}) && | ||
!(normalizeIdentifier(id) in map) && | ||
!isAllowed(id) | ||
) { | ||
// @ts-expect-error: assume we have a correct point. | ||
file.message('Found reference to undefined definition', pos) | ||
} | ||
let id = normalizeIdentifier( | ||
collapseWhiteSpace( | ||
value.slice(range[0 + offset] + 1, range[1 + offset] - 1), | ||
{style: 'html', trim: true} | ||
) | ||
) | ||
let defined = definitionIdentifiers | ||
if (label === 'footnote') { | ||
// Footnotes can’t have spaces. | ||
/* c8 ignore next -- bit superfluous to test. */ | ||
if (id.includes(' ')) return | ||
defined = footnoteDefinitionIdentifiers | ||
// Drop the `^`. | ||
id = id.slice(1) | ||
} | ||
} | ||
/** | ||
* @param {string} id | ||
* @returns {boolean} | ||
*/ | ||
function isAllowed(id) { | ||
const normalized = normalizeIdentifier(id) | ||
return ( | ||
strings.has(normalized) || | ||
regexes.some((regex) => regex.test(normalized)) | ||
) | ||
if ( | ||
(allowShortcutLink && range.length === 2) || | ||
defined.has(id) || | ||
strings.has(id) || | ||
regexes.some(function (regex) { | ||
return regex.test(id) | ||
}) | ||
) { | ||
return | ||
} | ||
const start = toPoint(range[0]) | ||
const end = toPoint(range[range.length - 1]) | ||
if (end && start) { | ||
file.message( | ||
'Unexpected reference to undefined definition, expected corresponding definition (`' + | ||
id.toLowerCase() + | ||
'`) for ' + | ||
(label === 'image' ? 'an' : 'a') + | ||
' ' + | ||
label + | ||
' or escaped opening bracket (`\\[`) for regular text', | ||
{ | ||
ancestors, | ||
place: {start, end} | ||
} | ||
) | ||
} | ||
} | ||
@@ -381,0 +464,0 @@ } |
{ | ||
"name": "remark-lint-no-undefined-references", | ||
"version": "4.2.1", | ||
"version": "5.0.0", | ||
"description": "remark-lint rule to warn when references to undefined definitions are found", | ||
"license": "MIT", | ||
"keywords": [ | ||
"definition", | ||
"lint", | ||
"reference", | ||
"remark", | ||
"lint", | ||
"rule", | ||
"remark-lint", | ||
"remark-lint-rule", | ||
"reference", | ||
"definition" | ||
"rule" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/remarkjs/remark-lint", | ||
"directory": "packages/remark-lint-no-undefined-references" | ||
}, | ||
"repository": "https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-undefined-references", | ||
"bugs": "https://github.com/remarkjs/remark-lint/issues", | ||
@@ -26,30 +23,43 @@ "funding": { | ||
"contributors": [ | ||
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)" | ||
"Merlijn Vos <merlijn@soverin.net>", | ||
"Murderlon <merlijn@soverin.net>", | ||
"Titus Wormer <tituswormer@gmail.com>" | ||
], | ||
"sideEffects": false, | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"exports": "./index.js", | ||
"files": [ | ||
"index.d.ts", | ||
"index.d.ts.map", | ||
"index.js" | ||
], | ||
"dependencies": { | ||
"@types/mdast": "^3.0.0", | ||
"micromark-util-normalize-identifier": "^1.0.0", | ||
"unified": "^10.0.0", | ||
"unified-lint-rule": "^2.0.0", | ||
"unist-util-generated": "^2.0.0", | ||
"unist-util-position": "^4.0.0", | ||
"unist-util-visit": "^4.0.0", | ||
"vfile-location": "^4.0.0" | ||
"@types/mdast": "^4.0.0", | ||
"collapse-white-space": "^2.0.0", | ||
"devlop": "^1.0.0", | ||
"micromark-util-normalize-identifier": "^2.0.0", | ||
"unified-lint-rule": "^3.0.0", | ||
"unist-util-position": "^5.0.0", | ||
"unist-util-visit-parents": "^6.0.0", | ||
"vfile-location": "^5.0.0" | ||
}, | ||
"scripts": {}, | ||
"xo": false, | ||
"typeCoverage": { | ||
"atLeast": 100, | ||
"detail": true, | ||
"strict": true, | ||
"ignoreCatch": true | ||
"ignoreCatch": true, | ||
"strict": true | ||
}, | ||
"xo": { | ||
"prettier": true, | ||
"rules": { | ||
"capitalized-comments": "off", | ||
"complexity": "off", | ||
"max-depth": "off", | ||
"unicorn/prefer-at": "off", | ||
"unicorn/prefer-code-point": "off", | ||
"unicorn/prefer-string-replace-all": "off", | ||
"unicorn/prefer-switch": "off" | ||
} | ||
} | ||
} |
323
readme.md
@@ -5,42 +5,41 @@ <!--This file is generated--> | ||
[![Build][build-badge]][build] | ||
[![Coverage][coverage-badge]][coverage] | ||
[![Downloads][downloads-badge]][downloads] | ||
[![Size][size-badge]][size] | ||
[![Sponsors][sponsors-badge]][collective] | ||
[![Backers][backers-badge]][collective] | ||
[![Chat][chat-badge]][chat] | ||
[![Build][badge-build-image]][badge-build-url] | ||
[![Coverage][badge-coverage-image]][badge-coverage-url] | ||
[![Downloads][badge-downloads-image]][badge-downloads-url] | ||
[![Size][badge-size-image]][badge-size-url] | ||
[![Sponsors][badge-funding-sponsors-image]][badge-funding-url] | ||
[![Backers][badge-funding-backers-image]][badge-funding-url] | ||
[![Chat][badge-chat-image]][badge-chat-url] | ||
[`remark-lint`][mono] rule to warn when undefined definitions are referenced. | ||
[`remark-lint`][github-remark-lint] rule to warn when undefined definitions are referenced. | ||
## Contents | ||
* [What is this?](#what-is-this) | ||
* [When should I use this?](#when-should-i-use-this) | ||
* [Presets](#presets) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`unified().use(remarkLintNoUndefinedReferences[, config])`](#unifieduseremarklintnoundefinedreferences-config) | ||
* [Recommendation](#recommendation) | ||
* [Examples](#examples) | ||
* [Compatibility](#compatibility) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
* [What is this?](#what-is-this) | ||
* [When should I use this?](#when-should-i-use-this) | ||
* [Presets](#presets) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`unified().use(remarkLintNoUndefinedReferences[, options])`](#unifieduseremarklintnoundefinedreferences-options) | ||
* [`Options`](#options) | ||
* [Recommendation](#recommendation) | ||
* [Examples](#examples) | ||
* [Compatibility](#compatibility) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
## What is this? | ||
This package is a [unified][] ([remark][]) plugin, specifically a `remark-lint` | ||
rule. | ||
Lint rules check markdown code style. | ||
This package checks that referenced definitions are defined. | ||
## When should I use this? | ||
You can use this package to check that referenced definitions are defined. | ||
You can use this package to check for broken references. | ||
## Presets | ||
This rule is included in the following presets: | ||
This plugin is included in the following presets: | ||
| Preset | Setting | | ||
| Preset | Options | | ||
| - | - | | ||
@@ -51,4 +50,5 @@ | [`remark-preset-lint-recommended`](https://github.com/remarkjs/remark-lint/tree/main/packages/remark-preset-lint-recommended) | | | ||
This package is [ESM only][esm]. | ||
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]: | ||
This package is [ESM only][github-gist-esm]. | ||
In Node.js (version 16+), | ||
install with [npm][npm-install]: | ||
@@ -59,13 +59,13 @@ ```sh | ||
In Deno with [`esm.sh`][esmsh]: | ||
In Deno with [`esm.sh`][esm-sh]: | ||
```js | ||
import remarkLintNoUndefinedReferences from 'https://esm.sh/remark-lint-no-undefined-references@4' | ||
import remarkLintNoUndefinedReferences from 'https://esm.sh/remark-lint-no-undefined-references@5' | ||
``` | ||
In browsers with [`esm.sh`][esmsh]: | ||
In browsers with [`esm.sh`][esm-sh]: | ||
```html | ||
<script type="module"> | ||
import remarkLintNoUndefinedReferences from 'https://esm.sh/remark-lint-no-undefined-references@4?bundle' | ||
import remarkLintNoUndefinedReferences from 'https://esm.sh/remark-lint-no-undefined-references@5?bundle' | ||
</script> | ||
@@ -79,18 +79,20 @@ ``` | ||
```js | ||
import remarkLint from 'remark-lint' | ||
import remarkLintNoUndefinedReferences from 'remark-lint-no-undefined-references' | ||
import remarkParse from 'remark-parse' | ||
import remarkStringify from 'remark-stringify' | ||
import {read} from 'to-vfile' | ||
import {unified} from 'unified' | ||
import {reporter} from 'vfile-reporter' | ||
import {remark} from 'remark' | ||
import remarkLint from 'remark-lint' | ||
import remarkLintNoUndefinedReferences from 'remark-lint-no-undefined-references' | ||
main() | ||
const file = await read('example.md') | ||
async function main() { | ||
const file = await remark() | ||
.use(remarkLint) | ||
.use(remarkLintNoUndefinedReferences) | ||
.process(await read('example.md')) | ||
await unified() | ||
.use(remarkParse) | ||
.use(remarkLint) | ||
.use(remarkLintNoUndefinedReferences) | ||
.use(remarkStringify) | ||
.process(file) | ||
console.error(reporter(file)) | ||
} | ||
console.error(reporter(file)) | ||
``` | ||
@@ -101,3 +103,3 @@ | ||
```sh | ||
remark --use remark-lint --use remark-lint-no-undefined-references example.md | ||
remark --frail --use remark-lint --use remark-lint-no-undefined-references . | ||
``` | ||
@@ -123,19 +125,31 @@ | ||
This package exports no identifiers. | ||
The default export is `remarkLintNoUndefinedReferences`. | ||
It exports the [TypeScript][typescript] type | ||
[`Options`][api-options]. | ||
The default export is | ||
[`remarkLintNoUndefinedReferences`][api-remark-lint-no-undefined-references]. | ||
### `unified().use(remarkLintNoUndefinedReferences[, config])` | ||
### `unified().use(remarkLintNoUndefinedReferences[, options])` | ||
This rule supports standard configuration that all remark lint rules accept | ||
(such as `false` to turn it off or `[1, options]` to configure it). | ||
Warn when undefined definitions are referenced. | ||
The following options (default: `undefined`) are accepted: | ||
###### Parameters | ||
* `Object` with the following fields: | ||
* `allow` (`Array<string | RegExp | { source: string }>`, | ||
default: `[]`) | ||
— text or regex that you want to be allowed between `[` and `]` | ||
even though it’s undefined; regex is provided via a `RegExp` object | ||
or via a `{source: string}` object where `source` is the source | ||
text of a case-insensitive regex | ||
* `options` ([`Options`][api-options], optional) | ||
— configuration | ||
###### Returns | ||
Transform ([`Transformer` from `unified`][github-unified-transformer]). | ||
### `Options` | ||
Configuration (TypeScript type). | ||
###### Fields | ||
* `allow` (`Array<RegExp | string>`, optional) | ||
— list of values to allow between `[` and `]` | ||
* `allowShortcutLink` (`boolean`, default: `false`) | ||
— allow shortcut references, which are just brackets such as `[text]` | ||
## Recommendation | ||
@@ -145,4 +159,5 @@ | ||
text. | ||
For example, it is reasonable to expect an author adding `[…]` to abbreviate | ||
some text somewhere in a document: | ||
To illustrate, | ||
it is reasonable to expect an author adding `[…]` to abbreviate some text | ||
somewhere in a document: | ||
@@ -153,13 +168,13 @@ ```markdown | ||
This isn’t a problem, but it might become one when an author later adds a | ||
definition: | ||
This isn’t a problem, | ||
but it might become one when an author later adds a definition: | ||
```markdown | ||
Some text. […][] | ||
Some new text […][]. | ||
[…] #read-more "Read more" | ||
[…]: #read-more | ||
``` | ||
The second author might expect only their newly added text to form a link, | ||
but their changes also result in a link for the first author’s text. | ||
but their changes also result in a link for the text by the first author. | ||
@@ -173,12 +188,13 @@ ## Examples | ||
```markdown | ||
[foo][] | ||
[Mercury][] is the first planet from the Sun and the smallest in the Solar | ||
System. | ||
Just a [ bracket. | ||
Venus is the second planet from the [Sun. | ||
Typically, you’d want to use escapes (with a backslash: \\) to escape what | ||
could turn into a \[reference otherwise]. | ||
Earth is the third planet from the \[Sun] and the only astronomical object | ||
known to harbor life\. | ||
Just two braces can’t link: []. | ||
Mars is the fourth planet from the Sun: []. | ||
[foo]: https://example.com | ||
[mercury]: https://example.com/mercury/ | ||
``` | ||
@@ -195,19 +211,22 @@ | ||
```markdown | ||
[bar] | ||
[Mercury] is the first planet from the Sun and the smallest in the Solar | ||
System. | ||
[baz][] | ||
[Venus][] is the second planet from the Sun. | ||
[text][qux] | ||
[Earth][earth] is the third planet from the Sun and the only astronomical | ||
object known to harbor life. | ||
Spread [over | ||
lines][] | ||
![Mars] is the fourth planet from the Sun in the [Solar | ||
System]. | ||
> in [a | ||
> block quote][] | ||
> Jupiter is the fifth planet from the Sun and the largest in the [Solar | ||
> System][]. | ||
[asd][a | ||
[Saturn][ is the sixth planet from the Sun and the second-largest | ||
in the Solar System, after Jupiter. | ||
Can include [*emphasis*]. | ||
[*Uranus*][] is the seventh planet from the Sun. | ||
Multiple pairs: [a][b][c]. | ||
[Neptune][neptune][more] is the eighth and farthest planet from the Sun. | ||
``` | ||
@@ -218,11 +237,12 @@ | ||
```text | ||
1:1-1:6: Found reference to undefined definition | ||
3:1-3:8: Found reference to undefined definition | ||
5:1-5:12: Found reference to undefined definition | ||
7:8-8:9: Found reference to undefined definition | ||
10:6-11:17: Found reference to undefined definition | ||
13:1-13:6: Found reference to undefined definition | ||
15:13-15:25: Found reference to undefined definition | ||
17:17-17:23: Found reference to undefined definition | ||
17:23-17:26: Found reference to undefined definition | ||
1:1-1:10: Unexpected reference to undefined definition, expected corresponding definition (`mercury`) for a link or escaped opening bracket (`\[`) for regular text | ||
4:1-4:10: Unexpected reference to undefined definition, expected corresponding definition (`venus`) for a link or escaped opening bracket (`\[`) for regular text | ||
6:1-6:15: Unexpected reference to undefined definition, expected corresponding definition (`earth`) for a link or escaped opening bracket (`\[`) for regular text | ||
9:2-9:8: Unexpected reference to undefined definition, expected corresponding definition (`mars`) for an image or escaped opening bracket (`\[`) for regular text | ||
9:50-10:8: Unexpected reference to undefined definition, expected corresponding definition (`solar system`) for a link or escaped opening bracket (`\[`) for regular text | ||
12:67-13:12: Unexpected reference to undefined definition, expected corresponding definition (`solar > system`) for a link or escaped opening bracket (`\[`) for regular text | ||
15:1-15:9: Unexpected reference to undefined definition, expected corresponding definition (`saturn`) for a link or escaped opening bracket (`\[`) for regular text | ||
18:1-18:13: Unexpected reference to undefined definition, expected corresponding definition (`*uranus*`) for a link or escaped opening bracket (`\[`) for regular text | ||
20:1-20:19: Unexpected reference to undefined definition, expected corresponding definition (`neptune`) for a link or escaped opening bracket (`\[`) for regular text | ||
20:19-20:25: Unexpected reference to undefined definition, expected corresponding definition (`more`) for a link or escaped opening bracket (`\[`) for regular text | ||
``` | ||
@@ -232,3 +252,3 @@ | ||
When configured with `{ allow: [ '...', '…' ] }`. | ||
When configured with `{ allow: [ '…' ] }`. | ||
@@ -238,3 +258,4 @@ ###### In | ||
```markdown | ||
> Eliding a portion of a quoted passage […] is acceptable. | ||
Mercury is the first planet from the Sun and the smallest in the Solar | ||
System. […] | ||
``` | ||
@@ -246,5 +267,5 @@ | ||
##### `ok-allow.md` | ||
##### `source.md` | ||
When configured with `{ allow: [ 'a', { source: '^b\\.' } ] }`. | ||
When configured with `{ allow: [ { source: '^mer' }, 'venus' ] }`. | ||
@@ -254,7 +275,6 @@ ###### In | ||
```markdown | ||
[foo][b.c] | ||
[Mercury][] is the first planet from the Sun and the smallest in the Solar | ||
System. | ||
[bar][a] | ||
Matching is case-insensitive: [bar][B.C] | ||
[Venus][] is the second planet from the Sun. | ||
``` | ||
@@ -266,12 +286,37 @@ | ||
##### `not-ok.md` | ||
##### `gfm.md` | ||
When configured with `{ allow: [ 'a', { source: '^b\\.' } ] }`. | ||
###### In | ||
> 👉 **Note**: this example uses | ||
> GFM ([`remark-gfm`][github-remark-gfm]). | ||
```markdown | ||
Mercury[^mercury] is the first planet from the Sun and the smallest in the | ||
Solar System. | ||
[^venus]: | ||
**Venus** is the second planet from the Sun. | ||
``` | ||
###### Out | ||
```text | ||
1:8-1:18: Unexpected reference to undefined definition, expected corresponding definition (`mercury`) for a footnote or escaped opening bracket (`\[`) for regular text | ||
``` | ||
##### `allow-shortcut-link.md` | ||
When configured with `{ allowShortcutLink: true }`. | ||
###### In | ||
```markdown | ||
[foo][a.c] | ||
[Mercury] is the first planet from the Sun and the smallest in the Solar | ||
System. | ||
[bar][b] | ||
[Venus][] is the second planet from the Sun. | ||
[Earth][earth] is the third planet from the Sun and the only astronomical object | ||
known to harbor life. | ||
``` | ||
@@ -282,4 +327,4 @@ | ||
```text | ||
1:1-1:11: Found reference to undefined definition | ||
3:1-3:9: Found reference to undefined definition | ||
4:1-4:10: Unexpected reference to undefined definition, expected corresponding definition (`venus`) for a link or escaped opening bracket (`\[`) for regular text | ||
6:1-6:15: Unexpected reference to undefined definition, expected corresponding definition (`earth`) for a link or escaped opening bracket (`\[`) for regular text | ||
``` | ||
@@ -289,14 +334,18 @@ | ||
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, | ||
`remark-lint-no-undefined-references@5`, | ||
compatible with Node.js 16. | ||
## Contribute | ||
See [`contributing.md`][contributing] in [`remarkjs/.github`][health] for ways | ||
See [`contributing.md`][github-dotfiles-contributing] in [`remarkjs/.github`][github-dotfiles-health] for ways | ||
to get started. | ||
See [`support.md`][support] for ways to get help. | ||
See [`support.md`][github-dotfiles-support] for ways to get help. | ||
This project has a [code of conduct][coc]. | ||
This project has a [code of conduct][github-dotfiles-coc]. | ||
By interacting with this repository, organization, or community you agree to | ||
@@ -307,52 +356,58 @@ abide by its terms. | ||
[MIT][license] © [Titus Wormer][author] | ||
[MIT][file-license] © [Titus Wormer][author] | ||
[build-badge]: https://github.com/remarkjs/remark-lint/workflows/main/badge.svg | ||
[api-options]: #options | ||
[build]: https://github.com/remarkjs/remark-lint/actions | ||
[api-remark-lint-no-undefined-references]: #unifieduseremarklintnoundefinedreferences-options | ||
[coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark-lint.svg | ||
[author]: https://wooorm.com | ||
[coverage]: https://codecov.io/github/remarkjs/remark-lint | ||
[badge-build-image]: https://github.com/remarkjs/remark-lint/workflows/main/badge.svg | ||
[downloads-badge]: https://img.shields.io/npm/dm/remark-lint-no-undefined-references.svg | ||
[badge-build-url]: https://github.com/remarkjs/remark-lint/actions | ||
[downloads]: https://www.npmjs.com/package/remark-lint-no-undefined-references | ||
[badge-chat-image]: https://img.shields.io/badge/chat-discussions-success.svg | ||
[size-badge]: https://img.shields.io/bundlephobia/minzip/remark-lint-no-undefined-references.svg | ||
[badge-chat-url]: https://github.com/remarkjs/remark/discussions | ||
[size]: https://bundlephobia.com/result?p=remark-lint-no-undefined-references | ||
[badge-coverage-image]: https://img.shields.io/codecov/c/github/remarkjs/remark-lint.svg | ||
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg | ||
[badge-coverage-url]: https://codecov.io/github/remarkjs/remark-lint | ||
[backers-badge]: https://opencollective.com/unified/backers/badge.svg | ||
[badge-downloads-image]: https://img.shields.io/npm/dm/remark-lint-no-undefined-references.svg | ||
[collective]: https://opencollective.com/unified | ||
[badge-downloads-url]: https://www.npmjs.com/package/remark-lint-no-undefined-references | ||
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg | ||
[badge-funding-backers-image]: https://opencollective.com/unified/backers/badge.svg | ||
[chat]: https://github.com/remarkjs/remark/discussions | ||
[badge-funding-sponsors-image]: https://opencollective.com/unified/sponsors/badge.svg | ||
[unified]: https://github.com/unifiedjs/unified | ||
[badge-funding-url]: https://opencollective.com/unified | ||
[remark]: https://github.com/remarkjs/remark | ||
[badge-size-image]: https://img.shields.io/bundlejs/size/remark-lint-no-undefined-references | ||
[mono]: https://github.com/remarkjs/remark-lint | ||
[badge-size-url]: https://bundlejs.com/?q=remark-lint-no-undefined-references | ||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[esm-sh]: https://esm.sh | ||
[esmsh]: https://esm.sh | ||
[file-license]: https://github.com/remarkjs/remark-lint/blob/main/license | ||
[npm]: https://docs.npmjs.com/cli/install | ||
[github-dotfiles-coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md | ||
[health]: https://github.com/remarkjs/.github | ||
[github-dotfiles-contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md | ||
[contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md | ||
[github-dotfiles-health]: https://github.com/remarkjs/.github | ||
[support]: https://github.com/remarkjs/.github/blob/main/support.md | ||
[github-dotfiles-support]: https://github.com/remarkjs/.github/blob/main/support.md | ||
[coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md | ||
[github-gist-esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[license]: https://github.com/remarkjs/remark-lint/blob/main/license | ||
[github-remark-gfm]: https://github.com/remarkjs/remark-gfm | ||
[author]: https://wooorm.com | ||
[github-remark-lint]: https://github.com/remarkjs/remark-lint | ||
[github-unified-transformer]: https://github.com/unifiedjs/unified#transformer | ||
[npm-install]: https://docs.npmjs.com/cli/install | ||
[typescript]: https://www.typescriptlang.org |
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
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
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
29429
5
441
395
1
1
+ Addedcollapse-white-space@^2.0.0
+ Addeddevlop@^1.0.0
+ Added@types/mdast@4.0.4(transitive)
+ Added@types/unist@3.0.3(transitive)
+ Addedcollapse-white-space@2.1.0(transitive)
+ Addeddequal@2.0.3(transitive)
+ Addeddevlop@1.1.0(transitive)
+ Addedmicromark-util-normalize-identifier@2.0.0(transitive)
+ Addedmicromark-util-symbol@2.0.0(transitive)
+ Addedunified@11.0.5(transitive)
+ Addedunified-lint-rule@3.0.0(transitive)
+ Addedunist-util-is@6.0.0(transitive)
+ Addedunist-util-position@5.0.0(transitive)
+ Addedunist-util-stringify-position@4.0.0(transitive)
+ Addedunist-util-visit-parents@6.0.1(transitive)
+ Addedvfile@6.0.3(transitive)
+ Addedvfile-location@5.0.3(transitive)
+ Addedvfile-message@4.0.2(transitive)
- Removedunified@^10.0.0
- Removedunist-util-generated@^2.0.0
- Removedunist-util-visit@^4.0.0
- Removed@types/mdast@3.0.15(transitive)
- Removed@types/unist@2.0.11(transitive)
- Removedis-buffer@2.0.5(transitive)
- Removedmicromark-util-normalize-identifier@1.1.0(transitive)
- Removedmicromark-util-symbol@1.1.0(transitive)
- Removedunified@10.1.2(transitive)
- Removedunified-lint-rule@2.1.2(transitive)
- Removedunist-util-generated@2.0.1(transitive)
- Removedunist-util-is@5.2.1(transitive)
- Removedunist-util-position@4.0.4(transitive)
- Removedunist-util-stringify-position@3.0.3(transitive)
- Removedunist-util-visit@4.1.2(transitive)
- Removedunist-util-visit-parents@5.1.3(transitive)
- Removedvfile@5.3.7(transitive)
- Removedvfile-location@4.1.0(transitive)
- Removedvfile-message@3.1.4(transitive)
Updated@types/mdast@^4.0.0
Updatedunified-lint-rule@^3.0.0
Updatedunist-util-position@^5.0.0
Updatedvfile-location@^5.0.0