/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/css/data.js
3 110 строк
86 KB
Alexander Akait
feat(css): join adjacent rules and fold more value spellings (#21648)
10 авг 2026, 08:55
Не верифицирован
10 авг 2026, 08:55
3197f80
Код
Авторство
О чём код?
/* MIT License http://www.opensource.org/licenses/mit-license.php Author sheo13666q @sheo13666q */ // GENERATED by tooling/generate-css-data.js — do not edit. // Sources: mdn-data 2.29.0, color-name 1.1.4. "use strict"; /** @typedef {(sums: Map<string, number>[]) => [string, number[]] | null} MathArgumentReader */ /** @typedef {(values: number[], strategy: string, table: Map<number, number> | null) => number | null} MathOperation */ // The arithmetic the math-function descriptors at the end of this file bind to. // It knows nothing of CSS beyond the shape of an evaluated argument, and names // no math function: which one uses which is the descriptors' business, and // `lib/css/syntax.js` only drives the binding. /** * Add two doubles, or decline when the sum carries rounding of its own. * @param {number} a one term * @param {number} b the other * @returns {number | null} their exact sum, or `null` */ const exactAdd = (a, b) => { const sum = a + b; return sum - b === a && sum - a === b ? sum : null; }; /** * Multiply, or decline, on the same terms. * @param {number} a the value * @param {number} k the factor * @returns {number | null} their exact product, or `null` */ const exactMultiply = (a, k) => { const product = a * k; if (!Number.isFinite(product)) return null; if (a === 0 || k === 0) return product; return product / k === a ? product : null; }; /** * Divide, or decline, on the same terms. * @param {number} a the value * @param {number} k the divisor * @returns {number | null} their exact quotient, or `null` */ const exactDivide = (a, k) => { if (k === 0) return null; const quotient = a / k; if (!Number.isFinite(quotient)) return null; return quotient * k === a ? quotient : null; }; /** * `floor(value / step)` for a positive step, checked against the step exactly. * The double quotient can land an ulp either side of an integer, which would put * the multiple a whole step out, so the candidate is verified by multiplying * back and nudged at most once either way. * @param {number} value the dividend * @param {number} step the divisor, greater than zero * @returns {number | null} the floor, or `null` when it cannot be pinned down */ const exactFloorDivide = (value, step) => { let n = Math.floor(value / step); if (!Number.isFinite(n)) return null; for (let attempt = 0; attempt < 3; attempt++) { const at = exactMultiply(n, step); const next = exactMultiply(n + 1, step); if (at === null || next === null) return null; if (at > value) { n--; continue; } if (next <= value) { n++; continue; } return n; } return null; }; /** * The square root of a value, where it is one that can be written down. IEEE-754 * makes `Math.sqrt` correctly rounded, so squaring the result back is a complete * test — and it fails for every irrational root, which is most of them. * @param {number} value the radicand * @returns {number | null} the root, or `null` */ const exactSquareRoot = (value) => { if (!(value >= 0)) return null; const root = Math.sqrt(value); const back = exactMultiply(root, root); return back === null || back !== value ? null : root; }; // Beyond this an integer exponent is not worth multiplying out, and every result // overflows a double for all but a base within an ulp of 1. const POWER_LIMIT = 64; /** * `base ** exponent` for a whole exponent, by multiplying out. Every step is * checked, so the result is the one an engine computing in doubles gets — which * `Math.pow` is not required to be for a general exponent. * @param {number} base the base * @param {number} exponent a whole exponent * @returns {number | null} the power, or `null` */ const exactIntegerPower = (base, exponent) => { if (!Number.isInteger(exponent) || Math.abs(exponent) > POWER_LIMIT) { return null; } let power = 1; for (let n = Math.abs(exponent); n > 0; n--) { const next = exactMultiply(power, base); if (next === null) return null; power = next; } return exponent < 0 ? exactDivide(1, power) : power; }; /** * One evaluated argument list, read as a shared unit and its coefficients. A * percentage is refused: its basis can be negative (a `background-position` * against an image wider than its box), and comparing two of them depends on * that sign in a way `calc()`'s arithmetic does not — scaling a percentage is * linear, picking the smaller of two is not. * @param {Map<string, number>[]} sums the evaluated arguments * @returns {[string, number[]] | null} the shared unit and the coefficients */ const readSameUnit = (sums) => { /** @type {string | null} */ let shared = null; /** @type {number[]} */ const values = []; for (const sum of sums) { if (sum.size !== 1) return null; const [[key, coefficient]] = sum; if (key === "%") return null; if (shared === null) shared = key; else if (shared !== key) return null; values.push(coefficient); } return shared === null ? null : [shared, values]; }; /** * The same, narrowed to arguments that reduced to a plain `<number>`. * @param {Map<string, number>[]} sums the evaluated arguments * @returns {[string, number[]] | null} the unit (always `""`) and the numbers */ const readNumber = (sums) => { const shared = readSameUnit(sums); return shared === null || shared[0] !== "" ? null : shared; }; /** * A reader answering which eighth turn a single angle argument is, as the one * "coefficient" — a lookup key rather than a magnitude, which `lookup` takes. A * plain number is an angle in radians, where only zero lands on a whole one. * @param {Map<string, number>} quarterTurnAngle a quarter turn in each unit that spells one exactly * @returns {(sums: Map<string, number>[]) => [string, number[]] | null} the reader */ const eighthTurnReader = (quarterTurnAngle) => (sums) => { const shared = readSameUnit(sums); if (shared === null) return null; const [unit, [angle]] = shared; if (unit === "") return angle === 0 ? ["", [0]] : null; const quarter = quarterTurnAngle.get(unit); if (quarter === undefined) return null; // Halving a quarter turn is exact in each unit that spells one: 45, 50 and an // eighth, which is a power of two. const eighths = exactDivide(angle, quarter / 2); if (eighths === null || !Number.isInteger(eighths)) return null; return ["", [((eighths % 8) + 8) % 8]]; }; /** * @param {number[]} values the coefficients * @returns {number} the smallest */ const minimum = (values) => Math.min(...values); /** * @param {number[]} values the coefficients * @returns {number} the largest */ const maximum = (values) => Math.max(...values); /** * CSS Values 4 §10.4: the lower bound wins a contradictory pair. * @param {number[]} values the lower bound, the value and the upper bound * @returns {number} the value held between them */ const clamp = ([lower, value, upper]) => Math.max(lower, Math.min(value, upper)); /** * @param {number[]} values the one coefficient * @returns {number} its magnitude */ const absolute = ([value]) => Math.abs(value); /** * The one operation whose answer changes unit: a sign is a `<number>`. Every * unit reaching here scales by a positive factor, so the coefficient's sign is * the value's even where the factor is not known. * @param {number[]} values the one coefficient * @returns {number} its sign */ const sign = ([value]) => Math.sign(value); /** * @param {number[]} values the coefficients * @returns {number | null} the root of their sum of squares, or `null` */ const hypotenuse = (values) => { let total = 0; for (const value of values) { const square = exactMultiply(value, value); if (square === null) return null; const sum = exactAdd(total, square); if (sum === null) return null; total = sum; } return exactSquareRoot(total); }; /** * The multiple of `step` that `strategy` rounds `value` to, as CSS Values 4 * §10.6 defines them and headless Chromium confirms: `nearest` breaks a tie * toward positive infinity, and the other three are the ceiling, the floor and * the truncation. A step of zero is NaN per the spec and engines do not agree * on what that renders as; a negative one is left alone rather than reasoned * about. * @param {number[]} values the value and the step * @param {string} strategy one of the grammar's rounding strategies * @returns {number | null} the rounded multiple, or `null` */ const round = ([value, step], strategy) => { if (!(step > 0)) return null; const below = exactFloorDivide(value, step); if (below === null) return null; const at = /** @type {number} */ (exactMultiply(below, step)); // Exactly on a step is where engines stop agreeing: these are step functions, // so an ulp of error in the engine's own conversion moves the answer a whole // step. Headless Chromium reads `round(down,10cm,2cm)` as `8cm` and // `round(down,-7cm,.5cm)` as `-7.5cm`. Away from a boundary the gap is orders // of magnitude wider than any such error, so only the boundary is refused. if (at === value) return null; let multiple; if (strategy === "down") { multiple = below; } else if (strategy === "up") { multiple = below + 1; } else if (strategy === "to-zero") { multiple = value < 0 ? below + 1 : below; } else { // The remainder is in `[0, step)`, so twice it against the step is the // comparison, and an exact half rounds up — toward positive infinity. const remainder = exactAdd(value, -at); if (remainder === null) return null; const doubled = exactMultiply(remainder, 2); if (doubled === null) return null; multiple = doubled >= step ? below + 1 : below; } return exactMultiply(multiple, step); }; /** * The remainder carrying the divisor's sign. * @param {number[]} values the dividend and the divisor * @returns {number | null} the remainder, or `null` */ const modulus = ([value, divisor]) => { if (divisor === 0) return null; const remainder = value % divisor; // A zero remainder is the boundary these two share with `round()`, and engines // do not agree on it: headless Chromium reads `mod(10px,-2px)` and // `mod(-9px,3px)` as the divisor where both are zero. if (remainder === 0) return null; // A remainder on the other side of zero is brought back across it. return remainder < 0 === divisor < 0 ? remainder : exactAdd(remainder, divisor); }; /** * The remainder carrying the dividend's sign, which is what `%` already does. * @param {number[]} values the dividend and the divisor * @returns {number | null} the remainder, or `null` */ const remainder = ([value, divisor]) => { if (divisor === 0) return null; // The same zero boundary `modulus` declines. const rest = value % divisor; return rest === 0 ? null : rest; }; /** * @param {number[]} values the one radicand * @returns {number | null} its root, or `null` */ const squareRoot = ([value]) => exactSquareRoot(value); /** * @param {number[]} values the base and the exponent * @returns {number | null} the power, or `null` */ const power = ([base, exponent]) => exactIntegerPower(base, exponent); /** * A logarithm is transcendental except where it lands on a whole power of its * base, so the candidate is raised back and only an exact match is taken. The * natural logarithm's base is not a double at all, which leaves only `log(1)`. * @param {number[]} values the value and, optionally, the base * @returns {number | null} the logarithm, or `null` */ const logarithm = ([value, base]) => { if (base === undefined) return value === 1 ? 0 : null; const exponent = Math.round(Math.log(value) / Math.log(base)); const back = exactIntegerPower(base, exponent); return back === null || back !== value ? null : exponent; }; /** * `e` is not a double, so every other power of it is a number this cannot write * down and an engine's math library rounds its own way. * @param {number[]} values the one exponent * @returns {number | null} the power of `e`, or `null` */ const exponential = ([value]) => (value === 0 ? 1 : null); /** * Read the answer out of the table the descriptor carries. Absent means the * value is one no stylesheet can hold, so the call stays written out. * @param {number[]} values the one lookup key * @param {string} _strategy unused * @param {Map<number, number> | null} table the descriptor's table * @returns {number | null} the answer, or `null` */ const lookup = ([key], _strategy, table) => { const value = /** @type {Map<number, number>} */ (table).get(key); return value === undefined ? null : value; }; /** * The eight directions the arc tangent of a ratio is a whole number of degrees * in, an eighth turn apart. Both zero is refused: the spec leaves it to the * engine. * @param {number[]} values the two coordinates * @returns {number | null} the angle in degrees, or `null` */ const arcTangent2 = ([y, x]) => { if (y === 0 && x === 0) return null; if (y === 0) return x > 0 ? 0 : 180; if (x === 0) return y > 0 ? 90 : -90; if (Math.abs(y) !== Math.abs(x)) return null; if (x > 0) return y > 0 ? 45 : -45; return y > 0 ? 135 : -135; }; // Properties whose value is CSS's `{1,4}` box notation, where an omitted value // is copied from the opposite side. That makes a repeated value redundant: // `margin:1px 1px 1px 1px` is `margin:1px`. `border-radius` collapses each side // of its `/` independently. const BOX_SHORTHANDS = new Set([ "border-color", "border-image-outset", "border-image-width", "border-radius", "border-style", "border-width", "corner-shape", "inset", "margin", "mask-border-outset", "mask-border-width", "padding", "scroll-margin", "scroll-padding" ]); // The subset carrying a second box after a `/`, which collapses on its own. const SLASH_BOX_SHORTHANDS = new Set(["border-radius"]); // The four longhands each box shorthand sets, in the order `{1,4}` writes them: // `top right bottom left`, or clockwise from the top left for a corner family. // Only the families whose longhands are those four: merging those into the // shorthand sets exactly the same properties, resetting nothing extra. // prettier-ignore const BOX_LONGHANDS = new Map([ ["border-color", ["border-top-color", "border-right-color", "border-bottom-color", "border-left-color"]], ["border-radius", ["border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius"]], ["border-style", ["border-top-style", "border-right-style", "border-bottom-style", "border-left-style"]], ["border-width", ["border-top-width", "border-right-width", "border-bottom-width", "border-left-width"]], ["corner-shape", ["corner-top-left-shape", "corner-top-right-shape", "corner-bottom-right-shape", "corner-bottom-left-shape"]], ["inset", ["top", "right", "bottom", "left"]], ["margin", ["margin-top", "margin-right", "margin-bottom", "margin-left"]], ["padding", ["padding-top", "padding-right", "padding-bottom", "padding-left"]], ["scroll-margin", ["scroll-margin-top", "scroll-margin-right", "scroll-margin-bottom", "scroll-margin-left"]], ["scroll-padding", ["scroll-padding-top", "scroll-padding-right", "scroll-padding-bottom", "scroll-padding-left"]] ]); // The shorthands setting exactly two longhands, positionally — the same merge // as the box families, two values wide. Only these: a shorthand gathering a // whole family resets longhands `computed` does not name. const PAIR_LONGHANDS = new Map([ [ "border-block-color", ["border-block-start-color", "border-block-end-color"] ], [ "border-block-style", ["border-block-start-style", "border-block-end-style"] ], [ "border-block-width", ["border-block-start-width", "border-block-end-width"] ], [ "border-inline-color", ["border-inline-start-color", "border-inline-end-color"] ], [ "border-inline-style", ["border-inline-start-style", "border-inline-end-style"] ], [ "border-inline-width", ["border-inline-start-width", "border-inline-end-width"] ], [ "contain-intrinsic-size", ["contain-intrinsic-width", "contain-intrinsic-height"] ], [ "corner-block-end-shape", ["corner-end-start-shape", "corner-end-end-shape"] ], [ "corner-block-start-shape", ["corner-start-start-shape", "corner-start-end-shape"] ], [ "corner-bottom-shape", ["corner-bottom-left-shape", "corner-bottom-right-shape"] ], [ "corner-inline-end-shape", ["corner-start-end-shape", "corner-end-end-shape"] ], [ "corner-inline-start-shape", ["corner-start-start-shape", "corner-end-start-shape"] ], ["corner-left-shape", ["corner-top-left-shape", "corner-bottom-left-shape"]], [ "corner-right-shape", ["corner-top-right-shape", "corner-bottom-right-shape"] ], ["corner-top-shape", ["corner-top-left-shape", "corner-top-right-shape"]], ["gap", ["row-gap", "column-gap"]], ["inset-block", ["inset-block-start", "inset-block-end"]], ["inset-inline", ["inset-inline-start", "inset-inline-end"]], ["interest-delay", ["interest-delay-start", "interest-delay-end"]], ["margin-block", ["margin-block-start", "margin-block-end"]], ["margin-inline", ["margin-inline-start", "margin-inline-end"]], ["overflow", ["overflow-x", "overflow-y"]], ["overscroll-behavior", ["overscroll-behavior-x", "overscroll-behavior-y"]], ["padding-block", ["padding-block-start", "padding-block-end"]], ["padding-inline", ["padding-inline-start", "padding-inline-end"]], [ "scroll-margin-block", ["scroll-margin-block-start", "scroll-margin-block-end"] ], [ "scroll-margin-inline", ["scroll-margin-inline-start", "scroll-margin-inline-end"] ], [ "scroll-padding-block", ["scroll-padding-block-start", "scroll-padding-block-end"] ], [ "scroll-padding-inline", ["scroll-padding-inline-start", "scroll-padding-inline-end"] ] ]); // The subset whose two-value form is newer than the longhands, so only a merge // collapsing to one value may emit it. const ONE_VALUE_PAIR_SHORTHANDS = new Set(["overflow"]); // The shorthands written as an order-free `||` of their own longhands, each // appearing once, in grammar order. A merge emits every value, so the only // question is whether each parses back into the longhand it was authored on. // prettier-ignore const FAMILY_LONGHANDS = new Map([["border-bottom", ["border-bottom-width","border-bottom-style","border-bottom-color"]], ["border-left", ["border-left-width","border-left-style","border-left-color"]], ["border-right", ["border-right-width","border-right-style","border-right-color"]], ["border-top", ["border-top-width","border-top-style","border-top-color"]], ["column-rule", ["column-rule-width","column-rule-style","column-rule-color"]], ["flex-flow", ["flex-direction","flex-wrap"]], ["list-style", ["list-style-type","list-style-position","list-style-image"]], ["outline", ["outline-width","outline-style","outline-color"]], ["text-decoration", ["text-decoration-line","text-decoration-style","text-decoration-color","text-decoration-thickness"]], ["text-emphasis", ["text-emphasis-style","text-emphasis-color"]], ["text-wrap", ["text-wrap-mode","text-wrap-style"]]]); // What each of those longhands accepts as a whole value: the keywords it names, // and the value classes it reaches. A value acceptable to a second slot is what // makes the merge ambiguous, and `FAMILY_SLOT_CLASSES` names a type the printer // cannot classify as readily as one it can, so an unknown one declines. // prettier-ignore const FAMILY_SLOT_KEYWORDS = new Map([["border-bottom-width", ["medium","thick","thin"]], ["border-bottom-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-bottom-color", []], ["border-left-width", ["medium","thick","thin"]], ["border-left-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-left-color", []], ["border-right-width", ["medium","thick","thin"]], ["border-right-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-right-color", []], ["border-top-width", ["medium","thick","thin"]], ["border-top-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["border-top-color", []], ["column-rule-width", ["medium","thick","thin"]], ["column-rule-style", ["dashed","dotted","double","groove","hidden","inset","none","outset","ridge","solid"]], ["column-rule-color", []], ["flex-direction", ["column","column-reverse","row","row-reverse"]], ["flex-wrap", ["nowrap","wrap","wrap-reverse"]], ["list-style-type", ["none"]], ["list-style-position", ["inside","outside"]], ["list-style-image", ["none"]], ["outline-width", ["medium","thick","thin"]], ["outline-style", ["auto","dashed","dotted","double","groove","inset","none","outset","ridge","solid"]], ["outline-color", ["auto"]], ["text-decoration-line", ["blink","grammar-error","line-through","none","overline","spelling-error","underline"]], ["text-decoration-style", ["dashed","dotted","double","solid","wavy"]], ["text-decoration-color", []], ["text-decoration-thickness", ["auto","from-font"]], ["text-emphasis-style", ["circle","dot","double-circle","filled","none","open","sesame","triangle"]], ["text-emphasis-color", []], ["text-wrap-mode", ["nowrap","wrap"]], ["text-wrap-style", ["auto","balance","pretty","stable"]]]); // prettier-ignore const FAMILY_SLOT_CLASSES = new Map([["border-bottom-width", ["length"]], ["border-bottom-style", []], ["border-bottom-color", ["color"]], ["border-left-width", ["length"]], ["border-left-style", []], ["border-left-color", ["color"]], ["border-right-width", ["length"]], ["border-right-style", []], ["border-right-color", ["color"]], ["border-top-width", ["length"]], ["border-top-style", []], ["border-top-color", ["color"]], ["column-rule-width", ["length"]], ["column-rule-style", []], ["column-rule-color", ["color"]], ["flex-direction", []], ["flex-wrap", []], ["list-style-type", ["custom-ident","string"]], ["list-style-position", []], ["list-style-image", ["image"]], ["outline-width", ["length"]], ["outline-style", []], ["outline-color", ["color"]], ["text-decoration-line", []], ["text-decoration-style", []], ["text-decoration-color", ["color"]], ["text-decoration-thickness", ["length","percentage"]], ["text-emphasis-style", ["string"]], ["text-emphasis-color", ["color"]], ["text-wrap-mode", []], ["text-wrap-style", []]]); // The identifiers that are a `<color>` on their own — named, system and the two // context-dependent ones. Read off the `<color>` grammar outside any function, // so a channel keyword like the `none` in `hsl(0 none 0)` is not among them. // cspell:ignore accentcolor accentcolortext activeborder activecaption activetext aliceblue antiquewhite appworkspace aqua aquamarine azure background beige bisque black blanchedalmond blue blueviolet brown burlywood buttonborder buttonface buttonhighlight buttonshadow buttontext cadetblue canvas canvastext captiontext chartreuse chocolate coral cornflowerblue cornsilk crimson currentcolor cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue field fieldtext firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray graytext green greenyellow grey highlight highlighttext honeydew hotpink inactiveborder inactivecaption inactivecaptiontext indianred indigo infobackground infotext ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen linktext magenta mark marktext maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred menu menutext midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown scrollbar seagreen seashell selecteditem selecteditemtext sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle threeddarkshadow threedface threedhighlight threedlightshadow threedshadow tomato transparent turquoise violet visitedtext wheat white whitesmoke window windowframe windowtext yellow yellowgreen const COLOR_KEYWORDS = new Set([ "accentcolor", "accentcolortext", "activeborder", "activecaption", "activetext", "aliceblue", "antiquewhite", "appworkspace", "aqua", "aquamarine", "azure", "background", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "buttonborder", "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cadetblue", "canvas", "canvastext", "captiontext", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "currentcolor", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "field", "fieldtext", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "graytext", "green", "greenyellow", "grey", "highlight", "highlighttext", "honeydew", "hotpink", "inactiveborder", "inactivecaption", "inactivecaptiontext", "indianred", "indigo", "infobackground", "infotext", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "linktext", "magenta", "mark", "marktext", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "menu", "menutext", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "scrollbar", "seagreen", "seashell", "selecteditem", "selecteditemtext", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "threeddarkshadow", "threedface", "threedhighlight", "threedlightshadow", "threedshadow", "tomato", "transparent", "turquoise", "violet", "visitedtext", "wheat", "white", "whitesmoke", "window", "windowframe", "windowtext", "yellow", "yellowgreen" ]); // The name prefix a declaration between two box longhands must not carry for the // merge to step over it. The shorthand's first segment, which is deliberately // wider than the family: `border-color` blocks every `border*` property, since // `border`, `border-top` and `border-block-start-color` all write its longhands // and `mdn-data`'s `computed` lists only some of them. const BOX_FAMILY_PREFIX = new Map([ ["border-color", "border"], ["border-radius", "border"], ["border-style", "border"], ["border-width", "border"], ["corner-shape", "corner"], ["inset", "inset"], ["margin", "margin"], ["padding", "padding"], ["scroll-margin", "scroll"], ["scroll-padding", "scroll"] ]); // Functions that take a `<color>` directly, so a hash among their arguments is a // hex color rather than a case-sensitive reference (`element(#id)`). Only direct // arguments: a gradient nested in `image-set()` is matched as the gradient. const COLOR_ARGUMENT_FUNCTIONS = new Set([ "color", "color-mix", "conic-gradient", "cross-fade", "drop-shadow", "image", "light-dark", "linear-gradient", "radial-gradient", "repeating-conic-gradient", "repeating-linear-gradient", "repeating-radial-gradient" ]); // Functions that substitute an arbitrary token sequence, so two identical // references need not be one repeated value: with `--x:1px 2px`, // `margin:var(--x) var(--x)` is four values, not two. const SUBSTITUTION_FUNCTIONS = new Set([ "attr", "env", "first-valid", "if", "inherit", "paint", "random-item", "var" ]); // The pseudo-class functions whose argument is An+B, where `2n+1` is the // notation `odd` names in one byte less. const NTH_PSEUDO_FUNCTIONS = new Set([ "nth-child", "nth-last-child", "nth-last-of-type", "nth-of-type" ]); // The properties taking a color and never an identifier of the author's own, so // a named color written in one is that color and may be spelled the shortest way. const COLOR_ONLY_PROPERTIES = new Set([ "-moz-border-bottom-colors", "-moz-border-left-colors", "-moz-border-right-colors", "-moz-border-top-colors", "-ms-scrollbar-3dlight-color", "-ms-scrollbar-arrow-color", "-ms-scrollbar-base-color", "-ms-scrollbar-darkshadow-color", "-ms-scrollbar-face-color", "-ms-scrollbar-highlight-color", "-ms-scrollbar-shadow-color", "-ms-scrollbar-track-color", "-webkit-border-after", "-webkit-border-after-color", "-webkit-border-before", "-webkit-border-before-color", "-webkit-border-end", "-webkit-border-end-color", "-webkit-border-start", "-webkit-border-start-color", "-webkit-tap-highlight-color", "-webkit-text-fill-color", "-webkit-text-stroke", "-webkit-text-stroke-color", "accent-color", "backdrop-filter", "background-color", "border", "border-block", "border-block-color", "border-block-end", "border-block-end-color", "border-block-start", "border-block-start-color", "border-bottom", "border-bottom-color", "border-color", "border-inline", "border-inline-color", "border-inline-end", "border-inline-end-color", "border-inline-start", "border-inline-start-color", "border-left", "border-left-color", "border-right", "border-right-color", "border-top", "border-top-color", "box-shadow", "caret", "caret-color", "color", "column-rule", "column-rule-color", "fill", "filter", "flood-color", "lighting-color", "outline", "outline-color", "scrollbar-color", "stop-color", "stroke", "stroke-color", "text-decoration", "text-decoration-color", "text-emphasis", "text-emphasis-color", "text-shadow" ]); // Each two-keyword `display` -> the single keyword naming the same box. const DISPLAY_SHORT_FORMS = new Map([ ["block flex", "flex"], ["block flow", "block"], ["block flow-root", "flow-root"], ["block grid", "grid"], ["block table", "table"], ["inline flow", "inline"], ["inline flow-root", "inline-block"], ["inline ruby", "ruby"], ["run-in flow", "run-in"] ]); // Each property whose value is a list of shadows -> the count of lengths a // shadow cannot go below, past which a trailing zero is already implied. const SHADOW_PROPERTIES = new Map([ ["box-shadow", 2], ["text-shadow", 2] ]); // Each shorthand -> the keywords one of its values may drop, each with every // spelling its own slot takes: the slot's keywords, and each function it // accepts written `name()`. A sibling out of that set means the value fills the // slot twice, which is a declaration the engine drops. const SHORTHAND_INITIAL_KEYWORDS = new Map([ [ "animation", new Map([ [ "ease", new Set([ "cubic-bezier()", "ease", "ease-in", "ease-in-out", "ease-out", "linear", "linear()", "step-end", "step-start", "steps()" ]) ], [ "normal", new Set(["alternate", "alternate-reverse", "normal", "reverse"]) ], ["running", new Set(["paused", "running"])] ]) ], [ "background", new Map([ [ "none", new Set([ "color()", "color-mix()", "conic-gradient()", "cross-fade()", "element()", "hsl()", "hsla()", "hwb()", "image()", "image-set()", "lab()", "lch()", "light-dark()", "linear-gradient()", "none", "oklab()", "oklch()", "paint()", "radial-gradient()", "repeating-conic-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()", "rgb()", "rgba()", "src()", "type()", "url()" ]) ], [ "repeat", new Set([ "no-repeat", "repeat", "repeat-x", "repeat-y", "round", "space" ]) ], ["scroll", new Set(["fixed", "local", "scroll"])] ]) ], [ "border", new Map([ [ "none", new Set([ "dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid" ]) ] ]) ], [ "border-bottom", new Map([ [ "none", new Set([ "dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid" ]) ] ]) ], [ "border-image", new Map([ [ "none", new Set([ "color()", "color-mix()", "conic-gradient()", "cross-fade()", "element()", "hsl()", "hsla()", "hwb()", "image()", "image-set()", "lab()", "lch()", "light-dark()", "linear-gradient()", "none", "oklab()", "oklch()", "paint()", "radial-gradient()", "repeating-conic-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()", "rgb()", "rgba()", "src()", "type()", "url()" ]) ], ["stretch", new Set(["repeat", "round", "space", "stretch"])] ]) ], [ "border-left", new Map([ [ "none", new Set([ "dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid" ]) ] ]) ], [ "border-right", new Map([ [ "none", new Set([ "dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid" ]) ] ]) ], [ "border-top", new Map([ [ "none", new Set([ "dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid" ]) ] ]) ], [ "column-rule", new Map([ [ "none", new Set([ "dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid" ]) ] ]) ], [ "flex-flow", new Map([ ["nowrap", new Set(["nowrap", "wrap", "wrap-reverse"])], ["row", new Set(["column", "column-reverse", "row", "row-reverse"])] ]) ], ["list-style", new Map([["outside", new Set(["inside", "outside"])]])], [ "mask", new Map([ ["add", new Set(["add", "exclude", "intersect", "subtract"])], ["match-source", new Set(["alpha", "luminance", "match-source"])], [ "none", new Set([ "color()", "color-mix()", "conic-gradient()", "cross-fade()", "element()", "hsl()", "hsla()", "hwb()", "image()", "image-set()", "lab()", "lch()", "light-dark()", "linear-gradient()", "none", "oklab()", "oklch()", "paint()", "radial-gradient()", "repeating-conic-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()", "rgb()", "rgba()", "src()", "type()", "url()" ]) ], [ "repeat", new Set([ "no-repeat", "repeat", "repeat-x", "repeat-y", "round", "space" ]) ] ]) ], [ "mask-border", new Map([ ["alpha", new Set(["alpha", "luminance"])], [ "none", new Set([ "color()", "color-mix()", "conic-gradient()", "cross-fade()", "element()", "hsl()", "hsla()", "hwb()", "image()", "image-set()", "lab()", "lch()", "light-dark()", "linear-gradient()", "none", "oklab()", "oklch()", "paint()", "radial-gradient()", "repeating-conic-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()", "rgb()", "rgba()", "src()", "type()", "url()" ]) ], ["stretch", new Set(["repeat", "round", "space", "stretch"])] ]) ], [ "outline", new Map([ [ "none", new Set([ "auto", "dashed", "dotted", "double", "groove", "inset", "none", "outset", "ridge", "solid" ]) ] ]) ], [ "text-decoration", new Map([ [ "none", new Set([ "blink", "grammar-error", "line-through", "none", "overline", "spelling-error", "underline" ]) ], ["solid", new Set(["dashed", "dotted", "double", "solid", "wavy"])] ]) ], [ "transition", new Map([ [ "ease", new Set([ "cubic-bezier()", "ease", "ease-in", "ease-in-out", "ease-out", "linear", "linear()", "step-end", "step-start", "steps()" ]) ], ["normal", new Set(["allow-discrete", "normal"])] ]) ] ]); // Each `font-stretch` keyword -> the percentage it names, which is the same // value in fewer bytes. const FONT_STRETCH_PERCENTAGES = new Map([ ["ultra-condensed", "50%"], ["extra-condensed", "62.5%"], ["condensed", "75%"], ["semi-condensed", "87.5%"], ["normal", "100%"], ["semi-expanded", "112.5%"], ["expanded", "125%"], ["extra-expanded", "150%"], ["ultra-expanded", "200%"] ]); // Each `<filter-function>` with an optional argument -> the amount an omitted // one means, which is what writing that amount already says. const FILTER_FUNCTION_OMITTED = new Map([ ["blur", "0"], ["brightness", "1"], ["contrast", "1"], ["grayscale", "1"], ["hue-rotate", "0"], ["invert", "1"], ["opacity", "1"], ["saturate", "1"], ["sepia", "1"] ]); // The generic font families: an unquoted one of these names the generic rather // than a family called that, so a quoted family spelled like one keeps its quotes. const GENERIC_FONT_FAMILIES = new Set([ "cursive", "emoji", "fangsong", "fantasy", "math", "monospace", "sans-serif", "serif", "system-ui", "ui-monospace", "ui-rounded", "ui-sans-serif", "ui-serif" ]); // Each gradient function -> the positions its last color stop already means, so // writing one of them there says nothing (CSS Images 3 §3.4.3). const GRADIENT_LAST_POSITIONS = new Map([ ["conic-gradient", new Set(["100%", "360deg", "1turn"])], ["linear-gradient", new Set(["100%"])], ["radial-gradient", new Set(["100%"])], ["repeating-conic-gradient", new Set(["100%", "360deg", "1turn"])], ["repeating-linear-gradient", new Set(["100%"])], ["repeating-radial-gradient", new Set(["100%"])] ]); // The properties whose value is a position, where each edge keyword names the // percentage that axis resolves to. const POSITION_PROPERTIES = new Set([ "-webkit-mask-position", "background-position", "mask-position", "object-position", "offset-anchor", "offset-position", "perspective-origin", "scroll-snap-coordinate", "scroll-snap-destination", "transform-origin" ]); // Each keyword one axis of a `<position>` accepts -> the percentage it resolves // to. A keyword both maps carry (`center`) names whichever axis is still free, // and every free axis is `50%` anyway. const POSITION_X_KEYWORDS = new Map([ ["center", "50%"], ["left", "0%"], ["right", "100%"] ]); const POSITION_Y_KEYWORDS = new Map([ ["bottom", "100%"], ["center", "50%"], ["top", "0%"] ]); // The keywords one `<repeat-style>` axis can be: a pair only collapses where // both halves are one of these. const REPEAT_STYLE_KEYWORDS = new Set([ "no-repeat", "repeat", "round", "space" ]); // The properties whose value is a `<repeat-style>`, where one value already // says what two equal ones do. const REPEAT_STYLE_PROPERTIES = new Set([ "-webkit-mask", "-webkit-mask-repeat", "background", "background-repeat", "mask", "mask-repeat" ]); // Each property whose initial value is a keyword shorter than `initial` -> that // keyword, which is the same declaration written in fewer bytes. const INITIAL_VALUE_KEYWORDS = new Map([ ["-moz-binding", "none"], ["-moz-border-bottom-colors", "none"], ["-moz-border-left-colors", "none"], ["-moz-border-right-colors", "none"], ["-moz-border-top-colors", "none"], ["-moz-context-properties", "none"], ["-moz-orient", "inline"], ["-moz-text-blink", "none"], ["-moz-user-focus", "none"], ["-moz-user-input", "auto"], ["-moz-window-dragging", "drag"], ["-ms-accelerator", "false"], ["-ms-block-progression", "tb"], ["-ms-content-zoom-chaining", "none"], ["-ms-content-zoom-snap-type", "none"], ["-ms-flow-from", "none"], ["-ms-flow-into", "none"], ["-ms-grid-columns", "none"], ["-ms-grid-rows", "none"], ["-ms-high-contrast-adjust", "auto"], ["-ms-hyphenate-limit-chars", "auto"], ["-ms-ime-align", "auto"], ["-ms-overflow-style", "auto"], ["-ms-scroll-limit-x-max", "auto"], ["-ms-scroll-limit-y-max", "auto"], ["-ms-scroll-rails", "railed"], ["-ms-scroll-snap-type", "none"], ["-ms-scroll-translation", "none"], ["-ms-text-autospace", "none"], ["-ms-user-select", "text"], ["-ms-wrap-flow", "auto"], ["-ms-wrap-through", "wrap"], ["-webkit-border-after-style", "none"], ["-webkit-border-after-width", "medium"], ["-webkit-border-before-style", "none"], ["-webkit-border-before-width", "medium"], ["-webkit-border-end-style", "none"], ["-webkit-border-end-width", "medium"], ["-webkit-border-start-style", "none"], ["-webkit-border-start-width", "medium"], ["-webkit-line-clamp", "none"], ["-webkit-mask-attachment", "scroll"], ["-webkit-mask-clip", "border"], ["-webkit-mask-image", "none"], ["-webkit-mask-repeat", "repeat"], ["-webkit-mask-repeat-x", "repeat"], ["-webkit-mask-repeat-y", "repeat"], ["-webkit-overflow-scrolling", "auto"], ["-webkit-user-select", "auto"], ["accent-color", "auto"], ["align-content", "normal"], ["align-items", "normal"], ["align-self", "auto"], ["align-tracks", "normal"], ["anchor-name", "none"], ["anchor-scope", "none"], ["animation-direction", "normal"], ["animation-fill-mode", "none"], ["animation-name", "none"], ["animation-range-end", "normal"], ["animation-range-start", "normal"], ["animation-timeline", "auto"], ["animation-timing-function", "ease"], ["animation-trigger", "none"], ["appearance", "none"], ["aspect-ratio", "auto"], ["backdrop-filter", "none"], ["background-attachment", "scroll"], ["background-blend-mode", "normal"], ["background-image", "none"], ["background-repeat", "repeat"], ["baseline-source", "auto"], ["block-size", "auto"], ["border-block-end-style", "none"], ["border-block-end-width", "medium"], ["border-block-start-style", "none"], ["border-block-start-width", "medium"], ["border-bottom-style", "none"], ["border-bottom-width", "medium"], ["border-image-source", "none"], ["border-inline-end-style", "none"], ["border-inline-end-width", "medium"], ["border-inline-start-style", "none"], ["border-inline-start-width", "medium"], ["border-left-style", "none"], ["border-left-width", "medium"], ["border-right-style", "none"], ["border-right-width", "medium"], ["border-shape", "none"], ["border-top-style", "none"], ["border-top-width", "medium"], ["bottom", "auto"], ["box-decoration-break", "slice"], ["box-direction", "normal"], ["box-lines", "single"], ["box-pack", "start"], ["box-shadow", "none"], ["break-after", "auto"], ["break-before", "auto"], ["break-inside", "auto"], ["caption-side", "top"], ["caret-animation", "auto"], ["caret-color", "auto"], ["caret-shape", "auto"], ["clear", "none"], ["clip", "auto"], ["clip-path", "none"], ["color-scheme", "normal"], ["column-count", "auto"], ["column-gap", "normal"], ["column-height", "auto"], ["column-rule-style", "none"], ["column-rule-width", "medium"], ["column-span", "none"], ["column-width", "auto"], ["column-wrap", "auto"], ["contain", "none"], ["contain-intrinsic-block-size", "none"], ["contain-intrinsic-height", "none"], ["contain-intrinsic-inline-size", "none"], ["contain-intrinsic-width", "none"], ["container-name", "none"], ["container-type", "normal"], ["content", "normal"], ["corner-bottom-left-shape", "round"], ["corner-bottom-right-shape", "round"], ["corner-end-end-shape", "round"], ["corner-end-start-shape", "round"], ["corner-start-end-shape", "round"], ["corner-start-start-shape", "round"], ["corner-top-left-shape", "round"], ["corner-top-right-shape", "round"], ["counter-increment", "none"], ["counter-reset", "none"], ["counter-set", "none"], ["cursor", "auto"], ["d", "none"], ["direction", "ltr"], ["display", "inline"], ["dominant-baseline", "auto"], ["empty-cells", "show"], ["field-sizing", "fixed"], ["filter", "none"], ["flex-basis", "auto"], ["flex-direction", "row"], ["flex-wrap", "nowrap"], ["float", "none"], ["font-feature-settings", "normal"], ["font-kerning", "auto"], ["font-language-override", "normal"], ["font-optical-sizing", "auto"], ["font-palette", "normal"], ["font-size", "medium"], ["font-size-adjust", "none"], ["font-smooth", "auto"], ["font-stretch", "normal"], ["font-style", "normal"], ["font-synthesis-position", "none"], ["font-synthesis-small-caps", "auto"], ["font-synthesis-style", "auto"], ["font-synthesis-weight", "auto"], ["font-variant", "normal"], ["font-variant-alternates", "normal"], ["font-variant-caps", "normal"], ["font-variant-east-asian", "normal"], ["font-variant-emoji", "normal"], ["font-variant-ligatures", "normal"], ["font-variant-numeric", "normal"], ["font-variant-position", "normal"], ["font-variation-settings", "normal"], ["font-weight", "normal"], ["font-width", "normal"], ["forced-color-adjust", "auto"], ["frame-sizing", "auto"], ["grid-auto-columns", "auto"], ["grid-auto-flow", "row"], ["grid-auto-rows", "auto"], ["grid-column-end", "auto"], ["grid-column-start", "auto"], ["grid-row-end", "auto"], ["grid-row-start", "auto"], ["grid-template-areas", "none"], ["grid-template-columns", "none"], ["grid-template-rows", "none"], ["hanging-punctuation", "none"], ["height", "auto"], ["hyphenate-character", "auto"], ["hyphenate-limit-chars", "auto"], ["hyphens", "manual"], ["image-rendering", "auto"], ["ime-mode", "auto"], ["initial-letter", "normal"], ["initial-letter-align", "auto"], ["inline-size", "auto"], ["inset-block-end", "auto"], ["inset-block-start", "auto"], ["inset-inline-end", "auto"], ["inset-inline-start", "auto"], ["interactivity", "auto"], ["interest-delay-end", "normal"], ["interest-delay-start", "normal"], ["isolation", "auto"], ["justify-content", "normal"], ["justify-items", "legacy"], ["justify-self", "auto"], ["justify-tracks", "normal"], ["left", "auto"], ["letter-spacing", "normal"], ["line-break", "auto"], ["line-clamp", "none"], ["line-height", "normal"], ["list-style-image", "none"], ["margin-trim", "none"], ["marker-end", "none"], ["marker-mid", "none"], ["marker-start", "none"], ["mask-border-mode", "alpha"], ["mask-border-source", "none"], ["mask-border-width", "auto"], ["mask-composite", "add"], ["mask-image", "none"], ["mask-repeat", "repeat"], ["mask-size", "auto"], ["masonry-auto-flow", "pack"], ["math-shift", "normal"], ["math-style", "normal"], ["max-block-size", "none"], ["max-height", "none"], ["max-inline-size", "none"], ["max-lines", "none"], ["max-width", "none"], ["min-height", "auto"], ["min-width", "auto"], ["mix-blend-mode", "normal"], ["object-fit", "fill"], ["object-view-box", "none"], ["offset-anchor", "auto"], ["offset-path", "none"], ["offset-position", "normal"], ["offset-rotate", "auto"], ["outline-color", "auto"], ["outline-style", "none"], ["outline-width", "medium"], ["overflow-anchor", "auto"], ["overflow-block", "auto"], ["overflow-inline", "auto"], ["overflow-wrap", "normal"], ["overlay", "none"], ["overscroll-behavior", "auto"], ["overscroll-behavior-block", "auto"], ["overscroll-behavior-inline", "auto"], ["overscroll-behavior-x", "auto"], ["overscroll-behavior-y", "auto"], ["page", "auto"], ["page-break-after", "auto"], ["page-break-before", "auto"], ["page-break-inside", "auto"], ["paint-order", "normal"], ["perspective", "none"], ["pointer-events", "auto"], ["position", "static"], ["position-anchor", "normal"], ["position-area", "none"], ["position-try-fallbacks", "none"], ["position-try-order", "normal"], ["reading-flow", "normal"], ["resize", "none"], ["right", "auto"], ["rotate", "none"], ["row-gap", "normal"], ["ruby-overhang", "auto"], ["rx", "auto"], ["ry", "auto"], ["scale", "none"], ["scroll-behavior", "auto"], ["scroll-initial-target", "none"], ["scroll-marker-group", "none"], ["scroll-padding-block-end", "auto"], ["scroll-padding-block-start", "auto"], ["scroll-padding-bottom", "auto"], ["scroll-padding-inline-end", "auto"], ["scroll-padding-inline-start", "auto"], ["scroll-padding-left", "auto"], ["scroll-padding-right", "auto"], ["scroll-padding-top", "auto"], ["scroll-snap-align", "none"], ["scroll-snap-coordinate", "none"], ["scroll-snap-points-x", "none"], ["scroll-snap-points-y", "none"], ["scroll-snap-stop", "normal"], ["scroll-snap-type", "none"], ["scroll-snap-type-x", "none"], ["scroll-snap-type-y", "none"], ["scroll-target-group", "none"], ["scroll-timeline-axis", "block"], ["scroll-timeline-name", "none"], ["scrollbar-color", "auto"], ["scrollbar-gutter", "auto"], ["scrollbar-width", "auto"], ["shape-outside", "none"], ["shape-rendering", "auto"], ["stroke-dasharray", "none"], ["stroke-linecap", "butt"], ["stroke-linejoin", "miter"], ["table-layout", "auto"], ["text-align-last", "auto"], ["text-anchor", "start"], ["text-autospace", "normal"], ["text-box", "normal"], ["text-box-edge", "auto"], ["text-box-trim", "none"], ["text-combine-upright", "none"], ["text-decoration-line", "none"], ["text-decoration-skip-ink", "auto"], ["text-decoration-style", "solid"], ["text-decoration-thickness", "auto"], ["text-emphasis-position", "auto"], ["text-emphasis-style", "none"], ["text-justify", "auto"], ["text-orientation", "mixed"], ["text-overflow", "clip"], ["text-rendering", "auto"], ["text-shadow", "none"], ["text-spacing-trim", "normal"], ["text-transform", "none"], ["text-underline-offset", "auto"], ["text-underline-position", "auto"], ["text-wrap", "wrap"], ["text-wrap-mode", "wrap"], ["text-wrap-style", "auto"], ["timeline-scope", "none"], ["timeline-trigger-activation-range-end", "normal"], ["timeline-trigger-activation-range-start", "normal"], ["timeline-trigger-active-range-end", "auto"], ["timeline-trigger-active-range-start", "auto"], ["timeline-trigger-name", "none"], ["timeline-trigger-source", "auto"], ["top", "auto"], ["touch-action", "auto"], ["transform", "none"], ["transform-style", "flat"], ["transition-behavior", "normal"], ["transition-property", "all"], ["transition-timing-function", "ease"], ["translate", "none"], ["trigger-scope", "none"], ["unicode-bidi", "normal"], ["user-select", "auto"], ["vector-effect", "none"], ["view-timeline-axis", "block"], ["view-timeline-inset", "auto"], ["view-timeline-name", "none"], ["view-transition-class", "none"], ["view-transition-name", "none"], ["view-transition-scope", "none"], ["white-space", "normal"], ["width", "auto"], ["will-change", "auto"], ["word-break", "normal"], ["word-spacing", "normal"], ["word-wrap", "normal"], ["z-index", "auto"] ]); // Each named color a shorter spelling beats -> that spelling, so a name written // where a color is unambiguous prints as the shortest text for the same value. const COLOR_NAME_TO_SHORTEST = new Map([ ["aliceblue", "#f0f8ff"], ["antiquewhite", "#faebd7"], ["aquamarine", "#7fffd4"], ["black", "#000"], ["blanchedalmond", "#ffebcd"], ["blueviolet", "#8a2be2"], ["burlywood", "#deb887"], ["cadetblue", "#5f9ea0"], ["chartreuse", "#7fff00"], ["chocolate", "#d2691e"], ["cornflowerblue", "#6495ed"], ["cornsilk", "#fff8dc"], ["darkblue", "#00008b"], ["darkcyan", "#008b8b"], ["darkgoldenrod", "#b8860b"], ["darkgray", "#a9a9a9"], ["darkgreen", "#006400"], ["darkgrey", "#a9a9a9"], ["darkkhaki", "#bdb76b"], ["darkmagenta", "#8b008b"], ["darkolivegreen", "#556b2f"], ["darkorange", "#ff8c00"], ["darkorchid", "#9932cc"], ["darksalmon", "#e9967a"], ["darkseagreen", "#8fbc8f"], ["darkslateblue", "#483d8b"], ["darkslategray", "#2f4f4f"], ["darkslategrey", "#2f4f4f"], ["darkturquoise", "#00ced1"], ["darkviolet", "#9400d3"], ["deeppink", "#ff1493"], ["deepskyblue", "#00bfff"], ["dodgerblue", "#1e90ff"], ["firebrick", "#b22222"], ["floralwhite", "#fffaf0"], ["forestgreen", "#228b22"], ["fuchsia", "#f0f"], ["gainsboro", "#dcdcdc"], ["ghostwhite", "#f8f8ff"], ["goldenrod", "#daa520"], ["greenyellow", "#adff2f"], ["honeydew", "#f0fff0"], ["indianred", "#cd5c5c"], ["lavender", "#e6e6fa"], ["lavenderblush", "#fff0f5"], ["lawngreen", "#7cfc00"], ["lemonchiffon", "#fffacd"], ["lightblue", "#add8e6"], ["lightcoral", "#f08080"], ["lightcyan", "#e0ffff"], ["lightgoldenrodyellow", "#fafad2"], ["lightgray", "#d3d3d3"], ["lightgreen", "#90ee90"], ["lightgrey", "#d3d3d3"], ["lightpink", "#ffb6c1"], ["lightsalmon", "#ffa07a"], ["lightseagreen", "#20b2aa"], ["lightskyblue", "#87cefa"], ["lightslategray", "#789"], ["lightslategrey", "#789"], ["lightsteelblue", "#b0c4de"], ["lightyellow", "#ffffe0"], ["limegreen", "#32cd32"], ["magenta", "#f0f"], ["mediumaquamarine", "#66cdaa"], ["mediumblue", "#0000cd"], ["mediumorchid", "#ba55d3"], ["mediumpurple", "#9370db"], ["mediumseagreen", "#3cb371"], ["mediumslateblue", "#7b68ee"], ["mediumspringgreen", "#00fa9a"], ["mediumturquoise", "#48d1cc"], ["mediumvioletred", "#c71585"], ["midnightblue", "#191970"], ["mintcream", "#f5fffa"], ["mistyrose", "#ffe4e1"], ["moccasin", "#ffe4b5"], ["navajowhite", "#ffdead"], ["olivedrab", "#6b8e23"], ["orangered", "#ff4500"], ["palegoldenrod", "#eee8aa"], ["palegreen", "#98fb98"], ["paleturquoise", "#afeeee"], ["palevioletred", "#db7093"], ["papayawhip", "#ffefd5"], ["peachpuff", "#ffdab9"], ["powderblue", "#b0e0e6"], ["rebeccapurple", "#639"], ["rosybrown", "#bc8f8f"], ["royalblue", "#4169e1"], ["saddlebrown", "#8b4513"], ["sandybrown", "#f4a460"], ["seagreen", "#2e8b57"], ["seashell", "#fff5ee"], ["slateblue", "#6a5acd"], ["slategray", "#708090"], ["slategrey", "#708090"], ["springgreen", "#00ff7f"], ["steelblue", "#4682b4"], ["turquoise", "#40e0d0"], ["white", "#fff"], ["whitesmoke", "#f5f5f5"], ["yellow", "#ff0"], ["yellowgreen", "#9acd32"] ]); // The functions whose argument is a selector, so a `>` / `+` / `~` inside one // is a combinator and needs no whitespace around it. const SELECTOR_FUNCTIONS = new Set([ "cue", "element", "has", "host", "host-context", "is", "not", "nth-child", "nth-last-child", "selector", "slotted", "where" ]); // The functions every argument of which is an angle, so a zero one needs no // unit wherever it stands. const ZERO_ANGLE_FUNCTIONS = new Set([ "hue-rotate", "rotate", "rotatex", "rotatey", "rotatez", "skew", "skewx", "skewy" ]); // CSS Values 4's math functions: everything inside one is a math expression, so // `*` and `/` there are operators, and the whitespace around them carries nothing. const MATH_FUNCTIONS = new Set([ "abs", "acos", "asin", "atan", "atan2", "calc", "calc-size", "clamp", "cos", "exp", "hypot", "log", "max", "min", "mod", "pow", "rem", "round", "sign", "sin", "sqrt", "tan" ]); // How many `<calc-sum>` arguments each of them takes, off its own grammar. A // function whose arguments are not all expressions (`round()` leads with a // strategy, `calc-size()` with a basis) is absent, and absence is what the // folding reads as "leave this one alone". /** @type {Map<string, [number, number]>} */ const MATH_FUNCTION_ARITY = new Map([ ["abs", [1, 1]], ["acos", [1, 1]], ["asin", [1, 1]], ["atan", [1, 1]], ["atan2", [2, 2]], ["calc", [1, 1]], ["clamp", [3, 3]], ["cos", [1, 1]], ["exp", [1, 1]], ["hypot", [1, Infinity]], ["log", [1, 2]], ["max", [1, Infinity]], ["min", [1, Infinity]], ["mod", [2, 2]], ["pow", [2, 2]], ["rem", [2, 2]], ["round", [2, 2]], ["sign", [1, 1]], ["sin", [1, 1]], ["sqrt", [1, 1]], ["tan", [1, 1]] ]); // The optional keyword a math function may lead with, for the ones whose // grammar offers a choice of them (`round( <rounding-strategy>?, … )`). Read // off that production, so a strategy joining it needs no edit here. /** @type {Map<string, string[]>} */ const MATH_FUNCTION_KEYWORDS = new Map([ ["round", ["down", "nearest", "to-zero", "up"]] ]); // Where a function the fold cannot read as a whole still takes a `<calc-sum>`, // so that argument reduces on its own. Keyed by name to the argument positions. /** @type {Map<string, number[]>} */ const MATH_FUNCTION_SUM_ARGUMENTS = new Map([["calc-size", [1]]]); // A CSS-wide keyword is only valid as the whole value, so a box repeating one is // invalid and already discarded — collapsing it would switch the declaration on. const CSS_WIDE_KEYWORDS = new Set([ "inherit", "initial", "revert", "revert-layer", "unset" ]); // `<easing-function>` argument lists that are exactly a shorter keyword, keyed // by the arguments as `Number` prints them. const CUBIC_BEZIER_KEYWORDS = new Map([ ["0.25,0.1,0.25,1", "ease"], ["0,0,1,1", "linear"], ["0.42,0,1,1", "ease-in"], ["0,0,0.58,1", "ease-out"], ["0.42,0,0.58,1", "ease-in-out"] ]); // The two `flex` values CSS Flexbox 7.1.1 gives a keyword spelling. const FLEX_KEYWORDS = new Map([ ["0 0 auto", "none"], ["1 1 auto", "auto"] ]); // The `font-weight` keywords CSS Fonts 4 §2.2 defines as a number, which is what // `getComputedStyle().fontWeight` reports either way. const FONT_WEIGHT_NUMBERS = new Map([ ["normal", "400"], ["bold", "700"] ]); // Selectors 4 §3.3: the pseudo-elements engines must also accept with one colon, // so their second colon carries nothing. const LEGACY_PSEUDO_ELEMENTS = new Set([ "before", "after", "first-line", "first-letter" ]); // What may follow the `*` a compound selector implies: another simple selector // in the same compound. A separator between them would be a descendant // combinator instead, and `|` makes the `*` a namespace's, not a redundant one. const COMPOUND_CONTINUATIONS = new Set([":", ".", "#", "["]); // The properties whose zero length keeps its unit — the one place it is still // load-bearing. const ZERO_UNIT_KEEPING_PROPERTIES = new Set(["flex", "flex-basis"]); // At-rules whose empty block is inert, so dropping it changes nothing. const DROPPABLE_WHEN_EMPTY_AT_RULES = new Set([ "media", "supports", "container" ]); // At-rules whose block holds rules and whose prelude states a condition, so two // adjacent blocks with the same prelude are the one block they resolve to. const MERGEABLE_AT_RULES = new Set([ "container", "document", "layer", "media", "scope", "starting-style", "supports" ]); // The math functions whose result steps with their arguments, so a value inside // one keeps the unit and the digits it was written with. const STEPPED_FUNCTIONS = new Set(["mod", "rem", "round"]); // The units fixed against each other (CSS Values 4 §6.2, §8), as // `unit -> [group, how many of the group's base unit one is]`. Two units in the // same group convert into each other exactly when the ratio is binary-exact. /** @type {Map<string, [string, number]>} */ const ABSOLUTE_UNIT_SCALE = new Map([ ["px", ["length", 381]], ["pc", ["length", 6096]], ["pt", ["length", 508]], ["in", ["length", 36576]], ["cm", ["length", 14400]], ["mm", ["length", 1440]], ["q", ["length", 360]], ["ms", ["time", 1]], ["s", ["time", 1000]] ]); // Each convertible group's reference unit, as `group -> [unit, scale]`. A sum // counted in the group's base unit divides by the scale to get back to a unit // that can be written down. /** @type {Map<string, [string, number]>} */ const UNIT_GROUP_BASE = new Map([ ["length", ["px", 381]], ["time", ["ms", 1]] ]); // The units a conversion may emit. Every one is CSS 2.1's, so rewriting into it // cannot outrun what an engine reading the stylesheet already parses. const UNIT_CONVERSION_TARGETS = new Set([ "px", "pc", "pt", "in", "cm", "mm", "ms", "s" ]); // The angle units. Excluded from rounding: `rotate()` runs its argument through // trig, which turns a truncated digit into a different computed matrix. const ANGLE_UNITS = new Set(["deg", "grad", "rad", "turn"]); // A quarter turn in each unit that spells it exactly (CSS Values 4 §8.1), as // `unit -> the count`. The trig functions are folded only where their argument // is a whole number of these, which is where sine and cosine are rational. /** @type {Map<string, number>} */ const QUARTER_TURN_ANGLE = new Map([ ["deg", 90], ["grad", 100], ["turn", 0.25] ]); // Sine, cosine and tangent as `eighth turn from zero -> value`. The eighths // where the value is irrational are absent — sine and cosine on the odd ones, // tangent on the asymptotes. Cosine is sine a quarter turn along. /** @type {Map<number, number>} */ const EIGHTH_TURN_SINE = new Map([ [0, 0], [2, 1], [4, 0], [6, -1] ]); /** @type {Map<number, number>} */ const EIGHTH_TURN_COSINE = new Map([ [0, 1], [2, 0], [4, -1], [6, 0] ]); /** @type {Map<number, number>} */ const EIGHTH_TURN_TANGENT = new Map([ [0, 0], [1, 1], [3, -1], [4, 0], [5, 1], [7, -1] ]); // What each inverse trig function answers, as `argument -> degrees`, by // inverting the table above it over that function's principal branch. Every // other argument is transcendental and leaves the call written out. /** @type {Map<number, number>} */ const ARC_SINE_DEGREES = new Map([ [-1, -90], [0, 0], [1, 90] ]); /** @type {Map<number, number>} */ const ARC_COSINE_DEGREES = new Map([ [-1, 180], [0, 90], [1, 0] ]); /** @type {Map<number, number>} */ const ARC_TANGENT_DEGREES = new Map([ [-1, -45], [0, 0], [1, 45] ]); // The reader that needs a table, built once here — `mathPrimitives` knows the // arithmetic of an eighth turn but not which units spell one. const readEighthTurn = eighthTurnReader(QUARTER_TURN_ANGLE); // What folding each math function comes down to, as // `name -> { read, apply, result, table }`: how its arguments are read, which // arithmetic runs, and the unit the answer carries. `read` and `apply` are the // functions themselves, so `lib/css/syntax.js` drives the fold while naming // neither a math function nor an arithmetic of its own. /** @type {Map<string, { read: MathArgumentReader, apply: MathOperation, result: string, table: Map<number, number> | null }>} */ const MATH_FUNCTION_FOLD = new Map([ ["abs", { read: readSameUnit, apply: absolute, result: "same", table: null }], [ "acos", { read: readNumber, apply: lookup, result: "deg", table: ARC_COSINE_DEGREES } ], [ "asin", { read: readNumber, apply: lookup, result: "deg", table: ARC_SINE_DEGREES } ], [ "atan", { read: readNumber, apply: lookup, result: "deg", table: ARC_TANGENT_DEGREES } ], [ "atan2", { read: readSameUnit, apply: arcTangent2, result: "deg", table: null } ], ["clamp", { read: readSameUnit, apply: clamp, result: "same", table: null }], [ "cos", { read: readEighthTurn, apply: lookup, result: "", table: EIGHTH_TURN_COSINE } ], ["exp", { read: readNumber, apply: exponential, result: "", table: null }], [ "hypot", { read: readSameUnit, apply: hypotenuse, result: "same", table: null } ], ["log", { read: readNumber, apply: logarithm, result: "", table: null }], ["max", { read: readSameUnit, apply: maximum, result: "same", table: null }], ["min", { read: readSameUnit, apply: minimum, result: "same", table: null }], ["mod", { read: readSameUnit, apply: modulus, result: "same", table: null }], ["pow", { read: readNumber, apply: power, result: "", table: null }], [ "rem", { read: readSameUnit, apply: remainder, result: "same", table: null } ], ["round", { read: readSameUnit, apply: round, result: "same", table: null }], ["sign", { read: readSameUnit, apply: sign, result: "", table: null }], [ "sin", { read: readEighthTurn, apply: lookup, result: "", table: EIGHTH_TURN_SINE } ], ["sqrt", { read: readNumber, apply: squareRoot, result: "", table: null }], [ "tan", { read: readEighthTurn, apply: lookup, result: "", table: EIGHTH_TURN_TANGENT } ] ]); // Properties whose grammar can reach an `<integer>`. Deliberately wide: a // non-integer where an integer is expected is rounded rather than dropped // (`z-index: calc(1.5)` computes to `2`), so this is read to refuse a rewrite, // and one name too many costs only that rewrite. const INTEGER_PROPERTIES = new Set([ "-ms-grid-columns", "-ms-grid-rows", "-ms-hyphenate-limit-chars", "-ms-hyphenate-limit-lines", "-webkit-line-clamp", "animation", "animation-timing-function", "box-flex-group", "box-ordinal-group", "column-count", "columns", "counter-increment", "counter-reset", "counter-set", "font-feature-settings", "grid", "grid-area", "grid-column", "grid-column-end", "grid-column-start", "grid-row", "grid-row-end", "grid-row-start", "grid-template", "grid-template-columns", "grid-template-rows", "hyphenate-limit-chars", "initial-letter", "line-clamp", "math-depth", "max-lines", "order", "orphans", "reading-order", "tab-size", "text-combine-upright", "transition", "transition-timing-function", "widows", "z-index" ]); // The properties whose value is one `<number> | <percentage>`, where the // percentage is the number hundredfold and the two compute to the same thing. const ALPHA_VALUE_PROPERTIES = new Set(["opacity", "shape-image-threshold"]); // The properties taking a `<ratio>`, whose second number of `1` is the one an // omitted denominator means. const RATIO_PROPERTIES = new Set(["aspect-ratio"]); // The keywords of every property a `css/module` reads a scoped name out of, // each mapped to how many times it may be spelled before the next one is the // name (`Infinity` — never the name). Derived from each property's grammar. const CSS_MODULES_KEYWORDS = new Map([ [ "animation", new Map([ ["alternate", 1], ["alternate-reverse", 1], ["auto", Infinity], ["backwards", 1], ["both", 1], ["ease", 1], ["ease-in", 1], ["ease-in-out", 1], ["ease-out", 1], ["forwards", 1], ["infinite", 1], ["inherit", Infinity], ["initial", Infinity], ["linear", 1], ["none", Infinity], ["normal", 1], ["paused", 1], ["reverse", 1], ["revert", Infinity], ["revert-layer", Infinity], ["running", 1], ["step-end", 1], ["step-start", 1], ["unset", Infinity] ]) ], [ "animation-name", new Map([ ["inherit", Infinity], ["initial", Infinity], ["none", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "container", new Map([ ["inherit", Infinity], ["initial", Infinity], ["inline-size", 1], ["none", Infinity], ["normal", 1], ["revert", Infinity], ["revert-layer", Infinity], ["scroll-state", 1], ["size", 1], ["unset", Infinity] ]) ], [ "container-name", new Map([ ["inherit", Infinity], ["initial", Infinity], ["none", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "list-style", new Map([ ["arabic-indic", 1], ["armenian", 1], ["bengali", 1], ["cambodian", 1], ["circle", 1], ["cjk-decimal", 1], ["cjk-earthly-branch", 1], ["cjk-heavenly-stem", 1], ["cjk-ideographic", 1], ["decimal", 1], ["decimal-leading-zero", 1], ["devanagari", 1], ["disc", 1], ["disclosure-closed", 1], ["disclosure-open", 1], ["ethiopic-numeric", 1], ["georgian", 1], ["gujarati", 1], ["gurmukhi", 1], ["hebrew", 1], ["hiragana", 1], ["hiragana-iroha", 1], ["inherit", Infinity], ["initial", Infinity], ["inside", 1], ["japanese-formal", 1], ["japanese-informal", 1], ["kannada", 1], ["katakana", 1], ["katakana-iroha", 1], ["khmer", 1], ["korean-hangul-formal", 1], ["korean-hanja-formal", 1], ["korean-hanja-informal", 1], ["lao", 1], ["lower-alpha", 1], ["lower-armenian", 1], ["lower-greek", 1], ["lower-latin", 1], ["lower-roman", 1], ["malayalam", 1], ["mongolian", 1], ["myanmar", 1], ["none", Infinity], ["oriya", 1], ["outside", 1], ["persian", 1], ["revert", Infinity], ["revert-layer", Infinity], ["simp-chinese-formal", 1], ["simp-chinese-informal", 1], ["square", 1], ["tamil", 1], ["telugu", 1], ["thai", 1], ["tibetan", 1], ["trad-chinese-formal", 1], ["trad-chinese-informal", 1], ["unset", Infinity], ["upper-alpha", 1], ["upper-armenian", 1], ["upper-latin", 1], ["upper-roman", 1] ]) ], [ "list-style-type", new Map([ ["arabic-indic", 1], ["armenian", 1], ["bengali", 1], ["cambodian", 1], ["circle", 1], ["cjk-decimal", 1], ["cjk-earthly-branch", 1], ["cjk-heavenly-stem", 1], ["cjk-ideographic", 1], ["decimal", 1], ["decimal-leading-zero", 1], ["devanagari", 1], ["disc", 1], ["disclosure-closed", 1], ["disclosure-open", 1], ["ethiopic-numeric", 1], ["georgian", 1], ["gujarati", 1], ["gurmukhi", 1], ["hebrew", 1], ["hiragana", 1], ["hiragana-iroha", 1], ["inherit", Infinity], ["initial", Infinity], ["japanese-formal", 1], ["japanese-informal", 1], ["kannada", 1], ["katakana", 1], ["katakana-iroha", 1], ["khmer", 1], ["korean-hangul-formal", 1], ["korean-hanja-formal", 1], ["korean-hanja-informal", 1], ["lao", 1], ["lower-alpha", 1], ["lower-armenian", 1], ["lower-greek", 1], ["lower-latin", 1], ["lower-roman", 1], ["malayalam", 1], ["mongolian", 1], ["myanmar", 1], ["none", Infinity], ["oriya", 1], ["persian", 1], ["revert", Infinity], ["revert-layer", Infinity], ["simp-chinese-formal", 1], ["simp-chinese-informal", 1], ["square", 1], ["tamil", 1], ["telugu", 1], ["thai", 1], ["tibetan", 1], ["trad-chinese-formal", 1], ["trad-chinese-informal", 1], ["unset", Infinity], ["upper-alpha", 1], ["upper-armenian", 1], ["upper-latin", 1], ["upper-roman", 1] ]) ], [ "system", new Map([ ["additive", 1], ["alphabetic", 1], ["arabic-indic", 1], ["armenian", 1], ["bengali", 1], ["cambodian", 1], ["circle", 1], ["cjk-decimal", 1], ["cjk-earthly-branch", 1], ["cjk-heavenly-stem", 1], ["cjk-ideographic", 1], ["cyclic", 1], ["decimal", 1], ["decimal-leading-zero", 1], ["devanagari", 1], ["disc", 1], ["disclosure-closed", 1], ["disclosure-open", 1], ["ethiopic-numeric", 1], ["extends", 1], ["fixed", 1], ["georgian", 1], ["gujarati", 1], ["gurmukhi", 1], ["hebrew", 1], ["hiragana", 1], ["hiragana-iroha", 1], ["japanese-formal", 1], ["japanese-informal", 1], ["kannada", 1], ["katakana", 1], ["katakana-iroha", 1], ["khmer", 1], ["korean-hangul-formal", 1], ["korean-hanja-formal", 1], ["korean-hanja-informal", 1], ["lao", 1], ["lower-alpha", 1], ["lower-armenian", 1], ["lower-greek", 1], ["lower-latin", 1], ["lower-roman", 1], ["malayalam", 1], ["mongolian", 1], ["myanmar", 1], ["numeric", 1], ["oriya", 1], ["persian", 1], ["simp-chinese-formal", 1], ["simp-chinese-informal", 1], ["square", 1], ["symbolic", 1], ["tamil", 1], ["telugu", 1], ["thai", 1], ["tibetan", 1], ["trad-chinese-formal", 1], ["trad-chinese-informal", 1], ["upper-alpha", 1], ["upper-armenian", 1], ["upper-latin", 1], ["upper-roman", 1] ]) ], [ "fallback", new Map([ ["arabic-indic", 1], ["armenian", 1], ["bengali", 1], ["cambodian", 1], ["circle", 1], ["cjk-decimal", 1], ["cjk-earthly-branch", 1], ["cjk-heavenly-stem", 1], ["cjk-ideographic", 1], ["decimal", 1], ["decimal-leading-zero", 1], ["devanagari", 1], ["disc", 1], ["disclosure-closed", 1], ["disclosure-open", 1], ["ethiopic-numeric", 1], ["georgian", 1], ["gujarati", 1], ["gurmukhi", 1], ["hebrew", 1], ["hiragana", 1], ["hiragana-iroha", 1], ["japanese-formal", 1], ["japanese-informal", 1], ["kannada", 1], ["katakana", 1], ["katakana-iroha", 1], ["khmer", 1], ["korean-hangul-formal", 1], ["korean-hanja-formal", 1], ["korean-hanja-informal", 1], ["lao", 1], ["lower-alpha", 1], ["lower-armenian", 1], ["lower-greek", 1], ["lower-latin", 1], ["lower-roman", 1], ["malayalam", 1], ["mongolian", 1], ["myanmar", 1], ["oriya", 1], ["persian", 1], ["simp-chinese-formal", 1], ["simp-chinese-informal", 1], ["square", 1], ["tamil", 1], ["telugu", 1], ["thai", 1], ["tibetan", 1], ["trad-chinese-formal", 1], ["trad-chinese-informal", 1], ["upper-alpha", 1], ["upper-armenian", 1], ["upper-latin", 1], ["upper-roman", 1] ]) ], [ "speak-as", new Map([ ["arabic-indic", 1], ["armenian", 1], ["auto", Infinity], ["bengali", 1], ["bullets", Infinity], ["cambodian", 1], ["circle", 1], ["cjk-decimal", 1], ["cjk-earthly-branch", 1], ["cjk-heavenly-stem", 1], ["cjk-ideographic", 1], ["decimal", 1], ["decimal-leading-zero", 1], ["devanagari", 1], ["disc", 1], ["disclosure-closed", 1], ["disclosure-open", 1], ["ethiopic-numeric", 1], ["georgian", 1], ["gujarati", 1], ["gurmukhi", 1], ["hebrew", 1], ["hiragana", 1], ["hiragana-iroha", 1], ["japanese-formal", 1], ["japanese-informal", 1], ["kannada", 1], ["katakana", 1], ["katakana-iroha", 1], ["khmer", 1], ["korean-hangul-formal", 1], ["korean-hanja-formal", 1], ["korean-hanja-informal", 1], ["lao", 1], ["lower-alpha", 1], ["lower-armenian", 1], ["lower-greek", 1], ["lower-latin", 1], ["lower-roman", 1], ["malayalam", 1], ["mongolian", 1], ["myanmar", 1], ["numbers", Infinity], ["oriya", 1], ["persian", 1], ["simp-chinese-formal", 1], ["simp-chinese-informal", 1], ["spell-out", Infinity], ["square", 1], ["tamil", 1], ["telugu", 1], ["thai", 1], ["tibetan", 1], ["trad-chinese-formal", 1], ["trad-chinese-informal", 1], ["upper-alpha", 1], ["upper-armenian", 1], ["upper-latin", 1], ["upper-roman", 1], ["words", Infinity] ]) ], [ "counter-reset", new Map([ ["inherit", Infinity], ["initial", Infinity], ["list-item", Infinity], ["none", 1], ["page", Infinity], ["pages", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "counter-increment", new Map([ ["inherit", Infinity], ["initial", Infinity], ["list-item", Infinity], ["none", 1], ["page", Infinity], ["pages", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "counter-set", new Map([ ["inherit", Infinity], ["initial", Infinity], ["list-item", Infinity], ["none", 1], ["page", Infinity], ["pages", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "view-transition-name", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["match-element", Infinity], ["none", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "view-transition-group", new Map([ ["contain", Infinity], ["inherit", Infinity], ["initial", Infinity], ["nearest", Infinity], ["normal", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "view-transition-class", new Map([ ["inherit", Infinity], ["initial", Infinity], ["none", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "grid", new Map([ ["auto", Infinity], ["auto-flow", 1], ["column", 1], ["dense", 1], ["inherit", Infinity], ["initial", Infinity], ["masonry", 1], ["max-content", Infinity], ["min-content", Infinity], ["none", 2], ["revert", Infinity], ["revert-layer", Infinity], ["row", 1], ["subgrid", 2], ["unset", Infinity] ]) ], [ "grid-area", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["span", Infinity], ["unset", Infinity] ]) ], [ "grid-column", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["span", Infinity], ["unset", Infinity] ]) ], [ "grid-column-end", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["span", Infinity], ["unset", Infinity] ]) ], [ "grid-column-start", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["span", Infinity], ["unset", Infinity] ]) ], [ "grid-row", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["span", Infinity], ["unset", Infinity] ]) ], [ "grid-row-end", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["span", Infinity], ["unset", Infinity] ]) ], [ "grid-row-start", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["revert", Infinity], ["revert-layer", Infinity], ["span", Infinity], ["unset", Infinity] ]) ], [ "grid-template", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["masonry", 1], ["max-content", Infinity], ["min-content", Infinity], ["none", 2], ["revert", Infinity], ["revert-layer", Infinity], ["subgrid", 2], ["unset", Infinity] ]) ], [ "grid-template-areas", new Map([ ["inherit", Infinity], ["initial", Infinity], ["none", 1], ["revert", Infinity], ["revert-layer", Infinity], ["unset", Infinity] ]) ], [ "grid-template-columns", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["masonry", 1], ["max-content", Infinity], ["min-content", Infinity], ["none", 1], ["revert", Infinity], ["revert-layer", Infinity], ["subgrid", 1], ["unset", Infinity] ]) ], [ "grid-template-rows", new Map([ ["auto", Infinity], ["inherit", Infinity], ["initial", Infinity], ["masonry", 1], ["max-content", Infinity], ["min-content", Infinity], ["none", 1], ["revert", Infinity], ["revert-layer", Infinity], ["subgrid", 1], ["unset", Infinity] ]) ] ]); // The parser option gating each of them. const CSS_MODULES_KEYWORD_OPTIONS = new Map([ ["animation", "animation"], ["animation-name", "animation"], ["container", "container"], ["container-name", "container"], ["list-style", "customIdents"], ["list-style-type", "customIdents"], ["system", "customIdents"], ["fallback", "customIdents"], ["speak-as", "customIdents"], ["counter-reset", "customIdents"], ["counter-increment", "customIdents"], ["counter-set", "customIdents"], ["view-transition-name", "customIdents"], ["view-transition-group", "customIdents"], ["view-transition-class", "customIdents"], ["grid", "grid"], ["grid-area", "grid"], ["grid-column", "grid"], ["grid-column-end", "grid"], ["grid-column-start", "grid"], ["grid-row", "grid"], ["grid-row-end", "grid"], ["grid-row-start", "grid"], ["grid-template", "grid"], ["grid-template-areas", "grid"], ["grid-template-columns", "grid"], ["grid-template-rows", "grid"] ]); // The properties a negative value is valid on, so `calc(-5px)` may lose its // parentheses there. Read to permit a rewrite, which is the opposite of // `INTEGER_PROPERTIES` above: naming one property too many is a bug, naming one // too few only costs a rewrite. const NEGATIVE_ACCEPTING_PROPERTIES = new Set([ "animation-delay", "background-position", "background-position-x", "background-position-y", "bottom", "inset", "inset-block", "inset-block-end", "inset-block-start", "inset-inline", "inset-inline-end", "inset-inline-start", "left", "letter-spacing", "margin", "margin-block", "margin-block-end", "margin-block-start", "margin-bottom", "margin-inline", "margin-inline-end", "margin-inline-start", "margin-left", "margin-right", "margin-top", "offset-distance", "order", "outline-offset", "perspective-origin", "right", "rotate", "scroll-margin", "scroll-margin-block", "scroll-margin-bottom", "scroll-margin-inline", "scroll-margin-left", "scroll-margin-right", "scroll-margin-top", "stroke-dashoffset", "text-indent", "text-underline-offset", "top", "transform-origin", "transition-delay", "translate", "vertical-align", "word-spacing", "z-index" ]); // The functions whose every numeric argument is a length, so a zero inside one // drops its unit the way a whole component's does. Read to permit a rewrite: // any other numeric type would make the bare `0` mean something else, or make // a dropped declaration valid. const LENGTH_ONLY_FUNCTIONS = new Set([ "anchor", "anchor-size", "blur", "circle", "ellipse", "fit-content", "inset", "perspective", "polygon", "rect", "translate", "translate3d", "translatex", "translatey", "translatez", "view", "xywh" ]); // Packed `0xrrggbb` -> the shortest named color with that value. Only names that // can beat `#rrggbb`; anything longer would never be picked. const RGB_TO_NAME = new Map([ [0x000080, "navy"], [0x008000, "green"], [0x008080, "teal"], [0x4b0082, "indigo"], [0x800000, "maroon"], [0x800080, "purple"], [0x808000, "olive"], [0x808080, "gray"], [0xa0522d, "sienna"], [0xa52a2a, "brown"], [0xc0c0c0, "silver"], [0xcd853f, "peru"], [0xd2b48c, "tan"], [0xda70d6, "orchid"], [0xdda0dd, "plum"], [0xee82ee, "violet"], [0xf0e68c, "khaki"], [0xf0ffff, "azure"], [0xf5deb3, "wheat"], [0xf5f5dc, "beige"], [0xfa8072, "salmon"], [0xfaf0e6, "linen"], [0xff0000, "red"], [0xff6347, "tomato"], [0xff7f50, "coral"], [0xffa500, "orange"], [0xffc0cb, "pink"], [0xffd700, "gold"], [0xffe4c4, "bisque"], [0xfffafa, "snow"], [0xfffff0, "ivory"] ]); module.exports.ABSOLUTE_UNIT_SCALE = ABSOLUTE_UNIT_SCALE; module.exports.ALPHA_VALUE_PROPERTIES = ALPHA_VALUE_PROPERTIES; module.exports.ANGLE_UNITS = ANGLE_UNITS; module.exports.ARC_COSINE_DEGREES = ARC_COSINE_DEGREES; module.exports.ARC_SINE_DEGREES = ARC_SINE_DEGREES; module.exports.ARC_TANGENT_DEGREES = ARC_TANGENT_DEGREES; module.exports.BOX_FAMILY_PREFIX = BOX_FAMILY_PREFIX; module.exports.BOX_LONGHANDS = BOX_LONGHANDS; module.exports.BOX_SHORTHANDS = BOX_SHORTHANDS; module.exports.COLOR_ARGUMENT_FUNCTIONS = COLOR_ARGUMENT_FUNCTIONS; module.exports.COLOR_KEYWORDS = COLOR_KEYWORDS; module.exports.COLOR_NAME_TO_SHORTEST = COLOR_NAME_TO_SHORTEST; module.exports.COLOR_ONLY_PROPERTIES = COLOR_ONLY_PROPERTIES; module.exports.COMPOUND_CONTINUATIONS = COMPOUND_CONTINUATIONS; module.exports.CSS_MODULES_KEYWORDS = CSS_MODULES_KEYWORDS; module.exports.CSS_MODULES_KEYWORD_OPTIONS = CSS_MODULES_KEYWORD_OPTIONS; module.exports.CSS_WIDE_KEYWORDS = CSS_WIDE_KEYWORDS; module.exports.CUBIC_BEZIER_KEYWORDS = CUBIC_BEZIER_KEYWORDS; module.exports.DISPLAY_SHORT_FORMS = DISPLAY_SHORT_FORMS; module.exports.DROPPABLE_WHEN_EMPTY_AT_RULES = DROPPABLE_WHEN_EMPTY_AT_RULES; module.exports.EIGHTH_TURN_COSINE = EIGHTH_TURN_COSINE; module.exports.EIGHTH_TURN_SINE = EIGHTH_TURN_SINE; module.exports.EIGHTH_TURN_TANGENT = EIGHTH_TURN_TANGENT; module.exports.FAMILY_LONGHANDS = FAMILY_LONGHANDS; module.exports.FAMILY_SLOT_CLASSES = FAMILY_SLOT_CLASSES; module.exports.FAMILY_SLOT_KEYWORDS = FAMILY_SLOT_KEYWORDS; module.exports.FILTER_FUNCTION_OMITTED = FILTER_FUNCTION_OMITTED; module.exports.FLEX_KEYWORDS = FLEX_KEYWORDS; module.exports.FONT_STRETCH_PERCENTAGES = FONT_STRETCH_PERCENTAGES; module.exports.FONT_WEIGHT_NUMBERS = FONT_WEIGHT_NUMBERS; module.exports.GENERIC_FONT_FAMILIES = GENERIC_FONT_FAMILIES; module.exports.GRADIENT_LAST_POSITIONS = GRADIENT_LAST_POSITIONS; module.exports.INITIAL_VALUE_KEYWORDS = INITIAL_VALUE_KEYWORDS; module.exports.INTEGER_PROPERTIES = INTEGER_PROPERTIES; module.exports.LEGACY_PSEUDO_ELEMENTS = LEGACY_PSEUDO_ELEMENTS; module.exports.LENGTH_ONLY_FUNCTIONS = LENGTH_ONLY_FUNCTIONS; module.exports.MATH_FUNCTIONS = MATH_FUNCTIONS; module.exports.MATH_FUNCTION_ARITY = MATH_FUNCTION_ARITY; module.exports.MATH_FUNCTION_FOLD = MATH_FUNCTION_FOLD; module.exports.MATH_FUNCTION_KEYWORDS = MATH_FUNCTION_KEYWORDS; module.exports.MATH_FUNCTION_SUM_ARGUMENTS = MATH_FUNCTION_SUM_ARGUMENTS; module.exports.MERGEABLE_AT_RULES = MERGEABLE_AT_RULES; module.exports.NEGATIVE_ACCEPTING_PROPERTIES = NEGATIVE_ACCEPTING_PROPERTIES; module.exports.NTH_PSEUDO_FUNCTIONS = NTH_PSEUDO_FUNCTIONS; module.exports.ONE_VALUE_PAIR_SHORTHANDS = ONE_VALUE_PAIR_SHORTHANDS; module.exports.PAIR_LONGHANDS = PAIR_LONGHANDS; module.exports.POSITION_PROPERTIES = POSITION_PROPERTIES; module.exports.POSITION_X_KEYWORDS = POSITION_X_KEYWORDS; module.exports.POSITION_Y_KEYWORDS = POSITION_Y_KEYWORDS; module.exports.QUARTER_TURN_ANGLE = QUARTER_TURN_ANGLE; module.exports.RATIO_PROPERTIES = RATIO_PROPERTIES; module.exports.REPEAT_STYLE_KEYWORDS = REPEAT_STYLE_KEYWORDS; module.exports.REPEAT_STYLE_PROPERTIES = REPEAT_STYLE_PROPERTIES; module.exports.RGB_TO_NAME = RGB_TO_NAME; module.exports.SELECTOR_FUNCTIONS = SELECTOR_FUNCTIONS; module.exports.SHADOW_PROPERTIES = SHADOW_PROPERTIES; module.exports.SHORTHAND_INITIAL_KEYWORDS = SHORTHAND_INITIAL_KEYWORDS; module.exports.SLASH_BOX_SHORTHANDS = SLASH_BOX_SHORTHANDS; module.exports.STEPPED_FUNCTIONS = STEPPED_FUNCTIONS; module.exports.SUBSTITUTION_FUNCTIONS = SUBSTITUTION_FUNCTIONS; module.exports.UNIT_CONVERSION_TARGETS = UNIT_CONVERSION_TARGETS; module.exports.UNIT_GROUP_BASE = UNIT_GROUP_BASE; module.exports.ZERO_ANGLE_FUNCTIONS = ZERO_ANGLE_FUNCTIONS; module.exports.ZERO_UNIT_KEEPING_PROPERTIES = ZERO_UNIT_KEEPING_PROPERTIES; // The exact arithmetic the printer's own evaluator needs. Sorted after the // tables: `import/order` orders exports by case, uppercase first. module.exports.exactAdd = exactAdd; module.exports.exactDivide = exactDivide; module.exports.exactMultiply = exactMultiply;