markdownlint 0.26.1 → 0.26.2

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.
package/README.md CHANGED
@@ -48,6 +48,7 @@ and test cases came directly from that project.
48
48
  * [eslint-plugin-markdownlint for the ESLint analyzer](https://github.com/paweldrozd/eslint-plugin-markdownlint)
49
49
  * [grunt-markdownlint for the Grunt task runner](https://github.com/sagiegurari/grunt-markdownlint)
50
50
  * [Cake.Markdownlint addin for Cake build automation system](https://github.com/cake-contrib/Cake.Markdownlint)
51
+ * [Lombiq Node.js Extensions for MSBuild (.NET builds)](https://github.com/Lombiq/NodeJs-Extensions)
51
52
  * Ruby
52
53
  * [markdownlint/mdl gem for Ruby](https://rubygems.org/gems/mdl)
53
54
 
@@ -1020,6 +1021,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
1020
1021
  browser script to use ES2015, simplify JSON schema, address remaining CodeQL issues,
1021
1022
  improve performance, update dependencies.
1022
1023
  * 0.26.1 - Improve MD051.
1024
+ * 0.26.2 - Improve MD037/MD051/MD053.
1023
1025
 
1024
1026
  [npm-image]: https://img.shields.io/npm/v/markdownlint.svg
1025
1027
  [npm-url]: https://www.npmjs.com/package/markdownlint
@@ -1,4 +1,4 @@
1
- /*! markdownlint 0.26.1 https://github.com/DavidAnson/markdownlint @license MIT */
1
+ /*! markdownlint 0.26.2 https://github.com/DavidAnson/markdownlint @license MIT */
2
2
  var markdownlint;
3
3
  /******/ (() => { // webpackBootstrap
4
4
  /******/ var __webpack_modules__ = ({
@@ -52,8 +52,11 @@ module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
52
52
  module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
53
53
  // Regular expression for all instances of emphasis markers
54
54
  const emphasisMarkersRe = /[_*]/g;
55
- // Regular expression for reference links (full and collapsed but not shortcut)
56
- const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|[^(]|$)/g;
55
+ // Regular expression for blockquote prefixes
56
+ const blockquotePrefixRe = /^[>\s]*/;
57
+ module.exports.blockquotePrefixRe = blockquotePrefixRe;
58
+ // Regular expression for reference links (full, collapsed, and shortcut)
59
+ const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g;
57
60
  // Regular expression for link reference definitions
58
61
  const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/;
59
62
  module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
@@ -755,7 +758,7 @@ function getReferenceLinkImageData(lineMetadata) {
755
758
  // Define helper functions
756
759
  const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
757
760
  const exclusions = [];
758
- const excluded = (match) => withinAnyRange(exclusions, 0, match.index, match[0].length);
761
+ const excluded = (match) => withinAnyRange(exclusions, 0, match.index, match[0].length - (match[3] || "").length);
759
762
  // Convert input to single-line so multi-line links/images are easier
760
763
  const lineOffsets = [];
761
764
  let currentOffset = 0;
@@ -763,6 +766,7 @@ function getReferenceLinkImageData(lineMetadata) {
763
766
  forEachLine(lineMetadata, (line, lineIndex, inCode) => {
764
767
  lineOffsets[lineIndex] = currentOffset;
765
768
  if (!inCode) {
769
+ line = line.replace(blockquotePrefixRe, "");
766
770
  if (line.trim().length === 0) {
767
771
  // Allow RegExp to detect the end of a block
768
772
  line = "\0";
@@ -813,30 +817,29 @@ function getReferenceLinkImageData(lineMetadata) {
813
817
  !matchString.startsWith("!\\") &&
814
818
  !matchText.endsWith("\\") &&
815
819
  !(matchLabel || "").endsWith("\\") &&
816
- (topLevel || matchString.startsWith("!")) &&
817
- !excluded(referenceLinkMatch)) {
820
+ !(topLevel && excluded(referenceLinkMatch))) {
818
821
  const shortcutLink = (matchLabel === undefined);
819
822
  const collapsedLink = (!shortcutLink && (matchLabel.length === 0));
820
823
  const label = normalizeLabel((shortcutLink || collapsedLink) ? matchText : matchLabel);
821
824
  if (label.length > 0) {
825
+ const referenceindex = referenceLinkMatch.index;
826
+ if (topLevel) {
827
+ // Calculate line index
828
+ while (lineOffsets[lineIndex + 1] <= referenceindex) {
829
+ lineIndex++;
830
+ }
831
+ }
832
+ else {
833
+ // Use provided line index
834
+ lineIndex = contentLineIndex;
835
+ }
836
+ const referenceIndex = referenceindex +
837
+ (topLevel ? -lineOffsets[lineIndex] : contentIndex);
822
838
  if (shortcutLink) {
823
- // Track, but don't validate due to ambiguity: "text [text] text"
839
+ // Track separately due to ambiguity in "text [text] text"
824
840
  shortcuts.add(label);
825
841
  }
826
842
  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
843
  // Track reference and location
841
844
  const referenceData = references.get(label) || [];
842
845
  referenceData.push([
@@ -845,15 +848,15 @@ function getReferenceLinkImageData(lineMetadata) {
845
848
  matchString.length
846
849
  ]);
847
850
  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
- }
851
+ }
852
+ // Check for links embedded in brackets
853
+ if (!matchString.startsWith("!")) {
854
+ pendingContents.push({
855
+ "content": matchText,
856
+ "contentLineIndex": lineIndex,
857
+ "contentIndex": referenceIndex + 1,
858
+ "topLevel": false
859
+ });
857
860
  }
858
861
  }
859
862
  }
@@ -1187,7 +1190,7 @@ module.exports.referenceLinkImageData =
1187
1190
 
1188
1191
  module.exports.deprecatedRuleNames = ["MD002", "MD006"];
1189
1192
  module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
1190
- module.exports.version = "0.26.1";
1193
+ module.exports.version = "0.26.2";
1191
1194
 
1192
1195
 
1193
1196
  /***/ }),
@@ -1419,11 +1422,6 @@ function annotateAndFreezeTokens(tokens, lines) {
1419
1422
  if (!token.map && trMap) {
1420
1423
  token.map = [...trMap];
1421
1424
  }
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
1425
  // Update token metadata
1428
1426
  if (token.map) {
1429
1427
  token.line = lines[token.map[0]];
@@ -3588,9 +3586,8 @@ module.exports = {
3588
3586
  "use strict";
3589
3587
  // @ts-check
3590
3588
 
3591
- const { addErrorContext, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3589
+ const { addErrorContext, blockquotePrefixRe, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3592
3590
  const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3593
- const quotePrefixRe = /^[>\s]*/;
3594
3591
  module.exports = {
3595
3592
  "names": ["MD032", "blanks-around-lists"],
3596
3593
  "description": "Lists should be surrounded by blank lines",
@@ -3602,7 +3599,7 @@ module.exports = {
3602
3599
  const firstIndex = list.open.map[0];
3603
3600
  if (!isBlankLine(lines[firstIndex - 1])) {
3604
3601
  const line = lines[firstIndex];
3605
- const quotePrefix = line.match(quotePrefixRe)[0].trimEnd();
3602
+ const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
3606
3603
  addErrorContext(onError, firstIndex + 1, line.trim(), null, null, null, {
3607
3604
  "insertText": `${quotePrefix}\n`
3608
3605
  });
@@ -3610,7 +3607,7 @@ module.exports = {
3610
3607
  const lastIndex = list.lastLineIndex - 1;
3611
3608
  if (!isBlankLine(lines[lastIndex + 1])) {
3612
3609
  const line = lines[lastIndex];
3613
- const quotePrefix = line.match(quotePrefixRe)[0].trimEnd();
3610
+ const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
3614
3611
  addErrorContext(onError, lastIndex + 1, line.trim(), null, null, null, {
3615
3612
  "lineNumber": lastIndex + 2,
3616
3613
  "insertText": `${quotePrefix}\n`
@@ -3661,7 +3658,7 @@ module.exports = {
3661
3658
  if (!linkDestinationRe.test(prefix)) {
3662
3659
  const unescaped = unescapeMarkdown(prefix + "<", "_");
3663
3660
  if (!unescaped.endsWith("_")) {
3664
- addError(onError, lineIndex + 1, "Element: " + element, null, [match.index + 1, tag.length]);
3661
+ addError(onError, lineIndex + 1, "Element: " + element, undefined, [match.index + 1, tag.length]);
3665
3662
  }
3666
3663
  }
3667
3664
  }
@@ -3842,8 +3839,8 @@ module.exports = {
3842
3839
  "use strict";
3843
3840
  // @ts-check
3844
3841
 
3845
- const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3846
- const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3842
+ const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
3843
+ const { htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
3847
3844
  const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
3848
3845
  const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
3849
3846
  const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
@@ -3855,6 +3852,7 @@ module.exports = {
3855
3852
  "description": "Spaces inside emphasis markers",
3856
3853
  "tags": ["whitespace", "emphasis"],
3857
3854
  "function": function MD037(params, onError) {
3855
+ const exclusions = htmlElementRanges();
3858
3856
  // eslint-disable-next-line init-declarations
3859
3857
  let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength, pendingError = null;
3860
3858
  // eslint-disable-next-line jsdoc/require-jsdoc
@@ -3882,25 +3880,27 @@ module.exports = {
3882
3880
  // Report the violation
3883
3881
  const contextStart = emphasisIndex - emphasisLength;
3884
3882
  const contextEnd = matchIndex + contextLength;
3885
- const context = line.substring(contextStart, contextEnd);
3886
3883
  const column = contextStart + 1;
3887
3884
  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
- ];
3885
+ if (!withinAnyRange(exclusions, lineIndex, column, length)) {
3886
+ const context = line.substring(contextStart, contextEnd);
3887
+ const leftMarker = line.substring(contextStart, emphasisIndex);
3888
+ const rightMarker = match ? (match[2] || match[3]) : "";
3889
+ const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
3890
+ return [
3891
+ onError,
3892
+ lineIndex + 1,
3893
+ context,
3894
+ leftSpace,
3895
+ rightSpace,
3896
+ [column, length],
3897
+ {
3898
+ "editColumn": column,
3899
+ "deleteCount": length,
3900
+ "insertText": fixedText
3901
+ }
3902
+ ];
3903
+ }
3904
3904
  }
3905
3905
  return null;
3906
3906
  }
@@ -4601,7 +4601,8 @@ module.exports = [
4601
4601
 
4602
4602
  const { addError, escapeForRegExp, filterTokens, forEachInlineChild, forEachHeading, htmlElementRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
4603
4603
  // Regular expression for identifying HTML anchor names
4604
- const identifierRe = /(?:id|name)\s*=\s*['"]?([^'"\s>]+)/iu;
4604
+ const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
4605
+ const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
4605
4606
  /**
4606
4607
  * Converts a Markdown heading into an HTML fragment according to the rules
4607
4608
  * used by GitHub.
@@ -4643,11 +4644,10 @@ module.exports = {
4643
4644
  let match = null;
4644
4645
  while ((match = htmlElementRe.exec(token.content)) !== null) {
4645
4646
  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
- }
4647
+ const anchorMatch = idRe.exec(tag) ||
4648
+ (element.toLowerCase() === "a" && nameRe.exec(tag));
4649
+ if (anchorMatch) {
4650
+ fragments.set(`#${anchorMatch[1]}`, 0);
4651
4651
  }
4652
4652
  }
4653
4653
  };
@@ -4727,7 +4727,8 @@ module.exports = {
4727
4727
  "description": "Link and image reference definitions should be needed",
4728
4728
  "tags": ["images", "links"],
4729
4729
  "function": function MD053(params, onError) {
4730
- const { lines } = params;
4730
+ const ignored = new Set(params.config.ignored_definitions || ["//"]);
4731
+ const lines = params.lines;
4731
4732
  const { references, shortcuts, definitions, duplicateDefinitions } = referenceLinkImageData();
4732
4733
  const singleLineDefinition = (line) => (line.replace(linkReferenceDefinitionRe, "").trim().length > 0);
4733
4734
  const deleteFixInfo = {
@@ -4736,7 +4737,9 @@ module.exports = {
4736
4737
  // Look for unused link references (unreferenced by any link/image)
4737
4738
  for (const definition of definitions.entries()) {
4738
4739
  const [label, lineIndex] = definition;
4739
- if (!references.has(label) && !shortcuts.has(label)) {
4740
+ if (!ignored.has(label) &&
4741
+ !references.has(label) &&
4742
+ !shortcuts.has(label)) {
4740
4743
  const line = lines[lineIndex];
4741
4744
  addError(onError, lineIndex + 1, `Unused link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
4742
4745
  }
@@ -4744,8 +4747,10 @@ module.exports = {
4744
4747
  // Look for duplicate link references (defined more than once)
4745
4748
  for (const duplicateDefinition of duplicateDefinitions) {
4746
4749
  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);
4750
+ if (!ignored.has(label)) {
4751
+ const line = lines[lineIndex];
4752
+ addError(onError, lineIndex + 1, `Duplicate link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
4753
+ }
4749
4754
  }
4750
4755
  }
4751
4756
  };
package/doc/Rules.md CHANGED
@@ -1315,7 +1315,7 @@ To fix this, use 'pure' Markdown instead of including raw HTML:
1315
1315
  # Markdown heading
1316
1316
  ```
1317
1317
 
1318
- Note: To allow specific HTML elements, use the 'allowed_elements' parameter.
1318
+ Note: To allow specific HTML elements, use the `allowed_elements` parameter.
1319
1319
 
1320
1320
  Rationale: Raw HTML is allowed in Markdown, but this rule is included for
1321
1321
  those who want their documents to only include "pure" Markdown, or for those
@@ -2075,6 +2075,8 @@ Tags: images, links
2075
2075
 
2076
2076
  Aliases: link-image-reference-definitions
2077
2077
 
2078
+ Parameters: ignored_definitions (array of string; default [ "//" ])
2079
+
2078
2080
  Fixable: Most violations can be fixed by tooling
2079
2081
 
2080
2082
  Links and images in Markdown can provide the link destination or image source
@@ -2092,9 +2094,18 @@ unnecessary:
2092
2094
  used and the others can be deleted.
2093
2095
 
2094
2096
  This rule considers a reference definition to be used if any link or image
2095
- reference has the corresponding label. "Full", "collapsed", and "shortcut"
2097
+ reference has the corresponding label. The "full", "collapsed", and "shortcut"
2096
2098
  formats are all supported.
2097
2099
 
2100
+ If there are reference definitions that are deliberately unreferenced, they can
2101
+ be ignored by setting the `ignored_definitions` parameter. The default value of
2102
+ this parameter ignores the following convention for adding non-HTML comments to
2103
+ Markdown:
2104
+
2105
+ ```md
2106
+ [//]: # (This behaves like a comment)
2107
+ ```
2108
+
2098
2109
  <!-- markdownlint-configure-file {
2099
2110
  "no-inline-html": {
2100
2111
  "allowed_elements": [
@@ -30,9 +30,13 @@ module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
30
30
  // Regular expression for all instances of emphasis markers
31
31
  const emphasisMarkersRe = /[_*]/g;
32
32
 
33
- // Regular expression for reference links (full and collapsed but not shortcut)
33
+ // Regular expression for blockquote prefixes
34
+ const blockquotePrefixRe = /^[>\s]*/;
35
+ module.exports.blockquotePrefixRe = blockquotePrefixRe;
36
+
37
+ // Regular expression for reference links (full, collapsed, and shortcut)
34
38
  const referenceLinkRe =
35
- /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|[^(]|$)/g;
39
+ /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g;
36
40
 
37
41
  // Regular expression for link reference definitions
38
42
  const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/;
@@ -785,7 +789,7 @@ function getReferenceLinkImageData(lineMetadata) {
785
789
  const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
786
790
  const exclusions = [];
787
791
  const excluded = (match) => withinAnyRange(
788
- exclusions, 0, match.index, match[0].length
792
+ exclusions, 0, match.index, match[0].length - (match[3] || "").length
789
793
  );
790
794
  // Convert input to single-line so multi-line links/images are easier
791
795
  const lineOffsets = [];
@@ -794,6 +798,7 @@ function getReferenceLinkImageData(lineMetadata) {
794
798
  forEachLine(lineMetadata, (line, lineIndex, inCode) => {
795
799
  lineOffsets[lineIndex] = currentOffset;
796
800
  if (!inCode) {
801
+ line = line.replace(blockquotePrefixRe, "");
797
802
  if (line.trim().length === 0) {
798
803
  // Allow RegExp to detect the end of a block
799
804
  line = "\0";
@@ -845,8 +850,7 @@ function getReferenceLinkImageData(lineMetadata) {
845
850
  !matchString.startsWith("!\\") &&
846
851
  !matchText.endsWith("\\") &&
847
852
  !(matchLabel || "").endsWith("\\") &&
848
- (topLevel || matchString.startsWith("!")) &&
849
- !excluded(referenceLinkMatch)
853
+ !(topLevel && excluded(referenceLinkMatch))
850
854
  ) {
851
855
  const shortcutLink = (matchLabel === undefined);
852
856
  const collapsedLink =
@@ -855,22 +859,22 @@ function getReferenceLinkImageData(lineMetadata) {
855
859
  (shortcutLink || collapsedLink) ? matchText : matchLabel
856
860
  );
857
861
  if (label.length > 0) {
862
+ const referenceindex = referenceLinkMatch.index;
863
+ if (topLevel) {
864
+ // Calculate line index
865
+ while (lineOffsets[lineIndex + 1] <= referenceindex) {
866
+ lineIndex++;
867
+ }
868
+ } else {
869
+ // Use provided line index
870
+ lineIndex = contentLineIndex;
871
+ }
872
+ const referenceIndex = referenceindex +
873
+ (topLevel ? -lineOffsets[lineIndex] : contentIndex);
858
874
  if (shortcutLink) {
859
- // Track, but don't validate due to ambiguity: "text [text] text"
875
+ // Track separately due to ambiguity in "text [text] text"
860
876
  shortcuts.add(label);
861
877
  } else {
862
- const referenceindex = referenceLinkMatch.index;
863
- if (topLevel) {
864
- // Calculate line index
865
- while (lineOffsets[lineIndex + 1] <= referenceindex) {
866
- lineIndex++;
867
- }
868
- } else {
869
- // Use provided line index
870
- lineIndex = contentLineIndex;
871
- }
872
- const referenceIndex = referenceindex +
873
- (topLevel ? -lineOffsets[lineIndex] : contentIndex);
874
878
  // Track reference and location
875
879
  const referenceData = references.get(label) || [];
876
880
  referenceData.push([
@@ -879,17 +883,15 @@ function getReferenceLinkImageData(lineMetadata) {
879
883
  matchString.length
880
884
  ]);
881
885
  references.set(label, referenceData);
882
- // Check for images embedded in top-level link text
883
- if (!matchString.startsWith("!")) {
884
- pendingContents.push(
885
- {
886
- "content": matchText,
887
- "contentLineIndex": lineIndex,
888
- "contentIndex": referenceIndex + 1,
889
- "topLevel": false
890
- }
891
- );
892
- }
886
+ }
887
+ // Check for links embedded in brackets
888
+ if (!matchString.startsWith("!")) {
889
+ pendingContents.push({
890
+ "content": matchText,
891
+ "contentLineIndex": lineIndex,
892
+ "contentIndex": referenceIndex + 1,
893
+ "topLevel": false
894
+ });
893
895
  }
894
896
  }
895
897
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint-rule-helpers",
3
- "version": "0.17.1",
3
+ "version": "0.17.2",
4
4
  "description": "A collection of markdownlint helper functions for custom rules",
5
5
  "main": "./helpers.js",
6
6
  "exports": "./helpers.js",
package/lib/constants.js CHANGED
@@ -4,4 +4,4 @@
4
4
 
5
5
  module.exports.deprecatedRuleNames = [ "MD002", "MD006" ];
6
6
  module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
7
- module.exports.version = "0.26.1";
7
+ module.exports.version = "0.26.2";
@@ -233,11 +233,6 @@ function annotateAndFreezeTokens(tokens, lines) {
233
233
  if (!token.map && trMap) {
234
234
  token.map = [ ...trMap ];
235
235
  }
236
- // Adjust maps for math blocks
237
- if (helpers.isMathBlock(token) && token.map[1]) {
238
- // markdown-it-texmath plugin does not account for math_block_end
239
- token.map[1]++;
240
- }
241
236
  // Update token metadata
242
237
  if (token.map) {
243
238
  token.line = lines[token.map[0]];
package/lib/md032.js CHANGED
@@ -2,11 +2,10 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, isBlankLine } = require("../helpers");
5
+ const { addErrorContext, blockquotePrefixRe, isBlankLine } =
6
+ require("../helpers");
6
7
  const { flattenedLists } = require("./cache");
7
8
 
8
- const quotePrefixRe = /^[>\s]*/;
9
-
10
9
  module.exports = {
11
10
  "names": [ "MD032", "blanks-around-lists" ],
12
11
  "description": "Lists should be surrounded by blank lines",
@@ -18,7 +17,7 @@ module.exports = {
18
17
  const firstIndex = list.open.map[0];
19
18
  if (!isBlankLine(lines[firstIndex - 1])) {
20
19
  const line = lines[firstIndex];
21
- const quotePrefix = line.match(quotePrefixRe)[0].trimEnd();
20
+ const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
22
21
  addErrorContext(
23
22
  onError,
24
23
  firstIndex + 1,
@@ -33,7 +32,7 @@ module.exports = {
33
32
  const lastIndex = list.lastLineIndex - 1;
34
33
  if (!isBlankLine(lines[lastIndex + 1])) {
35
34
  const line = lines[lastIndex];
36
- const quotePrefix = line.match(quotePrefixRe)[0].trimEnd();
35
+ const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
37
36
  addErrorContext(
38
37
  onError,
39
38
  lastIndex + 1,
package/lib/md033.js CHANGED
@@ -38,7 +38,7 @@ module.exports = {
38
38
  const unescaped = unescapeMarkdown(prefix + "<", "_");
39
39
  if (!unescaped.endsWith("_")) {
40
40
  addError(onError, lineIndex + 1, "Element: " + element,
41
- null, [ match.index + 1, tag.length ]);
41
+ undefined, [ match.index + 1, tag.length ]);
42
42
  }
43
43
  }
44
44
  }
package/lib/md037.js CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine } =
6
- require("../helpers");
7
- const { lineMetadata } = require("./cache");
5
+ const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine,
6
+ withinAnyRange } = require("../helpers");
7
+ const { htmlElementRanges, lineMetadata } = require("./cache");
8
8
 
9
9
  const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
10
10
  const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
@@ -18,6 +18,7 @@ module.exports = {
18
18
  "description": "Spaces inside emphasis markers",
19
19
  "tags": [ "whitespace", "emphasis" ],
20
20
  "function": function MD037(params, onError) {
21
+ const exclusions = htmlElementRanges();
21
22
  // eslint-disable-next-line init-declarations
22
23
  let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength,
23
24
  pendingError = null;
@@ -50,25 +51,27 @@ module.exports = {
50
51
  // Report the violation
51
52
  const contextStart = emphasisIndex - emphasisLength;
52
53
  const contextEnd = matchIndex + contextLength;
53
- const context = line.substring(contextStart, contextEnd);
54
54
  const column = contextStart + 1;
55
55
  const length = contextEnd - contextStart;
56
- const leftMarker = line.substring(contextStart, emphasisIndex);
57
- const rightMarker = match ? (match[2] || match[3]) : "";
58
- const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
59
- return [
60
- onError,
61
- lineIndex + 1,
62
- context,
63
- leftSpace,
64
- rightSpace,
65
- [ column, length ],
66
- {
67
- "editColumn": column,
68
- "deleteCount": length,
69
- "insertText": fixedText
70
- }
71
- ];
56
+ if (!withinAnyRange(exclusions, lineIndex, column, length)) {
57
+ const context = line.substring(contextStart, contextEnd);
58
+ const leftMarker = line.substring(contextStart, emphasisIndex);
59
+ const rightMarker = match ? (match[2] || match[3]) : "";
60
+ const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
61
+ return [
62
+ onError,
63
+ lineIndex + 1,
64
+ context,
65
+ leftSpace,
66
+ rightSpace,
67
+ [ column, length ],
68
+ {
69
+ "editColumn": column,
70
+ "deleteCount": length,
71
+ "insertText": fixedText
72
+ }
73
+ ];
74
+ }
72
75
  }
73
76
  return null;
74
77
  }
package/lib/md051.js CHANGED
@@ -6,7 +6,8 @@ const { addError, escapeForRegExp, filterTokens, forEachInlineChild,
6
6
  forEachHeading, htmlElementRe } = require("../helpers");
7
7
 
8
8
  // Regular expression for identifying HTML anchor names
9
- const identifierRe = /(?:id|name)\s*=\s*['"]?([^'"\s>]+)/iu;
9
+ const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
10
+ const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
10
11
 
11
12
  /**
12
13
  * Converts a Markdown heading into an HTML fragment according to the rules
@@ -55,11 +56,10 @@ module.exports = {
55
56
  let match = null;
56
57
  while ((match = htmlElementRe.exec(token.content)) !== null) {
57
58
  const [ tag, , element ] = match;
58
- if (element.toLowerCase() === "a") {
59
- const idMatch = identifierRe.exec(tag);
60
- if (idMatch) {
61
- fragments.set(`#${idMatch[1]}`, 0);
62
- }
59
+ const anchorMatch = idRe.exec(tag) ||
60
+ (element.toLowerCase() === "a" && nameRe.exec(tag));
61
+ if (anchorMatch) {
62
+ fragments.set(`#${anchorMatch[1]}`, 0);
63
63
  }
64
64
  }
65
65
  };
package/lib/md053.js CHANGED
@@ -11,7 +11,8 @@ module.exports = {
11
11
  "description": "Link and image reference definitions should be needed",
12
12
  "tags": [ "images", "links" ],
13
13
  "function": function MD053(params, onError) {
14
- const { lines } = params;
14
+ const ignored = new Set(params.config.ignored_definitions || [ "//" ]);
15
+ const lines = params.lines;
15
16
  const { references, shortcuts, definitions, duplicateDefinitions } =
16
17
  referenceLinkImageData();
17
18
  const singleLineDefinition = (line) => (
@@ -23,7 +24,11 @@ module.exports = {
23
24
  // Look for unused link references (unreferenced by any link/image)
24
25
  for (const definition of definitions.entries()) {
25
26
  const [ label, lineIndex ] = definition;
26
- if (!references.has(label) && !shortcuts.has(label)) {
27
+ if (
28
+ !ignored.has(label) &&
29
+ !references.has(label) &&
30
+ !shortcuts.has(label)
31
+ ) {
27
32
  const line = lines[lineIndex];
28
33
  addError(
29
34
  onError,
@@ -38,15 +43,17 @@ module.exports = {
38
43
  // Look for duplicate link references (defined more than once)
39
44
  for (const duplicateDefinition of duplicateDefinitions) {
40
45
  const [ label, lineIndex ] = duplicateDefinition;
41
- const line = lines[lineIndex];
42
- addError(
43
- onError,
44
- lineIndex + 1,
45
- `Duplicate link or image reference definition: "${label}"`,
46
- ellipsify(line),
47
- [ 1, line.length ],
48
- singleLineDefinition(line) ? deleteFixInfo : 0
49
- );
46
+ if (!ignored.has(label)) {
47
+ const line = lines[lineIndex];
48
+ addError(
49
+ onError,
50
+ lineIndex + 1,
51
+ `Duplicate link or image reference definition: "${label}"`,
52
+ ellipsify(line),
53
+ [ 1, line.length ],
54
+ singleLineDefinition(line) ? deleteFixInfo : 0
55
+ );
56
+ }
50
57
  }
51
58
  }
52
59
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint",
3
- "version": "0.26.1",
3
+ "version": "0.26.2",
4
4
  "description": "A Node.js style checker and lint tool for Markdown/CommonMark files.",
5
5
  "type": "commonjs",
6
6
  "main": "./lib/markdownlint.js",
@@ -275,5 +275,10 @@
275
275
  "MD052": true,
276
276
 
277
277
  // MD053/link-image-reference-definitions - Link and image reference definitions should be needed
278
- "MD053": true
278
+ "MD053": {
279
+ // Ignored definitions
280
+ "ignored_definitions": [
281
+ "//"
282
+ ]
283
+ }
279
284
  }
@@ -249,4 +249,8 @@ MD051: true
249
249
  MD052: true
250
250
 
251
251
  # MD053/link-image-reference-definitions - Link and image reference definitions should be needed
252
- MD053: true
252
+ MD053:
253
+ # Ignored definitions
254
+ ignored_definitions: [
255
+ "//"
256
+ ]
@@ -909,8 +909,24 @@
909
909
  },
910
910
  "MD053": {
911
911
  "description": "MD053/link-image-reference-definitions - Link and image reference definitions should be needed",
912
- "type": "boolean",
913
- "default": true
912
+ "type": [
913
+ "boolean",
914
+ "object"
915
+ ],
916
+ "default": true,
917
+ "properties": {
918
+ "ignored_definitions": {
919
+ "description": "Ignored definitions",
920
+ "type": "array",
921
+ "items": {
922
+ "type": "string"
923
+ },
924
+ "default": [
925
+ "//"
926
+ ]
927
+ }
928
+ },
929
+ "additionalProperties": false
914
930
  },
915
931
  "link-image-reference-definitions": {
916
932
  "$ref": "#/properties/MD053"