markdownlint 0.12.0 → 0.14.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.
Files changed (61) hide show
  1. package/.eslintrc.json +52 -275
  2. package/.travis.yml +2 -2
  3. package/LICENSE +1 -1
  4. package/README.md +54 -27
  5. package/doc/CustomRules.md +7 -2
  6. package/doc/Rules.md +120 -33
  7. package/example/standalone.js +2 -2
  8. package/helpers/LICENSE +21 -0
  9. package/helpers/README.md +50 -0
  10. package/{lib/shared.js → helpers/helpers.js} +91 -82
  11. package/helpers/package.json +18 -0
  12. package/lib/cache.js +24 -0
  13. package/lib/markdownlint.js +78 -45
  14. package/lib/md001.js +3 -3
  15. package/lib/md002.js +2 -2
  16. package/lib/md003.js +5 -4
  17. package/lib/md004.js +11 -9
  18. package/lib/md005.js +12 -10
  19. package/lib/md006.js +7 -5
  20. package/lib/md007.js +7 -5
  21. package/lib/md009.js +10 -8
  22. package/lib/md010.js +5 -5
  23. package/lib/md011.js +4 -4
  24. package/lib/md012.js +4 -3
  25. package/lib/md013.js +41 -32
  26. package/lib/md014.js +7 -6
  27. package/lib/md018.js +6 -4
  28. package/lib/md019.js +6 -5
  29. package/lib/md020.js +5 -4
  30. package/lib/md021.js +6 -5
  31. package/lib/md022.js +22 -22
  32. package/lib/md023.js +5 -4
  33. package/lib/md024.js +6 -6
  34. package/lib/md025.js +11 -5
  35. package/lib/md026.js +4 -4
  36. package/lib/md027.js +6 -6
  37. package/lib/md028.js +2 -2
  38. package/lib/md029.js +17 -9
  39. package/lib/md030.js +8 -6
  40. package/lib/md031.js +7 -6
  41. package/lib/md032.js +10 -12
  42. package/lib/md033.js +27 -26
  43. package/lib/md034.js +15 -10
  44. package/lib/md035.js +3 -3
  45. package/lib/md036.js +2 -2
  46. package/lib/md037.js +12 -9
  47. package/lib/md038.js +6 -5
  48. package/lib/md039.js +7 -6
  49. package/lib/md040.js +3 -3
  50. package/lib/md041.js +17 -19
  51. package/lib/md042.js +5 -4
  52. package/lib/md043.js +5 -4
  53. package/lib/md044.js +14 -13
  54. package/lib/md045.js +3 -3
  55. package/lib/md046.js +32 -0
  56. package/lib/md047.js +18 -0
  57. package/lib/rules.js +3 -1
  58. package/package.json +12 -11
  59. package/schema/build-config-schema.js +36 -2
  60. package/schema/markdownlint-config-schema.json +178 -14
  61. package/style/cirosantilli.json +1 -1
package/lib/md001.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, filterTokens } = require("../helpers");
6
6
 
