Add new MD054/link-image-style rule (in-progress PR, no generated files).

This commit is contained in:
Tommy G 2023-10-24 21:07:46 -07:00 committed by David Anson
parent 20b8af5054
commit 460836445c
14 changed files with 296 additions and 11 deletions

View file

@ -8,7 +8,8 @@ module.exports.fixableRuleNames = [
"MD011", "MD012", "MD014", "MD018", "MD019", "MD020",
"MD021", "MD022", "MD023", "MD026", "MD027", "MD030",
"MD031", "MD032", "MD034", "MD037", "MD038", "MD039",
"MD044", "MD047", "MD049", "MD050", "MD051", "MD053"
"MD044", "MD047", "MD049", "MD050", "MD051", "MD053",
"MD054"
];
module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
module.exports.version = "0.31.1";

134
lib/md054.js Normal file
View file

@ -0,0 +1,134 @@
// @ts-check
"use strict";
const { addErrorContext } = require("../helpers");
const { filterByTypes, filterByPredicate, getTokenTextByType } =
require("../helpers/micromark.cjs");
const isInlineLink = ({ children }) => children.some(
({ type }) => type === "resource"
);
const isAutolink = ({ type }) => type === "autolink";
const getNestedTokenTextByType = (tokens, type) => getTokenTextByType(
filterByTypes(tokens, [ type ]),
type
);
const escapeParentheses = (unescaped) => unescaped
.replaceAll("(", "\\(")
.replaceAll(")", "\\)");
const escapeSquares = (unescaped) => unescaped
.replaceAll("[", "\\[")
.replaceAll("]", "\\]");
const escapeAngles = (unescaped) => unescaped
.replaceAll("<", "\\<")
.replaceAll(">", "\\>");
const unescapeParentheses = (escaped) => escaped
.replaceAll("\\(", "(")
.replaceAll("\\)", ")");
const unescapeAngles = (escaped) => escaped
.replaceAll("\\<", "<")
.replaceAll("\\>", ">");
const referenceLinkDestination = (link, tokens) => {
const reference = getNestedTokenTextByType([ link ], "reference");
const id = reference && reference !== "[]" ?
reference.replace(/^\[/, "").replace(/\]$/, "") :
getNestedTokenTextByType([ link ], "labelText");
const definition = filterByPredicate(
filterByTypes(tokens, [ "definition" ]),
(d) => getNestedTokenTextByType([ d ], "definitionLabelString") === id
);
return getNestedTokenTextByType(definition, "definitionDestination");
};
const inlineLinkDestination = (link) => {
const text = getNestedTokenTextByType([ link ], "resourceDestination");
return text && unescapeParentheses(text);
};
const autolinkDestination = (link) => {
const text = getNestedTokenTextByType([ link ], "autolinkProtocol");
return text && unescapeAngles(text);
};
const autolinkFixInfo = (tokens, link) => {
if (isAutolink(link)) {
return null;
}
const destination = isInlineLink(link) ?
inlineLinkDestination(link) :
referenceLinkDestination(link, tokens);
return {
"editColumn": link.startColumn,
"insertText": `<${escapeAngles(destination)}>`,
"deleteCount": link.endColumn - link.startColumn
};
};
const inlineFixInfo = (tokens, link) => {
if (isInlineLink(link)) {
return null;
}
const destination = isAutolink(link) ?
autolinkDestination(link) :
referenceLinkDestination(link, tokens);
return {
"editColumn": link.startColumn,
"insertText":
`[${escapeSquares(destination)}](${escapeParentheses(destination)})`,
"deleteCount": link.endColumn - link.startColumn
};
};
module.exports = {
"names": [ "MD054", "link-image-style" ],
"description": "Link and image style",
"tags": [ "images", "links" ],
"function": ({ parsers, config }, onError) => {
const style = String(config.style || "mixed");
const links = filterByTypes(
parsers.micromark.tokens,
[ "autolink", "link", "image" ]
);
for (const link of links) {
const inlineLink = isInlineLink(link);
const autolink = isAutolink(link);
const range = [ link.startColumn, link.endColumn - link.startColumn ];
let fixInfo = null;
if (style === "autolink_only") {
fixInfo = autolinkFixInfo(parsers.micromark.tokens, link);
} else if (style === "inline_only") {
fixInfo = inlineFixInfo(parsers.micromark.tokens, link);
}
if (
fixInfo ||
(style === "reference_only" && (inlineLink || autolink)) ||
(style === "inline_or_reference" && autolink) ||
(style === "inline_or_autolink" && !(inlineLink || autolink)) ||
(style === "reference_or_autolink" && inlineLink)
) {
addErrorContext(
onError,
link.startLine,
link.text,
null,
null,
range,
fixInfo
);
}
}
}
};

View file

@ -52,7 +52,8 @@ const rules = [
...require("./md049-md050"),
require("./md051"),
require("./md052"),
require("./md053")
require("./md053"),
require("./md054")
];
for (const rule of rules) {
const name = rule.names[0].toLowerCase();