markdownlint 0.21.1 → 0.24.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 +1 -0
- package/LICENSE +1 -1
- package/README.md +140 -80
- package/demo/markdownlint-browser.js +1209 -1701
- package/doc/Prettier.md +23 -0
- package/doc/Rules.md +121 -76
- package/helpers/LICENSE +1 -1
- package/helpers/helpers.js +126 -37
- package/helpers/package.json +1 -1
- package/lib/cache.js +18 -9
- package/lib/markdownlint.d.ts +28 -12
- package/lib/markdownlint.js +185 -62
- package/lib/md002.js +1 -1
- package/lib/md004.js +46 -13
- package/lib/md006.js +1 -1
- package/lib/md009.js +25 -23
- package/lib/md010.js +5 -1
- package/lib/md011.js +31 -27
- package/lib/md018.js +1 -1
- package/lib/md019.js +1 -1
- package/lib/md020.js +1 -1
- package/lib/md021.js +1 -1
- package/lib/md023.js +1 -1
- package/lib/md025.js +1 -1
- package/lib/md026.js +7 -4
- package/lib/md028.js +1 -9
- package/lib/md032.js +2 -2
- package/lib/md037.js +35 -9
- package/lib/md039.js +2 -2
- package/lib/md041.js +14 -3
- package/lib/md043.js +27 -11
- package/lib/md044.js +54 -71
- package/lib/rules.js +2 -1
- package/package.json +39 -32
- package/schema/.markdownlint.jsonc +252 -0
- package/schema/.markdownlint.yaml +227 -0
- package/schema/markdownlint-config-schema.json +36 -23
- package/schema/build-config-schema.js +0 -409
package/lib/markdownlint.js
CHANGED
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const fs = require("fs");
|
|
6
5
|
const path = require("path");
|
|
7
|
-
const
|
|
6
|
+
const { promisify } = require("util");
|
|
8
7
|
const markdownIt = require("markdown-it");
|
|
9
8
|
const rules = require("./rules");
|
|
10
9
|
const helpers = require("../helpers");
|
|
11
10
|
const cache = require("./cache");
|
|
12
11
|
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
// eslint-disable-next-line camelcase, max-len, no-inline-comments, no-undef
|
|
14
|
+
const dynamicRequire = (typeof __non_webpack_require__ === "undefined") ? require : /* c8 ignore next */ __non_webpack_require__;
|
|
15
|
+
// Capture native require implementation for dynamic loading of modules
|
|
16
|
+
|
|
13
17
|
const deprecatedRuleNames = [ "MD002", "MD006" ];
|
|
14
18
|
|
|
15
19
|
/**
|
|
@@ -51,10 +55,12 @@ function validateRuleList(ruleList) {
|
|
|
51
55
|
result = newError(property);
|
|
52
56
|
}
|
|
53
57
|
});
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
if (
|
|
59
|
+
!result &&
|
|
60
|
+
rule.information &&
|
|
61
|
+
(Object.getPrototypeOf(rule.information) !== URL.prototype)
|
|
62
|
+
) {
|
|
63
|
+
result = newError("information");
|
|
58
64
|
}
|
|
59
65
|
if (!result) {
|
|
60
66
|
rule.names.forEach(function forName(name) {
|
|
@@ -176,18 +182,27 @@ function removeFrontMatter(content, frontMatter) {
|
|
|
176
182
|
* @returns {void}
|
|
177
183
|
*/
|
|
178
184
|
function annotateTokens(tokens, lines) {
|
|
179
|
-
let
|
|
185
|
+
let tableMap = null;
|
|
180
186
|
tokens.forEach(function forToken(token) {
|
|
181
|
-
// Handle missing maps for table body
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
// Handle missing maps for table head/body
|
|
188
|
+
if (
|
|
189
|
+
(token.type === "thead_open") ||
|
|
190
|
+
(token.type === "tbody_open")
|
|
191
|
+
) {
|
|
192
|
+
tableMap = [ ...token.map ];
|
|
193
|
+
} else if (
|
|
194
|
+
(token.type === "tr_close") &&
|
|
195
|
+
tableMap
|
|
196
|
+
) {
|
|
197
|
+
tableMap[0]++;
|
|
198
|
+
} else if (
|
|
199
|
+
(token.type === "thead_close") ||
|
|
200
|
+
(token.type === "tbody_close")
|
|
201
|
+
) {
|
|
202
|
+
tableMap = null;
|
|
188
203
|
}
|
|
189
|
-
if (
|
|
190
|
-
token.map =
|
|
204
|
+
if (tableMap && !token.map) {
|
|
205
|
+
token.map = [ ...tableMap ];
|
|
191
206
|
}
|
|
192
207
|
// Update token metadata
|
|
193
208
|
if (token.map) {
|
|
@@ -322,13 +337,13 @@ function getEnabledRulesPerLineNumber(
|
|
|
322
337
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
323
338
|
function handleInlineConfig(perLine, forEachMatch, forEachLine) {
|
|
324
339
|
const input = perLine ? lines : [ lines.join("\n") ];
|
|
325
|
-
input.forEach((line) => {
|
|
340
|
+
input.forEach((line, lineIndex) => {
|
|
326
341
|
if (!noInlineConfig) {
|
|
327
342
|
let match = null;
|
|
328
343
|
while ((match = helpers.inlineCommentRe.exec(line))) {
|
|
329
344
|
const action = (match[1] || match[3]).toUpperCase();
|
|
330
345
|
const parameter = match[2] || match[4];
|
|
331
|
-
forEachMatch(action, parameter);
|
|
346
|
+
forEachMatch(action, parameter, lineIndex + 1);
|
|
332
347
|
}
|
|
333
348
|
}
|
|
334
349
|
if (forEachLine) {
|
|
@@ -351,21 +366,21 @@ function getEnabledRulesPerLineNumber(
|
|
|
351
366
|
}
|
|
352
367
|
}
|
|
353
368
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
354
|
-
function applyEnableDisable(action, parameter) {
|
|
369
|
+
function applyEnableDisable(action, parameter, state) {
|
|
355
370
|
const enabled = (action.startsWith("ENABLE"));
|
|
356
371
|
const items = parameter ?
|
|
357
372
|
parameter.trim().toUpperCase().split(/\s+/) :
|
|
358
373
|
allRuleNames;
|
|
359
374
|
items.forEach((nameUpper) => {
|
|
360
375
|
(aliasToRuleNames[nameUpper] || []).forEach((ruleName) => {
|
|
361
|
-
|
|
376
|
+
state[ruleName] = enabled;
|
|
362
377
|
});
|
|
363
378
|
});
|
|
364
379
|
}
|
|
365
380
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
366
381
|
function enableDisableFile(action, parameter) {
|
|
367
382
|
if ((action === "ENABLE-FILE") || (action === "DISABLE-FILE")) {
|
|
368
|
-
applyEnableDisable(action, parameter);
|
|
383
|
+
applyEnableDisable(action, parameter, enabledRules);
|
|
369
384
|
}
|
|
370
385
|
}
|
|
371
386
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -376,12 +391,22 @@ function getEnabledRulesPerLineNumber(
|
|
|
376
391
|
enabledRules = { ...capturedRules };
|
|
377
392
|
} else if ((action === "ENABLE") || (action === "DISABLE")) {
|
|
378
393
|
enabledRules = { ...enabledRules };
|
|
379
|
-
applyEnableDisable(action, parameter);
|
|
394
|
+
applyEnableDisable(action, parameter, enabledRules);
|
|
380
395
|
}
|
|
381
396
|
}
|
|
382
397
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
383
398
|
function updateLineState() {
|
|
384
|
-
enabledRulesPerLineNumber.push(enabledRules);
|
|
399
|
+
enabledRulesPerLineNumber.push({ ...enabledRules });
|
|
400
|
+
}
|
|
401
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
402
|
+
function disableNextLine(action, parameter, lineNumber) {
|
|
403
|
+
if (action === "DISABLE-NEXT-LINE") {
|
|
404
|
+
applyEnableDisable(
|
|
405
|
+
action,
|
|
406
|
+
parameter,
|
|
407
|
+
enabledRulesPerLineNumber[lineNumber + 1] || {}
|
|
408
|
+
);
|
|
409
|
+
}
|
|
385
410
|
}
|
|
386
411
|
// Handle inline comments
|
|
387
412
|
handleInlineConfig(false, configureFile);
|
|
@@ -395,6 +420,7 @@ function getEnabledRulesPerLineNumber(
|
|
|
395
420
|
capturedRules = enabledRules;
|
|
396
421
|
handleInlineConfig(true, enableDisableFile);
|
|
397
422
|
handleInlineConfig(true, captureRestoreEnableDisable, updateLineState);
|
|
423
|
+
handleInlineConfig(true, disableNextLine);
|
|
398
424
|
// Return results
|
|
399
425
|
return {
|
|
400
426
|
effectiveConfig,
|
|
@@ -439,8 +465,8 @@ function uniqueFilterForSortedErrors(value, index, array) {
|
|
|
439
465
|
*
|
|
440
466
|
* @param {Rule[]} ruleList List of rules.
|
|
441
467
|
* @param {string} name Identifier for the content.
|
|
442
|
-
* @param {string} content Markdown content
|
|
443
|
-
* @param {Object} md markdown-it
|
|
468
|
+
* @param {string} content Markdown content.
|
|
469
|
+
* @param {Object} md Instance of markdown-it.
|
|
444
470
|
* @param {Configuration} config Configuration object.
|
|
445
471
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
|
446
472
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
|
@@ -489,7 +515,8 @@ function lintContent(
|
|
|
489
515
|
frontMatterLines
|
|
490
516
|
};
|
|
491
517
|
cache.lineMetadata(helpers.getLineMetadata(params));
|
|
492
|
-
cache.flattenedLists(helpers.flattenLists(params));
|
|
518
|
+
cache.flattenedLists(helpers.flattenLists(params.tokens));
|
|
519
|
+
cache.inlineCodeSpanRanges(helpers.inlineCodeSpanRanges(params.lines));
|
|
493
520
|
// Function to run for each rule
|
|
494
521
|
const result = (resultVersion === 0) ? {} : [];
|
|
495
522
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -651,12 +678,13 @@ function lintContent(
|
|
|
651
678
|
*
|
|
652
679
|
* @param {Rule[]} ruleList List of rules.
|
|
653
680
|
* @param {string} file Path of file to lint.
|
|
654
|
-
* @param {Object} md markdown-it
|
|
681
|
+
* @param {Object} md Instance of markdown-it.
|
|
655
682
|
* @param {Configuration} config Configuration object.
|
|
656
683
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
|
657
684
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
|
658
685
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
|
659
686
|
* @param {number} resultVersion Version of the LintResults object to return.
|
|
687
|
+
* @param {Object} fs File system implementation.
|
|
660
688
|
* @param {boolean} synchronous Whether to execute synchronously.
|
|
661
689
|
* @param {Function} callback Callback (err, result) function.
|
|
662
690
|
* @returns {void}
|
|
@@ -670,6 +698,7 @@ function lintFile(
|
|
|
670
698
|
handleRuleFailures,
|
|
671
699
|
noInlineConfig,
|
|
672
700
|
resultVersion,
|
|
701
|
+
fs,
|
|
673
702
|
synchronous,
|
|
674
703
|
callback) {
|
|
675
704
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -682,10 +711,9 @@ function lintFile(
|
|
|
682
711
|
}
|
|
683
712
|
// Make a/synchronous call to read file
|
|
684
713
|
if (synchronous) {
|
|
685
|
-
|
|
686
|
-
lintContentWrapper(null, fs.readFileSync(file, helpers.utf8Encoding));
|
|
714
|
+
lintContentWrapper(null, fs.readFileSync(file, "utf8"));
|
|
687
715
|
} else {
|
|
688
|
-
fs.readFile(file,
|
|
716
|
+
fs.readFile(file, "utf8", lintContentWrapper);
|
|
689
717
|
}
|
|
690
718
|
}
|
|
691
719
|
|
|
@@ -701,6 +729,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
701
729
|
// Normalize inputs
|
|
702
730
|
options = options || {};
|
|
703
731
|
callback = callback || function noop() {};
|
|
732
|
+
// eslint-disable-next-line unicorn/prefer-spread
|
|
704
733
|
const ruleList = rules.concat(options.customRules || []);
|
|
705
734
|
const ruleErr = validateRuleList(ruleList);
|
|
706
735
|
if (ruleErr) {
|
|
@@ -708,7 +737,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
708
737
|
}
|
|
709
738
|
let files = [];
|
|
710
739
|
if (Array.isArray(options.files)) {
|
|
711
|
-
files = options.files
|
|
740
|
+
files = [ ...options.files ];
|
|
712
741
|
} else if (options.files) {
|
|
713
742
|
files = [ String(options.files) ];
|
|
714
743
|
}
|
|
@@ -727,6 +756,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
727
756
|
// @ts-ignore
|
|
728
757
|
md.use(...plugin);
|
|
729
758
|
});
|
|
759
|
+
const fs = options.fs || require("fs");
|
|
730
760
|
const results = newResults(ruleList);
|
|
731
761
|
let done = false;
|
|
732
762
|
// Linting of strings is always synchronous
|
|
@@ -766,6 +796,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
766
796
|
handleRuleFailures,
|
|
767
797
|
noInlineConfig,
|
|
768
798
|
resultVersion,
|
|
799
|
+
fs,
|
|
769
800
|
synchronous,
|
|
770
801
|
syncCallback
|
|
771
802
|
);
|
|
@@ -790,6 +821,7 @@ function lintInput(options, synchronous, callback) {
|
|
|
790
821
|
handleRuleFailures,
|
|
791
822
|
noInlineConfig,
|
|
792
823
|
resultVersion,
|
|
824
|
+
fs,
|
|
793
825
|
synchronous,
|
|
794
826
|
(err, result) => {
|
|
795
827
|
concurrency--;
|
|
@@ -833,7 +865,7 @@ function markdownlint(options, callback) {
|
|
|
833
865
|
return lintInput(options, false, callback);
|
|
834
866
|
}
|
|
835
867
|
|
|
836
|
-
const markdownlintPromisify =
|
|
868
|
+
const markdownlintPromisify = promisify && promisify(markdownlint);
|
|
837
869
|
|
|
838
870
|
/**
|
|
839
871
|
* Lint specified Markdown files.
|
|
@@ -894,23 +926,91 @@ function parseConfiguration(name, content, parsers) {
|
|
|
894
926
|
};
|
|
895
927
|
}
|
|
896
928
|
|
|
929
|
+
/**
|
|
930
|
+
* Resolve referenced "extends" path in a configuration file
|
|
931
|
+
* using path.resolve() with require.resolve() as a fallback.
|
|
932
|
+
*
|
|
933
|
+
* @param {string} configFile Configuration file name.
|
|
934
|
+
* @param {string} referenceId Referenced identifier to resolve.
|
|
935
|
+
* @param {Object} fs File system implementation.
|
|
936
|
+
* @param {ResolveConfigExtendsCallback} [callback] Callback (err, result)
|
|
937
|
+
* function.
|
|
938
|
+
* @returns {void}
|
|
939
|
+
*/
|
|
940
|
+
function resolveConfigExtends(configFile, referenceId, fs, callback) {
|
|
941
|
+
const configFileDirname = path.dirname(configFile);
|
|
942
|
+
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
|
943
|
+
fs.access(resolvedExtendsFile, (err) => {
|
|
944
|
+
if (err) {
|
|
945
|
+
// Not a file, try require.resolve
|
|
946
|
+
try {
|
|
947
|
+
return callback(null, dynamicRequire.resolve(
|
|
948
|
+
referenceId,
|
|
949
|
+
{ "paths": [ configFileDirname ] }
|
|
950
|
+
));
|
|
951
|
+
} catch {
|
|
952
|
+
// Unable to resolve, use resolvedExtendsFile
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return callback(null, resolvedExtendsFile);
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* Resolve referenced "extends" path in a configuration file
|
|
961
|
+
* using path.resolve() with require.resolve() as a fallback.
|
|
962
|
+
*
|
|
963
|
+
* @param {string} configFile Configuration file name.
|
|
964
|
+
* @param {string} referenceId Referenced identifier to resolve.
|
|
965
|
+
* @param {Object} fs File system implementation.
|
|
966
|
+
* @returns {string} Resolved path to file.
|
|
967
|
+
*/
|
|
968
|
+
function resolveConfigExtendsSync(configFile, referenceId, fs) {
|
|
969
|
+
const configFileDirname = path.dirname(configFile);
|
|
970
|
+
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
|
971
|
+
try {
|
|
972
|
+
fs.accessSync(resolvedExtendsFile);
|
|
973
|
+
return resolvedExtendsFile;
|
|
974
|
+
} catch {
|
|
975
|
+
// Not a file, try require.resolve
|
|
976
|
+
}
|
|
977
|
+
try {
|
|
978
|
+
return dynamicRequire.resolve(
|
|
979
|
+
referenceId,
|
|
980
|
+
{ "paths": [ configFileDirname ] }
|
|
981
|
+
);
|
|
982
|
+
} catch {
|
|
983
|
+
// Unable to resolve, return resolvedExtendsFile
|
|
984
|
+
}
|
|
985
|
+
return resolvedExtendsFile;
|
|
986
|
+
}
|
|
987
|
+
|
|
897
988
|
/**
|
|
898
989
|
* Read specified configuration file.
|
|
899
990
|
*
|
|
900
991
|
* @param {string} file Configuration file name.
|
|
901
992
|
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
|
|
902
993
|
* function(s).
|
|
994
|
+
* @param {Object} [fs] File system implementation.
|
|
903
995
|
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
|
904
996
|
* @returns {void}
|
|
905
997
|
*/
|
|
906
|
-
function readConfig(file, parsers, callback) {
|
|
998
|
+
function readConfig(file, parsers, fs, callback) {
|
|
907
999
|
if (!callback) {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1000
|
+
if (fs) {
|
|
1001
|
+
callback = fs;
|
|
1002
|
+
fs = null;
|
|
1003
|
+
} else {
|
|
1004
|
+
// @ts-ignore
|
|
1005
|
+
callback = parsers;
|
|
1006
|
+
parsers = null;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (!fs) {
|
|
1010
|
+
fs = require("fs");
|
|
911
1011
|
}
|
|
912
1012
|
// Read file
|
|
913
|
-
fs.readFile(file,
|
|
1013
|
+
fs.readFile(file, "utf8", (err, content) => {
|
|
914
1014
|
if (err) {
|
|
915
1015
|
return callback(err);
|
|
916
1016
|
}
|
|
@@ -924,33 +1024,43 @@ function readConfig(file, parsers, callback) {
|
|
|
924
1024
|
const configExtends = config.extends;
|
|
925
1025
|
if (configExtends) {
|
|
926
1026
|
delete config.extends;
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1027
|
+
return resolveConfigExtends(
|
|
1028
|
+
file,
|
|
1029
|
+
configExtends,
|
|
1030
|
+
fs,
|
|
1031
|
+
(_, resolvedExtends) => readConfig(
|
|
1032
|
+
resolvedExtends,
|
|
1033
|
+
parsers,
|
|
1034
|
+
fs,
|
|
1035
|
+
(errr, extendsConfig) => {
|
|
1036
|
+
if (errr) {
|
|
1037
|
+
return callback(errr);
|
|
1038
|
+
}
|
|
1039
|
+
return callback(null, {
|
|
1040
|
+
...extendsConfig,
|
|
1041
|
+
...config
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
)
|
|
1045
|
+
);
|
|
937
1046
|
}
|
|
938
1047
|
return callback(null, config);
|
|
939
1048
|
});
|
|
940
1049
|
}
|
|
941
1050
|
|
|
942
|
-
const readConfigPromisify =
|
|
1051
|
+
const readConfigPromisify = promisify && promisify(readConfig);
|
|
943
1052
|
|
|
944
1053
|
/**
|
|
945
1054
|
* Read specified configuration file.
|
|
946
1055
|
*
|
|
947
1056
|
* @param {string} file Configuration file name.
|
|
948
1057
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
|
1058
|
+
* @param {Object} [fs] File system implementation.
|
|
949
1059
|
* @returns {Promise<Configuration>} Configuration object.
|
|
950
1060
|
*/
|
|
951
|
-
function readConfigPromise(file, parsers) {
|
|
1061
|
+
function readConfigPromise(file, parsers, fs) {
|
|
952
1062
|
// @ts-ignore
|
|
953
|
-
return readConfigPromisify(file, parsers);
|
|
1063
|
+
return readConfigPromisify(file, parsers, fs);
|
|
954
1064
|
}
|
|
955
1065
|
|
|
956
1066
|
/**
|
|
@@ -958,12 +1068,16 @@ function readConfigPromise(file, parsers) {
|
|
|
958
1068
|
*
|
|
959
1069
|
* @param {string} file Configuration file name.
|
|
960
1070
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
|
1071
|
+
* @param {Object} [fs] File system implementation.
|
|
961
1072
|
* @returns {Configuration} Configuration object.
|
|
1073
|
+
* @throws An Error if processing fails.
|
|
962
1074
|
*/
|
|
963
|
-
function readConfigSync(file, parsers) {
|
|
1075
|
+
function readConfigSync(file, parsers, fs) {
|
|
1076
|
+
if (!fs) {
|
|
1077
|
+
fs = require("fs");
|
|
1078
|
+
}
|
|
964
1079
|
// Read file
|
|
965
|
-
|
|
966
|
-
const content = fs.readFileSync(file, helpers.utf8Encoding);
|
|
1080
|
+
const content = fs.readFileSync(file, "utf8");
|
|
967
1081
|
// Try to parse file
|
|
968
1082
|
const { config, message } = parseConfiguration(file, content, parsers);
|
|
969
1083
|
if (!config) {
|
|
@@ -973,11 +1087,9 @@ function readConfigSync(file, parsers) {
|
|
|
973
1087
|
const configExtends = config.extends;
|
|
974
1088
|
if (configExtends) {
|
|
975
1089
|
delete config.extends;
|
|
1090
|
+
const resolvedExtends = resolveConfigExtendsSync(file, configExtends, fs);
|
|
976
1091
|
return {
|
|
977
|
-
...readConfigSync(
|
|
978
|
-
path.resolve(path.dirname(file), configExtends),
|
|
979
|
-
parsers
|
|
980
|
-
),
|
|
1092
|
+
...readConfigSync(resolvedExtends, parsers, fs),
|
|
981
1093
|
...config
|
|
982
1094
|
};
|
|
983
1095
|
}
|
|
@@ -1020,7 +1132,7 @@ module.exports = markdownlint;
|
|
|
1020
1132
|
*
|
|
1021
1133
|
* @typedef {Object} RuleParams
|
|
1022
1134
|
* @property {string} name File/string name.
|
|
1023
|
-
* @property {MarkdownItToken[]} tokens markdown-it
|
|
1135
|
+
* @property {MarkdownItToken[]} tokens Token objects from markdown-it.
|
|
1024
1136
|
* @property {string[]} lines File/string lines.
|
|
1025
1137
|
* @property {string[]} frontMatterLines Front matter lines.
|
|
1026
1138
|
* @property {RuleConfiguration} config Rule configuration.
|
|
@@ -1100,10 +1212,11 @@ module.exports = markdownlint;
|
|
|
1100
1212
|
* @property {boolean} [noInlineConfig] True to ignore HTML directives.
|
|
1101
1213
|
* @property {number} [resultVersion] Results object version.
|
|
1102
1214
|
* @property {Plugin[]} [markdownItPlugins] Additional plugins.
|
|
1215
|
+
* @property {Object} [fs] File system implementation.
|
|
1103
1216
|
*/
|
|
1104
1217
|
|
|
1105
1218
|
/**
|
|
1106
|
-
* markdown-it plugin.
|
|
1219
|
+
* A markdown-it plugin.
|
|
1107
1220
|
*
|
|
1108
1221
|
* @typedef {Array} Plugin
|
|
1109
1222
|
*/
|
|
@@ -1134,20 +1247,21 @@ module.exports = markdownlint;
|
|
|
1134
1247
|
* @property {string} errorDetail Detail about the error.
|
|
1135
1248
|
* @property {string} errorContext Context for the error.
|
|
1136
1249
|
* @property {number[]} errorRange Column number (1-based) and length.
|
|
1137
|
-
* @property {FixInfo} fixInfo Fix information.
|
|
1250
|
+
* @property {FixInfo} [fixInfo] Fix information.
|
|
1138
1251
|
*/
|
|
1139
1252
|
|
|
1140
1253
|
/**
|
|
1141
1254
|
* Fix information.
|
|
1142
1255
|
*
|
|
1143
1256
|
* @typedef {Object} FixInfo
|
|
1257
|
+
* @property {number} [lineNumber] Line number (1-based).
|
|
1144
1258
|
* @property {number} [editColumn] Column of the fix (1-based).
|
|
1145
1259
|
* @property {number} [deleteCount] Count of characters to delete.
|
|
1146
1260
|
* @property {string} [insertText] Text to insert (after deleting).
|
|
1147
1261
|
*/
|
|
1148
1262
|
|
|
1149
1263
|
/**
|
|
1150
|
-
* Called with the result of the lint
|
|
1264
|
+
* Called with the result of the lint function.
|
|
1151
1265
|
*
|
|
1152
1266
|
* @callback LintCallback
|
|
1153
1267
|
* @param {Error | null} err Error object or null.
|
|
@@ -1177,10 +1291,19 @@ module.exports = markdownlint;
|
|
|
1177
1291
|
*/
|
|
1178
1292
|
|
|
1179
1293
|
/**
|
|
1180
|
-
* Called with the result of the readConfig
|
|
1294
|
+
* Called with the result of the readConfig function.
|
|
1181
1295
|
*
|
|
1182
1296
|
* @callback ReadConfigCallback
|
|
1183
1297
|
* @param {Error | null} err Error object or null.
|
|
1184
1298
|
* @param {Configuration} [config] Configuration object.
|
|
1185
1299
|
* @returns {void}
|
|
1186
1300
|
*/
|
|
1301
|
+
|
|
1302
|
+
/**
|
|
1303
|
+
* Called with the result of the resolveConfigExtends function.
|
|
1304
|
+
*
|
|
1305
|
+
* @callback ResolveConfigExtendsCallback
|
|
1306
|
+
* @param {Error | null} err Error object or null.
|
|
1307
|
+
* @param {string} [path] Resolved path to file.
|
|
1308
|
+
* @returns {void}
|
|
1309
|
+
*/
|
package/lib/md002.js
CHANGED
|
@@ -6,7 +6,7 @@ const { addErrorDetailIf } = require("../helpers");
|
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
"names": [ "MD002", "first-heading-h1", "first-header-h1" ],
|
|
9
|
-
"description": "First heading should be a top
|
|
9
|
+
"description": "First heading should be a top-level heading",
|
|
10
10
|
"tags": [ "headings", "headers" ],
|
|
11
11
|
"function": function MD002(params, onError) {
|
|
12
12
|
const level = Number(params.config.level || 1);
|
package/lib/md004.js
CHANGED
|
@@ -2,10 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorDetailIf, listItemMarkerRe,
|
|
6
|
-
|
|
5
|
+
const { addErrorDetailIf, listItemMarkerRe, unorderedListStyleFor } =
|
|
6
|
+
require("../helpers");
|
|
7
7
|
const { flattenedLists } = require("./cache");
|
|
8
8
|
|
|
9
|
+
const expectedStyleToMarker = {
|
|
10
|
+
"dash": "-",
|
|
11
|
+
"plus": "+",
|
|
12
|
+
"asterisk": "*"
|
|
13
|
+
};
|
|
14
|
+
const differentItemStyle = {
|
|
15
|
+
"dash": "plus",
|
|
16
|
+
"plus": "asterisk",
|
|
17
|
+
"asterisk": "dash"
|
|
18
|
+
};
|
|
19
|
+
const validStyles = Object.keys(expectedStyleToMarker);
|
|
20
|
+
|
|
9
21
|
module.exports = {
|
|
10
22
|
"names": [ "MD004", "ul-style" ],
|
|
11
23
|
"description": "Unordered list style",
|
|
@@ -23,19 +35,40 @@ module.exports = {
|
|
|
23
35
|
const itemStyle = unorderedListStyleFor(item);
|
|
24
36
|
if (style === "sublist") {
|
|
25
37
|
const nesting = list.nesting;
|
|
26
|
-
if (!nestingStyles[nesting]
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
nestingStyles[nesting], itemStyle, null, null,
|
|
32
|
-
rangeFromRegExp(item.line, listItemMarkerRe));
|
|
38
|
+
if (!nestingStyles[nesting]) {
|
|
39
|
+
nestingStyles[nesting] =
|
|
40
|
+
(itemStyle === nestingStyles[nesting - 1]) ?
|
|
41
|
+
differentItemStyle[itemStyle] :
|
|
42
|
+
itemStyle;
|
|
33
43
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
expectedStyle = nestingStyles[nesting];
|
|
45
|
+
}
|
|
46
|
+
if (!validStyles.includes(expectedStyle)) {
|
|
47
|
+
expectedStyle = validStyles[0];
|
|
48
|
+
}
|
|
49
|
+
let range = null;
|
|
50
|
+
let fixInfo = null;
|
|
51
|
+
const match = item.line.match(listItemMarkerRe);
|
|
52
|
+
if (match) {
|
|
53
|
+
const column = match.index + 1;
|
|
54
|
+
const length = match[0].length;
|
|
55
|
+
range = [ column, length ];
|
|
56
|
+
fixInfo = {
|
|
57
|
+
"editColumn": match[1].length + 1,
|
|
58
|
+
"deleteCount": 1,
|
|
59
|
+
"insertText": expectedStyleToMarker[expectedStyle]
|
|
60
|
+
};
|
|
38
61
|
}
|
|
62
|
+
addErrorDetailIf(
|
|
63
|
+
onError,
|
|
64
|
+
item.lineNumber,
|
|
65
|
+
expectedStyle,
|
|
66
|
+
itemStyle,
|
|
67
|
+
null,
|
|
68
|
+
null,
|
|
69
|
+
range,
|
|
70
|
+
fixInfo
|
|
71
|
+
);
|
|
39
72
|
});
|
|
40
73
|
}
|
|
41
74
|
});
|
package/lib/md006.js
CHANGED
package/lib/md009.js
CHANGED
|
@@ -47,30 +47,32 @@ module.exports = {
|
|
|
47
47
|
codeInlineLineNumbers.sort(numericSortAscending);
|
|
48
48
|
}
|
|
49
49
|
const expected = (brSpaces < 2) ? 0 : brSpaces;
|
|
50
|
-
|
|
51
|
-
forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence) => {
|
|
52
|
-
inFencedCode += onFence;
|
|
50
|
+
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
53
51
|
const lineNumber = lineIndex + 1;
|
|
54
|
-
const trailingSpaces = line.length - line.
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
52
|
+
const trailingSpaces = line.length - line.trimEnd().length;
|
|
53
|
+
if (
|
|
54
|
+
trailingSpaces &&
|
|
55
|
+
!inCode &&
|
|
56
|
+
!includesSorted(listItemLineNumbers, lineNumber) &&
|
|
57
|
+
(
|
|
58
|
+
(expected !== trailingSpaces) ||
|
|
59
|
+
(strict &&
|
|
60
|
+
(!includesSorted(paragraphLineNumbers, lineNumber) ||
|
|
61
|
+
includesSorted(codeInlineLineNumbers, lineNumber)))
|
|
62
|
+
)
|
|
63
|
+
) {
|
|
64
|
+
const column = line.length - trailingSpaces + 1;
|
|
65
|
+
addError(
|
|
66
|
+
onError,
|
|
67
|
+
lineNumber,
|
|
68
|
+
"Expected: " + (expected === 0 ? "" : "0 or ") +
|
|
69
|
+
expected + "; Actual: " + trailingSpaces,
|
|
70
|
+
null,
|
|
71
|
+
[ column, trailingSpaces ],
|
|
72
|
+
{
|
|
73
|
+
"editColumn": column,
|
|
74
|
+
"deleteCount": trailingSpaces
|
|
75
|
+
});
|
|
74
76
|
}
|
|
75
77
|
});
|
|
76
78
|
}
|
package/lib/md010.js
CHANGED
|
@@ -14,6 +14,10 @@ module.exports = {
|
|
|
14
14
|
"function": function MD010(params, onError) {
|
|
15
15
|
const codeBlocks = params.config.code_blocks;
|
|
16
16
|
const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
17
|
+
const spacesPerTab = params.config.spaces_per_tab;
|
|
18
|
+
const spaceMultiplier = (spacesPerTab === undefined) ?
|
|
19
|
+
1 :
|
|
20
|
+
Math.max(0, Number(spacesPerTab));
|
|
17
21
|
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
|
18
22
|
if (!inCode || includeCodeBlocks) {
|
|
19
23
|
let match = null;
|
|
@@ -29,7 +33,7 @@ module.exports = {
|
|
|
29
33
|
{
|
|
30
34
|
"editColumn": column,
|
|
31
35
|
"deleteCount": length,
|
|
32
|
-
"insertText": "".padEnd(length)
|
|
36
|
+
"insertText": "".padEnd(length * spaceMultiplier)
|
|
33
37
|
});
|
|
34
38
|
}
|
|
35
39
|
}
|