Skip to content

Commit a468abf

Browse files
authored
feat: implement a migrator to upgrade to eslint 6 (#5085)
* 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
1 parent 15679de commit a468abf

File tree

8 files changed

+236
-118
lines changed

8 files changed

+236
-118
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,7 @@
1-
const fs = require('fs')
2-
const path = require('path')
3-
const create = require('@vue/cli-test-utils/createTestProject')
1+
const create = require('@vue/cli-test-utils/createUpgradableProject')
42
const { logs } = require('@vue/cli-shared-utils')
53

6-
const Upgrader = require('../lib/Upgrader')
7-
84
jest.setTimeout(300000)
9-
10-
const outsideTestFolder = path.resolve(__dirname, '../../../../../vue-upgrade-tests')
11-
12-
beforeAll(() => {
13-
if (!fs.existsSync(outsideTestFolder)) {
14-
fs.mkdirSync(outsideTestFolder)
15-
}
16-
})
17-
185
beforeEach(() => {
196
process.env.VUE_CLI_TEST_DO_INSTALL_PLUGIN = true
207
})
@@ -26,12 +13,12 @@ test('upgrade: plugin-babel v3.5', async () => {
2613
version: '3.5.3'
2714
}
2815
}
29-
}, outsideTestFolder)
16+
})
3017

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

34-
await (new Upgrader(project.dir)).upgrade('babel', {})
21+
await project.upgrade('babel')
3522

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

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

57-
await (new Upgrader(project.dir)).upgrade('babel', {})
44+
await project.upgrade('babel')
5845

