markdownlint 0.20.2 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CONTRIBUTING.md +50 -47
  2. package/LICENSE +21 -21
  3. package/README.md +915 -871
  4. package/demo/markdownlint-browser.js +4693 -5400
  5. package/doc/CustomRules.md +315 -313
  6. package/doc/Rules.md +1868 -1795
  7. package/helpers/LICENSE +21 -21
  8. package/helpers/README.md +50 -50
  9. package/helpers/helpers.js +690 -671
  10. package/helpers/package.json +18 -18
  11. package/lib/cache.js +24 -24
  12. package/lib/markdownlint.d.ts +365 -352
  13. package/lib/markdownlint.js +1186 -1101
  14. package/lib/md001.js +22 -22
  15. package/lib/md002.js +22 -22
  16. package/lib/md003.js +42 -42
  17. package/lib/md004.js +43 -43
  18. package/lib/md005.js +69 -69
  19. package/lib/md006.js +34 -34
  20. package/lib/md007.js +47 -47
  21. package/lib/md009.js +77 -77
  22. package/lib/md010.js +38 -38
  23. package/lib/md011.js +42 -38
  24. package/lib/md012.js +32 -32
  25. package/lib/md013.js +99 -99
  26. package/lib/md014.js +53 -53
  27. package/lib/md018.js +34 -34
  28. package/lib/md019.js +39 -39
  29. package/lib/md020.js +62 -62
  30. package/lib/md021.js +60 -60
  31. package/lib/md022.js +56 -56
  32. package/lib/md023.js +38 -38
  33. package/lib/md024.js +38 -38
  34. package/lib/md025.js +32 -32
  35. package/lib/md026.js +40 -40
  36. package/lib/md027.js +56 -56
  37. package/lib/md028.js +38 -38
  38. package/lib/md029.js +66 -66
  39. package/lib/md030.js +50 -50
  40. package/lib/md031.js +40 -39
  41. package/lib/md032.js +50 -50
  42. package/lib/md033.js +45 -45
  43. package/lib/md034.js +61 -61
  44. package/lib/md035.js +21 -21
  45. package/lib/md036.js +56 -56
  46. package/lib/md037.js +150 -141
  47. package/lib/md038.js +68 -68
  48. package/lib/md039.js +64 -64
  49. package/lib/md040.js +18 -18
  50. package/lib/md041.js +31 -31
  51. package/lib/md042.js +42 -41
  52. package/lib/md043.js +45 -45
  53. package/lib/md044.js +94 -71
  54. package/lib/md045.js +18 -18
  55. package/lib/md046.js +32 -32
  56. package/lib/md047.js +28 -28
  57. package/lib/md048.js +29 -29
  58. package/lib/rules.js +60 -61
  59. package/package.json +74 -67
  60. package/schema/build-config-schema.js +409 -405
  61. package/schema/markdownlint-config-schema.json +7 -2
  62. package/style/all.json +5 -5
  63. package/style/cirosantilli.json +22 -22
  64. package/style/relaxed.json +13 -13
