markdownlint 0.34.0 → 0.36.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 (90) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +97 -45
  3. package/demo/markdownlint-browser.js +2186 -2164
  4. package/doc/CustomRules.md +66 -255
  5. package/doc/Rules.md +102 -29
  6. package/doc/md003.md +2 -2
  7. package/doc/md004.md +4 -3
  8. package/doc/md034.md +5 -0
  9. package/doc/md035.md +3 -8
  10. package/doc/md044.md +10 -0
  11. package/doc/md046.md +2 -2
  12. package/doc/md048.md +3 -2
  13. package/doc/md049.md +4 -3
  14. package/doc/md050.md +4 -4
  15. package/doc/md051.md +11 -3
  16. package/doc/md055.md +3 -2
  17. package/doc/md058.md +48 -0
  18. package/helpers/README.md +2 -45
  19. package/helpers/helpers.js +115 -607
  20. package/helpers/micromark-helpers.cjs +296 -0
  21. package/helpers/micromark-parse.cjs +313 -0
  22. package/helpers/package.json +5 -2
  23. package/helpers/shared.js +6 -0
  24. package/helpers/test.cjs +28 -0
  25. package/lib/cache.js +62 -13
  26. package/lib/configuration-strict.d.ts +1199 -0
  27. package/lib/configuration.d.ts +3 -1173
  28. package/lib/constants.js +3 -2
  29. package/lib/markdownit.cjs +172 -0
  30. package/lib/markdownlint.d.ts +103 -56
  31. package/lib/markdownlint.js +180 -120
  32. package/lib/md001.js +15 -9
  33. package/lib/md003.js +14 -9
  34. package/lib/md004.js +55 -48
  35. package/lib/md005.js +4 -13
  36. package/lib/md007.js +7 -11
  37. package/lib/md009.js +50 -44
  38. package/lib/md010.js +52 -33
  39. package/lib/md011.js +32 -23
  40. package/lib/md012.js +17 -9
  41. package/lib/md013.js +44 -38
  42. package/lib/md014.js +31 -38
  43. package/lib/md018.js +17 -9
  44. package/lib/md019-md021.js +80 -0
  45. package/lib/md020.js +14 -8
  46. package/lib/md022.js +13 -29
  47. package/lib/md023.js +22 -23
  48. package/lib/md024.js +12 -9
  49. package/lib/md025.js +15 -10
  50. package/lib/md026.js +2 -7
  51. package/lib/md027.js +7 -12
  52. package/lib/md028.js +3 -8
  53. package/lib/md029.js +40 -34
  54. package/lib/md030.js +4 -10
  55. package/lib/md031.js +45 -23
  56. package/lib/md032.js +33 -31
  57. package/lib/md033.js +3 -8
  58. package/lib/md034.js +21 -34
  59. package/lib/md035.js +2 -7
  60. package/lib/md036.js +19 -24
  61. package/lib/md037.js +3 -8
  62. package/lib/md038.js +11 -22
  63. package/lib/md039.js +64 -54
  64. package/lib/md040.js +13 -20
  65. package/lib/md041.js +5 -5
  66. package/lib/md042.js +44 -38
  67. package/lib/md043.js +20 -14
  68. package/lib/md044.js +34 -36
  69. package/lib/md045.js +5 -10
  70. package/lib/md046.js +2 -8
  71. package/lib/md048.js +30 -23
  72. package/lib/md049-md050.js +22 -12
  73. package/lib/md051.js +20 -28
  74. package/lib/md052.js +2 -2
  75. package/lib/md053.js +7 -6
  76. package/lib/md054.js +16 -23
  77. package/lib/md055.js +41 -49
  78. package/lib/md056.js +32 -33
  79. package/lib/md058.js +58 -0
  80. package/lib/rules.js +11 -4
  81. package/package.json +23 -20
  82. package/schema/.markdownlint.jsonc +58 -52
  83. package/schema/.markdownlint.yaml +56 -51
  84. package/schema/ValidatingConfiguration.md +6 -8
  85. package/schema/markdownlint-config-schema-strict.json +1841 -0
  86. package/schema/markdownlint-config-schema.json +141 -109
  87. package/style/prettier.json +1 -0
  88. package/helpers/micromark.cjs +0 -445
  89. package/lib/md019.js +0 -42
  90. package/lib/md021.js +0 -65
