markdownlint 0.26.1 → 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 (85) hide show
  1. package/CONTRIBUTING.md +81 -59
  2. package/README.md +424 -301
  3. package/demo/markdownlint-browser.js +445 -210
  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 +464 -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 +234 -70
  59. package/helpers/package.json +2 -2
  60. package/lib/constants.js +8 -1
  61. package/lib/markdownlint.js +7 -12
  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/md032.js +4 -5
  69. package/lib/md033.js +16 -5
  70. package/lib/md034.js +70 -45
  71. package/lib/md035.js +1 -1
  72. package/lib/md037.js +25 -22
  73. package/lib/md038.js +1 -1
  74. package/lib/md039.js +1 -1
  75. package/lib/md040.js +21 -2
  76. package/lib/md043.js +4 -2
  77. package/lib/md044.js +4 -3
  78. package/lib/md051.js +43 -11
  79. package/lib/md053.js +18 -11
  80. package/lib/rules.js +1 -1
  81. package/package.json +31 -21
  82. package/schema/.markdownlint.jsonc +16 -4
  83. package/schema/.markdownlint.yaml +13 -3
  84. package/schema/markdownlint-config-schema.json +45 -5
  85. package/style/prettier.json +26 -0
@@ -1,4 +1,4 @@
1
- /*! markdownlint 0.26.1 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,25 +37,27 @@ 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
54
53
  const emphasisMarkersRe = /[_*]/g;
55
- // Regular expression for reference links (full and collapsed but not shortcut)
56
- const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|[^(]|$)/g;
54
+ // Regular expression for blockquote prefixes
55
+ const blockquotePrefixRe = /^[>\s]*/;
56
+ module.exports.blockquotePrefixRe = blockquotePrefixRe;
57
+ // Regular expression for reference links (full, collapsed, and shortcut)
58
+ const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*\]|[^[\]\0])*)\](?:\[([^\]\0]*)\]|([^(])|$)/g;
57
59
  // Regular expression for link reference definitions
58
- const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/;
60
+ const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
59
61
  module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
60
62
  // All punctuation characters (normal and full-width)
61
63
  const allPunctuation = ".,;:!?。,;:!?";
@@ -151,6 +153,12 @@ module.exports.includesSorted = function includesSorted(array, element) {
151
153
  // https://spec.commonmark.org/0.29/#html-comment
152
154
  const htmlCommentBegin = "<!--";
153
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);
154
162
  module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
155
163
  let i = 0;
156
164
  while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
@@ -161,24 +169,27 @@ module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
161
169
  }
162
170
  // If the comment has content...
163
171
  if (j > i + htmlCommentBegin.length) {
164
- let k = i - 1;
165
- while (text[k] === " ") {
166
- k--;
167
- }
168
- // If comment is not within an indented code block...
169
- if (k >= i - 4) {
170
- const content = text.slice(i + htmlCommentBegin.length, j);
171
- const isBlock = (k < 0) || (text[k] === "\n");
172
- const isValid = isBlock ||
173
- (!content.startsWith(">") && !content.startsWith("->") &&
174
- !content.endsWith("-") && !content.includes("--"));
175
- // If a valid block/inline comment...
176
- if (isValid) {
177
- text =
178
- text.slice(0, i + htmlCommentBegin.length) +
179
- content.replace(/[^\r\n]/g, ".") +
180
- text.slice(j);
181
- }
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);
182
193
  }
183
194
  }
184
195
  i = j + htmlCommentEnd.length;
@@ -402,17 +413,22 @@ module.exports.flattenLists = function flattenLists(tokens) {
402
413
  }
403
414
  return flattenedLists;
404
415
  };
405
- // Calls the provided function for each specified inline child token
406
- module.exports.forEachInlineChild =
407
- function forEachInlineChild(params, type, handler) {
408
- filterTokens(params, "inline", function forToken(token) {
409
- for (const child of token.children) {
410
- if (child.type === type) {
411
- handler(child, token);
412
- }
413
- }
414
- });
415
- };
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;
416
432
  // Calls the provided function for each heading's content
