|
import negateValue from './negateValue' |
|
import corePluginList from '../corePluginList' |
|
import configurePlugins from './configurePlugins' |
|
import colors from '../public/colors' |
|
import { defaults } from './defaults' |
|
import { toPath } from './toPath' |
|
import { normalizeConfig } from './normalizeConfig' |
|
import isPlainObject from './isPlainObject' |
|
import { cloneDeep } from './cloneDeep' |
|
import { parseColorFormat } from './pluginUtils' |
|
import { withAlphaValue } from './withAlphaVariable' |
|
import toColorValue from './toColorValue' |
|
|
|
function isFunction(input) { |
|
return typeof input === 'function' |
|
} |
|
|
|
function mergeWith(target, ...sources) { |
|
let customizer = sources.pop() |
|
|
|
for (let source of sources) { |
|
for (let k in source) { |
|
let merged = customizer(target[k], source[k]) |
|
|
|
if (merged === undefined) { |
|
if (isPlainObject(target[k]) && isPlainObject(source[k])) { |
|
target[k] = mergeWith({}, target[k], source[k], customizer) |
|
} else { |
|
target[k] = source[k] |
|
} |
|
} else { |
|
target[k] = merged |
|
} |
|
} |
|
} |
|
|
|
return target |
|
} |
|
|
|
const configUtils = { |
|
colors, |
|
negative(scale) { |
|
|
|
return Object.keys(scale) |
|
.filter((key) => scale[key] !== '0') |
|
.reduce((negativeScale, key) => { |
|
let negativeValue = negateValue(scale[key]) |
|
|
|
if (negativeValue !== undefined) { |
|
negativeScale[`-${key}`] = negativeValue |
|
} |
|
|
|
return negativeScale |
|
}, {}) |
|
}, |
|
breakpoints(screens) { |
|
return Object.keys(screens) |
|
.filter((key) => typeof screens[key] === 'string') |
|
.reduce( |
|
(breakpoints, key) => ({ |
|
...breakpoints, |
|
[`screen-${key}`]: screens[key], |
|
}), |
|
{} |
|
) |
|
}, |
|
} |
|
|
|
function value(valueToResolve, ...args) { |
|
return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve |
|
} |
|
|
|
function collectExtends(items) { |
|
return items.reduce((merged, { extend }) => { |
|
return mergeWith(merged, extend, (mergedValue, extendValue) => { |
|
if (mergedValue === undefined) { |
|
return [extendValue] |
|
} |
|
|
|
if (Array.isArray(mergedValue)) { |
|
return [extendValue, ...mergedValue] |
|
} |
|
|
|
return [extendValue, mergedValue] |
|
}) |
|
}, {}) |
|
} |
|
|
|
function mergeThemes(themes) { |
|
return { |
|
...themes.reduce((merged, theme) => defaults(merged, theme), {}), |
|
|
|
|
|
|
|
extend: collectExtends(themes), |
|
} |
|
} |
|
|
|
function mergeExtensionCustomizer(merged, value) { |
|
|
|
if (Array.isArray(merged) && isPlainObject(merged[0])) { |
|
return merged.concat(value) |
|
} |
|
|
|
|
|
if (Array.isArray(value) && isPlainObject(value[0]) && isPlainObject(merged)) { |
|
return [merged, ...value] |
|
} |
|
|
|
|
|
if (Array.isArray(value)) { |
|
return value |
|
} |
|
|
|
|
|
return undefined |
|
} |
|
|
|
function mergeExtensions({ extend, ...theme }) { |
|
return mergeWith(theme, extend, (themeValue, extensions) => { |
|
|
|
if (!isFunction(themeValue) && !extensions.some(isFunction)) { |
|
return mergeWith({}, themeValue, ...extensions, mergeExtensionCustomizer) |
|
} |
|
|
|
return (resolveThemePath, utils) => |
|
mergeWith( |
|
{}, |
|
...[themeValue, ...extensions].map((e) => value(e, resolveThemePath, utils)), |
|
mergeExtensionCustomizer |
|
) |
|
}) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function* toPaths(key) { |
|
let path = toPath(key) |
|
|
|
if (path.length === 0) { |
|
return |
|
} |
|
|
|
yield path |
|
|
|
if (Array.isArray(key)) { |
|
return |
|
} |
|
|
|
let pattern = /^(.*?)\s*\/\s*([^/]+)$/ |
|
let matches = key.match(pattern) |
|
|
|
if (matches !== null) { |
|
let [, prefix, alpha] = matches |
|
|
|
let newPath = toPath(prefix) |
|
newPath.alpha = alpha |
|
|
|
yield newPath |
|
} |
|
} |
|
|
|
function resolveFunctionKeys(object) { |
|
|
|
|
|
const resolvePath = (key, defaultValue) => { |
|
for (const path of toPaths(key)) { |
|
let index = 0 |
|
let val = object |
|
|
|
while (val !== undefined && val !== null && index < path.length) { |
|
val = val[path[index++]] |
|
|
|
let shouldResolveAsFn = |
|
isFunction(val) && (path.alpha === undefined || index <= path.length - 1) |
|
|
|
val = shouldResolveAsFn ? val(resolvePath, configUtils) : val |
|
} |
|
|
|
if (val !== undefined) { |
|
if (path.alpha !== undefined) { |
|
let normalized = parseColorFormat(val) |
|
|
|
return withAlphaValue(normalized, path.alpha, toColorValue(normalized)) |
|
} |
|
|
|
if (isPlainObject(val)) { |
|
return cloneDeep(val) |
|
} |
|
|
|
return val |
|
} |
|
} |
|
|
|
return defaultValue |
|
} |
|
|
|
Object.assign(resolvePath, { |
|
theme: resolvePath, |
|
...configUtils, |
|
}) |
|
|
|
return Object.keys(object).reduce((resolved, key) => { |
|
resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key] |
|
|
|
return resolved |
|
}, {}) |
|
} |
|
|
|
function extractPluginConfigs(configs) { |
|
let allConfigs = [] |
|
|
|
configs.forEach((config) => { |
|
allConfigs = [...allConfigs, config] |
|
|
|
const plugins = config?.plugins ?? [] |
|
|
|
if (plugins.length === 0) { |
|
return |
|
} |
|
|
|
plugins.forEach((plugin) => { |
|
if (plugin.__isOptionsFunction) { |
|
plugin = plugin() |
|
} |
|
allConfigs = [...allConfigs, ...extractPluginConfigs([plugin?.config ?? {}])] |
|
}) |
|
}) |
|
|
|
return allConfigs |
|
} |
|
|
|
function resolveCorePlugins(corePluginConfigs) { |
|
const result = [...corePluginConfigs].reduceRight((resolved, corePluginConfig) => { |
|
if (isFunction(corePluginConfig)) { |
|
return corePluginConfig({ corePlugins: resolved }) |
|
} |
|
return configurePlugins(corePluginConfig, resolved) |
|
}, corePluginList) |
|
|
|
return result |
|
} |
|
|
|
function resolvePluginLists(pluginLists) { |
|
const result = [...pluginLists].reduceRight((resolved, pluginList) => { |
|
return [...resolved, ...pluginList] |
|
}, []) |
|
|
|
return result |
|
} |
|
|
|
export default function resolveConfig(configs) { |
|
let allConfigs = [ |
|
...extractPluginConfigs(configs), |
|
{ |
|
prefix: '', |
|
important: false, |
|
separator: ':', |
|
}, |
|
] |
|
|
|
return normalizeConfig( |
|
defaults( |
|
{ |
|
theme: resolveFunctionKeys( |
|
mergeExtensions(mergeThemes(allConfigs.map((t) => t?.theme ?? {}))) |
|
), |
|
corePlugins: resolveCorePlugins(allConfigs.map((c) => c.corePlugins)), |
|
plugins: resolvePluginLists(configs.map((c) => c?.plugins ?? [])), |
|
}, |
|
...allConfigs |
|
) |
|
) |
|
} |
|
|