mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 22:10:13 +01:00
Add new MD054/link-image-style rule (in-progress PR, no generated files).
This commit is contained in:
parent
20b8af5054
commit
460836445c
14 changed files with 296 additions and 11 deletions
|
|
@ -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
134
lib/md054.js
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue