markdownlint 0.37.4 → 0.39.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/CONTRIBUTING.md +2 -3
  3. package/README.md +175 -87
  4. package/doc/Rules.md +273 -47
  5. package/doc/md001.md +14 -0
  6. package/doc/md009.md +8 -9
  7. package/doc/md010.md +6 -0
  8. package/doc/md027.md +8 -0
  9. package/doc/md029.md +2 -0
  10. package/doc/md033.md +7 -1
  11. package/doc/md038.md +23 -11
  12. package/doc/md041.md +31 -16
  13. package/doc/md043.md +22 -4
  14. package/doc/md045.md +9 -1
  15. package/doc/md051.md +17 -0
  16. package/doc/md052.md +12 -0
  17. package/doc/md053.md +3 -3
  18. package/doc/md055.md +1 -1
  19. package/doc/md056.md +1 -1
  20. package/doc/md059.md +33 -0
  21. package/doc/md060.md +70 -0
  22. package/helpers/README.md +2 -2
  23. package/helpers/helpers.cjs +174 -20
  24. package/helpers/micromark-helpers.cjs +37 -7
  25. package/helpers/package.json +1 -1
  26. package/lib/cache.mjs +25 -7
  27. package/lib/configuration-strict.d.ts +1494 -292
  28. package/lib/constants.mjs +6 -5
  29. package/lib/defer-require.cjs +2 -0
  30. package/lib/exports.d.mts +2 -2
  31. package/lib/exports.mjs +2 -2
  32. package/lib/markdownit.cjs +8 -14
  33. package/lib/markdownlint.d.mts +136 -52
  34. package/lib/markdownlint.mjs +469 -409
  35. package/lib/md001.mjs +6 -2
  36. package/lib/md004.mjs +7 -18
  37. package/lib/md007.mjs +2 -1
  38. package/lib/md009.mjs +9 -5
  39. package/lib/md010.mjs +1 -1
  40. package/lib/md022.mjs +5 -2
  41. package/lib/md025.mjs +23 -15
  42. package/lib/md027.mjs +11 -1
  43. package/lib/md029.mjs +25 -14
  44. package/lib/md031.mjs +0 -1
  45. package/lib/md032.mjs +3 -1
  46. package/lib/md033.mjs +28 -20
  47. package/lib/md034.mjs +2 -1
  48. package/lib/md036.mjs +16 -4
  49. package/lib/md037.mjs +10 -7
  50. package/lib/md038.mjs +52 -71
  51. package/lib/md041.mjs +54 -16
  52. package/lib/md042.mjs +4 -2
  53. package/lib/md043.mjs +4 -2
  54. package/lib/md044.mjs +1 -1
  55. package/lib/md045.mjs +3 -1
  56. package/lib/md046.mjs +6 -6
  57. package/lib/md051.mjs +13 -5
  58. package/lib/md052.mjs +2 -1
  59. package/lib/md053.mjs +1 -1
  60. package/lib/md054.mjs +7 -5
  61. package/lib/md055.mjs +7 -6
  62. package/lib/md056.mjs +1 -1
  63. package/lib/md059.mjs +71 -0
  64. package/lib/md060.mjs +121 -0
  65. package/lib/micromark-parse.mjs +17 -3
  66. package/lib/node-imports-browser.mjs +2 -0
  67. package/lib/parse-configuration.mjs +47 -0
  68. package/lib/rules.mjs +5 -1
  69. package/package.json +32 -30
  70. package/schema/.markdownlint.jsonc +97 -62
  71. package/schema/.markdownlint.yaml +86 -57
  72. package/schema/markdownlint-config-schema-strict.json +4713 -1436
  73. package/schema/markdownlint-config-schema.json +4713 -1436
@@ -9,11 +9,8 @@ const { newLineRe, nextLinesRe } = require("./shared.cjs");
9
9
  module.exports.newLineRe = newLineRe;
10
10
  module.exports.nextLinesRe = nextLinesRe;
11
11
 
12
- // @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529
13
12
  /** @typedef {import("../lib/exports.mjs").RuleOnError} RuleOnError */
14
- // @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529
15
13
  /** @typedef {import("../lib/exports.mjs").RuleOnErrorFixInfo} RuleOnErrorFixInfo */
