markdownlint 0.33.0 → 0.34.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 (70) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/CONTRIBUTING.md +4 -3
  3. package/demo/markdownlint-browser.js +2730 -1541
  4. package/doc/CustomRules.md +14 -7
  5. package/doc/Rules.md +40 -7
  6. package/doc/md013.md +8 -7
  7. package/doc/md049.md +3 -0
  8. package/doc/md050.md +3 -0
  9. package/doc/md051.md +26 -0
  10. package/helpers/README.md +5 -3
  11. package/helpers/helpers.js +5 -5
  12. package/helpers/micromark.cjs +45 -27
  13. package/helpers/package.json +2 -2
  14. package/lib/configuration.d.ts +102 -102
  15. package/lib/constants.js +1 -1
  16. package/lib/markdownlint.d.ts +79 -6
  17. package/lib/markdownlint.js +95 -20
  18. package/lib/md001.js +3 -0
  19. package/lib/md003.js +3 -0
  20. package/lib/md004.js +3 -0
  21. package/lib/md005.js +9 -1
  22. package/lib/md007.js +14 -9
  23. package/lib/md009.js +3 -0
  24. package/lib/md010.js +4 -1
  25. package/lib/md011.js +3 -0
  26. package/lib/md012.js +3 -0
  27. package/lib/md013.js +3 -0
  28. package/lib/md014.js +4 -0
  29. package/lib/md018.js +4 -0
  30. package/lib/md019.js +3 -0
  31. package/lib/md020.js +3 -0
  32. package/lib/md021.js +3 -0
  33. package/lib/md022.js +10 -2
  34. package/lib/md023.js +3 -0
  35. package/lib/md024.js +3 -0
  36. package/lib/md025.js +3 -0
  37. package/lib/md026.js +9 -5
  38. package/lib/md027.js +29 -43
  39. package/lib/md028.js +31 -14
  40. package/lib/md029.js +3 -0
  41. package/lib/md030.js +9 -4
  42. package/lib/md031.js +3 -0
  43. package/lib/md032.js +12 -14
  44. package/lib/md033.js +9 -2
  45. package/lib/md034.js +31 -5
  46. package/lib/md035.js +9 -2
  47. package/lib/md036.js +33 -39
  48. package/lib/md037.js +10 -2
  49. package/lib/md038.js +10 -3
  50. package/lib/md039.js +4 -0
  51. package/lib/md040.js +26 -21
  52. package/lib/md041.js +21 -26
  53. package/lib/md042.js +4 -0
  54. package/lib/md043.js +3 -0
  55. package/lib/md044.js +9 -1
  56. package/lib/md045.js +10 -3
  57. package/lib/md046.js +14 -7
  58. package/lib/md047.js +5 -2
  59. package/lib/md048.js +26 -13
  60. package/lib/md049-md050.js +26 -7
  61. package/lib/md051.js +20 -16
  62. package/lib/md052.js +3 -0
  63. package/lib/md053.js +3 -0
  64. package/lib/md054.js +10 -5
  65. package/lib/md055.js +9 -1
  66. package/lib/md056.js +9 -1
  67. package/package.json +17 -22
  68. package/schema/.markdownlint.jsonc +50 -50
  69. package/schema/.markdownlint.yaml +50 -50
  70. package/schema/markdownlint-config-schema.json +104 -104
package/lib/md022.js CHANGED
@@ -31,16 +31,24 @@ const getBlockQuote = (str, count) => (
31
31
  .repeat(count)
32
32
  );
33
33
 
