markdownlint 0.35.0 → 0.36.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/CHANGELOG.md +10 -0
- package/README.md +72 -35
- package/demo/markdownlint-browser.js +1258 -1214
- package/doc/CustomRules.md +55 -249
- package/doc/Rules.md +36 -29
- package/doc/md003.md +2 -2
- package/doc/md004.md +4 -3
- package/doc/md035.md +3 -8
- package/doc/md046.md +2 -2
- package/doc/md048.md +3 -2
- package/doc/md049.md +4 -3
- package/doc/md050.md +4 -4
- package/doc/md051.md +11 -3
- package/doc/md055.md +3 -2
- package/helpers/README.md +2 -19
- package/helpers/helpers.js +87 -347
- package/helpers/micromark-helpers.cjs +296 -0
- package/helpers/micromark-parse.cjs +313 -0
- package/helpers/package.json +5 -2
- package/helpers/shared.js +6 -0
- package/helpers/test.cjs +28 -0
- package/lib/cache.js +3 -3
- package/lib/configuration-strict.d.ts +120 -106
- package/lib/constants.js +1 -1
- package/lib/markdownit.cjs +172 -0
- package/lib/markdownlint.d.ts +41 -3
- package/lib/markdownlint.js +153 -115
- package/lib/md001.js +1 -1
- package/lib/md003.js +1 -1
- package/lib/md004.js +3 -3
- package/lib/md007.js +3 -3
- package/lib/md009.js +1 -1
- package/lib/md010.js +18 -14
- package/lib/md011.js +24 -23
- package/lib/md012.js +1 -1
- package/lib/md013.js +1 -1
- package/lib/md014.js +5 -9
- package/lib/md018.js +1 -1
- package/lib/md019-md021.js +1 -1
- package/lib/md020.js +2 -2
- package/lib/md022.js +9 -15
- package/lib/md024.js +1 -1
- package/lib/md025.js +1 -1
- package/lib/md027.js +2 -2
- package/lib/md029.js +3 -3
- package/lib/md031.js +8 -6
- package/lib/md032.js +27 -15
- package/lib/md033.js +1 -1
- package/lib/md034.js +21 -29
- package/lib/md036.js +18 -24
- package/lib/md037.js +1 -1
- package/lib/md038.js +9 -14
- package/lib/md039.js +13 -15
- package/lib/md040.js +11 -13
- package/lib/md041.js +4 -4
- package/lib/md042.js +2 -6
- package/lib/md043.js +1 -1
- package/lib/md044.js +31 -28
- package/lib/md045.js +2 -2
- package/lib/md048.js +28 -17
- package/lib/md049-md050.js +20 -5
- package/lib/md051.js +16 -18
- package/lib/md053.js +5 -4
- package/lib/md054.js +10 -12
- package/lib/md055.js +39 -46
- package/lib/md056.js +31 -36
- package/lib/md058.js +29 -14
- package/package.json +14 -13
- package/schema/.markdownlint.jsonc +55 -52
- package/schema/.markdownlint.yaml +54 -52
- package/schema/markdownlint-config-schema-strict.json +132 -110
- package/schema/markdownlint-config-schema.json +132 -110
- package/helpers/micromark.cjs +0 -544
package/helpers/README.md
CHANGED
|
@@ -17,30 +17,13 @@ change from release to release. There are brief descriptive comments above each
|
|
|
17
17
|
function, but no [JSDoc][jsdoc] annotations. That said, some of what's here will
|
|
18
18
|
be useful to custom rule authors and may avoid duplicating code.
|
|
19
19
|
|
|
20
|
-
## Examples
|
|
21
|
-
|
|
22
|
-
### Applying Recommended Fixes
|
|
23
|
-
|
|
24
|
-
```javascript
|
|
25
|
-
const { "sync": markdownlintSync } = require("markdownlint");
|
|
26
|
-
const markdownlintRuleHelpers = require("markdownlint-rule-helpers");
|
|
27
|
-
|
|
28
|
-
function fixMarkdownlintViolations(content) {
|
|
29
|
-
const fixResults = markdownlintSync({ strings: { content } });
|
|
30
|
-
return markdownlintRuleHelpers.applyFixes(content, fixResults.content);
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
See also: [`markdownlint` built-in rule implementations][lib].
|
|
35
|
-
|
|
36
20
|
## Tests
|
|
37
21
|
|
|
38
22
|
*None* - The entire body of code is tested to 100% coverage by the core
|
|
39
23
|
`markdownlint` project, so there are no additional tests here.
|
|
40
24
|
|
|
41
|
-
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.
|
|
25
|
+
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.36.0/doc/CustomRules.md
|
|
42
26
|
[jsdoc]: https://en.m.wikipedia.org/wiki/JSDoc
|
|
43
|
-
[lib]: https://github.com/DavidAnson/markdownlint/tree/v0.35.0/lib
|
|
44
27
|
[markdown]: https://en.wikipedia.org/wiki/Markdown
|
|
45
28
|
[markdownlint]: https://github.com/DavidAnson/markdownlint
|
|
46
|
-
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.
|
|
29
|
+
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.36.0/doc/Rules.md
|
package/helpers/helpers.js
CHANGED
|
@@ -2,30 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const micromark = require("./micromark.cjs");
|
|
5
|
+
const micromark = require("./micromark-helpers.cjs");
|
|
6
6
|
|
|
7
7
|
const { newLineRe, nextLinesRe } = require("./shared.js");
|
|
8
8
|
|
|
9
9
|
module.exports.newLineRe = newLineRe;
|
|
10
10
|
module.exports.nextLinesRe = nextLinesRe;
|
|
11
11
|
|
|
12
|
+
/** @typedef {import("../lib/markdownlint.js").RuleOnError} RuleOnError */
|
|
13
|
+
/** @typedef {import("../lib/markdownlint.js").RuleOnErrorFixInfo} RuleOnErrorFixInfo */
|
|
14
|
+
|
|
12
15
|
// Regular expression for matching common front matter (YAML and TOML)
|
|
13
16
|
module.exports.frontMatterRe =
|
|
14
|
-
/((
|
|
17
|
+
/((^---[^\S\r\n\u2028\u2029]*$[\s\S]+?^---\s*)|(^\+\+\+[^\S\r\n\u2028\u2029]*$[\s\S]+?^(\+\+\+|\.\.\.)\s*)|(^\{[^\S\r\n\u2028\u2029]*$[\s\S]+?^\}\s*))(\r\n|\r|\n|$)/m;
|
|
15
18
|
|
|
16
19
|
// Regular expression for matching the start of inline disable/enable comments
|
|
17
20
|
const inlineCommentStartRe =
|
|
18
21
|
/(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/gi;
|
|
19
22
|
module.exports.inlineCommentStartRe = inlineCommentStartRe;
|
|
20
23
|
|
|
21
|
-
// Regular expression for blockquote prefixes
|
|
22
|
-
const blockquotePrefixRe = /^[>\s]*/;
|
|
23
|
-
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
|
24
|
-
|
|
25
|
-
// Regular expression for link reference definitions
|
|
26
|
-
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
|
|
27
|
-
module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
|
|
28
|
-
|
|
29
24
|
// Regular expression for identifying an HTML entity at the end of a line
|
|
30
25
|
module.exports.endOfLineHtmlEntityRe =
|
|
31
26
|
/&(?:#\d+|#[xX][\da-fA-F]+|[a-zA-Z]{2,31}|blk\d{2}|emsp1[34]|frac\d{2}|sup\d|there4);$/;
|
|
@@ -223,99 +218,6 @@ module.exports.escapeForRegExp = function escapeForRegExp(str) {
|
|
|
223
218
|
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
224
219
|
};
|
|
225
220
|
|
|
226
|
-
/**
|
|
227
|
-
* Return the string representation of a fence markup character.
|
|
228
|
-
*
|
|
229
|
-
* @param {string} markup Fence string.
|
|
230
|
-
* @returns {string} String representation.
|
|
231
|
-
*/
|
|
232
|
-
module.exports.fencedCodeBlockStyleFor =
|
|
233
|
-
function fencedCodeBlockStyleFor(markup) {
|
|
234
|
-
switch (markup[0]) {
|
|
235
|
-
case "~":
|
|
236
|
-
return "tilde";
|
|
237
|
-
default:
|
|
238
|
-
return "backtick";
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Return the string representation of a emphasis or strong markup character.
|
|
244
|
-
*
|
|
245
|
-
* @param {string} markup Emphasis or strong string.
|
|
246
|
-
* @returns {"asterisk" | "underscore"} String representation.
|
|
247
|
-
*/
|
|
248
|
-
module.exports.emphasisOrStrongStyleFor =
|
|
249
|
-
function emphasisOrStrongStyleFor(markup) {
|
|
250
|
-
switch (markup[0]) {
|
|
251
|
-
case "*":
|
|
252
|
-
return "asterisk";
|
|
253
|
-
default:
|
|
254
|
-
return "underscore";
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* @callback InlineCodeSpanCallback
|
|
260
|
-
* @param {string} code Code content.
|
|
261
|
-
* @param {number} lineIndex Line index (0-based).
|
|
262
|
-
* @param {number} columnIndex Column index (0-based).
|
|
263
|
-
* @param {number} ticks Count of backticks.
|
|
264
|
-
* @returns {void}
|
|
265
|
-
*/
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Calls the provided function for each inline code span's content.
|
|
269
|
-
*
|
|
270
|
-
* @param {string} input Markdown content.
|
|
271
|
-
* @param {InlineCodeSpanCallback} handler Callback function taking (code,
|
|
272
|
-
* lineIndex, columnIndex, ticks).
|
|
273
|
-
* @returns {void}
|
|
274
|
-
*/
|
|
275
|
-
function forEachInlineCodeSpan(input, handler) {
|
|
276
|
-
const backtickRe = /`+/g;
|
|
277
|
-
let match = null;
|
|
278
|
-
const backticksLengthAndIndex = [];
|
|
279
|
-
while ((match = backtickRe.exec(input)) !== null) {
|
|
280
|
-
backticksLengthAndIndex.push([ match[0].length, match.index ]);
|
|
281
|
-
}
|
|
282
|
-
const newLinesIndex = [];
|
|
283
|
-
while ((match = newLineRe.exec(input)) !== null) {
|
|
284
|
-
newLinesIndex.push(match.index);
|
|
285
|
-
}
|
|
286
|
-
let lineIndex = 0;
|
|
287
|
-
let lineStartIndex = 0;
|
|
288
|
-
let k = 0;
|
|
289
|
-
for (let i = 0; i < backticksLengthAndIndex.length - 1; i++) {
|
|
290
|
-
const [ startLength, startIndex ] = backticksLengthAndIndex[i];
|
|
291
|
-
if ((startIndex === 0) || (input[startIndex - 1] !== "\\")) {
|
|
292
|
-
for (let j = i + 1; j < backticksLengthAndIndex.length; j++) {
|
|
293
|
-
const [ endLength, endIndex ] = backticksLengthAndIndex[j];
|
|
294
|
-
if (startLength === endLength) {
|
|
295
|
-
for (; k < newLinesIndex.length; k++) {
|
|
296
|
-
const newLineIndex = newLinesIndex[k];
|
|
297
|
-
if (startIndex < newLineIndex) {
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
lineIndex++;
|
|
301
|
-
lineStartIndex = newLineIndex + 1;
|
|
302
|
-
}
|
|
303
|
-
const columnIndex = startIndex - lineStartIndex + startLength;
|
|
304
|
-
handler(
|
|
305
|
-
input.slice(startIndex + startLength, endIndex),
|
|
306
|
-
lineIndex,
|
|
307
|
-
columnIndex,
|
|
308
|
-
startLength
|
|
309
|
-
);
|
|
310
|
-
i = j;
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
module.exports.forEachInlineCodeSpan = forEachInlineCodeSpan;
|
|
318
|
-
|
|
319
221
|
/**
|
|
320
222
|
* Adds ellipsis to the left/right/middle of the specified text.
|
|
321
223
|
*
|
|
@@ -341,12 +243,12 @@ module.exports.ellipsify = ellipsify;
|
|
|
341
243
|
/**
|
|
342
244
|
* Adds a generic error object via the onError callback.
|
|
343
245
|
*
|
|
344
|
-
* @param {
|
|
246
|
+
* @param {RuleOnError} onError RuleOnError instance.
|
|
345
247
|
* @param {number} lineNumber Line number.
|
|
346
248
|
* @param {string} [detail] Error details.
|
|
347
249
|
* @param {string} [context] Error context.
|
|
348
250
|
* @param {number[]} [range] Column and length of error.
|
|
349
|
-
* @param {
|
|
251
|
+
* @param {RuleOnErrorFixInfo} [fixInfo] RuleOnErrorFixInfo instance.
|
|
350
252
|
* @returns {void}
|
|
351
253
|
*/
|
|
352
254
|
function addError(onError, lineNumber, detail, context, range, fixInfo) {
|
|
@@ -363,14 +265,14 @@ module.exports.addError = addError;
|
|
|
363
265
|
/**
|
|
364
266
|
* Adds an error object with details conditionally via the onError callback.
|
|
365
267
|
*
|
|
366
|
-
* @param {
|
|
268
|
+
* @param {RuleOnError} onError RuleOnError instance.
|
|
367
269
|
* @param {number} lineNumber Line number.
|
|
368
270
|
* @param {Object} expected Expected value.
|
|
369
271
|
* @param {Object} actual Actual value.
|
|
370
272
|
* @param {string} [detail] Error details.
|
|
371
273
|
* @param {string} [context] Error context.
|
|
372
274
|
* @param {number[]} [range] Column and length of error.
|
|
373
|
-
* @param {
|
|
275
|
+
* @param {RuleOnErrorFixInfo} [fixInfo] RuleOnErrorFixInfo instance.
|
|
374
276
|
* @returns {void}
|
|
375
277
|
*/
|
|
376
278
|
function addErrorDetailIf(
|
|
@@ -391,13 +293,13 @@ module.exports.addErrorDetailIf = addErrorDetailIf;
|
|
|
391
293
|
/**
|
|
392
294
|
* Adds an error object with context via the onError callback.
|
|
393
295
|
*
|
|
394
|
-
* @param {
|
|
296
|
+
* @param {RuleOnError} onError RuleOnError instance.
|
|
395
297
|
* @param {number} lineNumber Line number.
|
|
396
298
|
* @param {string} context Error context.
|
|
397
299
|
* @param {boolean} [start] True iff the start of the text is important.
|
|
398
300
|
* @param {boolean} [end] True iff the end of the text is important.
|
|
399
301
|
* @param {number[]} [range] Column and length of error.
|
|
400
|
-
* @param {
|
|
302
|
+
* @param {RuleOnErrorFixInfo} [fixInfo] RuleOnErrorFixInfo instance.
|
|
401
303
|
* @returns {void}
|
|
402
304
|
*/
|
|
403
305
|
function addErrorContext(
|
|
@@ -408,50 +310,42 @@ function addErrorContext(
|
|
|
408
310
|
module.exports.addErrorContext = addErrorContext;
|
|
409
311
|
|
|
410
312
|
/**
|
|
411
|
-
*
|
|
313
|
+
* Defines a range within a file (start line/column to end line/column, subset of MicromarkToken).
|
|
412
314
|
*
|
|
413
|
-
* @
|
|
414
|
-
* @
|
|
415
|
-
* @
|
|
416
|
-
* @
|
|
417
|
-
* @
|
|
315
|
+
* @typedef {Object} FileRange
|
|
316
|
+
* @property {number} startLine Start line (1-based).
|
|
317
|
+
* @property {number} startColumn Start column (1-based).
|
|
318
|
+
* @property {number} endLine End line (1-based).
|
|
319
|
+
* @property {number} endColumn End column (1-based).
|
|
418
320
|
*/
|
|
419
|
-
function addErrorContextForLine(onError, lines, lineIndex, lineNumber) {
|
|
420
|
-
const line = lines[lineIndex];
|
|
421
|
-
// @ts-ignore
|
|
422
|
-
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
423
|
-
addErrorContext(
|
|
424
|
-
onError,
|
|
425
|
-
lineIndex + 1,
|
|
426
|
-
line.trim(),
|
|
427
|
-
undefined,
|
|
428
|
-
undefined,
|
|
429
|
-
undefined,
|
|
430
|
-
{
|
|
431
|
-
lineNumber,
|
|
432
|
-
"insertText": `${quotePrefix}\n`
|
|
433
|
-
}
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
module.exports.addErrorContextForLine = addErrorContextForLine;
|
|
437
321
|
|
|
438
322
|
/**
|
|
439
|
-
*
|
|
323
|
+
* Returns whether line/column A is less than or equal to line/column B.
|
|
440
324
|
*
|
|
441
|
-
* @param {number
|
|
442
|
-
* @param {number}
|
|
443
|
-
* @param {number}
|
|
444
|
-
* @param {number}
|
|
445
|
-
* @returns {boolean} True iff
|
|
325
|
+
* @param {number} lineA Line A.
|
|
326
|
+
* @param {number} columnA Column A.
|
|
327
|
+
* @param {number} lineB Line B.
|
|
328
|
+
* @param {number} columnB Column B.
|
|
329
|
+
* @returns {boolean} True iff A is less than or equal to B.
|
|
446
330
|
*/
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
(index < span[1]) ||
|
|
451
|
-
(index + length > span[1] + span[2])
|
|
452
|
-
))
|
|
331
|
+
const positionLessThanOrEqual = (lineA, columnA, lineB, columnB) => (
|
|
332
|
+
(lineA < lineB) ||
|
|
333
|
+
((lineA === lineB) && (columnA <= columnB))
|
|
453
334
|
);
|
|
454
|
-
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Returns whether two ranges (or MicromarkTokens) overlap anywhere.
|
|
338
|
+
*
|
|
339
|
+
* @param {FileRange|import("../lib/markdownlint.js").MicromarkToken} rangeA Range A.
|
|
340
|
+
* @param {FileRange|import("../lib/markdownlint.js").MicromarkToken} rangeB Range B.
|
|
341
|
+
* @returns {boolean} True iff the two ranges overlap.
|
|
342
|
+
*/
|
|
343
|
+
module.exports.hasOverlap = function hasOverlap(rangeA, rangeB) {
|
|
344
|
+
const lte = positionLessThanOrEqual(rangeA.startLine, rangeA.startColumn, rangeB.startLine, rangeB.startColumn);
|
|
345
|
+
const first = lte ? rangeA : rangeB;
|
|
346
|
+
const second = lte ? rangeB : rangeA;
|
|
347
|
+
return positionLessThanOrEqual(second.startLine, second.startColumn, first.endLine, first.endColumn);
|
|
348
|
+
};
|
|
455
349
|
|
|
456
350
|
// Determines if the front matter includes a title
|
|
457
351
|
module.exports.frontMatterHasTitle =
|
|
@@ -470,16 +364,28 @@ module.exports.frontMatterHasTitle =
|
|
|
470
364
|
/**
|
|
471
365
|
* Returns an object with information about reference links and images.
|
|
472
366
|
*
|
|
473
|
-
* @param {import("../helpers/micromark.cjs").Token[]} tokens Micromark tokens.
|
|
367
|
+
* @param {import("../helpers/micromark-helpers.cjs").Token[]} tokens Micromark tokens.
|
|
474
368
|
* @returns {Object} Reference link/image data.
|
|
475
369
|
*/
|
|
476
370
|
function getReferenceLinkImageData(tokens) {
|
|
477
371
|
const normalizeReference = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
|
|
372
|
+
const references = new Map();
|
|
373
|
+
const shortcuts = new Map();
|
|
374
|
+
const addReferenceToDictionary = (token, label, isShortcut) => {
|
|
375
|
+
const referenceDatum = [
|
|
376
|
+
token.startLine - 1,
|
|
377
|
+
token.startColumn - 1,
|
|
378
|
+
token.text.length
|
|
379
|
+
];
|
|
380
|
+
const reference = normalizeReference(label);
|
|
381
|
+
const dictionary = isShortcut ? shortcuts : references;
|
|
382
|
+
const referenceData = dictionary.get(reference) || [];
|
|
383
|
+
referenceData.push(referenceDatum);
|
|
384
|
+
dictionary.set(reference, referenceData);
|
|
385
|
+
};
|
|
478
386
|
const definitions = new Map();
|
|
479
387
|
const definitionLineIndices = [];
|
|
480
388
|
const duplicateDefinitions = [];
|
|
481
|
-
const references = new Map();
|
|
482
|
-
const shortcuts = new Map();
|
|
483
389
|
const filteredTokens =
|
|
484
390
|
micromark.filterByTypes(
|
|
485
391
|
tokens,
|
|
@@ -489,7 +395,9 @@ function getReferenceLinkImageData(tokens) {
|
|
|
489
395
|
// definitions and definitionLineIndices
|
|
490
396
|
"definitionLabelString", "gfmFootnoteDefinitionLabelString",
|
|
491
397
|
// references and shortcuts
|
|
492
|
-
"gfmFootnoteCall", "image", "link"
|
|
398
|
+
"gfmFootnoteCall", "image", "link",
|
|
399
|
+
// undefined link labels
|
|
400
|
+
"undefinedReferenceCollapsed", "undefinedReferenceFull", "undefinedReferenceShortcut"
|
|
493
401
|
]
|
|
494
402
|
);
|
|
495
403
|
for (const token of filteredTokens) {
|
|
@@ -512,15 +420,10 @@ function getReferenceLinkImageData(tokens) {
|
|
|
512
420
|
if (definitions.has(reference)) {
|
|
513
421
|
duplicateDefinitions.push([ reference, token.startLine - 1 ]);
|
|
514
422
|
} else {
|
|
515
|
-
let destinationString = null;
|
|
516
423
|
const parent =
|
|
517
|
-
micromark.
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
micromark.filterByPredicate(parent.children),
|
|
521
|
-
"definitionDestinationString"
|
|
522
|
-
);
|
|
523
|
-
}
|
|
424
|
+
micromark.getParentOfType(token, [ "definition" ]);
|
|
425
|
+
const destinationString = parent &&
|
|
426
|
+
micromark.getDescendantsByType(parent, [ "definitionDestination", "definitionDestinationRaw", "definitionDestinationString" ])[0]?.text;
|
|
524
427
|
definitions.set(
|
|
525
428
|
reference,
|
|
526
429
|
[ token.startLine - 1, destinationString ]
|
|
@@ -532,67 +435,38 @@ function getReferenceLinkImageData(tokens) {
|
|
|
532
435
|
case "image":
|
|
533
436
|
case "link":
|
|
534
437
|
{
|
|
535
|
-
|
|
536
|
-
let
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
if
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
);
|
|
546
|
-
isShortcut = (labelText !== null);
|
|
547
|
-
}
|
|
548
|
-
const fullAndCollapsedCandidate =
|
|
549
|
-
micromark.matchAndGetTokensByType(
|
|
550
|
-
token.children, [ "label", "reference" ]
|
|
438
|
+
// Identify if shortcut or full/collapsed
|
|
439
|
+
let isShortcut = (token.children.length === 1);
|
|
440
|
+
const isFullOrCollapsed = (token.children.length === 2) && !token.children.some((t) => t.type === "resource");
|
|
441
|
+
const [ labelText ] = micromark.getDescendantsByType(token, [ "label", "labelText" ]);
|
|
442
|
+
const [ referenceString ] = micromark.getDescendantsByType(token, [ "reference", "referenceString" ]);
|
|
443
|
+
let label = labelText?.text;
|
|
444
|
+
// Identify if footnote
|
|
445
|
+
if (!isShortcut && !isFullOrCollapsed) {
|
|
446
|
+
const [ footnoteCallMarker, footnoteCallString ] = token.children.filter(
|
|
447
|
+
(t) => [ "gfmFootnoteCallMarker", "gfmFootnoteCallString" ].includes(t.type)
|
|
551
448
|
);
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
);
|
|
557
|
-
referenceStringText =
|
|
558
|
-
micromark.getTokenTextByType(
|
|
559
|
-
fullAndCollapsedCandidate[1].children, "referenceString"
|
|
560
|
-
);
|
|
561
|
-
isFullOrCollapsed = (labelText !== null);
|
|
562
|
-
}
|
|
563
|
-
const footnote = micromark.matchAndGetTokensByType(
|
|
564
|
-
token.children,
|
|
565
|
-
[
|
|
566
|
-
"gfmFootnoteCallLabelMarker", "gfmFootnoteCallMarker",
|
|
567
|
-
"gfmFootnoteCallString", "gfmFootnoteCallLabelMarker"
|
|
568
|
-
],
|
|
569
|
-
[ "gfmFootnoteCallMarker", "gfmFootnoteCallString" ]
|
|
570
|
-
);
|
|
571
|
-
if (footnote) {
|
|
572
|
-
const callMarkerText = footnote[0].text;
|
|
573
|
-
const callString = footnote[1].text;
|
|
574
|
-
labelText = `${callMarkerText}${callString}`;
|
|
575
|
-
isShortcut = true;
|
|
449
|
+
if (footnoteCallMarker && footnoteCallString) {
|
|
450
|
+
label = `${footnoteCallMarker.text}${footnoteCallString.text}`;
|
|
451
|
+
isShortcut = true;
|
|
452
|
+
}
|
|
576
453
|
}
|
|
577
|
-
// Track shortcuts separately due to ambiguity in "text [text] text"
|
|
454
|
+
// Track link (handle shortcuts separately due to ambiguity in "text [text] text")
|
|
578
455
|
if (isShortcut || isFullOrCollapsed) {
|
|
579
|
-
|
|
580
|
-
token.startLine - 1,
|
|
581
|
-
token.startColumn - 1,
|
|
582
|
-
token.text.length,
|
|
583
|
-
// @ts-ignore
|
|
584
|
-
labelText.length,
|
|
585
|
-
(referenceStringText || "").length
|
|
586
|
-
];
|
|
587
|
-
const reference =
|
|
588
|
-
normalizeReference(referenceStringText || labelText);
|
|
589
|
-
const dictionary = isShortcut ? shortcuts : references;
|
|
590
|
-
const referenceData = dictionary.get(reference) || [];
|
|
591
|
-
referenceData.push(referenceDatum);
|
|
592
|
-
dictionary.set(reference, referenceData);
|
|
456
|
+
addReferenceToDictionary(token, referenceString?.text || label, isShortcut);
|
|
593
457
|
}
|
|
594
458
|
}
|
|
595
459
|
break;
|
|
460
|
+
case "undefinedReferenceCollapsed":
|
|
461
|
+
case "undefinedReferenceFull":
|
|
462
|
+
case "undefinedReferenceShortcut":
|
|
463
|
+
{
|
|
464
|
+
const undefinedReference = micromark.getDescendantsByType(token, [ "undefinedReference" ])[0];
|
|
465
|
+
const label = undefinedReference.children.map((t) => t.text).join("");
|
|
466
|
+
const isShortcut = (token.type === "undefinedReferenceShortcut");
|
|
467
|
+
addReferenceToDictionary(token, label, isShortcut);
|
|
468
|
+
}
|
|
469
|
+
break;
|
|
596
470
|
}
|
|
597
471
|
}
|
|
598
472
|
return {
|
|
@@ -645,120 +519,6 @@ function getPreferredLineEnding(input, os) {
|
|
|
645
519
|
}
|
|
646
520
|
module.exports.getPreferredLineEnding = getPreferredLineEnding;
|
|
647
521
|
|
|
648
|
-
/**
|
|
649
|
-
* Normalizes the fields of a RuleOnErrorFixInfo instance.
|
|
650
|
-
*
|
|
651
|
-
* @param {Object} fixInfo RuleOnErrorFixInfo instance.
|
|
652
|
-
* @param {number} [lineNumber] Line number.
|
|
653
|
-
* @returns {Object} Normalized RuleOnErrorFixInfo instance.
|
|
654
|
-
*/
|
|
655
|
-
function normalizeFixInfo(fixInfo, lineNumber) {
|
|
656
|
-
return {
|
|
657
|
-
"lineNumber": fixInfo.lineNumber || lineNumber,
|
|
658
|
-
"editColumn": fixInfo.editColumn || 1,
|
|
659
|
-
"deleteCount": fixInfo.deleteCount || 0,
|
|
660
|
-
"insertText": fixInfo.insertText || ""
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
* Fixes the specified error on a line of Markdown content.
|
|
666
|
-
*
|
|
667
|
-
* @param {string} line Line of Markdown content.
|
|
668
|
-
* @param {Object} fixInfo RuleOnErrorFixInfo instance.
|
|
669
|
-
* @param {string} [lineEnding] Line ending to use.
|
|
670
|
-
* @returns {string | null} Fixed content.
|
|
671
|
-
*/
|
|
672
|
-
function applyFix(line, fixInfo, lineEnding) {
|
|
673
|
-
const { editColumn, deleteCount, insertText } = normalizeFixInfo(fixInfo);
|
|
674
|
-
const editIndex = editColumn - 1;
|
|
675
|
-
return (deleteCount === -1) ?
|
|
676
|
-
null :
|
|
677
|
-
line.slice(0, editIndex) +
|
|
678
|
-
insertText.replace(/\n/g, lineEnding || "\n") +
|
|
679
|
-
line.slice(editIndex + deleteCount);
|
|
680
|
-
}
|
|
681
|
-
module.exports.applyFix = applyFix;
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* Applies as many fixes as possible to Markdown content.
|
|
685
|
-
*
|
|
686
|
-
* @param {string} input Lines of Markdown content.
|
|
687
|
-
* @param {Object[]} errors RuleOnErrorInfo instances.
|
|
688
|
-
* @returns {string} Corrected content.
|
|
689
|
-
*/
|
|
690
|
-
function applyFixes(input, errors) {
|
|
691
|
-
const lineEnding = getPreferredLineEnding(input, require("node:os"));
|
|
692
|
-
const lines = input.split(newLineRe);
|
|
693
|
-
// Normalize fixInfo objects
|
|
694
|
-
let fixInfos = errors
|
|
695
|
-
.filter((error) => error.fixInfo)
|
|
696
|
-
.map((error) => normalizeFixInfo(error.fixInfo, error.lineNumber));
|
|
697
|
-
// Sort bottom-to-top, line-deletes last, right-to-left, long-to-short
|
|
698
|
-
fixInfos.sort((a, b) => {
|
|
699
|
-
const aDeletingLine = (a.deleteCount === -1);
|
|
700
|
-
const bDeletingLine = (b.deleteCount === -1);
|
|
701
|
-
return (
|
|
702
|
-
(b.lineNumber - a.lineNumber) ||
|
|
703
|
-
(aDeletingLine ? 1 : (bDeletingLine ? -1 : 0)) ||
|
|
704
|
-
(b.editColumn - a.editColumn) ||
|
|
705
|
-
(b.insertText.length - a.insertText.length)
|
|
706
|
-
);
|
|
707
|
-
});
|
|
708
|
-
// Remove duplicate entries (needed for following collapse step)
|
|
709
|
-
let lastFixInfo = {};
|
|
710
|
-
fixInfos = fixInfos.filter((fixInfo) => {
|
|
711
|
-
const unique = (
|
|
712
|
-
(fixInfo.lineNumber !== lastFixInfo.lineNumber) ||
|
|
713
|
-
(fixInfo.editColumn !== lastFixInfo.editColumn) ||
|
|
714
|
-
(fixInfo.deleteCount !== lastFixInfo.deleteCount) ||
|
|
715
|
-
(fixInfo.insertText !== lastFixInfo.insertText)
|
|
716
|
-
);
|
|
717
|
-
lastFixInfo = fixInfo;
|
|
718
|
-
return unique;
|
|
719
|
-
});
|
|
720
|
-
// Collapse insert/no-delete and no-insert/delete for same line/column
|
|
721
|
-
lastFixInfo = {
|
|
722
|
-
"lineNumber": -1
|
|
723
|
-
};
|
|
724
|
-
for (const fixInfo of fixInfos) {
|
|
725
|
-
if (
|
|
726
|
-
(fixInfo.lineNumber === lastFixInfo.lineNumber) &&
|
|
727
|
-
(fixInfo.editColumn === lastFixInfo.editColumn) &&
|
|
728
|
-
!fixInfo.insertText &&
|
|
729
|
-
(fixInfo.deleteCount > 0) &&
|
|
730
|
-
lastFixInfo.insertText &&
|
|
731
|
-
!lastFixInfo.deleteCount) {
|
|
732
|
-
fixInfo.insertText = lastFixInfo.insertText;
|
|
733
|
-
lastFixInfo.lineNumber = 0;
|
|
734
|
-
}
|
|
735
|
-
lastFixInfo = fixInfo;
|
|
736
|
-
}
|
|
737
|
-
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber);
|
|
738
|
-
// Apply all (remaining/updated) fixes
|
|
739
|
-
let lastLineIndex = -1;
|
|
740
|
-
let lastEditIndex = -1;
|
|
741
|
-
for (const fixInfo of fixInfos) {
|
|
742
|
-
const { lineNumber, editColumn, deleteCount } = fixInfo;
|
|
743
|
-
const lineIndex = lineNumber - 1;
|
|
744
|
-
const editIndex = editColumn - 1;
|
|
745
|
-
if (
|
|
746
|
-
(lineIndex !== lastLineIndex) ||
|
|
747
|
-
(deleteCount === -1) ||
|
|
748
|
-
((editIndex + deleteCount) <=
|
|
749
|
-
(lastEditIndex - ((deleteCount > 0) ? 0 : 1)))
|
|
750
|
-
) {
|
|
751
|
-
// @ts-ignore
|
|
752
|
-
lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding);
|
|
753
|
-
}
|
|
754
|
-
lastLineIndex = lineIndex;
|
|
755
|
-
lastEditIndex = editIndex;
|
|
756
|
-
}
|
|
757
|
-
// Return corrected input
|
|
758
|
-
return lines.filter((line) => line !== null).join(lineEnding);
|
|
759
|
-
}
|
|
760
|
-
module.exports.applyFixes = applyFixes;
|
|
761
|
-
|
|
762
522
|
/**
|
|
763
523
|
* Expands a path with a tilde to an absolute path.
|
|
764
524
|
*
|
|
@@ -771,23 +531,3 @@ function expandTildePath(file, os) {
|
|
|
771
531
|
return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file;
|
|
772
532
|
}
|
|
773
533
|
module.exports.expandTildePath = expandTildePath;
|
|
774
|
-
|
|
775
|
-
// Copied from markdownlint.js to avoid TypeScript compiler import() issue.
|
|
776
|
-
/**
|
|
777
|
-
* @typedef {Object} MarkdownItToken
|
|
778
|
-
* @property {string[][]} attrs HTML attributes.
|
|
779
|
-
* @property {boolean} block Block-level token.
|
|
780
|
-
* @property {MarkdownItToken[]} children Child nodes.
|
|
781
|
-
* @property {string} content Tag contents.
|
|
782
|
-
* @property {boolean} hidden Ignore element.
|
|
783
|
-
* @property {string} info Fence info.
|
|
784
|
-
* @property {number} level Nesting level.
|
|
785
|
-
* @property {number[]} map Beginning/ending line numbers.
|
|
786
|
-
* @property {string} markup Markup text.
|
|
787
|
-
* @property {Object} meta Arbitrary data.
|
|
788
|
-
* @property {number} nesting Level change.
|
|
789
|
-
* @property {string} tag HTML tag name.
|
|
790
|
-
* @property {string} type Token type.
|
|
791
|
-
* @property {number} lineNumber Line number (1-based).
|
|
792
|
-
* @property {string} line Line content.
|
|
793
|
-
*/
|