markdownlint 0.34.0 → 0.35.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/CHANGELOG.md +11 -0
- package/README.md +25 -10
- package/demo/markdownlint-browser.js +1144 -1166
- package/doc/CustomRules.md +11 -6
- package/doc/Rules.md +66 -0
- package/doc/md034.md +5 -0
- package/doc/md044.md +10 -0
- package/doc/md058.md +48 -0
- package/helpers/README.md +3 -29
- package/helpers/helpers.js +56 -288
- package/helpers/micromark.cjs +111 -12
- package/helpers/package.json +1 -1
- package/lib/cache.js +62 -13
- package/lib/configuration-strict.d.ts +1185 -0
- package/lib/configuration.d.ts +3 -1173
- package/lib/constants.js +3 -2
- package/lib/markdownlint.d.ts +65 -56
- package/lib/markdownlint.js +59 -37
- package/lib/md001.js +15 -9
- package/lib/md003.js +14 -9
- package/lib/md004.js +55 -48
- package/lib/md005.js +4 -13
- package/lib/md007.js +5 -9
- package/lib/md009.js +50 -44
- package/lib/md010.js +48 -33
- package/lib/md011.js +16 -8
- package/lib/md012.js +17 -9
- package/lib/md013.js +44 -38
- package/lib/md014.js +35 -38
- package/lib/md018.js +17 -9
- package/lib/md019-md021.js +80 -0
- package/lib/md020.js +13 -7
- package/lib/md022.js +6 -16
- package/lib/md023.js +22 -23
- package/lib/md024.js +12 -9
- package/lib/md025.js +15 -10
- package/lib/md026.js +2 -7
- package/lib/md027.js +5 -10
- package/lib/md028.js +3 -8
- package/lib/md029.js +40 -34
- package/lib/md030.js +4 -10
- package/lib/md031.js +43 -23
- package/lib/md032.js +16 -26
- package/lib/md033.js +3 -8
- package/lib/md034.js +5 -10
- package/lib/md035.js +2 -7
- package/lib/md036.js +3 -2
- package/lib/md037.js +2 -7
- package/lib/md038.js +3 -9
- package/lib/md039.js +66 -54
- package/lib/md040.js +3 -8
- package/lib/md041.js +1 -1
- package/lib/md042.js +48 -38
- package/lib/md043.js +20 -14
- package/lib/md044.js +3 -8
- package/lib/md045.js +3 -8
- package/lib/md046.js +2 -8
- package/lib/md048.js +3 -7
- package/lib/md049-md050.js +2 -7
- package/lib/md051.js +6 -12
- package/lib/md052.js +2 -2
- package/lib/md053.js +2 -2
- package/lib/md054.js +8 -13
- package/lib/md055.js +7 -8
- package/lib/md056.js +15 -11
- package/lib/md058.js +43 -0
- package/lib/rules.js +11 -4
- package/package.json +19 -17
- package/schema/.markdownlint.jsonc +54 -51
- package/schema/.markdownlint.yaml +53 -50
- package/schema/ValidatingConfiguration.md +6 -8
- package/schema/markdownlint-config-schema-strict.json +1819 -0
- package/schema/markdownlint-config-schema.json +115 -105
- package/style/prettier.json +1 -0
- package/lib/md019.js +0 -42
- package/lib/md021.js +0 -65
package/doc/CustomRules.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Custom Rules
|
|
2
2
|
|
|
3
3
|
In addition to its built-in rules, `markdownlint` lets you enhance the linting
|
|
4
|
-
experience by passing
|
|
4
|
+
experience by passing an array of custom rules using the [`options.customRules`
|
|
5
5
|
property][options-custom-rules]. Custom rules can do everything the built-in
|
|
6
6
|
rules can and are defined inline or imported from another package ([keyword
|
|
7
|
-
`markdownlint-rule` on npm][markdownlint-rule]).
|
|
8
|
-
|
|
7
|
+
`markdownlint-rule` on npm][markdownlint-rule]). When defined by a file or
|
|
8
|
+
package, the export can be a single rule object (see below) or an array of them.
|
|
9
|
+
Custom rules can be disabled, enabled, and customized using the same syntax as
|
|
10
|
+
built-in rules.
|
|
9
11
|
|
|
10
12
|
## Implementing Simple Rules
|
|
11
13
|
|
|
@@ -129,8 +131,9 @@ exception.
|
|
|
129
131
|
|
|
130
132
|
- [Simple rules used by the project's test cases][test-rules]
|
|
131
133
|
- [Code for all `markdownlint` built-in rules][lib]
|
|
132
|
-
- [
|
|
133
|
-
|
|
134
|
+
- [Complete example rule including npm configuration][extended-ascii]
|
|
135
|
+
- [Custom rules from the github/docs repository][github-docs]
|
|
136
|
+
- [Custom rules from the electron/lint-roller repository][electron]
|
|
134
137
|
- [Custom rules from the webhintio/hint repository][hint]
|
|
135
138
|
|
|
136
139
|
## References
|
|
@@ -372,6 +375,9 @@ Yields the `params` object:
|
|
|
372
375
|
```
|
|
373
376
|
|
|
374
377
|
[commonmark]: https://commonmark.org/
|
|
378
|
+
[electron]: https://github.com/electron/lint-roller/tree/main/markdownlint-rules
|
|
379
|
+
[extended-ascii]: https://github.com/DavidAnson/markdownlint-rule-extended-ascii
|
|
380
|
+
[github-docs]: https://github.com/github/docs/tree/main/src/content-linter/lib/linting-rules
|
|
375
381
|
[hint]: https://github.com/webhintio/hint/blob/main/scripts/lint-markdown.js
|
|
376
382
|
[lib]: ../lib
|
|
377
383
|
[markdown-it]: https://github.com/markdown-it/markdown-it
|
|
@@ -380,4 +386,3 @@ Yields the `params` object:
|
|
|
380
386
|
[rule-helpers]: https://www.npmjs.com/package/markdownlint-rule-helpers
|
|
381
387
|
[options-custom-rules]: ../README.md#optionscustomrules
|
|
382
388
|
[test-rules]: ../test/rules
|
|
383
|
-
[test-rules-npm]: ../test/rules/npm
|
package/doc/Rules.md
CHANGED
|
@@ -1354,6 +1354,11 @@ To fix this, add angle brackets around the URL or email address:
|
|
|
1354
1354
|
For more info, visit <https://www.example.com/> or email <user@example.com>.
|
|
1355
1355
|
```
|
|
1356
1356
|
|
|
1357
|
+
If a URL or email address contains non-ASCII characters, it may be not be
|
|
1358
|
+
handled as intended even when angle brackets are present. In such cases,
|
|
1359
|
+
[percent-encoding](https://en.m.wikipedia.org/wiki/Percent-encoding) can be used
|
|
1360
|
+
to comply with the required syntax for URL and email.
|
|
1361
|
+
|
|
1357
1362
|
Note: To include a bare URL or email without it being converted into a link,
|
|
1358
1363
|
wrap it in a code span:
|
|
1359
1364
|
|
|
@@ -1829,6 +1834,16 @@ enforce the proper capitalization, specify the desired letter case in the
|
|
|
1829
1834
|
]
|
|
1830
1835
|
```
|
|
1831
1836
|
|
|
1837
|
+
Sometimes a proper name is capitalized differently in certain contexts. In such
|
|
1838
|
+
cases, add both forms to the `names` array:
|
|
1839
|
+
|
|
1840
|
+
```json
|
|
1841
|
+
[
|
|
1842
|
+
"GitHub",
|
|
1843
|
+
"github.com"
|
|
1844
|
+
]
|
|
1845
|
+
```
|
|
1846
|
+
|
|
1832
1847
|
Set the `code_blocks` parameter to `false` to disable this rule for code blocks
|
|
1833
1848
|
and spans. Set the `html_elements` parameter to `false` to disable this rule
|
|
1834
1849
|
for HTML elements and attributes (such as when using a proper name as part of
|
|
@@ -2453,6 +2468,57 @@ Missing cells in a row create holes in the table and suggest an omission.
|
|
|
2453
2468
|
|
|
2454
2469
|
[gfm-table-056]: https://github.github.com/gfm/#tables-extension-
|
|
2455
2470
|
|
|
2471
|
+
<a name="md058"></a>
|
|
2472
|
+
|
|
2473
|
+
## `MD058` - Tables should be surrounded by blank lines
|
|
2474
|
+
|
|
2475
|
+
Tags: `table`
|
|
2476
|
+
|
|
2477
|
+
Aliases: `blanks-around-tables`
|
|
2478
|
+
|
|
2479
|
+
Fixable: Some violations can be fixed by tooling
|
|
2480
|
+
|
|
2481
|
+
This rule is triggered when tables are either not preceded or not followed by a
|
|
2482
|
+
blank line:
|
|
2483
|
+
|
|
2484
|
+
```markdown
|
|
2485
|
+
Some text
|
|
2486
|
+
| Header | Header |
|
|
2487
|
+
| ------ | ------ |
|
|
2488
|
+
| Cell | Cell |
|
|
2489
|
+
> Blockquote
|
|
2490
|
+
```
|
|
2491
|
+
|
|
2492
|
+
To fix violations of this rule, ensure that all tables have a blank line both
|
|
2493
|
+
before and after (except when the table is at the very beginning or end of the
|
|
2494
|
+
document):
|
|
2495
|
+
|
|
2496
|
+
```markdown
|
|
2497
|
+
Some text
|
|
2498
|
+
|
|
2499
|
+
| Header | Header |
|
|
2500
|
+
| ------ | ------ |
|
|
2501
|
+
| Cell | Cell |
|
|
2502
|
+
|
|
2503
|
+
> Blockquote
|
|
2504
|
+
```
|
|
2505
|
+
|
|
2506
|
+
Note that text immediately following a table (i.e., not separated by an empty
|
|
2507
|
+
line) is treated as part of the table (per the specification) and will not
|
|
2508
|
+
trigger this rule:
|
|
2509
|
+
|
|
2510
|
+
```markdown
|
|
2511
|
+
| Header | Header |
|
|
2512
|
+
| ------ | ------ |
|
|
2513
|
+
| Cell | Cell |
|
|
2514
|
+
This text is part of the table and the next line is blank
|
|
2515
|
+
|
|
2516
|
+
Some text
|
|
2517
|
+
```
|
|
2518
|
+
|
|
2519
|
+
Rationale: In addition to aesthetic reasons, some parsers will incorrectly parse
|
|
2520
|
+
tables that don't have blank lines before and after them.
|
|
2521
|
+
|
|
2456
2522
|
<!-- markdownlint-configure-file {
|
|
2457
2523
|
"no-inline-html": {
|
|
2458
2524
|
"allowed_elements": [
|
package/doc/md034.md
CHANGED
|
@@ -19,6 +19,11 @@ To fix this, add angle brackets around the URL or email address:
|
|
|
19
19
|
For more info, visit <https://www.example.com/> or email <user@example.com>.
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
If a URL or email address contains non-ASCII characters, it may be not be
|
|
23
|
+
handled as intended even when angle brackets are present. In such cases,
|
|
24
|
+
[percent-encoding](https://en.m.wikipedia.org/wiki/Percent-encoding) can be used
|
|
25
|
+
to comply with the required syntax for URL and email.
|
|
26
|
+
|
|
22
27
|
Note: To include a bare URL or email without it being converted into a link,
|
|
23
28
|
wrap it in a code span:
|
|
24
29
|
|
package/doc/md044.md
CHANGED
|
@@ -27,6 +27,16 @@ enforce the proper capitalization, specify the desired letter case in the
|
|
|
27
27
|
]
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
Sometimes a proper name is capitalized differently in certain contexts. In such
|
|
31
|
+
cases, add both forms to the `names` array:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
[
|
|
35
|
+
"GitHub",
|
|
36
|
+
"github.com"
|
|
37
|
+
]
|
|
38
|
+
```
|
|
39
|
+
|
|
30
40
|
Set the `code_blocks` parameter to `false` to disable this rule for code blocks
|
|
31
41
|
and spans. Set the `html_elements` parameter to `false` to disable this rule
|
|
32
42
|
for HTML elements and attributes (such as when using a proper name as part of
|
package/doc/md058.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `MD058` - Tables should be surrounded by blank lines
|
|
2
|
+
|
|
3
|
+
Tags: `table`
|
|
4
|
+
|
|
5
|
+
Aliases: `blanks-around-tables`
|
|
6
|
+
|
|
7
|
+
Fixable: Some violations can be fixed by tooling
|
|
8
|
+
|
|
9
|
+
This rule is triggered when tables are either not preceded or not followed by a
|
|
10
|
+
blank line:
|
|
11
|
+
|
|
12
|
+
```markdown
|
|
13
|
+
Some text
|
|
14
|
+
| Header | Header |
|
|
15
|
+
| ------ | ------ |
|
|
16
|
+
| Cell | Cell |
|
|
17
|
+
> Blockquote
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
To fix violations of this rule, ensure that all tables have a blank line both
|
|
21
|
+
before and after (except when the table is at the very beginning or end of the
|
|
22
|
+
document):
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
Some text
|
|
26
|
+
|
|
27
|
+
| Header | Header |
|
|
28
|
+
| ------ | ------ |
|
|
29
|
+
| Cell | Cell |
|
|
30
|
+
|
|
31
|
+
> Blockquote
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Note that text immediately following a table (i.e., not separated by an empty
|
|
35
|
+
line) is treated as part of the table (per the specification) and will not
|
|
36
|
+
trigger this rule:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
| Header | Header |
|
|
40
|
+
| ------ | ------ |
|
|
41
|
+
| Cell | Cell |
|
|
42
|
+
This text is part of the table and the next line is blank
|
|
43
|
+
|
|
44
|
+
Some text
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Rationale: In addition to aesthetic reasons, some parsers will incorrectly parse
|
|
48
|
+
tables that don't have blank lines before and after them.
|
package/helpers/README.md
CHANGED
|
@@ -19,32 +19,6 @@ be useful to custom rule authors and may avoid duplicating code.
|
|
|
19
19
|
|
|
20
20
|
## Examples
|
|
21
21
|
|
|
22
|
-
### Using Helpers from a Custom Rule
|
|
23
|
-
|
|
24
|
-
```javascript
|
|
25
|
-
const { forEachLine, getLineMetadata } = require("markdownlint-rule-helpers");
|
|
26
|
-
|
|
27
|
-
/** @type import("markdownlint").Rule */
|
|
28
|
-
module.exports = {
|
|
29
|
-
"names": [ "every-n-lines" ],
|
|
30
|
-
"description": "Rule that reports an error every N lines",
|
|
31
|
-
"tags": [ "test" ],
|
|
32
|
-
"parser": "none",
|
|
33
|
-
"function": (params, onError) => {
|
|
34
|
-
const n = params.config.n || 2;
|
|
35
|
-
forEachLine(getLineMetadata(params), (line, lineIndex) => {
|
|
36
|
-
const lineNumber = lineIndex + 1;
|
|
37
|
-
if ((lineNumber % n) === 0) {
|
|
38
|
-
onError({
|
|
39
|
-
"lineNumber": lineNumber,
|
|
40
|
-
"detail": "Line number " + lineNumber
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
```
|
|
47
|
-
|
|
48
22
|
### Applying Recommended Fixes
|
|
49
23
|
|
|
50
24
|
```javascript
|
|
@@ -64,9 +38,9 @@ See also: [`markdownlint` built-in rule implementations][lib].
|
|
|
64
38
|
*None* - The entire body of code is tested to 100% coverage by the core
|
|
65
39
|
`markdownlint` project, so there are no additional tests here.
|
|
66
40
|
|
|
67
|
-
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.
|
|
41
|
+
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/CustomRules.md
|
|
68
42
|
[jsdoc]: https://en.m.wikipedia.org/wiki/JSDoc
|
|
69
|
-
[lib]: https://github.com/DavidAnson/markdownlint/tree/v0.
|
|
43
|
+
[lib]: https://github.com/DavidAnson/markdownlint/tree/v0.35.0/lib
|
|
70
44
|
[markdown]: https://en.wikipedia.org/wiki/Markdown
|
|
71
45
|
[markdownlint]: https://github.com/DavidAnson/markdownlint
|
|
72
|
-
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.
|
|
46
|
+
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/Rules.md
|
package/helpers/helpers.js
CHANGED
|
@@ -18,10 +18,6 @@ const inlineCommentStartRe =
|
|
|
18
18
|
/(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/gi;
|
|
19
19
|
module.exports.inlineCommentStartRe = inlineCommentStartRe;
|
|
20
20
|
|
|
21
|
-
// Regular expressions for range matching
|
|
22
|
-
module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
|
|
23
|
-
module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
|
24
|
-
|
|
25
21
|
// Regular expression for blockquote prefixes
|
|
26
22
|
const blockquotePrefixRe = /^[>\s]*/;
|
|
27
23
|
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
|
@@ -143,7 +139,6 @@ function isBlankLine(line) {
|
|
|
143
139
|
const startComment = "<!--";
|
|
144
140
|
const endComment = "-->";
|
|
145
141
|
const removeComments = (s) => {
|
|
146
|
-
// eslint-disable-next-line no-constant-condition
|
|
147
142
|
while (true) {
|
|
148
143
|
const start = s.indexOf(startComment);
|
|
149
144
|
const end = s.indexOf(endComment);
|
|
@@ -170,35 +165,6 @@ function isBlankLine(line) {
|
|
|
170
165
|
}
|
|
171
166
|
module.exports.isBlankLine = isBlankLine;
|
|
172
167
|
|
|
173
|
-
/**
|
|
174
|
-
* Compare function for Array.prototype.sort for ascending order of numbers.
|
|
175
|
-
*
|
|
176
|
-
* @param {number} a First number.
|
|
177
|
-
* @param {number} b Second number.
|
|
178
|
-
* @returns {number} Positive value if a>b, negative value if b<a, 0 otherwise.
|
|
179
|
-
*/
|
|
180
|
-
module.exports.numericSortAscending = function numericSortAscending(a, b) {
|
|
181
|
-
return a - b;
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Returns true iff the sorted array contains the specified element
|
|
185
|
-
module.exports.includesSorted = function includesSorted(array, element) {
|
|
186
|
-
let left = 0;
|
|
187
|
-
let right = array.length - 1;
|
|
188
|
-
while (left <= right) {
|
|
189
|
-
// eslint-disable-next-line no-bitwise
|
|
190
|
-
const mid = (left + right) >> 1;
|
|
191
|
-
if (array[mid] < element) {
|
|
192
|
-
left = mid + 1;
|
|
193
|
-
} else if (array[mid] > element) {
|
|
194
|
-
right = mid - 1;
|
|
195
|
-
} else {
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return false;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
168
|
// Replaces the content of properly-formatted CommonMark comments with "."
|
|
203
169
|
// This preserves the line/column information for the rest of the document
|
|
204
170
|
// https://spec.commonmark.org/0.29/#html-blocks
|
|
@@ -289,208 +255,6 @@ module.exports.emphasisOrStrongStyleFor =
|
|
|
289
255
|
}
|
|
290
256
|
};
|
|
291
257
|
|
|
292
|
-
/**
|
|
293
|
-
* Return the number of characters of indent for a token.
|
|
294
|
-
*
|
|
295
|
-
* @param {Object} token MarkdownItToken instance.
|
|
296
|
-
* @returns {number} Characters of indent.
|
|
297
|
-
*/
|
|
298
|
-
function indentFor(token) {
|
|
299
|
-
const line = token.line.replace(/^[\s>]*(> |>)/, "");
|
|
300
|
-
return line.length - line.trimStart().length;
|
|
301
|
-
}
|
|
302
|
-
module.exports.indentFor = indentFor;
|
|
303
|
-
|
|
304
|
-
// Returns the heading style for a heading token
|
|
305
|
-
module.exports.headingStyleFor = function headingStyleFor(token) {
|
|
306
|
-
if ((token.map[1] - token.map[0]) === 1) {
|
|
307
|
-
if (/[^\\]#\s*$/.test(token.line)) {
|
|
308
|
-
return "atx_closed";
|
|
309
|
-
}
|
|
310
|
-
return "atx";
|
|
311
|
-
}
|
|
312
|
-
return "setext";
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Return the string representation of an unordered list marker.
|
|
317
|
-
*
|
|
318
|
-
* @param {Object} token MarkdownItToken instance.
|
|
319
|
-
* @returns {"asterisk" | "dash" | "plus"} String representation.
|
|
320
|
-
*/
|
|
321
|
-
module.exports.unorderedListStyleFor = function unorderedListStyleFor(token) {
|
|
322
|
-
switch (token.markup) {
|
|
323
|
-
case "-":
|
|
324
|
-
return "dash";
|
|
325
|
-
case "+":
|
|
326
|
-
return "plus";
|
|
327
|
-
// case "*":
|
|
328
|
-
default:
|
|
329
|
-
return "asterisk";
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* @callback TokenCallback
|
|
335
|
-
* @param {MarkdownItToken} token Current token.
|
|
336
|
-
* @returns {void}
|
|
337
|
-
*/
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Calls the provided function for each matching token.
|
|
341
|
-
*
|
|
342
|
-
* @param {Object} params RuleParams instance.
|
|
343
|
-
* @param {string} type Token type identifier.
|
|
344
|
-
* @param {TokenCallback} handler Callback function.
|
|
345
|
-
* @returns {void}
|
|
346
|
-
*/
|
|
347
|
-
function filterTokens(params, type, handler) {
|
|
348
|
-
for (const token of params.parsers.markdownit.tokens) {
|
|
349
|
-
if (token.type === type) {
|
|
350
|
-
handler(token);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
module.exports.filterTokens = filterTokens;
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* @typedef {Array} LineMetadata
|
|
358
|
-
*/
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Gets a line metadata array.
|
|
362
|
-
*
|
|
363
|
-
* @param {Object} params RuleParams instance.
|
|
364
|
-
* @returns {LineMetadata} Line metadata.
|
|
365
|
-
*/
|
|
366
|
-
function getLineMetadata(params) {
|
|
367
|
-
const lineMetadata = params.lines.map(
|
|
368
|
-
(line, index) => [ line, index, false, 0, false, false, false ]
|
|
369
|
-
);
|
|
370
|
-
filterTokens(params, "fence", (token) => {
|
|
371
|
-
lineMetadata[token.map[0]][3] = 1;
|
|
372
|
-
lineMetadata[token.map[1] - 1][3] = -1;
|
|
373
|
-
for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) {
|
|
374
|
-
lineMetadata[i][2] = true;
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
filterTokens(params, "code_block", (token) => {
|
|
378
|
-
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
379
|
-
lineMetadata[i][2] = true;
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
filterTokens(params, "table_open", (token) => {
|
|
383
|
-
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
384
|
-
lineMetadata[i][4] = true;
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
filterTokens(params, "list_item_open", (token) => {
|
|
388
|
-
let count = 1;
|
|
389
|
-
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
390
|
-
lineMetadata[i][5] = count;
|
|
391
|
-
count++;
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
filterTokens(params, "hr", (token) => {
|
|
395
|
-
lineMetadata[token.map[0]][6] = true;
|
|
396
|
-
});
|
|
397
|
-
return lineMetadata;
|
|
398
|
-
}
|
|
399
|
-
module.exports.getLineMetadata = getLineMetadata;
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* @callback EachLineCallback
|
|
403
|
-
* @param {string} line Line content.
|
|
404
|
-
* @param {number} lineIndex Line index (0-based).
|
|
405
|
-
* @param {boolean} inCode Iff in a code block.
|
|
406
|
-
* @param {number} onFence + if open, - if closed, 0 otherwise.
|
|
407
|
-
* @param {boolean} inTable Iff in a table.
|
|
408
|
-
* @param {boolean} inItem Iff in a list item.
|
|
409
|
-
* @param {boolean} inBreak Iff in semantic break.
|
|
410
|
-
* @returns {void}
|
|
411
|
-
*/
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Calls the provided function for each line.
|
|
415
|
-
*
|
|
416
|
-
* @param {LineMetadata} lineMetadata Line metadata object.
|
|
417
|
-
* @param {EachLineCallback} handler Function taking (line, lineIndex, inCode,
|
|
418
|
-
* onFence, inTable, inItem, inBreak).
|
|
419
|
-
* @returns {void}
|
|
420
|
-
*/
|
|
421
|
-
function forEachLine(lineMetadata, handler) {
|
|
422
|
-
for (const metadata of lineMetadata) {
|
|
423
|
-
// @ts-ignore
|
|
424
|
-
handler(...metadata);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
module.exports.forEachLine = forEachLine;
|
|
428
|
-
|
|
429
|
-
// Returns (nested) lists as a flat array (in order)
|
|
430
|
-
module.exports.flattenLists = function flattenLists(tokens) {
|
|
431
|
-
const flattenedLists = [];
|
|
432
|
-
const stack = [];
|
|
433
|
-
let current = null;
|
|
434
|
-
let nesting = 0;
|
|
435
|
-
const nestingStack = [];
|
|
436
|
-
let lastWithMap = { "map": [ 0, 1 ] };
|
|
437
|
-
for (const token of tokens) {
|
|
438
|
-
if ((token.type === "bullet_list_open") ||
|
|
439
|
-
(token.type === "ordered_list_open")) {
|
|
440
|
-
// Save current context and start a new one
|
|
441
|
-
stack.push(current);
|
|
442
|
-
current = {
|
|
443
|
-
"unordered": (token.type === "bullet_list_open"),
|
|
444
|
-
"parentsUnordered": !current ||
|
|
445
|
-
(current.unordered && current.parentsUnordered),
|
|
446
|
-
"open": token,
|
|
447
|
-
"indent": indentFor(token),
|
|
448
|
-
"parentIndent": (current && current.indent) || 0,
|
|
449
|
-
"items": [],
|
|
450
|
-
"nesting": nesting,
|
|
451
|
-
"lastLineIndex": -1,
|
|
452
|
-
"insert": flattenedLists.length
|
|
453
|
-
};
|
|
454
|
-
nesting++;
|
|
455
|
-
} else if ((token.type === "bullet_list_close") ||
|
|
456
|
-
(token.type === "ordered_list_close")) {
|
|
457
|
-
// Finalize current context and restore previous
|
|
458
|
-
current.lastLineIndex = lastWithMap.map[1];
|
|
459
|
-
flattenedLists.splice(current.insert, 0, current);
|
|
460
|
-
delete current.insert;
|
|
461
|
-
current = stack.pop();
|
|
462
|
-
nesting--;
|
|
463
|
-
} else if (token.type === "list_item_open") {
|
|
464
|
-
// Add list item
|
|
465
|
-
current.items.push(token);
|
|
466
|
-
} else if (token.type === "blockquote_open") {
|
|
467
|
-
nestingStack.push(nesting);
|
|
468
|
-
nesting = 0;
|
|
469
|
-
} else if (token.type === "blockquote_close") {
|
|
470
|
-
nesting = nestingStack.pop() || 0;
|
|
471
|
-
}
|
|
472
|
-
if (token.map) {
|
|
473
|
-
// Track last token with map
|
|
474
|
-
lastWithMap = token;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
return flattenedLists;
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
// Calls the provided function for each heading's content
|
|
481
|
-
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
|
482
|
-
let heading = null;
|
|
483
|
-
for (const token of params.parsers.markdownit.tokens) {
|
|
484
|
-
if (token.type === "heading_open") {
|
|
485
|
-
heading = token;
|
|
486
|
-
} else if (token.type === "heading_close") {
|
|
487
|
-
heading = null;
|
|
488
|
-
} else if ((token.type === "inline") && heading) {
|
|
489
|
-
handler(heading, token.content, token);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
};
|
|
493
|
-
|
|
494
258
|
/**
|
|
495
259
|
* @callback InlineCodeSpanCallback
|
|
496
260
|
* @param {string} code Code content.
|
|
@@ -596,8 +360,20 @@ function addError(onError, lineNumber, detail, context, range, fixInfo) {
|
|
|
596
360
|
}
|
|
597
361
|
module.exports.addError = addError;
|
|
598
362
|
|
|
599
|
-
|
|
600
|
-
|
|
363
|
+
/**
|
|
364
|
+
* Adds an error object with details conditionally via the onError callback.
|
|
365
|
+
*
|
|
366
|
+
* @param {Object} onError RuleOnError instance.
|
|
367
|
+
* @param {number} lineNumber Line number.
|
|
368
|
+
* @param {Object} expected Expected value.
|
|
369
|
+
* @param {Object} actual Actual value.
|
|
370
|
+
* @param {string} [detail] Error details.
|
|
371
|
+
* @param {string} [context] Error context.
|
|
372
|
+
* @param {number[]} [range] Column and length of error.
|
|
373
|
+
* @param {Object} [fixInfo] RuleOnErrorFixInfo instance.
|
|
374
|
+
* @returns {void}
|
|
375
|
+
*/
|
|
376
|
+
function addErrorDetailIf(
|
|
601
377
|
onError, lineNumber, expected, actual, detail, context, range, fixInfo) {
|
|
602
378
|
if (expected !== actual) {
|
|
603
379
|
addError(
|
|
@@ -609,51 +385,55 @@ module.exports.addErrorDetailIf = function addErrorDetailIf(
|
|
|
609
385
|
range,
|
|
610
386
|
fixInfo);
|
|
611
387
|
}
|
|
612
|
-
}
|
|
388
|
+
}
|
|
389
|
+
module.exports.addErrorDetailIf = addErrorDetailIf;
|
|
613
390
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
391
|
+
/**
|
|
392
|
+
* Adds an error object with context via the onError callback.
|
|
393
|
+
*
|
|
394
|
+
* @param {Object} onError RuleOnError instance.
|
|
395
|
+
* @param {number} lineNumber Line number.
|
|
396
|
+
* @param {string} context Error context.
|
|
397
|
+
* @param {boolean} [start] True iff the start of the text is important.
|
|
398
|
+
* @param {boolean} [end] True iff the end of the text is important.
|
|
399
|
+
* @param {number[]} [range] Column and length of error.
|
|
400
|
+
* @param {Object} [fixInfo] RuleOnErrorFixInfo instance.
|
|
401
|
+
* @returns {void}
|
|
402
|
+
*/
|
|
403
|
+
function addErrorContext(
|
|
404
|
+
onError, lineNumber, context, start, end, range, fixInfo) {
|
|
405
|
+
context = ellipsify(context, start, end);
|
|
618
406
|
addError(onError, lineNumber, undefined, context, range, fixInfo);
|
|
619
|
-
}
|
|
407
|
+
}
|
|
408
|
+
module.exports.addErrorContext = addErrorContext;
|
|
620
409
|
|
|
621
410
|
/**
|
|
622
|
-
*
|
|
411
|
+
* Adds an error object with context for a construct missing a blank line.
|
|
623
412
|
*
|
|
624
|
-
* @param {Object}
|
|
625
|
-
* @param {
|
|
626
|
-
* @
|
|
413
|
+
* @param {Object} onError RuleOnError instance.
|
|
414
|
+
* @param {string[]} lines Lines of Markdown content.
|
|
415
|
+
* @param {number} lineIndex Line index of line.
|
|
416
|
+
* @param {number} [lineNumber] Line number for override.
|
|
417
|
+
* @returns {void}
|
|
627
418
|
*/
|
|
628
|
-
|
|
629
|
-
const
|
|
630
|
-
//
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
(code, lineIndex, columnIndex) => {
|
|
643
|
-
const codeLines = code.split(newLineRe);
|
|
644
|
-
for (const [ i, line ] of codeLines.entries()) {
|
|
645
|
-
exclusions.push([
|
|
646
|
-
token.lineNumber - 1 + lineIndex + i,
|
|
647
|
-
i ? 0 : columnIndex,
|
|
648
|
-
line.length
|
|
649
|
-
]);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
);
|
|
419
|
+
function addErrorContextForLine(onError, lines, lineIndex, lineNumber) {
|
|
420
|
+
const line = lines[lineIndex];
|
|
421
|
+
// @ts-ignore
|
|
422
|
+
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
423
|
+
addErrorContext(
|
|
424
|
+
onError,
|
|
425
|
+
lineIndex + 1,
|
|
426
|
+
line.trim(),
|
|
427
|
+
undefined,
|
|
428
|
+
undefined,
|
|
429
|
+
undefined,
|
|
430
|
+
{
|
|
431
|
+
lineNumber,
|
|
432
|
+
"insertText": `${quotePrefix}\n`
|
|
653
433
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
module.exports.addErrorContextForLine = addErrorContextForLine;
|
|
657
437
|
|
|
658
438
|
/**
|
|
659
439
|
* Determines whether the specified range is within another range.
|
|
@@ -673,18 +453,6 @@ const withinAnyRange = (ranges, lineIndex, index, length) => (
|
|
|
673
453
|
);
|
|
674
454
|
module.exports.withinAnyRange = withinAnyRange;
|
|
675
455
|
|
|
676
|
-
// Returns a range object for a line by applying a RegExp
|
|
677
|
-
module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
|
678
|
-
let range = null;
|
|
679
|
-
const match = line.match(regexp);
|
|
680
|
-
if (match) {
|
|
681
|
-
const column = match.index + 1;
|
|
682
|
-
const length = match[0].length;
|
|
683
|
-
range = [ column, length ];
|
|
684
|
-
}
|
|
685
|
-
return range;
|
|
686
|
-
};
|
|
687
|
-
|
|
688
456
|
// Determines if the front matter includes a title
|
|
689
457
|
module.exports.frontMatterHasTitle =
|
|
690
458
|
function frontMatterHasTitle(frontMatterLines, frontMatterTitlePattern) {
|