markdownlint 0.25.1 → 0.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +2 -0
- package/README.md +126 -83
- package/demo/markdownlint-browser.js +1743 -1288
- package/doc/Rules.md +145 -16
- package/helpers/helpers.js +429 -192
- package/helpers/package.json +6 -2
- package/lib/cache.js +15 -25
- package/lib/constants.js +1 -1
- package/lib/markdownlint.d.ts +21 -17
- package/lib/markdownlint.js +237 -151
- package/lib/md004.js +4 -4
- package/lib/md005.js +4 -4
- package/lib/md006.js +4 -4
- package/lib/md007.js +4 -4
- package/lib/md009.js +20 -13
- package/lib/md010.js +15 -2
- package/lib/md011.js +2 -2
- package/lib/md013.js +4 -5
- package/lib/md014.js +4 -4
- package/lib/md021.js +3 -1
- package/lib/md026.js +1 -1
- package/lib/md027.js +2 -2
- package/lib/md028.js +2 -2
- package/lib/md029.js +5 -4
- package/lib/md030.js +4 -4
- package/lib/md031.js +2 -2
- package/lib/md032.js +7 -7
- package/lib/md033.js +3 -4
- package/lib/md034.js +2 -2
- package/lib/md035.js +7 -2
- package/lib/md036.js +2 -2
- package/lib/md037.js +23 -20
- package/lib/md038.js +7 -4
- package/lib/md039.js +6 -4
- package/lib/md042.js +17 -10
- package/lib/md043.js +2 -2
- package/lib/md044.js +20 -9
- package/lib/md046.js +14 -13
- package/lib/md048.js +13 -14
- package/lib/md049-md050.js +73 -0
- package/lib/md051.js +87 -0
- package/lib/md052.js +35 -0
- package/lib/md053.js +59 -0
- package/lib/rules.js +6 -4
- package/package.json +25 -18
- package/schema/.markdownlint.jsonc +19 -1
- package/schema/.markdownlint.yaml +18 -1
- package/schema/markdownlint-config-schema.json +126 -728
- package/lib/md049.js +0 -45
- package/lib/md050.js +0 -45
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! markdownlint 0.
|
|
1
|
+
/*! markdownlint 0.26.2 https://github.com/DavidAnson/markdownlint @license MIT */
|
|
2
2
|
var markdownlint;
|
|
3
3
|
/******/ (() => { // webpackBootstrap
|
|
4
4
|
/******/ var __webpack_modules__ = ({
|
|
@@ -25,37 +25,43 @@ module.exports = webpackEmptyContext;
|
|
|
25
25
|
/*!*****************************!*\
|
|
26
26
|
!*** ../helpers/helpers.js ***!
|
|
27
27
|
\*****************************/
|
|
28
|
-
/***/ ((module) => {
|
|
28
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
29
29
|
|
|
30
30
|
"use strict";
|
|
31
31
|
// @ts-check
|
|
32
32
|
|
|
33
33
|
// Regular expression for matching common newline characters
|
|
34
34
|
// See NEWLINES_RE in markdown-it/lib/rules_core/normalize.js
|
|
35
|
-
|
|
35
|
+
const newLineRe = /\r\n?|\n/g;
|
|
36
36
|
module.exports.newLineRe = newLineRe;
|
|
37
37
|
// Regular expression for matching common front matter (YAML and TOML)
|
|
38
38
|
module.exports.frontMatterRe =
|
|
39
39
|
// eslint-disable-next-line max-len
|
|
40
40
|
/((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m;
|
|
41
|
-
// Regular expression for matching inline disable/enable comments
|
|
42
|
-
|
|
41
|
+
// Regular expression for matching the start of inline disable/enable comments
|
|
42
|
+
const inlineCommentStartRe =
|
|
43
43
|
// eslint-disable-next-line max-len
|
|
44
|
-
|
|
45
|
-
module.exports.
|
|
44
|
+
/(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/ig;
|
|
45
|
+
module.exports.inlineCommentStartRe = inlineCommentStartRe;
|
|
46
|
+
// Regular expression for matching HTML elements
|
|
47
|
+
const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^`>]*)?)\/?>/g;
|
|
48
|
+
module.exports.htmlElementRe = htmlElementRe;
|
|
46
49
|
// Regular expressions for range matching
|
|
47
50
|
module.exports.bareUrlRe = /(?:http|ftp)s?:\/\/[^\s\]"']*(?:\/|[^\s\]"'\W])/ig;
|
|
48
51
|
module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
|
|
49
52
|
module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
|
50
53
|
// Regular expression for all instances of emphasis markers
|
|
51
|
-
|
|
52
|
-
// Regular expression for
|
|
53
|
-
|
|
54
|
-
module.exports.
|
|
55
|
-
// Regular expression for
|
|
56
|
-
|
|
54
|
+
const emphasisMarkersRe = /[_*]/g;
|
|
55
|
+
// Regular expression for blockquote prefixes
|
|
56
|
+
const blockquotePrefixRe = /^[>\s]*/;
|
|
57
|
+
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
|
58
|
+
// Regular expression for reference links (full, collapsed, and shortcut)
|
|
59
|
+
const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g;
|
|
60
|
+
// Regular expression for link reference definitions
|
|
61
|
+
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/;
|
|
62
|
+
module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
|
|
57
63
|
// All punctuation characters (normal and full-width)
|
|
58
|
-
|
|
64
|
+
const allPunctuation = ".,;:!?。,;:!?";
|
|
59
65
|
module.exports.allPunctuation = allPunctuation;
|
|
60
66
|
// All punctuation characters without question mark (normal and full-width)
|
|
61
67
|
module.exports.allPunctuationNoQuestion = allPunctuation.replace(/[??]/gu, "");
|
|
@@ -75,20 +81,44 @@ module.exports.isEmptyString = function isEmptyString(str) {
|
|
|
75
81
|
module.exports.isObject = function isObject(obj) {
|
|
76
82
|
return (obj !== null) && (typeof obj === "object") && !Array.isArray(obj);
|
|
77
83
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Returns true iff the input line is blank (contains nothing, whitespace, or
|
|
86
|
+
* comments (unclosed start/end comments allowed)).
|
|
87
|
+
*
|
|
88
|
+
* @param {string} line Input line.
|
|
89
|
+
* @returns {boolean} True iff line is blank.
|
|
90
|
+
*/
|
|
91
|
+
function isBlankLine(line) {
|
|
92
|
+
const startComment = "<!--";
|
|
93
|
+
const endComment = "-->";
|
|
94
|
+
const removeComments = (s) => {
|
|
95
|
+
// eslint-disable-next-line no-constant-condition
|
|
96
|
+
while (true) {
|
|
97
|
+
const start = s.indexOf(startComment);
|
|
98
|
+
const end = s.indexOf(endComment);
|
|
99
|
+
if ((end !== -1) && ((start === -1) || (end < start))) {
|
|
100
|
+
// Unmatched end comment is first
|
|
101
|
+
s = s.slice(end + endComment.length);
|
|
102
|
+
}
|
|
103
|
+
else if ((start !== -1) && (end !== -1)) {
|
|
104
|
+
// Start comment is before end comment
|
|
105
|
+
s = s.slice(0, start) + s.slice(end + endComment.length);
|
|
106
|
+
}
|
|
107
|
+
else if ((start !== -1) && (end === -1)) {
|
|
108
|
+
// Unmatched start comment is last
|
|
109
|
+
s = s.slice(0, start);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// No more comments to remove
|
|
113
|
+
return s;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
83
117
|
return (!line ||
|
|
84
118
|
!line.trim() ||
|
|
85
|
-
!line
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.replace(/^.*-->/g, "")
|
|
89
|
-
.replace(/>/g, "")
|
|
90
|
-
.trim());
|
|
91
|
-
};
|
|
119
|
+
!removeComments(line).replace(/>/g, "").trim());
|
|
120
|
+
}
|
|
121
|
+
module.exports.isBlankLine = isBlankLine;
|
|
92
122
|
/**
|
|
93
123
|
* Compare function for Array.prototype.sort for ascending order of numbers.
|
|
94
124
|
*
|
|
@@ -101,11 +131,11 @@ module.exports.numericSortAscending = function numericSortAscending(a, b) {
|
|
|
101
131
|
};
|
|
102
132
|
// Returns true iff the sorted array contains the specified element
|
|
103
133
|
module.exports.includesSorted = function includesSorted(array, element) {
|
|
104
|
-
|
|
105
|
-
|
|
134
|
+
let left = 0;
|
|
135
|
+
let right = array.length - 1;
|
|
106
136
|
while (left <= right) {
|
|
107
137
|
// eslint-disable-next-line no-bitwise
|
|
108
|
-
|
|
138
|
+
const mid = (left + right) >> 1;
|
|
109
139
|
if (array[mid] < element) {
|
|
110
140
|
left = mid + 1;
|
|
111
141
|
}
|
|
@@ -122,41 +152,35 @@ module.exports.includesSorted = function includesSorted(array, element) {
|
|
|
122
152
|
// This preserves the line/column information for the rest of the document
|
|
123
153
|
// https://spec.commonmark.org/0.29/#html-blocks
|
|
124
154
|
// https://spec.commonmark.org/0.29/#html-comment
|
|
125
|
-
|
|
126
|
-
|
|
155
|
+
const htmlCommentBegin = "<!--";
|
|
156
|
+
const htmlCommentEnd = "-->";
|
|
127
157
|
module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
|
|
128
|
-
|
|
158
|
+
let i = 0;
|
|
129
159
|
while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
|
|
130
|
-
|
|
160
|
+
const j = text.indexOf(htmlCommentEnd, i + 2);
|
|
131
161
|
if (j === -1) {
|
|
132
162
|
// Un-terminated comments are treated as text
|
|
133
163
|
break;
|
|
134
164
|
}
|
|
135
165
|
// If the comment has content...
|
|
136
166
|
if (j > i + htmlCommentBegin.length) {
|
|
137
|
-
|
|
167
|
+
let k = i - 1;
|
|
138
168
|
while (text[k] === " ") {
|
|
139
169
|
k--;
|
|
140
170
|
}
|
|
141
171
|
// If comment is not within an indented code block...
|
|
142
172
|
if (k >= i - 4) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
173
|
+
const content = text.slice(i + htmlCommentBegin.length, j);
|
|
174
|
+
const isBlock = (k < 0) || (text[k] === "\n");
|
|
175
|
+
const isValid = isBlock ||
|
|
146
176
|
(!content.startsWith(">") && !content.startsWith("->") &&
|
|
147
177
|
!content.endsWith("-") && !content.includes("--"));
|
|
148
178
|
// If a valid block/inline comment...
|
|
149
179
|
if (isValid) {
|
|
150
|
-
|
|
151
|
-
.slice(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (inlineCommentIndex === -1) {
|
|
155
|
-
text =
|
|
156
|
-
text.slice(0, i + htmlCommentBegin.length) +
|
|
157
|
-
content.replace(/[^\r\n]/g, ".") +
|
|
158
|
-
text.slice(j);
|
|
159
|
-
}
|
|
180
|
+
text =
|
|
181
|
+
text.slice(0, i + htmlCommentBegin.length) +
|
|
182
|
+
content.replace(/[^\r\n]/g, ".") +
|
|
183
|
+
text.slice(j);
|
|
160
184
|
}
|
|
161
185
|
}
|
|
162
186
|
}
|
|
@@ -169,11 +193,11 @@ module.exports.escapeForRegExp = function escapeForRegExp(str) {
|
|
|
169
193
|
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
170
194
|
};
|
|
171
195
|
// Un-escapes Markdown content (simple algorithm; not a parser)
|
|
172
|
-
|
|
196
|
+
const escapedMarkdownRe = /\\./g;
|
|
173
197
|
module.exports.unescapeMarkdown =
|
|
174
198
|
function unescapeMarkdown(markdown, replacement) {
|
|
175
|
-
return markdown.replace(escapedMarkdownRe,
|
|
176
|
-
|
|
199
|
+
return markdown.replace(escapedMarkdownRe, (match) => {
|
|
200
|
+
const char = match[1];
|
|
177
201
|
if ("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".includes(char)) {
|
|
178
202
|
return replacement || char;
|
|
179
203
|
}
|
|
@@ -217,7 +241,7 @@ module.exports.emphasisOrStrongStyleFor =
|
|
|
217
241
|
* @returns {number} Characters of indent.
|
|
218
242
|
*/
|
|
219
243
|
function indentFor(token) {
|
|
220
|
-
|
|
244
|
+
const line = token.line.replace(/^[\s>]*(> |>)/, "");
|
|
221
245
|
return line.length - line.trimStart().length;
|
|
222
246
|
}
|
|
223
247
|
module.exports.indentFor = indentFor;
|
|
@@ -257,11 +281,11 @@ module.exports.unorderedListStyleFor = function unorderedListStyleFor(token) {
|
|
|
257
281
|
* @returns {void}
|
|
258
282
|
*/
|
|
259
283
|
function filterTokens(params, type, handler) {
|
|
260
|
-
params.tokens
|
|
284
|
+
for (const token of params.tokens) {
|
|
261
285
|
if (token.type === type) {
|
|
262
286
|
handler(token);
|
|
263
287
|
}
|
|
264
|
-
}
|
|
288
|
+
}
|
|
265
289
|
}
|
|
266
290
|
module.exports.filterTokens = filterTokens;
|
|
267
291
|
/**
|
|
@@ -278,39 +302,39 @@ function isMathBlock(token) {
|
|
|
278
302
|
module.exports.isMathBlock = isMathBlock;
|
|
279
303
|
// Get line metadata array
|
|
280
304
|
module.exports.getLineMetadata = function getLineMetadata(params) {
|
|
281
|
-
|
|
282
|
-
filterTokens(params, "fence",
|
|
305
|
+
const lineMetadata = params.lines.map((line, index) => [line, index, false, 0, false, false, false, false]);
|
|
306
|
+
filterTokens(params, "fence", (token) => {
|
|
283
307
|
lineMetadata[token.map[0]][3] = 1;
|
|
284
308
|
lineMetadata[token.map[1] - 1][3] = -1;
|
|
285
|
-
for (
|
|
309
|
+
for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) {
|
|
286
310
|
lineMetadata[i][2] = true;
|
|
287
311
|
}
|
|
288
312
|
});
|
|
289
|
-
filterTokens(params, "code_block",
|
|
290
|
-
for (
|
|
313
|
+
filterTokens(params, "code_block", (token) => {
|
|
314
|
+
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
291
315
|
lineMetadata[i][2] = true;
|
|
292
316
|
}
|
|
293
317
|
});
|
|
294
|
-
filterTokens(params, "table_open",
|
|
295
|
-
for (
|
|
318
|
+
filterTokens(params, "table_open", (token) => {
|
|
319
|
+
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
296
320
|
lineMetadata[i][4] = true;
|
|
297
321
|
}
|
|
298
322
|
});
|
|
299
|
-
filterTokens(params, "list_item_open",
|
|
300
|
-
|
|
301
|
-
for (
|
|
323
|
+
filterTokens(params, "list_item_open", (token) => {
|
|
324
|
+
let count = 1;
|
|
325
|
+
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
302
326
|
lineMetadata[i][5] = count;
|
|
303
327
|
count++;
|
|
304
328
|
}
|
|
305
329
|
});
|
|
306
|
-
filterTokens(params, "hr",
|
|
330
|
+
filterTokens(params, "hr", (token) => {
|
|
307
331
|
lineMetadata[token.map[0]][6] = true;
|
|
308
332
|
});
|
|
309
|
-
params.tokens.filter(isMathBlock)
|
|
310
|
-
for (
|
|
333
|
+
for (const token of params.tokens.filter(isMathBlock)) {
|
|
334
|
+
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
311
335
|
lineMetadata[i][7] = true;
|
|
312
336
|
}
|
|
313
|
-
}
|
|
337
|
+
}
|
|
314
338
|
return lineMetadata;
|
|
315
339
|
};
|
|
316
340
|
/**
|
|
@@ -322,20 +346,20 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
|
|
322
346
|
* @returns {void}
|
|
323
347
|
*/
|
|
324
348
|
function forEachLine(lineMetadata, handler) {
|
|
325
|
-
|
|
326
|
-
handler
|
|
327
|
-
}
|
|
349
|
+
for (const metadata of lineMetadata) {
|
|
350
|
+
handler(...metadata);
|
|
351
|
+
}
|
|
328
352
|
}
|
|
329
353
|
module.exports.forEachLine = forEachLine;
|
|
330
354
|
// Returns (nested) lists as a flat array (in order)
|
|
331
355
|
module.exports.flattenLists = function flattenLists(tokens) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
356
|
+
const flattenedLists = [];
|
|
357
|
+
const stack = [];
|
|
358
|
+
let current = null;
|
|
359
|
+
let nesting = 0;
|
|
360
|
+
const nestingStack = [];
|
|
361
|
+
let lastWithMap = { "map": [0, 1] };
|
|
362
|
+
for (const token of tokens) {
|
|
339
363
|
if ((token.type === "bullet_list_open") ||
|
|
340
364
|
(token.type === "ordered_list_open")) {
|
|
341
365
|
// Save current context and start a new one
|
|
@@ -372,30 +396,30 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
|
|
372
396
|
nesting = 0;
|
|
373
397
|
}
|
|
374
398
|
else if (token.type === "blockquote_close") {
|
|
375
|
-
nesting = nestingStack.pop();
|
|
399
|
+
nesting = nestingStack.pop() || 0;
|
|
376
400
|
}
|
|
377
|
-
|
|
401
|
+
if (token.map) {
|
|
378
402
|
// Track last token with map
|
|
379
403
|
lastWithMap = token;
|
|
380
404
|
}
|
|
381
|
-
}
|
|
405
|
+
}
|
|
382
406
|
return flattenedLists;
|
|
383
407
|
};
|
|
384
408
|
// Calls the provided function for each specified inline child token
|
|
385
409
|
module.exports.forEachInlineChild =
|
|
386
410
|
function forEachInlineChild(params, type, handler) {
|
|
387
411
|
filterTokens(params, "inline", function forToken(token) {
|
|
388
|
-
token.children
|
|
412
|
+
for (const child of token.children) {
|
|
389
413
|
if (child.type === type) {
|
|
390
414
|
handler(child, token);
|
|
391
415
|
}
|
|
392
|
-
}
|
|
416
|
+
}
|
|
393
417
|
});
|
|
394
418
|
};
|
|
395
419
|
// Calls the provided function for each heading's content
|
|
396
420
|
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
|
397
|
-
|
|
398
|
-
params.tokens
|
|
421
|
+
let heading = null;
|
|
422
|
+
for (const token of params.tokens) {
|
|
399
423
|
if (token.type === "heading_open") {
|
|
400
424
|
heading = token;
|
|
401
425
|
}
|
|
@@ -403,9 +427,9 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
|
|
|
403
427
|
heading = null;
|
|
404
428
|
}
|
|
405
429
|
else if ((token.type === "inline") && heading) {
|
|
406
|
-
handler(heading, token.content);
|
|
430
|
+
handler(heading, token.content, token);
|
|
407
431
|
}
|
|
408
|
-
}
|
|
432
|
+
}
|
|
409
433
|
};
|
|
410
434
|
/**
|
|
411
435
|
* Calls the provided function for each inline code span's content.
|
|
@@ -416,87 +440,67 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
|
|
|
416
440
|
* @returns {void}
|
|
417
441
|
*/
|
|
418
442
|
function forEachInlineCodeSpan(input, handler) {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
while (
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
// Count backticks at start or end of code span
|
|
451
|
-
currentTicks++;
|
|
452
|
-
if ((startIndex === -1) || (startColumn === -1)) {
|
|
453
|
-
startIndex = index + 1;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
if ((startIndex >= 0) &&
|
|
458
|
-
(startColumn >= 0) &&
|
|
459
|
-
(tickCount === currentTicks)) {
|
|
460
|
-
// Found end backticks; invoke callback for code span
|
|
461
|
-
handler(input.substring(startIndex, index - currentTicks), startLine, startColumn, tickCount);
|
|
462
|
-
startIndex = -1;
|
|
463
|
-
startColumn = -1;
|
|
464
|
-
}
|
|
465
|
-
else if ((startIndex >= 0) && (startColumn === -1)) {
|
|
466
|
-
// Found start backticks
|
|
467
|
-
tickCount = currentTicks;
|
|
468
|
-
startLine = currentLine;
|
|
469
|
-
startColumn = currentColumn;
|
|
443
|
+
const backtickRe = /`+/g;
|
|
444
|
+
let match = null;
|
|
445
|
+
const backticksLengthAndIndex = [];
|
|
446
|
+
while ((match = backtickRe.exec(input)) !== null) {
|
|
447
|
+
backticksLengthAndIndex.push([match[0].length, match.index]);
|
|
448
|
+
}
|
|
449
|
+
const newLinesIndex = [];
|
|
450
|
+
while ((match = newLineRe.exec(input)) !== null) {
|
|
451
|
+
newLinesIndex.push(match.index);
|
|
452
|
+
}
|
|
453
|
+
let lineIndex = 0;
|
|
454
|
+
let lineStartIndex = 0;
|
|
455
|
+
let k = 0;
|
|
456
|
+
for (let i = 0; i < backticksLengthAndIndex.length - 1; i++) {
|
|
457
|
+
const [startLength, startIndex] = backticksLengthAndIndex[i];
|
|
458
|
+
if ((startIndex === 0) || (input[startIndex - 1] !== "\\")) {
|
|
459
|
+
for (let j = i + 1; j < backticksLengthAndIndex.length; j++) {
|
|
460
|
+
const [endLength, endIndex] = backticksLengthAndIndex[j];
|
|
461
|
+
if (startLength === endLength) {
|
|
462
|
+
for (; k < newLinesIndex.length; k++) {
|
|
463
|
+
const newLineIndex = newLinesIndex[k];
|
|
464
|
+
if (startIndex < newLineIndex) {
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
lineIndex++;
|
|
468
|
+
lineStartIndex = newLineIndex + 1;
|
|
469
|
+
}
|
|
470
|
+
const columnIndex = startIndex - lineStartIndex + startLength;
|
|
471
|
+
handler(input.slice(startIndex + startLength, endIndex), lineIndex, columnIndex, startLength);
|
|
472
|
+
i = j;
|
|
473
|
+
break;
|
|
470
474
|
}
|
|
471
|
-
// Not in backticks
|
|
472
|
-
currentTicks = 0;
|
|
473
|
-
}
|
|
474
|
-
if (char === "\n") {
|
|
475
|
-
// On next line
|
|
476
|
-
currentLine++;
|
|
477
|
-
currentColumn = 0;
|
|
478
475
|
}
|
|
479
|
-
else if ((char === "\\") &&
|
|
480
|
-
((startIndex === -1) || (startColumn === -1)) &&
|
|
481
|
-
(input[index + 1] !== "\n")) {
|
|
482
|
-
// Escape character outside code, skip next
|
|
483
|
-
index++;
|
|
484
|
-
currentColumn += 2;
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
// On next column
|
|
488
|
-
currentColumn++;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
if (startIndex >= 0) {
|
|
492
|
-
// Restart loop after unmatched start backticks (ex: "`text``code``")
|
|
493
|
-
index = startIndex;
|
|
494
|
-
currentLine = startLine;
|
|
495
|
-
currentColumn = startColumn;
|
|
496
476
|
}
|
|
497
477
|
}
|
|
498
478
|
}
|
|
499
479
|
module.exports.forEachInlineCodeSpan = forEachInlineCodeSpan;
|
|
480
|
+
/**
|
|
481
|
+
* Adds ellipsis to the left/right/middle of the specified text.
|
|
482
|
+
*
|
|
483
|
+
* @param {string} text Text to ellipsify.
|
|
484
|
+
* @param {boolean} [start] True iff the start of the text is important.
|
|
485
|
+
* @param {boolean} [end] True iff the end of the text is important.
|
|
486
|
+
* @returns {string} Ellipsified text.
|
|
487
|
+
*/
|
|
488
|
+
function ellipsify(text, start, end) {
|
|
489
|
+
if (text.length <= 30) {
|
|
490
|
+
// Nothing to do
|
|
491
|
+
}
|
|
492
|
+
else if (start && end) {
|
|
493
|
+
text = text.slice(0, 15) + "..." + text.slice(-15);
|
|
494
|
+
}
|
|
495
|
+
else if (end) {
|
|
496
|
+
text = "..." + text.slice(-30);
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
text = text.slice(0, 30) + "...";
|
|
500
|
+
}
|
|
501
|
+
return text;
|
|
502
|
+
}
|
|
503
|
+
module.exports.ellipsify = ellipsify;
|
|
500
504
|
/**
|
|
501
505
|
* Adds a generic error object via the onError callback.
|
|
502
506
|
*
|
|
@@ -510,11 +514,11 @@ module.exports.forEachInlineCodeSpan = forEachInlineCodeSpan;
|
|
|
510
514
|
*/
|
|
511
515
|
function addError(onError, lineNumber, detail, context, range, fixInfo) {
|
|
512
516
|
onError({
|
|
513
|
-
lineNumber
|
|
514
|
-
detail
|
|
515
|
-
context
|
|
516
|
-
range
|
|
517
|
-
fixInfo
|
|
517
|
+
lineNumber,
|
|
518
|
+
detail,
|
|
519
|
+
context,
|
|
520
|
+
range,
|
|
521
|
+
fixInfo
|
|
518
522
|
});
|
|
519
523
|
}
|
|
520
524
|
module.exports.addError = addError;
|
|
@@ -527,19 +531,8 @@ module.exports.addErrorDetailIf = function addErrorDetailIf(onError, lineNumber,
|
|
|
527
531
|
};
|
|
528
532
|
// Adds an error object with context via the onError callback
|
|
529
533
|
module.exports.addErrorContext = function addErrorContext(onError, lineNumber, context, left, right, range, fixInfo) {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
}
|
|
533
|
-
else if (left && right) {
|
|
534
|
-
context = context.substr(0, 15) + "..." + context.substr(-15);
|
|
535
|
-
}
|
|
536
|
-
else if (right) {
|
|
537
|
-
context = "..." + context.substr(-30);
|
|
538
|
-
}
|
|
539
|
-
else {
|
|
540
|
-
context = context.substr(0, 30) + "...";
|
|
541
|
-
}
|
|
542
|
-
addError(onError, lineNumber, null, context, range, fixInfo);
|
|
534
|
+
context = ellipsify(context, left, right);
|
|
535
|
+
addError(onError, lineNumber, undefined, context, range, fixInfo);
|
|
543
536
|
};
|
|
544
537
|
/**
|
|
545
538
|
* Returns an array of code block and span content ranges.
|
|
@@ -548,22 +541,21 @@ module.exports.addErrorContext = function addErrorContext(onError, lineNumber, c
|
|
|
548
541
|
* @param {Object} lineMetadata Line metadata object.
|
|
549
542
|
* @returns {number[][]} Array of ranges (lineIndex, columnIndex, length).
|
|
550
543
|
*/
|
|
551
|
-
module.exports.codeBlockAndSpanRanges =
|
|
552
|
-
|
|
544
|
+
module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => {
|
|
545
|
+
const exclusions = [];
|
|
553
546
|
// Add code block ranges (excludes fences)
|
|
554
|
-
forEachLine(lineMetadata,
|
|
547
|
+
forEachLine(lineMetadata, (line, lineIndex, inCode, onFence) => {
|
|
555
548
|
if (inCode && !onFence) {
|
|
556
549
|
exclusions.push([lineIndex, 0, line.length]);
|
|
557
550
|
}
|
|
558
551
|
});
|
|
559
552
|
// Add code span ranges (excludes ticks)
|
|
560
|
-
filterTokens(params, "inline",
|
|
561
|
-
if (token.children.some(
|
|
562
|
-
|
|
563
|
-
forEachInlineCodeSpan(tokenLines.join("\n"),
|
|
564
|
-
|
|
565
|
-
for (
|
|
566
|
-
var _b = _a[_i], i = _b[0], line = _b[1];
|
|
553
|
+
filterTokens(params, "inline", (token) => {
|
|
554
|
+
if (token.children.some((child) => child.type === "code_inline")) {
|
|
555
|
+
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
|
556
|
+
forEachInlineCodeSpan(tokenLines.join("\n"), (code, lineIndex, columnIndex) => {
|
|
557
|
+
const codeLines = code.split(newLineRe);
|
|
558
|
+
for (const [i, line] of codeLines.entries()) {
|
|
567
559
|
exclusions.push([
|
|
568
560
|
token.lineNumber - 1 + lineIndex + i,
|
|
569
561
|
i ? 0 : columnIndex,
|
|
@@ -576,24 +568,43 @@ module.exports.codeBlockAndSpanRanges = function (params, lineMetadata) {
|
|
|
576
568
|
return exclusions;
|
|
577
569
|
};
|
|
578
570
|
/**
|
|
579
|
-
*
|
|
571
|
+
* Returns an array of HTML element ranges.
|
|
572
|
+
*
|
|
573
|
+
* @param {Object} params RuleParams instance.
|
|
574
|
+
* @param {Object} lineMetadata Line metadata object.
|
|
575
|
+
* @returns {number[][]} Array of ranges (lineIndex, columnIndex, length).
|
|
576
|
+
*/
|
|
577
|
+
module.exports.htmlElementRanges = (params, lineMetadata) => {
|
|
578
|
+
const exclusions = [];
|
|
579
|
+
forEachLine(lineMetadata, (line, lineIndex, inCode) => {
|
|
580
|
+
let match = null;
|
|
581
|
+
// eslint-disable-next-line no-unmodified-loop-condition
|
|
582
|
+
while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) {
|
|
583
|
+
exclusions.push([lineIndex, match.index, match[0].length]);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
return exclusions;
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* Determines whether the specified range is within another range.
|
|
580
590
|
*
|
|
581
591
|
* @param {number[][]} ranges Array of ranges (line, index, length).
|
|
582
592
|
* @param {number} lineIndex Line index to check.
|
|
583
593
|
* @param {number} index Index to check.
|
|
584
594
|
* @param {number} length Length to check.
|
|
585
|
-
* @returns {boolean} True iff the specified range
|
|
595
|
+
* @returns {boolean} True iff the specified range is within.
|
|
586
596
|
*/
|
|
587
|
-
|
|
588
|
-
(index
|
|
589
|
-
(index > span[1] + span[2]))
|
|
597
|
+
const withinAnyRange = (ranges, lineIndex, index, length) => (!ranges.every((span) => ((lineIndex !== span[0]) ||
|
|
598
|
+
(index < span[1]) ||
|
|
599
|
+
(index + length > span[1] + span[2]))));
|
|
600
|
+
module.exports.withinAnyRange = withinAnyRange;
|
|
590
601
|
// Returns a range object for a line by applying a RegExp
|
|
591
602
|
module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
|
592
|
-
|
|
593
|
-
|
|
603
|
+
let range = null;
|
|
604
|
+
const match = line.match(regexp);
|
|
594
605
|
if (match) {
|
|
595
|
-
|
|
596
|
-
|
|
606
|
+
const column = match.index + 1;
|
|
607
|
+
const length = match[0].length;
|
|
597
608
|
range = [column, length];
|
|
598
609
|
}
|
|
599
610
|
return range;
|
|
@@ -601,11 +612,94 @@ module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
|
|
601
612
|
// Determines if the front matter includes a title
|
|
602
613
|
module.exports.frontMatterHasTitle =
|
|
603
614
|
function frontMatterHasTitle(frontMatterLines, frontMatterTitlePattern) {
|
|
604
|
-
|
|
605
|
-
|
|
615
|
+
const ignoreFrontMatter = (frontMatterTitlePattern !== undefined) && !frontMatterTitlePattern;
|
|
616
|
+
const frontMatterTitleRe = new RegExp(String(frontMatterTitlePattern || "^\\s*\"?title\"?\\s*[:=]"), "i");
|
|
606
617
|
return !ignoreFrontMatter &&
|
|
607
|
-
frontMatterLines.some(
|
|
618
|
+
frontMatterLines.some((line) => frontMatterTitleRe.test(line));
|
|
619
|
+
};
|
|
620
|
+
/**
|
|
621
|
+
* Calls the provided function for each link.
|
|
622
|
+
*
|
|
623
|
+
* @param {string} line Line of Markdown input.
|
|
624
|
+
* @param {Function} handler Function taking (index, link, text, destination).
|
|
625
|
+
* @returns {void}
|
|
626
|
+
*/
|
|
627
|
+
function forEachLink(line, handler) {
|
|
628
|
+
// Helper to find matching close symbol for link text/destination
|
|
629
|
+
const findClosingSymbol = (index) => {
|
|
630
|
+
const begin = line[index];
|
|
631
|
+
const end = (begin === "[") ? "]" : ")";
|
|
632
|
+
let nesting = 0;
|
|
633
|
+
let escaping = false;
|
|
634
|
+
let pointy = false;
|
|
635
|
+
for (let i = index + 1; i < line.length; i++) {
|
|
636
|
+
const current = line[i];
|
|
637
|
+
if (current === "\\") {
|
|
638
|
+
escaping = !escaping;
|
|
639
|
+
}
|
|
640
|
+
else if (!escaping && (current === begin)) {
|
|
641
|
+
nesting++;
|
|
642
|
+
}
|
|
643
|
+
else if (!escaping && (current === end)) {
|
|
644
|
+
if (nesting > 0) {
|
|
645
|
+
nesting--;
|
|
646
|
+
}
|
|
647
|
+
else if (!pointy) {
|
|
648
|
+
// Return index after matching close symbol
|
|
649
|
+
return i + 1;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
else if ((i === index + 1) && (begin === "(") && (current === "<")) {
|
|
653
|
+
pointy = true;
|
|
654
|
+
}
|
|
655
|
+
else if (!escaping && pointy && current === ">") {
|
|
656
|
+
pointy = false;
|
|
657
|
+
nesting = 0;
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
escaping = false;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
// No match found
|
|
664
|
+
return -1;
|
|
608
665
|
};
|
|
666
|
+
// Scan line for unescaped "[" character
|
|
667
|
+
let escaping = false;
|
|
668
|
+
for (let i = 0; i < line.length; i++) {
|
|
669
|
+
const current = line[i];
|
|
670
|
+
if (current === "\\") {
|
|
671
|
+
escaping = !escaping;
|
|
672
|
+
}
|
|
673
|
+
else if (!escaping && (current === "[")) {
|
|
674
|
+
// Scan for matching close "]" of link text
|
|
675
|
+
const textEnd = findClosingSymbol(i);
|
|
676
|
+
if (textEnd !== -1) {
|
|
677
|
+
if ((line[textEnd] === "(") || (line[textEnd] === "[")) {
|
|
678
|
+
// Scan for matching close ")" or "]" of link destination
|
|
679
|
+
const destEnd = findClosingSymbol(textEnd);
|
|
680
|
+
if (destEnd !== -1) {
|
|
681
|
+
// Call handler with link text and destination
|
|
682
|
+
const link = line.slice(i, destEnd);
|
|
683
|
+
const text = line.slice(i, textEnd);
|
|
684
|
+
const dest = line.slice(textEnd, destEnd);
|
|
685
|
+
handler(i, link, text, dest);
|
|
686
|
+
i = destEnd;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
if (i < textEnd) {
|
|
690
|
+
// Call handler with link text only
|
|
691
|
+
const text = line.slice(i, textEnd);
|
|
692
|
+
handler(i, text, text);
|
|
693
|
+
i = textEnd;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
escaping = false;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
module.exports.forEachLink = forEachLink;
|
|
609
703
|
/**
|
|
610
704
|
* Returns a list of emphasis markers in code spans and links.
|
|
611
705
|
*
|
|
@@ -613,56 +707,182 @@ module.exports.frontMatterHasTitle =
|
|
|
613
707
|
* @returns {number[][]} List of markers.
|
|
614
708
|
*/
|
|
615
709
|
function emphasisMarkersInContent(params) {
|
|
616
|
-
|
|
617
|
-
|
|
710
|
+
const { lines } = params;
|
|
711
|
+
const byLine = new Array(lines.length);
|
|
618
712
|
// Search links
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
inLine.push(linkMatch.index + markerMatch.index);
|
|
713
|
+
for (const [tokenLineIndex, tokenLine] of lines.entries()) {
|
|
714
|
+
const inLine = [];
|
|
715
|
+
forEachLink(tokenLine, (index, match) => {
|
|
716
|
+
let markerMatch = null;
|
|
717
|
+
while ((markerMatch = emphasisMarkersRe.exec(match))) {
|
|
718
|
+
inLine.push(index + markerMatch.index);
|
|
626
719
|
}
|
|
627
|
-
}
|
|
720
|
+
});
|
|
628
721
|
byLine[tokenLineIndex] = inLine;
|
|
629
|
-
}
|
|
722
|
+
}
|
|
630
723
|
// Search code spans
|
|
631
|
-
filterTokens(params, "inline",
|
|
632
|
-
|
|
633
|
-
if (children.some(
|
|
634
|
-
|
|
635
|
-
forEachInlineCodeSpan(tokenLines.join("\n"),
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
724
|
+
filterTokens(params, "inline", (token) => {
|
|
725
|
+
const { children, lineNumber, map } = token;
|
|
726
|
+
if (children.some((child) => child.type === "code_inline")) {
|
|
727
|
+
const tokenLines = lines.slice(map[0], map[1]);
|
|
728
|
+
forEachInlineCodeSpan(tokenLines.join("\n"), (code, lineIndex, column, tickCount) => {
|
|
729
|
+
const codeLines = code.split(newLineRe);
|
|
730
|
+
for (const [codeLineIndex, codeLine] of codeLines.entries()) {
|
|
731
|
+
const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
|
|
732
|
+
const inLine = byLine[byLineIndex];
|
|
733
|
+
const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
|
|
734
|
+
let match = null;
|
|
642
735
|
while ((match = emphasisMarkersRe.exec(codeLine))) {
|
|
643
736
|
inLine.push(codeLineOffset + match.index);
|
|
644
737
|
}
|
|
645
738
|
byLine[byLineIndex] = inLine;
|
|
646
|
-
}
|
|
739
|
+
}
|
|
647
740
|
});
|
|
648
741
|
}
|
|
649
742
|
});
|
|
650
743
|
return byLine;
|
|
651
744
|
}
|
|
652
745
|
module.exports.emphasisMarkersInContent = emphasisMarkersInContent;
|
|
746
|
+
/**
|
|
747
|
+
* Returns an object with information about reference links and images.
|
|
748
|
+
*
|
|
749
|
+
* @param {Object} lineMetadata Line metadata object.
|
|
750
|
+
* @returns {Object} Reference link/image data.
|
|
751
|
+
*/
|
|
752
|
+
function getReferenceLinkImageData(lineMetadata) {
|
|
753
|
+
// Initialize return values
|
|
754
|
+
const references = new Map();
|
|
755
|
+
const shortcuts = new Set();
|
|
756
|
+
const definitions = new Map();
|
|
757
|
+
const duplicateDefinitions = [];
|
|
758
|
+
// Define helper functions
|
|
759
|
+
const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
|
|
760
|
+
const exclusions = [];
|
|
761
|
+
const excluded = (match) => withinAnyRange(exclusions, 0, match.index, match[0].length - (match[3] || "").length);
|
|
762
|
+
// Convert input to single-line so multi-line links/images are easier
|
|
763
|
+
const lineOffsets = [];
|
|
764
|
+
let currentOffset = 0;
|
|
765
|
+
const contentLines = [];
|
|
766
|
+
forEachLine(lineMetadata, (line, lineIndex, inCode) => {
|
|
767
|
+
lineOffsets[lineIndex] = currentOffset;
|
|
768
|
+
if (!inCode) {
|
|
769
|
+
line = line.replace(blockquotePrefixRe, "");
|
|
770
|
+
if (line.trim().length === 0) {
|
|
771
|
+
// Allow RegExp to detect the end of a block
|
|
772
|
+
line = "\0";
|
|
773
|
+
}
|
|
774
|
+
contentLines.push(line);
|
|
775
|
+
currentOffset += line.length + 1;
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
lineOffsets.push(currentOffset);
|
|
779
|
+
const contentLine = contentLines.join(" ");
|
|
780
|
+
// Determine single-line exclusions for inline code spans
|
|
781
|
+
forEachInlineCodeSpan(contentLine, (code, lineIndex, columnIndex) => {
|
|
782
|
+
exclusions.push([0, columnIndex, code.length]);
|
|
783
|
+
});
|
|
784
|
+
// Identify all link/image reference definitions
|
|
785
|
+
forEachLine(lineMetadata, (line, lineIndex, inCode) => {
|
|
786
|
+
if (!inCode) {
|
|
787
|
+
const linkReferenceDefinitionMatch = linkReferenceDefinitionRe.exec(line);
|
|
788
|
+
if (linkReferenceDefinitionMatch) {
|
|
789
|
+
const label = normalizeLabel(linkReferenceDefinitionMatch[1]);
|
|
790
|
+
if (definitions.has(label)) {
|
|
791
|
+
duplicateDefinitions.push([label, lineIndex]);
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
definitions.set(label, lineIndex);
|
|
795
|
+
}
|
|
796
|
+
exclusions.push([0, lineOffsets[lineIndex], line.length]);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
// Identify all link and image references
|
|
801
|
+
let lineIndex = 0;
|
|
802
|
+
const pendingContents = [
|
|
803
|
+
{
|
|
804
|
+
"content": contentLine,
|
|
805
|
+
"contentLineIndex": 0,
|
|
806
|
+
"contentIndex": 0,
|
|
807
|
+
"topLevel": true
|
|
808
|
+
}
|
|
809
|
+
];
|
|
810
|
+
let pendingContent = null;
|
|
811
|
+
while ((pendingContent = pendingContents.shift())) {
|
|
812
|
+
const { content, contentLineIndex, contentIndex, topLevel } = pendingContent;
|
|
813
|
+
let referenceLinkMatch = null;
|
|
814
|
+
while ((referenceLinkMatch = referenceLinkRe.exec(content)) !== null) {
|
|
815
|
+
const [matchString, matchText, matchLabel] = referenceLinkMatch;
|
|
816
|
+
if (!matchString.startsWith("\\") &&
|
|
817
|
+
!matchString.startsWith("!\\") &&
|
|
818
|
+
!matchText.endsWith("\\") &&
|
|
819
|
+
!(matchLabel || "").endsWith("\\") &&
|
|
820
|
+
!(topLevel && excluded(referenceLinkMatch))) {
|
|
821
|
+
const shortcutLink = (matchLabel === undefined);
|
|
822
|
+
const collapsedLink = (!shortcutLink && (matchLabel.length === 0));
|
|
823
|
+
const label = normalizeLabel((shortcutLink || collapsedLink) ? matchText : matchLabel);
|
|
824
|
+
if (label.length > 0) {
|
|
825
|
+
const referenceindex = referenceLinkMatch.index;
|
|
826
|
+
if (topLevel) {
|
|
827
|
+
// Calculate line index
|
|
828
|
+
while (lineOffsets[lineIndex + 1] <= referenceindex) {
|
|
829
|
+
lineIndex++;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
// Use provided line index
|
|
834
|
+
lineIndex = contentLineIndex;
|
|
835
|
+
}
|
|
836
|
+
const referenceIndex = referenceindex +
|
|
837
|
+
(topLevel ? -lineOffsets[lineIndex] : contentIndex);
|
|
838
|
+
if (shortcutLink) {
|
|
839
|
+
// Track separately due to ambiguity in "text [text] text"
|
|
840
|
+
shortcuts.add(label);
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
// Track reference and location
|
|
844
|
+
const referenceData = references.get(label) || [];
|
|
845
|
+
referenceData.push([
|
|
846
|
+
lineIndex,
|
|
847
|
+
referenceIndex,
|
|
848
|
+
matchString.length
|
|
849
|
+
]);
|
|
850
|
+
references.set(label, referenceData);
|
|
851
|
+
}
|
|
852
|
+
// Check for links embedded in brackets
|
|
853
|
+
if (!matchString.startsWith("!")) {
|
|
854
|
+
pendingContents.push({
|
|
855
|
+
"content": matchText,
|
|
856
|
+
"contentLineIndex": lineIndex,
|
|
857
|
+
"contentIndex": referenceIndex + 1,
|
|
858
|
+
"topLevel": false
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return {
|
|
866
|
+
references,
|
|
867
|
+
shortcuts,
|
|
868
|
+
definitions,
|
|
869
|
+
duplicateDefinitions
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
module.exports.getReferenceLinkImageData = getReferenceLinkImageData;
|
|
653
873
|
/**
|
|
654
874
|
* Gets the most common line ending, falling back to the platform default.
|
|
655
875
|
*
|
|
656
876
|
* @param {string} input Markdown content to analyze.
|
|
657
|
-
* @param {
|
|
877
|
+
* @param {Object} [os] Node.js "os" module.
|
|
658
878
|
* @returns {string} Preferred line ending.
|
|
659
879
|
*/
|
|
660
|
-
function getPreferredLineEnding(input,
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
880
|
+
function getPreferredLineEnding(input, os) {
|
|
881
|
+
let cr = 0;
|
|
882
|
+
let lf = 0;
|
|
883
|
+
let crlf = 0;
|
|
884
|
+
const endings = input.match(newLineRe) || [];
|
|
885
|
+
for (const ending of endings) {
|
|
666
886
|
// eslint-disable-next-line default-case
|
|
667
887
|
switch (ending) {
|
|
668
888
|
case "\r":
|
|
@@ -675,11 +895,10 @@ function getPreferredLineEnding(input, platform) {
|
|
|
675
895
|
crlf++;
|
|
676
896
|
break;
|
|
677
897
|
}
|
|
678
|
-
}
|
|
679
|
-
|
|
898
|
+
}
|
|
899
|
+
let preferredLineEnding = null;
|
|
680
900
|
if (!cr && !lf && !crlf) {
|
|
681
|
-
preferredLineEnding =
|
|
682
|
-
((platform || process.platform) === "win32") ? "\r\n" : "\n";
|
|
901
|
+
preferredLineEnding = (os && os.EOL) || "\n";
|
|
683
902
|
}
|
|
684
903
|
else if ((lf >= crlf) && (lf >= cr)) {
|
|
685
904
|
preferredLineEnding = "\n";
|
|
@@ -713,12 +932,12 @@ function normalizeFixInfo(fixInfo, lineNumber) {
|
|
|
713
932
|
*
|
|
714
933
|
* @param {string} line Line of Markdown content.
|
|
715
934
|
* @param {Object} fixInfo RuleOnErrorFixInfo instance.
|
|
716
|
-
* @param {string} lineEnding Line ending to use.
|
|
717
|
-
* @returns {string} Fixed content.
|
|
935
|
+
* @param {string} [lineEnding] Line ending to use.
|
|
936
|
+
* @returns {string | null} Fixed content.
|
|
718
937
|
*/
|
|
719
938
|
function applyFix(line, fixInfo, lineEnding) {
|
|
720
|
-
|
|
721
|
-
|
|
939
|
+
const { editColumn, deleteCount, insertText } = normalizeFixInfo(fixInfo);
|
|
940
|
+
const editIndex = editColumn - 1;
|
|
722
941
|
return (deleteCount === -1) ?
|
|
723
942
|
null :
|
|
724
943
|
line.slice(0, editIndex) +
|
|
@@ -726,27 +945,33 @@ function applyFix(line, fixInfo, lineEnding) {
|
|
|
726
945
|
line.slice(editIndex + deleteCount);
|
|
727
946
|
}
|
|
728
947
|
module.exports.applyFix = applyFix;
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
948
|
+
/**
|
|
949
|
+
* Applies as many fixes as possible to Markdown content.
|
|
950
|
+
*
|
|
951
|
+
* @param {string} input Lines of Markdown content.
|
|
952
|
+
* @param {Object[]} errors RuleOnErrorInfo instances.
|
|
953
|
+
* @returns {string} Corrected content.
|
|
954
|
+
*/
|
|
955
|
+
function applyFixes(input, errors) {
|
|
956
|
+
const lineEnding = getPreferredLineEnding(input, __webpack_require__(/*! os */ "?591e"));
|
|
957
|
+
const lines = input.split(newLineRe);
|
|
733
958
|
// Normalize fixInfo objects
|
|
734
|
-
|
|
735
|
-
.filter(
|
|
736
|
-
.map(
|
|
959
|
+
let fixInfos = errors
|
|
960
|
+
.filter((error) => error.fixInfo)
|
|
961
|
+
.map((error) => normalizeFixInfo(error.fixInfo, error.lineNumber));
|
|
737
962
|
// Sort bottom-to-top, line-deletes last, right-to-left, long-to-short
|
|
738
|
-
fixInfos.sort(
|
|
739
|
-
|
|
740
|
-
|
|
963
|
+
fixInfos.sort((a, b) => {
|
|
964
|
+
const aDeletingLine = (a.deleteCount === -1);
|
|
965
|
+
const bDeletingLine = (b.deleteCount === -1);
|
|
741
966
|
return ((b.lineNumber - a.lineNumber) ||
|
|
742
967
|
(aDeletingLine ? 1 : (bDeletingLine ? -1 : 0)) ||
|
|
743
968
|
(b.editColumn - a.editColumn) ||
|
|
744
969
|
(b.insertText.length - a.insertText.length));
|
|
745
970
|
});
|
|
746
971
|
// Remove duplicate entries (needed for following collapse step)
|
|
747
|
-
|
|
748
|
-
fixInfos = fixInfos.filter(
|
|
749
|
-
|
|
972
|
+
let lastFixInfo = {};
|
|
973
|
+
fixInfos = fixInfos.filter((fixInfo) => {
|
|
974
|
+
const unique = ((fixInfo.lineNumber !== lastFixInfo.lineNumber) ||
|
|
750
975
|
(fixInfo.editColumn !== lastFixInfo.editColumn) ||
|
|
751
976
|
(fixInfo.deleteCount !== lastFixInfo.deleteCount) ||
|
|
752
977
|
(fixInfo.insertText !== lastFixInfo.insertText));
|
|
@@ -754,8 +979,10 @@ module.exports.applyFixes = function applyFixes(input, errors) {
|
|
|
754
979
|
return unique;
|
|
755
980
|
});
|
|
756
981
|
// Collapse insert/no-delete and no-insert/delete for same line/column
|
|
757
|
-
lastFixInfo = {
|
|
758
|
-
|
|
982
|
+
lastFixInfo = {
|
|
983
|
+
"lineNumber": -1
|
|
984
|
+
};
|
|
985
|
+
for (const fixInfo of fixInfos) {
|
|
759
986
|
if ((fixInfo.lineNumber === lastFixInfo.lineNumber) &&
|
|
760
987
|
(fixInfo.editColumn === lastFixInfo.editColumn) &&
|
|
761
988
|
!fixInfo.insertText &&
|
|
@@ -766,27 +993,29 @@ module.exports.applyFixes = function applyFixes(input, errors) {
|
|
|
766
993
|
lastFixInfo.lineNumber = 0;
|
|
767
994
|
}
|
|
768
995
|
lastFixInfo = fixInfo;
|
|
769
|
-
}
|
|
770
|
-
fixInfos = fixInfos.filter(
|
|
996
|
+
}
|
|
997
|
+
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber);
|
|
771
998
|
// Apply all (remaining/updated) fixes
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
999
|
+
let lastLineIndex = -1;
|
|
1000
|
+
let lastEditIndex = -1;
|
|
1001
|
+
for (const fixInfo of fixInfos) {
|
|
1002
|
+
const { lineNumber, editColumn, deleteCount } = fixInfo;
|
|
1003
|
+
const lineIndex = lineNumber - 1;
|
|
1004
|
+
const editIndex = editColumn - 1;
|
|
778
1005
|
if ((lineIndex !== lastLineIndex) ||
|
|
779
1006
|
(deleteCount === -1) ||
|
|
780
1007
|
((editIndex + deleteCount) <=
|
|
781
1008
|
(lastEditIndex - ((deleteCount > 0) ? 0 : 1)))) {
|
|
1009
|
+
// @ts-ignore
|
|
782
1010
|
lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding);
|
|
783
1011
|
}
|
|
784
1012
|
lastLineIndex = lineIndex;
|
|
785
1013
|
lastEditIndex = editIndex;
|
|
786
|
-
}
|
|
1014
|
+
}
|
|
787
1015
|
// Return corrected input
|
|
788
|
-
return lines.filter(
|
|
789
|
-
}
|
|
1016
|
+
return lines.filter((line) => line !== null).join(lineEnding);
|
|
1017
|
+
}
|
|
1018
|
+
module.exports.applyFixes = applyFixes;
|
|
790
1019
|
/**
|
|
791
1020
|
* Gets the range and fixInfo values for reporting an error if the expected
|
|
792
1021
|
* text is found on the specified line.
|
|
@@ -795,28 +1024,33 @@ module.exports.applyFixes = function applyFixes(input, errors) {
|
|
|
795
1024
|
* @param {number} lineIndex Line index to check.
|
|
796
1025
|
* @param {string} search Text to search for.
|
|
797
1026
|
* @param {string} replace Text to replace with.
|
|
1027
|
+
* @param {number} [instance] Instance on the line (1-based).
|
|
798
1028
|
* @returns {Object} Range and fixInfo wrapper.
|
|
799
1029
|
*/
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1030
|
+
module.exports.getRangeAndFixInfoIfFound =
|
|
1031
|
+
(lines, lineIndex, search, replace, instance = 1) => {
|
|
1032
|
+
let range = null;
|
|
1033
|
+
let fixInfo = null;
|
|
1034
|
+
let searchIndex = -1;
|
|
1035
|
+
while (instance > 0) {
|
|
1036
|
+
searchIndex = lines[lineIndex].indexOf(search, searchIndex + 1);
|
|
1037
|
+
instance--;
|
|
1038
|
+
}
|
|
1039
|
+
if (searchIndex !== -1) {
|
|
1040
|
+
const column = searchIndex + 1;
|
|
1041
|
+
const length = search.length;
|
|
1042
|
+
range = [column, length];
|
|
1043
|
+
fixInfo = {
|
|
1044
|
+
"editColumn": column,
|
|
1045
|
+
"deleteCount": length,
|
|
1046
|
+
"insertText": replace
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
return {
|
|
1050
|
+
range,
|
|
1051
|
+
fixInfo
|
|
812
1052
|
};
|
|
813
|
-
}
|
|
814
|
-
return {
|
|
815
|
-
range: range,
|
|
816
|
-
fixInfo: fixInfo
|
|
817
1053
|
};
|
|
818
|
-
}
|
|
819
|
-
module.exports.getRangeAndFixInfoIfFound = getRangeAndFixInfoIfFound;
|
|
820
1054
|
/**
|
|
821
1055
|
* Gets the next (subsequent) child token if it is of the expected type.
|
|
822
1056
|
*
|
|
@@ -827,8 +1061,8 @@ module.exports.getRangeAndFixInfoIfFound = getRangeAndFixInfoIfFound;
|
|
|
827
1061
|
* @returns {Object} Next token.
|
|
828
1062
|
*/
|
|
829
1063
|
function getNextChildToken(parentToken, childToken, nextType, nextNextType) {
|
|
830
|
-
|
|
831
|
-
|
|
1064
|
+
const { children } = parentToken;
|
|
1065
|
+
const index = children.indexOf(childToken);
|
|
832
1066
|
if ((index !== -1) &&
|
|
833
1067
|
(children.length > index + 2) &&
|
|
834
1068
|
(children[index + 1].type === nextType) &&
|
|
@@ -839,28 +1073,79 @@ function getNextChildToken(parentToken, childToken, nextType, nextNextType) {
|
|
|
839
1073
|
}
|
|
840
1074
|
module.exports.getNextChildToken = getNextChildToken;
|
|
841
1075
|
/**
|
|
842
|
-
*
|
|
1076
|
+
* Expands a path with a tilde to an absolute path.
|
|
843
1077
|
*
|
|
844
|
-
* @param {
|
|
845
|
-
* @
|
|
1078
|
+
* @param {string} file Path that may begin with a tilde.
|
|
1079
|
+
* @param {Object} os Node.js "os" module.
|
|
1080
|
+
* @returns {string} Absolute path (or original path).
|
|
846
1081
|
*/
|
|
847
|
-
function
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
while ((current = pending.shift())) {
|
|
851
|
-
Object.freeze(current);
|
|
852
|
-
for (var _i = 0, _a = Object.getOwnPropertyNames(current); _i < _a.length; _i++) {
|
|
853
|
-
var name = _a[_i];
|
|
854
|
-
var value = current[name];
|
|
855
|
-
if (value && (typeof value === "object")) {
|
|
856
|
-
pending.push(value);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
return obj;
|
|
1082
|
+
function expandTildePath(file, os) {
|
|
1083
|
+
const homedir = os && os.homedir && os.homedir();
|
|
1084
|
+
return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file;
|
|
861
1085
|
}
|
|
862
|
-
module.exports.
|
|
1086
|
+
module.exports.expandTildePath = expandTildePath;
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
/***/ }),
|
|
1090
|
+
|
|
1091
|
+
/***/ "markdown-it":
|
|
1092
|
+
/*!*****************************!*\
|
|
1093
|
+
!*** external "markdownit" ***!
|
|
1094
|
+
\*****************************/
|
|
1095
|
+
/***/ ((module) => {
|
|
1096
|
+
|
|
1097
|
+
"use strict";
|
|
1098
|
+
module.exports = markdownit;
|
|
1099
|
+
|
|
1100
|
+
/***/ }),
|
|
1101
|
+
|
|
1102
|
+
/***/ "?591e":
|
|
1103
|
+
/*!********************!*\
|
|
1104
|
+
!*** os (ignored) ***!
|
|
1105
|
+
\********************/
|
|
1106
|
+
/***/ (() => {
|
|
1107
|
+
|
|
1108
|
+
/* (ignored) */
|
|
1109
|
+
|
|
1110
|
+
/***/ }),
|
|
1111
|
+
|
|
1112
|
+
/***/ "?ec0a":
|
|
1113
|
+
/*!********************!*\
|
|
1114
|
+
!*** fs (ignored) ***!
|
|
1115
|
+
\********************/
|
|
1116
|
+
/***/ (() => {
|
|
1117
|
+
|
|
1118
|
+
/* (ignored) */
|
|
1119
|
+
|
|
1120
|
+
/***/ }),
|
|
1121
|
+
|
|
1122
|
+
/***/ "?a32b":
|
|
1123
|
+
/*!********************!*\
|
|
1124
|
+
!*** os (ignored) ***!
|
|
1125
|
+
\********************/
|
|
1126
|
+
/***/ (() => {
|
|
1127
|
+
|
|
1128
|
+
/* (ignored) */
|
|
1129
|
+
|
|
1130
|
+
/***/ }),
|
|
1131
|
+
|
|
1132
|
+
/***/ "?b85c":
|
|
1133
|
+
/*!**********************!*\
|
|
1134
|
+
!*** path (ignored) ***!
|
|
1135
|
+
\**********************/
|
|
1136
|
+
/***/ (() => {
|
|
1137
|
+
|
|
1138
|
+
/* (ignored) */
|
|
863
1139
|
|
|
1140
|
+
/***/ }),
|
|
1141
|
+
|
|
1142
|
+
/***/ "?96a2":
|
|
1143
|
+
/*!**********************!*\
|
|
1144
|
+
!*** util (ignored) ***!
|
|
1145
|
+
\**********************/
|
|
1146
|
+
/***/ (() => {
|
|
1147
|
+
|
|
1148
|
+
/* (ignored) */
|
|
864
1149
|
|
|
865
1150
|
/***/ }),
|
|
866
1151
|
|
|
@@ -873,32 +1158,23 @@ module.exports.deepFreeze = deepFreeze;
|
|
|
873
1158
|
"use strict";
|
|
874
1159
|
// @ts-check
|
|
875
1160
|
|
|
876
|
-
|
|
877
|
-
module.exports.
|
|
878
|
-
|
|
879
|
-
|
|
1161
|
+
const map = new Map();
|
|
1162
|
+
module.exports.set = (keyValuePairs) => {
|
|
1163
|
+
for (const [key, value] of Object.entries(keyValuePairs)) {
|
|
1164
|
+
map.set(key, value);
|
|
880
1165
|
}
|
|
881
|
-
return codeBlockAndSpanRanges;
|
|
882
|
-
};
|
|
883
|
-
var flattenedLists = null;
|
|
884
|
-
module.exports.flattenedLists = function (value) {
|
|
885
|
-
if (value) {
|
|
886
|
-
flattenedLists = value;
|
|
887
|
-
}
|
|
888
|
-
return flattenedLists;
|
|
889
|
-
};
|
|
890
|
-
var lineMetadata = null;
|
|
891
|
-
module.exports.lineMetadata = function (value) {
|
|
892
|
-
if (value) {
|
|
893
|
-
lineMetadata = value;
|
|
894
|
-
}
|
|
895
|
-
return lineMetadata;
|
|
896
|
-
};
|
|
897
|
-
module.exports.clear = function () {
|
|
898
|
-
codeBlockAndSpanRanges = null;
|
|
899
|
-
flattenedLists = null;
|
|
900
|
-
lineMetadata = null;
|
|
901
1166
|
};
|
|
1167
|
+
module.exports.clear = () => map.clear();
|
|
1168
|
+
module.exports.codeBlockAndSpanRanges =
|
|
1169
|
+
() => map.get("codeBlockAndSpanRanges");
|
|
1170
|
+
module.exports.flattenedLists =
|
|
1171
|
+
() => map.get("flattenedLists");
|
|
1172
|
+
module.exports.htmlElementRanges =
|
|
1173
|
+
() => map.get("htmlElementRanges");
|
|
1174
|
+
module.exports.lineMetadata =
|
|
1175
|
+
() => map.get("lineMetadata");
|
|
1176
|
+
module.exports.referenceLinkImageData =
|
|
1177
|
+
() => map.get("referenceLinkImageData");
|
|
902
1178
|
|
|
903
1179
|
|
|
904
1180
|
/***/ }),
|
|
@@ -914,7 +1190,7 @@ module.exports.clear = function () {
|
|
|
914
1190
|
|
|
915
1191
|
module.exports.deprecatedRuleNames = ["MD002", "MD006"];
|
|
916
1192
|
module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
|
|
917
|
-
module.exports.version = "0.
|
|
1193
|
+
module.exports.version = "0.26.2";
|
|
918
1194
|
|
|
919
1195
|
|
|
920
1196
|
/***/ }),
|
|
@@ -923,81 +1199,61 @@ module.exports.version = "0.25.1";
|
|
|
923
1199
|
/*!******************************!*\
|
|
924
1200
|
!*** ../lib/markdownlint.js ***!
|
|
925
1201
|
\******************************/
|
|
926
|
-
/***/ (
|
|
1202
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
927
1203
|
|
|
928
1204
|
"use strict";
|
|
929
1205
|
// @ts-check
|
|
930
1206
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
return t;
|
|
939
|
-
};
|
|
940
|
-
return __assign.apply(this, arguments);
|
|
941
|
-
};
|
|
942
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
943
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
944
|
-
if (ar || !(i in from)) {
|
|
945
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
946
|
-
ar[i] = from[i];
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
950
|
-
};
|
|
951
|
-
var path = __webpack_require__(/*! path */ "?b85c");
|
|
952
|
-
var promisify = (__webpack_require__(/*! util */ "?96a2").promisify);
|
|
953
|
-
var markdownIt = __webpack_require__(/*! markdown-it */ "markdown-it");
|
|
954
|
-
var deprecatedRuleNames = (__webpack_require__(/*! ./constants */ "../lib/constants.js").deprecatedRuleNames);
|
|
955
|
-
var rules = __webpack_require__(/*! ./rules */ "../lib/rules.js");
|
|
956
|
-
var helpers = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
957
|
-
var cache = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
1207
|
+
const path = __webpack_require__(/*! path */ "?b85c");
|
|
1208
|
+
const { promisify } = __webpack_require__(/*! util */ "?96a2");
|
|
1209
|
+
const markdownIt = __webpack_require__(/*! markdown-it */ "markdown-it");
|
|
1210
|
+
const { deprecatedRuleNames } = __webpack_require__(/*! ./constants */ "../lib/constants.js");
|
|
1211
|
+
const rules = __webpack_require__(/*! ./rules */ "../lib/rules.js");
|
|
1212
|
+
const helpers = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
1213
|
+
const cache = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
958
1214
|
// @ts-ignore
|
|
959
1215
|
// eslint-disable-next-line camelcase, max-len, no-inline-comments, no-undef
|
|
960
|
-
|
|
1216
|
+
const dynamicRequire = (typeof require === "undefined") ? __webpack_require__("../lib sync recursive") : /* c8 ignore next */ require;
|
|
961
1217
|
// Capture native require implementation for dynamic loading of modules
|
|
962
1218
|
/**
|
|
963
1219
|
* Validate the list of rules for structure and reuse.
|
|
964
1220
|
*
|
|
965
1221
|
* @param {Rule[]} ruleList List of rules.
|
|
966
1222
|
* @param {boolean} synchronous Whether to execute synchronously.
|
|
967
|
-
* @returns {
|
|
1223
|
+
* @returns {Error | null} Error message if validation fails.
|
|
968
1224
|
*/
|
|
969
1225
|
function validateRuleList(ruleList, synchronous) {
|
|
970
|
-
|
|
1226
|
+
let result = null;
|
|
971
1227
|
if (ruleList.length === rules.length) {
|
|
972
1228
|
// No need to validate if only using built-in rules
|
|
973
1229
|
return result;
|
|
974
1230
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1231
|
+
const allIds = {};
|
|
1232
|
+
for (const [index, rule] of ruleList.entries()) {
|
|
1233
|
+
const customIndex = index - rules.length;
|
|
1234
|
+
// eslint-disable-next-line no-inner-declarations, jsdoc/require-jsdoc
|
|
979
1235
|
function newError(property) {
|
|
980
1236
|
return new Error("Property '" + property + "' of custom rule at index " +
|
|
981
1237
|
customIndex + " is incorrect.");
|
|
982
1238
|
}
|
|
983
|
-
["names", "tags"]
|
|
984
|
-
|
|
1239
|
+
for (const property of ["names", "tags"]) {
|
|
1240
|
+
const value = rule[property];
|
|
985
1241
|
if (!result &&
|
|
986
1242
|
(!value || !Array.isArray(value) || (value.length === 0) ||
|
|
987
1243
|
!value.every(helpers.isString) || value.some(helpers.isEmptyString))) {
|
|
988
1244
|
result = newError(property);
|
|
989
1245
|
}
|
|
990
|
-
}
|
|
991
|
-
[
|
|
1246
|
+
}
|
|
1247
|
+
for (const propertyInfo of [
|
|
992
1248
|
["description", "string"],
|
|
993
1249
|
["function", "function"]
|
|
994
|
-
]
|
|
995
|
-
|
|
996
|
-
|
|
1250
|
+
]) {
|
|
1251
|
+
const property = propertyInfo[0];
|
|
1252
|
+
const value = rule[property];
|
|
997
1253
|
if (!result && (!value || (typeof value !== propertyInfo[1]))) {
|
|
998
1254
|
result = newError(property);
|
|
999
1255
|
}
|
|
1000
|
-
}
|
|
1256
|
+
}
|
|
1001
1257
|
if (!result &&
|
|
1002
1258
|
rule.information &&
|
|
1003
1259
|
(Object.getPrototypeOf(rule.information) !== URL.prototype)) {
|
|
@@ -1013,24 +1269,24 @@ function validateRuleList(ruleList, synchronous) {
|
|
|
1013
1269
|
" is asynchronous and can not be used in a synchronous context.");
|
|
1014
1270
|
}
|
|
1015
1271
|
if (!result) {
|
|
1016
|
-
rule.names
|
|
1017
|
-
|
|
1272
|
+
for (const name of rule.names) {
|
|
1273
|
+
const nameUpper = name.toUpperCase();
|
|
1018
1274
|
if (!result && (allIds[nameUpper] !== undefined)) {
|
|
1019
1275
|
result = new Error("Name '" + name + "' of custom rule at index " +
|
|
1020
1276
|
customIndex + " is already used as a name or tag.");
|
|
1021
1277
|
}
|
|
1022
1278
|
allIds[nameUpper] = true;
|
|
1023
|
-
}
|
|
1024
|
-
rule.tags
|
|
1025
|
-
|
|
1279
|
+
}
|
|
1280
|
+
for (const tag of rule.tags) {
|
|
1281
|
+
const tagUpper = tag.toUpperCase();
|
|
1026
1282
|
if (!result && allIds[tagUpper]) {
|
|
1027
1283
|
result = new Error("Tag '" + tag + "' of custom rule at index " +
|
|
1028
1284
|
customIndex + " is already used as a name.");
|
|
1029
1285
|
}
|
|
1030
1286
|
allIds[tagUpper] = false;
|
|
1031
|
-
}
|
|
1287
|
+
}
|
|
1032
1288
|
}
|
|
1033
|
-
}
|
|
1289
|
+
}
|
|
1034
1290
|
return result;
|
|
1035
1291
|
}
|
|
1036
1292
|
/**
|
|
@@ -1040,18 +1296,18 @@ function validateRuleList(ruleList, synchronous) {
|
|
|
1040
1296
|
* @returns {LintResults} New LintResults instance.
|
|
1041
1297
|
*/
|
|
1042
1298
|
function newResults(ruleList) {
|
|
1043
|
-
|
|
1299
|
+
const lintResults = {};
|
|
1044
1300
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1045
1301
|
function toString(useAlias) {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1302
|
+
let ruleNameToRule = null;
|
|
1303
|
+
const results = [];
|
|
1304
|
+
const keys = Object.keys(lintResults);
|
|
1049
1305
|
keys.sort();
|
|
1050
|
-
|
|
1051
|
-
|
|
1306
|
+
for (const file of keys) {
|
|
1307
|
+
const fileResults = lintResults[file];
|
|
1052
1308
|
if (Array.isArray(fileResults)) {
|
|
1053
|
-
|
|
1054
|
-
|
|
1309
|
+
for (const result of fileResults) {
|
|
1310
|
+
const ruleMoniker = result.ruleNames ?
|
|
1055
1311
|
result.ruleNames.join("/") :
|
|
1056
1312
|
(result.ruleName + "/" + result.ruleAlias);
|
|
1057
1313
|
results.push(file + ": " +
|
|
@@ -1064,30 +1320,32 @@ function newResults(ruleList) {
|
|
|
1064
1320
|
(result.errorContext ?
|
|
1065
1321
|
" [Context: \"" + result.errorContext + "\"]" :
|
|
1066
1322
|
""));
|
|
1067
|
-
}
|
|
1323
|
+
}
|
|
1068
1324
|
}
|
|
1069
1325
|
else {
|
|
1070
1326
|
if (!ruleNameToRule) {
|
|
1071
1327
|
ruleNameToRule = {};
|
|
1072
|
-
|
|
1073
|
-
|
|
1328
|
+
for (const rule of ruleList) {
|
|
1329
|
+
const ruleName = rule.names[0].toUpperCase();
|
|
1074
1330
|
ruleNameToRule[ruleName] = rule;
|
|
1075
|
-
}
|
|
1331
|
+
}
|
|
1076
1332
|
}
|
|
1077
|
-
Object.
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1333
|
+
for (const [ruleName, ruleResults] of Object.entries(fileResults)) {
|
|
1334
|
+
const rule = ruleNameToRule[ruleName.toUpperCase()];
|
|
1335
|
+
for (const lineNumber of ruleResults) {
|
|
1336
|
+
// @ts-ignore
|
|
1337
|
+
const nameIndex = Math.min(useAlias ? 1 : 0, rule.names.length - 1);
|
|
1338
|
+
const result = file + ": " +
|
|
1083
1339
|
lineNumber + ": " +
|
|
1340
|
+
// @ts-ignore
|
|
1084
1341
|
rule.names[nameIndex] + " " +
|
|
1342
|
+
// @ts-ignore
|
|
1085
1343
|
rule.description;
|
|
1086
1344
|
results.push(result);
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1089
1347
|
}
|
|
1090
|
-
}
|
|
1348
|
+
}
|
|
1091
1349
|
return results.join("\n");
|
|
1092
1350
|
}
|
|
1093
1351
|
Object.defineProperty(lintResults, "toString", { "value": toString });
|
|
@@ -1102,11 +1360,11 @@ function newResults(ruleList) {
|
|
|
1102
1360
|
* @returns {Object} Trimmed content and front matter lines.
|
|
1103
1361
|
*/
|
|
1104
1362
|
function removeFrontMatter(content, frontMatter) {
|
|
1105
|
-
|
|
1363
|
+
let frontMatterLines = [];
|
|
1106
1364
|
if (frontMatter) {
|
|
1107
|
-
|
|
1365
|
+
const frontMatterMatch = content.match(frontMatter);
|
|
1108
1366
|
if (frontMatterMatch && !frontMatterMatch.index) {
|
|
1109
|
-
|
|
1367
|
+
const contentMatched = frontMatterMatch[0];
|
|
1110
1368
|
content = content.slice(contentMatched.length);
|
|
1111
1369
|
frontMatterLines = contentMatched.split(helpers.newLineRe);
|
|
1112
1370
|
if ((frontMatterLines.length > 0) &&
|
|
@@ -1121,15 +1379,39 @@ function removeFrontMatter(content, frontMatter) {
|
|
|
1121
1379
|
};
|
|
1122
1380
|
}
|
|
1123
1381
|
/**
|
|
1124
|
-
*
|
|
1382
|
+
* Freeze all freeze-able members of a token and its children.
|
|
1383
|
+
*
|
|
1384
|
+
* @param {MarkdownItToken} token A markdown-it token.
|
|
1385
|
+
* @returns {void}
|
|
1386
|
+
*/
|
|
1387
|
+
function freezeToken(token) {
|
|
1388
|
+
if (token.attrs) {
|
|
1389
|
+
for (const attr of token.attrs) {
|
|
1390
|
+
Object.freeze(attr);
|
|
1391
|
+
}
|
|
1392
|
+
Object.freeze(token.attrs);
|
|
1393
|
+
}
|
|
1394
|
+
if (token.children) {
|
|
1395
|
+
for (const child of token.children) {
|
|
1396
|
+
freezeToken(child);
|
|
1397
|
+
}
|
|
1398
|
+
Object.freeze(token.children);
|
|
1399
|
+
}
|
|
1400
|
+
if (token.map) {
|
|
1401
|
+
Object.freeze(token.map);
|
|
1402
|
+
}
|
|
1403
|
+
Object.freeze(token);
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Annotate tokens with line/lineNumber and freeze them.
|
|
1125
1407
|
*
|
|
1126
1408
|
* @param {MarkdownItToken[]} tokens Array of markdown-it tokens.
|
|
1127
1409
|
* @param {string[]} lines Lines of Markdown content.
|
|
1128
1410
|
* @returns {void}
|
|
1129
1411
|
*/
|
|
1130
|
-
function
|
|
1131
|
-
|
|
1132
|
-
|
|
1412
|
+
function annotateAndFreezeTokens(tokens, lines) {
|
|
1413
|
+
let trMap = null;
|
|
1414
|
+
for (const token of tokens) {
|
|
1133
1415
|
// Provide missing maps for table content
|
|
1134
1416
|
if (token.type === "tr_open") {
|
|
1135
1417
|
trMap = token.map;
|
|
@@ -1138,12 +1420,7 @@ function annotateTokens(tokens, lines) {
|
|
|
1138
1420
|
trMap = null;
|
|
1139
1421
|
}
|
|
1140
1422
|
if (!token.map && trMap) {
|
|
1141
|
-
token.map =
|
|
1142
|
-
}
|
|
1143
|
-
// Adjust maps for math blocks
|
|
1144
|
-
if (helpers.isMathBlock(token) && token.map[1]) {
|
|
1145
|
-
// markdown-it-texmath plugin does not account for math_block_end
|
|
1146
|
-
token.map[1]++;
|
|
1423
|
+
token.map = [...trMap];
|
|
1147
1424
|
}
|
|
1148
1425
|
// Update token metadata
|
|
1149
1426
|
if (token.map) {
|
|
@@ -1153,24 +1430,30 @@ function annotateTokens(tokens, lines) {
|
|
|
1153
1430
|
while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) {
|
|
1154
1431
|
token.map[1]--;
|
|
1155
1432
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1433
|
+
}
|
|
1434
|
+
// Annotate children with lineNumber
|
|
1435
|
+
if (token.children) {
|
|
1436
|
+
const codeSpanExtraLines = [];
|
|
1437
|
+
if (token.children.some((child) => child.type === "code_inline")) {
|
|
1438
|
+
helpers.forEachInlineCodeSpan(token.content, (code) => {
|
|
1439
|
+
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
let lineNumber = token.lineNumber;
|
|
1443
|
+
for (const child of token.children) {
|
|
1444
|
+
child.lineNumber = lineNumber;
|
|
1445
|
+
child.line = lines[lineNumber - 1];
|
|
1165
1446
|
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
|
1166
|
-
|
|
1447
|
+
lineNumber++;
|
|
1167
1448
|
}
|
|
1168
1449
|
else if (child.type === "code_inline") {
|
|
1169
|
-
|
|
1450
|
+
lineNumber += codeSpanExtraLines.shift();
|
|
1170
1451
|
}
|
|
1171
|
-
}
|
|
1452
|
+
}
|
|
1172
1453
|
}
|
|
1173
|
-
|
|
1454
|
+
freezeToken(token);
|
|
1455
|
+
}
|
|
1456
|
+
Object.freeze(tokens);
|
|
1174
1457
|
}
|
|
1175
1458
|
/**
|
|
1176
1459
|
* Map rule names/tags to canonical rule name.
|
|
@@ -1179,26 +1462,26 @@ function annotateTokens(tokens, lines) {
|
|
|
1179
1462
|
* @returns {Object.<string, string[]>} Map of alias to rule name.
|
|
1180
1463
|
*/
|
|
1181
1464
|
function mapAliasToRuleNames(ruleList) {
|
|
1182
|
-
|
|
1465
|
+
const aliasToRuleNames = {};
|
|
1183
1466
|
// const tagToRuleNames = {};
|
|
1184
|
-
|
|
1185
|
-
|
|
1467
|
+
for (const rule of ruleList) {
|
|
1468
|
+
const ruleName = rule.names[0].toUpperCase();
|
|
1186
1469
|
// The following is useful for updating README.md:
|
|
1187
1470
|
// console.log(
|
|
1188
1471
|
// "* **[" + ruleName + "](doc/Rules.md#" + ruleName.toLowerCase() +
|
|
1189
1472
|
// ")** *" + rule.names.slice(1).join("/") + "* - " + rule.description);
|
|
1190
|
-
rule.names
|
|
1191
|
-
|
|
1473
|
+
for (const name of rule.names) {
|
|
1474
|
+
const nameUpper = name.toUpperCase();
|
|
1192
1475
|
aliasToRuleNames[nameUpper] = [ruleName];
|
|
1193
|
-
}
|
|
1194
|
-
rule.tags
|
|
1195
|
-
|
|
1196
|
-
|
|
1476
|
+
}
|
|
1477
|
+
for (const tag of rule.tags) {
|
|
1478
|
+
const tagUpper = tag.toUpperCase();
|
|
1479
|
+
const ruleNames = aliasToRuleNames[tagUpper] || [];
|
|
1197
1480
|
ruleNames.push(ruleName);
|
|
1198
1481
|
aliasToRuleNames[tagUpper] = ruleNames;
|
|
1199
1482
|
// tagToRuleNames[tag] = ruleName;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1202
1485
|
// The following is useful for updating README.md:
|
|
1203
1486
|
// Object.keys(tagToRuleNames).sort().forEach(function forTag(tag) {
|
|
1204
1487
|
// console.log("* **" + tag + "** - " +
|
|
@@ -1217,18 +1500,18 @@ function mapAliasToRuleNames(ruleList) {
|
|
|
1217
1500
|
* @returns {Configuration} Effective configuration.
|
|
1218
1501
|
*/
|
|
1219
1502
|
function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1503
|
+
const defaultKey = Object.keys(config).filter((key) => key.toUpperCase() === "DEFAULT");
|
|
1504
|
+
const ruleDefault = (defaultKey.length === 0) || !!config[defaultKey[0]];
|
|
1505
|
+
const effectiveConfig = {};
|
|
1506
|
+
for (const rule of ruleList) {
|
|
1507
|
+
const ruleName = rule.names[0].toUpperCase();
|
|
1225
1508
|
effectiveConfig[ruleName] = ruleDefault;
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1509
|
+
}
|
|
1510
|
+
for (const ruleName of deprecatedRuleNames) {
|
|
1228
1511
|
effectiveConfig[ruleName] = false;
|
|
1229
|
-
}
|
|
1230
|
-
Object.keys(config)
|
|
1231
|
-
|
|
1512
|
+
}
|
|
1513
|
+
for (const key of Object.keys(config)) {
|
|
1514
|
+
let value = config[key];
|
|
1232
1515
|
if (value) {
|
|
1233
1516
|
if (!(value instanceof Object)) {
|
|
1234
1517
|
value = {};
|
|
@@ -1237,13 +1520,46 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
|
|
1237
1520
|
else {
|
|
1238
1521
|
value = false;
|
|
1239
1522
|
}
|
|
1240
|
-
|
|
1241
|
-
(aliasToRuleNames[keyUpper] || [])
|
|
1523
|
+
const keyUpper = key.toUpperCase();
|
|
1524
|
+
for (const ruleName of (aliasToRuleNames[keyUpper] || [])) {
|
|
1242
1525
|
effectiveConfig[ruleName] = value;
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1245
1528
|
return effectiveConfig;
|
|
1246
1529
|
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Parse the content of a configuration file.
|
|
1532
|
+
*
|
|
1533
|
+
* @param {string} name Name of the configuration file.
|
|
1534
|
+
* @param {string} content Configuration content.
|
|
1535
|
+
* @param {ConfigurationParser[] | null} [parsers] Parsing function(s).
|
|
1536
|
+
* @returns {Object} Configuration object and error message.
|
|
1537
|
+
*/
|
|
1538
|
+
function parseConfiguration(name, content, parsers) {
|
|
1539
|
+
let config = null;
|
|
1540
|
+
let message = "";
|
|
1541
|
+
const errors = [];
|
|
1542
|
+
let index = 0;
|
|
1543
|
+
// Try each parser
|
|
1544
|
+
(parsers || [JSON.parse]).every((parser) => {
|
|
1545
|
+
try {
|
|
1546
|
+
config = parser(content);
|
|
1547
|
+
}
|
|
1548
|
+
catch (error) {
|
|
1549
|
+
errors.push(`Parser ${index++}: ${error.message}`);
|
|
1550
|
+
}
|
|
1551
|
+
return !config;
|
|
1552
|
+
});
|
|
1553
|
+
// Message if unable to parse
|
|
1554
|
+
if (!config) {
|
|
1555
|
+
errors.unshift(`Unable to parse '${name}'`);
|
|
1556
|
+
message = errors.join("; ");
|
|
1557
|
+
}
|
|
1558
|
+
return {
|
|
1559
|
+
config,
|
|
1560
|
+
message
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1247
1563
|
/**
|
|
1248
1564
|
* Create a mapping of enabled rules per line.
|
|
1249
1565
|
*
|
|
@@ -1252,57 +1568,59 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
|
|
1252
1568
|
* @param {string[]} frontMatterLines List of front matter lines.
|
|
1253
1569
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
|
1254
1570
|
* @param {Configuration} config Configuration object.
|
|
1571
|
+
* @param {ConfigurationParser[] | null} configParsers Configuration parsers.
|
|
1255
1572
|
* @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule
|
|
1256
1573
|
* names.
|
|
1257
1574
|
* @returns {Object} Effective configuration and enabled rules per line number.
|
|
1258
1575
|
*/
|
|
1259
|
-
function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlineConfig, config, aliasToRuleNames) {
|
|
1576
|
+
function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlineConfig, config, configParsers, aliasToRuleNames) {
|
|
1260
1577
|
// Shared variables
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1578
|
+
let enabledRules = {};
|
|
1579
|
+
let capturedRules = {};
|
|
1580
|
+
const allRuleNames = [];
|
|
1581
|
+
const enabledRulesPerLineNumber = new Array(1 + frontMatterLines.length);
|
|
1265
1582
|
// Helper functions
|
|
1266
1583
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1267
1584
|
function handleInlineConfig(input, forEachMatch, forEachLine) {
|
|
1268
|
-
|
|
1585
|
+
for (const [lineIndex, line] of input.entries()) {
|
|
1269
1586
|
if (!noInlineConfig) {
|
|
1270
|
-
|
|
1271
|
-
while ((match = helpers.
|
|
1272
|
-
|
|
1273
|
-
|
|
1587
|
+
let match = null;
|
|
1588
|
+
while ((match = helpers.inlineCommentStartRe.exec(line))) {
|
|
1589
|
+
const action = match[2].toUpperCase();
|
|
1590
|
+
const startIndex = match.index + match[1].length;
|
|
1591
|
+
const endIndex = line.indexOf("-->", startIndex);
|
|
1592
|
+
if (endIndex === -1) {
|
|
1593
|
+
break;
|
|
1594
|
+
}
|
|
1595
|
+
const parameter = line.slice(startIndex, endIndex);
|
|
1274
1596
|
forEachMatch(action, parameter, lineIndex + 1);
|
|
1275
1597
|
}
|
|
1276
1598
|
}
|
|
1277
1599
|
if (forEachLine) {
|
|
1278
1600
|
forEachLine();
|
|
1279
1601
|
}
|
|
1280
|
-
}
|
|
1602
|
+
}
|
|
1281
1603
|
}
|
|
1282
1604
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1283
1605
|
function configureFile(action, parameter) {
|
|
1284
1606
|
if (action === "CONFIGURE-FILE") {
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
config =
|
|
1288
|
-
}
|
|
1289
|
-
catch (_a) {
|
|
1290
|
-
// Ignore parse errors for inline configuration
|
|
1607
|
+
const { "config": parsed } = parseConfiguration("CONFIGURE-FILE", parameter, configParsers);
|
|
1608
|
+
if (parsed) {
|
|
1609
|
+
config = Object.assign(Object.assign({}, config), parsed);
|
|
1291
1610
|
}
|
|
1292
1611
|
}
|
|
1293
1612
|
}
|
|
1294
1613
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1295
1614
|
function applyEnableDisable(action, parameter, state) {
|
|
1296
|
-
state =
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
(aliasToRuleNames[nameUpper] || []).forEach(function (ruleName) {
|
|
1615
|
+
state = Object.assign({}, state);
|
|
1616
|
+
const enabled = (action.startsWith("ENABLE"));
|
|
1617
|
+
const trimmed = parameter && parameter.trim();
|
|
1618
|
+
const items = trimmed ? trimmed.toUpperCase().split(/\s+/) : allRuleNames;
|
|
1619
|
+
for (const nameUpper of items) {
|
|
1620
|
+
for (const ruleName of (aliasToRuleNames[nameUpper] || [])) {
|
|
1303
1621
|
state[ruleName] = enabled;
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1306
1624
|
return state;
|
|
1307
1625
|
}
|
|
1308
1626
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -1328,29 +1646,31 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
|
|
1328
1646
|
enabledRulesPerLineNumber.push(enabledRules);
|
|
1329
1647
|
}
|
|
1330
1648
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1331
|
-
function
|
|
1332
|
-
|
|
1333
|
-
|
|
1649
|
+
function disableLineNextLine(action, parameter, lineNumber) {
|
|
1650
|
+
const disableLine = (action === "DISABLE-LINE");
|
|
1651
|
+
const disableNextLine = (action === "DISABLE-NEXT-LINE");
|
|
1652
|
+
if (disableLine || disableNextLine) {
|
|
1653
|
+
const nextLineNumber = frontMatterLines.length + lineNumber + (disableNextLine ? 1 : 0);
|
|
1334
1654
|
enabledRulesPerLineNumber[nextLineNumber] =
|
|
1335
1655
|
applyEnableDisable(action, parameter, enabledRulesPerLineNumber[nextLineNumber] || {});
|
|
1336
1656
|
}
|
|
1337
1657
|
}
|
|
1338
1658
|
// Handle inline comments
|
|
1339
1659
|
handleInlineConfig([lines.join("\n")], configureFile);
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1660
|
+
const effectiveConfig = getEffectiveConfig(ruleList, config, aliasToRuleNames);
|
|
1661
|
+
for (const rule of ruleList) {
|
|
1662
|
+
const ruleName = rule.names[0].toUpperCase();
|
|
1343
1663
|
allRuleNames.push(ruleName);
|
|
1344
1664
|
enabledRules[ruleName] = !!effectiveConfig[ruleName];
|
|
1345
|
-
}
|
|
1665
|
+
}
|
|
1346
1666
|
capturedRules = enabledRules;
|
|
1347
1667
|
handleInlineConfig(lines, enableDisableFile);
|
|
1348
1668
|
handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState);
|
|
1349
|
-
handleInlineConfig(lines,
|
|
1669
|
+
handleInlineConfig(lines, disableLineNextLine);
|
|
1350
1670
|
// Return results
|
|
1351
1671
|
return {
|
|
1352
|
-
effectiveConfig
|
|
1353
|
-
enabledRulesPerLineNumber
|
|
1672
|
+
effectiveConfig,
|
|
1673
|
+
enabledRulesPerLineNumber
|
|
1354
1674
|
};
|
|
1355
1675
|
}
|
|
1356
1676
|
/**
|
|
@@ -1361,6 +1681,7 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
|
|
1361
1681
|
* @param {string} content Markdown content.
|
|
1362
1682
|
* @param {Object} md Instance of markdown-it.
|
|
1363
1683
|
* @param {Configuration} config Configuration object.
|
|
1684
|
+
* @param {ConfigurationParser[] | null} configParsers Configuration parsers.
|
|
1364
1685
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
|
1365
1686
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
|
1366
1687
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
|
@@ -1368,37 +1689,47 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
|
|
1368
1689
|
* @param {Function} callback Callback (err, result) function.
|
|
1369
1690
|
* @returns {void}
|
|
1370
1691
|
*/
|
|
1371
|
-
function lintContent(ruleList, name, content, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback) {
|
|
1692
|
+
function lintContent(ruleList, name, content, md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback) {
|
|
1372
1693
|
// Remove UTF-8 byte order marker (if present)
|
|
1373
1694
|
content = content.replace(/^\uFEFF/, "");
|
|
1374
1695
|
// Remove front matter
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1696
|
+
const removeFrontMatterResult = removeFrontMatter(content, frontMatter);
|
|
1697
|
+
const { frontMatterLines } = removeFrontMatterResult;
|
|
1698
|
+
content = removeFrontMatterResult.content;
|
|
1699
|
+
// Get enabled rules per line (with HTML comments present)
|
|
1700
|
+
const { effectiveConfig, enabledRulesPerLineNumber } = getEnabledRulesPerLineNumber(ruleList, content.split(helpers.newLineRe), frontMatterLines, noInlineConfig, config, configParsers, mapAliasToRuleNames(ruleList));
|
|
1701
|
+
// Hide the content of HTML comments from rules, etc.
|
|
1702
|
+
content = helpers.clearHtmlCommentText(content);
|
|
1379
1703
|
// Parse content into tokens and lines
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
"
|
|
1388
|
-
"
|
|
1389
|
-
"lines": helpers.deepFreeze(lines),
|
|
1390
|
-
"frontMatterLines": helpers.deepFreeze(frontMatterLines)
|
|
1704
|
+
const tokens = md.parse(content, {});
|
|
1705
|
+
const lines = content.split(helpers.newLineRe);
|
|
1706
|
+
annotateAndFreezeTokens(tokens, lines);
|
|
1707
|
+
// Create (frozen) parameters for rules
|
|
1708
|
+
const paramsBase = {
|
|
1709
|
+
name,
|
|
1710
|
+
tokens,
|
|
1711
|
+
"lines": Object.freeze(lines),
|
|
1712
|
+
"frontMatterLines": Object.freeze(frontMatterLines)
|
|
1391
1713
|
};
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1714
|
+
const lineMetadata = helpers.getLineMetadata(paramsBase);
|
|
1715
|
+
const codeBlockAndSpanRanges = helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata);
|
|
1716
|
+
const flattenedLists = helpers.flattenLists(paramsBase.tokens);
|
|
1717
|
+
const htmlElementRanges = helpers.htmlElementRanges(paramsBase, lineMetadata);
|
|
1718
|
+
const referenceLinkImageData = helpers.getReferenceLinkImageData(lineMetadata);
|
|
1719
|
+
cache.set({
|
|
1720
|
+
codeBlockAndSpanRanges,
|
|
1721
|
+
flattenedLists,
|
|
1722
|
+
htmlElementRanges,
|
|
1723
|
+
lineMetadata,
|
|
1724
|
+
referenceLinkImageData
|
|
1725
|
+
});
|
|
1395
1726
|
// Function to run for each rule
|
|
1396
|
-
|
|
1727
|
+
let results = [];
|
|
1397
1728
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1398
1729
|
function forRule(rule) {
|
|
1399
1730
|
// Configure rule
|
|
1400
|
-
|
|
1401
|
-
params.config
|
|
1731
|
+
const ruleName = rule.names[0].toUpperCase();
|
|
1732
|
+
const params = Object.assign(Object.assign({}, paramsBase), { "config": effectiveConfig[ruleName] });
|
|
1402
1733
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1403
1734
|
function throwError(property) {
|
|
1404
1735
|
throw new Error("Property '" + property + "' of onError parameter is incorrect.");
|
|
@@ -1411,7 +1742,7 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1411
1742
|
(errorInfo.lineNumber > lines.length)) {
|
|
1412
1743
|
throwError("lineNumber");
|
|
1413
1744
|
}
|
|
1414
|
-
|
|
1745
|
+
const lineNumber = errorInfo.lineNumber + frontMatterLines.length;
|
|
1415
1746
|
if (!enabledRulesPerLineNumber[lineNumber][ruleName]) {
|
|
1416
1747
|
return;
|
|
1417
1748
|
}
|
|
@@ -1434,8 +1765,8 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1434
1765
|
lines[errorInfo.lineNumber - 1].length))) {
|
|
1435
1766
|
throwError("range");
|
|
1436
1767
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1768
|
+
const fixInfo = errorInfo.fixInfo;
|
|
1769
|
+
const cleanFixInfo = {};
|
|
1439
1770
|
if (fixInfo) {
|
|
1440
1771
|
if (!helpers.isObject(fixInfo)) {
|
|
1441
1772
|
throwError("fixInfo");
|
|
@@ -1449,7 +1780,7 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1449
1780
|
cleanFixInfo.lineNumber =
|
|
1450
1781
|
fixInfo.lineNumber + frontMatterLines.length;
|
|
1451
1782
|
}
|
|
1452
|
-
|
|
1783
|
+
const effectiveLineNumber = fixInfo.lineNumber || errorInfo.lineNumber;
|
|
1453
1784
|
if (fixInfo.editColumn !== undefined) {
|
|
1454
1785
|
if ((!helpers.isNumber(fixInfo.editColumn) ||
|
|
1455
1786
|
(fixInfo.editColumn < 1) ||
|
|
@@ -1476,26 +1807,26 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1476
1807
|
}
|
|
1477
1808
|
}
|
|
1478
1809
|
results.push({
|
|
1479
|
-
lineNumber
|
|
1810
|
+
lineNumber,
|
|
1480
1811
|
"ruleName": rule.names[0],
|
|
1481
1812
|
"ruleNames": rule.names,
|
|
1482
1813
|
"ruleDescription": rule.description,
|
|
1483
1814
|
"ruleInformation": rule.information ? rule.information.href : null,
|
|
1484
1815
|
"errorDetail": errorInfo.detail || null,
|
|
1485
1816
|
"errorContext": errorInfo.context || null,
|
|
1486
|
-
"errorRange": errorInfo.range ?
|
|
1817
|
+
"errorRange": errorInfo.range ? [...errorInfo.range] : null,
|
|
1487
1818
|
"fixInfo": fixInfo ? cleanFixInfo : null
|
|
1488
1819
|
});
|
|
1489
1820
|
}
|
|
1490
1821
|
// Call (possibly external) rule function to report errors
|
|
1491
|
-
|
|
1822
|
+
const catchCallsOnError = (error) => onError({
|
|
1492
1823
|
"lineNumber": 1,
|
|
1493
|
-
"detail":
|
|
1494
|
-
});
|
|
1495
|
-
|
|
1824
|
+
"detail": `This rule threw an exception: ${error.message || error}`
|
|
1825
|
+
});
|
|
1826
|
+
const invokeRuleFunction = () => rule.function(params, onError);
|
|
1496
1827
|
if (rule.asynchronous) {
|
|
1497
1828
|
// Asynchronous rule, ensure it returns a Promise
|
|
1498
|
-
|
|
1829
|
+
const ruleFunctionPromise = Promise.resolve().then(invokeRuleFunction);
|
|
1499
1830
|
return handleRuleFailures ?
|
|
1500
1831
|
ruleFunctionPromise.catch(catchCallsOnError) :
|
|
1501
1832
|
ruleFunctionPromise;
|
|
@@ -1517,27 +1848,26 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1517
1848
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1518
1849
|
function formatResults() {
|
|
1519
1850
|
// Sort results by rule name by line number
|
|
1520
|
-
results.sort(
|
|
1521
|
-
a.lineNumber - b.lineNumber)
|
|
1851
|
+
results.sort((a, b) => (a.ruleName.localeCompare(b.ruleName) ||
|
|
1852
|
+
a.lineNumber - b.lineNumber));
|
|
1522
1853
|
if (resultVersion < 3) {
|
|
1523
1854
|
// Remove fixInfo and multiple errors for the same rule and line number
|
|
1524
|
-
|
|
1855
|
+
const noPrevious = {
|
|
1525
1856
|
"ruleName": null,
|
|
1526
1857
|
"lineNumber": -1
|
|
1527
1858
|
};
|
|
1528
|
-
results = results.filter(
|
|
1859
|
+
results = results.filter((error, index, array) => {
|
|
1529
1860
|
delete error.fixInfo;
|
|
1530
|
-
|
|
1861
|
+
const previous = array[index - 1] || noPrevious;
|
|
1531
1862
|
return ((error.ruleName !== previous.ruleName) ||
|
|
1532
1863
|
(error.lineNumber !== previous.lineNumber));
|
|
1533
1864
|
});
|
|
1534
1865
|
}
|
|
1535
1866
|
if (resultVersion === 0) {
|
|
1536
1867
|
// Return a dictionary of rule->[line numbers]
|
|
1537
|
-
|
|
1538
|
-
for (
|
|
1539
|
-
|
|
1540
|
-
var ruleLines = dictionary[error.ruleName] || [];
|
|
1868
|
+
const dictionary = {};
|
|
1869
|
+
for (const error of results) {
|
|
1870
|
+
const ruleLines = dictionary[error.ruleName] || [];
|
|
1541
1871
|
ruleLines.push(error.lineNumber);
|
|
1542
1872
|
dictionary[error.ruleName] = ruleLines;
|
|
1543
1873
|
}
|
|
@@ -1546,29 +1876,30 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1546
1876
|
}
|
|
1547
1877
|
else if (resultVersion === 1) {
|
|
1548
1878
|
// Use ruleAlias instead of ruleNames
|
|
1549
|
-
for (
|
|
1550
|
-
var error = results_2[_a];
|
|
1879
|
+
for (const error of results) {
|
|
1551
1880
|
error.ruleAlias = error.ruleNames[1] || error.ruleName;
|
|
1552
1881
|
delete error.ruleNames;
|
|
1553
1882
|
}
|
|
1554
1883
|
}
|
|
1555
1884
|
else {
|
|
1556
1885
|
// resultVersion 2 or 3: Remove unwanted ruleName
|
|
1557
|
-
for (
|
|
1558
|
-
var error = results_3[_b];
|
|
1886
|
+
for (const error of results) {
|
|
1559
1887
|
delete error.ruleName;
|
|
1560
1888
|
}
|
|
1561
1889
|
}
|
|
1562
1890
|
return results;
|
|
1563
1891
|
}
|
|
1564
1892
|
// Run all rules
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1893
|
+
const ruleListAsync = ruleList.filter((rule) => rule.asynchronous);
|
|
1894
|
+
const ruleListSync = ruleList.filter((rule) => !rule.asynchronous);
|
|
1895
|
+
const ruleListAsyncFirst = [
|
|
1896
|
+
...ruleListAsync,
|
|
1897
|
+
...ruleListSync
|
|
1898
|
+
];
|
|
1899
|
+
const callbackSuccess = () => callback(null, formatResults());
|
|
1900
|
+
const callbackError = (error) => callback(error instanceof Error ? error : new Error(error));
|
|
1570
1901
|
try {
|
|
1571
|
-
|
|
1902
|
+
const ruleResults = ruleListAsyncFirst.map(forRule);
|
|
1572
1903
|
if (ruleListAsync.length > 0) {
|
|
1573
1904
|
Promise.all(ruleResults.slice(0, ruleListAsync.length))
|
|
1574
1905
|
.then(callbackSuccess)
|
|
@@ -1592,6 +1923,7 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1592
1923
|
* @param {string} file Path of file to lint.
|
|
1593
1924
|
* @param {Object} md Instance of markdown-it.
|
|
1594
1925
|
* @param {Configuration} config Configuration object.
|
|
1926
|
+
* @param {ConfigurationParser[] | null} configParsers Configuration parsers.
|
|
1595
1927
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
|
1596
1928
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
|
1597
1929
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
|
@@ -1601,13 +1933,13 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
|
|
1601
1933
|
* @param {Function} callback Callback (err, result) function.
|
|
1602
1934
|
* @returns {void}
|
|
1603
1935
|
*/
|
|
1604
|
-
function lintFile(ruleList, file, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, callback) {
|
|
1936
|
+
function lintFile(ruleList, file, md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, callback) {
|
|
1605
1937
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1606
1938
|
function lintContentWrapper(err, content) {
|
|
1607
1939
|
if (err) {
|
|
1608
1940
|
return callback(err);
|
|
1609
1941
|
}
|
|
1610
|
-
return lintContent(ruleList, file, content, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback);
|
|
1942
|
+
return lintContent(ruleList, file, content, md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback);
|
|
1611
1943
|
}
|
|
1612
1944
|
// Make a/synchronous call to read file
|
|
1613
1945
|
if (synchronous) {
|
|
@@ -1630,40 +1962,42 @@ function lintInput(options, synchronous, callback) {
|
|
|
1630
1962
|
options = options || {};
|
|
1631
1963
|
callback = callback || function noop() { };
|
|
1632
1964
|
// eslint-disable-next-line unicorn/prefer-spread
|
|
1633
|
-
|
|
1634
|
-
|
|
1965
|
+
const ruleList = rules.concat(options.customRules || []);
|
|
1966
|
+
const ruleErr = validateRuleList(ruleList, synchronous);
|
|
1635
1967
|
if (ruleErr) {
|
|
1636
|
-
|
|
1968
|
+
callback(ruleErr);
|
|
1969
|
+
return;
|
|
1637
1970
|
}
|
|
1638
|
-
|
|
1971
|
+
let files = [];
|
|
1639
1972
|
if (Array.isArray(options.files)) {
|
|
1640
|
-
files =
|
|
1973
|
+
files = [...options.files];
|
|
1641
1974
|
}
|
|
1642
1975
|
else if (options.files) {
|
|
1643
1976
|
files = [String(options.files)];
|
|
1644
1977
|
}
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1978
|
+
const strings = options.strings || {};
|
|
1979
|
+
const stringsKeys = Object.keys(strings);
|
|
1980
|
+
const config = options.config || { "default": true };
|
|
1981
|
+
const configParsers = options.configParsers || null;
|
|
1982
|
+
const frontMatter = (options.frontMatter === undefined) ?
|
|
1649
1983
|
helpers.frontMatterRe : options.frontMatter;
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1984
|
+
const handleRuleFailures = !!options.handleRuleFailures;
|
|
1985
|
+
const noInlineConfig = !!options.noInlineConfig;
|
|
1986
|
+
const resultVersion = (options.resultVersion === undefined) ?
|
|
1987
|
+
3 : options.resultVersion;
|
|
1988
|
+
const md = markdownIt({ "html": true });
|
|
1989
|
+
const markdownItPlugins = options.markdownItPlugins || [];
|
|
1990
|
+
for (const plugin of markdownItPlugins) {
|
|
1657
1991
|
// @ts-ignore
|
|
1658
|
-
md.use
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1992
|
+
md.use(...plugin);
|
|
1993
|
+
}
|
|
1994
|
+
const fs = options.fs || __webpack_require__(/*! fs */ "?ec0a");
|
|
1995
|
+
const results = newResults(ruleList);
|
|
1996
|
+
let done = false;
|
|
1997
|
+
let concurrency = 0;
|
|
1664
1998
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1665
1999
|
function lintWorker() {
|
|
1666
|
-
|
|
2000
|
+
let currentItem = null;
|
|
1667
2001
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
1668
2002
|
function lintWorkerCallback(err, result) {
|
|
1669
2003
|
concurrency--;
|
|
@@ -1684,13 +2018,12 @@ function lintInput(options, synchronous, callback) {
|
|
|
1684
2018
|
// Lint next file
|
|
1685
2019
|
concurrency++;
|
|
1686
2020
|
currentItem = files.shift();
|
|
1687
|
-
lintFile(ruleList, currentItem, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, lintWorkerCallback);
|
|
2021
|
+
lintFile(ruleList, currentItem, md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, lintWorkerCallback);
|
|
1688
2022
|
}
|
|
1689
|
-
else if (stringsKeys.
|
|
2023
|
+
else if ((currentItem = stringsKeys.shift())) {
|
|
1690
2024
|
// Lint next string
|
|
1691
2025
|
concurrency++;
|
|
1692
|
-
currentItem
|
|
1693
|
-
lintContent(ruleList, currentItem, strings[currentItem] || "", md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, lintWorkerCallback);
|
|
2026
|
+
lintContent(ruleList, currentItem, strings[currentItem] || "", md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, lintWorkerCallback);
|
|
1694
2027
|
}
|
|
1695
2028
|
else if (concurrency === 0) {
|
|
1696
2029
|
// Finish
|
|
@@ -1717,7 +2050,6 @@ function lintInput(options, synchronous, callback) {
|
|
|
1717
2050
|
lintWorker();
|
|
1718
2051
|
lintWorker();
|
|
1719
2052
|
}
|
|
1720
|
-
return null;
|
|
1721
2053
|
}
|
|
1722
2054
|
/**
|
|
1723
2055
|
* Lint specified Markdown files.
|
|
@@ -1729,7 +2061,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
1729
2061
|
function markdownlint(options, callback) {
|
|
1730
2062
|
return lintInput(options, false, callback);
|
|
1731
2063
|
}
|
|
1732
|
-
|
|
2064
|
+
const markdownlintPromisify = promisify && promisify(markdownlint);
|
|
1733
2065
|
/**
|
|
1734
2066
|
* Lint specified Markdown files.
|
|
1735
2067
|
*
|
|
@@ -1737,6 +2069,7 @@ var markdownlintPromisify = promisify && promisify(markdownlint);
|
|
|
1737
2069
|
* @returns {Promise<LintResults>} Results object.
|
|
1738
2070
|
*/
|
|
1739
2071
|
function markdownlintPromise(options) {
|
|
2072
|
+
// @ts-ignore
|
|
1740
2073
|
return markdownlintPromisify(options);
|
|
1741
2074
|
}
|
|
1742
2075
|
/**
|
|
@@ -1746,48 +2079,16 @@ function markdownlintPromise(options) {
|
|
|
1746
2079
|
* @returns {LintResults} Results object.
|
|
1747
2080
|
*/
|
|
1748
2081
|
function markdownlintSync(options) {
|
|
1749
|
-
|
|
2082
|
+
let results = {};
|
|
1750
2083
|
lintInput(options, true, function callback(error, res) {
|
|
1751
2084
|
if (error) {
|
|
1752
2085
|
throw error;
|
|
1753
2086
|
}
|
|
1754
2087
|
results = res;
|
|
1755
2088
|
});
|
|
2089
|
+
// @ts-ignore
|
|
1756
2090
|
return results;
|
|
1757
2091
|
}
|
|
1758
|
-
/**
|
|
1759
|
-
* Parse the content of a configuration file.
|
|
1760
|
-
*
|
|
1761
|
-
* @param {string} name Name of the configuration file.
|
|
1762
|
-
* @param {string} content Configuration content.
|
|
1763
|
-
* @param {ConfigurationParser[]} parsers Parsing function(s).
|
|
1764
|
-
* @returns {Object} Configuration object and error message.
|
|
1765
|
-
*/
|
|
1766
|
-
function parseConfiguration(name, content, parsers) {
|
|
1767
|
-
var config = null;
|
|
1768
|
-
var message = "";
|
|
1769
|
-
var errors = [];
|
|
1770
|
-
var index = 0;
|
|
1771
|
-
// Try each parser
|
|
1772
|
-
(parsers || [JSON.parse]).every(function (parser) {
|
|
1773
|
-
try {
|
|
1774
|
-
config = parser(content);
|
|
1775
|
-
}
|
|
1776
|
-
catch (error) {
|
|
1777
|
-
errors.push("Parser ".concat(index++, ": ").concat(error.message));
|
|
1778
|
-
}
|
|
1779
|
-
return !config;
|
|
1780
|
-
});
|
|
1781
|
-
// Message if unable to parse
|
|
1782
|
-
if (!config) {
|
|
1783
|
-
errors.unshift("Unable to parse '".concat(name, "'"));
|
|
1784
|
-
message = errors.join("; ");
|
|
1785
|
-
}
|
|
1786
|
-
return {
|
|
1787
|
-
config: config,
|
|
1788
|
-
message: message
|
|
1789
|
-
};
|
|
1790
|
-
}
|
|
1791
2092
|
/**
|
|
1792
2093
|
* Resolve referenced "extends" path in a configuration file
|
|
1793
2094
|
* using path.resolve() with require.resolve() as a fallback.
|
|
@@ -1795,14 +2096,14 @@ function parseConfiguration(name, content, parsers) {
|
|
|
1795
2096
|
* @param {string} configFile Configuration file name.
|
|
1796
2097
|
* @param {string} referenceId Referenced identifier to resolve.
|
|
1797
2098
|
* @param {Object} fs File system implementation.
|
|
1798
|
-
* @param {ResolveConfigExtendsCallback}
|
|
2099
|
+
* @param {ResolveConfigExtendsCallback} callback Callback (err, result)
|
|
1799
2100
|
* function.
|
|
1800
2101
|
* @returns {void}
|
|
1801
2102
|
*/
|
|
1802
2103
|
function resolveConfigExtends(configFile, referenceId, fs, callback) {
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
fs.access(resolvedExtendsFile,
|
|
2104
|
+
const configFileDirname = path.dirname(configFile);
|
|
2105
|
+
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
|
2106
|
+
fs.access(resolvedExtendsFile, (err) => {
|
|
1806
2107
|
if (err) {
|
|
1807
2108
|
// Not a file, try require.resolve
|
|
1808
2109
|
try {
|
|
@@ -1825,8 +2126,8 @@ function resolveConfigExtends(configFile, referenceId, fs, callback) {
|
|
|
1825
2126
|
* @returns {string} Resolved path to file.
|
|
1826
2127
|
*/
|
|
1827
2128
|
function resolveConfigExtendsSync(configFile, referenceId, fs) {
|
|
1828
|
-
|
|
1829
|
-
|
|
2129
|
+
const configFileDirname = path.dirname(configFile);
|
|
2130
|
+
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
|
1830
2131
|
try {
|
|
1831
2132
|
fs.accessSync(resolvedExtendsFile);
|
|
1832
2133
|
return resolvedExtendsFile;
|
|
@@ -1861,6 +2162,7 @@ function readConfig(file, parsers, fs, callback) {
|
|
|
1861
2162
|
else {
|
|
1862
2163
|
// @ts-ignore
|
|
1863
2164
|
callback = parsers;
|
|
2165
|
+
// @ts-ignore
|
|
1864
2166
|
parsers = null;
|
|
1865
2167
|
}
|
|
1866
2168
|
}
|
|
@@ -1868,31 +2170,40 @@ function readConfig(file, parsers, fs, callback) {
|
|
|
1868
2170
|
fs = __webpack_require__(/*! fs */ "?ec0a");
|
|
1869
2171
|
}
|
|
1870
2172
|
// Read file
|
|
1871
|
-
|
|
2173
|
+
const os = __webpack_require__(/*! os */ "?a32b");
|
|
2174
|
+
file = helpers.expandTildePath(file, os);
|
|
2175
|
+
fs.readFile(file, "utf8", (err, content) => {
|
|
1872
2176
|
if (err) {
|
|
2177
|
+
// @ts-ignore
|
|
1873
2178
|
return callback(err);
|
|
1874
2179
|
}
|
|
1875
2180
|
// Try to parse file
|
|
1876
2181
|
// @ts-ignore
|
|
1877
|
-
|
|
2182
|
+
const { config, message } = parseConfiguration(file, content, parsers);
|
|
1878
2183
|
if (!config) {
|
|
2184
|
+
// @ts-ignore
|
|
1879
2185
|
return callback(new Error(message));
|
|
1880
2186
|
}
|
|
1881
2187
|
// Extend configuration
|
|
1882
|
-
|
|
2188
|
+
const configExtends = config.extends;
|
|
1883
2189
|
if (configExtends) {
|
|
1884
2190
|
delete config.extends;
|
|
1885
|
-
return resolveConfigExtends(file, configExtends, fs,
|
|
2191
|
+
return resolveConfigExtends(file, helpers.expandTildePath(configExtends, os), fs, (_, resolvedExtends) => readConfig(
|
|
2192
|
+
// @ts-ignore
|
|
2193
|
+
resolvedExtends, parsers, fs, (errr, extendsConfig) => {
|
|
1886
2194
|
if (errr) {
|
|
2195
|
+
// @ts-ignore
|
|
1887
2196
|
return callback(errr);
|
|
1888
2197
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
2198
|
+
// @ts-ignore
|
|
2199
|
+
return callback(null, Object.assign(Object.assign({}, extendsConfig), config));
|
|
2200
|
+
}));
|
|
1891
2201
|
}
|
|
2202
|
+
// @ts-ignore
|
|
1892
2203
|
return callback(null, config);
|
|
1893
2204
|
});
|
|
1894
2205
|
}
|
|
1895
|
-
|
|
2206
|
+
const readConfigPromisify = promisify && promisify(readConfig);
|
|
1896
2207
|
/**
|
|
1897
2208
|
* Read specified configuration file.
|
|
1898
2209
|
*
|
|
@@ -1919,18 +2230,20 @@ function readConfigSync(file, parsers, fs) {
|
|
|
1919
2230
|
fs = __webpack_require__(/*! fs */ "?ec0a");
|
|
1920
2231
|
}
|
|
1921
2232
|
// Read file
|
|
1922
|
-
|
|
2233
|
+
const os = __webpack_require__(/*! os */ "?a32b");
|
|
2234
|
+
file = helpers.expandTildePath(file, os);
|
|
2235
|
+
const content = fs.readFileSync(file, "utf8");
|
|
1923
2236
|
// Try to parse file
|
|
1924
|
-
|
|
2237
|
+
const { config, message } = parseConfiguration(file, content, parsers);
|
|
1925
2238
|
if (!config) {
|
|
1926
2239
|
throw new Error(message);
|
|
1927
2240
|
}
|
|
1928
2241
|
// Extend configuration
|
|
1929
|
-
|
|
2242
|
+
const configExtends = config.extends;
|
|
1930
2243
|
if (configExtends) {
|
|
1931
2244
|
delete config.extends;
|
|
1932
|
-
|
|
1933
|
-
return
|
|
2245
|
+
const resolvedExtends = resolveConfigExtendsSync(file, helpers.expandTildePath(configExtends, os), fs);
|
|
2246
|
+
return Object.assign(Object.assign({}, readConfigSync(resolvedExtends, parsers, fs)), config);
|
|
1934
2247
|
}
|
|
1935
2248
|
return config;
|
|
1936
2249
|
}
|
|
@@ -1965,15 +2278,15 @@ module.exports = markdownlint;
|
|
|
1965
2278
|
"use strict";
|
|
1966
2279
|
// @ts-check
|
|
1967
2280
|
|
|
1968
|
-
|
|
2281
|
+
const { addErrorDetailIf, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
1969
2282
|
module.exports = {
|
|
1970
2283
|
"names": ["MD001", "heading-increment", "header-increment"],
|
|
1971
2284
|
"description": "Heading levels should only increment by one level at a time",
|
|
1972
2285
|
"tags": ["headings", "headers"],
|
|
1973
2286
|
"function": function MD001(params, onError) {
|
|
1974
|
-
|
|
2287
|
+
let prevLevel = 0;
|
|
1975
2288
|
filterTokens(params, "heading_open", function forToken(token) {
|
|
1976
|
-
|
|
2289
|
+
const level = Number.parseInt(token.tag.slice(1), 10);
|
|
1977
2290
|
if (prevLevel && (level > prevLevel)) {
|
|
1978
2291
|
addErrorDetailIf(onError, token.lineNumber, "h" + (prevLevel + 1), "h" + level);
|
|
1979
2292
|
}
|
|
@@ -1994,14 +2307,14 @@ module.exports = {
|
|
|
1994
2307
|
"use strict";
|
|
1995
2308
|
// @ts-check
|
|
1996
2309
|
|
|
1997
|
-
|
|
2310
|
+
const { addErrorDetailIf } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
1998
2311
|
module.exports = {
|
|
1999
2312
|
"names": ["MD002", "first-heading-h1", "first-header-h1"],
|
|
2000
2313
|
"description": "First heading should be a top-level heading",
|
|
2001
2314
|
"tags": ["headings", "headers"],
|
|
2002
2315
|
"function": function MD002(params, onError) {
|
|
2003
|
-
|
|
2004
|
-
|
|
2316
|
+
const level = Number(params.config.level || 1);
|
|
2317
|
+
const tag = "h" + level;
|
|
2005
2318
|
params.tokens.every(function forToken(token) {
|
|
2006
2319
|
if (token.type === "heading_open") {
|
|
2007
2320
|
addErrorDetailIf(onError, token.lineNumber, tag, token.tag);
|
|
@@ -2024,28 +2337,28 @@ module.exports = {
|
|
|
2024
2337
|
"use strict";
|
|
2025
2338
|
// @ts-check
|
|
2026
2339
|
|
|
2027
|
-
|
|
2340
|
+
const { addErrorDetailIf, filterTokens, headingStyleFor } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2028
2341
|
module.exports = {
|
|
2029
2342
|
"names": ["MD003", "heading-style", "header-style"],
|
|
2030
2343
|
"description": "Heading style",
|
|
2031
2344
|
"tags": ["headings", "headers"],
|
|
2032
2345
|
"function": function MD003(params, onError) {
|
|
2033
|
-
|
|
2346
|
+
let style = String(params.config.style || "consistent");
|
|
2034
2347
|
filterTokens(params, "heading_open", function forToken(token) {
|
|
2035
|
-
|
|
2348
|
+
const styleForToken = headingStyleFor(token);
|
|
2036
2349
|
if (style === "consistent") {
|
|
2037
2350
|
style = styleForToken;
|
|
2038
2351
|
}
|
|
2039
2352
|
if (styleForToken !== style) {
|
|
2040
|
-
|
|
2041
|
-
|
|
2353
|
+
const h12 = /h[12]/.test(token.tag);
|
|
2354
|
+
const setextWithAtx = (style === "setext_with_atx") &&
|
|
2042
2355
|
((h12 && (styleForToken === "setext")) ||
|
|
2043
2356
|
(!h12 && (styleForToken === "atx")));
|
|
2044
|
-
|
|
2357
|
+
const setextWithAtxClosed = (style === "setext_with_atx_closed") &&
|
|
2045
2358
|
((h12 && (styleForToken === "setext")) ||
|
|
2046
2359
|
(!h12 && (styleForToken === "atx_closed")));
|
|
2047
2360
|
if (!setextWithAtx && !setextWithAtxClosed) {
|
|
2048
|
-
|
|
2361
|
+
let expected = style;
|
|
2049
2362
|
if (style === "setext_with_atx") {
|
|
2050
2363
|
expected = h12 ? "setext" : "atx";
|
|
2051
2364
|
}
|
|
@@ -2071,36 +2384,36 @@ module.exports = {
|
|
|
2071
2384
|
"use strict";
|
|
2072
2385
|
// @ts-check
|
|
2073
2386
|
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2387
|
+
const { addErrorDetailIf, listItemMarkerRe, unorderedListStyleFor } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2388
|
+
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2389
|
+
const expectedStyleToMarker = {
|
|
2077
2390
|
"dash": "-",
|
|
2078
2391
|
"plus": "+",
|
|
2079
2392
|
"asterisk": "*"
|
|
2080
2393
|
};
|
|
2081
|
-
|
|
2394
|
+
const differentItemStyle = {
|
|
2082
2395
|
"dash": "plus",
|
|
2083
2396
|
"plus": "asterisk",
|
|
2084
2397
|
"asterisk": "dash"
|
|
2085
2398
|
};
|
|
2086
|
-
|
|
2399
|
+
const validStyles = Object.keys(expectedStyleToMarker);
|
|
2087
2400
|
module.exports = {
|
|
2088
2401
|
"names": ["MD004", "ul-style"],
|
|
2089
2402
|
"description": "Unordered list style",
|
|
2090
2403
|
"tags": ["bullet", "ul"],
|
|
2091
2404
|
"function": function MD004(params, onError) {
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2405
|
+
const style = String(params.config.style || "consistent");
|
|
2406
|
+
let expectedStyle = style;
|
|
2407
|
+
const nestingStyles = [];
|
|
2408
|
+
for (const list of flattenedLists()) {
|
|
2096
2409
|
if (list.unordered) {
|
|
2097
2410
|
if (expectedStyle === "consistent") {
|
|
2098
2411
|
expectedStyle = unorderedListStyleFor(list.items[0]);
|
|
2099
2412
|
}
|
|
2100
|
-
list.items
|
|
2101
|
-
|
|
2413
|
+
for (const item of list.items) {
|
|
2414
|
+
const itemStyle = unorderedListStyleFor(item);
|
|
2102
2415
|
if (style === "sublist") {
|
|
2103
|
-
|
|
2416
|
+
const nesting = list.nesting;
|
|
2104
2417
|
if (!nestingStyles[nesting]) {
|
|
2105
2418
|
nestingStyles[nesting] =
|
|
2106
2419
|
(itemStyle === nestingStyles[nesting - 1]) ?
|
|
@@ -2112,12 +2425,12 @@ module.exports = {
|
|
|
2112
2425
|
if (!validStyles.includes(expectedStyle)) {
|
|
2113
2426
|
expectedStyle = validStyles[0];
|
|
2114
2427
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2428
|
+
let range = null;
|
|
2429
|
+
let fixInfo = null;
|
|
2430
|
+
const match = item.line.match(listItemMarkerRe);
|
|
2118
2431
|
if (match) {
|
|
2119
|
-
|
|
2120
|
-
|
|
2432
|
+
const column = match.index + 1;
|
|
2433
|
+
const length = match[0].length;
|
|
2121
2434
|
range = [column, length];
|
|
2122
2435
|
fixInfo = {
|
|
2123
2436
|
"editColumn": match[1].length + 1,
|
|
@@ -2126,9 +2439,9 @@ module.exports = {
|
|
|
2126
2439
|
};
|
|
2127
2440
|
}
|
|
2128
2441
|
addErrorDetailIf(onError, item.lineNumber, expectedStyle, itemStyle, null, null, range, fixInfo);
|
|
2129
|
-
}
|
|
2442
|
+
}
|
|
2130
2443
|
}
|
|
2131
|
-
}
|
|
2444
|
+
}
|
|
2132
2445
|
}
|
|
2133
2446
|
};
|
|
2134
2447
|
|
|
@@ -2144,22 +2457,22 @@ module.exports = {
|
|
|
2144
2457
|
"use strict";
|
|
2145
2458
|
// @ts-check
|
|
2146
2459
|
|
|
2147
|
-
|
|
2148
|
-
|
|
2460
|
+
const { addError, addErrorDetailIf, indentFor, listItemMarkerRe, orderedListItemMarkerRe, rangeFromRegExp } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2461
|
+
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2149
2462
|
module.exports = {
|
|
2150
2463
|
"names": ["MD005", "list-indent"],
|
|
2151
2464
|
"description": "Inconsistent indentation for list items at the same level",
|
|
2152
2465
|
"tags": ["bullet", "ul", "indentation"],
|
|
2153
2466
|
"function": function MD005(params, onError) {
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
list.items
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2467
|
+
for (const list of flattenedLists()) {
|
|
2468
|
+
const expectedIndent = list.indent;
|
|
2469
|
+
let expectedEnd = 0;
|
|
2470
|
+
let actualEnd = -1;
|
|
2471
|
+
let endMatching = false;
|
|
2472
|
+
for (const item of list.items) {
|
|
2473
|
+
const { line, lineNumber } = item;
|
|
2474
|
+
const actualIndent = indentFor(item);
|
|
2475
|
+
let match = null;
|
|
2163
2476
|
if (list.unordered) {
|
|
2164
2477
|
addErrorDetailIf(onError, lineNumber, expectedIndent, actualIndent, null, null, rangeFromRegExp(line, listItemMarkerRe)
|
|
2165
2478
|
// No fixInfo; MD007 handles this scenario better
|
|
@@ -2168,19 +2481,19 @@ module.exports = {
|
|
|
2168
2481
|
else if ((match = orderedListItemMarkerRe.exec(line))) {
|
|
2169
2482
|
actualEnd = match[0].length;
|
|
2170
2483
|
expectedEnd = expectedEnd || actualEnd;
|
|
2171
|
-
|
|
2484
|
+
const markerLength = match[1].length + 1;
|
|
2172
2485
|
if ((expectedIndent !== actualIndent) || endMatching) {
|
|
2173
2486
|
if (expectedEnd === actualEnd) {
|
|
2174
2487
|
endMatching = true;
|
|
2175
2488
|
}
|
|
2176
2489
|
else {
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2490
|
+
const detail = endMatching ?
|
|
2491
|
+
`Expected: (${expectedEnd}); Actual: (${actualEnd})` :
|
|
2492
|
+
`Expected: ${expectedIndent}; Actual: ${actualIndent}`;
|
|
2493
|
+
const expected = endMatching ?
|
|
2181
2494
|
expectedEnd - markerLength :
|
|
2182
2495
|
expectedIndent;
|
|
2183
|
-
|
|
2496
|
+
const actual = endMatching ?
|
|
2184
2497
|
actualEnd - markerLength :
|
|
2185
2498
|
actualIndent;
|
|
2186
2499
|
addError(onError, lineNumber, detail, null, rangeFromRegExp(line, listItemMarkerRe), {
|
|
@@ -2191,8 +2504,8 @@ module.exports = {
|
|
|
2191
2504
|
}
|
|
2192
2505
|
}
|
|
2193
2506
|
}
|
|
2194
|
-
}
|
|
2195
|
-
}
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2196
2509
|
}
|
|
2197
2510
|
};
|
|
2198
2511
|
|
|
@@ -2208,23 +2521,23 @@ module.exports = {
|
|
|
2208
2521
|
"use strict";
|
|
2209
2522
|
// @ts-check
|
|
2210
2523
|
|
|
2211
|
-
|
|
2212
|
-
|
|
2524
|
+
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2525
|
+
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2213
2526
|
module.exports = {
|
|
2214
2527
|
"names": ["MD006", "ul-start-left"],
|
|
2215
2528
|
"description": "Consider starting bulleted lists at the beginning of the line",
|
|
2216
2529
|
"tags": ["bullet", "ul", "indentation"],
|
|
2217
2530
|
"function": function MD006(params, onError) {
|
|
2218
|
-
|
|
2531
|
+
for (const list of flattenedLists()) {
|
|
2219
2532
|
if (list.unordered && !list.nesting && (list.indent !== 0)) {
|
|
2220
|
-
list.items
|
|
2221
|
-
|
|
2533
|
+
for (const item of list.items) {
|
|
2534
|
+
const { lineNumber, line } = item;
|
|
2222
2535
|
addErrorDetailIf(onError, lineNumber, 0, list.indent, null, null, rangeFromRegExp(line, listItemMarkerRe), {
|
|
2223
2536
|
"deleteCount": line.length - line.trimStart().length
|
|
2224
2537
|
});
|
|
2225
|
-
}
|
|
2538
|
+
}
|
|
2226
2539
|
}
|
|
2227
|
-
}
|
|
2540
|
+
}
|
|
2228
2541
|
}
|
|
2229
2542
|
};
|
|
2230
2543
|
|
|
@@ -2240,38 +2553,38 @@ module.exports = {
|
|
|
2240
2553
|
"use strict";
|
|
2241
2554
|
// @ts-check
|
|
2242
2555
|
|
|
2243
|
-
|
|
2244
|
-
|
|
2556
|
+
const { addErrorDetailIf, indentFor, listItemMarkerRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2557
|
+
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2245
2558
|
module.exports = {
|
|
2246
2559
|
"names": ["MD007", "ul-indent"],
|
|
2247
2560
|
"description": "Unordered list indentation",
|
|
2248
2561
|
"tags": ["bullet", "ul", "indentation"],
|
|
2249
2562
|
"function": function MD007(params, onError) {
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2563
|
+
const indent = Number(params.config.indent || 2);
|
|
2564
|
+
const startIndented = !!params.config.start_indented;
|
|
2565
|
+
const startIndent = Number(params.config.start_indent || indent);
|
|
2566
|
+
for (const list of flattenedLists()) {
|
|
2254
2567
|
if (list.unordered && list.parentsUnordered) {
|
|
2255
|
-
list.items
|
|
2256
|
-
|
|
2257
|
-
|
|
2568
|
+
for (const item of list.items) {
|
|
2569
|
+
const { lineNumber, line } = item;
|
|
2570
|
+
const expectedIndent = (startIndented ? startIndent : 0) +
|
|
2258
2571
|
(list.nesting * indent);
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2572
|
+
const actualIndent = indentFor(item);
|
|
2573
|
+
let range = null;
|
|
2574
|
+
let editColumn = 1;
|
|
2575
|
+
const match = line.match(listItemMarkerRe);
|
|
2263
2576
|
if (match) {
|
|
2264
2577
|
range = [1, match[0].length];
|
|
2265
2578
|
editColumn += match[1].length - actualIndent;
|
|
2266
2579
|
}
|
|
2267
2580
|
addErrorDetailIf(onError, lineNumber, expectedIndent, actualIndent, null, null, range, {
|
|
2268
|
-
editColumn
|
|
2581
|
+
editColumn,
|
|
2269
2582
|
"deleteCount": actualIndent,
|
|
2270
2583
|
"insertText": "".padEnd(expectedIndent)
|
|
2271
2584
|
});
|
|
2272
|
-
}
|
|
2585
|
+
}
|
|
2273
2586
|
}
|
|
2274
|
-
}
|
|
2587
|
+
}
|
|
2275
2588
|
}
|
|
2276
2589
|
};
|
|
2277
2590
|
|
|
@@ -2287,52 +2600,59 @@ module.exports = {
|
|
|
2287
2600
|
"use strict";
|
|
2288
2601
|
// @ts-check
|
|
2289
2602
|
|
|
2290
|
-
|
|
2291
|
-
|
|
2603
|
+
const { addError, filterTokens, forEachLine, includesSorted, numericSortAscending } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2604
|
+
const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2292
2605
|
module.exports = {
|
|
2293
2606
|
"names": ["MD009", "no-trailing-spaces"],
|
|
2294
2607
|
"description": "Trailing spaces",
|
|
2295
2608
|
"tags": ["whitespace"],
|
|
2296
2609
|
"function": function MD009(params, onError) {
|
|
2297
|
-
|
|
2610
|
+
let brSpaces = params.config.br_spaces;
|
|
2298
2611
|
brSpaces = Number((brSpaces === undefined) ? 2 : brSpaces);
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2612
|
+
const listItemEmptyLines = !!params.config.list_item_empty_lines;
|
|
2613
|
+
const strict = !!params.config.strict;
|
|
2614
|
+
const listItemLineNumbers = [];
|
|
2302
2615
|
if (listItemEmptyLines) {
|
|
2303
|
-
filterTokens(params, "list_item_open",
|
|
2304
|
-
for (
|
|
2616
|
+
filterTokens(params, "list_item_open", (token) => {
|
|
2617
|
+
for (let i = token.map[0]; i < token.map[1]; i++) {
|
|
2305
2618
|
listItemLineNumbers.push(i + 1);
|
|
2306
2619
|
}
|
|
2307
2620
|
});
|
|
2308
2621
|
listItemLineNumbers.sort(numericSortAscending);
|
|
2309
2622
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2623
|
+
const paragraphLineNumbers = [];
|
|
2624
|
+
const codeInlineLineNumbers = [];
|
|
2312
2625
|
if (strict) {
|
|
2313
|
-
filterTokens(params, "paragraph_open",
|
|
2314
|
-
for (
|
|
2626
|
+
filterTokens(params, "paragraph_open", (token) => {
|
|
2627
|
+
for (let i = token.map[0]; i < token.map[1] - 1; i++) {
|
|
2315
2628
|
paragraphLineNumbers.push(i + 1);
|
|
2316
2629
|
}
|
|
2317
2630
|
});
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2631
|
+
const addLineNumberRange = (start, end) => {
|
|
2632
|
+
for (let i = start; i < end; i++) {
|
|
2633
|
+
codeInlineLineNumbers.push(i);
|
|
2634
|
+
}
|
|
2635
|
+
};
|
|
2636
|
+
filterTokens(params, "inline", (token) => {
|
|
2637
|
+
let start = 0;
|
|
2638
|
+
for (const child of token.children) {
|
|
2639
|
+
if (start > 0) {
|
|
2640
|
+
addLineNumberRange(start, child.lineNumber);
|
|
2641
|
+
start = 0;
|
|
2642
|
+
}
|
|
2643
|
+
if (child.type === "code_inline") {
|
|
2644
|
+
start = child.lineNumber;
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
if (start > 0) {
|
|
2648
|
+
addLineNumberRange(start, token.map[1]);
|
|
2328
2649
|
}
|
|
2329
2650
|
});
|
|
2330
|
-
codeInlineLineNumbers.sort(numericSortAscending);
|
|
2331
2651
|
}
|
|
2332
|
-
|
|
2333
|
-
forEachLine(lineMetadata(),
|
|
2334
|
-
|
|
2335
|
-
|
|
2652
|
+
const expected = (brSpaces < 2) ? 0 : brSpaces;
|
|
2653
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
2654
|
+
const lineNumber = lineIndex + 1;
|
|
2655
|
+
const trailingSpaces = line.length - line.trimEnd().length;
|
|
2336
2656
|
if (trailingSpaces &&
|
|
2337
2657
|
!inCode &&
|
|
2338
2658
|
!includesSorted(listItemLineNumbers, lineNumber) &&
|
|
@@ -2340,9 +2660,9 @@ module.exports = {
|
|
|
2340
2660
|
(strict &&
|
|
2341
2661
|
(!includesSorted(paragraphLineNumbers, lineNumber) ||
|
|
2342
2662
|
includesSorted(codeInlineLineNumbers, lineNumber))))) {
|
|
2343
|
-
|
|
2663
|
+
const column = line.length - trailingSpaces + 1;
|
|
2344
2664
|
addError(onError, lineNumber, "Expected: " + (expected === 0 ? "" : "0 or ") +
|
|
2345
|
-
expected + "; Actual: " + trailingSpaces,
|
|
2665
|
+
expected + "; Actual: " + trailingSpaces, undefined, [column, trailingSpaces], {
|
|
2346
2666
|
"editColumn": column,
|
|
2347
2667
|
"deleteCount": trailingSpaces
|
|
2348
2668
|
});
|
|
@@ -2363,29 +2683,39 @@ module.exports = {
|
|
|
2363
2683
|
"use strict";
|
|
2364
2684
|
// @ts-check
|
|
2365
2685
|
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2686
|
+
const { addError, filterTokens, forEachLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2687
|
+
const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2688
|
+
const tabRe = /\t+/g;
|
|
2369
2689
|
module.exports = {
|
|
2370
2690
|
"names": ["MD010", "no-hard-tabs"],
|
|
2371
2691
|
"description": "Hard tabs",
|
|
2372
2692
|
"tags": ["whitespace", "hard_tab"],
|
|
2373
2693
|
"function": function MD010(params, onError) {
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2694
|
+
const codeBlocks = params.config.code_blocks;
|
|
2695
|
+
const includeCode = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
2696
|
+
const ignoreCodeLanguages = new Set((params.config.ignore_code_languages || [])
|
|
2697
|
+
.map((language) => language.toLowerCase()));
|
|
2698
|
+
const spacesPerTab = params.config.spaces_per_tab;
|
|
2699
|
+
const spaceMultiplier = (spacesPerTab === undefined) ?
|
|
2378
2700
|
1 :
|
|
2379
2701
|
Math.max(0, Number(spacesPerTab));
|
|
2380
|
-
|
|
2381
|
-
|
|
2702
|
+
const exclusions = includeCode ? [] : codeBlockAndSpanRanges();
|
|
2703
|
+
filterTokens(params, "fence", (token) => {
|
|
2704
|
+
const language = token.info.trim().toLowerCase();
|
|
2705
|
+
if (ignoreCodeLanguages.has(language)) {
|
|
2706
|
+
for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) {
|
|
2707
|
+
exclusions.push([i, 0, params.lines[i].length]);
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
});
|
|
2711
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
2382
2712
|
if (includeCode || !inCode) {
|
|
2383
|
-
|
|
2713
|
+
let match = null;
|
|
2384
2714
|
while ((match = tabRe.exec(line)) !== null) {
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
if (!
|
|
2715
|
+
const { index } = match;
|
|
2716
|
+
const column = index + 1;
|
|
2717
|
+
const length = match[0].length;
|
|
2718
|
+
if (!withinAnyRange(exclusions, lineIndex, index, length)) {
|
|
2389
2719
|
addError(onError, lineIndex + 1, "Column: " + column, null, [column, length], {
|
|
2390
2720
|
"editColumn": column,
|
|
2391
2721
|
"deleteCount": length,
|
|
@@ -2410,29 +2740,29 @@ module.exports = {
|
|
|
2410
2740
|
"use strict";
|
|
2411
2741
|
// @ts-check
|
|
2412
2742
|
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2743
|
+
const { addError, forEachLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2744
|
+
const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2745
|
+
const reversedLinkRe = /(^|[^\\])\(([^)]+)\)\[([^\]^][^\]]*)](?!\()/g;
|
|
2416
2746
|
module.exports = {
|
|
2417
2747
|
"names": ["MD011", "no-reversed-links"],
|
|
2418
2748
|
"description": "Reversed link syntax",
|
|
2419
2749
|
"tags": ["links"],
|
|
2420
2750
|
"function": function MD011(params, onError) {
|
|
2421
|
-
|
|
2422
|
-
forEachLine(lineMetadata(),
|
|
2751
|
+
const exclusions = codeBlockAndSpanRanges();
|
|
2752
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence) => {
|
|
2423
2753
|
if (!inCode && !onFence) {
|
|
2424
|
-
|
|
2754
|
+
let match = null;
|
|
2425
2755
|
while ((match = reversedLinkRe.exec(line)) !== null) {
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2756
|
+
const [reversedLink, preChar, linkText, linkDestination] = match;
|
|
2757
|
+
const index = match.index + preChar.length;
|
|
2758
|
+
const length = match[0].length - preChar.length;
|
|
2429
2759
|
if (!linkText.endsWith("\\") &&
|
|
2430
2760
|
!linkDestination.endsWith("\\") &&
|
|
2431
|
-
!
|
|
2761
|
+
!withinAnyRange(exclusions, lineIndex, index, length)) {
|
|
2432
2762
|
addError(onError, lineIndex + 1, reversedLink.slice(preChar.length), null, [index + 1, length], {
|
|
2433
2763
|
"editColumn": index + 1,
|
|
2434
2764
|
"deleteCount": length,
|
|
2435
|
-
"insertText":
|
|
2765
|
+
"insertText": `[${linkText}](${linkDestination})`
|
|
2436
2766
|
});
|
|
2437
2767
|
}
|
|
2438
2768
|
}
|
|
@@ -2453,16 +2783,16 @@ module.exports = {
|
|
|
2453
2783
|
"use strict";
|
|
2454
2784
|
// @ts-check
|
|
2455
2785
|
|
|
2456
|
-
|
|
2457
|
-
|
|
2786
|
+
const { addErrorDetailIf, forEachLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2787
|
+
const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2458
2788
|
module.exports = {
|
|
2459
2789
|
"names": ["MD012", "no-multiple-blanks"],
|
|
2460
2790
|
"description": "Multiple consecutive blank lines",
|
|
2461
2791
|
"tags": ["whitespace", "blank_lines"],
|
|
2462
2792
|
"function": function MD012(params, onError) {
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
forEachLine(lineMetadata(),
|
|
2793
|
+
const maximum = Number(params.config.maximum || 1);
|
|
2794
|
+
let count = 0;
|
|
2795
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
2466
2796
|
count = (inCode || (line.trim().length > 0)) ? 0 : count + 1;
|
|
2467
2797
|
if (maximum < count) {
|
|
2468
2798
|
addErrorDetailIf(onError, lineIndex + 1, maximum, count, null, null, null, {
|
|
@@ -2485,15 +2815,14 @@ module.exports = {
|
|
|
2485
2815
|
"use strict";
|
|
2486
2816
|
// @ts-check
|
|
2487
2817
|
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
var tokenTypeMap = {
|
|
2818
|
+
const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine, includesSorted, linkReferenceDefinitionRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2819
|
+
const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2820
|
+
const longLineRePrefix = "^.{";
|
|
2821
|
+
const longLineRePostfixRelaxed = "}.*\\s.*$";
|
|
2822
|
+
const longLineRePostfixStrict = "}.+$";
|
|
2823
|
+
const linkOrImageOnlyLineRe = /^[es]*(lT?L|I)[ES]*$/;
|
|
2824
|
+
const sternModeRe = /^([#>\s]*\s)?\S*$/;
|
|
2825
|
+
const tokenTypeMap = {
|
|
2497
2826
|
"em_open": "e",
|
|
2498
2827
|
"em_close": "E",
|
|
2499
2828
|
"image": "I",
|
|
@@ -2508,47 +2837,47 @@ module.exports = {
|
|
|
2508
2837
|
"description": "Line length",
|
|
2509
2838
|
"tags": ["line_length"],
|
|
2510
2839
|
"function": function MD013(params, onError) {
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2840
|
+
const lineLength = Number(params.config.line_length || 80);
|
|
2841
|
+
const headingLineLength = Number(params.config.heading_line_length || lineLength);
|
|
2842
|
+
const codeLineLength = Number(params.config.code_block_line_length || lineLength);
|
|
2843
|
+
const strict = !!params.config.strict;
|
|
2844
|
+
const stern = !!params.config.stern;
|
|
2845
|
+
const longLineRePostfix = (strict || stern) ? longLineRePostfixStrict : longLineRePostfixRelaxed;
|
|
2846
|
+
const longLineRe = new RegExp(longLineRePrefix + lineLength + longLineRePostfix);
|
|
2847
|
+
const longHeadingLineRe = new RegExp(longLineRePrefix + headingLineLength + longLineRePostfix);
|
|
2848
|
+
const longCodeLineRe = new RegExp(longLineRePrefix + codeLineLength + longLineRePostfix);
|
|
2849
|
+
const codeBlocks = params.config.code_blocks;
|
|
2850
|
+
const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
2851
|
+
const tables = params.config.tables;
|
|
2852
|
+
const includeTables = (tables === undefined) ? true : !!tables;
|
|
2853
|
+
let headings = params.config.headings;
|
|
2525
2854
|
if (headings === undefined) {
|
|
2526
2855
|
headings = params.config.headers;
|
|
2527
2856
|
}
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
forEachHeading(params,
|
|
2857
|
+
const includeHeadings = (headings === undefined) ? true : !!headings;
|
|
2858
|
+
const headingLineNumbers = [];
|
|
2859
|
+
forEachHeading(params, (heading) => {
|
|
2531
2860
|
headingLineNumbers.push(heading.lineNumber);
|
|
2532
2861
|
});
|
|
2533
|
-
|
|
2534
|
-
filterTokens(params, "inline",
|
|
2535
|
-
|
|
2536
|
-
token.children
|
|
2862
|
+
const linkOnlyLineNumbers = [];
|
|
2863
|
+
filterTokens(params, "inline", (token) => {
|
|
2864
|
+
let childTokenTypes = "";
|
|
2865
|
+
for (const child of token.children) {
|
|
2537
2866
|
if (child.type !== "text" || child.content !== "") {
|
|
2538
2867
|
childTokenTypes += tokenTypeMap[child.type] || "x";
|
|
2539
2868
|
}
|
|
2540
|
-
}
|
|
2869
|
+
}
|
|
2541
2870
|
if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
|
|
2542
2871
|
linkOnlyLineNumbers.push(token.lineNumber);
|
|
2543
2872
|
}
|
|
2544
2873
|
});
|
|
2545
|
-
forEachLine(lineMetadata(),
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2874
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => {
|
|
2875
|
+
const lineNumber = lineIndex + 1;
|
|
2876
|
+
const isHeading = includesSorted(headingLineNumbers, lineNumber);
|
|
2877
|
+
const length = inCode ?
|
|
2549
2878
|
codeLineLength :
|
|
2550
2879
|
(isHeading ? headingLineLength : lineLength);
|
|
2551
|
-
|
|
2880
|
+
const lengthRe = inCode ?
|
|
2552
2881
|
longCodeLineRe :
|
|
2553
2882
|
(isHeading ? longHeadingLineRe : longLineRe);
|
|
2554
2883
|
if ((includeCodeBlocks || !inCode) &&
|
|
@@ -2557,7 +2886,7 @@ module.exports = {
|
|
|
2557
2886
|
(strict ||
|
|
2558
2887
|
(!(stern && sternModeRe.test(line)) &&
|
|
2559
2888
|
!includesSorted(linkOnlyLineNumbers, lineNumber) &&
|
|
2560
|
-
!
|
|
2889
|
+
!linkReferenceDefinitionRe.test(line))) &&
|
|
2561
2890
|
lengthRe.test(line)) {
|
|
2562
2891
|
addErrorDetailIf(onError, lineNumber, length, line.length, null, null, [length + 1, line.length - length]);
|
|
2563
2892
|
}
|
|
@@ -2577,26 +2906,26 @@ module.exports = {
|
|
|
2577
2906
|
"use strict";
|
|
2578
2907
|
// @ts-check
|
|
2579
2908
|
|
|
2580
|
-
|
|
2581
|
-
|
|
2909
|
+
const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2910
|
+
const dollarCommandRe = /^(\s*)(\$\s+)/;
|
|
2582
2911
|
module.exports = {
|
|
2583
2912
|
"names": ["MD014", "commands-show-output"],
|
|
2584
2913
|
"description": "Dollar signs used before commands without showing output",
|
|
2585
2914
|
"tags": ["code"],
|
|
2586
2915
|
"function": function MD014(params, onError) {
|
|
2587
|
-
["code_block", "fence"]
|
|
2588
|
-
filterTokens(params, type,
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
for (
|
|
2593
|
-
|
|
2594
|
-
|
|
2916
|
+
for (const type of ["code_block", "fence"]) {
|
|
2917
|
+
filterTokens(params, type, (token) => {
|
|
2918
|
+
const margin = (token.type === "fence") ? 1 : 0;
|
|
2919
|
+
const dollarInstances = [];
|
|
2920
|
+
let allDollars = true;
|
|
2921
|
+
for (let i = token.map[0] + margin; i < token.map[1] - margin; i++) {
|
|
2922
|
+
const line = params.lines[i];
|
|
2923
|
+
const lineTrim = line.trim();
|
|
2595
2924
|
if (lineTrim) {
|
|
2596
|
-
|
|
2925
|
+
const match = dollarCommandRe.exec(line);
|
|
2597
2926
|
if (match) {
|
|
2598
|
-
|
|
2599
|
-
|
|
2927
|
+
const column = match[1].length + 1;
|
|
2928
|
+
const length = match[2].length;
|
|
2600
2929
|
dollarInstances.push([i, lineTrim, column, length]);
|
|
2601
2930
|
}
|
|
2602
2931
|
else {
|
|
@@ -2605,16 +2934,16 @@ module.exports = {
|
|
|
2605
2934
|
}
|
|
2606
2935
|
}
|
|
2607
2936
|
if (allDollars) {
|
|
2608
|
-
|
|
2609
|
-
|
|
2937
|
+
for (const instance of dollarInstances) {
|
|
2938
|
+
const [i, lineTrim, column, length] = instance;
|
|
2610
2939
|
addErrorContext(onError, i + 1, lineTrim, null, null, [column, length], {
|
|
2611
2940
|
"editColumn": column,
|
|
2612
2941
|
"deleteCount": length
|
|
2613
2942
|
});
|
|
2614
|
-
}
|
|
2943
|
+
}
|
|
2615
2944
|
}
|
|
2616
2945
|
});
|
|
2617
|
-
}
|
|
2946
|
+
}
|
|
2618
2947
|
}
|
|
2619
2948
|
};
|
|
2620
2949
|
|
|
@@ -2630,19 +2959,19 @@ module.exports = {
|
|
|
2630
2959
|
"use strict";
|
|
2631
2960
|
// @ts-check
|
|
2632
2961
|
|
|
2633
|
-
|
|
2634
|
-
|
|
2962
|
+
const { addErrorContext, forEachLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2963
|
+
const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2635
2964
|
module.exports = {
|
|
2636
2965
|
"names": ["MD018", "no-missing-space-atx"],
|
|
2637
2966
|
"description": "No space after hash on atx style heading",
|
|
2638
2967
|
"tags": ["headings", "headers", "atx", "spaces"],
|
|
2639
2968
|
"function": function MD018(params, onError) {
|
|
2640
|
-
forEachLine(lineMetadata(),
|
|
2969
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
2641
2970
|
if (!inCode &&
|
|
2642
2971
|
/^#+[^# \t]/.test(line) &&
|
|
2643
2972
|
!/#\s*$/.test(line) &&
|
|
2644
2973
|
!line.startsWith("#️⃣")) {
|
|
2645
|
-
|
|
2974
|
+
const hashCount = /^#+/.exec(line)[0].length;
|
|
2646
2975
|
addErrorContext(onError, lineIndex + 1, line.trim(), null, null, [1, hashCount + 1], {
|
|
2647
2976
|
"editColumn": hashCount + 1,
|
|
2648
2977
|
"insertText": " "
|
|
@@ -2664,18 +2993,18 @@ module.exports = {
|
|
|
2664
2993
|
"use strict";
|
|
2665
2994
|
// @ts-check
|
|
2666
2995
|
|
|
2667
|
-
|
|
2996
|
+
const { addErrorContext, filterTokens, headingStyleFor } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2668
2997
|
module.exports = {
|
|
2669
2998
|
"names": ["MD019", "no-multiple-space-atx"],
|
|
2670
2999
|
"description": "Multiple spaces after hash on atx style heading",
|
|
2671
3000
|
"tags": ["headings", "headers", "atx", "spaces"],
|
|
2672
3001
|
"function": function MD019(params, onError) {
|
|
2673
|
-
filterTokens(params, "heading_open",
|
|
3002
|
+
filterTokens(params, "heading_open", (token) => {
|
|
2674
3003
|
if (headingStyleFor(token) === "atx") {
|
|
2675
|
-
|
|
2676
|
-
|
|
3004
|
+
const { line, lineNumber } = token;
|
|
3005
|
+
const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line);
|
|
2677
3006
|
if (match) {
|
|
2678
|
-
|
|
3007
|
+
const [, { "length": hashLength }, { "length": spacesLength }] = match;
|
|
2679
3008
|
addErrorContext(onError, lineNumber, line.trim(), null, null, [1, hashLength + spacesLength + 1], {
|
|
2680
3009
|
"editColumn": hashLength + 1,
|
|
2681
3010
|
"deleteCount": spacesLength - 1
|
|
@@ -2698,25 +3027,25 @@ module.exports = {
|
|
|
2698
3027
|
"use strict";
|
|
2699
3028
|
// @ts-check
|
|
2700
3029
|
|
|
2701
|
-
|
|
2702
|
-
|
|
3030
|
+
const { addErrorContext, forEachLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3031
|
+
const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
2703
3032
|
module.exports = {
|
|
2704
3033
|
"names": ["MD020", "no-missing-space-closed-atx"],
|
|
2705
3034
|
"description": "No space inside hashes on closed atx style heading",
|
|
2706
3035
|
"tags": ["headings", "headers", "atx_closed", "spaces"],
|
|
2707
3036
|
"function": function MD020(params, onError) {
|
|
2708
|
-
forEachLine(lineMetadata(),
|
|
3037
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
2709
3038
|
if (!inCode) {
|
|
2710
|
-
|
|
3039
|
+
const match = /^(#+)([ \t]*)([^#]*?[^#\\])([ \t]*)((?:\\#)?)(#+)(\s*)$/.exec(line);
|
|
2711
3040
|
if (match) {
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
3041
|
+
const [, leftHash, { "length": leftSpaceLength }, content, { "length": rightSpaceLength }, rightEscape, rightHash, { "length": trailSpaceLength }] = match;
|
|
3042
|
+
const leftHashLength = leftHash.length;
|
|
3043
|
+
const rightHashLength = rightHash.length;
|
|
3044
|
+
const left = !leftSpaceLength;
|
|
3045
|
+
const right = !rightSpaceLength || rightEscape;
|
|
3046
|
+
const rightEscapeReplacement = rightEscape ? `${rightEscape} ` : "";
|
|
2718
3047
|
if (left || right) {
|
|
2719
|
-
|
|
3048
|
+
const range = left ?
|
|
2720
3049
|
[
|
|
2721
3050
|
1,
|
|
2722
3051
|
leftHashLength + 1
|
|
@@ -2728,7 +3057,7 @@ module.exports = {
|
|
|
2728
3057
|
addErrorContext(onError, lineIndex + 1, line.trim(), left, right, range, {
|
|
2729
3058
|
"editColumn": 1,
|
|
2730
3059
|
"deleteCount": line.length,
|
|
2731
|
-
"insertText":
|
|
3060
|
+
"insertText": `${leftHash} ${content} ${rightEscapeReplacement}${rightHash}`
|
|
2732
3061
|
});
|
|
2733
3062
|
}
|
|
2734
3063
|
}
|
|
@@ -2749,25 +3078,26 @@ module.exports = {
|
|
|
2749
3078
|
"use strict";
|
|
2750
3079
|
// @ts-check
|
|
2751
3080
|
|
|
2752
|
-
|
|
3081
|
+
const { addErrorContext, filterTokens, headingStyleFor } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3082
|
+
const closedAtxRe = /^(#+)([ \t]+)([^ \t]|[^ \t].*[^ \t])([ \t]+)(#+)(\s*)$/;
|
|
2753
3083
|
module.exports = {
|
|
2754
3084
|
"names": ["MD021", "no-multiple-space-closed-atx"],
|
|
2755
3085
|
"description": "Multiple spaces inside hashes on closed atx style heading",
|
|
2756
3086
|
"tags": ["headings", "headers", "atx_closed", "spaces"],
|
|
2757
3087
|
"function": function MD021(params, onError) {
|
|
2758
|
-
filterTokens(params, "heading_open",
|
|
3088
|
+
filterTokens(params, "heading_open", (token) => {
|
|
2759
3089
|
if (headingStyleFor(token) === "atx_closed") {
|
|
2760
|
-
|
|
2761
|
-
|
|
3090
|
+
const { line, lineNumber } = token;
|
|
3091
|
+
const match = closedAtxRe.exec(line);
|
|
2762
3092
|
if (match) {
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
3093
|
+
const [, leftHash, { "length": leftSpaceLength }, content, { "length": rightSpaceLength }, rightHash, { "length": trailSpaceLength }] = match;
|
|
3094
|
+
const left = leftSpaceLength > 1;
|
|
3095
|
+
const right = rightSpaceLength > 1;
|
|
2766
3096
|
if (left || right) {
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
3097
|
+
const length = line.length;
|
|
3098
|
+
const leftHashLength = leftHash.length;
|
|
3099
|
+
const rightHashLength = rightHash.length;
|
|
3100
|
+
const range = left ?
|
|
2771
3101
|
[
|
|
2772
3102
|
1,
|
|
2773
3103
|
leftHashLength + leftSpaceLength + 1
|
|
@@ -2779,7 +3109,7 @@ module.exports = {
|
|
|
2779
3109
|
addErrorContext(onError, lineNumber, line.trim(), left, right, range, {
|
|
2780
3110
|
"editColumn": 1,
|
|
2781
3111
|
"deleteCount": length,
|
|
2782
|
-
"insertText":
|
|
3112
|
+
"insertText": `${leftHash} ${content} ${rightHash}`
|
|
2783
3113
|
});
|
|
2784
3114
|
}
|
|
2785
3115
|
}
|
|
@@ -2800,21 +3130,21 @@ module.exports = {
|
|
|
2800
3130
|
"use strict";
|
|
2801
3131
|
// @ts-check
|
|
2802
3132
|
|
|
2803
|
-
|
|
3133
|
+
const { addErrorDetailIf, filterTokens, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2804
3134
|
module.exports = {
|
|
2805
3135
|
"names": ["MD022", "blanks-around-headings", "blanks-around-headers"],
|
|
2806
3136
|
"description": "Headings should be surrounded by blank lines",
|
|
2807
3137
|
"tags": ["headings", "headers", "blank_lines"],
|
|
2808
3138
|
"function": function MD022(params, onError) {
|
|
2809
|
-
|
|
3139
|
+
let linesAbove = params.config.lines_above;
|
|
2810
3140
|
linesAbove = Number((linesAbove === undefined) ? 1 : linesAbove);
|
|
2811
|
-
|
|
3141
|
+
let linesBelow = params.config.lines_below;
|
|
2812
3142
|
linesBelow = Number((linesBelow === undefined) ? 1 : linesBelow);
|
|
2813
|
-
|
|
2814
|
-
filterTokens(params, "heading_open",
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
for (
|
|
3143
|
+
const { lines } = params;
|
|
3144
|
+
filterTokens(params, "heading_open", (token) => {
|
|
3145
|
+
const [topIndex, nextIndex] = token.map;
|
|
3146
|
+
let actualAbove = 0;
|
|
3147
|
+
for (let i = 0; i < linesAbove; i++) {
|
|
2818
3148
|
if (isBlankLine(lines[topIndex - i - 1])) {
|
|
2819
3149
|
actualAbove++;
|
|
2820
3150
|
}
|
|
@@ -2822,8 +3152,8 @@ module.exports = {
|
|
|
2822
3152
|
addErrorDetailIf(onError, topIndex + 1, linesAbove, actualAbove, "Above", lines[topIndex].trim(), null, {
|
|
2823
3153
|
"insertText": "".padEnd(linesAbove - actualAbove, "\n")
|
|
2824
3154
|
});
|
|
2825
|
-
|
|
2826
|
-
for (
|
|
3155
|
+
let actualBelow = 0;
|
|
3156
|
+
for (let i = 0; i < linesBelow; i++) {
|
|
2827
3157
|
if (isBlankLine(lines[nextIndex + i])) {
|
|
2828
3158
|
actualBelow++;
|
|
2829
3159
|
}
|
|
@@ -2848,20 +3178,20 @@ module.exports = {
|
|
|
2848
3178
|
"use strict";
|
|
2849
3179
|
// @ts-check
|
|
2850
3180
|
|
|
2851
|
-
|
|
2852
|
-
|
|
3181
|
+
const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3182
|
+
const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/;
|
|
2853
3183
|
module.exports = {
|
|
2854
3184
|
"names": ["MD023", "heading-start-left", "header-start-left"],
|
|
2855
3185
|
"description": "Headings must start at the beginning of the line",
|
|
2856
3186
|
"tags": ["headings", "headers", "spaces"],
|
|
2857
3187
|
"function": function MD023(params, onError) {
|
|
2858
3188
|
filterTokens(params, "heading_open", function forToken(token) {
|
|
2859
|
-
|
|
2860
|
-
|
|
3189
|
+
const { lineNumber, line } = token;
|
|
3190
|
+
const match = line.match(spaceBeforeHeadingRe);
|
|
2861
3191
|
if (match) {
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
3192
|
+
const [prefixAndFirstChar, prefix] = match;
|
|
3193
|
+
let deleteCount = prefix.length;
|
|
3194
|
+
const prefixLengthNoSpace = prefix.trimEnd().length;
|
|
2865
3195
|
if (prefixLengthNoSpace) {
|
|
2866
3196
|
deleteCount -= prefixLengthNoSpace - 1;
|
|
2867
3197
|
}
|
|
@@ -2886,20 +3216,20 @@ module.exports = {
|
|
|
2886
3216
|
"use strict";
|
|
2887
3217
|
// @ts-check
|
|
2888
3218
|
|
|
2889
|
-
|
|
3219
|
+
const { addErrorContext, forEachHeading } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2890
3220
|
module.exports = {
|
|
2891
3221
|
"names": ["MD024", "no-duplicate-heading", "no-duplicate-header"],
|
|
2892
3222
|
"description": "Multiple headings with the same content",
|
|
2893
3223
|
"tags": ["headings", "headers"],
|
|
2894
3224
|
"function": function MD024(params, onError) {
|
|
2895
|
-
|
|
3225
|
+
const siblingsOnly = !!params.config.siblings_only ||
|
|
2896
3226
|
!!params.config.allow_different_nesting || false;
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
forEachHeading(params,
|
|
3227
|
+
const knownContents = [null, []];
|
|
3228
|
+
let lastLevel = 1;
|
|
3229
|
+
let knownContent = knownContents[lastLevel];
|
|
3230
|
+
forEachHeading(params, (heading, content) => {
|
|
2901
3231
|
if (siblingsOnly) {
|
|
2902
|
-
|
|
3232
|
+
const newLevel = heading.tag.slice(1);
|
|
2903
3233
|
while (lastLevel < newLevel) {
|
|
2904
3234
|
lastLevel++;
|
|
2905
3235
|
knownContents[lastLevel] = [];
|
|
@@ -2932,16 +3262,16 @@ module.exports = {
|
|
|
2932
3262
|
"use strict";
|
|
2933
3263
|
// @ts-check
|
|
2934
3264
|
|
|
2935
|
-
|
|
3265
|
+
const { addErrorContext, filterTokens, frontMatterHasTitle } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
2936
3266
|
module.exports = {
|
|
2937
3267
|
"names": ["MD025", "single-title", "single-h1"],
|
|
2938
3268
|
"description": "Multiple top-level headings in the same document",
|
|
2939
3269
|
"tags": ["headings", "headers"],
|
|
2940
3270
|
"function": function MD025(params, onError) {
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
3271
|
+
const level = Number(params.config.level || 1);
|
|
3272
|
+
const tag = "h" + level;
|
|
3273
|
+
const foundFrontMatterTitle = frontMatterHasTitle(params.frontMatterLines, params.config.front_matter_title);
|
|
3274
|
+
let hasTopLevelHeading = false;
|
|
2945
3275
|
filterTokens(params, "heading_open", function forToken(token) {
|
|
2946
3276
|
if (token.tag === tag) {
|
|
2947
3277
|
if (hasTopLevelHeading || foundFrontMatterTitle) {
|
|
@@ -2967,25 +3297,25 @@ module.exports = {
|
|
|
2967
3297
|
"use strict";
|
|
2968
3298
|
// @ts-check
|
|
2969
3299
|
|
|
2970
|
-
|
|
2971
|
-
|
|
3300
|
+
const { addError, allPunctuationNoQuestion, escapeForRegExp, forEachHeading } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3301
|
+
const endOfLineHtmlEntityRe = /&#?[0-9a-zA-Z]+;$/;
|
|
2972
3302
|
module.exports = {
|
|
2973
3303
|
"names": ["MD026", "no-trailing-punctuation"],
|
|
2974
3304
|
"description": "Trailing punctuation in heading",
|
|
2975
3305
|
"tags": ["headings", "headers"],
|
|
2976
3306
|
"function": function MD026(params, onError) {
|
|
2977
|
-
|
|
3307
|
+
let punctuation = params.config.punctuation;
|
|
2978
3308
|
punctuation = String((punctuation === undefined) ? allPunctuationNoQuestion : punctuation);
|
|
2979
|
-
|
|
2980
|
-
forEachHeading(params,
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
3309
|
+
const trailingPunctuationRe = new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$");
|
|
3310
|
+
forEachHeading(params, (heading) => {
|
|
3311
|
+
const { line, lineNumber } = heading;
|
|
3312
|
+
const trimmedLine = line.replace(/([^\s#])[\s#]+$/, "$1");
|
|
3313
|
+
const match = trailingPunctuationRe.exec(trimmedLine);
|
|
2984
3314
|
if (match && !endOfLineHtmlEntityRe.test(trimmedLine)) {
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
addError(onError, lineNumber,
|
|
3315
|
+
const fullMatch = match[0];
|
|
3316
|
+
const column = match.index + 1;
|
|
3317
|
+
const length = fullMatch.length;
|
|
3318
|
+
addError(onError, lineNumber, `Punctuation: '${fullMatch}'`, null, [column, length], {
|
|
2989
3319
|
"editColumn": column,
|
|
2990
3320
|
"deleteCount": length
|
|
2991
3321
|
});
|
|
@@ -3006,17 +3336,17 @@ module.exports = {
|
|
|
3006
3336
|
"use strict";
|
|
3007
3337
|
// @ts-check
|
|
3008
3338
|
|
|
3009
|
-
|
|
3010
|
-
|
|
3339
|
+
const { addErrorContext, newLineRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3340
|
+
const spaceAfterBlockQuoteRe = /^((?:\s*>)+)(\s{2,})\S/;
|
|
3011
3341
|
module.exports = {
|
|
3012
3342
|
"names": ["MD027", "no-multiple-space-blockquote"],
|
|
3013
3343
|
"description": "Multiple spaces after blockquote symbol",
|
|
3014
3344
|
"tags": ["blockquote", "whitespace", "indentation"],
|
|
3015
3345
|
"function": function MD027(params, onError) {
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
params.tokens
|
|
3019
|
-
|
|
3346
|
+
let blockquoteNesting = 0;
|
|
3347
|
+
let listItemNesting = 0;
|
|
3348
|
+
for (const token of params.tokens) {
|
|
3349
|
+
const { content, lineNumber, type } = token;
|
|
3020
3350
|
if (type === "blockquote_open") {
|
|
3021
3351
|
blockquoteNesting++;
|
|
3022
3352
|
}
|
|
@@ -3030,12 +3360,12 @@ module.exports = {
|
|
|
3030
3360
|
listItemNesting--;
|
|
3031
3361
|
}
|
|
3032
3362
|
else if ((type === "inline") && blockquoteNesting) {
|
|
3033
|
-
|
|
3034
|
-
for (
|
|
3035
|
-
|
|
3036
|
-
|
|
3363
|
+
const lineCount = content.split(newLineRe).length;
|
|
3364
|
+
for (let i = 0; i < lineCount; i++) {
|
|
3365
|
+
const line = params.lines[lineNumber + i - 1];
|
|
3366
|
+
const match = line.match(spaceAfterBlockQuoteRe);
|
|
3037
3367
|
if (match) {
|
|
3038
|
-
|
|
3368
|
+
const [fullMatch, { "length": blockquoteLength }, { "length": spaceLength }] = match;
|
|
3039
3369
|
if (!listItemNesting || (fullMatch[fullMatch.length - 1] === ">")) {
|
|
3040
3370
|
addErrorContext(onError, lineNumber + i, line, null, null, [1, fullMatch.length], {
|
|
3041
3371
|
"editColumn": blockquoteLength + 1,
|
|
@@ -3045,7 +3375,7 @@ module.exports = {
|
|
|
3045
3375
|
}
|
|
3046
3376
|
}
|
|
3047
3377
|
}
|
|
3048
|
-
}
|
|
3378
|
+
}
|
|
3049
3379
|
}
|
|
3050
3380
|
};
|
|
3051
3381
|
|
|
@@ -3061,18 +3391,18 @@ module.exports = {
|
|
|
3061
3391
|
"use strict";
|
|
3062
3392
|
// @ts-check
|
|
3063
3393
|
|
|
3064
|
-
|
|
3394
|
+
const { addError } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3065
3395
|
module.exports = {
|
|
3066
3396
|
"names": ["MD028", "no-blanks-blockquote"],
|
|
3067
3397
|
"description": "Blank line inside blockquote",
|
|
3068
3398
|
"tags": ["blockquote", "whitespace"],
|
|
3069
3399
|
"function": function MD028(params, onError) {
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
params.tokens
|
|
3400
|
+
let prevToken = {};
|
|
3401
|
+
let prevLineNumber = null;
|
|
3402
|
+
for (const token of params.tokens) {
|
|
3073
3403
|
if ((token.type === "blockquote_open") &&
|
|
3074
3404
|
(prevToken.type === "blockquote_close")) {
|
|
3075
|
-
for (
|
|
3405
|
+
for (let lineNumber = prevLineNumber; lineNumber < token.lineNumber; lineNumber++) {
|
|
3076
3406
|
addError(onError, lineNumber);
|
|
3077
3407
|
}
|
|
3078
3408
|
}
|
|
@@ -3080,7 +3410,7 @@ module.exports = {
|
|
|
3080
3410
|
if (token.type === "blockquote_open") {
|
|
3081
3411
|
prevLineNumber = token.map[1] + 1;
|
|
3082
3412
|
}
|
|
3083
|
-
}
|
|
3413
|
+
}
|
|
3084
3414
|
}
|
|
3085
3415
|
};
|
|
3086
3416
|
|
|
@@ -3096,9 +3426,9 @@ module.exports = {
|
|
|
3096
3426
|
"use strict";
|
|
3097
3427
|
// @ts-check
|
|
3098
3428
|
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3429
|
+
const { addErrorDetailIf, listItemMarkerRe, orderedListItemMarkerRe, rangeFromRegExp } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3430
|
+
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3431
|
+
const listStyleExamples = {
|
|
3102
3432
|
"one": "1/1/1",
|
|
3103
3433
|
"ordered": "1/2/3",
|
|
3104
3434
|
"zero": "0/0/0"
|
|
@@ -3108,18 +3438,19 @@ module.exports = {
|
|
|
3108
3438
|
"description": "Ordered list item prefix",
|
|
3109
3439
|
"tags": ["ol"],
|
|
3110
3440
|
"function": function MD029(params, onError) {
|
|
3111
|
-
|
|
3112
|
-
flattenedLists().filter(
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3441
|
+
const style = String(params.config.style || "one_or_ordered");
|
|
3442
|
+
const filteredLists = flattenedLists().filter((list) => !list.unordered);
|
|
3443
|
+
for (const list of filteredLists) {
|
|
3444
|
+
const { items } = list;
|
|
3445
|
+
let current = 1;
|
|
3446
|
+
let incrementing = false;
|
|
3116
3447
|
// Check for incrementing number pattern 1/2/3 or 0/1/2
|
|
3117
3448
|
if (items.length >= 2) {
|
|
3118
|
-
|
|
3119
|
-
|
|
3449
|
+
const first = orderedListItemMarkerRe.exec(items[0].line);
|
|
3450
|
+
const second = orderedListItemMarkerRe.exec(items[1].line);
|
|
3120
3451
|
if (first && second) {
|
|
3121
|
-
|
|
3122
|
-
|
|
3452
|
+
const [, firstNumber] = first;
|
|
3453
|
+
const [, secondNumber] = second;
|
|
3123
3454
|
if ((secondNumber !== "1") || (firstNumber === "0")) {
|
|
3124
3455
|
incrementing = true;
|
|
3125
3456
|
if (firstNumber === "0") {
|
|
@@ -3129,7 +3460,7 @@ module.exports = {
|
|
|
3129
3460
|
}
|
|
3130
3461
|
}
|
|
3131
3462
|
// Determine effective style
|
|
3132
|
-
|
|
3463
|
+
let listStyle = style;
|
|
3133
3464
|
if (listStyle === "one_or_ordered") {
|
|
3134
3465
|
listStyle = incrementing ? "ordered" : "one";
|
|
3135
3466
|
}
|
|
@@ -3141,16 +3472,16 @@ module.exports = {
|
|
|
3141
3472
|
current = 1;
|
|
3142
3473
|
}
|
|
3143
3474
|
// Validate each list item marker
|
|
3144
|
-
|
|
3145
|
-
|
|
3475
|
+
for (const item of items) {
|
|
3476
|
+
const match = orderedListItemMarkerRe.exec(item.line);
|
|
3146
3477
|
if (match) {
|
|
3147
3478
|
addErrorDetailIf(onError, item.lineNumber, String(current), match[1], "Style: " + listStyleExamples[listStyle], null, rangeFromRegExp(item.line, listItemMarkerRe));
|
|
3148
3479
|
if (listStyle === "ordered") {
|
|
3149
3480
|
current++;
|
|
3150
3481
|
}
|
|
3151
3482
|
}
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3154
3485
|
}
|
|
3155
3486
|
};
|
|
3156
3487
|
|
|
@@ -3166,29 +3497,29 @@ module.exports = {
|
|
|
3166
3497
|
"use strict";
|
|
3167
3498
|
// @ts-check
|
|
3168
3499
|
|
|
3169
|
-
|
|
3170
|
-
|
|
3500
|
+
const { addErrorDetailIf } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3501
|
+
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3171
3502
|
module.exports = {
|
|
3172
3503
|
"names": ["MD030", "list-marker-space"],
|
|
3173
3504
|
"description": "Spaces after list markers",
|
|
3174
3505
|
"tags": ["ol", "ul", "whitespace"],
|
|
3175
3506
|
"function": function MD030(params, onError) {
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3507
|
+
const ulSingle = Number(params.config.ul_single || 1);
|
|
3508
|
+
const olSingle = Number(params.config.ol_single || 1);
|
|
3509
|
+
const ulMulti = Number(params.config.ul_multi || 1);
|
|
3510
|
+
const olMulti = Number(params.config.ol_multi || 1);
|
|
3511
|
+
for (const list of flattenedLists()) {
|
|
3512
|
+
const lineCount = list.lastLineIndex - list.open.map[0];
|
|
3513
|
+
const allSingle = lineCount === list.items.length;
|
|
3514
|
+
const expectedSpaces = list.unordered ?
|
|
3184
3515
|
(allSingle ? ulSingle : ulMulti) :
|
|
3185
3516
|
(allSingle ? olSingle : olMulti);
|
|
3186
|
-
list.items
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3517
|
+
for (const item of list.items) {
|
|
3518
|
+
const { line, lineNumber } = item;
|
|
3519
|
+
const match = /^[\s>]*\S+(\s*)/.exec(line);
|
|
3520
|
+
const [{ "length": matchLength }, { "length": actualSpaces }] = match;
|
|
3190
3521
|
if (matchLength < line.length) {
|
|
3191
|
-
|
|
3522
|
+
let fixInfo = null;
|
|
3192
3523
|
if (expectedSpaces !== actualSpaces) {
|
|
3193
3524
|
fixInfo = {
|
|
3194
3525
|
"editColumn": matchLength - actualSpaces + 1,
|
|
@@ -3198,8 +3529,8 @@ module.exports = {
|
|
|
3198
3529
|
}
|
|
3199
3530
|
addErrorDetailIf(onError, lineNumber, expectedSpaces, actualSpaces, null, null, [1, matchLength], fixInfo);
|
|
3200
3531
|
}
|
|
3201
|
-
}
|
|
3202
|
-
}
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3203
3534
|
}
|
|
3204
3535
|
};
|
|
3205
3536
|
|
|
@@ -3215,27 +3546,27 @@ module.exports = {
|
|
|
3215
3546
|
"use strict";
|
|
3216
3547
|
// @ts-check
|
|
3217
3548
|
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3549
|
+
const { addErrorContext, forEachLine, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3550
|
+
const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3551
|
+
const codeFencePrefixRe = /^(.*?)[`~]/;
|
|
3221
3552
|
module.exports = {
|
|
3222
3553
|
"names": ["MD031", "blanks-around-fences"],
|
|
3223
3554
|
"description": "Fenced code blocks should be surrounded by blank lines",
|
|
3224
3555
|
"tags": ["code", "blank_lines"],
|
|
3225
3556
|
"function": function MD031(params, onError) {
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
forEachLine(lineMetadata(),
|
|
3230
|
-
|
|
3231
|
-
|
|
3557
|
+
const listItems = params.config.list_items;
|
|
3558
|
+
const includeListItems = (listItems === undefined) ? true : !!listItems;
|
|
3559
|
+
const { lines } = params;
|
|
3560
|
+
forEachLine(lineMetadata(), (line, i, inCode, onFence, inTable, inItem) => {
|
|
3561
|
+
const onTopFence = (onFence > 0);
|
|
3562
|
+
const onBottomFence = (onFence < 0);
|
|
3232
3563
|
if ((includeListItems || !inItem) &&
|
|
3233
3564
|
((onTopFence && !isBlankLine(lines[i - 1])) ||
|
|
3234
3565
|
(onBottomFence && !isBlankLine(lines[i + 1])))) {
|
|
3235
|
-
|
|
3236
|
-
|
|
3566
|
+
const [, prefix] = line.match(codeFencePrefixRe) || [];
|
|
3567
|
+
const fixInfo = (prefix === undefined) ? null : {
|
|
3237
3568
|
"lineNumber": i + (onTopFence ? 1 : 2),
|
|
3238
|
-
"insertText":
|
|
3569
|
+
"insertText": `${prefix.replace(/[^>]/g, " ").trim()}\n`
|
|
3239
3570
|
};
|
|
3240
3571
|
addErrorContext(onError, i + 1, lines[i].trim(), null, null, null, fixInfo);
|
|
3241
3572
|
}
|
|
@@ -3255,34 +3586,34 @@ module.exports = {
|
|
|
3255
3586
|
"use strict";
|
|
3256
3587
|
// @ts-check
|
|
3257
3588
|
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
var quotePrefixRe = /^[>\s]*/;
|
|
3589
|
+
const { addErrorContext, blockquotePrefixRe, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3590
|
+
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3261
3591
|
module.exports = {
|
|
3262
3592
|
"names": ["MD032", "blanks-around-lists"],
|
|
3263
3593
|
"description": "Lists should be surrounded by blank lines",
|
|
3264
3594
|
"tags": ["bullet", "ul", "ol", "blank_lines"],
|
|
3265
3595
|
"function": function MD032(params, onError) {
|
|
3266
|
-
|
|
3267
|
-
flattenedLists().filter(
|
|
3268
|
-
|
|
3596
|
+
const { lines } = params;
|
|
3597
|
+
const filteredLists = flattenedLists().filter((list) => !list.nesting);
|
|
3598
|
+
for (const list of filteredLists) {
|
|
3599
|
+
const firstIndex = list.open.map[0];
|
|
3269
3600
|
if (!isBlankLine(lines[firstIndex - 1])) {
|
|
3270
|
-
|
|
3271
|
-
|
|
3601
|
+
const line = lines[firstIndex];
|
|
3602
|
+
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
3272
3603
|
addErrorContext(onError, firstIndex + 1, line.trim(), null, null, null, {
|
|
3273
|
-
"insertText":
|
|
3604
|
+
"insertText": `${quotePrefix}\n`
|
|
3274
3605
|
});
|
|
3275
3606
|
}
|
|
3276
|
-
|
|
3607
|
+
const lastIndex = list.lastLineIndex - 1;
|
|
3277
3608
|
if (!isBlankLine(lines[lastIndex + 1])) {
|
|
3278
|
-
|
|
3279
|
-
|
|
3609
|
+
const line = lines[lastIndex];
|
|
3610
|
+
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
3280
3611
|
addErrorContext(onError, lastIndex + 1, line.trim(), null, null, null, {
|
|
3281
3612
|
"lineNumber": lastIndex + 2,
|
|
3282
|
-
"insertText":
|
|
3613
|
+
"insertText": `${quotePrefix}\n`
|
|
3283
3614
|
});
|
|
3284
3615
|
}
|
|
3285
|
-
}
|
|
3616
|
+
}
|
|
3286
3617
|
}
|
|
3287
3618
|
};
|
|
3288
3619
|
|
|
@@ -3298,12 +3629,11 @@ module.exports = {
|
|
|
3298
3629
|
"use strict";
|
|
3299
3630
|
// @ts-check
|
|
3300
3631
|
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
var linkDestinationRe = /]\(\s*$/;
|
|
3632
|
+
const { addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3633
|
+
const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3634
|
+
const linkDestinationRe = /]\(\s*$/;
|
|
3305
3635
|
// See https://spec.commonmark.org/0.29/#autolinks
|
|
3306
|
-
|
|
3636
|
+
const emailAddressRe =
|
|
3307
3637
|
// eslint-disable-next-line max-len
|
|
3308
3638
|
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
3309
3639
|
module.exports = {
|
|
@@ -3311,24 +3641,24 @@ module.exports = {
|
|
|
3311
3641
|
"description": "Inline HTML",
|
|
3312
3642
|
"tags": ["html"],
|
|
3313
3643
|
"function": function MD033(params, onError) {
|
|
3314
|
-
|
|
3644
|
+
let allowedElements = params.config.allowed_elements;
|
|
3315
3645
|
allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
|
|
3316
|
-
allowedElements = allowedElements.map(
|
|
3317
|
-
|
|
3318
|
-
forEachLine(lineMetadata(),
|
|
3319
|
-
|
|
3646
|
+
allowedElements = allowedElements.map((element) => element.toLowerCase());
|
|
3647
|
+
const exclusions = codeBlockAndSpanRanges();
|
|
3648
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
3649
|
+
let match = null;
|
|
3320
3650
|
// eslint-disable-next-line no-unmodified-loop-condition
|
|
3321
3651
|
while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) {
|
|
3322
|
-
|
|
3652
|
+
const [tag, content, element] = match;
|
|
3323
3653
|
if (!allowedElements.includes(element.toLowerCase()) &&
|
|
3324
3654
|
!tag.endsWith("\\>") &&
|
|
3325
3655
|
!emailAddressRe.test(content) &&
|
|
3326
|
-
!
|
|
3327
|
-
|
|
3656
|
+
!withinAnyRange(exclusions, lineIndex, match.index, match[0].length)) {
|
|
3657
|
+
const prefix = line.substring(0, match.index);
|
|
3328
3658
|
if (!linkDestinationRe.test(prefix)) {
|
|
3329
|
-
|
|
3659
|
+
const unescaped = unescapeMarkdown(prefix + "<", "_");
|
|
3330
3660
|
if (!unescaped.endsWith("_")) {
|
|
3331
|
-
addError(onError, lineIndex + 1, "Element: " + element,
|
|
3661
|
+
addError(onError, lineIndex + 1, "Element: " + element, undefined, [match.index + 1, tag.length]);
|
|
3332
3662
|
}
|
|
3333
3663
|
}
|
|
3334
3664
|
}
|
|
@@ -3349,17 +3679,17 @@ module.exports = {
|
|
|
3349
3679
|
"use strict";
|
|
3350
3680
|
// @ts-check
|
|
3351
3681
|
|
|
3352
|
-
|
|
3682
|
+
const { addErrorContext, bareUrlRe, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3353
3683
|
module.exports = {
|
|
3354
3684
|
"names": ["MD034", "no-bare-urls"],
|
|
3355
3685
|
"description": "Bare URL used",
|
|
3356
3686
|
"tags": ["links", "url"],
|
|
3357
3687
|
"function": function MD034(params, onError) {
|
|
3358
|
-
filterTokens(params, "inline",
|
|
3359
|
-
|
|
3360
|
-
token.children
|
|
3361
|
-
|
|
3362
|
-
|
|
3688
|
+
filterTokens(params, "inline", (token) => {
|
|
3689
|
+
let inLink = false;
|
|
3690
|
+
for (const child of token.children) {
|
|
3691
|
+
const { content, line, lineNumber, type } = child;
|
|
3692
|
+
let match = null;
|
|
3363
3693
|
if (type === "link_open") {
|
|
3364
3694
|
inLink = true;
|
|
3365
3695
|
}
|
|
@@ -3368,32 +3698,32 @@ module.exports = {
|
|
|
3368
3698
|
}
|
|
3369
3699
|
else if ((type === "text") && !inLink) {
|
|
3370
3700
|
while ((match = bareUrlRe.exec(content)) !== null) {
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3701
|
+
const [bareUrl] = match;
|
|
3702
|
+
const matchIndex = match.index;
|
|
3703
|
+
const bareUrlLength = bareUrl.length;
|
|
3374
3704
|
// Allow "[https://example.com]" to avoid conflicts with
|
|
3375
3705
|
// MD011/no-reversed-links; allow quoting as another way
|
|
3376
3706
|
// of deliberately including a bare URL
|
|
3377
|
-
|
|
3378
|
-
|
|
3707
|
+
const leftChar = content[matchIndex - 1];
|
|
3708
|
+
const rightChar = content[matchIndex + bareUrlLength];
|
|
3379
3709
|
if (!((leftChar === "[") && (rightChar === "]")) &&
|
|
3380
3710
|
!((leftChar === "\"") && (rightChar === "\"")) &&
|
|
3381
3711
|
!((leftChar === "'") && (rightChar === "'"))) {
|
|
3382
|
-
|
|
3383
|
-
|
|
3712
|
+
const index = line.indexOf(content);
|
|
3713
|
+
const range = (index === -1) ? null : [
|
|
3384
3714
|
index + matchIndex + 1,
|
|
3385
3715
|
bareUrlLength
|
|
3386
3716
|
];
|
|
3387
|
-
|
|
3717
|
+
const fixInfo = range ? {
|
|
3388
3718
|
"editColumn": range[0],
|
|
3389
3719
|
"deleteCount": range[1],
|
|
3390
|
-
"insertText":
|
|
3720
|
+
"insertText": `<${bareUrl}>`
|
|
3391
3721
|
} : null;
|
|
3392
3722
|
addErrorContext(onError, lineNumber, bareUrl, null, null, range, fixInfo);
|
|
3393
3723
|
}
|
|
3394
3724
|
}
|
|
3395
3725
|
}
|
|
3396
|
-
}
|
|
3726
|
+
}
|
|
3397
3727
|
});
|
|
3398
3728
|
}
|
|
3399
3729
|
};
|
|
@@ -3410,15 +3740,20 @@ module.exports = {
|
|
|
3410
3740
|
"use strict";
|
|
3411
3741
|
// @ts-check
|
|
3412
3742
|
|
|
3413
|
-
|
|
3743
|
+
const { addErrorDetailIf, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3414
3744
|
module.exports = {
|
|
3415
3745
|
"names": ["MD035", "hr-style"],
|
|
3416
3746
|
"description": "Horizontal rule style",
|
|
3417
3747
|
"tags": ["hr"],
|
|
3418
3748
|
"function": function MD035(params, onError) {
|
|
3419
|
-
|
|
3420
|
-
filterTokens(params, "hr",
|
|
3421
|
-
|
|
3749
|
+
let style = String(params.config.style || "consistent").trim();
|
|
3750
|
+
filterTokens(params, "hr", (token) => {
|
|
3751
|
+
const { line, lineNumber } = token;
|
|
3752
|
+
let { markup } = token;
|
|
3753
|
+
const match = line.match(/[_*\-\s\t]+$/);
|
|
3754
|
+
if (match) {
|
|
3755
|
+
markup = match[0].trim();
|
|
3756
|
+
}
|
|
3422
3757
|
if (style === "consistent") {
|
|
3423
3758
|
style = markup;
|
|
3424
3759
|
}
|
|
@@ -3439,22 +3774,22 @@ module.exports = {
|
|
|
3439
3774
|
"use strict";
|
|
3440
3775
|
// @ts-check
|
|
3441
3776
|
|
|
3442
|
-
|
|
3777
|
+
const { addErrorContext, allPunctuation } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3443
3778
|
module.exports = {
|
|
3444
3779
|
"names": ["MD036", "no-emphasis-as-heading", "no-emphasis-as-header"],
|
|
3445
3780
|
"description": "Emphasis used instead of a heading",
|
|
3446
3781
|
"tags": ["headings", "headers", "emphasis"],
|
|
3447
3782
|
"function": function MD036(params, onError) {
|
|
3448
|
-
|
|
3783
|
+
let punctuation = params.config.punctuation;
|
|
3449
3784
|
punctuation =
|
|
3450
3785
|
String((punctuation === undefined) ? allPunctuation : punctuation);
|
|
3451
|
-
|
|
3786
|
+
const re = new RegExp("[" + punctuation + "]$");
|
|
3452
3787
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
3453
3788
|
function base(token) {
|
|
3454
3789
|
if (token.type === "paragraph_open") {
|
|
3455
3790
|
return function inParagraph(t) {
|
|
3456
3791
|
// Always paragraph_open/inline/paragraph_close,
|
|
3457
|
-
|
|
3792
|
+
const children = t.children.filter(function notEmptyText(child) {
|
|
3458
3793
|
return (child.type !== "text") || (child.content !== "");
|
|
3459
3794
|
});
|
|
3460
3795
|
if ((children.length === 3) &&
|
|
@@ -3485,10 +3820,10 @@ module.exports = {
|
|
|
3485
3820
|
}
|
|
3486
3821
|
return base;
|
|
3487
3822
|
}
|
|
3488
|
-
|
|
3489
|
-
params.tokens
|
|
3823
|
+
let state = base;
|
|
3824
|
+
for (const token of params.tokens) {
|
|
3490
3825
|
state = state(token);
|
|
3491
|
-
}
|
|
3826
|
+
}
|
|
3492
3827
|
}
|
|
3493
3828
|
};
|
|
3494
3829
|
|
|
@@ -3504,21 +3839,22 @@ module.exports = {
|
|
|
3504
3839
|
"use strict";
|
|
3505
3840
|
// @ts-check
|
|
3506
3841
|
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3842
|
+
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3843
|
+
const { htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3844
|
+
const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
|
|
3845
|
+
const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
|
|
3846
|
+
const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
|
|
3847
|
+
const leftSpaceRe = /^\s+/;
|
|
3848
|
+
const rightSpaceRe = /\s+$/;
|
|
3849
|
+
const tablePipeRe = /\|/;
|
|
3515
3850
|
module.exports = {
|
|
3516
3851
|
"names": ["MD037", "no-space-in-emphasis"],
|
|
3517
3852
|
"description": "Spaces inside emphasis markers",
|
|
3518
3853
|
"tags": ["whitespace", "emphasis"],
|
|
3519
3854
|
"function": function MD037(params, onError) {
|
|
3855
|
+
const exclusions = htmlElementRanges();
|
|
3520
3856
|
// eslint-disable-next-line init-declarations
|
|
3521
|
-
|
|
3857
|
+
let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength, pendingError = null;
|
|
3522
3858
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
3523
3859
|
function resetRunTracking() {
|
|
3524
3860
|
emphasisIndex = -1;
|
|
@@ -3530,47 +3866,49 @@ module.exports = {
|
|
|
3530
3866
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
3531
3867
|
function handleRunEnd(line, lineIndex, contextLength, match, matchIndex, inTable) {
|
|
3532
3868
|
// Close current run
|
|
3533
|
-
|
|
3869
|
+
let content = line.substring(emphasisIndex, matchIndex);
|
|
3534
3870
|
if (!emphasisLength) {
|
|
3535
3871
|
content = content.trimStart();
|
|
3536
3872
|
}
|
|
3537
3873
|
if (!match) {
|
|
3538
3874
|
content = content.trimEnd();
|
|
3539
3875
|
}
|
|
3540
|
-
|
|
3541
|
-
|
|
3876
|
+
const leftSpace = leftSpaceRe.test(content);
|
|
3877
|
+
const rightSpace = rightSpaceRe.test(content);
|
|
3542
3878
|
if ((leftSpace || rightSpace) &&
|
|
3543
3879
|
(!inTable || !tablePipeRe.test(content))) {
|
|
3544
3880
|
// Report the violation
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3881
|
+
const contextStart = emphasisIndex - emphasisLength;
|
|
3882
|
+
const contextEnd = matchIndex + contextLength;
|
|
3883
|
+
const column = contextStart + 1;
|
|
3884
|
+
const length = contextEnd - contextStart;
|
|
3885
|
+
if (!withinAnyRange(exclusions, lineIndex, column, length)) {
|
|
3886
|
+
const context = line.substring(contextStart, contextEnd);
|
|
3887
|
+
const leftMarker = line.substring(contextStart, emphasisIndex);
|
|
3888
|
+
const rightMarker = match ? (match[2] || match[3]) : "";
|
|
3889
|
+
const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
|
|
3890
|
+
return [
|
|
3891
|
+
onError,
|
|
3892
|
+
lineIndex + 1,
|
|
3893
|
+
context,
|
|
3894
|
+
leftSpace,
|
|
3895
|
+
rightSpace,
|
|
3896
|
+
[column, length],
|
|
3897
|
+
{
|
|
3898
|
+
"editColumn": column,
|
|
3899
|
+
"deleteCount": length,
|
|
3900
|
+
"insertText": fixedText
|
|
3901
|
+
}
|
|
3902
|
+
];
|
|
3903
|
+
}
|
|
3566
3904
|
}
|
|
3567
3905
|
return null;
|
|
3568
3906
|
}
|
|
3569
3907
|
// Initialize
|
|
3570
|
-
|
|
3908
|
+
const ignoreMarkersByLine = emphasisMarkersInContent(params);
|
|
3571
3909
|
resetRunTracking();
|
|
3572
|
-
forEachLine(lineMetadata(),
|
|
3573
|
-
|
|
3910
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable, inItem, onBreak, inMath) => {
|
|
3911
|
+
const onItemStart = (inItem === 1);
|
|
3574
3912
|
if (inCode ||
|
|
3575
3913
|
onFence ||
|
|
3576
3914
|
inTable ||
|
|
@@ -3587,22 +3925,22 @@ module.exports = {
|
|
|
3587
3925
|
// Emphasis has no meaning here
|
|
3588
3926
|
return;
|
|
3589
3927
|
}
|
|
3590
|
-
|
|
3928
|
+
let patchedLine = line.replace(embeddedUnderscoreRe, "$1 $2");
|
|
3591
3929
|
if (onItemStart) {
|
|
3592
3930
|
// Trim overlapping '*' list item marker
|
|
3593
3931
|
patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2");
|
|
3594
3932
|
}
|
|
3595
|
-
|
|
3933
|
+
let match = null;
|
|
3596
3934
|
// Match all emphasis-looking runs in the line...
|
|
3597
3935
|
while ((match = emphasisRe.exec(patchedLine))) {
|
|
3598
|
-
|
|
3599
|
-
|
|
3936
|
+
const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex];
|
|
3937
|
+
const matchIndex = match.index + match[1].length;
|
|
3600
3938
|
if (ignoreMarkersForLine.includes(matchIndex)) {
|
|
3601
3939
|
// Ignore emphasis markers inside code spans and links
|
|
3602
3940
|
continue;
|
|
3603
3941
|
}
|
|
3604
|
-
|
|
3605
|
-
|
|
3942
|
+
const matchLength = match[0].length - match[1].length;
|
|
3943
|
+
const matchKind = (match[2] || match[3])[0];
|
|
3606
3944
|
if (emphasisIndex === -1) {
|
|
3607
3945
|
// New run
|
|
3608
3946
|
emphasisIndex = matchIndex + matchLength;
|
|
@@ -3616,13 +3954,13 @@ module.exports = {
|
|
|
3616
3954
|
// Ending an existing run, report any pending error
|
|
3617
3955
|
if (pendingError) {
|
|
3618
3956
|
// @ts-ignore
|
|
3619
|
-
addErrorContext
|
|
3957
|
+
addErrorContext(...pendingError);
|
|
3620
3958
|
pendingError = null;
|
|
3621
3959
|
}
|
|
3622
|
-
|
|
3960
|
+
const error = handleRunEnd(line, lineIndex, effectiveEmphasisLength, match, matchIndex, inTable);
|
|
3623
3961
|
if (error) {
|
|
3624
3962
|
// @ts-ignore
|
|
3625
|
-
addErrorContext
|
|
3963
|
+
addErrorContext(...error);
|
|
3626
3964
|
}
|
|
3627
3965
|
// Reset
|
|
3628
3966
|
resetRunTracking();
|
|
@@ -3674,43 +4012,43 @@ module.exports = {
|
|
|
3674
4012
|
"use strict";
|
|
3675
4013
|
// @ts-check
|
|
3676
4014
|
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
4015
|
+
const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4016
|
+
const leftSpaceRe = /^\s([^`]|$)/;
|
|
4017
|
+
const rightSpaceRe = /[^`]\s$/;
|
|
4018
|
+
const spaceInsideCodeInline = (token) => ((token.type === "code_inline") &&
|
|
4019
|
+
(leftSpaceRe.test(token.content) || rightSpaceRe.test(token.content)));
|
|
3681
4020
|
module.exports = {
|
|
3682
4021
|
"names": ["MD038", "no-space-in-code"],
|
|
3683
4022
|
"description": "Spaces inside code span elements",
|
|
3684
4023
|
"tags": ["whitespace", "code"],
|
|
3685
4024
|
"function": function MD038(params, onError) {
|
|
3686
|
-
filterTokens(params, "inline",
|
|
3687
|
-
if (token.children.some(
|
|
3688
|
-
|
|
3689
|
-
forEachInlineCodeSpan(
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
4025
|
+
filterTokens(params, "inline", (token) => {
|
|
4026
|
+
if (token.children.some(spaceInsideCodeInline)) {
|
|
4027
|
+
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
|
4028
|
+
forEachInlineCodeSpan(tokenLines.join("\n"), (code, lineIndex, columnIndex, tickCount) => {
|
|
4029
|
+
let rangeIndex = columnIndex - tickCount;
|
|
4030
|
+
let rangeLength = code.length + (2 * tickCount);
|
|
4031
|
+
let rangeLineOffset = 0;
|
|
4032
|
+
let fixIndex = columnIndex;
|
|
4033
|
+
let fixLength = code.length;
|
|
4034
|
+
const codeLines = code.split(newLineRe);
|
|
4035
|
+
const left = leftSpaceRe.test(code);
|
|
4036
|
+
const right = !left && rightSpaceRe.test(code);
|
|
3698
4037
|
if (right && (codeLines.length > 1)) {
|
|
3699
4038
|
rangeIndex = 0;
|
|
3700
4039
|
rangeLineOffset = codeLines.length - 1;
|
|
3701
4040
|
fixIndex = 0;
|
|
3702
4041
|
}
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
var codeLinesRange = codeLines[rangeLineOffset];
|
|
4042
|
+
if (left || right) {
|
|
4043
|
+
const codeLinesRange = codeLines[rangeLineOffset];
|
|
3706
4044
|
if (codeLines.length > 1) {
|
|
3707
4045
|
rangeLength = codeLinesRange.length + tickCount;
|
|
3708
4046
|
fixLength = codeLinesRange.length;
|
|
3709
4047
|
}
|
|
3710
|
-
|
|
4048
|
+
const context = tokenLines[lineIndex + rangeLineOffset]
|
|
3711
4049
|
.substring(rangeIndex, rangeIndex + rangeLength);
|
|
3712
|
-
|
|
3713
|
-
|
|
4050
|
+
const codeLinesRangeTrim = codeLinesRange.trim();
|
|
4051
|
+
const fixText = (codeLinesRangeTrim.startsWith("`") ? " " : "") +
|
|
3714
4052
|
codeLinesRangeTrim +
|
|
3715
4053
|
(codeLinesRangeTrim.endsWith("`") ? " " : "");
|
|
3716
4054
|
addErrorContext(onError, token.lineNumber + lineIndex + rangeLineOffset, context, left, right, [rangeIndex + 1, rangeLength], {
|
|
@@ -3737,37 +4075,37 @@ module.exports = {
|
|
|
3737
4075
|
"use strict";
|
|
3738
4076
|
// @ts-check
|
|
3739
4077
|
|
|
3740
|
-
|
|
3741
|
-
|
|
4078
|
+
const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4079
|
+
const spaceInLinkRe = /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=((?:\([^)]*\))|(?:\[[^\]]*\])))/;
|
|
3742
4080
|
module.exports = {
|
|
3743
4081
|
"names": ["MD039", "no-space-in-links"],
|
|
3744
4082
|
"description": "Spaces inside link text",
|
|
3745
4083
|
"tags": ["whitespace", "links"],
|
|
3746
4084
|
"function": function MD039(params, onError) {
|
|
3747
|
-
filterTokens(params, "inline",
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
4085
|
+
filterTokens(params, "inline", (token) => {
|
|
4086
|
+
const { children } = token;
|
|
4087
|
+
let { lineNumber } = token;
|
|
4088
|
+
let inLink = false;
|
|
4089
|
+
let linkText = "";
|
|
4090
|
+
let lineIndex = 0;
|
|
4091
|
+
for (const child of children) {
|
|
4092
|
+
const { content, markup, type } = child;
|
|
3755
4093
|
if (type === "link_open") {
|
|
3756
4094
|
inLink = true;
|
|
3757
4095
|
linkText = "";
|
|
3758
4096
|
}
|
|
3759
4097
|
else if (type === "link_close") {
|
|
3760
4098
|
inLink = false;
|
|
3761
|
-
|
|
3762
|
-
|
|
4099
|
+
const left = linkText.trimStart().length !== linkText.length;
|
|
4100
|
+
const right = linkText.trimEnd().length !== linkText.length;
|
|
3763
4101
|
if (left || right) {
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
4102
|
+
const line = params.lines[lineNumber - 1];
|
|
4103
|
+
let range = null;
|
|
4104
|
+
let fixInfo = null;
|
|
4105
|
+
const match = line.slice(lineIndex).match(spaceInLinkRe);
|
|
3768
4106
|
if (match) {
|
|
3769
|
-
|
|
3770
|
-
|
|
4107
|
+
const column = match.index + lineIndex + 1;
|
|
4108
|
+
const length = match[0].length;
|
|
3771
4109
|
range = [column, length];
|
|
3772
4110
|
fixInfo = {
|
|
3773
4111
|
"editColumn": column + 1,
|
|
@@ -3776,7 +4114,7 @@ module.exports = {
|
|
|
3776
4114
|
};
|
|
3777
4115
|
lineIndex = column + length - 1;
|
|
3778
4116
|
}
|
|
3779
|
-
addErrorContext(onError, lineNumber,
|
|
4117
|
+
addErrorContext(onError, lineNumber, `[${linkText}]`, left, right, range, fixInfo);
|
|
3780
4118
|
}
|
|
3781
4119
|
}
|
|
3782
4120
|
else if ((type === "softbreak") || (type === "hardbreak")) {
|
|
@@ -3784,9 +4122,11 @@ module.exports = {
|
|
|
3784
4122
|
lineIndex = 0;
|
|
3785
4123
|
}
|
|
3786
4124
|
else if (inLink) {
|
|
3787
|
-
linkText +=
|
|
4125
|
+
linkText += type.endsWith("_inline") ?
|
|
4126
|
+
`${markup}${content}${markup}` :
|
|
4127
|
+
(content || markup);
|
|
3788
4128
|
}
|
|
3789
|
-
}
|
|
4129
|
+
}
|
|
3790
4130
|
});
|
|
3791
4131
|
}
|
|
3792
4132
|
};
|
|
@@ -3803,7 +4143,7 @@ module.exports = {
|
|
|
3803
4143
|
"use strict";
|
|
3804
4144
|
// @ts-check
|
|
3805
4145
|
|
|
3806
|
-
|
|
4146
|
+
const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3807
4147
|
module.exports = {
|
|
3808
4148
|
"names": ["MD040", "fenced-code-language"],
|
|
3809
4149
|
"description": "Fenced code blocks should have a language specified",
|
|
@@ -3829,25 +4169,25 @@ module.exports = {
|
|
|
3829
4169
|
"use strict";
|
|
3830
4170
|
// @ts-check
|
|
3831
4171
|
|
|
3832
|
-
|
|
4172
|
+
const { addErrorContext, frontMatterHasTitle } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3833
4173
|
module.exports = {
|
|
3834
4174
|
"names": ["MD041", "first-line-heading", "first-line-h1"],
|
|
3835
4175
|
"description": "First line in a file should be a top-level heading",
|
|
3836
4176
|
"tags": ["headings", "headers"],
|
|
3837
4177
|
"function": function MD041(params, onError) {
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
4178
|
+
const level = Number(params.config.level || 1);
|
|
4179
|
+
const tag = "h" + level;
|
|
4180
|
+
const foundFrontMatterTitle = frontMatterHasTitle(params.frontMatterLines, params.config.front_matter_title);
|
|
3841
4181
|
if (!foundFrontMatterTitle) {
|
|
3842
|
-
|
|
3843
|
-
params.tokens.every(
|
|
3844
|
-
|
|
4182
|
+
const htmlHeadingRe = new RegExp(`^<h${level}[ />]`, "i");
|
|
4183
|
+
params.tokens.every((token) => {
|
|
4184
|
+
let isError = false;
|
|
3845
4185
|
if (token.type === "html_block") {
|
|
3846
4186
|
if (token.content.startsWith("<!--")) {
|
|
3847
4187
|
// Ignore leading HTML comments
|
|
3848
4188
|
return true;
|
|
3849
4189
|
}
|
|
3850
|
-
else if (!
|
|
4190
|
+
else if (!htmlHeadingRe.test(token.content)) {
|
|
3851
4191
|
// Something other than an HTML heading
|
|
3852
4192
|
isError = true;
|
|
3853
4193
|
}
|
|
@@ -3877,38 +4217,44 @@ module.exports = {
|
|
|
3877
4217
|
"use strict";
|
|
3878
4218
|
// @ts-check
|
|
3879
4219
|
|
|
3880
|
-
|
|
3881
|
-
var emptyLinkRe = /\[[^\]]*](?:\((?:#?|(?:<>))\))/;
|
|
4220
|
+
const { addErrorContext, escapeForRegExp, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3882
4221
|
module.exports = {
|
|
3883
4222
|
"names": ["MD042", "no-empty-links"],
|
|
3884
4223
|
"description": "No empty links",
|
|
3885
4224
|
"tags": ["links"],
|
|
3886
4225
|
"function": function MD042(params, onError) {
|
|
3887
4226
|
filterTokens(params, "inline", function forToken(token) {
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
token.children
|
|
4227
|
+
let inLink = false;
|
|
4228
|
+
let linkText = "";
|
|
4229
|
+
let emptyLink = false;
|
|
4230
|
+
for (const child of token.children) {
|
|
3892
4231
|
if (child.type === "link_open") {
|
|
3893
4232
|
inLink = true;
|
|
3894
4233
|
linkText = "";
|
|
3895
|
-
child.attrs
|
|
4234
|
+
for (const attr of child.attrs) {
|
|
3896
4235
|
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
|
3897
4236
|
emptyLink = true;
|
|
3898
4237
|
}
|
|
3899
|
-
}
|
|
4238
|
+
}
|
|
3900
4239
|
}
|
|
3901
4240
|
else if (child.type === "link_close") {
|
|
3902
4241
|
inLink = false;
|
|
3903
4242
|
if (emptyLink) {
|
|
3904
|
-
|
|
4243
|
+
let context = `[${linkText}]`;
|
|
4244
|
+
let range = null;
|
|
4245
|
+
const match = child.line.match(new RegExp(`${escapeForRegExp(context)}\\((?:|#|<>)\\)`));
|
|
4246
|
+
if (match) {
|
|
4247
|
+
context = match[0];
|
|
4248
|
+
range = [match.index + 1, match[0].length];
|
|
4249
|
+
}
|
|
4250
|
+
addErrorContext(onError, child.lineNumber, context, null, null, range);
|
|
3905
4251
|
emptyLink = false;
|
|
3906
4252
|
}
|
|
3907
4253
|
}
|
|
3908
4254
|
else if (inLink) {
|
|
3909
4255
|
linkText += child.content;
|
|
3910
4256
|
}
|
|
3911
|
-
}
|
|
4257
|
+
}
|
|
3912
4258
|
});
|
|
3913
4259
|
}
|
|
3914
4260
|
};
|
|
@@ -3925,56 +4271,56 @@ module.exports = {
|
|
|
3925
4271
|
"use strict";
|
|
3926
4272
|
// @ts-check
|
|
3927
4273
|
|
|
3928
|
-
|
|
4274
|
+
const { addErrorContext, addErrorDetailIf, forEachHeading } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3929
4275
|
module.exports = {
|
|
3930
4276
|
"names": ["MD043", "required-headings", "required-headers"],
|
|
3931
4277
|
"description": "Required heading structure",
|
|
3932
4278
|
"tags": ["headings", "headers"],
|
|
3933
4279
|
"function": function MD043(params, onError) {
|
|
3934
|
-
|
|
4280
|
+
const requiredHeadings = params.config.headings || params.config.headers;
|
|
3935
4281
|
if (Array.isArray(requiredHeadings)) {
|
|
3936
|
-
|
|
3937
|
-
[1, 2, 3, 4, 5, 6]
|
|
3938
|
-
|
|
3939
|
-
}
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
forEachHeading(params,
|
|
3946
|
-
if (!
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
4282
|
+
const levels = {};
|
|
4283
|
+
for (const level of [1, 2, 3, 4, 5, 6]) {
|
|
4284
|
+
levels["h" + level] = "######".substr(-level);
|
|
4285
|
+
}
|
|
4286
|
+
let i = 0;
|
|
4287
|
+
let matchAny = false;
|
|
4288
|
+
let hasError = false;
|
|
4289
|
+
let anyHeadings = false;
|
|
4290
|
+
const getExpected = () => requiredHeadings[i++] || "[None]";
|
|
4291
|
+
forEachHeading(params, (heading, content) => {
|
|
4292
|
+
if (!hasError) {
|
|
4293
|
+
anyHeadings = true;
|
|
4294
|
+
const actual = levels[heading.tag] + " " + content;
|
|
4295
|
+
const expected = getExpected();
|
|
3950
4296
|
if (expected === "*") {
|
|
3951
|
-
|
|
4297
|
+
const nextExpected = getExpected();
|
|
3952
4298
|
if (nextExpected.toLowerCase() !== actual.toLowerCase()) {
|
|
3953
|
-
|
|
3954
|
-
|
|
4299
|
+
matchAny = true;
|
|
4300
|
+
i--;
|
|
3955
4301
|
}
|
|
3956
4302
|
}
|
|
3957
4303
|
else if (expected === "+") {
|
|
3958
|
-
|
|
4304
|
+
matchAny = true;
|
|
3959
4305
|
}
|
|
3960
4306
|
else if (expected.toLowerCase() === actual.toLowerCase()) {
|
|
3961
|
-
|
|
4307
|
+
matchAny = false;
|
|
3962
4308
|
}
|
|
3963
|
-
else if (
|
|
3964
|
-
|
|
4309
|
+
else if (matchAny) {
|
|
4310
|
+
i--;
|
|
3965
4311
|
}
|
|
3966
4312
|
else {
|
|
3967
4313
|
addErrorDetailIf(onError, heading.lineNumber, expected, actual);
|
|
3968
|
-
|
|
4314
|
+
hasError = true;
|
|
3969
4315
|
}
|
|
3970
4316
|
}
|
|
3971
4317
|
});
|
|
3972
|
-
|
|
3973
|
-
if (!
|
|
4318
|
+
const extraHeadings = requiredHeadings.length - i;
|
|
4319
|
+
if (!hasError &&
|
|
3974
4320
|
((extraHeadings > 1) ||
|
|
3975
|
-
((extraHeadings === 1) && (requiredHeadings[
|
|
3976
|
-
(
|
|
3977
|
-
addErrorContext(onError, params.lines.length, requiredHeadings[
|
|
4321
|
+
((extraHeadings === 1) && (requiredHeadings[i] !== "*"))) &&
|
|
4322
|
+
(anyHeadings || !requiredHeadings.every((heading) => heading === "*"))) {
|
|
4323
|
+
addErrorContext(onError, params.lines.length, requiredHeadings[i]);
|
|
3978
4324
|
}
|
|
3979
4325
|
}
|
|
3980
4326
|
}
|
|
@@ -3992,53 +4338,58 @@ module.exports = {
|
|
|
3992
4338
|
"use strict";
|
|
3993
4339
|
// @ts-check
|
|
3994
4340
|
|
|
3995
|
-
|
|
3996
|
-
|
|
4341
|
+
const { addErrorDetailIf, bareUrlRe, escapeForRegExp, forEachLine, forEachLink, withinAnyRange, linkReferenceDefinitionRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4342
|
+
const { codeBlockAndSpanRanges, htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3997
4343
|
module.exports = {
|
|
3998
4344
|
"names": ["MD044", "proper-names"],
|
|
3999
4345
|
"description": "Proper names should have the correct capitalization",
|
|
4000
4346
|
"tags": ["spelling"],
|
|
4001
4347
|
"function": function MD044(params, onError) {
|
|
4002
|
-
|
|
4348
|
+
let names = params.config.names;
|
|
4003
4349
|
names = Array.isArray(names) ? names : [];
|
|
4004
|
-
names.sort(
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4350
|
+
names.sort((a, b) => (b.length - a.length) || a.localeCompare(b));
|
|
4351
|
+
const codeBlocks = params.config.code_blocks;
|
|
4352
|
+
const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
4353
|
+
const htmlElements = params.config.html_elements;
|
|
4354
|
+
const includeHtmlElements = (htmlElements === undefined) ? true : !!htmlElements;
|
|
4355
|
+
const exclusions = [];
|
|
4356
|
+
forEachLine(lineMetadata(), (line, lineIndex) => {
|
|
4357
|
+
if (linkReferenceDefinitionRe.test(line)) {
|
|
4010
4358
|
exclusions.push([lineIndex, 0, line.length]);
|
|
4011
4359
|
}
|
|
4012
4360
|
else {
|
|
4013
|
-
|
|
4361
|
+
let match = null;
|
|
4014
4362
|
while ((match = bareUrlRe.exec(line)) !== null) {
|
|
4015
4363
|
exclusions.push([lineIndex, match.index, match[0].length]);
|
|
4016
4364
|
}
|
|
4017
|
-
|
|
4018
|
-
var text = match[1], destination = match[2];
|
|
4365
|
+
forEachLink(line, (index, _, text, destination) => {
|
|
4019
4366
|
if (destination) {
|
|
4020
|
-
exclusions.push([lineIndex,
|
|
4367
|
+
exclusions.push([lineIndex, index + text.length, destination.length]);
|
|
4021
4368
|
}
|
|
4022
|
-
}
|
|
4369
|
+
});
|
|
4023
4370
|
}
|
|
4024
4371
|
});
|
|
4025
4372
|
if (!includeCodeBlocks) {
|
|
4026
|
-
exclusions.push
|
|
4027
|
-
}
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4373
|
+
exclusions.push(...codeBlockAndSpanRanges());
|
|
4374
|
+
}
|
|
4375
|
+
if (!includeHtmlElements) {
|
|
4376
|
+
exclusions.push(...htmlElementRanges());
|
|
4377
|
+
}
|
|
4378
|
+
for (const name of names) {
|
|
4379
|
+
const escapedName = escapeForRegExp(name);
|
|
4380
|
+
const startNamePattern = /^\W/.test(name) ? "" : "\\b_*";
|
|
4381
|
+
const endNamePattern = /\W$/.test(name) ? "" : "_*\\b";
|
|
4382
|
+
const namePattern = `(${startNamePattern})(${escapedName})${endNamePattern}`;
|
|
4383
|
+
const nameRe = new RegExp(namePattern, "gi");
|
|
4384
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence) => {
|
|
4035
4385
|
if (includeCodeBlocks || (!inCode && !onFence)) {
|
|
4036
|
-
|
|
4386
|
+
let match = null;
|
|
4037
4387
|
while ((match = nameRe.exec(line)) !== null) {
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
if (!
|
|
4388
|
+
const [, leftMatch, nameMatch] = match;
|
|
4389
|
+
const index = match.index + leftMatch.length;
|
|
4390
|
+
const length = nameMatch.length;
|
|
4391
|
+
if (!withinAnyRange(exclusions, lineIndex, index, length) &&
|
|
4392
|
+
!names.includes(nameMatch)) {
|
|
4042
4393
|
addErrorDetailIf(onError, lineIndex + 1, name, nameMatch, null, null, [index + 1, length], {
|
|
4043
4394
|
"editColumn": index + 1,
|
|
4044
4395
|
"deleteCount": length,
|
|
@@ -4049,10 +4400,6 @@ module.exports = {
|
|
|
4049
4400
|
}
|
|
4050
4401
|
}
|
|
4051
4402
|
});
|
|
4052
|
-
};
|
|
4053
|
-
for (var _i = 0, names_1 = names; _i < names_1.length; _i++) {
|
|
4054
|
-
var name = names_1[_i];
|
|
4055
|
-
_loop_1(name);
|
|
4056
4403
|
}
|
|
4057
4404
|
}
|
|
4058
4405
|
};
|
|
@@ -4069,7 +4416,7 @@ module.exports = {
|
|
|
4069
4416
|
"use strict";
|
|
4070
4417
|
// @ts-check
|
|
4071
4418
|
|
|
4072
|
-
|
|
4419
|
+
const { addError, forEachInlineChild } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4073
4420
|
module.exports = {
|
|
4074
4421
|
"names": ["MD045", "no-alt-text"],
|
|
4075
4422
|
"description": "Images should have alternate text (alt text)",
|
|
@@ -4095,8 +4442,8 @@ module.exports = {
|
|
|
4095
4442
|
"use strict";
|
|
4096
4443
|
// @ts-check
|
|
4097
4444
|
|
|
4098
|
-
|
|
4099
|
-
|
|
4445
|
+
const { addErrorDetailIf } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4446
|
+
const tokenTypeToStyle = {
|
|
4100
4447
|
"fence": "fenced",
|
|
4101
4448
|
"code_block": "indented"
|
|
4102
4449
|
};
|
|
@@ -4105,16 +4452,15 @@ module.exports = {
|
|
|
4105
4452
|
"description": "Code block style",
|
|
4106
4453
|
"tags": ["code"],
|
|
4107
4454
|
"function": function MD046(params, onError) {
|
|
4108
|
-
|
|
4109
|
-
params.tokens
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
var lineNumber = token.lineNumber, type = token.type;
|
|
4455
|
+
let expectedStyle = String(params.config.style || "consistent");
|
|
4456
|
+
const codeBlocksAndFences = params.tokens.filter((token) => (token.type === "code_block") || (token.type === "fence"));
|
|
4457
|
+
for (const token of codeBlocksAndFences) {
|
|
4458
|
+
const { lineNumber, type } = token;
|
|
4113
4459
|
if (expectedStyle === "consistent") {
|
|
4114
4460
|
expectedStyle = tokenTypeToStyle[type];
|
|
4115
4461
|
}
|
|
4116
4462
|
addErrorDetailIf(onError, lineNumber, expectedStyle, tokenTypeToStyle[type]);
|
|
4117
|
-
}
|
|
4463
|
+
}
|
|
4118
4464
|
}
|
|
4119
4465
|
};
|
|
4120
4466
|
|
|
@@ -4130,14 +4476,14 @@ module.exports = {
|
|
|
4130
4476
|
"use strict";
|
|
4131
4477
|
// @ts-check
|
|
4132
4478
|
|
|
4133
|
-
|
|
4479
|
+
const { addError, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4134
4480
|
module.exports = {
|
|
4135
4481
|
"names": ["MD047", "single-trailing-newline"],
|
|
4136
4482
|
"description": "Files should end with a single newline character",
|
|
4137
4483
|
"tags": ["blank_lines"],
|
|
4138
4484
|
"function": function MD047(params, onError) {
|
|
4139
|
-
|
|
4140
|
-
|
|
4485
|
+
const lastLineNumber = params.lines.length;
|
|
4486
|
+
const lastLine = params.lines[lastLineNumber - 1];
|
|
4141
4487
|
if (!isBlankLine(lastLine)) {
|
|
4142
4488
|
addError(onError, lastLineNumber, null, null, [lastLine.length, 1], {
|
|
4143
4489
|
"insertText": "\n",
|
|
@@ -4159,62 +4505,168 @@ module.exports = {
|
|
|
4159
4505
|
"use strict";
|
|
4160
4506
|
// @ts-check
|
|
4161
4507
|
|
|
4162
|
-
|
|
4508
|
+
const { addErrorDetailIf, fencedCodeBlockStyleFor } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4163
4509
|
module.exports = {
|
|
4164
4510
|
"names": ["MD048", "code-fence-style"],
|
|
4165
4511
|
"description": "Code fence style",
|
|
4166
4512
|
"tags": ["code"],
|
|
4167
4513
|
"function": function MD048(params, onError) {
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
params.tokens
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
var lineNumber = fenceToken.lineNumber, markup = fenceToken.markup;
|
|
4514
|
+
const style = String(params.config.style || "consistent");
|
|
4515
|
+
let expectedStyle = style;
|
|
4516
|
+
const fenceTokens = params.tokens.filter((token) => token.type === "fence");
|
|
4517
|
+
for (const fenceToken of fenceTokens) {
|
|
4518
|
+
const { lineNumber, markup } = fenceToken;
|
|
4174
4519
|
if (expectedStyle === "consistent") {
|
|
4175
4520
|
expectedStyle = fencedCodeBlockStyleFor(markup);
|
|
4176
4521
|
}
|
|
4177
4522
|
addErrorDetailIf(onError, lineNumber, expectedStyle, fencedCodeBlockStyleFor(markup));
|
|
4178
|
-
}
|
|
4523
|
+
}
|
|
4179
4524
|
}
|
|
4180
4525
|
};
|
|
4181
4526
|
|
|
4182
4527
|
|
|
4183
4528
|
/***/ }),
|
|
4184
4529
|
|
|
4185
|
-
/***/ "../lib/md049.js":
|
|
4530
|
+
/***/ "../lib/md049-md050.js":
|
|
4531
|
+
/*!*****************************!*\
|
|
4532
|
+
!*** ../lib/md049-md050.js ***!
|
|
4533
|
+
\*****************************/
|
|
4534
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
4535
|
+
|
|
4536
|
+
"use strict";
|
|
4537
|
+
// @ts-check
|
|
4538
|
+
|
|
4539
|
+
const { addError, emphasisOrStrongStyleFor, forEachInlineChild, getNextChildToken, getRangeAndFixInfoIfFound } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4540
|
+
const impl = (params, onError, tagPrefix, asterisk, underline, style) => {
|
|
4541
|
+
let lastLineNumber = -1;
|
|
4542
|
+
const instances = new Map();
|
|
4543
|
+
forEachInlineChild(params, `${tagPrefix}_open`, (token, parent) => {
|
|
4544
|
+
const { lineNumber, markup } = token;
|
|
4545
|
+
const markupStyle = emphasisOrStrongStyleFor(markup);
|
|
4546
|
+
if (style === "consistent") {
|
|
4547
|
+
style = markupStyle;
|
|
4548
|
+
}
|
|
4549
|
+
if (style !== markupStyle) {
|
|
4550
|
+
let rangeAndFixInfo = {};
|
|
4551
|
+
const contentToken = getNextChildToken(parent, token, "text", `${tagPrefix}_close`);
|
|
4552
|
+
if (contentToken) {
|
|
4553
|
+
const { content } = contentToken;
|
|
4554
|
+
const actual = `${markup}${content}${markup}`;
|
|
4555
|
+
const expectedMarkup = (style === "asterisk") ? asterisk : underline;
|
|
4556
|
+
const expected = `${expectedMarkup}${content}${expectedMarkup}`;
|
|
4557
|
+
if (lastLineNumber !== lineNumber) {
|
|
4558
|
+
lastLineNumber = lineNumber;
|
|
4559
|
+
instances.clear();
|
|
4560
|
+
}
|
|
4561
|
+
const instance = (instances.get(expected) || 0) + 1;
|
|
4562
|
+
instances.set(expected, instance);
|
|
4563
|
+
rangeAndFixInfo = getRangeAndFixInfoIfFound(params.lines, lineNumber - 1, actual, expected, instance);
|
|
4564
|
+
}
|
|
4565
|
+
addError(onError, lineNumber, `Expected: ${style}; Actual: ${markupStyle}`, null, rangeAndFixInfo.range, rangeAndFixInfo.fixInfo);
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
};
|
|
4569
|
+
module.exports = [
|
|
4570
|
+
{
|
|
4571
|
+
"names": ["MD049", "emphasis-style"],
|
|
4572
|
+
"description": "Emphasis style should be consistent",
|
|
4573
|
+
"tags": ["emphasis"],
|
|
4574
|
+
"function": function MD049(params, onError) {
|
|
4575
|
+
const style = String(params.config.style || "consistent");
|
|
4576
|
+
return impl(params, onError, "em", "*", "_", style);
|
|
4577
|
+
}
|
|
4578
|
+
},
|
|
4579
|
+
{
|
|
4580
|
+
"names": ["MD050", "strong-style"],
|
|
4581
|
+
"description": "Strong style should be consistent",
|
|
4582
|
+
"tags": ["emphasis"],
|
|
4583
|
+
"function": function MD050(params, onError) {
|
|
4584
|
+
const style = String(params.config.style || "consistent");
|
|
4585
|
+
return impl(params, onError, "strong", "**", "__", style);
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
];
|
|
4589
|
+
|
|
4590
|
+
|
|
4591
|
+
/***/ }),
|
|
4592
|
+
|
|
4593
|
+
/***/ "../lib/md051.js":
|
|
4186
4594
|
/*!***********************!*\
|
|
4187
|
-
!*** ../lib/
|
|
4595
|
+
!*** ../lib/md051.js ***!
|
|
4188
4596
|
\***********************/
|
|
4189
4597
|
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
4190
4598
|
|
|
4191
4599
|
"use strict";
|
|
4192
4600
|
// @ts-check
|
|
4193
4601
|
|
|
4194
|
-
|
|
4602
|
+
const { addError, escapeForRegExp, filterTokens, forEachInlineChild, forEachHeading, htmlElementRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4603
|
+
// Regular expression for identifying HTML anchor names
|
|
4604
|
+
const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
|
|
4605
|
+
const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
|
|
4606
|
+
/**
|
|
4607
|
+
* Converts a Markdown heading into an HTML fragment according to the rules
|
|
4608
|
+
* used by GitHub.
|
|
4609
|
+
*
|
|
4610
|
+
* @param {Object} inline Inline token for heading.
|
|
4611
|
+
* @returns {string} Fragment string for heading.
|
|
4612
|
+
*/
|
|
4613
|
+
function convertHeadingToHTMLFragment(inline) {
|
|
4614
|
+
const inlineText = inline.children
|
|
4615
|
+
.filter((token) => token.type !== "html_inline")
|
|
4616
|
+
.map((token) => token.content)
|
|
4617
|
+
.join("");
|
|
4618
|
+
return "#" + encodeURIComponent(inlineText
|
|
4619
|
+
.toLowerCase()
|
|
4620
|
+
// RegExp source with Ruby's \p{Word} expanded into its General Categories
|
|
4621
|
+
// eslint-disable-next-line max-len
|
|
4622
|
+
// https://github.com/gjtorikian/html-pipeline/blob/main/lib/html/pipeline/toc_filter.rb
|
|
4623
|
+
// https://ruby-doc.org/core-3.0.2/Regexp.html
|
|
4624
|
+
.replace(/[^\p{Letter}\p{Mark}\p{Number}\p{Connector_Punctuation}\- ]/gu, "")
|
|
4625
|
+
.replace(/ /gu, "-"));
|
|
4626
|
+
}
|
|
4195
4627
|
module.exports = {
|
|
4196
|
-
"names": ["
|
|
4197
|
-
"description": "
|
|
4198
|
-
"tags": ["
|
|
4199
|
-
"function": function
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4628
|
+
"names": ["MD051", "link-fragments"],
|
|
4629
|
+
"description": "Link fragments should be valid",
|
|
4630
|
+
"tags": ["links"],
|
|
4631
|
+
"function": function MD051(params, onError) {
|
|
4632
|
+
const fragments = new Map();
|
|
4633
|
+
// Process headings
|
|
4634
|
+
forEachHeading(params, (heading, content, inline) => {
|
|
4635
|
+
const fragment = convertHeadingToHTMLFragment(inline);
|
|
4636
|
+
const count = fragments.get(fragment) || 0;
|
|
4637
|
+
if (count) {
|
|
4638
|
+
fragments.set(`${fragment}-${count}`, 0);
|
|
4639
|
+
}
|
|
4640
|
+
fragments.set(fragment, count + 1);
|
|
4641
|
+
});
|
|
4642
|
+
// Process HTML anchors
|
|
4643
|
+
const processHtmlToken = (token) => {
|
|
4644
|
+
let match = null;
|
|
4645
|
+
while ((match = htmlElementRe.exec(token.content)) !== null) {
|
|
4646
|
+
const [tag, , element] = match;
|
|
4647
|
+
const anchorMatch = idRe.exec(tag) ||
|
|
4648
|
+
(element.toLowerCase() === "a" && nameRe.exec(tag));
|
|
4649
|
+
if (anchorMatch) {
|
|
4650
|
+
fragments.set(`#${anchorMatch[1]}`, 0);
|
|
4651
|
+
}
|
|
4206
4652
|
}
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4653
|
+
};
|
|
4654
|
+
filterTokens(params, "html_block", processHtmlToken);
|
|
4655
|
+
forEachInlineChild(params, "html_inline", processHtmlToken);
|
|
4656
|
+
// Process link fragments
|
|
4657
|
+
forEachInlineChild(params, "link_open", (token) => {
|
|
4658
|
+
const { attrs, lineNumber, line } = token;
|
|
4659
|
+
const href = attrs.find((attr) => attr[0] === "href");
|
|
4660
|
+
const id = href && href[1];
|
|
4661
|
+
if (id && (id.length > 1) && (id[0] === "#") && !fragments.has(id)) {
|
|
4662
|
+
let context = id;
|
|
4663
|
+
let range = null;
|
|
4664
|
+
const match = line.match(new RegExp(`\\[.*?\\]\\(${escapeForRegExp(context)}\\)`));
|
|
4665
|
+
if (match) {
|
|
4666
|
+
context = match[0];
|
|
4667
|
+
range = [match.index + 1, match[0].length];
|
|
4216
4668
|
}
|
|
4217
|
-
addError(onError, lineNumber,
|
|
4669
|
+
addError(onError, lineNumber, undefined, context, range);
|
|
4218
4670
|
}
|
|
4219
4671
|
});
|
|
4220
4672
|
}
|
|
@@ -4223,41 +4675,83 @@ module.exports = {
|
|
|
4223
4675
|
|
|
4224
4676
|
/***/ }),
|
|
4225
4677
|
|
|
4226
|
-
/***/ "../lib/
|
|
4678
|
+
/***/ "../lib/md052.js":
|
|
4227
4679
|
/*!***********************!*\
|
|
4228
|
-
!*** ../lib/
|
|
4680
|
+
!*** ../lib/md052.js ***!
|
|
4229
4681
|
\***********************/
|
|
4230
4682
|
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
4231
4683
|
|
|
4232
4684
|
"use strict";
|
|
4233
4685
|
// @ts-check
|
|
4234
4686
|
|
|
4235
|
-
|
|
4687
|
+
const { addError } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4688
|
+
const { referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
4236
4689
|
module.exports = {
|
|
4237
|
-
"names": ["
|
|
4238
|
-
"description": "
|
|
4239
|
-
"tags": ["
|
|
4240
|
-
"function": function
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
var content = contentToken.content;
|
|
4253
|
-
var actual = "".concat(markup).concat(content).concat(markup);
|
|
4254
|
-
var expectedMarkup = (expectedStyle === "asterisk") ? "**" : "__";
|
|
4255
|
-
var expected = "".concat(expectedMarkup).concat(content).concat(expectedMarkup);
|
|
4256
|
-
rangeAndFixInfo = getRangeAndFixInfoIfFound(params.lines, lineNumber - 1, actual, expected);
|
|
4690
|
+
"names": ["MD052", "reference-links-images"],
|
|
4691
|
+
"description": "Reference links and images should use a label that is defined",
|
|
4692
|
+
"tags": ["images", "links"],
|
|
4693
|
+
"function": function MD052(params, onError) {
|
|
4694
|
+
const { lines } = params;
|
|
4695
|
+
const { references, definitions } = referenceLinkImageData();
|
|
4696
|
+
// Look for links/images that use an undefined link reference
|
|
4697
|
+
for (const reference of references.entries()) {
|
|
4698
|
+
const [label, datas] = reference;
|
|
4699
|
+
if (!definitions.has(label)) {
|
|
4700
|
+
for (const data of datas) {
|
|
4701
|
+
const [lineIndex, index, length] = data;
|
|
4702
|
+
// Context will be incomplete if reporting for a multi-line link
|
|
4703
|
+
const context = lines[lineIndex].slice(index, index + length);
|
|
4704
|
+
addError(onError, lineIndex + 1, `Missing link or image reference definition: "${label}"`, context, [index + 1, context.length]);
|
|
4257
4705
|
}
|
|
4258
|
-
addError(onError, lineNumber, "Expected: ".concat(expectedStyle, "; Actual: ").concat(markupStyle), null, rangeAndFixInfo.range, rangeAndFixInfo.fixInfo);
|
|
4259
4706
|
}
|
|
4260
|
-
}
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4709
|
+
};
|
|
4710
|
+
|
|
4711
|
+
|
|
4712
|
+
/***/ }),
|
|
4713
|
+
|
|
4714
|
+
/***/ "../lib/md053.js":
|
|
4715
|
+
/*!***********************!*\
|
|
4716
|
+
!*** ../lib/md053.js ***!
|
|
4717
|
+
\***********************/
|
|
4718
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
4719
|
+
|
|
4720
|
+
"use strict";
|
|
4721
|
+
// @ts-check
|
|
4722
|
+
|
|
4723
|
+
const { addError, ellipsify, linkReferenceDefinitionRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4724
|
+
const { referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
4725
|
+
module.exports = {
|
|
4726
|
+
"names": ["MD053", "link-image-reference-definitions"],
|
|
4727
|
+
"description": "Link and image reference definitions should be needed",
|
|
4728
|
+
"tags": ["images", "links"],
|
|
4729
|
+
"function": function MD053(params, onError) {
|
|
4730
|
+
const ignored = new Set(params.config.ignored_definitions || ["//"]);
|
|
4731
|
+
const lines = params.lines;
|
|
4732
|
+
const { references, shortcuts, definitions, duplicateDefinitions } = referenceLinkImageData();
|
|
4733
|
+
const singleLineDefinition = (line) => (line.replace(linkReferenceDefinitionRe, "").trim().length > 0);
|
|
4734
|
+
const deleteFixInfo = {
|
|
4735
|
+
"deleteCount": -1
|
|
4736
|
+
};
|
|
4737
|
+
// Look for unused link references (unreferenced by any link/image)
|
|
4738
|
+
for (const definition of definitions.entries()) {
|
|
4739
|
+
const [label, lineIndex] = definition;
|
|
4740
|
+
if (!ignored.has(label) &&
|
|
4741
|
+
!references.has(label) &&
|
|
4742
|
+
!shortcuts.has(label)) {
|
|
4743
|
+
const line = lines[lineIndex];
|
|
4744
|
+
addError(onError, lineIndex + 1, `Unused link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
|
|
4745
|
+
}
|
|
4746
|
+
}
|
|
4747
|
+
// Look for duplicate link references (defined more than once)
|
|
4748
|
+
for (const duplicateDefinition of duplicateDefinitions) {
|
|
4749
|
+
const [label, lineIndex] = duplicateDefinition;
|
|
4750
|
+
if (!ignored.has(label)) {
|
|
4751
|
+
const line = lines[lineIndex];
|
|
4752
|
+
addError(onError, lineIndex + 1, `Duplicate link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4261
4755
|
}
|
|
4262
4756
|
};
|
|
4263
4757
|
|
|
@@ -4273,8 +4767,8 @@ module.exports = {
|
|
|
4273
4767
|
"use strict";
|
|
4274
4768
|
// @ts-check
|
|
4275
4769
|
|
|
4276
|
-
|
|
4277
|
-
|
|
4770
|
+
const { homepage, version } = __webpack_require__(/*! ./constants */ "../lib/constants.js");
|
|
4771
|
+
const rules = [
|
|
4278
4772
|
__webpack_require__(/*! ./md001 */ "../lib/md001.js"),
|
|
4279
4773
|
__webpack_require__(/*! ./md002 */ "../lib/md002.js"),
|
|
4280
4774
|
__webpack_require__(/*! ./md003 */ "../lib/md003.js"),
|
|
@@ -4319,59 +4813,20 @@ var rules = [
|
|
|
4319
4813
|
__webpack_require__(/*! ./md046 */ "../lib/md046.js"),
|
|
4320
4814
|
__webpack_require__(/*! ./md047 */ "../lib/md047.js"),
|
|
4321
4815
|
__webpack_require__(/*! ./md048 */ "../lib/md048.js"),
|
|
4322
|
-
__webpack_require__(/*! ./md049 */ "../lib/md049.js"),
|
|
4323
|
-
__webpack_require__(/*! ./
|
|
4816
|
+
...__webpack_require__(/*! ./md049-md050 */ "../lib/md049-md050.js"),
|
|
4817
|
+
__webpack_require__(/*! ./md051 */ "../lib/md051.js"),
|
|
4818
|
+
__webpack_require__(/*! ./md052 */ "../lib/md052.js"),
|
|
4819
|
+
__webpack_require__(/*! ./md053 */ "../lib/md053.js")
|
|
4324
4820
|
];
|
|
4325
|
-
|
|
4326
|
-
|
|
4821
|
+
for (const rule of rules) {
|
|
4822
|
+
const name = rule.names[0].toLowerCase();
|
|
4327
4823
|
// eslint-disable-next-line dot-notation
|
|
4328
4824
|
rule["information"] =
|
|
4329
|
-
new URL(
|
|
4330
|
-
}
|
|
4825
|
+
new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
|
|
4826
|
+
}
|
|
4331
4827
|
module.exports = rules;
|
|
4332
4828
|
|
|
4333
4829
|
|
|
4334
|
-
/***/ }),
|
|
4335
|
-
|
|
4336
|
-
/***/ "markdown-it":
|
|
4337
|
-
/*!*****************************!*\
|
|
4338
|
-
!*** external "markdownit" ***!
|
|
4339
|
-
\*****************************/
|
|
4340
|
-
/***/ ((module) => {
|
|
4341
|
-
|
|
4342
|
-
"use strict";
|
|
4343
|
-
module.exports = markdownit;
|
|
4344
|
-
|
|
4345
|
-
/***/ }),
|
|
4346
|
-
|
|
4347
|
-
/***/ "?ec0a":
|
|
4348
|
-
/*!********************!*\
|
|
4349
|
-
!*** fs (ignored) ***!
|
|
4350
|
-
\********************/
|
|
4351
|
-
/***/ (() => {
|
|
4352
|
-
|
|
4353
|
-
/* (ignored) */
|
|
4354
|
-
|
|
4355
|
-
/***/ }),
|
|
4356
|
-
|
|
4357
|
-
/***/ "?b85c":
|
|
4358
|
-
/*!**********************!*\
|
|
4359
|
-
!*** path (ignored) ***!
|
|
4360
|
-
\**********************/
|
|
4361
|
-
/***/ (() => {
|
|
4362
|
-
|
|
4363
|
-
/* (ignored) */
|
|
4364
|
-
|
|
4365
|
-
/***/ }),
|
|
4366
|
-
|
|
4367
|
-
/***/ "?96a2":
|
|
4368
|
-
/*!**********************!*\
|
|
4369
|
-
!*** util (ignored) ***!
|
|
4370
|
-
\**********************/
|
|
4371
|
-
/***/ (() => {
|
|
4372
|
-
|
|
4373
|
-
/* (ignored) */
|
|
4374
|
-
|
|
4375
4830
|
/***/ })
|
|
4376
4831
|
|
|
4377
4832
|
/******/ });
|
|
@@ -4394,7 +4849,7 @@ module.exports = markdownit;
|
|
|
4394
4849
|
/******/ };
|
|
4395
4850
|
/******/
|
|
4396
4851
|
/******/ // Execute the module function
|
|
4397
|
-
/******/ __webpack_modules__[moduleId]
|
|
4852
|
+
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
4398
4853
|
/******/
|
|
4399
4854
|
/******/ // Return the exports of the module
|
|
4400
4855
|
/******/ return module.exports;
|