markdownlint 0.35.0 → 0.36.1

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 (73) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +72 -35
  3. package/demo/markdownlint-browser.js +1259 -1215
  4. package/doc/CustomRules.md +55 -249
  5. package/doc/Rules.md +36 -29
  6. package/doc/md003.md +2 -2
  7. package/doc/md004.md +4 -3
  8. package/doc/md035.md +3 -8
  9. package/doc/md046.md +2 -2
  10. package/doc/md048.md +3 -2
  11. package/doc/md049.md +4 -3
  12. package/doc/md050.md +4 -4
  13. package/doc/md051.md +11 -3
  14. package/doc/md055.md +3 -2
  15. package/helpers/README.md +2 -19
  16. package/helpers/helpers.js +87 -347
  17. package/helpers/micromark-helpers.cjs +296 -0
  18. package/helpers/micromark-parse.cjs +313 -0
  19. package/helpers/package.json +5 -2
  20. package/helpers/shared.js +6 -0
  21. package/helpers/test.cjs +28 -0
  22. package/lib/cache.js +3 -3
  23. package/lib/configuration-strict.d.ts +120 -106
  24. package/lib/constants.js +1 -1
  25. package/lib/markdownit.cjs +172 -0
  26. package/lib/markdownlint.d.ts +41 -3
  27. package/lib/markdownlint.js +153 -115
  28. package/lib/md001.js +1 -1
  29. package/lib/md003.js +1 -1
  30. package/lib/md004.js +3 -3
  31. package/lib/md007.js +3 -3
  32. package/lib/md009.js +1 -1
  33. package/lib/md010.js +18 -14
  34. package/lib/md011.js +24 -23
  35. package/lib/md012.js +1 -1
  36. package/lib/md013.js +1 -1
  37. package/lib/md014.js +5 -9
  38. package/lib/md018.js +1 -1
  39. package/lib/md019-md021.js +1 -1
  40. package/lib/md020.js +2 -2
  41. package/lib/md022.js +9 -15
  42. package/lib/md024.js +1 -1
  43. package/lib/md025.js +1 -1
  44. package/lib/md027.js +2 -2
  45. package/lib/md029.js +3 -3
  46. package/lib/md031.js +8 -6
  47. package/lib/md032.js +27 -15
  48. package/lib/md033.js +1 -1
  49. package/lib/md034.js +21 -29
  50. package/lib/md036.js +18 -24
  51. package/lib/md037.js +1 -1
  52. package/lib/md038.js +9 -14
  53. package/lib/md039.js +13 -15
  54. package/lib/md040.js +11 -13
  55. package/lib/md041.js +4 -4
  56. package/lib/md042.js +2 -6
  57. package/lib/md043.js +1 -1
  58. package/lib/md044.js +31 -28
  59. package/lib/md045.js +2 -2
  60. package/lib/md048.js +28 -17
  61. package/lib/md049-md050.js +20 -5
  62. package/lib/md051.js +16 -18
  63. package/lib/md053.js +5 -4
  64. package/lib/md054.js +11 -13
  65. package/lib/md055.js +39 -46
  66. package/lib/md056.js +31 -36
  67. package/lib/md058.js +29 -14
  68. package/package.json +14 -13
  69. package/schema/.markdownlint.jsonc +55 -52
  70. package/schema/.markdownlint.yaml +54 -52
  71. package/schema/markdownlint-config-schema-strict.json +132 -110
  72. package/schema/markdownlint-config-schema.json +132 -110
  73. package/helpers/micromark.cjs +0 -544
package/lib/md038.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext } = require("../helpers");
6
- const { tokenIfType } = require("../helpers/micromark.cjs");
6
+ const { getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
7
7
  const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  const leftSpaceRe = /^\s(?:[^`]|$)/;
@@ -29,24 +29,19 @@ module.exports = {
29
29
  "function": function MD038(params, onError) {
30
30
  const codeTexts = filterByTypesCached([ "codeText" ]);
31
31
  for (const codeText of codeTexts) {
32
- const { children } = codeText;
33
- const first = 0;
34
- const last = children.length - 1;
35
- const startSequence = tokenIfType(children[first], "codeTextSequence");
36
- const endSequence = tokenIfType(children[last], "codeTextSequence");
37
- const startData =
38
- tokenIfType(children[first + 1], "codeTextData") ||
39
- tokenIfType(children[first + 2], "codeTextData");
40
- const endData =
41
- tokenIfType(children[last - 1], "codeTextData") ||
42
- tokenIfType(children[last - 2], "codeTextData");
32
+ const sequences = getDescendantsByType(codeText, [ "codeTextSequence" ]);
33
+ const startSequence = sequences[0];
34
+ const endSequence = sequences[sequences.length - 1];
35
+ const datas = getDescendantsByType(codeText, [ "codeTextData" ]);
36
+ const startData = datas[0];
37
+ const endData = datas[datas.length - 1];
43
38
  if (startSequence && endSequence && startData && endData) {
44
39
  const spaceLeft = leftSpaceRe.test(startData.text);
45
40
  const spaceRight = rightSpaceRe.test(endData.text);
46
41
  if (spaceLeft || spaceRight) {
47
42
  let lineNumber = startSequence.startLine;
48
- let range = null;
49
- let fixInfo = null;
43
+ let range = undefined;
44
+ let fixInfo = undefined;
50
45
  if (startSequence.startLine === endSequence.endLine) {
51
46
  range = [
52
47
  startSequence.startColumn,
package/lib/md039.js CHANGED
@@ -3,15 +3,14 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext } = require("../helpers");
6
- const { filterByTypes } = require("../helpers/micromark.cjs");
7
6
  const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
8
7
 
9
8
  /**
10
9
  * Adds an error for a label space issue.
11
10
  *
12
11
  * @param {import("./markdownlint").RuleOnError} onError Error-reporting callback.
13
- * @param {import("../helpers/micromark.cjs").Token} label Label token.
14
- * @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
12
+ * @param {import("../helpers/micromark-helpers.cjs").Token} label Label token.
13
+ * @param {import("../helpers/micromark-helpers.cjs").Token} labelText LabelText token.
15
14
  * @param {boolean} isStart True iff error is at the start of the link.
16
15
  */
17
16
  function addLabelSpaceError(onError, label, labelText, isStart) {
@@ -29,18 +28,20 @@ function addLabelSpaceError(onError, label, labelText, isStart) {
29
28
  isStart,
30
29
  !isStart,
31
30
  range,
32
- range ? {
33
- "editColumn": range[0],
34
- "deleteCount": range[1]
35
- } : undefined
31
+ range ?
32
+ {
33
+ "editColumn": range[0],
34
+ "deleteCount": range[1]
35
+ } :
36
+ undefined
36
37
  );
37
38
  }
38
39
 
39
40
  /**
40
41
  * Determines if a link is a valid link (and not a fake shortcut link due to parser tricks).
41
42
  *
42
- * @param {import("../helpers/micromark.cjs").Token} label Label token.
43
- * @param {import("../helpers/micromark.cjs").Token} labelText LabelText token.
43
+ * @param {import("../helpers/micromark-helpers.cjs").Token} label Label token.
44
+ * @param {import("../helpers/micromark-helpers.cjs").Token} labelText LabelText token.
44
45
  * @param {Map<string, any>} definitions Map of link definitions.
45
46
  * @returns {boolean} True iff the link is valid.
46
47
  */
@@ -57,13 +58,10 @@ module.exports = {
57
58
  "parser": "micromark",
58
59
  "function": function MD039(params, onError) {
59
60
  const { definitions } = getReferenceLinkImageData();
60
- const labels = filterByTypesCached([ "label" ]).
61
- filter((label) => label.parent?.type === "link");
61
+ const labels = filterByTypesCached([ "label" ])
62
+ .filter((label) => label.parent?.type === "link");
62
63
  for (const label of labels) {
63
- const labelTexts = filterByTypes(
64
- label.children,
65
- [ "labelText" ]
66
- );
64
+ const labelTexts = label.children.filter((child) => child.type === "labelText");
67
65
  for (const labelText of labelTexts) {
68
66
  if (
69
67
  (labelText.text.trimStart().length !== labelText.text.length) &&
package/lib/md040.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addError, addErrorContext } = require("../helpers");
6
- const { getTokenTextByType, tokenIfType } = require("../helpers/micromark.cjs");
6
+ const { getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
7
7
  const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  // eslint-disable-next-line jsdoc/valid-types
@@ -19,18 +19,16 @@ module.exports = {
19
19
  const languageOnly = !!params.config.language_only;
20
20
  const fencedCodes = filterByTypesCached([ "codeFenced" ]);
21
21
  for (const fencedCode of fencedCodes) {
22
- const openingFence = tokenIfType(fencedCode.children[0], "codeFencedFence");
23
- if (openingFence) {
24
- const { children, startLine, text } = openingFence;
25
- const info = getTokenTextByType(children, "codeFencedFenceInfo");
26
- if (!info) {
27
- addErrorContext(onError, startLine, text);
28
- } else if ((allowed.length > 0) && !allowed.includes(info)) {
29
- addError(onError, startLine, `"${info}" is not allowed`);
30
- }
31
- if (languageOnly && getTokenTextByType(children, "codeFencedFenceMeta")) {
32
- addError(onError, startLine, `Info string contains more than language: "${text}"`);
33
- }
22
+ const openingFence = getDescendantsByType(fencedCode, [ "codeFencedFence" ])[0];
23
+ const { startLine, text } = openingFence;
24
+ const info = getDescendantsByType(openingFence, [ "codeFencedFenceInfo" ])[0]?.text;
25
+ if (!info) {
26
+ addErrorContext(onError, startLine, text);
27
+ } else if ((allowed.length > 0) && !allowed.includes(info)) {
28
+ addError(onError, startLine, `"${info}" is not allowed`);
29
+ }
30
+ if (languageOnly && getDescendantsByType(openingFence, [ "codeFencedFenceMeta" ]).length > 0) {
31
+ addError(onError, startLine, `Info string contains more than language: "${text}"`);
34
32
  }
35
33
  }
36
34
  }
package/lib/md041.js CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  const { addErrorContext, frontMatterHasTitle } = require("../helpers");
6
6
  const { filterByTypes, getHeadingLevel, getHtmlTagInfo, isHtmlFlowComment, nonContentTokens } =
7
- require("../helpers/micromark.cjs");
7
+ require("../helpers/micromark-helpers.cjs");
8
8
 
9
9
  // eslint-disable-next-line jsdoc/valid-types
10
10
  /** @type import("./markdownlint").Rule */
@@ -16,9 +16,9 @@ module.exports = {
16
16
  "function": function MD041(params, onError) {
17
17
  const level = Number(params.config.level || 1);
18
18
  if (!frontMatterHasTitle(params.frontMatterLines, params.config.front_matter_title)) {
19
- params.parsers.micromark.tokens.
20
- filter((token) => !nonContentTokens.has(token.type) && !isHtmlFlowComment(token)).
21
- every((token) => {
19
+ params.parsers.micromark.tokens
20
+ .filter((token) => !nonContentTokens.has(token.type) && !isHtmlFlowComment(token))
21
+ .every((token) => {
22
22
  let isError = true;
23
23
  if ((token.type === "atxHeading") || (token.type === "setextHeading")) {
24
24
  isError = (getHeadingLevel(token) !== level);
package/lib/md042.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext } = require("../helpers");
6
- const { getDescendantsByType } = require("../helpers/micromark.cjs");
6
+ const { getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
7
7
  const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
8
8
 
9
9
  // eslint-disable-next-line jsdoc/valid-types
@@ -25,11 +25,7 @@ module.exports = {
25
25
  const reference = getDescendantsByType(link, [ "reference" ]);
26
26
  const resource = getDescendantsByType(link, [ "resource" ]);
27
27
  const referenceString = getDescendantsByType(reference, [ "referenceString" ]);
28
- const resourceDestination = getDescendantsByType(resource, [ "resourceDestination" ]);
29
- const resourceDestinationString = [
30
- ...getDescendantsByType(resourceDestination, [ "resourceDestinationRaw", "resourceDestinationString" ]),
31
- ...getDescendantsByType(resourceDestination, [ "resourceDestinationLiteral", "resourceDestinationString" ])
32
- ];
28
+ const resourceDestinationString = getDescendantsByType(resource, [ "resourceDestination", [ "resourceDestinationLiteral", "resourceDestinationRaw" ], "resourceDestinationString" ]);
33
29
  const hasLabelText = labelText.length > 0;
34
30
  const hasReference = reference.length > 0;
35
31
  const hasResource = resource.length > 0;
package/lib/md043.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext, addErrorDetailIf } = require("../helpers");
6
- const { getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs");
6
+ const { getHeadingLevel, getHeadingText } = require("../helpers/micromark-helpers.cjs");
7
7
  const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  // eslint-disable-next-line jsdoc/valid-types
package/lib/md044.js CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorDetailIf, escapeForRegExp, withinAnyRange } =
6
- require("../helpers");
7
- const { filterByPredicate, filterByTypes, parse } =
8
- require("../helpers/micromark.cjs");
5
+ const { addErrorDetailIf, escapeForRegExp, hasOverlap } = require("../helpers");
6
+ const { filterByPredicate, filterByTypes } = require("../helpers/micromark-helpers.cjs");
7
+ const { parse } = require("../helpers/micromark-parse.cjs");
9
8
 
10
9
  const ignoredChildTypes = new Set(
11
10
  [ "codeFencedFence", "definition", "reference", "resource" ]
@@ -49,43 +48,47 @@ module.exports = {
49
48
  token.children.filter((t) => !ignoredChildTypes.has(t.type))
50
49
  )
51
50
  );
51
+ /** @type {import("../helpers").FileRange[]} */
52
52
  const exclusions = [];
53
- const autoLinked = new Set();
53
+ const scannedTokens = new Set();
54
54
  for (const name of names) {
55
55
  const escapedName = escapeForRegExp(name);
56
56
  const startNamePattern = /^\W/.test(name) ? "" : "\\b_*";
57
57
  const endNamePattern = /\W$/.test(name) ? "" : "_*\\b";
58
- const namePattern =
59
- `(${startNamePattern})(${escapedName})${endNamePattern}`;
58
+ const namePattern = `(${startNamePattern})(${escapedName})${endNamePattern}`;
60
59
  const nameRe = new RegExp(namePattern, "gi");
61
60
  for (const token of contentTokens) {
62
61
  let match = null;
63
62
  while ((match = nameRe.exec(token.text)) !== null) {
64
63
  const [ , leftMatch, nameMatch ] = match;
65
- const index = token.startColumn - 1 + match.index + leftMatch.length;
64
+ const column = token.startColumn + match.index + leftMatch.length;
66
65
  const length = nameMatch.length;
67
- const lineIndex = token.startLine - 1;
66
+ const lineNumber = token.startLine;
67
+ /** @type {import("../helpers").FileRange} */
68
+ const nameRange = {
69
+ "startLine": lineNumber,
70
+ "startColumn": column,
71
+ "endLine": lineNumber,
72
+ "endColumn": column + length - 1
73
+ };
68
74
  if (
69
- !withinAnyRange(exclusions, lineIndex, index, length) &&
70
- !names.includes(nameMatch)
75
+ !names.includes(nameMatch) &&
76
+ !exclusions.some((exclusion) => hasOverlap(exclusion, nameRange))
71
77
  ) {
72
- let urlRanges = [];
73
- if (!autoLinked.has(token)) {
74
- urlRanges = filterByTypes(
75
- parse(token.text),
76
- [ "literalAutolink" ]
77
- ).map(
78
- (t) => [
79
- lineIndex,
80
- token.startColumn - 1 + t.startColumn - 1,
81
- t.endColumn - t.startColumn
82
- ]
83
- );
84
- exclusions.push(...urlRanges);
85
- autoLinked.add(token);
78
+ /** @type {import("../helpers").FileRange[]} */
79
+ let autolinkRanges = [];
80
+ if (!scannedTokens.has(token)) {
81
+ autolinkRanges = filterByTypes(parse(token.text), [ "literalAutolink" ])
82
+ .map((tok) => ({
83
+ "startLine": lineNumber,
84
+ "startColumn": token.startColumn + tok.startColumn - 1,
85
+ "endLine": lineNumber,
86
+ "endColumn": token.endColumn + tok.endColumn - 1
87
+ }));
88
+ exclusions.push(...autolinkRanges);
89
+ scannedTokens.add(token);
86
90
  }
87
- if (!withinAnyRange(urlRanges, lineIndex, index, length)) {
88
- const column = index + 1;
91
+ if (!autolinkRanges.some((autolinkRange) => hasOverlap(autolinkRange, nameRange))) {
89
92
  addErrorDetailIf(
90
93
  onError,
91
94
  token.startLine,
@@ -102,7 +105,7 @@ module.exports = {
102
105
  );
103
106
  }
104
107
  }
105
- exclusions.push([ lineIndex, index, length ]);
108
+ exclusions.push(nameRange);
106
109
  }
107
110
  }
108
111
  }
package/lib/md045.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addError, getHtmlAttributeRe, nextLinesRe } = require("../helpers");
6
- const { filterByTypes, getHtmlTagInfo } = require("../helpers/micromark.cjs");
6
+ const { getHtmlTagInfo, getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
7
7
  const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  const altRe = getHtmlAttributeRe("alt");
@@ -19,7 +19,7 @@ module.exports = {
19
19
  // Process Markdown images
20
20
  const images = filterByTypesCached([ "image" ]);
21
21
  for (const image of images) {
22
- const labelTexts = filterByTypes(image.children, [ "labelText" ]);
22
+ const labelTexts = getDescendantsByType(image, [ "label", "labelText" ]);
23
23
  if (labelTexts.some((labelText) => labelText.text.length === 0)) {
24
24
  const range = (image.startLine === image.endLine) ?
25
25
  [ image.startColumn, image.endColumn - image.startColumn ] :
package/lib/md048.js CHANGED
@@ -2,10 +2,25 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorDetailIf, fencedCodeBlockStyleFor } = require("../helpers");
6
- const { tokenIfType } = require("../helpers/micromark.cjs");
5
+ const { addErrorDetailIf } = require("../helpers");
6
+ const { getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
7
7
  const { filterByTypesCached } = require("./cache");
8
8
 
9
+ /**
10
+ * Return the string representation of a fence markup character.
11
+ *
12
+ * @param {string} markup Fence string.
13
+ * @returns {"tilde" | "backtick"} String representation.
14
+ */
15
+ function fencedCodeBlockStyleFor(markup) {
16
+ switch (markup[0]) {
17
+ case "~":
18
+ return "tilde";
19
+ default:
20
+ return "backtick";
21
+ }
22
+ };
23
+
9
24
  // eslint-disable-next-line jsdoc/valid-types
10
25
  /** @type import("./markdownlint").Rule */
11
26
  module.exports = {
@@ -18,22 +33,18 @@ module.exports = {
18
33
  let expectedStyle = style;
19
34
  const codeFenceds = filterByTypesCached([ "codeFenced" ]);
20
35
  for (const codeFenced of codeFenceds) {
21
- const codeFencedFence = tokenIfType(codeFenced.children[0], "codeFencedFence");
22
- if (codeFencedFence) {
23
- const codeFencedFenceSequence = tokenIfType(codeFencedFence.children[0], "codeFencedFenceSequence");
24
- if (codeFencedFenceSequence) {
25
- const { startLine, text } = codeFencedFenceSequence;
26
- if (expectedStyle === "consistent") {
27
- expectedStyle = fencedCodeBlockStyleFor(text);
28
- }
29
- addErrorDetailIf(
30
- onError,
31
- startLine,
32
- expectedStyle,
33
- fencedCodeBlockStyleFor(text)
34
- );
35
- }
36
+ const codeFencedFenceSequence =
37
+ getDescendantsByType(codeFenced, [ "codeFencedFence", "codeFencedFenceSequence" ])[0];
38
+ const { startLine, text } = codeFencedFenceSequence;
39
+ if (expectedStyle === "consistent") {
40
+ expectedStyle = fencedCodeBlockStyleFor(text);
36
41
  }
42
+ addErrorDetailIf(
43
+ onError,
44
+ startLine,
45
+ expectedStyle,
46
+ fencedCodeBlockStyleFor(text)
47
+ );
37
48
  }
38
49
  }
39
50
  };
@@ -2,11 +2,26 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, emphasisOrStrongStyleFor } = require("../helpers");
6
- const { filterByPredicate, tokenIfType } = require("../helpers/micromark.cjs");
5
+ const { addError } = require("../helpers");
6
+ const { filterByPredicate, getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
7
7
 
8
8
  const intrawordRe = /^\w$/;
9
9
 
10
+ /**
11
+ * Return the string representation of a emphasis or strong markup character.
12
+ *
13
+ * @param {string} markup Emphasis or strong string.
14
+ * @returns {"asterisk" | "underscore"} String representation.
15
+ */
16
+ function emphasisOrStrongStyleFor(markup) {
17
+ switch (markup[0]) {
18
+ case "*":
19
+ return "asterisk";
20
+ default:
21
+ return "underscore";
22
+ }
23
+ };
24
+
10
25
  /**
11
26
  * @param {import("./markdownlint").RuleParams} params Rule parameters.
12
27
  * @param {import("./markdownlint").RuleOnError} onError Error-reporting callback.
@@ -25,9 +40,9 @@ const impl =
25
40
  (token) => ((token.type === "htmlFlow") ? [] : token.children)
26
41
  );
27
42
  for (const token of emphasisTokens) {
28
- const { children } = token;
29
- const startSequence = tokenIfType(children[0], typeSequence);
30
- const endSequence = tokenIfType(children[children.length - 1], typeSequence);
43
+ const sequences = getDescendantsByType(token, [ typeSequence ]);
44
+ const startSequence = sequences[0];
45
+ const endSequence = sequences[sequences.length - 1];
31
46
  if (startSequence && endSequence) {
32
47
  const markupStyle = emphasisOrStrongStyleFor(startSequence.text);
33
48
  if (style === "consistent") {
package/lib/md051.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, addErrorDetailIf, getHtmlAttributeRe } = require("../helpers");
6
- const { filterByPredicate, filterByTypes, getHtmlTagInfo } = require("../helpers/micromark.cjs");
5
+ const { addError, getHtmlAttributeRe } = require("../helpers");
6
+ const { filterByPredicate, filterByTypes, getHtmlTagInfo } = require("../helpers/micromark-helpers.cjs");
7
7
  const { filterByTypesCached } = require("./cache");
8
8
 
9
9
  // Regular expression for identifying HTML anchor names
@@ -22,7 +22,7 @@ const tokensInclude = new Set(
22
22
  * Converts a Markdown heading into an HTML fragment according to the rules
23
23
  * used by GitHub.
24
24
  *
25
- * @param {import("../helpers/micromark.cjs").Token} headingText Heading text token.
25
+ * @param {import("../helpers/micromark-helpers.cjs").Token} headingText Heading text token.
26
26
  * @returns {string} Fragment string for heading.
27
27
  */
28
28
  function convertHeadingToHTMLFragment(headingText) {
@@ -51,7 +51,7 @@ function convertHeadingToHTMLFragment(headingText) {
51
51
  /**
52
52
  * Unescapes the text of a String-type micromark Token.
53
53
  *
54
- * @param {import("../helpers/micromark.cjs").Token} token String-type micromark Token.
54
+ * @param {import("../helpers/micromark-helpers.cjs").Token} token String-type micromark Token.
55
55
  * @returns {string} Unescaped token text.
56
56
  */
57
57
  function unescapeStringTokenText(token) {
@@ -68,6 +68,7 @@ module.exports = {
68
68
  "tags": [ "links" ],
69
69
  "parser": "micromark",
70
70
  "function": function MD051(params, onError) {
71
+ const ignoreCase = params.config.ignore_case || false;
71
72
  const fragments = new Map();
72
73
 
73
74
  // Process headings
@@ -104,7 +105,7 @@ module.exports = {
104
105
 
105
106
  // Process link and definition fragments
106
107
  // eslint-disable-next-line jsdoc/valid-types
107
- /** @type import("../helpers/micromark.cjs").TokenType[][] */
108
+ /** @type import("../helpers/micromark-helpers.cjs").TokenType[][] */
108
109
  const parentChilds = [
109
110
  [ "link", "resourceDestinationString" ],
110
111
  [ "definition", "definitionDestinationString" ]
@@ -123,11 +124,8 @@ module.exports = {
123
124
  !fragments.has(encodedText) &&
124
125
  !lineFragmentRe.test(encodedText)
125
126
  ) {
126
- // eslint-disable-next-line no-undef-init
127
127
  let context = undefined;
128
- // eslint-disable-next-line no-undef-init
129
128
  let range = undefined;
130
- // eslint-disable-next-line no-undef-init
131
129
  let fixInfo = undefined;
132
130
  if (link.startLine === link.endLine) {
133
131
  context = link.text;
@@ -143,16 +141,16 @@ module.exports = {
143
141
  if (mixedCaseKey) {
144
142
  // @ts-ignore
145
143
  (fixInfo || {}).insertText = mixedCaseKey;
146
- addErrorDetailIf(
147
- onError,
148
- link.startLine,
149
- mixedCaseKey,
150
- text,
151
- undefined,
152
- context,
153
- range,
154
- fixInfo
155
- );
144
+ if (!ignoreCase && (mixedCaseKey !== text)) {
145
+ addError(
146
+ onError,
147
+ link.startLine,
148
+ `Expected: ${mixedCaseKey}; Actual: ${text}`,
149
+ context,
150
+ range,
151
+ fixInfo
152
+ );
153
+ }
156
154
  } else {
157
155
  addError(
158
156
  onError,
package/lib/md053.js CHANGED
@@ -2,10 +2,11 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, ellipsify, linkReferenceDefinitionRe } =
6
- require("../helpers");
5
+ const { addError, ellipsify } = require("../helpers");
7
6
  const { getReferenceLinkImageData } = require("./cache");
8
7
 
8
+ const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
9
+
9
10
  // eslint-disable-next-line jsdoc/valid-types
10
11
  /** @type import("./markdownlint").Rule */
11
12
  module.exports = {
@@ -39,7 +40,7 @@ module.exports = {
39
40
  `Unused link or image reference definition: "${label}"`,
40
41
  ellipsify(line),
41
42
  [ 1, line.length ],
42
- singleLineDefinition(line) ? deleteFixInfo : 0
43
+ singleLineDefinition(line) ? deleteFixInfo : undefined
43
44
  );
44
45
  }
45
46
  }
@@ -54,7 +55,7 @@ module.exports = {
54
55
  `Duplicate link or image reference definition: "${label}"`,
55
56
  ellipsify(line),
56
57
  [ 1, line.length ],
57
- singleLineDefinition(line) ? deleteFixInfo : 0
58
+ singleLineDefinition(line) ? deleteFixInfo : undefined
58
59
  );
59
60
  }
60
61
  }
package/lib/md054.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext, nextLinesRe } = require("../helpers");
6
- const { filterByPredicate, getTokenTextByType } = require("../helpers/micromark.cjs");
6
+ const { getDescendantsByType } = require("../helpers/micromark-helpers.cjs");
7
7
  const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
8
8
 
9
9
  const backslashEscapeRe = /\\([!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])/g;
@@ -45,24 +45,23 @@ module.exports = {
45
45
  let label = null;
46
46
  let destination = null;
47
47
  const {
48
- children, endColumn, endLine, startColumn, startLine, text, type
48
+ endColumn, endLine, startColumn, startLine, text, type
49
49
  } = link;
50
50
  const image = (type === "image");
51
51
  let isError = false;
52
52
  if (type === "autolink") {
53
53
  // link kind is an autolink
54
- destination = getTokenTextByType(children, "autolinkProtocol");
54
+ destination = getDescendantsByType(link, [ [ "autolinkEmail", "autolinkProtocol" ] ])[0]?.text;
55
55
  label = destination;
56
- isError = !autolink;
56
+ isError = !autolink && Boolean(destination);
57
57
  } else {
58
58
  // link type is "image" or "link"
59
- const descendents = filterByPredicate(children);
60
- label = getTokenTextByType(descendents, "labelText");
59
+ label = getDescendantsByType(link, [ "label", "labelText" ])[0].text;
61
60
  destination =
62
- getTokenTextByType(descendents, "resourceDestinationString");
61
+ getDescendantsByType(link, [ "resource", "resourceDestination", [ "resourceDestinationLiteral", "resourceDestinationRaw" ], "resourceDestinationString" ])[0]?.text;
63
62
  if (destination) {
64
63
  // link kind is an inline link
65
- const title = getTokenTextByType(descendents, "resourceTitleString");
64
+ const title = getDescendantsByType(link, [ "resource", "resourceTitle", "resourceTitleString" ])[0]?.text;
66
65
  isError = !inline || (
67
66
  !urlInline &&
68
67
  autolink &&
@@ -73,9 +72,9 @@ module.exports = {
73
72
  );
74
73
  } else {
75
74
  // link kind is a full/collapsed/shortcut reference link
76
- const isShortcut = !children.some((t) => t.type === "reference");
77
- const referenceString = getTokenTextByType(descendents, "referenceString");
78
- const isCollapsed = (referenceString === null);
75
+ const isShortcut = getDescendantsByType(link, [ "reference" ]).length === 0;
76
+ const referenceString = getDescendantsByType(link, [ "reference", "referenceString" ])[0]?.text;
77
+ const isCollapsed = (referenceString === undefined);
79
78
  const definition = definitions.get(referenceString || label);
80
79
  destination = definition && definition[1];
81
80
  isError = destination &&
@@ -83,9 +82,8 @@ module.exports = {
83
82
  }
84
83
  }
85
84
  if (isError) {
86
- // eslint-disable-next-line no-undef-init
87
85
  let range = undefined;
88
- let fixInfo = null;
86
+ let fixInfo = undefined;
89
87
  if (startLine === endLine) {
90
88
  range = [ startColumn, endColumn - startColumn ];
91
89
  let insertText = null;