first commit
This commit is contained in:
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce reference-style links when URL matches a defined identifier.
|
||||
* @author TKDev7
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// Imports
|
||||
//-----------------------------------------------------------------------------
|
||||
import { normalizeIdentifier } from "micromark-util-normalize-identifier";
|
||||
//-----------------------------------------------------------------------------
|
||||
// Type Definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* @import { Image, Link } from "mdast";
|
||||
* @import { MarkdownRuleDefinition } from "../types.js";
|
||||
* @typedef {"referenceLikeUrl"} NoReferenceLikeUrlsMessageIds
|
||||
* @typedef {[]} NoReferenceLikeUrlsOptions
|
||||
* @typedef {MarkdownRuleDefinition<{ RuleOptions: NoReferenceLikeUrlsOptions, MessageIds: NoReferenceLikeUrlsMessageIds }>} NoReferenceLikeUrlsRuleDefinition
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Pattern to match both inline links: `[text](url)` and images: ``, with optional title */
|
||||
const linkOrImagePattern = /\[(?<label>(?:\\.|[^()\\]|\([\s\S]*\))*?)\]\((?<destination>[ \t]*\r?\n?(?<![ \t])[ \t]*(?:<[^>]*>|[^ \t()]+))(?:[ \t]*\r?\n?(?<![ \t])[ \t]*(?:"[^"]*"|'[^']*'|\([^)]*\)))?[ \t]*\r?\n?(?<![ \t])[ \t]*\)$/u;
|
||||
//-----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//-----------------------------------------------------------------------------
|
||||
export default /** @satisfies {NoReferenceLikeUrlsRuleDefinition} */ ({
|
||||
meta: {
|
||||
type: "problem",
|
||||
docs: {
|
||||
recommended: true,
|
||||
description: "Disallow URLs that match defined reference identifiers",
|
||||
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-reference-like-urls.md",
|
||||
},
|
||||
fixable: "code",
|
||||
messages: {
|
||||
referenceLikeUrl: "Unexpected resource {{type}} ('{{prefix}}[text](url)') with URL that matches a definition identifier. Use '[text][id]' syntax instead.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const { sourceCode } = context;
|
||||
/** @type {Set<string>} */
|
||||
const definitionIdentifiers = new Set();
|
||||
/** @type {Array<Image | Link>} */
|
||||
const relevantNodes = [];
|
||||
return {
|
||||
definition(node) {
|
||||
definitionIdentifiers.add(node.identifier);
|
||||
},
|
||||
"image, link"(/** @type {Image | Link} */ node) {
|
||||
relevantNodes.push(node);
|
||||
},
|
||||
"root:exit"() {
|
||||
for (const node of relevantNodes) {
|
||||
const text = sourceCode.getText(node);
|
||||
const match = linkOrImagePattern.exec(text);
|
||||
if (match !== null) {
|
||||
const { label, destination } = match.groups;
|
||||
const { type, title } = node;
|
||||
const prefix = type === "image" ? "!" : "";
|
||||
const url = normalizeIdentifier(destination).toLowerCase();
|
||||
if (definitionIdentifiers.has(url)) {
|
||||
context.report({
|
||||
loc: node.position,
|
||||
messageId: "referenceLikeUrl",
|
||||
data: {
|
||||
type,
|
||||
prefix,
|
||||
},
|
||||
fix(fixer) {
|
||||
// The AST treats both missing and empty titles as null, so it's safe to auto-fix in both cases.
|
||||
if (title) {
|
||||
return null;
|
||||
}
|
||||
return fixer.replaceText(node, `${prefix}[${label}][${destination}]`);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user