markdownlint 0.35.0 → 0.36.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/CHANGELOG.md +14 -0
- package/README.md +72 -35
- package/demo/markdownlint-browser.js +1259 -1215
- package/doc/CustomRules.md +55 -249
- package/doc/Rules.md +36 -29
- package/doc/md003.md +2 -2
- package/doc/md004.md +4 -3
- package/doc/md035.md +3 -8
- package/doc/md046.md +2 -2
- package/doc/md048.md +3 -2
- package/doc/md049.md +4 -3
- package/doc/md050.md +4 -4
- package/doc/md051.md +11 -3
- package/doc/md055.md +3 -2
- package/helpers/README.md +2 -19
- package/helpers/helpers.js +87 -347
- package/helpers/micromark-helpers.cjs +296 -0
- package/helpers/micromark-parse.cjs +313 -0
- package/helpers/package.json +5 -2
- package/helpers/shared.js +6 -0
- package/helpers/test.cjs +28 -0
- package/lib/cache.js +3 -3
- package/lib/configuration-strict.d.ts +120 -106
- package/lib/constants.js +1 -1
- package/lib/markdownit.cjs +172 -0
- package/lib/markdownlint.d.ts +41 -3
- package/lib/markdownlint.js +153 -115
- package/lib/md001.js +1 -1
- package/lib/md003.js +1 -1
- package/lib/md004.js +3 -3
- package/lib/md007.js +3 -3
- package/lib/md009.js +1 -1
- package/lib/md010.js +18 -14
- package/lib/md011.js +24 -23
- package/lib/md012.js +1 -1
- package/lib/md013.js +1 -1
- package/lib/md014.js +5 -9
- package/lib/md018.js +1 -1
- package/lib/md019-md021.js +1 -1
- package/lib/md020.js +2 -2
- package/lib/md022.js +9 -15
- package/lib/md024.js +1 -1
- package/lib/md025.js +1 -1
- package/lib/md027.js +2 -2
- package/lib/md029.js +3 -3
- package/lib/md031.js +8 -6
- package/lib/md032.js +27 -15
- package/lib/md033.js +1 -1
- package/lib/md034.js +21 -29
- package/lib/md036.js +18 -24
- package/lib/md037.js +1 -1
- package/lib/md038.js +9 -14
- package/lib/md039.js +13 -15
- package/lib/md040.js +11 -13
- package/lib/md041.js +4 -4
- package/lib/md042.js +2 -6
- package/lib/md043.js +1 -1
- package/lib/md044.js +31 -28
- package/lib/md045.js +2 -2
- package/lib/md048.js +28 -17
- package/lib/md049-md050.js +20 -5
- package/lib/md051.js +16 -18
- package/lib/md053.js +5 -4
- package/lib/md054.js +11 -13
- package/lib/md055.js +39 -46
- package/lib/md056.js +31 -36
- package/lib/md058.js +29 -14
- package/package.json +14 -13
- package/schema/.markdownlint.jsonc +55 -52
- package/schema/.markdownlint.yaml +54 -52
- package/schema/markdownlint-config-schema-strict.json +132 -110
- package/schema/markdownlint-config-schema.json +132 -110
- package/helpers/micromark.cjs +0 -544
package/lib/constants.js
CHANGED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const { newLineRe } = require("../helpers");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @callback InlineCodeSpanCallback
|
|
9
|
+
* @param {string} code Code content.
|
|
10
|
+
* @param {number} lineIndex Line index (0-based).
|
|
11
|
+
* @param {number} columnIndex Column index (0-based).
|
|
12
|
+
* @param {number} ticks Count of backticks.
|
|
13
|
+
* @returns {void}
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Calls the provided function for each inline code span's content.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} input Markdown content.
|
|
20
|
+
* @param {InlineCodeSpanCallback} handler Callback function taking (code,
|
|
21
|
+
* lineIndex, columnIndex, ticks).
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
function forEachInlineCodeSpan(input, handler) {
|
|
25
|
+
const backtickRe = /`+/g;
|
|
26
|
+
let match = null;
|
|
27
|
+
const backticksLengthAndIndex = [];
|
|
28
|
+
while ((match = backtickRe.exec(input)) !== null) {
|
|
29
|
+
backticksLengthAndIndex.push([ match[0].length, match.index ]);
|
|
30
|
+
}
|
|
31
|
+
const newLinesIndex = [];
|
|
32
|
+
while ((match = newLineRe.exec(input)) !== null) {
|
|
33
|
+
newLinesIndex.push(match.index);
|
|
34
|
+
}
|
|
35
|
+
let lineIndex = 0;
|
|
36
|
+
let lineStartIndex = 0;
|
|
37
|
+
let k = 0;
|
|
38
|
+
for (let i = 0; i < backticksLengthAndIndex.length - 1; i++) {
|
|
39
|
+
const [ startLength, startIndex ] = backticksLengthAndIndex[i];
|
|
40
|
+
if ((startIndex === 0) || (input[startIndex - 1] !== "\\")) {
|
|
41
|
+
for (let j = i + 1; j < backticksLengthAndIndex.length; j++) {
|
|
42
|
+
const [ endLength, endIndex ] = backticksLengthAndIndex[j];
|
|
43
|
+
if (startLength === endLength) {
|
|
44
|
+
for (; k < newLinesIndex.length; k++) {
|
|
45
|
+
const newLineIndex = newLinesIndex[k];
|
|
46
|
+
if (startIndex < newLineIndex) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
lineIndex++;
|
|
50
|
+
lineStartIndex = newLineIndex + 1;
|
|
51
|
+
}
|
|
52
|
+
const columnIndex = startIndex - lineStartIndex + startLength;
|
|
53
|
+
handler(
|
|
54
|
+
input.slice(startIndex + startLength, endIndex),
|
|
55
|
+
lineIndex,
|
|
56
|
+
columnIndex,
|
|
57
|
+
startLength
|
|
58
|
+
);
|
|
59
|
+
i = j;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Freeze all freeze-able members of a token and its children.
|
|
69
|
+
*
|
|
70
|
+
* @param {import("./markdownlint").MarkdownItToken} token A markdown-it token.
|
|
71
|
+
* @returns {void}
|
|
72
|
+
*/
|
|
73
|
+
function freezeToken(token) {
|
|
74
|
+
if (token.attrs) {
|
|
75
|
+
for (const attr of token.attrs) {
|
|
76
|
+
Object.freeze(attr);
|
|
77
|
+
}
|
|
78
|
+
Object.freeze(token.attrs);
|
|
79
|
+
}
|
|
80
|
+
if (token.children) {
|
|
81
|
+
for (const child of token.children) {
|
|
82
|
+
freezeToken(child);
|
|
83
|
+
}
|
|
84
|
+
Object.freeze(token.children);
|
|
85
|
+
}
|
|
86
|
+
if (token.map) {
|
|
87
|
+
Object.freeze(token.map);
|
|
88
|
+
}
|
|
89
|
+
Object.freeze(token);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Annotate tokens with line/lineNumber and freeze them.
|
|
94
|
+
*
|
|
95
|
+
* @param {Object[]} tokens Array of markdown-it tokens.
|
|
96
|
+
* @param {string[]} lines Lines of Markdown content.
|
|
97
|
+
* @returns {void}
|
|
98
|
+
*/
|
|
99
|
+
function annotateAndFreezeTokens(tokens, lines) {
|
|
100
|
+
let trMap = null;
|
|
101
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
102
|
+
/** @type import("./markdownlint").MarkdownItToken[] */
|
|
103
|
+
// @ts-ignore
|
|
104
|
+
const markdownItTokens = tokens;
|
|
105
|
+
for (const token of markdownItTokens) {
|
|
106
|
+
// Provide missing maps for table content
|
|
107
|
+
if (token.type === "tr_open") {
|
|
108
|
+
trMap = token.map;
|
|
109
|
+
} else if (token.type === "tr_close") {
|
|
110
|
+
trMap = null;
|
|
111
|
+
}
|
|
112
|
+
if (!token.map && trMap) {
|
|
113
|
+
token.map = [ ...trMap ];
|
|
114
|
+
}
|
|
115
|
+
// Update token metadata
|
|
116
|
+
if (token.map) {
|
|
117
|
+
token.line = lines[token.map[0]];
|
|
118
|
+
token.lineNumber = token.map[0] + 1;
|
|
119
|
+
// Trim bottom of token to exclude whitespace lines
|
|
120
|
+
while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) {
|
|
121
|
+
token.map[1]--;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Annotate children with lineNumber
|
|
125
|
+
if (token.children) {
|
|
126
|
+
const codeSpanExtraLines = [];
|
|
127
|
+
if (token.children.some((child) => child.type === "code_inline")) {
|
|
128
|
+
forEachInlineCodeSpan(token.content, (code) => {
|
|
129
|
+
codeSpanExtraLines.push(code.split(newLineRe).length - 1);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
let lineNumber = token.lineNumber;
|
|
133
|
+
for (const child of token.children) {
|
|
134
|
+
child.lineNumber = lineNumber;
|
|
135
|
+
child.line = lines[lineNumber - 1];
|
|
136
|
+
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
|
137
|
+
lineNumber++;
|
|
138
|
+
} else if (child.type === "code_inline") {
|
|
139
|
+
lineNumber += codeSpanExtraLines.shift();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
freezeToken(token);
|
|
144
|
+
}
|
|
145
|
+
Object.freeze(tokens);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Gets an array of markdown-it tokens for the input.
|
|
150
|
+
*
|
|
151
|
+
* @param {import("./markdownlint").Plugin[]} markdownItPlugins Additional plugins.
|
|
152
|
+
* @param {string} content Markdown content.
|
|
153
|
+
* @param {string[]} lines Lines of Markdown content.
|
|
154
|
+
* @returns {import("../lib/markdownlint").MarkdownItToken} Array of markdown-it tokens.
|
|
155
|
+
*/
|
|
156
|
+
function getMarkdownItTokens(markdownItPlugins, content, lines) {
|
|
157
|
+
const markdownit = require("markdown-it");
|
|
158
|
+
const md = markdownit({ "html": true });
|
|
159
|
+
for (const plugin of markdownItPlugins) {
|
|
160
|
+
// @ts-ignore
|
|
161
|
+
md.use(...plugin);
|
|
162
|
+
}
|
|
163
|
+
const tokens = md.parse(content, {});
|
|
164
|
+
annotateAndFreezeTokens(tokens, lines);
|
|
165
|
+
// @ts-ignore
|
|
166
|
+
return tokens;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
module.exports = {
|
|
170
|
+
forEachInlineCodeSpan,
|
|
171
|
+
getMarkdownItTokens
|
|
172
|
+
};
|
package/lib/markdownlint.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export = markdownlint;
|
|
|
8
8
|
*/
|
|
9
9
|
declare function markdownlint(options: Options | null, callback: LintCallback): void;
|
|
10
10
|
declare namespace markdownlint {
|
|
11
|
-
export { markdownlintSync as sync, readConfig, readConfigSync, getVersion, promises,
|
|
11
|
+
export { markdownlintSync as sync, readConfig, readConfigSync, getVersion, promises, applyFix, applyFixes, RuleFunction, RuleParams, MarkdownParsers, ParserMarkdownIt, ParserMicromark, MarkdownItToken, MicromarkTokenType, MicromarkToken, RuleOnError, RuleOnErrorInfo, RuleOnErrorFixInfo, RuleOnErrorFixInfoNormalized, Rule, Options, Plugin, ToStringCallback, LintResults, LintError, FixInfo, LintContentCallback, LintCallback, Configuration, ConfigurationStrict, RuleConfiguration, ConfigurationParser, ReadConfigCallback, ResolveConfigExtendsCallback };
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Lint specified Markdown files synchronously.
|
|
@@ -50,9 +50,22 @@ declare namespace promises {
|
|
|
50
50
|
export { readConfigPromise as readConfig };
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* Applies the specified fix to a Markdown content line.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} line Line of Markdown content.
|
|
56
|
+
* @param {RuleOnErrorFixInfo} fixInfo RuleOnErrorFixInfo instance.
|
|
57
|
+
* @param {string} [lineEnding] Line ending to use.
|
|
58
|
+
* @returns {string | null} Fixed content or null if deleted.
|
|
59
|
+
*/
|
|
60
|
+
declare function applyFix(line: string, fixInfo: RuleOnErrorFixInfo, lineEnding?: string): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Applies as many of the specified fixes as possible to Markdown content.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} input Lines of Markdown content.
|
|
65
|
+
* @param {RuleOnErrorInfo[]} errors RuleOnErrorInfo instances.
|
|
66
|
+
* @returns {string} Fixed content.
|
|
54
67
|
*/
|
|
55
|
-
|
|
68
|
+
declare function applyFixes(input: string, errors: RuleOnErrorInfo[]): string;
|
|
56
69
|
/**
|
|
57
70
|
* Function to implement rule logic.
|
|
58
71
|
*/
|
|
@@ -81,6 +94,10 @@ type RuleParams = {
|
|
|
81
94
|
* Rule configuration.
|
|
82
95
|
*/
|
|
83
96
|
config: RuleConfiguration;
|
|
97
|
+
/**
|
|
98
|
+
* Version of the markdownlint library.
|
|
99
|
+
*/
|
|
100
|
+
version: string;
|
|
84
101
|
};
|
|
85
102
|
/**
|
|
86
103
|
* Markdown parser data.
|
|
@@ -270,6 +287,27 @@ type RuleOnErrorFixInfo = {
|
|
|
270
287
|
*/
|
|
271
288
|
insertText?: string;
|
|
272
289
|
};
|
|
290
|
+
/**
|
|
291
|
+
* RuleOnErrorInfo with all optional properties present.
|
|
292
|
+
*/
|
|
293
|
+
type RuleOnErrorFixInfoNormalized = {
|
|
294
|
+
/**
|
|
295
|
+
* Line number (1-based).
|
|
296
|
+
*/
|
|
297
|
+
lineNumber: number;
|
|
298
|
+
/**
|
|
299
|
+
* Column of the fix (1-based).
|
|
300
|
+
*/
|
|
301
|
+
editColumn: number;
|
|
302
|
+
/**
|
|
303
|
+
* Count of characters to delete.
|
|
304
|
+
*/
|
|
305
|
+
deleteCount: number;
|
|
306
|
+
/**
|
|
307
|
+
* Text to insert (after deleting).
|
|
308
|
+
*/
|
|
309
|
+
insertText: string;
|
|
310
|
+
};
|
|
273
311
|
/**
|
|
274
312
|
* Rule definition.
|
|
275
313
|
*/
|
package/lib/markdownlint.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
const path = require("node:path");
|
|
6
6
|
const { promisify } = require("node:util");
|
|
7
|
-
const micromark = require("../helpers/micromark.cjs");
|
|
8
|
-
|
|
7
|
+
const micromark = require("../helpers/micromark-parse.cjs");
|
|
8
|
+
const { version } = require("./constants");
|
|
9
9
|
const rules = require("./rules");
|
|
10
10
|
const helpers = require("../helpers");
|
|
11
11
|
const cache = require("./cache");
|
|
@@ -58,7 +58,7 @@ function validateRuleList(ruleList, synchronous) {
|
|
|
58
58
|
!result &&
|
|
59
59
|
(rule.parser !== undefined) &&
|
|
60
60
|
(rule.parser !== "markdownit") &&
|
|
61
|
-
|
|
61
|
+
(rule.parser !== "micromark") &&
|
|
62
62
|
(rule.parser !== "none")
|
|
63
63
|
) {
|
|
64
64
|
result = newError("parser", rule.parser);
|
|
@@ -197,87 +197,6 @@ function removeFrontMatter(content, frontMatter) {
|
|
|
197
197
|
};
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
/**
|
|
201
|
-
* Freeze all freeze-able members of a token and its children.
|
|
202
|
-
*
|
|
203
|
-
* @param {MarkdownItToken} token A markdown-it token.
|
|
204
|
-
* @returns {void}
|
|
205
|
-
*/
|
|
206
|
-
function freezeToken(token) {
|
|
207
|
-
if (token.attrs) {
|
|
208
|
-
for (const attr of token.attrs) {
|
|
209
|
-
Object.freeze(attr);
|
|
210
|
-
}
|
|
211
|
-
Object.freeze(token.attrs);
|
|
212
|
-
}
|
|
213
|
-
if (token.children) {
|
|
214
|
-
for (const child of token.children) {
|
|
215
|
-
freezeToken(child);
|
|
216
|
-
}
|
|
217
|
-
Object.freeze(token.children);
|
|
218
|
-
}
|
|
219
|
-
if (token.map) {
|
|
220
|
-
Object.freeze(token.map);
|
|
221
|
-
}
|
|
222
|
-
Object.freeze(token);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Annotate tokens with line/lineNumber and freeze them.
|
|
227
|
-
*
|
|
228
|
-
* @param {import("markdown-it").Token[]} tokens Array of markdown-it tokens.
|
|
229
|
-
* @param {string[]} lines Lines of Markdown content.
|
|
230
|
-
* @returns {void}
|
|
231
|
-
*/
|
|
232
|
-
function annotateAndFreezeTokens(tokens, lines) {
|
|
233
|
-
let trMap = null;
|
|
234
|
-
// eslint-disable-next-line jsdoc/valid-types
|
|
235
|
-
/** @type MarkdownItToken[] */
|
|
236
|
-
// @ts-ignore
|
|
237
|
-
const markdownItTokens = tokens;
|
|
238
|
-
for (const token of markdownItTokens) {
|
|
239
|
-
// Provide missing maps for table content
|
|
240
|
-
if (token.type === "tr_open") {
|
|
241
|
-
trMap = token.map;
|
|
242
|
-
} else if (token.type === "tr_close") {
|
|
243
|
-
trMap = null;
|
|
244
|
-
}
|
|
245
|
-
if (!token.map && trMap) {
|
|
246
|
-
token.map = [ ...trMap ];
|
|
247
|
-
}
|
|
248
|
-
// Update token metadata
|
|
249
|
-
if (token.map) {
|
|
250
|
-
token.line = lines[token.map[0]];
|
|
251
|
-
token.lineNumber = token.map[0] + 1;
|
|
252
|
-
// Trim bottom of token to exclude whitespace lines
|
|
253
|
-
while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) {
|
|
254
|
-
token.map[1]--;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
// Annotate children with lineNumber
|
|
258
|
-
if (token.children) {
|
|
259
|
-
const codeSpanExtraLines = [];
|
|
260
|
-
if (token.children.some((child) => child.type === "code_inline")) {
|
|
261
|
-
helpers.forEachInlineCodeSpan(token.content, (code) => {
|
|
262
|
-
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
let lineNumber = token.lineNumber;
|
|
266
|
-
for (const child of token.children) {
|
|
267
|
-
child.lineNumber = lineNumber;
|
|
268
|
-
child.line = lines[lineNumber - 1];
|
|
269
|
-
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
|
270
|
-
lineNumber++;
|
|
271
|
-
} else if (child.type === "code_inline") {
|
|
272
|
-
lineNumber += codeSpanExtraLines.shift();
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
freezeToken(token);
|
|
277
|
-
}
|
|
278
|
-
Object.freeze(tokens);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
200
|
/**
|
|
282
201
|
* Map rule names/tags to canonical rule name.
|
|
283
202
|
*
|
|
@@ -533,7 +452,7 @@ function getEnabledRulesPerLineNumber(
|
|
|
533
452
|
* names.
|
|
534
453
|
* @param {string} name Identifier for the content.
|
|
535
454
|
* @param {string} content Markdown content.
|
|
536
|
-
* @param {
|
|
455
|
+
* @param {Plugin[]} markdownItPlugins Additional plugins.
|
|
537
456
|
* @param {Configuration} config Configuration object.
|
|
538
457
|
* @param {ConfigurationParser[] | null} configParsers Configuration parsers.
|
|
539
458
|
* @param {RegExp | null} frontMatter Regular expression for front matter.
|
|
@@ -548,7 +467,7 @@ function lintContent(
|
|
|
548
467
|
aliasToRuleNames,
|
|
549
468
|
name,
|
|
550
469
|
content,
|
|
551
|
-
|
|
470
|
+
markdownItPlugins,
|
|
552
471
|
config,
|
|
553
472
|
configParsers,
|
|
554
473
|
frontMatter,
|
|
@@ -576,14 +495,20 @@ function lintContent(
|
|
|
576
495
|
const needMarkdownItTokens = enabledRuleList.some(
|
|
577
496
|
(rule) => (rule.parser === "markdownit") || (rule.parser === undefined)
|
|
578
497
|
);
|
|
498
|
+
const customRulesPresent = (ruleList.length !== rules.length);
|
|
579
499
|
// Parse content into parser tokens
|
|
580
|
-
const
|
|
581
|
-
|
|
500
|
+
const micromarkTokens = micromark.parse(
|
|
501
|
+
content,
|
|
502
|
+
{ "freezeTokens": customRulesPresent }
|
|
503
|
+
);
|
|
582
504
|
// Hide the content of HTML comments from rules
|
|
505
|
+
const preClearedContent = content;
|
|
583
506
|
content = helpers.clearHtmlCommentText(content);
|
|
584
|
-
// Parse content into lines and
|
|
507
|
+
// Parse content into lines and get markdown-it tokens
|
|
585
508
|
const lines = content.split(helpers.newLineRe);
|
|
586
|
-
|
|
509
|
+
const markdownitTokens = needMarkdownItTokens ?
|
|
510
|
+
require("./markdownit.cjs").getMarkdownItTokens(markdownItPlugins, preClearedContent, lines) :
|
|
511
|
+
[];
|
|
587
512
|
// Create (frozen) parameters for rules
|
|
588
513
|
/** @type {MarkdownParsers} */
|
|
589
514
|
// @ts-ignore
|
|
@@ -604,6 +529,7 @@ function lintContent(
|
|
|
604
529
|
const parsersNone = Object.freeze({});
|
|
605
530
|
const paramsBase = {
|
|
606
531
|
name,
|
|
532
|
+
version,
|
|
607
533
|
"lines": Object.freeze(lines),
|
|
608
534
|
"frontMatterLines": Object.freeze(frontMatterLines)
|
|
609
535
|
};
|
|
@@ -836,7 +762,7 @@ function lintContent(
|
|
|
836
762
|
* @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule
|
|
837
763
|
* names.
|
|
838
764
|
* @param {string} file Path of file to lint.
|
|
839
|
-
* @param {
|
|
765
|
+
* @param {Plugin[]} markdownItPlugins Additional plugins.
|
|
840
766
|
* @param {Configuration} config Configuration object.
|
|
841
767
|
* @param {ConfigurationParser[] | null} configParsers Configuration parsers.
|
|
842
768
|
* @param {RegExp | null} frontMatter Regular expression for front matter.
|
|
@@ -852,7 +778,7 @@ function lintFile(
|
|
|
852
778
|
ruleList,
|
|
853
779
|
aliasToRuleNames,
|
|
854
780
|
file,
|
|
855
|
-
|
|
781
|
+
markdownItPlugins,
|
|
856
782
|
config,
|
|
857
783
|
configParsers,
|
|
858
784
|
frontMatter,
|
|
@@ -872,7 +798,7 @@ function lintFile(
|
|
|
872
798
|
aliasToRuleNames,
|
|
873
799
|
file,
|
|
874
800
|
content,
|
|
875
|
-
|
|
801
|
+
markdownItPlugins,
|
|
876
802
|
config,
|
|
877
803
|
configParsers,
|
|
878
804
|
frontMatter,
|
|
@@ -932,21 +858,14 @@ function lintInput(options, synchronous, callback) {
|
|
|
932
858
|
const config = options.config || { "default": true };
|
|
933
859
|
const configParsers = options.configParsers || null;
|
|
934
860
|
const frontMatter = (options.frontMatter === undefined) ?
|
|
935
|
-
helpers.frontMatterRe :
|
|
861
|
+
helpers.frontMatterRe :
|
|
862
|
+
options.frontMatter;
|
|
936
863
|
const handleRuleFailures = !!options.handleRuleFailures;
|
|
937
864
|
const noInlineConfig = !!options.noInlineConfig;
|
|
938
865
|
const resultVersion = (options.resultVersion === undefined) ?
|
|
939
|
-
3 :
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const md = markdownit({ "html": true });
|
|
943
|
-
const markdownItPlugins = options.markdownItPlugins || [];
|
|
944
|
-
for (const plugin of markdownItPlugins) {
|
|
945
|
-
// @ts-ignore
|
|
946
|
-
md.use(...plugin);
|
|
947
|
-
}
|
|
948
|
-
return md;
|
|
949
|
-
};
|
|
866
|
+
3 :
|
|
867
|
+
options.resultVersion;
|
|
868
|
+
const markdownItPlugins = options.markdownItPlugins || [];
|
|
950
869
|
const fs = options.fs || require("node:fs");
|
|
951
870
|
const aliasToRuleNames = mapAliasToRuleNames(ruleList);
|
|
952
871
|
const results = newResults(ruleList);
|
|
@@ -978,7 +897,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
978
897
|
ruleList,
|
|
979
898
|
aliasToRuleNames,
|
|
980
899
|
currentItem,
|
|
981
|
-
|
|
900
|
+
markdownItPlugins,
|
|
982
901
|
config,
|
|
983
902
|
configParsers,
|
|
984
903
|
frontMatter,
|
|
@@ -997,7 +916,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
997
916
|
aliasToRuleNames,
|
|
998
917
|
currentItem,
|
|
999
918
|
strings[currentItem] || "",
|
|
1000
|
-
|
|
919
|
+
markdownItPlugins,
|
|
1001
920
|
config,
|
|
1002
921
|
configParsers,
|
|
1003
922
|
frontMatter,
|
|
@@ -1289,13 +1208,126 @@ function readConfigSync(file, parsers, fs) {
|
|
|
1289
1208
|
return config;
|
|
1290
1209
|
}
|
|
1291
1210
|
|
|
1211
|
+
/**
|
|
1212
|
+
* Normalizes the fields of a RuleOnErrorFixInfo instance.
|
|
1213
|
+
*
|
|
1214
|
+
* @param {RuleOnErrorFixInfo} fixInfo RuleOnErrorFixInfo instance.
|
|
1215
|
+
* @param {number} [lineNumber] Line number.
|
|
1216
|
+
* @returns {RuleOnErrorFixInfoNormalized} Normalized RuleOnErrorFixInfo instance.
|
|
1217
|
+
*/
|
|
1218
|
+
function normalizeFixInfo(fixInfo, lineNumber = 0) {
|
|
1219
|
+
return {
|
|
1220
|
+
"lineNumber": fixInfo.lineNumber || lineNumber,
|
|
1221
|
+
"editColumn": fixInfo.editColumn || 1,
|
|
1222
|
+
"deleteCount": fixInfo.deleteCount || 0,
|
|
1223
|
+
"insertText": fixInfo.insertText || ""
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* Applies the specified fix to a Markdown content line.
|
|
1229
|
+
*
|
|
1230
|
+
* @param {string} line Line of Markdown content.
|
|
1231
|
+
* @param {RuleOnErrorFixInfo} fixInfo RuleOnErrorFixInfo instance.
|
|
1232
|
+
* @param {string} [lineEnding] Line ending to use.
|
|
1233
|
+
* @returns {string | null} Fixed content or null if deleted.
|
|
1234
|
+
*/
|
|
1235
|
+
function applyFix(line, fixInfo, lineEnding = "\n") {
|
|
1236
|
+
const { editColumn, deleteCount, insertText } = normalizeFixInfo(fixInfo);
|
|
1237
|
+
const editIndex = editColumn - 1;
|
|
1238
|
+
return (deleteCount === -1) ?
|
|
1239
|
+
null :
|
|
1240
|
+
line.slice(0, editIndex) + insertText.replace(/\n/g, lineEnding) + line.slice(editIndex + deleteCount);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Applies as many of the specified fixes as possible to Markdown content.
|
|
1245
|
+
*
|
|
1246
|
+
* @param {string} input Lines of Markdown content.
|
|
1247
|
+
* @param {RuleOnErrorInfo[]} errors RuleOnErrorInfo instances.
|
|
1248
|
+
* @returns {string} Fixed content.
|
|
1249
|
+
*/
|
|
1250
|
+
function applyFixes(input, errors) {
|
|
1251
|
+
const lineEnding = helpers.getPreferredLineEnding(input, require("node:os"));
|
|
1252
|
+
const lines = input.split(helpers.newLineRe);
|
|
1253
|
+
// Normalize fixInfo objects
|
|
1254
|
+
let fixInfos = errors
|
|
1255
|
+
.filter((error) => error.fixInfo)
|
|
1256
|
+
// @ts-ignore
|
|
1257
|
+
.map((error) => normalizeFixInfo(error.fixInfo, error.lineNumber));
|
|
1258
|
+
// Sort bottom-to-top, line-deletes last, right-to-left, long-to-short
|
|
1259
|
+
fixInfos.sort((a, b) => {
|
|
1260
|
+
const aDeletingLine = (a.deleteCount === -1);
|
|
1261
|
+
const bDeletingLine = (b.deleteCount === -1);
|
|
1262
|
+
return (
|
|
1263
|
+
(b.lineNumber - a.lineNumber) ||
|
|
1264
|
+
(aDeletingLine ? 1 : (bDeletingLine ? -1 : 0)) ||
|
|
1265
|
+
(b.editColumn - a.editColumn) ||
|
|
1266
|
+
(b.insertText.length - a.insertText.length)
|
|
1267
|
+
);
|
|
1268
|
+
});
|
|
1269
|
+
// Remove duplicate entries (needed for following collapse step)
|
|
1270
|
+
// eslint-disable-next-line jsdoc/valid-types
|
|
1271
|
+
/** @type RuleOnErrorFixInfo */
|
|
1272
|
+
let lastFixInfo = {};
|
|
1273
|
+
fixInfos = fixInfos.filter((fixInfo) => {
|
|
1274
|
+
const unique = (
|
|
1275
|
+
(fixInfo.lineNumber !== lastFixInfo.lineNumber) ||
|
|
1276
|
+
(fixInfo.editColumn !== lastFixInfo.editColumn) ||
|
|
1277
|
+
(fixInfo.deleteCount !== lastFixInfo.deleteCount) ||
|
|
1278
|
+
(fixInfo.insertText !== lastFixInfo.insertText)
|
|
1279
|
+
);
|
|
1280
|
+
lastFixInfo = fixInfo;
|
|
1281
|
+
return unique;
|
|
1282
|
+
});
|
|
1283
|
+
// Collapse insert/no-delete and no-insert/delete for same line/column
|
|
1284
|
+
lastFixInfo = {
|
|
1285
|
+
"lineNumber": -1
|
|
1286
|
+
};
|
|
1287
|
+
for (const fixInfo of fixInfos) {
|
|
1288
|
+
if (
|
|
1289
|
+
(fixInfo.lineNumber === lastFixInfo.lineNumber) &&
|
|
1290
|
+
(fixInfo.editColumn === lastFixInfo.editColumn) &&
|
|
1291
|
+
!fixInfo.insertText &&
|
|
1292
|
+
(fixInfo.deleteCount > 0) &&
|
|
1293
|
+
lastFixInfo.insertText &&
|
|
1294
|
+
!lastFixInfo.deleteCount) {
|
|
1295
|
+
fixInfo.insertText = lastFixInfo.insertText;
|
|
1296
|
+
lastFixInfo.lineNumber = 0;
|
|
1297
|
+
}
|
|
1298
|
+
lastFixInfo = fixInfo;
|
|
1299
|
+
}
|
|
1300
|
+
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber);
|
|
1301
|
+
// Apply all (remaining/updated) fixes
|
|
1302
|
+
let lastLineIndex = -1;
|
|
1303
|
+
let lastEditIndex = -1;
|
|
1304
|
+
for (const fixInfo of fixInfos) {
|
|
1305
|
+
const { lineNumber, editColumn, deleteCount } = fixInfo;
|
|
1306
|
+
const lineIndex = lineNumber - 1;
|
|
1307
|
+
const editIndex = editColumn - 1;
|
|
1308
|
+
if (
|
|
1309
|
+
(lineIndex !== lastLineIndex) ||
|
|
1310
|
+
(deleteCount === -1) ||
|
|
1311
|
+
((editIndex + deleteCount) <=
|
|
1312
|
+
(lastEditIndex - ((deleteCount > 0) ? 0 : 1)))
|
|
1313
|
+
) {
|
|
1314
|
+
// @ts-ignore
|
|
1315
|
+
lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding);
|
|
1316
|
+
}
|
|
1317
|
+
lastLineIndex = lineIndex;
|
|
1318
|
+
lastEditIndex = editIndex;
|
|
1319
|
+
}
|
|
1320
|
+
// Return corrected input
|
|
1321
|
+
return lines.filter((line) => line !== null).join(lineEnding);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1292
1324
|
/**
|
|
1293
1325
|
* Gets the (semantic) version of the library.
|
|
1294
1326
|
*
|
|
1295
1327
|
* @returns {string} SemVer string.
|
|
1296
1328
|
*/
|
|
1297
1329
|
function getVersion() {
|
|
1298
|
-
return
|
|
1330
|
+
return version;
|
|
1299
1331
|
}
|
|
1300
1332
|
|
|
1301
1333
|
// Export a/synchronous/Promise APIs
|
|
@@ -1308,17 +1340,12 @@ markdownlint.promises = {
|
|
|
1308
1340
|
"extendConfig": extendConfigPromise,
|
|
1309
1341
|
"readConfig": readConfigPromise
|
|
1310
1342
|
};
|
|
1343
|
+
markdownlint.applyFix = applyFix;
|
|
1344
|
+
markdownlint.applyFixes = applyFixes;
|
|
1311
1345
|
module.exports = markdownlint;
|
|
1312
1346
|
|
|
1313
1347
|
// Type declarations
|
|
1314
1348
|
|
|
1315
|
-
/**
|
|
1316
|
-
* Function to get an instance of the markdown-it parser.
|
|
1317
|
-
*
|
|
1318
|
-
* @callback GetMarkdownIt
|
|
1319
|
-
* @returns {import("markdown-it")}
|
|
1320
|
-
*/
|
|
1321
|
-
|
|
1322
1349
|
/**
|
|
1323
1350
|
* Function to implement rule logic.
|
|
1324
1351
|
*
|
|
@@ -1339,6 +1366,7 @@ module.exports = markdownlint;
|
|
|
1339
1366
|
* @property {readonly string[]} lines File/string lines.
|
|
1340
1367
|
* @property {readonly string[]} frontMatterLines Front matter lines.
|
|
1341
1368
|
* @property {RuleConfiguration} config Rule configuration.
|
|
1369
|
+
* @property {string} version Version of the markdownlint library.
|
|
1342
1370
|
*/
|
|
1343
1371
|
|
|
1344
1372
|
/* eslint-enable jsdoc/valid-types */
|
|
@@ -1432,6 +1460,16 @@ module.exports = markdownlint;
|
|
|
1432
1460
|
* @property {string} [insertText] Text to insert (after deleting).
|
|
1433
1461
|
*/
|
|
1434
1462
|
|
|
1463
|
+
/**
|
|
1464
|
+
* RuleOnErrorInfo with all optional properties present.
|
|
1465
|
+
*
|
|
1466
|
+
* @typedef {Object} RuleOnErrorFixInfoNormalized
|
|
1467
|
+
* @property {number} lineNumber Line number (1-based).
|
|
1468
|
+
* @property {number} editColumn Column of the fix (1-based).
|
|
1469
|
+
* @property {number} deleteCount Count of characters to delete.
|
|
1470
|
+
* @property {string} insertText Text to insert (after deleting).
|
|
1471
|
+
*/
|
|
1472
|
+
|
|
1435
1473
|
/**
|
|
1436
1474
|
* Rule definition.
|
|
1437
1475
|
*
|
package/lib/md001.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorDetailIf } = require("../helpers");
|
|
6
|
-
const { getHeadingLevel } = require("../helpers/micromark.cjs");
|
|
6
|
+
const { getHeadingLevel } = require("../helpers/micromark-helpers.cjs");
|
|
7
7
|
const { filterByTypesCached } = require("./cache");
|
|
8
8
|
|
|
9
9
|
// eslint-disable-next-line jsdoc/valid-types
|
package/lib/md003.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorDetailIf } = require("../helpers");
|
|
6
|
-
const { getHeadingLevel, getHeadingStyle } = require("../helpers/micromark.cjs");
|
|
6
|
+
const { getHeadingLevel, getHeadingStyle } = require("../helpers/micromark-helpers.cjs");
|
|
7
7
|
const { filterByTypesCached } = require("./cache");
|
|
8
8
|
|
|
9
9
|
// eslint-disable-next-line jsdoc/valid-types
|
package/lib/md004.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const { addErrorDetailIf } = require("../helpers");
|
|
6
|
-
const { getDescendantsByType,
|
|
6
|
+
const { getDescendantsByType, getParentOfType } = require("../helpers/micromark-helpers.cjs");
|
|
7
7
|
const { filterByTypesCached } = require("./cache");
|
|
8
8
|
|
|
9
9
|
const markerToStyle = {
|
|
@@ -43,10 +43,10 @@ module.exports = {
|
|
|
43
43
|
for (const listUnordered of filterByTypesCached([ "listUnordered" ])) {
|
|
44
44
|
let nesting = 0;
|
|
45
45
|
if (style === "sublist") {
|
|
46
|
-
/** @type {import("../helpers/micromark.cjs").Token | null} */
|
|
46
|
+
/** @type {import("../helpers/micromark-helpers.cjs").Token | null} */
|
|
47
47
|
let parent = listUnordered;
|
|
48
48
|
// @ts-ignore
|
|
49
|
-
while ((parent =
|
|
49
|
+
while ((parent = getParentOfType(parent, [ "listOrdered", "listUnordered" ]))) {
|
|
50
50
|
nesting++;
|
|
51
51
|
}
|
|
52
52
|
}
|