@tbela99/css-parser
Version:
CSS parser for node and the browser
127 lines (124 loc) • 6.57 kB
JavaScript
import { EnumToken } from '../types.js';
import { walkValues, WalkerValueEvent } from '../walk.js';
import { evaluate } from '../math/expression.js';
import { renderToken } from '../../renderer/render.js';
import { mathFuncs } from '../../syntax/syntax.js';
class ComputeCalcExpressionFeature {
static get ordering() {
return 1;
}
static register(options) {
if (options.computeCalcExpression) {
for (const feature of options.features) {
if (feature instanceof ComputeCalcExpressionFeature) {
return;
}
}
// @ts-ignore
options.features.push(new ComputeCalcExpressionFeature());
}
}
run(ast) {
if (!('chi' in ast)) {
return;
}
// @ts-ignore
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: WalkerValueEvent.Enter,
fn(node, parent, event) {
if (parent != null &&
parent.typ == EnumToken.DeclarationNodeType &&
parent.val.length == 1 &&
node.typ == EnumToken.FunctionTokenType &&
mathFuncs.includes(node.val) &&
node.chi.length == 1 &&
node.chi[0].typ == EnumToken.IdenTokenType) {
return 'ignore';
}
if ((node.typ == EnumToken.FunctionTokenType && node.val == 'var') || (!mathFuncs.includes(parent.val) && [EnumToken.ColorTokenType, EnumToken.DeclarationNodeType, EnumToken.RuleNodeType, EnumToken.AtRuleNodeType, EnumToken.StyleSheetNodeType].includes(parent?.typ))) {
return null;
}
// @ts-ignore
const slice = (node.typ == EnumToken.FunctionTokenType ? node.chi : (node.typ == EnumToken.DeclarationNodeType ? node.val : node.chi))?.slice();
if (slice != null && node.typ == EnumToken.FunctionTokenType && mathFuncs.includes(node.val)) {
// @ts-ignore
const cp = (node.typ == EnumToken.FunctionTokenType && mathFuncs.includes(node.val) && node.val != 'calc' ? [node] : (node.typ == EnumToken.DeclarationNodeType ? node.val : node.chi)).slice();
const values = evaluate(cp);
const key = 'chi' in node ? 'chi' : 'val';
const str1 = renderToken({ ...node, [key]: slice });
const str2 = renderToken(node); // values.reduce((acc: string, curr: Token): string => acc + renderToken(curr), '');
if (str1.length <= str2.length) {
// @ts-ignore
node[key] = slice;
}
else {
// @ts-ignore
node[key] = values;
}
return 'ignore';
}
return null;
}
})) {
if (value != null && value.typ == EnumToken.FunctionTokenType && mathFuncs.includes(value.val)) {
if (!set.has(value)) {
set.add(value);
if (parent != null) {
// @ts-ignore
const cp = value.typ == EnumToken.FunctionTokenType && mathFuncs.includes(value.val) && value.val != 'calc' ? [value] : (value.typ == EnumToken.DeclarationNodeType ? value.val : value.chi);
const values = evaluate(cp);
// @ts-ignore
const children = parent.typ == EnumToken.DeclarationNodeType ? parent.val : parent.chi;
if (values.length == 1 && values[0].typ != EnumToken.BinaryExpressionTokenType) {
if (parent.typ == EnumToken.BinaryExpressionTokenType) {
if (parent.l == value) {
parent.l = values[0];
}
else {
parent.r = values[0];
}
}
else {
for (let i = 0; i < children.length; i++) {
if (children[i] == value) {
// @ts-ignore
children.splice(i, 1, !(parent.typ == EnumToken.FunctionTokenType && parent.val == 'calc') && typeof values[0].val != 'string' ? {
typ: EnumToken.FunctionTokenType,
val: 'calc',
chi: values
} : values[0]);
break;
}
}
}
}
else {
for (let i = 0; i < children.length; i++) {
if (children[i] == value) {
if (parent.typ == EnumToken.FunctionTokenType && parent.val == 'calc') {
children.splice(i, 1, ...values);
}
else {
children.splice(i, 1, {
typ: EnumToken.FunctionTokenType,
val: 'calc',
chi: values
});
}
break;
}
}
}
}
}
}
}
}
}
}
export { ComputeCalcExpressionFeature };