From 482d288bfea2f52f06e81bc886fc4daf077e2b86 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 11 Jan 2018 11:34:17 -0500 Subject: [PATCH] refactor linter prompts and compat w/ TS --- __mocks__/inquirer.js | 3 ++ packages/@vue/cli-plugin-eslint/generator.js | 6 +-- .../cli-plugin-typescript/generator/index.js | 46 +++++++++++++------ .../generator/template/src/views/About.vue | 7 --- .../generator/template/tslint.json | 2 + packages/@vue/cli-plugin-typescript/index.js | 5 +- packages/@vue/cli/lib/create.js | 8 ++-- .../{eslint.spec.js => linter.spec.js} | 24 +++++----- .../__tests__/typescript.spec.js | 43 +++++++++++++++++ .../promptModules/{eslint.js => linter.js} | 26 +++++------ .../@vue/cli/lib/promptModules/typescript.js | 7 ++- 11 files changed, 120 insertions(+), 57 deletions(-) delete mode 100644 packages/@vue/cli-plugin-typescript/generator/template/src/views/About.vue rename packages/@vue/cli/lib/promptModules/__tests__/{eslint.spec.js => linter.spec.js} (80%) create mode 100644 packages/@vue/cli/lib/promptModules/__tests__/typescript.spec.js rename packages/@vue/cli/lib/promptModules/{eslint.js => linter.js} (68%) diff --git a/__mocks__/inquirer.js b/__mocks__/inquirer.js index 307f56f7a..3383be398 100644 --- a/__mocks__/inquirer.js +++ b/__mocks__/inquirer.js @@ -26,6 +26,9 @@ exports.prompt = prompts => { } const a = pendingAssertions[i - skipped] + if (!a) { + console.error(`no matching assertion for prompt:`, prompt) + } if (a.message) { const message = typeof prompt.message === 'function' diff --git a/packages/@vue/cli-plugin-eslint/generator.js b/packages/@vue/cli-plugin-eslint/generator.js index 9fdfc3738..5755a90fe 100644 --- a/packages/@vue/cli-plugin-eslint/generator.js +++ b/packages/@vue/cli-plugin-eslint/generator.js @@ -1,4 +1,4 @@ -module.exports = (api, { config, lintOn }) => { +module.exports = (api, { config, lintOn = [] }) => { const pkg = { scripts: { lint: 'vue-cli-service lint' @@ -28,13 +28,13 @@ module.exports = (api, { config, lintOn }) => { pkg.eslintConfig.extends.push('eslint:recommended') } - if (lintOn === 'save') { + if (lintOn.includes('save')) { pkg.vue = { lintOnSave: true // eslint-loader configured in runtime plugin } } - if (lintOn === 'commit') { + if (lintOn.includes('commit')) { Object.assign(pkg.devDependencies, { 'lint-staged': '^6.0.0' }) diff --git a/packages/@vue/cli-plugin-typescript/generator/index.js b/packages/@vue/cli-plugin-typescript/generator/index.js index ce251fee9..2156a6866 100644 --- a/packages/@vue/cli-plugin-typescript/generator/index.js +++ b/packages/@vue/cli-plugin-typescript/generator/index.js @@ -1,11 +1,5 @@ -module.exports = (api, options) => { - api.extendPackage({ - scripts: { - lint: 'vue-cli-service lint' - } - }) - - if (options.classComponent) { +module.exports = (api, { classComponent, lint, lintOn = [] }) => { + if (classComponent) { api.extendPackage({ devDependencies: { 'vue-class-component': '^6.0.0', @@ -14,6 +8,37 @@ module.exports = (api, options) => { }) } + if (lint) { + api.extendPackage({ + scripts: { + lint: 'vue-cli-service lint' + }, + vue: { + lintOnSave: lintOn.includes('save') + } + }) + + if (lintOn.includes('commit')) { + api.extendPackage({ + devDependencies: { + 'lint-staged': '^6.0.0' + }, + gitHooks: { + 'pre-commit': 'lint-staged' + }, + 'lint-staged': { + '*.js': ['vue-cli-service lint', 'git add'], + '*.vue': ['vue-cli-service lint', 'git add'] + } + }) + } + + // lint and fix files on creation complete + api.onCreateComplete(() => { + return require('../lib/tslint')({}, api, true) + }) + } + // inject necessary typings for other plugins const hasMocha = api.hasPlugin('@vue/cli-plugin-unit-mocha') @@ -57,9 +82,4 @@ module.exports = (api, options) => { } } }) - - // lint and fix files on creation complete - api.onCreateComplete(() => { - return require('../lib/tslint')({}, api, true) - }) } diff --git a/packages/@vue/cli-plugin-typescript/generator/template/src/views/About.vue b/packages/@vue/cli-plugin-typescript/generator/template/src/views/About.vue deleted file mode 100644 index 72e8abd0d..000000000 --- a/packages/@vue/cli-plugin-typescript/generator/template/src/views/About.vue +++ /dev/null @@ -1,7 +0,0 @@ -<%_ if (rootOptions.router) { _%> - -<%_ } _%> diff --git a/packages/@vue/cli-plugin-typescript/generator/template/tslint.json b/packages/@vue/cli-plugin-typescript/generator/template/tslint.json index 8db22b351..b01d0512f 100644 --- a/packages/@vue/cli-plugin-typescript/generator/template/tslint.json +++ b/packages/@vue/cli-plugin-typescript/generator/template/tslint.json @@ -1,3 +1,4 @@ +<%_ if (options.lint) { _%> { "defaultSeverity": "warning", "extends": [ @@ -11,3 +12,4 @@ "object-literal-sort-keys": false } } +<%_ } _%> diff --git a/packages/@vue/cli-plugin-typescript/index.js b/packages/@vue/cli-plugin-typescript/index.js index b451f6b3a..7eb9c3f31 100644 --- a/packages/@vue/cli-plugin-typescript/index.js +++ b/packages/@vue/cli-plugin-typescript/index.js @@ -1,4 +1,4 @@ -module.exports = api => { +module.exports = (api, options) => { api.chainWebpack(config => { config.entry('app') .clear() @@ -26,8 +26,7 @@ module.exports = api => { .plugin('fork-ts-checker') .use(require('fork-ts-checker-webpack-plugin'), [{ vue: true, - tslint: true, - silent: true, + tslint: options.lintOnSave, formatter: 'codeframe' }]) }) diff --git a/packages/@vue/cli/lib/create.js b/packages/@vue/cli/lib/create.js index 6d9536b06..4c2db22d5 100644 --- a/packages/@vue/cli/lib/create.js +++ b/packages/@vue/cli/lib/create.js @@ -36,14 +36,14 @@ async function create (projectName, options) { const promptModules = [ 'babel', + 'typescript', + 'pwa', 'router', 'vuex', 'cssPreprocessors', - 'eslint', + 'linter', 'unit', - 'e2e', - 'pwa', - 'typescript' + 'e2e' ].map(file => require(`./promptModules/${file}`)) const creator = new Creator(projectName, targetDir, promptModules) diff --git a/packages/@vue/cli/lib/promptModules/__tests__/eslint.spec.js b/packages/@vue/cli/lib/promptModules/__tests__/linter.spec.js similarity index 80% rename from packages/@vue/cli/lib/promptModules/__tests__/eslint.spec.js rename to packages/@vue/cli/lib/promptModules/__tests__/linter.spec.js index afdb44bf3..542bfb70c 100644 --- a/packages/@vue/cli/lib/promptModules/__tests__/eslint.spec.js +++ b/packages/@vue/cli/lib/promptModules/__tests__/linter.spec.js @@ -3,7 +3,7 @@ jest.mock('inquirer') const assertPromptModule = require('@vue/cli-test-utils/assertPromptModule') -const moduleToTest = require('../eslint') +const moduleToTest = require('../linter') test('base', async () => { const expectedPrompts = [ @@ -18,9 +18,9 @@ test('base', async () => { choose: 0 }, { - message: 'Pick a lint mode', - choices: ['on save', 'on commit', 'Manually'], - choose: 0 + message: 'Pick additional lint features', + choices: ['on save', 'on commit'], + check: [0, 1] } ] @@ -28,7 +28,7 @@ test('base', async () => { plugins: { '@vue/cli-plugin-eslint': { config: 'base', - lintOn: 'save' + lintOn: ['save', 'commit'] } } } @@ -54,9 +54,8 @@ test('airbnb', async () => { choose: 1 }, { - message: 'Pick a lint mode', - choices: ['on save', 'on commit', 'Manually'], - choose: 1 + choices: ['on save', 'on commit'], + check: [1] } ] @@ -64,7 +63,7 @@ test('airbnb', async () => { plugins: { '@vue/cli-plugin-eslint': { config: 'airbnb', - lintOn: 'commit' + lintOn: ['commit'] } } } @@ -90,9 +89,8 @@ test('standard', async () => { choose: 2 }, { - message: 'Pick a lint mode', - choices: ['on save', 'on commit', 'Manually'], - choose: 2 + choices: ['on save', 'on commit'], + check: [] } ] @@ -100,7 +98,7 @@ test('standard', async () => { plugins: { '@vue/cli-plugin-eslint': { config: 'standard', - lintOn: false + lintOn: [] } } } diff --git a/packages/@vue/cli/lib/promptModules/__tests__/typescript.spec.js b/packages/@vue/cli/lib/promptModules/__tests__/typescript.spec.js new file mode 100644 index 000000000..ec3332f07 --- /dev/null +++ b/packages/@vue/cli/lib/promptModules/__tests__/typescript.spec.js @@ -0,0 +1,43 @@ +jest.mock('fs') +jest.mock('inquirer') + +const assertPromptModule = require('@vue/cli-test-utils/assertPromptModule') + +const moduleToTest = require('../typescript') +const linterModule = require('../linter') + +test('should work', async () => { + const expectedPrompts = [ + { + message: 'features', + choices: ['TypeScript', 'Linter'], + check: [0, 1] + }, + { + message: 'Use class-style component', + confirm: true + }, + { + message: 'Pick additional lint features', + choices: ['on save', 'on commit'], + check: [0, 1] + } + ] + + const expectedOptions = { + plugins: { + '@vue/cli-plugin-typescript': { + classComponent: true, + lint: true, + lintOn: ['save', 'commit'] + } + } + } + + await assertPromptModule( + [moduleToTest, linterModule], + expectedPrompts, + expectedOptions, + { plguinsOnly: true } + ) +}) diff --git a/packages/@vue/cli/lib/promptModules/eslint.js b/packages/@vue/cli/lib/promptModules/linter.js similarity index 68% rename from packages/@vue/cli/lib/promptModules/eslint.js rename to packages/@vue/cli/lib/promptModules/linter.js index 789c689c2..b0b8cad03 100644 --- a/packages/@vue/cli/lib/promptModules/eslint.js +++ b/packages/@vue/cli/lib/promptModules/linter.js @@ -3,14 +3,17 @@ module.exports = cli => { const { hasGit } = require('@vue/cli-shared-utils') cli.injectFeature({ - name: 'Linter', - value: 'eslint', + name: 'Linter / Formatter', + value: 'linter', short: 'Linter' }) cli.injectPrompt({ name: 'eslintConfig', - when: answers => answers.features.includes('eslint'), + when: answers => ( + answers.features.includes('linter') && + !answers.features.includes('ts') + ), type: 'list', message: 'Pick a lint config:', choices: [ @@ -39,27 +42,24 @@ module.exports = cli => { cli.injectPrompt({ name: 'lintOn', - message: 'Pick a lint mode:', - when: answers => answers.features.includes('eslint'), - type: 'list', + message: 'Pick additional lint features:', + when: answers => answers.features.includes('linter'), + type: 'checkbox', choices: [ { - name: 'Lint + fix on save', + name: 'Lint on save', value: 'save' }, { - name: 'Lint + fix on commit' + (hasGit ? '' : chalk.red(' (requires Git)')), + name: 'Lint and fix on commit' + (hasGit ? '' : chalk.red(' (requires Git)')), value: 'commit' - }, - { - name: 'Manually run npm script', - value: false } ] }) cli.onPromptComplete((answers, options) => { - if (answers.features.includes('eslint')) { + if (answers.features.includes('linter') && + !answers.features.includes('ts')) { options.plugins['@vue/cli-plugin-eslint'] = { config: answers.eslintConfig, lintOn: answers.lintOn diff --git a/packages/@vue/cli/lib/promptModules/typescript.js b/packages/@vue/cli/lib/promptModules/typescript.js index 1d80fb263..6f709f450 100644 --- a/packages/@vue/cli/lib/promptModules/typescript.js +++ b/packages/@vue/cli/lib/promptModules/typescript.js @@ -14,9 +14,14 @@ module.exports = cli => { cli.onPromptComplete((answers, options) => { if (answers.features.includes('ts')) { - options.plugins['@vue/cli-plugin-typescript'] = { + const tsOptions = { classComponent: answers.tsClassComponent } + if (answers.features.includes('linter')) { + tsOptions.lint = true + tsOptions.lintOn = answers.lintOn + } + options.plugins['@vue/cli-plugin-typescript'] = tsOptions } }) }