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:
Evan You
2018-07-18 16:44:03 -04:00
parent d6d2af5628
commit ba4d0f285b
4 changed files with 40 additions and 18 deletions

View File

@@ -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,

View File

@@ -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())
})

View File

@@ -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
}

View File

@@ -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 = {