eslint-markdown 0.18.0 → 0.19.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/build/configs/all.d.ts +1 -0
- package/build/configs/all.js +1 -0
- package/build/configs/stylistic.d.ts +1 -0
- package/build/configs/stylistic.js +1 -0
- package/build/core/constants.d.ts +6 -0
- package/build/core/constants.js +6 -0
- package/build/rules/consistent-code-style.js +32 -19
- package/build/rules/consistent-ordered-list-style.d.ts +62 -0
- package/build/rules/consistent-ordered-list-style.js +108 -0
- package/build/rules/index.d.ts +50 -0
- package/build/rules/index.js +2 -0
- package/build/rules/no-control-character.d.ts +20 -0
- package/build/rules/no-control-character.js +17 -1
- package/build/rules/no-double-punctuation.js +8 -2
- package/build/rules/no-trailing-heading-punctuation.js +2 -10
- package/package.json +2 -2
package/build/configs/all.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export default function all(plugin: ESLint.Plugin): {
|
|
|
25
25
|
readonly 'md/consistent-emphasis-style': "error";
|
|
26
26
|
readonly 'md/consistent-heading-style': "error";
|
|
27
27
|
readonly 'md/consistent-inline-code-style': "error";
|
|
28
|
+
readonly 'md/consistent-ordered-list-style': "error";
|
|
28
29
|
readonly 'md/consistent-strong-style': "error";
|
|
29
30
|
readonly 'md/consistent-thematic-break-style': "error";
|
|
30
31
|
readonly 'md/consistent-unordered-list-style': "error";
|
package/build/configs/all.js
CHANGED
|
@@ -33,6 +33,7 @@ export default function all(plugin) {
|
|
|
33
33
|
'md/consistent-emphasis-style': 'error',
|
|
34
34
|
'md/consistent-heading-style': 'error',
|
|
35
35
|
'md/consistent-inline-code-style': 'error',
|
|
36
|
+
'md/consistent-ordered-list-style': 'error',
|
|
36
37
|
'md/consistent-strong-style': 'error',
|
|
37
38
|
'md/consistent-thematic-break-style': 'error',
|
|
38
39
|
'md/consistent-unordered-list-style': 'error',
|
|
@@ -21,6 +21,7 @@ export default function stylistic(plugin: ESLint.Plugin): {
|
|
|
21
21
|
readonly 'md/consistent-emphasis-style': "error";
|
|
22
22
|
readonly 'md/consistent-heading-style': "error";
|
|
23
23
|
readonly 'md/consistent-inline-code-style': "error";
|
|
24
|
+
readonly 'md/consistent-ordered-list-style': "error";
|
|
24
25
|
readonly 'md/consistent-strong-style': "error";
|
|
25
26
|
readonly 'md/consistent-thematic-break-style': "error";
|
|
26
27
|
readonly 'md/consistent-unordered-list-style': "error";
|
|
@@ -29,6 +29,7 @@ export default function stylistic(plugin) {
|
|
|
29
29
|
'md/consistent-emphasis-style': 'error',
|
|
30
30
|
'md/consistent-heading-style': 'error',
|
|
31
31
|
'md/consistent-inline-code-style': 'error',
|
|
32
|
+
'md/consistent-ordered-list-style': 'error',
|
|
32
33
|
'md/consistent-strong-style': 'error',
|
|
33
34
|
'md/consistent-thematic-break-style': 'error',
|
|
34
35
|
'md/consistent-unordered-list-style': 'error',
|
|
@@ -40,6 +40,12 @@ export declare const escapedTrailingBackslashRegex: RegExp;
|
|
|
40
40
|
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L36-L38
|
|
41
41
|
*/
|
|
42
42
|
export declare const gemojiRegex: RegExp;
|
|
43
|
+
/**
|
|
44
|
+
* Regular expression for identifying an HTML entity.
|
|
45
|
+
* - NOTE: This pattern is based on `markdownlint`.
|
|
46
|
+
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L32-L34
|
|
47
|
+
*/
|
|
48
|
+
export declare const htmlEntityRegex: RegExp;
|
|
43
49
|
/**
|
|
44
50
|
* Matches the closing sequence of a closed ATX heading.
|
|
45
51
|
* @see https://spec.commonmark.org/0.31.2/#atx-headings
|
package/build/core/constants.js
CHANGED
|
@@ -59,6 +59,12 @@ export const escapedTrailingBackslashRegex = /(?<=(?<!\\)(?:\\{2})*)\\$/u;
|
|
|
59
59
|
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L36-L38
|
|
60
60
|
*/
|
|
61
61
|
export const gemojiRegex = /:(?:[abmovx]|[-+]1|100|1234|(?:1st|2nd|3rd)_place_medal|8ball|clock\d{1,4}|e-mail|non-potable_water|o2|t-rex|u5272|u5408|u55b6|u6307|u6708|u6709|u6e80|u7121|u7533|u7981|u7a7a|[a-z]{2,15}2?|[a-z]{1,14}(?:_[a-z\d]{1,16})+):/;
|
|
62
|
+
/**
|
|
63
|
+
* Regular expression for identifying an HTML entity.
|
|
64
|
+
* - NOTE: This pattern is based on `markdownlint`.
|
|
65
|
+
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L32-L34
|
|
66
|
+
*/
|
|
67
|
+
export const htmlEntityRegex = /(?<=(?<!\\)(?:\\{2})*)&(?:#\d+|#[xX][\da-fA-F]+|[a-zA-Z]{2,31}|blk\d{2}|emsp1[34]|frac\d{2}|sup\d|there4);/;
|
|
62
68
|
/**
|
|
63
69
|
* Matches the closing sequence of a closed ATX heading.
|
|
64
70
|
* @see https://spec.commonmark.org/0.31.2/#atx-headings
|
|
@@ -103,28 +103,30 @@ export default {
|
|
|
103
103
|
const currentCodeStyle = getCodeStyle(currentCodeFenceChar);
|
|
104
104
|
const nodeStartLineIndex = start.line - 1;
|
|
105
105
|
const nodeEndLineIndex = end.line - 1;
|
|
106
|
+
const nodeStartLineText = lines[nodeStartLineIndex];
|
|
107
|
+
const nodeEndLineText = lines[nodeEndLineIndex];
|
|
108
|
+
const leadingCodeFenceLoc = {
|
|
109
|
+
start,
|
|
110
|
+
end: {
|
|
111
|
+
line: start.line,
|
|
112
|
+
column: (() => {
|
|
113
|
+
if (currentCodeStyle === 'indent') {
|
|
114
|
+
return nodeStartLineText.length + 1;
|
|
115
|
+
}
|
|
116
|
+
let { column } = start;
|
|
117
|
+
while (nodeStartLineText[column - 1] === currentCodeFenceChar) {
|
|
118
|
+
column++;
|
|
119
|
+
}
|
|
120
|
+
return column;
|
|
121
|
+
})(),
|
|
122
|
+
},
|
|
123
|
+
};
|
|
106
124
|
if (codeStyle === null) {
|
|
107
125
|
codeStyle = currentCodeStyle;
|
|
108
126
|
}
|
|
109
127
|
if (codeStyle !== currentCodeStyle) {
|
|
110
128
|
context.report({
|
|
111
|
-
loc:
|
|
112
|
-
start,
|
|
113
|
-
end: {
|
|
114
|
-
line: start.line,
|
|
115
|
-
column: (() => {
|
|
116
|
-
const nodeStartLineText = lines[nodeStartLineIndex];
|
|
117
|
-
if (currentCodeStyle === 'indent') {
|
|
118
|
-
return nodeStartLineText.length + 1;
|
|
119
|
-
}
|
|
120
|
-
let { column } = start;
|
|
121
|
-
while (nodeStartLineText[column - 1] === currentCodeFenceChar) {
|
|
122
|
-
column++;
|
|
123
|
-
}
|
|
124
|
-
return column;
|
|
125
|
-
})(),
|
|
126
|
-
},
|
|
127
|
-
},
|
|
129
|
+
loc: leadingCodeFenceLoc,
|
|
128
130
|
messageId: 'style',
|
|
129
131
|
data: {
|
|
130
132
|
style: codeStyle,
|
|
@@ -150,7 +152,7 @@ export default {
|
|
|
150
152
|
continue;
|
|
151
153
|
}
|
|
152
154
|
context.report({
|
|
153
|
-
|
|
155
|
+
loc: leadingCodeFenceLoc,
|
|
154
156
|
messageId: 'blankLineAbove',
|
|
155
157
|
data: {
|
|
156
158
|
blankLineAbove,
|
|
@@ -179,7 +181,18 @@ export default {
|
|
|
179
181
|
continue;
|
|
180
182
|
}
|
|
181
183
|
context.report({
|
|
182
|
-
|
|
184
|
+
// Report the last line of the code block, as highlighting only the trailing
|
|
185
|
+
// code fence characters involves many edge cases that cannot be handled reliably.
|
|
186
|
+
loc: {
|
|
187
|
+
start: {
|
|
188
|
+
line: end.line,
|
|
189
|
+
column: 1,
|
|
190
|
+
},
|
|
191
|
+
end: {
|
|
192
|
+
line: end.line,
|
|
193
|
+
column: nodeEndLineText.length + 1,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
183
196
|
messageId: 'blankLineBelow',
|
|
184
197
|
data: {
|
|
185
198
|
blankLineBelow,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule to enforce consistent ordered list style.
|
|
3
|
+
* @author Ga eun Lee(tooth-is-silver)
|
|
4
|
+
*/
|
|
5
|
+
import type { ListItem } from 'mdast';
|
|
6
|
+
type OrderedListStyle = (typeof ORDERED_LIST_STYLE)[number];
|
|
7
|
+
/**
|
|
8
|
+
* Options for the `consistent-ordered-list-style` rule.
|
|
9
|
+
*/
|
|
10
|
+
type RuleOptions = [
|
|
11
|
+
{
|
|
12
|
+
/**
|
|
13
|
+
* When `style` is set to `'one-or-ordered'`, the rule allows either the `'one'` or `'ordered'` style based on the first two list item prefixes.
|
|
14
|
+
*
|
|
15
|
+
* When `style` is set to `'one'`, the rule requires every prefix to be `1`.
|
|
16
|
+
*
|
|
17
|
+
* When `style` is set to `'ordered'`, the rule requires prefixes to increase sequentially, starting from `1` or from `0` when the list has two or more items.
|
|
18
|
+
*
|
|
19
|
+
* When `style` is set to `'zero'`, the rule requires every prefix to be `0`.
|
|
20
|
+
* @default 'one-or-ordered'
|
|
21
|
+
*/
|
|
22
|
+
style: 'one-or-ordered' | OrderedListStyle;
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
declare const ORDERED_LIST_STYLE: readonly ["one", "ordered", "zero"];
|
|
26
|
+
declare const _default: {
|
|
27
|
+
readonly meta: {
|
|
28
|
+
readonly type: "layout";
|
|
29
|
+
readonly docs: {
|
|
30
|
+
readonly description: "Enforce consistent ordered list style";
|
|
31
|
+
readonly url: string;
|
|
32
|
+
readonly recommended: false;
|
|
33
|
+
readonly stylistic: true;
|
|
34
|
+
};
|
|
35
|
+
readonly schema: [{
|
|
36
|
+
readonly type: "object";
|
|
37
|
+
readonly properties: {
|
|
38
|
+
readonly style: {
|
|
39
|
+
readonly enum: ["one-or-ordered", "one", "ordered", "zero"];
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
readonly additionalProperties: false;
|
|
43
|
+
}];
|
|
44
|
+
readonly defaultOptions: [{
|
|
45
|
+
readonly style: "one-or-ordered";
|
|
46
|
+
}];
|
|
47
|
+
readonly messages: {
|
|
48
|
+
readonly style: "Ordered list style should be `{{ style }}`.";
|
|
49
|
+
};
|
|
50
|
+
readonly language: "markdown";
|
|
51
|
+
readonly dialects: ["commonmark", "gfm"];
|
|
52
|
+
};
|
|
53
|
+
readonly create: (context: import("../core/types.js").RuleContext<{
|
|
54
|
+
RuleOptions: RuleOptions;
|
|
55
|
+
MessageIds: "style";
|
|
56
|
+
}>) => {
|
|
57
|
+
'list[ordered=true]'(): void;
|
|
58
|
+
'list[ordered=true] > listItem'(node: ListItem): void;
|
|
59
|
+
'list[ordered=true]:exit'(): void;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export default _default;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule to enforce consistent ordered list style.
|
|
3
|
+
* @author Ga eun Lee(tooth-is-silver)
|
|
4
|
+
*/
|
|
5
|
+
import { URL_RULE_DOCS } from '../core/constants.js';
|
|
6
|
+
// --------------------------------------------------------------------------------
|
|
7
|
+
// Helper
|
|
8
|
+
// --------------------------------------------------------------------------------
|
|
9
|
+
const ORDERED_LIST_STYLE = ['one', 'ordered', 'zero'];
|
|
10
|
+
/**
|
|
11
|
+
* Ordered list start numbers must be nine digits or less.
|
|
12
|
+
* @see https://spec.commonmark.org/0.31.2/#example-265
|
|
13
|
+
*/
|
|
14
|
+
const orderedListPrefixRegex = /^\d{1,9}/u;
|
|
15
|
+
// --------------------------------------------------------------------------------
|
|
16
|
+
// Rule Definition
|
|
17
|
+
// --------------------------------------------------------------------------------
|
|
18
|
+
export default {
|
|
19
|
+
meta: {
|
|
20
|
+
type: 'layout',
|
|
21
|
+
docs: {
|
|
22
|
+
description: 'Enforce consistent ordered list style',
|
|
23
|
+
url: URL_RULE_DOCS('consistent-ordered-list-style'),
|
|
24
|
+
recommended: false,
|
|
25
|
+
stylistic: true,
|
|
26
|
+
},
|
|
27
|
+
schema: [
|
|
28
|
+
{
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
style: {
|
|
32
|
+
enum: ['one-or-ordered', ...ORDERED_LIST_STYLE],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
defaultOptions: [
|
|
39
|
+
{
|
|
40
|
+
style: 'one-or-ordered',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
messages: {
|
|
44
|
+
style: 'Ordered list style should be `{{ style }}`.',
|
|
45
|
+
},
|
|
46
|
+
language: 'markdown',
|
|
47
|
+
dialects: ['commonmark', 'gfm'],
|
|
48
|
+
},
|
|
49
|
+
create(context) {
|
|
50
|
+
const { sourceCode } = context;
|
|
51
|
+
const [{ style }] = context.options;
|
|
52
|
+
const orderedListPrefixesStack = [];
|
|
53
|
+
return {
|
|
54
|
+
'list[ordered=true]'() {
|
|
55
|
+
orderedListPrefixesStack.push([]);
|
|
56
|
+
},
|
|
57
|
+
'list[ordered=true] > listItem'(node) {
|
|
58
|
+
const [nodeStartOffset] = sourceCode.getRange(node);
|
|
59
|
+
// `match` is never `null` because this visitor only runs for
|
|
60
|
+
// ordered list items, whose source text starts with a numeric marker.
|
|
61
|
+
const match = orderedListPrefixRegex.exec(sourceCode.getText(node));
|
|
62
|
+
const orderedListPrefix = match[0];
|
|
63
|
+
orderedListPrefixesStack[orderedListPrefixesStack.length - 1].push({
|
|
64
|
+
startOffset: nodeStartOffset,
|
|
65
|
+
endOffset: nodeStartOffset + orderedListPrefix.length,
|
|
66
|
+
number: Number(orderedListPrefix),
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
'list[ordered=true]:exit'() {
|
|
70
|
+
// Can never be `undefined` because `list[ordered=true]` always pushes to the stack before exiting.
|
|
71
|
+
const orderedListPrefixes = orderedListPrefixesStack.pop();
|
|
72
|
+
const [firstOrderedListPrefix, secondOrderedListPrefix] = orderedListPrefixes;
|
|
73
|
+
const hasMultipleItems = orderedListPrefixes.length > 1;
|
|
74
|
+
let orderedListStyle = style;
|
|
75
|
+
if (orderedListStyle === 'one-or-ordered') {
|
|
76
|
+
orderedListStyle =
|
|
77
|
+
hasMultipleItems &&
|
|
78
|
+
(firstOrderedListPrefix.number === 0 || secondOrderedListPrefix.number !== 1)
|
|
79
|
+
? 'ordered'
|
|
80
|
+
: 'one';
|
|
81
|
+
}
|
|
82
|
+
let expectedOrderedListPrefixNumber = orderedListStyle === 'zero' ||
|
|
83
|
+
(orderedListStyle === 'ordered' &&
|
|
84
|
+
hasMultipleItems &&
|
|
85
|
+
firstOrderedListPrefix.number === 0)
|
|
86
|
+
? 0
|
|
87
|
+
: 1;
|
|
88
|
+
for (const { startOffset, endOffset, number } of orderedListPrefixes) {
|
|
89
|
+
if (number !== expectedOrderedListPrefixNumber) {
|
|
90
|
+
context.report({
|
|
91
|
+
loc: {
|
|
92
|
+
start: sourceCode.getLocFromIndex(startOffset),
|
|
93
|
+
end: sourceCode.getLocFromIndex(endOffset),
|
|
94
|
+
},
|
|
95
|
+
messageId: 'style',
|
|
96
|
+
data: {
|
|
97
|
+
style: orderedListStyle,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (orderedListStyle === 'ordered') {
|
|
102
|
+
expectedOrderedListPrefixNumber++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
};
|
package/build/rules/index.d.ts
CHANGED
|
@@ -632,6 +632,44 @@ declare const _default: {
|
|
|
632
632
|
inlineCode(node: import("mdast").InlineCode): void;
|
|
633
633
|
};
|
|
634
634
|
};
|
|
635
|
+
'consistent-ordered-list-style': {
|
|
636
|
+
readonly meta: {
|
|
637
|
+
readonly type: "layout";
|
|
638
|
+
readonly docs: {
|
|
639
|
+
readonly description: "Enforce consistent ordered list style";
|
|
640
|
+
readonly url: string;
|
|
641
|
+
readonly recommended: false;
|
|
642
|
+
readonly stylistic: true;
|
|
643
|
+
};
|
|
644
|
+
readonly schema: [{
|
|
645
|
+
readonly type: "object";
|
|
646
|
+
readonly properties: {
|
|
647
|
+
readonly style: {
|
|
648
|
+
readonly enum: ["one-or-ordered", "one", "ordered", "zero"];
|
|
649
|
+
};
|
|
650
|
+
};
|
|
651
|
+
readonly additionalProperties: false;
|
|
652
|
+
}];
|
|
653
|
+
readonly defaultOptions: [{
|
|
654
|
+
readonly style: "one-or-ordered";
|
|
655
|
+
}];
|
|
656
|
+
readonly messages: {
|
|
657
|
+
readonly style: "Ordered list style should be `{{ style }}`.";
|
|
658
|
+
};
|
|
659
|
+
readonly language: "markdown";
|
|
660
|
+
readonly dialects: ["commonmark", "gfm"];
|
|
661
|
+
};
|
|
662
|
+
readonly create: (context: import("../core/types.js").RuleContext<{
|
|
663
|
+
RuleOptions: [{
|
|
664
|
+
style: "one-or-ordered" | ("one" | "ordered" | "zero");
|
|
665
|
+
}];
|
|
666
|
+
MessageIds: "style";
|
|
667
|
+
}>) => {
|
|
668
|
+
'list[ordered=true]'(): void;
|
|
669
|
+
'list[ordered=true] > listItem'(node: import("mdast").ListItem): void;
|
|
670
|
+
'list[ordered=true]:exit'(): void;
|
|
671
|
+
};
|
|
672
|
+
};
|
|
635
673
|
'consistent-strong-style': {
|
|
636
674
|
readonly meta: {
|
|
637
675
|
readonly type: "layout";
|
|
@@ -838,6 +876,12 @@ declare const _default: {
|
|
|
838
876
|
readonly skipInlineCode: {
|
|
839
877
|
readonly type: "boolean";
|
|
840
878
|
};
|
|
879
|
+
readonly skipMath: {
|
|
880
|
+
readonly type: "boolean";
|
|
881
|
+
};
|
|
882
|
+
readonly skipInlineMath: {
|
|
883
|
+
readonly type: "boolean";
|
|
884
|
+
};
|
|
841
885
|
};
|
|
842
886
|
readonly additionalProperties: false;
|
|
843
887
|
}];
|
|
@@ -845,6 +889,8 @@ declare const _default: {
|
|
|
845
889
|
readonly allow: [];
|
|
846
890
|
readonly skipCode: true;
|
|
847
891
|
readonly skipInlineCode: true;
|
|
892
|
+
readonly skipMath: false;
|
|
893
|
+
readonly skipInlineMath: false;
|
|
848
894
|
}];
|
|
849
895
|
readonly messages: {
|
|
850
896
|
readonly noControlCharacter: "Control character `{{ controlCharacter }}` is not allowed.";
|
|
@@ -858,11 +904,15 @@ declare const _default: {
|
|
|
858
904
|
allow: string[];
|
|
859
905
|
skipCode: boolean | string[];
|
|
860
906
|
skipInlineCode: boolean;
|
|
907
|
+
skipMath: boolean;
|
|
908
|
+
skipInlineMath: boolean;
|
|
861
909
|
}];
|
|
862
910
|
MessageIds: "noControlCharacter" | "suggestRemove";
|
|
863
911
|
}>) => {
|
|
864
912
|
code(node: import("mdast").Code): void;
|
|
865
913
|
inlineCode(node: import("mdast").InlineCode): void;
|
|
914
|
+
math(node: import("mdast-util-math").Math): void;
|
|
915
|
+
inlineMath(node: import("mdast-util-math").InlineMath): void;
|
|
866
916
|
'root:exit'(): void;
|
|
867
917
|
};
|
|
868
918
|
};
|
package/build/rules/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import consistentDeleteStyle from './consistent-delete-style.js';
|
|
|
9
9
|
import consistentEmphasisStyle from './consistent-emphasis-style.js';
|
|
10
10
|
import consistentHeadingStyle from './consistent-heading-style.js';
|
|
11
11
|
import consistentInlineCodeStyle from './consistent-inline-code-style.js';
|
|
12
|
+
import consistentOrderedListStyle from './consistent-ordered-list-style.js';
|
|
12
13
|
import consistentStrongStyle from './consistent-strong-style.js';
|
|
13
14
|
import consistentThematicBreakStyle from './consistent-thematic-break-style.js';
|
|
14
15
|
import consistentUnorderedListStyle from './consistent-unordered-list-style.js';
|
|
@@ -40,6 +41,7 @@ export default {
|
|
|
40
41
|
'consistent-emphasis-style': consistentEmphasisStyle,
|
|
41
42
|
'consistent-heading-style': consistentHeadingStyle,
|
|
42
43
|
'consistent-inline-code-style': consistentInlineCodeStyle,
|
|
44
|
+
'consistent-ordered-list-style': consistentOrderedListStyle,
|
|
43
45
|
'consistent-strong-style': consistentStrongStyle,
|
|
44
46
|
'consistent-thematic-break-style': consistentThematicBreakStyle,
|
|
45
47
|
'consistent-unordered-list-style': consistentUnorderedListStyle,
|
|
@@ -24,6 +24,16 @@ type RuleOptions = [
|
|
|
24
24
|
* @default true
|
|
25
25
|
*/
|
|
26
26
|
skipInlineCode: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* `true` allows control characters in all math blocks.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
skipMath: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* `true` allows control characters in all inline math.
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
skipInlineMath: boolean;
|
|
27
37
|
}
|
|
28
38
|
];
|
|
29
39
|
type MessageIds = 'noControlCharacter' | 'suggestRemove';
|
|
@@ -61,6 +71,12 @@ declare const _default: {
|
|
|
61
71
|
readonly skipInlineCode: {
|
|
62
72
|
readonly type: "boolean";
|
|
63
73
|
};
|
|
74
|
+
readonly skipMath: {
|
|
75
|
+
readonly type: "boolean";
|
|
76
|
+
};
|
|
77
|
+
readonly skipInlineMath: {
|
|
78
|
+
readonly type: "boolean";
|
|
79
|
+
};
|
|
64
80
|
};
|
|
65
81
|
readonly additionalProperties: false;
|
|
66
82
|
}];
|
|
@@ -68,6 +84,8 @@ declare const _default: {
|
|
|
68
84
|
readonly allow: [];
|
|
69
85
|
readonly skipCode: true;
|
|
70
86
|
readonly skipInlineCode: true;
|
|
87
|
+
readonly skipMath: false;
|
|
88
|
+
readonly skipInlineMath: false;
|
|
71
89
|
}];
|
|
72
90
|
readonly messages: {
|
|
73
91
|
readonly noControlCharacter: "Control character `{{ controlCharacter }}` is not allowed.";
|
|
@@ -82,6 +100,8 @@ declare const _default: {
|
|
|
82
100
|
}>) => {
|
|
83
101
|
code(node: import("mdast").Code): void;
|
|
84
102
|
inlineCode(node: import("mdast").InlineCode): void;
|
|
103
|
+
math(node: import("mdast-util-math").Math): void;
|
|
104
|
+
inlineMath(node: import("mdast-util-math").InlineMath): void;
|
|
85
105
|
'root:exit'(): void;
|
|
86
106
|
};
|
|
87
107
|
};
|
|
@@ -53,6 +53,12 @@ export default {
|
|
|
53
53
|
skipInlineCode: {
|
|
54
54
|
type: 'boolean',
|
|
55
55
|
},
|
|
56
|
+
skipMath: {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
},
|
|
59
|
+
skipInlineMath: {
|
|
60
|
+
type: 'boolean',
|
|
61
|
+
},
|
|
56
62
|
},
|
|
57
63
|
additionalProperties: false,
|
|
58
64
|
},
|
|
@@ -62,6 +68,8 @@ export default {
|
|
|
62
68
|
allow: [],
|
|
63
69
|
skipCode: true,
|
|
64
70
|
skipInlineCode: true,
|
|
71
|
+
skipMath: false,
|
|
72
|
+
skipInlineMath: false,
|
|
65
73
|
},
|
|
66
74
|
],
|
|
67
75
|
messages: {
|
|
@@ -73,7 +81,7 @@ export default {
|
|
|
73
81
|
},
|
|
74
82
|
create(context) {
|
|
75
83
|
const { sourceCode } = context;
|
|
76
|
-
const [{ allow, skipCode, skipInlineCode }] = context.options;
|
|
84
|
+
const [{ allow, skipCode, skipInlineCode, skipMath, skipInlineMath }] = context.options;
|
|
77
85
|
const skipRanges = new SkipRanges();
|
|
78
86
|
return {
|
|
79
87
|
code(node) {
|
|
@@ -84,6 +92,14 @@ export default {
|
|
|
84
92
|
if (skipInlineCode)
|
|
85
93
|
skipRanges.push(sourceCode.getRange(node)); // Store range information of `InlineCode`.
|
|
86
94
|
},
|
|
95
|
+
math(node) {
|
|
96
|
+
if (skipMath)
|
|
97
|
+
skipRanges.push(sourceCode.getRange(node)); // Store range information of `Math`.
|
|
98
|
+
},
|
|
99
|
+
inlineMath(node) {
|
|
100
|
+
if (skipInlineMath)
|
|
101
|
+
skipRanges.push(sourceCode.getRange(node)); // Store range information of `InlineMath`.
|
|
102
|
+
},
|
|
87
103
|
'root:exit'() {
|
|
88
104
|
const matches = sourceCode.text.matchAll(controlCharacterRegex);
|
|
89
105
|
for (const match of matches) {
|
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
// Import
|
|
7
7
|
// --------------------------------------------------------------------------------
|
|
8
8
|
import { escapeStringRegexp } from '../core/utils/index.js';
|
|
9
|
-
import { URL_RULE_DOCS, asciiPunctuationWithQuestionMark } from '../core/constants.js';
|
|
9
|
+
import { URL_RULE_DOCS, asciiPunctuationWithQuestionMark, gemojiRegex as originalGemojiRegex, htmlEntityRegex as originalHtmlEntityRegex, } from '../core/constants.js';
|
|
10
10
|
// --------------------------------------------------------------------------------
|
|
11
11
|
// Helper
|
|
12
12
|
// --------------------------------------------------------------------------------
|
|
13
13
|
const escapedAsciiPunctuationWithQuestionMark = escapeStringRegexp(asciiPunctuationWithQuestionMark.join(''));
|
|
14
|
+
const gemojiRegex = new RegExp(originalGemojiRegex.source, 'g');
|
|
15
|
+
const htmlEntityRegex = new RegExp(originalHtmlEntityRegex.source, 'g');
|
|
14
16
|
/**
|
|
15
17
|
* This pattern is based on the punctuation list used by `remark-lint`.
|
|
16
18
|
* @see https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-punctuation#parameters
|
|
@@ -67,7 +69,11 @@ export default {
|
|
|
67
69
|
return {
|
|
68
70
|
text(node) {
|
|
69
71
|
const [nodeStartOffset] = sourceCode.getRange(node);
|
|
70
|
-
const matches = sourceCode
|
|
72
|
+
const matches = sourceCode
|
|
73
|
+
.getText(node) // Mask HTML entities and gemoji without changing their offsets in the original text.
|
|
74
|
+
.replace(gemojiRegex, match => ' '.repeat(match.length))
|
|
75
|
+
.replace(htmlEntityRegex, match => ' '.repeat(match.length))
|
|
76
|
+
.matchAll(doublePunctuationRegex);
|
|
71
77
|
for (const match of matches) {
|
|
72
78
|
const punctuation = match[0];
|
|
73
79
|
const startOffset = nodeStartOffset + match.index;
|
|
@@ -6,20 +6,12 @@
|
|
|
6
6
|
// Import
|
|
7
7
|
// --------------------------------------------------------------------------------
|
|
8
8
|
import { escapeStringRegexp } from '../core/utils/index.js';
|
|
9
|
-
import { URL_RULE_DOCS, punctuation as defaultPunctuation, escapedTrailingBackslashRegex, gemojiRegex, } from '../core/constants.js';
|
|
9
|
+
import { URL_RULE_DOCS, punctuation as defaultPunctuation, escapedTrailingBackslashRegex, gemojiRegex, htmlEntityRegex, } from '../core/constants.js';
|
|
10
10
|
// --------------------------------------------------------------------------------
|
|
11
11
|
// Helper
|
|
12
12
|
// --------------------------------------------------------------------------------
|
|
13
|
-
/**
|
|
14
|
-
* Regular expression for identifying a GitHub emoji code at the end of a line.
|
|
15
|
-
*/
|
|
16
13
|
const trailingGemojiRegex = new RegExp(`${gemojiRegex.source}$`, gemojiRegex.flags);
|
|
17
|
-
|
|
18
|
-
* Regular expression for identifying an HTML entity at the end of a line.
|
|
19
|
-
* - NOTE: These patterns are based on the `markdownlint`.
|
|
20
|
-
* @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/helpers/helpers.cjs#L32-L34
|
|
21
|
-
*/
|
|
22
|
-
const trailingHtmlEntityRegex = /&(?:#\d+|#[xX][\da-fA-F]+|[a-zA-Z]{2,31}|blk\d{2}|emsp1[34]|frac\d{2}|sup\d|there4);$/;
|
|
14
|
+
const trailingHtmlEntityRegex = new RegExp(`${htmlEntityRegex.source}$`, htmlEntityRegex.flags);
|
|
23
15
|
// --------------------------------------------------------------------------------
|
|
24
16
|
// Rule Definition
|
|
25
17
|
// --------------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-markdown",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Lint your Markdown with ESLint. Additional rules for use with `@eslint/markdown`.🛠️",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"prepublishOnly": "npm run build",
|
|
60
|
-
"build": "tsc -b tsconfig.build.json && node ../../scripts/build-config.js && tsc -b tsconfig.build.json && node ../../scripts/cp.js ../../
|
|
60
|
+
"build": "tsc -b tsconfig.build.json && node ../../scripts/build-config.js && tsc -b tsconfig.build.json && node ../../scripts/cp.js ../../README.md README.md",
|
|
61
61
|
"test": "npm run test:types && npm run test:unit",
|
|
62
62
|
"test:types": "tsc -b ./tsconfig.test-d.json",
|
|
63
63
|
"test:unit": "vitest run"
|