markdownlint 0.21.0 → 0.23.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 +1 -0
- package/LICENSE +1 -1
- package/README.md +106 -70
- package/demo/markdownlint-browser.js +1037 -1600
- package/doc/Rules.md +106 -76
- package/helpers/LICENSE +1 -1
- package/helpers/helpers.js +83 -33
- package/helpers/package.json +1 -1
- package/lib/markdownlint.d.ts +11 -5
- package/lib/markdownlint.js +102 -38
- package/lib/md002.js +1 -1
- package/lib/md004.js +46 -13
- package/lib/md006.js +1 -1
- package/lib/md009.js +25 -23
- package/lib/md011.js +10 -6
- package/lib/md018.js +1 -1
- package/lib/md019.js +1 -1
- package/lib/md020.js +1 -1
- package/lib/md021.js +1 -1
- package/lib/md023.js +1 -1
- package/lib/md025.js +1 -1
- package/lib/md026.js +7 -4
- package/lib/md028.js +1 -9
- package/lib/md031.js +6 -5
- package/lib/md032.js +2 -2
- package/lib/md037.js +22 -8
- package/lib/md039.js +2 -2
- package/lib/md041.js +14 -3
- package/lib/md043.js +22 -11
- package/lib/rules.js +2 -1
- package/package.json +32 -33
- package/schema/.markdownlint.jsonc +250 -0
- package/schema/.markdownlint.yaml +225 -0
- package/schema/markdownlint-config-schema.json +23 -20
- package/schema/build-config-schema.js +0 -410
package/helpers/helpers.js
CHANGED
|
@@ -12,12 +12,12 @@ module.exports.newLineRe = newLineRe;
|
|
|
12
12
|
// Regular expression for matching common front matter (YAML and TOML)
|
|
13
13
|
module.exports.frontMatterRe =
|
|
14
14
|
// eslint-disable-next-line max-len
|
|
15
|
-
/((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$))(\r\n|\r|\n|$)/m;
|
|
15
|
+
/((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m;
|
|
16
16
|
|
|
17
17
|
// Regular expression for matching inline disable/enable comments
|
|
18
18
|
const inlineCommentRe =
|
|
19
19
|
// eslint-disable-next-line max-len
|
|
20
|
-
/<!--\s*markdownlint-(?:(?:(disable|enable|capture|restore|disable-file|enable-file)((?:\s+[a-z0-9_-]+)*))|(?:(configure-file)\s+([\s\S]*?)))\s*-->/ig;
|
|
20
|
+
/<!--\s*markdownlint-(?:(?:(disable|enable|capture|restore|disable-file|enable-file|disable-next-line)((?:\s+[a-z0-9_-]+)*))|(?:(configure-file)\s+([\s\S]*?)))\s*-->/ig;
|
|
21
21
|
module.exports.inlineCommentRe = inlineCommentRe;
|
|
22
22
|
|
|
23
23
|
// Regular expressions for range matching
|
|
@@ -35,7 +35,11 @@ const linkRe = /\[(?:[^[\]]|\[[^\]]*\])*\](?:\(\S*\))?/g;
|
|
|
35
35
|
module.exports.utf8Encoding = "utf8";
|
|
36
36
|
|
|
37
37
|
// All punctuation characters (normal and full-width)
|
|
38
|
-
|
|
38
|
+
const allPunctuation = ".,;:!?。,;:!?";
|
|
39
|
+
module.exports.allPunctuation = allPunctuation;
|
|
40
|
+
|
|
41
|
+
// All punctuation characters without question mark (normal and full-width)
|
|
42
|
+
module.exports.allPunctuationNoQuestion = allPunctuation.replace(/[??]/gu, "");
|
|
39
43
|
|
|
40
44
|
// Returns true iff the input is a number
|
|
41
45
|
module.exports.isNumber = function isNumber(obj) {
|
|
@@ -61,6 +65,8 @@ module.exports.isObject = function isObject(obj) {
|
|
|
61
65
|
// Example: Contains nothing, whitespace, or comments
|
|
62
66
|
const blankLineRe = />|(?:<!--.*?-->)/g;
|
|
63
67
|
module.exports.isBlankLine = function isBlankLine(line) {
|
|
68
|
+
// Call to String.replace follows best practices and is not a security check
|
|
69
|
+
// False-positive for js/incomplete-multi-character-sanitization
|
|
64
70
|
return !line || !line.trim() || !line.replace(blankLineRe, "").trim();
|
|
65
71
|
};
|
|
66
72
|
|
|
@@ -93,32 +99,47 @@ module.exports.includesSorted = function includesSorted(array, element) {
|
|
|
93
99
|
return false;
|
|
94
100
|
};
|
|
95
101
|
|
|
96
|
-
// Replaces the
|
|
102
|
+
// Replaces the content of properly-formatted CommonMark comments with "."
|
|
97
103
|
// This preserves the line/column information for the rest of the document
|
|
98
|
-
//
|
|
99
|
-
//
|
|
104
|
+
// https://spec.commonmark.org/0.29/#html-blocks
|
|
105
|
+
// https://spec.commonmark.org/0.29/#html-comment
|
|
100
106
|
const htmlCommentBegin = "<!--";
|
|
101
107
|
const htmlCommentEnd = "-->";
|
|
102
108
|
module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
|
|
103
109
|
let i = 0;
|
|
104
110
|
while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
|
|
105
|
-
const j = text.indexOf(htmlCommentEnd, i);
|
|
111
|
+
const j = text.indexOf(htmlCommentEnd, i + 2);
|
|
106
112
|
if (j === -1) {
|
|
107
113
|
// Un-terminated comments are treated as text
|
|
108
114
|
break;
|
|
109
115
|
}
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
// If the comment has content...
|
|
117
|
+
if (j > i + htmlCommentBegin.length) {
|
|
118
|
+
let k = i - 1;
|
|
119
|
+
while (text[k] === " ") {
|
|
120
|
+
k--;
|
|
121
|
+
}
|
|
122
|
+
// If comment is not within an indented code block...
|
|
123
|
+
if (k >= i - 4) {
|
|
124
|
+
const content = text.slice(i + htmlCommentBegin.length, j);
|
|
125
|
+
const isBlock = (k < 0) || (text[k] === "\n");
|
|
126
|
+
const isValid = isBlock ||
|
|
127
|
+
(!content.startsWith(">") && !content.startsWith("->") &&
|
|
128
|
+
!content.endsWith("-") && !content.includes("--"));
|
|
129
|
+
// If a valid block/inline comment...
|
|
130
|
+
if (isValid) {
|
|
131
|
+
const inlineCommentIndex = text
|
|
132
|
+
.slice(i, j + htmlCommentEnd.length)
|
|
133
|
+
.search(inlineCommentRe);
|
|
134
|
+
// If not a markdownlint inline directive...
|
|
135
|
+
if (inlineCommentIndex === -1) {
|
|
136
|
+
text =
|
|
137
|
+
text.slice(0, i + htmlCommentBegin.length) +
|
|
138
|
+
content.replace(/[^\r\n]/g, ".") +
|
|
139
|
+
text.slice(j);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
122
143
|
}
|
|
123
144
|
i = j + htmlCommentEnd.length;
|
|
124
145
|
}
|
|
@@ -167,7 +188,7 @@ module.exports.fencedCodeBlockStyleFor =
|
|
|
167
188
|
*/
|
|
168
189
|
function indentFor(token) {
|
|
169
190
|
const line = token.line.replace(/^[\s>]*(> |>)/, "");
|
|
170
|
-
return line.length - line.
|
|
191
|
+
return line.length - line.trimStart().length;
|
|
171
192
|
}
|
|
172
193
|
module.exports.indentFor = indentFor;
|
|
173
194
|
|
|
@@ -217,45 +238,65 @@ function filterTokens(params, type, handler) {
|
|
|
217
238
|
}
|
|
218
239
|
module.exports.filterTokens = filterTokens;
|
|
219
240
|
|
|
241
|
+
/**
|
|
242
|
+
* Returns whether a token is a math block (created by markdown-it-texmath).
|
|
243
|
+
*
|
|
244
|
+
* @param {Object} token MarkdownItToken instance.
|
|
245
|
+
* @returns {boolean} True iff token is a math block.
|
|
246
|
+
*/
|
|
247
|
+
function isMathBlock(token) {
|
|
248
|
+
return (
|
|
249
|
+
(token.tag === "math") &&
|
|
250
|
+
token.type.startsWith("math_block") &&
|
|
251
|
+
!token.type.endsWith("_end")
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
220
255
|
// Get line metadata array
|
|
221
256
|
module.exports.getLineMetadata = function getLineMetadata(params) {
|
|
222
|
-
const lineMetadata = params.lines.map(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
filterTokens(params, "fence",
|
|
257
|
+
const lineMetadata = params.lines.map(
|
|
258
|
+
(line, index) => [ line, index, false, 0, false, false, false, false ]
|
|
259
|
+
);
|
|
260
|
+
filterTokens(params, "fence", (token) => {
|
|
226
261
|
lineMetadata[token.map[0]][3] = 1;
|
|
227
262
|
lineMetadata[token.map[1] - 1][3] = -1;
|
|
228
263
|
for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) {
|
|
229
264
|
lineMetadata[i][2] = true;
|
|
230
265
|
}
|
|
231
266
|
});
|
|
232
|
-
filterTokens(params, "code_block",
|
|
267
|
+
filterTokens(params, "code_block", (token) => {
|
|
233
268
|
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
234
269
|
lineMetadata[i][2] = true;
|
|
235
270
|
}
|
|
236
271
|
});
|
|
237
|
-
filterTokens(params, "table_open",
|
|
272
|
+
filterTokens(params, "table_open", (token) => {
|
|
238
273
|
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
239
274
|
lineMetadata[i][4] = true;
|
|
240
275
|
}
|
|
241
276
|
});
|
|
242
|
-
filterTokens(params, "list_item_open",
|
|
277
|
+
filterTokens(params, "list_item_open", (token) => {
|
|
243
278
|
let count = 1;
|
|
244
279
|
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
245
280
|
lineMetadata[i][5] = count;
|
|
246
281
|
count++;
|
|
247
282
|
}
|
|
248
283
|
});
|
|
249
|
-
filterTokens(params, "hr",
|
|
284
|
+
filterTokens(params, "hr", (token) => {
|
|
250
285
|
lineMetadata[token.map[0]][6] = true;
|
|
251
286
|
});
|
|
287
|
+
params.tokens.filter(isMathBlock).forEach((token) => {
|
|
288
|
+
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
289
|
+
lineMetadata[i][7] = true;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
252
292
|
return lineMetadata;
|
|
253
293
|
};
|
|
254
294
|
|
|
255
295
|
// Calls the provided function for each line (with context)
|
|
256
296
|
module.exports.forEachLine = function forEachLine(lineMetadata, handler) {
|
|
257
297
|
lineMetadata.forEach(function forMetadata(metadata) {
|
|
258
|
-
// Parameters:
|
|
298
|
+
// Parameters:
|
|
299
|
+
// line, lineIndex, inCode, onFence, inTable, inItem, inBreak, inMath
|
|
259
300
|
handler(...metadata);
|
|
260
301
|
});
|
|
261
302
|
};
|
|
@@ -268,7 +309,11 @@ module.exports.flattenLists = function flattenLists(params) {
|
|
|
268
309
|
let nesting = 0;
|
|
269
310
|
const nestingStack = [];
|
|
270
311
|
let lastWithMap = { "map": [ 0, 1 ] };
|
|
271
|
-
params.tokens.forEach(
|
|
312
|
+
params.tokens.forEach((token) => {
|
|
313
|
+
if (isMathBlock(token) && token.map[1]) {
|
|
314
|
+
// markdown-it-texmath plugin does not account for math_block_end
|
|
315
|
+
token.map[1]++;
|
|
316
|
+
}
|
|
272
317
|
if ((token.type === "bullet_list_open") ||
|
|
273
318
|
(token.type === "ordered_list_open")) {
|
|
274
319
|
// Save current context and start a new one
|
|
@@ -355,6 +400,7 @@ function forEachInlineCodeSpan(input, handler) {
|
|
|
355
400
|
let currentTicks = 0;
|
|
356
401
|
let state = "normal";
|
|
357
402
|
// Deliberate <= so trailing 0 completes the last span (ex: "text `code`")
|
|
403
|
+
// False-positive for js/index-out-of-bounds
|
|
358
404
|
for (; index <= input.length; index++) {
|
|
359
405
|
const char = input[index];
|
|
360
406
|
// Ignore backticks in link destination
|
|
@@ -491,7 +537,10 @@ module.exports.frontMatterHasTitle =
|
|
|
491
537
|
const ignoreFrontMatter =
|
|
492
538
|
(frontMatterTitlePattern !== undefined) && !frontMatterTitlePattern;
|
|
493
539
|
const frontMatterTitleRe =
|
|
494
|
-
new RegExp(
|
|
540
|
+
new RegExp(
|
|
541
|
+
String(frontMatterTitlePattern || "^\\s*\"?title\"?\\s*[:=]"),
|
|
542
|
+
"i"
|
|
543
|
+
);
|
|
495
544
|
return !ignoreFrontMatter &&
|
|
496
545
|
frontMatterLines.some((line) => frontMatterTitleRe.test(line));
|
|
497
546
|
};
|
|
@@ -674,8 +723,9 @@ module.exports.applyFixes = function applyFixes(input, errors) {
|
|
|
674
723
|
const editIndex = editColumn - 1;
|
|
675
724
|
if (
|
|
676
725
|
(lineIndex !== lastLineIndex) ||
|
|
677
|
-
(
|
|
678
|
-
(
|
|
726
|
+
(deleteCount === -1) ||
|
|
727
|
+
((editIndex + deleteCount) <=
|
|
728
|
+
(lastEditIndex - ((deleteCount > 0) ? 0 : 1)))
|
|
679
729
|
) {
|
|
680
730
|
lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding);
|
|
681
731
|
}
|
package/helpers/package.json
CHANGED
package/lib/markdownlint.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export = markdownlint;
|
|
|
8
8
|
*/
|
|
9
9
|
declare function markdownlint(options: Options, callback: LintCallback): void;
|
|
10
10
|
declare namespace markdownlint {
|
|
11
|
-
export { markdownlintSync as sync, readConfig, readConfigSync, promises, RuleFunction, RuleParams, MarkdownItToken, RuleOnError, RuleOnErrorInfo, RuleOnErrorFixInfo, Rule, Options, Plugin, ToStringCallback, LintResults, LintError, FixInfo, LintCallback, Configuration, RuleConfiguration, ConfigurationParser, ReadConfigCallback };
|
|
11
|
+
export { markdownlintSync as sync, readConfig, readConfigSync, getVersion, promises, RuleFunction, RuleParams, MarkdownItToken, RuleOnError, RuleOnErrorInfo, RuleOnErrorFixInfo, Rule, Options, Plugin, ToStringCallback, LintResults, LintError, FixInfo, LintCallback, Configuration, RuleConfiguration, ConfigurationParser, ReadConfigCallback };
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Configuration options.
|
|
@@ -51,7 +51,7 @@ type Options = {
|
|
|
51
51
|
/**
|
|
52
52
|
* Additional plugins.
|
|
53
53
|
*/
|
|
54
|
-
markdownItPlugins?:
|
|
54
|
+
markdownItPlugins?: Plugin[];
|
|
55
55
|
};
|
|
56
56
|
/**
|
|
57
57
|
* Called with the result of the lint operation.
|
|
@@ -82,6 +82,12 @@ declare function readConfig(file: string, parsers: ConfigurationParser[] | ReadC
|
|
|
82
82
|
* @returns {Configuration} Configuration object.
|
|
83
83
|
*/
|
|
84
84
|
declare function readConfigSync(file: string, parsers?: ConfigurationParser[]): Configuration;
|
|
85
|
+
/**
|
|
86
|
+
* Gets the (semantic) version of the library.
|
|
87
|
+
*
|
|
88
|
+
* @returns {string} SemVer string.
|
|
89
|
+
*/
|
|
90
|
+
declare function getVersion(): string;
|
|
85
91
|
declare namespace promises {
|
|
86
92
|
export { markdownlintPromise as markdownlint };
|
|
87
93
|
export { readConfigPromise as readConfig };
|
|
@@ -99,7 +105,7 @@ type RuleParams = {
|
|
|
99
105
|
*/
|
|
100
106
|
name: string;
|
|
101
107
|
/**
|
|
102
|
-
* markdown-it
|
|
108
|
+
* Token objects from markdown-it.
|
|
103
109
|
*/
|
|
104
110
|
tokens: MarkdownItToken[];
|
|
105
111
|
/**
|
|
@@ -256,7 +262,7 @@ type Rule = {
|
|
|
256
262
|
function: RuleFunction;
|
|
257
263
|
};
|
|
258
264
|
/**
|
|
259
|
-
* markdown-it plugin.
|
|
265
|
+
* A markdown-it plugin.
|
|
260
266
|
*/
|
|
261
267
|
type Plugin = any[];
|
|
262
268
|
/**
|
|
@@ -304,7 +310,7 @@ type LintError = {
|
|
|
304
310
|
/**
|
|
305
311
|
* Fix information.
|
|
306
312
|
*/
|
|
307
|
-
fixInfo
|
|
313
|
+
fixInfo?: FixInfo;
|
|
308
314
|
};
|
|
309
315
|
/**
|
|
310
316
|
* Fix information.
|
package/lib/markdownlint.js
CHANGED
|
@@ -4,12 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
7
|
-
const
|
|
7
|
+
const { promisify } = require("util");
|
|
8
8
|
const markdownIt = require("markdown-it");
|
|
9
9
|
const rules = require("./rules");
|
|
10
10
|
const helpers = require("../helpers");
|
|
11
11
|
const cache = require("./cache");
|
|
12
12
|
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
// eslint-disable-next-line camelcase, max-len, no-inline-comments, no-undef
|
|
15
|
+
const dynamicRequire = (typeof __non_webpack_require__ === "undefined") ? require : /* c8 ignore next */ __non_webpack_require__;
|
|
16
|
+
// Capture native require implementation for dynamic loading of modules
|
|
17
|
+
|
|
13
18
|
const deprecatedRuleNames = [ "MD002", "MD006" ];
|
|
14
19
|
|
|
15
20
|
/**
|
|
@@ -51,10 +56,12 @@ function validateRuleList(ruleList) {
|
|
|
51
56
|
result = newError(property);
|
|
52
57
|
}
|
|
53
58
|
});
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
if (
|
|
60
|
+
!result &&
|
|
61
|
+
rule.information &&
|
|
62
|
+
(Object.getPrototypeOf(rule.information) !== URL.prototype)
|
|
63
|
+
) {
|
|
64
|
+
result = newError("information");
|
|
58
65
|
}
|
|
59
66
|
if (!result) {
|
|
60
67
|
rule.names.forEach(function forName(name) {
|
|
@@ -176,18 +183,27 @@ function removeFrontMatter(content, frontMatter) {
|
|
|
176
183
|
* @returns {void}
|
|
177
184
|
*/
|
|
178
185
|
function annotateTokens(tokens, lines) {
|
|
179
|
-
let
|
|
186
|
+
let tableMap = null;
|
|
180
187
|
tokens.forEach(function forToken(token) {
|
|
181
|
-
// Handle missing maps for table body
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
// Handle missing maps for table head/body
|
|
189
|
+
if (
|
|
190
|
+
(token.type === "thead_open") ||
|
|
191
|
+
(token.type === "tbody_open")
|
|
192
|
+
) {
|
|
193
|
+
tableMap = token.map.slice();
|
|
194
|
+
} else if (
|
|
195
|
+
(token.type === "tr_close") &&
|
|
196
|
+
tableMap
|
|
197
|
+
) {
|
|
198
|
+
tableMap[0]++;
|
|
199
|
+
} else if (
|
|
200
|
+
(token.type === "thead_close") ||
|
|
201
|
+
(token.type === "tbody_close")
|
|
202
|
+
) {
|
|
203
|
+
tableMap = null;
|
|
188
204
|
}
|
|
189
|
-
if (
|
|
190
|
-
token.map =
|
|
205
|
+
if (tableMap && !token.map) {
|
|
206
|
+
token.map = tableMap.slice();
|
|
191
207
|
}
|
|
192
208
|
// Update token metadata
|
|
193
209
|
if (token.map) {
|
|
@@ -322,13 +338,13 @@ function getEnabledRulesPerLineNumber(
|
|
|
322
338
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
323
339
|
function handleInlineConfig(perLine, forEachMatch, forEachLine) {
|
|
324
340
|
const input = perLine ? lines : [ lines.join("\n") ];
|
|
325
|
-
input.forEach((line) => {
|
|
341
|
+
input.forEach((line, lineIndex) => {
|
|
326
342
|
if (!noInlineConfig) {
|
|
327
343
|
let match = null;
|
|
328
344
|
while ((match = helpers.inlineCommentRe.exec(line))) {
|
|
329
345
|
const action = (match[1] || match[3]).toUpperCase();
|
|
330
346
|
const parameter = match[2] || match[4];
|
|
331
|
-
forEachMatch(action, parameter);
|
|
347
|
+
forEachMatch(action, parameter, lineIndex + 1);
|
|
332
348
|
}
|
|
333
349
|
}
|
|
334
350
|
if (forEachLine) {
|
|
@@ -345,28 +361,27 @@ function getEnabledRulesPerLineNumber(
|
|
|
345
361
|
...config,
|
|
346
362
|
...json
|
|
347
363
|
};
|
|
348
|
-
|
|
349
|
-
} catch (error) {
|
|
364
|
+
} catch {
|
|
350
365
|
// Ignore parse errors for inline configuration
|
|
351
366
|
}
|
|
352
367
|
}
|
|
353
368
|
}
|
|
354
369
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
355
|
-
function applyEnableDisable(action, parameter) {
|
|
370
|
+
function applyEnableDisable(action, parameter, state) {
|
|
356
371
|
const enabled = (action.startsWith("ENABLE"));
|
|
357
372
|
const items = parameter ?
|
|
358
373
|
parameter.trim().toUpperCase().split(/\s+/) :
|
|
359
374
|
allRuleNames;
|
|
360
375
|
items.forEach((nameUpper) => {
|
|
361
376
|
(aliasToRuleNames[nameUpper] || []).forEach((ruleName) => {
|
|
362
|
-
|
|
377
|
+
state[ruleName] = enabled;
|
|
363
378
|
});
|
|
364
379
|
});
|
|
365
380
|
}
|
|
366
381
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
367
382
|
function enableDisableFile(action, parameter) {
|
|
368
383
|
if ((action === "ENABLE-FILE") || (action === "DISABLE-FILE")) {
|
|
369
|
-
applyEnableDisable(action, parameter);
|
|
384
|
+
applyEnableDisable(action, parameter, enabledRules);
|
|
370
385
|
}
|
|
371
386
|
}
|
|
372
387
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -377,12 +392,22 @@ function getEnabledRulesPerLineNumber(
|
|
|
377
392
|
enabledRules = { ...capturedRules };
|
|
378
393
|
} else if ((action === "ENABLE") || (action === "DISABLE")) {
|
|
379
394
|
enabledRules = { ...enabledRules };
|
|
380
|
-
applyEnableDisable(action, parameter);
|
|
395
|
+
applyEnableDisable(action, parameter, enabledRules);
|
|
381
396
|
}
|
|
382
397
|
}
|
|
383
398
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
384
399
|
function updateLineState() {
|
|
385
|
-
enabledRulesPerLineNumber.push(enabledRules);
|
|
400
|
+
enabledRulesPerLineNumber.push({ ...enabledRules });
|
|
401
|
+
}
|
|
402
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
403
|
+
function disableNextLine(action, parameter, lineNumber) {
|
|
404
|
+
if (action === "DISABLE-NEXT-LINE") {
|
|
405
|
+
applyEnableDisable(
|
|
406
|
+
action,
|
|
407
|
+
parameter,
|
|
408
|
+
enabledRulesPerLineNumber[lineNumber + 1] || {}
|
|
409
|
+
);
|
|
410
|
+
}
|
|
386
411
|
}
|
|
387
412
|
// Handle inline comments
|
|
388
413
|
handleInlineConfig(false, configureFile);
|
|
@@ -396,6 +421,7 @@ function getEnabledRulesPerLineNumber(
|
|
|
396
421
|
capturedRules = enabledRules;
|
|
397
422
|
handleInlineConfig(true, enableDisableFile);
|
|
398
423
|
handleInlineConfig(true, captureRestoreEnableDisable, updateLineState);
|
|
424
|
+
handleInlineConfig(true, disableNextLine);
|
|
399
425
|
// Return results
|
|
400
426
|
return {
|
|
401
427
|
effectiveConfig,
|
|
@@ -440,8 +466,8 @@ function uniqueFilterForSortedErrors(value, index, array) {
|
|
|
440
466
|
*
|
|
441
467
|
* @param {Rule[]} ruleList List of rules.
|
|
442
468
|
* @param {string} name Identifier for the content.
|
|
443
|
-
* @param {string} content Markdown content
|
|
444
|
-
* @param {Object} md markdown-it
|
|
469
|
+
* @param {string} content Markdown content.
|
|
470
|
+
* @param {Object} md Instance of markdown-it.
|
|
445
471
|
* @param {Configuration} config Configuration object.
|
|
446
472
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
|
447
473
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
|
@@ -652,7 +678,7 @@ function lintContent(
|
|
|
652
678
|
*
|
|
653
679
|
* @param {Rule[]} ruleList List of rules.
|
|
654
680
|
* @param {string} file Path of file to lint.
|
|
655
|
-
* @param {Object} md markdown-it
|
|
681
|
+
* @param {Object} md Instance of markdown-it.
|
|
656
682
|
* @param {Configuration} config Configuration object.
|
|
657
683
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
|
658
684
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
|
@@ -702,6 +728,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
702
728
|
// Normalize inputs
|
|
703
729
|
options = options || {};
|
|
704
730
|
callback = callback || function noop() {};
|
|
731
|
+
// eslint-disable-next-line unicorn/prefer-spread
|
|
705
732
|
const ruleList = rules.concat(options.customRules || []);
|
|
706
733
|
const ruleErr = validateRuleList(ruleList);
|
|
707
734
|
if (ruleErr) {
|
|
@@ -834,7 +861,7 @@ function markdownlint(options, callback) {
|
|
|
834
861
|
return lintInput(options, false, callback);
|
|
835
862
|
}
|
|
836
863
|
|
|
837
|
-
const markdownlintPromisify =
|
|
864
|
+
const markdownlintPromisify = promisify && promisify(markdownlint);
|
|
838
865
|
|
|
839
866
|
/**
|
|
840
867
|
* Lint specified Markdown files.
|
|
@@ -895,6 +922,35 @@ function parseConfiguration(name, content, parsers) {
|
|
|
895
922
|
};
|
|
896
923
|
}
|
|
897
924
|
|
|
925
|
+
/**
|
|
926
|
+
* Resolve referenced "extends" path in a configuration file
|
|
927
|
+
* using path.resolve() with require.resolve() as a fallback.
|
|
928
|
+
*
|
|
929
|
+
* @param {string} configFile Configuration file name.
|
|
930
|
+
* @param {string} referenceId Referenced identifier to resolve.
|
|
931
|
+
* @returns {string} Resolved path to file.
|
|
932
|
+
*/
|
|
933
|
+
function resolveConfigExtends(configFile, referenceId) {
|
|
934
|
+
const configFileDirname = path.dirname(configFile);
|
|
935
|
+
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
|
936
|
+
try {
|
|
937
|
+
if (fs.statSync(resolvedExtendsFile).isFile()) {
|
|
938
|
+
return resolvedExtendsFile;
|
|
939
|
+
}
|
|
940
|
+
} catch {
|
|
941
|
+
// If not a file or fs.statSync throws, try require.resolve
|
|
942
|
+
}
|
|
943
|
+
try {
|
|
944
|
+
return dynamicRequire.resolve(
|
|
945
|
+
referenceId,
|
|
946
|
+
{ "paths": [ configFileDirname ] }
|
|
947
|
+
);
|
|
948
|
+
} catch {
|
|
949
|
+
// If require.resolve throws, return resolvedExtendsFile
|
|
950
|
+
}
|
|
951
|
+
return resolvedExtendsFile;
|
|
952
|
+
}
|
|
953
|
+
|
|
898
954
|
/**
|
|
899
955
|
* Read specified configuration file.
|
|
900
956
|
*
|
|
@@ -925,8 +981,8 @@ function readConfig(file, parsers, callback) {
|
|
|
925
981
|
const configExtends = config.extends;
|
|
926
982
|
if (configExtends) {
|
|
927
983
|
delete config.extends;
|
|
928
|
-
const
|
|
929
|
-
return readConfig(
|
|
984
|
+
const resolvedExtends = resolveConfigExtends(file, configExtends);
|
|
985
|
+
return readConfig(resolvedExtends, parsers, (errr, extendsConfig) => {
|
|
930
986
|
if (errr) {
|
|
931
987
|
return callback(errr);
|
|
932
988
|
}
|
|
@@ -940,7 +996,7 @@ function readConfig(file, parsers, callback) {
|
|
|
940
996
|
});
|
|
941
997
|
}
|
|
942
998
|
|
|
943
|
-
const readConfigPromisify =
|
|
999
|
+
const readConfigPromisify = promisify && promisify(readConfig);
|
|
944
1000
|
|
|
945
1001
|
/**
|
|
946
1002
|
* Read specified configuration file.
|
|
@@ -974,21 +1030,29 @@ function readConfigSync(file, parsers) {
|
|
|
974
1030
|
const configExtends = config.extends;
|
|
975
1031
|
if (configExtends) {
|
|
976
1032
|
delete config.extends;
|
|
1033
|
+
const resolvedExtends = resolveConfigExtends(file, configExtends);
|
|
977
1034
|
return {
|
|
978
|
-
...readConfigSync(
|
|
979
|
-
path.resolve(path.dirname(file), configExtends),
|
|
980
|
-
parsers
|
|
981
|
-
),
|
|
1035
|
+
...readConfigSync(resolvedExtends, parsers),
|
|
982
1036
|
...config
|
|
983
1037
|
};
|
|
984
1038
|
}
|
|
985
1039
|
return config;
|
|
986
1040
|
}
|
|
987
1041
|
|
|
1042
|
+
/**
|
|
1043
|
+
* Gets the (semantic) version of the library.
|
|
1044
|
+
*
|
|
1045
|
+
* @returns {string} SemVer string.
|
|
1046
|
+
*/
|
|
1047
|
+
function getVersion() {
|
|
1048
|
+
return require("../package.json").version;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
988
1051
|
// Export a/synchronous/Promise APIs
|
|
989
1052
|
markdownlint.sync = markdownlintSync;
|
|
990
1053
|
markdownlint.readConfig = readConfig;
|
|
991
1054
|
markdownlint.readConfigSync = readConfigSync;
|
|
1055
|
+
markdownlint.getVersion = getVersion;
|
|
992
1056
|
markdownlint.promises = {
|
|
993
1057
|
"markdownlint": markdownlintPromise,
|
|
994
1058
|
"readConfig": readConfigPromise
|
|
@@ -1011,7 +1075,7 @@ module.exports = markdownlint;
|
|
|
1011
1075
|
*
|
|
1012
1076
|
* @typedef {Object} RuleParams
|
|
1013
1077
|
* @property {string} name File/string name.
|
|
1014
|
-
* @property {MarkdownItToken[]} tokens markdown-it
|
|
1078
|
+
* @property {MarkdownItToken[]} tokens Token objects from markdown-it.
|
|
1015
1079
|
* @property {string[]} lines File/string lines.
|
|
1016
1080
|
* @property {string[]} frontMatterLines Front matter lines.
|
|
1017
1081
|
* @property {RuleConfiguration} config Rule configuration.
|
|
@@ -1094,7 +1158,7 @@ module.exports = markdownlint;
|
|
|
1094
1158
|
*/
|
|
1095
1159
|
|
|
1096
1160
|
/**
|
|
1097
|
-
* markdown-it plugin.
|
|
1161
|
+
* A markdown-it plugin.
|
|
1098
1162
|
*
|
|
1099
1163
|
* @typedef {Array} Plugin
|
|
1100
1164
|
*/
|
|
@@ -1125,7 +1189,7 @@ module.exports = markdownlint;
|
|
|
1125
1189
|
* @property {string} errorDetail Detail about the error.
|
|
1126
1190
|
* @property {string} errorContext Context for the error.
|
|
1127
1191
|
* @property {number[]} errorRange Column number (1-based) and length.
|
|
1128
|
-
* @property {FixInfo} fixInfo Fix information.
|
|
1192
|
+
* @property {FixInfo} [fixInfo] Fix information.
|
|
1129
1193
|
*/
|
|
1130
1194
|
|
|
1131
1195
|
/**
|
package/lib/md002.js
CHANGED
|
@@ -6,7 +6,7 @@ const { addErrorDetailIf } = require("../helpers");
|
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
"names": [ "MD002", "first-heading-h1", "first-header-h1" ],
|
|
9
|
-
"description": "First heading should be a top
|
|
9
|
+
"description": "First heading should be a top-level heading",
|
|
10
10
|
"tags": [ "headings", "headers" ],
|
|
11
11
|
"function": function MD002(params, onError) {
|
|
12
12
|
const level = Number(params.config.level || 1);
|