mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 22:10:13 +01:00
Update MD039/no-space-in-links to report separate errors for start and end spaces (more granular; avoids conflicts).
This commit is contained in:
parent
daa155d5a1
commit
a6cf08dfc6
5 changed files with 990 additions and 270 deletions
|
|
@ -5660,6 +5660,48 @@ const { addErrorContext } = __webpack_require__(/*! ../helpers */ "../helpers/he
|
||||||
const { filterByTypes } = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs");
|
const { filterByTypes } = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs");
|
||||||
const { referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
const { referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an error for a label space issue.
|
||||||
|
*
|
||||||
|
* @param {import("./markdownlint").RuleOnError} onError Error-reporting callback.
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} label Label token.
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
|
||||||
|
* @param {boolean} isStart True iff error is at the start of the link.
|
||||||
|
*/
|
||||||
|
function addLabelSpaceError(onError, label, labelText, isStart) {
|
||||||
|
const match = labelText.text.match(isStart ? /^[^\S\r\n]+/ : /[^\S\r\n]+$/);
|
||||||
|
const range = match ?
|
||||||
|
[
|
||||||
|
(isStart ? (labelText.startColumn) : (labelText.endColumn - match[0].length)),
|
||||||
|
match[0].length
|
||||||
|
] :
|
||||||
|
undefined;
|
||||||
|
addErrorContext(
|
||||||
|
onError,
|
||||||
|
isStart ? (labelText.startLine + (match ? 0 : 1)) : (labelText.endLine - (match ? 0 : 1)),
|
||||||
|
label.text.replace(/\s+/g, " "),
|
||||||
|
isStart,
|
||||||
|
!isStart,
|
||||||
|
range,
|
||||||
|
range ? {
|
||||||
|
"editColumn": range[0],
|
||||||
|
"deleteCount": range[1]
|
||||||
|
} : undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a link is a valid link (and not a fake shortcut link due to parser tricks).
|
||||||
|
*
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} label Label token.
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
|
||||||
|
* @param {Map<string, any>} definitions Map of link definitions.
|
||||||
|
* @returns {boolean} True iff the link is valid.
|
||||||
|
*/
|
||||||
|
function validLink(label, labelText, definitions) {
|
||||||
|
return (label.parent?.children.length !== 1) || definitions.has(labelText.text.trim());
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line jsdoc/valid-types
|
// eslint-disable-next-line jsdoc/valid-types
|
||||||
/** @type import("./markdownlint").Rule */
|
/** @type import("./markdownlint").Rule */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
@ -5674,44 +5716,22 @@ module.exports = {
|
||||||
[ "label" ]
|
[ "label" ]
|
||||||
).filter((label) => label.parent?.type === "link");
|
).filter((label) => label.parent?.type === "link");
|
||||||
for (const label of labels) {
|
for (const label of labels) {
|
||||||
const labelTexts = filterByTypes(label.children, [ "labelText" ]);
|
const labelTexts = filterByTypes(
|
||||||
|
label.children,
|
||||||
|
[ "labelText" ]
|
||||||
|
);
|
||||||
for (const labelText of labelTexts) {
|
for (const labelText of labelTexts) {
|
||||||
const leftSpace =
|
|
||||||
labelText.text.trimStart().length !== labelText.text.length;
|
|
||||||
const rightSpace =
|
|
||||||
labelText.text.trimEnd().length !== labelText.text.length;
|
|
||||||
if (
|
if (
|
||||||
(leftSpace || rightSpace) &&
|
(labelText.text.trimStart().length !== labelText.text.length) &&
|
||||||
// Ignore non-shortcut link content "[ text ]"
|
validLink(label, labelText, definitions)
|
||||||
((label.parent?.children.length !== 1) || definitions.has(labelText.text.trim()))
|
|
||||||
) {
|
) {
|
||||||
// eslint-disable-next-line no-undef-init
|
addLabelSpaceError(onError, label, labelText, true);
|
||||||
let range = undefined;
|
}
|
||||||
if (label.startLine === label.endLine) {
|
if (
|
||||||
const labelColumn = label.startColumn;
|
(labelText.text.trimEnd().length !== labelText.text.length) &&
|
||||||
const labelLength = label.endColumn - label.startColumn;
|
validLink(label, labelText, definitions)
|
||||||
range = [ labelColumn, labelLength ];
|
) {
|
||||||
}
|
addLabelSpaceError(onError, label, labelText, false);
|
||||||
// eslint-disable-next-line no-undef-init
|
|
||||||
let fixInfo = undefined;
|
|
||||||
if (labelText.startLine === labelText.endLine) {
|
|
||||||
const textColumn = labelText.startColumn;
|
|
||||||
const textLength = labelText.endColumn - labelText.startColumn;
|
|
||||||
fixInfo = {
|
|
||||||
"editColumn": textColumn,
|
|
||||||
"deleteCount": textLength,
|
|
||||||
"insertText": labelText.text.trim()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
addErrorContext(
|
|
||||||
onError,
|
|
||||||
labelText.startLine,
|
|
||||||
label.text.replace(/\s+/g, " "),
|
|
||||||
leftSpace,
|
|
||||||
rightSpace,
|
|
||||||
range,
|
|
||||||
fixInfo
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
90
lib/md039.js
90
lib/md039.js
|
|
@ -6,6 +6,48 @@ const { addErrorContext } = require("../helpers");
|
||||||
const { filterByTypes } = require("../helpers/micromark.cjs");
|
const { filterByTypes } = require("../helpers/micromark.cjs");
|
||||||
const { referenceLinkImageData } = require("./cache");
|
const { referenceLinkImageData } = require("./cache");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an error for a label space issue.
|
||||||
|
*
|
||||||
|
* @param {import("./markdownlint").RuleOnError} onError Error-reporting callback.
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} label Label token.
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
|
||||||
|
* @param {boolean} isStart True iff error is at the start of the link.
|
||||||
|
*/
|
||||||
|
function addLabelSpaceError(onError, label, labelText, isStart) {
|
||||||
|
const match = labelText.text.match(isStart ? /^[^\S\r\n]+/ : /[^\S\r\n]+$/);
|
||||||
|
const range = match ?
|
||||||
|
[
|
||||||
|
(isStart ? (labelText.startColumn) : (labelText.endColumn - match[0].length)),
|
||||||
|
match[0].length
|
||||||
|
] :
|
||||||
|
undefined;
|
||||||
|
addErrorContext(
|
||||||
|
onError,
|
||||||
|
isStart ? (labelText.startLine + (match ? 0 : 1)) : (labelText.endLine - (match ? 0 : 1)),
|
||||||
|
label.text.replace(/\s+/g, " "),
|
||||||
|
isStart,
|
||||||
|
!isStart,
|
||||||
|
range,
|
||||||
|
range ? {
|
||||||
|
"editColumn": range[0],
|
||||||
|
"deleteCount": range[1]
|
||||||
|
} : undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a link is a valid link (and not a fake shortcut link due to parser tricks).
|
||||||
|
*
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} label Label token.
|
||||||
|
* @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
|
||||||
|
* @param {Map<string, any>} definitions Map of link definitions.
|
||||||
|
* @returns {boolean} True iff the link is valid.
|
||||||
|
*/
|
||||||
|
function validLink(label, labelText, definitions) {
|
||||||
|
return (label.parent?.children.length !== 1) || definitions.has(labelText.text.trim());
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line jsdoc/valid-types
|
// eslint-disable-next-line jsdoc/valid-types
|
||||||
/** @type import("./markdownlint").Rule */
|
/** @type import("./markdownlint").Rule */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
@ -20,44 +62,22 @@ module.exports = {
|
||||||
[ "label" ]
|
[ "label" ]
|
||||||
).filter((label) => label.parent?.type === "link");
|
).filter((label) => label.parent?.type === "link");
|
||||||
for (const label of labels) {
|
for (const label of labels) {
|
||||||
const labelTexts = filterByTypes(label.children, [ "labelText" ]);
|
const labelTexts = filterByTypes(
|
||||||
|
label.children,
|
||||||
|
[ "labelText" ]
|
||||||
|
);
|
||||||
for (const labelText of labelTexts) {
|
for (const labelText of labelTexts) {
|
||||||
const leftSpace =
|
|
||||||
labelText.text.trimStart().length !== labelText.text.length;
|
|
||||||
const rightSpace =
|
|
||||||
labelText.text.trimEnd().length !== labelText.text.length;
|
|
||||||
if (
|
if (
|
||||||
(leftSpace || rightSpace) &&
|
(labelText.text.trimStart().length !== labelText.text.length) &&
|
||||||
// Ignore non-shortcut link content "[ text ]"
|
validLink(label, labelText, definitions)
|
||||||
((label.parent?.children.length !== 1) || definitions.has(labelText.text.trim()))
|
|
||||||
) {
|
) {
|
||||||
// eslint-disable-next-line no-undef-init
|
addLabelSpaceError(onError, label, labelText, true);
|
||||||
let range = undefined;
|
}
|
||||||
if (label.startLine === label.endLine) {
|
if (
|
||||||
const labelColumn = label.startColumn;
|
(labelText.text.trimEnd().length !== labelText.text.length) &&
|
||||||
const labelLength = label.endColumn - label.startColumn;
|
validLink(label, labelText, definitions)
|
||||||
range = [ labelColumn, labelLength ];
|
) {
|
||||||
}
|
addLabelSpaceError(onError, label, labelText, false);
|
||||||
// eslint-disable-next-line no-undef-init
|
|
||||||
let fixInfo = undefined;
|
|
||||||
if (labelText.startLine === labelText.endLine) {
|
|
||||||
const textColumn = labelText.startColumn;
|
|
||||||
const textLength = labelText.endColumn - labelText.startColumn;
|
|
||||||
fixInfo = {
|
|
||||||
"editColumn": textColumn,
|
|
||||||
"deleteCount": textLength,
|
|
||||||
"insertText": labelText.text.trim()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
addErrorContext(
|
|
||||||
onError,
|
|
||||||
labelText.startLine,
|
|
||||||
label.text.replace(/\s+/g, " "),
|
|
||||||
leftSpace,
|
|
||||||
rightSpace,
|
|
||||||
range,
|
|
||||||
fixInfo
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -48,11 +48,32 @@ function MoreCodeButNotCode(input) {
|
||||||
[with](spaces)
|
[with](spaces)
|
||||||
[error ]({MD039})
|
[error ]({MD039})
|
||||||
|
|
||||||
Wrapped [ link with leading space {MD039}
|
|
||||||
](https://example.com)
|
|
||||||
|
|
||||||
Non-wrapped [ link with leading space](https://example.com) {MD039}
|
Non-wrapped [ link with leading space](https://example.com) {MD039}
|
||||||
|
|
||||||
|
Non-wrapped [link with trailing space ](https://example.com) {MD039}
|
||||||
|
|
||||||
|
Non-wrapped [ link with leading and trailing space ](https://example.com) {MD039}
|
||||||
|
|
||||||
|
Wrapped [
|
||||||
|
link with leading space](https://example.com) {MD039}
|
||||||
|
|
||||||
|
Wrapped [
|
||||||
|
link with leading space](https://example.com) {MD009:-1} {MD039:-1}
|
||||||
|
|
||||||
|
Wrapped [link with trailing space
|
||||||
|
](https://example.com) {MD009:-1} {MD039:-1}
|
||||||
|
|
||||||
|
Wrapped [link with trailing space
|
||||||
|
](https://example.com) {MD039}
|
||||||
|
|
||||||
|
Wrapped [
|
||||||
|
link with leading and trailing space
|
||||||
|
](https://example.com) {MD009:-2} {MD039:-2} {MD039}
|
||||||
|
|
||||||
|
Wrapped [
|
||||||
|
link with leading and trailing space
|
||||||
|
](https://example.com) {MD009:-1} {MD039:-1}
|
||||||
|
|
||||||
[][ref]
|
[][ref]
|
||||||
|
|
||||||
[link][ref]
|
[link][ref]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue