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
package/lib/md007.js CHANGED
@@ -3,8 +3,8 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorDetailIf } = require("../helpers");
6
- const { filterByTypes, getTokenParentOfType, inHtmlFlow } =
7
- require("../helpers/micromark.cjs");
6
+ const { getTokenParentOfType } = require("../helpers/micromark.cjs");
7
+ const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  // eslint-disable-next-line jsdoc/valid-types
10
10
  /** @type import("markdownlint-micromark").TokenType[] */
@@ -26,14 +26,9 @@ module.exports = {
26
26
  const indent = Number(params.config.indent || 2);
27
27
  const startIndented = !!params.config.start_indented;
28
28
  const startIndent = Number(params.config.start_indent || indent);
29
- // eslint-disable-next-line jsdoc/valid-types
30
- /** @type import("../helpers/micromark.cjs").Token[] */
31
- const micromarkTokens =
32
- // @ts-ignore
33
- params.parsers.micromark.tokens;
34
29
  const unorderedListNesting = new Map();
35
30
  let lastBlockQuotePrefix = null;
36
- const tokens = filterByTypes(micromarkTokens, unorderedListTypes);
31
+ const tokens = filterByTypesCached(unorderedListTypes);
37
32
  for (const token of tokens) {
38
33
  const { endColumn, parent, startColumn, startLine, type } = token;
39
34
  if (type === "blockQuotePrefix") {
@@ -43,6 +38,7 @@ module.exports = {
43
38
  /** @type {import("../helpers/micromark.cjs").Token | null} */
44
39
  let current = token;
45
40
  while (
41
+ // @ts-ignore
46
42
  (current = getTokenParentOfType(current, unorderedParentTypes))
47
43
  ) {
48
44
  if (current.type === "listUnordered") {
@@ -57,7 +53,7 @@ module.exports = {
57
53
  if (nesting >= 0) {
58
54
  unorderedListNesting.set(token, nesting);
59
55
  }
60
- } else if (!inHtmlFlow(token)) {
56
+ } else {
61
57
  // listItemPrefix
62
58
  const nesting = unorderedListNesting.get(parent);
63
59
  if (nesting !== undefined) {
package/lib/md009.js CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, filterTokens, forEachLine, includesSorted,
6
- numericSortAscending } = require("../helpers");
7
- const { lineMetadata } = require("./cache");
5
+ const { addError } = require("../helpers");
6
+ const { addRangeToSet } = require("../helpers/micromark.cjs");
7
+ const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  // eslint-disable-next-line jsdoc/valid-types
10
10
  /** @type import("./markdownlint").Rule */
@@ -12,63 +12,68 @@ module.exports = {
12
12
  "names": [ "MD009", "no-trailing-spaces" ],
13
13
  "description": "Trailing spaces",
14
14
  "tags": [ "whitespace" ],
15
- "parser": "markdownit",
15
+ "parser": "micromark",
16
16
  "function": function MD009(params, onError) {
17
17
  let brSpaces = params.config.br_spaces;
18
18
  brSpaces = Number((brSpaces === undefined) ? 2 : brSpaces);
19
19
  const listItemEmptyLines = !!params.config.list_item_empty_lines;
20
20
  const strict = !!params.config.strict;
21
- const listItemLineNumbers = [];
21
+ const codeBlockLineNumbers = new Set();
22
+ for (const codeBlock of filterByTypesCached([ "codeFenced" ])) {
23
+ addRangeToSet(codeBlockLineNumbers, codeBlock.startLine + 1, codeBlock.endLine - 1);
24
+ }
25
+ for (const codeBlock of filterByTypesCached([ "codeIndented" ])) {
26
+ addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
27
+ }
28
+ const listItemLineNumbers = new Set();
22
29
  if (listItemEmptyLines) {
23
- filterTokens(params, "list_item_open", (token) => {
24
- for (let i = token.map[0]; i < token.map[1]; i++) {
25
- listItemLineNumbers.push(i + 1);
30
+ for (const listBlock of filterByTypesCached([ "listOrdered", "listUnordered" ])) {
31
+ addRangeToSet(listItemLineNumbers, listBlock.startLine, listBlock.endLine);
32
+ let trailingIndent = true;
33
+ for (let i = listBlock.children.length - 1; i >= 0; i--) {
34
+ const child = listBlock.children[i];
35
+ switch (child.type) {
36
+ case "content":
37
+ trailingIndent = false;
38
+ break;
39
+ case "listItemIndent":
40
+ if (trailingIndent) {
41
+ listItemLineNumbers.delete(child.startLine);
42
+ }
43
+ break;
44
+ case "listItemPrefix":
45
+ trailingIndent = true;
46
+ break;
47
+ default:
48
+ break;
49
+ }
26
50
  }
27
- });
28
- listItemLineNumbers.sort(numericSortAscending);
51
+ }
29
52
  }
30
- const paragraphLineNumbers = [];
31
- const codeInlineLineNumbers = [];
53
+ const paragraphLineNumbers = new Set();
54
+ const codeInlineLineNumbers = new Set();
32
55
  if (strict) {
33
- filterTokens(params, "paragraph_open", (token) => {
34
- for (let i = token.map[0]; i < token.map[1] - 1; i++) {
35
- paragraphLineNumbers.push(i + 1);
36
- }
37
- });
38
- const addLineNumberRange = (start, end) => {
39
- for (let i = start; i < end; i++) {
40
- codeInlineLineNumbers.push(i);
41
- }
42
- };
43
- filterTokens(params, "inline", (token) => {
44
- let start = 0;
45
- for (const child of token.children) {
46
- if (start > 0) {
47
- addLineNumberRange(start, child.lineNumber);
48
- start = 0;
49
- }
50
- if (child.type === "code_inline") {
51
- start = child.lineNumber;
52
- }
53
- }
54
- if (start > 0) {
55
- addLineNumberRange(start, token.map[1]);
56
- }
57
- });
56
+ for (const paragraph of filterByTypesCached([ "paragraph" ])) {
57
+ addRangeToSet(paragraphLineNumbers, paragraph.startLine, paragraph.endLine - 1);
58
+ }
59
+ for (const codeText of filterByTypesCached([ "codeText" ])) {
60
+ addRangeToSet(codeInlineLineNumbers, codeText.startLine, codeText.endLine - 1);
61
+ }
58
62
  }
59
63
  const expected = (brSpaces < 2) ? 0 : brSpaces;
60
- forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
64
+ for (let lineIndex = 0; lineIndex < params.lines.length; lineIndex++) {
65
+ const line = params.lines[lineIndex];
61
66
  const lineNumber = lineIndex + 1;
62
67
  const trailingSpaces = line.length - line.trimEnd().length;
63
68
  if (
64
69
  trailingSpaces &&
65
- !inCode &&
66
- !includesSorted(listItemLineNumbers, lineNumber) &&
70
+ !codeBlockLineNumbers.has(lineNumber) &&
71
+ !listItemLineNumbers.has(lineNumber) &&
67
72
  (
68
73
  (expected !== trailingSpaces) ||
69
74
  (strict &&
70
- (!includesSorted(paragraphLineNumbers, lineNumber) ||
71
- includesSorted(codeInlineLineNumbers, lineNumber)))
75
+ (!paragraphLineNumbers.has(lineNumber) ||
76
+ codeInlineLineNumbers.has(lineNumber)))
72
77
  )
73
78
  ) {
74
79
  const column = line.length - trailingSpaces + 1;
@@ -82,8 +87,9 @@ module.exports = {
82
87
  {
83
88
  "editColumn": column,
84
89
  "deleteCount": trailingSpaces
85
- });
90
+ }
91
+ );
86
92
  }
87
- });
93
+ }
88
94
  }
89
95
  };
package/lib/md010.js CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, filterTokens, forEachLine, withinAnyRange } =
6
- require("../helpers");
7
- const { codeBlockAndSpanRanges, lineMetadata } = require("./cache");
5
+ const { addError, withinAnyRange } = require("../helpers");
6
+ const { getDescendantsByType, getExclusionsForToken } = require("../helpers/micromark.cjs");
7
+ const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  const tabRe = /\t+/g;
10
10
 
@@ -14,7 +14,7 @@ module.exports = {
14
14
  "names": [ "MD010", "no-hard-tabs" ],
15
15
  "description": "Hard tabs",
16
16
  "tags": [ "whitespace", "hard_tab" ],
17
- "parser": "markdownit",
17
+ "parser": "micromark",
18
18
  "function": function MD010(params, onError) {
19
19
  const codeBlocks = params.config.code_blocks;
20
20
  const includeCode = (codeBlocks === undefined) ? true : !!codeBlocks;
@@ -26,38 +26,53 @@ module.exports = {
26
26
  const spaceMultiplier = (spacesPerTab === undefined) ?
27
27
  1 :
28
28
  Math.max(0, Number(spacesPerTab));
29
- const exclusions = includeCode ? [] : codeBlockAndSpanRanges();
30
- filterTokens(params, "fence", (token) => {
31
- const language = token.info.trim().toLowerCase();
32
- if (ignoreCodeLanguages.has(language)) {
33
- for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) {
34
- exclusions.push([ i, 0, params.lines[i].length ]);
35
- }
29
+ const exclusions = [];
30
+ // eslint-disable-next-line jsdoc/valid-types
31
+ /** @type import("../helpers/micromark.cjs").TokenType[] */
32
+ const exclusionTypes = [];
33
+ if (includeCode) {
34
+ if (ignoreCodeLanguages.size > 0) {
35
+ exclusionTypes.push("codeFenced");
36
+ }
37
+ } else {
38
+ exclusionTypes.push("codeFenced", "codeIndented", "codeText");
39
+ }
40
+ const codeTokens = filterByTypesCached(exclusionTypes).filter((token) => {
41
+ if ((token.type === "codeFenced") && (ignoreCodeLanguages.size > 0)) {
42
+ const fenceInfos = getDescendantsByType(token, [ "codeFencedFence", "codeFencedFenceInfo" ]);
43
+ return fenceInfos.every((fenceInfo) => ignoreCodeLanguages.has(fenceInfo.text.toLowerCase()));
36
44
  }
45
+ return true;
37
46
  });
38
- forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
39
- if (includeCode || !inCode) {
40
- let match = null;
41
- while ((match = tabRe.exec(line)) !== null) {
42
- const { index } = match;
43
- const column = index + 1;
44
- const length = match[0].length;
45
- if (!withinAnyRange(exclusions, lineIndex, index, length)) {
46
- addError(
47
- onError,
48
- lineIndex + 1,
49
- "Column: " + column,
50
- undefined,
51
- [ column, length ],
52
- {
53
- "editColumn": column,
54
- "deleteCount": length,
55
- "insertText": "".padEnd(length * spaceMultiplier)
56
- }
57
- );
58
- }
47
+ for (const codeToken of codeTokens) {
48
+ const exclusionsForToken = getExclusionsForToken(params.lines, codeToken);
49
+ if (codeToken.type === "codeFenced") {
50
+ exclusionsForToken.pop();
51
+ exclusionsForToken.shift();
52
+ }
53
+ exclusions.push(...exclusionsForToken);
54
+ }
55
+ for (let lineIndex = 0; lineIndex < params.lines.length; lineIndex++) {
56
+ const line = params.lines[lineIndex];
57
+ let match = null;
58
+ while ((match = tabRe.exec(line)) !== null) {
59
+ const column = match.index + 1;
60
+ const length = match[0].length;
61
+ if (!withinAnyRange(exclusions, lineIndex + 1, column, length)) {
62
+ addError(
63
+ onError,
64
+ lineIndex + 1,
65
+ "Column: " + column,
66
+ undefined,
67
+ [ column, length ],
68
+ {
69
+ "editColumn": column,
70
+ "deleteCount": length,
71
+ "insertText": "".padEnd(length * spaceMultiplier)
72
+ }
73
+ );
59
74
  }
60
75
  }
61
- });
76
+ }
62
77
  }
63
78
  };
package/lib/md011.js CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, forEachLine, withinAnyRange } = require("../helpers");
6
- const { codeBlockAndSpanRanges, lineMetadata } = require("./cache");
5
+ const { addError, withinAnyRange } = require("../helpers");
6
+ const { addRangeToSet, getExclusionsForToken } = require("../helpers/micromark.cjs");
7
+ const { filterByTypesCached } = require("./cache");
7
8
 
8
9
  const reversedLinkRe =
9
10
  /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)\](?!\()/g;
@@ -14,11 +15,18 @@ module.exports = {
14
15
  "names": [ "MD011", "no-reversed-links" ],
15
16
  "description": "Reversed link syntax",
16
17
  "tags": [ "links" ],
17
- "parser": "none",
18
+ "parser": "micromark",
18
19
  "function": function MD011(params, onError) {
19
- const exclusions = codeBlockAndSpanRanges();
20
- forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence) => {
21
- if (!inCode && !onFence) {
20
+ const codeBlockLineNumbers = new Set();
21
+ for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
22
+ addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
23
+ }
24
+ const exclusions = [];
25
+ for (const codeText of filterByTypesCached([ "codeText" ])) {
26
+ exclusions.push(...getExclusionsForToken(params.lines, codeText));
27
+ }
28
+ for (const [ lineIndex, line ] of params.lines.entries()) {
29
+ if (!codeBlockLineNumbers.has(lineIndex + 1)) {
22
30
  let match = null;
23
31
  while ((match = reversedLinkRe.exec(line)) !== null) {
24
32
  const [ reversedLink, preChar, linkText, linkDestination ] = match;
@@ -27,7 +35,7 @@ module.exports = {
27
35
  if (
28
36
  !linkText.endsWith("\\") &&
29
37
  !linkDestination.endsWith("\\") &&
30
- !withinAnyRange(exclusions, lineIndex, index, length)
38
+ !withinAnyRange(exclusions, lineIndex + 1, index, length)
31
39
  ) {
32
40
  addError(
33
41
  onError,
@@ -44,6 +52,6 @@ module.exports = {
44
52
  }
45
53
  }
46
54
  }
47
- });
55
+ }
48
56
  }
49
57
  };
package/lib/md012.js CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorDetailIf, forEachLine } = require("../helpers");
6
- const { lineMetadata } = require("./cache");
5
+ const { addErrorDetailIf } = require("../helpers");
6
+ const { addRangeToSet } = require("../helpers/micromark.cjs");
7
+ const { filterByTypesCached } = require("./cache");
7
8
 
8
9
  // eslint-disable-next-line jsdoc/valid-types
9
10
  /** @type import("./markdownlint").Rule */
@@ -11,11 +12,17 @@ module.exports = {
11
12
  "names": [ "MD012", "no-multiple-blanks" ],
12
13
  "description": "Multiple consecutive blank lines",
13
14
  "tags": [ "whitespace", "blank_lines" ],
14
- "parser": "none",
15
+ "parser": "micromark",
15
16
  "function": function MD012(params, onError) {
16
17
  const maximum = Number(params.config.maximum || 1);
18
+ const { lines } = params;
19
+ const codeBlockLineNumbers = new Set();
20
+ for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
21
+ addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
22
+ }
17
23
  let count = 0;
18
- forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
24
+ for (const [ lineIndex, line ] of lines.entries()) {
25
+ const inCode = codeBlockLineNumbers.has(lineIndex + 1);
19
26
  count = (inCode || (line.trim().length > 0)) ? 0 : count + 1;
20
27
  if (maximum < count) {
21
28
  addErrorDetailIf(
@@ -23,13 +30,14 @@ module.exports = {
23
30
  lineIndex + 1,
24
31
  maximum,
25
32
  count,
26
- null,
27
- null,
28
- null,
33
+ undefined,
34
+ undefined,
35
+ undefined,
29
36
  {
30
37
  "deleteCount": -1
31
- });
38
+ }
39
+ );
32
40
  }
33
- });
41
+ }
34
42
  }
35
43
  };
package/lib/md013.js CHANGED
@@ -2,25 +2,15 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine,
6
- includesSorted } = require("../helpers");
7
- const { lineMetadata, referenceLinkImageData } = require("./cache");
5
+ const { addErrorDetailIf } = require("../helpers");
6
+ const { getReferenceLinkImageData } = require("./cache");
7
+ const { addRangeToSet, getDescendantsByType } = require("../helpers/micromark.cjs");
8
+ const { filterByTypesCached } = require("./cache");
8
9
 
9
10
  const longLineRePrefix = "^.{";
10
11
  const longLineRePostfixRelaxed = "}.*\\s.*$";
11
12
  const longLineRePostfixStrict = "}.+$";
12
- const linkOrImageOnlyLineRe = /^[es]*(?:lT?L|I)[ES]*$/;
13
13
  const sternModeRe = /^(?:[#>\s]*\s)?\S*$/;
14
- const tokenTypeMap = {
15
- "em_open": "e",
16
- "em_close": "E",
17
- "image": "I",
18
- "link_open": "l",
19
- "link_close": "L",
20
- "strong_open": "s",
21
- "strong_close": "S",
22
- "text": "T"
23
- };
24
14
 
25
15
  // eslint-disable-next-line jsdoc/valid-types
26
16
  /** @type import("./markdownlint").Rule */
@@ -28,7 +18,7 @@ module.exports = {
28
18
  "names": [ "MD013", "line-length" ],
29
19
  "description": "Line length",
30
20
  "tags": [ "line_length" ],
31
- "parser": "markdownit",
21
+ "parser": "micromark",
32
22
  "function": function MD013(params, onError) {
33
23
  const lineLength = Number(params.config.line_length || 80);
34
24
  const headingLineLength =
@@ -51,26 +41,41 @@ module.exports = {
51
41
  const includeTables = (tables === undefined) ? true : !!tables;
52
42
  const headings = params.config.headings;
53
43
  const includeHeadings = (headings === undefined) ? true : !!headings;
54
- const headingLineNumbers = [];
55
- forEachHeading(params, (heading) => {
56
- headingLineNumbers.push(heading.lineNumber);
57
- });
58
- const linkOnlyLineNumbers = [];
59
- filterTokens(params, "inline", (token) => {
60
- let childTokenTypes = "";
61
- for (const child of token.children) {
62
- if (child.type !== "text" || child.content !== "") {
63
- childTokenTypes += tokenTypeMap[child.type] || "x";
64
- }
44
+ const headingLineNumbers = new Set();
45
+ for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
46
+ addRangeToSet(headingLineNumbers, heading.startLine, heading.endLine);
47
+ }
48
+ const codeBlockLineNumbers = new Set();
49
+ for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
50
+ addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
51
+ }
52
+ const tableLineNumbers = new Set();
53
+ for (const table of filterByTypesCached([ "table" ])) {
54
+ addRangeToSet(tableLineNumbers, table.startLine, table.endLine);
55
+ }
56
+ const linkLineNumbers = new Set();
57
+ for (const link of filterByTypesCached([ "autolink", "image", "link", "literalAutolink" ])) {
58
+ addRangeToSet(linkLineNumbers, link.startLine, link.endLine);
59
+ }
60
+ const paragraphDataLineNumbers = new Set();
61
+ for (const paragraph of filterByTypesCached([ "paragraph" ])) {
62
+ for (const data of getDescendantsByType(paragraph, [ "data" ])) {
63
+ addRangeToSet(paragraphDataLineNumbers, data.startLine, data.endLine);
65
64
  }
66
- if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
67
- linkOnlyLineNumbers.push(token.lineNumber);
65
+ }
66
+ const linkOnlyLineNumbers = new Set();
67
+ for (const lineNumber of linkLineNumbers) {
68
+ if (!paragraphDataLineNumbers.has(lineNumber)) {
69
+ linkOnlyLineNumbers.add(lineNumber);
68
70
  }
69
- });
70
- const { definitionLineIndices } = referenceLinkImageData();
71
- forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => {
71
+ }
72
+ const definitionLineIndices = new Set(getReferenceLinkImageData().definitionLineIndices);
73
+ for (let lineIndex = 0; lineIndex < params.lines.length; lineIndex++) {
74
+ const line = params.lines[lineIndex];
72
75
  const lineNumber = lineIndex + 1;
73
- const isHeading = includesSorted(headingLineNumbers, lineNumber);
76
+ const isHeading = headingLineNumbers.has(lineNumber);
77
+ const inCode = codeBlockLineNumbers.has(lineNumber);
78
+ const inTable = tableLineNumbers.has(lineNumber);
74
79
  const length = inCode ?
75
80
  codeLineLength :
76
81
  (isHeading ? headingLineLength : lineLength);
@@ -80,20 +85,21 @@ module.exports = {
80
85
  if ((includeCodeBlocks || !inCode) &&
81
86
  (includeTables || !inTable) &&
82
87
  (includeHeadings || !isHeading) &&
83
- !includesSorted(definitionLineIndices, lineIndex) &&
88
+ !definitionLineIndices.has(lineIndex) &&
84
89
  (strict ||
85
90
  (!(stern && sternModeRe.test(line)) &&
86
- !includesSorted(linkOnlyLineNumbers, lineNumber))) &&
91
+ !linkOnlyLineNumbers.has(lineNumber))) &&
87
92
  lengthRe.test(line)) {
88
93
  addErrorDetailIf(
89
94
  onError,
90
95
  lineNumber,
91
96
  length,
92
97
  line.length,
93
- null,
94
- null,
95
- [ length + 1, line.length - length ]);
98
+ undefined,
99
+ undefined,
100
+ [ length + 1, line.length - length ]
101
+ );
96
102
  }
97
- });
103
+ }
98
104
  }
