eslint-markdown 0.15.0 → 0.16.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.
@@ -23,6 +23,7 @@ export default function all(plugin: ESLint.Plugin): {
23
23
  readonly 'md/consistent-code-style': "error";
24
24
  readonly 'md/consistent-delete-style': "error";
25
25
  readonly 'md/consistent-emphasis-style': "error";
26
+ readonly 'md/consistent-heading-style': "error";
26
27
  readonly 'md/consistent-inline-code-style': "error";
27
28
  readonly 'md/consistent-strong-style': "error";
28
29
  readonly 'md/consistent-thematic-break-style': "error";
@@ -31,6 +31,7 @@ export default function all(plugin) {
31
31
  'md/consistent-code-style': 'error',
32
32
  'md/consistent-delete-style': 'error',
33
33
  'md/consistent-emphasis-style': 'error',
34
+ 'md/consistent-heading-style': 'error',
34
35
  'md/consistent-inline-code-style': 'error',
35
36
  'md/consistent-strong-style': 'error',
36
37
  'md/consistent-thematic-break-style': 'error',
@@ -19,6 +19,7 @@ export default function stylistic(plugin: ESLint.Plugin): {
19
19
  readonly 'md/consistent-code-style': "error";
20
20
  readonly 'md/consistent-delete-style': "error";
21
21
  readonly 'md/consistent-emphasis-style': "error";
22
+ readonly 'md/consistent-heading-style': "error";
22
23
  readonly 'md/consistent-inline-code-style': "error";
23
24
  readonly 'md/consistent-strong-style': "error";
24
25
  readonly 'md/consistent-thematic-break-style': "error";
@@ -27,6 +27,7 @@ export default function stylistic(plugin) {
27
27
  'md/consistent-code-style': 'error',
28
28
  'md/consistent-delete-style': 'error',
29
29
  'md/consistent-emphasis-style': 'error',
30
+ 'md/consistent-heading-style': 'error',
30
31
  'md/consistent-inline-code-style': 'error',
31
32
  'md/consistent-strong-style': 'error',
32
33
  'md/consistent-thematic-break-style': 'error',
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @fileoverview Rule to enforce consistent heading style.
3
+ * @author Ga eun Lee(tooth-is-silver)
4
+ * @author lumir(lumirlumir)
5
+ * @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/lib/md003.mjs
6
+ */
7
+ import type { Heading } from 'mdast';
8
+ type HeadingStyle = (typeof HEADING_STYLE)[number];
9
+ type RuleOptions = [{
10
+ style: HeadingStyle;
11
+ }];
12
+ type MessageIds = 'style' | 'suggestAtxToSetext' | 'suggestAtxClosedToSetext';
13
+ declare const HEADING_STYLE: readonly ["consistent", "atx", "atx-closed", "setext", "setext-with-atx", "setext-with-atx-closed"];
14
+ declare const _default: {
15
+ readonly meta: {
16
+ readonly type: "layout";
17
+ readonly docs: {
18
+ readonly description: "Enforce consistent heading style";
19
+ readonly url: string;
20
+ readonly recommended: false;
21
+ readonly stylistic: true;
22
+ };
23
+ readonly fixable: "code";
24
+ readonly hasSuggestions: true;
25
+ readonly schema: [{
26
+ readonly type: "object";
27
+ readonly properties: {
28
+ readonly style: {
29
+ readonly enum: readonly ["consistent", "atx", "atx-closed", "setext", "setext-with-atx", "setext-with-atx-closed"];
30
+ };
31
+ };
32
+ readonly additionalProperties: false;
33
+ }];
34
+ readonly defaultOptions: [{
35
+ readonly style: "consistent";
36
+ }];
37
+ readonly messages: {
38
+ readonly style: "Heading style should be `{{ style }}`.";
39
+ readonly suggestAtxToSetext: "Replace ATX heading with a Setext heading.";
40
+ readonly suggestAtxClosedToSetext: "Replace ATX closed heading with a Setext heading.";
41
+ };
42
+ readonly language: "markdown";
43
+ readonly dialects: ["commonmark", "gfm"];
44
+ };
45
+ readonly create: (context: import("../core/types.js").RuleContext<{
46
+ RuleOptions: RuleOptions;
47
+ MessageIds: MessageIds;
48
+ }>) => {
49
+ heading(node: Heading): void;
50
+ "heading[depth<=2]"(): void;
51
+ "heading[depth>2]"(): void;
52
+ 'heading:exit'(node: Heading): void;
53
+ };
54
+ };
55
+ export default _default;
@@ -0,0 +1,290 @@
1
+ /**
2
+ * @fileoverview Rule to enforce consistent heading style.
3
+ * @author Ga eun Lee(tooth-is-silver)
4
+ * @author lumir(lumirlumir)
5
+ * @see https://github.com/DavidAnson/markdownlint/blob/v0.41.1/lib/md003.mjs
6
+ */
7
+ import { URL_RULE_DOCS } from '../core/constants.js';
8
+ // --------------------------------------------------------------------------------
9
+ // Helper
10
+ // --------------------------------------------------------------------------------
11
+ const SETEXT_MAX_DEPTH = 2;
12
+ const HEADING_STYLE = [
13
+ 'consistent',
14
+ 'atx',
15
+ 'atx-closed',
16
+ 'setext',
17
+ 'setext-with-atx',
18
+ 'setext-with-atx-closed',
19
+ ];
20
+ /**
21
+ * Matches the closing sequence of a closed ATX heading.
22
+ * @see https://spec.commonmark.org/0.31.2/#atx-headings
23
+ */
24
+ const trailingAtxHeadingHashRegex = /[ \t]#+[ \t]*$/;
25
+ /**
26
+ * Returns the setext marker for the given heading depth.
27
+ * @param depth The depth of the heading (`1` or `2`).
28
+ * @returns The setext marker for the given heading depth.
29
+ */
30
+ function getSetextMarker(depth) {
31
+ return depth === 1 ? '=' : '-';
32
+ }
33
+ // --------------------------------------------------------------------------------
34
+ // Rule Definition
35
+ // --------------------------------------------------------------------------------
36
+ export default {
37
+ meta: {
38
+ type: 'layout',
39
+ docs: {
40
+ description: 'Enforce consistent heading style',
41
+ url: URL_RULE_DOCS('consistent-heading-style'),
42
+ recommended: false,
43
+ stylistic: true,
44
+ },
45
+ fixable: 'code',
46
+ hasSuggestions: true,
47
+ schema: [
48
+ {
49
+ type: 'object',
50
+ properties: {
51
+ style: {
52
+ enum: HEADING_STYLE,
53
+ },
54
+ },
55
+ additionalProperties: false,
56
+ },
57
+ ],
58
+ defaultOptions: [
59
+ {
60
+ style: 'consistent',
61
+ },
62
+ ],
63
+ messages: {
64
+ style: 'Heading style should be `{{ style }}`.',
65
+ suggestAtxToSetext: 'Replace ATX heading with a Setext heading.',
66
+ suggestAtxClosedToSetext: 'Replace ATX closed heading with a Setext heading.',
67
+ },
68
+ language: 'markdown',
69
+ dialects: ['commonmark', 'gfm'],
70
+ },
71
+ create(context) {
72
+ const { sourceCode } = context;
73
+ const [{ style }] = context.options;
74
+ let headingStyle = style === 'consistent' ? null : style;
75
+ let currentHeadingStyle = null;
76
+ let expectedHeadingStyle = null;
77
+ function reportStyle(node, fix = null, ...suggest) {
78
+ context.report({
79
+ node,
80
+ messageId: 'style',
81
+ data: {
82
+ style: expectedHeadingStyle,
83
+ },
84
+ fix,
85
+ suggest,
86
+ });
87
+ }
88
+ return {
89
+ // The `heading` selector is more general, so it is visited before the other `heading[xxx]` selectors.
90
+ heading(node) {
91
+ const { start, end } = sourceCode.getLoc(node);
92
+ if (start.line !== end.line /* Multiline Heading */) {
93
+ currentHeadingStyle = 'setext';
94
+ }
95
+ else if (trailingAtxHeadingHashRegex.test(sourceCode.getText(node))) {
96
+ currentHeadingStyle = 'atx-closed';
97
+ }
98
+ else {
99
+ currentHeadingStyle = 'atx';
100
+ }
101
+ if (headingStyle === null) {
102
+ headingStyle = currentHeadingStyle;
103
+ }
104
+ },
105
+ [`heading[depth<=${SETEXT_MAX_DEPTH}]`]() {
106
+ if (headingStyle === 'setext-with-atx' ||
107
+ headingStyle === 'setext-with-atx-closed') {
108
+ expectedHeadingStyle = 'setext';
109
+ }
110
+ else {
111
+ expectedHeadingStyle = headingStyle;
112
+ }
113
+ },
114
+ [`heading[depth>${SETEXT_MAX_DEPTH}]`]() {
115
+ if (headingStyle === 'setext-with-atx') {
116
+ expectedHeadingStyle = 'atx';
117
+ }
118
+ else if (headingStyle === 'setext-with-atx-closed') {
119
+ expectedHeadingStyle = 'atx-closed';
120
+ }
121
+ else {
122
+ expectedHeadingStyle = headingStyle;
123
+ }
124
+ },
125
+ 'heading:exit'(node) {
126
+ if (currentHeadingStyle === expectedHeadingStyle) {
127
+ // Early return if the current heading style matches the expected heading style.
128
+ return;
129
+ }
130
+ /*
131
+ * Possible fix combinations include:
132
+ *
133
+ * - autofix: 🔧
134
+ * - suggestion: 💡
135
+ * - no fix: ❌
136
+ *
137
+ * 1. Converting `atx` to `atx-closed`.
138
+ * 1-1. If `atx` is empty, it can be converted to `atx-closed`. (🔧)
139
+ * 1-2. If `atx` is not empty, it can be converted to `atx-closed`. (🔧)
140
+ * 2. Converting `atx` to `setext`.
141
+ * 2-1. If `atx` is empty, it cannot be converted to `setext`. (❌)
142
+ * 2-2. If `atx` is not empty:
143
+ * 2-2-1. If its depth is 1 or 2, conversion can be offered as a suggestion. (💡)
144
+ * Some edge cases are unsafe: `# > Heading`, `# - Heading`, and `# 1. Heading`.
145
+ * 2-2-2. If its depth is greater than 2, it cannot be converted to `setext`. (❌)
146
+ * 3. Converting `atx-closed` to `atx`.
147
+ * 3-1. If `atx-closed` is empty, it can be converted to `atx`. (🔧)
148
+ * 3-2. If `atx-closed` is not empty, it can be converted to `atx`. (🔧)
149
+ * 4. Converting `atx-closed` to `setext`.
150
+ * 4-1. If `atx-closed` is empty, it cannot be converted to `setext`. (❌)
151
+ * 4-2. If `atx-closed` is not empty:
152
+ * 4-2-1. If its depth is 1 or 2, conversion can be offered as a suggestion. (💡)
153
+ * Some edge cases are unsafe: `# > Heading #`, `# - Heading #`, and `# 1. Heading #`.
154
+ * 4-2-2. If its depth is greater than 2, it cannot be converted to `setext`. (❌)
155
+ * 5. Converting `setext` to `atx`.
156
+ * 5-1. Setext headings cannot be empty (https://spec.commonmark.org/0.31.2/#example-97)
157
+ * 5-2. If `setext` is not empty:
158
+ * 5-2-1. If it is single-line, it can be converted to `atx`. (🔧)
159
+ * 5-2-2. If it is multiline, it cannot be converted to `atx`. (❌)
160
+ * 6. Converting `setext` to `atx-closed`.
161
+ * 6-1. Setext headings cannot be empty (https://spec.commonmark.org/0.31.2/#example-97)
162
+ * 6-2. If `setext` is not empty:
163
+ * 6-2-1. If it is single-line, it can be converted to `atx-closed`. (🔧)
164
+ * 6-2-2. If it is multiline, it cannot be converted to `atx-closed`. (❌)
165
+ */
166
+ const [nodeStartOffset, nodeEndOffset] = sourceCode.getRange(node);
167
+ // The final style checks are exhaustive after matching styles return early.
168
+ if (currentHeadingStyle === 'atx') {
169
+ if (expectedHeadingStyle === 'atx-closed') {
170
+ if (node.children.length === 0) {
171
+ reportStyle(node, function* fix(fixer) {
172
+ if (nodeStartOffset + node.depth === nodeEndOffset) {
173
+ yield fixer.insertTextAfter(node, ' ');
174
+ }
175
+ yield fixer.insertTextAfter(node, '#'.repeat(node.depth));
176
+ });
177
+ }
178
+ else {
179
+ reportStyle(node, function* fix(fixer) {
180
+ const [, lastChildNodeEndOffset] = sourceCode.getRange(node.children[node.children.length - 1]);
181
+ if (lastChildNodeEndOffset === nodeEndOffset) {
182
+ yield fixer.insertTextAfter(node, ' ');
183
+ }
184
+ yield fixer.insertTextAfter(node, '#'.repeat(node.depth));
185
+ });
186
+ }
187
+ /* v8 ignore start */
188
+ }
189
+ else if (expectedHeadingStyle === 'setext') {
190
+ /* v8 ignore stop */
191
+ if (node.children.length === 0) {
192
+ // Empty ATX headings cannot be converted to Setext headings,
193
+ // so report the mismatch without a fix.
194
+ reportStyle(node);
195
+ }
196
+ else if (node.depth <= SETEXT_MAX_DEPTH) {
197
+ reportStyle(node, null, {
198
+ messageId: 'suggestAtxToSetext',
199
+ *fix(fixer) {
200
+ const [firstChildNodeStartOffset] = sourceCode.getRange(node.children[0]);
201
+ const [, lastChildNodeEndOffset] = sourceCode.getRange(node.children[node.children.length - 1]);
202
+ yield fixer.removeRange([nodeStartOffset, firstChildNodeStartOffset]);
203
+ yield fixer.replaceTextRange([lastChildNodeEndOffset, nodeEndOffset], `\n${getSetextMarker(node.depth).repeat(lastChildNodeEndOffset - firstChildNodeStartOffset)}`);
204
+ },
205
+ });
206
+ }
207
+ else {
208
+ reportStyle(node);
209
+ }
210
+ }
211
+ }
212
+ else if (currentHeadingStyle === 'atx-closed') {
213
+ if (expectedHeadingStyle === 'atx') {
214
+ if (node.children.length === 0) {
215
+ reportStyle(node, fixer => fixer.removeRange([nodeStartOffset + node.depth, nodeEndOffset]));
216
+ }
217
+ else {
218
+ reportStyle(node, fixer => {
219
+ const [, lastChildNodeEndOffset] = sourceCode.getRange(node.children[node.children.length - 1]);
220
+ return fixer.removeRange([lastChildNodeEndOffset, nodeEndOffset]);
221
+ });
222
+ }
223
+ /* v8 ignore start */
224
+ }
225
+ else if (expectedHeadingStyle === 'setext') {
226
+ /* v8 ignore stop */
227
+ if (node.children.length === 0) {
228
+ // Empty ATX Closed headings cannot be converted to Setext headings,
229
+ // so report the mismatch without a fix.
230
+ reportStyle(node);
231
+ }
232
+ else if (node.depth <= SETEXT_MAX_DEPTH) {
233
+ reportStyle(node, null, {
234
+ messageId: 'suggestAtxClosedToSetext',
235
+ *fix(fixer) {
236
+ const [firstChildNodeStartOffset] = sourceCode.getRange(node.children[0]);
237
+ const [, lastChildNodeEndOffset] = sourceCode.getRange(node.children[node.children.length - 1]);
238
+ yield fixer.removeRange([nodeStartOffset, firstChildNodeStartOffset]);
239
+ yield fixer.replaceTextRange([lastChildNodeEndOffset, nodeEndOffset], `\n${getSetextMarker(node.depth).repeat(lastChildNodeEndOffset - firstChildNodeStartOffset)}`);
240
+ },
241
+ });
242
+ }
243
+ else {
244
+ reportStyle(node);
245
+ }
246
+ }
247
+ /* v8 ignore start */
248
+ }
249
+ else if (currentHeadingStyle === 'setext') {
250
+ /* v8 ignore stop */
251
+ const firstChildNode = node.children[0];
252
+ const lastChildNode = node.children[node.children.length - 1];
253
+ const { start } = sourceCode.getLoc(firstChildNode);
254
+ const { end } = sourceCode.getLoc(lastChildNode);
255
+ if (expectedHeadingStyle === 'atx') {
256
+ if (start.line === end.line /* Singleline Heading */) {
257
+ reportStyle(node, function* fix(fixer) {
258
+ const [lastChildNodeStartOffset, lastChildNodeEndOffset] = sourceCode.getRange(lastChildNode);
259
+ // Prevent trailing hashes from becoming an ATX closing sequence.
260
+ const match = trailingAtxHeadingHashRegex.exec(sourceCode.getText(lastChildNode));
261
+ if (match) {
262
+ yield fixer.insertTextBeforeRange([lastChildNodeStartOffset + match.index + 1, lastChildNodeEndOffset], '\\');
263
+ }
264
+ yield fixer.insertTextBefore(firstChildNode, `${'#'.repeat(node.depth)} `);
265
+ yield fixer.removeRange([lastChildNodeEndOffset, nodeEndOffset]);
266
+ });
267
+ }
268
+ else /* Multiline Heading */ {
269
+ reportStyle(node);
270
+ }
271
+ /* v8 ignore start */
272
+ }
273
+ else if (expectedHeadingStyle === 'atx-closed') {
274
+ /* v8 ignore stop */
275
+ if (start.line === end.line /* Singleline Heading */) {
276
+ reportStyle(node, function* fix(fixer) {
277
+ const [, lastChildNodeEndOffset] = sourceCode.getRange(lastChildNode);
278
+ yield fixer.insertTextBefore(firstChildNode, `${'#'.repeat(node.depth)} `);
279
+ yield fixer.replaceTextRange([lastChildNodeEndOffset, nodeEndOffset], ` ${'#'.repeat(node.depth)}`);
280
+ });
281
+ }
282
+ else /* Multiline Heading */ {
283
+ reportStyle(node);
284
+ }
285
+ }
286
+ }
287
+ },
288
+ };
289
+ },
290
+ };
@@ -566,6 +566,49 @@ declare const _default: {
566
566
  emphasis(node: import("mdast").Emphasis): void;
567
567
  };
568
568
  };
569
+ 'consistent-heading-style': {
570
+ readonly meta: {
571
+ readonly type: "layout";
572
+ readonly docs: {
573
+ readonly description: "Enforce consistent heading style";
574
+ readonly url: string;
575
+ readonly recommended: false;
576
+ readonly stylistic: true;
577
+ };
578
+ readonly fixable: "code";
579
+ readonly hasSuggestions: true;
580
+ readonly schema: [{
581
+ readonly type: "object";
582
+ readonly properties: {
583
+ readonly style: {
584
+ readonly enum: readonly ["consistent", "atx", "atx-closed", "setext", "setext-with-atx", "setext-with-atx-closed"];
585
+ };
586
+ };
587
+ readonly additionalProperties: false;
588
+ }];
589
+ readonly defaultOptions: [{
590
+ readonly style: "consistent";
591
+ }];
592
+ readonly messages: {
593
+ readonly style: "Heading style should be `{{ style }}`.";
594
+ readonly suggestAtxToSetext: "Replace ATX heading with a Setext heading.";
595
+ readonly suggestAtxClosedToSetext: "Replace ATX closed heading with a Setext heading.";
596
+ };
597
+ readonly language: "markdown";
598
+ readonly dialects: ["commonmark", "gfm"];
599
+ };
600
+ readonly create: (context: import("../core/types.js").RuleContext<{
601
+ RuleOptions: [{
602
+ style: "consistent" | "atx" | "atx-closed" | "setext" | "setext-with-atx" | "setext-with-atx-closed";
603
+ }];
604
+ MessageIds: "style" | "suggestAtxToSetext" | "suggestAtxClosedToSetext";
605
+ }>) => {
606
+ heading(node: import("mdast").Heading): void;
607
+ "heading[depth<=2]"(): void;
608
+ "heading[depth>2]"(): void;
609
+ 'heading:exit'(node: import("mdast").Heading): void;
610
+ };
611
+ };
569
612
  'consistent-inline-code-style': {
570
613
  readonly meta: {
571
614
  readonly type: "layout";
@@ -694,7 +737,7 @@ declare const _default: {
694
737
  };
695
738
  readonly create: (context: import("../core/types.js").RuleContext<{
696
739
  RuleOptions: [{
697
- style: "consistent" | "sublist" | ("*" | "+" | "-");
740
+ style: "consistent" | "sublist" | ("*" | "-" | "+");
698
741
  }];
699
742
  MessageIds: "style";
700
743
  }>) => {
@@ -1139,6 +1182,12 @@ declare const _default: {
1139
1182
  readonly skipInlineCode: {
1140
1183
  readonly type: "boolean";
1141
1184
  };
1185
+ readonly skipMath: {
1186
+ readonly type: "boolean";
1187
+ };
1188
+ readonly skipInlineMath: {
1189
+ readonly type: "boolean";
1190
+ };
1142
1191
  };
1143
1192
  readonly additionalProperties: false;
1144
1193
  }];
@@ -1146,6 +1195,8 @@ declare const _default: {
1146
1195
  readonly allow: [];
1147
1196
  readonly skipCode: true;
1148
1197
  readonly skipInlineCode: true;
1198
+ readonly skipMath: true;
1199
+ readonly skipInlineMath: true;
1149
1200
  }];
1150
1201
  readonly messages: {
1151
1202
  readonly noIrregularWhitespace: "Irregular whitespace `{{ irregularWhitespace }}` is not allowed.";
@@ -1158,11 +1209,15 @@ declare const _default: {
1158
1209
  allow: string[];
1159
1210
  skipCode: boolean | string[];
1160
1211
  skipInlineCode: boolean;
1212
+ skipMath: boolean;
1213
+ skipInlineMath: boolean;
1161
1214
  }];
1162
1215
  MessageIds: "noIrregularWhitespace";
1163
1216
  }>) => {
1164
1217
  code(node: import("mdast").Code): void;
1165
1218
  inlineCode(node: import("mdast").InlineCode): void;
1219
+ math(node: import("mdast-util-math").Math): void;
1220
+ inlineMath(node: import("mdast-util-math").InlineMath): void;
1166
1221
  'root:exit'(): void;
1167
1222
  };
1168
1223
  };