package/lib/md014.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, filterTokens } = require("../helpers");
5
+ const { addErrorContext } = require("../helpers");
6
+ const { filterByTypesCached } = require("./cache");
6
7
 
7
8
  const dollarCommandRe = /^(\s*)(\$\s+)/;
8
9
 
@@ -12,46 +13,38 @@ module.exports = {
12
13
  "names": [ "MD014", "commands-show-output" ],
13
14
  "description": "Dollar signs used before commands without showing output",
14
15
  "tags": [ "code" ],
15
- "parser": "markdownit",
16
+ "parser": "micromark",
16
17
  "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;
18
+ for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
19
+ const codeFlowValues = codeBlock.children.filter((child) => child.type === "codeFlowValue");
20
+ const dollarMatches = codeFlowValues
21
+ .map((codeFlowValue) => ({
22
+ "result": codeFlowValue.text.match(dollarCommandRe),
23
+ "startColumn": codeFlowValue.startColumn,
24
+ "startLine": codeFlowValue.startLine,
25
+ "text": codeFlowValue.text
26
+ }))
27
+ .filter((dollarMatch) => dollarMatch.result);
28
+ if (dollarMatches.length === codeFlowValues.length) {
29
+ for (const dollarMatch of dollarMatches) {
30
+ // @ts-ignore
31
+ const column = dollarMatch.startColumn + dollarMatch.result[1].length;
32
+ // @ts-ignore
33
+ const length = dollarMatch.result[2].length;
34
+ addErrorContext(
35
+ onError,
36
+ dollarMatch.startLine,
37
+ dollarMatch.text,
38
+ undefined,
39
+ undefined,
40
+ [ column, length ],
41
+ {
42
+ "editColumn": column,
43
+ "deleteCount": length
33
44
  }
34
- }
45
+ );
35
46
  }
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
- });
47
+ }
55
48
  }
56
49
  }
57
50
  };
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-helpers.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
  };
@@ -0,0 +1,80 @@
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addErrorContext } = require("../helpers/helpers");
6
+ const { getHeadingStyle } = require("../helpers/micromark-helpers.cjs");
7
+ const { filterByTypesCached } = require("./cache");
8
+
9
+ /**
10
+ * Validate heading sequence and whitespace length at start or end.
11
+ *
12
+ * @param {import("./markdownlint").RuleOnError} onError Error-reporting callback.
13
+ * @param {import("./markdownlint").MicromarkToken} heading ATX heading token.
14
+ * @param {number} delta Direction to scan.
15
+ * @returns {void}
16
+ */
17
+ function validateHeadingSpaces(onError, heading, delta) {
18
+ const { children, startLine, text } = heading;
19
+ let index = (delta > 0) ? 0 : (children.length - 1);
20
+ while (
21
+ children[index] &&
22
+ (children[index].type !== "atxHeadingSequence")
23
+ ) {
24
+ index += delta;
25
+ }
26
+ const headingSequence = children[index];
27
+ const whitespace = children[index + delta];
28
+ if (
29
+ (headingSequence?.type === "atxHeadingSequence") &&
30
+ (whitespace?.type === "whitespace") &&
31
+ (whitespace.text.length > 1)
32
+ ) {
33
+ const column = whitespace.startColumn + 1;
34
+ const length = whitespace.endColumn - column;
35
+ addErrorContext(
36
+ onError,
37
+ startLine,
38
+ text.trim(),
39
+ delta > 0,
40
+ delta < 0,
41
+ [ column, length ],
42
+ {
43
+ "editColumn": column,
44
+ "deleteCount": length
45
+ }
46
+ );
47
+ }
48
+ }
49
+
50
+ // eslint-disable-next-line jsdoc/valid-types
51
+ /** @type import("./markdownlint").Rule[] */
52
+ module.exports = [
53
+ {
54
+ "names": [ "MD019", "no-multiple-space-atx" ],
55
+ "description": "Multiple spaces after hash on atx style heading",
56
+ "tags": [ "headings", "atx", "spaces" ],
57
+ "parser": "micromark",
58
+ "function": function MD019(params, onError) {
59
+ const atxHeadings = filterByTypesCached([ "atxHeading" ])
60
+ .filter((heading) => getHeadingStyle(heading) === "atx");
61
+ for (const atxHeading of atxHeadings) {
62
+ validateHeadingSpaces(onError, atxHeading, 1);
63
+ }
64
+ }
65
+ },
66
+ {
67
+ "names": [ "MD021", "no-multiple-space-closed-atx" ],
68
+ "description": "Multiple spaces inside hashes on closed atx style heading",
69
+ "tags": [ "headings", "atx_closed", "spaces" ],
70
+ "parser": "micromark",
71
+ "function": function MD021(params, onError) {
72
+ const atxClosedHeadings = filterByTypesCached([ "atxHeading" ])
73
+ .filter((heading) => getHeadingStyle(heading) === "atx_closed");
74
+ for (const atxClosedHeading of atxClosedHeadings) {
75
+ validateHeadingSpaces(onError, atxClosedHeading, 1);
76
+ validateHeadingSpaces(onError, atxClosedHeading, -1);
77
+ }
78
+ }
79
+ }
80
+ ];
package/lib/md020.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-helpers.cjs");
7
+ const { filterByTypesCached } = require("./cache");
7
8
 
