'use strict'; const genericConst = require('./generic-const.cjs'); const genericAnPlusB = require('./generic-an-plus-b.cjs'); const genericUrange = require('./generic-urange.cjs'); const types = require('../tokenizer/types.cjs'); const charCodeDefinitions = require('../tokenizer/char-code-definitions.cjs'); const utils = require('../tokenizer/utils.cjs'); const calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc(']; const balancePair = new Map([ [types.Function, types.RightParenthesis], [types.LeftParenthesis, types.RightParenthesis], [types.LeftSquareBracket, types.RightSquareBracket], [types.LeftCurlyBracket, types.RightCurlyBracket] ]); // units const LENGTH = [ // absolute length units https://www.w3.org/TR/css-values-3/#lengths 'cm', 'mm', 'q', 'in', 'pt', 'pc', 'px', // font-relative length units https://drafts.csswg.org/css-values-4/#font-relative-lengths 'em', 'rem', 'ex', 'rex', 'cap', 'rcap', 'ch', 'rch', 'ic', 'ric', 'lh', 'rlh', // viewport-percentage lengths https://drafts.csswg.org/css-values-4/#viewport-relative-lengths 'vw', 'svw', 'lvw', 'dvw', 'vh', 'svh', 'lvh', 'dvh', 'vi', 'svi', 'lvi', 'dvi', 'vb', 'svb', 'lvb', 'dvb', 'vmin', 'svmin', 'lvmin', 'dvmin', 'vmax', 'svmax', 'lvmax', 'dvmax', // container relative lengths https://drafts.csswg.org/css-contain-3/#container-lengths 'cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax' ]; const ANGLE = ['deg', 'grad', 'rad', 'turn']; // https://www.w3.org/TR/css-values-3/#angles const TIME = ['s', 'ms']; // https://www.w3.org/TR/css-values-3/#time const FREQUENCY = ['hz', 'khz']; // https://www.w3.org/TR/css-values-3/#frequency const RESOLUTION = ['dpi', 'dpcm', 'dppx', 'x']; // https://www.w3.org/TR/css-values-3/#resolution const FLEX = ['fr']; // https://drafts.csswg.org/css-grid/#fr-unit const DECIBEL = ['db']; // https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume const SEMITONES = ['st']; // https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch // 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 , , ,