5946
const updatedPkg = JSON.parse(await project.read('package.json'))
6047
expect(updatedPkg.dependencies['core-js']).toMatch('^3')
6148
})
62-
63-
test('upgrade: should add eslint to devDependencies', async () => {
64-
const project = await create('plugin-eslint-v3.0', {
65-
plugins: {
66-
'@vue/cli-plugin-eslint': {
67-
version: '3.0.0'
68-
}
69-
}
70-
}, outsideTestFolder)
71-
72-
const pkg = JSON.parse(await project.read('package.json'))
73-
expect(pkg.devDependencies).not.toHaveProperty('eslint')
74-
75-
await (new Upgrader(project.dir)).upgrade('eslint', {})
76-
77-
const updatedPkg = JSON.parse(await project.read('package.json'))
78-
expect(updatedPkg.devDependencies.eslint).toMatch('^4')
79-
})
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
jest.setTimeout(300000)
2+
jest.mock('inquirer')
3+
4+
beforeEach(() => {
5+
process.env.VUE_CLI_TEST_DO_INSTALL_PLUGIN = true
6+
})
7+
8+
const create = require('@vue/cli-test-utils/createUpgradableProject')
9+
const { expectPrompts } = require('inquirer')
10+
11+
test('upgrade: should add eslint to devDependencies', async () => {
12+
const project = await create('plugin-eslint-v3.0', {
13+
plugins: {
14+
'@vue/cli-plugin-eslint': {
15+
version: '3.0.0'
16+
}
17+
}
18+
})
19+
20+
const pkg = JSON.parse(await project.read('package.json'))
21+
expect(pkg.devDependencies).not.toHaveProperty('eslint')
22+
23+
expectPrompts([
24+
{
25+
message: `Your current ESLint version is v4`,
26+
confirm: false
27+
}
28+
])
29+
30+
await project.upgrade('eslint')
31+
32+
const updatedPkg = JSON.parse(await project.read('package.json'))
33+
expect(updatedPkg.devDependencies.eslint).toMatch('^4')
34+
})
35+
36+
test.only('upgrade: should upgrade eslint from v5 to v6', async () => {
37+
const project = await create('plugin-eslint-with-eslint-5', {
38+
plugins: {
39+
'@vue/cli-plugin-eslint': {
40+
version: '3.12.1',
41+
config: 'airbnb'
42+
}
43+
}
44+
})
45+
46+
const pkg = JSON.parse(await project.read('package.json'))
47+
expect(pkg.devDependencies.eslint).toMatch('^5')
48+
49+
expectPrompts([
50+
{
51+
message: `Your current ESLint version is v5`,
52+
confirm: true
53+
}
54+
])
55+
56+
try {
57+
await project.upgrade('eslint')
58+
} catch (e) {
59+
// TODO:
60+
// Currently the `afterInvoke` hook will fail,
61+
// because deps are not correctly installed in test env.
62+
// Need to fix later.
63+
}
64+
65+
const updatedPkg = JSON.parse(await project.read('package.json'))
66+
expect(updatedPkg.devDependencies.eslint).toMatch('^6')
67+
expect(updatedPkg.devDependencies).toHaveProperty('eslint-plugin-import')
68+
})
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const DEPS_MAP = {
2+
base: {
3+
eslint: '^6.7.2',
4+
'eslint-plugin-vue': '^6.1.2'
5+
},
6+
airbnb: {
7+
'@vue/eslint-config-airbnb': '^5.0.1',
8+
'eslint-plugin-import': '^2.18.2'
9+
},
10+
prettier: {
11+
'@vue/eslint-config-prettier': '^6.0.0',
12+
'eslint-plugin-prettier': '^3.1.1',
13+
prettier: '^1.19.1'
14+
},
15+
standard: {
16+
'@vue/eslint-config-standard': '^5.1.0',
17+
'eslint-plugin-import': '^2.18.2',
18+
'eslint-plugin-node': '^9.1.0',
19+
'eslint-plugin-promise': '^4.2.1',
20+
'eslint-plugin-standard': '^4.0.0'
21+
},
22+
typescript: {
23+
'@vue/eslint-config-typescript': '^5.0.1',
24+
'@typescript-eslint/eslint-plugin': '^2.10.0',
25+
'@typescript-eslint/parser': '^2.10.0'
26+
}
27+
}
28+
29+
exports.DEPS_MAP = DEPS_MAP
30+
31+
exports.getDeps = function (api, preset) {
32+
const deps = Object.assign({}, DEPS_MAP.base, DEPS_MAP[preset])
33+
34+
if (api.hasPlugin('typescript')) {
35+
Object.assign(deps, DEPS_MAP.typescript)
36+
}
37+
38+
if (api.hasPlugin('babel') && !api.hasPlugin('typescript')) {
39+
Object.assign(deps, {
40+
'babel-eslint': '^10.0.3'
41+
})
42+
}
43+
44+
return deps
45+
}

