eslint-markdown 0.17.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/core/constants.d.ts +21 -1
- package/build/core/constants.js +28 -13
- package/build/rules/index.d.ts +1 -1
- package/build/rules/no-double-punctuation.d.ts +1 -1
- package/build/rules/no-double-punctuation.js +5 -3
- package/build/rules/no-shell-dollar.js +2 -4
- package/build/rules/no-trailing-heading-punctuation.js +12 -4
- package/build/rules/require-image-title.js +17 -3
- package/build/rules/require-link-title.js +10 -3
- package/package.json +1 -1
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
* @fileoverview This file declares constants used throughout the `eslint-markdown` package.
|
|
3
3
|
*/
|
|
4
4
|
export declare const URL_RULE_DOCS: (ruleName?: string) => string;
|
|
5
|
+
/**
|
|
6
|
+
* ASCII punctuation characters.
|
|
7
|
+
*/
|
|
8
|
+
export declare const asciiPunctuation: readonly [".", ",", ";", ":", "!"];
|
|
9
|
+
/**
|
|
10
|
+
* ASCII punctuation characters including the question mark.
|
|
11
|
+
*/
|
|
12
|
+
export declare const asciiPunctuationWithQuestionMark: readonly [".", ",", ";", ":", "!", "?"];
|
|
13
|
+
/**
|
|
14
|
+
* Non-ASCII punctuation characters.
|
|
15
|
+
*/
|
|
16
|
+
export declare const nonAsciiPunctuation: readonly ["。", ",", ";", ":", "!"];
|
|
17
|
+
/**
|
|
18
|
+
* Non-ASCII punctuation characters including the question mark.
|
|
19
|
+
*/
|
|
20
|
+
export declare const nonAsciiPunctuationWithQuestionMark: readonly ["。", ",", ";", ":", "!", "?"];
|
|
5
21
|
/**
|
|
6
22
|
* This pattern is based on the punctuation list used by `markdownlint` and `remark-lint`.
|
|
7
23
|
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L41
|
|
@@ -13,7 +29,11 @@ export declare const punctuation: readonly [".", ",", ";", ":", "!", "。", ",
|
|
|
13
29
|
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L41
|
|
14
30
|
* @see https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-punctuation#parameters
|
|
15
31
|
*/
|
|
16
|
-
export declare const punctuationWithQuestionMark: readonly [".", ",", ";", ":", "!", "。", ",", ";", ":", "!", "
|
|
32
|
+
export declare const punctuationWithQuestionMark: readonly [".", ",", ";", ":", "!", "?", "。", ",", ";", ":", "!", "?"];
|
|
33
|
+
/**
|
|
34
|
+
* Regular expression for identifying an odd-length run of backslashes at the end of a string.
|
|
35
|
+
*/
|
|
36
|
+
export declare const escapedTrailingBackslashRegex: RegExp;
|
|
17
37
|
/**
|
|
18
38
|
* Regular expression for identifying a GitHub emoji code.
|
|
19
39
|
* - NOTE: These patterns are based on the `markdownlint`.
|
package/build/core/constants.js
CHANGED
|
@@ -11,33 +11,48 @@ import pkg from '../../package.json' with { type: 'json' };
|
|
|
11
11
|
export const URL_RULE_DOCS = (ruleName = '') => `${pkg.homepage}/docs/rules/${ruleName}`;
|
|
12
12
|
// --------------------------------------------------------------------------------
|
|
13
13
|
// #region array
|
|
14
|
+
/**
|
|
15
|
+
* ASCII punctuation characters.
|
|
16
|
+
*/
|
|
17
|
+
export const asciiPunctuation = ['.', ',', ';', ':', '!'];
|
|
18
|
+
/**
|
|
19
|
+
* ASCII punctuation characters including the question mark.
|
|
20
|
+
*/
|
|
21
|
+
export const asciiPunctuationWithQuestionMark = [...asciiPunctuation, '?'];
|
|
22
|
+
/**
|
|
23
|
+
* Non-ASCII punctuation characters.
|
|
24
|
+
*/
|
|
25
|
+
export const nonAsciiPunctuation = ['。', ',', ';', ':', '!'];
|
|
26
|
+
/**
|
|
27
|
+
* Non-ASCII punctuation characters including the question mark.
|
|
28
|
+
*/
|
|
29
|
+
export const nonAsciiPunctuationWithQuestionMark = [
|
|
30
|
+
...nonAsciiPunctuation,
|
|
31
|
+
'?',
|
|
32
|
+
];
|
|
14
33
|
/**
|
|
15
34
|
* This pattern is based on the punctuation list used by `markdownlint` and `remark-lint`.
|
|
16
35
|
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L41
|
|
17
36
|
* @see https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-punctuation#parameters
|
|
18
37
|
*/
|
|
19
|
-
export const punctuation = [
|
|
20
|
-
'.',
|
|
21
|
-
',',
|
|
22
|
-
';',
|
|
23
|
-
':',
|
|
24
|
-
'!',
|
|
25
|
-
'。',
|
|
26
|
-
',',
|
|
27
|
-
';',
|
|
28
|
-
':',
|
|
29
|
-
'!',
|
|
30
|
-
];
|
|
38
|
+
export const punctuation = [...asciiPunctuation, ...nonAsciiPunctuation];
|
|
31
39
|
/**
|
|
32
40
|
* This pattern is based on the punctuation list used by `markdownlint` and `remark-lint`.
|
|
33
41
|
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L41
|
|
34
42
|
* @see https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-punctuation#parameters
|
|
35
43
|
*/
|
|
36
|
-
export const punctuationWithQuestionMark = [
|
|
44
|
+
export const punctuationWithQuestionMark = [
|
|
45
|
+
...asciiPunctuationWithQuestionMark,
|
|
46
|
+
...nonAsciiPunctuationWithQuestionMark,
|
|
47
|
+
];
|
|
37
48
|
// #endregion array
|
|
38
49
|
// --------------------------------------------------------------------------------
|
|
39
50
|
// --------------------------------------------------------------------------------
|
|
40
51
|
// #region regex
|
|
52
|
+
/**
|
|
53
|
+
* Regular expression for identifying an odd-length run of backslashes at the end of a string.
|
|
54
|
+
*/
|
|
55
|
+
export const escapedTrailingBackslashRegex = /(?<=(?<!\\)(?:\\{2})*)\\$/u;
|
|
41
56
|
/**
|
|
42
57
|
* Regular expression for identifying a GitHub emoji code.
|
|
43
58
|
* - NOTE: These patterns are based on the `markdownlint`.
|
package/build/rules/index.d.ts
CHANGED
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
// --------------------------------------------------------------------------------
|
|
6
6
|
// Import
|
|
7
7
|
// --------------------------------------------------------------------------------
|
|
8
|
-
import {
|
|
8
|
+
import { escapeStringRegexp } from '../core/utils/index.js';
|
|
9
|
+
import { URL_RULE_DOCS, asciiPunctuationWithQuestionMark } from '../core/constants.js';
|
|
9
10
|
// --------------------------------------------------------------------------------
|
|
10
11
|
// Helper
|
|
11
12
|
// --------------------------------------------------------------------------------
|
|
13
|
+
const escapedAsciiPunctuationWithQuestionMark = escapeStringRegexp(asciiPunctuationWithQuestionMark.join(''));
|
|
12
14
|
/**
|
|
13
15
|
* This pattern is based on the punctuation list used by `remark-lint`.
|
|
14
16
|
* @see https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-punctuation#parameters
|
|
15
17
|
*/
|
|
16
|
-
const doublePunctuationRegex =
|
|
18
|
+
const doublePunctuationRegex = new RegExp(`(?:^|(?<=[^${escapedAsciiPunctuationWithQuestionMark}]))[${escapedAsciiPunctuationWithQuestionMark}]{2}(?:$|(?=[^${escapedAsciiPunctuationWithQuestionMark}]))`, 'g');
|
|
17
19
|
// --------------------------------------------------------------------------------
|
|
18
20
|
// Rule Definition
|
|
19
21
|
// --------------------------------------------------------------------------------
|
|
@@ -38,7 +40,7 @@ export default {
|
|
|
38
40
|
type: 'string',
|
|
39
41
|
minLength: 2,
|
|
40
42
|
maxLength: 2,
|
|
41
|
-
pattern:
|
|
43
|
+
pattern: `^[${escapedAsciiPunctuationWithQuestionMark}]{2}$`,
|
|
42
44
|
},
|
|
43
45
|
uniqueItems: true,
|
|
44
46
|
},
|
|
@@ -7,13 +7,12 @@
|
|
|
7
7
|
// Import
|
|
8
8
|
// --------------------------------------------------------------------------------
|
|
9
9
|
import { getCodeStyle, isBlankLine } from '../core/utils/index.js';
|
|
10
|
-
import { URL_RULE_DOCS } from '../core/constants.js';
|
|
10
|
+
import { URL_RULE_DOCS, escapedTrailingBackslashRegex } from '../core/constants.js';
|
|
11
11
|
// --------------------------------------------------------------------------------
|
|
12
12
|
// Helper
|
|
13
13
|
// --------------------------------------------------------------------------------
|
|
14
14
|
const dollarCommandRegex = /^[ \t]*\$[ \t]+/u;
|
|
15
15
|
const promptRegex = /\$[ \t]+/u;
|
|
16
|
-
const trailingBackslashRegex = /\\+$/u;
|
|
17
16
|
const lineEndingRegex = /\r\n|[\r\n]/u;
|
|
18
17
|
// --------------------------------------------------------------------------------
|
|
19
18
|
// Rule Definition
|
|
@@ -89,8 +88,7 @@ export default {
|
|
|
89
88
|
const endOffset = startOffset + match[0].length;
|
|
90
89
|
promptRanges.push([startOffset, endOffset]);
|
|
91
90
|
}
|
|
92
|
-
isPreviousLineContinues =
|
|
93
|
-
(trailingBackslashRegex.exec(codeLine)?.[0].length ?? 0) % 2 === 1;
|
|
91
|
+
isPreviousLineContinues = escapedTrailingBackslashRegex.test(codeLine);
|
|
94
92
|
}
|
|
95
93
|
for (const [startOffset, endOffset] of promptRanges) {
|
|
96
94
|
context.report({
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Import
|
|
7
7
|
// --------------------------------------------------------------------------------
|
|
8
8
|
import { escapeStringRegexp } from '../core/utils/index.js';
|
|
9
|
-
import { URL_RULE_DOCS, punctuation as defaultPunctuation, gemojiRegex, } from '../core/constants.js';
|
|
9
|
+
import { URL_RULE_DOCS, punctuation as defaultPunctuation, escapedTrailingBackslashRegex, gemojiRegex, } from '../core/constants.js';
|
|
10
10
|
// --------------------------------------------------------------------------------
|
|
11
11
|
// Helper
|
|
12
12
|
// --------------------------------------------------------------------------------
|
|
@@ -65,7 +65,7 @@ export default {
|
|
|
65
65
|
create(context) {
|
|
66
66
|
const { sourceCode } = context;
|
|
67
67
|
const [{ punctuation }] = context.options;
|
|
68
|
-
const trailingPunctuationRegex = new RegExp(`[ \\t\\r\\n]*[${escapeStringRegexp(punctuation.join(''))}]+$`);
|
|
68
|
+
const trailingPunctuationRegex = new RegExp(`(?<leadingSpaces>[ \\t\\r\\n]*)[${escapeStringRegexp(punctuation.join(''))}]+$`);
|
|
69
69
|
return {
|
|
70
70
|
heading(node) {
|
|
71
71
|
/*
|
|
@@ -128,9 +128,10 @@ export default {
|
|
|
128
128
|
}
|
|
129
129
|
const lastChildText = sourceCode.getText(lastChildNode);
|
|
130
130
|
const match = trailingPunctuationRegex.exec(lastChildText);
|
|
131
|
-
if (!match) {
|
|
131
|
+
if (!match || !match.groups) {
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
|
+
const { leadingSpaces } = match.groups;
|
|
134
135
|
let trailingPunctuation = match[0];
|
|
135
136
|
/*
|
|
136
137
|
* Slice from the beginning of the trailing `text` node through the first
|
|
@@ -176,7 +177,14 @@ export default {
|
|
|
176
177
|
},
|
|
177
178
|
messageId: 'noTrailingHeadingPunctuation',
|
|
178
179
|
fix(fixer) {
|
|
179
|
-
return fixer.removeRange([
|
|
180
|
+
return fixer.removeRange([
|
|
181
|
+
startOffset -
|
|
182
|
+
Number(
|
|
183
|
+
// When `leadingSpaces` is `''` (empty string), check for an escaped trailing backslash.
|
|
184
|
+
!leadingSpaces &&
|
|
185
|
+
escapedTrailingBackslashRegex.test(lastChildText.slice(0, -trailingPunctuation.length))),
|
|
186
|
+
endOffset,
|
|
187
|
+
]);
|
|
180
188
|
},
|
|
181
189
|
});
|
|
182
190
|
},
|
|
@@ -64,14 +64,28 @@ export default {
|
|
|
64
64
|
const [nodeStartOffset] = sourceCode.getRange(node);
|
|
65
65
|
const html = sourceCode.getText(node);
|
|
66
66
|
for (const { attrs, sourceCodeLocation } of getElementsByTagName(html, 'img')) {
|
|
67
|
-
|
|
67
|
+
if (!sourceCodeLocation ||
|
|
68
|
+
(!sourceCodeLocation.attrs?.src &&
|
|
69
|
+
!sourceCodeLocation.attrs?.srcset &&
|
|
70
|
+
!sourceCodeLocation.attrs?.alt)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
let needsTitle = true;
|
|
68
74
|
for (const { name, value } of attrs) {
|
|
69
75
|
if (name === 'title' && value) {
|
|
70
|
-
|
|
76
|
+
needsTitle = false;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
if (name === 'alt' && !value) {
|
|
80
|
+
needsTitle = false;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
if (name === 'aria-hidden' && value.toLowerCase() === 'true') {
|
|
84
|
+
needsTitle = false;
|
|
71
85
|
break;
|
|
72
86
|
}
|
|
73
87
|
}
|
|
74
|
-
if (
|
|
88
|
+
if (needsTitle) {
|
|
75
89
|
report({
|
|
76
90
|
start: sourceCode.getLocFromIndex(nodeStartOffset + sourceCodeLocation.startOffset),
|
|
77
91
|
end: sourceCode.getLocFromIndex(nodeStartOffset + sourceCodeLocation.endOffset),
|
|
@@ -67,14 +67,21 @@ export default {
|
|
|
67
67
|
const [nodeStartOffset] = sourceCode.getRange(node);
|
|
68
68
|
const html = sourceCode.getText(node);
|
|
69
69
|
for (const { attrs, sourceCodeLocation } of getElementsByTagName(html, 'a')) {
|
|
70
|
-
|
|
70
|
+
if (!sourceCodeLocation?.startTag || !sourceCodeLocation.attrs?.href) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
let needsTitle = true;
|
|
71
74
|
for (const { name, value } of attrs) {
|
|
72
75
|
if (name === 'title' && value) {
|
|
73
|
-
|
|
76
|
+
needsTitle = false;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
if (name === 'aria-hidden' && value.toLowerCase() === 'true') {
|
|
80
|
+
needsTitle = false;
|
|
74
81
|
break;
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
|
-
if (
|
|
84
|
+
if (needsTitle) {
|
|
78
85
|
report({
|
|
79
86
|
start: sourceCode.getLocFromIndex(nodeStartOffset + sourceCodeLocation.startTag.startOffset),
|
|
80
87
|
end: sourceCode.getLocFromIndex(nodeStartOffset + sourceCodeLocation.startTag.endOffset),
|