Skip to content

Commit 6c8ef48

Browse files
authored
Update MD051/link-fragments to support id attributes on non-a elements (fixes #538).
The `name` is only an anchor on `a` elements, but `id` is a universal attribute on all elements. Also fix match on id/name to be complete, not just a suffix.
1 parent cba2ca0 commit 6c8ef48

File tree

5 files changed

+102
-18
lines changed

5 files changed

+102
-18
lines changed

demo/markdownlint-browser.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4601,7 +4601,8 @@ module.exports = [
46014601

46024602
const { addError, escapeForRegExp, filterTokens, forEachInlineChild, forEachHeading, htmlElementRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
46034603
// Regular expression for identifying HTML anchor names
4604-
const identifierRe = /(?:id|name)\s*=\s*['"]?([^'"\s>]+)/iu;
4604+
const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
4605+
const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
46054606
/**
46064607
* Converts a Markdown heading into an HTML fragment according to the rules
46074608
* used by GitHub.
@@ -4643,11 +4644,10 @@ module.exports = {
46434644
let match = null;
46444645
while ((match = htmlElementRe.exec(token.content)) !== null) {
46454646
const [tag, , element] = match;
4646-
if (element.toLowerCase() === "a") {
4647-
const idMatch = identifierRe.exec(tag);
4648-
if (idMatch) {
4649-
fragments.set(`#${idMatch[1]}`, 0);
4650-
}
4647+
const anchorMatch = idRe.exec(tag) ||
4648+
(element.toLowerCase() === "a" && nameRe.exec(tag));
4649+
if (anchorMatch) {
4650+
fragments.set(`#${anchorMatch[1]}`, 0);
46514651
}
46524652
}
46534653
};

lib/md051.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ const { addError, escapeForRegExp, filterTokens, forEachInlineChild,
66
forEachHeading, htmlElementRe } = require("../helpers");
77

88
// Regular expression for identifying HTML anchor names
9-
const identifierRe = /(?:id|name)\s*=\s*['"]?([^'"\s>]+)/iu;
9+
const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
10+
const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
1011

1112
/**
1213
* Converts a Markdown heading into an HTML fragment according to the rules
@@ -55,11 +56,10 @@ module.exports = {
5556
let match = null;
5657
while ((match = htmlElementRe.exec(token.content)) !== null) {
5758
const [ tag, , element ] = match;
58-
if (element.toLowerCase() === "a") {
59-
const idMatch = identifierRe.exec(tag);
60-
if (idMatch) {
61-
fragments.set(`#${idMatch[1]}`, 0);
62-
}
59+
const anchorMatch = idRe.exec(tag) ||
60+
(element.toLowerCase() === "a" && nameRe.exec(tag));
61+
if (anchorMatch) {
62+
fragments.set(`#${anchorMatch[1]}`, 0);
6363
}
6464
}
6565
};

test/link-fragments.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252

5353
[Valid](#HREFandID)
5454

55+
[Valid](#id-for-other-element)
56+
57+
[Valid](#id-after-name)
58+
5559
[Valid][goodref]
5660

5761
### Valid H3 Heading
@@ -125,6 +129,14 @@ Text
125129

126130
<A href="https://example.com" id="HREFandID">Text</A>
127131

132+
<p id="id-for-other-element"></p>
133+
134+
<p name="name-for-other-element"></p>
135+
136+
<input name="name-should-be-ignored" id="id-after-name">
137+
138+
<a data-id="not-an-id-should-be-ignored">
139+
128140
[goodref]: #namedlink
129141

130142
## Invalid Fragments
@@ -139,6 +151,12 @@ Text
139151

140152
[Invalid](#hrefandid) {MD051}
141153

154+
[Invalid](#name-for-other-element) {MD051}
155+
156+
[Invalid](#name-should-be-ignored) {MD051}
157+
158+
[Invalid](#not-an-id-should-be-ignored) {MD051}
159+
142160
[Invalid][badref] {MD051}
143161

144162
[badref]: #missing

test/snapshots/markdownlint-test-scenarios.js.md

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20950,7 +20950,7 @@ Generated by [AVA](https://avajs.dev).
2095020950
31,
2095120951
],
2095220952
fixInfo: null,
20953-
lineNumber: 132,
20953+
lineNumber: 144,
2095420954
ruleDescription: 'Link fragments should be valid',
2095520955
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
2095620956
ruleNames: [
@@ -20966,7 +20966,7 @@ Generated by [AVA](https://avajs.dev).
2096620966
36,
2096720967
],
2096820968
fixInfo: null,
20969-
lineNumber: 134,
20969+
lineNumber: 146,
2097020970
ruleDescription: 'Link fragments should be valid',
2097120971
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
2097220972
ruleNames: [
@@ -20982,7 +20982,7 @@ Generated by [AVA](https://avajs.dev).
2098220982
28,
2098320983
],
2098420984
fixInfo: null,
20985-
lineNumber: 136,
20985+
lineNumber: 148,
2098620986
ruleDescription: 'Link fragments should be valid',
2098720987
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
2098820988
ruleNames: [
@@ -20998,7 +20998,7 @@ Generated by [AVA](https://avajs.dev).
2099820998
18,
2099920999
],
2100021000
fixInfo: null,
21001-
lineNumber: 138,
21001+
lineNumber: 150,
2100221002
ruleDescription: 'Link fragments should be valid',
2100321003
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
2100421004
ruleNames: [
@@ -21014,7 +21014,55 @@ Generated by [AVA](https://avajs.dev).
2101421014
21,
2101521015
],
2101621016
fixInfo: null,
21017-
lineNumber: 140,
21017+
lineNumber: 152,
21018+
ruleDescription: 'Link fragments should be valid',
21019+
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
21020+
ruleNames: [
21021+
'MD051',
21022+
'link-fragments',
21023+
],
21024+
},
21025+
{
21026+
errorContext: '[Invalid](#name-for-other-element)',
21027+
errorDetail: null,
21028+
errorRange: [
21029+
1,
21030+
34,
21031+
],
21032+
fixInfo: null,
21033+
lineNumber: 154,
21034+
ruleDescription: 'Link fragments should be valid',
21035+
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
21036+
ruleNames: [
21037+
'MD051',
21038+
'link-fragments',
21039+
],
21040+
},
21041+
{
21042+
errorContext: '[Invalid](#name-should-be-ignored)',
21043+
errorDetail: null,
21044+
errorRange: [
21045+
1,
21046+
34,
21047+
],
21048+
fixInfo: null,
21049+
lineNumber: 156,
21050+
ruleDescription: 'Link fragments should be valid',
21051+
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
21052+
ruleNames: [
21053+
'MD051',
21054+
'link-fragments',
21055+
],
21056+
},
21057+
{
21058+
errorContext: '[Invalid](#not-an-id-should-be-ignored)',
21059+
errorDetail: null,
21060+
errorRange: [
21061+
1,
21062+
39,
21063+
],
21064+
fixInfo: null,
21065+
lineNumber: 158,
2101821066
ruleDescription: 'Link fragments should be valid',
2101921067
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
2102021068
ruleNames: [
@@ -21027,7 +21075,7 @@ Generated by [AVA](https://avajs.dev).
2102721075
errorDetail: null,
2102821076
errorRange: null,
2102921077
fixInfo: null,
21030-
lineNumber: 142,
21078+
lineNumber: 160,
2103121079
ruleDescription: 'Link fragments should be valid',
2103221080
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md051',
2103321081
ruleNames: [
@@ -21090,6 +21138,10 @@ Generated by [AVA](https://avajs.dev).
2109021138
2109121139
[Valid](#HREFandID)␊
2109221140
21141+
[Valid](#id-for-other-element)␊
21142+
21143+
[Valid](#id-after-name)␊
21144+
2109321145
[Valid][goodref]␊
2109421146
2109521147
### Valid H3 Heading␊
@@ -21163,6 +21215,14 @@ Generated by [AVA](https://avajs.dev).
2116321215
2116421216
<A href="https://example.com" id="HREFandID">Text</A>␊
2116521217
21218+
<p id="id-for-other-element"></p>␊
21219+
21220+
<p name="name-for-other-element"></p>␊
21221+
21222+
<input name="name-should-be-ignored" id="id-after-name">␊
21223+
21224+
<a data-id="not-an-id-should-be-ignored">␊
21225+
2116621226
[goodref]: #namedlink␊
2116721227
2116821228
## Invalid Fragments␊
@@ -21177,6 +21237,12 @@ Generated by [AVA](https://avajs.dev).
2117721237
2117821238
[Invalid](#hrefandid) {MD051}␊
2117921239
21240+
[Invalid](#name-for-other-element) {MD051}␊
21241+
21242+
[Invalid](#name-should-be-ignored) {MD051}␊
21243+
21244+
[Invalid](#not-an-id-should-be-ignored) {MD051}␊
21245+
2118021246
[Invalid][badref] {MD051}␊
2118121247
2118221248
[badref]: #missing␊
255 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)