From c7994f39e8720bad61e604faa45e0c8a476ac62d Mon Sep 17 00:00:00 2001 From: Benjamin Wilking Date: Tue, 13 Feb 2024 16:45:53 +0100 Subject: [PATCH 1/6] add possibility to parse toml files like pyproject.toml add small fix to js and json config file --- README.md | 13 ++++++++++++- markdownlint.js | 10 +++++++++- package-lock.json | 13 ++++++++++++- package.json | 3 ++- test/md043-config.js | 2 +- test/md043-config.json | 2 +- test/md043-config.toml | 3 +++ test/test.js | 7 +++++++ 8 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 test/md043-config.toml diff --git a/README.md b/README.md index 46010e737..f1d35daf5 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Because this option makes changes to the input files, it is good to make a backu `markdownlint-cli` reuses [the rules][rules] from `markdownlint` package. -Configuration is stored in JSON, JSONC, YAML, or INI files in the same [config format][config]. +Configuration is stored in JSON, JSONC, YAML, or INI files in the same [config format][config]. Further, configuration can be stored as TOML file under ```[tool.markdownlint]``` A sample configuration file: @@ -102,6 +102,15 @@ A sample configuration file: } ``` +```toml +[tool.markdownlint] +default = true +heading-style = { style = "atx_closed" } +ul-indent = { indent = 4 } +no-hard-tabs = false +whitespace = false +``` + For more examples, see [.markdownlint.jsonc][markdownlint-jsonc], [.markdownlint.yaml][markdownlint-yaml], or the [style folder][style-folder]. The CLI argument `--config` is not required. @@ -118,6 +127,8 @@ If a rule is passed to both `--enable` and `--disable`, it will be disabled. > JS configuration files must be provided via the `--config` argument; they are not automatically loaded because running untrusted code is a security concern. +> TOML configuration files must be provided via the `--config` argument; they are not automatically loaded. + ## Exit codes `markdownlint-cli` returns one of the following exit codes: diff --git a/markdownlint.js b/markdownlint.js index 8d6984704..4f880901f 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -36,6 +36,10 @@ function yamlParse(text) { return require('js-yaml').load(text); } +function tomlParse(text) { + return require('toml').parse(text).tool.markdownlint; +} + const exitCodes = { lintFindings: 1, failedToWriteOutputFile: 2, @@ -44,7 +48,7 @@ const exitCodes = { }; const projectConfigFiles = ['.markdownlint.jsonc', '.markdownlint.json', '.markdownlint.yaml', '.markdownlint.yml']; -const configParsers = [jsoncParse, yamlParse]; +const configParsers = [jsoncParse, yamlParse, tomlParse]; const fsOptions = {encoding: 'utf8'}; const processCwd = process.cwd(); @@ -330,3 +334,7 @@ try { console.error(error); process.exit(exitCodes.unexpectedError); } + + + +"Unable to parse '../ci-analytics-poc/pyproject.toml'; Parser 0: Unable to parse JSON(C) content, InvalidSymbol (offset 1, length 23), InvalidSymbol (offset 26, length 10), InvalidSymbol (offset 37, length 1), EndOfFileExpected (offset 39, length 1); Parser 1: end of the stream or a document separator is expected (2:1)\n\n 1 | [tool.pytest.ini_options]\n 2 | pythonpath = [\n-----^\n 3 | \"ci_analytics_automation/issue ...\n 4 | ]; Parser 2: a is not defined" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f1746e366..57e22b02b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,8 @@ "jsonc-parser": "~3.2.1", "markdownlint": "~0.33.0", "minimatch": "~9.0.3", - "run-con": "~1.3.2" + "run-con": "~1.3.2", + "toml": "^3.0.0" }, "bin": { "markdownlint": "markdownlint.js" @@ -7015,6 +7016,11 @@ "node": ">=8.0" } }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -12768,6 +12774,11 @@ "is-number": "^7.0.0" } }, + "toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", diff --git a/package.json b/package.json index 979bacd95..e8654bea3 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "jsonc-parser": "~3.2.1", "markdownlint": "~0.33.0", "minimatch": "~9.0.3", - "run-con": "~1.3.2" + "run-con": "~1.3.2", + "toml": "^3.0.0" }, "devDependencies": { "ava": "^6.1.1", diff --git a/test/md043-config.js b/test/md043-config.js index 77a6849d4..ea1c133e1 100644 --- a/test/md043-config.js +++ b/test/md043-config.js @@ -6,6 +6,6 @@ module.exports = { MD012: false, MD043: { - headers: ['# First', '## Second', '### Third'] + headings: ['# First', '## Second', '### Third'] } }; diff --git a/test/md043-config.json b/test/md043-config.json index d9844a936..990663de2 100644 --- a/test/md043-config.json +++ b/test/md043-config.json @@ -1,7 +1,7 @@ { "MD012": false, "MD043": { - "headers": [ + "headings": [ "# First", "## Second", "### Third" diff --git a/test/md043-config.toml b/test/md043-config.toml new file mode 100644 index 000000000..1265a71be --- /dev/null +++ b/test/md043-config.toml @@ -0,0 +1,3 @@ +[tool.markdownlint] +MD012 = false +MD043 = { headings = ["# First", "## Second", "### Third"] } \ No newline at end of file diff --git a/test/test.js b/test/test.js index 70f8d84c6..a1003e821 100644 --- a/test/test.js +++ b/test/test.js @@ -400,6 +400,13 @@ test('configuration file can be JavaScript', async t => { t.is(result.exitCode, 0); }); +test('configuration file can be TOML', async t => { + const result = await execa('../markdownlint.js', ['--config', 'md043-config.toml', 'md043-config.md'], {stripFinalNewline: false}); + t.is(result.stdout, ''); + t.is(result.stderr, ''); + t.is(result.exitCode, 0); +}); + test('error on configuration file not found', async t => { try { await execa('../markdownlint.js', ['--config', 'non-existent-file-path.yaml', 'correct.md'], {stripFinalNewline: false}); From ded23fdca1a6de1d996c0f2dcd607ac872f8100b Mon Sep 17 00:00:00 2001 From: Benjamin Wilking <102791996+BenniWi@users.noreply.github.com> Date: Wed, 14 Feb 2024 08:01:10 +0100 Subject: [PATCH 2/6] remove debugging stuff --- markdownlint.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/markdownlint.js b/markdownlint.js index 4f880901f..7843fd107 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -334,7 +334,3 @@ try { console.error(error); process.exit(exitCodes.unexpectedError); } - - - -"Unable to parse '../ci-analytics-poc/pyproject.toml'; Parser 0: Unable to parse JSON(C) content, InvalidSymbol (offset 1, length 23), InvalidSymbol (offset 26, length 10), InvalidSymbol (offset 37, length 1), EndOfFileExpected (offset 39, length 1); Parser 1: end of the stream or a document separator is expected (2:1)\n\n 1 | [tool.pytest.ini_options]\n 2 | pythonpath = [\n-----^\n 3 | \"ci_analytics_automation/issue ...\n 4 | ]; Parser 2: a is not defined" \ No newline at end of file From 400e3c40d5e634cce8a2e5280c98de57f4b9b201 Mon Sep 17 00:00:00 2001 From: Benjamin Wilking <102791996+BenniWi@users.noreply.github.com> Date: Wed, 14 Feb 2024 08:02:31 +0100 Subject: [PATCH 3/6] fix missing newline in md043-config.toml --- test/md043-config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/md043-config.toml b/test/md043-config.toml index 1265a71be..1b644d40f 100644 --- a/test/md043-config.toml +++ b/test/md043-config.toml @@ -1,3 +1,3 @@ [tool.markdownlint] MD012 = false -MD043 = { headings = ["# First", "## Second", "### Third"] } \ No newline at end of file +MD043 = { headings = ["# First", "## Second", "### Third"] } From ae3615b9bebde62ff90511cfa767ec6d712db88b Mon Sep 17 00:00:00 2001 From: Benjamin Wilking Date: Mon, 19 Feb 2024 12:39:06 +0100 Subject: [PATCH 4/6] use root to find configuration of toml file --- README.md | 5 +---- markdownlint.js | 5 +++-- test/config-files/toml/.markdownlint.toml | 2 ++ test/config-files/toml/heading-dollar.md | 3 +++ test/md043-config.toml | 1 - test/test.js | 2 ++ 6 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 test/config-files/toml/.markdownlint.toml create mode 100644 test/config-files/toml/heading-dollar.md diff --git a/README.md b/README.md index f1d35daf5..4dc5e5837 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Because this option makes changes to the input files, it is good to make a backu `markdownlint-cli` reuses [the rules][rules] from `markdownlint` package. -Configuration is stored in JSON, JSONC, YAML, or INI files in the same [config format][config]. Further, configuration can be stored as TOML file under ```[tool.markdownlint]``` +Configuration is stored in JSON, JSONC, YAML, INI, or TOML files in the same [config format][config]. A sample configuration file: @@ -103,7 +103,6 @@ A sample configuration file: ``` ```toml -[tool.markdownlint] default = true heading-style = { style = "atx_closed" } ul-indent = { indent = 4 } @@ -127,8 +126,6 @@ If a rule is passed to both `--enable` and `--disable`, it will be disabled. > JS configuration files must be provided via the `--config` argument; they are not automatically loaded because running untrusted code is a security concern. -> TOML configuration files must be provided via the `--config` argument; they are not automatically loaded. - ## Exit codes `markdownlint-cli` returns one of the following exit codes: diff --git a/markdownlint.js b/markdownlint.js index 7843fd107..108add706 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -37,7 +37,7 @@ function yamlParse(text) { } function tomlParse(text) { - return require('toml').parse(text).tool.markdownlint; + return require('toml').parse(text); } const exitCodes = { @@ -47,7 +47,7 @@ const exitCodes = { unexpectedError: 4 }; -const projectConfigFiles = ['.markdownlint.jsonc', '.markdownlint.json', '.markdownlint.yaml', '.markdownlint.yml']; +const projectConfigFiles = ['.markdownlint.jsonc', '.markdownlint.json', '.markdownlint.yaml', '.markdownlint.yml', '.markdownlint.toml']; const configParsers = [jsoncParse, yamlParse, tomlParse]; const fsOptions = {encoding: 'utf8'}; const processCwd = process.cwd(); @@ -57,6 +57,7 @@ function readConfiguration(userConfigFile) { // Load from well-known config files let config = rc('markdownlint', {}); + for (const projectConfigFile of projectConfigFiles) { try { fs.accessSync(projectConfigFile, fs.R_OK); diff --git a/test/config-files/toml/.markdownlint.toml b/test/config-files/toml/.markdownlint.toml new file mode 100644 index 000000000..8db87e7fc --- /dev/null +++ b/test/config-files/toml/.markdownlint.toml @@ -0,0 +1,2 @@ +[no-trailing-punctuation] +punctuation="$" diff --git a/test/config-files/toml/heading-dollar.md b/test/config-files/toml/heading-dollar.md new file mode 100644 index 000000000..d976ce366 --- /dev/null +++ b/test/config-files/toml/heading-dollar.md @@ -0,0 +1,3 @@ +# Heading$ + +Text diff --git a/test/md043-config.toml b/test/md043-config.toml index 1b644d40f..e40f3c285 100644 --- a/test/md043-config.toml +++ b/test/md043-config.toml @@ -1,3 +1,2 @@ -[tool.markdownlint] MD012 = false MD043 = { headings = ["# First", "## Second", "### Third"] } diff --git a/test/test.js b/test/test.js index a1003e821..70ee2e66b 100644 --- a/test/test.js +++ b/test/test.js @@ -448,6 +448,8 @@ test('.markdownlint.jsonc in cwd is used automatically', getCwdConfigFileTest('j test('.markdownlint.json in cwd is used automatically', getCwdConfigFileTest('json')); +test('.markdownlint.toml in cwd is used automatically', getCwdConfigFileTest('toml')); + test('.markdownlint.yaml in cwd is used automatically', getCwdConfigFileTest('yaml')); test('.markdownlint.yml in cwd is used automatically', getCwdConfigFileTest('yml')); From 6b5899dc65d82cee89486fb2a027ed5fd153d27a Mon Sep 17 00:00:00 2001 From: Benjamin Wilking Date: Tue, 20 Feb 2024 08:55:40 +0100 Subject: [PATCH 5/6] fix review comments and add additional tests also chang the order of parsers to be used --- README.md | 15 ++++---------- markdownlint.js | 9 +++++---- package.json | 2 +- test/config-files/toml/.markdownlint.toml | 2 -- test/config-files/toml/heading-dollar.md | 3 --- test/test-config.toml | 14 +++++++++++++ test/test-config.yaml | 12 ++++++++++++ test/test.js | 24 +++++++++++++++++++++-- 8 files changed, 58 insertions(+), 23 deletions(-) delete mode 100644 test/config-files/toml/.markdownlint.toml delete mode 100644 test/config-files/toml/heading-dollar.md create mode 100644 test/test-config.toml create mode 100644 test/test-config.yaml diff --git a/README.md b/README.md index 4dc5e5837..f7493981f 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ markdownlint --help Options: -V, --version output the version number - -c, --config [configFile] configuration file (JSON, JSONC, JS, or YAML) + -c, --config [configFile] configuration file (JSON, JSONC, JS, YAML, or TOML) -d, --dot include files/folders with a dot (for example `.github`) -f, --fix fix basic errors (does not work with STDIN) -i, --ignore [file|directory|glob] file(s) to ignore/exclude (default: []) @@ -102,15 +102,7 @@ A sample configuration file: } ``` -```toml -default = true -heading-style = { style = "atx_closed" } -ul-indent = { indent = 4 } -no-hard-tabs = false -whitespace = false -``` - -For more examples, see [.markdownlint.jsonc][markdownlint-jsonc], [.markdownlint.yaml][markdownlint-yaml], or the [style folder][style-folder]. +For more examples, see [.markdownlint.jsonc][markdownlint-jsonc], [.markdownlint.yaml][markdownlint-yaml], [test-config.toml](test/test-config.toml) or the [style folder][style-folder]. The CLI argument `--config` is not required. If it is not provided, `markdownlint-cli` looks for the file `.markdownlint.jsonc`/`.markdownlint.json`/`.markdownlint.yaml`/`.markdownlint.yml` in current folder, or for the file `.markdownlintrc` in the current or all parent folders. @@ -124,7 +116,8 @@ A JS configuration file may internally `require` one or more npm packages as a w `--enable` and `--disable` override configuration files; if a configuration file disables `MD123` and you pass `--enable MD123`, it will be enabled. If a rule is passed to both `--enable` and `--disable`, it will be disabled. -> JS configuration files must be provided via the `--config` argument; they are not automatically loaded because running untrusted code is a security concern. +> - JS configuration files must be provided via the `--config` argument; they are not automatically loaded because running untrusted code is a security concern. +> - TOML configuration files must be provided via the `--config` argument; they are not automatically loaded. ## Exit codes diff --git a/markdownlint.js b/markdownlint.js index 108add706..8edafcf45 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -37,7 +37,8 @@ function yamlParse(text) { } function tomlParse(text) { - return require('toml').parse(text); + //It is necessary to add the prototype manually because of https://github.com/BinaryMuse/toml-node/issues/55 + return require('deep-extend')({}, require('toml').parse(text)); } const exitCodes = { @@ -47,8 +48,9 @@ const exitCodes = { unexpectedError: 4 }; -const projectConfigFiles = ['.markdownlint.jsonc', '.markdownlint.json', '.markdownlint.yaml', '.markdownlint.yml', '.markdownlint.toml']; -const configParsers = [jsoncParse, yamlParse, tomlParse]; +const projectConfigFiles = ['.markdownlint.jsonc', '.markdownlint.json', '.markdownlint.yaml', '.markdownlint.yml']; +// toml files can be (incorrectly) read by yamlParse but not vice versa -> tomlParse needs to go first in the list +const configParsers = [jsoncParse, tomlParse, yamlParse]; const fsOptions = {encoding: 'utf8'}; const processCwd = process.cwd(); @@ -57,7 +59,6 @@ function readConfiguration(userConfigFile) { // Load from well-known config files let config = rc('markdownlint', {}); - for (const projectConfigFile of projectConfigFiles) { try { fs.accessSync(projectConfigFile, fs.R_OK); diff --git a/package.json b/package.json index e8654bea3..77b696968 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "markdownlint": "~0.33.0", "minimatch": "~9.0.3", "run-con": "~1.3.2", - "toml": "^3.0.0" + "toml": "~3.0.0" }, "devDependencies": { "ava": "^6.1.1", diff --git a/test/config-files/toml/.markdownlint.toml b/test/config-files/toml/.markdownlint.toml deleted file mode 100644 index 8db87e7fc..000000000 --- a/test/config-files/toml/.markdownlint.toml +++ /dev/null @@ -1,2 +0,0 @@ -[no-trailing-punctuation] -punctuation="$" diff --git a/test/config-files/toml/heading-dollar.md b/test/config-files/toml/heading-dollar.md deleted file mode 100644 index d976ce366..000000000 --- a/test/config-files/toml/heading-dollar.md +++ /dev/null @@ -1,3 +0,0 @@ -# Heading$ - -Text diff --git a/test/test-config.toml b/test/test-config.toml new file mode 100644 index 000000000..30e4697f6 --- /dev/null +++ b/test/test-config.toml @@ -0,0 +1,14 @@ +default = true +no-hard-tabs = false +whitespace = false +MD033 = false +MD034 = false + +[MD003] +style = "atx" + +[MD007] +indent = 4 + +[MD013] +line_length = 200 diff --git a/test/test-config.yaml b/test/test-config.yaml new file mode 100644 index 000000000..ce01fb632 --- /dev/null +++ b/test/test-config.yaml @@ -0,0 +1,12 @@ +default: true +no-hard-tabs: false +whitespace: false +MD033: false +MD034: false +MD003: + style: atx +MD007: + indent: 2 +MD013: + line_length: 200 + diff --git a/test/test.js b/test/test.js index 70ee2e66b..59a31c518 100644 --- a/test/test.js +++ b/test/test.js @@ -407,6 +407,28 @@ test('configuration file can be TOML', async t => { t.is(result.exitCode, 0); }); +test('linting using a toml configuration file works', async t => { + try { + await execa('../markdownlint.js', ['--config', 'test-config.toml', '**/*.md'], {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr.match(errorPattern).length, 15); + t.is(error.exitCode, 1); + } +}); + +test('linting using a yaml configuration file works', async t => { + try { + await execa('../markdownlint.js', ['--config', 'test-config.yaml', '**/*.md'], {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr.match(errorPattern).length, 15); + t.is(error.exitCode, 1); + } +}); + test('error on configuration file not found', async t => { try { await execa('../markdownlint.js', ['--config', 'non-existent-file-path.yaml', 'correct.md'], {stripFinalNewline: false}); @@ -448,8 +470,6 @@ test('.markdownlint.jsonc in cwd is used automatically', getCwdConfigFileTest('j test('.markdownlint.json in cwd is used automatically', getCwdConfigFileTest('json')); -test('.markdownlint.toml in cwd is used automatically', getCwdConfigFileTest('toml')); - test('.markdownlint.yaml in cwd is used automatically', getCwdConfigFileTest('yaml')); test('.markdownlint.yml in cwd is used automatically', getCwdConfigFileTest('yml')); From 8a7341020df13835d8a1727d8c4610477afa525f Mon Sep 17 00:00:00 2001 From: David Anson Date: Tue, 20 Feb 2024 18:51:26 -0800 Subject: [PATCH 6/6] Address 2 lint violations. --- markdownlint.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/markdownlint.js b/markdownlint.js index 8edafcf45..c025abe84 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -37,7 +37,7 @@ function yamlParse(text) { } function tomlParse(text) { - //It is necessary to add the prototype manually because of https://github.com/BinaryMuse/toml-node/issues/55 + // It is necessary to add the prototype manually because of https://github.com/BinaryMuse/toml-node/issues/55 return require('deep-extend')({}, require('toml').parse(text)); } @@ -49,7 +49,7 @@ const exitCodes = { }; const projectConfigFiles = ['.markdownlint.jsonc', '.markdownlint.json', '.markdownlint.yaml', '.markdownlint.yml']; -// toml files can be (incorrectly) read by yamlParse but not vice versa -> tomlParse needs to go first in the list +// TOML files can be (incorrectly) read by yamlParse (but not vice versa), so tomlParse needs to go before yamlParse const configParsers = [jsoncParse, tomlParse, yamlParse]; const fsOptions = {encoding: 'utf8'}; const processCwd = process.cwd();