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.
- package/CONTRIBUTING.md +50 -47
- package/LICENSE +21 -21
- package/README.md +915 -871
- package/demo/markdownlint-browser.js +4693 -5400
- package/doc/CustomRules.md +315 -313
- package/doc/Rules.md +1868 -1795
- package/helpers/LICENSE +21 -21
- package/helpers/README.md +50 -50
- package/helpers/helpers.js +690 -671
- package/helpers/package.json +18 -18
- package/lib/cache.js +24 -24
- package/lib/markdownlint.d.ts +365 -352
- package/lib/markdownlint.js +1186 -1101
- package/lib/md001.js +22 -22
- package/lib/md002.js +22 -22
- package/lib/md003.js +42 -42
- package/lib/md004.js +43 -43
- package/lib/md005.js +69 -69
- package/lib/md006.js +34 -34
- package/lib/md007.js +47 -47
- package/lib/md009.js +77 -77
- package/lib/md010.js +38 -38
- package/lib/md011.js +42 -38
- package/lib/md012.js +32 -32
- package/lib/md013.js +99 -99
- package/lib/md014.js +53 -53
- package/lib/md018.js +34 -34
- package/lib/md019.js +39 -39
- package/lib/md020.js +62 -62
- package/lib/md021.js +60 -60
- package/lib/md022.js +56 -56
- package/lib/md023.js +38 -38
- package/lib/md024.js +38 -38
- package/lib/md025.js +32 -32
- package/lib/md026.js +40 -40
- package/lib/md027.js +56 -56
- package/lib/md028.js +38 -38
- package/lib/md029.js +66 -66
- package/lib/md030.js +50 -50
- package/lib/md031.js +40 -39
- package/lib/md032.js +50 -50
- package/lib/md033.js +45 -45
- package/lib/md034.js +61 -61
- package/lib/md035.js +21 -21
- package/lib/md036.js +56 -56
- package/lib/md037.js +150 -141
- package/lib/md038.js +68 -68
- package/lib/md039.js +64 -64
- package/lib/md040.js +18 -18
- package/lib/md041.js +31 -31
- package/lib/md042.js +42 -41
- package/lib/md043.js +45 -45
- package/lib/md044.js +94 -71
- package/lib/md045.js +18 -18
- package/lib/md046.js +32 -32
- package/lib/md047.js +28 -28
- package/lib/md048.js +29 -29
- package/lib/rules.js +60 -61
- package/package.json +74 -67
- package/schema/build-config-schema.js +409 -405
- package/schema/markdownlint-config-schema.json +7 -2
- package/style/all.json +5 -5
- package/style/cirosantilli.json +22 -22
- package/style/relaxed.json +13 -13
package/lib/md037.js
CHANGED
|
@@ -1,141 +1,150 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
const { addErrorContext,
|
|
6
|
-
|
|
7
|
-
const { lineMetadata } = require("./cache");
|
|
8
|
-
|
|
9
|
-
const emphasisRe = /(^|[^\\])(?:(\*\*?\*?)|(__?_?))/g;
|
|
10
|
-
const asteriskListItemMarkerRe = /^(\s*)\*(\s+)/;
|
|
11
|
-
const leftSpaceRe = /^\s+/;
|
|
12
|
-
const rightSpaceRe = /\s+$/;
|
|
13
|
-
|
|
14
|
-
module.exports = {
|
|
15
|
-
"names": [ "MD037", "no-space-in-emphasis" ],
|
|
16
|
-
"description": "Spaces inside emphasis markers",
|
|
17
|
-
"tags": [ "whitespace", "emphasis" ],
|
|
18
|
-
"function": function MD037(params, onError) {
|
|
19
|
-
// eslint-disable-next-line init-declarations
|
|
20
|
-
let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength,
|
|
21
|
-
pendingError = null;
|
|
22
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
23
|
-
function resetRunTracking() {
|
|
24
|
-
emphasisIndex = -1;
|
|
25
|
-
emphasisLength = 0;
|
|
26
|
-
emphasisKind = "";
|
|
27
|
-
effectiveEmphasisLength = 0;
|
|
28
|
-
pendingError = null;
|
|
29
|
-
}
|
|
30
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
31
|
-
function handleRunEnd(line, lineIndex, contextLength, match, matchIndex) {
|
|
32
|
-
// Close current run
|
|
33
|
-
let content = line.substring(emphasisIndex, matchIndex);
|
|
34
|
-
if (!emphasisLength) {
|
|
35
|
-
content = content.
|
|
36
|
-
}
|
|
37
|
-
if (!match) {
|
|
38
|
-
content = content.
|
|
39
|
-
}
|
|
40
|
-
const leftSpace = leftSpaceRe.test(content);
|
|
41
|
-
const rightSpace = rightSpaceRe.test(content);
|
|
42
|
-
if (leftSpace || rightSpace) {
|
|
43
|
-
// Report the violation
|
|
44
|
-
const contextStart = emphasisIndex - emphasisLength;
|
|
45
|
-
const contextEnd = matchIndex + contextLength;
|
|
46
|
-
const context = line.substring(contextStart, contextEnd);
|
|
47
|
-
const column = contextStart + 1;
|
|
48
|
-
const length = contextEnd - contextStart;
|
|
49
|
-
const leftMarker = line.substring(contextStart, emphasisIndex);
|
|
50
|
-
const rightMarker = match ? (match[2] || match[3]) : "";
|
|
51
|
-
const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
|
|
52
|
-
return [
|
|
53
|
-
onError,
|
|
54
|
-
lineIndex + 1,
|
|
55
|
-
context,
|
|
56
|
-
leftSpace,
|
|
57
|
-
rightSpace,
|
|
58
|
-
[ column, length ],
|
|
59
|
-
{
|
|
60
|
-
"editColumn": column,
|
|
61
|
-
"deleteCount": length,
|
|
62
|
-
"insertText": fixedText
|
|
63
|
-
}
|
|
64
|
-
];
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
// Initialize
|
|
69
|
-
const ignoreMarkersByLine =
|
|
70
|
-
resetRunTracking();
|
|
71
|
-
forEachLine(
|
|
72
|
-
lineMetadata(),
|
|
73
|
-
(line, lineIndex, inCode, onFence, inTable, inItem, onBreak) => {
|
|
74
|
-
const onItemStart = (inItem === 1);
|
|
75
|
-
if (inCode || inTable || onBreak || onItemStart || isBlankLine(line)) {
|
|
76
|
-
// Emphasis resets when leaving a block
|
|
77
|
-
resetRunTracking();
|
|
78
|
-
}
|
|
79
|
-
if (inCode || onBreak) {
|
|
80
|
-
// Emphasis has no meaning here
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (onItemStart) {
|
|
84
|
-
// Trim overlapping '*' list item marker
|
|
85
|
-
line = line.replace(asteriskListItemMarkerRe, "$1 $2");
|
|
86
|
-
}
|
|
87
|
-
let match = null;
|
|
88
|
-
// Match all emphasis-looking runs in the line...
|
|
89
|
-
while ((match = emphasisRe.exec(line))) {
|
|
90
|
-
const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex] || [];
|
|
91
|
-
const matchIndex = match.index + match[1].length;
|
|
92
|
-
if (
|
|
93
|
-
// Ignore emphasis markers inside code spans
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
const matchLength = match[0].length - match[1].length;
|
|
97
|
-
const matchKind = (match[2] || match[3])[0];
|
|
98
|
-
if (emphasisIndex === -1) {
|
|
99
|
-
// New run
|
|
100
|
-
emphasisIndex = matchIndex + matchLength;
|
|
101
|
-
emphasisLength = matchLength;
|
|
102
|
-
emphasisKind = matchKind;
|
|
103
|
-
effectiveEmphasisLength = matchLength;
|
|
104
|
-
} else if (
|
|
105
|
-
|
|
106
|
-
(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
effectiveEmphasisLength
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine } =
|
|
6
|
+
require("../helpers");
|
|
7
|
+
const { lineMetadata } = require("./cache");
|
|
8
|
+
|
|
9
|
+
const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
|
|
10
|
+
const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
|
|
11
|
+
const leftSpaceRe = /^\s+/;
|
|
12
|
+
const rightSpaceRe = /\s+$/;
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
"names": [ "MD037", "no-space-in-emphasis" ],
|
|
16
|
+
"description": "Spaces inside emphasis markers",
|
|
17
|
+
"tags": [ "whitespace", "emphasis" ],
|
|
18
|
+
"function": function MD037(params, onError) {
|
|
19
|
+
// eslint-disable-next-line init-declarations
|
|
20
|
+
let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength,
|
|
21
|
+
pendingError = null;
|
|
22
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
23
|
+
function resetRunTracking() {
|
|
24
|
+
emphasisIndex = -1;
|
|
25
|
+
emphasisLength = 0;
|
|
26
|
+
emphasisKind = "";
|
|
27
|
+
effectiveEmphasisLength = 0;
|
|
28
|
+
pendingError = null;
|
|
29
|
+
}
|
|
30
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
31
|
+
function handleRunEnd(line, lineIndex, contextLength, match, matchIndex) {
|
|
32
|
+
// Close current run
|
|
33
|
+
let content = line.substring(emphasisIndex, matchIndex);
|
|
34
|
+
if (!emphasisLength) {
|
|
35
|
+
content = content.trimLeft();
|
|
36
|
+
}
|
|
37
|
+
if (!match) {
|
|
38
|
+
content = content.trimRight();
|
|
39
|
+
}
|
|
40
|
+
const leftSpace = leftSpaceRe.test(content);
|
|
41
|
+
const rightSpace = rightSpaceRe.test(content);
|
|
42
|
+
if (leftSpace || rightSpace) {
|
|
43
|
+
// Report the violation
|
|
44
|
+
const contextStart = emphasisIndex - emphasisLength;
|
|
45
|
+
const contextEnd = matchIndex + contextLength;
|
|
46
|
+
const context = line.substring(contextStart, contextEnd);
|
|
47
|
+
const column = contextStart + 1;
|
|
48
|
+
const length = contextEnd - contextStart;
|
|
49
|
+
const leftMarker = line.substring(contextStart, emphasisIndex);
|
|
50
|
+
const rightMarker = match ? (match[2] || match[3]) : "";
|
|
51
|
+
const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
|
|
52
|
+
return [
|
|
53
|
+
onError,
|
|
54
|
+
lineIndex + 1,
|
|
55
|
+
context,
|
|
56
|
+
leftSpace,
|
|
57
|
+
rightSpace,
|
|
58
|
+
[ column, length ],
|
|
59
|
+
{
|
|
60
|
+
"editColumn": column,
|
|
61
|
+
"deleteCount": length,
|
|
62
|
+
"insertText": fixedText
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
// Initialize
|
|
69
|
+
const ignoreMarkersByLine = emphasisMarkersInContent(params);
|
|
70
|
+
resetRunTracking();
|
|
71
|
+
forEachLine(
|
|
72
|
+
lineMetadata(),
|
|
73
|
+
(line, lineIndex, inCode, onFence, inTable, inItem, onBreak) => {
|
|
74
|
+
const onItemStart = (inItem === 1);
|
|
75
|
+
if (inCode || inTable || onBreak || onItemStart || isBlankLine(line)) {
|
|
76
|
+
// Emphasis resets when leaving a block
|
|
77
|
+
resetRunTracking();
|
|
78
|
+
}
|
|
79
|
+
if (inCode || onBreak) {
|
|
80
|
+
// Emphasis has no meaning here
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (onItemStart) {
|
|
84
|
+
// Trim overlapping '*' list item marker
|
|
85
|
+
line = line.replace(asteriskListItemMarkerRe, "$1 $2");
|
|
86
|
+
}
|
|
87
|
+
let match = null;
|
|
88
|
+
// Match all emphasis-looking runs in the line...
|
|
89
|
+
while ((match = emphasisRe.exec(line))) {
|
|
90
|
+
const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex] || [];
|
|
91
|
+
const matchIndex = match.index + match[1].length;
|
|
92
|
+
if (ignoreMarkersForLine.includes(matchIndex)) {
|
|
93
|
+
// Ignore emphasis markers inside code spans and links
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const matchLength = match[0].length - match[1].length;
|
|
97
|
+
const matchKind = (match[2] || match[3])[0];
|
|
98
|
+
if (emphasisIndex === -1) {
|
|
99
|
+
// New run
|
|
100
|
+
emphasisIndex = matchIndex + matchLength;
|
|
101
|
+
emphasisLength = matchLength;
|
|
102
|
+
emphasisKind = matchKind;
|
|
103
|
+
effectiveEmphasisLength = matchLength;
|
|
104
|
+
} else if (matchKind === emphasisKind) {
|
|
105
|
+
// Matching emphasis markers
|
|
106
|
+
if (matchLength === effectiveEmphasisLength) {
|
|
107
|
+
// Ending an existing run, report any pending error
|
|
108
|
+
if (pendingError) {
|
|
109
|
+
addErrorContext(...pendingError);
|
|
110
|
+
pendingError = null;
|
|
111
|
+
}
|
|
112
|
+
const error = handleRunEnd(
|
|
113
|
+
line, lineIndex, effectiveEmphasisLength, match, matchIndex);
|
|
114
|
+
if (error) {
|
|
115
|
+
addErrorContext(...error);
|
|
116
|
+
}
|
|
117
|
+
// Reset
|
|
118
|
+
resetRunTracking();
|
|
119
|
+
} else if (matchLength === 3) {
|
|
120
|
+
// Swap internal run length (1->2 or 2->1)
|
|
121
|
+
effectiveEmphasisLength = matchLength - effectiveEmphasisLength;
|
|
122
|
+
} else if (effectiveEmphasisLength === 3) {
|
|
123
|
+
// Downgrade internal run (3->1 or 3->2)
|
|
124
|
+
effectiveEmphasisLength -= matchLength;
|
|
125
|
+
} else {
|
|
126
|
+
// Upgrade to internal run (1->3 or 2->3)
|
|
127
|
+
effectiveEmphasisLength += matchLength;
|
|
128
|
+
}
|
|
129
|
+
// Back up one character so RegExp has a chance to match the
|
|
130
|
+
// next marker (ex: "**star**_underscore_")
|
|
131
|
+
if (emphasisRe.lastIndex > 1) {
|
|
132
|
+
emphasisRe.lastIndex--;
|
|
133
|
+
}
|
|
134
|
+
} else if (emphasisRe.lastIndex > 1) {
|
|
135
|
+
// Back up one character so RegExp has a chance to match the
|
|
136
|
+
// mis-matched marker (ex: "*text_*")
|
|
137
|
+
emphasisRe.lastIndex--;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (emphasisIndex !== -1) {
|
|
141
|
+
pendingError = pendingError ||
|
|
142
|
+
handleRunEnd(line, lineIndex, 0, null, line.length);
|
|
143
|
+
// Adjust for pending run on new line
|
|
144
|
+
emphasisIndex = 0;
|
|
145
|
+
emphasisLength = 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
};
|
package/lib/md038.js
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } =
|
|
6
|
-
require("../helpers");
|
|
7
|
-
|
|
8
|
-
const leftSpaceRe = /^\s([^`]|$)/;
|
|
9
|
-
const rightSpaceRe = /[^`]\s$/;
|
|
10
|
-
const singleLeftRightSpaceRe = /^\s(?:\S.*\S|\S)\s$/;
|
|
11
|
-
|
|
12
|
-
module.exports = {
|
|
13
|
-
"names": [ "MD038", "no-space-in-code" ],
|
|
14
|
-
"description": "Spaces inside code span elements",
|
|
15
|
-
"tags": [ "whitespace", "code" ],
|
|
16
|
-
"function": function MD038(params, onError) {
|
|
17
|
-
filterTokens(params, "inline", (token) => {
|
|
18
|
-
if (token.children.some((child) => child.type === "code_inline")) {
|
|
19
|
-
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
|
20
|
-
forEachInlineCodeSpan(
|
|
21
|
-
tokenLines.join("\n"),
|
|
22
|
-
(code, lineIndex, columnIndex, tickCount) => {
|
|
23
|
-
let rangeIndex = columnIndex - tickCount;
|
|
24
|
-
let rangeLength = code.length + (2 * tickCount);
|
|
25
|
-
let rangeLineOffset = 0;
|
|
26
|
-
let fixIndex = columnIndex;
|
|
27
|
-
let fixLength = code.length;
|
|
28
|
-
const codeLines = code.split(newLineRe);
|
|
29
|
-
const left = leftSpaceRe.test(code);
|
|
30
|
-
const right = !left && rightSpaceRe.test(code);
|
|
31
|
-
if (right && (codeLines.length > 1)) {
|
|
32
|
-
rangeIndex = 0;
|
|
33
|
-
rangeLineOffset = codeLines.length - 1;
|
|
34
|
-
fixIndex = 0;
|
|
35
|
-
}
|
|
36
|
-
const allowed = singleLeftRightSpaceRe.test(code);
|
|
37
|
-
if ((left || right) && !allowed) {
|
|
38
|
-
const codeLinesRange = codeLines[rangeLineOffset];
|
|
39
|
-
if (codeLines.length > 1) {
|
|
40
|
-
rangeLength = codeLinesRange.length + tickCount;
|
|
41
|
-
fixLength = codeLinesRange.length;
|
|
42
|
-
}
|
|
43
|
-
const context = tokenLines[lineIndex + rangeLineOffset]
|
|
44
|
-
.substring(rangeIndex, rangeIndex + rangeLength);
|
|
45
|
-
const codeLinesRangeTrim = codeLinesRange.trim();
|
|
46
|
-
const fixText =
|
|
47
|
-
(codeLinesRangeTrim.startsWith("`") ? " " : "") +
|
|
48
|
-
codeLinesRangeTrim +
|
|
49
|
-
(codeLinesRangeTrim.endsWith("`") ? " " : "");
|
|
50
|
-
addErrorContext(
|
|
51
|
-
onError,
|
|
52
|
-
token.lineNumber + lineIndex + rangeLineOffset,
|
|
53
|
-
context,
|
|
54
|
-
left,
|
|
55
|
-
right,
|
|
56
|
-
[ rangeIndex + 1, rangeLength ],
|
|
57
|
-
{
|
|
58
|
-
"editColumn": fixIndex + 1,
|
|
59
|
-
"deleteCount": fixLength,
|
|
60
|
-
"insertText": fixText
|
|
61
|
-
}
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
};
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } =
|
|
6
|
+
require("../helpers");
|
|
7
|
+
|
|
8
|
+
const leftSpaceRe = /^\s([^`]|$)/;
|
|
9
|
+
const rightSpaceRe = /[^`]\s$/;
|
|
10
|
+
const singleLeftRightSpaceRe = /^\s(?:\S.*\S|\S)\s$/;
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
"names": [ "MD038", "no-space-in-code" ],
|
|
14
|
+
"description": "Spaces inside code span elements",
|
|
15
|
+
"tags": [ "whitespace", "code" ],
|
|
16
|
+
"function": function MD038(params, onError) {
|
|
17
|
+
filterTokens(params, "inline", (token) => {
|
|
18
|
+
if (token.children.some((child) => child.type === "code_inline")) {
|
|
19
|
+
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
|
20
|
+
forEachInlineCodeSpan(
|
|
21
|
+
tokenLines.join("\n"),
|
|
22
|
+
(code, lineIndex, columnIndex, tickCount) => {
|
|
23
|
+
let rangeIndex = columnIndex - tickCount;
|
|
24
|
+
let rangeLength = code.length + (2 * tickCount);
|
|
25
|
+
let rangeLineOffset = 0;
|
|
26
|
+
let fixIndex = columnIndex;
|
|
27
|
+
let fixLength = code.length;
|
|
28
|
+
const codeLines = code.split(newLineRe);
|
|
29
|
+
const left = leftSpaceRe.test(code);
|
|
30
|
+
const right = !left && rightSpaceRe.test(code);
|
|
31
|
+
if (right && (codeLines.length > 1)) {
|
|
32
|
+
rangeIndex = 0;
|
|
33
|
+
rangeLineOffset = codeLines.length - 1;
|
|
34
|
+
fixIndex = 0;
|
|
35
|
+
}
|
|
36
|
+
const allowed = singleLeftRightSpaceRe.test(code);
|
|
37
|
+
if ((left || right) && !allowed) {
|
|
38
|
+
const codeLinesRange = codeLines[rangeLineOffset];
|
|
39
|
+
if (codeLines.length > 1) {
|
|
40
|
+
rangeLength = codeLinesRange.length + tickCount;
|
|
41
|
+
fixLength = codeLinesRange.length;
|
|
42
|
+
}
|
|
43
|
+
const context = tokenLines[lineIndex + rangeLineOffset]
|
|
44
|
+
.substring(rangeIndex, rangeIndex + rangeLength);
|
|
45
|
+
const codeLinesRangeTrim = codeLinesRange.trim();
|
|
46
|
+
const fixText =
|
|
47
|
+
(codeLinesRangeTrim.startsWith("`") ? " " : "") +
|
|
48
|
+
codeLinesRangeTrim +
|
|
49
|
+
(codeLinesRangeTrim.endsWith("`") ? " " : "");
|
|
50
|
+
addErrorContext(
|
|
51
|
+
onError,
|
|
52
|
+
token.lineNumber + lineIndex + rangeLineOffset,
|
|
53
|
+
context,
|
|
54
|
+
left,
|
|
55
|
+
right,
|
|
56
|
+
[ rangeIndex + 1, rangeLength ],
|
|
57
|
+
{
|
|
58
|
+
"editColumn": fixIndex + 1,
|
|
59
|
+
"deleteCount": fixLength,
|
|
60
|
+
"insertText": fixText
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
package/lib/md039.js
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
const { addErrorContext, filterTokens } = require("../helpers");
|
|
6
|
-
|
|
7
|
-
const spaceInLinkRe = /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=\(\S*\))/;
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
"names": [ "MD039", "no-space-in-links" ],
|
|
11
|
-
"description": "Spaces inside link text",
|
|
12
|
-
"tags": [ "whitespace", "links" ],
|
|
13
|
-
"function": function MD039(params, onError) {
|
|
14
|
-
filterTokens(params, "inline", (token) => {
|
|
15
|
-
const { children } = token;
|
|
16
|
-
let { lineNumber } = token;
|
|
17
|
-
let inLink = false;
|
|
18
|
-
let linkText = "";
|
|
19
|
-
let lineIndex = 0;
|
|
20
|
-
children.forEach((child) => {
|
|
21
|
-
const { content, type } = child;
|
|
22
|
-
if (type === "link_open") {
|
|
23
|
-
inLink = true;
|
|
24
|
-
linkText = "";
|
|
25
|
-
} else if (type === "link_close") {
|
|
26
|
-
inLink = false;
|
|
27
|
-
const left = linkText.trimLeft().length !== linkText.length;
|
|
28
|
-
const right = linkText.trimRight().length !== linkText.length;
|
|
29
|
-
if (left || right) {
|
|
30
|
-
const line = params.lines[lineNumber - 1];
|
|
31
|
-
let range = null;
|
|
32
|
-
let fixInfo = null;
|
|
33
|
-
const match = line.slice(lineIndex).match(spaceInLinkRe);
|
|
34
|
-
if (match) {
|
|
35
|
-
const column = match.index + lineIndex + 1;
|
|
36
|
-
const length = match[0].length;
|
|
37
|
-
range = [ column, length ];
|
|
38
|
-
fixInfo = {
|
|
39
|
-
"editColumn": column + 1,
|
|
40
|
-
"deleteCount": length - 2,
|
|
41
|
-
"insertText": linkText.trim()
|
|
42
|
-
};
|
|
43
|
-
lineIndex = column + length - 1;
|
|
44
|
-
}
|
|
45
|
-
addErrorContext(
|
|
46
|
-
onError,
|
|
47
|
-
lineNumber,
|
|
48
|
-
`[${linkText}]`,
|
|
49
|
-
left,
|
|
50
|
-
right,
|
|
51
|
-
range,
|
|
52
|
-
fixInfo
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
} else if ((type === "softbreak") || (type === "hardbreak")) {
|
|
56
|
-
lineNumber++;
|
|
57
|
-
lineIndex = 0;
|
|
58
|
-
} else if (inLink) {
|
|
59
|
-
linkText += content;
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
};
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { addErrorContext, filterTokens } = require("../helpers");
|
|
6
|
+
|
|
7
|
+
const spaceInLinkRe = /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=\(\S*\))/;
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
"names": [ "MD039", "no-space-in-links" ],
|
|
11
|
+
"description": "Spaces inside link text",
|
|
12
|
+
"tags": [ "whitespace", "links" ],
|
|
13
|
+
"function": function MD039(params, onError) {
|
|
14
|
+
filterTokens(params, "inline", (token) => {
|
|
15
|
+
const { children } = token;
|
|
16
|
+
let { lineNumber } = token;
|
|
17
|
+
let inLink = false;
|
|
18
|
+
let linkText = "";
|
|
19
|
+
let lineIndex = 0;
|
|
20
|
+
children.forEach((child) => {
|
|
21
|
+
const { content, type } = child;
|
|
22
|
+
if (type === "link_open") {
|
|
23
|
+
inLink = true;
|
|
24
|
+
linkText = "";
|
|
25
|
+
} else if (type === "link_close") {
|
|
26
|
+
inLink = false;
|
|
27
|
+
const left = linkText.trimLeft().length !== linkText.length;
|
|
28
|
+
const right = linkText.trimRight().length !== linkText.length;
|
|
29
|
+
if (left || right) {
|
|
30
|
+
const line = params.lines[lineNumber - 1];
|
|
31
|
+
let range = null;
|
|
32
|
+
let fixInfo = null;
|
|
33
|
+
const match = line.slice(lineIndex).match(spaceInLinkRe);
|
|
34
|
+
if (match) {
|
|
35
|
+
const column = match.index + lineIndex + 1;
|
|
36
|
+
const length = match[0].length;
|
|
37
|
+
range = [ column, length ];
|
|
38
|
+
fixInfo = {
|
|
39
|
+
"editColumn": column + 1,
|
|
40
|
+
"deleteCount": length - 2,
|
|
41
|
+
"insertText": linkText.trim()
|
|
42
|
+
};
|
|
43
|
+
lineIndex = column + length - 1;
|
|
44
|
+
}
|
|
45
|
+
addErrorContext(
|
|
46
|
+
onError,
|
|
47
|
+
lineNumber,
|
|
48
|
+
`[${linkText}]`,
|
|
49
|
+
left,
|
|
50
|
+
right,
|
|
51
|
+
range,
|
|
52
|
+
fixInfo
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
} else if ((type === "softbreak") || (type === "hardbreak")) {
|
|
56
|
+
lineNumber++;
|
|
57
|
+
lineIndex = 0;
|
|
58
|
+
} else if (inLink) {
|
|
59
|
+
linkText += content;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
package/lib/md040.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
const { addErrorContext, filterTokens } = require("../helpers");
|
|
6
|
-
|
|
7
|
-
module.exports = {
|
|
8
|
-
"names": [ "MD040", "fenced-code-language" ],
|
|
9
|
-
"description": "Fenced code blocks should have a language specified",
|
|
10
|
-
"tags": [ "code", "language" ],
|
|
11
|
-
"function": function MD040(params, onError) {
|
|
12
|
-
filterTokens(params, "fence", function forToken(token) {
|
|
13
|
-
if (!token.info.trim()) {
|
|
14
|
-
addErrorContext(onError, token.lineNumber, token.line);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
};
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { addErrorContext, filterTokens } = require("../helpers");
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
"names": [ "MD040", "fenced-code-language" ],
|
|
9
|
+
"description": "Fenced code blocks should have a language specified",
|
|
10
|
+
"tags": [ "code", "language" ],
|
|
11
|
+
"function": function MD040(params, onError) {
|
|
12
|
+
filterTokens(params, "fence", function forToken(token) {
|
|
13
|
+
if (!token.info.trim()) {
|
|
14
|
+
addErrorContext(onError, token.lineNumber, token.line);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
};
|
package/lib/md041.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
const { addErrorContext, frontMatterHasTitle } = require("../helpers");
|
|
6
|
-
|
|
7
|
-
module.exports = {
|
|
8
|
-
"names": [ "MD041", "first-line-heading", "first-line-h1" ],
|
|
9
|
-
"description": "First line in file should be a top level heading",
|
|
10
|
-
"tags": [ "headings", "headers" ],
|
|
11
|
-
"function": function MD041(params, onError) {
|
|
12
|
-
const level = Number(params.config.level || 1);
|
|
13
|
-
const tag = "h" + level;
|
|
14
|
-
const foundFrontMatterTitle =
|
|
15
|
-
frontMatterHasTitle(
|
|
16
|
-
params.frontMatterLines,
|
|
17
|
-
params.config.front_matter_title
|
|
18
|
-
);
|
|
19
|
-
if (!foundFrontMatterTitle) {
|
|
20
|
-
params.tokens.every((token) => {
|
|
21
|
-
if (token.type === "html_block") {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
if ((token.type !== "heading_open") || (token.tag !== tag)) {
|
|
25
|
-
addErrorContext(onError, token.lineNumber, token.line);
|
|
26
|
-
}
|
|
27
|
-
return false;
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
};
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { addErrorContext, frontMatterHasTitle } = require("../helpers");
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
"names": [ "MD041", "first-line-heading", "first-line-h1" ],
|
|
9
|
+
"description": "First line in file should be a top level heading",
|
|
10
|
+
"tags": [ "headings", "headers" ],
|
|
11
|
+
"function": function MD041(params, onError) {
|
|
12
|
+
const level = Number(params.config.level || 1);
|
|
13
|
+
const tag = "h" + level;
|
|
14
|
+
const foundFrontMatterTitle =
|
|
15
|
+
frontMatterHasTitle(
|
|
16
|
+
params.frontMatterLines,
|
|
17
|
+
params.config.front_matter_title
|
|
18
|
+
);
|
|
19
|
+
if (!foundFrontMatterTitle) {
|
|
20
|
+
params.tokens.every((token) => {
|
|
21
|
+
if (token.type === "html_block") {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if ((token.type !== "heading_open") || (token.tag !== tag)) {
|
|
25
|
+
addErrorContext(onError, token.lineNumber, token.line);
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|