2018-01-21 21:44:25 -08:00
|
|
|
// @ts-check
|
|
|
|
|
2024-11-28 20:36:44 -08:00
|
|
|
import { addErrorContext } from "../helpers/helpers.cjs";
|
|
|
|
import { filterByPredicate, getHtmlTagInfo, inHtmlFlow } from "../helpers/micromark-helpers.cjs";
|
2018-01-21 21:44:25 -08:00
|
|
|
|
2024-11-28 20:36:44 -08:00
|
|
|
/** @typedef {import("micromark-extension-gfm-autolink-literal")} */
|
2022-11-13 21:39:14 -08:00
|
|
|
|
2024-12-03 19:58:28 -08:00
|
|
|
/** @type {import("markdownlint").Rule} */
|
2024-11-28 20:36:44 -08:00
|
|
|
export default {
|
2018-01-21 21:44:25 -08:00
|
|
|
"names": [ "MD034", "no-bare-urls" ],
|
|
|
|
"description": "Bare URL used",
|
|
|
|
"tags": [ "links", "url" ],
|
2024-03-09 16:17:50 -08:00
|
|
|
"parser": "micromark",
|
2018-01-21 21:44:25 -08:00
|
|
|
"function": function MD034(params, onError) {
|
2023-10-23 20:55:37 -07:00
|
|
|
const literalAutolinks = (tokens) => (
|
|
|
|
filterByPredicate(
|
|
|
|
tokens,
|
2024-03-03 19:06:14 -08:00
|
|
|
(token) => {
|
|
|
|
if ((token.type === "literalAutolink") && !inHtmlFlow(token)) {
|
|
|
|
// Detect and ignore https://github.com/micromark/micromark/issues/164
|
|
|
|
const siblings = token.parent?.children;
|
|
|
|
const index = siblings?.indexOf(token);
|
|
|
|
// @ts-ignore
|
|
|
|
const prev = siblings?.at(index - 1);
|
|
|
|
// @ts-ignore
|
|
|
|
const next = siblings?.at(index + 1);
|
|
|
|
return !(
|
|
|
|
prev &&
|
|
|
|
next &&
|
|
|
|
(prev.type === "data") &&
|
|
|
|
(next.type === "data") &&
|
|
|
|
prev.text.endsWith("<") &&
|
|
|
|
next.text.startsWith(">")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
2023-10-23 20:55:37 -07:00
|
|
|
(token) => {
|
2024-10-21 20:56:22 -07:00
|
|
|
// Ignore content of inline HTML tags
|
2023-10-23 20:55:37 -07:00
|
|
|
const { children } = token;
|
|
|
|
const result = [];
|
|
|
|
for (let i = 0; i < children.length; i++) {
|
|
|
|
const current = children[i];
|
|
|
|
const openTagInfo = getHtmlTagInfo(current);
|
|
|
|
if (openTagInfo && !openTagInfo.close) {
|
|
|
|
let count = 1;
|
|
|
|
for (let j = i + 1; j < children.length; j++) {
|
|
|
|
const candidate = children[j];
|
|
|
|
const closeTagInfo = getHtmlTagInfo(candidate);
|
|
|
|
if (closeTagInfo && (openTagInfo.name === closeTagInfo.name)) {
|
|
|
|
if (closeTagInfo.close) {
|
|
|
|
count--;
|
|
|
|
if (count === 0) {
|
|
|
|
i = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
count++;
|
|
|
|
}
|
2023-02-05 16:58:06 -08:00
|
|
|
}
|
|
|
|
}
|
2023-10-23 20:55:37 -07:00
|
|
|
} else {
|
|
|
|
result.push(current);
|
2023-02-05 16:58:06 -08:00
|
|
|
}
|
2019-09-22 21:31:02 -07:00
|
|
|
}
|
2023-10-23 20:55:37 -07:00
|
|
|
return result;
|
2023-05-23 04:01:55 +00:00
|
|
|
}
|
2023-10-23 20:55:37 -07:00
|
|
|
)
|
|
|
|
);
|
2024-10-21 20:56:22 -07:00
|
|
|
for (const token of literalAutolinks(params.parsers.micromark.tokens)) {
|
|
|
|
const range = [
|
|
|
|
token.startColumn,
|
|
|
|
token.endColumn - token.startColumn
|
|
|
|
];
|
|
|
|
const fixInfo = {
|
|
|
|
"editColumn": range[0],
|
|
|
|
"deleteCount": range[1],
|
|
|
|
"insertText": `<${token.text}>`
|
|
|
|
};
|
|
|
|
addErrorContext(
|
|
|
|
onError,
|
|
|
|
token.startLine,
|
|
|
|
token.text,
|
|
|
|
undefined,
|
|
|
|
undefined,
|
|
|
|
range,
|
|
|
|
fixInfo
|
|
|
|
);
|
2022-12-06 22:14:40 -08:00
|
|
|
}
|
2018-01-21 21:44:25 -08:00
|
|
|
}
|
|
|
|
};
|