-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add --verbose
flag
#415
base: master
Are you sure you want to change the base?
add --verbose
flag
#415
Changes from all commits
258c974
4ffb3ae
11663f4
d4d48a2
d29523c
df9cf88
4ab0678
6f6dd18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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}: ✔`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would expect failing files to end with a little 'x'? |
||
}); | ||
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,11 +218,20 @@ 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', 'verbose mode') | ||
.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); | ||
|
||
if (options.quiet && options.verbose) { | ||
options.verbose = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes me feel like it's one setting with three values? |
||
} | ||
|
||
if (options.verbose && !options.output) { | ||
console.log(pkg.name, 'version', pkg.version); | ||
} | ||
|
||
function tryResolvePath(filepath) { | ||
try { | ||
if (path.basename(filepath) === filepath && path.extname(filepath) === '') { | ||
|
@@ -256,6 +291,9 @@ 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 && !options.stdin) { | ||
console.log('files to check:', diff.join(' ')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be all on the same line? That is harder to scan visually. |
||
} | ||
|
||
function lintAndPrint(stdin, files) { | ||
files = files || []; | ||
|
@@ -299,6 +337,10 @@ function lintAndPrint(stdin, files) { | |
const fixResult = markdownlint.sync(fixOptions); | ||
const fixes = fixResult[file].filter(error => error.fixInfo); | ||
if (fixes.length > 0) { | ||
if (options.verbose && !options.output) { | ||
console.log('fixing', file); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there is a colon above, let's use one here also. |
||
} | ||
|
||
const originalText = fs.readFileSync(file, fsOptions); | ||
const fixedText = markdownlintRuleHelpers.applyFixes(originalText, fixes); | ||
if (originalText !== fixedText) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -824,3 +824,79 @@ test('configuration can be .cjs in the ESM (module) workspace', async t => { | |
t.is(result.stderr, ''); | ||
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('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('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); | ||
}); | ||
|
||
test('--verbose flag with --fix for incorrect file', async t => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing test for verbose with broken file (no fix). |
||
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('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); | ||
}); | ||
|
||
test('--output and --verbose with valid input logs nothing to console', async t => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could argue that verbose should always mean "verbose to console". If so, these two test cases would not be different. Just like I don't like how |
||
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); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of keeping this, I think it can be removed and recreated if it is needed. It looks like it is empty exactly when the strings array has no elements?