markdownlint 0.22.0 → 0.25.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.
@@ -2,8 +2,6 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const os = require("os");
6
-
7
5
  // Regular expression for matching common newline characters
8
6
  // See NEWLINES_RE in markdown-it/lib/rules_core/normalize.js
9
7
  const newLineRe = /\r\n?|\n/g;
@@ -29,10 +27,11 @@ module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
29
27
  const emphasisMarkersRe = /[_*]/g;
30
28
 
31
29
  // Regular expression for inline links and shortcut reference links
32
- const linkRe = /\[(?:[^[\]]|\[[^\]]*\])*\](?:\(\S*\))?/g;
30
+ const linkRe = /(\[(?:[^[\]]|\[[^\]]*\])*\])(\(\S*\)|\[\S*\])?/g;
31
+ module.exports.linkRe = linkRe;
33
32
 
34
- // readFile options for reading with the UTF-8 encoding
35
- module.exports.utf8Encoding = "utf8";
33
+ // Regular expression for link reference definition lines
34
+ module.exports.linkReferenceRe = /^ {0,3}\[[^\]]+]:\s.*$/;
36
35
 
37
36
  // All punctuation characters (normal and full-width)
38
37
  const allPunctuation = ".,;:!?。,;:!?";
@@ -62,12 +61,20 @@ module.exports.isObject = function isObject(obj) {
62
61
  };
63
62
 
64
63
  // Returns true iff the input line is blank (no content)
65
- // Example: Contains nothing, whitespace, or comments
66
- const blankLineRe = />|(?:<!--.*?-->)/g;
64
+ // Example: Contains nothing, whitespace, or comment (unclosed start/end okay)
67
65
  module.exports.isBlankLine = function isBlankLine(line) {
68
66
  // Call to String.replace follows best practices and is not a security check
69
67
  // False-positive for js/incomplete-multi-character-sanitization
70
- return !line || !line.trim() || !line.replace(blankLineRe, "").trim();
68
+ return (
69
+ !line ||
70
+ !line.trim() ||
71
+ !line
72
+ .replace(/<!--.*?-->/g, "")
73
+ .replace(/<!--.*$/g, "")
74
+ .replace(/^.*-->/g, "")
75
+ .replace(/>/g, "")
76
+ .trim()
77
+ );
71
78
  };
72
79
 
73
80
  /**
@@ -99,32 +106,47 @@ module.exports.includesSorted = function includesSorted(array, element) {
99
106
  return false;
100
107
  };
101
108
 
102
- // Replaces the text of all properly-formatted HTML comments with whitespace
109
+ // Replaces the content of properly-formatted CommonMark comments with "."
103
110
  // This preserves the line/column information for the rest of the document
104
- // Trailing whitespace is avoided with a '\' character in the last column
105
- // See https://www.w3.org/TR/html5/syntax.html#comments for details
111
+ // https://spec.commonmark.org/0.29/#html-blocks
112
+ // https://spec.commonmark.org/0.29/#html-comment
106
113
  const htmlCommentBegin = "<!--";
107
114
  const htmlCommentEnd = "-->";
108
115
  module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) {
109
116
  let i = 0;
110
117
  while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) {
111
- const j = text.indexOf(htmlCommentEnd, i);
118
+ const j = text.indexOf(htmlCommentEnd, i + 2);
112
119
  if (j === -1) {
113
120
  // Un-terminated comments are treated as text
114
121
  break;
115
122
  }
116
- const comment = text.slice(i + htmlCommentBegin.length, j);
117
- if ((comment.length > 0) &&
118
- (comment[0] !== ">") &&
119
- (comment[comment.length - 1] !== "-") &&
120
- !comment.includes("--") &&
121
- (text.slice(i, j + htmlCommentEnd.length)
122
- .search(inlineCommentRe) === -1)) {
123
- const blanks = comment
124
- .replace(/[^\r\n]/g, " ")
125
- .replace(/ ([\r\n])/g, "\\$1");
126
- text = text.slice(0, i + htmlCommentBegin.length) +
127
- blanks + text.slice(j);
123
+ // If the comment has content...
124
+ if (j > i + htmlCommentBegin.length) {
125
+ let k = i - 1;
126
+ while (text[k] === " ") {
127
+ k--;
128
+ }
129
+ // If comment is not within an indented code block...
130
+ if (k >= i - 4) {
131
+ const content = text.slice(i + htmlCommentBegin.length, j);
132
+ const isBlock = (k < 0) || (text[k] === "\n");
133
+ const isValid = isBlock ||
134
+ (!content.startsWith(">") && !content.startsWith("->") &&
135
+ !content.endsWith("-") && !content.includes("--"));
136
+ // If a valid block/inline comment...
137
+ if (isValid) {
138
+ const inlineCommentIndex = text
139
+ .slice(i, j + htmlCommentEnd.length)
140
+ .search(inlineCommentRe);
141
+ // If not a markdownlint inline directive...
142
+ if (inlineCommentIndex === -1) {
143
+ text =
144
+ text.slice(0, i + htmlCommentBegin.length) +
145
+ content.replace(/[^\r\n]/g, ".") +
146
+ text.slice(j);
147
+ }
148
+ }
149
+ }
128
150
  }
129
151
  i = j + htmlCommentEnd.length;
130
152
  }
@@ -165,6 +187,22 @@ module.exports.fencedCodeBlockStyleFor =
165
187
  }
166
188
  };
167
189
 
190
+ /**
191
+ * Return the string representation of a emphasis or strong markup character.
192
+ *
193
+ * @param {string} markup Emphasis or strong string.
194
+ * @returns {string} String representation.
195
+ */
196
+ module.exports.emphasisOrStrongStyleFor =
197
+ function emphasisOrStrongStyleFor(markup) {
198
+ switch (markup[0]) {
199
+ case "*":
200
+ return "asterisk";
201
+ default:
202
+ return "underscore";
203
+ }
204
+ };
205
+
168
206
  /**
169
207
  * Return the number of characters of indent for a token.
170
208
  *
@@ -173,7 +211,7 @@ module.exports.fencedCodeBlockStyleFor =
173
211
  */
174
212
  function indentFor(token) {
175
213
  const line = token.line.replace(/^[\s>]*(> |>)/, "");
176
- return line.length - line.trimLeft().length;
214
+ return line.length - line.trimStart().length;
177
215
  }
178
216
  module.exports.indentFor = indentFor;
179
217
 
@@ -223,66 +261,85 @@ function filterTokens(params, type, handler) {
223
261
  }
224
262
  module.exports.filterTokens = filterTokens;
225
263
 
264
+ /**
265
+ * Returns whether a token is a math block (created by markdown-it-texmath).
266
+ *
267
+ * @param {Object} token MarkdownItToken instance.
268
+ * @returns {boolean} True iff token is a math block.
269
+ */
270
+ function isMathBlock(token) {
271
+ return (
272
+ ((token.tag === "$$") || (token.tag === "math")) &&
273
+ token.type.startsWith("math_block") &&
274
+ !token.type.endsWith("_end")
275
+ );
276
+ }
277
+ module.exports.isMathBlock = isMathBlock;
278
+
226
279
  // Get line metadata array
227
280
  module.exports.getLineMetadata = function getLineMetadata(params) {
228
- const lineMetadata = params.lines.map(function mapLine(line, index) {
229
- return [ line, index, false, 0, false, false ];
230
- });
231
- filterTokens(params, "fence", function forToken(token) {
281
+ const lineMetadata = params.lines.map(
282
+ (line, index) => [ line, index, false, 0, false, false, false, false ]
283
+ );
284
+ filterTokens(params, "fence", (token) => {
232
285
  lineMetadata[token.map[0]][3] = 1;
233
286
  lineMetadata[token.map[1] - 1][3] = -1;
234
287
  for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) {
235
288
  lineMetadata[i][2] = true;
236
289
  }
237
290
  });
238
- filterTokens(params, "code_block", function forToken(token) {
291
+ filterTokens(params, "code_block", (token) => {
239
292
  for (let i = token.map[0]; i < token.map[1]; i++) {
240
293
  lineMetadata[i][2] = true;
241
294
  }
242
295
  });
243
- filterTokens(params, "table_open", function forToken(token) {
296
+ filterTokens(params, "table_open", (token) => {
244
297
  for (let i = token.map[0]; i < token.map[1]; i++) {
245
298
  lineMetadata[i][4] = true;
246
299
  }
247
300
  });
248
- filterTokens(params, "list_item_open", function forToken(token) {
301
+ filterTokens(params, "list_item_open", (token) => {
249
302
  let count = 1;
250
303
  for (let i = token.map[0]; i < token.map[1]; i++) {
251
304
  lineMetadata[i][5] = count;
252
305
  count++;
253
306
  }
254
307
  });
255
- filterTokens(params, "hr", function forToken(token) {
308
+ filterTokens(params, "hr", (token) => {
256
309
  lineMetadata[token.map[0]][6] = true;
257
310
  });
311
+ params.tokens.filter(isMathBlock).forEach((token) => {
312
+ for (let i = token.map[0]; i < token.map[1]; i++) {
313
+ lineMetadata[i][7] = true;
314
+ }
315
+ });
258
316
  return lineMetadata;
259
317
  };
260
318
 
261
- // Calls the provided function for each line (with context)
262
- module.exports.forEachLine = function forEachLine(lineMetadata, handler) {
319
+ /**
320
+ * Calls the provided function for each line.
321
+ *
322
+ * @param {Object} lineMetadata Line metadata object.
323
+ * @param {Function} handler Function taking (line, lineIndex, inCode, onFence,
324
+ * inTable, inItem, inBreak, inMath).
325
+ * @returns {void}
326
+ */
327
+ function forEachLine(lineMetadata, handler) {
263
328
  lineMetadata.forEach(function forMetadata(metadata) {
264
- // Parameters: line, lineIndex, inCode, onFence, inTable, inItem, inBreak
265
329
  handler(...metadata);
266
330
  });
267
- };
331
+ }
332
+ module.exports.forEachLine = forEachLine;
268
333
 
269
334
  // Returns (nested) lists as a flat array (in order)
270
- module.exports.flattenLists = function flattenLists(params) {
335
+ module.exports.flattenLists = function flattenLists(tokens) {
271
336
  const flattenedLists = [];
272
337
  const stack = [];
273
338
  let current = null;
274
339
  let nesting = 0;
275
340
  const nestingStack = [];
276
341
  let lastWithMap = { "map": [ 0, 1 ] };
277
- params.tokens.forEach(function forToken(token) {
278
- if (
279
- (token.type === "math_block") &&
280
- (token.tag === "math") &&
281
- token.map[1]
282
- ) {
283
- // markdown-it-texmath package does not account for math_block_end
284
- token.map[1]++;
285
- }
342
+ tokens.forEach((token) => {
286
343
  if ((token.type === "bullet_list_open") ||
287
344
  (token.type === "ordered_list_open")) {
288
345
  // Save current context and start a new one
@@ -354,7 +411,8 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
354
411
  * Calls the provided function for each inline code span's content.
355
412
  *
356
413
  * @param {string} input Markdown content.
357
- * @param {Function} handler Callback function.
414
+ * @param {Function} handler Callback function taking (code, lineIndex,
415
+ * columnIndex, ticks).
358
416
  * @returns {void}
359
417
  */
360
418
  function forEachInlineCodeSpan(input, handler) {
@@ -488,6 +546,60 @@ module.exports.addErrorContext = function addErrorContext(
488
546
  addError(onError, lineNumber, null, context, range, fixInfo);
489
547
  };
490
548
 
549
+ /**
550
+ * Returns an array of code block and span content ranges.
551
+ *
552
+ * @param {Object} params RuleParams instance.
553
+ * @param {Object} lineMetadata Line metadata object.
554
+ * @returns {number[][]} Array of ranges (lineIndex, columnIndex, length).
555
+ */
556
+ module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => {
557
+ const exclusions = [];
558
+ // Add code block ranges (excludes fences)
559
+ forEachLine(lineMetadata, (line, lineIndex, inCode, onFence) => {
560
+ if (inCode && !onFence) {
561
+ exclusions.push([ lineIndex, 0, line.length ]);
562
+ }
563
+ });
564
+ // Add code span ranges (excludes ticks)
565
+ filterTokens(params, "inline", (token) => {
566
+ if (token.children.some((child) => child.type === "code_inline")) {
567
+ const tokenLines = params.lines.slice(token.map[0], token.map[1]);
568
+ forEachInlineCodeSpan(
569
+ tokenLines.join("\n"),
570
+ (code, lineIndex, columnIndex) => {
571
+ const codeLines = code.split(newLineRe);
572
+ for (const [ i, line ] of codeLines.entries()) {
573
+ exclusions.push([
574
+ token.lineNumber - 1 + lineIndex + i,
575
+ i ? 0 : columnIndex,
576
+ line.length
577
+ ]);
578
+ }
579
+ }
580
+ );
581
+ }
582
+ });
583
+ return exclusions;
584
+ };
585
+
586
+ /**
587
+ * Determines whether the specified range overlaps another range.
588
+ *
589
+ * @param {number[][]} ranges Array of ranges (line, index, length).
590
+ * @param {number} lineIndex Line index to check.
591
+ * @param {number} index Index to check.
592
+ * @param {number} length Length to check.
593
+ * @returns {boolean} True iff the specified range overlaps.
594
+ */
595
+ module.exports.overlapsAnyRange = (ranges, lineIndex, index, length) => (
596
+ !ranges.every((span) => (
597
+ (lineIndex !== span[0]) ||
598
+ (index + length < span[1]) ||
599
+ (index > span[1] + span[2])
600
+ ))
601
+ );
602
+
491
603
  // Returns a range object for a line by applying a RegExp
492
604
  module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
493
605
  let range = null;
@@ -523,6 +635,18 @@ module.exports.frontMatterHasTitle =
523
635
  function emphasisMarkersInContent(params) {
524
636
  const { lines } = params;
525
637
  const byLine = new Array(lines.length);
638
+ // Search links
639
+ lines.forEach((tokenLine, tokenLineIndex) => {
640
+ const inLine = [];
641
+ let linkMatch = null;
642
+ while ((linkMatch = linkRe.exec(tokenLine))) {
643
+ let markerMatch = null;
644
+ while ((markerMatch = emphasisMarkersRe.exec(linkMatch[0]))) {
645
+ inLine.push(linkMatch.index + markerMatch.index);
646
+ }
647
+ }
648
+ byLine[tokenLineIndex] = inLine;
649
+ });
526
650
  // Search code spans
527
651
  filterTokens(params, "inline", (token) => {
528
652
  const { children, lineNumber, map } = token;
@@ -533,31 +657,19 @@ function emphasisMarkersInContent(params) {
533
657
  (code, lineIndex, column, tickCount) => {
534
658
  const codeLines = code.split(newLineRe);
535
659
  codeLines.forEach((codeLine, codeLineIndex) => {
660
+ const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
661
+ const inLine = byLine[byLineIndex];
662
+ const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
536
663
  let match = null;
537
664
  while ((match = emphasisMarkersRe.exec(codeLine))) {
538
- const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
539
- const inLine = byLine[byLineIndex] || [];
540
- const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
541
665
  inLine.push(codeLineOffset + match.index);
542
- byLine[byLineIndex] = inLine;
543
666
  }
667
+ byLine[byLineIndex] = inLine;
544
668
  });
545
669
  }
546
670
  );
547
671
  }
548
672
  });
549
- // Search links
550
- lines.forEach((tokenLine, tokenLineIndex) => {
551
- let linkMatch = null;
552
- while ((linkMatch = linkRe.exec(tokenLine))) {
553
- let markerMatch = null;
554
- while ((markerMatch = emphasisMarkersRe.exec(linkMatch[0]))) {
555
- const inLine = byLine[tokenLineIndex] || [];
556
- inLine.push(linkMatch.index + markerMatch.index);
557
- byLine[tokenLineIndex] = inLine;
558
- }
559
- }
560
- });
561
673
  return byLine;
562
674
  }
563
675
  module.exports.emphasisMarkersInContent = emphasisMarkersInContent;
@@ -566,9 +678,10 @@ module.exports.emphasisMarkersInContent = emphasisMarkersInContent;
566
678
  * Gets the most common line ending, falling back to the platform default.
567
679
  *
568
680
  * @param {string} input Markdown content to analyze.
681
+ * @param {string} [platform] Platform identifier (process.platform).
569
682
  * @returns {string} Preferred line ending.
570
683
  */
571
- function getPreferredLineEnding(input) {
684
+ function getPreferredLineEnding(input, platform) {
572
685
  let cr = 0;
573
686
  let lf = 0;
574
687
  let crlf = 0;
@@ -589,7 +702,8 @@ function getPreferredLineEnding(input) {
589
702
  });
590
703
  let preferredLineEnding = null;
591
704
  if (!cr && !lf && !crlf) {
592
- preferredLineEnding = os.EOL;
705
+ preferredLineEnding =
706
+ ((platform || process.platform) === "win32") ? "\r\n" : "\n";
593
707
  } else if ((lf >= crlf) && (lf >= cr)) {
594
708
  preferredLineEnding = "\n";
595
709
  } else if (crlf >= cr) {
@@ -692,8 +806,9 @@ module.exports.applyFixes = function applyFixes(input, errors) {
692
806
  const editIndex = editColumn - 1;
693
807
  if (
694
808
  (lineIndex !== lastLineIndex) ||
695
- ((editIndex + deleteCount) < lastEditIndex) ||
696
- (deleteCount === -1)
809
+ (deleteCount === -1) ||
810
+ ((editIndex + deleteCount) <=
811
+ (lastEditIndex - ((deleteCount > 0) ? 0 : 1)))
697
812
  ) {
698
813
  lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding);
699
814
  }
@@ -703,3 +818,80 @@ module.exports.applyFixes = function applyFixes(input, errors) {
703
818
  // Return corrected input
704
819
  return lines.filter((line) => line !== null).join(lineEnding);
705
820
  };
821
+
822
+ /**
823
+ * Gets the range and fixInfo values for reporting an error if the expected
824
+ * text is found on the specified line.
825
+ *
826
+ * @param {string[]} lines Lines of Markdown content.
827
+ * @param {number} lineIndex Line index to check.
828
+ * @param {string} search Text to search for.
829
+ * @param {string} replace Text to replace with.
830
+ * @returns {Object} Range and fixInfo wrapper.
831
+ */
832
+ function getRangeAndFixInfoIfFound(lines, lineIndex, search, replace) {
833
+ let range = null;
834
+ let fixInfo = null;
835
+ const searchIndex = lines[lineIndex].indexOf(search);
836
+ if (searchIndex !== -1) {
837
+ const column = searchIndex + 1;
838
+ const length = search.length;
839
+ range = [ column, length ];
840
+ fixInfo = {
841
+ "editColumn": column,
842
+ "deleteCount": length,
843
+ "insertText": replace
844
+ };
845
+ }
846
+ return {
847
+ range,
848
+ fixInfo
849
+ };
850
+ }
851
+ module.exports.getRangeAndFixInfoIfFound = getRangeAndFixInfoIfFound;
852
+
853
+ /**
854
+ * Gets the next (subsequent) child token if it is of the expected type.
855
+ *
856
+ * @param {Object} parentToken Parent token.
857
+ * @param {Object} childToken Child token basis.
858
+ * @param {string} nextType Token type of next token.
859
+ * @param {string} nextNextType Token type of next-next token.
860
+ * @returns {Object} Next token.
861
+ */
862
+ function getNextChildToken(parentToken, childToken, nextType, nextNextType) {
863
+ const { children } = parentToken;
864
+ const index = children.indexOf(childToken);
865
+ if (
866
+ (index !== -1) &&
867
+ (children.length > index + 2) &&
868
+ (children[index + 1].type === nextType) &&
869
+ (children[index + 2].type === nextNextType)
870
+ ) {
871
+ return children[index + 1];
872
+ }
873
+ return null;
874
+ }
875
+ module.exports.getNextChildToken = getNextChildToken;
876
+
877
+ /**
878
+ * Calls Object.freeze() on an object and its children.
879
+ *
880
+ * @param {Object} obj Object to deep freeze.
881
+ * @returns {Object} Object passed to the function.
882
+ */
883
+ function deepFreeze(obj) {
884
+ const pending = [ obj ];
885
+ let current = null;
886
+ while ((current = pending.shift())) {
887
+ Object.freeze(current);
888
+ for (const name of Object.getOwnPropertyNames(current)) {
889
+ const value = current[name];
890
+ if (value && (typeof value === "object")) {
891
+ pending.push(value);
892
+ }
893
+ }
894
+ }
895
+ return obj;
896
+ }
897
+ module.exports.deepFreeze = deepFreeze;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint-rule-helpers",
3
- "version": "0.13.0",
3
+ "version": "0.16.0",
4
4
  "description": "A collection of markdownlint helper functions for custom rules",
5
5
  "main": "helpers.js",
6
6
  "author": "David Anson (https://dlaa.me/)",
package/lib/cache.js CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- let lineMetadata = null;
6
- module.exports.lineMetadata = (value) => {
5
+ let codeBlockAndSpanRanges = null;
6
+ module.exports.codeBlockAndSpanRanges = (value) => {
7
7
  if (value) {
8
- lineMetadata = value;
8
+ codeBlockAndSpanRanges = value;
9
9
  }
10
- return lineMetadata;
10
+ return codeBlockAndSpanRanges;
11
11
  };
12
12
 
13
13
  let flattenedLists = null;
@@ -18,7 +18,16 @@ module.exports.flattenedLists = (value) => {
18
18
  return flattenedLists;
19
19
  };
20
20
 
21
+ let lineMetadata = null;
22
+ module.exports.lineMetadata = (value) => {
23
+ if (value) {
24
+ lineMetadata = value;
25
+ }
26
+ return lineMetadata;
27
+ };
28
+
21
29
  module.exports.clear = () => {
22
- lineMetadata = null;
30
+ codeBlockAndSpanRanges = null;
23
31
  flattenedLists = null;
32
+ lineMetadata = null;
24
33
  };
@@ -0,0 +1,7 @@
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ module.exports.deprecatedRuleNames = [ "MD002", "MD006" ];
6
+ module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
7
+ module.exports.version = "0.25.0";
@@ -8,7 +8,7 @@ export = markdownlint;
8
8
  */
9
9
  declare function markdownlint(options: Options, callback: LintCallback): void;
10
10
  declare namespace markdownlint {
11
- export { markdownlintSync as sync, readConfig, readConfigSync, getVersion, promises, RuleFunction, RuleParams, MarkdownItToken, RuleOnError, RuleOnErrorInfo, RuleOnErrorFixInfo, Rule, Options, Plugin, ToStringCallback, LintResults, LintError, FixInfo, LintCallback, Configuration, RuleConfiguration, ConfigurationParser, ReadConfigCallback };
11
+ export { markdownlintSync as sync, readConfig, readConfigSync, getVersion, promises, RuleFunction, RuleParams, MarkdownItToken, RuleOnError, RuleOnErrorInfo, RuleOnErrorFixInfo, Rule, Options, Plugin, ToStringCallback, LintResults, LintError, FixInfo, LintCallback, Configuration, RuleConfiguration, ConfigurationParser, ReadConfigCallback, ResolveConfigExtendsCallback };
12
12
  }
13
13
  /**
14
14
  * Configuration options.
@@ -52,9 +52,13 @@ type Options = {
52
52
  * Additional plugins.
53
53
  */
54
54
  markdownItPlugins?: Plugin[];
55
+ /**
56
+ * File system implementation.
57
+ */
58
+ fs?: any;
55
59
  };
56
60
  /**
57
- * Called with the result of the lint operation.
61
+ * Called with the result of the lint function.
58
62
  */
59
63
  type LintCallback = (err: Error | null, results?: LintResults) => void;
60
64
  /**
@@ -70,18 +74,21 @@ declare function markdownlintSync(options: Options): LintResults;
70
74
  * @param {string} file Configuration file name.
71
75
  * @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
72
76
  * function(s).
77
+ * @param {Object} [fs] File system implementation.
73
78
  * @param {ReadConfigCallback} [callback] Callback (err, result) function.
74
79
  * @returns {void}
75
80
  */
76
- declare function readConfig(file: string, parsers: ConfigurationParser[] | ReadConfigCallback, callback?: ReadConfigCallback): void;
81
+ declare function readConfig(file: string, parsers: ConfigurationParser[] | ReadConfigCallback, fs?: any, callback?: ReadConfigCallback): void;
77
82
  /**
78
83
  * Read specified configuration file synchronously.
79
84
  *
80
85
  * @param {string} file Configuration file name.
81
86
  * @param {ConfigurationParser[]} [parsers] Parsing function(s).
87
+ * @param {Object} [fs] File system implementation.
82
88
  * @returns {Configuration} Configuration object.
89
+ * @throws An Error if processing fails.
83
90
  */
84
- declare function readConfigSync(file: string, parsers?: ConfigurationParser[]): Configuration;
91
+ declare function readConfigSync(file: string, parsers?: ConfigurationParser[], fs?: any): Configuration;
85
92
  /**
86
93
  * Gets the (semantic) version of the library.
87
94
  *
@@ -199,9 +206,9 @@ type RuleOnErrorInfo = {
199
206
  */
200
207
  lineNumber: number;
201
208
  /**
202
- * Details about the error.
209
+ * Detail about the error.
203
210
  */
204
- details?: string;
211
+ detail?: string;
205
212
  /**
206
213
  * Context for the error.
207
214
  */
@@ -256,6 +263,10 @@ type Rule = {
256
263
  * Rule tag(s).
257
264
  */
258
265
  tags: string[];
266
+ /**
267
+ * True if asynchronous.
268
+ */
269
+ asynchronous?: boolean;
259
270
  /**
260
271
  * Rule implementation.
261
272
  */
@@ -310,12 +321,16 @@ type LintError = {
310
321
  /**
311
322
  * Fix information.
312
323
  */
313
- fixInfo: FixInfo;
324
+ fixInfo?: FixInfo;
314
325
  };
315
326
  /**
316
327
  * Fix information.
317
328
  */
318
329
  type FixInfo = {
330
+ /**
331
+ * Line number (1-based).
332
+ */
333
+ lineNumber?: number;
319
334
  /**
320
335
  * Column of the fix (1-based).
321
336
  */
@@ -334,20 +349,24 @@ type FixInfo = {
334
349
  * {@link ../schema/markdownlint-config-schema.json}.
335
350
  */
336
351
  type Configuration = {
337
- [x: string]: any;
352
+ [x: string]: RuleConfiguration;
338
353
  };
339
354
  /**
340
355
  * Rule configuration.
341
356
  */
342
- type RuleConfiguration = any;
357
+ type RuleConfiguration = boolean | any;
343
358
  /**
344
359
  * Parses a configuration string and returns a configuration object.
345
360
  */
346
361
  type ConfigurationParser = (text: string) => Configuration;
347
362
  /**
348
- * Called with the result of the readConfig operation.
363
+ * Called with the result of the readConfig function.
349
364
  */
350
365
  type ReadConfigCallback = (err: Error | null, config?: Configuration) => void;
366
+ /**
367
+ * Called with the result of the resolveConfigExtends function.
368
+ */
369
+ type ResolveConfigExtendsCallback = (err: Error | null, path?: string) => void;
351
370
  /**
352
371
  * Lint specified Markdown files.
353
372
  *
@@ -360,6 +379,7 @@ declare function markdownlintPromise(options: Options): Promise<LintResults>;
360
379
  *
361
380
  * @param {string} file Configuration file name.
362
381
  * @param {ConfigurationParser[]} [parsers] Parsing function(s).
382
+ * @param {Object} [fs] File system implementation.
363
383
  * @returns {Promise<Configuration>} Configuration object.
364
384
  */
365
- declare function readConfigPromise(file: string, parsers?: ConfigurationParser[]): Promise<Configuration>;
385
+ declare function readConfigPromise(file: string, parsers?: ConfigurationParser[], fs?: any): Promise<Configuration>;