@@ -7,6 +7,7 @@ import codeLangShorthand from './code-lang-shorthand.js';
7
7
  import consistentCodeStyle from './consistent-code-style.js';
8
8
  import consistentDeleteStyle from './consistent-delete-style.js';
9
9
  import consistentEmphasisStyle from './consistent-emphasis-style.js';
10
+ import consistentHeadingStyle from './consistent-heading-style.js';
10
11
  import consistentInlineCodeStyle from './consistent-inline-code-style.js';
11
12
  import consistentStrongStyle from './consistent-strong-style.js';
12
13
  import consistentThematicBreakStyle from './consistent-thematic-break-style.js';
@@ -35,6 +36,7 @@ export default {
35
36
  'consistent-code-style': consistentCodeStyle,
36
37
  'consistent-delete-style': consistentDeleteStyle,
37
38
  'consistent-emphasis-style': consistentEmphasisStyle,
39
+ 'consistent-heading-style': consistentHeadingStyle,
38
40
  'consistent-inline-code-style': consistentInlineCodeStyle,
39
41
  'consistent-strong-style': consistentStrongStyle,
40
42
  'consistent-thematic-break-style': consistentThematicBreakStyle,
@@ -13,7 +13,7 @@ type RuleOptions = [
13
13
  */
14
14
  skipCode: boolean | string[];
15
15
  /**
16
- * `true` allows Git conflict markers in math blocks.
16
+ * `true` allows Git conflict markers in all math blocks.
17
17
  * @default true
18
18
  */
19
19
  skipMath: boolean;
@@ -24,6 +24,16 @@ type RuleOptions = [
24
24
  * @default true
25
25
  */
26
26
  skipInlineCode: boolean;
27
+ /**
28
+ * `true` allows irregular whitespaces in all math blocks.
29
+ * @default true
30
+ */
31
+ skipMath: boolean;
32
+ /**
33
+ * `true` allows irregular whitespaces in all inline math.
34
+ * @default true
35
+ */
36
+ skipInlineMath: boolean;
27
37
  }
28
38
  ];
29
39
  declare const _default: {
@@ -59,6 +69,12 @@ declare const _default: {
59
69
  readonly skipInlineCode: {
60
70
  readonly type: "boolean";
61
71
  };
72
+ readonly skipMath: {
73
+ readonly type: "boolean";
74
+ };
75
+ readonly skipInlineMath: {
76
+ readonly type: "boolean";
77
+ };
62
78
  };
63
79
  readonly additionalProperties: false;
64
80
  }];
