diff --git a/cjs/html/style-element.js b/cjs/html/style-element.js
index 78cf8a0f..e4bc2b11 100644
--- a/cjs/html/style-element.js
+++ b/cjs/html/style-element.js
@@ -1,5 +1,5 @@
'use strict';
-const {parse} = require('@acemir/cssom');
+const {parse} = require('cssomnom/parse');
const {registerHTMLClass} = require('../shared/register-html-class.js');
const {SHEET} = require('../shared/symbols.js');
diff --git a/esm/html/style-element.js b/esm/html/style-element.js
index 9f23dde0..59b36160 100644
--- a/esm/html/style-element.js
+++ b/esm/html/style-element.js
@@ -1,4 +1,4 @@
-import {parse} from '@acemir/cssom';
+import {parse} from 'cssomnom/parse';
import {registerHTMLClass} from '../shared/register-html-class.js';
import {SHEET} from '../shared/symbols.js';
diff --git a/package-lock.json b/package-lock.json
index 0c7a320b..43d2b641 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,8 +9,8 @@
"version": "0.18.14",
"license": "ISC",
"dependencies": {
- "@acemir/cssom": "^0.9.32",
"css-select": "^7.0.0",
+ "cssomnom": "^0.1.11",
"html-escaper": "^3.0.3",
"htmlparser2": "^10.1.0",
"uhyphen": "^0.2.0"
@@ -37,12 +37,6 @@
}
}
},
- "node_modules/@acemir/cssom": {
- "version": "0.9.32",
- "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.32.tgz",
- "integrity": "sha512-OijrAUu7rrJhSIoHNg6LMPS5e344nwUHA+1EFYYjrh64D+GmytUsfBQjci45TjT+rd5Spsp8B5xsZDT+TgyXXQ==",
- "license": "MIT"
- },
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
@@ -1104,6 +1098,15 @@
"url": "https://github.com/sponsors/fb55"
}
},
+ "node_modules/cssomnom": {
+ "version": "0.1.11",
+ "resolved": "https://registry.npmjs.org/cssomnom/-/cssomnom-0.1.11.tgz",
+ "integrity": "sha512-P4RkO1Sq2Ual77xypEmAc4MkM5k2Ha4UwtBPCOpJmXculGCYPgzsU/xnOCy084esZaPePgGkkJg4Il/HE7GS5A==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
diff --git a/package.json b/package.json
index e370264d..7f20e5e8 100644
--- a/package.json
+++ b/package.json
@@ -70,8 +70,8 @@
}
},
"dependencies": {
- "@acemir/cssom": "^0.9.32",
"css-select": "^7.0.0",
+ "cssomnom": "^0.1.11",
"html-escaper": "^3.0.3",
"htmlparser2": "^10.1.0",
"uhyphen": "^0.2.0"
diff --git a/worker.js b/worker.js
index 31bb78a1..2c72ca4c 100644
--- a/worker.js
+++ b/worker.js
@@ -757,7 +757,7 @@ const Sequences = {
]), // ` {
const end = self[END];
@@ -2276,7 +2276,7 @@ const parseFromString = (document, isHTML, markupLanguage) => {
let ownerSVGElement = null;
let parsingCData = false;
- const content = new Parser({
+ const content = new Parser$1({
//
onprocessinginstruction(name, data) {
if (name.toLowerCase() === '!doctype')
@@ -8631,7432 +8631,9426 @@ class HTMLBodyElement extends HTMLElement {
}
}
-var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
-
-var lib = {};
-
-var CSSOM_1;
-var hasRequiredCSSOM;
-
-function requireCSSOM () {
- if (hasRequiredCSSOM) return CSSOM_1;
- hasRequiredCSSOM = 1;
- var CSSOM = {
- /**
- * Creates and configures a new CSSOM instance with the specified options.
- *
- * @param {Object} opts - Configuration options for the CSSOM instance
- * @param {Object} [opts.globalObject] - Optional global object to be assigned to CSSOM objects prototype
- * @returns {Object} A new CSSOM instance with the applied configuration
- * @description
- * This method creates a new instance of CSSOM and optionally
- * configures CSSStyleSheet with a global object reference. When a globalObject is provided
- * and CSSStyleSheet exists on the instance, it creates a new CSSStyleSheet constructor
- * using a factory function and assigns the globalObject to its prototype's __globalObject property.
- */
- setup: function (opts) {
- var instance = Object.create(this);
- if (opts.globalObject) {
- if (instance.CSSStyleSheet) {
- var factoryCSSStyleSheet = createFunctionFactory(instance.CSSStyleSheet);
- var CSSStyleSheet = factoryCSSStyleSheet();
- CSSStyleSheet.prototype.__globalObject = opts.globalObject;
-
- instance.CSSStyleSheet = CSSStyleSheet;
- }
- }
- return instance;
- }
- };
-
- function createFunctionFactory(fn) {
- return function() {
- // Create a new function that delegates to the original
- var newFn = function() {
- return fn.apply(this, arguments);
- };
-
- // Copy prototype chain
- Object.setPrototypeOf(newFn, Object.getPrototypeOf(fn));
-
- // Copy own properties
- for (var key in fn) {
- if (Object.prototype.hasOwnProperty.call(fn, key)) {
- newFn[key] = fn[key];
- }
- }
-
- // Clone the .prototype object for constructor-like behavior
- if (fn.prototype) {
- newFn.prototype = Object.create(fn.prototype);
- }
-
- return newFn;
- };
+// @ts-nocheck
+// src/data/gen/property-list.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+const SUPPORTED_PROPERTIES = /* @__PURE__ */ new Set("-webkit-align-content,-webkit-align-items,-webkit-align-self,-webkit-animation,-webkit-animation-delay,-webkit-animation-direction,-webkit-animation-duration,-webkit-animation-fill-mode,-webkit-animation-iteration-count,-webkit-animation-name,-webkit-animation-play-state,-webkit-animation-timing-function,-webkit-appearance,-webkit-backface-visibility,-webkit-background-clip,-webkit-background-origin,-webkit-background-size,-webkit-border-bottom-left-radius,-webkit-border-bottom-right-radius,-webkit-border-radius,-webkit-border-top-left-radius,-webkit-border-top-right-radius,-webkit-box-align,-webkit-box-flex,-webkit-box-ordinal-group,-webkit-box-orient,-webkit-box-pack,-webkit-box-shadow,-webkit-box-sizing,-webkit-filter,-webkit-flex,-webkit-flex-basis,-webkit-flex-direction,-webkit-flex-flow,-webkit-flex-grow,-webkit-flex-shrink,-webkit-flex-wrap,-webkit-justify-content,-webkit-line-clamp,-webkit-mask,-webkit-mask-box-image,-webkit-mask-box-image-outset,-webkit-mask-box-image-repeat,-webkit-mask-box-image-slice,-webkit-mask-box-image-source,-webkit-mask-box-image-width,-webkit-mask-clip,-webkit-mask-composite,-webkit-mask-image,-webkit-mask-origin,-webkit-mask-position,-webkit-mask-repeat,-webkit-mask-size,-webkit-order,-webkit-perspective,-webkit-perspective-origin,-webkit-text-fill-color,-webkit-text-size-adjust,-webkit-text-stroke,-webkit-text-stroke-color,-webkit-text-stroke-width,-webkit-transform,-webkit-transform-origin,-webkit-transform-style,-webkit-transition,-webkit-transition-delay,-webkit-transition-duration,-webkit-transition-property,-webkit-transition-timing-function,-webkit-user-select,accent-color,align-content,align-items,align-self,alignment-baseline,all,anchor-name,anchor-scope,animation,animation-composition,animation-delay,animation-delay-end,animation-delay-start,animation-direction,animation-duration,animation-fill-mode,animation-iteration-count,animation-name,animation-play-state,animation-range,animation-range-center,animation-range-end,animation-range-start,animation-timeline,animation-timing-function,animation-trigger,appearance,aspect-ratio,backdrop-filter,backface-visibility,background,background-attachment,background-blend-mode,background-clip,background-color,background-image,background-origin,background-position,background-position-block,background-position-inline,background-position-x,background-position-y,background-repeat,background-repeat-block,background-repeat-inline,background-repeat-x,background-repeat-y,background-size,background-tbd,baseline-shift,baseline-source,block-ellipsis,block-size,block-step,block-step-align,block-step-insert,block-step-round,block-step-size,bookmark-label,bookmark-level,bookmark-state,border,border-block,border-block-clip,border-block-color,border-block-end,border-block-end-clip,border-block-end-color,border-block-end-radius,border-block-end-style,border-block-end-width,border-block-start,border-block-start-clip,border-block-start-color,border-block-start-radius,border-block-start-style,border-block-start-width,border-block-style,border-block-width,border-bottom,border-bottom-clip,border-bottom-color,border-bottom-left-radius,border-bottom-radius,border-bottom-right-radius,border-bottom-style,border-bottom-width,border-boundary,border-clip,border-collapse,border-color,border-end-end-radius,border-end-start-radius,border-image,border-image-outset,border-image-repeat,border-image-slice,border-image-source,border-image-width,border-inline,border-inline-clip,border-inline-color,border-inline-end,border-inline-end-clip,border-inline-end-color,border-inline-end-radius,border-inline-end-style,border-inline-end-width,border-inline-start,border-inline-start-clip,border-inline-start-color,border-inline-start-radius,border-inline-start-style,border-inline-start-width,border-inline-style,border-inline-width,border-left,border-left-clip,border-left-color,border-left-radius,border-left-style,border-left-width,border-limit,border-radius,border-right,border-right-clip,border-right-color,border-right-radius,border-right-style,border-right-width,border-shape,border-spacing,border-start-end-radius,border-start-start-radius,border-style,border-top,border-top-clip,border-top-color,border-top-left-radius,border-top-radius,border-top-right-radius,border-top-style,border-top-width,border-width,bottom,box-decoration-break,box-shadow,box-shadow-blur,box-shadow-color,box-shadow-offset,box-shadow-position,box-shadow-spread,box-sizing,box-snap,break-after,break-before,break-inside,caption-side,caret,caret-animation,caret-color,caret-shape,clear,clip,clip-path,clip-rule,color,color-adjust,color-interpolation,color-interpolation-filters,color-scheme,column-count,column-fill,column-gap,column-height,column-rule,column-rule-break,column-rule-color,column-rule-inset,column-rule-inset-cap,column-rule-inset-cap-end,column-rule-inset-cap-start,column-rule-inset-end,column-rule-inset-junction,column-rule-inset-junction-end,column-rule-inset-junction-start,column-rule-inset-start,column-rule-style,column-rule-visibility-items,column-rule-width,column-span,column-width,column-wrap,columns,contain,contain-intrinsic-block-size,contain-intrinsic-height,contain-intrinsic-inline-size,contain-intrinsic-size,contain-intrinsic-width,container,container-name,container-type,content,content-visibility,continue,copy-into,corner,corner-block-end,corner-block-end-shape,corner-block-start,corner-block-start-shape,corner-bottom,corner-bottom-left,corner-bottom-left-shape,corner-bottom-right,corner-bottom-right-shape,corner-bottom-shape,corner-end-end,corner-end-end-shape,corner-end-start,corner-end-start-shape,corner-inline-end,corner-inline-end-shape,corner-inline-start,corner-inline-start-shape,corner-left,corner-left-shape,corner-right,corner-right-shape,corner-shape,corner-start-end,corner-start-end-shape,corner-start-start,corner-start-start-shape,corner-top,corner-top-left,corner-top-left-shape,corner-top-right,corner-top-right-shape,corner-top-shape,counter-increment,counter-reset,counter-set,cue,cue-after,cue-before,cursor,cx,cy,d,direction,display,dominant-baseline,dynamic-range-limit,empty-cells,event-trigger,event-trigger-name,event-trigger-source,field-sizing,fill,fill-break,fill-color,fill-image,fill-opacity,fill-origin,fill-position,fill-repeat,fill-rule,fill-size,filter,fit-tolerance,flex,flex-basis,flex-direction,flex-flow,flex-grow,flex-line-count,flex-shrink,flex-wrap,float,float-defer,float-offset,float-reference,flood-color,flood-opacity,flow-from,flow-into,font,font-family,font-feature-settings,font-kerning,font-language-override,font-optical-sizing,font-palette,font-presentation,font-size,font-size-adjust,font-stretch,font-style,font-synthesis,font-synthesis-position,font-synthesis-small-caps,font-synthesis-style,font-synthesis-weight,font-variant,font-variant-alternates,font-variant-caps,font-variant-east-asian,font-variant-emoji,font-variant-ligatures,font-variant-numeric,font-variant-position,font-variation-settings,font-weight,font-width,footnote-display,footnote-policy,forced-color-adjust,frame-sizing,gap,glyph-orientation-vertical,grid,grid-area,grid-auto-columns,grid-auto-flow,grid-auto-rows,grid-column,grid-column-end,grid-column-gap,grid-column-start,grid-gap,grid-row,grid-row-end,grid-row-gap,grid-row-start,grid-template,grid-template-areas,grid-template-columns,grid-template-rows,hanging-punctuation,height,hyphenate-character,hyphenate-limit-chars,hyphenate-limit-last,hyphenate-limit-lines,hyphenate-limit-zone,hyphens,image-animation,image-orientation,image-rendering,image-resolution,initial-letter,initial-letter-align,initial-letter-wrap,inline-size,inline-sizing,input-security,inset,inset-block,inset-block-end,inset-block-start,inset-inline,inset-inline-end,inset-inline-start,interactivity,interest-delay,interest-delay-end,interest-delay-start,interpolate-size,isolation,justify-content,justify-items,justify-self,left,letter-spacing,lighting-color,line-break,line-clamp,line-fit-edge,line-grid,line-height,line-height-step,line-padding,line-snap,link-parameters,list-style,list-style-image,list-style-position,list-style-type,margin,margin-block,margin-block-end,margin-block-start,margin-bottom,margin-break,margin-inline,margin-inline-end,margin-inline-start,margin-left,margin-right,margin-top,margin-trim,marker,marker-end,marker-mid,marker-side,marker-start,mask,mask-border,mask-border-mode,mask-border-outset,mask-border-repeat,mask-border-slice,mask-border-source,mask-border-width,mask-clip,mask-composite,mask-image,mask-mode,mask-origin,mask-position,mask-repeat,mask-size,mask-type,math-depth,math-shift,math-style,max-block-size,max-height,max-inline-size,max-lines,max-size,max-width,min-block-size,min-height,min-inline-size,min-intrinsic-sizing,min-size,min-width,mix-blend-mode,nav-down,nav-left,nav-right,nav-up,object-fit,object-position,object-view-box,offset,offset-anchor,offset-distance,offset-path,offset-position,offset-rotate,opacity,order,orphans,outline,outline-color,outline-offset,outline-style,outline-width,overflow,overflow-anchor,overflow-block,overflow-clip-margin,overflow-clip-margin-block,overflow-clip-margin-block-end,overflow-clip-margin-block-start,overflow-clip-margin-bottom,overflow-clip-margin-inline,overflow-clip-margin-inline-end,overflow-clip-margin-inline-start,overflow-clip-margin-left,overflow-clip-margin-right,overflow-clip-margin-top,overflow-inline,overflow-wrap,overflow-x,overflow-y,overlay,overscroll-behavior,overscroll-behavior-block,overscroll-behavior-inline,overscroll-behavior-x,overscroll-behavior-y,padding,padding-block,padding-block-end,padding-block-start,padding-bottom,padding-inline,padding-inline-end,padding-inline-start,padding-left,padding-right,padding-top,page,page-break-after,page-break-before,page-break-inside,paint-order,path-length,pause,pause-after,pause-before,perspective,perspective-origin,place-content,place-items,place-self,pointer-events,pointer-timeline,pointer-timeline-axis,pointer-timeline-name,position,position-anchor,position-area,position-try,position-try-fallbacks,position-try-order,position-visibility,print-color-adjust,quotes,r,reading-flow,reading-order,region-fragment,resize,rest,rest-after,rest-before,right,rotate,row-gap,row-rule,row-rule-break,row-rule-color,row-rule-inset,row-rule-inset-cap,row-rule-inset-cap-end,row-rule-inset-cap-start,row-rule-inset-end,row-rule-inset-junction,row-rule-inset-junction-end,row-rule-inset-junction-start,row-rule-inset-start,row-rule-style,row-rule-visibility-items,row-rule-width,ruby-align,ruby-merge,ruby-overhang,ruby-position,rule,rule-break,rule-color,rule-inset,rule-inset-cap,rule-inset-end,rule-inset-junction,rule-inset-start,rule-overlap,rule-style,rule-visibility-items,rule-width,rx,ry,scale,scroll-axis-lock,scroll-behavior,scroll-initial-target,scroll-margin,scroll-margin-block,scroll-margin-block-end,scroll-margin-block-start,scroll-margin-bottom,scroll-margin-inline,scroll-margin-inline-end,scroll-margin-inline-start,scroll-margin-left,scroll-margin-right,scroll-margin-top,scroll-marker-group,scroll-padding,scroll-padding-block,scroll-padding-block-end,scroll-padding-block-start,scroll-padding-bottom,scroll-padding-inline,scroll-padding-inline-end,scroll-padding-inline-start,scroll-padding-left,scroll-padding-right,scroll-padding-top,scroll-snap-align,scroll-snap-stop,scroll-snap-type,scroll-target-group,scroll-timeline,scroll-timeline-axis,scroll-timeline-name,scrollbar-color,scrollbar-gutter,scrollbar-width,shape-image-threshold,shape-inside,shape-margin,shape-outside,shape-padding,shape-rendering,size,slider-orientation,spatial-navigation-action,spatial-navigation-contain,spatial-navigation-function,speak,speak-as,stop-color,stop-opacity,string-set,stroke,stroke-align,stroke-alignment,stroke-break,stroke-color,stroke-dash-corner,stroke-dash-justify,stroke-dashadjust,stroke-dasharray,stroke-dashcorner,stroke-dashoffset,stroke-image,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-origin,stroke-position,stroke-repeat,stroke-size,stroke-width,tab-size,table-layout,text-align,text-align-all,text-align-last,text-anchor,text-autospace,text-box,text-box-edge,text-box-trim,text-combine-upright,text-decoration,text-decoration-color,text-decoration-inset,text-decoration-line,text-decoration-skip,text-decoration-skip-box,text-decoration-skip-ink,text-decoration-skip-self,text-decoration-skip-spaces,text-decoration-style,text-decoration-thickness,text-emphasis,text-emphasis-color,text-emphasis-position,text-emphasis-skip,text-emphasis-style,text-fit,text-group-align,text-indent,text-justify,text-orientation,text-overflow,text-rendering,text-shadow,text-size-adjust,text-spacing,text-spacing-trim,text-transform,text-underline-offset,text-underline-position,text-wrap,text-wrap-mode,text-wrap-style,timeline-scope,timeline-trigger,timeline-trigger-activation-range,timeline-trigger-activation-range-end,timeline-trigger-activation-range-start,timeline-trigger-active-range,timeline-trigger-active-range-end,timeline-trigger-active-range-start,timeline-trigger-name,timeline-trigger-range,timeline-trigger-source,top,touch-action,transform,transform-box,transform-origin,transform-style,transition,transition-behavior,transition-delay,transition-duration,transition-property,transition-timing-function,translate,trigger-scope,unicode-bidi,user-select,vector-effect,vertical-align,view-timeline,view-timeline-axis,view-timeline-inset,view-timeline-name,view-transition-class,view-transition-group,view-transition-name,view-transition-scope,visibility,voice-balance,voice-duration,voice-family,voice-pitch,voice-range,voice-rate,voice-stress,voice-volume,white-space,white-space-collapse,white-space-trim,widows,width,will-change,window-drag,word-break,word-space-transform,word-spacing,word-wrap,wrap-after,wrap-before,wrap-flow,wrap-inside,wrap-through,writing-mode,x,y,z-index,zoom".split(","));
+const CUSTOM_IDENT_PROPERTIES = /* @__PURE__ */ new Set("-webkit-animation,-webkit-animation-name,-webkit-transition,-webkit-transition-property,animation,animation-name,color-scheme,container,container-name,copy-into,counter-increment,counter-reset,counter-set,flow-from,flow-into,font,font-family,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,list-style,list-style-type,page,string-set,transition,transition-property,view-transition-class,view-transition-group,view-transition-name,will-change".split(","));
+const FONT_FACE_DESCRIPTORS = /* @__PURE__ */ new Set("ascent-override,descent-override,font-display,font-family,font-feature-settings,font-language-override,font-named-instance,font-size,font-stretch,font-style,font-variant,font-variation-settings,font-weight,font-width,line-gap-override,size-adjust,src,subscript-position-override,subscript-size-override,superscript-position-override,superscript-size-override,unicode-range".split(","));
+const PAGE_ALLOWED_PROPERTIES = /* @__PURE__ */ new Set("bleed,break-after,break-before,break-inside,counter-increment,counter-reset,counter-set,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,marks,orphans,page,page-break-after,page-break-before,page-break-inside,page-margin-safety,page-orientation,quotes,size,widows".split(","));
+const PAGE_DESCRIPTOR_PROPERTIES = [
+ "margin",
+ "margin-top",
+ "margin-right",
+ "margin-bottom",
+ "margin-left",
+ "size",
+ "page-orientation",
+ "marks",
+ "bleed"
+];
+const POSITION_TRY_ALLOWED_PROPERTIES = /* @__PURE__ */ new Set("align-self,block-size,bottom,height,inline-size,inset,inset-area,inset-block,inset-block-end,inset-block-start,inset-inline,inset-inline-end,inset-inline-start,justify-self,left,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,max-block-size,max-height,max-inline-size,max-width,min-block-size,min-height,min-inline-size,min-width,place-self,position-anchor,position-area,right,top,width".split(","));
+const COUNTER_STYLE_PROP_BY_DESCRIPTOR = /* @__PURE__ */ new Map([
+ ["additive-symbols", "additiveSymbols"],
+ ["fallback", "fallback"],
+ ["negative", "negative"],
+ ["pad", "pad"],
+ ["prefix", "prefix"],
+ ["range", "range"],
+ ["speak-as", "speakAs"],
+ ["suffix", "suffix"],
+ ["symbols", "symbols"],
+ ["system", "system"]
+]);
+const FONT_FEATURE_VALUE_MAP_DEFS = [
+ ["annotation", "annotation"],
+ ["ornaments", "ornaments"],
+ ["stylistic", "stylistic"],
+ ["swash", "swash"],
+ ["character-variant", "characterVariant"],
+ ["styleset", "styleset"],
+ ["historical-forms", "historicalForms"]
+];
+const FONT_FEATURE_VALUE_BLOCKS = {
+ "annotation": "annotation",
+ "ornaments": "ornaments",
+ "stylistic": "stylistic",
+ "swash": "swash",
+ "character-variant": "characterVariant",
+ "charactervariant": "characterVariant",
+ "styleset": "styleset",
+ "historical-forms": "historicalForms",
+ "historicalforms": "historicalForms"
+};
+const MARGIN_RULE_NAMES = /* @__PURE__ */ new Set("bottom-center,bottom-left,bottom-left-corner,bottom-right,bottom-right-corner,left-bottom,left-middle,left-top,right-bottom,right-middle,right-top,top-center,top-left,top-left-corner,top-right,top-right-corner".split(","));
+const GENERIC_FONT_FAMILIES = /* @__PURE__ */ new Set("cursive,emoji,fangsong,fantasy,math,monospace,sans-serif,serif,system-ui,ui-monospace,ui-rounded,ui-sans-serif,ui-serif".split(","));
+const FONT_VARIANT_LIGATURES_KEYWORDS = /* @__PURE__ */ new Set("common-ligatures,no-common-ligatures,discretionary-ligatures,no-discretionary-ligatures,historical-ligatures,no-historical-ligatures,contextual,no-contextual".split(","));
+const FONT_VARIANT_CAPS_KEYWORDS = /* @__PURE__ */ new Set("small-caps,all-small-caps,petite-caps,all-petite-caps,unicase,titling-caps".split(","));
+const FONT_VARIANT_NUMERIC_KEYWORDS = /* @__PURE__ */ new Set("lining-nums,oldstyle-nums,proportional-nums,tabular-nums,diagonal-fractions,stacked-fractions,ordinal,slashed-zero".split(","));
+const FONT_VARIANT_EAST_ASIAN_KEYWORDS = /* @__PURE__ */ new Set("jis78,jis83,jis90,jis04,simplified,traditional,full-width,proportional-width,ruby".split(","));
+const FONT_VARIANT_POSITION_KEYWORDS = /* @__PURE__ */ new Set("sub,super".split(","));
+const FONT_VARIANT_EMOJI_KEYWORDS = /* @__PURE__ */ new Set("text,emoji,unicode".split(","));
+const FONT_VARIANT_ALTERNATES_FUNCTIONS = /* @__PURE__ */ new Set("stylistic,styleset,character-variant,swash,ornaments,annotation".split(","));
+const SYSTEM_FONT_KEYWORDS = /* @__PURE__ */ new Set("initial,inherit,unset,revert,revert-layer,default,caption,icon,menu,message-box,small-caption,status-bar".split(","));
+const FONT_STRETCH_KEYWORDS = /* @__PURE__ */ new Set("ultra-condensed,extra-condensed,condensed,semi-condensed,semi-expanded,expanded,extra-expanded,ultra-expanded".split(","));
+const FONT_SIZE_KEYWORDS = /* @__PURE__ */ new Set("xx-small,x-small,small,medium,large,x-large,xx-large,xxx-large,smaller,larger".split(","));
+const FLEX_BASIS_KEYWORDS = /* @__PURE__ */ new Set("auto,content,max-content,min-content,fit-content".split(","));
+// src/webidl.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+function hideInternalFields(instance) {
+ for (const key of Object.getOwnPropertyNames(instance)) if (key.startsWith("_")) Object.defineProperty(instance, key, { enumerable: false });
+}
+const appliedCtors = /* @__PURE__ */ new WeakSet();
+/**
+* Aligns regular prototype properties of a WebIDL interface object with specification requirements:
+* 1. Interface prototype members are { enumerable: true, configurable: true }.
+* 2. Attribute getters/setters perform brand checks, throwing TypeError when invoked on the prototype
+* itself or on an incompatible receiver (WebIDL § 3.6.1, § 3.6.2).
+* 3. Operations are { writable: true, enumerable: true, configurable: true } and throw TypeError
+* when invoked with fewer arguments than required (WebIDL § 3.7).
+*/
+function applyWebIDLInterface(ctor, options = {}) {
+ const proto = ctor.prototype;
+ if (!proto) return;
+ if (appliedCtors.has(ctor)) return;
+ appliedCtors.add(ctor);
+ const brandCheck = options.brandCheck ?? true;
+ const arityCheck = options.arityCheck ?? true;
+ const interfaceName = options.interfaceName || ctor.name;
+ const excludeSet = new Set(options.exclude || []);
+ const rejectSet = new Set(options.rejectOperations || []);
+ Object.defineProperty(ctor, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true
+ });
+ Object.defineProperty(proto, Symbol.toStringTag, {
+ value: interfaceName,
+ writable: false,
+ enumerable: false,
+ configurable: true
+ });
+ const names = Object.getOwnPropertyNames(proto);
+ for (const name of names) {
+ if (name === "constructor" || name.startsWith("_") || excludeSet.has(name)) continue;
+ const desc = Object.getOwnPropertyDescriptor(proto, name);
+ if (!desc) continue;
+ if (desc.get || desc.set) {
+ const origGet = desc.get;
+ const origSet = desc.set;
+ let get = origGet;
+ if (origGet && brandCheck) {
+ get = function() {
+ if (!this || this === proto || !(this instanceof ctor)) throw new TypeError(`Failed to read the '${name}' property from '${interfaceName}': The provided value is not of type '${interfaceName}'.`);
+ return origGet.call(this);
+ };
+ Object.defineProperty(get, "name", {
+ value: `get ${name}`,
+ configurable: true
+ });
+ }
+ let set = origSet;
+ if (origSet && brandCheck) {
+ set = function(val) {
+ if (!this || this === proto || !(this instanceof ctor)) throw new TypeError(`Failed to set the '${name}' property on '${interfaceName}': The provided value is not of type '${interfaceName}'.`);
+ return origSet.call(this, val);
+ };
+ Object.defineProperty(set, "name", {
+ value: `set ${name}`,
+ configurable: true
+ });
+ }
+ Object.defineProperty(proto, name, {
+ get,
+ set: origSet ? set : void 0,
+ enumerable: true,
+ configurable: true
+ });
+ continue;
+ }
+ if (typeof desc.value === "function") {
+ const origFn = desc.value;
+ const minArgs = origFn.length;
+ let fn = origFn;
+ if (brandCheck || arityCheck && minArgs > 0) {
+ fn = function(...args) {
+ if (brandCheck && (!this || this === proto || !(this instanceof ctor))) {
+ const err = /* @__PURE__ */ new TypeError(`Failed to execute '${name}' on '${interfaceName}': The provided value is not of type '${interfaceName}'.`);
+ if (rejectSet.has(name)) return Promise.reject(err);
+ throw err;
+ }
+ if (arityCheck && arguments.length < minArgs) {
+ const err = /* @__PURE__ */ new TypeError(`Failed to execute '${name}' on '${interfaceName}': ${minArgs} argument${minArgs === 1 ? "" : "s"} required, but only ${arguments.length} present.`);
+ if (rejectSet.has(name)) return Promise.reject(err);
+ throw err;
+ }
+ return origFn.apply(this, args);
+ };
+ Object.defineProperty(fn, "name", {
+ value: origFn.name,
+ configurable: true
+ });
+ Object.defineProperty(fn, "length", {
+ value: minArgs,
+ configurable: true
+ });
+ }
+ Object.defineProperty(proto, name, {
+ value: fn,
+ writable: true,
+ enumerable: true,
+ configurable: true
+ });
+ }
}
-
- //.CommonJS
- CSSOM_1 = CSSOM;
- ///CommonJS
- return CSSOM_1;
}
-
-var errorUtils = {};
-
-var hasRequiredErrorUtils;
-
-function requireErrorUtils () {
- if (hasRequiredErrorUtils) return errorUtils;
- hasRequiredErrorUtils = 1;
- // Utility functions for CSSOM error handling
-
- /**
- * Gets the appropriate error constructor from the global object context.
- * Tries to find the error constructor from parentStyleSheet.__globalObject,
- * then from __globalObject, then falls back to the native constructor.
- *
- * @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
- * @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
- * @return {Function} The error constructor
- */
- function getErrorConstructor(context, errorType) {
- // Try parentStyleSheet.__globalObject first
- if (context.parentStyleSheet && context.parentStyleSheet.__globalObject && context.parentStyleSheet.__globalObject[errorType]) {
- return context.parentStyleSheet.__globalObject[errorType];
+/**
+* Defines constants on an interface object and its prototype per WebIDL:
+* - WebIDL #es-constants: { [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }
+* - WebIDL #constants-on-interface-prototype-object: same attributes on prototype
+*/
+function applyWebIDLConstants(ctor, constants) {
+ for (const [name, val] of Object.entries(constants)) {
+ Object.defineProperty(ctor, name, {
+ value: val,
+ writable: false,
+ enumerable: true,
+ configurable: false
+ });
+ if (ctor.prototype) Object.defineProperty(ctor.prototype, name, {
+ value: val,
+ writable: false,
+ enumerable: true,
+ configurable: false
+ });
+ }
+}
+// src/utils.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+function camelToDashed(str) {
+ return str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()).replace(/^ms-/, "-ms-");
+}
+function createIndexedProxy(target, getArray, mapValue) {
+ hideInternalFields(target);
+ return new Proxy(target, {
+ get(t, prop, receiver) {
+ if (typeof prop === "string") {
+ const index = Number(prop);
+ if (Number.isInteger(index) && index >= 0) {
+ const val = getArray(t)[index];
+ return val !== void 0 ? mapValue ? mapValue(val) : val : void 0;
+ }
+ }
+ return Reflect.get(t, prop, receiver);
+ },
+ set(t, prop, value) {
+ return Reflect.set(t, prop, value, t);
}
-
- // Try __parentStyleSheet (alternative naming)
- if (context.__parentStyleSheet && context.__parentStyleSheet.__globalObject && context.__parentStyleSheet.__globalObject[errorType]) {
- return context.__parentStyleSheet.__globalObject[errorType];
+ });
+}
+function deleteRuleFromArray(rules, index) {
+ if (index < 0 || index >= rules.length) throw new DOMException("Index size error", "IndexSizeError");
+ const oldRule = rules[index];
+ rules.splice(index, 1);
+ if (oldRule && typeof oldRule === "object") {
+ if ("_parentRule" in oldRule) oldRule._parentRule = null;
+ if ("_parentStyleSheet" in oldRule) oldRule._parentStyleSheet = null;
+ }
+ return oldRule;
+}
+// src/parse-hooks.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+* Upward optional feature hooks allowing `cssomnom/parse` (`./parse`) to tree-shake
+* out Typed OM, `@property` registry, `MediaParser`, and `CSS.supports`.
+*
+* Downward parser functions are imported directly from `src/parser.ts`.
+*/
+const ParseHooks = {
+ parseMediaQueryList: (text) => {
+ return text.split(",").map((s) => s.trim()).filter(Boolean).map((m) => ({
+ type: "media-query",
+ mediaType: m,
+ tokens: [],
+ raw: m
+ }));
+ },
+ serializeMediaQuery: (query) => {
+ return query.raw ?? query.mediaType ?? "";
+ },
+ validatePropertyValue: (_property, _value, _rawValue) => {
+ return true;
+ },
+ supports: (_conditionText) => {
+ return false;
+ },
+ createStylePropertyMap: (_style) => {
+ throw new Error("createStylePropertyMap not injected (import cssomnom/typed-om)");
+ },
+ validatePropertyRuleDescriptor: (_def) => {
+ return true;
+ },
+ registerPropertyRule: (_def) => {
+ return false;
+ },
+ unregisterPropertyRule: (_name) => {}
+};
+// src/rules/collections.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+var StyleSheetList = class {
+ /** @internal */
+ _sheets;
+ constructor(sheets) {
+ this._sheets = sheets;
+ return createIndexedProxy(this, (t) => t._sheets);
+ }
+ get length() {
+ return this._sheets.length;
+ }
+ item(index) {
+ return this._sheets[index] || null;
+ }
+ *[Symbol.iterator]() {
+ for (let i = 0; i < this.length; i++) yield this._sheets[i];
+ }
+};
+var MediaList = class {
+ /** @internal */
+ _mediaQueries = [];
+ constructor(mediaText = "") {
+ this.mediaText = mediaText;
+ return createIndexedProxy(this, (t) => t._mediaQueries.map((q) => ParseHooks.serializeMediaQuery(q)));
+ }
+ get mediaText() {
+ return this._mediaQueries.map((q) => ParseHooks.serializeMediaQuery(q)).join(", ");
+ }
+ set mediaText(value) {
+ if (!value) {
+ this._mediaQueries = [];
+ return;
}
-
- // Try __globalObject on the context itself
- if (context.__globalObject && context.__globalObject[errorType]) {
- return context.__globalObject[errorType];
+ this._mediaQueries = ParseHooks.parseMediaQueryList(value);
+ }
+ get length() {
+ return this._mediaQueries.length;
+ }
+ item(index) {
+ const q = this._mediaQueries[index];
+ return q ? ParseHooks.serializeMediaQuery(q) : null;
+ }
+ toString() {
+ return this.mediaText;
+ }
+ appendMedium(medium) {
+ const parsed = ParseHooks.parseMediaQueryList(medium);
+ if (parsed.length !== 1) return;
+ const m = parsed[0];
+ const mText = ParseHooks.serializeMediaQuery(m);
+ if (this._mediaQueries.some((q) => ParseHooks.serializeMediaQuery(q) === mText)) return;
+ this._mediaQueries.push(m);
+ }
+ deleteMedium(medium) {
+ const parsed = ParseHooks.parseMediaQueryList(medium);
+ if (parsed.length !== 1) return;
+ const mText = ParseHooks.serializeMediaQuery(parsed[0]);
+ let i = this._mediaQueries.length;
+ let found = false;
+ while (i--) if (ParseHooks.serializeMediaQuery(this._mediaQueries[i]) === mText) {
+ this._mediaQueries.splice(i, 1);
+ found = true;
}
-
- // Fall back to native constructor
- return (typeof commonjsGlobal !== 'undefined' && commonjsGlobal[errorType]) ||
- (typeof window !== 'undefined' && window[errorType]) ||
- eval(errorType);
+ if (!found) throw new DOMException(`The medium '${medium}' does not exist in the MediaList.`, "NotFoundError");
}
-
- /**
- * Creates an appropriate error with context-aware constructor.
- *
- * @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
- * @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
- * @param {string} message - The error message
- * @param {string} [name] - Optional name for DOMException
- */
- function createError(context, errorType, message, name) {
- var ErrorConstructor = getErrorConstructor(context, errorType);
- return new ErrorConstructor(message, name);
+ *[Symbol.iterator]() {
+ for (let i = 0; i < this.length; i++) yield ParseHooks.serializeMediaQuery(this._mediaQueries[i]);
}
-
- /**
- * Creates and throws an appropriate error with context-aware constructor.
- *
- * @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
- * @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
- * @param {string} message - The error message
- * @param {string} [name] - Optional name for DOMException
- */
- function throwError(context, errorType, message, name) {
- throw createError(context, errorType, message, name);
+};
+var CSSRuleList = class {
+ /** @internal */
+ _getRules;
+ constructor(rulesOrGetter) {
+ this._getRules = typeof rulesOrGetter === "function" ? rulesOrGetter : () => rulesOrGetter;
+ return createIndexedProxy(this, (t) => t._getRules(), (v) => v);
}
-
- /**
- * Throws a TypeError for missing required arguments.
- *
- * @param {Object} context - The CSSOM object
- * @param {string} methodName - The method name (e.g., 'appendRule')
- * @param {string} objectName - The object name (e.g., 'CSSKeyframesRule')
- * @param {number} [required=1] - Number of required arguments
- * @param {number} [provided=0] - Number of provided arguments
- */
- function throwMissingArguments(context, methodName, objectName, required, provided) {
- required = required || 1;
- provided = provided || 0;
- var message = "Failed to execute '" + methodName + "' on '" + objectName + "': " +
- required + " argument" + (required > 1 ? "s" : "") + " required, but only " +
- provided + " present.";
- throwError(context, 'TypeError', message);
+ get length() {
+ return this._getRules().length;
}
-
- /**
- * Throws a DOMException for parse errors.
- *
- * @param {Object} context - The CSSOM object
- * @param {string} methodName - The method name
- * @param {string} objectName - The object name
- * @param {string} rule - The rule that failed to parse
- * @param {string} [name='SyntaxError'] - The DOMException name
- */
- function throwParseError(context, methodName, objectName, rule, name) {
- var message = "Failed to execute '" + methodName + "' on '" + objectName + "': " +
- "Failed to parse the rule '" + rule + "'.";
- throwError(context, 'DOMException', message, name || 'SyntaxError');
+ item(index) {
+ return this._getRules()[index] || null;
}
-
- /**
- * Throws a DOMException for index errors.
- *
- * @param {Object} context - The CSSOM object
- * @param {string} methodName - The method name
- * @param {string} objectName - The object name
- * @param {number} index - The invalid index
- * @param {number} maxIndex - The maximum valid index
- * @param {string} [name='IndexSizeError'] - The DOMException name
- */
- function throwIndexError(context, methodName, objectName, index, maxIndex, name) {
- var message = "Failed to execute '" + methodName + "' on '" + objectName + "': " +
- "The index provided (" + index + ") is larger than the maximum index (" + maxIndex + ").";
- throwError(context, 'DOMException', message, name || 'IndexSizeError');
- }
-
- var errorUtils$1 = {
- createError: createError,
- getErrorConstructor: getErrorConstructor,
- throwError: throwError,
- throwMissingArguments: throwMissingArguments,
- throwParseError: throwParseError,
- throwIndexError: throwIndexError
- };
-
- //.CommonJS
- errorUtils.errorUtils = errorUtils$1;
- ///CommonJS
- return errorUtils;
+ *[Symbol.iterator]() {
+ const rules = this._getRules();
+ for (let i = 0; i < rules.length; i++) yield rules[i];
+ }
+};
+// src/rules/utils.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+function isImportRule(r) {
+ return r.type === 3;
}
-
-var regexPatterns = {};
-
-var hasRequiredRegexPatterns;
-
-function requireRegexPatterns () {
- if (hasRequiredRegexPatterns) return regexPatterns;
- hasRequiredRegexPatterns = 1;
- // Shared regex patterns for CSS parsing and validation
- // These patterns are compiled once and reused across multiple files for better performance
-
- // Regex patterns for CSS parsing
- var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g; // Match @keyframes and vendor-prefixed @keyframes
- var beforeRulePortionRegExp = /{(?!.*{)|}(?!.*})|;(?!.*;)|\*\/(?!.*\*\/)/g; // Match the closest allowed character (a opening or closing brace, a semicolon or a comment ending) before the rule
- var beforeRuleValidationRegExp = /^[\s{};]*(\*\/\s*)?$/; // Match that the portion before the rule is empty or contains only whitespace, semicolons, opening/closing braces, and optionally a comment ending (*/) followed by whitespace
- var forwardRuleValidationRegExp = /(?:\s|\/\*|\{|\()/; // Match that the rule is followed by any whitespace, a opening comment, a condition opening parenthesis or a opening brace
- var forwardImportRuleValidationRegExp = /(?:\s|\/\*|'|")/; // Match that the rule is followed by any whitespace, an opening comment, a single quote or double quote
- var forwardRuleClosingBraceRegExp = /{[^{}]*}|}/; // Finds the next closing brace of a rule block
- var forwardRuleSemicolonAndOpeningBraceRegExp = /^.*?({|;)/; // Finds the next semicolon or opening brace after the at-rule
-
- // Regex patterns for CSS selector validation and parsing
- var cssCustomIdentifierRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates a css custom identifier
- var startsWithCombinatorRegExp = /^\s*[>+~]/; // Checks if a selector starts with a CSS combinator (>, +, ~)
-
- /**
- * Parse `@page` selectorText for page name and pseudo-pages
- * Valid formats:
- * - (empty - no name, no pseudo-page)
- * - `:left`, `:right`, `:first`, `:blank` (pseudo-page only)
- * - `named` (named page only)
- * - `named:first` (named page with single pseudo-page)
- * - `named:first:left` (named page with multiple pseudo-pages)
- */
- var atPageRuleSelectorRegExp = /^([^\s:]+)?((?::\w+)*)$/; // Validates @page rule selectors
-
- // Regex patterns for CSSImportRule parsing
- var layerRegExp = /layer\(([^)]*)\)/; // Matches layer() function in @import
- var layerRuleNameRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates layer name (same as custom identifier)
- var doubleOrMoreSpacesRegExp = /\s{2,}/g; // Matches two or more consecutive whitespace characters
-
-
- // Regex patterns for CSS escape sequences and identifiers
- var startsWithHexEscapeRegExp = /^\\[0-9a-fA-F]/; // Checks if escape sequence starts with hex escape
- var identStartCharRegExp = /[a-zA-Z_\u00A0-\uFFFF]/; // Valid identifier start character
- var identCharRegExp = /^[a-zA-Z0-9_\-\u00A0-\uFFFF\\]/; // Valid identifier character
- var specialCharsNeedEscapeRegExp = /[!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~\s]/; // Characters that need escaping
- var combinatorOrSeparatorRegExp = /[\s>+~,()]/; // Selector boundaries and combinators
- var afterHexEscapeSeparatorRegExp = /[\s>+~,(){}\[\]]/; // Characters that separate after hex escape
- var trailingSpaceSeparatorRegExp = /[\s>+~,(){}]/; // Characters that allow trailing space
- var endsWithHexEscapeRegExp = /\\[0-9a-fA-F]{1,6}\s+$/; // Matches selector ending with hex escape + space(s)
-
- /**
- * Regular expression to detect invalid characters in the value portion of a CSS style declaration.
- *
- * This regex matches a colon (:) that is not inside parentheses and not inside single or double quotes.
- * It is used to ensure that the value part of a CSS property does not contain unexpected colons,
- * which would indicate a malformed declaration (e.g., "color: foo:bar;" is invalid).
- *
- * The negative lookahead `(?![^(]*\))` ensures that the colon is not followed by a closing
- * parenthesis without encountering an opening parenthesis, effectively ignoring colons inside
- * function-like values (e.g., `url(data:image/png;base64,...)`).
- *
- * The lookahead `(?=(?:[^'"]|'[^']*'|"[^"]*")*$)` ensures that the colon is not inside single or double quotes,
- * allowing colons within quoted strings (e.g., `content: ":";` or `background: url("foo:bar.png");`).
- *
- * Example:
- * - `color: red;` // valid, does not match
- * - `background: url(data:image/png;base64,...);` // valid, does not match
- * - `content: ':';` // valid, does not match
- * - `color: foo:bar;` // invalid, matches
- */
- var basicStylePropertyValueValidationRegExp = /:(?![^(]*\))(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/;
-
- // Attribute selector pattern: matches attribute-name operator value
- // Operators: =, ~=, |=, ^=, $=, *=
- // Rewritten to avoid ReDoS by using greedy match and trimming in JavaScript
- var attributeSelectorContentRegExp = /^([^\s=~|^$*]+)\s*(~=|\|=|\^=|\$=|\*=|=)\s*(.+)$/;
-
- // Selector validation patterns
- var pseudoElementRegExp = /::[a-zA-Z][\w-]*|:(before|after|first-line|first-letter)(?![a-zA-Z0-9_-])/; // Matches pseudo-elements
- var invalidCombinatorLtGtRegExp = /<>/; // Invalid <> combinator
- var invalidCombinatorDoubleGtRegExp = />>/; // Invalid >> combinator
- var consecutiveCombinatorsRegExp = /[>+~]\s*[>+~]/; // Invalid consecutive combinators
- var invalidSlottedRegExp = /(?:^|[\s>+~,\[])slotted\s*\(/i; // Invalid slotted() without ::
- var invalidPartRegExp = /(?:^|[\s>+~,\[])part\s*\(/i; // Invalid part() without ::
- var invalidCueRegExp = /(?:^|[\s>+~,\[])cue\s*\(/i; // Invalid cue() without ::
- var invalidCueRegionRegExp = /(?:^|[\s>+~,\[])cue-region\s*\(/i; // Invalid cue-region() without ::
- var invalidNestingPattern = /&(?![.\#\[:>\+~\s])[a-zA-Z]/; // Invalid & followed by type selector
- var emptyPseudoClassRegExp = /:(?:is|not|where|has)\(\s*\)/; // Empty pseudo-class like :is()
- var whitespaceNormalizationRegExp = /(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g; // Normalize newlines outside quotes
- var newlineRemovalRegExp = /\n/g; // Remove all newlines
- var whitespaceAndDotRegExp = /[\s.]/; // Matches whitespace or dot
- var declarationOrOpenBraceRegExp = /[{;}]/; // Matches declaration separator or open brace
- var ampersandRegExp = /&/; // Matches nesting selector
- var hexEscapeSequenceRegExp = /^([0-9a-fA-F]{1,6})[ \t\r\n\f]?/; // Matches hex escape sequence (1-6 hex digits optionally followed by whitespace)
- var attributeCaseFlagRegExp = /^(.+?)\s+([is])$/i; // Matches case-sensitivity flag at end of attribute value
- var prependedAmpersandRegExp = /^&\s+[:\\.]/; // Matches prepended ampersand pattern (& followed by space and : or .)
- var openBraceGlobalRegExp = /{/g; // Matches opening braces (global)
- var closeBraceGlobalRegExp = /}/g; // Matches closing braces (global)
- var scopePreludeSplitRegExp = /\s*\)\s*to\s+\(/; // Splits scope prelude by ") to ("
- var leadingWhitespaceRegExp = /^\s+/; // Matches leading whitespace (used to implement a ES5-compliant alternative to trimStart())
- var doubleQuoteRegExp = /"/g; // Match all double quotes (for escaping in attribute values)
- var backslashRegExp = /\\/g; // Match all backslashes (for escaping in attribute values)
-
- // Media query validation patterns
- var invalidMediaOperatorWithoutSpaceRegExp = /\)(and|or)\(/i; // )and( or )or( - missing space after operator
- var invalidMediaNotAfterOperatorRegExp = /\b(and|or)\s+not\b/i; // and not or or not - not after operator
- var invalidMediaNotIdentifierRegExp = /\)\s+not\(/i; // ) not( - not() identifier after media feature
- var invalidMediaNotAfterFeatureRegExp = /\)\s+not\s+/i; // ) not - not operator after media feature (only valid at start or after comma)
- var invalidMediaOperatorBetweenParensRegExp = /\)\s+(?!and\b|or\b)[a-z]+\s+\(/i; // ) xx ( - invalid operator between ) and (
- var invalidMediaNotWithMediaTypeRegExp = /\bnot\s+[a-z][a-z0-9_-]*\s+\(/i; // not ( - missing 'and' between media type and feature
-
- // Media query normalization patterns
- var mediaFeatureColonRegExp = /(\(\s*)([^():]+):(\s*)([^()]*\))/g; // Match colon in media features
- var identifierBeforeParenRegExp = /[a-z0-9_-]/i; // Match identifier character before opening paren
- var mediaAndOperatorRegExp = /\s*\band\b\s*/gi; // Match 'and' operator with word boundaries
- var mediaOrOperatorRegExp = /\s*\bor\b\s*/gi; // Match 'or' operator with word boundaries
- var mediaNotOperatorStartRegExp = /^\s*not\s+(?=\S)/i; // Match 'not' operator at start
- var mediaNotOperatorRegExp = /\s+\bnot\s+(?=\S)/gi; // Match 'not' operator after space
-
- var regexPatterns$1 = {
- // Parsing patterns
- atKeyframesRegExp: atKeyframesRegExp,
- beforeRulePortionRegExp: beforeRulePortionRegExp,
- beforeRuleValidationRegExp: beforeRuleValidationRegExp,
- forwardRuleValidationRegExp: forwardRuleValidationRegExp,
- forwardImportRuleValidationRegExp: forwardImportRuleValidationRegExp,
- forwardRuleClosingBraceRegExp: forwardRuleClosingBraceRegExp,
- forwardRuleSemicolonAndOpeningBraceRegExp: forwardRuleSemicolonAndOpeningBraceRegExp,
-
- // Selector validation patterns
- cssCustomIdentifierRegExp: cssCustomIdentifierRegExp,
- startsWithCombinatorRegExp: startsWithCombinatorRegExp,
- atPageRuleSelectorRegExp: atPageRuleSelectorRegExp,
-
- // Parsing patterns used in CSSImportRule
- layerRegExp: layerRegExp,
- layerRuleNameRegExp: layerRuleNameRegExp,
- doubleOrMoreSpacesRegExp: doubleOrMoreSpacesRegExp,
-
- // Escape sequence and identifier patterns
- startsWithHexEscapeRegExp: startsWithHexEscapeRegExp,
- identStartCharRegExp: identStartCharRegExp,
- identCharRegExp: identCharRegExp,
- specialCharsNeedEscapeRegExp: specialCharsNeedEscapeRegExp,
- combinatorOrSeparatorRegExp: combinatorOrSeparatorRegExp,
- afterHexEscapeSeparatorRegExp: afterHexEscapeSeparatorRegExp,
- trailingSpaceSeparatorRegExp: trailingSpaceSeparatorRegExp,
- endsWithHexEscapeRegExp: endsWithHexEscapeRegExp,
-
- // Basic style property value validation
- basicStylePropertyValueValidationRegExp: basicStylePropertyValueValidationRegExp,
-
- // Attribute selector patterns
- attributeSelectorContentRegExp: attributeSelectorContentRegExp,
-
- // Selector validation patterns
- pseudoElementRegExp: pseudoElementRegExp,
- invalidCombinatorLtGtRegExp: invalidCombinatorLtGtRegExp,
- invalidCombinatorDoubleGtRegExp: invalidCombinatorDoubleGtRegExp,
- consecutiveCombinatorsRegExp: consecutiveCombinatorsRegExp,
- invalidSlottedRegExp: invalidSlottedRegExp,
- invalidPartRegExp: invalidPartRegExp,
- invalidCueRegExp: invalidCueRegExp,
- invalidCueRegionRegExp: invalidCueRegionRegExp,
- invalidNestingPattern: invalidNestingPattern,
- emptyPseudoClassRegExp: emptyPseudoClassRegExp,
- whitespaceNormalizationRegExp: whitespaceNormalizationRegExp,
- newlineRemovalRegExp: newlineRemovalRegExp,
- whitespaceAndDotRegExp: whitespaceAndDotRegExp,
- declarationOrOpenBraceRegExp: declarationOrOpenBraceRegExp,
- ampersandRegExp: ampersandRegExp,
- hexEscapeSequenceRegExp: hexEscapeSequenceRegExp,
- attributeCaseFlagRegExp: attributeCaseFlagRegExp,
- prependedAmpersandRegExp: prependedAmpersandRegExp,
- openBraceGlobalRegExp: openBraceGlobalRegExp,
- closeBraceGlobalRegExp: closeBraceGlobalRegExp,
- scopePreludeSplitRegExp: scopePreludeSplitRegExp,
- leadingWhitespaceRegExp: leadingWhitespaceRegExp,
- doubleQuoteRegExp: doubleQuoteRegExp,
- backslashRegExp: backslashRegExp,
-
- // Media query validation patterns
- invalidMediaOperatorWithoutSpaceRegExp: invalidMediaOperatorWithoutSpaceRegExp,
- invalidMediaNotAfterOperatorRegExp: invalidMediaNotAfterOperatorRegExp,
- invalidMediaNotIdentifierRegExp: invalidMediaNotIdentifierRegExp,
- invalidMediaNotAfterFeatureRegExp: invalidMediaNotAfterFeatureRegExp,
- invalidMediaOperatorBetweenParensRegExp: invalidMediaOperatorBetweenParensRegExp,
- invalidMediaNotWithMediaTypeRegExp: invalidMediaNotWithMediaTypeRegExp,
-
- // Media query normalization patterns
- mediaFeatureColonRegExp: mediaFeatureColonRegExp,
- identifierBeforeParenRegExp: identifierBeforeParenRegExp,
- mediaAndOperatorRegExp: mediaAndOperatorRegExp,
- mediaOrOperatorRegExp: mediaOrOperatorRegExp,
- mediaNotOperatorStartRegExp: mediaNotOperatorStartRegExp,
- mediaNotOperatorRegExp: mediaNotOperatorRegExp
+function isNamespaceRule(r) {
+ return r.type === 10;
+}
+function isRegularRule(r) {
+ return !isImportRule(r) && !isNamespaceRule(r);
+}
+function serializeGroupingRule(atKeyword, condition, rules) {
+ const cond = condition ? " " + condition : "";
+ const ruleTexts = rules.map((r) => r.cssText).filter((p) => p !== "");
+ if (ruleTexts.length === 0) return atKeyword === "keyframes" ? `@${atKeyword}${cond} { }` : `@${atKeyword}${cond} {\n}`;
+ return `@${atKeyword}${cond} {\n${ruleTexts.map((t) => " " + t).join("\n")}\n}`;
+}
+function findParentStyleSheet(rule) {
+ let sheet = rule.parentStyleSheet;
+ let curr = rule.parentRule;
+ while (!sheet && curr) {
+ sheet = curr.parentStyleSheet;
+ curr = curr.parentRule;
+ }
+ return sheet;
+}
+/**
+* Validates that component values match grammar.
+* css-conditional-3 #at-supports
+*/
+function isGrammaticallyValidSupportsCondition(values) {
+ const items = values.filter((v) => v.type !== "whitespace" && v.type !== "comment");
+ if (items.length === 0) return false;
+ const isSupportsInParens = (item) => {
+ if (item.type === "function") return true;
+ if (item.type === "simple-block" && item.associatedToken.value === "(") {
+ const blockValues = item.value.filter((v) => v.type !== "whitespace" && v.type !== "comment");
+ if (blockValues.length === 0) return true;
+ const hasTopOp = blockValues.some((v) => v.type === "ident" && [
+ "and",
+ "or",
+ "not"
+ ].includes(String(v.value).toLowerCase()));
+ const isNestedParenBlock = blockValues.length === 1 && blockValues[0].type === "simple-block" && blockValues[0].associatedToken.value === "(";
+ if (hasTopOp || isNestedParenBlock) return isGrammaticallyValidSupportsCondition(item.value);
+ return true;
+ }
+ return false;
};
-
- //.CommonJS
- regexPatterns.regexPatterns = regexPatterns$1;
- ///CommonJS
- return regexPatterns;
+ const operands = [];
+ const operators = [];
+ let i = 0;
+ while (i < items.length) {
+ if (items[i].type === "ident" && String(items[i].value).toLowerCase() === "not") {
+ if (i + 1 >= items.length) return false;
+ if (!isSupportsInParens(items[i + 1])) return false;
+ operands.push(true);
+ i += 2;
+ } else if (isSupportsInParens(items[i])) {
+ operands.push(true);
+ i += 1;
+ } else return false;
+ if (i < items.length) {
+ if (items[i].type !== "ident") return false;
+ const op = String(items[i].value).toLowerCase();
+ if (op !== "and" && op !== "or") return false;
+ operators.push(op);
+ i += 1;
+ }
+ }
+ if (operands.length === 0) return false;
+ if (operands.length !== operators.length + 1) return false;
+ if (operators.length > 0) {
+ const firstOp = operators[0];
+ if (!operators.every((op) => op === firstOp)) return false;
+ }
+ return true;
}
-
-var CSSStyleDeclaration = {};
-
-var parse$1 = {};
-
-var CSSStyleSheet = {};
-
-var MediaList = {};
-
-var hasRequiredMediaList;
-
-function requireMediaList () {
- if (hasRequiredMediaList) return MediaList;
- hasRequiredMediaList = 1;
- //.CommonJS
- var CSSOM = {};
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://dev.w3.org/csswg/cssom/#the-medialist-interface
- */
- CSSOM.MediaList = function MediaList(){
- this.length = 0;
+// src/rules/base.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+const RULE_CONSTANTS = {
+ STYLE_RULE: 1,
+ CHARSET_RULE: 2,
+ IMPORT_RULE: 3,
+ MEDIA_RULE: 4,
+ FONT_FACE_RULE: 5,
+ PAGE_RULE: 6,
+ KEYFRAMES_RULE: 7,
+ KEYFRAME_RULE: 8,
+ MARGIN_RULE: 9,
+ NAMESPACE_RULE: 10,
+ COUNTER_STYLE_RULE: 11,
+ SUPPORTS_RULE: 12,
+ FONT_FEATURE_VALUES_RULE: 14
+};
+var CSSRule = class {
+ /** @internal */
+ _parentRule = null;
+ /** @internal */
+ _parentStyleSheet = null;
+ /** @internal */
+ _location;
+ /** @internal */
+ _assignedLayerName = null;
+ constructor() {
+ hideInternalFields(this);
+ }
+ get location() {
+ return this._location;
+ }
+ get parentRule() {
+ return this._parentRule;
+ }
+ get parentStyleSheet() {
+ if (this._parentStyleSheet) return this._parentStyleSheet;
+ if (this._parentRule) return this._parentRule.parentStyleSheet;
+ return null;
+ }
+ get type() {
+ return 0;
+ }
+ get cssText() {
+ throw new Error("Not implemented");
+ }
+ set cssText(_value) {}
+};
+applyWebIDLConstants(CSSRule, RULE_CONSTANTS);
+var CSSGroupingRule = class CSSGroupingRule extends CSSRule {
+ /** @internal */
+ static _parser = null;
+ /** @internal */
+ _cssRules;
+ /** @internal */
+ _rules;
+ get cssRules() {
+ if (!this._cssRules) this._cssRules = new CSSRuleList(() => this._rules);
+ return this._cssRules;
+ }
+ constructor(rules, _parseRuleInBlock) {
+ super();
+ this._rules = rules;
+ this._cssRules = new CSSRuleList(() => this._rules);
+ for (const rule of rules) if (rule instanceof CSSRule) rule._parentRule = this;
+ hideInternalFields(this);
+ }
+ insertRule(rule, index = 0) {
+ if (index < 0 || index > this._rules.length) throw new DOMException("Index size error", "IndexSizeError");
+ const isScopeRule = (r) => r[Symbol.toStringTag] === "CSSScopeRule";
+ const isStyleRule = (r) => r[Symbol.toStringTag] === "CSSStyleRule";
+ const isNested = isStyleRule(this) || isScopeRule(this) || this.parentRule !== null;
+ let isInsideStyleRule = isStyleRule(this);
+ let isDirectlyInScope = isScopeRule(this);
+ for (let p = this.parentRule, seenStyle = isInsideStyleRule; p; p = p.parentRule) if (isStyleRule(p)) {
+ isInsideStyleRule = true;
+ seenStyle = true;
+ } else if (!seenStyle && isScopeRule(p)) isDirectlyInScope = true;
+ if (!CSSGroupingRule._parser) throw new DOMException("Parser not initialized", "SyntaxError");
+ const { parseRule, parseRuleInBlock, parseRuleInScopeBlock } = CSSGroupingRule._parser;
+ let topRule = null;
+ try {
+ topRule = parseRule(rule);
+ } catch {}
+ if (topRule) {
+ if (isImportRule(topRule) || isNamespaceRule(topRule)) throw new DOMException("HierarchyRequestError: @import and @namespace rules are not allowed inside grouping rules", "HierarchyRequestError");
+ if (isInsideStyleRule && !(topRule instanceof CSSGroupingRule)) throw new DOMException("HierarchyRequestError: This rule cannot be inserted inside a nested rule", "HierarchyRequestError");
+ }
+ const parsedRule = isDirectlyInScope ? parseRuleInScopeBlock(rule) : parseRuleInBlock(rule, isNested);
+ if (!parsedRule) throw new DOMException("Syntax error", "SyntaxError");
+ if (isImportRule(parsedRule) || isNamespaceRule(parsedRule)) throw new DOMException("HierarchyRequestError: @import and @namespace rules are not allowed inside grouping rules", "HierarchyRequestError");
+ if (parsedRule[Symbol.toStringTag] === "CSSNestedDeclarations") {
+ if (!isNested) throw new DOMException("Syntax error: CSSNestedDeclarations cannot be inserted into top-level grouping rule", "SyntaxError");
+ if (parsedRule.style._declarations.filter((d) => {
+ const name = d.name.toLowerCase();
+ return name.startsWith("--") || SUPPORTED_PROPERTIES.has(name);
+ }).length === 0) throw new DOMException("Syntax error: CSSNestedDeclarations contains no valid declarations", "SyntaxError");
+ }
+ if (parsedRule instanceof CSSRule) {
+ parsedRule._parentRule = this;
+ parsedRule._parentStyleSheet = null;
+ }
+ this._rules.splice(index, 0, parsedRule);
+ return index;
+ }
+ deleteRule(index) {
+ deleteRuleFromArray(this._rules, index);
+ }
+};
+// src/data/gen/shorthands.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+const SHORTHANDS_DATA = {
+ "-webkit-animation": [
+ "animation-name",
+ "animation-duration",
+ "animation-timing-function",
+ "animation-delay",
+ "animation-iteration-count",
+ "animation-direction",
+ "animation-fill-mode",
+ "animation-play-state",
+ "animation-timeline"
+ ],
+ "-webkit-border-radius": [
+ "border-top-left-radius",
+ "border-top-right-radius",
+ "border-bottom-right-radius",
+ "border-bottom-left-radius"
+ ],
+ "-webkit-box-shadow": [
+ "box-shadow-color",
+ "box-shadow-offset",
+ "box-shadow-blur",
+ "box-shadow-spread",
+ "box-shadow-position"
+ ],
+ "-webkit-flex": [
+ "flex-grow",
+ "flex-shrink",
+ "flex-basis"
+ ],
+ "-webkit-flex-flow": ["flex-direction", "flex-wrap"],
+ "-webkit-line-clamp": [
+ "max-lines",
+ "block-ellipsis",
+ "continue"
+ ],
+ "-webkit-mask": [
+ "mask-image",
+ "mask-position",
+ "mask-size",
+ "mask-repeat",
+ "mask-origin",
+ "mask-clip",
+ "mask-composite",
+ "mask-mode"
+ ],
+ "-webkit-mask-box-image": [
+ "mask-border-source",
+ "mask-border-slice",
+ "mask-border-width",
+ "mask-border-outset",
+ "mask-border-repeat",
+ "mask-border-mode"
+ ],
+ "-webkit-text-stroke": ["-webkit-text-stroke-width", "-webkit-text-stroke-color"],
+ "-webkit-transition": [
+ "transition-property",
+ "transition-duration",
+ "transition-timing-function",
+ "transition-delay",
+ "transition-behavior"
+ ],
+ "animation": [
+ "animation-name",
+ "animation-duration",
+ "animation-timing-function",
+ "animation-delay",
+ "animation-iteration-count",
+ "animation-direction",
+ "animation-fill-mode",
+ "animation-play-state",
+ "animation-timeline"
+ ],
+ "animation-delay": ["animation-delay-start", "animation-delay-end"],
+ "animation-range": ["animation-range-start", "animation-range-end"],
+ "background": [
+ "background-image",
+ "background-position",
+ "background-size",
+ "background-repeat",
+ "background-attachment",
+ "background-origin",
+ "background-clip",
+ "background-color"
+ ],
+ "background-position": ["background-position-x", "background-position-y"],
+ "block-step": [
+ "block-step-size",
+ "block-step-insert",
+ "block-step-align",
+ "block-step-round"
+ ],
+ "border": [
+ "border-width",
+ "border-style",
+ "border-color"
+ ],
+ "border-block": ["border-block-start", "border-block-end"],
+ "border-block-clip": ["border-block-start-clip", "border-block-end-clip"],
+ "border-block-color": ["border-block-start-color", "border-block-end-color"],
+ "border-block-end": [
+ "border-block-end-width",
+ "border-block-end-style",
+ "border-block-end-color"
+ ],
+ "border-block-end-radius": ["border-end-start-radius", "border-end-end-radius"],
+ "border-block-start": [
+ "border-block-start-width",
+ "border-block-start-style",
+ "border-block-start-color"
+ ],
+ "border-block-start-radius": ["border-start-start-radius", "border-start-end-radius"],
+ "border-block-style": ["border-block-start-style", "border-block-end-style"],
+ "border-block-width": ["border-block-start-width", "border-block-end-width"],
+ "border-bottom": [
+ "border-bottom-width",
+ "border-bottom-style",
+ "border-bottom-color"
+ ],
+ "border-bottom-radius": ["border-bottom-left-radius", "border-bottom-right-radius"],
+ "border-clip": [
+ "border-top-clip",
+ "border-right-clip",
+ "border-bottom-clip",
+ "border-left-clip"
+ ],
+ "border-color": [
+ "border-top-color",
+ "border-right-color",
+ "border-bottom-color",
+ "border-left-color"
+ ],
+ "border-image": [
+ "border-image-source",
+ "border-image-slice",
+ "border-image-width",
+ "border-image-outset",
+ "border-image-repeat"
+ ],
+ "border-inline": ["border-inline-start", "border-inline-end"],
+ "border-inline-clip": ["border-inline-start-clip", "border-inline-end-clip"],
+ "border-inline-color": ["border-inline-start-color", "border-inline-end-color"],
+ "border-inline-end": [
+ "border-inline-end-width",
+ "border-inline-end-style",
+ "border-inline-end-color"
+ ],
+ "border-inline-end-radius": ["border-start-end-radius", "border-end-end-radius"],
+ "border-inline-start": [
+ "border-inline-start-width",
+ "border-inline-start-style",
+ "border-inline-start-color"
+ ],
+ "border-inline-start-radius": ["border-start-start-radius", "border-end-start-radius"],
+ "border-inline-style": ["border-inline-start-style", "border-inline-end-style"],
+ "border-inline-width": ["border-inline-start-width", "border-inline-end-width"],
+ "border-left": [
+ "border-left-width",
+ "border-left-style",
+ "border-left-color"
+ ],
+ "border-left-radius": ["border-top-left-radius", "border-bottom-left-radius"],
+ "border-radius": [
+ "border-top-left-radius",
+ "border-top-right-radius",
+ "border-bottom-right-radius",
+ "border-bottom-left-radius"
+ ],
+ "border-right": [
+ "border-right-width",
+ "border-right-style",
+ "border-right-color"
+ ],
+ "border-right-radius": ["border-top-right-radius", "border-bottom-right-radius"],
+ "border-style": [
+ "border-top-style",
+ "border-right-style",
+ "border-bottom-style",
+ "border-left-style"
+ ],
+ "border-top": [
+ "border-top-width",
+ "border-top-style",
+ "border-top-color"
+ ],
+ "border-top-radius": ["border-top-left-radius", "border-top-right-radius"],
+ "border-width": [
+ "border-top-width",
+ "border-right-width",
+ "border-bottom-width",
+ "border-left-width"
+ ],
+ "box-shadow": [
+ "box-shadow-color",
+ "box-shadow-offset",
+ "box-shadow-blur",
+ "box-shadow-spread",
+ "box-shadow-position"
+ ],
+ "caret": [
+ "caret-color",
+ "caret-animation",
+ "caret-shape"
+ ],
+ "color-adjust": ["print-color-adjust"],
+ "column-rule": [
+ "column-rule-width",
+ "column-rule-style",
+ "column-rule-color"
+ ],
+ "column-rule-inset": [
+ "column-rule-inset-cap-start",
+ "column-rule-inset-cap-end",
+ "column-rule-inset-junction-start",
+ "column-rule-inset-junction-end"
+ ],
+ "column-rule-inset-cap": ["column-rule-inset-cap-start", "column-rule-inset-cap-end"],
+ "column-rule-inset-end": ["column-rule-inset-cap-end", "column-rule-inset-junction-end"],
+ "column-rule-inset-junction": ["column-rule-inset-junction-start", "column-rule-inset-junction-end"],
+ "column-rule-inset-start": ["column-rule-inset-cap-start", "column-rule-inset-junction-start"],
+ "columns": [
+ "column-width",
+ "column-count",
+ "column-height"
+ ],
+ "contain-intrinsic-size": ["contain-intrinsic-width", "contain-intrinsic-height"],
+ "container": ["container-name", "container-type"],
+ "corner": ["corner-shape", "border-radius"],
+ "corner-block-end": ["border-block-end-radius", "corner-block-end-shape"],
+ "corner-block-end-shape": ["corner-end-start-shape", "corner-end-end-shape"],
+ "corner-block-start": ["border-block-start-radius", "corner-block-start-shape"],
+ "corner-block-start-shape": ["corner-start-start-shape", "corner-start-end-shape"],
+ "corner-bottom": ["border-bottom-radius", "corner-bottom-shape"],
+ "corner-bottom-left": ["border-bottom-left-radius", "corner-bottom-left-shape"],
+ "corner-bottom-right": ["border-bottom-right-radius", "corner-bottom-right-shape"],
+ "corner-bottom-shape": ["corner-bottom-left-shape", "corner-bottom-right-shape"],
+ "corner-end-end": ["border-end-end-radius", "corner-end-end-shape"],
+ "corner-end-start": ["border-end-start-radius", "corner-end-start-shape"],
+ "corner-inline-end": ["border-inline-end-radius", "corner-inline-end-shape"],
+ "corner-inline-end-shape": ["corner-start-end-shape", "corner-end-end-shape"],
+ "corner-inline-start": ["border-inline-start-radius", "corner-inline-start-shape"],
+ "corner-inline-start-shape": ["corner-start-start-shape", "corner-end-start-shape"],
+ "corner-left": ["border-left-radius", "corner-left-shape"],
+ "corner-left-shape": ["corner-top-left-shape", "corner-bottom-left-shape"],
+ "corner-right": ["border-right-radius", "corner-right-shape"],
+ "corner-right-shape": ["corner-top-right-shape", "corner-bottom-right-shape"],
+ "corner-shape": [
+ "corner-top-left-shape",
+ "corner-top-right-shape",
+ "corner-bottom-right-shape",
+ "corner-bottom-left-shape"
+ ],
+ "corner-start-end": ["border-start-end-radius", "corner-start-end-shape"],
+ "corner-start-start": ["border-start-start-radius", "corner-start-start-shape"],
+ "corner-top": ["border-top-radius", "corner-top-shape"],
+ "corner-top-left": ["border-top-left-radius", "corner-top-left-shape"],
+ "corner-top-right": ["border-top-right-radius", "corner-top-right-shape"],
+ "corner-top-shape": ["corner-top-left-shape", "corner-top-right-shape"],
+ "cue": ["cue-before", "cue-after"],
+ "flex": [
+ "flex-grow",
+ "flex-shrink",
+ "flex-basis"
+ ],
+ "flex-flow": ["flex-direction", "flex-wrap"],
+ "font": [
+ "font-style",
+ "font-variant",
+ "font-weight",
+ "font-stretch",
+ "font-size",
+ "line-height",
+ "font-family"
+ ],
+ "font-synthesis": [
+ "font-synthesis-weight",
+ "font-synthesis-style",
+ "font-synthesis-small-caps"
+ ],
+ "font-variant": [
+ "font-variant-ligatures",
+ "font-variant-caps",
+ "font-variant-alternates",
+ "font-variant-numeric",
+ "font-variant-east-asian",
+ "font-variant-position",
+ "font-variant-emoji"
+ ],
+ "gap": ["row-gap", "column-gap"],
+ "grid": [
+ "grid-template-rows",
+ "grid-template-columns",
+ "grid-template-areas",
+ "grid-auto-rows",
+ "grid-auto-columns",
+ "grid-auto-flow"
+ ],
+ "grid-area": [
+ "grid-row-start",
+ "grid-column-start",
+ "grid-row-end",
+ "grid-column-end"
+ ],
+ "grid-column": ["grid-column-start", "grid-column-end"],
+ "grid-gap": ["row-gap", "column-gap"],
+ "grid-row": ["grid-row-start", "grid-row-end"],
+ "grid-template": [
+ "grid-template-rows",
+ "grid-template-columns",
+ "grid-template-areas"
+ ],
+ "inset": [
+ "top",
+ "right",
+ "bottom",
+ "left"
+ ],
+ "inset-block": ["inset-block-start", "inset-block-end"],
+ "inset-inline": ["inset-inline-start", "inset-inline-end"],
+ "interest-delay": ["interest-delay-start", "interest-delay-end"],
+ "line-clamp": [
+ "max-lines",
+ "block-ellipsis",
+ "continue"
+ ],
+ "list-style": [
+ "list-style-type",
+ "list-style-position",
+ "list-style-image"
+ ],
+ "margin": [
+ "margin-top",
+ "margin-right",
+ "margin-bottom",
+ "margin-left"
+ ],
+ "margin-block": ["margin-block-start", "margin-block-end"],
+ "margin-inline": ["margin-inline-start", "margin-inline-end"],
+ "marker": [
+ "marker-start",
+ "marker-mid",
+ "marker-end"
+ ],
+ "mask": [
+ "mask-image",
+ "mask-position",
+ "mask-size",
+ "mask-repeat",
+ "mask-origin",
+ "mask-clip",
+ "mask-composite",
+ "mask-mode"
+ ],
+ "mask-border": [
+ "mask-border-source",
+ "mask-border-slice",
+ "mask-border-width",
+ "mask-border-outset",
+ "mask-border-repeat",
+ "mask-border-mode"
+ ],
+ "max-size": ["max-width", "max-height"],
+ "min-size": ["min-width", "min-height"],
+ "offset": [
+ "offset-path",
+ "offset-distance",
+ "offset-rotate",
+ "offset-anchor",
+ "offset-position"
+ ],
+ "outline": [
+ "outline-width",
+ "outline-style",
+ "outline-color"
+ ],
+ "overflow": ["overflow-x", "overflow-y"],
+ "overflow-clip-margin": [
+ "overflow-clip-margin-top",
+ "overflow-clip-margin-right",
+ "overflow-clip-margin-bottom",
+ "overflow-clip-margin-left"
+ ],
+ "overflow-clip-margin-block": ["overflow-clip-margin-block-start", "overflow-clip-margin-block-end"],
+ "overflow-clip-margin-inline": ["overflow-clip-margin-inline-start", "overflow-clip-margin-inline-end"],
+ "overscroll-behavior": ["overscroll-behavior-x", "overscroll-behavior-y"],
+ "padding": [
+ "padding-top",
+ "padding-right",
+ "padding-bottom",
+ "padding-left"
+ ],
+ "padding-block": ["padding-block-start", "padding-block-end"],
+ "padding-inline": ["padding-inline-start", "padding-inline-end"],
+ "pause": ["pause-before", "pause-after"],
+ "place-content": ["align-content", "justify-content"],
+ "place-items": ["align-items", "justify-items"],
+ "place-self": ["align-self", "justify-self"],
+ "pointer-timeline": ["pointer-timeline-name", "pointer-timeline-axis"],
+ "position-try": ["position-try-order", "position-try-fallbacks"],
+ "rest": ["rest-before", "rest-after"],
+ "row-rule": [
+ "row-rule-width",
+ "row-rule-style",
+ "row-rule-color"
+ ],
+ "row-rule-inset": [
+ "row-rule-inset-cap-start",
+ "row-rule-inset-cap-end",
+ "row-rule-inset-junction-start",
+ "row-rule-inset-junction-end"
+ ],
+ "row-rule-inset-cap": ["row-rule-inset-cap-start", "row-rule-inset-cap-end"],
+ "row-rule-inset-end": ["row-rule-inset-cap-end", "row-rule-inset-junction-end"],
+ "row-rule-inset-junction": ["row-rule-inset-junction-start", "row-rule-inset-junction-end"],
+ "row-rule-inset-start": ["row-rule-inset-cap-start", "row-rule-inset-junction-start"],
+ "rule": ["column-rule", "row-rule"],
+ "rule-break": ["column-rule-break", "row-rule-break"],
+ "rule-color": ["column-rule-color", "row-rule-color"],
+ "rule-inset": ["column-rule-inset", "row-rule-inset"],
+ "rule-inset-cap": ["column-rule-inset-cap"],
+ "rule-inset-end": ["column-rule-inset-end", "row-rule-inset-end"],
+ "rule-inset-junction": ["column-rule-inset-junction"],
+ "rule-inset-start": ["column-rule-inset-start", "row-rule-inset-start"],
+ "rule-style": ["column-rule-style", "row-rule-style"],
+ "rule-visibility-items": ["column-rule-visibility-items"],
+ "rule-width": ["column-rule-width", "row-rule-width"],
+ "scroll-margin": [
+ "scroll-margin-top",
+ "scroll-margin-right",
+ "scroll-margin-bottom",
+ "scroll-margin-left"
+ ],
+ "scroll-margin-block": ["scroll-margin-block-start", "scroll-margin-block-end"],
+ "scroll-margin-inline": ["scroll-margin-inline-start", "scroll-margin-inline-end"],
+ "scroll-padding": [
+ "scroll-padding-top",
+ "scroll-padding-right",
+ "scroll-padding-bottom",
+ "scroll-padding-left"
+ ],
+ "scroll-padding-block": ["scroll-padding-block-start", "scroll-padding-block-end"],
+ "scroll-padding-inline": ["scroll-padding-inline-start", "scroll-padding-inline-end"],
+ "scroll-timeline": ["scroll-timeline-name", "scroll-timeline-axis"],
+ "size": ["width", "height"],
+ "text-align": ["text-align-all", "text-align-last"],
+ "text-decoration": [
+ "text-decoration-line",
+ "text-decoration-thickness",
+ "text-decoration-style",
+ "text-decoration-color"
+ ],
+ "text-decoration-skip": [
+ "text-decoration-skip-self",
+ "text-decoration-skip-box",
+ "text-decoration-skip-spaces",
+ "text-decoration-skip-ink"
+ ],
+ "text-emphasis": ["text-emphasis-style", "text-emphasis-color"],
+ "text-spacing": ["text-spacing-trim", "text-autospace"],
+ "text-wrap": ["text-wrap-mode", "text-wrap-style"],
+ "timeline-trigger": [
+ "timeline-trigger-name",
+ "timeline-trigger-source",
+ "timeline-trigger-range"
+ ],
+ "timeline-trigger-activation-range": ["timeline-trigger-activation-range-start", "timeline-trigger-activation-range-end"],
+ "timeline-trigger-active-range": ["timeline-trigger-active-range-start", "timeline-trigger-active-range-end"],
+ "timeline-trigger-range": ["timeline-trigger-activation-range", "timeline-trigger-active-range"],
+ "transition": [
+ "transition-property",
+ "transition-duration",
+ "transition-timing-function",
+ "transition-delay",
+ "transition-behavior"
+ ],
+ "vertical-align": [
+ "alignment-baseline",
+ "baseline-shift",
+ "baseline-source"
+ ],
+ "view-timeline": ["view-timeline-name", "view-timeline-axis"],
+ "white-space": ["white-space-collapse", "text-wrap-mode"]
+};
+// src/data/gen/LogicalMapping.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+* Logical property to physical property mapping for default horizontal-tb, ltr.
+* css-logical-1 #box
+*/
+const LOGICAL_MAPPING = {
+ "background-position-block": "background-position-y",
+ "background-position-inline": "background-position-x",
+ "background-repeat-block": "background-repeat-y",
+ "background-repeat-inline": "background-repeat-x",
+ "block-size": "height",
+ "border-block-end-clip": "border-bottom-clip",
+ "border-block-end-color": "border-bottom-color",
+ "border-block-end-style": "border-bottom-style",
+ "border-block-end-width": "border-bottom-width",
+ "border-block-start-clip": "border-top-clip",
+ "border-block-start-color": "border-top-color",
+ "border-block-start-style": "border-top-style",
+ "border-block-start-width": "border-top-width",
+ "border-end-end-radius": "border-bottom-right-radius",
+ "border-end-start-radius": "border-bottom-left-radius",
+ "border-inline-end-clip": "border-right-clip",
+ "border-inline-end-color": "border-right-color",
+ "border-inline-end-style": "border-right-style",
+ "border-inline-end-width": "border-right-width",
+ "border-inline-start-clip": "border-left-clip",
+ "border-inline-start-color": "border-left-color",
+ "border-inline-start-style": "border-left-style",
+ "border-inline-start-width": "border-left-width",
+ "border-start-end-radius": "border-top-right-radius",
+ "border-start-start-radius": "border-top-left-radius",
+ "contain-intrinsic-block-size": "contain-intrinsic-height",
+ "contain-intrinsic-inline-size": "contain-intrinsic-width",
+ "corner-end-end-shape": "corner-bottom-right-shape",
+ "corner-end-start-shape": "corner-bottom-left-shape",
+ "corner-start-end-shape": "corner-top-right-shape",
+ "corner-start-start-shape": "corner-top-left-shape",
+ "inline-size": "width",
+ "inset-block-end": "bottom",
+ "inset-block-start": "top",
+ "inset-inline-end": "right",
+ "inset-inline-start": "left",
+ "margin-block-end": "margin-bottom",
+ "margin-block-start": "margin-top",
+ "margin-inline-end": "margin-right",
+ "margin-inline-start": "margin-left",
+ "max-block-size": "max-height",
+ "max-inline-size": "max-width",
+ "min-block-size": "min-height",
+ "min-inline-size": "min-width",
+ "overflow-block": "overflow-y",
+ "overflow-clip-margin-block-end": "overflow-clip-margin-bottom",
+ "overflow-clip-margin-block-start": "overflow-clip-margin-top",
+ "overflow-clip-margin-inline-end": "overflow-clip-margin-right",
+ "overflow-clip-margin-inline-start": "overflow-clip-margin-left",
+ "overflow-inline": "overflow-x",
+ "overscroll-behavior-block": "overscroll-behavior-y",
+ "overscroll-behavior-inline": "overscroll-behavior-x",
+ "padding-block-end": "padding-bottom",
+ "padding-block-start": "padding-top",
+ "padding-inline-end": "padding-right",
+ "padding-inline-start": "padding-left",
+ "scroll-margin-block-end": "scroll-margin-bottom",
+ "scroll-margin-block-start": "scroll-margin-top",
+ "scroll-margin-inline-end": "scroll-margin-right",
+ "scroll-margin-inline-start": "scroll-margin-left",
+ "scroll-padding-block-end": "scroll-padding-bottom",
+ "scroll-padding-block-start": "scroll-padding-top",
+ "scroll-padding-inline-end": "scroll-padding-right",
+ "scroll-padding-inline-start": "scroll-padding-left"
+};
+const PHYSICAL_TO_LOGICAL = {};
+for (const [logical, physical] of Object.entries(LOGICAL_MAPPING)) {
+ if (!PHYSICAL_TO_LOGICAL[physical]) PHYSICAL_TO_LOGICAL[physical] = [];
+ PHYSICAL_TO_LOGICAL[physical].push(logical);
+}
+/**
+* Logical property groups and mapping logic.
+* css-logical-1 #logical-property-group
+*/
+const LOGICAL_PROPERTY_INFO = {
+ "background-position-block": {
+ group: "background-position",
+ logic: "logical"
+ },
+ "background-position-inline": {
+ group: "background-position",
+ logic: "logical"
+ },
+ "background-position-x": {
+ group: "background-position",
+ logic: "physical"
+ },
+ "background-position-y": {
+ group: "background-position",
+ logic: "physical"
+ },
+ "background-repeat-block": {
+ group: "background-repeat",
+ logic: "logical"
+ },
+ "background-repeat-inline": {
+ group: "background-repeat",
+ logic: "logical"
+ },
+ "background-repeat-x": {
+ group: "background-repeat",
+ logic: "physical"
+ },
+ "background-repeat-y": {
+ group: "background-repeat",
+ logic: "physical"
+ },
+ "block-size": {
+ group: "size",
+ logic: "logical"
+ },
+ "border-block-end-clip": {
+ group: "border-clip",
+ logic: "logical"
+ },
+ "border-block-end-color": {
+ group: "border-color",
+ logic: "logical"
+ },
+ "border-block-end-style": {
+ group: "border-style",
+ logic: "logical"
+ },
+ "border-block-end-width": {
+ group: "border-width",
+ logic: "logical"
+ },
+ "border-block-start-clip": {
+ group: "border-clip",
+ logic: "logical"
+ },
+ "border-block-start-color": {
+ group: "border-color",
+ logic: "logical"
+ },
+ "border-block-start-style": {
+ group: "border-style",
+ logic: "logical"
+ },
+ "border-block-start-width": {
+ group: "border-width",
+ logic: "logical"
+ },
+ "border-bottom-clip": {
+ group: "border-clip",
+ logic: "physical"
+ },
+ "border-bottom-color": {
+ group: "border-color",
+ logic: "physical"
+ },
+ "border-bottom-left-radius": {
+ group: "border-radius",
+ logic: "physical"
+ },
+ "border-bottom-right-radius": {
+ group: "border-radius",
+ logic: "physical"
+ },
+ "border-bottom-style": {
+ group: "border-style",
+ logic: "physical"
+ },
+ "border-bottom-width": {
+ group: "border-width",
+ logic: "physical"
+ },
+ "border-end-end-radius": {
+ group: "border-radius",
+ logic: "logical"
+ },
+ "border-end-start-radius": {
+ group: "border-radius",
+ logic: "logical"
+ },
+ "border-inline-end-clip": {
+ group: "border-clip",
+ logic: "logical"
+ },
+ "border-inline-end-color": {
+ group: "border-color",
+ logic: "logical"
+ },
+ "border-inline-end-style": {
+ group: "border-style",
+ logic: "logical"
+ },
+ "border-inline-end-width": {
+ group: "border-width",
+ logic: "logical"
+ },
+ "border-inline-start-clip": {
+ group: "border-clip",
+ logic: "logical"
+ },
+ "border-inline-start-color": {
+ group: "border-color",
+ logic: "logical"
+ },
+ "border-inline-start-style": {
+ group: "border-style",
+ logic: "logical"
+ },
+ "border-inline-start-width": {
+ group: "border-width",
+ logic: "logical"
+ },
+ "border-left-clip": {
+ group: "border-clip",
+ logic: "physical"
+ },
+ "border-left-color": {
+ group: "border-color",
+ logic: "physical"
+ },
+ "border-left-style": {
+ group: "border-style",
+ logic: "physical"
+ },
+ "border-left-width": {
+ group: "border-width",
+ logic: "physical"
+ },
+ "border-right-clip": {
+ group: "border-clip",
+ logic: "physical"
+ },
+ "border-right-color": {
+ group: "border-color",
+ logic: "physical"
+ },
+ "border-right-style": {
+ group: "border-style",
+ logic: "physical"
+ },
+ "border-right-width": {
+ group: "border-width",
+ logic: "physical"
+ },
+ "border-start-end-radius": {
+ group: "border-radius",
+ logic: "logical"
+ },
+ "border-start-start-radius": {
+ group: "border-radius",
+ logic: "logical"
+ },
+ "border-top-clip": {
+ group: "border-clip",
+ logic: "physical"
+ },
+ "border-top-color": {
+ group: "border-color",
+ logic: "physical"
+ },
+ "border-top-left-radius": {
+ group: "border-radius",
+ logic: "physical"
+ },
+ "border-top-right-radius": {
+ group: "border-radius",
+ logic: "physical"
+ },
+ "border-top-style": {
+ group: "border-style",
+ logic: "physical"
+ },
+ "border-top-width": {
+ group: "border-width",
+ logic: "physical"
+ },
+ "bottom": {
+ group: "inset",
+ logic: "physical"
+ },
+ "contain-intrinsic-block-size": {
+ group: "contain-intrinsic-size",
+ logic: "logical"
+ },
+ "contain-intrinsic-height": {
+ group: "contain-intrinsic-size",
+ logic: "physical"
+ },
+ "contain-intrinsic-inline-size": {
+ group: "contain-intrinsic-size",
+ logic: "logical"
+ },
+ "contain-intrinsic-width": {
+ group: "contain-intrinsic-size",
+ logic: "physical"
+ },
+ "corner-bottom-left-shape": {
+ group: "corner-shape",
+ logic: "physical"
+ },
+ "corner-bottom-right-shape": {
+ group: "corner-shape",
+ logic: "physical"
+ },
+ "corner-end-end-shape": {
+ group: "corner-shape",
+ logic: "logical"
+ },
+ "corner-end-start-shape": {
+ group: "corner-shape",
+ logic: "logical"
+ },
+ "corner-start-end-shape": {
+ group: "corner-shape",
+ logic: "logical"
+ },
+ "corner-start-start-shape": {
+ group: "corner-shape",
+ logic: "logical"
+ },
+ "corner-top-left-shape": {
+ group: "corner-shape",
+ logic: "physical"
+ },
+ "corner-top-right-shape": {
+ group: "corner-shape",
+ logic: "physical"
+ },
+ "height": {
+ group: "size",
+ logic: "physical"
+ },
+ "inline-size": {
+ group: "size",
+ logic: "logical"
+ },
+ "inset-block-end": {
+ group: "inset",
+ logic: "logical"
+ },
+ "inset-block-start": {
+ group: "inset",
+ logic: "logical"
+ },
+ "inset-inline-end": {
+ group: "inset",
+ logic: "logical"
+ },
+ "inset-inline-start": {
+ group: "inset",
+ logic: "logical"
+ },
+ "left": {
+ group: "inset",
+ logic: "physical"
+ },
+ "margin-block-end": {
+ group: "margin",
+ logic: "logical"
+ },
+ "margin-block-start": {
+ group: "margin",
+ logic: "logical"
+ },
+ "margin-bottom": {
+ group: "margin",
+ logic: "physical"
+ },
+ "margin-inline-end": {
+ group: "margin",
+ logic: "logical"
+ },
+ "margin-inline-start": {
+ group: "margin",
+ logic: "logical"
+ },
+ "margin-left": {
+ group: "margin",
+ logic: "physical"
+ },
+ "margin-right": {
+ group: "margin",
+ logic: "physical"
+ },
+ "margin-top": {
+ group: "margin",
+ logic: "physical"
+ },
+ "max-block-size": {
+ group: "max-size",
+ logic: "logical"
+ },
+ "max-height": {
+ group: "max-size",
+ logic: "physical"
+ },
+ "max-inline-size": {
+ group: "max-size",
+ logic: "logical"
+ },
+ "max-width": {
+ group: "max-size",
+ logic: "physical"
+ },
+ "min-block-size": {
+ group: "min-size",
+ logic: "logical"
+ },
+ "min-height": {
+ group: "min-size",
+ logic: "physical"
+ },
+ "min-inline-size": {
+ group: "min-size",
+ logic: "logical"
+ },
+ "min-width": {
+ group: "min-size",
+ logic: "physical"
+ },
+ "overflow-block": {
+ group: "overflow",
+ logic: "logical"
+ },
+ "overflow-clip-margin-block-end": {
+ group: "overflow-clip-margin",
+ logic: "logical"
+ },
+ "overflow-clip-margin-block-start": {
+ group: "overflow-clip-margin",
+ logic: "logical"
+ },
+ "overflow-clip-margin-bottom": {
+ group: "overflow-clip-margin",
+ logic: "physical"
+ },
+ "overflow-clip-margin-inline-end": {
+ group: "overflow-clip-margin",
+ logic: "logical"
+ },
+ "overflow-clip-margin-inline-start": {
+ group: "overflow-clip-margin",
+ logic: "logical"
+ },
+ "overflow-clip-margin-left": {
+ group: "overflow-clip-margin",
+ logic: "physical"
+ },
+ "overflow-clip-margin-right": {
+ group: "overflow-clip-margin",
+ logic: "physical"
+ },
+ "overflow-clip-margin-top": {
+ group: "overflow-clip-margin",
+ logic: "physical"
+ },
+ "overflow-inline": {
+ group: "overflow",
+ logic: "logical"
+ },
+ "overflow-x": {
+ group: "overflow",
+ logic: "physical"
+ },
+ "overflow-y": {
+ group: "overflow",
+ logic: "physical"
+ },
+ "overscroll-behavior-block": {
+ group: "overscroll-behavior",
+ logic: "logical"
+ },
+ "overscroll-behavior-inline": {
+ group: "overscroll-behavior",
+ logic: "logical"
+ },
+ "overscroll-behavior-x": {
+ group: "overscroll-behavior",
+ logic: "physical"
+ },
+ "overscroll-behavior-y": {
+ group: "overscroll-behavior",
+ logic: "physical"
+ },
+ "padding-block-end": {
+ group: "padding",
+ logic: "logical"
+ },
+ "padding-block-start": {
+ group: "padding",
+ logic: "logical"
+ },
+ "padding-bottom": {
+ group: "padding",
+ logic: "physical"
+ },
+ "padding-inline-end": {
+ group: "padding",
+ logic: "logical"
+ },
+ "padding-inline-start": {
+ group: "padding",
+ logic: "logical"
+ },
+ "padding-left": {
+ group: "padding",
+ logic: "physical"
+ },
+ "padding-right": {
+ group: "padding",
+ logic: "physical"
+ },
+ "padding-top": {
+ group: "padding",
+ logic: "physical"
+ },
+ "right": {
+ group: "inset",
+ logic: "physical"
+ },
+ "scroll-margin-block-end": {
+ group: "scroll-margin",
+ logic: "logical"
+ },
+ "scroll-margin-block-start": {
+ group: "scroll-margin",
+ logic: "logical"
+ },
+ "scroll-margin-bottom": {
+ group: "scroll-margin",
+ logic: "physical"
+ },
+ "scroll-margin-inline-end": {
+ group: "scroll-margin",
+ logic: "logical"
+ },
+ "scroll-margin-inline-start": {
+ group: "scroll-margin",
+ logic: "logical"
+ },
+ "scroll-margin-left": {
+ group: "scroll-margin",
+ logic: "physical"
+ },
+ "scroll-margin-right": {
+ group: "scroll-margin",
+ logic: "physical"
+ },
+ "scroll-margin-top": {
+ group: "scroll-margin",
+ logic: "physical"
+ },
+ "scroll-padding-block-end": {
+ group: "scroll-padding",
+ logic: "logical"
+ },
+ "scroll-padding-block-start": {
+ group: "scroll-padding",
+ logic: "logical"
+ },
+ "scroll-padding-bottom": {
+ group: "scroll-padding",
+ logic: "physical"
+ },
+ "scroll-padding-inline-end": {
+ group: "scroll-padding",
+ logic: "logical"
+ },
+ "scroll-padding-inline-start": {
+ group: "scroll-padding",
+ logic: "logical"
+ },
+ "scroll-padding-left": {
+ group: "scroll-padding",
+ logic: "physical"
+ },
+ "scroll-padding-right": {
+ group: "scroll-padding",
+ logic: "physical"
+ },
+ "scroll-padding-top": {
+ group: "scroll-padding",
+ logic: "physical"
+ },
+ "top": {
+ group: "inset",
+ logic: "physical"
+ },
+ "width": {
+ group: "size",
+ logic: "physical"
+ }
+};
+/**
+* Resolves a logical property to its physical counterpart based on writing mode and direction.
+*/
+function resolveLogicalProperty(name, writingMode = "horizontal-tb", direction = "ltr") {
+ if (!(name in LOGICAL_MAPPING)) return name;
+ let blockStart = "top";
+ let blockEnd = "bottom";
+ let inlineStart = "left";
+ let inlineEnd = "right";
+ let blockAxis = "y";
+ let inlineAxis = "x";
+ if (writingMode === "vertical-rl" || writingMode === "sideways-rl") {
+ blockStart = "right";
+ blockEnd = "left";
+ inlineStart = "top";
+ inlineEnd = "bottom";
+ blockAxis = "x";
+ inlineAxis = "y";
+ } else if (writingMode === "vertical-lr") {
+ blockStart = "left";
+ blockEnd = "right";
+ inlineStart = "top";
+ inlineEnd = "bottom";
+ blockAxis = "x";
+ inlineAxis = "y";
+ } else if (writingMode === "sideways-lr") {
+ blockStart = "left";
+ blockEnd = "right";
+ inlineStart = "bottom";
+ inlineEnd = "top";
+ blockAxis = "x";
+ inlineAxis = "y";
+ }
+ if (direction === "rtl") {
+ const tmp = inlineStart;
+ inlineStart = inlineEnd;
+ inlineEnd = tmp;
+ }
+ if (name.startsWith("inset-block-start")) return blockStart;
+ if (name.startsWith("inset-block-end")) return blockEnd;
+ if (name.startsWith("inset-inline-start")) return inlineStart;
+ if (name.startsWith("inset-inline-end")) return inlineEnd;
+ const radius = (s1, s2) => {
+ return `-${s1 === "top" || s1 === "bottom" ? s1 : s2}-${s1 === "left" || s1 === "right" ? s1 : s2}-radius`;
};
-
- CSSOM.MediaList.prototype = {
-
- constructor: CSSOM.MediaList,
-
- /**
- * @return {string}
- */
- get mediaText() {
- return Array.prototype.join.call(this, ", ");
+ const shape = (s1, s2) => {
+ return `-${s1 === "top" || s1 === "bottom" ? s1 : s2}-${s1 === "left" || s1 === "right" ? s1 : s2}-shape`;
+ };
+ const replacements = [
+ {
+ logical: "-block-start",
+ physical: `-${blockStart}`
},
-
- /**
- * @param {string} value
- */
- set mediaText(value) {
- if (typeof value === "string") {
- var values = value.split(",").filter(function(text){
- return !!text;
- });
- var length = this.length = values.length;
- for (var i=0; i v.type !== "whitespace" && v.type !== "comment" && v.type !== "EOF");
}
-
-var CSSStyleRule = {};
-
-var CSSRule = {};
-
-var hasRequiredCSSRule;
-
-function requireCSSRule () {
- if (hasRequiredCSSRule) return CSSRule;
- hasRequiredCSSRule = 1;
- //.CommonJS
- var CSSOM = {};
- ///CommonJS
-
- /**
- * @constructor
- * @see http://dev.w3.org/csswg/cssom/#the-cssrule-interface
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSRule
- */
- CSSOM.CSSRule = function CSSRule() {
- this.__parentRule = null;
- this.__parentStyleSheet = null;
- };
-
- CSSOM.CSSRule.UNKNOWN_RULE = 0; // obsolete
- CSSOM.CSSRule.STYLE_RULE = 1;
- CSSOM.CSSRule.CHARSET_RULE = 2; // obsolete
- CSSOM.CSSRule.IMPORT_RULE = 3;
- CSSOM.CSSRule.MEDIA_RULE = 4;
- CSSOM.CSSRule.FONT_FACE_RULE = 5;
- CSSOM.CSSRule.PAGE_RULE = 6;
- CSSOM.CSSRule.KEYFRAMES_RULE = 7;
- CSSOM.CSSRule.KEYFRAME_RULE = 8;
- CSSOM.CSSRule.MARGIN_RULE = 9;
- CSSOM.CSSRule.NAMESPACE_RULE = 10;
- CSSOM.CSSRule.COUNTER_STYLE_RULE = 11;
- CSSOM.CSSRule.SUPPORTS_RULE = 12;
- CSSOM.CSSRule.DOCUMENT_RULE = 13;
- CSSOM.CSSRule.FONT_FEATURE_VALUES_RULE = 14;
- CSSOM.CSSRule.VIEWPORT_RULE = 15;
- CSSOM.CSSRule.REGION_STYLE_RULE = 16;
- CSSOM.CSSRule.CONTAINER_RULE = 17;
- CSSOM.CSSRule.LAYER_BLOCK_RULE = 18;
- CSSOM.CSSRule.STARTING_STYLE_RULE = 1002;
-
- Object.defineProperties(CSSOM.CSSRule.prototype, {
-
- constructor: { value: CSSOM.CSSRule },
-
- cssRule: {
- value: "",
- configurable: true,
- enumerable: true
- },
-
- cssText: {
- get: function() {
- // Default getter: subclasses should override this
- return "";
- },
- set: function(cssText) {
- return cssText;
- }
- },
-
- parentRule: {
- get: function() {
- return this.__parentRule
- }
- },
-
- parentStyleSheet: {
- get: function() {
- return this.__parentStyleSheet
- }
- },
-
- UNKNOWN_RULE: { value: 0, enumerable: true }, // obsolet
- STYLE_RULE: { value: 1, enumerable: true },
- CHARSET_RULE: { value: 2, enumerable: true }, // obsolet
- IMPORT_RULE: { value: 3, enumerable: true },
- MEDIA_RULE: { value: 4, enumerable: true },
- FONT_FACE_RULE: { value: 5, enumerable: true },
- PAGE_RULE: { value: 6, enumerable: true },
- KEYFRAMES_RULE: { value: 7, enumerable: true },
- KEYFRAME_RULE: { value: 8, enumerable: true },
- MARGIN_RULE: { value: 9, enumerable: true },
- NAMESPACE_RULE: { value: 10, enumerable: true },
- COUNTER_STYLE_RULE: { value: 11, enumerable: true },
- SUPPORTS_RULE: { value: 12, enumerable: true },
- DOCUMENT_RULE: { value: 13, enumerable: true },
- FONT_FEATURE_VALUES_RULE: { value: 14, enumerable: true },
- VIEWPORT_RULE: { value: 15, enumerable: true },
- REGION_STYLE_RULE: { value: 16, enumerable: true },
- CONTAINER_RULE: { value: 17, enumerable: true },
- LAYER_BLOCK_RULE: { value: 18, enumerable: true },
- STARTING_STYLE_RULE: { value: 1002, enumerable: true },
- });
-
- //.CommonJS
- CSSRule.CSSRule = CSSOM.CSSRule;
- ///CommonJS
- return CSSRule;
+function splitTokensByComma(tokens) {
+ const res = [[]];
+ for (const t of tokens) if (t.type === "comma") res.push([]);
+ else res[res.length - 1].push(t);
+ return res;
}
-
-var CSSGroupingRule = {};
-
-var hasRequiredCSSGroupingRule;
-
-function requireCSSGroupingRule () {
- if (hasRequiredCSSGroupingRule) return CSSGroupingRule;
- hasRequiredCSSGroupingRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- parse: requireParse().parse
+function expandUniformLonghands(longhands, val) {
+ const res = {};
+ for (const lh of longhands) res[lh] = val;
+ return res;
+}
+function tryExpandCssWide(filtered, longhands, extraKeywords) {
+ if (filtered.length === 1 && filtered[0].type === "ident") {
+ const v = filtered[0].value.toLowerCase();
+ if (CSS_WIDE_KEYWORDS$2.has(v) || extraKeywords?.has(v)) return expandUniformLonghands(longhands, [filtered[0]]);
+ }
+ return null;
+}
+function checkUniformCssWide(serializedVals, checkVar = false) {
+ if (serializedVals.some((v) => CSS_WIDE_KEYWORDS$2.has(v.toLowerCase()) || checkVar && v.toLowerCase().startsWith("var("))) return serializedVals.every((v) => v.toLowerCase() === serializedVals[0].toLowerCase()) ? serializedVals[0] : null;
+}
+function expandFourSides(data) {
+ const s0 = [data[0]];
+ const s1 = data.length > 1 ? [data[1]] : s0;
+ return [
+ s0,
+ s1,
+ data.length > 2 ? [data[2]] : s0,
+ data.length > 3 ? [data[3]] : s1
+ ];
+}
+function formatFourSides(a, b, c, d) {
+ if (a === b && a === c && a === d) return a;
+ if (a === c && b === d) return `${a} ${b}`;
+ if (b === d) return `${a} ${b} ${c}`;
+ return `${a} ${b} ${c} ${d}`;
+}
+function getFunctionName(token) {
+ if (token.type === "function") {
+ if ("name" in token && typeof token.name === "string") return token.name.toLowerCase();
+ if ("value" in token && typeof token.value === "string") return token.value.toLowerCase();
+ }
+ return "";
+}
+function isRepeatKeyword(token) {
+ return token.type === "ident" && REPEAT_KEYWORDS.has(token.value.toLowerCase());
+}
+function isAttachmentKeyword(token) {
+ return token.type === "ident" && ATTACHMENT_KEYWORDS.has(token.value.toLowerCase());
+}
+function isBoxKeyword(token) {
+ return token.type === "ident" && BOX_KEYWORDS.has(token.value.toLowerCase());
+}
+function isClipOnlyBoxKeyword(keyword) {
+ return CLIP_ONLY_BOX_KEYWORDS.has(keyword.toLowerCase());
+}
+function isColorToken(token) {
+ if (token.type === "hash") return true;
+ if (token.type === "ident") return NAMED_COLORS.has(token.value.toLowerCase());
+ if (token.type === "function") return COLOR_FUNCTIONS.has(getFunctionName(token));
+ return false;
+}
+function isImageToken(token) {
+ if (token.type === "ident" && token.value.toLowerCase() === "none") return true;
+ if (token.type === "url") return true;
+ if (token.type === "function") return IMAGE_FUNCTIONS.has(getFunctionName(token));
+ return false;
+}
+function isPositionOrSizeValue(token) {
+ if (token.type === "ident") return POSITION_OR_SIZE_KEYWORDS.has(token.value.toLowerCase());
+ if (token.type === "percentage" || token.type === "dimension") return true;
+ if (token.type === "number" && token.value === 0) return true;
+ if (token.type === "function") return MATH_FUNCTIONS.has(getFunctionName(token));
+ return false;
+}
+function extractSizeTokens(tokens, slashIdx) {
+ if (slashIdx + 1 >= tokens.length) return null;
+ const first = tokens[slashIdx + 1];
+ if (first.type === "ident" && ["cover", "contain"].includes(first.value.toLowerCase())) return {
+ size: [first],
+ consumed: 1
};
- var errorUtils = requireErrorUtils().errorUtils;
- ///CommonJS
-
-
- /**
- * @constructor
- * @see https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface
- */
- CSSOM.CSSGroupingRule = function CSSGroupingRule() {
- CSSOM.CSSRule.call(this);
- this.__cssRules = new CSSOM.CSSRuleList();
+ const isSizeVal = (t) => t.type === "ident" && t.value.toLowerCase() === "auto" || t.type === "percentage" || t.type === "dimension" || t.type === "number" && t.value === 0 || t.type === "function" && MATH_FUNCTIONS.has(getFunctionName(t));
+ if (!isSizeVal(first)) return null;
+ if (slashIdx + 2 < tokens.length && isSizeVal(tokens[slashIdx + 2])) return {
+ size: [first, tokens[slashIdx + 2]],
+ consumed: 2
};
-
- CSSOM.CSSGroupingRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
-
- Object.setPrototypeOf(CSSOM.CSSGroupingRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSGroupingRule.prototype, "cssRules", {
- get: function() {
- return this.__cssRules;
- }
- });
-
- /**
- * Used to insert a new CSS rule to a list of CSS rules.
- *
- * @example
- * cssGroupingRule.cssText
- * -> "body{margin:0;}"
- * cssGroupingRule.insertRule("img{border:none;}", 1)
- * -> 1
- * cssGroupingRule.cssText
- * -> "body{margin:0;}img{border:none;}"
- *
- * @param {string} rule
- * @param {number} [index]
- * @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-insertrule
- * @return {number} The index within the grouping rule's collection of the newly inserted rule.
- */
- CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule, index) {
- if (rule === undefined && index === undefined) {
- errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
- }
- if (index === void 0) {
- index = 0;
- }
- index = Number(index);
- if (index < 0) {
- index = 4294967296 + index;
- }
- if (index > this.cssRules.length) {
- errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
- }
- var ruleToParse = processedRuleToParse = String(rule);
- ruleToParse = ruleToParse.trim().replace(/^\/\*[\s\S]*?\*\/\s*/, "");
- var isNestedSelector = this.constructor.name === "CSSStyleRule";
- if (isNestedSelector === false) {
- var currentRule = this;
- while (currentRule.parentRule) {
- currentRule = currentRule.parentRule;
- if (currentRule.constructor.name === "CSSStyleRule") {
- isNestedSelector = true;
- break;
- }
- }
- }
- if (isNestedSelector) {
- processedRuleToParse = 's { n { } ' + ruleToParse + '}';
- }
- var isScopeRule = this.constructor.name === "CSSScopeRule";
- if (isScopeRule) {
- if (isNestedSelector) {
- processedRuleToParse = 's { ' + '@scope {' + ruleToParse + '}}';
- } else {
- processedRuleToParse = '@scope {' + ruleToParse + '}';
- }
- }
- var parsedRules = new CSSOM.CSSRuleList();
- CSSOM.parse(processedRuleToParse, {
- styleSheet: this.parentStyleSheet,
- cssRules: parsedRules
+ return {
+ size: [first],
+ consumed: 1
+ };
+}
+function mapBoxKeywords(keywords) {
+ if (keywords.length === 0) return {
+ origin: "padding-box",
+ clip: "border-box"
+ };
+ if (keywords.length === 1) {
+ const a = keywords[0].toLowerCase();
+ return isClipOnlyBoxKeyword(a) ? {
+ origin: "border-box",
+ clip: a
+ } : {
+ origin: a,
+ clip: a
+ };
+ }
+ if (keywords.length === 2) {
+ const a = keywords[0].toLowerCase();
+ const b = keywords[1].toLowerCase();
+ const aClip = isClipOnlyBoxKeyword(a);
+ const bClip = isClipOnlyBoxKeyword(b);
+ if (aClip && bClip) return {
+ origin: "border-box",
+ clip: `${a} ${b}`
+ };
+ if (aClip) return {
+ origin: b,
+ clip: a
+ };
+ if (bClip) return {
+ origin: a,
+ clip: b
+ };
+ return {
+ origin: a,
+ clip: b
+ };
+ }
+ if (keywords.length === 3) {
+ const clips = keywords.filter(isClipOnlyBoxKeyword);
+ const origins = keywords.filter((k) => !isClipOnlyBoxKeyword(k));
+ return clips.length === 2 && origins.length === 1 ? {
+ origin: origins[0],
+ clip: clips.join(" ")
+ } : null;
+ }
+ return null;
+}
+function parseRepeatTokens(tokens) {
+ if (tokens.length === 1) {
+ const val = tokens[0].value?.toString().toLowerCase();
+ if (val === "repeat-x") return [{
+ type: "ident",
+ value: "repeat"
+ }, {
+ type: "ident",
+ value: "no-repeat"
+ }];
+ if (val === "repeat-y") return [{
+ type: "ident",
+ value: "no-repeat"
+ }, {
+ type: "ident",
+ value: "repeat"
+ }];
+ return [tokens[0]];
+ }
+ return tokens.length === 2 ? tokens : null;
+}
+function normalizePositionTokens(tokens) {
+ if (tokens.length === 1) {
+ const t0 = tokens[0];
+ if (t0.type === "ident") {
+ const v = t0.value.toLowerCase();
+ if (v === "left" || v === "right") return [t0, {
+ type: "ident",
+ value: "center"
+ }];
+ if (v === "top" || v === "bottom") return [{
+ type: "ident",
+ value: "center"
+ }, t0];
+ if (v === "center") return [t0, t0];
+ } else return [t0, {
+ type: "percentage",
+ value: 50,
+ sign: null
+ }];
+ }
+ if (tokens.length === 2 && tokens[0].type === "ident" && tokens[1].type === "ident") {
+ const [t0, t1] = tokens;
+ const v0 = t0.value.toLowerCase();
+ const v1 = t1.value.toLowerCase();
+ const isHoriz = (v) => v === "left" || v === "right";
+ const isVert = (v) => v === "top" || v === "bottom";
+ if (isVert(v0) && isHoriz(v1) || isVert(v0) && v1 === "center") return [t1, t0];
+ }
+ return tokens;
+}
+function normalizeSizeTokens(tokens) {
+ if (tokens.length === 1) {
+ const t0 = tokens[0];
+ if (t0.type === "ident" && ["cover", "contain"].includes(t0.value.toLowerCase())) return [t0];
+ return [t0, {
+ type: "ident",
+ value: "auto"
+ }];
+ }
+ return tokens;
+}
+function joinWithWhitespace(tokens) {
+ const res = [];
+ for (let i = 0; i < tokens.length; i++) {
+ if (i > 0) res.push({
+ type: "whitespace",
+ value: " "
});
- if (isScopeRule) {
- if (isNestedSelector) {
- parsedRules = parsedRules[0].cssRules[0].cssRules;
- } else {
- parsedRules = parsedRules[0].cssRules;
- }
+ res.push(tokens[i]);
+ }
+ return res;
+}
+function expandBackground(values) {
+ const cssWide = tryExpandCssWide(filterSignificantTokens(values), SHORTHANDS_DATA["background"]);
+ if (cssWide) return cssWide;
+ const layers = splitTokensByComma(values);
+ const numLayers = layers.length;
+ if (numLayers === 0) return null;
+ const imageLayers = [];
+ const positionLayers = [];
+ const sizeLayers = [];
+ const repeatLayers = [];
+ const attachmentLayers = [];
+ const originLayers = [];
+ const clipLayers = [];
+ let parsedColor = null;
+ for (let i = 0; i < numLayers; i++) {
+ const layerClean = filterSignificantTokens(layers[i]);
+ if (layerClean.length === 0) return null;
+ const slashIdx = layerClean.findIndex((t) => t.type === "delim" && t.value === "/");
+ let sizeTokens = null;
+ if (slashIdx !== -1) {
+ const sizeResult = extractSizeTokens(layerClean, slashIdx);
+ if (!sizeResult) return null;
+ sizeTokens = sizeResult.size;
+ layerClean.splice(slashIdx, 1 + sizeResult.consumed);
}
- if (isNestedSelector) {
- parsedRules = parsedRules[0].cssRules.slice(1);
+ const repeatTokens = [];
+ const attachmentTokens = [];
+ const boxKeywords = [];
+ let colorTokens = null;
+ let imageTokens = null;
+ const positionTokens = [];
+ for (const token of layerClean) if (isRepeatKeyword(token)) repeatTokens.push(token);
+ else if (isAttachmentKeyword(token)) attachmentTokens.push(token);
+ else if (isBoxKeyword(token)) boxKeywords.push(token.value);
+ else if (isColorToken(token)) {
+ if (i !== numLayers - 1 || colorTokens !== null) return null;
+ colorTokens = [token];
+ } else if (isImageToken(token)) {
+ if (imageTokens !== null) return null;
+ imageTokens = [token];
+ } else if (isPositionOrSizeValue(token)) positionTokens.push(token);
+ else return null;
+ if (sizeTokens !== null && positionTokens.length === 0 || positionTokens.length > 4) return null;
+ const boxMapped = mapBoxKeywords(boxKeywords);
+ if (!boxMapped) return null;
+ const repeatMapped = parseRepeatTokens(repeatTokens);
+ imageLayers.push(imageTokens || [{
+ type: "ident",
+ value: "none"
+ }]);
+ positionLayers.push(positionTokens.length > 0 ? joinWithWhitespace(normalizePositionTokens(positionTokens)) : joinWithWhitespace([{
+ type: "percentage",
+ value: 0,
+ sign: null
+ }, {
+ type: "percentage",
+ value: 0,
+ sign: null
+ }]));
+ sizeLayers.push(sizeTokens !== null ? joinWithWhitespace(normalizeSizeTokens(sizeTokens)) : [{
+ type: "ident",
+ value: "auto"
+ }]);
+ repeatLayers.push(repeatMapped ? joinWithWhitespace(repeatMapped) : [{
+ type: "ident",
+ value: "repeat"
+ }]);
+ attachmentLayers.push(attachmentTokens.length > 0 ? joinWithWhitespace(attachmentTokens) : [{
+ type: "ident",
+ value: "scroll"
+ }]);
+ originLayers.push([{
+ type: "ident",
+ value: boxMapped.origin
+ }]);
+ clipLayers.push(joinWithWhitespace(boxMapped.clip.split(" ").map((c) => ({
+ type: "ident",
+ value: c
+ }))));
+ if (colorTokens !== null) parsedColor = colorTokens;
+ }
+ const joinLayers = (layerList) => {
+ const res = [];
+ for (let i = 0; i < layerList.length; i++) {
+ if (i > 0) res.push({
+ type: "comma",
+ value: ","
+ }, {
+ type: "whitespace",
+ value: " "
+ });
+ res.push(...layerList[i]);
}
- if (parsedRules.length !== 1) {
- if (isNestedSelector && parsedRules.length === 0 && ruleToParse.indexOf('@font-face') === 0) {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': " +
- "Only conditional nested group rules, style rules, @scope rules, @apply rules, and nested declaration rules may be nested.",
- 'HierarchyRequestError');
- } else {
- errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
- }
+ return res;
+ };
+ return {
+ "background-image": joinLayers(imageLayers),
+ "background-position": joinLayers(positionLayers),
+ "background-size": joinLayers(sizeLayers),
+ "background-repeat": joinLayers(repeatLayers),
+ "background-attachment": joinLayers(attachmentLayers),
+ "background-origin": joinLayers(originLayers),
+ "background-clip": joinLayers(clipLayers),
+ "background-color": parsedColor || [{
+ type: "ident",
+ value: "transparent"
+ }]
+ };
+}
+function contractBackground(longhands) {
+ const image = longhands["background-image"];
+ const position = longhands["background-position"];
+ const size = longhands["background-size"];
+ const repeat = longhands["background-repeat"];
+ const attachment = longhands["background-attachment"];
+ const origin = longhands["background-origin"];
+ const clip = longhands["background-clip"];
+ const color = longhands["background-color"];
+ if (!image || !position || !size || !repeat || !attachment || !origin || !clip || !color) return null;
+ const imageLayers = splitTokensByComma(image);
+ const positionLayers = splitTokensByComma(position);
+ const sizeLayers = splitTokensByComma(size);
+ const repeatLayers = splitTokensByComma(repeat);
+ const attachmentLayers = splitTokensByComma(attachment);
+ const originLayers = splitTokensByComma(origin);
+ const clipLayers = splitTokensByComma(clip);
+ const numLayers = imageLayers.length;
+ if (positionLayers.length !== numLayers || sizeLayers.length !== numLayers || repeatLayers.length !== numLayers || attachmentLayers.length !== numLayers || originLayers.length !== numLayers || clipLayers.length !== numLayers) return null;
+ const layerStrings = [];
+ for (let i = 0; i < numLayers; i++) {
+ const imgVal = serialize(imageLayers[i]).trim();
+ const posVal = serialize(positionLayers[i]).trim();
+ const sizeVal = serialize(sizeLayers[i]).trim();
+ const repVal = serialize(repeatLayers[i]).trim();
+ const attVal = serialize(attachmentLayers[i]).trim();
+ const origVal = serialize(originLayers[i]).trim();
+ const clipVal = serialize(clipLayers[i]).trim();
+ const parts = [];
+ if (imgVal !== "none" && imgVal !== "") parts.push(imgVal);
+ const isInitialPosition = posVal !== "" && [
+ "0% 0%",
+ "left top",
+ "0% center",
+ "center left",
+ "left center"
+ ].includes(posVal.toLowerCase());
+ const isInitialSize = sizeVal !== "" && ["auto", "auto auto"].includes(sizeVal.toLowerCase());
+ if (posVal !== "" && sizeVal !== "") {
+ if (!isInitialSize) parts.push(`${posVal} / ${sizeVal}`);
+ else if (!isInitialPosition) parts.push(posVal);
}
- var cssRule = parsedRules[0];
-
- if (cssRule.constructor.name === 'CSSNestedDeclarations' && cssRule.style.length === 0) {
- errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
+ const isInitialRepeat = repVal !== "" && ["repeat", "repeat repeat"].includes(repVal.toLowerCase());
+ if (repVal !== "" && !isInitialRepeat) {
+ const tokens = repeatLayers[i].filter((t) => t.type !== "whitespace" && t.type !== "EOF");
+ if (tokens.length === 2) {
+ const v0 = tokens[0].value?.toString().toLowerCase();
+ const v1 = tokens[1].value?.toString().toLowerCase();
+ if (v0 === "repeat" && v1 === "no-repeat") parts.push("repeat-x");
+ else if (v0 === "no-repeat" && v1 === "repeat") parts.push("repeat-y");
+ else if (v0 === v1 && v0) parts.push(v0);
+ else parts.push(`${v0} ${v1}`);
+ } else parts.push(repVal);
}
-
- // Check for rules that cannot be inserted inside a CSSGroupingRule
- if (cssRule.constructor.name === 'CSSImportRule' || cssRule.constructor.name === 'CSSNamespaceRule') {
- var ruleKeyword = cssRule.constructor.name === 'CSSImportRule' ? '@import' : '@namespace';
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': " +
- "'" + ruleKeyword + "' rules cannot be inserted inside a group rule.",
- 'HierarchyRequestError');
+ if (attVal !== "" && attVal.toLowerCase() !== "scroll") parts.push(attVal);
+ if (origVal !== "" && clipVal !== "") {
+ const isClipOnly = ["text", "border-area"].includes(clipVal.toLowerCase()) || clipVal.toLowerCase().includes("text") || clipVal.toLowerCase().includes("border-area");
+ const defaultOrigin = isClipOnly ? "border-box" : "padding-box";
+ if (origVal.toLowerCase() !== "padding-box" || clipVal.toLowerCase() !== "border-box") {
+ if (isClipOnly) parts.push(origVal.toLowerCase() === defaultOrigin ? clipVal : `${origVal} ${clipVal}`);
+ else parts.push(origVal.toLowerCase() === clipVal.toLowerCase() ? origVal : `${origVal} ${clipVal}`);
+ }
}
-
- // Check for CSSLayerStatementRule (@layer statement rules)
- if (cssRule.constructor.name === 'CSSLayerStatementRule') {
- errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
+ if (i === numLayers - 1) {
+ const colVal = serialize(color).trim();
+ if (colVal !== "" && colVal.toLowerCase() !== "transparent") parts.push(colVal);
}
-
- cssRule.__parentRule = this;
- this.cssRules.splice(index, 0, cssRule);
- return index;
+ if (parts.length === 0) parts.push("none");
+ layerStrings.push(parts.join(" "));
+ }
+ return layerStrings.join(", ");
+}
+function isValidLengthOrPercentage(val, allowNegative = true) {
+ if (val.type === "ident") {
+ const kw = (val.value ?? "").toString().toLowerCase();
+ return kw === "auto" || CSS_WIDE_KEYWORDS$2.has(kw);
+ }
+ if (val.type === "dimension") {
+ if (!allowNegative && typeof val.value === "number" && val.value < 0) return false;
+ return LENGTH_UNITS.has((val.unit ?? "").toLowerCase());
+ }
+ if (val.type === "percentage") return allowNegative || typeof val.value !== "number" || val.value >= 0;
+ if (val.type === "number" && val.value === 0) return true;
+ if (val.type === "function") {
+ const fnName = getFunctionName(val);
+ return MATH_FUNCTIONS.has(fnName) || fnName === "env";
+ }
+ return false;
+}
+const expandBox = (physical, logical) => (values) => {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0) return null;
+ const isLogical = filtered[0].type === "ident" && filtered[0].value.toLowerCase() === "logical";
+ const data = isLogical ? filtered.slice(1) : filtered;
+ if (data.length < 1 || data.length > 4) return null;
+ const isLengthBox = physical[0].startsWith("margin") || physical[0].startsWith("padding") || physical[0] === "top" || physical[0].startsWith("scroll-") || physical[0].startsWith("border-") && physical[0].endsWith("-width");
+ const allowNegative = !physical[0].startsWith("padding") && !physical[0].startsWith("scroll-padding") && !(physical[0].startsWith("border-") && physical[0].endsWith("-width"));
+ if (isLengthBox && !data.every((v) => isValidLengthOrPercentage(v, allowNegative))) return null;
+ const target = isLogical ? logical : physical;
+ const [s0, s1, s2, s3] = expandFourSides(data);
+ return {
+ [target[0]]: s0,
+ [target[1]]: s1,
+ [target[2]]: s2,
+ [target[3]]: s3
};
-
- /**
- * Used to delete a rule from the grouping rule.
- *
- * cssGroupingRule.cssText
- * -> "img{border:none;}body{margin:0;}"
- * cssGroupingRule.deleteRule(0)
- * cssGroupingRule.cssText
- * -> "body{margin:0;}"
- *
- * @param {number} index within the grouping rule's rule list of the rule to remove.
- * @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-deleterule
- */
- CSSOM.CSSGroupingRule.prototype.deleteRule = function deleteRule(index) {
- if (index === undefined) {
- errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
- }
- index = Number(index);
- if (index < 0) {
- index = 4294967296 + index;
- }
- if (index >= this.cssRules.length) {
- errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
- }
- this.cssRules[index].__parentRule = null;
- this.cssRules[index].__parentStyleSheet = null;
- this.cssRules.splice(index, 1);
+};
+const contractBox = (physical, logical) => (values) => {
+ const t = values[physical[0]];
+ const r = values[physical[1]];
+ const b = values[physical[2]];
+ const l = values[physical[3]];
+ if (t && r && b && l) {
+ const serialized = [
+ t,
+ r,
+ b,
+ l
+ ].map((v) => serialize(v).trim());
+ const cssWide = checkUniformCssWide(serialized);
+ if (cssWide !== void 0) return cssWide;
+ return formatFourSides(serialized[0], serialized[1], serialized[2], serialized[3]);
+ }
+ const lbs = values[logical[0]];
+ const lbe = values[logical[2]];
+ const lis = values[logical[1]];
+ const lie = values[logical[3]];
+ if (lbs && lbe && lis && lie) {
+ const [sbs, sis, sbe, sie] = [
+ lbs,
+ lis,
+ lbe,
+ lie
+ ].map((v) => serialize(v).trim());
+ const cssWide = checkUniformCssWide([
+ sbs,
+ sis,
+ sbe,
+ sie
+ ]);
+ if (cssWide !== void 0) return cssWide;
+ return `logical ${formatFourSides(sbs, sis, sbe, sie)}`;
+ }
+ return null;
+};
+const expandTwoValue = (longhands) => (values) => {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length < 1 || filtered.length > 2) return null;
+ if (longhands[0].startsWith("padding") || longhands[0].endsWith("-width")) {
+ for (const v of filtered) if ((v.type === "dimension" || v.type === "percentage" || v.type === "number") && typeof v.value === "number" && v.value < 0) return null;
+ }
+ return {
+ [longhands[0]]: [filtered[0]],
+ [longhands[1]]: filtered.length > 1 ? [filtered[1]] : [filtered[0]]
};
-
- //.CommonJS
- CSSGroupingRule.CSSGroupingRule = CSSOM.CSSGroupingRule;
- ///CommonJS
- return CSSGroupingRule;
+};
+const contractTwoValue = (longhands) => (values) => {
+ const v1 = values[longhands[0]];
+ const v2 = values[longhands[1]];
+ if (!v1 || !v2) return null;
+ const s1 = serialize(v1).trim();
+ const s2 = serialize(v2).trim();
+ const cssWide = checkUniformCssWide([s1, s2]);
+ if (cssWide !== void 0) return cssWide;
+ return s1 === s2 ? s1 : `${s1} ${s2}`;
+};
+function formatBorderSideValue(widthVal, styleVal, colorVal) {
+ const w = widthVal.trim();
+ const s = styleVal.trim();
+ const c = colorVal.trim();
+ const cssWide = checkUniformCssWide([
+ w,
+ s,
+ c
+ ]);
+ if (cssWide !== void 0) return cssWide;
+ const isInitialWidth = w.toLowerCase() === "medium";
+ const isInitialStyle = s.toLowerCase() === "none";
+ const isInitialColor = c.toLowerCase() === "currentcolor";
+ if (isInitialWidth && isInitialStyle && isInitialColor) return "none";
+ const parts = [];
+ if (!isInitialWidth) parts.push(w);
+ if (!isInitialStyle) parts.push(s);
+ if (!isInitialColor) parts.push(c);
+ return parts.length === 0 ? "none" : parts.join(" ");
}
-
-var hasRequiredCSSStyleRule;
-
-function requireCSSStyleRule () {
- if (hasRequiredCSSStyleRule) return CSSStyleRule;
- hasRequiredCSSStyleRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration,
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule,
+function parseBorderTriplet(filtered, allowAutoStyle = false) {
+ let widthVal = [{
+ type: "ident",
+ value: "medium"
+ }];
+ let styleVal = [{
+ type: "ident",
+ value: "none"
+ }];
+ let colorVal = [{
+ type: "ident",
+ value: "currentcolor"
+ }];
+ for (const val of filtered) if (val.type === "ident") {
+ const v = val.value.toLowerCase();
+ if (BORDER_WIDTH_KEYWORDS.has(v)) widthVal = [val];
+ else if (BORDER_STYLE_KEYWORDS.has(v) || allowAutoStyle && v === "auto") styleVal = [val];
+ else colorVal = [val];
+ } else if (val.type === "dimension" || val.type === "percentage" || val.type === "number") widthVal = [val];
+ else colorVal = [val];
+ return {
+ widthVal,
+ styleVal,
+ colorVal
};
- var regexPatterns = requireRegexPatterns().regexPatterns;
- // Use cssstyle if available
- try {
- CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
- } catch (e) {
- // ignore
- }
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://dev.w3.org/csswg/cssom/#cssstylerule
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleRule
- */
- CSSOM.CSSStyleRule = function CSSStyleRule() {
- CSSOM.CSSGroupingRule.call(this);
- this.__selectorText = "";
- this.__style = new CSSOM.CSSStyleDeclaration();
- this.__style.parentRule = this;
+}
+const BORDER_IMAGE_LONGHANDS = [
+ "border-image-source",
+ "border-image-slice",
+ "border-image-width",
+ "border-image-outset",
+ "border-image-repeat"
+];
+const BORDER_ALL_LONGHANDS = [
+ "border-top-width",
+ "border-right-width",
+ "border-bottom-width",
+ "border-left-width",
+ "border-top-style",
+ "border-right-style",
+ "border-bottom-style",
+ "border-left-style",
+ "border-top-color",
+ "border-right-color",
+ "border-bottom-color",
+ "border-left-color",
+ ...BORDER_IMAGE_LONGHANDS
+];
+function createInitialBorderImageValues(source = [{
+ type: "ident",
+ value: "none"
+}]) {
+ return {
+ "border-image-source": source,
+ "border-image-slice": [{
+ type: "percentage",
+ value: 100,
+ sign: null
+ }],
+ "border-image-width": [{
+ type: "number",
+ value: 1,
+ sign: null,
+ numberType: "integer"
+ }],
+ "border-image-outset": [{
+ type: "number",
+ value: 0,
+ sign: null,
+ numberType: "integer"
+ }],
+ "border-image-repeat": [{
+ type: "ident",
+ value: "stretch"
+ }]
};
-
- CSSOM.CSSStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
- CSSOM.CSSStyleRule.prototype.constructor = CSSOM.CSSStyleRule;
-
- Object.setPrototypeOf(CSSOM.CSSStyleRule, CSSOM.CSSGroupingRule);
-
- Object.defineProperty(CSSOM.CSSStyleRule.prototype, "type", {
- value: 1,
- writable: false
- });
-
- Object.defineProperty(CSSOM.CSSStyleRule.prototype, "selectorText", {
- get: function() {
- return this.__selectorText;
- },
- set: function(value) {
- if (typeof value === "string") {
- // Don't trim if the value ends with a hex escape sequence followed by space
- // (e.g., ".\31 " where the space is part of the escape terminator)
- var endsWithHexEscapeRegExp = regexPatterns.endsWithHexEscapeRegExp;
- var endsWithEscape = endsWithHexEscapeRegExp.test(value);
- var trimmedValue = endsWithEscape ? value.replace(/\s+$/, ' ').trimStart() : value.trim();
-
- if (trimmedValue === '') {
- return;
- }
-
- // TODO: Setting invalid selectorText should be ignored
- // There are some validations already on lib/parse.js
- // but the same validations should be applied here.
- // Check if we can move these validation logic to a shared function.
-
- this.__selectorText = trimmedValue;
- }
- },
- configurable: true
- });
-
- Object.defineProperty(CSSOM.CSSStyleRule.prototype, "style", {
- get: function() {
- return this.__style;
- },
- set: function(value) {
- if (typeof value === "string") {
- this.__style.cssText = value;
- } else {
- this.__style = value;
- }
- },
- configurable: true
- });
-
- Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
- get: function() {
- var text;
- if (this.selectorText) {
- var values = "";
- if (this.cssRules.length) {
- var valuesArr = [" {"];
- this.style.cssText && valuesArr.push(this.style.cssText);
- valuesArr.push(this.cssRules.reduce(function(acc, rule){
- if (rule.cssText !== "") {
- acc.push(rule.cssText);
- }
- return acc;
- }, []).join("\n "));
- values = valuesArr.join("\n ") + "\n}";
- } else {
- values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
- }
- text = this.selectorText + values;
- } else {
- text = "";
- }
- return text;
- }
- });
-
- //.CommonJS
- CSSStyleRule.CSSStyleRule = CSSOM.CSSStyleRule;
- ///CommonJS
- return CSSStyleRule;
}
-
-var hasRequiredCSSStyleSheet;
-
-function requireCSSStyleSheet () {
- if (hasRequiredCSSStyleSheet) return CSSStyleSheet;
- hasRequiredCSSStyleSheet = 1;
- //.CommonJS
- var CSSOM = {
- MediaList: requireMediaList().MediaList,
- StyleSheet: requireStyleSheet().StyleSheet,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- CSSStyleRule: requireCSSStyleRule().CSSStyleRule,
+function isInitialBorderImage(values) {
+ const src = values["border-image-source"];
+ const slice = values["border-image-slice"];
+ const width = values["border-image-width"];
+ const outset = values["border-image-outset"];
+ const repeat = values["border-image-repeat"];
+ if (!src || !slice || !width || !outset || !repeat) return false;
+ const sSrc = serialize(src).trim().toLowerCase();
+ const sSlice = serialize(slice).trim().toLowerCase();
+ const sWidth = serialize(width).trim().toLowerCase();
+ const sOutset = serialize(outset).trim().toLowerCase();
+ const sRepeat = serialize(repeat).trim().toLowerCase();
+ return (sSrc === "none" || sSrc === "") && (sSlice === "100%" || sSlice === "100% 100% 100% 100%" || sSlice === "") && (sWidth === "1" || sWidth === "1 1 1 1" || sWidth === "") && (sOutset === "0" || sOutset === "0px" || sOutset === "0s" || sOutset === "0 0 0 0" || sOutset === "") && (sRepeat === "stretch" || sRepeat === "stretch stretch" || sRepeat === "");
+}
+const expandBorderSide = (prefix) => (values) => {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0 || filtered.length > 3) return null;
+ const longhands = [
+ `${prefix}-width`,
+ `${prefix}-style`,
+ `${prefix}-color`
+ ];
+ const cssWide = tryExpandCssWide(filtered, longhands);
+ if (cssWide) return cssWide;
+ const { widthVal, styleVal, colorVal } = parseBorderTriplet(filtered);
+ return {
+ [longhands[0]]: widthVal,
+ [longhands[1]]: styleVal,
+ [longhands[2]]: colorVal
};
- var errorUtils = requireErrorUtils().errorUtils;
- ///CommonJS
-
-
- /**
- * @constructor
- * @param {CSSStyleSheetInit} [opts] - CSSStyleSheetInit options.
- * @param {string} [opts.baseURL] - The base URL of the stylesheet.
- * @param {boolean} [opts.disabled] - The disabled attribute of the stylesheet.
- * @param {MediaList | string} [opts.media] - The media attribute of the stylesheet.
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
- */
- CSSOM.CSSStyleSheet = function CSSStyleSheet(opts) {
- CSSOM.StyleSheet.call(this);
- this.__constructed = true;
- this.__cssRules = new CSSOM.CSSRuleList();
- this.__ownerRule = null;
-
- if (opts && typeof opts === "object") {
- if (opts.baseURL && typeof opts.baseURL === "string") {
- this.__baseURL = opts.baseURL;
- }
- if (opts.media && typeof opts.media === "string") {
- this.media.mediaText = opts.media;
- }
- if (typeof opts.disabled === "boolean") {
- this.disabled = opts.disabled;
- }
- }
+};
+const contractBorderSide = (prefix) => (values) => {
+ const w = values[`${prefix}-width`];
+ const s = values[`${prefix}-style`];
+ const c = values[`${prefix}-color`];
+ if (!w || !s || !c) return null;
+ return formatBorderSideValue(serialize(w), serialize(s), serialize(c));
+};
+function expandBorder(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0 || filtered.length > 3) return null;
+ const cssWide = tryExpandCssWide(filtered, BORDER_ALL_LONGHANDS);
+ if (cssWide) return cssWide;
+ const { widthVal, styleVal, colorVal } = parseBorderTriplet(filtered);
+ return {
+ "border-top-width": widthVal,
+ "border-right-width": widthVal,
+ "border-bottom-width": widthVal,
+ "border-left-width": widthVal,
+ "border-top-style": styleVal,
+ "border-right-style": styleVal,
+ "border-bottom-style": styleVal,
+ "border-left-style": styleVal,
+ "border-top-color": colorVal,
+ "border-right-color": colorVal,
+ "border-bottom-color": colorVal,
+ "border-left-color": colorVal,
+ ...createInitialBorderImageValues()
};
-
-
- CSSOM.CSSStyleSheet.prototype = Object.create(CSSOM.StyleSheet.prototype);
- CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
-
- Object.setPrototypeOf(CSSOM.CSSStyleSheet, CSSOM.StyleSheet);
-
- Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "cssRules", {
- get: function() {
- return this.__cssRules;
- }
- });
-
- Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "rules", {
- get: function() {
- return this.__cssRules;
- }
- });
-
- Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "ownerRule", {
- get: function() {
- return this.__ownerRule;
- }
- });
-
- /**
- * Used to insert a new rule into the style sheet. The new rule now becomes part of the cascade.
- *
- * sheet = new Sheet("body {margin: 0}")
- * sheet.toString()
- * -> "body{margin:0;}"
- * sheet.insertRule("img {border: none}", 0)
- * -> 0
- * sheet.toString()
- * -> "img{border:none;}body{margin:0;}"
- *
- * @param {string} rule
- * @param {number} [index=0]
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-insertRule
- * @return {number} The index within the style sheet's rule collection of the newly inserted rule.
- */
- CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
- if (rule === undefined && index === undefined) {
- errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
- }
- if (index === void 0) {
- index = 0;
- }
- index = Number(index);
- if (index < 0) {
- index = 4294967296 + index;
- }
- if (index > this.cssRules.length) {
- errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
- }
-
- var ruleToParse = String(rule);
- var parseErrors = [];
- var parsedSheet = CSSOM.parse(ruleToParse, undefined, function(err) {
- parseErrors.push(err);
- } );
- if (parsedSheet.cssRules.length !== 1) {
- errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
- }
- var cssRule = parsedSheet.cssRules[0];
-
- // Helper function to find the first index of a rule that's NOT of specified constructors
- function findFirstNonConstructorIndex(rules, constructorNames) {
- for (var i = 0; i < rules.length; i++) {
- if (constructorNames.indexOf(rules[i].constructor.name) === -1) {
- return i;
- }
- }
- return rules.length;
- }
-
- // Validate rule ordering based on CSS specification
- if (cssRule.constructor.name === 'CSSImportRule') {
- if (this.__constructed === true) {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': Can't insert @import rules into a constructed stylesheet.",
- 'SyntaxError');
- }
- // @import rules cannot be inserted after @layer rules that already exist
- // They can only be inserted at the beginning or after other @import rules
- var firstLayerIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
- if (firstLayerIndex < this.cssRules.length && this.cssRules[firstLayerIndex].constructor.name === 'CSSLayerStatementRule' && index > firstLayerIndex) {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
- 'HierarchyRequestError');
- }
-
- // Also cannot insert after @namespace or other rules
- var firstNonImportIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
- if (index > firstNonImportIndex && firstNonImportIndex < this.cssRules.length &&
- this.cssRules[firstNonImportIndex].constructor.name !== 'CSSLayerStatementRule') {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
- 'HierarchyRequestError');
- }
- } else if (cssRule.constructor.name === 'CSSNamespaceRule') {
- // @namespace rules can come after @layer and @import, but before any other rules
- // They cannot come before @import rules
- var firstImportIndex = -1;
- for (var i = 0; i < this.cssRules.length; i++) {
- if (this.cssRules[i].constructor.name === 'CSSImportRule') {
- firstImportIndex = i;
- break;
- }
- }
- var firstNonImportNamespaceIndex = findFirstNonConstructorIndex(this.cssRules, [
- 'CSSLayerStatementRule',
- 'CSSImportRule',
- 'CSSNamespaceRule'
- ]);
-
- // Cannot insert before @import rules
- if (firstImportIndex !== -1 && index <= firstImportIndex) {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
- 'HierarchyRequestError');
- }
-
- // Cannot insert if there are already non-special rules
- if (firstNonImportNamespaceIndex < this.cssRules.length) {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
- 'InvalidStateError');
- }
-
- // Cannot insert after other types of rules
- if (index > firstNonImportNamespaceIndex) {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
- 'HierarchyRequestError');
- }
-
-
- } else if (cssRule.constructor.name === 'CSSLayerStatementRule') ; else {
- // Any other rule cannot be inserted before @import and @namespace
- var firstNonSpecialRuleIndex = findFirstNonConstructorIndex(this.cssRules, [
- 'CSSLayerStatementRule',
- 'CSSImportRule',
- 'CSSNamespaceRule'
- ]);
-
- if (index < firstNonSpecialRuleIndex) {
- errorUtils.throwError(this, 'DOMException',
- "Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
- 'HierarchyRequestError');
- }
-
- if (parseErrors.filter(function(error) { return !error.isNested; }).length !== 0) {
- errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
- }
- }
-
- cssRule.__parentStyleSheet = this;
- this.cssRules.splice(index, 0, cssRule);
- return index;
+}
+function contractBorder(values) {
+ for (const lh of BORDER_ALL_LONGHANDS) if (!values[lh]) return null;
+ const allSerialized = BORDER_ALL_LONGHANDS.map((lh) => serialize(values[lh]).trim());
+ const cssWide = checkUniformCssWide(allSerialized);
+ if (cssWide !== void 0) return cssWide;
+ if (!isInitialBorderImage(values)) return null;
+ const [w0, w1, w2, w3, s0, s1, s2, s3, c0, c1, c2, c3] = allSerialized;
+ if (w0 !== w1 || w0 !== w2 || w0 !== w3) return null;
+ if (s0 !== s1 || s0 !== s2 || s0 !== s3) return null;
+ if (c0 !== c1 || c0 !== c2 || c0 !== c3) return null;
+ return formatBorderSideValue(w0, s0, c0);
+}
+function expandBorderImage(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0) return null;
+ const cssWide = tryExpandCssWide(filtered, BORDER_IMAGE_LONGHANDS);
+ if (cssWide) return cssWide;
+ if (filtered.length === 1 && filtered[0].type === "ident" && filtered[0].value.toLowerCase() === "none") return createInitialBorderImageValues();
+ if (filtered.some((t) => t.type === "function" && getFunctionName(t) === "var")) return expandUniformLonghands(BORDER_IMAGE_LONGHANDS, values);
+ let source = [{
+ type: "ident",
+ value: "none"
+ }];
+ for (const token of filtered) if (token.type === "url" || token.type === "function" && [
+ "linear-gradient",
+ "radial-gradient",
+ "conic-gradient",
+ "image",
+ "image-set"
+ ].includes(getFunctionName(token))) source = [token];
+ return createInitialBorderImageValues(source);
+}
+function contractBorderImage(values) {
+ for (const lh of BORDER_IMAGE_LONGHANDS) if (!values[lh]) return null;
+ const allVals = BORDER_IMAGE_LONGHANDS.map((lh) => serialize(values[lh]).trim());
+ const cssWide = checkUniformCssWide(allVals, true);
+ if (cssWide !== void 0) return cssWide;
+ if (isInitialBorderImage(values)) return "none";
+ const [sSrc, sSlice, sWidth, sOutset, sRepeat] = allVals;
+ return (sSlice === "100%" || sSlice === "100% 100% 100% 100%") && (sWidth === "1" || sWidth === "1 1 1 1") && (sOutset === "0" || sOutset === "0px" || sOutset === "0s" || sOutset === "0 0 0 0") && (sRepeat === "stretch" || sRepeat === "stretch stretch") ? sSrc : null;
+}
+function expandOutline(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0 || filtered.length > 3) return null;
+ const cssWide = tryExpandCssWide(filtered, [
+ "outline-color",
+ "outline-style",
+ "outline-width"
+ ]);
+ if (cssWide) return cssWide;
+ const { widthVal, styleVal, colorVal } = parseBorderTriplet(filtered, true);
+ return {
+ "outline-color": colorVal,
+ "outline-style": styleVal,
+ "outline-width": widthVal
};
-
- CSSOM.CSSStyleSheet.prototype.addRule = function(selector, styleBlock, index) {
- if (index === void 0) {
- index = this.cssRules.length;
+}
+function contractOutline(values) {
+ const c = values["outline-color"];
+ const s = values["outline-style"];
+ const w = values["outline-width"];
+ if (!c || !s || !w) return null;
+ const sc = serialize(c).trim();
+ const ss = serialize(s).trim();
+ const sw = serialize(w).trim();
+ const cssWide = checkUniformCssWide([
+ sc,
+ ss,
+ sw
+ ]);
+ if (cssWide !== void 0) return cssWide;
+ const isInitialColor = sc.toLowerCase() === "currentcolor";
+ const isInitialStyle = ss.toLowerCase() === "none";
+ const isInitialWidth = sw.toLowerCase() === "medium";
+ if (isInitialColor && isInitialStyle && isInitialWidth) return "none";
+ const parts = [];
+ if (!isInitialColor) parts.push(sc);
+ if (!isInitialStyle) parts.push(ss);
+ if (!isInitialWidth) parts.push(sw);
+ return parts.length === 0 ? "none" : parts.join(" ");
+}
+const FONT_VARIANT_LONGHANDS = [
+ "font-variant-ligatures",
+ "font-variant-caps",
+ "font-variant-alternates",
+ "font-variant-numeric",
+ "font-variant-east-asian",
+ "font-variant-position",
+ "font-variant-emoji"
+];
+function expandFontVariant(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0) return null;
+ const wide = tryExpandCssWide(filtered, FONT_VARIANT_LONGHANDS);
+ if (wide) return wide;
+ if (filtered.length === 1 && filtered[0].type === "ident") {
+ const v = filtered[0].value.toLowerCase();
+ if (v === "normal") return expandUniformLonghands(FONT_VARIANT_LONGHANDS, [{
+ type: "ident",
+ value: "normal"
+ }]);
+ if (v === "none") {
+ const res = expandUniformLonghands(FONT_VARIANT_LONGHANDS, [{
+ type: "ident",
+ value: "normal"
+ }]);
+ res["font-variant-ligatures"] = [{
+ type: "ident",
+ value: "none"
+ }];
+ return res;
}
- this.insertRule(selector + "{" + styleBlock + "}", index);
- return -1;
+ }
+ const buckets = {
+ "font-variant-ligatures": [],
+ "font-variant-caps": [],
+ "font-variant-alternates": [],
+ "font-variant-numeric": [],
+ "font-variant-east-asian": [],
+ "font-variant-position": [],
+ "font-variant-emoji": []
};
-
- /**
- * Used to delete a rule from the style sheet.
- *
- * sheet = new Sheet("img{border:none} body{margin:0}")
- * sheet.toString()
- * -> "img{border:none;}body{margin:0;}"
- * sheet.deleteRule(0)
- * sheet.toString()
- * -> "body{margin:0;}"
- *
- * @param {number} index within the style sheet's rule list of the rule to remove.
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-deleteRule
- */
- CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
- if (index === undefined) {
- errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
- }
- index = Number(index);
- if (index < 0) {
- index = 4294967296 + index;
- }
- if (index >= this.cssRules.length) {
- errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
- }
- if (this.cssRules[index]) {
- if (this.cssRules[index].constructor.name == "CSSNamespaceRule") {
- var shouldContinue = this.cssRules.every(function (rule) {
- return ['CSSImportRule','CSSLayerStatementRule','CSSNamespaceRule'].indexOf(rule.constructor.name) !== -1
- });
- if (!shouldContinue) {
- errorUtils.throwError(this, 'DOMException', "Failed to execute 'deleteRule' on '" + this.constructor.name + "': Failed to delete rule.", "InvalidStateError");
- }
+ for (const token of filtered) if (token.type === "ident") {
+ const val = token.value.toLowerCase();
+ if (val === "normal") continue;
+ if (val === "none" || FONT_VARIANT_LIGATURES_KEYWORDS.has(val)) buckets["font-variant-ligatures"].push(token);
+ else if (FONT_VARIANT_CAPS_KEYWORDS.has(val)) buckets["font-variant-caps"].push(token);
+ else if (val === "historical-forms") buckets["font-variant-alternates"].push(token);
+ else if (FONT_VARIANT_NUMERIC_KEYWORDS.has(val)) buckets["font-variant-numeric"].push(token);
+ else if (FONT_VARIANT_EAST_ASIAN_KEYWORDS.has(val)) buckets["font-variant-east-asian"].push(token);
+ else if (FONT_VARIANT_POSITION_KEYWORDS.has(val)) buckets["font-variant-position"].push(token);
+ else if (FONT_VARIANT_EMOJI_KEYWORDS.has(val)) buckets["font-variant-emoji"].push(token);
+ else return null;
+ } else if (token.type === "function" && FONT_VARIANT_ALTERNATES_FUNCTIONS.has(getFunctionName(token))) buckets["font-variant-alternates"].push(token);
+ else return null;
+ const norm = [{
+ type: "ident",
+ value: "normal"
+ }];
+ const res = {};
+ for (const lh of FONT_VARIANT_LONGHANDS) res[lh] = buckets[lh].length > 0 ? joinWithWhitespace(buckets[lh]) : norm;
+ return res;
+}
+function contractFontVariant(values) {
+ for (const lh of FONT_VARIANT_LONGHANDS) if (!values[lh]) return null;
+ const allVals = FONT_VARIANT_LONGHANDS.map((lh) => serialize(values[lh]).trim());
+ const wide = checkUniformCssWide(allVals);
+ if (wide !== void 0) return wide;
+ if (allVals.every((v) => v.toLowerCase() === "normal")) return "normal";
+ if (allVals[0].toLowerCase() === "none") return allVals.slice(1).every((v) => v.toLowerCase() === "normal") ? "none" : null;
+ const nonNormal = allVals.filter((v) => v.toLowerCase() !== "normal");
+ return nonNormal.length === 0 ? "normal" : nonNormal.join(" ");
+}
+const FONT_LONGHANDS = [
+ "font-style",
+ "font-variant-caps",
+ "font-variant-ligatures",
+ "font-variant-alternates",
+ "font-variant-numeric",
+ "font-variant-east-asian",
+ "font-variant-position",
+ "font-variant-emoji",
+ "font-weight",
+ "font-stretch",
+ "font-size",
+ "line-height",
+ "font-family"
+];
+function expandFont(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0) return null;
+ if (filtered.length === 1 && filtered[0].type === "ident" && SYSTEM_FONT_KEYWORDS.has(filtered[0].value.toLowerCase())) return expandUniformLonghands(FONT_LONGHANDS, [filtered[0]]);
+ const norm = [{
+ type: "ident",
+ value: "normal"
+ }];
+ let styleVal = norm;
+ let capsVal = norm;
+ let weightVal = norm;
+ let stretchVal = norm;
+ let lineHeightVal = norm;
+ let i = 0;
+ while (i < filtered.length) {
+ const token = filtered[i];
+ if (token.type === "ident") {
+ const v = token.value.toLowerCase();
+ if (v === "italic" || v === "oblique") {
+ styleVal = [token];
+ i++;
+ continue;
}
- if (this.cssRules[index].constructor.name == "CSSImportRule") {
- this.cssRules[index].styleSheet.__parentStyleSheet = null;
+ if (v === "small-caps") {
+ capsVal = [token];
+ i++;
+ continue;
}
-
- this.cssRules[index].__parentStyleSheet = null;
- }
- this.cssRules.splice(index, 1);
- };
-
- CSSOM.CSSStyleSheet.prototype.removeRule = function(index) {
- if (index === void 0) {
- index = 0;
- }
- this.deleteRule(index);
- };
-
-
- /**
- * Replaces the rules of a {@link CSSStyleSheet}
- *
- * @returns a promise
- * @see https://www.w3.org/TR/cssom-1/#dom-cssstylesheet-replace
- */
- CSSOM.CSSStyleSheet.prototype.replace = function(text) {
- var _Promise;
- if (this.__globalObject && this.__globalObject['Promise']) {
- _Promise = this.__globalObject['Promise'];
- } else {
- _Promise = Promise;
- }
- var _setTimeout;
- if (this.__globalObject && this.__globalObject['setTimeout']) {
- _setTimeout = this.__globalObject['setTimeout'];
- } else {
- _setTimeout = setTimeout;
- }
- var sheet = this;
- return new _Promise(function (resolve, reject) {
- // If the constructed flag is not set, or the disallow modification flag is set, throw a NotAllowedError DOMException.
- if (!sheet.__constructed || sheet.__disallowModification) {
- reject(errorUtils.createError(sheet, 'DOMException',
- "Failed to execute 'replaceSync' on '" + sheet.constructor.name + "': Not allowed.",
- 'NotAllowedError'));
+ if (v === "bold" || v === "bolder" || v === "lighter") {
+ weightVal = [token];
+ i++;
+ continue;
}
- // Set the disallow modification flag.
- sheet.__disallowModification = true;
-
- // In parallel, do these steps:
- _setTimeout(function() {
- // Let rules be the result of running parse a stylesheet's contents from text.
- var rules = new CSSOM.CSSRuleList();
- CSSOM.parse(text, { styleSheet: sheet, cssRules: rules });
- // If rules contains one or more @import rules, remove those rules from rules.
- var i = 0;
- while (i < rules.length) {
- if (rules[i].constructor.name === 'CSSImportRule') {
- rules.splice(i, 1);
- } else {
- i++;
- }
- }
- // Set sheet's CSS rules to rules.
- sheet.__cssRules.splice.apply(sheet.__cssRules, [0, sheet.__cssRules.length].concat(rules));
- // Unset sheet’s disallow modification flag.
- delete sheet.__disallowModification;
- // Resolve promise with sheet.
- resolve(sheet);
- });
- });
- };
-
- /**
- * Synchronously replaces the rules of a {@link CSSStyleSheet}
- *
- * @see https://www.w3.org/TR/cssom-1/#dom-cssstylesheet-replacesync
- */
- CSSOM.CSSStyleSheet.prototype.replaceSync = function(text) {
- var sheet = this;
- // If the constructed flag is not set, or the disallow modification flag is set, throw a NotAllowedError DOMException.
- if (!sheet.__constructed || sheet.__disallowModification) {
- errorUtils.throwError(sheet, 'DOMException',
- "Failed to execute 'replaceSync' on '" + sheet.constructor.name + "': Not allowed.",
- 'NotAllowedError');
- }
- // Let rules be the result of running parse a stylesheet's contents from text.
- var rules = new CSSOM.CSSRuleList();
- CSSOM.parse(text, { styleSheet: sheet, cssRules: rules });
- // If rules contains one or more @import rules, remove those rules from rules.
- var i = 0;
- while (i < rules.length) {
- if (rules[i].constructor.name === 'CSSImportRule') {
- rules.splice(i, 1);
- } else {
+ if (FONT_STRETCH_KEYWORDS.has(v)) {
+ stretchVal = [token];
i++;
+ continue;
}
+ if (v === "normal") {
+ i++;
+ continue;
+ }
+ } else if (token.type === "number" && typeof token.value === "number" && token.value >= 1 && token.value <= 1e3) {
+ weightVal = [token];
+ i++;
+ continue;
}
- // Set sheet's CSS rules to rules.
- sheet.__cssRules.splice.apply(sheet.__cssRules, [0, sheet.__cssRules.length].concat(rules));
- };
-
- /**
- * NON-STANDARD
- * @return {string} serialize stylesheet
- */
- CSSOM.CSSStyleSheet.prototype.toString = function() {
- var result = "";
- var rules = this.cssRules;
- for (var i=0; i= filtered.length) return null;
+ const sizeToken = filtered[i];
+ if (!(sizeToken.type === "dimension" || sizeToken.type === "percentage" || sizeToken.type === "number" && sizeToken.value === 0 || sizeToken.type === "ident" && FONT_SIZE_KEYWORDS.has(sizeToken.value.toLowerCase()) || sizeToken.type === "function" && MATH_FUNCTIONS.has(getFunctionName(sizeToken)))) return null;
+ const sizeVal = [sizeToken];
+ i++;
+ if (i < filtered.length && filtered[i].type === "delim" && filtered[i].value === "/") {
+ i++;
+ if (i >= filtered.length) return null;
+ const lhToken = filtered[i];
+ if (!(lhToken.type === "number" || lhToken.type === "dimension" || lhToken.type === "percentage" || lhToken.type === "ident" && lhToken.value.toLowerCase() === "normal" || lhToken.type === "function" && MATH_FUNCTIONS.has(getFunctionName(lhToken)))) return null;
+ lineHeightVal = [lhToken];
+ i++;
+ }
+ if (i >= filtered.length) return null;
+ const lastConsumed = lineHeightVal !== norm ? lineHeightVal[0] : sizeToken;
+ const lastIdx = values.indexOf(lastConsumed);
+ let familyVal;
+ if (lastIdx !== -1) {
+ familyVal = values.slice(lastIdx + 1).filter((t) => t.type !== "EOF");
+ while (familyVal.length > 0 && (familyVal[0].type === "whitespace" || familyVal[0].type === "comment")) familyVal.shift();
+ } else familyVal = filtered.slice(i);
+ const res = expandUniformLonghands(FONT_LONGHANDS, norm);
+ res["font-style"] = styleVal;
+ res["font-variant-caps"] = capsVal;
+ res["font-weight"] = weightVal;
+ res["font-stretch"] = stretchVal;
+ res["font-size"] = sizeVal;
+ res["line-height"] = lineHeightVal;
+ res["font-family"] = familyVal;
+ return res;
+}
+const FONT_PRIMARY_LONGHANDS = [
+ "font-style",
+ "font-variant-caps",
+ "font-weight",
+ "font-stretch",
+ "font-size",
+ "line-height",
+ "font-family"
+];
+const FONT_OTHER_VARIANTS = [
+ "font-variant-ligatures",
+ "font-variant-alternates",
+ "font-variant-numeric",
+ "font-variant-east-asian",
+ "font-variant-position",
+ "font-variant-emoji"
+];
+function contractFont(values) {
+ for (const lh of FONT_PRIMARY_LONGHANDS) if (!values[lh]) return null;
+ for (const lh of FONT_OTHER_VARIANTS) if (values[lh] && serialize(values[lh]).trim().toLowerCase() !== "normal") return null;
+ const sStyle = serialize(values["font-style"]).trim();
+ const sCaps = serialize(values["font-variant-caps"]).trim();
+ const sWeight = serialize(values["font-weight"]).trim();
+ const sStretch = serialize(values["font-stretch"]).trim();
+ const sSize = serialize(values["font-size"]).trim();
+ const sLineHeight = serialize(values["line-height"]).trim();
+ const sFamily = serialize(values["font-family"], false, "font-family").trim();
+ const wide = checkUniformCssWide([
+ sStyle,
+ sCaps,
+ sWeight,
+ sStretch,
+ sSize,
+ sLineHeight,
+ sFamily
+ ]);
+ if (wide !== void 0) return wide;
+ if (!sSize || !sFamily) return null;
+ const parts = [];
+ if (sStyle.toLowerCase() !== "normal") parts.push(sStyle);
+ if (sCaps.toLowerCase() !== "normal") parts.push(sCaps);
+ if (sWeight.toLowerCase() !== "normal" && sWeight !== "400") parts.push(sWeight);
+ if (sStretch.toLowerCase() !== "normal") parts.push(sStretch);
+ parts.push(sLineHeight.toLowerCase() !== "normal" ? `${sSize} / ${sLineHeight}` : sSize);
+ parts.push(sFamily);
+ return parts.join(" ");
+}
+const LIST_STYLE_LONGHANDS = [
+ "list-style-type",
+ "list-style-position",
+ "list-style-image"
+];
+function expandListStyle(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0 || filtered.length > 3) return null;
+ const wide = tryExpandCssWide(filtered, LIST_STYLE_LONGHANDS);
+ if (wide) return wide;
+ let typeVal = [{
+ type: "ident",
+ value: "disc"
+ }];
+ let posVal = [{
+ type: "ident",
+ value: "outside"
+ }];
+ let imgVal = [{
+ type: "ident",
+ value: "none"
+ }];
+ let hasType = false;
+ let hasPos = false;
+ let hasImg = false;
+ for (const token of filtered) if (token.type === "ident") {
+ const v = token.value.toLowerCase();
+ if ((v === "inside" || v === "outside") && !hasPos) {
+ posVal = [token];
+ hasPos = true;
+ } else if (v === "none") {
+ if (!hasImg && !hasType) {
+ imgVal = [token];
+ typeVal = [token];
+ hasImg = true;
+ hasType = true;
+ } else if (!hasImg) {
+ imgVal = [token];
+ hasImg = true;
+ } else if (!hasType) {
+ typeVal = [token];
+ hasType = true;
+ }
+ } else if (!hasType) {
+ typeVal = [token];
+ hasType = true;
+ } else return null;
+ } else if ((token.type === "url" || token.type === "function" && IMAGE_FUNCTIONS.has(getFunctionName(token))) && !hasImg) {
+ imgVal = [token];
+ hasImg = true;
+ } else return null;
+ return {
+ "list-style-type": typeVal,
+ "list-style-position": posVal,
+ "list-style-image": imgVal
};
-
-
- //.CommonJS
- CSSStyleSheet.CSSStyleSheet = CSSOM.CSSStyleSheet;
- CSSOM.parse = requireParse().parse; // Cannot be included sooner due to the mutual dependency between parse.js and CSSStyleSheet.js
- ///CommonJS
- return CSSStyleSheet;
}
-
-var CSSNestedDeclarations = {};
-
-var hasRequiredCSSNestedDeclarations;
-
-function requireCSSNestedDeclarations () {
- if (hasRequiredCSSNestedDeclarations) return CSSNestedDeclarations;
- hasRequiredCSSNestedDeclarations = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration
+function contractListStyle(values) {
+ const t = values["list-style-type"];
+ const p = values["list-style-position"];
+ const i = values["list-style-image"];
+ if (!t || !p || !i) return null;
+ const st = serialize(t).trim();
+ const sp = serialize(p).trim();
+ const si = serialize(i).trim();
+ const wide = checkUniformCssWide([
+ st,
+ sp,
+ si
+ ]);
+ if (wide !== void 0) return wide;
+ const parts = [];
+ if (sp.toLowerCase() !== "outside") parts.push(sp);
+ if (si.toLowerCase() !== "none") parts.push(si);
+ if (st.toLowerCase() !== "disc") parts.push(st);
+ return parts.length === 0 ? "disc" : parts.join(" ");
+}
+const FLEX_LONGHANDS = [
+ "flex-grow",
+ "flex-shrink",
+ "flex-basis"
+];
+function expandFlex(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0 || filtered.length > 3) return null;
+ const wide = tryExpandCssWide(filtered, FLEX_LONGHANDS);
+ if (wide) return wide;
+ if (filtered.length === 1 && filtered[0].type === "ident") {
+ const v = filtered[0].value.toLowerCase();
+ if (v === "none") return {
+ "flex-grow": [{
+ type: "number",
+ value: 0,
+ sign: null,
+ numberType: "integer"
+ }],
+ "flex-shrink": [{
+ type: "number",
+ value: 0,
+ sign: null,
+ numberType: "integer"
+ }],
+ "flex-basis": [{
+ type: "ident",
+ value: "auto"
+ }]
+ };
+ if (v === "auto") return {
+ "flex-grow": [{
+ type: "number",
+ value: 1,
+ sign: null,
+ numberType: "integer"
+ }],
+ "flex-shrink": [{
+ type: "number",
+ value: 1,
+ sign: null,
+ numberType: "integer"
+ }],
+ "flex-basis": [{
+ type: "ident",
+ value: "auto"
+ }]
+ };
+ }
+ let grow = null;
+ let shrink = null;
+ let basis = null;
+ for (const token of filtered) if (token.type === "number") {
+ if (grow === null) grow = [token];
+ else if (shrink === null) shrink = [token];
+ else return null;
+ } else if (isValidLengthOrPercentage(token) || token.type === "ident" && FLEX_BASIS_KEYWORDS.has(token.value.toLowerCase())) {
+ if (basis === null) basis = [token];
+ else return null;
+ } else return null;
+ if (grow === null && basis === null) return null;
+ const one = [{
+ type: "number",
+ value: 1,
+ sign: null,
+ numberType: "integer"
+ }];
+ return {
+ "flex-grow": grow ?? one,
+ "flex-shrink": shrink ?? one,
+ "flex-basis": basis ?? (grow !== null ? [{
+ type: "dimension",
+ value: 0,
+ unit: "px",
+ sign: null,
+ numberType: "integer"
+ }] : [{
+ type: "ident",
+ value: "auto"
+ }])
};
- // Use cssstyle if available
- try {
- CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
- } catch (e) {
- // ignore
+}
+function contractFlex(values) {
+ const g = values["flex-grow"];
+ const s = values["flex-shrink"];
+ const b = values["flex-basis"];
+ if (!g || !s || !b) return null;
+ const sg = serialize(g).trim();
+ const ss = serialize(s).trim();
+ const sb = serialize(b).trim();
+ const wide = checkUniformCssWide([
+ sg,
+ ss,
+ sb
+ ]);
+ if (wide !== void 0) return wide;
+ if (sg.includes("var(") || ss.includes("var(") || sb.includes("var(")) return sg === ss && sg === sb ? sg : null;
+ if (sb.toLowerCase() === "auto") {
+ if (sg === "0" && ss === "1") return "initial";
+ if (sg === "1" && ss === "1") return "auto";
+ if (sg === "0" && ss === "0") return "none";
}
- ///CommonJS
-
-
- /**
- * @constructor
- * @see https://drafts.csswg.org/css-nesting-1/
- */
- CSSOM.CSSNestedDeclarations = function CSSNestedDeclarations() {
- CSSOM.CSSRule.call(this);
- this.__style = new CSSOM.CSSStyleDeclaration();
- this.__style.parentRule = this;
- };
-
- CSSOM.CSSNestedDeclarations.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSNestedDeclarations.prototype.constructor = CSSOM.CSSNestedDeclarations;
-
- Object.setPrototypeOf(CSSOM.CSSNestedDeclarations, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "type", {
- value: 0,
- writable: false
- });
-
- Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "style", {
- get: function() {
- return this.__style;
- },
- set: function(value) {
- if (typeof value === "string") {
- this.__style.cssText = value;
- } else {
- this.__style = value;
- }
- }
- });
-
- Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "cssText", {
- get: function () {
- return this.style.cssText;
- }
- });
-
- //.CommonJS
- CSSNestedDeclarations.CSSNestedDeclarations = CSSOM.CSSNestedDeclarations;
- ///CommonJS
- return CSSNestedDeclarations;
+ if ((sb === "0px" || sb === "0%" || sb === "0") && ss === "1") return `${sg} 1 0px`;
+ return `${sg} ${ss} ${sb}`;
}
-
-var CSSImportRule = {};
-
-var hasRequiredCSSImportRule;
-
-function requireCSSImportRule () {
- if (hasRequiredCSSImportRule) return CSSImportRule;
- hasRequiredCSSImportRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSStyleSheet: requireCSSStyleSheet().CSSStyleSheet,
- MediaList: requireMediaList().MediaList
- };
- var regexPatterns = requireRegexPatterns().regexPatterns;
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://dev.w3.org/csswg/cssom/#cssimportrule
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSImportRule
- */
- CSSOM.CSSImportRule = function CSSImportRule() {
- CSSOM.CSSRule.call(this);
- this.__href = "";
- this.__media = new CSSOM.MediaList();
- this.__layerName = null;
- this.__supportsText = null;
- this.__styleSheet = new CSSOM.CSSStyleSheet();
- };
-
- CSSOM.CSSImportRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSImportRule.prototype.constructor = CSSOM.CSSImportRule;
-
- Object.setPrototypeOf(CSSOM.CSSImportRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "type", {
- value: 3,
- writable: false
- });
-
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
- get: function() {
- var mediaText = this.media.mediaText;
- return "@import url(\"" + this.href.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + "\")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
- }
- });
-
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "href", {
- get: function() {
- return this.__href;
- }
- });
-
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "media", {
- get: function() {
- return this.__media;
- },
- set: function(value) {
- if (typeof value === "string") {
- this.__media.mediaText = value;
- } else {
- this.__media = value;
- }
- }
- });
-
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "layerName", {
- get: function() {
- return this.__layerName;
- }
- });
-
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "supportsText", {
- get: function() {
- return this.__supportsText;
- }
- });
-
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "styleSheet", {
- get: function() {
- return this.__styleSheet;
- }
- });
-
- /**
- * NON-STANDARD
- * Rule text parser.
- * @param {string} cssText
- */
- Object.defineProperty(CSSOM.CSSImportRule.prototype, "parse", {
- value: function(cssText) {
- var i = 0;
-
- /**
- * @import url(partial.css) screen, handheld;
- * || |
- * after-import media
- * |
- * url
- */
- var state = '';
-
- var buffer = '';
- var index;
-
- var layerRegExp = regexPatterns.layerRegExp;
- var layerRuleNameRegExp = regexPatterns.layerRuleNameRegExp;
- var doubleOrMoreSpacesRegExp = regexPatterns.doubleOrMoreSpacesRegExp;
-
- /**
- * Extracts the content inside supports() handling nested parentheses.
- * @param {string} text - The text to parse
- * @returns {object|null} - {content: string, endIndex: number} or null if not found
- */
- function extractSupportsContent(text) {
- var supportsIndex = text.indexOf('supports(');
- if (supportsIndex !== 0) {
- return null;
- }
-
- var depth = 0;
- var start = supportsIndex + 'supports('.length;
- var i = start;
-
- for (; i < text.length; i++) {
- if (text[i] === '(') {
- depth++;
- } else if (text[i] === ')') {
- if (depth === 0) {
- // Found the closing parenthesis for supports()
- return {
- content: text.slice(start, i),
- endIndex: i
- };
- }
- depth--;
- }
- }
-
- return null; // Unbalanced parentheses
- }
-
- for (var character; (character = cssText.charAt(i)); i++) {
-
- switch (character) {
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- case '\f':
- if (state === 'after-import') {
- state = 'url';
- } else {
- buffer += character;
- }
- break;
-
- case '@':
- if (!state && cssText.indexOf('@import', i) === i) {
- state = 'after-import';
- i += 'import'.length;
- buffer = '';
- }
- break;
-
- case 'u':
- if (state === 'media') {
- buffer += character;
- }
- if (state === 'url' && cssText.indexOf('url(', i) === i) {
- index = cssText.indexOf(')', i + 1);
- if (index === -1) {
- throw i + ': ")" not found';
- }
- i += 'url('.length;
- var url = cssText.slice(i, index);
- if (url[0] === url[url.length - 1]) {
- if (url[0] === '"' || url[0] === "'") {
- url = url.slice(1, -1);
- }
- }
- this.__href = url;
- i = index;
- state = 'media';
- }
- break;
-
- case '"':
- if (state === 'after-import' || state === 'url') {
- index = cssText.indexOf('"', i + 1);
- if (!index) {
- throw i + ": '\"' not found";
- }
- this.__href = cssText.slice(i + 1, index);
- i = index;
- state = 'media';
- }
- break;
-
- case "'":
- if (state === 'after-import' || state === 'url') {
- index = cssText.indexOf("'", i + 1);
- if (!index) {
- throw i + ': "\'" not found';
- }
- this.__href = cssText.slice(i + 1, index);
- i = index;
- state = 'media';
- }
- break;
-
- case ';':
- if (state === 'media') {
- if (buffer) {
- var bufferTrimmed = buffer.trim();
-
- if (bufferTrimmed.indexOf('layer') === 0) {
- var layerMatch = bufferTrimmed.match(layerRegExp);
-
- if (layerMatch) {
- var layerName = layerMatch[1].trim();
-
- if (layerName.match(layerRuleNameRegExp) !== null) {
- this.__layerName = layerMatch[1].trim();
- bufferTrimmed = bufferTrimmed.replace(layerRegExp, '')
- .replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
- .trim();
- } else {
- // REVIEW: In the browser, an empty layer() is not processed as a unamed layer
- // and treats the rest of the string as mediaText, ignoring the parse of supports()
- if (bufferTrimmed) {
- this.media.mediaText = bufferTrimmed;
- return;
- }
- }
- } else {
- this.__layerName = "";
- bufferTrimmed = bufferTrimmed.substring('layer'.length).trim();
- }
- }
-
- var supportsResult = extractSupportsContent(bufferTrimmed);
-
- if (supportsResult) {
- // REVIEW: In the browser, an empty supports() invalidates and ignores the entire @import rule
- this.__supportsText = supportsResult.content.trim();
- // Remove the entire supports(...) from the buffer
- bufferTrimmed = bufferTrimmed.slice(0, 0) + bufferTrimmed.slice(supportsResult.endIndex + 1);
- bufferTrimmed = bufferTrimmed.replace(doubleOrMoreSpacesRegExp, ' ').trim();
- }
-
- // REVIEW: In the browser, any invalid media is replaced with 'not all'
- if (bufferTrimmed) {
- this.media.mediaText = bufferTrimmed;
- }
- }
- }
- break;
-
- default:
- if (state === 'media') {
- buffer += character;
- }
- break;
- }
- }
- }
- });
-
-
- //.CommonJS
- CSSImportRule.CSSImportRule = CSSOM.CSSImportRule;
- ///CommonJS
- return CSSImportRule;
+function contractOverflow(values) {
+ const x = values["overflow-x"];
+ const y = values["overflow-y"];
+ if (!x || !y) return null;
+ const sx = serialize(x).trim();
+ const sy = serialize(y).trim();
+ const wide = checkUniformCssWide([sx, sy]);
+ if (wide !== void 0) return wide;
+ if (sx.includes("var(") || sy.includes("var(")) return sx === sy ? sx : null;
+ return sx === sy ? sx : `${sx} ${sy}`;
}
-
-var CSSNamespaceRule = {};
-
-var hasRequiredCSSNamespaceRule;
-
-function requireCSSNamespaceRule () {
- if (hasRequiredCSSNamespaceRule) return CSSNamespaceRule;
- hasRequiredCSSNamespaceRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSStyleSheet: requireCSSStyleSheet().CSSStyleSheet
+const LINE_CLAMP_LONGHANDS = [
+ "max-lines",
+ "block-ellipsis",
+ "continue"
+];
+function expandLineClamp(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0) return null;
+ const wide = tryExpandCssWide(filtered, LINE_CLAMP_LONGHANDS);
+ if (wide) return wide;
+ const autoToken = [{
+ type: "ident",
+ value: "auto"
+ }];
+ if (filtered.length === 1 && filtered[0].type === "ident" && filtered[0].value.toLowerCase() === "none") return {
+ "max-lines": [{
+ type: "ident",
+ value: "none"
+ }],
+ "block-ellipsis": autoToken,
+ "continue": autoToken
};
- ///CommonJS
-
-
- /**
- * @constructor
- * @see https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface
- */
- CSSOM.CSSNamespaceRule = function CSSNamespaceRule() {
- CSSOM.CSSRule.call(this);
- this.__prefix = "";
- this.__namespaceURI = "";
+ return {
+ "max-lines": filtered,
+ "block-ellipsis": autoToken,
+ "continue": autoToken
};
-
- CSSOM.CSSNamespaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSNamespaceRule.prototype.constructor = CSSOM.CSSNamespaceRule;
-
- Object.setPrototypeOf(CSSOM.CSSNamespaceRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "type", {
- value: 10,
- writable: false
- });
-
- Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "cssText", {
- get: function() {
- return "@namespace" + (this.prefix && " " + this.prefix) + " url(\"" + this.namespaceURI + "\");";
- }
- });
-
- Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "prefix", {
- get: function() {
- return this.__prefix;
- }
- });
-
- Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "namespaceURI", {
- get: function() {
- return this.__namespaceURI;
- }
- });
-
-
- /**
- * NON-STANDARD
- * Rule text parser.
- * @param {string} cssText
- */
- Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "parse", {
- value: function(cssText) {
- var newPrefix = "";
- var newNamespaceURI = "";
-
- // Remove @namespace and trim
- var text = cssText.trim();
- if (text.indexOf('@namespace') === 0) {
- text = text.slice('@namespace'.length).trim();
- }
-
- // Remove trailing semicolon if present
- if (text.charAt(text.length - 1) === ';') {
- text = text.slice(0, -1).trim();
- }
-
- // Regex to match valid namespace syntax:
- // 1. [optional prefix] url("...") or [optional prefix] url('...') or [optional prefix] url() or [optional prefix] url(unquoted)
- // 2. [optional prefix] "..." or [optional prefix] '...'
- // The prefix must be a valid CSS identifier (letters, digits, hyphens, underscores, starting with letter or underscore)
- var re = /^(?:([a-zA-Z_][a-zA-Z0-9_-]*)\s+)?(?:url\(\s*(?:(['"])(.*?)\2\s*|([^)]*?))\s*\)|(['"])(.*?)\5)$/;
- var match = text.match(re);
-
- if (match) {
- // If prefix is present
- if (match[1]) {
- newPrefix = match[1];
- }
- // If url(...) form with quotes
- if (typeof match[3] !== "undefined") {
- newNamespaceURI = match[3];
- }
- // If url(...) form without quotes
- else if (typeof match[4] !== "undefined") {
- newNamespaceURI = match[4].trim();
- }
- // If quoted string form
- else if (typeof match[6] !== "undefined") {
- newNamespaceURI = match[6];
- }
-
- this.__prefix = newPrefix;
- this.__namespaceURI = newNamespaceURI;
- } else {
- throw new DOMException("Invalid @namespace rule", "InvalidStateError");
- }
- }
+}
+function contractLineClamp(values) {
+ const lines = values["max-lines"];
+ if (!lines) return null;
+ const sLines = serialize(lines).trim();
+ return sLines.toLowerCase() === "none" ? "none" : sLines;
+}
+const BORDER_RADIUS_PHYSICAL = [
+ "border-top-left-radius",
+ "border-top-right-radius",
+ "border-bottom-right-radius",
+ "border-bottom-left-radius"
+];
+function expandBorderRadius(values) {
+ const filtered = filterSignificantTokens(values);
+ if (filtered.length === 0) return null;
+ if (filtered[0].type === "ident" && filtered[0].value.toLowerCase() === "logical") return null;
+ const slashIndex = filtered.findIndex((v) => v.type === "delim" && v.value === "/");
+ let hValues;
+ let vValues;
+ if (slashIndex !== -1) {
+ hValues = filtered.slice(0, slashIndex);
+ vValues = filtered.slice(slashIndex + 1);
+ if (hValues.length === 0 || hValues.length > 4 || vValues.length === 0 || vValues.length > 4) return null;
+ if (vValues.some((v) => v.type === "delim" && v.value === "/")) return null;
+ } else {
+ if (filtered.length > 4) return null;
+ hValues = filtered;
+ vValues = filtered;
+ }
+ const hExpanded = expandFourSides(hValues);
+ const vExpanded = expandFourSides(vValues);
+ const result = {};
+ for (let i = 0; i < 4; i++) {
+ const h = hExpanded[i];
+ const v = vExpanded[i];
+ result[BORDER_RADIUS_PHYSICAL[i]] = serialize(h) === serialize(v) ? h : [
+ ...h,
+ {
+ type: "whitespace",
+ value: " "
+ },
+ ...v
+ ];
+ }
+ return result;
+}
+function contractBorderRadius(values) {
+ if (!BORDER_RADIUS_PHYSICAL.every((prop) => values[prop] !== void 0)) return null;
+ const longhands = BORDER_RADIUS_PHYSICAL.map((prop) => values[prop]);
+ const wide = checkUniformCssWide(longhands.map((lh) => serialize(lh).trim()));
+ if (wide !== void 0) return wide;
+ const parsed = longhands.map((lh) => {
+ const filtered = filterSignificantTokens(lh);
+ return {
+ h: serialize([filtered[0]]).trim(),
+ v: serialize([filtered.length > 1 ? filtered[1] : filtered[0]]).trim()
+ };
});
- //.CommonJS
- CSSNamespaceRule.CSSNamespaceRule = CSSOM.CSSNamespaceRule;
- ///CommonJS
- return CSSNamespaceRule;
+ const hStr = formatFourSides(parsed[0].h, parsed[1].h, parsed[2].h, parsed[3].h);
+ const vStr = formatFourSides(parsed[0].v, parsed[1].v, parsed[2].v, parsed[3].v);
+ return hStr === vStr ? hStr : `${hStr} / ${vStr}`;
}
-
-var CSSMediaRule = {};
-
-var CSSConditionRule = {};
-
-var hasRequiredCSSConditionRule;
-
-function requireCSSConditionRule () {
- if (hasRequiredCSSConditionRule) return CSSConditionRule;
- hasRequiredCSSConditionRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule
- };
- ///CommonJS
-
-
- /**
- * @constructor
- * @see https://www.w3.org/TR/css-conditional-3/#the-cssconditionrule-interface
- */
- CSSOM.CSSConditionRule = function CSSConditionRule() {
- CSSOM.CSSGroupingRule.call(this);
- this.__conditionText = '';
+const logicalLonghands = [];
+const physicalLonghands = [];
+for (const prop of SUPPORTED_PROPERTIES) if (prop !== "all" && prop !== "direction" && prop !== "unicode-bidi" && !prop.startsWith("--") && !(prop in SHORTHANDS_DATA)) {
+ if (prop in LOGICAL_MAPPING) logicalLonghands.push(prop);
+ else physicalLonghands.push(prop);
+}
+const ALL_SHORTHAND_LONGHANDS = Object.freeze([...logicalLonghands, ...physicalLonghands]);
+function isCSSWideKeywordOrVar(tokens) {
+ const nonWs = filterSignificantTokens(tokens);
+ if (nonWs.length === 1 && nonWs[0].type === "ident" && CSS_WIDE_KEYWORDS$2.has(nonWs[0].value.toLowerCase())) return true;
+ return nonWs.some((t) => t.type === "function" && getFunctionName(t) === "var");
+}
+function expandAll(value) {
+ if (!value || value.length === 0 || !isCSSWideKeywordOrVar(value)) return null;
+ return expandUniformLonghands(ALL_SHORTHAND_LONGHANDS, value);
+}
+function contractAll(longhands) {
+ let firstVal = null;
+ for (const lh of ALL_SHORTHAND_LONGHANDS) {
+ const valTokens = longhands[lh];
+ if (!valTokens || valTokens.length === 0) return null;
+ const serialized = serialize(valTokens).trim();
+ if (firstVal === null) firstVal = serialized;
+ else if (serialized !== firstVal) return null;
+ }
+ if (!firstVal) return null;
+ const lower = firstVal.toLowerCase();
+ return CSS_WIDE_KEYWORDS$2.has(lower) || lower.startsWith("var(") ? firstVal : null;
+}
+function createBoxShorthand(name, physical, logical) {
+ return {
+ longhands: SHORTHANDS_DATA[name],
+ logicalLonghands: logical,
+ expand: expandBox(physical, logical),
+ contract: contractBox(physical, logical)
};
-
- CSSOM.CSSConditionRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
- CSSOM.CSSConditionRule.prototype.constructor = CSSOM.CSSConditionRule;
-
- Object.setPrototypeOf(CSSOM.CSSConditionRule, CSSOM.CSSGroupingRule);
-
- Object.defineProperty(CSSOM.CSSConditionRule.prototype, "conditionText", {
- get: function () {
- return this.__conditionText;
- }
- });
-
- //.CommonJS
- CSSConditionRule.CSSConditionRule = CSSOM.CSSConditionRule;
- ///CommonJS
- return CSSConditionRule;
}
-
-var hasRequiredCSSMediaRule;
-
-function requireCSSMediaRule () {
- if (hasRequiredCSSMediaRule) return CSSMediaRule;
- hasRequiredCSSMediaRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule,
- CSSConditionRule: requireCSSConditionRule().CSSConditionRule,
- MediaList: requireMediaList().MediaList
+function createTwoValueShorthand(name, physicalLonghands) {
+ const longhands = SHORTHANDS_DATA[name];
+ return {
+ longhands,
+ ...physicalLonghands ? { physicalLonghands } : {},
+ expand: expandTwoValue(longhands),
+ contract: contractTwoValue(longhands)
};
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://dev.w3.org/csswg/cssom/#cssmediarule
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSMediaRule
- */
- CSSOM.CSSMediaRule = function CSSMediaRule() {
- CSSOM.CSSConditionRule.call(this);
- this.__media = new CSSOM.MediaList();
+}
+function createBorderSideShorthand(prefix, longhands, physicalLonghands) {
+ return {
+ longhands,
+ ...physicalLonghands ? { physicalLonghands } : {},
+ expand: expandBorderSide(prefix),
+ contract: contractBorderSide(prefix)
};
-
- CSSOM.CSSMediaRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
- CSSOM.CSSMediaRule.prototype.constructor = CSSOM.CSSMediaRule;
-
- Object.setPrototypeOf(CSSOM.CSSMediaRule, CSSOM.CSSConditionRule);
-
- Object.defineProperty(CSSOM.CSSMediaRule.prototype, "type", {
- value: 4,
- writable: false
- });
-
- // https://opensource.apple.com/source/WebCore/WebCore-7611.1.21.161.3/css/CSSMediaRule.cpp
- Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
- "media": {
- get: function() {
- return this.__media;
- },
- set: function(value) {
- if (typeof value === "string") {
- this.__media.mediaText = value;
- } else {
- this.__media = value;
- }
- },
- configurable: true,
- enumerable: true
- },
- "conditionText": {
- get: function() {
- return this.media.mediaText;
- }
- },
- "cssText": {
- get: function() {
- var values = "";
- var valuesArr = [" {"];
- if (this.cssRules.length) {
- valuesArr.push(this.cssRules.reduce(function(acc, rule){
- if (rule.cssText !== "") {
- acc.push(rule.cssText);
- }
- return acc;
- }, []).join("\n "));
- }
- values = valuesArr.join("\n ") + "\n}";
- return "@media " + this.media.mediaText + values;
- }
- }
- });
-
-
- //.CommonJS
- CSSMediaRule.CSSMediaRule = CSSOM.CSSMediaRule;
- ///CommonJS
- return CSSMediaRule;
}
-
-var CSSCounterStyleRule = {};
-
-var hasRequiredCSSCounterStyleRule;
-
-function requireCSSCounterStyleRule () {
- if (hasRequiredCSSCounterStyleRule) return CSSCounterStyleRule;
- hasRequiredCSSCounterStyleRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule
+function createBorderAxisShorthand(name, startProp, endProp, physicalLonghands, logicalLonghands) {
+ return {
+ longhands: SHORTHANDS_DATA[name],
+ physicalLonghands,
+ logicalLonghands,
+ expand: (values) => {
+ if (filterSignificantTokens(values).length === 0) return null;
+ return {
+ [startProp]: values,
+ [endProp]: values
+ };
+ },
+ contract: (values) => {
+ const sVal = values[startProp];
+ const eVal = values[endProp];
+ const start = sVal ? serialize(sVal).trim() : contractBorderSide(startProp)(values);
+ const end = eVal ? serialize(eVal).trim() : contractBorderSide(endProp)(values);
+ return start && end && start === end ? start : null;
+ }
};
- ///CommonJS
-
-
+}
+const SHORTHANDS = {
+ "border-block": createBorderAxisShorthand("border-block", "border-block-start", "border-block-end", [
+ "border-top-width",
+ "border-top-style",
+ "border-top-color",
+ "border-bottom-width",
+ "border-bottom-style",
+ "border-bottom-color"
+ ], [
+ "border-block-start-width",
+ "border-block-start-style",
+ "border-block-start-color",
+ "border-block-end-width",
+ "border-block-end-style",
+ "border-block-end-color"
+ ]),
+ "border-block-color": createTwoValueShorthand("border-block-color", ["border-top-color", "border-bottom-color"]),
+ "border-block-end": createBorderSideShorthand("border-block-end", SHORTHANDS_DATA["border-block-end"], [
+ "border-bottom-width",
+ "border-bottom-style",
+ "border-bottom-color"
+ ]),
+ "border-block-start": createBorderSideShorthand("border-block-start", SHORTHANDS_DATA["border-block-start"], [
+ "border-top-width",
+ "border-top-style",
+ "border-top-color"
+ ]),
+ "border-block-style": createTwoValueShorthand("border-block-style", ["border-top-style", "border-bottom-style"]),
+ "border-block-width": createTwoValueShorthand("border-block-width", ["border-top-width", "border-bottom-width"]),
+ "border": {
+ longhands: BORDER_ALL_LONGHANDS,
+ expand: expandBorder,
+ contract: contractBorder
+ },
+ "border-top": createBorderSideShorthand("border-top", [
+ "border-top-width",
+ "border-top-style",
+ "border-top-color"
+ ]),
+ "border-right": createBorderSideShorthand("border-right", [
+ "border-right-width",
+ "border-right-style",
+ "border-right-color"
+ ]),
+ "border-bottom": createBorderSideShorthand("border-bottom", [
+ "border-bottom-width",
+ "border-bottom-style",
+ "border-bottom-color"
+ ]),
+ "border-left": createBorderSideShorthand("border-left", [
+ "border-left-width",
+ "border-left-style",
+ "border-left-color"
+ ]),
+ "border-image": {
+ longhands: BORDER_IMAGE_LONGHANDS,
+ expand: expandBorderImage,
+ contract: contractBorderImage
+ },
+ "outline": {
+ longhands: [
+ "outline-color",
+ "outline-style",
+ "outline-width"
+ ],
+ expand: expandOutline,
+ contract: contractOutline
+ },
+ "font-variant": {
+ longhands: FONT_VARIANT_LONGHANDS,
+ expand: expandFontVariant,
+ contract: contractFontVariant
+ },
+ "font": {
+ longhands: FONT_LONGHANDS,
+ expand: expandFont,
+ contract: contractFont
+ },
+ "list-style": {
+ longhands: LIST_STYLE_LONGHANDS,
+ expand: expandListStyle,
+ contract: contractListStyle
+ },
+ "overflow": {
+ longhands: SHORTHANDS_DATA["overflow"],
+ expand: expandTwoValue(SHORTHANDS_DATA["overflow"]),
+ contract: contractOverflow
+ },
+ "flex": {
+ longhands: FLEX_LONGHANDS,
+ expand: expandFlex,
+ contract: contractFlex
+ },
+ "-webkit-flex": {
+ longhands: FLEX_LONGHANDS,
+ expand: expandFlex,
+ contract: contractFlex
+ },
+ "line-clamp": {
+ longhands: LINE_CLAMP_LONGHANDS,
+ expand: expandLineClamp,
+ contract: contractLineClamp
+ },
+ "-webkit-line-clamp": {
+ longhands: LINE_CLAMP_LONGHANDS,
+ expand: expandLineClamp,
+ contract: contractLineClamp
+ },
+ "border-color": createBoxShorthand("border-color", [
+ "border-top-color",
+ "border-right-color",
+ "border-bottom-color",
+ "border-left-color"
+ ], [
+ "border-block-start-color",
+ "border-inline-start-color",
+ "border-block-end-color",
+ "border-inline-end-color"
+ ]),
+ "border-inline": createBorderAxisShorthand("border-inline", "border-inline-start", "border-inline-end", [
+ "border-left-width",
+ "border-left-style",
+ "border-left-color",
+ "border-right-width",
+ "border-right-style",
+ "border-right-color"
+ ], [
+ "border-inline-start-width",
+ "border-inline-start-style",
+ "border-inline-start-color",
+ "border-inline-end-width",
+ "border-inline-end-style",
+ "border-inline-end-color"
+ ]),
+ "border-inline-color": createTwoValueShorthand("border-inline-color", ["border-left-color", "border-right-color"]),
+ "border-inline-end": createBorderSideShorthand("border-inline-end", SHORTHANDS_DATA["border-inline-end"], [
+ "border-right-width",
+ "border-right-style",
+ "border-right-color"
+ ]),
+ "border-inline-start": createBorderSideShorthand("border-inline-start", SHORTHANDS_DATA["border-inline-start"], [
+ "border-left-width",
+ "border-left-style",
+ "border-left-color"
+ ]),
+ "border-inline-style": createTwoValueShorthand("border-inline-style", ["border-left-style", "border-right-style"]),
+ "border-inline-width": createTwoValueShorthand("border-inline-width", ["border-left-width", "border-right-width"]),
+ "border-radius": {
+ longhands: SHORTHANDS_DATA["border-radius"],
+ logicalLonghands: [
+ "border-start-start-radius",
+ "border-start-end-radius",
+ "border-end-end-radius",
+ "border-end-start-radius"
+ ],
+ expand: expandBorderRadius,
+ contract: contractBorderRadius
+ },
+ "border-style": createBoxShorthand("border-style", [
+ "border-top-style",
+ "border-right-style",
+ "border-bottom-style",
+ "border-left-style"
+ ], [
+ "border-block-start-style",
+ "border-inline-start-style",
+ "border-block-end-style",
+ "border-inline-end-style"
+ ]),
+ "border-width": createBoxShorthand("border-width", [
+ "border-top-width",
+ "border-right-width",
+ "border-bottom-width",
+ "border-left-width"
+ ], [
+ "border-block-start-width",
+ "border-inline-start-width",
+ "border-block-end-width",
+ "border-inline-end-width"
+ ]),
+ "inset": createBoxShorthand("inset", [
+ "top",
+ "right",
+ "bottom",
+ "left"
+ ], [
+ "inset-block-start",
+ "inset-inline-start",
+ "inset-block-end",
+ "inset-inline-end"
+ ]),
+ "inset-block": createTwoValueShorthand("inset-block", ["top", "bottom"]),
+ "inset-inline": createTwoValueShorthand("inset-inline", ["left", "right"]),
+ "margin": createBoxShorthand("margin", [
+ "margin-top",
+ "margin-right",
+ "margin-bottom",
+ "margin-left"
+ ], [
+ "margin-block-start",
+ "margin-inline-start",
+ "margin-block-end",
+ "margin-inline-end"
+ ]),
+ "margin-block": createTwoValueShorthand("margin-block", ["margin-top", "margin-bottom"]),
+ "margin-inline": createTwoValueShorthand("margin-inline", ["margin-left", "margin-right"]),
+ "padding": createBoxShorthand("padding", [
+ "padding-top",
+ "padding-right",
+ "padding-bottom",
+ "padding-left"
+ ], [
+ "padding-block-start",
+ "padding-inline-start",
+ "padding-block-end",
+ "padding-inline-end"
+ ]),
+ "padding-block": createTwoValueShorthand("padding-block", ["padding-top", "padding-bottom"]),
+ "padding-inline": createTwoValueShorthand("padding-inline", ["padding-left", "padding-right"]),
+ "scroll-margin": createBoxShorthand("scroll-margin", [
+ "scroll-margin-top",
+ "scroll-margin-right",
+ "scroll-margin-bottom",
+ "scroll-margin-left"
+ ], [
+ "scroll-margin-block-start",
+ "scroll-margin-inline-start",
+ "scroll-margin-block-end",
+ "scroll-margin-inline-end"
+ ]),
+ "scroll-padding": createBoxShorthand("scroll-padding", [
+ "scroll-padding-top",
+ "scroll-padding-right",
+ "scroll-padding-bottom",
+ "scroll-padding-left"
+ ], [
+ "scroll-padding-block-start",
+ "scroll-padding-inline-start",
+ "scroll-padding-block-end",
+ "scroll-padding-inline-end"
+ ]),
+ "background": {
+ longhands: SHORTHANDS_DATA["background"],
+ expand: expandBackground,
+ contract: contractBackground
+ },
+ "all": {
+ longhands: ALL_SHORTHAND_LONGHANDS,
+ expand: expandAll,
+ contract: contractAll
+ }
+};
+function getShorthandAllLonghands(shorthand) {
+ if (shorthand.allLonghands) return shorthand.allLonghands;
+ if (!shorthand.logicalLonghands && !shorthand.physicalLonghands) return shorthand.longhands;
+ const combined = Object.freeze([
+ ...shorthand.longhands,
+ ...shorthand.logicalLonghands || [],
+ ...shorthand.physicalLonghands || []
+ ]);
+ shorthand.allLonghands = combined;
+ return combined;
+}
+const LONGHAND_TO_SHORTHAND = {};
+for (const [shorthand, def] of Object.entries(SHORTHANDS)) {
+ def.allLonghands = Object.freeze([
+ ...def.longhands,
+ ...def.logicalLonghands || [],
+ ...def.physicalLonghands || []
+ ]);
+ if (shorthand === "all") continue;
+ for (const longhand of def.longhands) {
+ if (!LONGHAND_TO_SHORTHAND[longhand]) LONGHAND_TO_SHORTHAND[longhand] = [];
+ LONGHAND_TO_SHORTHAND[longhand].push(shorthand);
+ }
+ if (def.logicalLonghands) for (const longhand of def.logicalLonghands) {
+ if (!LONGHAND_TO_SHORTHAND[longhand]) LONGHAND_TO_SHORTHAND[longhand] = [];
+ LONGHAND_TO_SHORTHAND[longhand].push(shorthand);
+ }
+ if (def.physicalLonghands) for (const longhand of def.physicalLonghands) {
+ if (!LONGHAND_TO_SHORTHAND[longhand]) LONGHAND_TO_SHORTHAND[longhand] = [];
+ if (!LONGHAND_TO_SHORTHAND[longhand].includes(shorthand)) LONGHAND_TO_SHORTHAND[longhand].push(shorthand);
+ }
+}
+// src/utils/format.ts
+/** @license Copyright 2026 Google LLC. SPDX-License-Identifier: Apache-2.0 */
+const formatter = new Intl.NumberFormat("en-US", {
+ useGrouping: false,
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 6
+});
+function formatNumber(val) {
+ if (val === 0) return "0";
+ if (!Number.isFinite(val)) {
+ if (val === Infinity) return "infinity";
+ if (val === -Infinity) return "-infinity";
+ return "nan";
+ }
+ const formatted = formatter.format(val);
+ return formatted === "-0" ? "0" : formatted;
+}
+// src/data/gen/selectors.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+const PSEUDO_CLASSES = /* @__PURE__ */ new Set("active,active-view-transition,active-view-transition-type,after,animated-image,any-link,autofill,before,blank,buffering,checked,current,default,defined,dir,disabled,empty,enabled,first,first-child,first-letter,first-line,first-of-page,first-of-type,focus,focus-visible,focus-within,fullscreen,future,has,has-slotted,heading,high-value,host,host-context,hover,in-range,indeterminate,interest-source,interest-target,invalid,is,lang,last-child,last-of-page,last-of-type,left,link,link-to,local-link,low-value,matches,modal,muted,navigation-source,not,nth,nth-child,nth-col,nth-last-child,nth-last-col,nth-last-of-type,nth-of-page,nth-of-type,only-child,only-of-type,open,optimal-value,optional,out-of-range,past,paused,picture-in-picture,placeholder-shown,playing,popover-open,read-only,read-write,required,right,root,scope,seeking,snapped,snapped-block,snapped-inline,snapped-x,snapped-y,stalled,start-of-page,state,target,target-after,target-before,target-current,target-within,unchecked,user-invalid,user-valid,valid,visited,volume-locked,where,xr-overlay".split(","));
+const PSEUDO_ELEMENTS = /* @__PURE__ */ new Set("-moz-progress-bar,-moz-range-progress,-moz-range-thumb,-moz-range-track,-ms-browse,-ms-check,-ms-clear,-ms-expand,-ms-fill,-ms-fill-lower,-ms-fill-upper,-ms-reveal,-ms-thumb,-ms-ticks-after,-ms-ticks-before,-ms-tooltip,-ms-track,-ms-value,-webkit-progress-bar,-webkit-progress-inner-value,-webkit-progress-value,-webkit-slider-runnable-track,-webkit-slider-thumb,after,backdrop,before,checkmark,clear-icon,color-swatch,column,cue,cue-region,details-content,field-component,field-content,field-separator,file-selector-button,first-letter,first-line,grammar-error,highlight,interest-button,marker,nth-fragment,part,picker,picker-icon,placeholder,reveal-icon,scroll-button,scroll-marker,scroll-marker-group,search-text,selection,slider-fill,slider-thumb,slider-track,slotted,spelling-error,step-control,step-down,step-up,target-text,view-transition,view-transition-group,view-transition-group-children,view-transition-image-pair,view-transition-new,view-transition-old".split(","));
+// src/SelectorParser.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+function isIdentToken(val) {
+ return val !== void 0 && val.type === "ident";
+}
+function isDelimToken(val, char) {
+ return val !== void 0 && val.type === "delim" && (char === void 0 || val.value === char);
+}
+function isHashToken(val) {
+ return val !== void 0 && val.type === "hash";
+}
+function isStringToken(val) {
+ return val !== void 0 && (val.type === "string" || val.type === "bad-string");
+}
+function isNumberToken(val) {
+ return val !== void 0 && val.type === "number";
+}
+function isDimensionToken(val) {
+ return val !== void 0 && val.type === "dimension";
+}
+function isSimpleBlock(val, associatedType) {
+ return val !== void 0 && val.type === "simple-block" && (associatedType === void 0 || val.associatedToken.type === associatedType);
+}
+function isCSSFunction(val, name) {
+ return val !== void 0 && val.type === "function" && (name === void 0);
+}
+var ComponentValueCursor = class {
+ values;
+ _i = 0;
+ constructor(values) {
+ this.values = values;
+ }
+ get hasNext() {
+ return this._i < this.values.length;
+ }
+ get i() {
+ return this._i;
+ }
+ set i(pos) {
+ this._i = pos;
+ }
+ get length() {
+ return this.values.length;
+ }
+ get next() {
+ return this.values[this._i];
+ }
+ peek(offset = 1) {
+ return this.values[this._i + offset];
+ }
+ consume() {
+ return this.values[this._i++] || { type: "EOF" };
+ }
+ skipWhitespace() {
+ while (this._i < this.values.length && this.values[this._i].type === "whitespace") this._i++;
+ }
+ skipToNextComma() {
+ const commaOffset = this.values.slice(this._i).findIndex((v) => v.type === "comma");
+ this._i = commaOffset === -1 ? this.values.length : this._i + commaOffset;
+ }
+ slice(start, end) {
+ return this.values.slice(start, end ?? this._i);
+ }
+};
+const LEGACY_PSEUDO_CLASS_ALIASES = { "-webkit-autofill": "autofill" };
+/**
+* Selector Parser according to Selectors Level 4.
+*
+* selectors-4 #grammar
+* selectors-4 #parse-selector
+* selectors-4 #parse-relative-selector
+*/
+var SelectorParser = class SelectorParser {
+ static PSEUDO_CLASSES = PSEUDO_CLASSES;
+ static PSEUDO_ELEMENTS = PSEUDO_ELEMENTS;
+ cursor;
+ allowRelative;
+ forgiving;
+ insideHas;
+ forbidPseudo;
+ declaredNamespaces;
+ strictSupports;
+ allowVendorPseudos;
+ allowUnknownPseudos;
+ constructor(values, options = {}) {
+ this.cursor = new ComponentValueCursor(values);
+ this.allowRelative = options.allowRelative ?? false;
+ this.forgiving = options.forgiving ?? false;
+ this.insideHas = options.insideHas ?? false;
+ this.forbidPseudo = options.forbidPseudo ?? false;
+ this.declaredNamespaces = options.declaredNamespaces;
+ this.strictSupports = options.strictSupports ?? false;
+ this.allowVendorPseudos = options.allowVendorPseudos ?? false;
+ this.allowUnknownPseudos = options.allowUnknownPseudos ?? false;
+ }
+ hasAmpersand(values) {
+ return values.some((val) => {
+ if (isDelimToken(val, "&")) return true;
+ if (isSimpleBlock(val)) return this.hasAmpersand(val.value);
+ if (isCSSFunction(val)) return this.hasAmpersand(val.value);
+ return false;
+ });
+ }
/**
- * @constructor
- * @see https://drafts.csswg.org/css-counter-styles/#the-csscounterstylerule-interface
- */
- CSSOM.CSSCounterStyleRule = function CSSCounterStyleRule() {
- CSSOM.CSSRule.call(this);
- this.name = "";
- this.__props = "";
- };
-
- CSSOM.CSSCounterStyleRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSCounterStyleRule.prototype.constructor = CSSOM.CSSCounterStyleRule;
-
- Object.setPrototypeOf(CSSOM.CSSCounterStyleRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "type", {
- value: 11,
- writable: false
- });
-
- Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "cssText", {
- get: function() {
- // FIXME : Implement real cssText generation based on properties
- return "@counter-style " + this.name + " { " + this.__props + " }";
+ * Parses component values into a SelectorList.
+ *
+ * selectors-4 #grouping ()
+ * selectors-4 #grammar ()
+ * selectors-4 #forgiving-selector (parsing forgiving selector list)
+ * selectors-4 #parse-selector
+ */
+ parse() {
+ const selectors = [];
+ while (this.cursor.hasNext) {
+ this.cursor.skipWhitespace();
+ if (!this.cursor.hasNext || this.cursor.next?.type === "EOF") break;
+ const start = this.cursor.i;
+ try {
+ const selector = this.consumeComplexSelector();
+ this.cursor.skipWhitespace();
+ const next = this.cursor.next;
+ if (!next || next.type === "comma") selectors.push(selector);
+ else throw new DOMException("Unexpected token in selector", "SyntaxError");
+ } catch (e) {
+ if (this.forgiving) {
+ this.cursor.skipToNextComma();
+ const rawSlice = this.cursor.slice(start, this.cursor.i);
+ let trimmedStart = 0;
+ while (trimmedStart < rawSlice.length && rawSlice[trimmedStart].type === "whitespace") trimmedStart++;
+ let trimmedEnd = rawSlice.length - 1;
+ while (trimmedEnd >= trimmedStart && rawSlice[trimmedEnd].type === "whitespace") trimmedEnd--;
+ const failedTokens = rawSlice.slice(trimmedStart, trimmedEnd + 1);
+ if (failedTokens.length > 0) selectors.push({
+ type: "invalid-selector",
+ tokens: failedTokens
+ });
+ } else throw e;
+ }
+ if (this.cursor.next?.type === "comma") this.cursor.consume();
}
- });
-
+ if (!this.forgiving && selectors.length === 0) throw new DOMException("Selector list cannot be empty", "SyntaxError");
+ return {
+ type: "selector-list",
+ selectors
+ };
+ }
/**
- * NON-STANDARD
- * Rule text parser.
- * @param {string} cssText
- */
- Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "parse", {
- value: function(cssText) {
- // Extract the name from "@counter-style { ... }"
- var match = cssText.match(/@counter-style\s+([^\s{]+)\s*\{([^]*)\}/);
- if (match) {
- this.name = match[1];
- // Get the text inside the brackets and clean it up
- var propsText = match[2];
- this.__props = propsText.trim().replace(/\n/g, " ").replace(/(['"])(?:\\.|[^\\])*?\1|(\s{2,})/g, function (match, quote) {
- return quote ? match : ' ';
- });
+ * Validates namespace prefixes against declared namespaces.
+ *
+ * selectors-4 #namespaces
+ * selectors-4 #parse-selector step 2
+ */
+ validateNamespace(namespace) {
+ if (this.declaredNamespaces !== void 0 && namespace !== void 0 && namespace !== "*" && namespace !== "") {
+ if (!this.declaredNamespaces.has(namespace)) throw new DOMException(`Undeclared namespace prefix: "${namespace}"`, "SyntaxError");
+ }
+ }
+ /**
+ * Consumes a complex selector.
+ *
+ * selectors-4 #structure ()
+ * selectors-4 #grammar
+ */
+ consumeComplexSelector() {
+ const items = [];
+ const start = this.cursor.i;
+ let seenPseudoElement = false;
+ while (this.cursor.hasNext) {
+ this.cursor.skipWhitespace();
+ if (!this.cursor.hasNext || this.cursor.next?.type === "comma") break;
+ const combinator = this.tryConsumeCombinator();
+ if (combinator) {
+ if (items.length === 0 && !this.allowRelative) throw new DOMException("Relative selector not allowed in this context", "SyntaxError");
+ if (seenPseudoElement) throw new DOMException("Pseudo-element must be at the end of the selector", "SyntaxError");
+ if (items.length > 0 && items[items.length - 1].type === "combinator") throw new DOMException("Consecutive combinators are not allowed", "SyntaxError");
+ items.push(combinator);
+ continue;
}
+ const compound = this.consumeCompoundSelector();
+ if (compound.selectors.length > 0) {
+ if (seenPseudoElement) throw new DOMException("Pseudo-element must be at the end of the selector", "SyntaxError");
+ const hasPseudo = compound.selectors.some((s) => s.type === "pseudo-element-selector");
+ if (items.length > 0 && items[items.length - 1].type === "compound-selector") items.push({
+ type: "combinator",
+ value: " "
+ });
+ items.push(compound);
+ if (hasPseudo) seenPseudoElement = true;
+ } else break;
}
- });
-
- //.CommonJS
- CSSCounterStyleRule.CSSCounterStyleRule = CSSOM.CSSCounterStyleRule;
- ///CommonJS
- return CSSCounterStyleRule;
-}
-
-var CSSPropertyRule = {};
-
-var hasRequiredCSSPropertyRule;
-
-function requireCSSPropertyRule () {
- if (hasRequiredCSSPropertyRule) return CSSPropertyRule;
- hasRequiredCSSPropertyRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule
- };
- ///CommonJS
-
-
+ if (items.length > 0 && items[items.length - 1].type === "combinator") throw new DOMException("Trailing combinator is not allowed", "SyntaxError");
+ if (items.length === 0) throw new DOMException("Complex selector cannot be empty", "SyntaxError");
+ const end = this.cursor.i;
+ return {
+ type: "complex-selector",
+ items,
+ tokens: this.cursor.slice(start, end)
+ };
+ }
/**
- * @constructor
- * @see https://drafts.css-houdini.org/css-properties-values-api/#the-css-property-rule-interface
- */
- CSSOM.CSSPropertyRule = function CSSPropertyRule() {
- CSSOM.CSSRule.call(this);
- this.__name = "";
- this.__syntax = "";
- this.__inherits = false;
- this.__initialValue = null;
- };
-
- CSSOM.CSSPropertyRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSPropertyRule.prototype.constructor = CSSOM.CSSPropertyRule;
-
- Object.setPrototypeOf(CSSOM.CSSPropertyRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "type", {
- value: 0,
- writable: false
- });
-
- Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "cssText", {
- get: function() {
- var text = "@property " + this.name + " {";
- if (this.syntax !== "") {
- text += " syntax: \"" + this.syntax.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + "\";";
+ * selectors-4 #combinators
+ * selectors-5 #the-column-combinator (||)
+ */
+ tryConsumeCombinator() {
+ const token = this.cursor.next;
+ if (!token) return null;
+ if (isDelimToken(token)) {
+ const val = token.value;
+ if (val === ">" || val === "+" || val === "~") {
+ this.cursor.consume();
+ return {
+ type: "combinator",
+ value: val
+ };
}
- text += " inherits: " + (this.inherits ? "true" : "false") + ";";
- if (this.initialValue !== null) {
- text += " initial-value: " + this.initialValue + ";";
+ if (val === "|" && isDelimToken(this.cursor.peek(1), "|")) {
+ this.cursor.consume();
+ this.cursor.consume();
+ return {
+ type: "combinator",
+ value: "||"
+ };
}
- text += " }";
- return text;
- }
- });
-
- Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "name", {
- get: function() {
- return this.__name;
- }
- });
-
- Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "syntax", {
- get: function() {
- return this.__syntax;
- }
- });
-
- Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "inherits", {
- get: function() {
- return this.__inherits;
}
- });
-
- Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "initialValue", {
- get: function() {
- return this.__initialValue;
- }
- });
-
- /**
- * NON-STANDARD
- * Rule text parser.
- * @param {string} cssText
- * @returns {boolean} True if the rule is valid and was parsed successfully
- */
- Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "parse", {
- value: function(cssText) {
- // Extract the name from "@property { ... }"
- var match = cssText.match(/@property\s+(--[^\s{]+)\s*\{([^]*)\}/);
- if (!match) {
- return false;
+ return null;
+ }
+ isUserActionPseudoClass(name) {
+ const lower = name.toLowerCase();
+ return [
+ "hover",
+ "active",
+ "focus",
+ "focus-visible",
+ "focus-within"
+ ].includes(lower);
+ }
+ validateSimpleSelectorAfterPseudo(selector) {
+ if (selector.type === "pseudo-class-selector") {
+ const lowerName = selector.name.toLowerCase();
+ if ([
+ "not",
+ "is",
+ "where",
+ "has"
+ ].includes(lowerName)) return;
+ else if (!this.isUserActionPseudoClass(selector.name)) throw new DOMException("Only user-action pseudo-classes are allowed after a pseudo-element", "SyntaxError");
+ } else throw new DOMException("Only user-action pseudo-classes are allowed after a pseudo-element", "SyntaxError");
+ }
+ consumeCompoundSelector() {
+ const selectors = [];
+ let lastPseudoElement = null;
+ while (this.cursor.hasNext) {
+ const token = this.cursor.next;
+ if (!token || token.type === "whitespace" || token.type === "comma") break;
+ if (isDelimToken(token)) {
+ const val = token.value;
+ if (val === ">" || val === "+" || val === "~") break;
+ if (val === "|") {
+ if (lastPseudoElement) break;
+ if (isDelimToken(this.cursor.peek(1), "|")) break;
+ if (selectors.length > 0) throw new DOMException("Type selector must be first in compound selector", "SyntaxError");
+ selectors.push(this.consumeTypeOrUniversalSelector());
+ continue;
+ }
+ if (val === "*") {
+ if (lastPseudoElement) break;
+ if (selectors.length > 0) throw new DOMException("Universal selector must be first in compound selector", "SyntaxError");
+ selectors.push(this.consumeTypeOrUniversalSelector());
+ continue;
+ }
+ if (val === ".") {
+ if (lastPseudoElement) break;
+ selectors.push(this.consumeClassSelector());
+ continue;
+ }
+ if (val === "&") {
+ if (lastPseudoElement) break;
+ this.cursor.consume();
+ selectors.push({ type: "nesting-selector" });
+ continue;
+ }
}
-
- this.__name = match[1];
- var bodyText = match[2];
-
- // Parse syntax descriptor (REQUIRED)
- var syntaxMatch = bodyText.match(/syntax\s*:\s*(['"])([^]*?)\1\s*;/);
- if (!syntaxMatch) {
- return false; // syntax is required
+ if (isHashToken(token)) {
+ if (token.hashType !== "id") throw new DOMException("ID selector must be an identifier", "SyntaxError");
+ if (lastPseudoElement) break;
+ selectors.push({
+ type: "id-selector",
+ name: token.value
+ });
+ this.cursor.consume();
+ continue;
}
- this.__syntax = syntaxMatch[2];
-
- // Syntax cannot be empty
- if (this.__syntax === "") {
- return false;
+ if (isIdentToken(token)) {
+ if (lastPseudoElement) break;
+ if (selectors.length > 0) throw new DOMException("Type selector must be first in compound selector", "SyntaxError");
+ selectors.push(this.consumeTypeOrUniversalSelector());
+ continue;
}
-
- // Parse inherits descriptor (REQUIRED)
- var inheritsMatch = bodyText.match(/inherits\s*:\s*(true|false)\s*;/);
- if (!inheritsMatch) {
- return false; // inherits is required
+ if (isSimpleBlock(token, "[")) {
+ if (lastPseudoElement) break;
+ selectors.push(this.consumeAttributeSelector());
+ continue;
}
- this.__inherits = inheritsMatch[1] === "true";
-
- // Parse initial-value descriptor (OPTIONAL, but required if syntax is not "*")
- var initialValueMatch = bodyText.match(/initial-value\s*:\s*([^;]+);/);
- if (initialValueMatch) {
- this.__initialValue = initialValueMatch[1].trim();
- } else {
- // If syntax is not "*", initial-value is required
- if (this.__syntax !== "*") {
- return false;
+ if (token.type === "colon") {
+ const selector = this.consumePseudoSelector();
+ if (lastPseudoElement) {
+ const isSlottedOrPart = ["slotted", "part"].includes(lastPseudoElement.toLowerCase());
+ if (selector.type === "pseudo-element-selector") {
+ if (!isSlottedOrPart) throw new DOMException("Pseudo-elements cannot be nested", "SyntaxError");
+ } else if (selector.type === "pseudo-class-selector") {
+ if (!isSlottedOrPart) this.validateSimpleSelectorAfterPseudo(selector);
+ } else throw new DOMException("Unexpected selector after pseudo-element", "SyntaxError");
}
+ if (selector.type === "pseudo-element-selector") lastPseudoElement = selector.name;
+ selectors.push(selector);
+ continue;
}
-
- return true; // Successfully parsed
+ break;
}
- });
-
- //.CommonJS
- CSSPropertyRule.CSSPropertyRule = CSSOM.CSSPropertyRule;
- ///CommonJS
- return CSSPropertyRule;
-}
-
-var CSSContainerRule = {};
-
-var hasRequiredCSSContainerRule;
-
-function requireCSSContainerRule () {
- if (hasRequiredCSSContainerRule) return CSSContainerRule;
- hasRequiredCSSContainerRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule,
- CSSConditionRule: requireCSSConditionRule().CSSConditionRule,
- };
- ///CommonJS
-
-
- /**
- * @constructor
- * @see https://drafts.csswg.org/css-contain-3/
- * @see https://www.w3.org/TR/css-contain-3/
- */
- CSSOM.CSSContainerRule = function CSSContainerRule() {
- CSSOM.CSSConditionRule.call(this);
- };
-
- CSSOM.CSSContainerRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
- CSSOM.CSSContainerRule.prototype.constructor = CSSOM.CSSContainerRule;
-
- Object.setPrototypeOf(CSSOM.CSSContainerRule, CSSOM.CSSConditionRule);
-
- Object.defineProperty(CSSOM.CSSContainerRule.prototype, "type", {
- value: 17,
- writable: false
- });
-
- Object.defineProperties(CSSOM.CSSContainerRule.prototype, {
- "cssText": {
- get: function() {
- var values = "";
- var valuesArr = [" {"];
- if (this.cssRules.length) {
- valuesArr.push(this.cssRules.reduce(function(acc, rule){
- if (rule.cssText !== "") {
- acc.push(rule.cssText);
- }
- return acc;
- }, []).join("\n "));
- }
- values = valuesArr.join("\n ") + "\n}";
- return "@container " + this.conditionText + values;
- }
- },
- "containerName": {
- get: function() {
- var parts = this.conditionText.trim().split(/\s+/);
- if (parts.length > 1 && parts[0] !== '(' && !parts[0].startsWith('(')) {
- return parts[0];
- }
- return "";
- }
- },
- "containerQuery": {
- get: function() {
- var parts = this.conditionText.trim().split(/\s+/);
- if (parts.length > 1 && parts[0] !== '(' && !parts[0].startsWith('(')) {
- return parts.slice(1).join(' ');
- }
- return this.conditionText;
- }
- },
- });
-
-
- //.CommonJS
- CSSContainerRule.CSSContainerRule = CSSOM.CSSContainerRule;
- ///CommonJS
- return CSSContainerRule;
-}
-
-var CSSSupportsRule = {};
-
-var hasRequiredCSSSupportsRule;
-
-function requireCSSSupportsRule () {
- if (hasRequiredCSSSupportsRule) return CSSSupportsRule;
- hasRequiredCSSSupportsRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule,
- CSSConditionRule: requireCSSConditionRule().CSSConditionRule
- };
- ///CommonJS
-
-
- /**
- * @constructor
- * @see https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
- */
- CSSOM.CSSSupportsRule = function CSSSupportsRule() {
- CSSOM.CSSConditionRule.call(this);
- };
-
- CSSOM.CSSSupportsRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
- CSSOM.CSSSupportsRule.prototype.constructor = CSSOM.CSSSupportsRule;
-
- Object.setPrototypeOf(CSSOM.CSSSupportsRule, CSSOM.CSSConditionRule);
-
- Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "type", {
- value: 12,
- writable: false
- });
-
- Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "cssText", {
- get: function() {
- var values = "";
- var valuesArr = [" {"];
- if (this.cssRules.length) {
- valuesArr.push(this.cssRules.reduce(function(acc, rule){
- if (rule.cssText !== "") {
- acc.push(rule.cssText);
- }
- return acc;
- }, []).join("\n "));
- }
- values = valuesArr.join("\n ") + "\n}";
- return "@supports " + this.conditionText + values;
- }
- });
-
- //.CommonJS
- CSSSupportsRule.CSSSupportsRule = CSSOM.CSSSupportsRule;
- ///CommonJS
- return CSSSupportsRule;
-}
-
-var CSSFontFaceRule = {};
-
-var hasRequiredCSSFontFaceRule;
-
-function requireCSSFontFaceRule () {
- if (hasRequiredCSSFontFaceRule) return CSSFontFaceRule;
- hasRequiredCSSFontFaceRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration,
- CSSRule: requireCSSRule().CSSRule
- };
- // Use cssstyle if available
- try {
- CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
- } catch (e) {
- // ignore
+ return {
+ type: "compound-selector",
+ selectors
+ };
}
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://dev.w3.org/csswg/cssom/#css-font-face-rule
- */
- CSSOM.CSSFontFaceRule = function CSSFontFaceRule() {
- CSSOM.CSSRule.call(this);
- this.__style = new CSSOM.CSSStyleDeclaration();
- this.__style.parentRule = this;
- };
-
- CSSOM.CSSFontFaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSFontFaceRule.prototype.constructor = CSSOM.CSSFontFaceRule;
-
- Object.setPrototypeOf(CSSOM.CSSFontFaceRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "type", {
- value: 5,
- writable: false
- });
-
- //FIXME
- //CSSOM.CSSFontFaceRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
- //CSSOM.CSSFontFaceRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
-
- Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "style", {
- get: function() {
- return this.__style;
- },
- set: function(value) {
- if (typeof value === "string") {
- this.__style.cssText = value;
- } else {
- this.__style = value;
- }
- }
- });
-
- // http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSFontFaceRule.cpp
- Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "cssText", {
- get: function() {
- return "@font-face {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
- }
- });
-
-
- //.CommonJS
- CSSFontFaceRule.CSSFontFaceRule = CSSOM.CSSFontFaceRule;
- ///CommonJS
- return CSSFontFaceRule;
-}
-
-var CSSHostRule = {};
-
-var hasRequiredCSSHostRule;
-
-function requireCSSHostRule () {
- if (hasRequiredCSSHostRule) return CSSHostRule;
- hasRequiredCSSHostRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList
- };
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://www.w3.org/TR/shadow-dom/#host-at-rule
- * @see http://html5index.org/Shadow%20DOM%20-%20CSSHostRule.html
- * @deprecated This rule was part of early Shadow DOM drafts but was removed in favor of the more flexible :host and :host-context() pseudo-classes in modern CSS for Web Components.
- */
- CSSOM.CSSHostRule = function CSSHostRule() {
- CSSOM.CSSRule.call(this);
- this.cssRules = new CSSOM.CSSRuleList();
- };
-
- CSSOM.CSSHostRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSHostRule.prototype.constructor = CSSOM.CSSHostRule;
-
- Object.setPrototypeOf(CSSOM.CSSHostRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSHostRule.prototype, "type", {
- value: 1001,
- writable: false
- });
-
- //FIXME
- //CSSOM.CSSHostRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
- //CSSOM.CSSHostRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
-
- Object.defineProperty(CSSOM.CSSHostRule.prototype, "cssText", {
- get: function() {
- var values = "";
- var valuesArr = [" {"];
- if (this.cssRules.length) {
- valuesArr.push(this.cssRules.reduce(function(acc, rule){
- if (rule.cssText !== "") {
- acc.push(rule.cssText);
- }
- return acc;
- }, []).join("\n "));
- }
- values = valuesArr.join("\n ") + "\n}";
- return "@host" + values;
+ consumeTypeOrUniversalSelector() {
+ let namespace = void 0;
+ const token = this.cursor.next;
+ if (!token) throw new DOMException("Unexpected EOF in type selector", "SyntaxError");
+ const isNextPipe = isDelimToken(this.cursor.peek(1), "|");
+ const isNextNextPipe = isDelimToken(this.cursor.peek(2), "|");
+ const isColumnCombinator = isNextPipe && isNextNextPipe;
+ if (isIdentToken(token) && isNextPipe && !isColumnCombinator) {
+ namespace = token.value;
+ this.cursor.i += 2;
+ } else if (isDelimToken(token, "*") && isNextPipe && !isColumnCombinator) {
+ namespace = "*";
+ this.cursor.i += 2;
+ } else if (isDelimToken(token, "|") && !isNextPipe) {
+ namespace = "";
+ this.cursor.i += 1;
}
- });
-
-
- //.CommonJS
- CSSHostRule.CSSHostRule = CSSOM.CSSHostRule;
- ///CommonJS
- return CSSHostRule;
-}
-
-var CSSStartingStyleRule = {};
-
-var hasRequiredCSSStartingStyleRule;
-
-function requireCSSStartingStyleRule () {
- if (hasRequiredCSSStartingStyleRule) return CSSStartingStyleRule;
- hasRequiredCSSStartingStyleRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- CSSGroupingRule: requireCSSGroupingRule().CSSGroupingRule
- };
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://www.w3.org/TR/shadow-dom/#host-at-rule
- */
- CSSOM.CSSStartingStyleRule = function CSSStartingStyleRule() {
- CSSOM.CSSGroupingRule.call(this);
- };
-
- CSSOM.CSSStartingStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
- CSSOM.CSSStartingStyleRule.prototype.constructor = CSSOM.CSSStartingStyleRule;
-
- Object.setPrototypeOf(CSSOM.CSSStartingStyleRule, CSSOM.CSSGroupingRule);
-
- Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "type", {
- value: 1002,
- writable: false
- });
-
- //FIXME
- //CSSOM.CSSStartingStyleRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
- //CSSOM.CSSStartingStyleRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
-
- Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "cssText", {
- get: function() {
- var values = "";
- var valuesArr = [" {"];
- if (this.cssRules.length) {
- valuesArr.push(this.cssRules.reduce(function(acc, rule){
- if (rule.cssText !== "") {
- acc.push(rule.cssText);
- }
- return acc;
- }, []).join("\n "));
- }
- values = valuesArr.join("\n ") + "\n}";
- return "@starting-style" + values;
+ const next = this.cursor.consume();
+ if (isDelimToken(next, "*")) {
+ this.validateNamespace(namespace);
+ return {
+ type: "universal-selector",
+ namespace
+ };
}
- });
-
-
- //.CommonJS
- CSSStartingStyleRule.CSSStartingStyleRule = CSSOM.CSSStartingStyleRule;
- ///CommonJS
- return CSSStartingStyleRule;
-}
-
-var CSSKeyframeRule = {};
-
-var hasRequiredCSSKeyframeRule;
-
-function requireCSSKeyframeRule () {
- if (hasRequiredCSSKeyframeRule) return CSSKeyframeRule;
- hasRequiredCSSKeyframeRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSStyleDeclaration: requireCSSStyleDeclaration().CSSStyleDeclaration
- };
- // Use cssstyle if available
- try {
- CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
- } catch (e) {
- // ignore
+ if (!isIdentToken(next)) throw new DOMException("Expected identifier or * after namespace pipe", "SyntaxError");
+ this.validateNamespace(namespace);
+ return {
+ type: "type-selector",
+ name: next.value,
+ namespace
+ };
}
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframeRule
- */
- CSSOM.CSSKeyframeRule = function CSSKeyframeRule() {
- CSSOM.CSSRule.call(this);
- this.keyText = '';
- this.__style = new CSSOM.CSSStyleDeclaration();
- this.__style.parentRule = this;
- };
-
- CSSOM.CSSKeyframeRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSKeyframeRule.prototype.constructor = CSSOM.CSSKeyframeRule;
-
- Object.setPrototypeOf(CSSOM.CSSKeyframeRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "type", {
- value: 8,
- writable: false
- });
-
- //FIXME
- //CSSOM.CSSKeyframeRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
- //CSSOM.CSSKeyframeRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
-
- Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "style", {
- get: function() {
- return this.__style;
- },
- set: function(value) {
- if (typeof value === "string") {
- this.__style.cssText = value;
- } else {
- this.__style = value;
+ consumeClassSelector() {
+ this.cursor.consume();
+ const ident = this.cursor.consume();
+ if (!isIdentToken(ident)) return {
+ type: "class-selector",
+ name: ""
+ };
+ return {
+ type: "class-selector",
+ name: ident.value
+ };
+ }
+ consumeAttributeSelector() {
+ const block = this.cursor.consume();
+ if (!isSimpleBlock(block, "[")) throw new DOMException("Expected attribute selector block", "SyntaxError");
+ const subCursor = new ComponentValueCursor(block.value);
+ let name = "";
+ let namespace = void 0;
+ let operator = "";
+ let value = "";
+ let flags = "";
+ subCursor.skipWhitespace();
+ if (subCursor.hasNext) {
+ const v1 = subCursor.next;
+ const v2 = subCursor.peek(1);
+ const v3 = subCursor.peek(2);
+ const isPipeFollowedByEquals = isDelimToken(v2, "|") && isDelimToken(v3, "=");
+ if (isIdentToken(v1) && isDelimToken(v2, "|") && !isPipeFollowedByEquals) {
+ namespace = v1.value;
+ subCursor.i += 2;
+ } else if (isDelimToken(v1, "*") && isDelimToken(v2, "|") && !isPipeFollowedByEquals) {
+ namespace = "*";
+ subCursor.i += 2;
+ } else if (isDelimToken(v1, "|") && !isDelimToken(v2, "=")) {
+ namespace = "";
+ subCursor.i += 1;
}
}
- });
-
- // http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframeRule.cpp
- Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "cssText", {
- get: function() {
- return this.keyText + " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
- }
- });
-
-
- //.CommonJS
- CSSKeyframeRule.CSSKeyframeRule = CSSOM.CSSKeyframeRule;
- ///CommonJS
- return CSSKeyframeRule;
-}
-
-var CSSKeyframesRule = {};
-
-var hasRequiredCSSKeyframesRule;
-
-function requireCSSKeyframesRule () {
- if (hasRequiredCSSKeyframesRule) return CSSKeyframesRule;
- hasRequiredCSSKeyframesRule = 1;
- //.CommonJS
- var CSSOM = {
- CSSRule: requireCSSRule().CSSRule,
- CSSRuleList: requireCSSRuleList().CSSRuleList,
- parse: requireParse().parse
- };
- var errorUtils = requireErrorUtils().errorUtils;
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframesRule
- */
- CSSOM.CSSKeyframesRule = function CSSKeyframesRule() {
- CSSOM.CSSRule.call(this);
- this.name = '';
- this.cssRules = new CSSOM.CSSRuleList();
-
- // Set up initial indexed access
- this._setupIndexedAccess();
-
- // Override cssRules methods after initial setup, store references as non-enumerable properties
- var self = this;
- var originalPush = this.cssRules.push;
- var originalSplice = this.cssRules.splice;
-
- // Create non-enumerable method overrides
- Object.defineProperty(this.cssRules, 'push', {
- value: function() {
- var result = originalPush.apply(this, arguments);
- self._setupIndexedAccess();
- return result;
- },
- writable: true,
- enumerable: false,
- configurable: true
- });
-
- Object.defineProperty(this.cssRules, 'splice', {
- value: function() {
- var result = originalSplice.apply(this, arguments);
- self._setupIndexedAccess();
- return result;
- },
- writable: true,
- enumerable: false,
- configurable: true
- });
- };
-
- CSSOM.CSSKeyframesRule.prototype = Object.create(CSSOM.CSSRule.prototype);
- CSSOM.CSSKeyframesRule.prototype.constructor = CSSOM.CSSKeyframesRule;
-
- Object.setPrototypeOf(CSSOM.CSSKeyframesRule, CSSOM.CSSRule);
-
- Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "type", {
- value: 7,
- writable: false
- });
-
- // http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframesRule.cpp
- Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "cssText", {
- get: function() {
- var values = "";
- var valuesArr = [" {"];
- if (this.cssRules.length) {
- valuesArr.push(this.cssRules.reduce(function(acc, rule){
- if (rule.cssText !== "") {
- acc.push(rule.cssText);
+ const valName = subCursor.next;
+ if (isIdentToken(valName)) {
+ name = valName.value;
+ subCursor.consume();
+ }
+ subCursor.skipWhitespace();
+ const valOp = subCursor.next;
+ if (isDelimToken(valOp)) {
+ operator = valOp.value;
+ subCursor.consume();
+ const valEq = subCursor.next;
+ if (isDelimToken(valEq, "=")) {
+ operator += valEq.value;
+ subCursor.consume();
}
- return acc;
- }, []).join("\n "));
}
- values = valuesArr.join("\n ") + "\n}";
- var cssWideKeywords = ['initial', 'inherit', 'revert', 'revert-layer', 'unset', 'none'];
- var processedName = cssWideKeywords.includes(this.name) ? '"' + this.name + '"' : this.name;
- return "@" + (this._vendorPrefix || '') + "keyframes " + processedName + values;
- }
- });
-
- /**
- * Appends a new keyframe rule to the list of keyframes.
- *
- * @param {string} rule - The keyframe rule string to append (e.g., "50% { opacity: 0.5; }")
- * @see https://www.w3.org/TR/css-animations-1/#dom-csskeyframesrule-appendrule
- */
- CSSOM.CSSKeyframesRule.prototype.appendRule = function appendRule(rule) {
- if (arguments.length === 0) {
- errorUtils.throwMissingArguments(this, 'appendRule', 'CSSKeyframesRule');
+ subCursor.skipWhitespace();
+ const valVal = subCursor.next;
+ if (isStringToken(valVal) || isIdentToken(valVal)) {
+ value = valVal.value;
+ subCursor.consume();
}
-
- var parsedRule;
- try {
- // Parse the rule string as a keyframe rule
- var tempStyleSheet = CSSOM.parse("@keyframes temp { " + rule + " }");
- if (tempStyleSheet.cssRules.length > 0 && tempStyleSheet.cssRules[0].cssRules.length > 0) {
- parsedRule = tempStyleSheet.cssRules[0].cssRules[0];
- } else {
- throw new Error("Failed to parse keyframe rule");
- }
- } catch (e) {
- errorUtils.throwParseError(this, 'appendRule', 'CSSKeyframesRule', rule);
+ subCursor.skipWhitespace();
+ const valFlag = subCursor.next;
+ if (isIdentToken(valFlag)) {
+ const flagValue = valFlag.value;
+ const lowerFlag = flagValue.toLowerCase();
+ if (lowerFlag !== "i" && lowerFlag !== "s") throw new DOMException(`Invalid attribute selector flag: ${flagValue}`, "SyntaxError");
+ flags = flagValue;
+ subCursor.consume();
}
-
- parsedRule.__parentRule = this;
- this.cssRules.push(parsedRule);
- };
-
- /**
- * Deletes a keyframe rule that matches the specified key.
- *
- * @param {string} select - The keyframe selector to delete (e.g., "50%", "from", "to")
- * @see https://www.w3.org/TR/css-animations-1/#dom-csskeyframesrule-deleterule
- */
- CSSOM.CSSKeyframesRule.prototype.deleteRule = function deleteRule(select) {
- if (arguments.length === 0) {
- errorUtils.throwMissingArguments(this, 'deleteRule', 'CSSKeyframesRule');
+ subCursor.skipWhitespace();
+ if (subCursor.hasNext) throw new DOMException("Unexpected content in attribute selector", "SyntaxError");
+ if (!name) throw new DOMException("Expected attribute name in attribute selector", "SyntaxError");
+ this.validateNamespace(namespace);
+ return {
+ type: "attribute-selector",
+ name,
+ namespace,
+ operator,
+ value,
+ flags
+ };
+ }
+ consumePseudoSelector() {
+ this.cursor.consume();
+ let isPseudoElement = false;
+ if (this.cursor.next?.type === "colon") {
+ this.cursor.consume();
+ isPseudoElement = true;
}
-
- var normalizedSelect = this._normalizeKeyText(select);
-
- for (var i = 0; i < this.cssRules.length; i++) {
- var rule = this.cssRules[i];
- if (this._normalizeKeyText(rule.keyText) === normalizedSelect) {
- rule.__parentRule = null;
- this.cssRules.splice(i, 1);
- return;
+ const token = this.cursor.consume();
+ if (!token) return {
+ type: "pseudo-class-selector",
+ name: ""
+ };
+ if (isIdentToken(token)) {
+ const originalName = token.value;
+ const lowerName = originalName.toLowerCase();
+ const name = LEGACY_PSEUDO_CLASS_ALIASES[lowerName] || originalName;
+ const effectiveLowerName = name.toLowerCase();
+ const isVendorPrefixed = /^-[a-zA-Z0-9]+-/.test(effectiveLowerName);
+ if (isPseudoElement) {
+ if (this.forbidPseudo || this.insideHas) throw new DOMException("Pseudo-elements are not allowed in this context", "SyntaxError");
+ const isAllowedVendor = this.allowVendorPseudos && isVendorPrefixed || !this.strictSupports && effectiveLowerName.startsWith("-webkit-");
+ if (!PSEUDO_ELEMENTS.has(effectiveLowerName) && !isAllowedVendor && !this.allowUnknownPseudos) throw new DOMException(`Unknown pseudo-element ::${name}`, "SyntaxError");
+ return {
+ type: "pseudo-element-selector",
+ name
+ };
+ }
+ if ([
+ "before",
+ "after",
+ "first-line",
+ "first-letter"
+ ].includes(effectiveLowerName)) {
+ if (this.forbidPseudo || this.insideHas) throw new DOMException("Pseudo-elements are not allowed in this context", "SyntaxError");
+ return {
+ type: "pseudo-element-selector",
+ name
+ };
+ }
+ const isAllowedVendor = this.allowVendorPseudos && isVendorPrefixed || !this.strictSupports && effectiveLowerName.startsWith("-webkit-");
+ if (!PSEUDO_CLASSES.has(effectiveLowerName) && !isAllowedVendor && !this.allowUnknownPseudos) throw new DOMException(`Unknown pseudo-class :${name}`, "SyntaxError");
+ return {
+ type: "pseudo-class-selector",
+ name
+ };
+ } else if (isCSSFunction(token)) {
+ const func = token;
+ const name = func.name;
+ const lowerName = name.toLowerCase();
+ const isVendorPrefixed = /^-[a-zA-Z0-9]+-/.test(lowerName);
+ if (isPseudoElement) {
+ if (this.forbidPseudo || this.insideHas) throw new DOMException("Pseudo-elements are not allowed in this context", "SyntaxError");
+ if (!PSEUDO_ELEMENTS.has(lowerName) && !(this.allowVendorPseudos && isVendorPrefixed) && !this.allowUnknownPseudos) throw new DOMException(`Unknown pseudo-element ::${name}()`, "SyntaxError");
+ if (lowerName === "slotted") {
+ const subParser = new SelectorParser(func.value, {
+ insideHas: this.insideHas,
+ forbidPseudo: true,
+ declaredNamespaces: this.declaredNamespaces,
+ strictSupports: this.strictSupports,
+ allowVendorPseudos: this.allowVendorPseudos,
+ allowUnknownPseudos: this.allowUnknownPseudos
+ });
+ subParser.cursor.skipWhitespace();
+ const compound = subParser.consumeCompoundSelector();
+ subParser.cursor.skipWhitespace();
+ if (subParser.cursor.i !== func.value.length || compound.selectors.length === 0) throw new DOMException("Argument to ::slotted() must be a compound selector", "SyntaxError");
+ return {
+ type: "pseudo-element-selector",
+ name,
+ argument: {
+ type: "selector-list",
+ selectors: [{
+ type: "complex-selector",
+ items: [compound],
+ tokens: func.value
+ }]
+ }
+ };
+ }
+ return {
+ type: "pseudo-element-selector",
+ name,
+ argument: func.value
+ };
+ }
+ if (!PSEUDO_CLASSES.has(lowerName) && lowerName !== "matches" && !(this.allowVendorPseudos && isVendorPrefixed) && !this.allowUnknownPseudos) throw new DOMException(`Unknown pseudo-class :${name}()`, "SyntaxError");
+ if ([
+ "is",
+ "not",
+ "has",
+ "where",
+ "matches"
+ ].includes(lowerName)) {
+ const isHas = lowerName === "has";
+ if (isHas && this.insideHas) throw new DOMException(":has() cannot be nested", "SyntaxError");
+ const isForgiving = !this.strictSupports && [
+ "is",
+ "where",
+ "matches"
+ ].includes(lowerName);
+ const isLogicalPseudo = [
+ "is",
+ "where",
+ "not",
+ "matches"
+ ].includes(lowerName);
+ return {
+ type: "pseudo-class-selector",
+ name,
+ argument: new SelectorParser(func.value, {
+ allowRelative: isHas,
+ forgiving: isForgiving,
+ insideHas: isHas || this.insideHas,
+ forbidPseudo: isLogicalPseudo || isHas || this.forbidPseudo,
+ declaredNamespaces: this.declaredNamespaces,
+ strictSupports: this.strictSupports,
+ allowVendorPseudos: this.allowVendorPseudos,
+ allowUnknownPseudos: this.allowUnknownPseudos
+ }).parse()
+ };
+ }
+ if (["host", "host-context"].includes(lowerName)) {
+ const subParser = new SelectorParser(func.value, {
+ insideHas: this.insideHas,
+ forbidPseudo: true,
+ declaredNamespaces: this.declaredNamespaces,
+ strictSupports: this.strictSupports,
+ allowVendorPseudos: this.allowVendorPseudos,
+ allowUnknownPseudos: this.allowUnknownPseudos
+ });
+ subParser.cursor.skipWhitespace();
+ const compound = subParser.consumeCompoundSelector();
+ subParser.cursor.skipWhitespace();
+ if (subParser.cursor.i !== func.value.length || compound.selectors.length === 0) throw new DOMException(`Argument to :${name}() must be a compound selector`, "SyntaxError");
+ return {
+ type: "pseudo-class-selector",
+ name,
+ argument: {
+ type: "selector-list",
+ selectors: [{
+ type: "complex-selector",
+ items: [compound],
+ tokens: func.value
+ }]
+ }
+ };
+ }
+ if ([
+ "nth-child",
+ "nth-last-child",
+ "nth-of-type",
+ "nth-last-of-type"
+ ].includes(lowerName)) {
+ let ofIdx = -1;
+ for (let k = 0; k < func.value.length; k++) {
+ const v = func.value[k];
+ if (isIdentToken(v) && v.value.toLowerCase() === "of") {
+ ofIdx = k;
+ break;
+ }
+ }
+ if (ofIdx !== -1) {
+ if (["nth-of-type", "nth-last-of-type"].includes(lowerName)) throw new DOMException(`'of' is not allowed in :${name}()`, "SyntaxError");
+ const nth = func.value.slice(0, ofIdx);
+ this.validateAnPlusB(nth);
+ return {
+ type: "pseudo-class-selector",
+ name,
+ argument: new SelectorParser(func.value.slice(ofIdx + 1), {
+ insideHas: this.insideHas,
+ forbidPseudo: true,
+ allowRelative: false,
+ declaredNamespaces: this.declaredNamespaces,
+ strictSupports: this.strictSupports,
+ allowVendorPseudos: this.allowVendorPseudos,
+ allowUnknownPseudos: this.allowUnknownPseudos
+ }).parse(),
+ nth
+ };
+ } else {
+ this.validateAnPlusB(func.value);
+ return {
+ type: "pseudo-class-selector",
+ name,
+ argument: func.value,
+ nth: func.value
+ };
+ }
}
+ if (lowerName === "dir") this.validateDir(func.value);
+ if (lowerName === "heading") this.validateHeading(func.value);
+ if (lowerName === "lang") this.validateLang(func.value);
+ return {
+ type: "pseudo-class-selector",
+ name,
+ argument: func.value
+ };
+ }
+ throw new DOMException("Expected identifier or function after colon in pseudo-selector", "SyntaxError");
+ }
+ validateAnPlusB(values) {
+ const res = parseAnPlusB(values);
+ if (!res) {
+ const text = getOriginalText(values).trim();
+ throw new DOMException(`Invalid An+B expression: ${text}`, "SyntaxError");
+ }
+ return res;
+ }
+ validateHeading(values) {
+ const nonComment = values.filter((v) => v.type !== "comment");
+ let start = 0;
+ while (start < nonComment.length && nonComment[start].type === "whitespace") start++;
+ let end = nonComment.length - 1;
+ while (end >= start && nonComment[end].type === "whitespace") end--;
+ if (start > end) throw new DOMException("Argument to :heading() cannot be empty", "SyntaxError");
+ const tokens = nonComment.slice(start, end + 1);
+ let expectInteger = true;
+ for (let i = 0; i < tokens.length; i++) {
+ const t = tokens[i];
+ if (t.type === "whitespace") continue;
+ if (expectInteger) {
+ if (t.type === "number" && t.numberType === "integer") expectInteger = false;
+ else throw new DOMException("Argument to :heading() must be comma-separated integers", "SyntaxError");
+ } else if (t.type === "comma" || t.type === "delim" && t.value === ",") expectInteger = true;
+ else throw new DOMException("Expected comma in :heading() arguments", "SyntaxError");
+ }
+ if (expectInteger) throw new DOMException("Trailing comma in :heading() arguments", "SyntaxError");
+ }
+ validateDir(values) {
+ const nonWs = values.filter((v) => v.type !== "whitespace" && v.type !== "comment");
+ const firstToken = nonWs[0];
+ if (nonWs.length !== 1 || !isIdentToken(firstToken)) throw new DOMException("Argument to :dir() must be a single identifier", "SyntaxError");
+ const val = firstToken.value.toLowerCase();
+ if (val !== "ltr" && val !== "rtl" && val !== "auto") throw new DOMException("Argument to :dir() must be ltr, rtl, or auto", "SyntaxError");
+ }
+ validateLang(values) {
+ const nonWs = values.filter((v) => v.type !== "whitespace" && v.type !== "comment");
+ if (nonWs.length === 0) throw new DOMException("Argument to :lang() cannot be empty", "SyntaxError");
+ let expectItem = true;
+ for (const v of nonWs) if (expectItem) {
+ if (!isIdentToken(v) && !isStringToken(v)) throw new DOMException("Argument to :lang() must be identifiers or strings", "SyntaxError");
+ expectItem = false;
+ } else {
+ if (v.type !== "comma") throw new DOMException("Expected comma in :lang() argument", "SyntaxError");
+ expectItem = true;
}
+ if (expectItem) throw new DOMException("Trailing comma in :lang() argument", "SyntaxError");
+ }
+};
+/**
+* Parses An+B microsyntax into { a, b }.
+*
+* selectors-4 #child-index
+* css-syntax-3 #anb-microsyntax
+* css-syntax-3 #anb-syntax
+* css-syntax-3 #the-anb-type ( production)
+*/
+function parseAnPlusB(values) {
+ const nonComment = values.filter((v) => v.type !== "comment");
+ let start = 0;
+ while (start < nonComment.length && nonComment[start].type === "whitespace") start++;
+ let end = nonComment.length - 1;
+ while (end >= start && nonComment[end].type === "whitespace") end--;
+ if (start > end) return null;
+ const tokens = nonComment.slice(start, end + 1);
+ const isIntegerNumber = (t) => {
+ return isNumberToken(t) && t.numberType === "integer";
};
-
- /**
- * Finds and returns the keyframe rule that matches the specified key.
- * When multiple rules have the same key, returns the last one.
- *
- * @param {string} select - The keyframe selector to find (e.g., "50%", "from", "to")
- * @return {CSSKeyframeRule|null} The matching keyframe rule, or null if not found
- * @see https://www.w3.org/TR/css-animations-1/#dom-csskeyframesrule-findrule
- */
- CSSOM.CSSKeyframesRule.prototype.findRule = function findRule(select) {
- if (arguments.length === 0) {
- errorUtils.throwMissingArguments(this, 'findRule', 'CSSKeyframesRule');
+ if (tokens.length === 1) {
+ const t = tokens[0];
+ if (isIdentToken(t)) {
+ const lower = t.value.toLowerCase();
+ if (lower === "odd") return {
+ a: 2,
+ b: 1
+ };
+ if (lower === "even") return {
+ a: 2,
+ b: 0
+ };
+ if (lower === "n") return {
+ a: 1,
+ b: 0
+ };
+ if (lower === "-n") return {
+ a: -1,
+ b: 0
+ };
+ const matchNdashDigit = lower.match(/^n-(\d+)$/);
+ if (matchNdashDigit) return {
+ a: 1,
+ b: -parseInt(matchNdashDigit[1], 10)
+ };
+ const matchDashNdashDigit = lower.match(/^-n-(\d+)$/);
+ if (matchDashNdashDigit) return {
+ a: -1,
+ b: -parseInt(matchDashNdashDigit[1], 10)
+ };
+ return null;
}
-
- var normalizedSelect = this._normalizeKeyText(select);
-
- // Iterate backwards to find the last matching rule
- for (var i = this.cssRules.length - 1; i >= 0; i--) {
- var rule = this.cssRules[i];
- if (this._normalizeKeyText(rule.keyText) === normalizedSelect) {
- return rule;
- }
+ if (isIntegerNumber(t)) return {
+ a: 0,
+ b: Number(t.value)
+ };
+ if (isDimensionToken(t) && t.numberType === "integer") {
+ const unit = (t.unit || "").toLowerCase();
+ if (unit === "n") return {
+ a: Number(t.value),
+ b: 0
+ };
+ const matchDim = unit.match(/^n-(\d+)$/);
+ if (matchDim) return {
+ a: Number(t.value),
+ b: -parseInt(matchDim[1], 10)
+ };
+ return null;
}
-
return null;
+ }
+ let idx = 0;
+ let plusPrefix = false;
+ if (isDelimToken(tokens[0], "+")) {
+ plusPrefix = true;
+ idx = 1;
+ if (tokens[1]?.type === "whitespace") return null;
+ }
+ const nextNonWs = (from) => {
+ let p = from;
+ while (p < tokens.length && tokens[p].type === "whitespace") p++;
+ return p;
};
-
- /**
- * Normalizes keyframe selector text for comparison.
- * Handles "from" -> "0%" and "to" -> "100%" conversions and trims whitespace.
- *
- * @private
- * @param {string} keyText - The keyframe selector text to normalize
- * @return {string} The normalized keyframe selector text
- */
- CSSOM.CSSKeyframesRule.prototype._normalizeKeyText = function _normalizeKeyText(keyText) {
- if (!keyText) return '';
-
- var normalized = keyText.toString().trim().toLowerCase();
-
- // Convert keywords to percentages for comparison
- if (normalized === 'from') {
- return '0%';
- } else if (normalized === 'to') {
- return '100%';
+ const t1 = tokens[idx];
+ if (!t1) return null;
+ let a = null;
+ let hasDashAfterN = false;
+ if (isIdentToken(t1)) {
+ const lower = t1.value.toLowerCase();
+ if (lower === "n") a = 1;
+ else if (lower === "-n" && !plusPrefix) a = -1;
+ else if (lower === "n-") {
+ a = 1;
+ hasDashAfterN = true;
+ } else if (lower === "-n-" && !plusPrefix) {
+ a = -1;
+ hasDashAfterN = true;
+ } else if (lower.startsWith("n-")) {
+ const match = lower.match(/^n-(\d+)$/);
+ if (match && idx === tokens.length - 1) return {
+ a: 1,
+ b: -parseInt(match[1], 10)
+ };
}
-
- return normalized;
- };
-
- /**
- * Makes CSSKeyframesRule iterable over its cssRules.
- * Allows for...of loops and other iterable methods.
- */
- if (typeof Symbol !== 'undefined' && Symbol.iterator) {
- CSSOM.CSSKeyframesRule.prototype[Symbol.iterator] = function() {
- var index = 0;
- var cssRules = this.cssRules;
-
+ } else if (isDimensionToken(t1) && t1.numberType === "integer" && !plusPrefix) {
+ const unit = (t1.unit || "").toLowerCase();
+ if (unit === "n") a = Number(t1.value);
+ else if (unit === "n-") {
+ a = Number(t1.value);
+ hasDashAfterN = true;
+ }
+ }
+ if (a === null) return null;
+ const afterT1 = nextNonWs(idx + 1);
+ if (afterT1 >= tokens.length) {
+ if (!hasDashAfterN) return {
+ a,
+ b: 0
+ };
+ return null;
+ }
+ const t2 = tokens[afterT1];
+ if (hasDashAfterN) {
+ if (isIntegerNumber(t2) && !t2.sign) {
+ if (nextNonWs(afterT1 + 1) < tokens.length) return null;
return {
- next: function() {
- if (index < cssRules.length) {
- return { value: cssRules[index++], done: false };
- } else {
- return { done: true };
- }
- }
+ a,
+ b: -Number(t2.value)
};
+ }
+ return null;
+ }
+ if (isIntegerNumber(t2) && t2.sign) {
+ if (nextNonWs(afterT1 + 1) < tokens.length) return null;
+ return {
+ a,
+ b: Number(t2.value)
};
}
-
- /**
- * Adds indexed getters for direct access to cssRules by index.
- * This enables rule[0], rule[1], etc. access patterns.
- * Works in environments where Proxy is not available (like jsdom).
- */
- CSSOM.CSSKeyframesRule.prototype._setupIndexedAccess = function() {
- // Remove any existing indexed properties
- for (var i = 0; i < 1000; i++) { // reasonable upper limit
- if (this.hasOwnProperty(i)) {
- delete this[i];
- } else {
- break;
- }
- }
-
- // Add indexed getters for current cssRules
- for (var i = 0; i < this.cssRules.length; i++) {
- (function(index) {
- Object.defineProperty(this, index, {
- get: function() {
- return this.cssRules[index];
- },
- enumerable: false,
- configurable: true
- });
- }.call(this, i));
+ if (isDelimToken(t2, "+") || isDelimToken(t2, "-")) {
+ const sign = t2.value === "+" ? 1 : -1;
+ const afterT2 = nextNonWs(afterT1 + 1);
+ if (afterT2 >= tokens.length) return null;
+ const t3 = tokens[afterT2];
+ if (isIntegerNumber(t3) && !t3.sign) {
+ if (nextNonWs(afterT2 + 1) < tokens.length) return null;
+ return {
+ a,
+ b: sign * Number(t3.value)
+ };
}
-
- // Update length property
- Object.defineProperty(this, 'length', {
- get: function() {
- return this.cssRules.length;
- },
- enumerable: false,
- configurable: true
- });
+ return null;
+ }
+ return null;
+}
+// src/serializer.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+* Determines whether two consecutive tokens require an empty comment separator
+* between them to prevent coalescing per css-syntax-3 #serialization.
+* // css-syntax-3 #serialization-tables
+*/
+function requiresTokenSeparator(t1, t2) {
+ const isIdent1 = t1.type === "ident";
+ const isAtKeyword1 = t1.type === "at-keyword";
+ const isHash1 = t1.type === "hash";
+ const isDimension1 = t1.type === "dimension";
+ const isDelimHash1 = t1.type === "delim" && t1.value === "#";
+ const isDelimDash1 = t1.type === "delim" && t1.value === "-";
+ const isNumber1 = t1.type === "number";
+ const isDelimAt1 = t1.type === "delim" && t1.value === "@";
+ const isDelimDot1 = t1.type === "delim" && t1.value === ".";
+ const isDelimPlus1 = t1.type === "delim" && t1.value === "+";
+ const isDelimSlash1 = t1.type === "delim" && t1.value === "/";
+ if (!isIdent1 && !isAtKeyword1 && !isHash1 && !isDimension1 && !isDelimHash1 && !isDelimDash1 && !isNumber1 && !isDelimAt1 && !isDelimDot1 && !isDelimPlus1 && !isDelimSlash1) return false;
+ const isIdent2 = t2.type === "ident";
+ const isFunction2 = t2.type === "function";
+ const isUrl2 = t2.type === "url";
+ const isBadUrl2 = t2.type === "bad-url";
+ const isDelimDash2 = t2.type === "delim" && t2.value === "-";
+ const isNumber2 = t2.type === "number";
+ const isPercentage2 = t2.type === "percentage";
+ const isDimension2 = t2.type === "dimension";
+ const isCDC2 = t2.type === "CDC";
+ const isOpenParen2 = t2.type === "(" || t2.type === "delim" && t2.value === "(";
+ const isDelimStar2 = t2.type === "delim" && t2.value === "*";
+ const isDelimPercent2 = t2.type === "delim" && t2.value === "%";
+ const inGroupA = isIdent2 || isFunction2 || isUrl2 || isBadUrl2 || isDelimDash2 || isNumber2 || isPercentage2 || isDimension2 || isCDC2;
+ if (isIdent1) return inGroupA || isOpenParen2;
+ if (isAtKeyword1 || isHash1 || isDimension1 || isDelimHash1 || isDelimDash1) return inGroupA;
+ if (isNumber1) return isIdent2 || isFunction2 || isUrl2 || isBadUrl2 || isNumber2 || isPercentage2 || isDimension2 || isCDC2 || isDelimPercent2;
+ if (isDelimAt1) return isIdent2 || isFunction2 || isUrl2 || isBadUrl2 || isDelimDash2 || isCDC2;
+ if (isDelimDot1 || isDelimPlus1) return isNumber2 || isPercentage2 || isDimension2;
+ if (isDelimSlash1) return isDelimStar2;
+ return false;
+}
+function getFirstToken(node) {
+ if (typeof node !== "object" || node === null) return null;
+ if (node.type === "simple-block") return node.associatedToken;
+ if (node.type === "function" && "name" in node) return {
+ type: "function",
+ value: node.name
};
-
-
-
-
-
- //.CommonJS
- CSSKeyframesRule.CSSKeyframesRule = CSSOM.CSSKeyframesRule;
- ///CommonJS
- return CSSKeyframesRule;
+ const t = node;
+ if (t.type === "EOF") return null;
+ return t;
}
-
-var CSSValueExpression = {};
-
-var CSSValue = {};
-
-var hasRequiredCSSValue;
-
-function requireCSSValue () {
- if (hasRequiredCSSValue) return CSSValue;
- hasRequiredCSSValue = 1;
- //.CommonJS
- var CSSOM = {};
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
- *
- * TODO: add if needed
- */
- CSSOM.CSSValue = function CSSValue() {
+function getLastToken(node) {
+ if (typeof node !== "object" || node === null) return null;
+ if (node.type === "simple-block") {
+ const start = node.associatedToken?.value;
+ const end = getMirrorToken(start);
+ return {
+ type: end || ")",
+ value: end
+ };
+ }
+ if (node.type === "function" && "name" in node) return {
+ type: ")",
+ value: ")"
};
-
- CSSOM.CSSValue.prototype = {
- constructor: CSSOM.CSSValue,
-
- // @see: http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
- set cssText(text) {
- var name = this._getConstructorName();
-
- throw new Error('DOMException: property "cssText" of "' + name + '" is readonly and can not be replaced with "' + text + '"!');
- },
-
- get cssText() {
- var name = this._getConstructorName();
-
- throw new Error('getter "cssText" of "' + name + '" is not implemented!');
- },
-
- _getConstructorName: function() {
- var s = this.constructor.toString(),
- c = s.match(/function\s([^\(]+)/),
- name = c[1];
-
- return name;
- }
- };
-
-
- //.CommonJS
- CSSValue.CSSValue = CSSOM.CSSValue;
- ///CommonJS
- return CSSValue;
+ const t = node;
+ if (t.type === "EOF") return null;
+ return t;
}
-
-var hasRequiredCSSValueExpression;
-
-function requireCSSValueExpression () {
- if (hasRequiredCSSValueExpression) return CSSValueExpression;
- hasRequiredCSSValueExpression = 1;
- //.CommonJS
- var CSSOM = {
- CSSValue: requireCSSValue().CSSValue
- };
- ///CommonJS
-
-
- /**
- * @constructor
- * @see http://msdn.microsoft.com/en-us/library/ms537634(v=vs.85).aspx
- *
- */
- CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) {
- this._token = token;
- this._idx = idx;
+/**
+* Serializes an array of CSS component values or tokens back into a CSS string,
+* inserting `/** /` comment separators between adjacent tokens that would otherwise merge.
+*/
+function serialize(nodes, preserveCase = false, propertyName) {
+ if (propertyName === "font-family") return serializeFontFamily(nodes);
+ let result = "";
+ let prevLastToken = null;
+ for (const node of nodes) {
+ if (node.type === "EOF") continue;
+ const firstToken = getFirstToken(node);
+ if (prevLastToken && firstToken && requiresTokenSeparator(prevLastToken, firstToken)) result += "/**/";
+ result += serializeNode(node, preserveCase);
+ const last = getLastToken(node);
+ if (last) prevLastToken = last;
+ }
+ return result;
+}
+function trimWhitespaceTokens(tokens) {
+ let start = 0;
+ while (start < tokens.length && tokens[start].type === "whitespace") start++;
+ let end = tokens.length - 1;
+ while (end >= start && tokens[end].type === "whitespace") end--;
+ return start <= end ? tokens.slice(start, end + 1) : [];
+}
+function serializeNode(node, preserveCase) {
+ if (typeof node !== "object" || node === null || !("type" in node)) return "";
+ if (node.type === "simple-block") {
+ const start = node.associatedToken.value;
+ return start + serialize(node.value, preserveCase) + getMirrorToken(start);
+ }
+ if (node.type === "function" && "name" in node) {
+ let args = node.value;
+ const funcName = preserveCase ? node.name : node.name.toLowerCase();
+ if (funcName === "counter") {
+ let i = args.length - 1;
+ while (i >= 0 && args[i].type === "whitespace") i--;
+ if (i >= 0 && args[i].type === "ident" && args[i].value === "decimal") {
+ let j = i - 1;
+ while (j >= 0 && args[j].type === "whitespace") j--;
+ if (j >= 0 && args[j].type === "comma") args = args.slice(0, j);
+ }
+ } else if (funcName === "url") args = trimWhitespaceTokens(args);
+ else if (funcName === "attr") {
+ let i = 0;
+ while (i < args.length && args[i].type === "whitespace") i++;
+ if (i < args.length && args[i].type === "delim" && args[i].value === "|") {
+ args = args.slice(i + 1);
+ let k = args.length - 1;
+ while (k >= 0 && args[k].type === "whitespace") k--;
+ if (k >= 0 && args[k].type === "string" && args[k].value === "") {
+ let l = k - 1;
+ while (l >= 0 && args[l].type === "whitespace") l--;
+ if (l >= 0 && args[l].type === "comma") args = args.slice(0, l);
+ }
+ }
+ args = trimWhitespaceTokens(args);
+ }
+ return `${funcName}(${serialize(args, preserveCase)})`;
+ }
+ return serializeToken(node, preserveCase);
+}
+function serializeToken(token, preserveCase = false) {
+ switch (token.type) {
+ case "ident": return serializeIdentifier(token.value);
+ case "at-keyword": return "@" + serializeIdentifier(token.value);
+ case "hash": return "#" + token.value;
+ case "string": return preserveCase && token.originalText && !token.originalText.endsWith("\\") ? token.originalText : serializeString(token.value);
+ case "url": return preserveCase ? serializeUrlToken(token.value, token.originalText) : serializeUrl(token.value);
+ case "delim": return token.value === "\\" ? "\\\n" : token.value;
+ case "number": return formatNumber(token.value);
+ case "percentage": return formatNumber(token.value) + "%";
+ case "dimension": return formatNumber(token.value) + (token.unit ? serializeIdentifier(token.unit) : "");
+ case "whitespace": return preserveCase && token.originalText ? token.originalText : token.value;
+ case "comment": return token.value || "/**/";
+ case "CDO": return "";
+ case "colon": return ":";
+ case "semicolon": return ";";
+ case "comma": return ",";
+ case "[":
+ case "]":
+ case "{":
+ case "}":
+ case "(":
+ case ")": return token.value;
+ case "function": return serializeIdentifier(preserveCase ? token.value : token.value.toLowerCase()) + "(";
+ case "unicode-range": return token.value;
+ case "EOF": return "";
+ default: return token.value || "";
+ }
+}
+function getMirrorToken(start) {
+ if (start === "{") return "}";
+ if (start === "[") return "]";
+ if (start === "(") return ")";
+ return "";
+}
+function getOriginalText(values) {
+ let text = "";
+ for (const val of values) if (val.type === "simple-block") text += (val.associatedToken.originalText || "") + getOriginalText(val.value) + getMirrorToken(val.associatedToken.value);
+ else if (val.type === "function") {
+ const func = val;
+ text += `${func.name}(${getOriginalText(func.value)})`;
+ } else text += val.originalText || val.value;
+ return text;
+}
+/**
+* // cssom-1 #serialize-an-identifier
+*/
+function serializeIdentifier(id) {
+ let result = "";
+ for (let i = 0; i < id.length; i++) {
+ const charCode = id.charCodeAt(i);
+ const char = id[i];
+ if (charCode === 0) {
+ result += "�";
+ continue;
+ }
+ if (charCode >= 1 && charCode <= 31 || charCode === 127) {
+ result += escapeAsCodePoint(charCode);
+ continue;
+ }
+ if (i === 0 && charCode >= 48 && charCode <= 57) {
+ result += escapeAsCodePoint(charCode);
+ continue;
+ }
+ if (i === 1 && charCode >= 48 && charCode <= 57 && id.charCodeAt(0) === 45) {
+ result += escapeAsCodePoint(charCode);
+ continue;
+ }
+ if (i === 0 && charCode === 45 && id.length === 1) {
+ result += "\\-";
+ continue;
+ }
+ if (charCode >= 128 || charCode === 45 || charCode === 95 || charCode >= 48 && charCode <= 57 || charCode >= 65 && charCode <= 90 || charCode >= 97 && charCode <= 122) {
+ result += char;
+ continue;
+ }
+ result += "\\" + char;
+ }
+ return result;
+}
+/**
+* // cssom-1 #serialize-a-string
+*/
+function serializeString(s) {
+ let result = "\"";
+ for (let i = 0; i < s.length; i++) {
+ const charCode = s.charCodeAt(i);
+ const char = s[i];
+ if (charCode === 0) {
+ result += "�";
+ continue;
+ }
+ if (charCode >= 1 && charCode <= 31 || charCode === 127) {
+ result += escapeAsCodePoint(charCode);
+ continue;
+ }
+ if (charCode === 34 || charCode === 92) {
+ result += "\\" + char;
+ continue;
+ }
+ result += char;
+ }
+ result += "\"";
+ return result;
+}
+function serializeUrl(val) {
+ return `url(${serializeString(val)})`;
+}
+function serializeUrlToken(val, originalText) {
+ if (originalText && !val.includes("�") && originalText.endsWith(")")) return originalText;
+ let result = "";
+ for (let i = 0; i < val.length; i++) {
+ const charCode = val.charCodeAt(i);
+ const char = val[i];
+ if (charCode === 34 || charCode === 39 || charCode === 40 || charCode === 41 || charCode === 92 || charCode <= 32 || charCode === 127) result += "\\" + char;
+ else result += char;
+ }
+ return `url(${result})`;
+}
+function escapeAsCodePoint(charCode) {
+ return "\\" + charCode.toString(16) + " ";
+}
+const logicalShorthandsEntries = Object.entries({
+ "margin-inline": {
+ start: "margin-inline-start",
+ end: "margin-inline-end",
+ allowDifferent: true
+ },
+ "padding-inline": {
+ start: "padding-inline-start",
+ end: "padding-inline-end",
+ allowDifferent: true
+ },
+ "margin-block": {
+ start: "margin-block-start",
+ end: "margin-block-end",
+ allowDifferent: true
+ },
+ "padding-block": {
+ start: "padding-block-start",
+ end: "padding-block-end",
+ allowDifferent: true
+ },
+ "inset-inline": {
+ start: "inset-inline-start",
+ end: "inset-inline-end",
+ allowDifferent: true
+ },
+ "inset-block": {
+ start: "inset-block-start",
+ end: "inset-block-end",
+ allowDifferent: true
+ },
+ "border-inline-width": {
+ start: "border-inline-start-width",
+ end: "border-inline-end-width",
+ allowDifferent: true
+ },
+ "border-block-width": {
+ start: "border-block-start-width",
+ end: "border-block-end-width",
+ allowDifferent: true
+ },
+ "border-inline-style": {
+ start: "border-inline-start-style",
+ end: "border-inline-end-style",
+ allowDifferent: true
+ },
+ "border-block-style": {
+ start: "border-block-start-style",
+ end: "border-block-end-style",
+ allowDifferent: true
+ },
+ "border-inline-color": {
+ start: "border-inline-start-color",
+ end: "border-inline-end-color",
+ allowDifferent: true
+ },
+ "border-block-color": {
+ start: "border-block-start-color",
+ end: "border-block-end-color",
+ allowDifferent: true
+ },
+ "border-inline": {
+ start: "border-inline-start",
+ end: "border-inline-end",
+ allowDifferent: false
+ },
+ "border-block": {
+ start: "border-block-start",
+ end: "border-block-end",
+ allowDifferent: false
+ },
+ "overflow": {
+ start: "overflow-x",
+ end: "overflow-y",
+ allowDifferent: true
+ },
+ "overscroll-behavior": {
+ start: "overscroll-behavior-x",
+ end: "overscroll-behavior-y",
+ allowDifferent: true
+ }
+});
+const propertyToGroup = {
+ "margin-top": "margin",
+ "margin-right": "margin",
+ "margin-bottom": "margin",
+ "margin-left": "margin",
+ "margin-inline-start": "margin",
+ "margin-inline-end": "margin",
+ "margin-block-start": "margin",
+ "margin-block-end": "margin",
+ "padding-top": "padding",
+ "padding-right": "padding",
+ "padding-bottom": "padding",
+ "padding-left": "padding",
+ "padding-inline-start": "padding",
+ "padding-inline-end": "padding",
+ "padding-block-start": "padding",
+ "padding-block-end": "padding",
+ "top": "inset",
+ "right": "inset",
+ "bottom": "inset",
+ "left": "inset",
+ "inset-inline-start": "inset",
+ "inset-inline-end": "inset",
+ "inset-block-start": "inset",
+ "inset-block-end": "inset",
+ "border-top-width": "border-width",
+ "border-right-width": "border-width",
+ "border-bottom-width": "border-width",
+ "border-left-width": "border-width",
+ "border-inline-start-width": "border-width",
+ "border-inline-end-width": "border-width",
+ "border-block-start-width": "border-width",
+ "border-block-end-width": "border-width",
+ "border-top-style": "border-style",
+ "border-right-style": "border-style",
+ "border-bottom-style": "border-style",
+ "border-left-style": "border-style",
+ "border-inline-start-style": "border-style",
+ "border-inline-end-style": "border-style",
+ "border-block-start-style": "border-style",
+ "border-block-end-style": "border-style",
+ "border-top-color": "border-color",
+ "border-right-color": "border-color",
+ "border-bottom-color": "border-color",
+ "border-left-color": "border-color",
+ "border-inline-start-color": "border-color",
+ "border-inline-end-color": "border-color",
+ "border-block-start-color": "border-color",
+ "border-block-end-color": "border-color",
+ "width": "size",
+ "height": "size",
+ "inline-size": "size",
+ "block-size": "size",
+ "min-width": "min-size",
+ "min-height": "min-size",
+ "min-inline-size": "min-size",
+ "min-block-size": "min-size",
+ "max-width": "max-size",
+ "max-height": "max-size",
+ "max-inline-size": "max-size",
+ "max-block-size": "max-size",
+ "border-top-left-radius": "border-radius",
+ "border-top-right-radius": "border-radius",
+ "border-bottom-right-radius": "border-radius",
+ "border-bottom-left-radius": "border-radius",
+ "border-start-start-radius": "border-radius",
+ "border-start-end-radius": "border-radius",
+ "border-end-start-radius": "border-radius",
+ "border-end-end-radius": "border-radius",
+ "border-top": "border",
+ "border-right": "border",
+ "border-bottom": "border",
+ "border-left": "border",
+ "border-block-start": "border",
+ "border-block-end": "border",
+ "border-inline-start": "border",
+ "border-inline-end": "border",
+ "overflow-x": "overflow",
+ "overflow-y": "overflow",
+ "overflow-inline": "overflow",
+ "overflow-block": "overflow",
+ "overscroll-behavior-x": "overscroll-behavior",
+ "overscroll-behavior-y": "overscroll-behavior",
+ "overscroll-behavior-inline": "overscroll-behavior",
+ "overscroll-behavior-block": "overscroll-behavior",
+ "outline-color": "outline",
+ "outline-style": "outline",
+ "outline-width": "outline",
+ "list-style-type": "list-style",
+ "list-style-position": "list-style",
+ "list-style-image": "list-style",
+ "flex-grow": "flex",
+ "flex-shrink": "flex",
+ "flex-basis": "flex",
+ "font-style": "font",
+ "font-variant-caps": "font",
+ "font-weight": "font",
+ "font-stretch": "font",
+ "font-size": "font",
+ "line-height": "font",
+ "font-family": "font",
+ "font-variant-ligatures": "font-variant",
+ "font-variant-alternates": "font-variant",
+ "font-variant-numeric": "font-variant",
+ "font-variant-east-asian": "font-variant",
+ "font-variant-position": "font-variant",
+ "font-variant-emoji": "font-variant"
+};
+const genericShorthands = {
+ "border-top": [
+ "border-top-width",
+ "border-top-style",
+ "border-top-color"
+ ],
+ "border-right": [
+ "border-right-width",
+ "border-right-style",
+ "border-right-color"
+ ],
+ "border-bottom": [
+ "border-bottom-width",
+ "border-bottom-style",
+ "border-bottom-color"
+ ],
+ "border-left": [
+ "border-left-width",
+ "border-left-style",
+ "border-left-color"
+ ],
+ "border-block-start": [
+ "border-block-start-width",
+ "border-block-start-style",
+ "border-block-start-color"
+ ],
+ "border-block-end": [
+ "border-block-end-width",
+ "border-block-end-style",
+ "border-block-end-color"
+ ],
+ "border-inline-start": [
+ "border-inline-start-width",
+ "border-inline-start-style",
+ "border-inline-start-color"
+ ],
+ "border-inline-end": [
+ "border-inline-end-width",
+ "border-inline-end-style",
+ "border-inline-end-color"
+ ],
+ "outline": [
+ "outline-color",
+ "outline-style",
+ "outline-width"
+ ],
+ "list-style": [
+ "list-style-type",
+ "list-style-position",
+ "list-style-image"
+ ],
+ "flex": [
+ "flex-grow",
+ "flex-shrink",
+ "flex-basis"
+ ],
+ "border-image": [
+ "border-image-source",
+ "border-image-slice",
+ "border-image-width",
+ "border-image-outset",
+ "border-image-repeat"
+ ],
+ "line-clamp": [
+ "max-lines",
+ "block-ellipsis",
+ "continue"
+ ]
+};
+const genericShorthandsEntries = Object.entries(genericShorthands);
+function checkIntervening(decls, allDecls, declIndices) {
+ const indices = decls.map((d) => declIndices.get(d));
+ const startIdx = Math.min(...indices);
+ const endIdx = Math.max(...indices);
+ const names = new Set(decls.map((d) => d.name));
+ const groups = new Set(decls.map((d) => propertyToGroup[d.name]).filter(Boolean));
+ const isSideShorthand = groups.size > 1;
+ for (let i = startIdx + 1; i < endIdx; i++) {
+ const intervening = allDecls[i];
+ if (names.has(intervening.name)) continue;
+ const interveningGroup = propertyToGroup[intervening.name];
+ if (!interveningGroup) continue;
+ if (isSideShorthand) {
+ const sidePrefix = decls[0].name.replace(/-(width|style|color)$/, "");
+ if (intervening.name.startsWith(sidePrefix + "-") || ["all", "border"].includes(intervening.name)) return true;
+ } else {
+ if (groups.has(interveningGroup)) return true;
+ if (["all", "border"].includes(intervening.name)) return true;
+ }
+ }
+ return false;
+}
+const BOX_SHORTHAND_NAMES = /* @__PURE__ */ new Set("margin,padding,border-width,border-style,border-color,scroll-margin,scroll-padding,inset,overflow-clip-margin,border-radius".split(","));
+const BOX_SHORTHAND_ENTRIES = Object.entries(SHORTHANDS).filter(([shorthand, def]) => BOX_SHORTHAND_NAMES.has(shorthand) && def.logicalLonghands?.length === 4);
+function tryCombineBoxShorthand(d, declMap, processed, declarations, declIndices) {
+ for (const [shorthand, def] of BOX_SHORTHAND_ENTRIES) {
+ const physical = def.longhands;
+ const logical = def.logicalLonghands;
+ const isPhysical = physical.includes(d.name);
+ const isLogical = logical.includes(d.name);
+ if (!isPhysical && !isLogical) continue;
+ const allDecls = (isPhysical ? physical : logical).map((name) => declMap.get(name));
+ if (!allDecls.every((other) => other && !processed.has(other) && other.important === d.important)) continue;
+ if (checkIntervening(allDecls, declarations, declIndices)) continue;
+ const valuesForContract = {};
+ for (const other of allDecls) valuesForContract[other.name] = other.value;
+ const value = def.contract(valuesForContract);
+ if (value !== null) {
+ for (const other of allDecls) processed.add(other);
+ return `${shorthand}: ${value}${d.important ? " !important" : ""}`;
+ }
+ }
+ return null;
+}
+function tryCombineLogicalShorthand(d, declMap, processed, declarations, declIndices) {
+ for (const [shorthand, longhands] of logicalShorthandsEntries) {
+ if (d.name !== longhands.start && d.name !== longhands.end) continue;
+ const otherName = d.name === longhands.start ? longhands.end : longhands.start;
+ const otherDecl = declMap.get(otherName);
+ if (!otherDecl || processed.has(otherDecl) || d.important !== otherDecl.important) continue;
+ if (checkIntervening([d, otherDecl], declarations, declIndices)) continue;
+ const startDecl = d.name === longhands.start ? d : otherDecl;
+ const endDecl = d.name === longhands.end ? d : otherDecl;
+ const valS = serialize(startDecl.value).trim();
+ const valE = serialize(endDecl.value).trim();
+ if (valS === valE) {
+ processed.add(startDecl);
+ processed.add(endDecl);
+ return `${shorthand}: ${valS}${d.important ? " !important" : ""}`;
+ }
+ if (longhands.allowDifferent && !valS.includes("var(") && !valE.includes("var(")) {
+ processed.add(startDecl);
+ processed.add(endDecl);
+ return `${shorthand}: ${valS} ${valE}${d.important ? " !important" : ""}`;
+ }
+ }
+ return null;
+}
+function tryCombineGenericShorthand(d, declMap, processed, declarations, declIndices) {
+ for (const [shorthand, longhands] of genericShorthandsEntries) {
+ if (!longhands.includes(d.name)) continue;
+ const allDecls = longhands.map((name) => declMap.get(name));
+ if (!allDecls.every((other) => other && !processed.has(other) && other.important === d.important)) continue;
+ if (checkIntervening(allDecls, declarations, declIndices)) continue;
+ const record = {};
+ for (const other of allDecls) record[other.name] = other.value;
+ const contracted = SHORTHANDS[shorthand]?.contract(record);
+ if (contracted !== null && contracted !== void 0) {
+ for (const other of allDecls) processed.add(other);
+ return {
+ name: shorthand,
+ value: contracted,
+ important: d.important
+ };
+ }
+ }
+ return null;
+}
+const BORDER_PHYSICAL_SIDE_LONGHANDS = [
+ "border-top-width",
+ "border-top-style",
+ "border-top-color",
+ "border-right-width",
+ "border-right-style",
+ "border-right-color",
+ "border-bottom-width",
+ "border-bottom-style",
+ "border-bottom-color",
+ "border-left-width",
+ "border-left-style",
+ "border-left-color"
+];
+const BORDER_IMAGE_LONGHAND_NAMES = [
+ "border-image-source",
+ "border-image-slice",
+ "border-image-width",
+ "border-image-outset",
+ "border-image-repeat"
+];
+function tryCombineBorderFull(d, declMap, processed, declarations, declIndices) {
+ if (!BORDER_PHYSICAL_SIDE_LONGHANDS.includes(d.name)) return null;
+ const allDecls = BORDER_PHYSICAL_SIDE_LONGHANDS.map((name) => declMap.get(name));
+ if (!allDecls.every((other) => other && !processed.has(other) && other.important === d.important)) return null;
+ if (checkIntervening(allDecls, declarations, declIndices)) return null;
+ const imageDecls = BORDER_IMAGE_LONGHAND_NAMES.map((name) => declMap.get(name)).filter((img) => Boolean(img && !processed.has(img)));
+ if (imageDecls.length === 0) return null;
+ const imageRecord = {
+ "border-image-source": [{
+ type: "ident",
+ value: "none"
+ }],
+ "border-image-slice": [{
+ type: "percentage",
+ value: 100,
+ sign: null
+ }],
+ "border-image-width": [{
+ type: "number",
+ value: 1,
+ sign: null,
+ numberType: "integer"
+ }],
+ "border-image-outset": [{
+ type: "number",
+ value: 0,
+ sign: null,
+ numberType: "integer"
+ }],
+ "border-image-repeat": [{
+ type: "ident",
+ value: "stretch"
+ }]
};
-
- CSSOM.CSSValueExpression.prototype = Object.create(CSSOM.CSSValue.prototype);
- CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression;
-
- Object.setPrototypeOf(CSSOM.CSSValueExpression, CSSOM.CSSValue);
-
- /**
- * parse css expression() value
- *
- * @return {Object}
- * - error:
- * or
- * - idx:
- * - expression:
- *
- * Example:
- *
- * .selector {
- * zoom: expression(documentElement.clientWidth > 1000 ? '1000px' : 'auto');
- * }
- */
- CSSOM.CSSValueExpression.prototype.parse = function() {
- var token = this._token,
- idx = this._idx;
-
- var character = '',
- expression = '',
- error = '',
- info,
- paren = [];
-
-
- for (; ; ++idx) {
- character = token.charAt(idx);
-
- // end of token
- if (character === '') {
- error = 'css expression error: unfinished expression!';
- break;
+ for (const img of imageDecls) imageRecord[img.name] = img.value;
+ if (!isInitialBorderImage(imageRecord)) return null;
+ const record = { ...imageRecord };
+ for (const other of allDecls) record[other.name] = other.value;
+ const contracted = SHORTHANDS["border"]?.contract(record);
+ if (contracted !== null && contracted !== void 0) {
+ for (const other of allDecls) processed.add(other);
+ for (const img of imageDecls) processed.add(img);
+ return `border: ${contracted}${d.important ? " !important" : ""}`;
+ }
+ return null;
+}
+const ORDERED_SHORTHAND_COMBINERS = [
+ {
+ name: "font",
+ longhands: SHORTHANDS["font"].longhands
+ },
+ {
+ name: "font-variant",
+ longhands: SHORTHANDS["font-variant"].longhands
+ },
+ {
+ name: "background",
+ longhands: [
+ "background-image",
+ "background-position",
+ "background-size",
+ "background-repeat",
+ "background-attachment",
+ "background-origin",
+ "background-clip",
+ "background-color"
+ ]
+ },
+ {
+ name: "border-block",
+ longhands: [
+ "border-block-start-width",
+ "border-block-start-style",
+ "border-block-start-color",
+ "border-block-end-width",
+ "border-block-end-style",
+ "border-block-end-color"
+ ]
+ },
+ {
+ name: "border-inline",
+ longhands: [
+ "border-inline-start-width",
+ "border-inline-start-style",
+ "border-inline-start-color",
+ "border-inline-end-width",
+ "border-inline-end-style",
+ "border-inline-end-color"
+ ]
+ }
+];
+function tryCombineNamedShorthand(shorthandName, longhands, d, declMap, processed, declarations, declIndices) {
+ if (!longhands.includes(d.name)) return null;
+ const allDecls = longhands.map((name) => declMap.get(name));
+ if (!allDecls.every((other) => other && !processed.has(other) && other.important === d.important)) return null;
+ if (checkIntervening(allDecls, declarations, declIndices)) return null;
+ const record = {};
+ for (const other of allDecls) record[other.name] = other.value;
+ const contracted = SHORTHANDS[shorthandName]?.contract(record);
+ if (contracted !== null && contracted !== void 0) {
+ for (const other of allDecls) processed.add(other);
+ return `${shorthandName}: ${contracted}${d.important ? " !important" : ""}`;
+ }
+ return null;
+}
+const CSS_WIDE_AND_DEFAULT = /* @__PURE__ */ new Set("initial,inherit,unset,revert,revert-layer,default".split(","));
+function serializeFontFamilyItem(tokens) {
+ const nonWs = tokens.filter((t) => t.type !== "whitespace" && t.type !== "comment" && t.type !== "EOF");
+ if (nonWs.length === 1 && nonWs[0].type === "string") {
+ let strVal = nonWs[0].value;
+ if (strVal.startsWith("'") && strVal.endsWith("'") || strVal.startsWith("\"") && strVal.endsWith("\"")) strVal = strVal.slice(1, -1);
+ const lower = strVal.toLowerCase();
+ if (GENERIC_FONT_FAMILIES.has(lower) || CSS_WIDE_AND_DEFAULT.has(lower)) return `"${strVal}"`;
+ if (strVal !== strVal.trim() || /\s{2,}|\t|\n|\r/.test(strVal)) return `"${strVal}"`;
+ const words = strVal.split(" ");
+ return words.length > 0 && words.every((word) => word.length > 0 && !/^[0-9]|^--|^-[0-9]/.test(word) && /^[a-zA-Z_-][a-zA-Z0-9_-]*$/.test(word)) ? strVal : `"${strVal}"`;
+ }
+ if (nonWs.every((t) => t.type === "ident")) return nonWs.map((t) => serializeNode(t, false)).join(" ");
+ return tokens.map((t) => serializeNode(t, false)).join("");
+}
+function serializeFontFamily(values) {
+ const groups = [];
+ let current = [];
+ for (const token of values) if (token.type === "comma") {
+ groups.push(current);
+ current = [];
+ } else current.push(token);
+ if (current.length > 0) groups.push(current);
+ return groups.map((g) => serializeFontFamilyItem(g).trim()).filter((s) => s.length > 0).join(", ");
+}
+function serializeDeclarations(declarations) {
+ if (declarations.length === 0) return "";
+ const declMap = /* @__PURE__ */ new Map();
+ const declIndices = /* @__PURE__ */ new Map();
+ for (let i = 0; i < declarations.length; i++) {
+ const d = declarations[i];
+ declMap.set(d.name, d);
+ declIndices.set(d, i);
+ }
+ if (declarations.length >= ALL_SHORTHAND_LONGHANDS.length) {
+ const firstDecl = declMap.get(ALL_SHORTHAND_LONGHANDS[0]);
+ if (firstDecl) {
+ const firstValLower = serialize(firstDecl.value).trim().toLowerCase();
+ const firstImportant = firstDecl.important;
+ if (CSS_WIDE_AND_DEFAULT.has(firstValLower) || firstValLower.startsWith("var(")) {
+ if (ALL_SHORTHAND_LONGHANDS.every((lh) => {
+ const d = declMap.get(lh);
+ return d && serialize(d.value).trim().toLowerCase() === firstValLower && d.important === firstImportant;
+ })) {
+ const allLonghandsSet = new Set(ALL_SHORTHAND_LONGHANDS);
+ const allDecl = {
+ type: "declaration",
+ name: "all",
+ value: firstDecl.value,
+ important: firstImportant
+ };
+ const newDecls = [];
+ let inserted = false;
+ for (const d of declarations) if (allLonghandsSet.has(d.name)) {
+ if (!inserted) {
+ newDecls.push(allDecl);
+ inserted = true;
+ }
+ } else newDecls.push(d);
+ return serializeDeclarations(newDecls);
+ }
}
-
- switch(character) {
- case '(':
- paren.push(character);
- expression += character;
- break;
-
- case ')':
- paren.pop(character);
- expression += character;
- break;
-
- case '/':
- if ((info = this._parseJSComment(token, idx))) { // comment?
- if (info.error) {
- error = 'css expression error: unfinished comment in expression!';
- } else {
- idx = info.idx;
- // ignore the comment
+ }
+ }
+ const processed = /* @__PURE__ */ new Set();
+ const result = [];
+ for (const d of declarations) {
+ if (processed.has(d)) continue;
+ let combined = tryCombineBorderFull(d, declMap, processed, declarations, declIndices);
+ if (!combined) for (const spec of ORDERED_SHORTHAND_COMBINERS) {
+ combined = tryCombineNamedShorthand(spec.name, spec.longhands, d, declMap, processed, declarations, declIndices);
+ if (combined) break;
+ }
+ if (!combined) combined = tryCombineBoxShorthand(d, declMap, processed, declarations, declIndices);
+ if (!combined) {
+ const generic = tryCombineGenericShorthand(d, declMap, processed, declarations, declIndices);
+ if (generic) {
+ const sides = [
+ "border-top",
+ "border-right",
+ "border-bottom",
+ "border-left"
+ ];
+ if (sides.includes(generic.name)) {
+ const sideResults = sides.map((side) => {
+ if (side === generic.name) return generic;
+ const existing = declMap.get(side);
+ if (existing && !processed.has(existing)) return {
+ name: side,
+ value: serialize(existing.value).trim(),
+ important: existing.important,
+ decl: existing
+ };
+ const longhands = genericShorthands[side];
+ if (!longhands) return null;
+ const sideLonghands = longhands.map((lh) => declMap.get(lh));
+ if (sideLonghands.every((lh) => lh && !processed.has(lh) && lh.important === generic.important)) {
+ if (checkIntervening(sideLonghands, declarations, declIndices)) return null;
+ return {
+ name: side,
+ value: sideLonghands.map((lh) => serialize(lh.value).trim()).filter((v) => v !== "").join(" "),
+ important: generic.important,
+ longhands: sideLonghands
+ };
}
- } else if ((info = this._parseJSRexExp(token, idx))) { // regexp
- idx = info.idx;
- expression += info.text;
- } else { // other
- expression += character;
+ return null;
+ });
+ if (sideResults.every((r) => r !== null && r.value === generic.value && r.important === generic.important)) {
+ for (const r of sideResults) if (r && "longhands" in r) r.longhands.forEach((lh) => processed.add(lh));
+ else if (r && "decl" in r) processed.add(r.decl);
+ combined = `border: ${generic.value}${generic.important ? " !important" : ""}`;
+ } else combined = `${generic.name}: ${generic.value}${generic.important ? " !important" : ""}`;
+ } else combined = `${generic.name}: ${generic.value}${generic.important ? " !important" : ""}`;
+ }
+ }
+ if (!combined) combined = tryCombineLogicalShorthand(d, declMap, processed, declarations, declIndices);
+ if (combined) result.push(combined);
+ else {
+ const isCustom = d.name.startsWith("--");
+ let val;
+ if (d.name === "font-family") val = serializeFontFamily(d.value);
+ else if (d.name === "flex-basis" && serialize(d.value).trim() === "0") val = "0px";
+ else val = d.raw && !d.raw.includes("var(") ? d.raw : serialize(d.value, isCustom, d.name).trim();
+ result.push(`${serializeIdentifier(d.name)}: ${val}${d.important ? " !important" : ""}`);
+ processed.add(d);
+ }
+ }
+ return result.join("; ") + ";";
+}
+function serializeSelectorList(list, nsContext) {
+ const context = {
+ hasDefaultNamespace: typeof nsContext === "boolean" ? nsContext : Boolean(nsContext?.hasDefaultNamespace),
+ defaultNamespacePrefixes: typeof nsContext === "object" && nsContext !== null ? nsContext.defaultNamespacePrefixes : void 0
+ };
+ return list.selectors.map((s) => s.type === "invalid-selector" ? serialize(s.tokens) : serializeComplexSelector(s, context)).join(", ");
+}
+function serializeComplexSelector(complex, nsContext) {
+ const { hasDefaultNamespace, defaultNamespacePrefixes } = nsContext;
+ return complex.items.map((item, idx) => {
+ if (item.type === "combinator") {
+ if (item.value === " ") return " ";
+ return idx === 0 ? `${item.value} ` : ` ${item.value} `;
+ }
+ return item.selectors.filter((s, sIdx) => {
+ if (s.type === "universal-selector" && item.selectors.length > 1 && sIdx === 0) {
+ const isDefaultNs = s.namespace !== void 0 && s.namespace !== "" && defaultNamespacePrefixes?.has(s.namespace);
+ if (s.namespace === void 0 || isDefaultNs || s.namespace === "*" && !hasDefaultNamespace) return false;
+ }
+ return true;
+ }).map((s) => serializeSimpleSelector(s, nsContext)).join("");
+ }).join("");
+}
+function formatAnPlusB(tokens) {
+ const parsed = parseAnPlusB(tokens);
+ if (parsed === null) return serialize(tokens).trim();
+ const { a, b } = parsed;
+ if (a === 0) return b.toString();
+ const partA = a === 1 ? "n" : a === -1 ? "-n" : `${a}n`;
+ if (b === 0) return partA;
+ return b > 0 ? `${partA}+${b}` : `${partA}${b}`;
+}
+function formatSelectorNamespacePrefix(namespace, nsContext, isElementSelector) {
+ if (namespace === void 0) return "";
+ if (isElementSelector && namespace !== "" && nsContext.defaultNamespacePrefixes?.has(namespace)) return "";
+ if (namespace === "*") return !isElementSelector || nsContext.hasDefaultNamespace ? "*|" : "";
+ if (namespace === "") return isElementSelector ? "|" : "";
+ return `${serializeIdentifier(namespace)}|`;
+}
+const NTH_PSEUDO_CLASSES = /* @__PURE__ */ new Set("nth-child,nth-last-child,nth-of-type,nth-last-of-type".split(","));
+function serializeSimpleSelector(simple, nsContext) {
+ switch (simple.type) {
+ case "type-selector": return formatSelectorNamespacePrefix(simple.namespace, nsContext, true) + serializeIdentifier(simple.name);
+ case "universal-selector": return formatSelectorNamespacePrefix(simple.namespace, nsContext, true) + "*";
+ case "id-selector": return "#" + serializeIdentifier(simple.name);
+ case "class-selector": return "." + serializeIdentifier(simple.name);
+ case "attribute-selector": {
+ let attr = "[" + formatSelectorNamespacePrefix(simple.namespace, nsContext, false) + serializeIdentifier(simple.name);
+ if (simple.operator) attr += simple.operator + serializeString(simple.value || "");
+ if (simple.flags) attr += " " + simple.flags;
+ return attr + "]";
+ }
+ case "pseudo-class-selector": {
+ let pc = `:${simple.name}`;
+ const isNth = NTH_PSEUDO_CLASSES.has(simple.name.toLowerCase());
+ if (simple.argument) {
+ if ("type" in simple.argument && simple.argument.type === "selector-list") {
+ const selStr = serializeSelectorList(simple.argument, nsContext);
+ pc += isNth && simple.nth ? `(${formatAnPlusB(simple.nth)} of ${selStr})` : `(${selStr})`;
+ } else {
+ const tokens = simple.argument;
+ pc += `(${isNth ? formatAnPlusB(tokens) : serialize(tokens).trim()})`;
+ }
+ }
+ return pc;
+ }
+ case "pseudo-element-selector": {
+ let pe = `::${simple.name}`;
+ if (simple.argument) pe += "type" in simple.argument && simple.argument.type === "selector-list" ? `(${serializeSelectorList(simple.argument, nsContext)})` : `(${serialize(simple.argument).trim()})`;
+ return pe;
+ }
+ case "nesting-selector": return "&";
+ default: return "";
+ }
+}
+// src/AbstractTokenizer.ts
+/**
+* @license
+* Copyright 2026 Google LLC
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+var AbstractTokenizer = class {
+ unicodeRangesAllowed = false;
+ errors = [];
+ parseError(message) {
+ this.errors.push({ message });
+ console.warn(`CSS Parse Error: ${message}`);
+ }
+ consumeToken() {
+ while (true) {
+ this.consumeComments();
+ const cp = this.consume();
+ if (cp === -1) return {
+ type: "EOF",
+ value: ""
+ };
+ if (this.isWhitespace(cp)) {
+ while (this.isWhitespace(this.cp)) this.consume();
+ return {
+ type: "whitespace",
+ value: " "
+ };
+ }
+ switch (cp) {
+ case 34: return this.consumeStringToken(34);
+ case 35:
+ if (this.isIdentCodePoint(this.cp) || this.isValidEscape(this.cp, this.peek(1))) {
+ const token = {
+ type: "hash",
+ value: "",
+ hashType: "unrestricted"
+ };
+ if (this.wouldStartIdentSequence(this.cp, this.peek(1), this.peek(2))) token.hashType = "id";
+ token.value = this.consumeIdentSequence();
+ return token;
}
- break;
-
- case "'":
- case '"':
- info = this._parseJSString(token, idx, character);
- if (info) { // string
- idx = info.idx;
- expression += info.text;
- } else {
- expression += character;
+ return {
+ type: "delim",
+ value: String.fromCodePoint(cp)
+ };
+ case 39: return this.consumeStringToken(39);
+ case 40: return {
+ type: "(",
+ value: "("
+ };
+ case 41: return {
+ type: ")",
+ value: ")"
+ };
+ case 43:
+ if (this.wouldStartNumber(cp, this.cp, this.peek(1))) {
+ this.reconsume();
+ return this.consumeNumericToken();
}
- break;
-
- default:
- expression += character;
- break;
+ return {
+ type: "delim",
+ value: "+"
+ };
+ case 44: return {
+ type: "comma",
+ value: ","
+ };
+ case 45:
+ if (this.wouldStartNumber(cp, this.cp, this.peek(1))) {
+ this.reconsume();
+ return this.consumeNumericToken();
+ }
+ if (this.cp === 45 && this.peek(1) === 62) {
+ this.consume();
+ this.consume();
+ return {
+ type: "CDC",
+ value: "-->"
+ };
+ }
+ if (this.wouldStartIdentSequence(cp, this.cp, this.peek(1))) {
+ this.reconsume();
+ return this.consumeIdentLikeToken();
+ }
+ return {
+ type: "delim",
+ value: "-"
+ };
+ case 46:
+ if (this.wouldStartNumber(cp, this.cp, this.peek(1))) {
+ this.reconsume();
+ return this.consumeNumericToken();
+ }
+ return {
+ type: "delim",
+ value: "."
+ };
+ case 47: return {
+ type: "delim",
+ value: "/"
+ };
+ case 58: return {
+ type: "colon",
+ value: ":"
+ };
+ case 59: return {
+ type: "semicolon",
+ value: ";"
+ };
+ case 60:
+ if (this.cp === 33 && this.peek(1) === 45 && this.peek(2) === 45) {
+ this.consume();
+ this.consume();
+ this.consume();
+ return {
+ type: "CDO",
+ value: "