markdownlint 0.26.2 → 0.27.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 (83) hide show
  1. package/CONTRIBUTING.md +81 -59
  2. package/README.md +424 -303
  3. package/demo/markdownlint-browser.js +374 -144
  4. package/doc/CustomRules.md +101 -50
  5. package/doc/Prettier.md +14 -10
  6. package/doc/ReleaseProcess.md +20 -0
  7. package/doc/Rules.md +453 -296
  8. package/doc/md001.md +37 -0
  9. package/doc/md002.md +37 -0
  10. package/doc/md003.md +59 -0
  11. package/doc/md004.md +49 -0
  12. package/doc/md005.md +53 -0
  13. package/doc/md006.md +46 -0
  14. package/doc/md007.md +55 -0
  15. package/doc/md009.md +51 -0
  16. package/doc/md010.md +56 -0
  17. package/doc/md011.md +30 -0
  18. package/doc/md012.md +38 -0
  19. package/doc/md013.md +60 -0
  20. package/doc/md014.md +54 -0
  21. package/doc/md018.md +27 -0
  22. package/doc/md019.md +28 -0
  23. package/doc/md020.md +29 -0
  24. package/doc/md021.md +31 -0
  25. package/doc/md022.md +46 -0
  26. package/doc/md023.md +26 -0
  27. package/doc/md024.md +47 -0
  28. package/doc/md025.md +49 -0
  29. package/doc/md026.md +41 -0
  30. package/doc/md027.md +24 -0
  31. package/doc/md028.md +40 -0
  32. package/doc/md029.md +98 -0
  33. package/doc/md030.md +82 -0
  34. package/doc/md031.md +50 -0
  35. package/doc/md032.md +38 -0
  36. package/doc/md033.md +27 -0
  37. package/doc/md034.md +44 -0
  38. package/doc/md035.md +42 -0
  39. package/doc/md036.md +45 -0
  40. package/doc/md037.md +37 -0
  41. package/doc/md038.md +40 -0
  42. package/doc/md039.md +21 -0
  43. package/doc/md040.md +52 -0
  44. package/doc/md041.md +49 -0
  45. package/doc/md042.md +32 -0
  46. package/doc/md043.md +72 -0
  47. package/doc/md044.md +35 -0
  48. package/doc/md045.md +34 -0
  49. package/doc/md046.md +40 -0
  50. package/doc/md047.md +34 -0
  51. package/doc/md048.md +41 -0
  52. package/doc/md049.md +32 -0
  53. package/doc/md050.md +32 -0
  54. package/doc/md051.md +50 -0
  55. package/doc/md052.md +33 -0
  56. package/doc/md053.md +38 -0
  57. package/helpers/README.md +35 -15
  58. package/helpers/helpers.js +204 -42
  59. package/helpers/package.json +2 -2
  60. package/lib/constants.js +8 -1
  61. package/lib/markdownlint.js +7 -7
  62. package/lib/md011.js +2 -2
  63. package/lib/md013.js +7 -6
  64. package/lib/md019.js +1 -1
  65. package/lib/md022.js +15 -3
  66. package/lib/md023.js +1 -1
  67. package/lib/md026.js +1 -1
  68. package/lib/md033.js +15 -4
  69. package/lib/md034.js +70 -45
  70. package/lib/md035.js +1 -1
  71. package/lib/md037.js +2 -2
  72. package/lib/md038.js +1 -1
  73. package/lib/md039.js +1 -1
  74. package/lib/md040.js +21 -2
  75. package/lib/md043.js +4 -2
  76. package/lib/md044.js +4 -3
  77. package/lib/md051.js +37 -5
  78. package/lib/rules.js +1 -1
  79. package/package.json +31 -21
  80. package/schema/.markdownlint.jsonc +10 -3
  81. package/schema/.markdownlint.yaml +8 -2
  82. package/schema/markdownlint-config-schema.json +27 -3
  83. package/style/prettier.json +26 -0
@@ -1,4 +1,4 @@
1
- /*! markdownlint 0.26.2 https://github.com/DavidAnson/markdownlint @license MIT */
1
+ /*! markdownlint 0.27.0 https://github.com/DavidAnson/markdownlint @license MIT */
2
2
  var markdownlint;
