From 3182fa01467e8fe391caa60ff5de8eb184afdd0e Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Tue, 16 Nov 2021 04:31:44 +0000 Subject: [PATCH] Add --enable and --disable CLI flags (fixes #214) --- README.md | 12 ++++-- markdownlint.js | 16 +++++++- test/default-false-config.yml | 1 + test/test.js | 69 +++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 test/default-false-config.yml diff --git a/README.md b/README.md index 80136482..9ece1caa 100644 --- a/README.md +++ b/README.md @@ -26,19 +26,20 @@ markdownlint --help MarkdownLint Command Line Interface Options: - - -h, --help output usage information -V, --version output the version number -c, --config [configFile] configuration file (JSON, JSONC, JS, or YAML) -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 + -i, --ignore [file|directory|glob] file(s) to ignore/exclude (default: []) -j, --json write issues in json format -o, --output [outputFile] write issues to file (no console) -p, --ignore-path [file] path to file with ignore pattern(s) -q, --quiet do not write issues to STDOUT - -r, --rules [file|directory|glob|package] custom rule files + -r, --rules [file|directory|glob|package] include custom rule files (default: []) -s, --stdin read from STDIN (does not work with files) + --enable [rules...] Enable certain rules, e.g. --enable MD013 MD041 + --disable [rules...] Disable certain rules, e.g. --disable MD013 MD041 + -h, --help display help for command ``` ### Globbing @@ -101,6 +102,9 @@ If the `--config` argument is provided, the file must be valid JSON, JSONC, JS, JS configuration files contain JavaScript code, must have the `.js` extension, and must export (via `module.exports = ...`) a configuration object of the form shown above. A JS configuration file may internally `require` one or more npm packages as a way of reusing configuration across projects. +`--enable` and `--disable` override configuration files; if a configuration file disables `MD002` and you pass `--enable MD002`, 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. ## Exit codes diff --git a/markdownlint.js b/markdownlint.js index b697013d..343d352f 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -216,8 +216,10 @@ program .option('-o, --output [outputFile]', 'write issues to file (no console)') .option('-p, --ignore-path [file]', 'path to file with ignore pattern(s)') .option('-q, --quiet', 'do not write issues to STDOUT') - .option('-r, --rules [file|directory|glob|package]', 'custom rule files', concatArray, []) - .option('-s, --stdin', 'read from STDIN (does not work with files)'); + .option('-r, --rules [file|directory|glob|package]', 'include custom rule files', concatArray, []) + .option('-s, --stdin', 'read from STDIN (does not work with files)') + .option('--enable [rules...]', 'Enable certain rules, e.g. --enable MD013 MD041') + .option('--disable [rules...]', 'Disable certain rules, e.g. --disable MD013 MD041'); program.parse(process.argv); @@ -291,6 +293,16 @@ const diff = differenceWith(files, ignores, function (a, b) { function lintAndPrint(stdin, files) { files = files || []; const config = readConfiguration(options.config); + + for (const rule of options.enable || []) { + // leave default values in place if rule is an object + if (!config[rule]) { + config[rule] = true; + } + } + for (const rule of options.disable || []) { + config[rule] = false; + } const lintOptions = { config, customRules, diff --git a/test/default-false-config.yml b/test/default-false-config.yml new file mode 100644 index 00000000..e20e3245 --- /dev/null +++ b/test/default-false-config.yml @@ -0,0 +1 @@ +default: false diff --git a/test/test.js b/test/test.js index 3537d13b..cef53b9b 100644 --- a/test/test.js +++ b/test/test.js @@ -851,3 +851,72 @@ test('with --quiet option does not print to stdout or stderr', async t => { t.is(error.exitCode, 1) } }); + +test('--enable flag', async t => { + try { + await execa('../markdownlint.js', + ['--enable', 'MD002', '--config', 'default-false-config.yml', 'incorrect.md'], + {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr, 'incorrect.md:1 MD002/first-heading-h1/first-header-h1 First heading should be a top-level heading [Expected: h1; Actual: h2]\n'); + t.is(error.exitCode, 1) + } +}); + +test('--enable flag does not modify already enabled rules', async t => { + try { + await execa('../markdownlint.js', + ['--enable', 'MD043', '--config', 'md043-config.yaml', 'correct.md'], + {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr, 'correct.md:1 MD043/required-headings/required-headers Required heading structure [Expected: # First; Actual: # header]\n'); + t.is(error.exitCode, 1) + } +}); + +test('--enable flag accepts rule alias', async t => { + try { + await execa('../markdownlint.js', + ['--enable', 'first-header-h1', '--config', 'default-false-config.yml', 'incorrect.md'], + {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr, 'incorrect.md:1 MD002/first-heading-h1/first-header-h1 First heading should be a top-level heading [Expected: h1; Actual: h2]\n'); + t.is(error.exitCode, 1) + } +}); + +test('--disable flag', async t => { + const result = await execa('../markdownlint.js', + ['--disable', 'MD002', 'MD014', 'MD022', 'MD041', '--', 'incorrect.md'], + {stripFinalNewline: false}); + + t.is(result.stdout, ''); + t.is(result.stderr, ''); + t.is(result.exitCode, 0) + + try { + await execa('../markdownlint.js', + ['--disable', 'MD014', 'MD014', 'MD022', '--', 'incorrect.md'], + {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr, 'incorrect.md:1 MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "## header 2"]\n'); + t.is(error.exitCode, 1) + } +}); + +test('--disable flag overrides --enable flag', async t => { + const result = await execa('../markdownlint.js', + ['--disable', 'MD002', '--enable', 'MD002', '--config', 'default-false-config.yml', 'incorrect.md'], + {stripFinalNewline: false}); + t.is(result.stdout, ''); + t.is(result.stderr, ''); + t.is(result.exitCode, 0) +});