8
9
  // eslint-disable-next-line jsdoc/valid-types
9
10
  /** @type import("./markdownlint").Rule */
@@ -11,12 +12,17 @@ module.exports = {
11
12
  "names": [ "MD020", "no-missing-space-closed-atx" ],
12
13
  "description": "No space inside hashes on closed atx style heading",
13
14
  "tags": [ "headings", "atx_closed", "spaces" ],
14
- "parser": "none",
15
+ "parser": "micromark",
15
16
  "function": function MD020(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 (!ignoreBlockLineNumbers.has(lineIndex + 1)) {
18
24
  const match =
19
- /^(#+)([ \t]*)([^#]*?[^#\\])([ \t]*)((?:\\#)?)(#+)(\s*)$/.exec(line);
25
+ /^(#+)([ \t]*)([^# \t\\]|[^# \t][^#]*?[^# \t\\])([ \t]*)((?:\\#)?)(#+)(\s*)$/.exec(line);
20
26
  if (match) {
21
27
  const [
22
28
  ,
@@ -31,7 +37,7 @@ module.exports = {
31
37
  const leftHashLength = leftHash.length;
32
38
  const rightHashLength = rightHash.length;
33
39
  const left = !leftSpaceLength;
34
- const right = !rightSpaceLength || rightEscape;
40
+ const right = !rightSpaceLength || !!rightEscape;
35
41
  const rightEscapeReplacement = rightEscape ? `${rightEscape} ` : "";
36
42
  if (left || right) {
37
43
  const range = left ?
@@ -60,6 +66,6 @@ module.exports = {
60
66
  }
61
67
  }
62
68
  }
63
- });
69
+ }
64
70
  }
65
71
  };
package/lib/md022.js CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorDetailIf, blockquotePrefixRe, isBlankLine } =
6
- require("../helpers");
7
- const { filterByTypes, getHeadingLevel, inHtmlFlow } =
8
- require("../helpers/micromark.cjs");
5
+ const { addErrorDetailIf, isBlankLine } = require("../helpers");
6
+ const { getBlockQuotePrefixText, getHeadingLevel } = require("../helpers/micromark-helpers.cjs");
7
+ const { filterByTypesCached } = require("./cache");
9
8
 
10
9
  const defaultLines = 1;
11
10
 
@@ -22,15 +21,6 @@ const getLinesFunction = (linesParam) => {
22
21
  return () => lines;
23
22
  };
24
23
 
25
- const getBlockQuote = (str, count) => (
26
- (str || "")
27
- .match(blockquotePrefixRe)[0]
28
- .trimEnd()
29
- // eslint-disable-next-line unicorn/prefer-spread
30
- .concat("\n")
31
- .repeat(count)
32
- );
33
-
34
24
  // eslint-disable-next-line jsdoc/valid-types
35
25
  /** @type import("./markdownlint").Rule */
36
26
  module.exports = {
@@ -41,17 +31,9 @@ module.exports = {
41
31
  "function": function MD022(params, onError) {
42
32
  const getLinesAbove = getLinesFunction(params.config.lines_above);
43
33
  const getLinesBelow = getLinesFunction(params.config.lines_below);
44
- // eslint-disable-next-line jsdoc/valid-types
45
- /** @type import("../helpers/micromark.cjs").Token[] */
46
- const micromarkTokens =
47
- // @ts-ignore
48
- params.parsers.micromark.tokens;
49
34
  const { lines } = params;
50
- const headings = filterByTypes(
51
- micromarkTokens,
52
- [ "atxHeading", "setextHeading" ]
53
- ).filter((heading) => !inHtmlFlow(heading));
54
- for (const heading of headings) {
35
+ const blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
36
+ for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
55
37
  const { startLine, endLine } = heading;
56
38
  const line = lines[startLine - 1].trim();
57
39
 
@@ -73,10 +55,11 @@ module.exports = {
73
55
  actualAbove,
74
56
  "Above",
75
57
  line,
76
- null,
58
+ undefined,
77
59
  {
78
- "insertText": getBlockQuote(
79
- lines[startLine - 2],
60
+ "insertText": getBlockQuotePrefixText(
61
+ blockQuotePrefixes,
62
+ startLine - 1,
80
63
  linesAbove - actualAbove
81
64
  )
82
65
  }
@@ -101,11 +84,12 @@ module.exports = {
101
84
  actualBelow,
102
85
  "Below",
103
86
  line,
104
- null,
87
+ undefined,
105
88
  {
106
89
  "lineNumber": endLine + 1,
107
- "insertText": getBlockQuote(
108
- lines[endLine],
90
+ "insertText": getBlockQuotePrefixText(
91
+ blockQuotePrefixes,
92
+ endLine + 1,
109
93
  linesBelow - actualBelow
110
94
  )
111
95
  }
package/lib/md023.js CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, filterTokens } = require("../helpers");
6
-
7
- const spaceBeforeHeadingRe = /^(\s+|[>\s]+\s\s)[^>\s]/;
5
+ const { addErrorContext } = require("../helpers");
6
+ const { filterByTypesCached } = require("./cache");
8
7
 
9
8
  // eslint-disable-next-line jsdoc/valid-types
10
9
  /** @type import("./markdownlint").Rule */
@@ -12,30 +11,30 @@ module.exports = {
12
11
  "names": [ "MD023", "heading-start-left" ],
13
12
  "description": "Headings must start at the beginning of the line",
14
13
  "tags": [ "headings", "spaces" ],
15
- "parser": "markdownit",
14
+ "parser": "micromark",
16
15
  "function": function MD023(params, onError) {
17
- filterTokens(params, "heading_open", function forToken(token) {
18
- const { lineNumber, line } = token;
19
- const match = line.match(spaceBeforeHeadingRe);
20
- if (match) {
21
- const [ prefixAndFirstChar, prefix ] = match;
22
- let deleteCount = prefix.length;
23
- const prefixLengthNoSpace = prefix.trimEnd().length;
24
- if (prefixLengthNoSpace) {
25
- deleteCount -= prefixLengthNoSpace - 1;
26
- }
16
+ const headings = filterByTypesCached([ "atxHeading", "linePrefix", "setextHeading" ]);
17
+ for (let i = 0; i < headings.length - 1; i++) {
18
+ if (
19
+ (headings[i].type === "linePrefix") &&
20
+ (headings[i + 1].type !== "linePrefix") &&
21
+ (headings[i].startLine === headings[i + 1].startLine)
22
+ ) {
23
+ const { endColumn, startColumn, startLine } = headings[i];
24
+ const length = endColumn - startColumn;
27
25
  addErrorContext(
28
26
  onError,
29
- lineNumber,
30
- line,
31
- null,
32
- null,
33
- [ 1, prefixAndFirstChar.length ],
27
+ startLine,
28
+ params.lines[startLine - 1],
29
+ true,
30
+ false,
31
+ [ startColumn, length ],
34
32
  {
35
- "editColumn": prefixLengthNoSpace + 1,
36
- "deleteCount": deleteCount
37
- });
33
+ "editColumn": startColumn,
34
+ "deleteCount": length
35
+ }
36
+ );
38
37
  }
39
- });
38
+ }
40
39
  }
41
40
  };
package/lib/md024.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, forEachHeading } = require("../helpers");
5
+ const { addErrorContext } = require("../helpers");
6
+ const { getHeadingLevel, getHeadingText } = require("../helpers/micromark-helpers.cjs");
7
+ const { filterByTypesCached } = require("./cache");
6
8
 
7
9
  // eslint-disable-next-line jsdoc/valid-types
8
10
  /** @type import("./markdownlint").Rule */
@@ -10,15 +12,16 @@ module.exports = {
10
12
  "names": [ "MD024", "no-duplicate-heading" ],
11
13
  "description": "Multiple headings with the same content",
12
14
  "tags": [ "headings" ],
13
- "parser": "markdownit",
15
+ "parser": "micromark",
14
16
  "function": function MD024(params, onError) {
15
17
  const siblingsOnly = !!params.config.siblings_only || false;
16
18
  const knownContents = [ null, [] ];
17
19
  let lastLevel = 1;
18
20
  let knownContent = knownContents[lastLevel];
19
- forEachHeading(params, (heading, content) => {
21
+ for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
22
+ const headingText = getHeadingText(heading);
20
23
  if (siblingsOnly) {
21
- const newLevel = heading.tag.slice(1);
24
+ const newLevel = getHeadingLevel(heading);
22
25
  while (lastLevel < newLevel) {
23
26
  lastLevel++;
24
27
  knownContents[lastLevel] = [];
@@ -30,16 +33,16 @@ module.exports = {
30
33
  knownContent = knownContents[newLevel];
31
34
  }
32
35
  // @ts-ignore
33
- if (knownContent.includes(content)) {
36
+ if (knownContent.includes(headingText)) {
34
37
  addErrorContext(
35
38
  onError,
36
- heading.lineNumber,
37
- heading.line.trim()
39
+ heading.startLine,
40
+ headingText.trim()
38
41
  );
39
42
  } else {
40
43
  // @ts-ignore
41
- knownContent.push(content);
44
+ knownContent.push(headingText);
42
45
  }
43
- });
46
+ }
44
47
  }
45
48
  };
package/lib/md025.js CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, filterTokens, frontMatterHasTitle } =
6
- require("../helpers");
5
+ const { addErrorContext, frontMatterHasTitle } = require("../helpers");
6
+ const { getHeadingLevel, getHeadingText } = require("../helpers/micromark-helpers.cjs");
7
+ const { filterByTypesCached } = require("./cache");
7
8
 
8
9
  // eslint-disable-next-line jsdoc/valid-types
9
10
  /** @type import("./markdownlint").Rule */
@@ -11,25 +12,29 @@ module.exports = {
11
12
  "names": [ "MD025", "single-title", "single-h1" ],
12
13
  "description": "Multiple top-level headings in the same document",
13
14
  "tags": [ "headings" ],
14
- "parser": "markdownit",
15
+ "parser": "micromark",
15
16
  "function": function MD025(params, onError) {
16
17
  const level = Number(params.config.level || 1);
17
- const tag = "h" + level;
18
18
  const foundFrontMatterTitle =
19
19
  frontMatterHasTitle(
20
20
  params.frontMatterLines,
21
21
  params.config.front_matter_title
22
22
  );
23
23
  let hasTopLevelHeading = false;
24
- filterTokens(params, "heading_open", function forToken(token) {
25
- if (token.tag === tag) {
24
+ for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
25
+ const headingLevel = getHeadingLevel(heading);
26
+ if (headingLevel === level) {
26
27
  if (hasTopLevelHeading || foundFrontMatterTitle) {
27
- addErrorContext(onError, token.lineNumber,
28
- token.line.trim());
29
- } else if (token.lineNumber === 1) {
28
+ const headingText = getHeadingText(heading);
29
+ addErrorContext(
30
+ onError,
31
+ heading.startLine,
32
+ headingText
33
+ );
34
+ } else if (heading.startLine === 1) {
30
35
  hasTopLevelHeading = true;
31
36
  }
32
37
  }
33
- });
38
+ }
34
39
  }
35
40
  };
package/lib/md026.js CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  const { addError, allPunctuationNoQuestion, endOfLineGemojiCodeRe,
6
6
  endOfLineHtmlEntityRe, escapeForRegExp } = require("../helpers");
7
- const { filterByTypes } = 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 */
@@ -20,12 +20,7 @@ module.exports = {
20
20
  );
21
21
  const trailingPunctuationRe =
22
22
  new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$");
23
- // eslint-disable-next-line jsdoc/valid-types
24
- /** @type import("../helpers/micromark.cjs").Token[] */
25
- const micromarkTokens =
26
- // @ts-ignore
27
- params.parsers.micromark.tokens;
28
- const headings = filterByTypes(micromarkTokens, [ "atxHeadingText", "setextHeadingText" ]);
23
+ const headings = filterByTypesCached([ "atxHeadingText", "setextHeadingText" ]);
29
24
  for (const heading of headings) {
30
25
  const { endColumn, endLine, text } = heading;
31
26
  const match = trailingPunctuationRe.exec(text);
package/lib/md027.js CHANGED
@@ -3,23 +3,18 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext } = require("../helpers");
6
- const { filterByTypes } = require("../helpers/micromark.cjs");
6
+ const { filterByTypesCached } = require("./cache");
7
7
 
8
8
  // eslint-disable-next-line jsdoc/valid-types
9
9
  /** @type import("./markdownlint").Rule */
10
10
  module.exports = {
11
- "names": ["MD027", "no-multiple-space-blockquote"],
11
+ "names": [ "MD027", "no-multiple-space-blockquote" ],
12
12
  "description": "Multiple spaces after blockquote symbol",
13
- "tags": ["blockquote", "whitespace", "indentation"],
13
+ "tags": [ "blockquote", "whitespace", "indentation" ],
14
14
  "parser": "micromark",
15
15
  "function": function MD027(params, onError) {
16
- // eslint-disable-next-line jsdoc/valid-types
17
- /** @type import("../helpers/micromark.cjs").Token[] */
18
- const micromarkTokens =
19
- // @ts-ignore
20
- params.parsers.micromark.tokens;
21
- for (const token of filterByTypes(micromarkTokens, [ "linePrefix" ])) {
22
- const siblings = token.parent?.children || micromarkTokens;
16
+ for (const token of filterByTypesCached([ "linePrefix" ])) {
17
+ const siblings = token.parent?.children || params.parsers.micromark.tokens;
23
18
  if (siblings[siblings.indexOf(token) - 1]?.type === "blockQuotePrefix") {
24
19
  const { startColumn, startLine, text } = token;
25
20
  const { length } = text;
@@ -28,8 +23,8 @@ module.exports = {
28
23
  onError,
29
24
  startLine,
30
25
  line,
31
- null,
32
- null,
26
+ undefined,
27
+ undefined,
33
28
  [ startColumn, length ],
34
29
  {
35
30
  "editColumn": startColumn,
package/lib/md028.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addError } = require("../helpers");
6
- const { filterByTypes } = require("../helpers/micromark.cjs");
6
+ const { filterByTypesCached } = require("./cache");
7
7
 
8
8
  const ignoreTypes = new Set([ "lineEnding", "listItemIndent", "linePrefix" ]);
9
9
 
@@ -15,14 +15,9 @@ module.exports = {
15
15
  "tags": [ "blockquote", "whitespace" ],
16
16
  "parser": "micromark",
17
17
  "function": function MD028(params, onError) {
18
- // eslint-disable-next-line jsdoc/valid-types
19
- /** @type import("../helpers/micromark.cjs").Token[] */
20
- const micromarkTokens =
21
- // @ts-ignore
22
- params.parsers.micromark.tokens;
23
- for (const token of filterByTypes(micromarkTokens, [ "blockQuote" ])) {
18
+ for (const token of filterByTypesCached([ "blockQuote" ])) {
24
19
  const errorLineNumbers = [];
25
- const siblings = token.parent?.children || micromarkTokens;
20
+ const siblings = token.parent?.children || params.parsers.micromark.tokens;
26
21
  for (let i = siblings.indexOf(token) + 1; i < siblings.length; i++) {
27
22
  const sibling = siblings[i];
28
23
  const { startLine, type } = sibling;