UNPKG

@tbela99/css-parser

Version:

CSS parser, minifier and validator for node and the browser

156 lines (153 loc) 7.98 kB
import { EnumToken } from '../types.js'; import { walkValues, WalkerEvent, WalkerOptionEnum } from '../walk.js'; import { evaluate } from '../math/expression.js'; import { renderValue } from '../../renderer/render.js'; import { FeatureWalkMode } from './type.js'; import { mathFuncs, tokensfuncSet } from '../../syntax/constants.js'; class ComputeCalcExpressionFeature { accept = new Set([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType]); get ordering() { return 1; } get processMode() { return FeatureWalkMode.Post; } static register(options) { if (options.computeCalcExpression) { // @ts-ignore options.features.push(new ComputeCalcExpressionFeature()); } } run(ast) { if (!("chi" in ast)) { return null; } for (const node of ast.chi) { if (node.typ != EnumToken.DeclarationNodeType) { continue; } const set = new Set(); for (const { value, parent } of walkValues(node.val, node, { event: WalkerEvent.Enter, // @ts-ignore fn(node, parent) { if (parent != null && // @ts-ignore parent.typ == EnumToken.DeclarationNodeType && // @ts-ignore parent.val.length == 1 && (node.typ === EnumToken.MathFunctionTokenType || node.typ === EnumToken.FunctionTokenType) && mathFuncs.includes(node.val) && node.chi.length == 1 && node.chi[0].typ == EnumToken.IdenTokenType) { return WalkerOptionEnum.Ignore; } if ((node.typ === EnumToken.WildCardFunctionTokenType && node.val == "var") || (!mathFuncs.includes(parent.val) && [ EnumToken.MathFunctionTokenType, EnumToken.ColorTokenType, EnumToken.DeclarationNodeType, EnumToken.ImageFunc, EnumToken.RuleNodeType, EnumToken.AtRuleNodeType, EnumToken.StyleSheetNodeType, ].includes(parent?.typ))) { return null; } // @ts-ignore const slice = (node.typ == EnumToken.FunctionTokenType || node.typ == EnumToken.MathFunctionTokenType ? node.chi : node.typ == EnumToken.DeclarationNodeType ? node.val : node.chi)?.slice(); if (slice != null && (node.typ === EnumToken.MathFunctionTokenType || (node.typ == EnumToken.FunctionTokenType && mathFuncs.includes(node.val)))) { // @ts-ignore const key = "chi" in node ? "chi" : "val"; const str1 = renderValue({ ...node, [key]: slice }); const str2 = renderValue(node); // values.reduce((acc: string, curr: Token): string => acc + renderValue(curr), ''); if (str1.length < str2.length) { // @ts-ignore node[key] = slice; } return WalkerOptionEnum.Ignore; } return null; }, })) { if (value != null && tokensfuncSet.has(value.typ)) { if (!set.has(value)) { set.add(value); if (parent != null) { const shouldEvaluate = value.typ === EnumToken.MathFunctionTokenType || (value.typ == EnumToken.FunctionTokenType && mathFuncs.includes(value.val)); if (shouldEvaluate) { // @ts-ignore const cp = value.val != "calc" ? [value] : value.typ == EnumToken.DeclarationNodeType ? value.val : value.chi; const values = evaluate(cp); // fix a + -b to a - b for (const { value, parent: p } of walkValues(values)) { if (value.typ === EnumToken.BinaryExpressionTokenType) { if (value.op === EnumToken.Add && Math.sign(value.r.val) == -1) { value.op = EnumToken.Sub; // @ts-expect-error value.r.val *= -1; } } } // @ts-ignore const children = parent.typ == EnumToken.DeclarationNodeType ? parent.val : parent.chi; if (values.length == 1 && values[0].typ != EnumToken.BinaryExpressionTokenType) { for (let i = 0; i < children.length; i++) { if (children[i] == value) { children.splice(i, 1, !(parent.typ === EnumToken.MathFunctionTokenType || (parent.typ == EnumToken.FunctionTokenType && parent.val == "calc")) && typeof values[0].val != "number" && !(values[0].typ == EnumToken.MathFunctionTokenType || (values[0].typ == EnumToken.FunctionTokenType && mathFuncs.includes(values[0].val))) ? { typ: EnumToken.MathFunctionTokenType, val: "calc", chi: values, } : values[0]); break; } } } else { for (let i = 0; i < children.length; i++) { if (children[i] == value) { children.splice(i, 1, { typ: EnumToken.MathFunctionTokenType, val: "calc", chi: values, }); break; } } } } } } } } } return null; } } export { ComputeCalcExpressionFeature };