99
105
  };
package/lib/md014.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, filterTokens } = require("../helpers");
5
+ const { addErrorContext } = require("../helpers");
6
+ const { filterByTypes } = require("../helpers/micromark.cjs");
7
+ const { filterByTypesCached } = require("./cache");
6
8
 
7
9
  const dollarCommandRe = /^(\s*)(\$\s+)/;
8
10
 
@@ -12,46 +14,41 @@ module.exports = {
12
14
  "names": [ "MD014", "commands-show-output" ],
13
15
  "description": "Dollar signs used before commands without showing output",
14
16
  "tags": [ "code" ],
15
- "parser": "markdownit",
17
+ "parser": "micromark",
16
18
  "function": function MD014(params, onError) {
17
- for (const type of [ "code_block", "fence" ]) {
18
- filterTokens(params, type, (token) => {
19
- const margin = (token.type === "fence") ? 1 : 0;
20
- const dollarInstances = [];
21
- let allDollars = true;
22
- for (let i = token.map[0] + margin; i < token.map[1] - margin; i++) {
23
- const line = params.lines[i];
24
- const lineTrim = line.trim();
25
- if (lineTrim) {
26
- const match = dollarCommandRe.exec(line);
27
- if (match) {
28
- const column = match[1].length + 1;
29
- const length = match[2].length;
30
- dollarInstances.push([ i, lineTrim, column, length ]);
31
- } else {
32
- allDollars = false;
19
+ for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
20
+ const codeFlowValues = filterByTypes(
21
+ codeBlock.children,
22
+ [ "codeFlowValue" ]
23
+ );
24
+ const dollarMatches = codeFlowValues.
25
+ map((codeFlowValue) => ({
26
+ "result": codeFlowValue.text.match(dollarCommandRe),
27
+ "startColumn": codeFlowValue.startColumn,
28
+ "startLine": codeFlowValue.startLine,
29
+ "text": codeFlowValue.text
30
+ })).
31
+ filter((dollarMatch) => dollarMatch.result);
32
+ if (dollarMatches.length === codeFlowValues.length) {
33
+ for (const dollarMatch of dollarMatches) {
34
+ // @ts-ignore
35
+ const column = dollarMatch.startColumn + dollarMatch.result[1].length;
36
+ // @ts-ignore
37
+ const length = dollarMatch.result[2].length;
38
+ addErrorContext(
39
+ onError,
40
+ dollarMatch.startLine,
41
+ dollarMatch.text,
42
+ undefined,
43
+ undefined,
44
+ [ column, length ],
45
+ {
46
+ "editColumn": column,
47
+ "deleteCount": length
33
48
  }
34
- }
49
+ );
35
50
  }
36
- if (allDollars) {
37
- for (const instance of dollarInstances) {
38
- const [ i, lineTrim, column, length ] = instance;
39
- addErrorContext(
40
- onError,
41
- // @ts-ignore
42
- i + 1,
43
- lineTrim,
44
- null,
45
- null,
46
- [ column, length ],
47
- {
48
- "editColumn": column,
49
- "deleteCount": length
50
- }
51
- );
52
- }
53
- }
54
- });
51
+ }
55
52
  }
56
53
  }
57
54
  };
package/lib/md018.js CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, forEachLine } = require("../helpers");
6
- const { lineMetadata } = require("./cache");
5
+ const { addErrorContext } = require("../helpers");
6
+ const { addRangeToSet } = require("../helpers/micromark.cjs");
7
+ const { filterByTypesCached } = require("./cache");
7
8
 
8
9
  // eslint-disable-next-line jsdoc/valid-types
9
10
  /** @type import("./markdownlint").Rule */
@@ -11,21 +12,28 @@ module.exports = {
11
12
  "names": [ "MD018", "no-missing-space-atx" ],
12
13
  "description": "No space after hash on atx style heading",
13
14
  "tags": [ "headings", "atx", "spaces" ],
14
- "parser": "none",
15
+ "parser": "micromark",
15
16
  "function": function MD018(params, onError) {
16
- forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
17
- if (!inCode &&
17
+ const { lines } = params;
18
+ const ignoreBlockLineNumbers = new Set();
19
+ for (const ignoreBlock of filterByTypesCached([ "codeFenced", "codeIndented", "htmlFlow" ])) {
20
+ addRangeToSet(ignoreBlockLineNumbers, ignoreBlock.startLine, ignoreBlock.endLine);
21
+ }
22
+ for (const [ lineIndex, line ] of lines.entries()) {
23
+ if (
24
+ !ignoreBlockLineNumbers.has(lineIndex + 1) &&
18
25
  /^#+[^# \t]/.test(line) &&
19
26
  !/#\s*$/.test(line) &&
20
- !line.startsWith("#️⃣")) {
27
+ !line.startsWith("#️⃣")
28
+ ) {
21
29
  // @ts-ignore
22
30
  const hashCount = /^#+/.exec(line)[0].length;
23
31
  addErrorContext(
24
32
  onError,
25
33
  lineIndex + 1,
26
34
  line.trim(),
27
- null,
28
- null,
35
+ undefined,
36
+ undefined,
29
37
  [ 1, hashCount + 1 ],
30
38
  {
31
39
  "editColumn": hashCount + 1,
@@ -33,6 +41,6 @@ module.exports = {
33
41
  }
34
42
  );
35
43
  }
36
- });
44
+ }
37
45
  }
38
46
  };