mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-21 21:30:47 +02:00
Add "configParsers" option so custom parsers can be used to handle the content of markdownlint-configure-file inline comments (fixes #528).
This commit is contained in:
parent
bbec8c5c1e
commit
00082ee8a5
6 changed files with 267 additions and 108 deletions
25
README.md
25
README.md
|
@ -263,8 +263,11 @@ or
|
||||||
-->
|
-->
|
||||||
```
|
```
|
||||||
|
|
||||||
These changes apply to the entire file regardless of where the comment
|
These changes apply to the entire file regardless of where the comment is
|
||||||
is located. Multiple such comments (if present) are applied top-to-bottom.
|
located. Multiple such comments (if present) are applied top-to-bottom. By
|
||||||
|
default, content of `markdownlint-configure-file` is assumed to be JSON, but
|
||||||
|
[`options.configParsers`](#optionsconfigparsers) can be used to support
|
||||||
|
alternate formats.
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
|
@ -406,6 +409,24 @@ const options = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### options.configParsers
|
||||||
|
|
||||||
|
Type: *Optional* `Array` of `Function` taking (`String`) and returning `Object`
|
||||||
|
|
||||||
|
Array of functions to parse the content of `markdownlint-configure-file` blocks.
|
||||||
|
|
||||||
|
As shown in the [Configuration](#configuration) section, inline comments can be
|
||||||
|
used to customize the [configuration object](#optionsconfig) for a document. By
|
||||||
|
default, the `JSON.parse` built-in is used, but custom parsers can be specified.
|
||||||
|
Content is passed to each parser function until one returns a value (vs. throwing
|
||||||
|
an exception). As such, strict parsers should come before flexible ones.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
[ JSON.parse, require("toml").parse, require("js-yaml").load ]
|
||||||
|
```
|
||||||
|
|
||||||
##### options.customRules
|
##### options.customRules
|
||||||
|
|
||||||
Type: `Array` of `Object`
|
Type: `Array` of `Object`
|
||||||
|
|
|
@ -1560,6 +1560,39 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
});
|
});
|
||||||
return effectiveConfig;
|
return effectiveConfig;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Parse the content of a configuration file.
|
||||||
|
*
|
||||||
|
* @param {string} name Name of the configuration file.
|
||||||
|
* @param {string} content Configuration content.
|
||||||
|
* @param {ConfigurationParser[]} parsers Parsing function(s).
|
||||||
|
* @returns {Object} Configuration object and error message.
|
||||||
|
*/
|
||||||
|
function parseConfiguration(name, content, parsers) {
|
||||||
|
let config = null;
|
||||||
|
let message = "";
|
||||||
|
const errors = [];
|
||||||
|
let index = 0;
|
||||||
|
// Try each parser
|
||||||
|
(parsers || [JSON.parse]).every((parser) => {
|
||||||
|
try {
|
||||||
|
config = parser(content);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
errors.push(`Parser ${index++}: ${error.message}`);
|
||||||
|
}
|
||||||
|
return !config;
|
||||||
|
});
|
||||||
|
// Message if unable to parse
|
||||||
|
if (!config) {
|
||||||
|
errors.unshift(`Unable to parse '${name}'`);
|
||||||
|
message = errors.join("; ");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
config,
|
||||||
|
message
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Create a mapping of enabled rules per line.
|
* Create a mapping of enabled rules per line.
|
||||||
*
|
*
|
||||||
|
@ -1568,11 +1601,12 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
* @param {string[]} frontMatterLines List of front matter lines.
|
* @param {string[]} frontMatterLines List of front matter lines.
|
||||||
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
||||||
* @param {Configuration} config Configuration object.
|
* @param {Configuration} config Configuration object.
|
||||||
|
* @param {ConfigurationParser[]} configParsers Configuration parsers.
|
||||||
* @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule
|
* @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule
|
||||||
* names.
|
* names.
|
||||||
* @returns {Object} Effective configuration and enabled rules per line number.
|
* @returns {Object} Effective configuration and enabled rules per line number.
|
||||||
*/
|
*/
|
||||||
function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlineConfig, config, aliasToRuleNames) {
|
function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlineConfig, config, configParsers, aliasToRuleNames) {
|
||||||
// Shared variables
|
// Shared variables
|
||||||
let enabledRules = {};
|
let enabledRules = {};
|
||||||
let capturedRules = {};
|
let capturedRules = {};
|
||||||
|
@ -1603,12 +1637,9 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
function configureFile(action, parameter) {
|
function configureFile(action, parameter) {
|
||||||
if (action === "CONFIGURE-FILE") {
|
if (action === "CONFIGURE-FILE") {
|
||||||
try {
|
const { "config": parsed } = parseConfiguration("CONFIGURE-FILE", parameter, configParsers);
|
||||||
const json = JSON.parse(parameter);
|
if (parsed) {
|
||||||
config = Object.assign(Object.assign({}, config), json);
|
config = Object.assign(Object.assign({}, config), parsed);
|
||||||
}
|
|
||||||
catch (_a) {
|
|
||||||
// Ignore parse errors for inline configuration
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1683,6 +1714,7 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
||||||
* @param {string} content Markdown content.
|
* @param {string} content Markdown content.
|
||||||
* @param {Object} md Instance of markdown-it.
|
* @param {Object} md Instance of markdown-it.
|
||||||
* @param {Configuration} config Configuration object.
|
* @param {Configuration} config Configuration object.
|
||||||
|
* @param {ConfigurationParser[]} configParsers Configuration parsers.
|
||||||
* @param {RegExp} frontMatter Regular expression for front matter.
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
||||||
* @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.
|
||||||
|
@ -1690,7 +1722,7 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
||||||
* @param {Function} callback Callback (err, result) function.
|
* @param {Function} callback Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function lintContent(ruleList, name, content, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback) {
|
function lintContent(ruleList, name, content, md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback) {
|
||||||
// Remove UTF-8 byte order marker (if present)
|
// Remove UTF-8 byte order marker (if present)
|
||||||
content = content.replace(/^\uFEFF/, "");
|
content = content.replace(/^\uFEFF/, "");
|
||||||
// Remove front matter
|
// Remove front matter
|
||||||
|
@ -1698,7 +1730,7 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
||||||
const { frontMatterLines } = removeFrontMatterResult;
|
const { frontMatterLines } = removeFrontMatterResult;
|
||||||
content = removeFrontMatterResult.content;
|
content = removeFrontMatterResult.content;
|
||||||
// Get enabled rules per line (with HTML comments present)
|
// Get enabled rules per line (with HTML comments present)
|
||||||
const { effectiveConfig, enabledRulesPerLineNumber } = getEnabledRulesPerLineNumber(ruleList, content.split(helpers.newLineRe), frontMatterLines, noInlineConfig, config, mapAliasToRuleNames(ruleList));
|
const { effectiveConfig, enabledRulesPerLineNumber } = getEnabledRulesPerLineNumber(ruleList, content.split(helpers.newLineRe), frontMatterLines, noInlineConfig, config, configParsers, mapAliasToRuleNames(ruleList));
|
||||||
// Hide the content of HTML comments from rules, etc.
|
// Hide the content of HTML comments from rules, etc.
|
||||||
content = helpers.clearHtmlCommentText(content);
|
content = helpers.clearHtmlCommentText(content);
|
||||||
// Parse content into tokens and lines
|
// Parse content into tokens and lines
|
||||||
|
@ -1924,6 +1956,7 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
||||||
* @param {string} file Path of file to lint.
|
* @param {string} file Path of file to lint.
|
||||||
* @param {Object} md Instance of markdown-it.
|
* @param {Object} md Instance of markdown-it.
|
||||||
* @param {Configuration} config Configuration object.
|
* @param {Configuration} config Configuration object.
|
||||||
|
* @param {ConfigurationParser[]} configParsers Configuration parsers.
|
||||||
* @param {RegExp} frontMatter Regular expression for front matter.
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
||||||
* @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.
|
||||||
|
@ -1933,13 +1966,13 @@ function lintContent(ruleList, name, content, md, config, frontMatter, handleRul
|
||||||
* @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, fs, synchronous, callback) {
|
function lintFile(ruleList, file, md, config, configParsers, 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) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
return lintContent(ruleList, file, content, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback);
|
return lintContent(ruleList, file, content, md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, callback);
|
||||||
}
|
}
|
||||||
// Make a/synchronous call to read file
|
// Make a/synchronous call to read file
|
||||||
if (synchronous) {
|
if (synchronous) {
|
||||||
|
@ -1977,6 +2010,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
const strings = options.strings || {};
|
const strings = options.strings || {};
|
||||||
const stringsKeys = Object.keys(strings);
|
const stringsKeys = Object.keys(strings);
|
||||||
const config = options.config || { "default": true };
|
const config = options.config || { "default": true };
|
||||||
|
const configParsers = options.configParsers || null;
|
||||||
const frontMatter = (options.frontMatter === undefined) ?
|
const frontMatter = (options.frontMatter === undefined) ?
|
||||||
helpers.frontMatterRe : options.frontMatter;
|
helpers.frontMatterRe : options.frontMatter;
|
||||||
const handleRuleFailures = !!options.handleRuleFailures;
|
const handleRuleFailures = !!options.handleRuleFailures;
|
||||||
|
@ -2016,13 +2050,13 @@ function lintInput(options, synchronous, callback) {
|
||||||
// Lint next file
|
// Lint next file
|
||||||
concurrency++;
|
concurrency++;
|
||||||
currentItem = files.shift();
|
currentItem = files.shift();
|
||||||
lintFile(ruleList, currentItem, md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, lintWorkerCallback);
|
lintFile(ruleList, currentItem, md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, fs, synchronous, lintWorkerCallback);
|
||||||
}
|
}
|
||||||
else if (stringsKeys.length > 0) {
|
else if (stringsKeys.length > 0) {
|
||||||
// Lint next string
|
// Lint next string
|
||||||
concurrency++;
|
concurrency++;
|
||||||
currentItem = stringsKeys.shift();
|
currentItem = stringsKeys.shift();
|
||||||
lintContent(ruleList, currentItem, strings[currentItem] || "", md, config, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, lintWorkerCallback);
|
lintContent(ruleList, currentItem, strings[currentItem] || "", md, config, configParsers, frontMatter, handleRuleFailures, noInlineConfig, resultVersion, lintWorkerCallback);
|
||||||
}
|
}
|
||||||
else if (concurrency === 0) {
|
else if (concurrency === 0) {
|
||||||
// Finish
|
// Finish
|
||||||
|
@ -2087,39 +2121,6 @@ function markdownlintSync(options) {
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Parse the content of a configuration file.
|
|
||||||
*
|
|
||||||
* @param {string} name Name of the configuration file.
|
|
||||||
* @param {string} content Configuration content.
|
|
||||||
* @param {ConfigurationParser[]} parsers Parsing function(s).
|
|
||||||
* @returns {Object} Configuration object and error message.
|
|
||||||
*/
|
|
||||||
function parseConfiguration(name, content, parsers) {
|
|
||||||
let config = null;
|
|
||||||
let message = "";
|
|
||||||
const errors = [];
|
|
||||||
let index = 0;
|
|
||||||
// Try each parser
|
|
||||||
(parsers || [JSON.parse]).every((parser) => {
|
|
||||||
try {
|
|
||||||
config = parser(content);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
errors.push(`Parser ${index++}: ${error.message}`);
|
|
||||||
}
|
|
||||||
return !config;
|
|
||||||
});
|
|
||||||
// Message if unable to parse
|
|
||||||
if (!config) {
|
|
||||||
errors.unshift(`Unable to parse '${name}'`);
|
|
||||||
message = errors.join("; ");
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
config,
|
|
||||||
message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Resolve referenced "extends" path in a configuration file
|
* Resolve referenced "extends" path in a configuration file
|
||||||
* using path.resolve() with require.resolve() as a fallback.
|
* using path.resolve() with require.resolve() as a fallback.
|
||||||
|
|
|
@ -88,6 +88,7 @@ options = {
|
||||||
"code_blocks": true
|
"code_blocks": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"configParsers": [ JSON.parse ],
|
||||||
"customRules": undefined,
|
"customRules": undefined,
|
||||||
"frontMatter": /---/,
|
"frontMatter": /---/,
|
||||||
"handleRuleFailures": false,
|
"handleRuleFailures": false,
|
||||||
|
|
36
lib/markdownlint.d.ts
vendored
36
lib/markdownlint.d.ts
vendored
|
@ -14,32 +14,38 @@ declare namespace markdownlint {
|
||||||
* Configuration options.
|
* Configuration options.
|
||||||
*/
|
*/
|
||||||
type Options = {
|
type Options = {
|
||||||
/**
|
|
||||||
* Files to lint.
|
|
||||||
*/
|
|
||||||
files?: string[] | string;
|
|
||||||
/**
|
|
||||||
* Strings to lint.
|
|
||||||
*/
|
|
||||||
strings?: {
|
|
||||||
[x: string]: string;
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* Configuration object.
|
* Configuration object.
|
||||||
*/
|
*/
|
||||||
config?: Configuration;
|
config?: Configuration;
|
||||||
|
/**
|
||||||
|
* Configuration parsers.
|
||||||
|
*/
|
||||||
|
configParsers?: ConfigurationParser[];
|
||||||
/**
|
/**
|
||||||
* Custom rules.
|
* Custom rules.
|
||||||
*/
|
*/
|
||||||
customRules?: Rule[] | Rule;
|
customRules?: Rule[] | Rule;
|
||||||
|
/**
|
||||||
|
* Files to lint.
|
||||||
|
*/
|
||||||
|
files?: string[] | string;
|
||||||
/**
|
/**
|
||||||
* Front matter pattern.
|
* Front matter pattern.
|
||||||
*/
|
*/
|
||||||
frontMatter?: RegExp;
|
frontMatter?: RegExp;
|
||||||
|
/**
|
||||||
|
* File system implementation.
|
||||||
|
*/
|
||||||
|
fs?: any;
|
||||||
/**
|
/**
|
||||||
* True to catch exceptions.
|
* True to catch exceptions.
|
||||||
*/
|
*/
|
||||||
handleRuleFailures?: boolean;
|
handleRuleFailures?: boolean;
|
||||||
|
/**
|
||||||
|
* Additional plugins.
|
||||||
|
*/
|
||||||
|
markdownItPlugins?: Plugin[];
|
||||||
/**
|
/**
|
||||||
* True to ignore HTML directives.
|
* True to ignore HTML directives.
|
||||||
*/
|
*/
|
||||||
|
@ -49,13 +55,11 @@ type Options = {
|
||||||
*/
|
*/
|
||||||
resultVersion?: number;
|
resultVersion?: number;
|
||||||
/**
|
/**
|
||||||
* Additional plugins.
|
* Strings to lint.
|
||||||
*/
|
*/
|
||||||
markdownItPlugins?: Plugin[];
|
strings?: {
|
||||||
/**
|
[x: string]: string;
|
||||||
* File system implementation.
|
};
|
||||||
*/
|
|
||||||
fs?: any;
|
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Called with the result of the lint function.
|
* Called with the result of the lint function.
|
||||||
|
|
|
@ -316,6 +316,39 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
return effectiveConfig;
|
return effectiveConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the content of a configuration file.
|
||||||
|
*
|
||||||
|
* @param {string} name Name of the configuration file.
|
||||||
|
* @param {string} content Configuration content.
|
||||||
|
* @param {ConfigurationParser[]} parsers Parsing function(s).
|
||||||
|
* @returns {Object} Configuration object and error message.
|
||||||
|
*/
|
||||||
|
function parseConfiguration(name, content, parsers) {
|
||||||
|
let config = null;
|
||||||
|
let message = "";
|
||||||
|
const errors = [];
|
||||||
|
let index = 0;
|
||||||
|
// Try each parser
|
||||||
|
(parsers || [ JSON.parse ]).every((parser) => {
|
||||||
|
try {
|
||||||
|
config = parser(content);
|
||||||
|
} catch (error) {
|
||||||
|
errors.push(`Parser ${index++}: ${error.message}`);
|
||||||
|
}
|
||||||
|
return !config;
|
||||||
|
});
|
||||||
|
// Message if unable to parse
|
||||||
|
if (!config) {
|
||||||
|
errors.unshift(`Unable to parse '${name}'`);
|
||||||
|
message = errors.join("; ");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
config,
|
||||||
|
message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mapping of enabled rules per line.
|
* Create a mapping of enabled rules per line.
|
||||||
*
|
*
|
||||||
|
@ -324,6 +357,7 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
* @param {string[]} frontMatterLines List of front matter lines.
|
* @param {string[]} frontMatterLines List of front matter lines.
|
||||||
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
* @param {boolean} noInlineConfig Whether to allow inline configuration.
|
||||||
* @param {Configuration} config Configuration object.
|
* @param {Configuration} config Configuration object.
|
||||||
|
* @param {ConfigurationParser[]} configParsers Configuration parsers.
|
||||||
* @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule
|
* @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule
|
||||||
* names.
|
* names.
|
||||||
* @returns {Object} Effective configuration and enabled rules per line number.
|
* @returns {Object} Effective configuration and enabled rules per line number.
|
||||||
|
@ -334,6 +368,7 @@ function getEnabledRulesPerLineNumber(
|
||||||
frontMatterLines,
|
frontMatterLines,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
config,
|
config,
|
||||||
|
configParsers,
|
||||||
aliasToRuleNames) {
|
aliasToRuleNames) {
|
||||||
// Shared variables
|
// Shared variables
|
||||||
let enabledRules = {};
|
let enabledRules = {};
|
||||||
|
@ -365,14 +400,14 @@ function getEnabledRulesPerLineNumber(
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
function configureFile(action, parameter) {
|
function configureFile(action, parameter) {
|
||||||
if (action === "CONFIGURE-FILE") {
|
if (action === "CONFIGURE-FILE") {
|
||||||
try {
|
const { "config": parsed } = parseConfiguration(
|
||||||
const json = JSON.parse(parameter);
|
"CONFIGURE-FILE", parameter, configParsers
|
||||||
|
);
|
||||||
|
if (parsed) {
|
||||||
config = {
|
config = {
|
||||||
...config,
|
...config,
|
||||||
...json
|
...parsed
|
||||||
};
|
};
|
||||||
} catch {
|
|
||||||
// Ignore parse errors for inline configuration
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,6 +487,7 @@ function getEnabledRulesPerLineNumber(
|
||||||
* @param {string} content Markdown content.
|
* @param {string} content Markdown content.
|
||||||
* @param {Object} md Instance of markdown-it.
|
* @param {Object} md Instance of markdown-it.
|
||||||
* @param {Configuration} config Configuration object.
|
* @param {Configuration} config Configuration object.
|
||||||
|
* @param {ConfigurationParser[]} configParsers Configuration parsers.
|
||||||
* @param {RegExp} frontMatter Regular expression for front matter.
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
||||||
* @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.
|
||||||
|
@ -465,6 +501,7 @@ function lintContent(
|
||||||
content,
|
content,
|
||||||
md,
|
md,
|
||||||
config,
|
config,
|
||||||
|
configParsers,
|
||||||
frontMatter,
|
frontMatter,
|
||||||
handleRuleFailures,
|
handleRuleFailures,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
|
@ -484,6 +521,7 @@ function lintContent(
|
||||||
frontMatterLines,
|
frontMatterLines,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
config,
|
config,
|
||||||
|
configParsers,
|
||||||
mapAliasToRuleNames(ruleList)
|
mapAliasToRuleNames(ruleList)
|
||||||
);
|
);
|
||||||
// Hide the content of HTML comments from rules, etc.
|
// Hide the content of HTML comments from rules, etc.
|
||||||
|
@ -720,6 +758,7 @@ function lintContent(
|
||||||
* @param {string} file Path of file to lint.
|
* @param {string} file Path of file to lint.
|
||||||
* @param {Object} md Instance of markdown-it.
|
* @param {Object} md Instance of markdown-it.
|
||||||
* @param {Configuration} config Configuration object.
|
* @param {Configuration} config Configuration object.
|
||||||
|
* @param {ConfigurationParser[]} configParsers Configuration parsers.
|
||||||
* @param {RegExp} frontMatter Regular expression for front matter.
|
* @param {RegExp} frontMatter Regular expression for front matter.
|
||||||
* @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.
|
||||||
|
@ -734,6 +773,7 @@ function lintFile(
|
||||||
file,
|
file,
|
||||||
md,
|
md,
|
||||||
config,
|
config,
|
||||||
|
configParsers,
|
||||||
frontMatter,
|
frontMatter,
|
||||||
handleRuleFailures,
|
handleRuleFailures,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
|
@ -746,8 +786,19 @@ function lintFile(
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
return lintContent(ruleList, file, content, md, config, frontMatter,
|
return lintContent(
|
||||||
handleRuleFailures, noInlineConfig, resultVersion, callback);
|
ruleList,
|
||||||
|
file,
|
||||||
|
content,
|
||||||
|
md,
|
||||||
|
config,
|
||||||
|
configParsers,
|
||||||
|
frontMatter,
|
||||||
|
handleRuleFailures,
|
||||||
|
noInlineConfig,
|
||||||
|
resultVersion,
|
||||||
|
callback
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Make a/synchronous call to read file
|
// Make a/synchronous call to read file
|
||||||
if (synchronous) {
|
if (synchronous) {
|
||||||
|
@ -784,6 +835,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
const strings = options.strings || {};
|
const strings = options.strings || {};
|
||||||
const stringsKeys = Object.keys(strings);
|
const stringsKeys = Object.keys(strings);
|
||||||
const config = options.config || { "default": true };
|
const config = options.config || { "default": true };
|
||||||
|
const configParsers = options.configParsers || null;
|
||||||
const frontMatter = (options.frontMatter === undefined) ?
|
const frontMatter = (options.frontMatter === undefined) ?
|
||||||
helpers.frontMatterRe : options.frontMatter;
|
helpers.frontMatterRe : options.frontMatter;
|
||||||
const handleRuleFailures = !!options.handleRuleFailures;
|
const handleRuleFailures = !!options.handleRuleFailures;
|
||||||
|
@ -827,6 +879,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
currentItem,
|
currentItem,
|
||||||
md,
|
md,
|
||||||
config,
|
config,
|
||||||
|
configParsers,
|
||||||
frontMatter,
|
frontMatter,
|
||||||
handleRuleFailures,
|
handleRuleFailures,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
|
@ -845,6 +898,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
strings[currentItem] || "",
|
strings[currentItem] || "",
|
||||||
md,
|
md,
|
||||||
config,
|
config,
|
||||||
|
configParsers,
|
||||||
frontMatter,
|
frontMatter,
|
||||||
handleRuleFailures,
|
handleRuleFailures,
|
||||||
noInlineConfig,
|
noInlineConfig,
|
||||||
|
@ -918,39 +972,6 @@ function markdownlintSync(options) {
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the content of a configuration file.
|
|
||||||
*
|
|
||||||
* @param {string} name Name of the configuration file.
|
|
||||||
* @param {string} content Configuration content.
|
|
||||||
* @param {ConfigurationParser[]} parsers Parsing function(s).
|
|
||||||
* @returns {Object} Configuration object and error message.
|
|
||||||
*/
|
|
||||||
function parseConfiguration(name, content, parsers) {
|
|
||||||
let config = null;
|
|
||||||
let message = "";
|
|
||||||
const errors = [];
|
|
||||||
let index = 0;
|
|
||||||
// Try each parser
|
|
||||||
(parsers || [ JSON.parse ]).every((parser) => {
|
|
||||||
try {
|
|
||||||
config = parser(content);
|
|
||||||
} catch (error) {
|
|
||||||
errors.push(`Parser ${index++}: ${error.message}`);
|
|
||||||
}
|
|
||||||
return !config;
|
|
||||||
});
|
|
||||||
// Message if unable to parse
|
|
||||||
if (!config) {
|
|
||||||
errors.unshift(`Unable to parse '${name}'`);
|
|
||||||
message = errors.join("; ");
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
config,
|
|
||||||
message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve referenced "extends" path in a configuration file
|
* Resolve referenced "extends" path in a configuration file
|
||||||
* using path.resolve() with require.resolve() as a fallback.
|
* using path.resolve() with require.resolve() as a fallback.
|
||||||
|
@ -1237,16 +1258,17 @@ module.exports = markdownlint;
|
||||||
* Configuration options.
|
* Configuration options.
|
||||||
*
|
*
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
* @property {string[] | string} [files] Files to lint.
|
|
||||||
* @property {Object.<string, string>} [strings] Strings to lint.
|
|
||||||
* @property {Configuration} [config] Configuration object.
|
* @property {Configuration} [config] Configuration object.
|
||||||
|
* @property {ConfigurationParser[]} [configParsers] Configuration parsers.
|
||||||
* @property {Rule[] | Rule} [customRules] Custom rules.
|
* @property {Rule[] | Rule} [customRules] Custom rules.
|
||||||
|
* @property {string[] | string} [files] Files to lint.
|
||||||
* @property {RegExp} [frontMatter] Front matter pattern.
|
* @property {RegExp} [frontMatter] Front matter pattern.
|
||||||
|
* @property {Object} [fs] File system implementation.
|
||||||
* @property {boolean} [handleRuleFailures] True to catch exceptions.
|
* @property {boolean} [handleRuleFailures] True to catch exceptions.
|
||||||
|
* @property {Plugin[]} [markdownItPlugins] Additional plugins.
|
||||||
* @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 {Object.<string, string>} [strings] Strings to lint.
|
||||||
* @property {Object} [fs] File system implementation.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -652,6 +652,7 @@ test.cb("readmeHeadings", (t) => {
|
||||||
"### Linting",
|
"### Linting",
|
||||||
"#### options",
|
"#### options",
|
||||||
"##### options.config",
|
"##### options.config",
|
||||||
|
"##### options.configParsers",
|
||||||
"##### options.customRules",
|
"##### options.customRules",
|
||||||
"##### options.files",
|
"##### options.files",
|
||||||
"##### options.frontMatter",
|
"##### options.frontMatter",
|
||||||
|
@ -1277,6 +1278,115 @@ test("token-map-spans", (t) => {
|
||||||
markdownlint.sync(options);
|
markdownlint.sync(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("configParsersInvalid", async(t) => {
|
||||||
|
t.plan(1);
|
||||||
|
const options = {
|
||||||
|
"strings": {
|
||||||
|
"content": [
|
||||||
|
"Text",
|
||||||
|
"",
|
||||||
|
"<!-- markdownlint-configure-file",
|
||||||
|
" \"first-line-heading\": false",
|
||||||
|
"-->",
|
||||||
|
""
|
||||||
|
].join("\n")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const expected = "content: 1: MD041/first-line-heading/first-line-h1 " +
|
||||||
|
"First line in a file should be a top-level heading [Context: \"Text\"]";
|
||||||
|
const actual = await markdownlint.promises.markdownlint(options);
|
||||||
|
t.is(actual.toString(), expected, "Unexpected results.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("configParsersJSON", async(t) => {
|
||||||
|
t.plan(1);
|
||||||
|
const options = {
|
||||||
|
"strings": {
|
||||||
|
"content": [
|
||||||
|
"Text",
|
||||||
|
"",
|
||||||
|
"<!-- markdownlint-configure-file",
|
||||||
|
"{",
|
||||||
|
" \"first-line-heading\": false",
|
||||||
|
"}",
|
||||||
|
"-->",
|
||||||
|
""
|
||||||
|
].join("\n")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const actual = await markdownlint.promises.markdownlint(options);
|
||||||
|
t.is(actual.toString(), "", "Unexpected results.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("configParsersJSONC", async(t) => {
|
||||||
|
t.plan(1);
|
||||||
|
// eslint-disable-next-line node/no-unsupported-features/es-syntax
|
||||||
|
const { "default": stripJsonComments } = await import("strip-json-comments");
|
||||||
|
const options = {
|
||||||
|
"strings": {
|
||||||
|
"content": [
|
||||||
|
"Text",
|
||||||
|
"",
|
||||||
|
"<!-- markdownlint-configure-file",
|
||||||
|
"/* Comment */",
|
||||||
|
"{",
|
||||||
|
" \"first-line-heading\": false // Comment",
|
||||||
|
"}",
|
||||||
|
"-->",
|
||||||
|
""
|
||||||
|
].join("\n")
|
||||||
|
},
|
||||||
|
"configParsers": [ (content) => JSON.parse(stripJsonComments(content)) ]
|
||||||
|
};
|
||||||
|
const actual = await markdownlint.promises.markdownlint(options);
|
||||||
|
t.is(actual.toString(), "", "Unexpected results.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("configParsersYAML", async(t) => {
|
||||||
|
t.plan(1);
|
||||||
|
const options = {
|
||||||
|
"strings": {
|
||||||
|
"content": [
|
||||||
|
"Text",
|
||||||
|
"",
|
||||||
|
"<!-- markdownlint-configure-file",
|
||||||
|
"# Comment",
|
||||||
|
"first-line-heading: false",
|
||||||
|
"-->",
|
||||||
|
""
|
||||||
|
].join("\n")
|
||||||
|
},
|
||||||
|
"configParsers": [ jsYaml.load ]
|
||||||
|
};
|
||||||
|
const actual = await markdownlint.promises.markdownlint(options);
|
||||||
|
t.is(actual.toString(), "", "Unexpected results.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("configParsersTOML", async(t) => {
|
||||||
|
t.plan(1);
|
||||||
|
// eslint-disable-next-line node/no-unsupported-features/es-syntax
|
||||||
|
const { "default": stripJsonComments } = await import("strip-json-comments");
|
||||||
|
const options = {
|
||||||
|
"strings": {
|
||||||
|
"content": [
|
||||||
|
"Text",
|
||||||
|
"",
|
||||||
|
"<!-- markdownlint-configure-file",
|
||||||
|
"# Comment",
|
||||||
|
"first-line-heading = false",
|
||||||
|
"-->",
|
||||||
|
""
|
||||||
|
].join("\n")
|
||||||
|
},
|
||||||
|
"configParsers": [
|
||||||
|
(content) => JSON.parse(stripJsonComments(content)),
|
||||||
|
require("toml").parse
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const actual = await markdownlint.promises.markdownlint(options);
|
||||||
|
t.is(actual.toString(), "", "Unexpected results.");
|
||||||
|
});
|
||||||
|
|
||||||
test("getVersion", (t) => {
|
test("getVersion", (t) => {
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
const actual = markdownlint.getVersion();
|
const actual = markdownlint.getVersion();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue