Skip to content

Commit 06a833a

Browse files
committed
feat: add ignoreLabels option to no-missing-label-refs
1 parent c790317 commit 06a833a

File tree

3 files changed

+167
-3
lines changed

3 files changed

+167
-3
lines changed

docs/rules/no-missing-label-refs.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,24 @@ Examples of **incorrect** code for this rule:
3030
[eslint]
3131
```
3232

33+
## Options
34+
35+
The following options are available on this rule:
36+
37+
* `ignoreLabels: Array<string>` - labels to ignore when checking for missing references. (default: `[]`)
38+
39+
Examples of **correct** code when configured as `"no-missing-label-refs": ["error", { ignoreLabels: ["eslint"] }]`:
40+
41+
```markdown
42+
<!-- eslint markdown/no-missing-label-refs: ["error", { ignoreLabels: ["eslint"] }] -->
43+
44+
[ESLint][eslint]
45+
46+
[eslint][]
47+
48+
[eslint]
49+
```
50+
3351
## When Not to Use It
3452

3553
If you aren't concerned with missing label references, you can safely disable this rule.

src/rules/no-missing-label-refs.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { findOffsets, illegalShorthandTailPattern } from "../util.js";
1818
* @import { Text } from "mdast";
1919
* @import { MarkdownRuleDefinition } from "../types.js";
2020
* @typedef {"notFound"} NoMissingLabelRefsMessageIds
21-
* @typedef {[]} NoMissingLabelRefsOptions
21+
* @typedef {[{ ignoreLabels?: string[] }]} NoMissingLabelRefsOptions
2222
* @typedef {MarkdownRuleDefinition<{ RuleOptions: NoMissingLabelRefsOptions, MessageIds: NoMissingLabelRefsMessageIds }>} NoMissingLabelRefsRuleDefinition
2323
*/
2424

@@ -118,13 +118,36 @@ export default {
118118
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-missing-label-refs.md",
119119
},
120120

121+
schema: [
122+
{
123+
type: "object",
124+
properties: {
125+
ignoreLabels: {
126+
type: "array",
127+
items: {
128+
type: "string",
129+
},
130+
uniqueItems: true,
131+
},
132+
},
133+
additionalProperties: false,
134+
},
135+
],
136+
137+
defaultOptions: [
138+
{
139+
ignoreLabels: [],
140+
},
141+
],
142+
121143
messages: {
122144
notFound: "Label reference '{{label}}' not found.",
123145
},
124146
},
125147

126148
create(context) {
127149
const { sourceCode } = context;
150+
const ignoreLabels = new Set(context.options[0].ignoreLabels);
128151

129152
/** @type {Array<{label:string,position:Position}>} */
130153
let allMissingReferences = [];
@@ -143,9 +166,16 @@ export default {
143166
},
144167

145168
text(node) {
146-
allMissingReferences.push(
147-
...findMissingReferences(node, sourceCode.getText(node)),
169+
const missingReferences = findMissingReferences(
170+
node,
171+
sourceCode.getText(node),
148172
);
173+
174+
for (const missingReference of missingReferences) {
175+
if (!ignoreLabels.has(missingReference.label)) {
176+
allMissingReferences.push(missingReference);
177+
}
178+
}
149179
},
150180

151181
definition(node) {

tests/rules/no-missing-label-refs.test.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,38 @@ ruleTester.run("no-missing-label-refs", rule, {
5555
"[escaped\\]\\[escaped\\]",
5656
"\\[escaped]\\[escaped]",
5757
"[escaped\\][escaped\\]",
58+
{
59+
code: "[foo][bar]",
60+
options: [{ ignoreLabels: ["bar"] }],
61+
},
62+
{
63+
code: "![foo][bar]",
64+
options: [{ ignoreLabels: ["bar"] }],
65+
},
66+
{
67+
code: "[foo][]",
68+
options: [{ ignoreLabels: ["foo"] }],
69+
},
70+
{
71+
code: "![foo][]",
72+
options: [{ ignoreLabels: ["foo"] }],
73+
},
74+
{
75+
code: "[foo]",
76+
options: [{ ignoreLabels: ["foo"] }],
77+
},
78+
{
79+
code: "![foo]",
80+
options: [{ ignoreLabels: ["foo"] }],
81+
},
82+
{
83+
code: "[foo]\n[bar]",
84+
options: [{ ignoreLabels: ["foo", "bar"] }],
85+
},
86+
{
87+
code: "[Foo][]\n[Bar][]",
88+
options: [{ ignoreLabels: ["Foo", "Bar"] }],
89+
},
5890
],
5991
invalid: [
6092
{
@@ -381,6 +413,90 @@ ruleTester.run("no-missing-label-refs", rule, {
381413
},
382414
],
383415
},
416+
{
417+
code: "[foo][bar]",
418+
options: [{ ignoreLabels: ["baz"] }],
419+
errors: [
420+
{
421+
messageId: "notFound",
422+
data: { label: "bar" },
423+
line: 1,
424+
column: 7,
425+
endLine: 1,
426+
endColumn: 10,
427+
},
428+
],
429+
},
430+
{
431+
code: "![foo][bar]",
432+
options: [{ ignoreLabels: ["foo"] }],
433+
errors: [
434+
{
435+
messageId: "notFound",
436+
data: { label: "bar" },
437+
line: 1,
438+
column: 8,
439+
endLine: 1,
440+
endColumn: 11,
441+
},
442+
],
443+
},
444+
{
445+
code: "[foo][]",
446+
options: [{ ignoreLabels: ["bar"] }],
447+
errors: [
448+
{
449+
messageId: "notFound",
450+
data: { label: "foo" },
451+
line: 1,
452+
column: 2,
453+
endLine: 1,
454+
endColumn: 5,
455+
},
456+
],
457+
},
458+
{
459+
code: "[foo]\n[bar]",
460+
options: [{ ignoreLabels: ["foo"] }],
461+
errors: [
462+
{
463+
messageId: "notFound",
464+
data: { label: "bar" },
465+
line: 2,
466+
column: 2,
467+
endLine: 2,
468+
endColumn: 5,
469+
},
470+
],
471+
},
472+
{
473+
code: "[Foo][]",
474+
options: [{ ignoreLabels: ["foo"] }],
475+
errors: [
476+
{
477+
messageId: "notFound",
478+
data: { label: "Foo" },
479+
line: 1,
480+
column: 2,
481+
endLine: 1,
482+
endColumn: 5,
483+
},
484+
],
485+
},
486+
{
487+
code: "[Foo][foo]\n[Bar][]",
488+
options: [{ ignoreLabels: ["Bar"] }],
489+
errors: [
490+
{
491+
messageId: "notFound",
492+
data: { label: "foo" },
493+
line: 1,
494+
column: 7,
495+
endLine: 1,
496+
endColumn: 10,
497+
},
498+
],
499+
},
384500
],
385501
});
386502

0 commit comments

Comments
 (0)