diff --git a/packages/@vue/cli-plugin-eslint/README.md b/packages/@vue/cli-plugin-eslint/README.md index 804af750ec..94ebd2c1fc 100644 --- a/packages/@vue/cli-plugin-eslint/README.md +++ b/packages/@vue/cli-plugin-eslint/README.md @@ -15,11 +15,12 @@ --no-fix do not fix errors --max-errors specify number of errors to make build failed (default: 0) --max-warnings specify number of warnings to make build failed (default: Infinity) + --output-file specify file to write report to ``` Lints and fixes files. If no specific files are given, it lints all files in `src` and `test`. - Other [ESLint CLI options](https://eslint.org/docs/user-guide/command-line-interface#options) are also supported. + Other [ESLint CLI options](https://eslint.org/docs/user-guide/command-line-interface#options) are not supported. ## Configuration diff --git a/packages/@vue/cli-plugin-eslint/__tests__/eslintPlugin.spec.js b/packages/@vue/cli-plugin-eslint/__tests__/eslintPlugin.spec.js index 80ea409740..a4aa46fe69 100644 --- a/packages/@vue/cli-plugin-eslint/__tests__/eslintPlugin.spec.js +++ b/packages/@vue/cli-plugin-eslint/__tests__/eslintPlugin.spec.js @@ -140,3 +140,58 @@ test('should not throw when src folder is ignored by .eslintignore', async () => // should not throw await run('vue-cli-service lint') }) + +test('should save report results to file with --output-file option', async () => { + const project = await create('eslint-output-file', { + plugins: { + '@vue/cli-plugin-babel': {}, + '@vue/cli-plugin-eslint': { + config: 'airbnb', + lintOn: 'commit' + } + } + }) + const { read, write, run } = project + // should've applied airbnb autofix + const main = await read('src/main.js') + expect(main).toMatch(';') + // remove semicolons + const updatedMain = main.replace(/;/g, '') + await write('src/main.js', updatedMain) + + // result file name + const resultsFile = 'lint_results.json' + + try { + // lint in JSON format to output-file + await run(`vue-cli-service lint --format json --output-file ${resultsFile} --no-fix`) + } catch (e) { + // lint with no fix should fail + expect(e.code).toBe(1) + expect(e.failed).toBeTruthy() + } + + let resultsFileContents = '' + + // results file should exist + try { + resultsFileContents = await read(resultsFile) + } catch (e) { + expect(e.code).toBe(0) + expect(e.failed).toBeFalsy() + } + + // results file should not be empty + expect(resultsFileContents.length).toBeGreaterThan(0) + + // results file is valid JSON + try { + JSON.parse(resultsFileContents) + } catch (e) { + expect(e.code).toBe(0) + expect(e.failed).toBeFalsy() + } + + // results file should show "Missing semicolon" errors + expect(resultsFileContents).toEqual(expect.stringContaining('Missing semicolon')) +}) diff --git a/packages/@vue/cli-plugin-eslint/index.js b/packages/@vue/cli-plugin-eslint/index.js index addc5d0358..532683e876 100644 --- a/packages/@vue/cli-plugin-eslint/index.js +++ b/packages/@vue/cli-plugin-eslint/index.js @@ -72,7 +72,9 @@ module.exports = (api, options) => { '--max-errors [limit]': 'specify number of errors to make build failed (default: 0)', '--max-warnings [limit]': - 'specify number of warnings to make build failed (default: Infinity)' + 'specify number of warnings to make build failed (default: Infinity)', + '--output-file [file_path]': + 'specify file to write report to' }, details: 'For more options, see https://eslint.org/docs/user-guide/command-line-interface#options' diff --git a/packages/@vue/cli-plugin-eslint/lint.js b/packages/@vue/cli-plugin-eslint/lint.js index 518fb1c68f..9d5eec9ea1 100644 --- a/packages/@vue/cli-plugin-eslint/lint.js +++ b/packages/@vue/cli-plugin-eslint/lint.js @@ -15,7 +15,8 @@ const renamedArgs = { rule: 'rules', eslintrc: 'useEslintrc', c: 'configFile', - config: 'configFile' + config: 'configFile', + 'output-file': 'outputFile' } module.exports = function lint (args = {}, api) { @@ -83,6 +84,16 @@ module.exports = function lint (args = {}, api) { const formatter = engine.getFormatter(args.format || 'codeframe') + if (config.outputFile) { + const outputFilePath = path.resolve(config.outputFile) + try { + fs.writeFileSync(outputFilePath, formatter(report.results)) + log(`Lint results saved to ${chalk.blue(outputFilePath)}`) + } catch (err) { + log(`Error saving lint results to ${chalk.blue(outputFilePath)}: ${chalk.red(err)}`) + } + } + if (config.fix) { CLIEngine.outputFixes(report) }