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