Update MD033/no-inline-html to ignore HTML in labels for reference links/images (fixes #658).

This commit is contained in:
David Anson 2022-12-06 22:57:45 -08:00
parent cba5e8d340
commit 2146bbae5f
6 changed files with 101 additions and 6 deletions

View file

@ -894,7 +894,9 @@ function getReferenceLinkImageData(lineMetadata) {
referenceData.push([ referenceData.push([
lineIndex, lineIndex,
referenceIndex, referenceIndex,
matchString.length matchString.length,
matchText.length,
matchLabel.length
]); ]);
references.set(label, referenceData); references.set(label, referenceData);
} }
@ -3688,7 +3690,7 @@ module.exports = {
// @ts-check // @ts-check
const { addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); const { codeBlockAndSpanRanges, lineMetadata, referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
const linkDestinationRe = /]\(\s*$/; const linkDestinationRe = /]\(\s*$/;
// See https://spec.commonmark.org/0.29/#autolinks // See https://spec.commonmark.org/0.29/#autolinks
const emailAddressRe = const emailAddressRe =
@ -3703,6 +3705,15 @@ module.exports = {
allowedElements = Array.isArray(allowedElements) ? allowedElements : []; allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
allowedElements = allowedElements.map((element) => element.toLowerCase()); allowedElements = allowedElements.map((element) => element.toLowerCase());
const exclusions = codeBlockAndSpanRanges(); const exclusions = codeBlockAndSpanRanges();
const { references, definitionLineIndices } = referenceLinkImageData();
for (const datas of references.values()) {
for (const data of datas) {
const [lineIndex, index, , textLength, labelLength] = data;
if (labelLength > 0) {
exclusions.push([lineIndex, index + 3 + textLength, labelLength]);
}
}
}
forEachLine(lineMetadata(), (line, lineIndex, inCode) => { forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
let match = null; let match = null;
// eslint-disable-next-line no-unmodified-loop-condition // eslint-disable-next-line no-unmodified-loop-condition
@ -3711,7 +3722,8 @@ module.exports = {
if (!allowedElements.includes(element.toLowerCase()) && if (!allowedElements.includes(element.toLowerCase()) &&
!tag.endsWith("\\>") && !tag.endsWith("\\>") &&
!emailAddressRe.test(content) && !emailAddressRe.test(content) &&
!withinAnyRange(exclusions, lineIndex, match.index, match[0].length)) { !withinAnyRange(exclusions, lineIndex, match.index, tag.length) &&
!definitionLineIndices.includes(lineIndex)) {
const prefix = line.substring(0, match.index); const prefix = line.substring(0, match.index);
if (!linkDestinationRe.test(prefix)) { if (!linkDestinationRe.test(prefix)) {
const unescaped = unescapeMarkdown(prefix + "<", "_"); const unescaped = unescapeMarkdown(prefix + "<", "_");

View file

@ -931,7 +931,9 @@ function getReferenceLinkImageData(lineMetadata) {
referenceData.push([ referenceData.push([
lineIndex, lineIndex,
referenceIndex, referenceIndex,
matchString.length matchString.length,
matchText.length,
matchLabel.length
]); ]);
references.set(label, referenceData); references.set(label, referenceData);
} }

View file

@ -5,7 +5,8 @@
const { const {
addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown
} = require("../helpers"); } = require("../helpers");
const { codeBlockAndSpanRanges, lineMetadata } = require("./cache"); const { codeBlockAndSpanRanges, lineMetadata, referenceLinkImageData } =
require("./cache");
const linkDestinationRe = /]\(\s*$/; const linkDestinationRe = /]\(\s*$/;
// See https://spec.commonmark.org/0.29/#autolinks // See https://spec.commonmark.org/0.29/#autolinks
@ -22,6 +23,15 @@ module.exports = {
allowedElements = Array.isArray(allowedElements) ? allowedElements : []; allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
allowedElements = allowedElements.map((element) => element.toLowerCase()); allowedElements = allowedElements.map((element) => element.toLowerCase());
const exclusions = codeBlockAndSpanRanges(); const exclusions = codeBlockAndSpanRanges();
const { references, definitionLineIndices } = referenceLinkImageData();
for (const datas of references.values()) {
for (const data of datas) {
const [ lineIndex, index, , textLength, labelLength ] = data;
if (labelLength > 0) {
exclusions.push([ lineIndex, index + 3 + textLength, labelLength ]);
}
}
}
forEachLine(lineMetadata(), (line, lineIndex, inCode) => { forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
let match = null; let match = null;
// eslint-disable-next-line no-unmodified-loop-condition // eslint-disable-next-line no-unmodified-loop-condition
@ -31,7 +41,8 @@ module.exports = {
!allowedElements.includes(element.toLowerCase()) && !allowedElements.includes(element.toLowerCase()) &&
!tag.endsWith("\\>") && !tag.endsWith("\\>") &&
!emailAddressRe.test(content) && !emailAddressRe.test(content) &&
!withinAnyRange(exclusions, lineIndex, match.index, match[0].length) !withinAnyRange(exclusions, lineIndex, match.index, tag.length) &&
!definitionLineIndices.includes(lineIndex)
) { ) {
const prefix = line.substring(0, match.index); const prefix = line.substring(0, match.index);
if (!linkDestinationRe.test(prefix)) { if (!linkDestinationRe.test(prefix)) {

View file

@ -120,3 +120,14 @@ code {MD046:114}
Text `code <element> code` text Text `code <element> code` text
Text <element> text {MD033} Text <element> text {MD033}
A [<link-with>][a-reference] is problematic. {MD033}
A [link with][a-<reference>] is okay.
A link with [a-<reference>][] is problematic. {MD033}
A link with [a-<reference>] is problematic. {MD033}
[a-reference]: https://example.com/
[a-<reference>]: https://example.com/

View file

@ -20807,6 +20807,54 @@ Generated by [AVA](https://avajs.dev).
'no-inline-html', 'no-inline-html',
], ],
}, },
{
errorContext: null,
errorDetail: 'Element: link-with',
errorRange: [
4,
11,
],
fixInfo: null,
lineNumber: 124,
ruleDescription: 'Inline HTML',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md033.md',
ruleNames: [
'MD033',
'no-inline-html',
],
},
{
errorContext: null,
errorDetail: 'Element: reference',
errorRange: [
16,
11,
],
fixInfo: null,
lineNumber: 128,
ruleDescription: 'Inline HTML',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md033.md',
ruleNames: [
'MD033',
'no-inline-html',
],
},
{
errorContext: null,
errorDetail: 'Element: reference',
errorRange: [
16,
11,
],
fixInfo: null,
lineNumber: 130,
ruleDescription: 'Inline HTML',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md033.md',
ruleNames: [
'MD033',
'no-inline-html',
],
},
{ {
errorContext: '`code <element `', errorContext: '`code <element `',
errorDetail: null, errorDetail: null,
@ -20976,6 +21024,17 @@ Generated by [AVA](https://avajs.dev).
Text \`code <element> code\` text␊ Text \`code <element> code\` text␊
Text <element> text {MD033}␊ Text <element> text {MD033}␊
A [<link-with>][a-reference] is problematic. {MD033}␊
A [link with][a-<reference>] is okay.␊
A link with [a-<reference>][] is problematic. {MD033}␊
A link with [a-<reference>] is problematic. {MD033}␊
[a-reference]: https://example.com/␊
[a-<reference>]: https://example.com/␊
`, `,
} }