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 Is an Image](https://example.com) + +### Valid Heading Has ![an Image](https://example.com) + @@ -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 Is an Image](https://example.com)␊ + ␊ + ### Valid Heading Has ![an Image](https://example.com)␊ + ␊ ␊ ␊ ␊ @@ -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