Skip to content

Commit

Permalink
feat: implement a migrator to upgrade to eslint 6 (vuejs#5085)
Browse files Browse the repository at this point in the history
* refactor: extract deps & config logic to separate files

* feat: implement a migrator to upgrade to eslint 6

* fix: add required deps for eslint v4

* test: move migrator tests to each standalone plugins

* refactor: use spread operator instead of Object.assign
  • Loading branch information
haoqunjiang authored Jan 27, 2020
1 parent 15679de commit a468abf
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
const fs = require('fs')
const path = require('path')
const create = require('@vue/cli-test-utils/createTestProject')
const create = require('@vue/cli-test-utils/createUpgradableProject')
const { logs } = require('@vue/cli-shared-utils')

const Upgrader = require('../lib/Upgrader')

jest.setTimeout(300000)

const outsideTestFolder = path.resolve(__dirname, '../../../../../vue-upgrade-tests')

beforeAll(() => {
if (!fs.existsSync(outsideTestFolder)) {
fs.mkdirSync(outsideTestFolder)
}
})

beforeEach(() => {
process.env.VUE_CLI_TEST_DO_INSTALL_PLUGIN = true
})
Expand All @@ -26,12 +13,12 @@ test('upgrade: plugin-babel v3.5', async () => {
version: '3.5.3'
}
}
}, outsideTestFolder)
})

const pkg = JSON.parse(await project.read('package.json'))
expect(pkg.dependencies).not.toHaveProperty('core-js')

await (new Upgrader(project.dir)).upgrade('babel', {})
await project.upgrade('babel')

const updatedPkg = JSON.parse(await project.read('package.json'))
expect(updatedPkg.dependencies).toHaveProperty('core-js')
Expand All @@ -49,31 +36,13 @@ test('upgrade: plugin-babel with core-js 2', async () => {
version: '3.8.0'
}
}
}, outsideTestFolder)
})

const pkg = JSON.parse(await project.read('package.json'))
expect(pkg.dependencies['core-js']).toMatch('^2')

await (new Upgrader(project.dir)).upgrade('babel', {})
await project.upgrade('babel')

const updatedPkg = JSON.parse(await project.read('package.json'))
expect(updatedPkg.dependencies['core-js']).toMatch('^3')
})

test('upgrade: should add eslint to devDependencies', async () => {
const project = await create('plugin-eslint-v3.0', {
plugins: {
'@vue/cli-plugin-eslint': {
version: '3.0.0'
}
}
}, outsideTestFolder)

const pkg = JSON.parse(await project.read('package.json'))
expect(pkg.devDependencies).not.toHaveProperty('eslint')

await (new Upgrader(project.dir)).upgrade('eslint', {})

const updatedPkg = JSON.parse(await project.read('package.json'))
expect(updatedPkg.devDependencies.eslint).toMatch('^4')
})
68 changes: 68 additions & 0 deletions packages/@vue/cli-plugin-eslint/__tests__/eslintMigrator.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
jest.setTimeout(300000)
jest.mock('inquirer')

beforeEach(() => {
process.env.VUE_CLI_TEST_DO_INSTALL_PLUGIN = true
})

const create = require('@vue/cli-test-utils/createUpgradableProject')
const { expectPrompts } = require('inquirer')

test('upgrade: should add eslint to devDependencies', async () => {
const project = await create('plugin-eslint-v3.0', {
plugins: {
'@vue/cli-plugin-eslint': {
version: '3.0.0'
}
}
})

const pkg = JSON.parse(await project.read('package.json'))
expect(pkg.devDependencies).not.toHaveProperty('eslint')

expectPrompts([
{
message: `Your current ESLint version is v4`,
confirm: false
}
])

await project.upgrade('eslint')

const updatedPkg = JSON.parse(await project.read('package.json'))
expect(updatedPkg.devDependencies.eslint).toMatch('^4')
})

test.only('upgrade: should upgrade eslint from v5 to v6', async () => {
const project = await create('plugin-eslint-with-eslint-5', {
plugins: {
'@vue/cli-plugin-eslint': {
version: '3.12.1',
config: 'airbnb'
}
}
})

const pkg = JSON.parse(await project.read('package.json'))
expect(pkg.devDependencies.eslint).toMatch('^5')

expectPrompts([
{
message: `Your current ESLint version is v5`,
confirm: true
}
])

try {
await project.upgrade('eslint')
} catch (e) {
// TODO:
// Currently the `afterInvoke` hook will fail,
// because deps are not correctly installed in test env.
// Need to fix later.
}

const updatedPkg = JSON.parse(await project.read('package.json'))
expect(updatedPkg.devDependencies.eslint).toMatch('^6')
expect(updatedPkg.devDependencies).toHaveProperty('eslint-plugin-import')
})
45 changes: 45 additions & 0 deletions packages/@vue/cli-plugin-eslint/eslintDeps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const DEPS_MAP = {
base: {
eslint: '^6.7.2',
'eslint-plugin-vue': '^6.1.2'
},
airbnb: {
'@vue/eslint-config-airbnb': '^5.0.1',
'eslint-plugin-import': '^2.18.2'
},
prettier: {
'@vue/eslint-config-prettier': '^6.0.0',
'eslint-plugin-prettier': '^3.1.1',
prettier: '^1.19.1'
},
standard: {
'@vue/eslint-config-standard': '^5.1.0',
'eslint-plugin-import': '^2.18.2',
'eslint-plugin-node': '^9.1.0',
'eslint-plugin-promise': '^4.2.1',
'eslint-plugin-standard': '^4.0.0'
},
typescript: {
'@vue/eslint-config-typescript': '^5.0.1',
'@typescript-eslint/eslint-plugin': '^2.10.0',
'@typescript-eslint/parser': '^2.10.0'
}
}

