From 258c974e08c36d319546ac45105f9fb9d7f5d872 Mon Sep 17 00:00:00 2001 From: meisam Date: Sun, 30 Jul 2023 13:35:31 +0200 Subject: [PATCH 1/8] add --verbose --- markdownlint.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/markdownlint.js b/markdownlint.js index 708a3b78..ff461468 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -192,6 +192,7 @@ program .option('-q, --quiet', 'do not write issues to STDOUT') .option('-r, --rules [file|directory|glob|package]', 'include custom rule files', concatArray, []) .option('-s, --stdin', 'read from STDIN (does not work with files)') + .option('-v, --verbose', 'write filenames to STDOUT') .option('--enable [rules...]', 'Enable certain rules, e.g. --enable MD013 MD041 --') .option('--disable [rules...]', 'Disable certain rules, e.g. --disable MD013 MD041 --'); @@ -295,10 +296,18 @@ function lintAndPrint(stdin, files) { }; const markdownlintRuleHelpers = require('markdownlint/helpers'); for (const file of files) { + if (options.verbose) { + console.log('checking', file); + } + fixOptions.files = [file]; const fixResult = markdownlint.sync(fixOptions); const fixes = fixResult[file].filter(error => error.fixInfo); if (fixes.length > 0) { + if (options.verbose) { + console.log('fixing', file); + } + const originalText = fs.readFileSync(file, fsOptions); const fixedText = markdownlintRuleHelpers.applyFixes(originalText, fixes); if (originalText !== fixedText) { From 4ffb3ae8f1908c3c0dd7900538209fc304c4dea6 Mon Sep 17 00:00:00 2001 From: meisam Date: Sun, 30 Jul 2023 13:55:42 +0200 Subject: [PATCH 2/8] add test for --verbose with --fix --- test/test.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test.js b/test/test.js index fc36d6ea..2a7c5a98 100644 --- a/test/test.js +++ b/test/test.js @@ -824,3 +824,26 @@ test('configuration can be .cjs in the ESM (module) workspace', async t => { t.is(result.stderr, ''); t.is(result.exitCode, 0); }); + +test('--verbose flag with --fix for correct file', async t => { + const result = await execa('../markdownlint.js', ['--fix', '--verbose', 'correct.md'], {stripFinalNewline: false}); + t.true(result.stdout.includes('checking correct.md')); + t.true(!result.stdout.includes('fixing correct.md')); + t.is(result.stderr, ''); + t.is(result.exitCode, 0); +}); + +test('--verbose flag with --fix for incorrect file', async t => { + const fixFileD = 'incorrect.d.mdf'; + try { + fs.copyFileSync('incorrect.md', fixFileD); + await execa('../markdownlint.js', ['--fix', '--verbose', '--config', 'test-config.json', path.resolve(fixFileD)], {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.true(error.stdout.includes('checking ' + path.resolve(fixFileD))); + t.true(error.stdout.includes('fixing ' + path.resolve(fixFileD))); + t.is(error.stderr.match(errorPattern).length, 2); + t.is(error.exitCode, 1); + fs.unlinkSync(fixFileD); + } +}); From 11663f4ff8bdc29a42dd613bed9af54623df36c8 Mon Sep 17 00:00:00 2001 From: meisam Date: Mon, 31 Jul 2023 23:09:53 +0200 Subject: [PATCH 3/8] log filenames in verbose mode --- markdownlint.js | 9 +++++---- test/test.js | 7 +++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/markdownlint.js b/markdownlint.js index ff461468..c760df42 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -257,6 +257,11 @@ const files = prepareFileList(program.args, ['md', 'markdown']).filter(value => const ignores = prepareFileList(options.ignore, ['md', 'markdown'], files); const customRules = loadCustomRules(options.rules); const diff = files.filter(file => !ignores.some(ignore => ignore.absolute === file.absolute)).map(paths => paths.original); +if (options.verbose) { + for (const file of diff) { + console.log('checking', file); + } +} function lintAndPrint(stdin, files) { files = files || []; @@ -296,10 +301,6 @@ function lintAndPrint(stdin, files) { }; const markdownlintRuleHelpers = require('markdownlint/helpers'); for (const file of files) { - if (options.verbose) { - console.log('checking', file); - } - fixOptions.files = [file]; const fixResult = markdownlint.sync(fixOptions); const fixes = fixResult[file].filter(error => error.fixInfo); diff --git a/test/test.js b/test/test.js index 2a7c5a98..b9eacf01 100644 --- a/test/test.js +++ b/test/test.js @@ -825,6 +825,13 @@ test('configuration can be .cjs in the ESM (module) workspace', async t => { t.is(result.exitCode, 0); }); +test('--verbose flag for correct file', async t => { + const result = await execa('../markdownlint.js', ['--verbose', 'correct.md'], {stripFinalNewline: false}); + t.true(result.stdout.includes('checking correct.md')); + t.is(result.stderr, ''); + t.is(result.exitCode, 0); +}); + test('--verbose flag with --fix for correct file', async t => { const result = await execa('../markdownlint.js', ['--fix', '--verbose', 'correct.md'], {stripFinalNewline: false}); t.true(result.stdout.includes('checking correct.md')); From d4d48a2c335a0bcac2e2fd08c785acf48a57e059 Mon Sep 17 00:00:00 2001 From: meisam Date: Tue, 1 Aug 2023 01:11:11 +0200 Subject: [PATCH 4/8] harmonize style --- markdownlint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markdownlint.js b/markdownlint.js index c760df42..4bc9935a 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -192,7 +192,7 @@ program .option('-q, --quiet', 'do not write issues to STDOUT') .option('-r, --rules [file|directory|glob|package]', 'include custom rule files', concatArray, []) .option('-s, --stdin', 'read from STDIN (does not work with files)') - .option('-v, --verbose', 'write filenames to STDOUT') + .option('-v, --verbose', 'write file names to STDOUT') .option('--enable [rules...]', 'Enable certain rules, e.g. --enable MD013 MD041 --') .option('--disable [rules...]', 'Disable certain rules, e.g. --disable MD013 MD041 --'); From d29523c37a4364062ec9c61b4ebac82459d22a20 Mon Sep 17 00:00:00 2001 From: meisam Date: Tue, 1 Aug 2023 23:44:04 +0200 Subject: [PATCH 5/8] log version in verbose mode --- markdownlint.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/markdownlint.js b/markdownlint.js index 4bc9935a..31ba152d 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -198,6 +198,11 @@ program program.parse(process.argv); +if (options.verbose) { + console.log(pkg.name, "version", pkg.version); +} + + function tryResolvePath(filepath) { try { if (path.basename(filepath) === filepath && path.extname(filepath) === '') { From df9cf88331406fde16710fd52d135fdcd9745bd8 Mon Sep 17 00:00:00 2001 From: meisam Date: Wed, 2 Aug 2023 00:36:18 +0200 Subject: [PATCH 6/8] --quiet overrides --verbose --- markdownlint.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/markdownlint.js b/markdownlint.js index 31ba152d..7ba2a3ba 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -198,6 +198,10 @@ program program.parse(process.argv); +if (options.quiet && options.verbose) { + options.verbose = false; +} + if (options.verbose) { console.log(pkg.name, "version", pkg.version); } From 4ab06783cdb8780bbecf0279cccc25a7f9214037 Mon Sep 17 00:00:00 2001 From: meisam Date: Thu, 3 Aug 2023 00:39:49 +0200 Subject: [PATCH 7/8] add more messages to verbose logs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit file names given to and received the library are logged independently linters’s success messages are logged to stdout and fail to stderr --- markdownlint.js | 91 +++++++++++++++++++++++++++++++------------------ test/test.js | 28 +++++++++++++-- 2 files changed, 82 insertions(+), 37 deletions(-) diff --git a/markdownlint.js b/markdownlint.js index 7ba2a3ba..79dfb528 100755 --- a/markdownlint.js +++ b/markdownlint.js @@ -116,48 +116,64 @@ function prepareFileList(files, fileExtensions, previousResults) { } function printResult(lintResult) { - const results = Object.keys(lintResult).flatMap(file => - lintResult[file].map(result => { - if (options.json) { + const results = Object.keys(lintResult) + .flatMap(file => { + if (lintResult[file].length > 0) { + return lintResult[file].map(result => { + if (options.json) { + return { + fileName: file, + ...result + }; + } + + return { + file: file, + lineNumber: result.lineNumber, + column: (result.errorRange && result.errorRange[0]) || 0, + names: result.ruleNames.join('/'), + description: result.ruleDescription + (result.errorDetail ? ' [' + result.errorDetail + ']' : '') + (result.errorContext ? ' [Context: "' + result.errorContext + '"]' : '') + }; + }); + } + + if (options.verbose && !options.json) { return { - fileName: file, - ...result + file: file }; } - return { - file: file, - lineNumber: result.lineNumber, - column: (result.errorRange && result.errorRange[0]) || 0, - names: result.ruleNames.join('/'), - description: result.ruleDescription + (result.errorDetail ? ' [' + result.errorDetail + ']' : '') + (result.errorContext ? ' [Context: "' + result.errorContext + '"]' : '') - }; + return null; }) - ); + .filter(Boolean); let lintResultString = ''; + let lintResultStrings = []; if (results.length > 0) { if (options.json) { + // Note: process.exit(1) will end abruptly, interrupting asynchronous IO + // streams (e.g., when the output is being piped). Just set the exit code + // and let the program terminate normally. + // @see {@link https://nodejs.org/dist/latest-v8.x/docs/api/process.html#process_process_exit_code} + // @see {@link https://github.com/igorshubovych/markdownlint-cli/pull/29#issuecomment-343535291} + process.exitCode = exitCodes.lintFindings; results.sort((a, b) => a.fileName.localeCompare(b.fileName) || a.lineNumber - b.lineNumber || a.ruleDescription.localeCompare(b.ruleDescription)); lintResultString = JSON.stringify(results, null, 2); } else { results.sort((a, b) => a.file.localeCompare(b.file) || a.lineNumber - b.lineNumber || a.names.localeCompare(b.names) || a.description.localeCompare(b.description)); - lintResultString = results - .map(result => { + lintResultStrings = results.map(result => { + if (result.lineNumber) { + process.exitCode = exitCodes.lintFindings; const {file, lineNumber, column, names, description} = result; const columnText = column ? `:${column}` : ''; return `${file}:${lineNumber}${columnText} ${names} ${description}`; - }) - .join('\n'); - } + } - // Note: process.exit(1) will end abruptly, interrupting asynchronous IO - // streams (e.g., when the output is being piped). Just set the exit code - // and let the program terminate normally. - // @see {@link https://nodejs.org/dist/latest-v8.x/docs/api/process.html#process_process_exit_code} - // @see {@link https://github.com/igorshubovych/markdownlint-cli/pull/29#issuecomment-343535291} - process.exitCode = exitCodes.lintFindings; + return `${result.file}: ✔`; + }); + lintResultString = lintResultStrings.join('\n'); + } } if (options.output) { @@ -169,7 +185,17 @@ function printResult(lintResult) { process.exitCode = exitCodes.failedToWriteOutputFile; } } else if (lintResultString && !options.quiet) { - console.error(lintResultString); + if (options.json) { + console.error(lintResultString); + } else { + for (const line of lintResultStrings) { + if (line.endsWith(': ✔')) { + console.log(line); + } else { + console.error(line); + } + } + } } } @@ -192,7 +218,7 @@ program .option('-q, --quiet', 'do not write issues to STDOUT') .option('-r, --rules [file|directory|glob|package]', 'include custom rule files', concatArray, []) .option('-s, --stdin', 'read from STDIN (does not work with files)') - .option('-v, --verbose', 'write file names to STDOUT') + .option('-v, --verbose', 'verbose mode') .option('--enable [rules...]', 'Enable certain rules, e.g. --enable MD013 MD041 --') .option('--disable [rules...]', 'Disable certain rules, e.g. --disable MD013 MD041 --'); @@ -202,11 +228,10 @@ if (options.quiet && options.verbose) { options.verbose = false; } -if (options.verbose) { - console.log(pkg.name, "version", pkg.version); +if (options.verbose && !options.output) { + console.log(pkg.name, 'version', pkg.version); } - function tryResolvePath(filepath) { try { if (path.basename(filepath) === filepath && path.extname(filepath) === '') { @@ -266,10 +291,8 @@ const files = prepareFileList(program.args, ['md', 'markdown']).filter(value => const ignores = prepareFileList(options.ignore, ['md', 'markdown'], files); const customRules = loadCustomRules(options.rules); const diff = files.filter(file => !ignores.some(ignore => ignore.absolute === file.absolute)).map(paths => paths.original); -if (options.verbose) { - for (const file of diff) { - console.log('checking', file); - } +if (options.verbose && !options.stdin) { + console.log('files to check:', diff.join(' ')); } function lintAndPrint(stdin, files) { @@ -314,7 +337,7 @@ function lintAndPrint(stdin, files) { const fixResult = markdownlint.sync(fixOptions); const fixes = fixResult[file].filter(error => error.fixInfo); if (fixes.length > 0) { - if (options.verbose) { + if (options.verbose && !options.output) { console.log('fixing', file); } diff --git a/test/test.js b/test/test.js index b9eacf01..da0ba10a 100644 --- a/test/test.js +++ b/test/test.js @@ -827,14 +827,16 @@ test('configuration can be .cjs in the ESM (module) workspace', async t => { test('--verbose flag for correct file', async t => { const result = await execa('../markdownlint.js', ['--verbose', 'correct.md'], {stripFinalNewline: false}); - t.true(result.stdout.includes('checking correct.md')); + t.true(result.stdout.includes('files to check: correct.md')); + t.true(result.stdout.includes('correct.md: ✔')); t.is(result.stderr, ''); t.is(result.exitCode, 0); }); test('--verbose flag with --fix for correct file', async t => { const result = await execa('../markdownlint.js', ['--fix', '--verbose', 'correct.md'], {stripFinalNewline: false}); - t.true(result.stdout.includes('checking correct.md')); + t.true(result.stdout.includes('files to check: correct.md')); + t.true(result.stdout.includes('correct.md: ✔')); t.true(!result.stdout.includes('fixing correct.md')); t.is(result.stderr, ''); t.is(result.exitCode, 0); @@ -847,10 +849,30 @@ test('--verbose flag with --fix for incorrect file', async t => { await execa('../markdownlint.js', ['--fix', '--verbose', '--config', 'test-config.json', path.resolve(fixFileD)], {stripFinalNewline: false}); t.fail(); } catch (error) { - t.true(error.stdout.includes('checking ' + path.resolve(fixFileD))); + t.true(error.stdout.includes('files to check: ' + path.resolve(fixFileD))); t.true(error.stdout.includes('fixing ' + path.resolve(fixFileD))); t.is(error.stderr.match(errorPattern).length, 2); t.is(error.exitCode, 1); fs.unlinkSync(fixFileD); } }); + +test('--quiet overrides --verbose', async t => { + try { + await execa('../markdownlint.js', ['--quiet', '--verbose', '--config', 'test-config.json', 'incorrect.md'], {stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr, ''); + t.is(error.exitCode, 1); + } +}); + +test('--stdin and --verbose with valid input logs stdin as source', async t => { + const input = ['# Heading', '', 'Text', ''].join('\n'); + const result = await execa('../markdownlint.js', ['--verbose', '--stdin'], {input, stripFinalNewline: false}); + t.true(result.stdout.includes('stdin: ✔')); + t.true(!result.stdout.includes('files to check:')); + t.is(result.stderr, ''); + t.is(result.exitCode, 0); +}); From 6f6dd18a844f6e634775d31a75495f4b545d9826 Mon Sep 17 00:00:00 2001 From: meisam Date: Thu, 3 Aug 2023 22:29:51 +0200 Subject: [PATCH 8/8] add test for --output and --verbose interaction --- test/test.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/test.js b/test/test.js index da0ba10a..e7405ced 100644 --- a/test/test.js +++ b/test/test.js @@ -876,3 +876,27 @@ test('--stdin and --verbose with valid input logs stdin as source', async t => { t.is(result.stderr, ''); t.is(result.exitCode, 0); }); + +test('--output and --verbose with valid input logs nothing to console', async t => { + const input = ['# Heading', '', 'Text', ''].join('\n'); + const output = '../outputG.txt'; + const result = await execa('../markdownlint.js', ['--stdin', '--verbose', '--output', output], {input, stripFinalNewline: false}); + t.is(result.stdout, ''); + t.is(result.stderr, ''); + t.is(result.exitCode, 0); + fs.unlinkSync(output); +}); + +test('--output and --verbose with invalid input logs nothing to console', async t => { + const input = ['Heading', '', 'Text ', ''].join('\n'); + const output = '../outputH.txt'; + try { + await execa('../markdownlint.js', ['--stdin', '--verbose', '--output', output], {input, stripFinalNewline: false}); + t.fail(); + } catch (error) { + t.is(error.stdout, ''); + t.is(error.stderr, ''); + t.is(error.exitCode, 1); + fs.unlinkSync(output); + } +});