packages/@vue/cli-plugin-eslint/eslintOptions.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
exports.config = api => {
1+
exports.config = (api, preset) => {
22
const config = {
33
root: true,
44
env: { node: true },
@@ -11,11 +11,35 @@ exports.config = api => {
1111
'no-debugger': makeJSOnlyValue(`process.env.NODE_ENV === 'production' ? 'error' : 'off'`)
1212
}
1313
}
14+
1415
if (api.hasPlugin('babel') && !api.hasPlugin('typescript')) {
1516
config.parserOptions = {
1617
parser: 'babel-eslint'
1718
}
1819
}
20+
21+
if (preset === 'airbnb') {
22+
config.extends.push('@vue/airbnb')
23+
} else if (preset === 'standard') {
24+
config.extends.push('@vue/standard')
25+
} else if (preset === 'prettier') {
26+
config.extends.push(...['eslint:recommended', '@vue/prettier'])
27+
} else {
28+
// default
29+
config.extends.push('eslint:recommended')
30+
}
31+
32+
if (api.hasPlugin('typescript')) {
33+
// typically, typescript ruleset should be appended to the end of the `extends` array
34+
// but that is not the case for prettier, as there are conflicting rules
35+
if (preset === 'prettier') {
36+
config.extends.pop()
37+
config.extends.push(...['@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint'])
38+
} else {
39+
config.extends.push('@vue/typescript/recommended')
40+
}
41+
}
42+
1943
return config
2044
}
2145

packages/@vue/cli-plugin-eslint/generator/index.js

Lines changed: 6 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,15 @@ const fs = require('fs')
22
const path = require('path')
33

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

98
const pkg = {
109
scripts: {
1110
lint: 'vue-cli-service lint'
1211
},
1312
eslintConfig,
14-
devDependencies: {
15-
eslint: '^6.7.2',
16-
'eslint-plugin-vue': '^6.1.2'
17-
}
18-
}
19-
20-
if (api.hasPlugin('babel') && !api.hasPlugin('typescript')) {
21-
pkg.devDependencies['babel-eslint'] = '^10.0.3'
22-
}
23-
24-
switch (config) {
25-
case 'airbnb':
26-
eslintConfig.extends.push('@vue/airbnb')
27-
Object.assign(pkg.devDependencies, {
28-
'@vue/eslint-config-airbnb': '^5.0.1',
29-
'eslint-plugin-import': '^2.18.2'
30-
})
31-
break
32-
case 'standard':
33-
eslintConfig.extends.push('@vue/standard')
34-
Object.assign(pkg.devDependencies, {
35-
'@vue/eslint-config-standard': '^5.1.0',
36-
'eslint-plugin-import': '^2.18.2',
37-
'eslint-plugin-node': '^9.1.0',
38-
'eslint-plugin-promise': '^4.2.1',
39-
'eslint-plugin-standard': '^4.0.0'
40-
})
41-
break
42-
case 'prettier':
43-
eslintConfig.extends.push(
44-
...(api.hasPlugin('typescript')
45-
? ['eslint:recommended', '@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint']
46-
: ['eslint:recommended', '@vue/prettier']
47-
)
48-
)
49-
Object.assign(pkg.devDependencies, {
50-
'@vue/eslint-config-prettier': '^6.0.0',
51-
'eslint-plugin-prettier': '^3.1.1',
52-
prettier: '^1.19.1'
53-
})
54-
break
55-
default:
56-
// default
57-
eslintConfig.extends.push('eslint:recommended')
58-
break
59-
}
60-
61-
// typescript support
62-
if (api.hasPlugin('typescript')) {
63-
Object.assign(pkg.devDependencies, {
64-
'@vue/eslint-config-typescript': '^5.0.1',
65-
'@typescript-eslint/eslint-plugin': '^2.10.0',
66-
'@typescript-eslint/parser': '^2.10.0'
67-
})
68-
if (config !== 'prettier') {
69-
// for any config other than `prettier`,
70-
// typescript ruleset should be appended to the end of the `extends` array
71-
eslintConfig.extends.push('@vue/typescript/recommended')
72-
}
13+
devDependencies
7314
}
7415

7516
const editorConfigTemplatePath = path.resolve(__dirname, `./template/${config}/_editorconfig`)
@@ -102,6 +43,8 @@ module.exports = (api, { config, lintOn = [] }, _, invoking) => {
10243
pkg.gitHooks = {
10344
'pre-commit': 'lint-staged'
10445
}
46+
const extentions = require('../eslintOptions').extensions(api)
47+
.map(ext => ext.replace(/^\./, '')) // remove the leading `.`
10548
pkg['lint-staged'] = {
10649
[`*.{${extentions.join(',')}}`]: ['vue-cli-service lint', 'git add']
10750
}
@@ -157,10 +100,6 @@ module.exports.applyTS = api => {
157100
parser: '@typescript-eslint/parser'
158101
}
159102
},
160-
devDependencies: {
161-
'@vue/eslint-config-typescript': '^5.0.1',
162-
'@typescript-eslint/eslint-plugin': '^2.7.0',
163-
'@typescript-eslint/parser': '^2.7.0'
164-
}
103+
devDependencies: require('../eslintDeps').DEPS_MAP.typescript
165104
})
166105
}

0 commit comments

Comments
 (0)