diff --git a/demo/markdownlint-browser.js b/demo/markdownlint-browser.js
index 6fc8f86e..57f93b50 100644
--- a/demo/markdownlint-browser.js
+++ b/demo/markdownlint-browser.js
@@ -6139,6 +6139,7 @@ var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
addError = _require.addError,
addErrorDetailIf = _require.addErrorDetailIf;
var _require2 = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs"),
+ filterByPredicate = _require2.filterByPredicate,
filterByTypes = _require2.filterByTypes,
getHtmlTagInfo = _require2.getHtmlTagInfo;
@@ -6147,6 +6148,10 @@ var idRe = /[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]i
var nameRe = /[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]name[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]*=[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]*["']?((?:(?![\t-\r "'>\xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uD800-\uDFFF\uFEFF])[\s\S]|[\uD800-\uDBFF][\uDC00-\uDFFF])+)/i;
var anchorRe = /\{(#[0-9a-z]+(?:[\x2D_][0-9a-z]+)*)\}/g;
+// Sets for filtering heading tokens during conversion
+var childrenExclude = new Set(["image", "reference", "resource"]);
+var tokensInclude = new Set(["codeTextData", "data"]);
+
/**
* Converts a Markdown heading into an HTML fragment according to the rules
* used by GitHub.
@@ -6155,7 +6160,11 @@ var anchorRe = /\{(#[0-9a-z]+(?:[\x2D_][0-9a-z]+)*)\}/g;
* @returns {string} Fragment string for heading.
*/
function convertHeadingToHTMLFragment(headingText) {
- var inlineText = filterByTypes(headingText.children, ["codeTextData", "data"]).map(function (token) {
+ var inlineText = filterByPredicate(headingText.children, function (token) {
+ return tokensInclude.has(token.type);
+ }, function (token) {
+ return childrenExclude.has(token.type) ? [] : token.children;
+ }).map(function (token) {
return token.text;
}).join("");
return "#" + encodeURIComponent(inlineText.toLowerCase()
@@ -6181,18 +6190,20 @@ module.exports = {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var headingText = _step.value;
var fragment = convertHeadingToHTMLFragment(headingText);
- var count = fragments.get(fragment) || 0;
- if (count) {
- fragments.set("".concat(fragment, "-").concat(count), 0);
- }
- fragments.set(fragment, count + 1);
- var match = null;
- while ((match = anchorRe.exec(headingText.text)) !== null) {
- var _match = match,
- _match2 = _slicedToArray(_match, 2),
- anchor = _match2[1];
- if (!fragments.has(anchor)) {
- fragments.set(anchor, 1);
+ if (fragment !== "#") {
+ var count = fragments.get(fragment) || 0;
+ if (count) {
+ fragments.set("".concat(fragment, "-").concat(count), 0);
+ }
+ fragments.set(fragment, count + 1);
+ var match = null;
+ while ((match = anchorRe.exec(headingText.text)) !== null) {
+ var _match = match,
+ _match2 = _slicedToArray(_match, 2),
+ anchor = _match2[1];
+ if (!fragments.has(anchor)) {
+ fragments.set(anchor, 1);
+ }
}
}
}
diff --git a/lib/md051.js b/lib/md051.js
index 0b501b96..30430208 100644
--- a/lib/md051.js
+++ b/lib/md051.js
@@ -3,13 +3,18 @@
"use strict";
const { addError, addErrorDetailIf } = require("../helpers");
-const { filterByTypes, getHtmlTagInfo } = require("../helpers/micromark.cjs");
+const { filterByPredicate, filterByTypes, getHtmlTagInfo } =
+ require("../helpers/micromark.cjs");
// Regular expression for identifying HTML anchor names
const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
const anchorRe = /\{(#[a-z\d]+(?:[-_][a-z\d]+)*)\}/gu;
+// Sets for filtering heading tokens during conversion
+const childrenExclude = new Set([ "image", "reference", "resource" ]);
+const tokensInclude = new Set([ "codeTextData", "data" ]);
+
/**
* Converts a Markdown heading into an HTML fragment according to the rules
* used by GitHub.
@@ -19,7 +24,11 @@ const anchorRe = /\{(#[a-z\d]+(?:[-_][a-z\d]+)*)\}/gu;
*/
function convertHeadingToHTMLFragment(headingText) {
const inlineText =
- filterByTypes(headingText.children, [ "codeTextData", "data" ])
+ filterByPredicate(
+ headingText.children,
+ (token) => tokensInclude.has(token.type),
+ (token) => (childrenExclude.has(token.type) ? [] : token.children)
+ )
.map((token) => token.text)
.join("");
return "#" + encodeURIComponent(
@@ -52,16 +61,18 @@ module.exports = {
);
for (const headingText of headingTexts) {
const fragment = convertHeadingToHTMLFragment(headingText);
- const count = fragments.get(fragment) || 0;
- if (count) {
- fragments.set(`${fragment}-${count}`, 0);
- }
- fragments.set(fragment, count + 1);
- let match = null;
- while ((match = anchorRe.exec(headingText.text)) !== null) {
- const [ , anchor ] = match;
- if (!fragments.has(anchor)) {
- fragments.set(anchor, 1);
+ if (fragment !== "#") {
+ const count = fragments.get(fragment) || 0;
+ if (count) {
+ fragments.set(`${fragment}-${count}`, 0);
+ }
+ fragments.set(fragment, count + 1);
+ let match = null;
+ while ((match = anchorRe.exec(headingText.text)) !== null) {
+ const [ , anchor ] = match;
+ if (!fragments.has(anchor)) {
+ fragments.set(anchor, 1);
+ }
}
}
}
diff --git a/test/link-fragments.md b/test/link-fragments.md
index 4e919c2a..1932a474 100644
--- a/test/link-fragments.md
+++ b/test/link-fragments.md
@@ -46,6 +46,16 @@
[Valid](#en-t%C3%AAte-valide-dans-fran%C3%A7ais-pour-v%C3%A9rification)
+[Valid](#valid-heading-is-a-link)
+
+[Valid](#valid-heading-has-a-link)
+
+[Valid](#valid-heading-is-a-reference-link)
+
+[Valid](#valid-heading-has-a-reference-link)
+
+[Valid](#valid-heading-has-)
+
[Valid](#namedlink)
[Valid](#idlink)
@@ -127,6 +137,18 @@ Text
### En-tête Valide Dans Français Pour Vérification
+### [Valid Heading Is a Link](https://example.com)
+
+### Valid Heading [Has a Link](https://example.com)
+
+### [Valid Heading Is a Reference Link][goodref]
+
+### Valid Heading [Has a Reference Link][goodref]
+
+### 
+
+### Valid Heading Has 
+
@@ -147,6 +169,8 @@ Text
## Invalid Fragments
+[Invalid](#valid-heading-is-an-image) {MD051}
+
[Invalid](#valid-heading-2004-) {MD051}
[Invalid](#valid-repeated-heading-3) {MD051}
diff --git a/test/snapshots/markdownlint-test-scenarios.js.md b/test/snapshots/markdownlint-test-scenarios.js.md
index 9334323b..a85bfb2d 100644
--- a/test/snapshots/markdownlint-test-scenarios.js.md
+++ b/test/snapshots/markdownlint-test-scenarios.js.md
@@ -23961,6 +23961,22 @@ Generated by [AVA](https://avajs.dev).
{
errors: [
+ {
+ errorContext: '[Invalid](#valid-heading-is-an-image)',
+ errorDetail: null,
+ errorRange: [
+ 1,
+ 37,
+ ],
+ fixInfo: null,
+ lineNumber: 172,
+ ruleDescription: 'Link fragments should be valid',
+ ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
+ ruleNames: [
+ 'MD051',
+ 'link-fragments',
+ ],
+ },
{
errorContext: '[Invalid](#valid-heading-2004-)',
errorDetail: null,
@@ -23969,7 +23985,7 @@ Generated by [AVA](https://avajs.dev).
31,
],
fixInfo: null,
- lineNumber: 150,
+ lineNumber: 174,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -23985,7 +24001,7 @@ Generated by [AVA](https://avajs.dev).
36,
],
fixInfo: null,
- lineNumber: 152,
+ lineNumber: 176,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24001,7 +24017,7 @@ Generated by [AVA](https://avajs.dev).
28,
],
fixInfo: null,
- lineNumber: 154,
+ lineNumber: 178,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24017,7 +24033,7 @@ Generated by [AVA](https://avajs.dev).
18,
],
fixInfo: null,
- lineNumber: 156,
+ lineNumber: 180,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24037,7 +24053,7 @@ Generated by [AVA](https://avajs.dev).
editColumn: 11,
insertText: '#HREFandID',
},
- lineNumber: 158,
+ lineNumber: 182,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24053,7 +24069,7 @@ Generated by [AVA](https://avajs.dev).
34,
],
fixInfo: null,
- lineNumber: 160,
+ lineNumber: 184,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24069,7 +24085,7 @@ Generated by [AVA](https://avajs.dev).
34,
],
fixInfo: null,
- lineNumber: 162,
+ lineNumber: 186,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24085,7 +24101,7 @@ Generated by [AVA](https://avajs.dev).
39,
],
fixInfo: null,
- lineNumber: 164,
+ lineNumber: 188,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24098,7 +24114,7 @@ Generated by [AVA](https://avajs.dev).
errorDetail: null,
errorRange: null,
fixInfo: null,
- lineNumber: 166,
+ lineNumber: 190,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24114,7 +24130,7 @@ Generated by [AVA](https://avajs.dev).
28,
],
fixInfo: null,
- lineNumber: 171,
+ lineNumber: 195,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24134,7 +24150,7 @@ Generated by [AVA](https://avajs.dev).
editColumn: 9,
insertText: '#valid-fragments',
},
- lineNumber: 175,
+ lineNumber: 199,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24154,7 +24170,7 @@ Generated by [AVA](https://avajs.dev).
editColumn: 12,
insertText: '#namedlink',
},
- lineNumber: 177,
+ lineNumber: 201,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24167,7 +24183,7 @@ Generated by [AVA](https://avajs.dev).
errorDetail: 'Expected: #namedlink; Actual: #NAMEDLINK',
errorRange: null,
fixInfo: null,
- lineNumber: 179,
+ lineNumber: 203,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24187,7 +24203,7 @@ Generated by [AVA](https://avajs.dev).
editColumn: 13,
insertText: '#idlink',
},
- lineNumber: 184,
+ lineNumber: 208,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24203,7 +24219,7 @@ Generated by [AVA](https://avajs.dev).
26,
],
fixInfo: null,
- lineNumber: 219,
+ lineNumber: 243,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24219,7 +24235,7 @@ Generated by [AVA](https://avajs.dev).
26,
],
fixInfo: null,
- lineNumber: 221,
+ lineNumber: 245,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24235,7 +24251,7 @@ Generated by [AVA](https://avajs.dev).
20,
],
fixInfo: null,
- lineNumber: 223,
+ lineNumber: 247,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24251,7 +24267,7 @@ Generated by [AVA](https://avajs.dev).
23,
],
fixInfo: null,
- lineNumber: 225,
+ lineNumber: 249,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24267,7 +24283,7 @@ Generated by [AVA](https://avajs.dev).
22,
],
fixInfo: null,
- lineNumber: 227,
+ lineNumber: 251,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24283,7 +24299,7 @@ Generated by [AVA](https://avajs.dev).
42,
],
fixInfo: null,
- lineNumber: 229,
+ lineNumber: 253,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24299,7 +24315,7 @@ Generated by [AVA](https://avajs.dev).
21,
],
fixInfo: null,
- lineNumber: 231,
+ lineNumber: 255,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24315,7 +24331,7 @@ Generated by [AVA](https://avajs.dev).
21,
],
fixInfo: null,
- lineNumber: 233,
+ lineNumber: 257,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
@@ -24372,6 +24388,16 @@ Generated by [AVA](https://avajs.dev).
␊
[Valid](#en-t%C3%AAte-valide-dans-fran%C3%A7ais-pour-v%C3%A9rification)␊
␊
+ [Valid](#valid-heading-is-a-link)␊
+ ␊
+ [Valid](#valid-heading-has-a-link)␊
+ ␊
+ [Valid](#valid-heading-is-a-reference-link)␊
+ ␊
+ [Valid](#valid-heading-has-a-reference-link)␊
+ ␊
+ [Valid](#valid-heading-has-)␊
+ ␊
[Valid](#namedlink)␊
␊
[Valid](#idlink)␊
@@ -24453,6 +24479,18 @@ Generated by [AVA](https://avajs.dev).
␊
### En-tête Valide Dans Français Pour Vérification␊
␊
+ ### [Valid Heading Is a Link](https://example.com)␊
+ ␊
+ ### Valid Heading [Has a Link](https://example.com)␊
+ ␊
+ ### [Valid Heading Is a Reference Link][goodref]␊
+ ␊
+ ### Valid Heading [Has a Reference Link][goodref]␊
+ ␊
+ ### ␊
+ ␊
+ ### Valid Heading Has ␊
+ ␊
␊
␊
␊
@@ -24473,6 +24511,8 @@ Generated by [AVA](https://avajs.dev).
␊
## Invalid Fragments␊
␊
+ [Invalid](#valid-heading-is-an-image) {MD051}␊
+ ␊
[Invalid](#valid-heading-2004-) {MD051}␊
␊
[Invalid](#valid-repeated-heading-3) {MD051}␊
diff --git a/test/snapshots/markdownlint-test-scenarios.js.snap b/test/snapshots/markdownlint-test-scenarios.js.snap
index af1a9009..6de7c901 100644
Binary files a/test/snapshots/markdownlint-test-scenarios.js.snap and b/test/snapshots/markdownlint-test-scenarios.js.snap differ