3
3
  /******/ (() => { // webpackBootstrap
4
4
  /******/ var __webpack_modules__ = ({
@@ -37,17 +37,16 @@ module.exports.newLineRe = newLineRe;
37
37
  // Regular expression for matching common front matter (YAML and TOML)
38
38
  module.exports.frontMatterRe =
39
39
  // eslint-disable-next-line max-len
40
- /((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m;
40
+ /((^---\s*$[\s\S]*?^---\s*)|(^\+\+\+\s*$[\s\S]*?^(\+\+\+|\.\.\.)\s*)|(^\{\s*$[\s\S]*?^\}\s*))(\r\n|\r|\n|$)/m;
41
41
  // Regular expression for matching the start of inline disable/enable comments
42
42
  const inlineCommentStartRe =
43
43
  // eslint-disable-next-line max-len
44
- /(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/ig;
44
+ /(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/gi;
45
45
  module.exports.inlineCommentStartRe = inlineCommentStartRe;
46
46
  // Regular expression for matching HTML elements
47
- const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^`>]*)?)\/?>/g;
47
+ const htmlElementRe = /<(([A-Za-z][A-Za-z\d-]*)(?:\s[^`>]*)?)\/?>/g;
48
48
  module.exports.htmlElementRe = htmlElementRe;
49
49
  // Regular expressions for range matching
50
- module.exports.bareUrlRe = /(?:http|ftp)s?:\/\/[^\s\]"']*(?:\/|[^\s\]"'\W])/ig;
51
50
  module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
52
51
  module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
53
52
  // Regular expression for all instances of emphasis markers
@@ -56,9 +55,9 @@ const emphasisMarkersRe = /[_*]/g;
56
55
  const blockquotePrefixRe = /^[>\s]*/;
57
56
  module.exports.blockquotePrefixRe = blockquotePrefixRe;
58
57
  // Regular expression for reference links (full, collapsed, and shortcut)
59
- const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g;
58
+ const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*\]|[^[\]\0])*)\](?:\[([^\]\0]*)\]|([^(])|$)/g;
60
59
  // Regular expression for link reference definitions
61
- const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/;
60
+ const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
62
61
  module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
63
62
  // All punctuation characters (normal and full-width)
64
63
  const allPunctuation = ".,;:!?。,;:!?";
@@ -154,6 +153,12 @@ module.exports.includesSorted = function includesSorted(array, element) {
154
153
  // https://spec.commonmark.org/0.29/#html-comment
155
154
  const htmlCommentBegin = "<!--";
156
155
  const htmlCommentEnd = "-->";
156
+ const safeCommentCharacter = ".";
157
+ const startsWithPipeRe = /^ *\|/;
158
+ const notCrLfRe = /[^\r\n]/g;
159
+ const notSpaceCrLfRe = /[^ \r\n]/g;
160
+ const trailingSpaceRe = / +[\r\n]/g;
161
+ const replaceTrailingSpace = (s) => s.replace(notCrLfRe, safeCommentCharacter);
157
162
  module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
158
163
  let i = 0;
159
164
  while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
@@ -164,24 +169,27 @@ module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
164
169
  }
165
170
  // If the comment has content...
166
171
  if (j > i + htmlCommentBegin.length) {
167
- let k = i - 1;
168
- while (text[k] === " ") {
169
- k--;
170
- }
171
- // If comment is not within an indented code block...
172
- if (k >= i - 4) {
173
- const content = text.slice(i + htmlCommentBegin.length, j);
174
- const isBlock = (k < 0) || (text[k] === "\n");
175
- const isValid = isBlock ||
176
- (!content.startsWith(">") && !content.startsWith("->") &&
177
- !content.endsWith("-") && !content.includes("--"));
178
- // If a valid block/inline comment...
179
- if (isValid) {
180
- text =
181
- text.slice(0, i + htmlCommentBegin.length) +
182
- content.replace(/[^\r\n]/g, ".") +
183
- text.slice(j);
184
- }
172
+ const content = text.slice(i + htmlCommentBegin.length, j);
173
+ const lastLf = text.lastIndexOf("\n", i) + 1;
174
+ const preText = text.slice(lastLf, i);
175
+ const isBlock = preText.trim().length === 0;
176
+ const couldBeTable = startsWithPipeRe.test(preText);
177
+ const spansTableCells = couldBeTable && content.includes("\n");
178
+ const isValid = isBlock ||
179
+ !(spansTableCells ||
180
+ content.startsWith(">") ||
181
+ content.startsWith("->") ||
182
+ content.endsWith("-") ||
183
+ content.includes("--"));
184
+ // If a valid block/inline comment...
185
+ if (isValid) {
186
+ const clearedContent = content
187
+ .replace(notSpaceCrLfRe, safeCommentCharacter)
188
+ .replace(trailingSpaceRe, replaceTrailingSpace);
189
+ text =
190
+ text.slice(0, i + htmlCommentBegin.length) +
191
+ clearedContent +
192
+ text.slice(j);
185
193
  }
186
194
  }
187
195
  i = j + htmlCommentEnd.length;
@@ -405,17 +413,22 @@ module.exports.flattenLists = function flattenLists(tokens) {
405
413
  }
406
414
  return flattenedLists;
407
415
  };
408
- // Calls the provided function for each specified inline child token
409
- module.exports.forEachInlineChild =
410
- function forEachInlineChild(params, type, handler) {
411
- filterTokens(params, "inline", function forToken(token) {
412
- for (const child of token.children) {
413
- if (child.type === type) {
414
- handler(child, token);
415
- }
416
- }
417
- });
418
- };
416
+ /**
417
+ * Calls the provided function for each specified inline child token.
418
+ *
419
+ * @param {Object} params RuleParams instance.
420
+ * @param {string} type Token type identifier.
421
+ * @param {Function} handler Callback function.
422
+ * @returns {void}
423
+ */
424
+ function forEachInlineChild(params, type, handler) {
425
+ filterTokens(params, "inline", (token) => {
426
+ for (const child of token.children.filter((c) => c.type === type)) {
427
+ handler(child, token);
428
+ }
429
+ });
430
+ }
431
+ module.exports.forEachInlineChild = forEachInlineChild;
419
432
  // Calls the provided function for each heading's content
420
433
  module.exports.forEachHeading = function forEachHeading(params, handler) {
421
434
  let heading = null;
@@ -576,6 +589,7 @@ module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => {
576
589
  */
577
590
  module.exports.htmlElementRanges = (params, lineMetadata) => {
578
591
  const exclusions = [];
592
+ // Match with htmlElementRe
579
593
  forEachLine(lineMetadata, (line, lineIndex, inCode) => {
580
594
  let match = null;
581
595
  // eslint-disable-next-line no-unmodified-loop-condition
@@ -583,6 +597,32 @@ module.exports.htmlElementRanges = (params, lineMetadata) => {
583
597
  exclusions.push([lineIndex, match.index, match[0].length]);
584
598
  }
585
599
  });
600
+ // Match with html_inline
601
+ forEachInlineChild(params, "html_inline", (token, parent) => {
602
+ const parentContent = parent.content;
603
+ let tokenContent = token.content;
604
+ const parentIndex = parentContent.indexOf(tokenContent);
605
+ let deltaLines = 0;
606
+ let indent = 0;
607
+ for (let i = parentIndex - 1; i >= 0; i--) {
608
+ if (parentContent[i] === "\n") {
609
+ deltaLines++;
610
+ }
611
+ else if (deltaLines === 0) {
612
+ indent++;
613
+ }
614
+ }
615
+ let lineIndex = token.lineNumber - 1 + deltaLines;
616
+ do {
617
+ const index = tokenContent.indexOf("\n");
618
+ const length = (index === -1) ? tokenContent.length : index;
619
+ exclusions.push([lineIndex, indent, length]);
620
+ tokenContent = tokenContent.slice(length + 1);
621
+ lineIndex++;
622
+ indent = 0;
623
+ } while (tokenContent.length > 0);
624
+ });
625
+ // Return results
586
626
  return exclusions;
587
627
  };
588
628
  /**
@@ -752,9 +792,10 @@ module.exports.emphasisMarkersInContent = emphasisMarkersInContent;
752
792
  function getReferenceLinkImageData(lineMetadata) {
753
793
  // Initialize return values
754
794
  const references = new Map();
755
- const shortcuts = new Set();
795
+ const shortcuts = new Map();
756
796
  const definitions = new Map();
757
797
  const duplicateDefinitions = [];
798
+ const definitionLineIndices = [];
758
799
  // Define helper functions
759
800
  const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
760
801
  const exclusions = [];
@@ -793,7 +834,13 @@ function getReferenceLinkImageData(lineMetadata) {
793
834
  else {
794
835
  definitions.set(label, lineIndex);
795
836
  }
796
- exclusions.push([0, lineOffsets[lineIndex], line.length]);
837
+ const labelLength = linkReferenceDefinitionMatch[0].length;
838
+ exclusions.push([0, lineOffsets[lineIndex], labelLength]);
839
+ const hasDefinition = line.slice(labelLength).trim().length > 0;
840
+ definitionLineIndices.push(lineIndex);
841
+ if (!hasDefinition) {
842
+ definitionLineIndices.push(lineIndex + 1);
843
+ }
797
844
  }
798
845
  }
799
846
  });
@@ -835,18 +882,23 @@ function getReferenceLinkImageData(lineMetadata) {
835
882
  }
836
883
  const referenceIndex = referenceindex +
837
884
  (topLevel ? -lineOffsets[lineIndex] : contentIndex);
885
+ const referenceDatum = [
886
+ lineIndex,
887
+ referenceIndex,
888
+ matchString.length,
889
+ matchText.length,
890
+ (matchLabel || "").length
891
+ ];
838
892
  if (shortcutLink) {
839
893
  // Track separately due to ambiguity in "text [text] text"
840
- shortcuts.add(label);
894
+ const shortcutData = shortcuts.get(label) || [];
895
+ shortcutData.push(referenceDatum);
896
+ shortcuts.set(label, shortcutData);
841
897
  }
842
898
  else {
843
899
  // Track reference and location
844
900
  const referenceData = references.get(label) || [];
845
- referenceData.push([
846
- lineIndex,
847
- referenceIndex,
848
- matchString.length
849
- ]);
901
+ referenceData.push(referenceDatum);
850
902
  references.set(label, referenceData);
851
903
  }
852
904
  // Check for links embedded in brackets
@@ -866,7 +918,8 @@ function getReferenceLinkImageData(lineMetadata) {
866
918
  references,
867
919
  shortcuts,
868
920
  definitions,
869
- duplicateDefinitions
921
+ duplicateDefinitions,
922
+ definitionLineIndices
870
923
  };
871
924
  }
872
925
  module.exports.getReferenceLinkImageData = getReferenceLinkImageData;
@@ -953,7 +1006,7 @@ module.exports.applyFix = applyFix;
953
1006
  * @returns {string} Corrected content.
954
1007
  */
955
1008
  function applyFixes(input, errors) {
956
- const lineEnding = getPreferredLineEnding(input, __webpack_require__(/*! os */ "?591e"));
1009
+ const lineEnding = getPreferredLineEnding(input, __webpack_require__(/*! node:os */ "?0176"));
957
1010
  const lines = input.split(newLineRe);
958
1011
  // Normalize fixInfo objects
959
1012
  let fixInfos = errors
@@ -1084,6 +1137,109 @@ function expandTildePath(file, os) {
1084
1137
  return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file;
1085
1138
  }
1086
1139
  module.exports.expandTildePath = expandTildePath;
1140
+ /**
1141
+ * RegExp.exec-style implementation of function expressions.
1142
+ *
1143
+ * @param {Function} funcExp Function that takes string and returns
1144
+ * [index, length] or null.
1145
+ * @param {string} input String to search.
1146
+ * @returns {string[] | null} RegExp.exec-style [match] with an index property.
1147
+ */
1148
+ function funcExpExec(funcExp, input) {
1149
+ // Start or resume match
1150
+ // @ts-ignore
1151
+ const lastIndex = funcExp.lastIndex || 0;
1152
+ const result = funcExp(input.slice(lastIndex));
1153
+ if (result) {
1154
+ // Update lastIndex and return match
1155
+ const [subIndex, length] = result;
1156
+ const index = lastIndex + subIndex;
1157
+ // @ts-ignore
1158
+ funcExp.lastIndex = index + length;
1159
+ const match = [input.slice(index, index + length)];
1160
+ // @ts-ignore
1161
+ match.index = index;
1162
+ return match;
1163
+ }
1164
+ // Reset lastIndex and return no match
1165
+ // @ts-ignore
1166
+ funcExp.lastIndex = 0;
1167
+ return null;
1168
+ }
1169
+ module.exports.funcExpExec = funcExpExec;
1170
+ const urlFeProtocolRe = /(?:http|ftp)s?:\/\//i;
1171
+ const urlFeAutolinkTerminalsRe = / |$/;
1172
+ const urlFeBareTerminalsRe = /[ ,!`'"\]]|$/;
1173
+ const urlFeNonTerminalsRe = "-#/";
1174
+ const urlFePunctuationRe = /\p{Punctuation}/u;
1175
+ const urlFePrefixToPostfix = new Map([
1176
+ [" ", " "],
1177
+ ["`", "`"],
1178
+ ["'", "'"],
1179
+ ["\"", "\""],
1180
+ ["‘", "’"],
1181
+ ["“", "”"],
1182
+ ["«", "»"],
1183
+ ["*", "*"],
1184
+ ["_", "_"],
1185
+ ["(", ")"],
1186
+ ["[", "]"],
1187
+ ["{", "}"],
1188
+ ["<", ">"],
1189
+ [">", "<"]
1190
+ ]);
1191
+ /**
1192
+ * Function expression that matches URLs.
1193
+ *
1194
+ * @param {string} input Substring to search for a URL.
1195
+ * @returns {Array | null} [index, length] of URL or null.
1196
+ */
1197
+ function urlFe(input) {
1198
+ // Find start of URL by searching for protocol
1199
+ const match = input.match(urlFeProtocolRe);
1200
+ if (match) {
1201
+ // Look for matching pre/postfix characters (ex: <...>)
1202
+ const start = match.index || 0;
1203
+ const length = match[0].length;
1204
+ const prefix = input[start - 1] || " ";
1205
+ const postfix = urlFePrefixToPostfix.get(prefix);
1206
+ // @ts-ignore
1207
+ let endPostfix = input.indexOf(postfix, start + length);
1208
+ if (endPostfix === -1) {
1209
+ endPostfix = input.length;
1210
+ }
1211
+ // Look for characters that terminate a URL
1212
+ const terminalsRe = (prefix === "<") ? urlFeAutolinkTerminalsRe : urlFeBareTerminalsRe;
1213
+ const endTerminal = start + input.slice(start).search(terminalsRe);
1214
+ // Determine tentative end of URL
1215
+ let end = Math.min(endPostfix, endTerminal);
1216
+ if (prefix === " ") {
1217
+ // If the URL used " " as pre/postfix characters, trim the end
1218
+ if (input[end - 1] === ")") {
1219
+ // Trim any ")" beyond the last "(...)" pair
1220
+ const lastOpenParen = input.lastIndexOf("(", end - 2);
1221
+ if (lastOpenParen <= start) {
1222
+ end--;
1223
+ }
1224
+ else {
1225
+ const nextCloseParen = input.indexOf(")", lastOpenParen + 1);
1226
+ end = nextCloseParen + 1;
1227
+ }
1228
+ }
1229
+ else {
1230
+ // Trim unwanted punctuation
1231
+ while (!urlFeNonTerminalsRe.includes(input[end - 1]) &&
1232
+ urlFePunctuationRe.test(input[end - 1])) {
1233
+ end--;
1234
+ }
1235
+ }
1236
+ }
1237
+ return [start, end - start];
1238
+ }
1239
+ // No match
1240
+ return null;
1241
+ }
1242
+ module.exports.urlFe = urlFe;
1087
1243
 
1088
1244
 
1089
1245
  /***/ }),
@@ -1099,50 +1255,50 @@ module.exports = markdownit;
1099
1255
 
1100
1256
  /***/ }),
1101
1257
 
1102
- /***/ "?591e":
1103
- /*!********************!*\
1104
- !*** os (ignored) ***!
1105
- \********************/
1258
+ /***/ "?0176":
1259
+ /*!*************************!*\
1260
+ !*** node:os (ignored) ***!
1261
+ \*************************/
1106
1262
  /***/ (() => {
1107
1263
 
1108
1264
  /* (ignored) */
1109
1265
 
1110
1266
  /***/ }),
1111
1267
 
1112
- /***/ "?ec0a":
1113
- /*!********************!*\
1114
- !*** fs (ignored) ***!
1115
- \********************/
1268
+ /***/ "?d0ee":
1269
+ /*!*************************!*\
1270
+ !*** node:fs (ignored) ***!
1271
+ \*************************/
1116
1272
  /***/ (() => {
1117
1273
 
1118
1274
  /* (ignored) */
1119
1275
 
1120
1276
  /***/ }),
1121
1277
 
1122
- /***/ "?a32b":
1123
- /*!********************!*\
1124
- !*** os (ignored) ***!
1125
- \********************/
1278
+ /***/ "?e6c4":
1279
+ /*!*************************!*\
1280
+ !*** node:os (ignored) ***!
1281
+ \*************************/
1126
1282
  /***/ (() => {
1127
1283
 
1128
1284
  /* (ignored) */
1129
1285
 
1130
1286
  /***/ }),
1131
1287
 
1132
- /***/ "?b85c":
1133
- /*!**********************!*\
1134
- !*** path (ignored) ***!
1135
- \**********************/
1288
+ /***/ "?9a52":
1289
+ /*!***************************!*\
1290
+ !*** node:path (ignored) ***!
1291
+ \***************************/
1136
1292
  /***/ (() => {
1137
1293
 
1138
1294
  /* (ignored) */
1139
1295
 
1140
1296
  /***/ }),
1141
1297
 
1142
- /***/ "?96a2":
1143
- /*!**********************!*\
1144
- !*** util (ignored) ***!
1145
- \**********************/
1298
+ /***/ "?39e5":
1299
+ /*!***************************!*\
1300
+ !*** node:util (ignored) ***!
1301
+ \***************************/
1146
1302
  /***/ (() => {
1147
1303
 
1148
1304
  /* (ignored) */
@@ -1189,8 +1345,15 @@ module.exports.referenceLinkImageData =
1189
1345
  // @ts-check
1190
1346
 
1191
1347
  module.exports.deprecatedRuleNames = ["MD002", "MD006"];
1348
+ module.exports.fixableRuleNames = [
1349
+ "MD004", "MD005", "MD006", "MD007", "MD009", "MD010",
1350
+ "MD011", "MD012", "MD014", "MD018", "MD019", "MD020",
1351
+ "MD021", "MD022", "MD023", "MD026", "MD027", "MD030",
1352
+ "MD031", "MD032", "MD034", "MD037", "MD038", "MD039",
1353
+ "MD044", "MD047", "MD049", "MD050", "MD051", "MD053"
1354
+ ];
1192
1355
  module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
1193
- module.exports.version = "0.26.2";
1356
+ module.exports.version = "0.27.0";
1194
1357
 
1195
1358
 
1196
1359
  /***/ }),
@@ -1204,8 +1367,8 @@ module.exports.version = "0.26.2";
1204
1367
  "use strict";
1205
1368
  // @ts-check
1206
1369
 
1207
- const path = __webpack_require__(/*! path */ "?b85c");
1208
- const { promisify } = __webpack_require__(/*! util */ "?96a2");
1370
+ const path = __webpack_require__(/*! node:path */ "?9a52");
1371
+ const { promisify } = __webpack_require__(/*! node:util */ "?39e5");
1209
1372
  const markdownIt = __webpack_require__(/*! markdown-it */ "markdown-it");
1210
1373
  const { deprecatedRuleNames } = __webpack_require__(/*! ./constants */ "../lib/constants.js");
1211
1374
  const rules = __webpack_require__(/*! ./rules */ "../lib/rules.js");
@@ -1991,7 +2154,7 @@ function lintInput(options, synchronous, callback) {
1991
2154
  // @ts-ignore
1992
2155
  md.use(...plugin);
1993
2156
  }
1994
- const fs = options.fs || __webpack_require__(/*! fs */ "?ec0a");
2157
+ const fs = options.fs || __webpack_require__(/*! node:fs */ "?d0ee");
1995
2158
  const results = newResults(ruleList);
1996
2159
  let done = false;
1997
2160
  let concurrency = 0;
@@ -2167,10 +2330,10 @@ function readConfig(file, parsers, fs, callback) {
2167
2330
  }
2168
2331
  }
2169
2332
  if (!fs) {
2170
- fs = __webpack_require__(/*! fs */ "?ec0a");
2333
+ fs = __webpack_require__(/*! node:fs */ "?d0ee");
2171
2334
  }
2172
2335
  // Read file
2173
- const os = __webpack_require__(/*! os */ "?a32b");
2336
+ const os = __webpack_require__(/*! node:os */ "?e6c4");
2174
2337
  file = helpers.expandTildePath(file, os);
2175
2338
  fs.readFile(file, "utf8", (err, content) => {
2176
2339
  if (err) {
@@ -2227,10 +2390,10 @@ function readConfigPromise(file, parsers, fs) {
2227
2390
  */
2228
2391
  function readConfigSync(file, parsers, fs) {
2229
2392
  if (!fs) {
2230
- fs = __webpack_require__(/*! fs */ "?ec0a");
2393
+ fs = __webpack_require__(/*! node:fs */ "?d0ee");
2231
2394
  }
2232
2395
  // Read file
2233
- const os = __webpack_require__(/*! os */ "?a32b");
2396
+ const os = __webpack_require__(/*! node:os */ "?e6c4");
2234
2397
  file = helpers.expandTildePath(file, os);
2235
2398
  const content = fs.readFileSync(file, "utf8");
2236
2399
  // Try to parse file
@@ -2742,7 +2905,7 @@ module.exports = {
2742
2905
 
2743
2906
  const { addError, forEachLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
2744
2907
  const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
2745
- const reversedLinkRe = /(^|[^\\])\(([^)]+)\)\[([^\]^][^\]]*)](?!\()/g;
2908
+ const reversedLinkRe = /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)\](?!\()/g;
2746
2909
  module.exports = {
2747
2910
  "names": ["MD011", "no-reversed-links"],
2748
2911
  "description": "Reversed link syntax",
@@ -2759,7 +2922,7 @@ module.exports = {
2759
2922
  if (!linkText.endsWith("\\") &&
2760
2923
  !linkDestination.endsWith("\\") &&
2761
2924
  !withinAnyRange(exclusions, lineIndex, index, length)) {
2762
- addError(onError, lineIndex + 1, reversedLink.slice(preChar.length), null, [index + 1, length], {
2925
+ addError(onError, lineIndex + 1, reversedLink.slice(preChar.length), undefined, [index + 1, length], {
2763
2926
  "editColumn": index + 1,
2764
2927
  "deleteCount": length,
2765
2928
  "insertText": `[${linkText}](${linkDestination})`
@@ -2815,13 +2978,13 @@ module.exports = {
2815
2978
  "use strict";
2816
2979
  // @ts-check
2817
2980
 
2818
- const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine, includesSorted, linkReferenceDefinitionRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
2819
- const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
2981
+ const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine, includesSorted } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
2982
+ const { lineMetadata, referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
2820
2983
  const longLineRePrefix = "^.{";
2821
2984
  const longLineRePostfixRelaxed = "}.*\\s.*$";
2822
2985
  const longLineRePostfixStrict = "}.+$";
2823
- const linkOrImageOnlyLineRe = /^[es]*(lT?L|I)[ES]*$/;
2824
- const sternModeRe = /^([#>\s]*\s)?\S*$/;
2986
+ const linkOrImageOnlyLineRe = /^[es]*(?:lT?L|I)[ES]*$/;
2987
+ const sternModeRe = /^(?:[#>\s]*\s)?\S*$/;
2825
2988
  const tokenTypeMap = {
2826
2989
  "em_open": "e",
2827
2990
  "em_close": "E",
@@ -2871,6 +3034,7 @@ module.exports = {
2871
3034
  linkOnlyLineNumbers.push(token.lineNumber);
2872
3035
  }
2873
3036
  });
3037
+ const { definitionLineIndices } = referenceLinkImageData();
2874
3038
  forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => {
2875
3039
  const lineNumber = lineIndex + 1;
2876
3040
  const isHeading = includesSorted(headingLineNumbers, lineNumber);
@@ -2883,10 +3047,10 @@ module.exports = {
2883
3047
  if ((includeCodeBlocks || !inCode) &&
2884
3048
  (includeTables || !inTable) &&
2885
3049
  (includeHeadings || !isHeading) &&
3050
+ !includesSorted(definitionLineIndices, lineIndex) &&
2886
3051
  (strict ||
2887
3052
  (!(stern && sternModeRe.test(line)) &&
2888
- !includesSorted(linkOnlyLineNumbers, lineNumber) &&
2889
- !linkReferenceDefinitionRe.test(line))) &&
3053
+ !includesSorted(linkOnlyLineNumbers, lineNumber))) &&
2890
3054
  lengthRe.test(line)) {
2891
3055
  addErrorDetailIf(onError, lineNumber, length, line.length, null, null, [length + 1, line.length - length]);
2892
3056
  }
@@ -3002,7 +3166,7 @@ module.exports = {
3002
3166
  filterTokens(params, "heading_open", (token) => {
3003
3167
  if (headingStyleFor(token) === "atx") {
3004
3168
  const { line, lineNumber } = token;
3005
- const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line);
3169
+ const match = /^(#+)([ \t]{2,})\S/.exec(line);
3006
3170
  if (match) {
3007
3171
  const [, { "length": hashLength }, { "length": spacesLength }] = match;
3008
3172
  addErrorContext(onError, lineNumber, line.trim(), null, null, [1, hashLength + spacesLength + 1], {
@@ -3130,7 +3294,13 @@ module.exports = {
3130
3294
  "use strict";
3131
3295
  // @ts-check
3132
3296
 
3133
- const { addErrorDetailIf, filterTokens, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3297
+ const { addErrorDetailIf, blockquotePrefixRe, filterTokens, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3298
+ const getBlockQuote = (str, count) => ((str || "")
3299
+ .match(blockquotePrefixRe)[0]
3300
+ .trimEnd()
3301
+ // eslint-disable-next-line unicorn/prefer-spread
3302
+ .concat("\n")
3303
+ .repeat(count));
3134
3304
  module.exports = {
3135
3305
  "names": ["MD022", "blanks-around-headings", "blanks-around-headers"],
3136
3306
  "description": "Headings should be surrounded by blank lines",
@@ -3150,7 +3320,7 @@ module.exports = {
3150
3320
  }
3151
3321
  }
3152
3322
  addErrorDetailIf(onError, topIndex + 1, linesAbove, actualAbove, "Above", lines[topIndex].trim(), null, {
3153
- "insertText": "".padEnd(linesAbove - actualAbove, "\n")
3323
+ "insertText": getBlockQuote(lines[topIndex - 1], linesAbove - actualAbove)
3154
3324
  });
3155
3325
  let actualBelow = 0;
3156
3326
  for (let i = 0; i < linesBelow; i++) {
@@ -3160,7 +3330,7 @@ module.exports = {
3160
3330
  }
3161
3331
  addErrorDetailIf(onError, topIndex + 1, linesBelow, actualBelow, "Below", lines[topIndex].trim(), null, {
3162
3332
  "lineNumber": nextIndex + 1,
3163
- "insertText": "".padEnd(linesBelow - actualBelow, "\n")
3333
+ "insertText": getBlockQuote(lines[nextIndex], linesBelow - actualBelow)
3164
3334
  });
3165
3335
  });
3166
3336
  }
@@ -3179,7 +3349,7 @@ module.exports = {
3179
3349
  // @ts-check
3180
3350
 
3181
3351
  const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3182
- const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/;
3352
+ const spaceBeforeHeadingRe = /^(\s+|[>\s]+\s\s)[^>\s]/;
3183
3353
  module.exports = {
3184
3354
  "names": ["MD023", "heading-start-left", "header-start-left"],
3185
3355
  "description": "Headings must start at the beginning of the line",
@@ -3298,7 +3468,7 @@ module.exports = {
3298
3468
  // @ts-check
3299
3469
 
3300
3470
  const { addError, allPunctuationNoQuestion, escapeForRegExp, forEachHeading } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3301
- const endOfLineHtmlEntityRe = /&#?[0-9a-zA-Z]+;$/;
3471
+ const endOfLineHtmlEntityRe = /&#?[\da-zA-Z]+;$/;
3302
3472
  module.exports = {
3303
3473
  "names": ["MD026", "no-trailing-punctuation"],
3304
3474
  "description": "Trailing punctuation in heading",
@@ -3630,12 +3800,12 @@ module.exports = {
3630
3800
  // @ts-check
3631
3801
 
3632
3802
  const { addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3633
- const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3634
- const linkDestinationRe = /]\(\s*$/;
3803
+ const { codeBlockAndSpanRanges, lineMetadata, referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3804
+ const linkDestinationRe = /\]\(\s*$/;
3635
3805
  // See https://spec.commonmark.org/0.29/#autolinks
3636
3806
  const emailAddressRe =
3637
3807
  // eslint-disable-next-line max-len
3638
- /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
3808
+ /^[\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?(?:\.[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?)*$/;
3639
3809
  module.exports = {
3640
3810
  "names": ["MD033", "no-inline-html"],
3641
3811
  "description": "Inline HTML",
@@ -3645,6 +3815,15 @@ module.exports = {
3645
3815
  allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
3646
3816
  allowedElements = allowedElements.map((element) => element.toLowerCase());
3647
3817
  const exclusions = codeBlockAndSpanRanges();
3818
+ const { references, definitionLineIndices } = referenceLinkImageData();
3819
+ for (const datas of references.values()) {
3820
+ for (const data of datas) {
3821
+ const [lineIndex, index, , textLength, labelLength] = data;
3822
+ if (labelLength > 0) {
3823
+ exclusions.push([lineIndex, index + 3 + textLength, labelLength]);
3824
+ }
3825
+ }
3826
+ }
3648
3827
  forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
3649
3828
  let match = null;
3650
3829
  // eslint-disable-next-line no-unmodified-loop-condition
@@ -3653,7 +3832,8 @@ module.exports = {
3653
3832
  if (!allowedElements.includes(element.toLowerCase()) &&
3654
3833
  !tag.endsWith("\\>") &&
3655
3834
  !emailAddressRe.test(content) &&
3656
- !withinAnyRange(exclusions, lineIndex, match.index, match[0].length)) {
3835
+ !withinAnyRange(exclusions, lineIndex, match.index, tag.length) &&
3836
+ !definitionLineIndices.includes(lineIndex)) {
3657
3837
  const prefix = line.substring(0, match.index);
3658
3838
  if (!linkDestinationRe.test(prefix)) {
3659
3839
  const unescaped = unescapeMarkdown(prefix + "<", "_");
@@ -3679,52 +3859,70 @@ module.exports = {
3679
3859
  "use strict";
3680
3860
  // @ts-check
3681
3861
 
3682
- const { addErrorContext, bareUrlRe, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3862
+ const { addErrorContext, filterTokens, funcExpExec, urlFe, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3863
+ const { codeBlockAndSpanRanges, htmlElementRanges, referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3864
+ const htmlLinkRe = /<a(?:\s[^>]*)?>[^<>]*<\/a\s*>/gi;
3683
3865
  module.exports = {
3684
3866
  "names": ["MD034", "no-bare-urls"],
3685
3867
  "description": "Bare URL used",
3686
3868
  "tags": ["links", "url"],
3687
3869
  "function": function MD034(params, onError) {
3688
- filterTokens(params, "inline", (token) => {
3689
- let inLink = false;
3690
- for (const child of token.children) {
3691
- const { content, line, lineNumber, type } = child;
3870
+ const { lines } = params;
3871
+ const codeExclusions = [
3872
+ ...codeBlockAndSpanRanges(),
3873
+ ...htmlElementRanges()
3874
+ ];
3875
+ filterTokens(params, "html_block", (token) => {
3876
+ for (let i = token.map[0]; i < token.map[1]; i++) {
3877
+ codeExclusions.push([i, 0, lines[i].length]);
3878
+ }
3879
+ });
3880
+ const { definitionLineIndices } = referenceLinkImageData();
3881
+ for (const [lineIndex, line] of lines.entries()) {
3882
+ if (definitionLineIndices[0] === lineIndex) {
3883
+ definitionLineIndices.shift();
3884
+ }
3885
+ else {
3692
3886
  let match = null;
3693
- if (type === "link_open") {
3694
- inLink = true;
3695
- }
3696
- else if (type === "link_close") {
3697
- inLink = false;
3887
+ const lineExclusions = [];
3888
+ while ((match = htmlLinkRe.exec(line)) !== null) {
3889
+ lineExclusions.push([lineIndex, match.index, match[0].length]);
3698
3890
  }
3699
- else if ((type === "text") && !inLink) {
3700
- while ((match = bareUrlRe.exec(content)) !== null) {
3701
- const [bareUrl] = match;
3702
- const matchIndex = match.index;
3703
- const bareUrlLength = bareUrl.length;
3704
- // Allow "[https://example.com]" to avoid conflicts with
3705
- // MD011/no-reversed-links; allow quoting as another way
3706
- // of deliberately including a bare URL
3707
- const leftChar = content[matchIndex - 1];
3708
- const rightChar = content[matchIndex + bareUrlLength];
3709
- if (!((leftChar === "[") && (rightChar === "]")) &&
3710
- !((leftChar === "\"") && (rightChar === "\"")) &&
3711
- !((leftChar === "'") && (rightChar === "'"))) {
3712
- const index = line.indexOf(content);
3713
- const range = (index === -1) ? null : [
3714
- index + matchIndex + 1,
3715
- bareUrlLength
3716
- ];
3717
- const fixInfo = range ? {
3718
- "editColumn": range[0],
3719
- "deleteCount": range[1],
3720
- "insertText": `<${bareUrl}>`
3721
- } : null;
3722
- addErrorContext(onError, lineNumber, bareUrl, null, null, range, fixInfo);
3723
- }
3891
+ while ((match = funcExpExec(urlFe, line)) !== null) {
3892
+ const [bareUrl] = match;
3893
+ // @ts-ignore
3894
+ const matchIndex = match.index;
3895
+ const bareUrlLength = bareUrl.length;
3896
+ const prefix = line.slice(0, matchIndex);
3897
+ const postfix = line.slice(matchIndex + bareUrlLength);
3898
+ if (
3899
+ // Allow <...> to avoid reporting non-bare links
3900
+ !(prefix.endsWith("<") && postfix.startsWith(">")) &&
3901
+ // Allow >...</ to avoid reporting <code>...</code>
3902
+ !(prefix.endsWith(">") && postfix.startsWith("</")) &&
3903
+ // Allow "..." and '...' to allow quoting a bare link
3904
+ !(prefix.endsWith("\"") && postfix.startsWith("\"")) &&
3905
+ !(prefix.endsWith("'") && postfix.startsWith("'")) &&
3906
+ // Allow ](... to avoid reporting Markdown-style links
3907
+ !(/\]\(\s*$/.test(prefix)) &&
3908
+ // Allow [...] to avoid MD011/no-reversed-links and nested links
3909
+ !(/\[[^\]]*$/.test(prefix) && /^[^[]*\]/.test(postfix)) &&
3910
+ !withinAnyRange(lineExclusions, lineIndex, matchIndex, bareUrlLength) &&
3911
+ !withinAnyRange(codeExclusions, lineIndex, matchIndex, bareUrlLength)) {
3912
+ const range = [
3913
+ matchIndex + 1,
3914
+ bareUrlLength
3915
+ ];
3916
+ const fixInfo = {
3917
+ "editColumn": range[0],
3918
+ "deleteCount": range[1],
3919
+ "insertText": `<${bareUrl}>`
3920
+ };
3921
+ addErrorContext(onError, lineIndex + 1, bareUrl, null, null, range, fixInfo);
3724
3922
  }
3725
3923
  }
3726
3924
  }
3727
- });
3925
+ }
3728
3926
  }
3729
3927
  };
3730
3928
 
@@ -3750,7 +3948,7 @@ module.exports = {
3750
3948
  filterTokens(params, "hr", (token) => {
3751
3949
  const { line, lineNumber } = token;
3752
3950
  let { markup } = token;
3753
- const match = line.match(/[_*\-\s\t]+$/);
3951
+ const match = line.match(/[_*\-\s]+$/);
3754
3952
  if (match) {
3755
3953
  markup = match[0].trim();
3756
3954
  }
@@ -3841,8 +4039,8 @@ module.exports = {
3841
4039
 
3842
4040
  const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3843
4041
  const { htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3844
- const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
3845
- const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
4042
+ const emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g;
4043
+ const embeddedUnderscoreRe = /([A-Za-z\d])_([A-Za-z\d])/g;
3846
4044
  const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
3847
4045
  const leftSpaceRe = /^\s+/;
3848
4046
  const rightSpaceRe = /\s+$/;
@@ -4013,7 +4211,7 @@ module.exports = {
4013
4211
  // @ts-check
4014
4212
 
4015
4213
  const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4016
- const leftSpaceRe = /^\s([^`]|$)/;
4214
+ const leftSpaceRe = /^\s(?:[^`]|$)/;
4017
4215
  const rightSpaceRe = /[^`]\s$/;
4018
4216
  const spaceInsideCodeInline = (token) => ((token.type === "code_inline") &&
4019
4217
  (leftSpaceRe.test(token.content) || rightSpaceRe.test(token.content)));
@@ -4076,7 +4274,7 @@ module.exports = {
4076
4274
  // @ts-check
4077
4275
 
4078
4276
  const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4079
- const spaceInLinkRe = /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=((?:\([^)]*\))|(?:\[[^\]]*\])))/;
4277
+ const spaceInLinkRe = /\[(?:\s[^\]]*|[^\]]*?\s)\](?=(\([^)]*\)|\[[^\]]*\]))/;
4080
4278
  module.exports = {
4081
4279
  "names": ["MD039", "no-space-in-links"],
4082
4280
  "description": "Spaces inside link text",
@@ -4143,16 +4341,26 @@ module.exports = {
4143
4341
  "use strict";
4144
4342
  // @ts-check
4145
4343
 
4146
- const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4344
+ const { addError, addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4147
4345
  module.exports = {
4148
4346
  "names": ["MD040", "fenced-code-language"],
4149
4347
  "description": "Fenced code blocks should have a language specified",
4150
4348
  "tags": ["code", "language"],
4151
4349
  "function": function MD040(params, onError) {
4350
+ let allowed = params.config.allowed_languages;
4351
+ allowed = Array.isArray(allowed) ? allowed : [];
4352
+ const languageOnly = !!params.config.language_only;
4152
4353
  filterTokens(params, "fence", function forToken(token) {
4153
- if (!token.info.trim()) {
4354
+ const lang = token.info.trim().split(/\s+/u).shift();
4355
+ if (lang === "") {
4154
4356
  addErrorContext(onError, token.lineNumber, token.line);
4155
4357
  }
4358
+ else if ((allowed.length > 0) && !allowed.includes(lang)) {
4359
+ addError(onError, token.lineNumber, `"${lang}" is not allowed`);
4360
+ }
4361
+ if (languageOnly && (token.info !== lang)) {
4362
+ addError(onError, token.lineNumber, `Info string contains more than language: "${token.info}"`);
4363
+ }
4156
4364
  });
4157
4365
  }
4158
4366
  };
@@ -4278,6 +4486,7 @@ module.exports = {
4278
4486
  "tags": ["headings", "headers"],
4279
4487
  "function": function MD043(params, onError) {
4280
4488
  const requiredHeadings = params.config.headings || params.config.headers;
4489
+ const matchCase = params.config.match_case || false;
4281
4490
  if (Array.isArray(requiredHeadings)) {
4282
4491
  const levels = {};
4283
4492
  for (const level of [1, 2, 3, 4, 5, 6]) {
@@ -4288,6 +4497,7 @@ module.exports = {
4288
4497
  let hasError = false;
4289
4498
  let anyHeadings = false;
4290
4499
  const getExpected = () => requiredHeadings[i++] || "[None]";
4500
+ const handleCase = (str) => (matchCase ? str : str.toLowerCase());
4291
4501
  forEachHeading(params, (heading, content) => {
4292
4502
  if (!hasError) {
4293
4503
  anyHeadings = true;
@@ -4295,7 +4505,7 @@ module.exports = {
4295
4505
  const expected = getExpected();
4296
4506
  if (expected === "*") {
4297
4507
  const nextExpected = getExpected();
4298
- if (nextExpected.toLowerCase() !== actual.toLowerCase()) {
4508
+ if (handleCase(nextExpected) !== handleCase(actual)) {
4299
4509
  matchAny = true;
4300
4510
  i--;
4301
4511
  }
@@ -4303,7 +4513,7 @@ module.exports = {
4303
4513
  else if (expected === "+") {
4304
4514
  matchAny = true;
4305
4515
  }
4306
- else if (expected.toLowerCase() === actual.toLowerCase()) {
4516
+ else if (handleCase(expected) === handleCase(actual)) {
4307
4517
  matchAny = false;
4308
4518
  }
4309
4519
  else if (matchAny) {
@@ -4338,7 +4548,7 @@ module.exports = {
4338
4548
  "use strict";
4339
4549
  // @ts-check
4340
4550
 
4341
- const { addErrorDetailIf, bareUrlRe, escapeForRegExp, forEachLine, forEachLink, withinAnyRange, linkReferenceDefinitionRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4551
+ const { addErrorDetailIf, escapeForRegExp, forEachLine, forEachLink, funcExpExec, linkReferenceDefinitionRe, urlFe, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4342
4552
  const { codeBlockAndSpanRanges, htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
4343
4553
  module.exports = {
4344
4554
  "names": ["MD044", "proper-names"],
@@ -4359,7 +4569,8 @@ module.exports = {
4359
4569
  }
4360
4570
  else {
4361
4571
  let match = null;
4362
- while ((match = bareUrlRe.exec(line)) !== null) {
4572
+ while ((match = funcExpExec(urlFe, line)) !== null) {
4573
+ // @ts-ignore
4363
4574
  exclusions.push([lineIndex, match.index, match[0].length]);
4364
4575
  }
4365
4576
  forEachLink(line, (index, _, text, destination) => {
@@ -4599,7 +4810,7 @@ module.exports = [
4599
4810
  "use strict";
4600
4811
  // @ts-check
4601
4812
 
4602
- const { addError, escapeForRegExp, filterTokens, forEachInlineChild, forEachHeading, htmlElementRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4813
+ const { addError, addErrorDetailIf, escapeForRegExp, filterTokens, forEachInlineChild, forEachHeading, htmlElementRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4603
4814
  // Regular expression for identifying HTML anchor names
4604
4815
  const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
4605
4816
  const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
@@ -4661,12 +4872,31 @@ module.exports = {
4661
4872
  if (id && (id.length > 1) && (id[0] === "#") && !fragments.has(id)) {
4662
4873
  let context = id;
4663
4874
  let range = null;
4875
+ let fixInfo = null;
4664
4876
  const match = line.match(new RegExp(`\\[.*?\\]\\(${escapeForRegExp(context)}\\)`));
4665
4877
  if (match) {
4666
- context = match[0];
4667
- range = [match.index + 1, match[0].length];
4878
+ [context] = match;
4879
+ const index = match.index;
4880
+ const length = context.length;
4881
+ range = [index + 1, length];
4882
+ fixInfo = {
4883
+ "editColumn": index + (length - id.length),
4884
+ "deleteCount": id.length,
4885
+ "insertText": null
4886
+ };
4887
+ }
4888
+ const idLower = id.toLowerCase();
4889
+ const mixedCaseKey = [...fragments.keys()]
4890
+ .find((key) => idLower === key.toLowerCase());
4891
+ if (mixedCaseKey) {
4892
+ (fixInfo || {}).insertText = mixedCaseKey;
4893
+ addErrorDetailIf(onError, lineNumber, mixedCaseKey, id, undefined, context, range, fixInfo);
4894
+ }
4895
+ else {
4896
+ addError(onError, lineNumber, undefined, context,
4897
+ // @ts-ignore
4898
+ range);
4668
4899
  }
4669
- addError(onError, lineNumber, undefined, context, range);
4670
4900
  }
4671
4901
  });
4672
4902
  }
@@ -4822,7 +5052,7 @@ for (const rule of rules) {
4822
5052
  const name = rule.names[0].toLowerCase();
4823
5053
  // eslint-disable-next-line dot-notation
4824
5054
  rule["information"] =
4825
- new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
5055
+ new URL(`${homepage}/blob/v${version}/doc/${name}.md`);
4826
5056
  }
4827
5057
  module.exports = rules;
4828
5058