7
7
  module.exports = {
8
8
  "names": [ "MD001", "heading-increment", "header-increment" ],
@@ -10,10 +10,10 @@ module.exports = {
10
10
  "tags": [ "headings", "headers" ],
11
11
  "function": function MD001(params, onError) {
12
12
  let prevLevel = 0;
13
- shared.filterTokens(params, "heading_open", function forToken(token) {
13
+ filterTokens(params, "heading_open", function forToken(token) {
14
14
  const level = parseInt(token.tag.slice(1), 10);
15
15
  if (prevLevel && (level > prevLevel)) {
16
- shared.addErrorDetailIf(onError, token.lineNumber,
16
+ addErrorDetailIf(onError, token.lineNumber,
17
17
  "h" + (prevLevel + 1), "h" + level);
18
18
  }
19
19
  prevLevel = level;
package/lib/md002.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf } = require("../helpers");
6
6
 
7
7
  module.exports = {
8
8
  "names": [ "MD002", "first-heading-h1", "first-header-h1" ],
@@ -13,7 +13,7 @@ module.exports = {
13
13
  const tag = "h" + level;
14
14
  params.tokens.every(function forToken(token) {
15
15
  if (token.type === "heading_open") {
16
- shared.addErrorDetailIf(onError, token.lineNumber, tag, token.tag);
16
+ addErrorDetailIf(onError, token.lineNumber, tag, token.tag);
17
17
  return false;
18
18
  }
19
19
  return true;
package/lib/md003.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, filterTokens, headingStyleFor } =
6
+ require("../helpers");
6
7
 
7
8
  module.exports = {
8
9
  "names": [ "MD003", "heading-style", "header-style" ],
@@ -10,8 +11,8 @@ module.exports = {
10
11
  "tags": [ "headings", "headers" ],
11
12
  "function": function MD003(params, onError) {
12
13
  let style = params.config.style || "consistent";
13
- shared.filterTokens(params, "heading_open", function forToken(token) {
14
- const styleForToken = shared.headingStyleFor(token);
14
+ filterTokens(params, "heading_open", function forToken(token) {
15
+ const styleForToken = headingStyleFor(token);
15
16
  if (style === "consistent") {
16
17
  style = styleForToken;
17
18
  }
@@ -32,7 +33,7 @@ module.exports = {
32
33
  } else if (style === "setext_with_atx_closed") {
33
34
  expected = h12 ? "setext" : "atx_closed";
34
35
  }
35
- shared.addErrorDetailIf(onError, token.lineNumber,
36
+ addErrorDetailIf(onError, token.lineNumber,
36
37
  expected, styleForToken);
37
38
  }
38
39
  }
package/lib/md004.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, listItemMarkerRe,
6
+ rangeFromRegExp } = require("../helpers");
7
+ const { flattenedLists } = require("./cache");
6
8
 
7
9
  // Returns the unordered list style for a list item token
8
10
  function unorderedListStyleFor(token) {
@@ -25,12 +27,12 @@ module.exports = {
25
27
  const style = params.config.style || "consistent";
26
28
  let expectedStyle = style;
27
29
  const nestingStyles = [];
28
- shared.flattenLists().forEach(function forList(list) {
30
+ flattenedLists().forEach((list) => {
29
31
  if (list.unordered) {
30
32
  if (expectedStyle === "consistent") {
31
33
  expectedStyle = unorderedListStyleFor(list.items[0]);
32
34
  }
33
- list.items.forEach(function forItem(item) {
35
+ list.items.forEach((item) => {
34
36
  const itemStyle = unorderedListStyleFor(item);
35
37
  if (style === "sublist") {
36
38
  const nesting = list.nesting;
@@ -38,14 +40,14 @@ module.exports = {
38
40
  (itemStyle !== nestingStyles[nesting - 1])) {
39
41
  nestingStyles[nesting] = itemStyle;
40
42
  } else {
41
- shared.addErrorDetailIf(onError, item.lineNumber,
42
- nestingStyles[nesting], itemStyle, null,
43
- shared.rangeFromRegExp(item.line, shared.listItemMarkerRe));
43
+ addErrorDetailIf(onError, item.lineNumber,
44
+ nestingStyles[nesting], itemStyle, null, null,
45
+ rangeFromRegExp(item.line, listItemMarkerRe));
44
46
  }
45
47
  } else {
46
- shared.addErrorDetailIf(onError, item.lineNumber,
47
- expectedStyle, itemStyle, null,
48
- shared.rangeFromRegExp(item.line, shared.listItemMarkerRe));
48
+ addErrorDetailIf(onError, item.lineNumber,
49
+ expectedStyle, itemStyle, null, null,
50
+ rangeFromRegExp(item.line, listItemMarkerRe));
49
51
  }
50
52
  });
51
53
  }
package/lib/md005.js CHANGED
@@ -2,26 +2,28 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addError, addErrorDetailIf, indentFor, listItemMarkerRe,
6
+ orderedListItemMarkerRe, rangeFromRegExp } = require("../helpers");
7
+ const { flattenedLists } = require("./cache");
6
8
 
7
9
  module.exports = {
8
10
  "names": [ "MD005", "list-indent" ],
9
11
  "description": "Inconsistent indentation for list items at the same level",
10
12
  "tags": [ "bullet", "ul", "indentation" ],
11
13
  "function": function MD005(params, onError) {
12
- shared.flattenLists().forEach(function forList(list) {
14
+ flattenedLists().forEach((list) => {
13
15
  const expectedIndent = list.indent;
14
16
  let expectedEnd = 0;
15
17
  let actualEnd = -1;
16
18
  let endMatching = false;
17
- list.items.forEach(function forItem(item) {
18
- const actualIndent = shared.indentFor(item);
19
+ list.items.forEach((item) => {
20
+ const actualIndent = indentFor(item);
19
21
  if (list.unordered) {
20
- shared.addErrorDetailIf(onError, item.lineNumber,
21
- expectedIndent, actualIndent, null,
22
- shared.rangeFromRegExp(item.line, shared.listItemMarkerRe));
22
+ addErrorDetailIf(onError, item.lineNumber,
23
+ expectedIndent, actualIndent, null, null,
24
+ rangeFromRegExp(item.line, listItemMarkerRe));
23
25
  } else {
24
- const match = shared.orderedListItemMarkerRe.exec(item.line);
26
+ const match = orderedListItemMarkerRe.exec(item.line);
25
27
  actualEnd = match && match[0].length;
26
28
  expectedEnd = expectedEnd || actualEnd;
27
29
  if ((expectedIndent !== actualIndent) || endMatching) {
@@ -31,8 +33,8 @@ module.exports = {
31
33
  const detail = endMatching ?
32
34
  `Expected: (${expectedEnd}); Actual: (${actualEnd})` :
33
35
  `Expected: ${expectedIndent}; Actual: ${actualIndent}`;
34
- shared.addError(onError, item.lineNumber, detail, null,
35
- shared.rangeFromRegExp(item.line, shared.listItemMarkerRe));
36
+ addError(onError, item.lineNumber, detail, null,
37
+ rangeFromRegExp(item.line, listItemMarkerRe));
36
38
  }
37
39
  }
38
40
  }
package/lib/md006.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
6
+ require("../helpers");
7
+ const { flattenedLists } = require("./cache");
6
8
 
7
9
  module.exports = {
8
10
  "names": [ "MD006", "ul-start-left" ],
@@ -10,11 +12,11 @@ module.exports = {
10
12
  "Consider starting bulleted lists at the beginning of the line",
11
13
  "tags": [ "bullet", "ul", "indentation" ],
12
14
  "function": function MD006(params, onError) {
13
- shared.flattenLists().forEach(function forList(list) {
15
+ flattenedLists().forEach((list) => {
14
16
  if (list.unordered && !list.nesting) {
15
- shared.addErrorDetailIf(onError, list.open.lineNumber,
16
- 0, list.indent, null,
17
- shared.rangeFromRegExp(list.open.line, shared.listItemMarkerRe));
17
+ addErrorDetailIf(onError, list.open.lineNumber,
18
+ 0, list.indent, null, null,
19
+ rangeFromRegExp(list.open.line, listItemMarkerRe));
18
20
  }
19
21
  });
20
22
  }
package/lib/md007.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
6
+ require("../helpers");
7
+ const { flattenedLists } = require("./cache");
6
8
 
7
9
  module.exports = {
8
10
  "names": [ "MD007", "ul-indent" ],
@@ -10,11 +12,11 @@ module.exports = {
10
12
  "tags": [ "bullet", "ul", "indentation" ],
11
13
  "function": function MD007(params, onError) {
12
14
  const optionsIndent = params.config.indent || 2;
13
- shared.flattenLists().forEach(function forList(list) {
15
+ flattenedLists().forEach((list) => {
14
16
  if (list.unordered && list.parentsUnordered && list.indent) {
15
- shared.addErrorDetailIf(onError, list.open.lineNumber,
16
- list.parentIndent + optionsIndent, list.indent, null,
17
- shared.rangeFromRegExp(list.open.line, shared.listItemMarkerRe));
17
+ addErrorDetailIf(onError, list.open.lineNumber,
18
+ list.parentIndent + optionsIndent, list.indent, null, null,
19
+ rangeFromRegExp(list.open.line, listItemMarkerRe));
18
20
  }
19
21
  });
20
22
  }
package/lib/md009.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addError, filterTokens, forEachLine, includesSorted, rangeFromRegExp } =
6
+ require("../helpers");
7
+ const { lineMetadata } = require("./cache");
6
8
 
7
9
  const trailingSpaceRe = /\s+$/;
8
10
 
@@ -20,24 +22,24 @@ module.exports = {
20
22
  (listItemEmptyLines === undefined) ? false : !!listItemEmptyLines;
21
23
  const listItemLineNumbers = [];
22
24
  if (allowListItemEmptyLines) {
23
- shared.filterTokens(params, "list_item_open", function forToken(token) {
25
+ filterTokens(params, "list_item_open", (token) => {
24
26
  for (let i = token.map[0]; i < token.map[1]; i++) {
25
27
  listItemLineNumbers.push(i + 1);
26
28
  }
27
29
  });
30
+ listItemLineNumbers.sort((a, b) => a - b);
28
31
  }
29
32
  const expected = (brSpaces < 2) ? 0 : brSpaces;
30
- shared.forEachLine(function forLine(line, lineIndex) {
33
+ forEachLine(lineMetadata(), (line, lineIndex) => {
31
34
  const lineNumber = lineIndex + 1;
32
35
  if (trailingSpaceRe.test(line) &&
33
- (listItemLineNumbers.indexOf(lineNumber) === -1)) {
34
- const actual = line.length - shared.trimRight(line).length;
36
+ !includesSorted(listItemLineNumbers, lineNumber)) {
37
+ const actual = line.length - line.trimRight().length;
35
38
  if (expected !== actual) {
36
- shared.addError(onError, lineNumber,
39
+ addError(onError, lineNumber,
37
40
  "Expected: " + (expected === 0 ? "" : "0 or ") +
38
41
  expected + "; Actual: " + actual,
39
- null,
40
- shared.rangeFromRegExp(line, trailingSpaceRe));
42
+ null, rangeFromRegExp(line, trailingSpaceRe));
41
43
  }
42
44
  }
43
45
  });
package/lib/md010.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addError, forEachLine, rangeFromRegExp } = require("../helpers");
6
+ const { lineMetadata } = require("./cache");
6
7
 
7
8
  const tabRe = /\t+/;
8
9
 
@@ -13,11 +14,10 @@ module.exports = {
13
14
  "function": function MD010(params, onError) {
14
15
  const codeBlocks = params.config.code_blocks;
15
16
  const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
16
- shared.forEachLine(function forLine(line, lineIndex, inCode) {
17
+ forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
17
18
  if (tabRe.test(line) && (!inCode || includeCodeBlocks)) {
18
- shared.addError(onError, lineIndex + 1,
19
- "Column: " + (line.indexOf("\t") + 1), null,
20
- shared.rangeFromRegExp(line, tabRe));
19
+ addError(onError, lineIndex + 1, "Column: " + (line.indexOf("\t") + 1),
20
+ null, rangeFromRegExp(line, tabRe));
21
21
  }
22
22
  });
23
23
  }
package/lib/md011.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addError, forEachInlineChild, rangeFromRegExp } = require("../helpers");
6
6
 
7
7
  const reversedLinkRe = /\([^)]+\)\[[^\]^][^\]]*]/;
8
8
 
@@ -11,11 +11,11 @@ module.exports = {
11
11
  "description": "Reversed link syntax",
12
12
  "tags": [ "links" ],
13
13
  "function": function MD011(params, onError) {
14
- shared.forEachInlineChild(params, "text", function forToken(token) {
14
+ forEachInlineChild(params, "text", function forToken(token) {
15
15
  const match = reversedLinkRe.exec(token.content);
16
16
  if (match) {
17
- shared.addError(onError, token.lineNumber, match[0], null,
18
- shared.rangeFromRegExp(token.line, reversedLinkRe));
17
+ addError(onError, token.lineNumber, match[0], null,
18
+ rangeFromRegExp(token.line, reversedLinkRe));
19
19
  }
20
20
  });
21
21
  }
package/lib/md012.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, forEachLine } = require("../helpers");
6
+ const { lineMetadata } = require("./cache");
6
7
 
7
8
  module.exports = {
8
9
  "names": [ "MD012", "no-multiple-blanks" ],
@@ -11,10 +12,10 @@ module.exports = {
11
12
  "function": function MD012(params, onError) {
12
13
  const maximum = params.config.maximum || 1;
13
14
  let count = 0;
14
- shared.forEachLine(function forLine(line, lineIndex, inCode) {
15
+ forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
15
16
  count = (inCode || line.trim().length) ? 0 : count + 1;
16
17
  if (maximum < count) {
17
- shared.addErrorDetailIf(onError, lineIndex + 1, maximum, count);
18
+ addErrorDetailIf(onError, lineIndex + 1, maximum, count);
18
19
  }
19
20
  });
20
21
  }
package/lib/md013.js CHANGED
@@ -2,9 +2,23 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine,
6
+ includesSorted, rangeFromRegExp } = require("../helpers");
7
+ const { lineMetadata } = require("./cache");
6
8
 
9
+ const longLineRePrefix = "^(.{";
10
+ const longLineRePostfix = "})(.*\\s.*)$";
7
11
  const labelRe = /^\s*\[.*[^\\]]:/;
12
+ const linkOnlyLineRe = /^[es]*lT?L[ES]*$/;
13
+ const tokenTypeMap = {
14
+ "em_open": "e",
15
+ "em_close": "E",
16
+ "link_open": "l",
17
+ "link_close": "L",
18
+ "strong_open": "s",
19
+ "strong_close": "S",
20
+ "text": "T"
21
+ };
8
22
 
9
23
  module.exports = {
10
24
  "names": [ "MD013", "line-length" ],
@@ -12,6 +26,11 @@ module.exports = {
12
26
  "tags": [ "line_length" ],
13
27
  "function": function MD013(params, onError) {
14
28
  const lineLength = params.config.line_length || 80;
29
+ const headingLineLength = params.config.heading_line_length || lineLength;
30
+ const longLineRe =
31
+ new RegExp(longLineRePrefix + lineLength + longLineRePostfix);
32
+ const longHeadingLineRe =
33
+ new RegExp(longLineRePrefix + headingLineLength + longLineRePostfix);
15
34
  const codeBlocks = params.config.code_blocks;
16
35
  const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
17
36
  const tables = params.config.tables;
@@ -22,45 +41,35 @@ module.exports = {
22
41
  }
23
42
  const includeHeadings = (headings === undefined) ? true : !!headings;
24
43
  const headingLineNumbers = [];
25
- if (!includeHeadings) {
26
- shared.forEachHeading(params, function forHeading(heading) {
27
- headingLineNumbers.push(heading.lineNumber);
28
- });
29
- }
30
- const tokenTypeMap = {
31
- "em_open": "e",
32
- "em_close": "E",
33
- "link_open": "l",
34
- "link_close": "L",
35
- "strong_open": "s",
36
- "strong_close": "S",
37
- "text": "T"
38
- };
44
+ forEachHeading(params, (heading) => {
45
+ headingLineNumbers.push(heading.lineNumber);
46
+ });
39
47
  const linkOnlyLineNumbers = [];
40
- shared.filterTokens(params, "inline", function forToken(token) {
48
+ filterTokens(params, "inline", (token) => {
41
49
  let childTokenTypes = "";
42
- token.children.forEach(function forChild(child) {
50
+ token.children.forEach((child) => {
43
51
  if (child.type !== "text" || child.content !== "") {
44
52
  childTokenTypes += tokenTypeMap[child.type] || "x";
45
53
  }
46
54
  });
47
- if (/^[es]*lT?L[ES]*$/.test(childTokenTypes)) {
55
+ if (linkOnlyLineRe.test(childTokenTypes)) {
48
56
  linkOnlyLineNumbers.push(token.lineNumber);
49
57
  }
50
58
  });
51
- const longLineRe = new RegExp("^(.{" + lineLength + "})(.*\\s.*)$");
52
- shared.forEachLine(
53
- function forLine(line, lineIndex, inCode, onFence, inTable) {
54
- const lineNumber = lineIndex + 1;
55
- if ((includeCodeBlocks || !inCode) &&
56
- (includeTables || !inTable) &&
57
- (includeHeadings || (headingLineNumbers.indexOf(lineNumber)) < 0) &&
58
- (linkOnlyLineNumbers.indexOf(lineNumber) < 0) &&
59
- longLineRe.test(line) &&
60
- !labelRe.test(line)) {
61
- shared.addErrorDetailIf(onError, lineNumber, lineLength,
62
- line.length, null, shared.rangeFromRegExp(line, longLineRe));
63
- }
64
- });
59
+ forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => {
60
+ const lineNumber = lineIndex + 1;
61
+ const isHeading = includesSorted(headingLineNumbers, lineNumber);
62
+ const length = isHeading ? headingLineLength : lineLength;
63
+ const lengthRe = isHeading ? longHeadingLineRe : longLineRe;
64
+ if ((includeCodeBlocks || !inCode) &&
65
+ (includeTables || !inTable) &&
66
+ (includeHeadings || !isHeading) &&
67
+ !includesSorted(linkOnlyLineNumbers, lineNumber) &&
68
+ lengthRe.test(line) &&
69
+ !labelRe.test(line)) {
70
+ addErrorDetailIf(onError, lineNumber, length, line.length,
71
+ null, null, rangeFromRegExp(line, lengthRe));
72
+ }
73
+ });
65
74
  }
66
75
  };
package/lib/md014.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorContext, filterTokens, newLineRe, rangeFromRegExp } =
6
+ require("../helpers");
6
7
 
7
8
  const dollarCommandRe = /^(\s*)(\$\s)/;
8
9
 
@@ -12,15 +13,15 @@ module.exports = {
12
13
  "tags": [ "code" ],
13
14
  "function": function MD014(params, onError) {
14
15
  [ "code_block", "fence" ].forEach(function forType(type) {
15
- shared.filterTokens(params, type, function forToken(token) {
16
+ filterTokens(params, type, function forToken(token) {
16
17
  let allBlank = true;
17
- if (token.content && token.content.split(shared.newLineRe)
18
+ if (token.content && token.content.split(newLineRe)
18
19
  .every(function forLine(line) {
19
20
  return !line || (allBlank = false) || dollarCommandRe.test(line);
20
21
  }) && !allBlank) {
21
- shared.addErrorContext(onError, token.lineNumber,
22
- token.content.split(shared.newLineRe)[0].trim(), null, null,
23
- shared.rangeFromRegExp(token.line, dollarCommandRe));
22
+ addErrorContext(onError, token.lineNumber,
23
+ token.content.split(newLineRe)[0].trim(), null, null,
24
+ rangeFromRegExp(token.line, dollarCommandRe));
24
25
  }
25
26
  });
26
27
  });
package/lib/md018.js CHANGED
@@ -2,17 +2,19 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorContext, atxHeadingSpaceRe, forEachLine,
6
+ rangeFromRegExp } = require("../helpers");
7
+ const { lineMetadata } = require("./cache");
6
8
 
7
9
  module.exports = {
8
10
  "names": [ "MD018", "no-missing-space-atx" ],
9
11
  "description": "No space after hash on atx style heading",
10
12
  "tags": [ "headings", "headers", "atx", "spaces" ],
11
13
  "function": function MD018(params, onError) {
12
- shared.forEachLine(function forLine(line, lineIndex, inCode) {
14
+ forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
13
15
  if (!inCode && /^#+[^#\s]/.test(line) && !/#$/.test(line)) {
14
- shared.addErrorContext(onError, lineIndex + 1, line.trim(), null,
15
- null, shared.rangeFromRegExp(line, shared.atxHeadingSpaceRe));
16
+ addErrorContext(onError, lineIndex + 1, line.trim(), null,
17
+ null, rangeFromRegExp(line, atxHeadingSpaceRe));
16
18
  }
17
19
  });
18
20
  }
package/lib/md019.js CHANGED
@@ -2,19 +2,20 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorContext, atxHeadingSpaceRe, filterTokens, headingStyleFor,
6
+ rangeFromRegExp } = require("../helpers");
6
7
 
7
8
  module.exports = {
8
9
  "names": [ "MD019", "no-multiple-space-atx" ],
9
10
  "description": "Multiple spaces after hash on atx style heading",
10
11
  "tags": [ "headings", "headers", "atx", "spaces" ],
11
12
  "function": function MD019(params, onError) {
12
- shared.filterTokens(params, "heading_open", function forToken(token) {
13
- if ((shared.headingStyleFor(token) === "atx") &&
13
+ filterTokens(params, "heading_open", function forToken(token) {
14
+ if ((headingStyleFor(token) === "atx") &&
14
15
  /^#+\s\s/.test(token.line)) {
15
- shared.addErrorContext(onError, token.lineNumber, token.line.trim(),
16
+ addErrorContext(onError, token.lineNumber, token.line.trim(),
16
17
  null, null,
17
- shared.rangeFromRegExp(token.line, shared.atxHeadingSpaceRe));
18
+ rangeFromRegExp(token.line, atxHeadingSpaceRe));
18
19
  }
19
20
  });
20
21
  }
package/lib/md020.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorContext, forEachLine, rangeFromRegExp } = require("../helpers");
6
+ const { lineMetadata } = require("./cache");
6
7
 
7
8
  const atxClosedHeadingNoSpaceRe = /(?:^#+[^#\s])|(?:[^#\s]#+\s*$)/;
8
9
 
@@ -11,13 +12,13 @@ module.exports = {
11
12
  "description": "No space inside hashes on closed atx style heading",
12
13
  "tags": [ "headings", "headers", "atx_closed", "spaces" ],
13
14
  "function": function MD020(params, onError) {
14
- shared.forEachLine(function forLine(line, lineIndex, inCode) {
15
+ forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
15
16
  if (!inCode && /^#+[^#]*[^\\]#+$/.test(line)) {
16
17
  const left = /^#+[^#\s]/.test(line);
17
18
  const right = /[^#\s]#+$/.test(line);
18
19
  if (left || right) {
19
- shared.addErrorContext(onError, lineIndex + 1, line.trim(), left,
20
- right, shared.rangeFromRegExp(line, atxClosedHeadingNoSpaceRe));
20
+ addErrorContext(onError, lineIndex + 1, line.trim(), left,
21
+ right, rangeFromRegExp(line, atxClosedHeadingNoSpaceRe));
21
22
  }
22
23
  }
23
24
  });
package/lib/md021.js CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorContext, filterTokens, headingStyleFor, rangeFromRegExp } =
6
+ require("../helpers");
6
7
 
7
8
  const atxClosedHeadingSpaceRe = /(?:^#+\s\s+?\S)|(?:\S\s\s+?#+\s*$)/;
8
9
 
@@ -11,14 +12,14 @@ module.exports = {
11
12
  "description": "Multiple spaces inside hashes on closed atx style heading",
12
13
  "tags": [ "headings", "headers", "atx_closed", "spaces" ],
13
14
  "function": function MD021(params, onError) {
14
- shared.filterTokens(params, "heading_open", function forToken(token) {
15
- if (shared.headingStyleFor(token) === "atx_closed") {
15
+ filterTokens(params, "heading_open", function forToken(token) {
16
+ if (headingStyleFor(token) === "atx_closed") {
16
17
  const left = /^#+\s\s/.test(token.line);
17
18
  const right = /\s\s#+$/.test(token.line);
18
19
  if (left || right) {
19
- shared.addErrorContext(onError, token.lineNumber, token.line.trim(),
20
+ addErrorContext(onError, token.lineNumber, token.line.trim(),
20
21
  left, right,
21
- shared.rangeFromRegExp(token.line, atxClosedHeadingSpaceRe));
22
+ rangeFromRegExp(token.line, atxClosedHeadingSpaceRe));
22
23
  }
23
24
  }
24
25
  });
package/lib/md022.js CHANGED
@@ -2,37 +2,37 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const shared = require("./shared");
5
+ const { addErrorDetailIf, filterTokens, isBlankLine } = require("../helpers");
6
6
 
7
7
  module.exports = {
8
8
  "names": [ "MD022", "blanks-around-headings", "blanks-around-headers" ],
9
9
  "description": "Headings should be surrounded by blank lines",
10
10
  "tags": [ "headings", "headers", "blank_lines" ],
11
11
  "function": function MD022(params, onError) {
12
- let prevHeadingLineNumber = 0;
13
- let prevMaxLineIndex = -1;
14
- let needBlankLine = false;
15
- params.tokens.forEach(function forToken(token) {
16
- if (token.type === "heading_open") {
17
- if ((token.map[0] - prevMaxLineIndex) === 0) {
18
- shared.addErrorContext(onError, token.lineNumber,
19
- token.line.trim());
12
+ let linesAbove = params.config.lines_above;
13
+ if (linesAbove === undefined) {
14
+ linesAbove = 1;
15
+ }
16
+ let linesBelow = params.config.lines_below;
17
+ if (linesBelow === undefined) {
18
+ linesBelow = 1;
19
+ }
20
+ const { lines } = params;
21
+ filterTokens(params, "heading_open", (token) => {
22
+ const [ topIndex, nextIndex ] = token.map;
23
+ for (let i = 0; i < linesAbove; i++) {
24
+ if (!isBlankLine(lines[topIndex - i - 1])) {
25
+ addErrorDetailIf(onError, topIndex + 1, linesAbove, i, "Above",
26
+ lines[topIndex].trim());
27
+ return;
20
28
  }
21
- } else if (token.type === "heading_close") {
22
- needBlankLine = true;
23
29
  }
24
- if (token.map) {
25
- if (needBlankLine) {
26
- if ((token.map[0] - prevMaxLineIndex) === 0) {
27
- shared.addErrorContext(onError, prevHeadingLineNumber,
28
- params.lines[prevHeadingLineNumber - 1].trim());
29
- }
30
- needBlankLine = false;
30
+ for (let i = 0; i < linesBelow; i++) {
31
+ if (!isBlankLine(lines[nextIndex + i])) {
32
+ addErrorDetailIf(onError, topIndex + 1, linesBelow, i, "Below",
33
+ lines[topIndex].trim());
34
+ return;
31
35
  }
32
- prevMaxLineIndex = Math.max(prevMaxLineIndex, token.map[1]);
33
- }
34
- if (token.type === "heading_open") {
35
- prevHeadingLineNumber = token.lineNumber;
36
36
  }
37
37
  });
38
38
  }