exports.DEPS_MAP = DEPS_MAP

exports.getDeps = function (api, preset) {
const deps = Object.assign({}, DEPS_MAP.base, DEPS_MAP[preset])

if (api.hasPlugin('typescript')) {
Object.assign(deps, DEPS_MAP.typescript)
}

if (api.hasPlugin('babel') && !api.hasPlugin('typescript')) {
Object.assign(deps, {
'babel-eslint': '^10.0.3'
})
}

return deps
}
26 changes: 25 additions & 1 deletion packages/@vue/cli-plugin-eslint/eslintOptions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
exports.config = api => {
exports.config = (api, preset) => {
const config = {
root: true,
env: { node: true },
Expand All @@ -11,11 +11,35 @@ exports.config = api => {
'no-debugger': makeJSOnlyValue(`process.env.NODE_ENV === 'production' ? 'error' : 'off'`)
}
}

if (api.hasPlugin('babel') && !api.hasPlugin('typescript')) {
config.parserOptions = {
parser: 'babel-eslint'
}
}

if (preset === 'airbnb') {
config.extends.push('@vue/airbnb')
} else if (preset === 'standard') {
config.extends.push('@vue/standard')
} else if (preset === 'prettier') {
config.extends.push(...['eslint:recommended', '@vue/prettier'])
} else {
// default
config.extends.push('eslint:recommended')
}

if (api.hasPlugin('typescript')) {
// typically, typescript ruleset should be appended to the end of the `extends` array
// but that is not the case for prettier, as there are conflicting rules
if (preset === 'prettier') {
config.extends.pop()
config.extends.push(...['@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint'])
} else {
config.extends.push('@vue/typescript/recommended')
}
}

return config
}

Expand Down
73 changes: 6 additions & 67 deletions packages/@vue/cli-plugin-eslint/generator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,74 +2,15 @@ const fs = require('fs')
const path = require('path')

module.exports = (api, { config, lintOn = [] }, _, invoking) => {
const eslintConfig = require('../eslintOptions').config(api)
const extentions = require('../eslintOptions').extensions(api)
.map(ext => ext.replace(/^\./, '')) // remove the leading `.`
const eslintConfig = require('../eslintOptions').config(api, config)
const devDependencies = require('../eslintDeps').getDeps(api, config)

const pkg = {
scripts: {
lint: 'vue-cli-service lint'
},
eslintConfig,
devDependencies: {
eslint: '^6.7.2',
'eslint-plugin-vue': '^6.1.2'
}
}

if (api.hasPlugin('babel') && !api.hasPlugin('typescript')) {
pkg.devDependencies['babel-eslint'] = '^10.0.3'
}

switch (config) {
case 'airbnb':
eslintConfig.extends.push('@vue/airbnb')
Object.assign(pkg.devDependencies, {
'@vue/eslint-config-airbnb': '^5.0.1',
'eslint-plugin-import': '^2.18.2'
})
break
case 'standard':
eslintConfig.extends.push('@vue/standard')
Object.assign(pkg.devDependencies, {
'@vue/eslint-config-standard': '^5.1.0',
'eslint-plugin-import': '^2.18.2',
'eslint-plugin-node': '^9.1.0',
'eslint-plugin-promise': '^4.2.1',
'eslint-plugin-standard': '^4.0.0'
})
break
case 'prettier':
eslintConfig.extends.push(
...(api.hasPlugin('typescript')
? ['eslint:recommended', '@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint']
: ['eslint:recommended', '@vue/prettier']
)
)
Object.assign(pkg.devDependencies, {
'@vue/eslint-config-prettier': '^6.0.0',
'eslint-plugin-prettier': '^3.1.1',
prettier: '^1.19.1'
})
break
default:
// default
eslintConfig.extends.push('eslint:recommended')
break
}

// typescript support
if (api.hasPlugin('typescript')) {
Object.assign(pkg.devDependencies, {
'@vue/eslint-config-typescript': '^5.0.1',
'@typescript-eslint/eslint-plugin': '^2.10.0',
'@typescript-eslint/parser': '^2.10.0'
})
if (config !== 'prettier') {
// for any config other than `prettier`,
// typescript ruleset should be appended to the end of the `extends` array
eslintConfig.extends.push('@vue/typescript/recommended')
}
devDependencies
}

const editorConfigTemplatePath = path.resolve(__dirname, `./template/${config}/_editorconfig`)
Expand Down Expand Up @@ -102,6 +43,8 @@ module.exports = (api, { config, lintOn = [] }, _, invoking) => {
pkg.gitHooks = {
'pre-commit': 'lint-staged'
}
const extentions = require('../eslintOptions').extensions(api)
.map(ext => ext.replace(/^\./, '')) // remove the leading `.`
pkg['lint-staged'] = {
[`*.{${extentions.join(',')}}`]: ['vue-cli-service lint', 'git add']
}
Expand Down Expand Up @@ -157,10 +100,6 @@ module.exports.applyTS = api => {
parser: '@typescript-eslint/parser'
}
},
devDependencies: {
'@vue/eslint-config-typescript': '^5.0.1',
'@typescript-eslint/eslint-plugin': '^2.7.0',
'@typescript-eslint/parser': '^2.7.0'
}
devDependencies: require('../eslintDeps').DEPS_MAP.typescript
})
}
Loading

0 comments on commit a468abf

Please sign in to comment.