'use strict'; const genericConst = require('./generic-const.cjs'); const genericAnPlusB = require('./generic-an-plus-b.cjs'); const genericUrange = require('./generic-urange.cjs'); const charCodeDefinitions = require('../tokenizer/char-code-definitions.cjs'); const types = require('../tokenizer/types.cjs'); const utils = require('../tokenizer/utils.cjs'); // CSS mathematical functions categorized by return type behavior // See: https://www.w3.org/TR/css-values-4/#math // Calculation functions that return different types depending on input const calcFunctionNames = [ 'calc(', '-moz-calc(', '-webkit-calc(' ]; // Comparison functions that return different types depending on input const comparisonFunctionNames = [ 'min(', 'max(', 'clamp(' ]; // Functions that return a stepped value, i.e. a value that is rounded to the nearest step const steppedValueFunctionNames = [ 'round(', 'mod(', 'rem(' ]; // Trigonometrical functions that return a const trigNumberFunctionNames = [ 'sin(', 'cos(', 'tan(' ]; // Trigonometrical functions that return a const trigAngleFunctionNames = [ 'asin(', 'acos(', 'atan(', 'atan2(' ]; // Other functions that return a const otherNumberFunctionNames = [ 'pow(', 'sqrt(', 'log(', 'exp(', 'sign(' ]; // Exponential functions that return a or or const expNumberDimensionPercentageFunctionNames = [ 'hypot(' ]; // Return the same type as the input const signFunctionNames = [ 'abs(' ]; const numberFunctionNames = [ ...calcFunctionNames, ...comparisonFunctionNames, ...steppedValueFunctionNames, ...trigNumberFunctionNames, ...otherNumberFunctionNames, ...expNumberDimensionPercentageFunctionNames, ...signFunctionNames ]; const percentageFunctionNames = [ ...calcFunctionNames, ...comparisonFunctionNames, ...steppedValueFunctionNames, ...expNumberDimensionPercentageFunctionNames, ...signFunctionNames ]; const dimensionFunctionNames = [ ...calcFunctionNames, ...comparisonFunctionNames, ...steppedValueFunctionNames, ...trigAngleFunctionNames, ...expNumberDimensionPercentageFunctionNames, ...signFunctionNames ]; const balancePair = new Map([ [types.Function, types.RightParenthesis], [types.LeftParenthesis, types.RightParenthesis], [types.LeftSquareBracket, types.RightSquareBracket], [types.LeftCurlyBracket, types.RightCurlyBracket] ]); // safe char code getter function charCodeAt(str, index) { return index < str.length ? str.charCodeAt(index) : 0; } function eqStr(actual, expected) { return utils.cmpStr(actual, 0, actual.length, expected); } function eqStrAny(actual, expected) { for (let i = 0; i < expected.length; i++) { if (eqStr(actual, expected[i])) { return true; } } return false; } // IE postfix hack, i.e. 123\0 or 123px\9 function isPostfixIeHack(str, offset) { if (offset !== str.length - 2) { return false; } return ( charCodeAt(str, offset) === 0x005C && // U+005C REVERSE SOLIDUS (\) charCodeDefinitions.isDigit(charCodeAt(str, offset + 1)) ); } function outOfRange(opts, value, numEnd) { if (opts && opts.type === 'Range') { const num = Number( numEnd !== undefined && numEnd !== value.length ? value.substr(0, numEnd) : value ); if (isNaN(num)) { return true; } // FIXME: when opts.min is a string it's a dimension, skip a range validation // for now since it requires a type covertation which is not implmented yet if (opts.min !== null && num < opts.min && typeof opts.min !== 'string') { return true; } // FIXME: when opts.max is a string it's a dimension, skip a range validation // for now since it requires a type covertation which is not implmented yet if (opts.max !== null && num > opts.max && typeof opts.max !== 'string') { return true; } } return false; } function consumeFunction(token, getNextToken) { let balanceCloseType = 0; let balanceStash = []; let length = 0; // balanced token consuming scan: do { switch (token.type) { case types.RightCurlyBracket: case types.RightParenthesis: case types.RightSquareBracket: if (token.type !== balanceCloseType) { break scan; } balanceCloseType = balanceStash.pop(); if (balanceStash.length === 0) { length++; break scan; } break; case types.Function: case types.LeftParenthesis: case types.LeftSquareBracket: case types.LeftCurlyBracket: balanceStash.push(balanceCloseType); balanceCloseType = balancePair.get(token.type); break; } length++; } while (token = getNextToken(length)); return length; } // TODO: implement // can be used wherever , , ,