@@ -66,6 +82,8 @@ declare const _default: {
66
82
  readonly allow: [];
67
83
  readonly skipCode: true;
68
84
  readonly skipInlineCode: true;
85
+ readonly skipMath: true;
86
+ readonly skipInlineMath: true;
69
87
  }];
70
88
  readonly messages: {
71
89
  readonly noIrregularWhitespace: "Irregular whitespace `{{ irregularWhitespace }}` is not allowed.";
@@ -79,6 +97,8 @@ declare const _default: {
79
97
  }>) => {
80
98
  code(node: import("mdast").Code): void;
81
99
  inlineCode(node: import("mdast").InlineCode): void;
100
+ math(node: import("mdast-util-math").Math): void;
101
+ inlineMath(node: import("mdast-util-math").InlineMath): void;
82
102
  'root:exit'(): void;
83
103
  };
84
104
  };
@@ -51,6 +51,12 @@ export default {
51
51
  skipInlineCode: {
52
52
  type: 'boolean',
53
53
  },
54
+ skipMath: {
55
+ type: 'boolean',
56
+ },
57
+ skipInlineMath: {
58
+ type: 'boolean',
59
+ },
54
60
  },
55
61
  additionalProperties: false,
56
62
  },
@@ -60,6 +66,8 @@ export default {
60
66
  allow: [],
61
67
  skipCode: true,
62
68
  skipInlineCode: true,
69
+ skipMath: true,
70
+ skipInlineMath: true,
63
71
  },
