@mapcss/config
Version:
Definition of MapCSS config, loader
180 lines (179 loc) • 6.62 kB
JavaScript
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);
}