From 83f5f4fced1c3f0bbf8a81ad140e2da958e3b783 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 18 May 2018 18:11:30 -0400 Subject: [PATCH] fix(eslint): ensure all config values are contained in config file close #1006, close #1313 --- .../__tests__/eslintGenerator.spec.js | 45 ++++++++++++------- .../@vue/cli-plugin-eslint/eslintOptions.js | 36 +++++++++------ packages/@vue/cli-plugin-eslint/generator.js | 17 ++++--- packages/@vue/cli-plugin-eslint/index.js | 7 +-- packages/@vue/cli-plugin-eslint/lint.js | 11 ++--- .../@vue/cli/lib/util/configTransforms.js | 11 ++++- 6 files changed, 80 insertions(+), 47 deletions(-) diff --git a/packages/@vue/cli-plugin-eslint/__tests__/eslintGenerator.spec.js b/packages/@vue/cli-plugin-eslint/__tests__/eslintGenerator.spec.js index 0959abc0ff..4a15191678 100644 --- a/packages/@vue/cli-plugin-eslint/__tests__/eslintGenerator.spec.js +++ b/packages/@vue/cli-plugin-eslint/__tests__/eslintGenerator.spec.js @@ -8,9 +8,11 @@ test('base', async () => { }) expect(pkg.scripts.lint).toBeTruthy() - expect(pkg.eslintConfig).toEqual({ - root: true, - extends: ['plugin:vue/essential', 'eslint:recommended'] + expect(pkg.eslintConfig.extends).toEqual([ + 'plugin:vue/essential', 'eslint:recommended' + ]) + expect(pkg.eslintConfig.parserOptions).toEqual({ + parser: 'babel-eslint' }) }) @@ -24,9 +26,12 @@ test('airbnb', async () => { }) expect(pkg.scripts.lint).toBeTruthy() - expect(pkg.eslintConfig).toEqual({ - root: true, - extends: ['plugin:vue/essential', '@vue/airbnb'] + expect(pkg.eslintConfig.extends).toEqual([ + 'plugin:vue/essential', + '@vue/airbnb' + ]) + expect(pkg.eslintConfig.parserOptions).toEqual({ + parser: 'babel-eslint' }) expect(pkg.devDependencies).toHaveProperty('@vue/eslint-config-airbnb') }) @@ -41,9 +46,12 @@ test('standard', async () => { }) expect(pkg.scripts.lint).toBeTruthy() - expect(pkg.eslintConfig).toEqual({ - root: true, - extends: ['plugin:vue/essential', '@vue/standard'] + expect(pkg.eslintConfig.extends).toEqual([ + 'plugin:vue/essential', + '@vue/standard' + ]) + expect(pkg.eslintConfig.parserOptions).toEqual({ + parser: 'babel-eslint' }) expect(pkg.devDependencies).toHaveProperty('@vue/eslint-config-standard') }) @@ -58,9 +66,12 @@ test('prettier', async () => { }) expect(pkg.scripts.lint).toBeTruthy() - expect(pkg.eslintConfig).toEqual({ - root: true, - extends: ['plugin:vue/essential', '@vue/prettier'] + expect(pkg.eslintConfig.extends).toEqual([ + 'plugin:vue/essential', + '@vue/prettier' + ]) + expect(pkg.eslintConfig.parserOptions).toEqual({ + parser: 'babel-eslint' }) expect(pkg.devDependencies).toHaveProperty('@vue/eslint-config-prettier') }) @@ -82,10 +93,12 @@ test('typescript', async () => { ]) expect(pkg.scripts.lint).toBeTruthy() - expect(pkg.eslintConfig).toEqual({ - root: true, - extends: ['plugin:vue/essential', '@vue/prettier', '@vue/typescript'] - }) + expect(pkg.eslintConfig.extends).toEqual([ + 'plugin:vue/essential', + '@vue/prettier', + '@vue/typescript' + ]) + expect(pkg.eslintConfig).not.toHaveProperty('parserOptions') expect(pkg.devDependencies).toHaveProperty('@vue/eslint-config-prettier') expect(pkg.devDependencies).toHaveProperty('@vue/eslint-config-typescript') }) diff --git a/packages/@vue/cli-plugin-eslint/eslintOptions.js b/packages/@vue/cli-plugin-eslint/eslintOptions.js index 2620d8f0b6..5c2896a0f0 100644 --- a/packages/@vue/cli-plugin-eslint/eslintOptions.js +++ b/packages/@vue/cli-plugin-eslint/eslintOptions.js @@ -1,20 +1,30 @@ -module.exports = api => { - const options = { - extensions: ['.js', '.vue'], - envs: ['node'], +exports.config = api => { + const config = { + root: true, + env: { node: true }, + extends: ['plugin:vue/essential'], rules: { - 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' + 'no-console': makeJSOnlyValue(`process.env.NODE_ENV === 'production' ? 'error' : 'off'`), + 'no-debugger': makeJSOnlyValue(`process.env.NODE_ENV === 'production' ? 'error' : 'off'`) } } - - if (api.hasPlugin('typescript')) { - options.extensions.push('.ts') - } else { - options.parserOptions = { - parser: require.resolve('babel-eslint') + if (!api.hasPlugin('typescript')) { + config.parserOptions = { + parser: 'babel-eslint' } } + return config +} - return options +// __expression is a special flag that allows us to customize stringification +// output when extracting configs into standalone files +function makeJSOnlyValue (str) { + const fn = () => {} + fn.__expression = str + return fn } + +const baseExtensions = ['.js', '.jsx', '.vue'] +exports.extensions = api => api.hasPlugin('typescript') + ? baseExtensions.concat('.ts', '.tsx') + : baseExtensions diff --git a/packages/@vue/cli-plugin-eslint/generator.js b/packages/@vue/cli-plugin-eslint/generator.js index ee519ff337..6a8156bb3a 100644 --- a/packages/@vue/cli-plugin-eslint/generator.js +++ b/packages/@vue/cli-plugin-eslint/generator.js @@ -3,40 +3,39 @@ module.exports = (api, { config, lintOn = [] }) => { lintOn = lintOn.split(',') } + const eslintConfig = require('./eslintOptions').config(api) + const pkg = { scripts: { lint: 'vue-cli-service lint' }, - eslintConfig: { - root: true, - extends: ['plugin:vue/essential'] - }, + eslintConfig, devDependencies: {} } if (config === 'airbnb') { - pkg.eslintConfig.extends.push('@vue/airbnb') + eslintConfig.extends.push('@vue/airbnb') Object.assign(pkg.devDependencies, { '@vue/eslint-config-airbnb': '^3.0.0-beta.10' }) } else if (config === 'standard') { - pkg.eslintConfig.extends.push('@vue/standard') + eslintConfig.extends.push('@vue/standard') Object.assign(pkg.devDependencies, { '@vue/eslint-config-standard': '^3.0.0-beta.10' }) } else if (config === 'prettier') { - pkg.eslintConfig.extends.push('@vue/prettier') + eslintConfig.extends.push('@vue/prettier') Object.assign(pkg.devDependencies, { '@vue/eslint-config-prettier': '^3.0.0-beta.10' }) } else { // default - pkg.eslintConfig.extends.push('eslint:recommended') + eslintConfig.extends.push('eslint:recommended') } // typescript support if (api.hasPlugin('typescript')) { - pkg.eslintConfig.extends.push('@vue/typescript') + eslintConfig.extends.push('@vue/typescript') Object.assign(pkg.devDependencies, { '@vue/eslint-config-typescript': '^3.0.0-beta.10' }) diff --git a/packages/@vue/cli-plugin-eslint/index.js b/packages/@vue/cli-plugin-eslint/index.js index 9428601aff..3dd40fad16 100644 --- a/packages/@vue/cli-plugin-eslint/index.js +++ b/packages/@vue/cli-plugin-eslint/index.js @@ -1,6 +1,6 @@ module.exports = (api, { lintOnSave }) => { if (lintOnSave) { - const options = require('./eslintOptions')(api) + const extensions = require('./eslintOptions').extensions(api) api.chainWebpack(webpackConfig => { webpackConfig.module .rule('eslint') @@ -12,10 +12,11 @@ module.exports = (api, { lintOnSave }) => { .test(/\.(vue|(j|t)sx?)$/) .use('eslint-loader') .loader('eslint-loader') - .options(Object.assign(options, { + .options({ + extensions, emitWarning: lintOnSave !== 'error', formatter: require('eslint/lib/formatters/codeframe') - })) + }) }) } diff --git a/packages/@vue/cli-plugin-eslint/lint.js b/packages/@vue/cli-plugin-eslint/lint.js index 6adbdf7d68..121da29273 100644 --- a/packages/@vue/cli-plugin-eslint/lint.js +++ b/packages/@vue/cli-plugin-eslint/lint.js @@ -20,12 +20,13 @@ module.exports = function lint (args = {}, api) { const chalk = require('chalk') const cwd = api.resolve('.') const { CLIEngine } = require('eslint') - const options = require('./eslintOptions')(api) const { log, done } = require('@vue/cli-shared-utils') const files = args._ && args._.length ? args._ : ['src', 'tests', '*.js'] + const extensions = require('./eslintOptions').extensions(api) const argsConfig = normalizeConfig(args) - const config = Object.assign({}, options, { + const config = Object.assign({ + extensions, fix: true, cwd }, argsConfig) @@ -36,7 +37,7 @@ module.exports = function lint (args = {}, api) { if (config.fix) { CLIEngine.outputFixes(report) } - + const maxErrors = argsConfig.maxErrors || 0 const maxWarnings = typeof argsConfig.maxWarnings === 'number' ? argsConfig.maxWarnings : Infinity const isErrorsExceeded = report.errorCount > maxErrors @@ -63,10 +64,10 @@ module.exports = function lint (args = {}, api) { } } else { console.log(formatter(report.results)) - if (isErrorsExceed && typeof argsConfig.maxErrors === 'number') { + if (isErrorsExceeded && typeof argsConfig.maxErrors === 'number') { log(`Eslint found too many errors (maximum: ${argsConfig.maxErrors}).`) } - if (isWarningsExceed) { + if (isWarningsExceeded) { log(`Eslint found too many warnings (maximum: ${argsConfig.maxWarnings}).`) } process.exit(1) diff --git a/packages/@vue/cli/lib/util/configTransforms.js b/packages/@vue/cli/lib/util/configTransforms.js index 99fed4e9c9..24efb354cb 100644 --- a/packages/@vue/cli/lib/util/configTransforms.js +++ b/packages/@vue/cli/lib/util/configTransforms.js @@ -1,7 +1,16 @@ const fs = require('fs') const path = require('path') const extendJSConfig = require('./extendJSConfig') -const stringifyJS = require('javascript-stringify') +const stringify = require('javascript-stringify') + +function stringifyJS (value) { + return stringify(value, (val, indent, stringify) => { + if (val && val.__expression) { + return val.__expression + } + return stringify(val) + }, 2) +} function makeJSTransform (filename) { return function transformToJS (value, checkExisting, context) {