@tbela99/css-parser
Version:
CSS parser, minifier and validator for node and the browser
983 lines (982 loc) • 63 kB
JavaScript
import { convertColor, toPrecisionAngle, toPrecisionValue, getAngle } from '../syntax/color/color.js';
import { reduceHexValue } from '../syntax/color/hex.js';
import { EnumToken, minifyNumber, ColorType } from '../ast/types.js';
import { expand } from '../ast/expand.js';
import { SourceMap } from './sourcemap/sourcemap.js';
import { pseudoElements, urlTokenMatcher, PARENT, tokensfuncSet, LOC, colorPrecision } from '../syntax/constants.js';
import { reducegradientBackgroundPosition, reduceConicColorStops, reduceColorStops, parseColor } from '../syntax/syntax.js';
import { move } from '../parser/tokenize.js';
import { equalsIgnoreCase } from '../parser/utils/text.js';
import { toDegrees } from '../parser/utils/angle.js';
/**
* render ast
* @param data
* @param options
* @param mapping
* @private
*/
function doRender(data, options = {}, mapping) {
const minify = options.minify ?? true;
const beautify = options.beautify ?? !minify;
options = {
...(beautify
? {
indent: " ",
newLine: "\n",
}
: {
indent: "",
newLine: "",
}),
...(minify
? {
removeEmpty: true,
removeComments: true,
minify: true,
}
: {
removeEmpty: false,
removeComments: false,
}),
sourcemap: false,
convertColor: true,
expandNestingRules: false,
preserveLicense: false,
...options,
};
if (options.withParents) {
// @ts-ignore
let parent = data[PARENT];
while (data[PARENT] != null) {
// @ts-ignore
parent = { ...data[PARENT], chi: [{ ...data }] };
// @ts-ignore
parent[PARENT] = data[PARENT][PARENT];
// @ts-ignore
data = parent;
}
}
const startTime = performance.now();
const errors = [];
const sourcemap = options.sourcemap ? new SourceMap() : null;
const cache = Object.create(null);
const position = {
ind: 0,
lin: 1,
col: 1,
};
let code = "";
if (mapping != null) {
if (mapping.importMapping != null) {
for (const [key, value] of Object.entries(mapping.importMapping)) {
code += `:import("${key}")${options.indent}{${options.newLine}${Object.entries(value).reduce((acc, [k, v]) => acc + (acc.length > 0 ? options.newLine : "") + `${options.indent}${v}:${options.indent}${k};`, "")}${options.newLine}}${options.newLine}`;
}
}
code += `:export${options.indent}{${options.newLine}${Object.entries(mapping.mapping).reduce((acc, [k, v]) => acc + (acc.length > 0 ? options.newLine : "") + `${options.indent}${k}:${options.indent}${v};`, "")}${options.newLine}}${options.newLine}`;
move(position, code);
}
const result = {
code: code +
renderAstNode(options.expandNestingRules &&
[EnumToken.StyleSheetNodeType, EnumToken.AtRuleNodeType, EnumToken.RuleNodeType].includes(data.typ) &&
"chi" in data
? expand(data)
: data, options, sourcemap, position, errors, function reducer(acc, curr) {
if (curr.typ == EnumToken.CommentTokenType && options.removeComments) {
if (!options.preserveLicense || !curr.val.startsWith("/*!")) {
return acc;
}
return acc + curr.val;
}
return acc + renderValue(curr, options, cache, reducer, errors);
}, cache),
errors,
stats: {
total: `${(performance.now() - startTime).toFixed(2)}ms`,
},
};
if (options.output != null) {
// @ts-ignore
options.output = options.resolve(options.output, options.cwd).absolute;
}
if (sourcemap != null) {
result.map = sourcemap;
if (options.sourcemap === "inline") {
result.code += `\n/*# sourceMappingURL=data:application/json,${encodeURIComponent(JSON.stringify(result.map))} */`;
}
}
return result;
}
/**
* Update source map
* @param node
* @param options
* @param cache
* @param sourcemap
* @param position
* @param str
*
* @internal
*/
function updateSourceMap(node, options, cache, sourcemap, position, str) {
if ([
EnumToken.RuleNodeType,
EnumToken.AtRuleNodeType,
EnumToken.KeyFramesRuleNodeType,
EnumToken.KeyframesAtRuleNodeType,
].includes(node.typ)) {
let src = node[LOC]?.src ?? "";
// console.debug(src);
sourcemap.add(
// @ts-ignore
{ src, sta: { ...position } }, {
...node[LOC],
// @ts-ignore
src,
});
}
move(position, str);
}
/**
* render ast node
* @param data
* @param options
* @param sourcemap
* @param position
* @param errors
* @param reducer
* @param cache
* @param level
* @param indents
*
* @internal
*/
function renderAstNode(data, options, sourcemap, position, errors, reducer, cache, level = 0, indents = []) {
if (indents.length < level + 1) {
indents.push(options.indent.repeat(level));
}
if (indents.length < level + 2) {
indents.push(options.indent.repeat(level + 1));
}
const indent = indents[level];
const indentSub = indents[level + 1];
switch (data.typ) {
case EnumToken.DeclarationNodeType:
return `${data.nam}:${options.indent}${(options.minify
? filterValues(data.val)
: data.val).reduce(reducer, "")}`;
case EnumToken.CommentNodeType:
case EnumToken.CDOCOMMNodeType:
if (data.val.startsWith("/*# sourceMappingURL=")) {
// ignore sourcemap
return "";
}
return !options.removeComments || (options.preserveLicense && data.val.startsWith("/*!"))
? data.val
: "";
case EnumToken.StyleSheetNodeType:
return data.chi.reduce((css, node) => {
const str = renderAstNode(node, options, sourcemap, { ...position }, errors, reducer, cache, level, indents);
if (str === "") {
return css;
}
if (css === "") {
if (sourcemap != null && node[LOC] != null) {
updateSourceMap(node, options, cache, sourcemap, position, str);
}
return str;
}
if (sourcemap != null && node[LOC] != null) {
move(position, options.newLine);
updateSourceMap(node, options, cache, sourcemap, position, str);
}
return `${css}${options.newLine}${str}`;
}, "");
case EnumToken.AtRuleNodeType:
case EnumToken.RuleNodeType:
case EnumToken.KeyFramesRuleNodeType:
case EnumToken.KeyframesAtRuleNodeType:
if ([EnumToken.AtRuleNodeType, EnumToken.KeyframesAtRuleNodeType].includes(data.typ) && !("chi" in data)) {
return `${indent}@${data.nam}${data.val === "" ? "" : options.indent || " "}${data.val};`;
}
// @ts-ignore
let children = data.chi.reduce((css, node) => {
let str;
if (node.typ == EnumToken.CommentNodeType) {
str =
options.removeComments &&
(!options.preserveLicense || !node.val.startsWith("/*!"))
? ""
: node.val;
}
else if (node.typ == EnumToken.DeclarationNodeType) {
// if (!(<AstDeclaration>node).nam.startsWith("--") && (<AstDeclaration>node).val.length === 0) {
// // @ts-ignore
// errors.push(<ErrorDescription>{
// action: "ignore",
// message: `render: invalid declaration ${JSON.stringify(node)}`,
// location: node[LOC],
// });
// return "";
// }
str = `${node.nam}:${options.indent}${(options.minify
? filterValues(node.val)
: node.val)
.reduce(reducer, "")
.trimEnd()};`;
}
// else if (node.typ == EnumToken.AtRuleNodeType && !("chi" in node)) {
// str = `${(<AstAtRule>node).val === "" ? "" : options.indent || " "}${(<AstAtRule>node).val};`;
// }
else {
str = renderAstNode(node, options, sourcemap, { ...position }, errors, reducer, cache, level + 1, indents);
}
if (css === "") {
return str;
}
if (str === "") {
return css;
}
return `${css}${options.newLine}${indentSub}${str}`;
}, "");
if (options.removeEmpty && children === "") {
return "";
}
if (children.endsWith(";")) {
children = children.slice(0, -1);
}
if ([EnumToken.AtRuleNodeType, EnumToken.KeyframesAtRuleNodeType].includes(data.typ)) {
return (`@${data.nam}${data.val === "" ? "" : options.indent || " "}${data.val}${options.indent}{${options.newLine}` +
(children === "" ? "" : indentSub + children + options.newLine) +
indent +
`}`);
}
return (data.sel +
`${options.indent}{${options.newLine}` +
(children === "" ? "" : indentSub + children + options.newLine) +
indent +
`}`);
// case EnumToken.CssVariableTokenType:
// case EnumToken.CssVariableImportTokenType:
// return `@value ${(<CssVariableToken | CssVariableImportTokenType>data).val}:${options.indent}${filterValues(
// options.minify
// ? (<CssVariableToken | CssVariableImportTokenType>data).val
// : (<CssVariableToken>data).val,
// )
// .reduce(reducer, "")
// .trim()};`;
// case EnumToken.CssVariableDeclarationMapTokenType:
// return `@value ${filterValues((data as CssVariableMapTokenType).vars)
// .reduce((acc, curr) => acc + renderValue(curr), "")
// .trim()} from ${filterValues((data as CssVariableMapTokenType).from)
// .reduce((acc, curr) => acc + renderValue(curr), "")
// .trim()};`;
// case EnumToken.InvalidDeclarationNodeType:
// case EnumToken.InvalidRuleNodeType:
// case EnumToken.InvalidAtRuleNodeType:
default:
return "";
}
}
/**
* render ast token
* @param token
* @param options
* @private
*/
function renderValue(token, options = {}, cache = Object.create(null), reducer, errors) {
if (token.typ === EnumToken.WhenElseFunctionTokenType &&
equalsIgnoreCase(token.val, "supports")) {
options = { ...options, minify: false, convertColor: false };
reducer = null;
}
if (reducer == null) {
reducer = function (acc, curr) {
if (curr.typ == EnumToken.CommentTokenType && options.removeComments) {
if (!options.preserveLicense || !curr.val.startsWith("/*!")) {
return acc;
}
return acc + curr.val;
}
return acc + renderValue(curr, options, cache, reducer, errors);
};
}
// if (token.typ == EnumToken.FunctionTokenType && colorsFunc.includes((token as FunctionToken).val)) {
// if (isColor(token)) {
// // @ts-ignore
// token.typ = EnumToken.ColorTokenType;
// if (
// // @ts-ignore
// (token as ColorToken)!.chi[0]!.typ == EnumToken.IdenTokenType &&
// // @ts-ignore
// ((token as ColorToken)!.chi[0] as IdentToken).val == "from"
// ) {
// // @ts-ignore
// (<ColorToken>token).cal = "rel";
// } else {
// // @ts-ignore
// if (
// (token as ColorToken).val == "color-mix" &&
// (token as ColorToken).chi?.[0]?.typ == EnumToken.IdenTokenType &&
// ((token as ColorToken).chi?.[0] as IdentToken).val == "in"
// ) {
// // @ts-ignore
// (<ColorToken>token).cal = "mix";
// } else {
// // @ts-ignore
// if ((token as ColorToken).val == "color") {
// // @ts-ignore
// token.cal = "col";
// }
// // @ts-ignore
// (token as ColorToken).chi = (token as ColorToken).chi!.filter(
// (t: Token) =>
// ![
// EnumToken.WhitespaceTokenType,
// EnumToken.CommaTokenType,
// EnumToken.CommentTokenType,
// ].includes(t.typ),
// );
// }
// }
// }
// }
switch (token.typ) {
case EnumToken.FunctionTokenDefType:
case EnumToken.UrlFunctionTokenDefType:
case EnumToken.MathFunctionTokenDefType:
case EnumToken.ImageFunctionTokenDefType:
case EnumToken.ColorFunctionTokenDefType:
case EnumToken.TimingFunctionTokenDefType:
case EnumToken.WhenElseFunctionTokenDefType:
case EnumToken.SupportsFunctionTokenDefType:
case EnumToken.TimelineFunctionTokenDefType:
case EnumToken.GridTemplateFuncTokenDefType:
case EnumToken.TransformFunctionTokenDefType:
case EnumToken.ContainerFunctionTokenDefType:
case EnumToken.PseudoClassFunctionTokenDefType:
case EnumToken.GeneralEnclosedFunctionTokenDefType:
case EnumToken.CustomFunctionTokenDefType:
case EnumToken.WildCardFunctionTokenDefType:
return token.val + "(";
case EnumToken.ListToken:
return token.chi.reduce((acc, curr) => acc + renderValue(curr, options, cache), "");
case EnumToken.BinaryExpressionTokenType:
if (EnumToken.Mul === token.op ||
EnumToken.Div === token.op) {
let result = "";
if (token.l.typ == EnumToken.BinaryExpressionTokenType &&
[EnumToken.Add, EnumToken.Sub].includes(token.l.op)) {
result = "(" + renderValue(token.l, options, cache) + ")";
}
else {
result = renderValue(token.l, options, cache);
}
result += token.op == EnumToken.Mul ? "*" : "/";
if (token.r.typ == EnumToken.BinaryExpressionTokenType &&
[EnumToken.Add, EnumToken.Sub].includes(token.r.op)) {
result += "(" + renderValue(token.r, options, cache) + ")";
}
else {
result += renderValue(token.r, options, cache);
}
return result;
}
return (renderValue(token.l, options, cache) +
(token.op == EnumToken.Add ? " + " : " - ") +
renderValue(token.r, options, cache));
case EnumToken.FractionTokenType:
const fraction = renderValue(token.l) + "/" + renderValue(token.r);
if (+token.r.val != 0) {
const value = minifyNumber(+token.l.val / +token.r.val);
if (value.length <= fraction.length) {
return value;
}
}
return fraction;
case EnumToken.Add:
return " + ";
case EnumToken.Sub:
return " - ";
case EnumToken.Star:
case EnumToken.UniversalSelectorTokenType:
case EnumToken.Mul:
return "*";
case EnumToken.Div:
return "/";
case EnumToken.WrappedValuesTokenType:
return ("{" +
token.chi.reduce((acc, curr) => acc + renderValue(curr, options, cache), "") +
"}");
case EnumToken.ColorTokenType:
if (token.kin == ColorType.LIGHT_DARK ||
("chi" in token && options.convertColor === false && token.chi.length == 2)) {
return (token.val +
"(" +
token.chi.reduce((acc, curr) => {
if (curr.typ === EnumToken.IdenTokenType) {
parseColor(curr);
}
return acc + renderValue(curr, options, cache);
}, "") +
")");
}
if (options.convertColor !== false) {
const value = convertColor(token, typeof options.convertColor === "boolean"
? ColorType.HEX
: (ColorType[ColorType[options.convertColor ?? "HEX"]
?.toUpperCase?.()
.replaceAll?.("-", "_")] ?? ColorType.HEX));
if (value != null) {
token = value;
}
if (token.kin == ColorType.HEX || token.kin == ColorType.LIT) {
return reduceHexValue(token.val);
}
}
if (token.kin === ColorType.SYS ||
token.kin === ColorType.DPSYS ||
token.kin === ColorType.NON_STD) {
return token.val;
}
if (token.kin == ColorType.HEX || token.kin == ColorType.LIT) {
return token.val;
}
if (Array.isArray(token.chi)) {
const fnName = token.val.toLowerCase();
const isLegacy = ["rgb", "rgba", "hsl", "hsla"].includes(token.val.toLowerCase());
const hasAlpha = [
"rgb",
"rgba",
"hsl",
"hsla",
"hwb",
"oklab",
"oklch",
"lab",
"lch",
].includes(fnName);
const useAlpha = (hasAlpha && token.chi.length == (isLegacy ? 7 : 4)) ||
("color" == token.val && token.chi.length == 5);
return ((hasAlpha && token.val.endsWith("a") ? fnName.slice(0, -1) : fnName) +
"(" +
token
.chi.reduce((acc, curr, index, array) => {
if (/[,/]\s*$/.test(acc)) {
if (curr.typ == EnumToken.WhitespaceTokenType) {
return acc.trimEnd();
}
return acc.trimStart() + renderValue(curr, options, cache);
}
if (isLegacy && curr.typ == EnumToken.CommaTokenType) {
return acc.trimEnd() + " ";
}
if (curr.typ == EnumToken.WhitespaceTokenType) {
return acc.trimEnd() + " ";
}
if (curr.typ == EnumToken.CommaTokenType ||
(curr.typ == EnumToken.LiteralTokenType && curr.val == "/")) {
return acc.trimEnd() + (curr.typ == EnumToken.CommaTokenType ? "," : "/");
}
return (acc.trimEnd() +
(useAlpha && index == array.length - 1 ? "/" : " ") +
renderValue(curr, options, cache));
}, "")
.trimStart() +
")");
}
case EnumToken.UrlFunctionTokenType:
if (options.minify && token.typ === EnumToken.UrlFunctionTokenType) {
for (const child of token.chi) {
if (child.typ === EnumToken.StringTokenType) {
if (child.val.slice(1, 5) !== "data:" &&
urlTokenMatcher.test(child.val)) {
Object.assign(child, {
typ: EnumToken.UrlTokenTokenType,
val: child.val.slice(1, -1),
});
}
break;
}
}
}
case EnumToken.ParensTokenType:
case EnumToken.FunctionTokenType:
case EnumToken.MathFunctionTokenType:
case EnumToken.ImageFunctionTokenType:
if (options.minify && token.typ === EnumToken.ImageFunctionTokenType) {
const slice = token.chi.slice();
switch (token.val) {
case "linear-gradient":
case "repeating-linear-gradient":
{
let i;
let k;
let j;
let key;
for (i = 0; i < slice.length; i++) {
if (slice[i].typ == EnumToken.ColorTokenType ||
slice[i].typ === EnumToken.CommaTokenType) {
break;
}
if (slice[i].typ == EnumToken.IdenTokenType &&
equalsIgnoreCase(slice[i].val, "to")) {
k = i + 1;
while (k < slice.length &&
(slice[k].typ === EnumToken.WhitespaceTokenType ||
slice[k].typ === EnumToken.CommentTokenType)) {
k++;
}
if (k < slice.length && slice[k].typ === EnumToken.IdenTokenType) {
// convert keyword to angle
key = slice[k].val.toLowerCase();
switch (key) {
case "right":
slice.splice(i, k - i + 1, {
typ: EnumToken.AngleTokenType,
val: 90,
});
break;
case "left":
slice.splice(i, k - i + 1, {
typ: EnumToken.AngleTokenType,
val: 270,
});
break;
case "top":
case "bottom":
j = k + 1;
while (j < slice.length &&
(slice[j].typ === EnumToken.WhitespaceTokenType ||
slice[j].typ === EnumToken.CommentTokenType)) {
j++;
}
if (j < slice.length && slice[j].typ !== EnumToken.CommaTokenType) {
i = j - 1;
break;
}
// https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/gradient/linear-gradient#:~:text=If%20unspecified%2C%20it%20defaults%20to%20to%20bottom
if (key === "bottom") {
// to bottom -> 180deg is the default angle and will be removed
while (k < slice.length &&
slice[k].typ != EnumToken.CommaTokenType) {
k++;
}
slice.splice(i, k - i + 1);
i--;
continue;
}
slice.splice(i, k - i + 1, {
typ: EnumToken.AngleTokenType,
val: key === "top" ? 0 : 180,
});
i--;
break;
}
}
}
else if (slice[i].typ == EnumToken.AngleTokenType) {
if ((180 - toDegrees(slice[i]).val) % 360 === 0) {
k = i + 1;
// while (k < slice.length && slice[k].typ !== EnumToken.CommaTokenType) {
// k++;
// }
slice.splice(i, k - i + 1);
}
}
}
if (slice[i]?.typ === EnumToken.CommaTokenType) {
i++;
// while (
// i < slice.length &&
// (slice[i].typ === EnumToken.WhitespaceTokenType ||
// slice[i].typ === EnumToken.CommentTokenType)
// ) {
// i++;
// }
}
if (slice[i]?.typ === EnumToken.ColorTokenType) {
slice.push(...reduceColorStops(slice.splice(i, slice.length - i)));
}
}
break;
case "radial-gradient":
case "repeating-radial-gradient":
{
let i = 0;
// while (
// i < slice.length &&
// (slice[i].typ === EnumToken.WhitespaceTokenType ||
// slice[i].typ === EnumToken.CommentTokenType)
// ) {
// i++;
// }
const positions = [];
const form = [];
const size = [];
const colorSpaceDef = [];
if (slice[i]?.typ === EnumToken.IdenTokenType) {
if (equalsIgnoreCase(slice[i].val, "farthest-corner") ||
equalsIgnoreCase(slice[i].val, "ellipse")) {
i++;
}
else if (equalsIgnoreCase(slice[i].val, "closest-side") ||
equalsIgnoreCase(slice[i].val, "closest-corner") ||
equalsIgnoreCase(slice[i].val, "farthest-side")) {
size.push(slice[i++]);
}
else if (equalsIgnoreCase(slice[i].val, "circle")) {
form.push(slice[i++]);
}
while (slice[i]?.typ === EnumToken.WhitespaceTokenType ||
slice[i]?.typ === EnumToken.CommentTokenType) {
i++;
}
}
if (slice[i]?.typ === EnumToken.IdenTokenType) {
if (equalsIgnoreCase(slice[i].val, "farthest-corner") ||
equalsIgnoreCase(slice[i].val, "ellipse")) {
i++;
}
else if (equalsIgnoreCase(slice[i].val, "closest-side") ||
equalsIgnoreCase(slice[i].val, "closest-corner") ||
equalsIgnoreCase(slice[i].val, "farthest-side")) {
size.push(slice[i++]);
}
else if (equalsIgnoreCase(slice[i].val, "circle")) {
form.push(slice[i++]);
}
while (slice[i]?.typ === EnumToken.WhitespaceTokenType ||
slice[i]?.typ === EnumToken.CommentTokenType) {
i++;
}
}
if (slice[i]?.typ === EnumToken.IdenTokenType &&
equalsIgnoreCase(slice[i].val, "at")) {
i++;
}
while (slice[i]?.typ === EnumToken.WhitespaceTokenType ||
slice[i]?.typ === EnumToken.CommentTokenType) {
i++;
}
if (slice[i]?.typ === EnumToken.PercentageTokenType ||
(slice[i]?.typ === EnumToken.NumberTokenType && 0 === slice[i].val) ||
(slice[i]?.typ === EnumToken.IdenTokenType &&
(equalsIgnoreCase(slice[i].val, "center") ||
equalsIgnoreCase(slice[i].val, "top") ||
equalsIgnoreCase(slice[i].val, "bottom") ||
equalsIgnoreCase(slice[i].val, "left") ||
equalsIgnoreCase(slice[i].val, "right")))) {
do {
if (slice[i]?.typ === EnumToken.IdenTokenType &&
"in" === slice[i].val) {
break;
}
positions.push(slice[i]);
i++;
} while (slice[i]?.typ !== EnumToken.CommaTokenType);
}
while (slice[i]?.typ !== EnumToken.CommaTokenType) {
colorSpaceDef.push(slice[i++]);
}
if (slice[i]?.typ === EnumToken.CommaTokenType) {
i++;
}
if (positions.length > 0) {
let k;
let position1 = "";
let position2 = "";
for (k = 0; k < positions.length; k++) {
if (positions[k].typ === EnumToken.IdenTokenType) {
if (position1.length === 0) {
position1 = positions[k].val;
}
else {
position2 = positions[k].val;
}
}
else if (positions[k].typ === EnumToken.PercentageTokenType ||
positions[k].typ === EnumToken.NumberTokenType) {
if (position1.length === 0) {
position1 = positions[k].val + "%";
}
else {
position2 = positions[k].val + "%";
}
}
if (position2.length > 0) {
break;
}
}
if (position1.length > 0) {
let key = `${position1} ${position2}`.trim();
if (key === "50% 50%" ||
key === "center center" ||
key === "50%" ||
key === "center") {
positions.length = 0;
}
else if (key === "0% 0%" ||
key === "0 0" ||
key === "top left" ||
key === "left top") {
positions.splice(0, positions.length, {
typ: EnumToken.PercentageTokenType,
val: 0,
});
}
else if (key === "50% 0%" ||
key === "50% 0" ||
key === "center top" ||
key === "top center") {
positions.splice(0, positions.length, {
typ: EnumToken.IdenTokenType,
val: "top",
});
}
else if (key === "top right" || key === "right top") {
positions.splice(0, positions.length, {
typ: EnumToken.PercentageTokenType,
val: 100,
}, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.PercentageTokenType, val: 0 });
}
else if (key === "0 50%" ||
key === "0% 50%" ||
key === "left center" ||
key === "center left") {
positions.splice(0, positions.length, {
typ: EnumToken.IdenTokenType,
val: "left",
});
}
else if (key === "100% 50%" || key === "right center" || key === "center right") {
positions.splice(0, positions.length, {
typ: EnumToken.IdenTokenType,
val: "right",
});
}
else if (key === "0 100%" ||
key === "0% 100%" ||
key === "left bottom" ||
key === "bottom left") {
positions.splice(0, positions.length, {
typ: EnumToken.IdenTokenType,
val: "bottom",
});
}
else if (key === "50% 100%" ||
key === "center bottom" ||
key === "bottom center") {
positions.splice(0, positions.length, {
typ: EnumToken.IdenTokenType,
val: "bottom",
});
}
else if (key === "100% 100%" ||
key === "right bottom" ||
key === "bottom right") {
positions.splice(0, positions.length, {
typ: EnumToken.PercentageTokenType,
val: 100,
});
}
else if (position1 === position2) {
positions.splice(0, positions.length, positions[k]);
}
}
}
const result = [];
if (form.length > 0) {
result.push(...form);
}
if (size.length > 0) {
if (result.length > 0) {
result.push({ typ: EnumToken.WhitespaceTokenType });
}
result.push(...size);
}
if (positions.length > 0) {
if (result.length > 0) {
result.push({ typ: EnumToken.WhitespaceTokenType });
}
result.push({ typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, ...positions);
}
if (colorSpaceDef.length > 0) {
if (result.length > 0) {
result.push({ typ: EnumToken.WhitespaceTokenType });
}
result.push(...colorSpaceDef);
}
if (result.length > 0) {
result.push({ typ: EnumToken.CommaTokenType });
}
result.push(...reduceColorStops(slice.slice(i)));
slice.length = 0;
slice.push(...result);
}
break;
case "conic-gradient":
case "repeating-conic-gradient":
{
let i = 0;
const angles = [];
const positions = [];
const colorSpaceDef = [];
// while (
// i < slice.length &&
// (slice[i].typ === EnumToken.WhitespaceTokenType ||
// slice[i].typ === EnumToken.CommentTokenType)
// ) {
// i++;
// }
if (slice[i]?.typ === EnumToken.IdenTokenType &&
equalsIgnoreCase(slice[i].val, "from")) {
angles.push(slice[i++]);
while (i < slice.length &&
(slice[i].typ === EnumToken.WhitespaceTokenType ||
slice[i].typ === EnumToken.CommentTokenType)) {
angles.push(slice[i++]);
}
if ((slice[i]?.typ === EnumToken.NumberTokenType ||
slice[i]?.typ === EnumToken.AngleTokenType) &&
0 === toDegrees(slice[i]).val) {
angles.length = 0;
i++;
}
else if (slice[i]?.typ !== EnumToken.CommaTokenType &&
slice[i].typ != EnumToken.IdenTokenType) {
angles.push(slice[i++]);
}
while (i < slice.length &&
(slice[i].typ === EnumToken.WhitespaceTokenType ||
slice[i].typ === EnumToken.CommentTokenType)) {
i++;
}
}
if (slice[i]?.typ === EnumToken.IdenTokenType &&
equalsIgnoreCase(slice[i].val, "at")) {
i++;
while (i < slice.length &&
(slice[i].typ === EnumToken.WhitespaceTokenType ||
slice[i].typ === EnumToken.CommentTokenType)) {
i++;
}
let position1 = "";
let position2 = "";
if (slice[i]?.typ === EnumToken.IdenTokenType &&
!equalsIgnoreCase("in", slice[i].val)) {
position1 = slice[i].val;
positions.push(slice[i++]);
}
else if (slice[i]?.typ === EnumToken.PercentageTokenType ||
slice[i]?.typ === EnumToken.NumberTokenType) {
position1 = slice[i].val + "%";
positions.push(slice[i++]);
}
while (i < slice.length &&
(slice[i].typ === EnumToken.WhitespaceTokenType ||
slice[i].typ === EnumToken.CommentTokenType)) {
positions.push(slice[i++]);
}
if (slice[i]?.typ === EnumToken.IdenTokenType &&
!equalsIgnoreCase("in", slice[i].val)) {
position2 = slice[i].val;
positions.push(slice[i++]);
}
else if (slice[i]?.typ === EnumToken.PercentageTokenType ||
slice[i]?.typ === EnumToken.NumberTokenType) {
position2 = slice[i].val + "%";
positions.push(slice[i++]);
}
while (i < slice.length &&
(slice[i].typ === EnumToken.WhitespaceTokenType ||
slice[i].typ === EnumToken.CommentTokenType)) {
i++;
}
if (position1.length > 0) {
reducegradientBackgroundPosition(positions, `${position1} ${position2}`.trim());
}
}
while (i < slice.length &&
(slice[i].typ === EnumToken.WhitespaceTokenType ||
slice[i].typ === EnumToken.CommentTokenType)) {
i++;
}
if (slice[i]?.typ === EnumToken.IdenTokenType &&
equalsIgnoreCase("in", slice[i].val)) {
while (i < slice.length && slice[i].typ !== EnumToken.CommaTokenType) {
colorSpaceDef.push(slice[i++]);
}
}
if (slice[i]?.typ === EnumToken.CommaTokenType) {
i++;
}
const result = [];
if (positions.length > 0) {
if (positions.length > 0) {
if (angles.length > 0) {
angles.push({ typ: EnumToken.WhitespaceTokenType });
}
angles.push({ typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, ...positions);
}
}
if (angles.length > 0) {
result.push(...angles, { typ: EnumToken.CommaTokenType });
}
if (colorSpaceDef.length > 0) {
if (colorSpaceDef.length > 0) {
if (result.length > 0) {
result.push({ typ: EnumToken.WhitespaceTokenType });
}
result.push(...colorSpaceDef);
}
result.push({ typ: EnumToken.CommaTokenType });
}
result.push(...reduceConicColorStops(slice.slice(i)));
slice.length = 0;
slice.push(...result);
}
break;
}
return token.val + "(" + slice.reduce(reducer, "") + ")";
}
case EnumToken.TimingFunctionTokenType:
case EnumToken.PseudoClassFuncTokenType:
case EnumToken.WhenElseFunctionTokenType:
case EnumToken.TimelineFunctionTokenType:
case EnumToken.GridTemplateFuncTokenType:
case EnumToken.SupportsFunctionTokenType:
case EnumToken.ContainerFunctionTokenType:
case EnumToken.TransformFunctionTokenType:
case EnumToken.GeneralEnclosedFunctionTokenType:
case EnumToken.CustomFunctionTokenType:
case EnumToken.WildCardFunctionTokenType:
if (token.typ == EnumToken.MathFunctionTokenType &&
token.chi.length == 1 &&
![EnumToken.BinaryExpressionTokenType, EnumToken.FractionTokenType, EnumToken.IdenTokenType].includes(token.chi[0].typ) &&
// @ts-ignore
token.chi[0].val
?.typ != EnumToken.FractionTokenType) {
return (token.val +
"(" +
token.chi.reduce((acc, curr) => acc +
renderValue(curr, token.typ == EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") +
")");
}
return (
/* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") +
"(" +
token.chi.reduce(reducer, "") +
")");
// case EnumToken.MatchExpressionTokenType:
// return (
// renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) +
// renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) +
// renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) +
// ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "")
// );
// case EnumToken.NameSpaceAttributeTokenType:
// return (
// ((token as NameSpaceAttributeToken).l == null
// ? ""
// : renderValue((token as NameSpaceAttributeToken).l as Token, options, ca