Allow plugins to provide their own config object

This commit is contained in:
Adam Wathan 2019-10-12 13:40:00 -04:00
parent cf9c9915cd
commit 65d45689ae
3 changed files with 151 additions and 29 deletions

View File

@ -1359,15 +1359,13 @@ test('more than two config objects can be resolved', () => {
},
})
})
test('plugin config modifications are applied', () => {
const userConfig = {
plugins: [
{
modifyConfig(config) {
return {
...config,
prefix: 'tw-',
}
config: {
prefix: 'tw-',
},
handler() {},
},
@ -1415,11 +1413,8 @@ test('user config takes precedence over plugin config modifications', () => {
prefix: 'user-',
plugins: [
{
modifyConfig(config) {
return {
...config,
prefix: 'plugin-',
}
config: {
prefix: 'tw-',
},
handler() {},
},
@ -1461,3 +1456,121 @@ test('user config takes precedence over plugin config modifications', () => {
plugins: userConfig.plugins,
})
})
test('plugin config can register plugins that also have config', () => {
const userConfig = {
plugins: [
{
config: {
prefix: 'tw-',
plugins: [
{
config: {
important: true,
},
handler() {}
},
{
config: {
separator: '__',
},
handler() {}
},
]
},
handler() {},
},
],
}
const defaultConfig = {
prefix: '',
important: false,
separator: ':',
theme: {
screens: {
mobile: '400px',
},
},
variants: {
appearance: ['responsive'],
borderCollapse: [],
borderColors: ['responsive', 'hover', 'focus'],
},
}
const result = resolveConfig([userConfig, defaultConfig])
expect(result).toEqual({
prefix: 'tw-',
important: true,
separator: '__',
theme: {
screens: {
mobile: '400px',
},
},
variants: {
appearance: ['responsive'],
borderCollapse: [],
borderColors: ['responsive', 'hover', 'focus'],
},
plugins: userConfig.plugins,
})
})
test('plugin configs take precedence over plugin configs registered by that plugin', () => {
const userConfig = {
plugins: [
{
config: {
prefix: 'outer-',
plugins: [
{
config: {
prefix: 'inner-',
},
handler() {}
}
]
},
handler() {},
},
],
}
const defaultConfig = {
prefix: '',
important: false,
separator: ':',
theme: {
screens: {
mobile: '400px',
},
},
variants: {
appearance: ['responsive'],
borderCollapse: [],
borderColors: ['responsive', 'hover', 'focus'],
},
}
const result = resolveConfig([userConfig, defaultConfig])
expect(result).toEqual({
prefix: 'outer-',
important: false,
separator: ':',
theme: {
screens: {
mobile: '400px',
},
},
variants: {
appearance: ['responsive'],
borderCollapse: [],
borderColors: ['responsive', 'hover', 'focus'],
},
plugins: userConfig.plugins,
})
})

View File

@ -56,7 +56,7 @@ const getConfigFunction = config => () => {
}
const configObject = _.isObject(config) ? _.get(config, 'config', config) : require(config)
return resolveConfig([configObject, defaultConfig])
}

View File

@ -1,10 +1,9 @@
import some from 'lodash/some'
import mergeWith from 'lodash/mergeWith'
import isEmpty from 'lodash/isEmpty'
import isFunction from 'lodash/isFunction'
import isUndefined from 'lodash/isUndefined'
import defaults from 'lodash/defaults'
import identity from 'lodash/identity'
import get from 'lodash/get'
import map from 'lodash/map'
import get from 'lodash/get'
import toPath from 'lodash/toPath'
@ -24,12 +23,6 @@ const configUtils = {
},
}
function applyPluginConfigModifications(config, plugins) {
return plugins.reduce((modified, plugin) => {
return get(plugin, 'modifyConfig', identity)(modified)
}, config)
}
function value(valueToResolve, ...args) {
return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve
}
@ -102,25 +95,41 @@ function resolveFunctionKeys(object) {
}, {})
}
export default function resolveConfig([userConfig, defaultConfig]) {
const modifiedDefaultConfig = applyPluginConfigModifications(
defaultConfig,
get(userConfig, 'plugins', [])
)
const configs = [userConfig, modifiedDefaultConfig]
function extractPluginConfigs(configs) {
let allConfigs = []
configs.forEach(config => {
allConfigs = [...allConfigs, config]
const plugins = get(config, 'plugins', [])
if (plugins.length === 0) {
return
}
plugins.forEach(plugin => {
allConfigs = [...allConfigs, ...extractPluginConfigs([get(plugin, 'config', {})])]
})
})
return allConfigs
}
export default function resolveConfig(configs) {
const allConfigs = extractPluginConfigs(configs)
return defaults(
{
// Need to get a default empty object if the config has no theme
theme: resolveFunctionKeys(
mergeExtensions(mergeThemes(map(configs, t => get(t, 'theme', {}))))
mergeExtensions(mergeThemes(map(allConfigs, t => get(t, 'theme', {}))))
),
variants: (firstVariants => {
return Array.isArray(firstVariants)
? firstVariants
: defaults({}, ...map(configs, 'variants'))
})(defaults({}, ...map(configs)).variants),
: defaults({}, ...map(allConfigs, 'variants'))
})(defaults({}, ...map(allConfigs)).variants),
},
...configs
...allConfigs
)
}