417
433
  module.exports.forEachHeading = function forEachHeading(params, handler) {
418
434
  let heading = null;
@@ -573,6 +589,7 @@ module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => {
573
589
  */
574
590
  module.exports.htmlElementRanges = (params, lineMetadata) => {
575
591
  const exclusions = [];
592
+ // Match with htmlElementRe
576
593
  forEachLine(lineMetadata, (line, lineIndex, inCode) => {
577
594
  let match = null;
578
595
  // eslint-disable-next-line no-unmodified-loop-condition
@@ -580,6 +597,32 @@ module.exports.htmlElementRanges = (params, lineMetadata) => {
580
597
  exclusions.push([lineIndex, match.index, match[0].length]);
581
598
  }
582
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
583
626
  return exclusions;
584
627
  };
585
628
  /**
@@ -749,13 +792,14 @@ module.exports.emphasisMarkersInContent = emphasisMarkersInContent;
749
792
  function getReferenceLinkImageData(lineMetadata) {
750
793
  // Initialize return values
751
794
  const references = new Map();
752
- const shortcuts = new Set();
795
+ const shortcuts = new Map();
753
796
  const definitions = new Map();
754
797
  const duplicateDefinitions = [];
798
+ const definitionLineIndices = [];
755
799
  // Define helper functions
756
800
  const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
757
801
  const exclusions = [];
758
- const excluded = (match) => withinAnyRange(exclusions, 0, match.index, match[0].length);
802
+ const excluded = (match) => withinAnyRange(exclusions, 0, match.index, match[0].length - (match[3] || "").length);
759
803
  // Convert input to single-line so multi-line links/images are easier
760
804
  const lineOffsets = [];
761
805
  let currentOffset = 0;
@@ -763,6 +807,7 @@ function getReferenceLinkImageData(lineMetadata) {
763
807
  forEachLine(lineMetadata, (line, lineIndex, inCode) => {
764
808
  lineOffsets[lineIndex] = currentOffset;
765
809
  if (!inCode) {
810
+ line = line.replace(blockquotePrefixRe, "");
766
811
  if (line.trim().length === 0) {
767
812
  // Allow RegExp to detect the end of a block
768
813
  line = "\0";
@@ -789,7 +834,13 @@ function getReferenceLinkImageData(lineMetadata) {
789
834
  else {
790
835
  definitions.set(label, lineIndex);
791
836
  }
792
- 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
+ }
793
844
  }
794
845
  }
795
846
  });
@@ -813,47 +864,51 @@ function getReferenceLinkImageData(lineMetadata) {
813
864
  !matchString.startsWith("!\\") &&
814
865
  !matchText.endsWith("\\") &&
815
866
  !(matchLabel || "").endsWith("\\") &&
816
- (topLevel || matchString.startsWith("!")) &&
817
- !excluded(referenceLinkMatch)) {
867
+ !(topLevel && excluded(referenceLinkMatch))) {
818
868
  const shortcutLink = (matchLabel === undefined);
819
869
  const collapsedLink = (!shortcutLink && (matchLabel.length === 0));
820
870
  const label = normalizeLabel((shortcutLink || collapsedLink) ? matchText : matchLabel);
821
871
  if (label.length > 0) {
872
+ const referenceindex = referenceLinkMatch.index;
873
+ if (topLevel) {
874
+ // Calculate line index
875
+ while (lineOffsets[lineIndex + 1] <= referenceindex) {
876
+ lineIndex++;
877
+ }
878
+ }
879
+ else {
880
+ // Use provided line index
881
+ lineIndex = contentLineIndex;
882
+ }
883
+ const referenceIndex = referenceindex +
884
+ (topLevel ? -lineOffsets[lineIndex] : contentIndex);
885
+ const referenceDatum = [
886
+ lineIndex,
887
+ referenceIndex,
888
+ matchString.length,
889
+ matchText.length,
890
+ (matchLabel || "").length
891
+ ];
822
892
  if (shortcutLink) {
823
- // Track, but don't validate due to ambiguity: "text [text] text"
824
- shortcuts.add(label);
893
+ // Track separately due to ambiguity in "text [text] text"
894
+ const shortcutData = shortcuts.get(label) || [];
895
+ shortcutData.push(referenceDatum);
896
+ shortcuts.set(label, shortcutData);
825
897
  }
826
898
  else {
827
- const referenceindex = referenceLinkMatch.index;
828
- if (topLevel) {
829
- // Calculate line index
830
- while (lineOffsets[lineIndex + 1] <= referenceindex) {
831
- lineIndex++;
832
- }
833
- }
834
- else {
835
- // Use provided line index
836
- lineIndex = contentLineIndex;
837
- }
838
- const referenceIndex = referenceindex +
839
- (topLevel ? -lineOffsets[lineIndex] : contentIndex);
840
899
  // Track reference and location
841
900
  const referenceData = references.get(label) || [];
842
- referenceData.push([
843
- lineIndex,
844
- referenceIndex,
845
- matchString.length
846
- ]);
901
+ referenceData.push(referenceDatum);
847
902
  references.set(label, referenceData);
848
- // Check for images embedded in top-level link text
849
- if (!matchString.startsWith("!")) {
850
- pendingContents.push({
851
- "content": matchText,
852
- "contentLineIndex": lineIndex,
853
- "contentIndex": referenceIndex + 1,
854
- "topLevel": false
855
- });
856
- }
903
+ }
904
+ // Check for links embedded in brackets
905
+ if (!matchString.startsWith("!")) {
906
+ pendingContents.push({
907
+ "content": matchText,
908
+ "contentLineIndex": lineIndex,
909
+ "contentIndex": referenceIndex + 1,
910
+ "topLevel": false
911
+ });
857
912
  }
858
913
  }
859
914
  }
@@ -863,7 +918,8 @@ function getReferenceLinkImageData(lineMetadata) {
863
918
  references,
864
919
  shortcuts,
865
920
  definitions,
866
- duplicateDefinitions
921
+ duplicateDefinitions,
922
+ definitionLineIndices
867
923
  };
868
924
  }
869
925
  module.exports.getReferenceLinkImageData = getReferenceLinkImageData;
@@ -950,7 +1006,7 @@ module.exports.applyFix = applyFix;
950
1006
  * @returns {string} Corrected content.
951
1007
  */
952
1008
  function applyFixes(input, errors) {
953
- const lineEnding = getPreferredLineEnding(input, __webpack_require__(/*! os */ "?591e"));
1009
+ const lineEnding = getPreferredLineEnding(input, __webpack_require__(/*! node:os */ "?0176"));
954
1010
  const lines = input.split(newLineRe);
955
1011
  // Normalize fixInfo objects
956
1012
  let fixInfos = errors
@@ -1081,6 +1137,109 @@ function expandTildePath(file, os) {
1081
1137
  return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file;
1082
1138
  }
1083
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;
1084
1243
 
1085
1244
 
1086
1245
  /***/ }),
@@ -1096,50 +1255,50 @@ module.exports = markdownit;
1096
1255
 
1097
1256
  /***/ }),
1098
1257
 
1099
- /***/ "?591e":
1100
- /*!********************!*\
1101
- !*** os (ignored) ***!
1102
- \********************/
1258
+ /***/ "?0176":
1259
+ /*!*************************!*\
1260
+ !*** node:os (ignored) ***!
1261
+ \*************************/
1103
1262
  /***/ (() => {
1104
1263
 
1105
1264
  /* (ignored) */
1106
1265
 
1107
1266
  /***/ }),
1108
1267
 
1109
- /***/ "?ec0a":
1110
- /*!********************!*\
1111
- !*** fs (ignored) ***!
1112
- \********************/
1268
+ /***/ "?d0ee":
1269
+ /*!*************************!*\
1270
+ !*** node:fs (ignored) ***!
1271
+ \*************************/
1113
1272
  /***/ (() => {
1114
1273
 
1115
1274
  /* (ignored) */
1116
1275
 
1117
1276
  /***/ }),
1118
1277
 
1119
- /***/ "?a32b":
1120
- /*!********************!*\
1121
- !*** os (ignored) ***!
1122
- \********************/
1278
+ /***/ "?e6c4":
1279
+ /*!*************************!*\
1280
+ !*** node:os (ignored) ***!
1281
+ \*************************/
1123
1282
  /***/ (() => {
1124
1283
 
1125
1284
  /* (ignored) */
1126
1285
 
1127
1286
  /***/ }),
1128
1287
 
1129
- /***/ "?b85c":
1130
- /*!**********************!*\
1131
- !*** path (ignored) ***!
1132
- \**********************/
1288
+ /***/ "?9a52":
1289
+ /*!***************************!*\
1290
+ !*** node:path (ignored) ***!
1291
+ \***************************/
1133
1292
  /***/ (() => {
1134
1293
 
1135
1294
  /* (ignored) */
1136
1295
 
1137
1296
  /***/ }),
1138
1297
 
1139
- /***/ "?96a2":
1140
- /*!**********************!*\
1141
- !*** util (ignored) ***!
1142
- \**********************/
1298
+ /***/ "?39e5":
1299
+ /*!***************************!*\
1300
+ !*** node:util (ignored) ***!
1301
+ \***************************/
1143
1302
  /***/ (() => {
1144
1303
 
1145
1304
  /* (ignored) */
@@ -1186,8 +1345,15 @@ module.exports.referenceLinkImageData =
1186
1345
  // @ts-check
1187
1346
 
1188
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
+ ];
1189
1355
  module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
1190
- module.exports.version = "0.26.1";
1356
+ module.exports.version = "0.27.0";
1191
1357
 
1192
1358
 
1193
1359
  /***/ }),
