Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

remark-lint-no-undefined-references

Package Overview
Dependencies
Maintainers
3
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

remark-lint-no-undefined-references - npm Package Compare versions

Comparing version 4.2.1 to 5.0.0

index.d.ts.map

61

index.d.ts

@@ -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
/**
* 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"
}
}
}

@@ -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
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc