mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 14:00:13 +01:00
Update new rule MD059/descriptive-link-text for project-level consistency.
This commit is contained in:
parent
b8374ec5d2
commit
571c2353ea
23 changed files with 466 additions and 383 deletions
8
lib/configuration-strict.d.ts
vendored
8
lib/configuration-strict.d.ts
vendored
|
|
@ -1107,9 +1107,9 @@ export interface ConfigurationStrict {
|
|||
| boolean
|
||||
| {
|
||||
/**
|
||||
* List of restricted link texts
|
||||
* Prohibited link texts
|
||||
*/
|
||||
link_texts?: string[];
|
||||
prohibited_texts?: string[];
|
||||
};
|
||||
/**
|
||||
* MD059/descriptive-link-text : Link text should be descriptive : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md059.md
|
||||
|
|
@ -1118,9 +1118,9 @@ export interface ConfigurationStrict {
|
|||
| boolean
|
||||
| {
|
||||
/**
|
||||
* List of restricted link texts
|
||||
* Prohibited link texts
|
||||
*/
|
||||
link_texts?: string[];
|
||||
prohibited_texts?: string[];
|
||||
};
|
||||
/**
|
||||
* headings : MD001, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// @ts-check
|
||||
|
||||
import { addErrorContext, newLineRe } from "../helpers/helpers.cjs";
|
||||
import { addErrorContext } from "../helpers/helpers.cjs";
|
||||
import { getDescendantsByType } from "../helpers/micromark-helpers.cjs";
|
||||
import { filterByTypesCached } from "./cache.mjs";
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ export default {
|
|||
const endSpaces = endCount > 0;
|
||||
// Check if safe to remove 1-space padding
|
||||
const removePadding = startSpaces && endSpaces && startPadding && endPadding && !startBacktick && !endBacktick;
|
||||
const context = codeText.text.replace(newLineRe, "\n");
|
||||
const context = codeText.text;
|
||||
// If extra space at start, report violation
|
||||
if (startSpaces) {
|
||||
const startColumn = (removePadding ? startPadding : startData).startColumn;
|
||||
|
|
|
|||
|
|
@ -1,28 +1,33 @@
|
|||
// @ts-check
|
||||
|
||||
import { addErrorContext } from "../helpers/helpers.cjs";
|
||||
import { getDescendantsByType } from "../helpers/micromark-helpers.cjs";
|
||||
import { filterByTypesCached } from "./cache.mjs";
|
||||
|
||||
const defaultBannedText = [
|
||||
/** @typedef {import("markdownlint").MicromarkTokenType} MicromarkTokenType */
|
||||
/** @type {Set<MicromarkTokenType>} */
|
||||
const allowedChildrenTypes = new Set([
|
||||
"codeText",
|
||||
"htmlText"
|
||||
]);
|
||||
const defaultProhibitedTexts = [
|
||||
"click here",
|
||||
"here",
|
||||
"learn more",
|
||||
"link",
|
||||
"more",
|
||||
"read more"
|
||||
"more"
|
||||
];
|
||||
|
||||
/**
|
||||
* Normalizes a string and removes extra whitespaces and punctuations.
|
||||
* Normalizes a string by removing extra whitespaces and punctuation.
|
||||
*
|
||||
* @param {string} text String to transform.
|
||||
* @returns {string} Normalized string with no punctuations or extra whitespaces.
|
||||
* @param {string} str String to normalize.
|
||||
* @returns {string} Normalized string.
|
||||
*/
|
||||
function normalizeText(text) {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(/\W+/g, " ")
|
||||
function normalize(str) {
|
||||
return str
|
||||
.replace(/[\W_]+/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.toLowerCase()
|
||||
.trim();
|
||||
}
|
||||
|
||||
|
|
@ -30,29 +35,35 @@ function normalizeText(text) {
|
|||
export default {
|
||||
"names": [ "MD059", "descriptive-link-text" ],
|
||||
"description": "Link text should be descriptive",
|
||||
"tags": [ "links", "accessibility" ],
|
||||
"tags": [ "accessibility", "links" ],
|
||||
"parser": "micromark",
|
||||
"function": function MD059(params, onError) {
|
||||
const bannedNames = new Set(params.config.link_texts || defaultBannedText);
|
||||
const labels = filterByTypesCached([ "label" ])
|
||||
.filter((label) => label.parent?.type === "link");
|
||||
|
||||
for (const label of labels) {
|
||||
const labelTexts = label.children.filter((child) => child.type === "labelText");
|
||||
for (const labelText of labelTexts) {
|
||||
const { text } = label;
|
||||
if (bannedNames.has(normalizeText(text))) {
|
||||
const range = labelText.startLine === labelText.endLine ?
|
||||
[ labelText.startColumn, text.length ] :
|
||||
undefined;
|
||||
addErrorContext(
|
||||
onError,
|
||||
labelText.startLine,
|
||||
text,
|
||||
undefined,
|
||||
undefined,
|
||||
range
|
||||
);
|
||||
const prohibitedTexts = new Set(
|
||||
(params.config.prohibited_texts || defaultProhibitedTexts).map(normalize)
|
||||
);
|
||||
if (prohibitedTexts.size > 0) {
|
||||
const links = filterByTypesCached([ "link" ]);
|
||||
for (const link of links) {
|
||||
const labelTexts = getDescendantsByType(link, [ "label", "labelText" ]);
|
||||
for (const labelText of labelTexts) {
|
||||
const { children, endColumn, endLine, parent, startColumn, startLine, text } = labelText;
|
||||
if (
|
||||
!children.some((child) => allowedChildrenTypes.has(child.type)) &&
|
||||
prohibitedTexts.has(normalize(text))
|
||||
) {
|
||||
const range = (startLine === endLine) ?
|
||||
[ startColumn, endColumn - startColumn ] :
|
||||
undefined;
|
||||
addErrorContext(
|
||||
onError,
|
||||
startLine,
|
||||
// @ts-ignore
|
||||
parent.text,
|
||||
undefined,
|
||||
undefined,
|
||||
range
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue