mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-17 06:20:12 +01:00
Allow custom file system implementation to be passed when linting or reading configuration.
This commit is contained in:
parent
b10147f16b
commit
211f09afbc
6 changed files with 277 additions and 52 deletions
|
|
@ -39,7 +39,7 @@
|
||||||
"max-depth": "off",
|
"max-depth": "off",
|
||||||
"max-lines": "off",
|
"max-lines": "off",
|
||||||
"max-lines-per-function": "off",
|
"max-lines-per-function": "off",
|
||||||
"max-params": ["error", 10],
|
"max-params": ["off"],
|
||||||
"max-statements": "off",
|
"max-statements": "off",
|
||||||
"multiline-comment-style": ["error", "separate-lines"],
|
"multiline-comment-style": ["error", "separate-lines"],
|
||||||
"multiline-ternary": "off",
|
"multiline-ternary": "off",
|
||||||
|
|
|
||||||
34
README.md
34
README.md
|
|
@ -294,7 +294,8 @@ function markdownlint(options) { ... }
|
||||||
|
|
||||||
Type: `Object`
|
Type: `Object`
|
||||||
|
|
||||||
Configures the function.
|
Configures the function. All properties are optional, but at least one
|
||||||
|
of `files` or `strings` should be set to provide input.
|
||||||
|
|
||||||
##### options.customRules
|
##### options.customRules
|
||||||
|
|
||||||
|
|
@ -534,6 +535,16 @@ Each item in the top-level `Array` should be of the form:
|
||||||
[ require("markdown-it-plugin"), plugin_param_0, plugin_param_1, ... ]
|
[ require("markdown-it-plugin"), plugin_param_0, plugin_param_1, ... ]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### options.fs
|
||||||
|
|
||||||
|
Type: `Object` implementing the [file system API](https://nodejs.org/api/fs.html)
|
||||||
|
|
||||||
|
In advanced scenarios, it may be desirable to bypass the default file system API.
|
||||||
|
If a custom file system implementation is provided, `markdownlint` will use that
|
||||||
|
instead of invoking `require("fs")`.
|
||||||
|
|
||||||
|
Note: The only methods called are `readFile` and `readFileSync`.
|
||||||
|
|
||||||
#### callback
|
#### callback
|
||||||
|
|
||||||
Type: `Function` taking (`Error`, `Object`)
|
Type: `Function` taking (`Error`, `Object`)
|
||||||
|
|
@ -566,10 +577,11 @@ Asynchronous API:
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing function(s).
|
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function readConfig(file, parsers, callback) { ... }
|
function readConfig(file, parsers, fs, callback) { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
Synchronous API:
|
Synchronous API:
|
||||||
|
|
@ -580,13 +592,14 @@ Synchronous API:
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Configuration} Configuration object.
|
* @returns {Configuration} Configuration object.
|
||||||
*/
|
*/
|
||||||
function readConfigSync(file, parsers) { ... }
|
function readConfigSync(file, parsers, fs) { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
Promise API (in the `promises` namespace like Node.js's
|
Promise API (in the `promises` namespace like Node.js's
|
||||||
[`fs` Promises API](https://nodejs.org/api/fs.html#fs_fs_promises_api)):
|
[`fs` Promises API](https://nodejs.org/api/fs.html#fs_promises_api)):
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/**
|
/**
|
||||||
|
|
@ -594,9 +607,10 @@ Promise API (in the `promises` namespace like Node.js's
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Promise<Configuration>} Configuration object.
|
* @returns {Promise<Configuration>} Configuration object.
|
||||||
*/
|
*/
|
||||||
function readConfig(file, parsers) { ... }
|
function readConfig(file, parsers, fs) { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
#### file
|
#### file
|
||||||
|
|
@ -627,6 +641,16 @@ For example:
|
||||||
[ JSON.parse, require("toml").parse, require("js-yaml").load ]
|
[ JSON.parse, require("toml").parse, require("js-yaml").load ]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### fs
|
||||||
|
|
||||||
|
Type: *Optional* `Object` implementing the [file system API](https://nodejs.org/api/fs.html)
|
||||||
|
|
||||||
|
In advanced scenarios, it may be desirable to bypass the default file system API.
|
||||||
|
If a custom file system implementation is provided, `markdownlint` will use that
|
||||||
|
instead of invoking `require("fs")`.
|
||||||
|
|
||||||
|
Note: The only methods called are `readFile`, `readFileSync`, and `accessSync`.
|
||||||
|
|
||||||
#### callback
|
#### callback
|
||||||
|
|
||||||
Type: `Function` taking (`Error`, `Object`)
|
Type: `Function` taking (`Error`, `Object`)
|
||||||
|
|
|
||||||
|
|
@ -813,7 +813,6 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
||||||
to[j] = from[i];
|
to[j] = from[i];
|
||||||
return to;
|
return to;
|
||||||
};
|
};
|
||||||
var fs = __webpack_require__(/*! fs */ "?ec0a");
|
|
||||||
var path = __webpack_require__(/*! path */ "?b85c");
|
var path = __webpack_require__(/*! path */ "?b85c");
|
||||||
var promisify = __webpack_require__(/*! util */ "?96a2").promisify;
|
var promisify = __webpack_require__(/*! util */ "?96a2").promisify;
|
||||||
var markdownIt = __webpack_require__(/*! markdown-it */ "markdown-it");
|
var markdownIt = __webpack_require__(/*! markdown-it */ "markdown-it");
|
||||||
|
|
@ -1446,11 +1445,12 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
||||||
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
||||||
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
||||||
* @param {number} resultVersion Version of the LintResults object to return.
|
* @param {number} resultVersion Version of the LintResults object to return.
|
||||||
|
* @param {Object} fs File system implementation.
|
||||||
* @param {boolean} synchronous Whether to execute synchronously.
|
* @param {boolean} synchronous Whether to execute synchronously.
|
||||||
* @param {Function} callback Callback (err, result) function.
|
* @param {Function} callback Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function lintFile(ruleList, file, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, synchronous, callback) {
|
function lintFile(ruleList, file, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, callback) {
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
function lintContentWrapper(err, content) {
|
function lintContentWrapper(err, content) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -1460,7 +1460,6 @@ function lintFile(ruleList, file, md, config, frontMatter, handleRuleFailures, n
|
||||||
}
|
}
|
||||||
// Make a/synchronous call to read file
|
// Make a/synchronous call to read file
|
||||||
if (synchronous) {
|
if (synchronous) {
|
||||||
// @ts-ignore
|
|
||||||
lintContentWrapper(null, fs.readFileSync(file, "utf8"));
|
lintContentWrapper(null, fs.readFileSync(file, "utf8"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -1507,6 +1506,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
md.use.apply(md, plugin);
|
md.use.apply(md, plugin);
|
||||||
});
|
});
|
||||||
|
var fs = options.fs || __webpack_require__(/*! fs */ "?ec0a");
|
||||||
var results = newResults(ruleList);
|
var results = newResults(ruleList);
|
||||||
var done = false;
|
var done = false;
|
||||||
// Linting of strings is always synchronous
|
// Linting of strings is always synchronous
|
||||||
|
|
@ -1526,7 +1526,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
if (synchronous) {
|
if (synchronous) {
|
||||||
// Lint files synchronously
|
// Lint files synchronously
|
||||||
while (!done && (syncItem = files.shift())) {
|
while (!done && (syncItem = files.shift())) {
|
||||||
lintFile(ruleList, syncItem, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, synchronous, syncCallback);
|
lintFile(ruleList, syncItem, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, syncCallback);
|
||||||
}
|
}
|
||||||
return done || callback(null, results);
|
return done || callback(null, results);
|
||||||
}
|
}
|
||||||
|
|
@ -1540,7 +1540,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
}
|
}
|
||||||
else if (asyncItem) {
|
else if (asyncItem) {
|
||||||
concurrency++;
|
concurrency++;
|
||||||
lintFile(ruleList, asyncItem, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, synchronous, function (err, result) {
|
lintFile(ruleList, asyncItem, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, function (err, result) {
|
||||||
concurrency--;
|
concurrency--;
|
||||||
if (err) {
|
if (err) {
|
||||||
done = true;
|
done = true;
|
||||||
|
|
@ -1644,24 +1644,24 @@ function parseConfiguration(name, content, parsers) {
|
||||||
*
|
*
|
||||||
* @param {string} configFile Configuration file name.
|
* @param {string} configFile Configuration file name.
|
||||||
* @param {string} referenceId Referenced identifier to resolve.
|
* @param {string} referenceId Referenced identifier to resolve.
|
||||||
|
* @param {Object} fs File system implementation.
|
||||||
* @returns {string} Resolved path to file.
|
* @returns {string} Resolved path to file.
|
||||||
*/
|
*/
|
||||||
function resolveConfigExtends(configFile, referenceId) {
|
function resolveConfigExtends(configFile, referenceId, fs) {
|
||||||
var configFileDirname = path.dirname(configFile);
|
var configFileDirname = path.dirname(configFile);
|
||||||
var resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
var resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
||||||
try {
|
try {
|
||||||
if (fs.statSync(resolvedExtendsFile).isFile()) {
|
fs.accessSync(resolvedExtendsFile);
|
||||||
return resolvedExtendsFile;
|
return resolvedExtendsFile;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (_a) {
|
catch (_a) {
|
||||||
// If not a file or fs.statSync throws, try require.resolve
|
// Not a file, try require.resolve
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return dynamicRequire.resolve(referenceId, { "paths": [configFileDirname] });
|
return dynamicRequire.resolve(referenceId, { "paths": [configFileDirname] });
|
||||||
}
|
}
|
||||||
catch (_b) {
|
catch (_b) {
|
||||||
// If require.resolve throws, return resolvedExtendsFile
|
// Unable to resolve, return resolvedExtendsFile
|
||||||
}
|
}
|
||||||
return resolvedExtendsFile;
|
return resolvedExtendsFile;
|
||||||
}
|
}
|
||||||
|
|
@ -1671,15 +1671,25 @@ function resolveConfigExtends(configFile, referenceId) {
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
|
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
|
||||||
* function(s).
|
* function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function readConfig(file, parsers, callback) {
|
function readConfig(file, parsers, fs, callback) {
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
|
if (fs) {
|
||||||
|
callback = fs;
|
||||||
|
fs = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
callback = parsers;
|
callback = parsers;
|
||||||
parsers = null;
|
parsers = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!fs) {
|
||||||
|
fs = __webpack_require__(/*! fs */ "?ec0a");
|
||||||
|
}
|
||||||
// Read file
|
// Read file
|
||||||
fs.readFile(file, "utf8", function (err, content) {
|
fs.readFile(file, "utf8", function (err, content) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -1695,8 +1705,8 @@ function readConfig(file, parsers, callback) {
|
||||||
var configExtends = config["extends"];
|
var configExtends = config["extends"];
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config["extends"];
|
delete config["extends"];
|
||||||
var resolvedExtends = resolveConfigExtends(file, configExtends);
|
var resolvedExtends = resolveConfigExtends(file, configExtends, fs);
|
||||||
return readConfig(resolvedExtends, parsers, function (errr, extendsConfig) {
|
return readConfig(resolvedExtends, parsers, fs, function (errr, extendsConfig) {
|
||||||
if (errr) {
|
if (errr) {
|
||||||
return callback(errr);
|
return callback(errr);
|
||||||
}
|
}
|
||||||
|
|
@ -1712,22 +1722,26 @@ var readConfigPromisify = promisify && promisify(readConfig);
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Promise<Configuration>} Configuration object.
|
* @returns {Promise<Configuration>} Configuration object.
|
||||||
*/
|
*/
|
||||||
function readConfigPromise(file, parsers) {
|
function readConfigPromise(file, parsers, fs) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return readConfigPromisify(file, parsers);
|
return readConfigPromisify(file, parsers, fs);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Read specified configuration file synchronously.
|
* Read specified configuration file synchronously.
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Configuration} Configuration object.
|
* @returns {Configuration} Configuration object.
|
||||||
*/
|
*/
|
||||||
function readConfigSync(file, parsers) {
|
function readConfigSync(file, parsers, fs) {
|
||||||
|
if (!fs) {
|
||||||
|
fs = __webpack_require__(/*! fs */ "?ec0a");
|
||||||
|
}
|
||||||
// Read file
|
// Read file
|
||||||
// @ts-ignore
|
|
||||||
var content = fs.readFileSync(file, "utf8");
|
var content = fs.readFileSync(file, "utf8");
|
||||||
// Try to parse file
|
// Try to parse file
|
||||||
var _a = parseConfiguration(file, content, parsers), config = _a.config, message = _a.message;
|
var _a = parseConfiguration(file, content, parsers), config = _a.config, message = _a.message;
|
||||||
|
|
@ -1738,8 +1752,8 @@ function readConfigSync(file, parsers) {
|
||||||
var configExtends = config["extends"];
|
var configExtends = config["extends"];
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config["extends"];
|
delete config["extends"];
|
||||||
var resolvedExtends = resolveConfigExtends(file, configExtends);
|
var resolvedExtends = resolveConfigExtends(file, configExtends, fs);
|
||||||
return __assign(__assign({}, readConfigSync(resolvedExtends, parsers)), config);
|
return __assign(__assign({}, readConfigSync(resolvedExtends, parsers, fs)), config);
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
lib/markdownlint.d.ts
vendored
13
lib/markdownlint.d.ts
vendored
|
|
@ -52,6 +52,10 @@ type Options = {
|
||||||
* Additional plugins.
|
* Additional plugins.
|
||||||
*/
|
*/
|
||||||
markdownItPlugins?: Plugin[];
|
markdownItPlugins?: Plugin[];
|
||||||
|
/**
|
||||||
|
* File system implementation.
|
||||||
|
*/
|
||||||
|
fs?: any;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Called with the result of the lint operation.
|
* Called with the result of the lint operation.
|
||||||
|
|
@ -70,18 +74,20 @@ declare function markdownlintSync(options: Options): LintResults;
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
|
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
|
||||||
* function(s).
|
* function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
declare function readConfig(file: string, parsers: ConfigurationParser[] | ReadConfigCallback, callback?: ReadConfigCallback): void;
|
declare function readConfig(file: string, parsers: ConfigurationParser[] | ReadConfigCallback, fs?: any, callback?: ReadConfigCallback): void;
|
||||||
/**
|
/**
|
||||||
* Read specified configuration file synchronously.
|
* Read specified configuration file synchronously.
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Configuration} Configuration object.
|
* @returns {Configuration} Configuration object.
|
||||||
*/
|
*/
|
||||||
declare function readConfigSync(file: string, parsers?: ConfigurationParser[]): Configuration;
|
declare function readConfigSync(file: string, parsers?: ConfigurationParser[], fs?: any): Configuration;
|
||||||
/**
|
/**
|
||||||
* Gets the (semantic) version of the library.
|
* Gets the (semantic) version of the library.
|
||||||
*
|
*
|
||||||
|
|
@ -364,6 +370,7 @@ declare function markdownlintPromise(options: Options): Promise<LintResults>;
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Promise<Configuration>} Configuration object.
|
* @returns {Promise<Configuration>} Configuration object.
|
||||||
*/
|
*/
|
||||||
declare function readConfigPromise(file: string, parsers?: ConfigurationParser[]): Promise<Configuration>;
|
declare function readConfigPromise(file: string, parsers?: ConfigurationParser[], fs?: any): Promise<Configuration>;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { promisify } = require("util");
|
const { promisify } = require("util");
|
||||||
const markdownIt = require("markdown-it");
|
const markdownIt = require("markdown-it");
|
||||||
|
|
@ -685,6 +684,7 @@ function lintContent(
|
||||||
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
* @param {boolean} handleRuleFailures Whether to handle exceptions in rules.
|
||||||
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
||||||
* @param {number} resultVersion Version of the LintResults object to return.
|
* @param {number} resultVersion Version of the LintResults object to return.
|
||||||
|
* @param {Object} fs File system implementation.
|
||||||
* @param {boolean} synchronous Whether to execute synchronously.
|
* @param {boolean} synchronous Whether to execute synchronously.
|
||||||
* @param {Function} callback Callback (err, result) function.
|
* @param {Function} callback Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
|
|
@ -698,6 +698,7 @@ function lintFile(
|
||||||
handleRuleFailures,
|
handleRuleFailures,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
resultVersion,
|
resultVersion,
|
||||||
|
fs,
|
||||||
synchronous,
|
synchronous,
|
||||||
callback) {
|
callback) {
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
|
|
@ -710,7 +711,6 @@ function lintFile(
|
||||||
}
|
}
|
||||||
// Make a/synchronous call to read file
|
// Make a/synchronous call to read file
|
||||||
if (synchronous) {
|
if (synchronous) {
|
||||||
// @ts-ignore
|
|
||||||
lintContentWrapper(null, fs.readFileSync(file, "utf8"));
|
lintContentWrapper(null, fs.readFileSync(file, "utf8"));
|
||||||
} else {
|
} else {
|
||||||
fs.readFile(file, "utf8", lintContentWrapper);
|
fs.readFile(file, "utf8", lintContentWrapper);
|
||||||
|
|
@ -756,6 +756,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
md.use(...plugin);
|
md.use(...plugin);
|
||||||
});
|
});
|
||||||
|
const fs = options.fs || require("fs");
|
||||||
const results = newResults(ruleList);
|
const results = newResults(ruleList);
|
||||||
let done = false;
|
let done = false;
|
||||||
// Linting of strings is always synchronous
|
// Linting of strings is always synchronous
|
||||||
|
|
@ -795,6 +796,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
handleRuleFailures,
|
handleRuleFailures,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
resultVersion,
|
resultVersion,
|
||||||
|
fs,
|
||||||
synchronous,
|
synchronous,
|
||||||
syncCallback
|
syncCallback
|
||||||
);
|
);
|
||||||
|
|
@ -819,6 +821,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
handleRuleFailures,
|
handleRuleFailures,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
resultVersion,
|
resultVersion,
|
||||||
|
fs,
|
||||||
synchronous,
|
synchronous,
|
||||||
(err, result) => {
|
(err, result) => {
|
||||||
concurrency--;
|
concurrency--;
|
||||||
|
|
@ -929,17 +932,17 @@ function parseConfiguration(name, content, parsers) {
|
||||||
*
|
*
|
||||||
* @param {string} configFile Configuration file name.
|
* @param {string} configFile Configuration file name.
|
||||||
* @param {string} referenceId Referenced identifier to resolve.
|
* @param {string} referenceId Referenced identifier to resolve.
|
||||||
|
* @param {Object} fs File system implementation.
|
||||||
* @returns {string} Resolved path to file.
|
* @returns {string} Resolved path to file.
|
||||||
*/
|
*/
|
||||||
function resolveConfigExtends(configFile, referenceId) {
|
function resolveConfigExtends(configFile, referenceId, fs) {
|
||||||
const configFileDirname = path.dirname(configFile);
|
const configFileDirname = path.dirname(configFile);
|
||||||
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);
|
||||||
try {
|
try {
|
||||||
if (fs.statSync(resolvedExtendsFile).isFile()) {
|
fs.accessSync(resolvedExtendsFile);
|
||||||
return resolvedExtendsFile;
|
return resolvedExtendsFile;
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
// If not a file or fs.statSync throws, try require.resolve
|
// Not a file, try require.resolve
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return dynamicRequire.resolve(
|
return dynamicRequire.resolve(
|
||||||
|
|
@ -947,7 +950,7 @@ function resolveConfigExtends(configFile, referenceId) {
|
||||||
{ "paths": [ configFileDirname ] }
|
{ "paths": [ configFileDirname ] }
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
// If require.resolve throws, return resolvedExtendsFile
|
// Unable to resolve, return resolvedExtendsFile
|
||||||
}
|
}
|
||||||
return resolvedExtendsFile;
|
return resolvedExtendsFile;
|
||||||
}
|
}
|
||||||
|
|
@ -958,15 +961,24 @@ function resolveConfigExtends(configFile, referenceId) {
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
|
* @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing
|
||||||
* function(s).
|
* function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
* @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function readConfig(file, parsers, callback) {
|
function readConfig(file, parsers, fs, callback) {
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
|
if (fs) {
|
||||||
|
callback = fs;
|
||||||
|
fs = null;
|
||||||
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
callback = parsers;
|
callback = parsers;
|
||||||
parsers = null;
|
parsers = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!fs) {
|
||||||
|
fs = require("fs");
|
||||||
|
}
|
||||||
// Read file
|
// Read file
|
||||||
fs.readFile(file, "utf8", (err, content) => {
|
fs.readFile(file, "utf8", (err, content) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -982,8 +994,8 @@ function readConfig(file, parsers, callback) {
|
||||||
const configExtends = config.extends;
|
const configExtends = config.extends;
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config.extends;
|
delete config.extends;
|
||||||
const resolvedExtends = resolveConfigExtends(file, configExtends);
|
const resolvedExtends = resolveConfigExtends(file, configExtends, fs);
|
||||||
return readConfig(resolvedExtends, parsers, (errr, extendsConfig) => {
|
return readConfig(resolvedExtends, parsers, fs, (errr, extendsConfig) => {
|
||||||
if (errr) {
|
if (errr) {
|
||||||
return callback(errr);
|
return callback(errr);
|
||||||
}
|
}
|
||||||
|
|
@ -1004,11 +1016,12 @@ const readConfigPromisify = promisify && promisify(readConfig);
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Promise<Configuration>} Configuration object.
|
* @returns {Promise<Configuration>} Configuration object.
|
||||||
*/
|
*/
|
||||||
function readConfigPromise(file, parsers) {
|
function readConfigPromise(file, parsers, fs) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return readConfigPromisify(file, parsers);
|
return readConfigPromisify(file, parsers, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1016,11 +1029,14 @@ function readConfigPromise(file, parsers) {
|
||||||
*
|
*
|
||||||
* @param {string} file Configuration file name.
|
* @param {string} file Configuration file name.
|
||||||
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
* @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
||||||
|
* @param {Object} [fs] File system implementation.
|
||||||
* @returns {Configuration} Configuration object.
|
* @returns {Configuration} Configuration object.
|
||||||
*/
|
*/
|
||||||
function readConfigSync(file, parsers) {
|
function readConfigSync(file, parsers, fs) {
|
||||||
|
if (!fs) {
|
||||||
|
fs = require("fs");
|
||||||
|
}
|
||||||
// Read file
|
// Read file
|
||||||
// @ts-ignore
|
|
||||||
const content = fs.readFileSync(file, "utf8");
|
const content = fs.readFileSync(file, "utf8");
|
||||||
// Try to parse file
|
// Try to parse file
|
||||||
const { config, message } = parseConfiguration(file, content, parsers);
|
const { config, message } = parseConfiguration(file, content, parsers);
|
||||||
|
|
@ -1031,9 +1047,9 @@ function readConfigSync(file, parsers) {
|
||||||
const configExtends = config.extends;
|
const configExtends = config.extends;
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config.extends;
|
delete config.extends;
|
||||||
const resolvedExtends = resolveConfigExtends(file, configExtends);
|
const resolvedExtends = resolveConfigExtends(file, configExtends, fs);
|
||||||
return {
|
return {
|
||||||
...readConfigSync(resolvedExtends, parsers),
|
...readConfigSync(resolvedExtends, parsers, fs),
|
||||||
...config
|
...config
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1156,6 +1172,7 @@ module.exports = markdownlint;
|
||||||
* @property {boolean} [noInlineConfig] True to ignore HTML directives.
|
* @property {boolean} [noInlineConfig] True to ignore HTML directives.
|
||||||
* @property {number} [resultVersion] Results object version.
|
* @property {number} [resultVersion] Results object version.
|
||||||
* @property {Plugin[]} [markdownItPlugins] Additional plugins.
|
* @property {Plugin[]} [markdownItPlugins] Additional plugins.
|
||||||
|
* @property {Object} [fs] File system implementation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -652,11 +652,13 @@ test.cb("readmeHeadings", (t) => {
|
||||||
"##### options.noInlineConfig",
|
"##### options.noInlineConfig",
|
||||||
"##### options.resultVersion",
|
"##### options.resultVersion",
|
||||||
"##### options.markdownItPlugins",
|
"##### options.markdownItPlugins",
|
||||||
|
"##### options.fs",
|
||||||
"#### callback",
|
"#### callback",
|
||||||
"#### result",
|
"#### result",
|
||||||
"### Config",
|
"### Config",
|
||||||
"#### file",
|
"#### file",
|
||||||
"#### parsers",
|
"#### parsers",
|
||||||
|
"#### fs",
|
||||||
"#### callback",
|
"#### callback",
|
||||||
"#### result",
|
"#### result",
|
||||||
"## Usage",
|
"## Usage",
|
||||||
|
|
@ -798,6 +800,40 @@ test.cb("missingStringValue", (t) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("customFileSystemSync", (t) => {
|
||||||
|
t.plan(2);
|
||||||
|
const file = "/dir/file.md";
|
||||||
|
const fsApi = {
|
||||||
|
"readFileSync": (p) => {
|
||||||
|
t.is(p, file);
|
||||||
|
return "# Heading";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const result = markdownlint.sync({
|
||||||
|
"files": file,
|
||||||
|
"fs": fsApi
|
||||||
|
});
|
||||||
|
t.deepEqual(result[file].length, 1, "Did not report violations.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test.cb("customFileSystemAsync", (t) => {
|
||||||
|
t.plan(3);
|
||||||
|
const file = "/dir/file.md";
|
||||||
|
const fsApi = {
|
||||||
|
"readFile": (p, o, cb) => {
|
||||||
|
t.is(p, file);
|
||||||
|
cb(null, "# Heading");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
markdownlint({
|
||||||
|
"files": file,
|
||||||
|
"fs": fsApi
|
||||||
|
}, function callback(err, result) {
|
||||||
|
t.falsy(err);
|
||||||
|
t.deepEqual(result[file].length, 1, "Did not report violations.");
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
test.cb("readme", (t) => {
|
test.cb("readme", (t) => {
|
||||||
t.plan(115);
|
t.plan(115);
|
||||||
const tagToRules = {};
|
const tagToRules = {};
|
||||||
|
|
@ -1105,6 +1141,52 @@ test.cb("configMultipleWithRequireResolve", (t) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.cb("configCustomFileSystem", (t) => {
|
||||||
|
t.plan(5);
|
||||||
|
const file = "/dir/file.json";
|
||||||
|
const extended = "/dir/extended.json";
|
||||||
|
const fileContent = {
|
||||||
|
"extends": extended,
|
||||||
|
"default": true,
|
||||||
|
"MD001": false
|
||||||
|
};
|
||||||
|
const extendedContent = {
|
||||||
|
"MD001": true,
|
||||||
|
"MD002": true
|
||||||
|
};
|
||||||
|
const fsApi = {
|
||||||
|
"accessSync": (p) => {
|
||||||
|
t.is(p, extended);
|
||||||
|
},
|
||||||
|
"readFile": (p, o, cb) => {
|
||||||
|
switch (p) {
|
||||||
|
case file:
|
||||||
|
t.is(p, file);
|
||||||
|
return cb(null, JSON.stringify(fileContent));
|
||||||
|
case extended:
|
||||||
|
t.is(p, extended);
|
||||||
|
return cb(null, JSON.stringify(extendedContent));
|
||||||
|
default:
|
||||||
|
return t.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
markdownlint.readConfig(
|
||||||
|
file,
|
||||||
|
null,
|
||||||
|
fsApi,
|
||||||
|
function callback(err, actual) {
|
||||||
|
t.falsy(err);
|
||||||
|
const expected = {
|
||||||
|
...extendedContent,
|
||||||
|
...fileContent
|
||||||
|
};
|
||||||
|
delete expected.extends;
|
||||||
|
t.deepEqual(actual, expected, "Config object not correct.");
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test.cb("configBadFile", (t) => {
|
test.cb("configBadFile", (t) => {
|
||||||
t.plan(4);
|
t.plan(4);
|
||||||
markdownlint.readConfig("./test/config/config-badfile.json",
|
markdownlint.readConfig("./test/config/config-badfile.json",
|
||||||
|
|
@ -1358,6 +1440,45 @@ test("configMultipleHybridSync", (t) => {
|
||||||
t.like(actual, expected, "Config object not correct.");
|
t.like(actual, expected, "Config object not correct.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("configCustomFileSystemSync", (t) => {
|
||||||
|
t.plan(4);
|
||||||
|
const file = "/dir/file.json";
|
||||||
|
const extended = "/dir/extended.json";
|
||||||
|
const fileContent = {
|
||||||
|
"extends": extended,
|
||||||
|
"default": true,
|
||||||
|
"MD001": false
|
||||||
|
};
|
||||||
|
const extendedContent = {
|
||||||
|
"MD001": true,
|
||||||
|
"MD002": true
|
||||||
|
};
|
||||||
|
const fsApi = {
|
||||||
|
"accessSync": (p) => {
|
||||||
|
t.is(p, extended);
|
||||||
|
},
|
||||||
|
"readFileSync": (p) => {
|
||||||
|
switch (p) {
|
||||||
|
case file:
|
||||||
|
t.is(p, file);
|
||||||
|
return JSON.stringify(fileContent);
|
||||||
|
case extended:
|
||||||
|
t.is(p, extended);
|
||||||
|
return JSON.stringify(extendedContent);
|
||||||
|
default:
|
||||||
|
return t.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const actual = markdownlint.readConfigSync(file, null, fsApi);
|
||||||
|
const expected = {
|
||||||
|
...extendedContent,
|
||||||
|
...fileContent
|
||||||
|
};
|
||||||
|
delete expected.extends;
|
||||||
|
t.deepEqual(actual, expected, "Config object not correct.");
|
||||||
|
});
|
||||||
|
|
||||||
test("configBadHybridSync", (t) => {
|
test("configBadHybridSync", (t) => {
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
t.throws(
|
t.throws(
|
||||||
|
|
@ -1385,6 +1506,48 @@ test.cb("configSinglePromise", (t) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.cb("configCustomFileSystemPromise", (t) => {
|
||||||
|
t.plan(4);
|
||||||
|
const file = "/dir/file.json";
|
||||||
|
const extended = "/dir/extended.json";
|
||||||
|
const fileContent = {
|
||||||
|
"extends": extended,
|
||||||
|
"default": true,
|
||||||
|
"MD001": false
|
||||||
|
};
|
||||||
|
const extendedContent = {
|
||||||
|
"MD001": true,
|
||||||
|
"MD002": true
|
||||||
|
};
|
||||||
|
const fsApi = {
|
||||||
|
"accessSync": (p) => {
|
||||||
|
t.is(p, extended);
|
||||||
|
},
|
||||||
|
"readFile": (p, o, cb) => {
|
||||||
|
switch (p) {
|
||||||
|
case file:
|
||||||
|
t.is(p, file);
|
||||||
|
return cb(null, JSON.stringify(fileContent));
|
||||||
|
case extended:
|
||||||
|
t.is(p, extended);
|
||||||
|
return cb(null, JSON.stringify(extendedContent));
|
||||||
|
default:
|
||||||
|
return t.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
markdownlint.promises.readConfig(file, null, fsApi)
|
||||||
|
.then((actual) => {
|
||||||
|
const expected = {
|
||||||
|
...extendedContent,
|
||||||
|
...fileContent
|
||||||
|
};
|
||||||
|
delete expected.extends;
|
||||||
|
t.deepEqual(actual, expected, "Config object not correct.");
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test.cb("configBadFilePromise", (t) => {
|
test.cb("configBadFilePromise", (t) => {
|
||||||
t.plan(2);
|
t.plan(2);
|
||||||
markdownlint.promises.readConfig("./test/config/config-badfile.json")
|
markdownlint.promises.readConfig("./test/config/config-badfile.json")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue