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.
Files changed (76) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +25 -10
  3. package/demo/markdownlint-browser.js +1144 -1166
  4. package/doc/CustomRules.md +11 -6
  5. package/doc/Rules.md +66 -0
  6. package/doc/md034.md +5 -0
  7. package/doc/md044.md +10 -0
  8. package/doc/md058.md +48 -0
  9. package/helpers/README.md +3 -29
  10. package/helpers/helpers.js +56 -288
  11. package/helpers/micromark.cjs +111 -12
  12. package/helpers/package.json +1 -1
  13. package/lib/cache.js +62 -13
  14. package/lib/configuration-strict.d.ts +1185 -0
  15. package/lib/configuration.d.ts +3 -1173
  16. package/lib/constants.js +3 -2
  17. package/lib/markdownlint.d.ts +65 -56
  18. package/lib/markdownlint.js +59 -37
  19. package/lib/md001.js +15 -9
  20. package/lib/md003.js +14 -9
  21. package/lib/md004.js +55 -48
  22. package/lib/md005.js +4 -13
  23. package/lib/md007.js +5 -9
  24. package/lib/md009.js +50 -44
  25. package/lib/md010.js +48 -33
  26. package/lib/md011.js +16 -8
  27. package/lib/md012.js +17 -9
  28. package/lib/md013.js +44 -38
  29. package/lib/md014.js +35 -38
  30. package/lib/md018.js +17 -9
  31. package/lib/md019-md021.js +80 -0
  32. package/lib/md020.js +13 -7
  33. package/lib/md022.js +6 -16
  34. package/lib/md023.js +22 -23
  35. package/lib/md024.js +12 -9
  36. package/lib/md025.js +15 -10
  37. package/lib/md026.js +2 -7
  38. package/lib/md027.js +5 -10
  39. package/lib/md028.js +3 -8
  40. package/lib/md029.js +40 -34
  41. package/lib/md030.js +4 -10
  42. package/lib/md031.js +43 -23
  43. package/lib/md032.js +16 -26
  44. package/lib/md033.js +3 -8
  45. package/lib/md034.js +5 -10
  46. package/lib/md035.js +2 -7
  47. package/lib/md036.js +3 -2
  48. package/lib/md037.js +2 -7
  49. package/lib/md038.js +3 -9
  50. package/lib/md039.js +66 -54
  51. package/lib/md040.js +3 -8
  52. package/lib/md041.js +1 -1
  53. package/lib/md042.js +48 -38
  54. package/lib/md043.js +20 -14
  55. package/lib/md044.js +3 -8
  56. package/lib/md045.js +3 -8
  57. package/lib/md046.js +2 -8
  58. package/lib/md048.js +3 -7
  59. package/lib/md049-md050.js +2 -7
  60. package/lib/md051.js +6 -12
  61. package/lib/md052.js +2 -2
  62. package/lib/md053.js +2 -2
  63. package/lib/md054.js +8 -13
  64. package/lib/md055.js +7 -8
  65. package/lib/md056.js +15 -11
  66. package/lib/md058.js +43 -0
  67. package/lib/rules.js +11 -4
  68. package/package.json +19 -17
  69. package/schema/.markdownlint.jsonc +54 -51
  70. package/schema/.markdownlint.yaml +53 -50
  71. package/schema/ValidatingConfiguration.md +6 -8
  72. package/schema/markdownlint-config-schema-strict.json +1819 -0
  73. package/schema/markdownlint-config-schema.json +115 -105
  74. package/style/prettier.json +1 -0
  75. package/lib/md019.js +0 -42
  76. package/lib/md021.js +0 -65
@@ -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 a list of custom rules using the [`options.customRules`
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]). Custom rules can be disabled,
8
- enabled, and customized using the same syntax as built-in rules.
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
- - [Package configuration for publishing to npm][test-rules-npm]
133
- - Packages should export a single rule object or an `Array` of rule objects
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.34.0/doc/CustomRules.md
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.34.0/lib
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.34.0/doc/Rules.md
46
+ [rules]: https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/Rules.md
@@ -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
- // Adds an error object with details conditionally via the onError callback
600
- module.exports.addErrorDetailIf = function addErrorDetailIf(
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
- // Adds an error object with context via the onError callback
615
- module.exports.addErrorContext = function addErrorContext(
616
- onError, lineNumber, context, left, right, range, fixInfo) {
617
- context = ellipsify(context, left, right);
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
- * Returns an array of code block and span content ranges.
411
+ * Adds an error object with context for a construct missing a blank line.
623
412
  *
624
- * @param {Object} params RuleParams instance.
625
- * @param {Object} lineMetadata Line metadata object.
626
- * @returns {number[][]} Array of ranges (lineIndex, columnIndex, length).
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
- module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => {
629
- const exclusions = [];
630
- // Add code block ranges (excludes fences)
631
- forEachLine(lineMetadata, (line, lineIndex, inCode, onFence) => {
632
- if (inCode && !onFence) {
633
- exclusions.push([ lineIndex, 0, line.length ]);
634
- }
635
- });
636
- // Add code span ranges (excludes ticks)
637
- filterTokens(params, "inline", (token) => {
638
- if (token.children.some((child) => child.type === "code_inline")) {
639
- const tokenLines = params.lines.slice(token.map[0], token.map[1]);
640
- forEachInlineCodeSpan(
641
- tokenLines.join("\n"),
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
- return exclusions;
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) {