Update MD034/no-bare-urls to scan all tokens when pruning HTML content so open/close pairs with different parents are handled (fixes #966).

This commit is contained in:
David Anson 2023-09-13 22:44:15 -07:00
parent de5fa400e7
commit daec896b8d
5 changed files with 100 additions and 60 deletions

View file

@ -5057,6 +5057,7 @@ var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
addErrorContext = _require.addErrorContext; addErrorContext = _require.addErrorContext;
var _require2 = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs"), var _require2 = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs"),
filterByPredicate = _require2.filterByPredicate, filterByPredicate = _require2.filterByPredicate,
filterByTypes = _require2.filterByTypes,
getHtmlTagInfo = _require2.getHtmlTagInfo, getHtmlTagInfo = _require2.getHtmlTagInfo,
parse = _require2.parse; parse = _require2.parse;
module.exports = { module.exports = {
@ -5065,39 +5066,40 @@ module.exports = {
"tags": ["links", "url"], "tags": ["links", "url"],
"function": function MD034(params, onError) { "function": function MD034(params, onError) {
var literalAutolinks = function literalAutolinks(tokens) { var literalAutolinks = function literalAutolinks(tokens) {
return filterByPredicate(tokens, function (token) { var flattened = filterByPredicate(tokens, function () {
return token.type === "literalAutolink"; return true;
}, function (token) { });
var children = token.children; var result = [];
var result = []; for (var i = 0; i < flattened.length; i++) {
for (var i = 0; i < children.length; i++) { var current = flattened[i];
var openToken = children[i]; var openTagInfo = getHtmlTagInfo(current);
var openTagInfo = getHtmlTagInfo(openToken); if (openTagInfo && !openTagInfo.close) {
if (openTagInfo && !openTagInfo.close) { var count = 1;
var count = 1; for (var j = i + 1; j < flattened.length; j++) {
for (var j = i + 1; j < children.length; j++) { var candidate = flattened[j];
var closeToken = children[j]; var closeTagInfo = getHtmlTagInfo(candidate);
var closeTagInfo = getHtmlTagInfo(closeToken); if (closeTagInfo && openTagInfo.name === closeTagInfo.name) {
if (closeTagInfo && openTagInfo.name === closeTagInfo.name) { if (closeTagInfo.close) {
if (closeTagInfo.close) { count--;
count--; if (count === 0) {
if (count === 0) { i = j;
i = j; break;
break;
}
} else {
count++;
} }
} else {
count++;
} }
} }
} else {
result.push(openToken);
} }
} else {
result.push(current);
} }
return result; }
return result.filter(function (token) {
return token.type === "literalAutolink";
}); });
}; };
if (literalAutolinks(params.parsers.micromark.tokens).length > 0) { var autoLinks = filterByTypes(params.parsers.micromark.tokens, ["literalAutolink"]);
if (autoLinks.length > 0) {
// Re-parse with correct link/image reference definition handling // Re-parse with correct link/image reference definition handling
var document = params.lines.join("\n"); var document = params.lines.join("\n");
var tokens = parse(document, undefined, false); var tokens = parse(document, undefined, false);

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByPredicate, getHtmlTagInfo, parse } = const { filterByPredicate, filterByTypes, getHtmlTagInfo, parse } =
require("../helpers/micromark.cjs"); require("../helpers/micromark.cjs");
module.exports = { module.exports = {
@ -11,42 +11,40 @@ module.exports = {
"description": "Bare URL used", "description": "Bare URL used",
"tags": [ "links", "url" ], "tags": [ "links", "url" ],
"function": function MD034(params, onError) { "function": function MD034(params, onError) {
const literalAutolinks = (tokens) => ( const literalAutolinks = (tokens) => {
filterByPredicate( const flattened = filterByPredicate(tokens, () => true);
tokens, const result = [];
(token) => token.type === "literalAutolink", for (let i = 0; i < flattened.length; i++) {
(token) => { const current = flattened[i];
const { children } = token; const openTagInfo = getHtmlTagInfo(current);
const result = []; if (openTagInfo && !openTagInfo.close) {
for (let i = 0; i < children.length; i++) { let count = 1;
const openToken = children[i]; for (let j = i + 1; j < flattened.length; j++) {
const openTagInfo = getHtmlTagInfo(openToken); const candidate = flattened[j];
if (openTagInfo && !openTagInfo.close) { const closeTagInfo = getHtmlTagInfo(candidate);
let count = 1; if (closeTagInfo && (openTagInfo.name === closeTagInfo.name)) {
for (let j = i + 1; j < children.length; j++) { if (closeTagInfo.close) {
const closeToken = children[j]; count--;
const closeTagInfo = getHtmlTagInfo(closeToken); if (count === 0) {
if (closeTagInfo && (openTagInfo.name === closeTagInfo.name)) { i = j;
if (closeTagInfo.close) { break;
count--;
if (count === 0) {
i = j;
break;
}
} else {
count++;
}
} }
} else {
count++;
} }
} else {
result.push(openToken);
} }
} }
return result; } else {
result.push(current);
} }
) }
return result.filter((token) => token.type === "literalAutolink");
};
const autoLinks = filterByTypes(
params.parsers.micromark.tokens,
[ "literalAutolink" ]
); );
if (literalAutolinks(params.parsers.micromark.tokens).length > 0) { if (autoLinks.length > 0) {
// Re-parse with correct link/image reference definition handling // Re-parse with correct link/image reference definition handling
const document = params.lines.join("\n"); const document = params.lines.join("\n");
const tokens = parse(document, undefined, false); const tokens = parse(document, undefined, false);

View file

@ -59,6 +59,26 @@ https://example.com
<pre>https://example.com</pre> <pre>https://example.com</pre>
</p> </p>
<div>
https://example.com
</div>
<div>
https://example.com
</div>
<div>
https://example.com
</div>
<div>
https://example.com
</div>
URLs in link and image text are not bare: URLs in link and image text are not bare:
Text [link to https://example.com site](https://example.com) text. Text [link to https://example.com site](https://example.com) text.

View file

@ -3526,7 +3526,7 @@ Generated by [AVA](https://avajs.dev).
editColumn: 27, editColumn: 27,
insertText: '<https://example.com#heading->', insertText: '<https://example.com#heading->',
}, },
lineNumber: 68, lineNumber: 88,
ruleDescription: 'Bare URL used', ruleDescription: 'Bare URL used',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md034.md', ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md034.md',
ruleNames: [ ruleNames: [
@ -3546,7 +3546,7 @@ Generated by [AVA](https://avajs.dev).
editColumn: 40, editColumn: 40,
insertText: '<user@example.com>', insertText: '<user@example.com>',
}, },
lineNumber: 76, lineNumber: 96,
ruleDescription: 'Bare URL used', ruleDescription: 'Bare URL used',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md034.md', ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md034.md',
ruleNames: [ ruleNames: [
@ -3566,7 +3566,7 @@ Generated by [AVA](https://avajs.dev).
editColumn: 59, editColumn: 59,
insertText: '<https://example.com>', insertText: '<https://example.com>',
}, },
lineNumber: 84, lineNumber: 104,
ruleDescription: 'Bare URL used', ruleDescription: 'Bare URL used',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md034.md', ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md034.md',
ruleNames: [ ruleNames: [
@ -3636,6 +3636,26 @@ Generated by [AVA](https://avajs.dev).
<pre>https://example.com</pre> <pre>https://example.com</pre>
</p> </p>
<div>
https://example.com␊
</div>
<div>
https://example.com␊
</div>
<div>
https://example.com␊
</div>
<div>
https://example.com␊
</div>
URLs in link and image text are not bare:␊ URLs in link and image text are not bare:␊
Text [link to https://example.com site](https://example.com) text.␊ Text [link to https://example.com site](https://example.com) text.␊