UNPKG

@mapcss/config

Version:

Definition of MapCSS config, loader

180 lines (179 loc) 6.62 kB
import { deepMerge, distinctBy, head, init, isFunction, isString, isUndefined, last, prop, propPath, tail, toAST, wrap, } from "./deps.js"; import { isBlockDefinition, isCSSDefinition, isRoot } from "./utils/assert.js"; function firstSplit(value, separator) { const arr = new RegExp(`(.+?)${separator}(.+)`).exec(value); if (!arr) return; const [_, ...rest] = arr; return rest; } function leftSplit(value, separator) { const _value = isString(value) ? [value] : value; const _last = last(_value); if (!_last) return [_value]; const result = firstSplit(_last, separator); if (!result) return [_value]; return [_value, ...leftSplit([...init(_value), ...result], separator)]; } export function resolveCSSMap(value, cssMap, context) { const _resolve = (path, cssMap) => { for (const map of wrap(cssMap)) { const paths = leftSplit(path, context.separator); for (const path of paths) { const first = head(path); const matchInfo = { fullPath: value, path, id: first ?? "", parentId: first, }; const maybeDefinition = prop(first ?? "", map) ?? prop("*", map); const resolve = (value) => { if (isUndefined(value)) return; if (isFunction(value)) { return resolve(value(matchInfo, context)); } else if (isCSSDefinition(value)) { return toAST(value.value); } else if (isRoot(value)) { return value; } else if (isBlockDefinition(value)) { return toAST({ [context.className]: value, }); } else { const rest = tail(path); return _resolve(rest, value); } }; const result = resolve(maybeDefinition); if (isUndefined(result)) continue; return result; } } }; return _resolve(value, cssMap); } /** resolve theme via propPath safety */ export function resolveTheme(identifier, themeRoot, { separator, theme }) { const paths = leftSplit(identifier, separator); for (const path of paths) { const result = propPath([themeRoot, ...path], theme); if (isString(result)) { return result; } } } /** new version for theme resolver */ export function $resolveTheme(identifier, themeRoot, { separator, theme }) { const recursive = (path, theme) => { const first = head(path); if (isUndefined(first)) return theme; const result = prop(first, theme); if (isString(result) || isUndefined(result)) return result; return recursive(tail(path), result); }; const paths = leftSplit(identifier, separator); for (const path of paths) { const rootResult = prop(themeRoot, theme); if (isUndefined(rootResult)) continue; if (isString(rootResult)) return rootResult; const result = recursive(path, rootResult); if (!isUndefined(result)) { return result; } } } function pickByName({ name }) { return name; } export function resolvePreProcessor(...postProcessors) { return distinctBy(postProcessors, pickByName); } export function resolveSyntax(...syntaxes) { return distinctBy(syntaxes, pickByName); } export function resolvePreset(preset, context) { return distinctBy(preset, pickByName).map(({ fn }) => { const { syntax = [], cssMap = {}, modifierMap = {}, theme = {}, preProcess = [], postcssPlugin = [], css = {}, } = fn(context); return { syntax, cssMap, modifierMap, theme, preProcess, postcssPlugin, css, }; }); } /** resolve config to deep merge */ export function resolveConfig({ syntax: _syntax = [], preset = [], cssMap: _cssMap = {}, theme: _theme = {}, preProcess: _postProcess = [], modifierMap: _modifierMap = {}, postcssPlugin: _postcssPlugin = [], css: _css = {}, }, context) { const _presets = resolvePreset(preset, context); const modifierMaps = [ ..._presets.map(({ modifierMap }) => modifierMap), _modifierMap, ]; const theme = _presets.map(({ theme }) => theme).reduce((acc, cur) => { return deepMerge(acc, cur); }, _theme); const syntax = resolveSyntax(..._syntax, ..._presets.map(({ syntax }) => syntax).flat()); const cssMaps = [..._presets.map(({ cssMap }) => cssMap), _cssMap]; const preProcess = resolvePreProcessor(..._postProcess, ..._presets.map(({ preProcess }) => preProcess).flat()); const css = [..._presets.map(({ css }) => css), _css].reduce((acc, cur) => deepMerge(acc, cur), {}); const postcssPlugin = [ ..._postcssPlugin, ..._presets.map(({ postcssPlugin }) => postcssPlugin).flat(), ]; return { cssMaps, theme, modifierMaps, syntax, preProcess, css, postcssPlugin, }; } export function resolveModifierMap(fullPath, modifierMap, parentNode, context) { const _resolve = (path, modifierMap) => { for (const map of wrap(modifierMap)) { const paths = leftSplit(path, context.separator); for (const path of paths) { const _head = head(path); const matchInfo = { id: _head ?? "", parentId: _head, fullPath, path, }; const modifier = prop(_head ?? "", map); if (isUndefined(modifier)) continue; if (isFunction(modifier)) { const maybeRoot = modifier(parentNode, matchInfo, context); if (isUndefined(maybeRoot)) continue; return maybeRoot; } const rest = tail(path); const result = _resolve(rest, modifier); if (result) { return result; } } } }; return _resolve(fullPath, modifierMap); }