package/lib/md042.js CHANGED
@@ -1,41 +1,42 @@
1
- // @ts-check
2
-
3
- "use strict";
4
-
5
- const { addErrorContext, filterTokens, rangeFromRegExp } =
6
- require("../helpers");
7
-
8
- const emptyLinkRe = /\[[^\]]*](?:\((?:#?|(?:<>))\))/;
9
-
10
- module.exports = {
11
- "names": [ "MD042", "no-empty-links" ],
12
- "description": "No empty links",
13
- "tags": [ "links" ],
14
- "function": function MD042(params, onError) {
15
- filterTokens(params, "inline", function forToken(token) {
16
- let inLink = false;
17
- let linkText = "";
18
- let emptyLink = false;
19
- token.children.forEach(function forChild(child) {
20
- if (child.type === "link_open") {
21
- inLink = true;
22
- linkText = "";
23
- child.attrs.forEach(function forAttr(attr) {
24
- if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
25
- emptyLink = true;
26
- }
27
- });
28
- } else if (child.type === "link_close") {
29
- inLink = false;
30
- if (emptyLink) {
31
- addErrorContext(onError, child.lineNumber,
32
- "[" + linkText + "]()", null, null,
33
- rangeFromRegExp(child.line, emptyLinkRe));
34
- }
35
- } else if (inLink) {
36
- linkText += child.content;
37
- }
38
- });
39
- });
40
- }
41
- };
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addErrorContext, filterTokens, rangeFromRegExp } =
6
+ require("../helpers");
7
+
8
+ const emptyLinkRe = /\[[^\]]*](?:\((?:#?|(?:<>))\))/;
9
+
10
+ module.exports = {
11
+ "names": [ "MD042", "no-empty-links" ],
12
+ "description": "No empty links",
13
+ "tags": [ "links" ],
14
+ "function": function MD042(params, onError) {
15
+ filterTokens(params, "inline", function forToken(token) {
16
+ let inLink = false;
17
+ let linkText = "";
18
+ let emptyLink = false;
19
+ token.children.forEach(function forChild(child) {
20
+ if (child.type === "link_open") {
21
+ inLink = true;
22
+ linkText = "";
23
+ child.attrs.forEach(function forAttr(attr) {
24
+ if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
25
+ emptyLink = true;
26
+ }
27
+ });
28
+ } else if (child.type === "link_close") {
29
+ inLink = false;
30
+ if (emptyLink) {
31
+ addErrorContext(onError, child.lineNumber,
32
+ "[" + linkText + "]()", null, null,
33
+ rangeFromRegExp(child.line, emptyLinkRe));
34
+ emptyLink = false;
35
+ }
36
+ } else if (inLink) {
37
+ linkText += child.content;
38
+ }
39
+ });
40
+ });
41
+ }
42
+ };
package/lib/md043.js CHANGED
@@ -1,45 +1,45 @@
1
- // @ts-check
2
-
3
- "use strict";
4
-
5
- const { addErrorContext, addErrorDetailIf, forEachHeading } =
6
- require("../helpers");
7
-
8
- module.exports = {
9
- "names": [ "MD043", "required-headings", "required-headers" ],
10
- "description": "Required heading structure",
11
- "tags": [ "headings", "headers" ],
12
- "function": function MD043(params, onError) {
13
- const requiredHeadings = params.config.headings || params.config.headers;
14
- if (Array.isArray(requiredHeadings)) {
15
- const levels = {};
16
- [ 1, 2, 3, 4, 5, 6 ].forEach(function forLevel(level) {
17
- levels["h" + level] = "######".substr(-level);
18
- });
19
- let i = 0;
20
- let optional = false;
21
- let errorCount = 0;
22
- forEachHeading(params, function forHeading(heading, content) {
23
- if (!errorCount) {
24
- const actual = levels[heading.tag] + " " + content;
25
- const expected = requiredHeadings[i++] || "[None]";
26
- if (expected === "*") {
27
- optional = true;
28
- } else if (expected.toLowerCase() === actual.toLowerCase()) {
29
- optional = false;
30
- } else if (optional) {
31
- i--;
32
- } else {
33
- addErrorDetailIf(onError, heading.lineNumber,
34
- expected, actual);
35
- errorCount++;
36
- }
37
- }
38
- });
39
- if ((i < requiredHeadings.length) && !errorCount) {
40
- addErrorContext(onError, params.lines.length,
41
- requiredHeadings[i]);
42
- }
43
- }
44
- }
45
- };
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addErrorContext, addErrorDetailIf, forEachHeading } =
6
+ require("../helpers");
7
+
8
+ module.exports = {
9
+ "names": [ "MD043", "required-headings", "required-headers" ],
10
+ "description": "Required heading structure",
11
+ "tags": [ "headings", "headers" ],
12
+ "function": function MD043(params, onError) {
13
+ const requiredHeadings = params.config.headings || params.config.headers;
14
+ if (Array.isArray(requiredHeadings)) {
15
+ const levels = {};
16
+ [ 1, 2, 3, 4, 5, 6 ].forEach(function forLevel(level) {
17
+ levels["h" + level] = "######".substr(-level);
18
+ });
19
+ let i = 0;
20
+ let optional = false;
21
+ let errorCount = 0;
22
+ forEachHeading(params, function forHeading(heading, content) {
23
+ if (!errorCount) {
24
+ const actual = levels[heading.tag] + " " + content;
25
+ const expected = requiredHeadings[i++] || "[None]";
26
+ if (expected === "*") {
27
+ optional = true;
28
+ } else if (expected.toLowerCase() === actual.toLowerCase()) {
29
+ optional = false;
30
+ } else if (optional) {
31
+ i--;
32
+ } else {
33
+ addErrorDetailIf(onError, heading.lineNumber,
34
+ expected, actual);
35
+ errorCount++;
36
+ }
37
+ }
38
+ });
39
+ if ((i < requiredHeadings.length) && !errorCount) {
40
+ addErrorContext(onError, params.lines.length,
41
+ requiredHeadings[i]);
42
+ }
43
+ }
44
+ }
45
+ };
package/lib/md044.js CHANGED
@@ -1,71 +1,94 @@
1
- // @ts-check
2
-
3
- "use strict";
4
-
5
- const { addErrorDetailIf, bareUrlRe, escapeForRegExp, filterTokens,
6
- forEachInlineChild, newLineRe } = require("../helpers");
7
-
8
- module.exports = {
9
- "names": [ "MD044", "proper-names" ],
10
- "description": "Proper names should have the correct capitalization",
11
- "tags": [ "spelling" ],
12
- "function": function MD044(params, onError) {
13
- let names = params.config.names;
14
- names = Array.isArray(names) ? names : [];
15
- const codeBlocks = params.config.code_blocks;
16
- const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
17
- names.forEach((name) => {
18
- const escapedName = escapeForRegExp(name);
19
- const namePattern = "\\S*\\b(" + escapedName + ")\\b\\S*";
20
- const anyNameRe = new RegExp(namePattern, "gi");
21
- // eslint-disable-next-line jsdoc/require-jsdoc
22
- function forToken(token) {
23
- const fenceOffset = (token.type === "fence") ? 1 : 0;
24
- token.content.split(newLineRe)
25
- .forEach((line, index) => {
26
- let match = null;
27
- while ((match = anyNameRe.exec(line)) !== null) {
28
- const fullMatch = match[0];
29
- if (fullMatch.search(bareUrlRe) === -1) {
30
- const wordMatch = fullMatch
31
- .replace(/^\W*/, "").replace(/\W*$/, "");
32
- if (!names.includes(wordMatch)) {
33
- const lineNumber = token.lineNumber + index + fenceOffset;
34
- const fullLine = params.lines[lineNumber - 1];
35
- let matchIndex = match.index;
36
- const matchLength = wordMatch.length;
37
- const fullLineWord =
38
- fullLine.slice(matchIndex, matchIndex + matchLength);
39
- if (fullLineWord !== wordMatch) {
40
- // Attempt to fix bad offset due to inline content
41
- matchIndex = fullLine.indexOf(wordMatch);
42
- }
43
- const range = [ matchIndex + 1, matchLength ];
44
- addErrorDetailIf(
45
- onError,
46
- lineNumber,
47
- name,
48
- match[1],
49
- null,
50
- null,
51
- range,
52
- {
53
- "editColumn": matchIndex + 1,
54
- "deleteCount": matchLength,
55
- "insertText": name
56
- }
57
- );
58
- }
59
- }
60
- }
61
- });
62
- }
63
- forEachInlineChild(params, "text", forToken);
64
- if (includeCodeBlocks) {
65
- forEachInlineChild(params, "code_inline", forToken);
66
- filterTokens(params, "code_block", forToken);
67
- filterTokens(params, "fence", forToken);
68
- }
69
- });
70
- }
71
- };
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addErrorDetailIf, bareUrlRe, escapeForRegExp, filterTokens,
6
+ forEachInlineChild, newLineRe } = require("../helpers");
7
+
8
+ const startNonWordRe = /^\W/;
9
+ const endNonWordRe = /\W$/;
10
+
11
+ module.exports = {
12
+ "names": [ "MD044", "proper-names" ],
13
+ "description": "Proper names should have the correct capitalization",
14
+ "tags": [ "spelling" ],
15
+ "function": function MD044(params, onError) {
16
+ let names = params.config.names;
17
+ names = Array.isArray(names) ? names : [];
18
+ const codeBlocks = params.config.code_blocks;
19
+ const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
20
+ // Text of automatic hyperlinks is implicitly a URL
21
+ const autolinkText = new Set();
22
+ filterTokens(params, "inline", (token) => {
23
+ let inAutoLink = false;
24
+ token.children.forEach((child) => {
25
+ const { info, type } = child;
26
+ if ((type === "link_open") && (info === "auto")) {
27
+ inAutoLink = true;
28
+ } else if (type === "link_close") {
29
+ inAutoLink = false;
30
+ } else if ((type === "text") && inAutoLink) {
31
+ autolinkText.add(child);
32
+ }
33
+ });
34
+ });
35
+ // For each proper name...
36
+ names.forEach((name) => {
37
+ const escapedName = escapeForRegExp(name);
38
+ const startNamePattern = startNonWordRe.test(name) ? "" : "\\S*\\b";
39
+ const endNamePattern = endNonWordRe.test(name) ? "" : "\\b\\S*";
40
+ const namePattern =
41
+ `(${startNamePattern})(${escapedName})(${endNamePattern})`;
42
+ const anyNameRe = new RegExp(namePattern, "gi");
43
+ // eslint-disable-next-line jsdoc/require-jsdoc
44
+ function forToken(token) {
45
+ if (!autolinkText.has(token)) {
46
+ const fenceOffset = (token.type === "fence") ? 1 : 0;
47
+ token.content.split(newLineRe).forEach((line, index) => {
48
+ let match = null;
49
+ while ((match = anyNameRe.exec(line)) !== null) {
50
+ const [ fullMatch, leftMatch, nameMatch, rightMatch ] = match;
51
+ if (fullMatch.search(bareUrlRe) === -1) {
52
+ const wordMatch = fullMatch
53
+ .replace(new RegExp(`^\\W{0,${leftMatch.length}}`), "")
54
+ .replace(new RegExp(`\\W{0,${rightMatch.length}}$`), "");
55
+ if (!names.includes(wordMatch)) {
56
+ const lineNumber = token.lineNumber + index + fenceOffset;
57
+ const fullLine = params.lines[lineNumber - 1];
58
+ const matchLength = wordMatch.length;
59
+ const matchIndex = fullLine.indexOf(wordMatch);
60
+ const range = (matchIndex === -1) ?
61
+ null :
62
+ [ matchIndex + 1, matchLength ];
63
+ const fixInfo = (matchIndex === -1) ?
64
+ null :
65
+ {
66
+ "editColumn": matchIndex + 1,
67
+ "deleteCount": matchLength,
68
+ "insertText": name
69
+ };
70
+ addErrorDetailIf(
71
+ onError,
72
+ lineNumber,
73
+ name,
74
+ nameMatch,
75
+ null,
76
+ null,
77
+ range,
78
+ fixInfo
79
+ );
80
+ }
81
+ }
82
+ }
83
+ });
84
+ }
85
+ }
86
+ forEachInlineChild(params, "text", forToken);
87
+ if (includeCodeBlocks) {
88
+ forEachInlineChild(params, "code_inline", forToken);
89
+ filterTokens(params, "code_block", forToken);
90
+ filterTokens(params, "fence", forToken);
91
+ }
92
+ });
93
+ }
94
+ };
package/lib/md045.js CHANGED
@@ -1,18 +1,18 @@
1
- // @ts-check
2
-
3
- "use strict";
4
-
5
- const { addError, forEachInlineChild } = require("../helpers");
6
-
7
- module.exports = {
8
- "names": [ "MD045", "no-alt-text" ],
9
- "description": "Images should have alternate text (alt text)",
10
- "tags": [ "accessibility", "images" ],
11
- "function": function MD045(params, onError) {
12
- forEachInlineChild(params, "image", function forToken(token) {
13
- if (token.content === "") {
14
- addError(onError, token.lineNumber);
15
- }
16
- });
17
- }
18
- };
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addError, forEachInlineChild } = require("../helpers");
6
+
7
+ module.exports = {
8
+ "names": [ "MD045", "no-alt-text" ],
9
+ "description": "Images should have alternate text (alt text)",
10
+ "tags": [ "accessibility", "images" ],
11
+ "function": function MD045(params, onError) {
12
+ forEachInlineChild(params, "image", function forToken(token) {
13
+ if (token.content === "") {
14
+ addError(onError, token.lineNumber);
15
+ }
16
+ });
17
+ }
18
+ };
package/lib/md046.js CHANGED
@@ -1,32 +1,32 @@
1
- // @ts-check
2
-
3
- "use strict";
4
-
5
- const { addErrorDetailIf } = require("../helpers");
6
-
7
- const tokenTypeToStyle = {
8
- "fence": "fenced",
9
- "code_block": "indented"
10
- };
11
-
12
- module.exports = {
13
- "names": [ "MD046", "code-block-style" ],
14
- "description": "Code block style",
15
- "tags": [ "code" ],
16
- "function": function MD046(params, onError) {
17
- let expectedStyle = String(params.config.style || "consistent");
18
- params.tokens
19
- .filter((token) => token.type === "code_block" || token.type === "fence")
20
- .forEach((token) => {
21
- const { lineNumber, type } = token;
22
- if (expectedStyle === "consistent") {
23
- expectedStyle = tokenTypeToStyle[type];
24
- }
25
- addErrorDetailIf(
26
- onError,
27
- lineNumber,
28
- expectedStyle,
29
- tokenTypeToStyle[type]);
30
- });
31
- }
32
- };
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addErrorDetailIf } = require("../helpers");
6
+
7
+ const tokenTypeToStyle = {
8
+ "fence": "fenced",
9
+ "code_block": "indented"
10
+ };
11
+
12
+ module.exports = {
13
+ "names": [ "MD046", "code-block-style" ],
14
+ "description": "Code block style",
15
+ "tags": [ "code" ],
16
+ "function": function MD046(params, onError) {
17
+ let expectedStyle = String(params.config.style || "consistent");
18
+ params.tokens
19
+ .filter((token) => token.type === "code_block" || token.type === "fence")
20
+ .forEach((token) => {
21
+ const { lineNumber, type } = token;
22
+ if (expectedStyle === "consistent") {
23
+ expectedStyle = tokenTypeToStyle[type];
24
+ }
25
+ addErrorDetailIf(
26
+ onError,
27
+ lineNumber,
28
+ expectedStyle,
29
+ tokenTypeToStyle[type]);
30
+ });
31
+ }
32
+ };
package/lib/md047.js CHANGED
@@ -1,28 +1,28 @@
1
- // @ts-check
2
-
3
- "use strict";
4
-
5
- const { addError, isBlankLine } = require("../helpers");
6
-
7
- module.exports = {
8
- "names": [ "MD047", "single-trailing-newline" ],
9
- "description": "Files should end with a single newline character",
10
- "tags": [ "blank_lines" ],
11
- "function": function MD047(params, onError) {
12
- const lastLineNumber = params.lines.length;
13
- const lastLine = params.lines[lastLineNumber - 1];
14
- if (!isBlankLine(lastLine)) {
15
- addError(
16
- onError,
17
- lastLineNumber,
18
- null,
19
- null,
20
- [ lastLine.length, 1 ],
21
- {
22
- "insertText": "\n",
23
- "editColumn": lastLine.length + 1
24
- }
25
- );
26
- }
27
- }
28
- };
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addError, isBlankLine } = require("../helpers");
6
+
7
+ module.exports = {
8
+ "names": [ "MD047", "single-trailing-newline" ],
9
+ "description": "Files should end with a single newline character",
10
+ "tags": [ "blank_lines" ],
11
+ "function": function MD047(params, onError) {
12
+ const lastLineNumber = params.lines.length;
13
+ const lastLine = params.lines[lastLineNumber - 1];
14
+ if (!isBlankLine(lastLine)) {
15
+ addError(
16
+ onError,
17
+ lastLineNumber,
18
+ null,
19
+ null,
20
+ [ lastLine.length, 1 ],
21
+ {
22
+ "insertText": "\n",
23
+ "editColumn": lastLine.length + 1
24
+ }
25
+ );
26
+ }
27
+ }
28
+ };
package/lib/md048.js CHANGED
@@ -1,29 +1,29 @@
1
- // @ts-check
2
-
3
- "use strict";
4
-
5
- const { addErrorDetailIf, fencedCodeBlockStyleFor } = require("../helpers");
6
-
7
- module.exports = {
8
- "names": [ "MD048", "code-fence-style" ],
9
- "description": "Code fence style",
10
- "tags": [ "code" ],
11
- "function": function MD048(params, onError) {
12
- const style = String(params.config.style || "consistent");
13
- let expectedStyle = style;
14
- params.tokens
15
- .filter((token) => token.type === "fence")
16
- .forEach((fenceToken) => {
17
- const { lineNumber, markup } = fenceToken;
18
- if (expectedStyle === "consistent") {
19
- expectedStyle = fencedCodeBlockStyleFor(markup);
20
- }
21
- addErrorDetailIf(
22
- onError,
23
- lineNumber,
24
- expectedStyle,
25
- fencedCodeBlockStyleFor(markup)
26
- );
27
- });
28
- }
29
- };
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ const { addErrorDetailIf, fencedCodeBlockStyleFor } = require("../helpers");
6
+
7
+ module.exports = {
8
+ "names": [ "MD048", "code-fence-style" ],
9
+ "description": "Code fence style",
10
+ "tags": [ "code" ],
11
+ "function": function MD048(params, onError) {
12
+ const style = String(params.config.style || "consistent");
13
+ let expectedStyle = style;
14
+ params.tokens
15
+ .filter((token) => token.type === "fence")
16
+ .forEach((fenceToken) => {
17
+ const { lineNumber, markup } = fenceToken;
18
+ if (expectedStyle === "consistent") {
19
+ expectedStyle = fencedCodeBlockStyleFor(markup);
20
+ }
21
+ addErrorDetailIf(
22
+ onError,
23
+ lineNumber,
24
+ expectedStyle,
25
+ fencedCodeBlockStyleFor(markup)
26
+ );
27
+ });
28
+ }
29
+ };