eslint-markdown 0.6.0 → 0.7.0
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/README.md +1 -2
- package/build/configs/all.d.ts +1 -0
- package/build/core/ast/is-blank-line.d.ts +3 -1
- package/build/rules/consistent-code-style.d.ts +2 -0
- package/build/rules/index.d.ts +1 -0
- package/build/rules/no-double-punctuation.d.ts +49 -0
- package/package.json +4 -3
- package/src/configs/all.js +2 -1
- package/src/configs/base.js +1 -1
- package/src/configs/recommended.js +1 -1
- package/src/configs/stylistic.js +1 -1
- package/src/core/ast/is-blank-line.js +13 -2
- package/src/rules/consistent-code-style.js +13 -2
- package/src/rules/consistent-unordered-list-style.js +1 -1
- package/src/rules/index.js +2 -0
- package/src/rules/no-double-punctuation.js +115 -0
package/README.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# eslint-markdown
|
|
2
2
|
|
|
3
|
-
[](https://github.com/lumirlumir/npm-eslint-markdown/actions/workflows/ci.yml)
|
|
4
4
|
[](https://github.com/lumirlumir/npm-eslint-markdown/actions/workflows/test.yml)
|
|
5
|
-
[](https://github.com/lumirlumir/npm-eslint-markdown/actions/workflows/test-cross-platform.yml)
|
|
6
5
|
[](https://codecov.io/gh/lumirlumir/npm-eslint-markdown)
|
|
7
6
|

|
|
8
7
|
|
package/build/configs/all.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export default function all(plugin: ESLint.Plugin): {
|
|
|
26
26
|
readonly 'md/consistent-unordered-list-style': "error";
|
|
27
27
|
readonly 'md/no-control-character': "error";
|
|
28
28
|
readonly 'md/no-curly-quote': "error";
|
|
29
|
+
readonly 'md/no-double-punctuation': "error";
|
|
29
30
|
readonly 'md/no-double-space': "error";
|
|
30
31
|
readonly 'md/no-emoji': "error";
|
|
31
32
|
readonly 'md/no-git-conflict-marker': "error";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Check if a line is blank.
|
|
3
|
+
* - NOTE: The `blockquoteDepth` parameter is zero-based: `0` means one blockquote marker, `1` means two, and so on.
|
|
3
4
|
* @param {string} str Line string.
|
|
5
|
+
* @param {number} [blockquoteDepth] The depth of blockquotes. Default is `-1`.
|
|
4
6
|
* @returns {boolean} `true` if the line is blank. `false` otherwise.
|
|
5
7
|
*/
|
|
6
|
-
export default function isBlankLine(str: string): boolean;
|
|
8
|
+
export default function isBlankLine(str: string, blockquoteDepth?: number): boolean;
|
package/build/rules/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ declare const _default: {
|
|
|
11
11
|
'consistent-unordered-list-style': import("../core/types.js").RuleModule<import("./consistent-unordered-list-style.js").RuleOptions, "style">;
|
|
12
12
|
'no-control-character': import("../core/types.js").RuleModule<import("./no-control-character.js").RuleOptions, "noControlCharacter">;
|
|
13
13
|
'no-curly-quote': import("../core/types.js").RuleModule<import("./no-curly-quote.js").RuleOptions, "noCurlyQuote">;
|
|
14
|
+
'no-double-punctuation': import("../core/types.js").RuleModule<import("./no-double-punctuation.js").RuleOptions, "noDoublePunctuation">;
|
|
14
15
|
'no-double-space': import("../core/types.js").RuleModule<import("./no-double-space.js").RuleOptions, import("./no-double-space.js").MessageIds>;
|
|
15
16
|
'no-emoji': import("../core/types.js").RuleModule<[], "noEmoji">;
|
|
16
17
|
'no-git-conflict-marker': import("../core/types.js").RuleModule<import("./no-git-conflict-marker.js").RuleOptions, "noGitConflictMarker">;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
meta: {
|
|
3
|
+
type: "problem";
|
|
4
|
+
docs: {
|
|
5
|
+
description: string;
|
|
6
|
+
url: string;
|
|
7
|
+
recommended: boolean;
|
|
8
|
+
stylistic: false;
|
|
9
|
+
};
|
|
10
|
+
schema: {
|
|
11
|
+
type: "object";
|
|
12
|
+
properties: {
|
|
13
|
+
allow: {
|
|
14
|
+
type: "array";
|
|
15
|
+
items: {
|
|
16
|
+
type: "string";
|
|
17
|
+
minLength: number;
|
|
18
|
+
maxLength: number;
|
|
19
|
+
pattern: string;
|
|
20
|
+
};
|
|
21
|
+
uniqueItems: true;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
additionalProperties: false;
|
|
25
|
+
}[];
|
|
26
|
+
defaultOptions: [{
|
|
27
|
+
allow: never[];
|
|
28
|
+
}];
|
|
29
|
+
messages: {
|
|
30
|
+
noDoublePunctuation: string;
|
|
31
|
+
};
|
|
32
|
+
language: string;
|
|
33
|
+
dialects: string[];
|
|
34
|
+
};
|
|
35
|
+
create(context: import("@eslint/core").RuleContext<{
|
|
36
|
+
LangOptions: import("@eslint/markdown").MarkdownLanguageOptions;
|
|
37
|
+
Code: import("@eslint/markdown").MarkdownSourceCode;
|
|
38
|
+
RuleOptions: RuleOptions;
|
|
39
|
+
Node: import("mdast").Node;
|
|
40
|
+
MessageIds: "noDoublePunctuation";
|
|
41
|
+
}>): {
|
|
42
|
+
text(node: import("mdast").Text): void;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export default _default;
|
|
46
|
+
export type RuleOptions = [{
|
|
47
|
+
allow: string[];
|
|
48
|
+
}];
|
|
49
|
+
export type MessageIds = "noDoublePunctuation";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-markdown",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Lint your Markdown with ESLint.🛠️",
|
|
6
6
|
"exports": {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"prepublishOnly": "npm run build",
|
|
62
|
-
"build": "node ../../scripts/build-config.
|
|
62
|
+
"build": "node ../../scripts/build-config.js && tsc && node ../../scripts/cp.js ../../LICENSE.md LICENSE.md ../../README.md README.md",
|
|
63
63
|
"test": "npm run test:types && npm run test:unit",
|
|
64
64
|
"test:types": "tsc -p ./tsconfig.test.json",
|
|
65
65
|
"test:unit": "node --test"
|
|
@@ -75,10 +75,11 @@
|
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@eslint/markdown": "^7.5.1",
|
|
77
77
|
"micromark-util-normalize-identifier": "^2.0.1",
|
|
78
|
-
"parse5": "^8.0.
|
|
78
|
+
"parse5": "^8.0.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@types/mdast": "^4.0.4",
|
|
82
|
+
"@types/unist": "^3.0.3",
|
|
82
83
|
"eslint": "^9.39.4"
|
|
83
84
|
}
|
|
84
85
|
}
|
package/src/configs/all.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `all` configuration.
|
|
3
|
-
* WARNING: This file is autogenerated using the `scripts/build-config.
|
|
3
|
+
* WARNING: This file is autogenerated using the `scripts/build-config.js`
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// --------------------------------------------------------------------------------
|
|
@@ -50,6 +50,7 @@ export default function all(plugin) {
|
|
|
50
50
|
'md/consistent-unordered-list-style': 'error',
|
|
51
51
|
'md/no-control-character': 'error',
|
|
52
52
|
'md/no-curly-quote': 'error',
|
|
53
|
+
'md/no-double-punctuation': 'error',
|
|
53
54
|
'md/no-double-space': 'error',
|
|
54
55
|
'md/no-emoji': 'error',
|
|
55
56
|
'md/no-git-conflict-marker': 'error',
|
package/src/configs/base.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `base` configuration.
|
|
3
|
-
* WARNING: This file is autogenerated using the `scripts/build-config.
|
|
3
|
+
* WARNING: This file is autogenerated using the `scripts/build-config.js`
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// --------------------------------------------------------------------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `recommended` configuration.
|
|
3
|
-
* WARNING: This file is autogenerated using the `scripts/build-config.
|
|
3
|
+
* WARNING: This file is autogenerated using the `scripts/build-config.js`
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// --------------------------------------------------------------------------------
|
package/src/configs/stylistic.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `stylistic` configuration.
|
|
3
|
-
* WARNING: This file is autogenerated using the `scripts/build-config.
|
|
3
|
+
* WARNING: This file is autogenerated using the `scripts/build-config.js`
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// --------------------------------------------------------------------------------
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// --------------------------------------------------------------------------------
|
|
9
9
|
|
|
10
10
|
const whitespaceChars = new Set([' ', '\t']);
|
|
11
|
+
const blockquoteChar = '>';
|
|
11
12
|
|
|
12
13
|
// --------------------------------------------------------------------------------
|
|
13
14
|
// Export
|
|
@@ -15,15 +16,25 @@ const whitespaceChars = new Set([' ', '\t']);
|
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Check if a line is blank.
|
|
19
|
+
* - NOTE: The `blockquoteDepth` parameter is zero-based: `0` means one blockquote marker, `1` means two, and so on.
|
|
18
20
|
* @param {string} str Line string.
|
|
21
|
+
* @param {number} [blockquoteDepth] The depth of blockquotes. Default is `-1`.
|
|
19
22
|
* @returns {boolean} `true` if the line is blank. `false` otherwise.
|
|
20
23
|
*/
|
|
21
|
-
export default function isBlankLine(str) {
|
|
24
|
+
export default function isBlankLine(str, blockquoteDepth = -1) {
|
|
22
25
|
// `.length` is cached for performance.
|
|
23
26
|
const strLength = str.length;
|
|
27
|
+
let remainingBlockquotes = blockquoteDepth + 1;
|
|
24
28
|
|
|
25
29
|
for (let i = 0; i < strLength; i++) {
|
|
26
|
-
|
|
30
|
+
const char = str[i];
|
|
31
|
+
|
|
32
|
+
if (!whitespaceChars.has(char)) {
|
|
33
|
+
if (remainingBlockquotes > 0 && char === blockquoteChar) {
|
|
34
|
+
remainingBlockquotes--;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
return false;
|
|
28
39
|
}
|
|
29
40
|
}
|
|
@@ -132,8 +132,14 @@ export default {
|
|
|
132
132
|
|
|
133
133
|
/** @type {CodeStyle | null} */
|
|
134
134
|
let codeStyle = style === 'consistent' ? null : style;
|
|
135
|
+
let blockquoteDepth = -1; // NOTE: Depth `0` is the first blockquote level, which is the top level.
|
|
135
136
|
|
|
136
137
|
return {
|
|
138
|
+
blockquote() {
|
|
139
|
+
// When entering a `blockquote` node, increase the depth.
|
|
140
|
+
blockquoteDepth++;
|
|
141
|
+
},
|
|
142
|
+
|
|
137
143
|
code(node) {
|
|
138
144
|
// ------------------------------------------------------------------------
|
|
139
145
|
// 1. Check code style consistency.
|
|
@@ -182,7 +188,7 @@ export default {
|
|
|
182
188
|
}
|
|
183
189
|
|
|
184
190
|
// If the line is blank, continue checking the next line. If it's not blank, report the issue.
|
|
185
|
-
if (isBlankLine(line)) {
|
|
191
|
+
if (isBlankLine(line, blockquoteDepth)) {
|
|
186
192
|
continue;
|
|
187
193
|
}
|
|
188
194
|
|
|
@@ -225,7 +231,7 @@ export default {
|
|
|
225
231
|
}
|
|
226
232
|
|
|
227
233
|
// If the line is blank, continue checking the next line. If it's not blank, report the issue.
|
|
228
|
-
if (isBlankLine(line)) {
|
|
234
|
+
if (isBlankLine(line, blockquoteDepth)) {
|
|
229
235
|
continue;
|
|
230
236
|
}
|
|
231
237
|
|
|
@@ -244,6 +250,11 @@ export default {
|
|
|
244
250
|
}
|
|
245
251
|
}
|
|
246
252
|
},
|
|
253
|
+
|
|
254
|
+
'blockquote:exit'() {
|
|
255
|
+
// When exiting a `blockquote` node, decrease the depth.
|
|
256
|
+
blockquoteDepth--;
|
|
257
|
+
},
|
|
247
258
|
};
|
|
248
259
|
},
|
|
249
260
|
};
|
|
@@ -94,7 +94,7 @@ export default {
|
|
|
94
94
|
const unorderedListStyle = [
|
|
95
95
|
style === 'consistent' || style === 'sublist' ? null : style,
|
|
96
96
|
];
|
|
97
|
-
let listDepth = -1;
|
|
97
|
+
let listDepth = -1; // NOTE: Depth `0` is the first list level, which is the top level.
|
|
98
98
|
|
|
99
99
|
return {
|
|
100
100
|
list() {
|
package/src/rules/index.js
CHANGED
|
@@ -18,6 +18,7 @@ import consistentUnorderedListStyle from './consistent-unordered-list-style.js';
|
|
|
18
18
|
// import noBoldParagraph from './no-bold-paragraph.js';
|
|
19
19
|
import noControlCharacter from './no-control-character.js';
|
|
20
20
|
import noCurlyQuote from './no-curly-quote.js';
|
|
21
|
+
import noDoublePunctuation from './no-double-punctuation.js';
|
|
21
22
|
import noDoubleSpace from './no-double-space.js';
|
|
22
23
|
import noEmoji from './no-emoji.js';
|
|
23
24
|
import noGitConflictMarker from './no-git-conflict-marker.js';
|
|
@@ -45,6 +46,7 @@ export default {
|
|
|
45
46
|
// 'no-bold-paragraph': noBoldParagraph,
|
|
46
47
|
'no-control-character': noControlCharacter,
|
|
47
48
|
'no-curly-quote': noCurlyQuote,
|
|
49
|
+
'no-double-punctuation': noDoublePunctuation,
|
|
48
50
|
'no-double-space': noDoubleSpace,
|
|
49
51
|
'no-emoji': noEmoji,
|
|
50
52
|
'no-git-conflict-marker': noGitConflictMarker,
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule to disallow double consecutive punctuation in text.
|
|
3
|
+
* @author 루밀LuMir(lumirlumir)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// --------------------------------------------------------------------------------
|
|
7
|
+
// Import
|
|
8
|
+
// --------------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import { URL_RULE_DOCS } from '../core/constants.js';
|
|
11
|
+
|
|
12
|
+
// --------------------------------------------------------------------------------
|
|
13
|
+
// Typedef
|
|
14
|
+
// --------------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @import { RuleModule } from '../core/types.js';
|
|
18
|
+
* @typedef {[{ allow: string[] }]} RuleOptions
|
|
19
|
+
* @typedef {'noDoublePunctuation'} MessageIds
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// --------------------------------------------------------------------------------
|
|
23
|
+
// Helper
|
|
24
|
+
// --------------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* This pattern is based on the punctuation list used by `remark-lint`.
|
|
28
|
+
* @see https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-punctuation#parameters
|
|
29
|
+
*/
|
|
30
|
+
const doublePunctuationRegex = /(?:^|(?<=[^!,.:;?]))[!,.:;?]{2}(?:$|(?=[^!,.:;?]))/g;
|
|
31
|
+
|
|
32
|
+
// --------------------------------------------------------------------------------
|
|
33
|
+
// Rule Definition
|
|
34
|
+
// --------------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/** @type {RuleModule<RuleOptions, MessageIds>} */
|
|
37
|
+
export default {
|
|
38
|
+
meta: {
|
|
39
|
+
type: 'problem',
|
|
40
|
+
|
|
41
|
+
docs: {
|
|
42
|
+
description: 'Disallow double consecutive punctuation in text',
|
|
43
|
+
url: URL_RULE_DOCS('no-double-punctuation'),
|
|
44
|
+
recommended: false,
|
|
45
|
+
stylistic: false,
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
schema: [
|
|
49
|
+
{
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
allow: {
|
|
53
|
+
type: 'array',
|
|
54
|
+
items: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
minLength: 2,
|
|
57
|
+
maxLength: 2,
|
|
58
|
+
pattern: '^[!,.:;?]{2}$',
|
|
59
|
+
},
|
|
60
|
+
uniqueItems: true,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
additionalProperties: false,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
|
|
67
|
+
defaultOptions: [
|
|
68
|
+
{
|
|
69
|
+
allow: [],
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
|
|
73
|
+
messages: {
|
|
74
|
+
noDoublePunctuation: 'Double punctuation mark `{{ punctuation }}` is not allowed.',
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
language: 'markdown',
|
|
78
|
+
|
|
79
|
+
dialects: ['commonmark', 'gfm'],
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
create(context) {
|
|
83
|
+
const { sourceCode } = context;
|
|
84
|
+
const [{ allow }] = context.options;
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
text(node) {
|
|
88
|
+
const [nodeStartOffset] = sourceCode.getRange(node);
|
|
89
|
+
const matches = sourceCode.getText(node).matchAll(doublePunctuationRegex);
|
|
90
|
+
|
|
91
|
+
for (const match of matches) {
|
|
92
|
+
const punctuation = match[0];
|
|
93
|
+
|
|
94
|
+
const startOffset = nodeStartOffset + match.index;
|
|
95
|
+
const endOffset = startOffset + punctuation.length;
|
|
96
|
+
|
|
97
|
+
if (allow.includes(punctuation)) continue;
|
|
98
|
+
|
|
99
|
+
context.report({
|
|
100
|
+
loc: {
|
|
101
|
+
start: sourceCode.getLocFromIndex(startOffset),
|
|
102
|
+
end: sourceCode.getLocFromIndex(endOffset),
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
data: {
|
|
106
|
+
punctuation,
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
messageId: 'noDoublePunctuation',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
};
|