summaryrefslogtreecommitdiff
path: root/node_modules/tailwindcss/src/util/resolveConfig.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/tailwindcss/src/util/resolveConfig.js')
-rw-r--r--node_modules/tailwindcss/src/util/resolveConfig.js277
1 files changed, 277 insertions, 0 deletions
diff --git a/node_modules/tailwindcss/src/util/resolveConfig.js b/node_modules/tailwindcss/src/util/resolveConfig.js
new file mode 100644
index 0000000..cfeda6e
--- /dev/null
+++ b/node_modules/tailwindcss/src/util/resolveConfig.js
@@ -0,0 +1,277 @@
+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) {
+ // TODO: Log that this function isn't really needed anymore?
+ 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), {}),
+
+ // In order to resolve n config objects, we combine all of their `extend` properties
+ // into arrays instead of objects so they aren't overridden.
+ extend: collectExtends(themes),
+ }
+}
+
+function mergeExtensionCustomizer(merged, value) {
+ // When we have an array of objects, we do want to merge it
+ if (Array.isArray(merged) && isPlainObject(merged[0])) {
+ return merged.concat(value)
+ }
+
+ // When the incoming value is an array, and the existing config is an object, prepend the existing object
+ if (Array.isArray(value) && isPlainObject(value[0]) && isPlainObject(merged)) {
+ return [merged, ...value]
+ }
+
+ // Override arrays (for example for font-families, box-shadows, ...)
+ if (Array.isArray(value)) {
+ return value
+ }
+
+ // Execute default behaviour
+ return undefined
+}
+
+function mergeExtensions({ extend, ...theme }) {
+ return mergeWith(theme, extend, (themeValue, extensions) => {
+ // The `extend` property is an array, so we need to check if it contains any functions
+ if (!isFunction(themeValue) && !extensions.some(isFunction)) {
+ return mergeWith({}, themeValue, ...extensions, mergeExtensionCustomizer)
+ }
+
+ return (resolveThemePath, utils) =>
+ mergeWith(
+ {},
+ ...[themeValue, ...extensions].map((e) => value(e, resolveThemePath, utils)),
+ mergeExtensionCustomizer
+ )
+ })
+}
+
+/**
+ *
+ * @param {string} key
+ * @return {Iterable<string[] & {alpha: string | undefined}>}
+ */
+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) {
+ // theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5]
+
+ 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
+ )
+ )
+}