UNPKG

@wix/css-property-parser

Version:

A comprehensive TypeScript library for parsing and serializing CSS property values with full MDN specification compliance

88 lines (87 loc) 3.52 kB
// CSS Function Parser Utility // Shared utility for parsing CSS math functions: calc(), min(), max(), clamp() // Eliminates duplication across type evaluators /** * Parse a CSS math function (calc, min, max, clamp) * @param value - The trimmed CSS value string * @param allowedFunctions - Array of function names to accept (defaults to all) * @returns Parsed function object or null if not a valid function */ export function parseCSSFunction(value, allowedFunctions = ['calc', 'min', 'max', 'clamp']) { if (!value || typeof value !== 'string') { return null; } const trimmed = value.trim(); // Check each allowed function for (const fn of allowedFunctions) { if (trimmed.startsWith(`${fn}(`) && trimmed.endsWith(')') && trimmed.length > fn.length + 2) { const expression = trimmed.slice(fn.length + 1, -1).trim(); // Remove function name and parentheses // Basic validation - reject obviously malformed expressions if (expression === '' || // Empty expression /[+\-*/]\s*$/.test(expression) || // Ends with operator /^\s*[+*/]/.test(expression) || // Starts with operator (except unary +/-) /[+\-*/]\s*[+\-*/]/.test(expression)) { // Adjacent operators return null; } // Validate function-specific argument requirements if (!validateFunctionArguments(fn, expression)) { return null; } return { type: 'function', expression, function: fn }; } } return null; } /** * Parse only calc() function (simpler version for basic type evaluators) * @param value - The trimmed CSS value string * @returns Parsed calc function object or null if not a valid calc */ export function parseCalcFunction(value) { return parseCSSFunction(value, ['calc']); } /** * Convert CSS function result back to CSS string * @param parsed - The parsed CSS function object * @returns CSS function string */ export function cssFunctionToCSSValue(parsed) { return `${parsed.function}(${parsed.expression})`; } /** * Check if a value is a CSS function call * @param value - The CSS value string * @param functionNames - Array of function names to check (defaults to all math functions) * @returns True if the value is a CSS function call */ export function isCSSFunction(value, functionNames = ['calc', 'min', 'max', 'clamp']) { if (!value || typeof value !== 'string') { return false; } const trimmed = value.trim(); return functionNames.some(fn => trimmed.startsWith(`${fn}(`) && trimmed.endsWith(')')); } // Internal helper function to validate function arguments function validateFunctionArguments(functionName, expression) { switch (functionName) { case 'min': case 'max': { // min() and max() require at least 2 arguments const args = expression.split(',').map(arg => arg.trim()); return args.length >= 2 && args.every(arg => arg !== ''); } case 'clamp': { // clamp() requires exactly 3 arguments: min, preferred, max const args = expression.split(',').map(arg => arg.trim()); return args.length === 3 && args.every(arg => arg !== ''); } case 'calc': default: // calc() can have any valid expression, so no additional validation needed return true; } }