Skip to content

Commit

Permalink
Update MD051/link-fragments to handle links and images in headings (f…
Browse files Browse the repository at this point in the history
…ixes #945).
  • Loading branch information
DavidAnson committed Sep 4, 2023
1 parent 6a2b867 commit a736588
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 47 deletions.
37 changes: 24 additions & 13 deletions demo/markdownlint-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand All @@ -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()
Expand All @@ -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);
}
}
}
}
Expand Down
35 changes: 23 additions & 12 deletions lib/md051.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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(
Expand Down Expand Up @@ -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);
}
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions test/link-fragments.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)

<a name="namedlink"></a>

<a id = idlink></a>
Expand All @@ -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}
Expand Down
Loading

0 comments on commit a736588

Please sign in to comment.