diff --git a/lib/markdownlint.mjs b/lib/markdownlint.mjs index d40277d2..c672a91e 100644 --- a/lib/markdownlint.mjs +++ b/lib/markdownlint.mjs @@ -8,6 +8,7 @@ import { requireMarkdownItCjs } from "./defer-require.cjs"; import { resolveModule } from "./resolve-module.cjs"; import rules from "./rules.mjs"; import { parse as micromarkParse } from "./micromark-parse.mjs"; +import parseConfiguration from "./parse-configuration.mjs"; import * as helpers from "../helpers/helpers.cjs"; /** @@ -268,39 +269,6 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) { return effectiveConfig; } -/** - * Parse the content of a configuration file. - * - * @param {string} name Name of the configuration file. - * @param {string} content Configuration content. - * @param {ConfigurationParser[] | null} [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. * @@ -309,7 +277,7 @@ function parseConfiguration(name, content, parsers) { * @param {string[]} frontMatterLines List of front matter lines. * @param {boolean} noInlineConfig Whether to allow inline configuration. * @param {Configuration} config Configuration object. - * @param {ConfigurationParser[] | null} configParsers Configuration parsers. + * @param {ConfigurationParser[] | undefined} configParsers Configuration parsers. * @param {Object.} aliasToRuleNames Map of alias to rule * names. * @returns {Object} Effective configuration and enabled rules per line number. @@ -448,7 +416,7 @@ function getEnabledRulesPerLineNumber( * @param {string} content Markdown content. * @param {MarkdownItFactory} markdownItFactory Function to create a markdown-it parser. * @param {Configuration} config Configuration object. - * @param {ConfigurationParser[] | null} configParsers Configuration parsers. + * @param {ConfigurationParser[] | undefined} configParsers Configuration parsers. * @param {RegExp | null} frontMatter Regular expression for front matter. * @param {boolean} handleRuleFailures Whether to handle exceptions in rules. * @param {boolean} noInlineConfig Whether to allow inline configuration. @@ -776,7 +744,7 @@ function lintContent( * @param {string} file Path of file to lint. * @param {MarkdownItFactory} markdownItFactory Function to create a markdown-it parser. * @param {Configuration} config Configuration object. - * @param {ConfigurationParser[] | null} configParsers Configuration parsers. + * @param {ConfigurationParser[] | undefined} configParsers Configuration parsers. * @param {RegExp | null} frontMatter Regular expression for front matter. * @param {boolean} handleRuleFailures Whether to handle exceptions in rules. * @param {boolean} noInlineConfig Whether to allow inline configuration. @@ -869,7 +837,7 @@ function lintInput(options, synchronous, callback) { const strings = options.strings || {}; const stringsKeys = Object.keys(strings); const config = options.config || { "default": true }; - const configParsers = options.configParsers || null; + const configParsers = options.configParsers || undefined; const frontMatter = (options.frontMatter === undefined) ? helpers.frontMatterRe : options.frontMatter; diff --git a/lib/parse-configuration.mjs b/lib/parse-configuration.mjs new file mode 100644 index 00000000..c3c96727 --- /dev/null +++ b/lib/parse-configuration.mjs @@ -0,0 +1,42 @@ +// @ts-check + +/** + * Result of a call to parseConfiguration. + * + * @typedef {Object} ParseConfigurationResult + * @property {Object | null} config Configuration object if successful. + * @property {string} message Error message if an error occurred. + */ + +/** + * Parse the content of a configuration file. + * + * @param {string} name Name of the configuration file. + * @param {string} content Configuration content. + * @param {import("./markdownlint.mjs").ConfigurationParser[]} [parsers] Parsing function(s). + * @returns {ParseConfigurationResult} Parse configuration result. + */ +export default 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 + }; +} diff --git a/package.json b/package.json index bbc4aad5..b484af8b 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "lint-test-repos": "ava --timeout=10m test/markdownlint-test-repos-*.mjs", "serial-config-docs": "npm run build-config && npm run build-docs", "serial-declaration": "npm run build-declaration && npm run test-declaration", - "test": "ava --timeout=30s test/markdownlint-test.mjs test/markdownlint-test-config.mjs test/markdownlint-test-custom-rules.mjs test/markdownlint-test-fixes.mjs test/markdownlint-test-helpers.mjs test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.mjs test/markdownlint-test-scenarios.mjs test/resolve-module-test.mjs helpers/test.cjs", + "test": "ava --timeout=30s test/markdownlint-test.mjs test/markdownlint-test-config.mjs test/markdownlint-test-custom-rules.mjs test/markdownlint-test-fixes.mjs test/markdownlint-test-helpers.mjs test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.mjs test/markdownlint-test-scenarios.mjs test/parse-configuration-test.mjs test/resolve-module-test.mjs helpers/test.cjs", "test-cover": "c8 --100 npm test", "test-declaration": "npm-run-all --continue-on-error --parallel test-declaration-cts test-declaration-mts", "test-declaration-cts": "cd example/typescript && node ../../scripts/index.mjs copy type-check.ts type-check-commonjs.cts && tsc --module commonjs --esModuleInterop type-check-commonjs.cts", diff --git a/test/parse-configuration-test.mjs b/test/parse-configuration-test.mjs new file mode 100644 index 00000000..1406106c --- /dev/null +++ b/test/parse-configuration-test.mjs @@ -0,0 +1,24 @@ +// @ts-check + +import test from "ava"; +import parseConfiguration from "../lib/parse-configuration.mjs"; + +const testObject = { + "string": "text", + "number": 10, + "object": { + "property": "value" + }, + "array": [ 1, 2, 3 ] +}; +const successfulTestObjectResult = { + "config": testObject, + "message": "" +}; +const testObjectJsonString = JSON.stringify(testObject); + +test("json object, default parsers", (t) => { + t.plan(1); + const actual = parseConfiguration("name", testObjectJsonString); + t.deepEqual(actual, successfulTestObjectResult); +});