16
- // @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529
17
14
  /** @typedef {import("../lib/exports.mjs").MicromarkToken} MicromarkToken */
18
15
  // eslint-disable-next-line jsdoc/valid-types
19
16
  /** @typedef {import("micromark-extension-gfm-footnote", { with: { "resolution-mode": "import" } })} */
@@ -114,10 +111,11 @@ module.exports.cloneIfArray = cloneIfArray;
114
111
  /**
115
112
  * Clones the input if it is a URL.
116
113
  *
117
- * @param {Object} url Object of unknown type.
114
+ * @param {Object | undefined} url Object of unknown type.
118
115
  * @returns {Object} Clone of obj iff obj is a URL.
119
116
  */
120
117
  function cloneIfUrl(url) {
118
+ // @ts-ignore
121
119
  return isUrl(url) ? new URL(url) : url;
122
120
  }
123
121
  module.exports.cloneIfUrl = cloneIfUrl;
@@ -142,7 +140,7 @@ module.exports.getHtmlAttributeRe = function getHtmlAttributeRe(name) {
142
140
  function isBlankLine(line) {
143
141
  const startComment = "<!--";
144
142
  const endComment = "-->";
145
- const removeComments = (s) => {
143
+ const removeComments = (/** @type {string} */ s) => {
146
144
  while (true) {
147
145
  const start = s.indexOf(startComment);
148
146
  const end = s.indexOf(endComment);
@@ -180,8 +178,8 @@ const startsWithPipeRe = /^ *\|/;
180
178
  const notCrLfRe = /[^\r\n]/g;
181
179
  const notSpaceCrLfRe = /[^ \r\n]/g;
182
180
  const trailingSpaceRe = / +[\r\n]/g;
183
- const replaceTrailingSpace = (s) => s.replace(notCrLfRe, safeCommentCharacter);
184
- module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
181
+ const replaceTrailingSpace = (/** @type {string} */ s) => s.replace(notCrLfRe, safeCommentCharacter);
182
+ module.exports.clearHtmlCommentText = function clearHtmlCommentText(/** @type {string} */ text) {
185
183
  let i = 0;
186
184
  while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
187
185
  const j = text.indexOf(htmlCommentEnd, i + 2);
@@ -223,7 +221,7 @@ module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
223
221
  };
224
222
 
225
223
  // Escapes a string for use in a RegExp
226
- module.exports.escapeForRegExp = function escapeForRegExp(str) {
224
+ module.exports.escapeForRegExp = function escapeForRegExp(/** @type {string} */ str) {
227
225
  return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
228
226
  };
229
227
 
@@ -311,9 +309,9 @@ module.exports.addErrorDetailIf = addErrorDetailIf;
311
309
  * @param {RuleOnErrorFixInfo} [fixInfo] RuleOnErrorFixInfo instance.
312
310
  * @returns {void}
313
311
  */
314
- function addErrorContext(
315
- onError, lineNumber, context, start, end, range, fixInfo) {
316
- context = ellipsify(context, start, end);
312
+ function addErrorContext(onError, lineNumber, context, start, end, range, fixInfo) {
313
+ // Normalize new line characters so Linux and Windows trim consistently
314
+ context = ellipsify(context.replace(newLineRe, "\n"), start, end);
317
315
  addError(onError, lineNumber, undefined, context, range, fixInfo);
318
316
  }
319
317
  module.exports.addErrorContext = addErrorContext;
@@ -358,7 +356,7 @@ module.exports.hasOverlap = function hasOverlap(rangeA, rangeB) {
358
356
 
359
357
  // Determines if the front matter includes a title
360
358
  module.exports.frontMatterHasTitle =
361
- function frontMatterHasTitle(frontMatterLines, frontMatterTitlePattern) {
359
+ function frontMatterHasTitle(/** @type {readonly string[]} */ frontMatterLines, /** @type {string} */ frontMatterTitlePattern) {
362
360
  const ignoreFrontMatter =
363
361
  (frontMatterTitlePattern !== undefined) && !frontMatterTitlePattern;
364
362
  const frontMatterTitleRe =
@@ -370,17 +368,31 @@ module.exports.frontMatterHasTitle =
370
368
  frontMatterLines.some((line) => frontMatterTitleRe.test(line));
371
369
  };
372
370
 
371
+ /**
372
+ * Result object for getReferenceLinkImageData.
373
+ *
374
+ * @typedef {Object} GetReferenceLinkImageDataResult
375
+ * @property {Map<string, number[][]>} references References.
376
+ * @property {Map<string, number[][]>} shortcuts Shortcuts.
377
+ * @property {Map<string, [number, string]>} definitions Definitions.
378
+ * @property {[string, number][]} duplicateDefinitions Duplicate definitions.
379
+ * @property {number[]} definitionLineIndices Definition line indices.
380
+ */
381
+
373
382
  /**
374
383
  * Returns an object with information about reference links and images.
375
384
  *
376
385
  * @param {MicromarkToken[]} tokens Micromark tokens.
377
- * @returns {Object} Reference link/image data.
386
+ * @returns {GetReferenceLinkImageDataResult} Reference link/image data.
378
387
  */
379
388
  function getReferenceLinkImageData(tokens) {
380
- const normalizeReference = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
389
+ const normalizeReference = (/** @type {string} */ s) => s.toLowerCase().trim().replace(/\s+/g, " ");
390
+ const getText = (/** @type {MicromarkToken} */ t) => t?.children.filter((c) => c.type !== "blockQuotePrefix").map((c) => c.text).join("");
391
+ /** @type {Map<string, number[][]>} */
381
392
  const references = new Map();
393
+ /** @type {Map<string, number[][]>} */
382
394
  const shortcuts = new Map();
383
- const addReferenceToDictionary = (token, label, isShortcut) => {
395
+ const addReferenceToDictionary = (/** @type {MicromarkToken} */ token, /** @type {string} */ label, /** @type {boolean} */ isShortcut) => {
384
396
  const referenceDatum = [
385
397
  token.startLine - 1,
386
398
  token.startColumn - 1,
@@ -392,8 +404,11 @@ function getReferenceLinkImageData(tokens) {
392
404
  referenceData.push(referenceDatum);
393
405
  dictionary.set(reference, referenceData);
394
406
  };
407
+ /** @type {Map<string, [number, string]>} */
395
408
  const definitions = new Map();
409
+ /** @type {number[]} */
396
410
  const definitionLineIndices = [];
411
+ /** @type {[string, number][]} */
397
412
  const duplicateDefinitions = [];
398
413
  const filteredTokens =
399
414
  micromark.filterByTypes(
@@ -435,7 +450,7 @@ function getReferenceLinkImageData(tokens) {
435
450
  micromark.getDescendantsByType(parent, [ "definitionDestination", "definitionDestinationRaw", "definitionDestinationString" ])[0]?.text;
436
451
  definitions.set(
437
452
  reference,
438
- [ token.startLine - 1, destinationString ]
453
+ [ token.startLine - 1, destinationString || "" ]
439
454
  );
440
455
  }
441
456
  }
@@ -449,7 +464,7 @@ function getReferenceLinkImageData(tokens) {
449
464
  const isFullOrCollapsed = (token.children.length === 2) && !token.children.some((t) => t.type === "resource");
450
465
  const [ labelText ] = micromark.getDescendantsByType(token, [ "label", "labelText" ]);
451
466
  const [ referenceString ] = micromark.getDescendantsByType(token, [ "reference", "referenceString" ]);
452
- let label = labelText?.text;
467
+ let label = getText(labelText);
453
468
  // Identify if footnote
454
469
  if (!isShortcut && !isFullOrCollapsed) {
455
470
  const [ footnoteCallMarker, footnoteCallString ] = token.children.filter(
@@ -462,7 +477,7 @@ function getReferenceLinkImageData(tokens) {
462
477
  }
463
478
  // Track link (handle shortcuts separately due to ambiguity in "text [text] text")
464
479
  if (isShortcut || isFullOrCollapsed) {
465
- addReferenceToDictionary(token, referenceString?.text || label, isShortcut);
480
+ addReferenceToDictionary(token, getText(referenceString) || label, isShortcut);
466
481
  }
467
482
  }
468
483
  break;
@@ -492,7 +507,7 @@ module.exports.getReferenceLinkImageData = getReferenceLinkImageData;
492
507
  * Gets the most common line ending, falling back to the platform default.
493
508
  *
494
509
  * @param {string} input Markdown content to analyze.
495
- * @param {Object} [os] Node.js "os" module.
510
+ * @param {{EOL: string}} [os] Node.js "os" module.
496
511
  * @returns {string} Preferred line ending.
497
512
  */
498
513
  function getPreferredLineEnding(input, os) {
@@ -532,7 +547,7 @@ module.exports.getPreferredLineEnding = getPreferredLineEnding;
532
547
  * Expands a path with a tilde to an absolute path.
533
548
  *
534
549
  * @param {string} file Path that may begin with a tilde.
535
- * @param {Object} os Node.js "os" module.
550
+ * @param {{homedir: () => string}} os Node.js "os" module.
536
551
  * @returns {string} Absolute path (or original path).
537
552
  */
538
553
  function expandTildePath(file, os) {
@@ -540,3 +555,142 @@ function expandTildePath(file, os) {
540
555
  return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file;
541
556
  }
542
557
  module.exports.expandTildePath = expandTildePath;
558
+
559
+ /** @typedef {import("../lib/markdownlint.mjs").LintError[]} LintErrors */
560
+ /** @typedef {import("../lib/markdownlint.mjs").LintResults} LintResults */
561
+
562
+ /**
563
+ * Converts lint errors from resultVersion 3 to 2.
564
+ *
565
+ * @param {LintErrors} errors Lint errors (v3).
566
+ * @returns {LintErrors} Lint errors (v2).
567
+ */
568
+ function convertLintErrorsVersion3To2(errors) {
569
+ const noPrevious = {
570
+ "ruleNames": [],
571
+ "lineNumber": -1
572
+ };
573
+ return errors.filter((error, index, array) => {
574
+ // @ts-ignore
575
+ delete error.fixInfo;
576
+ // @ts-ignore
577
+ delete error.severity;
578
+ const previous = array[index - 1] || noPrevious;
579
+ return (
580
+ (error.ruleNames[0] !== previous.ruleNames[0]) ||
581
+ (error.lineNumber !== previous.lineNumber)
582
+ );
583
+ });
584
+ }
585
+
586
+ /**
587
+ * Converts lint errors from resultVersion 2 to 1.
588
+ *
589
+ * @param {LintErrors} errors Lint errors (v2).
590
+ * @returns {LintErrors} Lint errors (v1).
591
+ */
592
+ function convertLintErrorsVersion2To1(errors) {
593
+ for (const error of errors) {
594
+ // @ts-ignore
595
+ error.ruleName = error.ruleNames[0];
596
+ // @ts-ignore
597
+ error.ruleAlias = error.ruleNames[1] || error.ruleName;
598
+ // @ts-ignore
599
+ delete error.ruleNames;
600
+ }
601
+ return errors;
602
+ }
603
+
604
+ /**
605
+ * Converts lint errors from resultVersion 2 to 0.
606
+ *
607
+ * @param {LintErrors} errors Lint errors (v2).
608
+ * @returns {LintErrors} Lint errors (v0).
609
+ */
610
+ function convertLintErrorsVersion2To0(errors) {
611
+ /** @type {Object.<string, number[]>} */
612
+ const dictionary = {};
613
+ for (const error of errors) {
614
+ const ruleName = error.ruleNames[0];
615
+ const ruleLines = dictionary[ruleName] || [];
616
+ ruleLines.push(error.lineNumber);
617
+ dictionary[ruleName] = ruleLines;
618
+ }
619
+ // @ts-ignore
620
+ return dictionary;
621
+ }
622
+
623
+ /**
624
+ * Copies and transforms lint results from resultVersion 3 to ?.
625
+ *
626
+ * @param {LintResults} results Lint results (v3).
627
+ * @param {(errors: LintErrors) => LintErrors} transform Lint errors (v?).
628
+ * @returns {LintResults} Lint results (v?).
629
+ */
630
+ function copyAndTransformResults(results, transform) {
631
+ /** @type {Object.<string, LintErrors>} */
632
+ const newResults = {};
633
+ Object.defineProperty(newResults, "toString", { "value": results.toString });
634
+ for (const key of Object.keys(results)) {
635
+ const arr = results[key].map((r) => ({ ...r }));
636
+ newResults[key] = transform(arr);
637
+ }
638
+ // @ts-ignore
639
+ return newResults;
640
+ }
641
+
642
+ /**
643
+ * Converts lint results from resultVersion 3 to 0.
644
+ *
645
+ * @param {LintResults} results Lint results (v3).
646
+ * @returns {LintResults} Lint results (v0).
647
+ */
648
+ module.exports.convertToResultVersion0 = function convertToResultVersion0(results) {
649
+ return copyAndTransformResults(results, (r) => convertLintErrorsVersion2To0(convertLintErrorsVersion3To2(r)));
650
+ };
651
+
652
+ /**
653
+ * Converts lint results from resultVersion 3 to 1.
654
+ *
655
+ * @param {LintResults} results Lint results (v3).
656
+ * @returns {LintResults} Lint results (v1).
657
+ */
658
+ module.exports.convertToResultVersion1 = function convertToResultVersion1(results) {
659
+ return copyAndTransformResults(results, (r) => convertLintErrorsVersion2To1(convertLintErrorsVersion3To2(r)));
660
+ };
661
+
662
+ /**
663
+ * Converts lint results from resultVersion 3 to 2.
664
+ *
665
+ * @param {LintResults} results Lint results (v3).
666
+ * @returns {LintResults} Lint results (v2).
667
+ */
668
+ module.exports.convertToResultVersion2 = function convertToResultVersion2(results) {
669
+ return copyAndTransformResults(results, convertLintErrorsVersion3To2);
670
+ };
671
+
672
+ /**
673
+ * Formats lint results to an array of strings.
674
+ *
675
+ * @param {LintResults|undefined} lintResults Lint results.
676
+ * @returns {string[]} Lint error strings.
677
+ */
678
+ module.exports.formatLintResults = function formatLintResults(lintResults) {
679
+ const results = [];
680
+ const entries = Object.entries(lintResults || {});
681
+ entries.sort((a, b) => a[0].localeCompare(b[0]));
682
+ for (const [ source, lintErrors ] of entries) {
683
+ for (const lintError of lintErrors) {
684
+ const { lineNumber, ruleNames, ruleDescription, errorDetail, errorContext, errorRange, severity } = lintError;
685
+ const rule = ruleNames.join("/");
686
+ const line = `:${lineNumber}`;
687
+ const rangeStart = (errorRange && errorRange[0]) || 0;
688
+ const column = rangeStart ? `:${rangeStart}` : "";
689
+ const description = ruleDescription;
690
+ const detail = (errorDetail ? ` [${errorDetail}]` : "");
691
+ const context = (errorContext ? ` [Context: "${errorContext}"]` : "");
692
+ results.push(`${source}${line}${column} ${severity} ${rule} ${description}${detail}${context}`);
693
+ }
694
+ }
695
+ return results;
696
+ };
@@ -2,12 +2,13 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { flatTokensSymbol, htmlFlowSymbol } = require("./shared.cjs");
5
+ const { flatTokensSymbol, htmlFlowSymbol, newLineRe } = require("./shared.cjs");
6
6
 
7
7
  // eslint-disable-next-line jsdoc/valid-types
8
8
  /** @typedef {import("micromark-util-types", { with: { "resolution-mode": "import" } }).TokenType} TokenType */
9
- // @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529
10
9
  /** @typedef {import("../lib/exports.mjs").MicromarkToken} Token */
10
+ // eslint-disable-next-line jsdoc/valid-types
11
+ /** @typedef {import("../lib/micromark-types.d.mts", { with: { "resolution-mode": "import" } })} */
11
12
 
12
13
  /**
13
14
  * Determines if a Micromark token is within an htmlFlow type.
@@ -16,6 +17,7 @@ const { flatTokensSymbol, htmlFlowSymbol } = require("./shared.cjs");
16
17
  * @returns {boolean} True iff the token is within an htmlFlow type.
17
18
  */
18
19
  function inHtmlFlow(token) {
20
+ // @ts-ignore
19
21
  return Boolean(token[htmlFlowSymbol]);
20
22
  }
21
23
 
@@ -125,8 +127,11 @@ function filterByPredicate(tokens, allowed, transformChildren) {
125
127
  * @returns {Token[]} Filtered tokens.
126
128
  */
127
129
  function filterByTypes(tokens, types, htmlFlow) {
128
- const predicate = (token) => types.includes(token.type) && (htmlFlow || !inHtmlFlow(token));
129
- const flatTokens = tokens[flatTokensSymbol];
130
+ const predicate = (/** @type {Token} */ token) => types.includes(token.type) && (htmlFlow || !inHtmlFlow(token));
131
+ /** @type {Token[]} */
132
+ const flatTokens =
133
+ // @ts-ignore
134
+ tokens[flatTokensSymbol];
130
135
  if (flatTokens) {
131
136
  return flatTokens.filter(predicate);
132
137
  }
@@ -162,7 +167,7 @@ function getBlockQuotePrefixText(tokens, lineNumber, count = 1) {
162
167
  function getDescendantsByType(parent, typePath) {
163
168
  let tokens = Array.isArray(parent) ? parent : [ parent ];
164
169
  for (const type of typePath) {
165
- const predicate = (token) => Array.isArray(type) ? type.includes(token.type) : (type === token.type);
170
+ const predicate = (/** @type {Token} */ token) => Array.isArray(type) ? type.includes(token.type) : (type === token.type);
166
171
  tokens = tokens.flatMap((t) => t.children.filter(predicate));
167
172
  }
168
173
  return tokens;
@@ -215,8 +220,11 @@ function getHeadingStyle(heading) {
215
220
  * @returns {string} Heading text.
216
221
  */
217
222
  function getHeadingText(heading) {
218
- const headingTexts = getDescendantsByType(heading, [ [ "atxHeadingText", "setextHeadingText" ] ]);
219
- return headingTexts[0]?.text.replace(/[\r\n]+/g, " ") || "";
223
+ return getDescendantsByType(heading, [ [ "atxHeadingText", "setextHeadingText" ] ])
224
+ .flatMap((descendant) => descendant.children.filter((child) => child.type !== "htmlText"))
225
+ .map((data) => data.text)
226
+ .join("")
227
+ .replace(newLineRe, " ");
220
228
  }
221
229
 
222
230
  /**
@@ -265,6 +273,26 @@ function getParentOfType(token, types) {
265
273
  return current;
266
274
  }
267
275
 
276
+ const docfxTabSyntaxRe = /^#tab\//;
277
+
278
+ /**
279
+ * Returns whether the specified Micromark token looks like a Docfx tab.
280
+ *
281
+ * @param {Token | null} heading Micromark token.
282
+ * @returns {boolean} True iff the token looks like a Docfx tab.
283
+ */
284
+ function isDocfxTab(heading) {
285
+ // See https://dotnet.github.io/docfx/docs/markdown.html?tabs=linux%2Cdotnet#tabs
286
+ if (heading?.type === "atxHeading") {
287
+ const headingTexts = getDescendantsByType(heading, [ "atxHeadingText" ]);
288
+ if ((headingTexts.length === 1) && (headingTexts[0].children.length === 1) && (headingTexts[0].children[0].type === "link")) {
289
+ const resourceDestinationStrings = filterByTypes(headingTexts[0].children[0].children, [ "resourceDestinationString" ]);
290
+ return (resourceDestinationStrings.length === 1) && docfxTabSyntaxRe.test(resourceDestinationStrings[0].text);
291
+ }
292
+ }
293
+ return false;
294
+ }
295
+
268
296
  /**
269
297
  * Set containing token types that do not contain content.
270
298
  *
@@ -274,6 +302,7 @@ const nonContentTokens = new Set([
274
302
  "blockQuoteMarker",
275
303
  "blockQuotePrefix",
276
304
  "blockQuotePrefixWhitespace",
305
+ "gfmFootnoteDefinitionIndent",
277
306
  "lineEnding",
278
307
  "lineEndingBlank",
279
308
  "linePrefix",
@@ -296,6 +325,7 @@ module.exports = {
296
325
  getHtmlTagInfo,
297
326
  getParentOfType,
298
327
  inHtmlFlow,
328
+ isDocfxTab,
299
329
  isHtmlFlowComment,
300
330
  nonContentTokens
301
331
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint-rule-helpers",
3
- "version": "0.28.0",
3
+ "version": "0.30.0",
4
4
  "description": "A collection of markdownlint helper functions for custom rules",
5
5
  "main": "./helpers.cjs",
6
6
  "exports": {
package/lib/cache.mjs CHANGED
@@ -3,14 +3,20 @@
3
3
  import { getReferenceLinkImageData as helpersGetReferenceLinkImageData } from "../helpers/helpers.cjs";
4
4
  import { filterByTypes } from "../helpers/micromark-helpers.cjs";
5
5
 
6
+ /** @typedef {import("markdownlint").RuleParams} RuleParams */
7
+ /** @typedef {import("markdownlint").MicromarkToken} MicromarkToken */
8
+ /** @typedef {import("markdownlint").MicromarkTokenType} MicromarkTokenType */
9
+ /** @typedef {import("../helpers/helpers.cjs").GetReferenceLinkImageDataResult} GetReferenceLinkImageDataResult */
10
+
6
11
  /** @type {Map<string, object>} */
7
12
  const map = new Map();
13
+ /** @type {RuleParams | undefined} */
8
14
  let params = undefined;
9
15
 
10
16
  /**
11
17
  * Initializes (resets) the cache.
12
18
  *
13
- * @param {import("markdownlint").RuleParams} [p] Rule parameters object.
19
+ * @param {RuleParams} [p] Rule parameters object.
14
20
  * @returns {void}
15
21
  */
16
22
  export function initialize(p) {
@@ -18,15 +24,25 @@ export function initialize(p) {
18
24
  params = p;
19
25
  }
20
26
 
27
+ /**
28
+ * Gets the cached Micromark token array (for testing).
29
+ *
30
+ * @returns {MicromarkToken[]} Micromark tokens.
31
+ */
32
+ export function micromarkTokens() {
33
+ return params?.parsers.micromark.tokens || [];
34
+ }
35
+
21
36
  /**
22
37
  * Gets a cached object value - computes it and caches it.
23
38
  *
24
39
  * @param {string} name Cache object name.
25
- * @param {Function} getValue Getter for object value.
40
+ * @param {() => Object} getValue Getter for object value.
26
41
  * @returns {Object} Object value.
27
42
  */
28
43
  function getCached(name, getValue) {
29
44
  if (map.has(name)) {
45
+ // @ts-ignore
30
46
  return map.get(name);
31
47
  }
32
48
  const value = getValue();
@@ -37,26 +53,28 @@ function getCached(name, getValue) {
37
53
  /**
38
54
  * Filters a list of Micromark tokens by type and caches the result.
39
55
  *
40
- * @param {import("markdownlint").MicromarkTokenType[]} types Types to allow.
56
+ * @param {MicromarkTokenType[]} types Types to allow.
41
57
  * @param {boolean} [htmlFlow] Whether to include htmlFlow content.
42
- * @returns {import("markdownlint").MicromarkToken[]} Filtered tokens.
58
+ * @returns {MicromarkToken[]} Filtered tokens.
43
59
  */
44
60
  export function filterByTypesCached(types, htmlFlow) {
61
+ // @ts-ignore
45
62
  return getCached(
46
63
  // eslint-disable-next-line prefer-rest-params
47
64
  JSON.stringify(arguments),
48
- () => filterByTypes(params.parsers.micromark.tokens, types, htmlFlow)
65
+ () => filterByTypes(micromarkTokens(), types, htmlFlow)
49
66
  );
50
67
  }
51
68
 
52
69
  /**
53
70
  * Gets a reference link and image data object.
54
71
  *
55
- * @returns {Object} Reference link and image data object.
72
+ * @returns {GetReferenceLinkImageDataResult} Reference link and image data object.
56
73
  */
57
74
  export function getReferenceLinkImageData() {
75
+ // @ts-ignore
58
76
  return getCached(
59
77
  getReferenceLinkImageData.name,
60
- () => helpersGetReferenceLinkImageData(params.parsers.micromark.tokens)
78
+ () => helpersGetReferenceLinkImageData(micromarkTokens())
61
79
  );
62
80
  }