From f7dfd59a5ecffe841a7aa267762d54478052f58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar=20Rubio?= Date: Thu, 21 Oct 2021 13:13:42 +0200 Subject: [PATCH] Update MD033/no-inline-html to handle HTML elements in multi-line code spans (fixes #436). --- demo/markdownlint-browser.js | 14 ++++----- lib/md033.js | 20 ++++++++----- test/inline_html.md | 57 ++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 15 deletions(-) diff --git a/demo/markdownlint-browser.js b/demo/markdownlint-browser.js index fc483429..3cf694ae 100644 --- a/demo/markdownlint-browser.js +++ b/demo/markdownlint-browser.js @@ -3158,11 +3158,10 @@ module.exports = { "use strict"; // @ts-check -var _a = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"), addError = _a.addError, forEachLine = _a.forEachLine, unescapeMarkdown = _a.unescapeMarkdown; -var lineMetadata = __webpack_require__(/*! ./cache */ "../lib/cache.js").lineMetadata; +var _a = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"), addError = _a.addError, forEachLine = _a.forEachLine, overlapsAnyRange = _a.overlapsAnyRange, unescapeMarkdown = _a.unescapeMarkdown; +var _b = __webpack_require__(/*! ./cache */ "../lib/cache.js"), inlineCodeSpanRanges = _b.inlineCodeSpanRanges, lineMetadata = _b.lineMetadata; var htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^>]*)?)\/?>/g; var linkDestinationRe = /]\(\s*$/; -var inlineCodeRe = /^[^`]*(`+[^`]+`+[^`]+)*`+[^`]*$/; // See https://spec.commonmark.org/0.29/#autolinks var emailAddressRe = // eslint-disable-next-line max-len @@ -3175,6 +3174,7 @@ module.exports = { var allowedElements = params.config.allowed_elements; allowedElements = Array.isArray(allowedElements) ? allowedElements : []; allowedElements = allowedElements.map(function (element) { return element.toLowerCase(); }); + var exclusions = inlineCodeSpanRanges(); forEachLine(lineMetadata(), function (line, lineIndex, inCode) { var match = null; // eslint-disable-next-line no-unmodified-loop-condition @@ -3182,12 +3182,12 @@ module.exports = { var tag = match[0], content = match[1], element = match[2]; if (!allowedElements.includes(element.toLowerCase()) && !tag.endsWith("\\>") && - !emailAddressRe.test(content)) { + !emailAddressRe.test(content) && + !overlapsAnyRange(exclusions, lineIndex, match.index, match[0].length)) { var prefix = line.substring(0, match.index); - if (!linkDestinationRe.test(prefix) && !inlineCodeRe.test(prefix)) { + if (!linkDestinationRe.test(prefix)) { var unescaped = unescapeMarkdown(prefix + "<", "_"); - if (!unescaped.endsWith("_") && - ((unescaped + "`").match(/`/g).length % 2)) { + if (!unescaped.endsWith("_")) { addError(onError, lineIndex + 1, "Element: " + element, null, [match.index + 1, tag.length]); } } diff --git a/lib/md033.js b/lib/md033.js index 9c002741..73737abe 100644 --- a/lib/md033.js +++ b/lib/md033.js @@ -2,12 +2,13 @@ "use strict"; -const { addError, forEachLine, unescapeMarkdown } = require("../helpers"); -const { lineMetadata } = require("./cache"); +const { + addError, forEachLine, overlapsAnyRange, unescapeMarkdown +} = require("../helpers"); +const { inlineCodeSpanRanges, lineMetadata } = require("./cache"); const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^>]*)?)\/?>/g; const linkDestinationRe = /]\(\s*$/; -const inlineCodeRe = /^[^`]*(`+[^`]+`+[^`]+)*`+[^`]*$/; // See https://spec.commonmark.org/0.29/#autolinks const emailAddressRe = // eslint-disable-next-line max-len @@ -21,19 +22,22 @@ module.exports = { let allowedElements = params.config.allowed_elements; allowedElements = Array.isArray(allowedElements) ? allowedElements : []; allowedElements = allowedElements.map((element) => element.toLowerCase()); + const exclusions = inlineCodeSpanRanges(); forEachLine(lineMetadata(), (line, lineIndex, inCode) => { let match = null; // eslint-disable-next-line no-unmodified-loop-condition while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) { const [ tag, content, element ] = match; - if (!allowedElements.includes(element.toLowerCase()) && + if ( + !allowedElements.includes(element.toLowerCase()) && !tag.endsWith("\\>") && - !emailAddressRe.test(content)) { + !emailAddressRe.test(content) && + !overlapsAnyRange(exclusions, lineIndex, match.index, match[0].length) + ) { const prefix = line.substring(0, match.index); - if (!linkDestinationRe.test(prefix) && !inlineCodeRe.test(prefix)) { + if (!linkDestinationRe.test(prefix)) { const unescaped = unescapeMarkdown(prefix + "<", "_"); - if (!unescaped.endsWith("_") && - ((unescaped + "`").match(/`/g).length % 2)) { + if (!unescaped.endsWith("_")) { addError(onError, lineIndex + 1, "Element: " + element, null, [ match.index + 1, tag.length ]); } diff --git a/test/inline_html.md b/test/inline_html.md index e76a4245..d70267b7 100644 --- a/test/inline_html.md +++ b/test/inline_html.md @@ -22,6 +22,63 @@ Text \` text `` text \` text `` text Text \`\` text `` text Text `` text \` text `` text +## Elements in multiple line code spans + +Text `code +` + +`code +` + +`code +` text + +Text `code +code + +` + +``code ``` ```` ` +code +`` + +Text `code + +code` text + +Text `code code +code ` text + +Text `code +code code` text + +Text `code code +code code +code code` text + +Text ````code code +code code +code code```` text + +Text `code code +code ` text +text `code code +code code` text + +Text `code code +code code` text +text `code code +code ` text + +Text `code code +code ` text +text `code code +code ` text + +Text `code code +code` text text `code {MD033} +code code` text + ## Slash in element name Text **\\another\directory\\** text