64
72
  ],
65
73
  messages: {
@@ -70,7 +78,7 @@ export default {
70
78
  },
71
79
  create(context) {
72
80
  const { sourceCode } = context;
73
- const [{ allow, skipCode, skipInlineCode }] = context.options;
81
+ const [{ allow, skipCode, skipInlineCode, skipMath, skipInlineMath }] = context.options;
74
82
  const skipRanges = new SkipRanges();
75
83
  return {
76
84
  code(node) {
@@ -81,6 +89,14 @@ export default {
81
89
  if (skipInlineCode)
82
90
  skipRanges.push(sourceCode.getRange(node)); // Store range information of `InlineCode`.
83
91
  },
92
+ math(node) {
93
+ if (skipMath)
94
+ skipRanges.push(sourceCode.getRange(node)); // Store range information of `Math`.
95
+ },
96
+ inlineMath(node) {
97
+ if (skipInlineMath)
98
+ skipRanges.push(sourceCode.getRange(node)); // Store range information of `InlineMath`.
99
+ },
84
100
  'root:exit'() {
85
101
  const matches = sourceCode.text.matchAll(irregularWhitespaceRegex);
86
102
  for (const match of matches) {
@@ -38,7 +38,7 @@ function hasTrailingSlash(url) {
38
38
  * -------------------------------------------------^
39
39
  */
40
40
  if (hash) {
41
- urlWithoutSearchAndHash = urlWithoutSearchAndHash.slice(0, url.indexOf(hash));
41
+ urlWithoutSearchAndHash = urlWithoutSearchAndHash.slice(0, url.indexOf('#'));
42
42
  }
43
43
  else if (urlWithoutSearchAndHash.endsWith('#')) {
44
44
  urlWithoutSearchAndHash = urlWithoutSearchAndHash.slice(0, -1);
@@ -56,7 +56,7 @@ function hasTrailingSlash(url) {
56
56
  * ------------------------------------^
57
57
  */
58
58
  if (search) {
59
- urlWithoutSearchAndHash = urlWithoutSearchAndHash.slice(0, url.indexOf(search));
59
+ urlWithoutSearchAndHash = urlWithoutSearchAndHash.slice(0, url.indexOf('?'));
60
60
  }
61
61
  else if (urlWithoutSearchAndHash.endsWith('?')) {
62
62
  urlWithoutSearchAndHash = urlWithoutSearchAndHash.slice(0, -1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-markdown",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Lint your Markdown with ESLint. Additional rules for use with `@eslint/markdown`.🛠️",