mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-03-13 12:40:18 -05:00
refactor(generator): ensure proper deep merge of array values in api.extendPackage
Also fixes #970 by injecting eslint config when invoking ts plugin in an existing project with eslint plugin installed.
This commit is contained in:
@@ -73,6 +73,18 @@ module.exports = (api, {
|
||||
})
|
||||
}
|
||||
|
||||
const hasESLint = api.hasPlugin('eslint')
|
||||
if (hasESLint) {
|
||||
api.extendPackage({
|
||||
devDependencies: {
|
||||
'@vue/eslint-config-typescript': '^3.0.0-rc.5'
|
||||
},
|
||||
eslintConfig: {
|
||||
extends: ['@vue/typescript']
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
api.render('./template', {
|
||||
isTest: process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG,
|
||||
hasMocha,
|
||||
|
||||
@@ -76,7 +76,7 @@ test('invoke with prompts', async () => {
|
||||
await assertUpdates(project)
|
||||
})
|
||||
|
||||
test('invoke with existing files', async () => {
|
||||
test('invoke with ts', async () => {
|
||||
const project = await create(`invoke-existing`, {
|
||||
useConfigFiles: true,
|
||||
plugins: {
|
||||
@@ -86,7 +86,7 @@ test('invoke with existing files', async () => {
|
||||
})
|
||||
// mock install
|
||||
const pkg = JSON.parse(await project.read('package.json'))
|
||||
pkg.devDependencies['@vue/cli-plugin-eslint'] = '*'
|
||||
pkg.devDependencies['@vue/cli-plugin-typescript'] = '*'
|
||||
await project.write('package.json', JSON.stringify(pkg, null, 2))
|
||||
|
||||
// mock existing vue.config.js
|
||||
@@ -97,11 +97,12 @@ test('invoke with existing files', async () => {
|
||||
extends: ['plugin:vue/essential', 'eslint:recommended']
|
||||
}))
|
||||
|
||||
await project.run(`${require.resolve('../bin/vue')} invoke eslint --config airbnb --lintOn commit`)
|
||||
await project.run(`${require.resolve('../bin/vue')} invoke typescript --classComponent --useTsWithBabel`)
|
||||
|
||||
await assertUpdates(project)
|
||||
const updatedVueConfig = await project.read('vue.config.js')
|
||||
expect(updatedVueConfig).toMatch(`module.exports = { lintOnSave: false }`)
|
||||
const updatedESLintrc = parseJS(await project.read('.eslintrc.js'))
|
||||
expect(updatedESLintrc).toEqual(Object.assign({}, baseESLintConfig, {
|
||||
extends: ['plugin:vue/essential', 'eslint:recommended', '@vue/typescript']
|
||||
}))
|
||||
})
|
||||
|
||||
test('invoke with existing files (yaml)', async () => {
|
||||
@@ -109,13 +110,9 @@ test('invoke with existing files (yaml)', async () => {
|
||||
useConfigFiles: true,
|
||||
plugins: {
|
||||
'@vue/cli-plugin-babel': {},
|
||||
'@vue/cli-plugin-eslint': { config: 'base' }
|
||||
'@vue/cli-plugin-eslint': {}
|
||||
}
|
||||
})
|
||||
// mock install
|
||||
const pkg = JSON.parse(await project.read('package.json'))
|
||||
pkg.devDependencies['@vue/cli-plugin-eslint'] = '*'
|
||||
await project.write('package.json', JSON.stringify(pkg, null, 2))
|
||||
|
||||
const eslintrc = parseJS(await project.read('.eslintrc.js'))
|
||||
expect(eslintrc).toEqual(Object.assign({}, baseESLintConfig, {
|
||||
@@ -137,6 +134,7 @@ extends:
|
||||
extends:
|
||||
- 'plugin:vue/essential'
|
||||
- 'eslint:recommended'
|
||||
- '@vue/airbnb'
|
||||
`.trim())
|
||||
})
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ const ConfigTransform = require('./ConfigTransform')
|
||||
const isString = val => typeof val === 'string'
|
||||
const isFunction = val => typeof val === 'function'
|
||||
const isObject = val => val && typeof val === 'object'
|
||||
const mergeArrayWithDedupe = (a, b) => Array.from(new Set([...a, ...b]))
|
||||
|
||||
class GeneratorAPI {
|
||||
/**
|
||||
@@ -140,9 +141,9 @@ class GeneratorAPI {
|
||||
} else if (!(key in pkg)) {
|
||||
pkg[key] = value
|
||||
} else if (Array.isArray(value) && Array.isArray(existing)) {
|
||||
pkg[key] = existing.concat(value)
|
||||
pkg[key] = mergeArrayWithDedupe(existing, value)
|
||||
} else if (isObject(value) && isObject(existing)) {
|
||||
pkg[key] = merge(existing, value)
|
||||
pkg[key] = merge(existing, value, { arrayMerge: mergeArrayWithDedupe })
|
||||
} else {
|
||||
pkg[key] = value
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ const stringifyJS = require('./stringifyJS')
|
||||
const { loadModule } = require('@vue/cli-shared-utils')
|
||||
const merge = require('deepmerge')
|
||||
|
||||
const mergeArrayWithDedupe = (a, b) => Array.from(new Set([...a, ...b]))
|
||||
const mergeOptions = {
|
||||
arrayMerge: mergeArrayWithDedupe
|
||||
}
|
||||
|
||||
const isObject = val => val && typeof val === 'object'
|
||||
|
||||
const transformJS = {
|
||||
@@ -20,10 +25,10 @@ const transformJS = {
|
||||
Object.keys(value).forEach(key => {
|
||||
const originalValue = existing[key]
|
||||
const newValue = value[key]
|
||||
if (Array.isArray(newValue)) {
|
||||
changedData[key] = newValue
|
||||
if (Array.isArray(originalValue) && Array.isArray(newValue)) {
|
||||
changedData[key] = mergeArrayWithDedupe(originalValue, newValue)
|
||||
} else if (isObject(originalValue) && isObject(newValue)) {
|
||||
changedData[key] = merge(originalValue, newValue)
|
||||
changedData[key] = merge(originalValue, newValue, mergeOptions)
|
||||
} else {
|
||||
changedData[key] = newValue
|
||||
}
|
||||
@@ -37,12 +42,18 @@ const transformJS = {
|
||||
|
||||
const transformJSON = {
|
||||
read: ({ source }) => JSON.parse(source),
|
||||
write: ({ value, existing }) => JSON.stringify(merge(existing, value), null, 2)
|
||||
write: ({ value, existing }) => {
|
||||
return JSON.stringify(merge(existing, value, mergeOptions), null, 2)
|
||||
}
|
||||
}
|
||||
|
||||
const transformYAML = {
|
||||
read: ({ source }) => require('js-yaml').safeLoad(source),
|
||||
write: ({ value, existing }) => require('js-yaml').safeDump(merge(existing, value))
|
||||
write: ({ value, existing }) => {
|
||||
return require('js-yaml').safeDump(merge(existing, value, mergeOptions), {
|
||||
skipInvalid: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const transformLines = {
|
||||
|
||||
Reference in New Issue
Block a user