@@ -1201,8 +1367,8 @@ module.exports.version = "0.26.1";
1201
1367
  "use strict";
1202
1368
  // @ts-check
1203
1369
 
1204
- const path = __webpack_require__(/*! path */ "?b85c");
1205
- const { promisify } = __webpack_require__(/*! util */ "?96a2");
1370
+ const path = __webpack_require__(/*! node:path */ "?9a52");
1371
+ const { promisify } = __webpack_require__(/*! node:util */ "?39e5");
1206
1372
  const markdownIt = __webpack_require__(/*! markdown-it */ "markdown-it");
1207
1373
  const { deprecatedRuleNames } = __webpack_require__(/*! ./constants */ "../lib/constants.js");
1208
1374
  const rules = __webpack_require__(/*! ./rules */ "../lib/rules.js");
@@ -1419,11 +1585,6 @@ function annotateAndFreezeTokens(tokens, lines) {
1419
1585
  if (!token.map && trMap) {
1420
1586
  token.map = [...trMap];
1421
1587
  }
1422
- // Adjust maps for math blocks
1423
- if (helpers.isMathBlock(token) && token.map[1]) {
1424
- // markdown-it-texmath plugin does not account for math_block_end
1425
- token.map[1]++;
1426
- }
1427
1588
  // Update token metadata
1428
1589
  if (token.map) {
1429
1590
  token.line = lines[token.map[0]];
@@ -1993,7 +2154,7 @@ function lintInput(options, synchronous, callback) {
1993
2154
  // @ts-ignore
1994
2155
  md.use(...plugin);
1995
2156
  }
1996
- const fs = options.fs || __webpack_require__(/*! fs */ "?ec0a");
2157
+ const fs = options.fs || __webpack_require__(/*! node:fs */ "?d0ee");
1997
2158
  const results = newResults(ruleList);
1998
2159
  let done = false;
1999
2160
  let concurrency = 0;
@@ -2169,10 +2330,10 @@ function readConfig(file, parsers, fs, callback) {
2169
2330
  }
2170
2331
  }
2171
2332
  if (!fs) {
2172
- fs = __webpack_require__(/*! fs */ "?ec0a");
2333
+ fs = __webpack_require__(/*! node:fs */ "?d0ee");
2173
2334
  }
2174
2335
  // Read file
2175
- const os = __webpack_require__(/*! os */ "?a32b");
2336
+ const os = __webpack_require__(/*! node:os */ "?e6c4");
2176
2337
  file = helpers.expandTildePath(file, os);
2177
2338
  fs.readFile(file, "utf8", (err, content) => {
2178
2339
  if (err) {
@@ -2229,10 +2390,10 @@ function readConfigPromise(file, parsers, fs) {
2229
2390
  */
2230
2391
  function readConfigSync(file, parsers, fs) {
2231
2392
  if (!fs) {
2232
- fs = __webpack_require__(/*! fs */ "?ec0a");
2393
+ fs = __webpack_require__(/*! node:fs */ "?d0ee");
2233
2394
  }
2234
2395
  // Read file
2235
- const os = __webpack_require__(/*! os */ "?a32b");
2396
+ const os = __webpack_require__(/*! node:os */ "?e6c4");
2236
2397
  file = helpers.expandTildePath(file, os);
2237
2398
  const content = fs.readFileSync(file, "utf8");
2238
2399
  // Try to parse file
@@ -2744,7 +2905,7 @@ module.exports = {
2744
2905
 
2745
2906
  const { addError, forEachLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
2746
2907
  const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
2747
- const reversedLinkRe = /(^|[^\\])\(([^)]+)\)\[([^\]^][^\]]*)](?!\()/g;
2908
+ const reversedLinkRe = /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)\](?!\()/g;
2748
2909
  module.exports = {
2749
2910
  "names": ["MD011", "no-reversed-links"],
2750
2911
  "description": "Reversed link syntax",
@@ -2761,7 +2922,7 @@ module.exports = {
2761
2922
  if (!linkText.endsWith("\\") &&
2762
2923
  !linkDestination.endsWith("\\") &&
2763
2924
  !withinAnyRange(exclusions, lineIndex, index, length)) {
2764
- 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], {
2765
2926
  "editColumn": index + 1,
2766
2927
  "deleteCount": length,
2767
2928
  "insertText": `[${linkText}](${linkDestination})`
@@ -2817,13 +2978,13 @@ module.exports = {
2817
2978
  "use strict";
2818
2979
  // @ts-check
2819
2980
 
2820
- const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine, includesSorted, linkReferenceDefinitionRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
2821
- 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");
2822
2983
  const longLineRePrefix = "^.{";
2823
2984
  const longLineRePostfixRelaxed = "}.*\\s.*$";
2824
2985
  const longLineRePostfixStrict = "}.+$";
2825
- const linkOrImageOnlyLineRe = /^[es]*(lT?L|I)[ES]*$/;
2826
- const sternModeRe = /^([#>\s]*\s)?\S*$/;
2986
+ const linkOrImageOnlyLineRe = /^[es]*(?:lT?L|I)[ES]*$/;
2987
+ const sternModeRe = /^(?:[#>\s]*\s)?\S*$/;
2827
2988
  const tokenTypeMap = {
2828
2989
  "em_open": "e",
2829
2990
  "em_close": "E",
@@ -2873,6 +3034,7 @@ module.exports = {
2873
3034
  linkOnlyLineNumbers.push(token.lineNumber);
2874
3035
  }
2875
3036
  });
3037
+ const { definitionLineIndices } = referenceLinkImageData();
2876
3038
  forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => {
2877
3039
  const lineNumber = lineIndex + 1;
2878
3040
  const isHeading = includesSorted(headingLineNumbers, lineNumber);
@@ -2885,10 +3047,10 @@ module.exports = {
2885
3047
  if ((includeCodeBlocks || !inCode) &&
2886
3048
  (includeTables || !inTable) &&
2887
3049
  (includeHeadings || !isHeading) &&
3050
+ !includesSorted(definitionLineIndices, lineIndex) &&
2888
3051
  (strict ||
2889
3052
  (!(stern && sternModeRe.test(line)) &&
2890
- !includesSorted(linkOnlyLineNumbers, lineNumber) &&
2891
- !linkReferenceDefinitionRe.test(line))) &&
3053
+ !includesSorted(linkOnlyLineNumbers, lineNumber))) &&
2892
3054
  lengthRe.test(line)) {
2893
3055
  addErrorDetailIf(onError, lineNumber, length, line.length, null, null, [length + 1, line.length - length]);
2894
3056
  }
@@ -3004,7 +3166,7 @@ module.exports = {
3004
3166
  filterTokens(params, "heading_open", (token) => {
3005
3167
  if (headingStyleFor(token) === "atx") {
3006
3168
  const { line, lineNumber } = token;
3007
- const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line);
3169
+ const match = /^(#+)([ \t]{2,})\S/.exec(line);
3008
3170
  if (match) {
3009
3171
  const [, { "length": hashLength }, { "length": spacesLength }] = match;
3010
3172
  addErrorContext(onError, lineNumber, line.trim(), null, null, [1, hashLength + spacesLength + 1], {
@@ -3132,7 +3294,13 @@ module.exports = {
3132
3294
  "use strict";
3133
3295
  // @ts-check
3134
3296
 
3135
- 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));
3136
3304
  module.exports = {
3137
3305
  "names": ["MD022", "blanks-around-headings", "blanks-around-headers"],
3138
3306
  "description": "Headings should be surrounded by blank lines",
@@ -3152,7 +3320,7 @@ module.exports = {
3152
3320
  }
3153
3321
  }
3154
3322
  addErrorDetailIf(onError, topIndex + 1, linesAbove, actualAbove, "Above", lines[topIndex].trim(), null, {
3155
- "insertText": "".padEnd(linesAbove - actualAbove, "\n")
3323
+ "insertText": getBlockQuote(lines[topIndex - 1], linesAbove - actualAbove)
3156
3324
  });
3157
3325
  let actualBelow = 0;
3158
3326
  for (let i = 0; i < linesBelow; i++) {
@@ -3162,7 +3330,7 @@ module.exports = {
3162
3330
  }
3163
3331
  addErrorDetailIf(onError, topIndex + 1, linesBelow, actualBelow, "Below", lines[topIndex].trim(), null, {
3164
3332
  "lineNumber": nextIndex + 1,
3165
- "insertText": "".padEnd(linesBelow - actualBelow, "\n")
3333
+ "insertText": getBlockQuote(lines[nextIndex], linesBelow - actualBelow)
3166
3334
  });
3167
3335
  });
3168
3336
  }
@@ -3181,7 +3349,7 @@ module.exports = {
3181
3349
  // @ts-check
3182
3350
 
3183
3351
  const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3184
- const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/;
3352
+ const spaceBeforeHeadingRe = /^(\s+|[>\s]+\s\s)[^>\s]/;
3185
3353
  module.exports = {
3186
3354
  "names": ["MD023", "heading-start-left", "header-start-left"],
3187
3355
  "description": "Headings must start at the beginning of the line",
@@ -3300,7 +3468,7 @@ module.exports = {
3300
3468
  // @ts-check
3301
3469
 
3302
3470
  const { addError, allPunctuationNoQuestion, escapeForRegExp, forEachHeading } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3303
- const endOfLineHtmlEntityRe = /&#?[0-9a-zA-Z]+;$/;
3471
+ const endOfLineHtmlEntityRe = /&#?[\da-zA-Z]+;$/;
3304
3472
  module.exports = {
3305
3473
  "names": ["MD026", "no-trailing-punctuation"],
3306
3474
  "description": "Trailing punctuation in heading",
@@ -3588,9 +3756,8 @@ module.exports = {
3588
3756
  "use strict";
3589
3757
  // @ts-check
3590
3758
 
3591
- const { addErrorContext, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3759
+ const { addErrorContext, blockquotePrefixRe, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3592
3760
  const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3593
- const quotePrefixRe = /^[>\s]*/;
3594
3761
  module.exports = {
3595
3762
  "names": ["MD032", "blanks-around-lists"],
3596
3763
  "description": "Lists should be surrounded by blank lines",
@@ -3602,7 +3769,7 @@ module.exports = {
3602
3769
  const firstIndex = list.open.map[0];
3603
3770
  if (!isBlankLine(lines[firstIndex - 1])) {
3604
3771
  const line = lines[firstIndex];
3605
- const quotePrefix = line.match(quotePrefixRe)[0].trimEnd();
3772
+ const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
3606
3773
  addErrorContext(onError, firstIndex + 1, line.trim(), null, null, null, {
3607
3774
  "insertText": `${quotePrefix}\n`
3608
3775
  });
@@ -3610,7 +3777,7 @@ module.exports = {
3610
3777
  const lastIndex = list.lastLineIndex - 1;
3611
3778
  if (!isBlankLine(lines[lastIndex + 1])) {
3612
3779
  const line = lines[lastIndex];
3613
- const quotePrefix = line.match(quotePrefixRe)[0].trimEnd();
3780
+ const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
3614
3781
  addErrorContext(onError, lastIndex + 1, line.trim(), null, null, null, {
3615
3782
  "lineNumber": lastIndex + 2,
3616
3783
  "insertText": `${quotePrefix}\n`
@@ -3633,12 +3800,12 @@ module.exports = {
3633
3800
  // @ts-check
3634
3801
 
3635
3802
  const { addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3636
- const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3637
- const linkDestinationRe = /]\(\s*$/;
3803
+ const { codeBlockAndSpanRanges, lineMetadata, referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3804
+ const linkDestinationRe = /\]\(\s*$/;
3638
3805
  // See https://spec.commonmark.org/0.29/#autolinks
3639
3806
  const emailAddressRe =
3640
3807
  // eslint-disable-next-line max-len
3641
- /^[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])?)*$/;
3642
3809
  module.exports = {
3643
3810
  "names": ["MD033", "no-inline-html"],
3644
3811
  "description": "Inline HTML",
@@ -3648,6 +3815,15 @@ module.exports = {
3648
3815
  allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
3649
3816
  allowedElements = allowedElements.map((element) => element.toLowerCase());
3650
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
+ }
3651
3827
  forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
3652
3828
  let match = null;
3653
3829
  // eslint-disable-next-line no-unmodified-loop-condition
@@ -3656,12 +3832,13 @@ module.exports = {
3656
3832
  if (!allowedElements.includes(element.toLowerCase()) &&
3657
3833
  !tag.endsWith("\\>") &&
3658
3834
  !emailAddressRe.test(content) &&
3659
- !withinAnyRange(exclusions, lineIndex, match.index, match[0].length)) {
3835
+ !withinAnyRange(exclusions, lineIndex, match.index, tag.length) &&
3836
+ !definitionLineIndices.includes(lineIndex)) {
3660
3837
  const prefix = line.substring(0, match.index);
3661
3838
  if (!linkDestinationRe.test(prefix)) {
3662
3839
  const unescaped = unescapeMarkdown(prefix + "<", "_");
3663
3840
  if (!unescaped.endsWith("_")) {
3664
- addError(onError, lineIndex + 1, "Element: " + element, null, [match.index + 1, tag.length]);
3841
+ addError(onError, lineIndex + 1, "Element: " + element, undefined, [match.index + 1, tag.length]);
3665
3842
  }
3666
3843
  }
3667
3844
  }
@@ -3682,52 +3859,70 @@ module.exports = {
3682
3859
  "use strict";
3683
3860
  // @ts-check
3684
3861
 
3685
- 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;
3686
3865
  module.exports = {
3687
3866
  "names": ["MD034", "no-bare-urls"],
3688
3867
  "description": "Bare URL used",
3689
3868
  "tags": ["links", "url"],
3690
3869
  "function": function MD034(params, onError) {
3691
- filterTokens(params, "inline", (token) => {
3692
- let inLink = false;
3693
- for (const child of token.children) {
3694
- 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 {
3695
3886
  let match = null;
3696
- if (type === "link_open") {
3697
- inLink = true;
3698
- }
3699
- else if (type === "link_close") {
3700
- inLink = false;
3887
+ const lineExclusions = [];
3888
+ while ((match = htmlLinkRe.exec(line)) !== null) {
3889
+ lineExclusions.push([lineIndex, match.index, match[0].length]);
3701
3890
  }
3702
- else if ((type === "text") && !inLink) {
3703
- while ((match = bareUrlRe.exec(content)) !== null) {
3704
- const [bareUrl] = match;
3705
- const matchIndex = match.index;
3706
- const bareUrlLength = bareUrl.length;
3707
- // Allow "[https://example.com]" to avoid conflicts with
3708
- // MD011/no-reversed-links; allow quoting as another way
3709
- // of deliberately including a bare URL
3710
- const leftChar = content[matchIndex - 1];
3711
- const rightChar = content[matchIndex + bareUrlLength];
3712
- if (!((leftChar === "[") && (rightChar === "]")) &&
3713
- !((leftChar === "\"") && (rightChar === "\"")) &&
3714
- !((leftChar === "'") && (rightChar === "'"))) {
3715
- const index = line.indexOf(content);
3716
- const range = (index === -1) ? null : [
3717
- index + matchIndex + 1,
3718
- bareUrlLength
3719
- ];
3720
- const fixInfo = range ? {
3721
- "editColumn": range[0],
3722
- "deleteCount": range[1],
3723
- "insertText": `<${bareUrl}>`
3724
- } : null;
3725
- addErrorContext(onError, lineNumber, bareUrl, null, null, range, fixInfo);
3726
- }
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);
3727
3922
  }
3728
3923
  }
3729
3924
  }
3730
- });
3925
+ }
3731
3926
  }
3732
3927
  };
3733
3928
 
@@ -3753,7 +3948,7 @@ module.exports = {
3753
3948
  filterTokens(params, "hr", (token) => {
3754
3949
  const { line, lineNumber } = token;
3755
3950
  let { markup } = token;
3756
- const match = line.match(/[_*\-\s\t]+$/);
3951
+ const match = line.match(/[_*\-\s]+$/);
3757
3952
  if (match) {
3758
3953
  markup = match[0].trim();
3759
3954
  }
@@ -3842,10 +4037,10 @@ module.exports = {
3842
4037
  "use strict";
3843
4038
  // @ts-check
3844
4039
 
3845
- const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3846
- const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3847
- const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
3848
- const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
4040
+ const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4041
+ const { htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
4042
+ const emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g;
4043
+ const embeddedUnderscoreRe = /([A-Za-z\d])_([A-Za-z\d])/g;
3849
4044
  const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
3850
4045
  const leftSpaceRe = /^\s+/;
3851
4046
  const rightSpaceRe = /\s+$/;
@@ -3855,6 +4050,7 @@ module.exports = {
3855
4050
  "description": "Spaces inside emphasis markers",
3856
4051
  "tags": ["whitespace", "emphasis"],
3857
4052
  "function": function MD037(params, onError) {
4053
+ const exclusions = htmlElementRanges();
3858
4054
  // eslint-disable-next-line init-declarations
3859
4055
  let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength, pendingError = null;
3860
4056
  // eslint-disable-next-line jsdoc/require-jsdoc
@@ -3882,25 +4078,27 @@ module.exports = {
3882
4078
  // Report the violation
3883
4079
  const contextStart = emphasisIndex - emphasisLength;
3884
4080
  const contextEnd = matchIndex + contextLength;
3885
- const context = line.substring(contextStart, contextEnd);
3886
4081
  const column = contextStart + 1;
3887
4082
  const length = contextEnd - contextStart;
3888
- const leftMarker = line.substring(contextStart, emphasisIndex);
3889
- const rightMarker = match ? (match[2] || match[3]) : "";
3890
- const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
3891
- return [
3892
- onError,
3893
- lineIndex + 1,
3894
- context,
3895
- leftSpace,
3896
- rightSpace,
3897
- [column, length],
3898
- {
3899
- "editColumn": column,
3900
- "deleteCount": length,
3901
- "insertText": fixedText
3902
- }
3903
- ];
4083
+ if (!withinAnyRange(exclusions, lineIndex, column, length)) {
4084
+ const context = line.substring(contextStart, contextEnd);
4085
+ const leftMarker = line.substring(contextStart, emphasisIndex);
4086
+ const rightMarker = match ? (match[2] || match[3]) : "";
4087
+ const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
4088
+ return [
4089
+ onError,
4090
+ lineIndex + 1,
4091
+ context,
4092
+ leftSpace,
4093
+ rightSpace,
4094
+ [column, length],
4095
+ {
4096
+ "editColumn": column,
4097
+ "deleteCount": length,
4098
+ "insertText": fixedText
4099
+ }
4100
+ ];
4101
+ }
3904
4102
  }
3905
4103
  return null;
3906
4104
  }
@@ -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,9 +4810,10 @@ 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
- const identifierRe = /(?:id|name)\s*=\s*['"]?([^'"\s>]+)/iu;
4815
+ const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
4816
+ const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
4605
4817
  /**
4606
4818
  * Converts a Markdown heading into an HTML fragment according to the rules
4607
4819
  * used by GitHub.
@@ -4643,11 +4855,10 @@ module.exports = {
4643
4855
  let match = null;
4644
4856
  while ((match = htmlElementRe.exec(token.content)) !== null) {
4645
4857
  const [tag, , element] = match;
4646
- if (element.toLowerCase() === "a") {
4647
- const idMatch = identifierRe.exec(tag);
4648
- if (idMatch) {
4649
- fragments.set(`#${idMatch[1]}`, 0);
4650
- }
4858
+ const anchorMatch = idRe.exec(tag) ||
4859
+ (element.toLowerCase() === "a" && nameRe.exec(tag));
4860
+ if (anchorMatch) {
4861
+ fragments.set(`#${anchorMatch[1]}`, 0);
4651
4862
  }
4652
4863
  }
4653
4864
  };
@@ -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
  }
@@ -4727,7 +4957,8 @@ module.exports = {
4727
4957
  "description": "Link and image reference definitions should be needed",
4728
4958
  "tags": ["images", "links"],
4729
4959
  "function": function MD053(params, onError) {
4730
- const { lines } = params;
4960
+ const ignored = new Set(params.config.ignored_definitions || ["//"]);
4961
+ const lines = params.lines;
4731
4962
  const { references, shortcuts, definitions, duplicateDefinitions } = referenceLinkImageData();
4732
4963
  const singleLineDefinition = (line) => (line.replace(linkReferenceDefinitionRe, "").trim().length > 0);
4733
4964
  const deleteFixInfo = {
@@ -4736,7 +4967,9 @@ module.exports = {
4736
4967
  // Look for unused link references (unreferenced by any link/image)
4737
4968
  for (const definition of definitions.entries()) {
4738
4969
  const [label, lineIndex] = definition;
4739
- if (!references.has(label) && !shortcuts.has(label)) {
4970
+ if (!ignored.has(label) &&
4971
+ !references.has(label) &&
4972
+ !shortcuts.has(label)) {
4740
4973
  const line = lines[lineIndex];
4741
4974
  addError(onError, lineIndex + 1, `Unused link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
4742
4975
  }
@@ -4744,8 +4977,10 @@ module.exports = {
4744
4977
  // Look for duplicate link references (defined more than once)
4745
4978
  for (const duplicateDefinition of duplicateDefinitions) {
4746
4979
  const [label, lineIndex] = duplicateDefinition;
4747
- const line = lines[lineIndex];
4748
- addError(onError, lineIndex + 1, `Duplicate link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
4980
+ if (!ignored.has(label)) {
4981
+ const line = lines[lineIndex];
4982
+ addError(onError, lineIndex + 1, `Duplicate link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
4983
+ }
4749
4984
  }
4750
4985
  }
4751
4986
  };
@@ -4817,7 +5052,7 @@ for (const rule of rules) {
4817
5052
  const name = rule.names[0].toLowerCase();
4818
5053
  // eslint-disable-next-line dot-notation
4819
5054
  rule["information"] =
4820
- new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
5055
+ new URL(`${homepage}/blob/v${version}/doc/${name}.md`);
4821
5056
  }
4822
5057
  module.exports = rules;
4823
5058