34
+ // eslint-disable-next-line jsdoc/valid-types
35
+ /** @type import("./markdownlint").Rule */
34
36
  module.exports = {
35
37
  "names": [ "MD022", "blanks-around-headings" ],
36
38
  "description": "Headings should be surrounded by blank lines",
37
39
  "tags": [ "headings", "blank_lines" ],
40
+ "parser": "micromark",
38
41
  "function": function MD022(params, onError) {
39
42
  const getLinesAbove = getLinesFunction(params.config.lines_above);
40
43
  const getLinesBelow = getLinesFunction(params.config.lines_below);
41
- const { lines, parsers } = params;
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
+ const { lines } = params;
42
50
  const headings = filterByTypes(
43
- parsers.micromark.tokens,
51
+ micromarkTokens,
44
52
  [ "atxHeading", "setextHeading" ]
45
53
  ).filter((heading) => !inHtmlFlow(heading));
46
54
  for (const heading of headings) {
package/lib/md023.js CHANGED
@@ -6,10 +6,13 @@ const { addErrorContext, filterTokens } = require("../helpers");
6
6
 
7
7
  const spaceBeforeHeadingRe = /^(\s+|[>\s]+\s\s)[^>\s]/;
8
8
 
9
+ // eslint-disable-next-line jsdoc/valid-types
10
+ /** @type import("./markdownlint").Rule */
9
11
  module.exports = {
10
12
  "names": [ "MD023", "heading-start-left" ],
11
13
  "description": "Headings must start at the beginning of the line",
12
14
  "tags": [ "headings", "spaces" ],
15
+ "parser": "markdownit",
13
16
  "function": function MD023(params, onError) {
14
17
  filterTokens(params, "heading_open", function forToken(token) {
15
18
  const { lineNumber, line } = token;
package/lib/md024.js CHANGED
@@ -4,10 +4,13 @@
4
4
 
5
5
  const { addErrorContext, forEachHeading } = require("../helpers");
6
6
 
7
+ // eslint-disable-next-line jsdoc/valid-types
8
+ /** @type import("./markdownlint").Rule */
7
9
  module.exports = {
8
10
  "names": [ "MD024", "no-duplicate-heading" ],
9
11
  "description": "Multiple headings with the same content",
10
12
  "tags": [ "headings" ],
13
+ "parser": "markdownit",
11
14
  "function": function MD024(params, onError) {
12
15
  const siblingsOnly = !!params.config.siblings_only || false;
13
16
  const knownContents = [ null, [] ];
package/lib/md025.js CHANGED
@@ -5,10 +5,13 @@
5
5
  const { addErrorContext, filterTokens, frontMatterHasTitle } =
6
6
  require("../helpers");
7
7
 
8
+ // eslint-disable-next-line jsdoc/valid-types
9
+ /** @type import("./markdownlint").Rule */
8
10
  module.exports = {
9
11
  "names": [ "MD025", "single-title", "single-h1" ],
10
12
  "description": "Multiple top-level headings in the same document",
11
13
  "tags": [ "headings" ],
14
+ "parser": "markdownit",
12
15
  "function": function MD025(params, onError) {
13
16
  const level = Number(params.config.level || 1);
14
17
  const tag = "h" + level;
package/lib/md026.js CHANGED
@@ -6,11 +6,13 @@ const { addError, allPunctuationNoQuestion, endOfLineGemojiCodeRe,
6
6
  endOfLineHtmlEntityRe, escapeForRegExp } = require("../helpers");
7
7
  const { filterByTypes } = require("../helpers/micromark.cjs");
8
8
 
9
-
9
+ // eslint-disable-next-line jsdoc/valid-types
10
+ /** @type import("./markdownlint").Rule */
10
11
  module.exports = {
11
12
  "names": [ "MD026", "no-trailing-punctuation" ],
12
13
  "description": "Trailing punctuation in heading",
13
14
  "tags": [ "headings" ],
15
+ "parser": "micromark",
14
16
  "function": function MD026(params, onError) {
15
17
  let punctuation = params.config.punctuation;
16
18
  punctuation = String(
@@ -18,10 +20,12 @@ module.exports = {
18
20
  );
19
21
  const trailingPunctuationRe =
20
22
  new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$");
21
- const headings = filterByTypes(
22
- params.parsers.micromark.tokens,
23
- [ "atxHeadingText", "setextHeadingText" ]
24
- );
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" ]);
25
29
  for (const heading of headings) {
26
30
  const { endColumn, endLine, text } = heading;
27
31
  const match = trailingPunctuationRe.exec(text);
package/lib/md027.js CHANGED
@@ -2,54 +2,40 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, newLineRe } = require("../helpers");
6
-
7
- const spaceAfterBlockQuoteRe = /^((?:\s*>)+)(\s{2,})\S/;
5
+ const { addErrorContext } = require("../helpers");
6
+ const { filterByTypes } = require("../helpers/micromark.cjs");
8
7
 
8
+ // eslint-disable-next-line jsdoc/valid-types
9
+ /** @type import("./markdownlint").Rule */
9
10
  module.exports = {
10
- "names": [ "MD027", "no-multiple-space-blockquote" ],
11
+ "names": ["MD027", "no-multiple-space-blockquote"],
11
12
  "description": "Multiple spaces after blockquote symbol",
12
- "tags": [ "blockquote", "whitespace", "indentation" ],
13
+ "tags": ["blockquote", "whitespace", "indentation"],
14
+ "parser": "micromark",
13
15
  "function": function MD027(params, onError) {
14
- let blockquoteNesting = 0;
15
- let listItemNesting = 0;
16
- for (const token of params.parsers.markdownit.tokens) {
17
- const { content, lineNumber, type } = token;
18
- if (type === "blockquote_open") {
19
- blockquoteNesting++;
20
- } else if (type === "blockquote_close") {
21
- blockquoteNesting--;
22
- } else if (type === "list_item_open") {
23
- listItemNesting++;
24
- } else if (type === "list_item_close") {
25
- listItemNesting--;
26
- } else if ((type === "inline") && blockquoteNesting) {
27
- const lineCount = content.split(newLineRe).length;
28
- for (let i = 0; i < lineCount; i++) {
29
- const line = params.lines[lineNumber + i - 1];
30
- const match = line.match(spaceAfterBlockQuoteRe);
31
- if (match) {
32
- const [
33
- fullMatch,
34
- { "length": blockquoteLength },
35
- { "length": spaceLength }
36
- ] = match;
37
- if (!listItemNesting || (fullMatch[fullMatch.length - 1] === ">")) {
38
- addErrorContext(
39
- onError,
40
- lineNumber + i,
41
- line,
42
- null,
43
- null,
44
- [ 1, fullMatch.length ],
45
- {
46
- "editColumn": blockquoteLength + 1,
47
- "deleteCount": spaceLength - 1
48
- }
49
- );
50
- }
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;
23
+ if (siblings[siblings.indexOf(token) - 1]?.type === "blockQuotePrefix") {
24
+ const { startColumn, startLine, text } = token;
25
+ const { length } = text;
26
+ const line = params.lines[startLine - 1];
27
+ addErrorContext(
28
+ onError,
29
+ startLine,
30
+ line,
31
+ null,
32
+ null,
33
+ [ startColumn, length ],
34
+ {
35
+ "editColumn": startColumn,
36
+ "deleteCount": length
51
37
  }
52
- }
38
+ );
53
39
  }
54
40
  }
55
41
  }
package/lib/md028.js CHANGED
@@ -3,28 +3,45 @@
3
3
  "use strict";
4
4
 
5
5
  const { addError } = require("../helpers");
6
+ const { filterByTypes } = require("../helpers/micromark.cjs");
6
7
 
8
+ const ignoreTypes = new Set([ "lineEnding", "listItemIndent", "linePrefix" ]);
9
+
10
+ // eslint-disable-next-line jsdoc/valid-types
11
+ /** @type import("./markdownlint").Rule */
7
12
  module.exports = {
8
13
  "names": [ "MD028", "no-blanks-blockquote" ],
9
14
  "description": "Blank line inside blockquote",
10
15
  "tags": [ "blockquote", "whitespace" ],
16
+ "parser": "micromark",
11
17
  "function": function MD028(params, onError) {
12
- let prevToken = {};
13
- let prevLineNumber = null;
14
- for (const token of params.parsers.markdownit.tokens) {
15
- if ((token.type === "blockquote_open") &&
16
- (prevToken.type === "blockquote_close")) {
17
- for (
18
- let lineNumber = prevLineNumber;
19
- lineNumber < token.lineNumber;
20
- lineNumber++) {
21
- addError(onError, lineNumber);
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" ])) {
24
+ const errorLineNumbers = [];
25
+ const siblings = token.parent?.children || micromarkTokens;
26
+ for (let i = siblings.indexOf(token) + 1; i < siblings.length; i++) {
27
+ const sibling = siblings[i];
28
+ const { startLine, type } = sibling;
29
+ if (type === "lineEndingBlank") {
30
+ // Possible blank between blockquotes
31
+ errorLineNumbers.push(startLine);
32
+ } else if (ignoreTypes.has(type)) {
33
+ // Ignore invisible formatting
34
+ } else if (type === "blockQuote") {
35
+ // Blockquote followed by blockquote
36
+ for (const lineNumber of errorLineNumbers) {
37
+ addError(onError, lineNumber);
38
+ }
39
+ break;
40
+ } else {
41
+ // Blockquote not followed by blockquote
42
+ break;
22
43
  }
23
44
  }
24
- prevToken = token;
25
- if (token.type === "blockquote_open") {
26
- prevLineNumber = token.map[1] + 1;
27
- }
28
45
  }
29
46
  }
30
47
  };
package/lib/md029.js CHANGED
@@ -12,10 +12,13 @@ const listStyleExamples = {
12
12
  "zero": "0/0/0"
13
13
  };
14
14
 
15
+ // eslint-disable-next-line jsdoc/valid-types
16
+ /** @type import("./markdownlint").Rule */
15
17
  module.exports = {
16
18
  "names": [ "MD029", "ol-prefix" ],
17
19
  "description": "Ordered list item prefix",
18
20
  "tags": [ "ol" ],
21
+ "parser": "none",
19
22
  "function": function MD029(params, onError) {
20
23
  const style = String(params.config.style || "one_or_ordered");
21
24
  const filteredLists = flattenedLists().filter((list) => !list.unordered);
package/lib/md030.js CHANGED
@@ -5,19 +5,24 @@
5
5
  const { addErrorDetailIf } = require("../helpers");
6
6
  const { filterByTypes } = require("../helpers/micromark.cjs");
7
7
 
8
+ // eslint-disable-next-line jsdoc/valid-types
9
+ /** @type import("./markdownlint").Rule */
8
10
  module.exports = {
9
11
  "names": [ "MD030", "list-marker-space" ],
10
12
  "description": "Spaces after list markers",
11
13
  "tags": [ "ol", "ul", "whitespace" ],
14
+ "parser": "micromark",
12
15
  "function": function MD030(params, onError) {
13
16
  const ulSingle = Number(params.config.ul_single || 1);
14
17
  const olSingle = Number(params.config.ol_single || 1);
15
18
  const ulMulti = Number(params.config.ul_multi || 1);
16
19
  const olMulti = Number(params.config.ol_multi || 1);
17
- const lists = filterByTypes(
18
- params.parsers.micromark.tokens,
19
- [ "listOrdered", "listUnordered" ]
20
- );
20
+ // eslint-disable-next-line jsdoc/valid-types
21
+ /** @type import("../helpers/micromark.cjs").Token[] */
22
+ const micromarkTokens =
23
+ // @ts-ignore
24
+ params.parsers.micromark.tokens;
25
+ const lists = filterByTypes(micromarkTokens, [ "listOrdered", "listUnordered" ]);
21
26
  for (const list of lists) {
22
27
  const ordered = (list.type === "listOrdered");
23
28
  const listItemPrefixes =
package/lib/md031.js CHANGED
@@ -7,10 +7,13 @@ const { lineMetadata } = require("./cache");
7
7
 
8
8
  const codeFencePrefixRe = /^(.*?)[`~]/;
9
9
 
10
+ // eslint-disable-next-line jsdoc/valid-types
11
+ /** @type import("./markdownlint").Rule */
10
12
  module.exports = {
11
13
  "names": [ "MD031", "blanks-around-fences" ],
12
14
  "description": "Fenced code blocks should be surrounded by blank lines",
13
15
  "tags": [ "code", "blank_lines" ],
16
+ "parser": "none",
14
17
  "function": function MD031(params, onError) {
15
18
  const listItems = params.config.list_items;
16
19
  const includeListItems = (listItems === undefined) ? true : !!listItems;
package/lib/md032.js CHANGED
@@ -2,19 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, blockquotePrefixRe, isBlankLine } =
6
- require("../helpers");
7
- const { filterByPredicate } = require("../helpers/micromark.cjs");
5
+ const { addErrorContext, blockquotePrefixRe, isBlankLine } = require("../helpers");
6
+ const { filterByPredicate, nonContentTokens } = require("../helpers/micromark.cjs");
8
7
 
9
- const nonContentTokens = new Set([
10
- "blockQuoteMarker",
11
- "blockQuotePrefix",
12
- "blockQuotePrefixWhitespace",
13
- "lineEnding",
14
- "lineEndingBlank",
15
- "linePrefix",
16
- "listItemIndent"
17
- ]);
18
8
  const isList = (token) => (
19
9
  (token.type === "listOrdered") || (token.type === "listUnordered")
20
10
  );
@@ -35,16 +25,24 @@ const addBlankLineError = (onError, lines, lineIndex, lineNumber) => {
35
25
  );
36
26
  };
37
27
 
28
+ // eslint-disable-next-line jsdoc/valid-types
29
+ /** @type import("./markdownlint").Rule */
38
30
  module.exports = {
39
31
  "names": [ "MD032", "blanks-around-lists" ],
40
32
  "description": "Lists should be surrounded by blank lines",
41
33
  "tags": [ "bullet", "ul", "ol", "blank_lines" ],
34
+ "parser": "micromark",
42
35
  "function": function MD032(params, onError) {
43
- const { lines, parsers } = params;
36
+ // eslint-disable-next-line jsdoc/valid-types
37
+ /** @type import("../helpers/micromark.cjs").Token[] */
38
+ const micromarkTokens =
39
+ // @ts-ignore
40
+ params.parsers.micromark.tokens;
41
+ const { lines } = params;
44
42
 
45
43
  // For every top-level list...
46
44
  const topLevelLists = filterByPredicate(
47
- parsers.micromark.tokens,
45
+ micromarkTokens,
48
46
  isList,
49
47
  (token) => (
50
48
  (isList(token) || (token.type === "htmlFlow")) ? [] : token.children
package/lib/md033.js CHANGED
@@ -6,16 +6,23 @@ const { addError, nextLinesRe } = require("../helpers");
6
6
  const { filterByTypes, getHtmlTagInfo } =
7
7
  require("../helpers/micromark.cjs");
8
8
 
9
+ // eslint-disable-next-line jsdoc/valid-types
10
+ /** @type import("./markdownlint").Rule */
9
11
  module.exports = {
10
12
  "names": [ "MD033", "no-inline-html" ],
11
13
  "description": "Inline HTML",
12
14
  "tags": [ "html" ],
15
+ "parser": "micromark",
13
16
  "function": function MD033(params, onError) {
14
17
  let allowedElements = params.config.allowed_elements;
15
18
  allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
16
19
  allowedElements = allowedElements.map((element) => element.toLowerCase());
17
- const { tokens } = params.parsers.micromark;
18
- for (const token of filterByTypes(tokens, [ "htmlText" ])) {
20
+ // eslint-disable-next-line jsdoc/valid-types
21
+ /** @type import("../helpers/micromark.cjs").Token[] */
22
+ const micromarkTokens =
23
+ // @ts-ignore
24
+ params.parsers.micromark.tokens;
25
+ for (const token of filterByTypes(micromarkTokens, [ "htmlText" ])) {
19
26
  const htmlTagInfo = getHtmlTagInfo(token);
20
27
  if (
21
28
  htmlTagInfo &&
package/lib/md034.js CHANGED
@@ -6,15 +6,44 @@ const { addErrorContext } = require("../helpers");
6
6
  const { filterByPredicate, filterByTypes, getHtmlTagInfo, inHtmlFlow, parse } =
7
7
  require("../helpers/micromark.cjs");
8
8
 
9
+ // eslint-disable-next-line jsdoc/valid-types
10
+ /** @type import("./markdownlint").Rule */
9
11
  module.exports = {
10
12
  "names": [ "MD034", "no-bare-urls" ],
11
13
  "description": "Bare URL used",
12
14
  "tags": [ "links", "url" ],
15
+ "parser": "micromark",
13
16
  "function": function MD034(params, onError) {
17
+ // eslint-disable-next-line jsdoc/valid-types
18
+ /** @type import("../helpers/micromark.cjs").Token[] */
19
+ const micromarkTokens =
20
+ // @ts-ignore
21
+ params.parsers.micromark.tokens;
14
22
  const literalAutolinks = (tokens) => (
15
23
  filterByPredicate(
16
24
  tokens,
17
- (token) => (token.type === "literalAutolink") && !inHtmlFlow(token),
25
+ (token) => {
26
+ if ((token.type === "literalAutolink") && !inHtmlFlow(token)) {
27
+ // Detect and ignore https://github.com/micromark/micromark/issues/164
28
+ const siblings = token.parent?.children;
29
+ // Commented-out due to not being able to exercise in test/code coverage
30
+ // || micromarkTokens;
31
+ const index = siblings?.indexOf(token);
32
+ // @ts-ignore
33
+ const prev = siblings?.at(index - 1);
34
+ // @ts-ignore
35
+ const next = siblings?.at(index + 1);
36
+ return !(
37
+ prev &&
38
+ next &&
39
+ (prev.type === "data") &&
40
+ (next.type === "data") &&
41
+ prev.text.endsWith("<") &&
42
+ next.text.startsWith(">")
43
+ );
44
+ }
45
+ return false;
46
+ },
18
47
  (token) => {
19
48
  const { children } = token;
20
49
  const result = [];
@@ -46,10 +75,7 @@ module.exports = {
46
75
  }
47
76
  )
48
77
  );
49
- const autoLinks = filterByTypes(
50
- params.parsers.micromark.tokens,
51
- [ "literalAutolink" ]
52
- );
78
+ const autoLinks = filterByTypes(micromarkTokens, [ "literalAutolink" ]);
53
79
  if (autoLinks.length > 0) {
54
80
  // Re-parse with correct link/image reference definition handling
55
81
  const document = params.lines.join("\n");
package/lib/md035.js CHANGED
@@ -5,14 +5,21 @@
5
5
  const { addErrorDetailIf } = require("../helpers");
6
6
  const { filterByTypes } = require("../helpers/micromark.cjs");
7
7
 
8
+ // eslint-disable-next-line jsdoc/valid-types
9
+ /** @type import("./markdownlint").Rule */
8
10
  module.exports = {
9
11
  "names": [ "MD035", "hr-style" ],
10
12
  "description": "Horizontal rule style",
11
13
  "tags": [ "hr" ],
14
+ "parser": "micromark",
12
15
  "function": function MD035(params, onError) {
13
16
  let style = String(params.config.style || "consistent").trim();
14
- const thematicBreaks =
15
- filterByTypes(params.parsers.micromark.tokens, [ "thematicBreak" ]);
17
+ // eslint-disable-next-line jsdoc/valid-types
18
+ /** @type import("../helpers/micromark.cjs").Token[] */
19
+ const micromarkTokens =
20
+ // @ts-ignore
21
+ params.parsers.micromark.tokens;
22
+ const thematicBreaks = filterByTypes(micromarkTokens, [ "thematicBreak" ]);
16
23
  for (const token of thematicBreaks) {
17
24
  const { startLine, text } = token;
18
25
  if (style === "consistent") {
package/lib/md036.js CHANGED
@@ -3,54 +3,48 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext, allPunctuation } = require("../helpers");
6
+ const { filterByTypes, matchAndGetTokensByType } = require("../helpers/micromark.cjs");
6
7
 
8
+ /** @typedef {import("../helpers/micromark.cjs").TokenType} TokenType */
9
+ /** @type {Map<TokenType, TokenType[]>} */
10
+ const emphasisAndChildrenTypes = new Map([
11
+ [ "emphasis", [ "emphasisSequence", "emphasisText", "emphasisSequence" ] ],
12
+ [ "strong", [ "strongSequence", "strongText", "strongSequence" ] ]
13
+ ]);
14
+
15
+ // eslint-disable-next-line jsdoc/valid-types
16
+ /** @type import("./markdownlint").Rule */
7
17
  module.exports = {
8
18
  "names": [ "MD036", "no-emphasis-as-heading" ],
9
19
  "description": "Emphasis used instead of a heading",
10
20
  "tags": [ "headings", "emphasis" ],
21
+ "parser": "micromark",
11
22
  "function": function MD036(params, onError) {
12
23
  let punctuation = params.config.punctuation;
13
- punctuation =
14
- String((punctuation === undefined) ? allPunctuation : punctuation);
15
- const re = new RegExp("[" + punctuation + "]$");
16
- // eslint-disable-next-line jsdoc/require-jsdoc
17
- function base(token) {
18
- if (token.type === "paragraph_open") {
19
- return function inParagraph(t) {
20
- // Always paragraph_open/inline/paragraph_close,
21
- const children = t.children.filter(function notEmptyText(child) {
22
- return (child.type !== "text") || (child.content !== "");
23
- });
24
- if ((children.length === 3) &&
25
- ((children[0].type === "strong_open") ||
26
- (children[0].type === "em_open")) &&
27
- (children[1].type === "text") &&
28
- !re.test(children[1].content)) {
29
- addErrorContext(onError, t.lineNumber,
30
- children[1].content);
31
- }
32
- return base;
33
- };
34
- } else if (token.type === "blockquote_open") {
35
- return function inBlockquote(t) {
36
- if (t.type !== "blockquote_close") {
37
- return inBlockquote;
24
+ punctuation = String((punctuation === undefined) ? allPunctuation : punctuation);
25
+ const punctuationRe = new RegExp("[" + punctuation + "]$");
26
+ const paragraphTokens =
27
+ filterByTypes(params.parsers.micromark.tokens, [ "paragraph" ]).
28
+ filter((token) =>
29
+ (token.parent?.type === "content") && !token.parent?.parent && (token.children.length === 1)
30
+ );
31
+ for (const paragraphToken of paragraphTokens) {
32
+ const childToken = paragraphToken.children[0];
33
+ for (const [ emphasisType, emphasisChildrenTypes ] of emphasisAndChildrenTypes) {
34
+ if (childToken.type === emphasisType) {
35
+ const matchingTokens = matchAndGetTokensByType(childToken.children, emphasisChildrenTypes);
36
+ if (matchingTokens) {
37
+ const textToken = matchingTokens[1];
38
+ if (
39
+ (textToken.children.length === 1) &&
40
+ (textToken.children[0].type === "data") &&
41
+ !punctuationRe.test(textToken.text)
42
+ ) {
43
+ addErrorContext(onError, textToken.startLine, textToken.text);
44
+ }
38
45
  }
39
- return base;
40
- };
41
- } else if (token.type === "list_item_open") {
42
- return function inListItem(t) {
43
- if (t.type !== "list_item_close") {
44
- return inListItem;
45
- }
46
- return base;
47
- };
46
+ }
48
47
  }
49
- return base;
50
- }
51
- let state = base;
52
- for (const token of params.parsers.markdownit.tokens) {
53
- state = state(token);
54
48
  }
55
49
  }
56
50
  };
package/lib/md037.js CHANGED
@@ -5,20 +5,28 @@
5
5
  const { addError } = require("../helpers");
6
6
  const { filterByPredicate, inHtmlFlow } = require("../helpers/micromark.cjs");
7
7
 
8
+ // eslint-disable-next-line jsdoc/valid-types
9
+ /** @type import("./markdownlint").Rule */
8
10
  module.exports = {
9
11
  "names": [ "MD037", "no-space-in-emphasis" ],
10
12
  "description": "Spaces inside emphasis markers",
11
13
  "tags": [ "whitespace", "emphasis" ],
14
+ "parser": "micromark",
12
15
  "function": function MD037(params, onError) {
13
16
 
14
17
  // Initialize variables
15
- const { lines, parsers } = params;
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
+ const { lines } = params;
16
24
  const emphasisTokensByMarker = new Map();
17
25
  for (const marker of [ "_", "__", "___", "*", "**", "***" ]) {
18
26
  emphasisTokensByMarker.set(marker, []);
19
27
  }
20
28
  const tokens = filterByPredicate(
21
- parsers.micromark.tokens,
29
+ micromarkTokens,
22
30
  (token) => token.children.some((child) => child.type === "data")
23
31
  );
24
32
  for (const token of tokens) {
package/lib/md038.js CHANGED
@@ -19,14 +19,21 @@ const trimCodeText = (text, start, end) => {
19
19
  return text;
20
20
  };
21
21
 
22
+ // eslint-disable-next-line jsdoc/valid-types
23
+ /** @type import("./markdownlint").Rule */
22
24
  module.exports = {
23
25
  "names": [ "MD038", "no-space-in-code" ],
24
26
  "description": "Spaces inside code span elements",
25
27
  "tags": [ "whitespace", "code" ],
28
+ "parser": "micromark",
26
29
  "function": function MD038(params, onError) {
27
- const codeTexts =
28
- filterByTypes(params.parsers.micromark.tokens, [ "codeText" ])
29
- .filter((codeText) => !inHtmlFlow(codeText));
30
+ // eslint-disable-next-line jsdoc/valid-types
31
+ /** @type import("../helpers/micromark.cjs").Token[] */
32
+ const micromarkTokens =
33
+ // @ts-ignore
34
+ params.parsers.micromark.tokens;
35
+ const codeTexts = filterByTypes(micromarkTokens, [ "codeText" ])
36
+ .filter((codeText) => !inHtmlFlow(codeText));
30
37
  for (const codeText of codeTexts) {
31
38
  const { children } = codeText;
32
39
  const first = 0;
package/lib/md039.js CHANGED
@@ -7,10 +7,13 @@ const { addErrorContext, filterTokens } = require("../helpers");
7
7
  const spaceInLinkRe =
8
8
  /\[(?:\s[^\]]*|[^\]]*?\s)\](?=(\([^)]*\)|\[[^\]]*\]))/;
9
9
 
10
+ // eslint-disable-next-line jsdoc/valid-types
11
+ /** @type import("./markdownlint").Rule */
10
12
  module.exports = {
11
13
  "names": [ "MD039", "no-space-in-links" ],
12
14
  "description": "Spaces inside link text",
13
15
  "tags": [ "whitespace", "links" ],
16
+ "parser": "markdownit",
14
17
  "function": function MD039(params, onError) {
15
18
  filterTokens(params, "inline", (token) => {
16
19
  const { children } = token;
@@ -33,6 +36,7 @@ module.exports = {
33
36
  let fixInfo = null;
34
37
  const match = line.slice(lineIndex).match(spaceInLinkRe);
35
38
  if (match) {
39
+ // @ts-ignore
36
40
  const column = match.index + lineIndex + 1;
37
41
  const length = match[0].length;
38
42
  range = [ column, length ];