Merge in cssstyle and replace @acemir/cssom#4092
Merged
Conversation
asamuzaK
reviewed
Mar 8, 2026
asamuzaK
reviewed
Mar 8, 2026
asamuzaK
reviewed
Mar 8, 2026
Member
Author
|
I've reviewed all files here except the new |
Replace the @acemir/cssom dependency with native jsdom implementations using the standard webidl2js pattern (.webidl + -impl.js → generated wrapper). Use css-tree for CSS parsing instead of @acemir/cssom's hand-written state machine. This adds 21 CSSOM interfaces (CSSStyleSheet, CSSRule and all its subclasses, CSSRuleList, MediaList, StyleSheet) as proper webidl2js-backed classes, along with a new css-parser.js module that translates css-tree ASTs into the CSSOM object model. CSSStyleDeclaration stays as its existing manual class (merged from cssstyle). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move css-value-parsing.js, generic-property-descriptor.js, and shorthand-properties.js into cssom/helpers/. Convert all -impl.js files and multi-export modules from module.exports to exports.x style. Remove lazy-loading workarounds in -impl.js files and css-parser.js by reordering interfaces.js so CSSRuleList and MediaList load before their dependents. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
For cases where a getter just returns an underscored property, assign the public property directly in the constructor instead. The generated wrapper has its own getter to preserve encapsulation, so this removes a level of indirection. Trivial setters (that just assign) are also removed. Getters are kept where needed: conditionText on CSSConditionRule (overridden by CSSMediaRule), style (non-trivial setter), selectorText on CSSPageRule (validation in setter), and CSSCounterStyleRule descriptors (delegated through _descriptors object). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The circular dependency (css-parser.js → generated wrappers → impl files → css-parser.js) is now broken by having the impl files keep a module reference to css-parser.js instead of destructuring. Property access on the module object is resolved at call time, by which point all modules have finished loading. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove over-defensive defaults (|| "", || null, || []) from privateData field access in all impl constructors except CSSStyleSheet and StyleSheet, which need defaults because CSSStyleSheet has an IDL constructor. All other impls are only created via css-parser.js which always provides all required values. Also remove dead code: StyleSheet's href, title, and media fields were read from privateData but never passed by any caller. href and title are now initialized to null directly, and media was removed since CSSStyleSheet always creates its own MediaList. In CSSMediaRule, read this._conditionText (set by super) instead of privateData.conditionText, which is cleaner. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the parsing of @container prelude into translateContainerRule() so the impl class receives containerName and containerQuery as separate privateData fields, matching the spec's architecture. The conditionText getter now derives its value from those two fields per the spec definition. This also removes the fallback heuristic parser and the css-tree dependency from CSSContainerRule-impl.js. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rule impls were storing wrappers for parentRule and parentStyleSheet, requiring constant implForWrapper/wrapperForImpl conversions in internal code. Store impls instead, since the generated WebIDL wrappers already handle the impl-to-wrapper conversion via tryWrapperForImpl when exposing these to JavaScript. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All csstree usage now goes through a single facade module that applies the @csstools/css-syntax-patches-for-csstree patches. An ESLint rule prevents direct imports of css-tree or the patches package from anywhere except the facade. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The spec's "insert a CSS rule" and "remove a CSS rule" algorithms operate on a CSSRuleList, so implement them as _insert()/_insertParsed() and _remove() on CSSRuleList-impl.js. CSSGroupingRule and CSSStyleSheet now delegate to these shared methods instead of duplicating the logic. Also use isImpl() for rule type checks instead of comparing .type numeric constants, reject @import in constructed stylesheets per spec, and add TODOs for origin-clean and disallow-modification flag checks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
replace() now sets the flag during its operation, preventing concurrent insertRule/deleteRule/replaceSync/replace calls per spec. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CSSImportRule.media now delegates to this.styleSheet.media per spec, instead of creating a separate MediaList. The @import media text is passed to the child CSSStyleSheet constructor. Replace ad-hoc CSS string/URL escaping with csstree.string.encode(), which implements the CSSOM "serialize a string" algorithm. This affects CSSImportRule, CSSNamespaceRule, and css-value-parsing.js helpers. Re-export csstree.string from the patched-csstree facade since fork() drops standalone utilities. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The getter normalizes "from" to "0%" and "to" to "100%". The setter validates the input is a valid keyframe selector (comma-separated list of "from", "to", or percentages) and throws SyntaxError for invalid values per spec. CSSKeyframesRule's deleteRule/findRule now also normalize their select argument for correct matching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the ad-hoc regex with csstree.lexer.matchType("keyframe-selector"), which correctly enforces the [0,100] range and accepts all valid CSS number formats (.5%, 1e1%, etc.). Normalize numbers via parseFloat() so that e.g. .5% becomes 0.5% and 100.0% becomes 100%, matching Chrome's behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
StyleSheetList._list was storing wrappers, requiring unnecessary implForWrapper conversions in style-rules.js every time computed styles were calculated. Switch to storing impls throughout: createStylesheet now returns an impl, addStylesheet/removeStylesheet pass impls, and scanForImportRules works directly with rule impl arrays. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add serializeCustomIdent helper for <custom-ident> serialization, using csstree.ident.encode() normally and csstree.string.encode() for excluded keywords (CSS-wide keywords, "default", and production-specific exclusions). Apply it to CSSKeyframesRule, CSSCounterStyleRule, and CSSContainerRule. - Fix CSSKeyframesRule indexed getter to return undefined instead of null for out-of-bounds access. - Remove incorrect type getters from CSSLayerBlockRule (was 16) and CSSLayerStatementRule (was 17); the base CSSRule class already returns 0, which is correct for rules with no spec-defined constant. - Update comments in CSSLayerStatementRule.webidl and CSSNestedDeclarations.webidl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract evaluateMediaList() from the inline media-matching logic in style-rules.js, and use it both there and in a new matches getter. This also fixes @media rules with "all" or empty media lists not being applied during style computation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…xt setter, and misc fixes - Add CSSSupportsRule's matches getter, evaluating @supports conditions against csstree's lexer (handles and/or/not and nested conditions). - Add CSSStyleRule's selectorText setter with validation via csstree — invalid selectors are silently ignored per spec. - Fix parseInt to Number in CSSStyleDeclaration's item(). - Update comments in CSSPageRule.webidl, CSSStyleRule.webidl. - Bump @domenic/eslint-config to ^5.1.0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use csstree to validate individual media queries instead of naive comma-splitting. Invalid queries become "not all" per spec. appendMedium/deleteMedium compare by canonical serialization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Split `parseStylesheet` into `parseStyleSheet` (creates new sheet) and `parseIntoStyleSheet` (populates existing sheet), with a shared `parseRules` helper. - Replace `createStylesheet` with `createStyleSheetForElement` (for `<style>` and `<link>`) and `parseImportedStyleSheet` (for `@import`), each deriving its own parameters instead of accepting an opaque options bag. - Rename `addStylesheet`/`removeStylesheet`/`fetchStylesheet` to camelCase `addStyleSheet`/`removeStyleSheet`/`fetchStyleSheet`. - Move `media`, `href`, `title`, and `ownerNode` from CSSStyleSheet to the StyleSheet base class, and uncomment `ownerNode` in StyleSheet.webidl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use csstree's own parser to handle tasks previously done by hand-written depth-tracking helpers (findAtDepthZero, findMatchingClose, splitSelectorList, containsTopLevelBrace): - normalizeNestedSelector: parse as selectorList with positions, extract original text to preserve whitespace - splitMisinterpretedRule: re-parse as stylesheet to recover misinterpreted nested rules - @import supports() extraction: use Function node positions from csstree's prelude parse - Nested rule detection: simple rawValue.includes("{") replaces containsTopLevelBrace The splitMisinterpretedRule change requires an isLastChild guard: when a declaration containing {} is NOT the last child, csstree correctly separated subsequent declarations and the {} was self-contained. When it IS the last child, csstree may have merged everything into one Raw value and re-splitting is needed. Add tuwpt tests for brace characters inside string values in nested rules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- parseKeyframeRule: reject input with trailing garbage, extra at-rules, or multiple keyframes by checking total children count instead of only counting Rule nodes - translateImportRule/translateNamespaceRule: return null for invalid preludes missing a URL, instead of manufacturing rules with empty href/namespaceURI - populateGroupingRuleChildren: filter out CSSNestedDeclarations in non-nesting context, since bare declarations inside top-level grouping rules are invalid Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
csstree already rejects preludes without a valid URL/string by throwing, so the regex-based href extraction in the catch branch could only manufacture rules from inputs the real parser rejected. With the !href validation guard, it was also dead code in practice. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The loop over csstree children was assigning prefix for every Identifier, so trailing junk after the URL (e.g. `@namespace foo url("a") bar;`) got silently absorbed. Validate the expected grammar (<prefix>? <url>) and reject preludes with extra children.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of creating CSSNestedDeclarations in non-nesting contexts and filtering them out in the caller, have parseRawAsNestedRules skip the parseRawAsDeclarations path entirely when the caller doesn't want declarations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When an @import has an invalid layer() (e.g. empty parens) followed by media queries like "screen", the invalid layer() gets demoted to a media query. The code was overwriting the existing media text instead of prepending to it, losing the trailing queries. Also clear supportsText when the layer is invalid, since Chrome drops all modifiers in this case. Also fix parseSingleMedium to reject media queries containing <general-enclosed> tokens (e.g. "layer()"), which csstree accepts but are invalid per spec and should become "not all". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR replaces jsdom’s existing CSSOM/style plumbing (previously driven by @acemir/cssom + cssstyle) with a new in-repo CSS/CSSOM implementation and adds a large set of WPTs to validate parsing/serialization and rule APIs.
Changes:
- Swap out third-party CSSOM integration for new
lib/jsdom/living/css/**WebIDL + implementations, plus updated node/style/link integration. - Add/adjust Web Platform Tests covering CSSOM rules, MediaList, constructed stylesheets, nesting, layers, etc.
- Update build/test wiring (WebIDL conversion dir, ESLint restricted requires, dependencies, and WPT runner expectations).
Reviewed changes
Copilot reviewed 166 out of 172 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/web-platform-tests/to-upstream/css/cssom/keyframes-appendRule-multiple.html | Adds WPT for CSSKeyframesRule.appendRule() with multiple rules behavior. |
| test/web-platform-tests/to-upstream/css/cssom/keyframes-appendRule-invalid.html | Adds WPTs asserting invalid appendRule() inputs are ignored. |
| test/web-platform-tests/to-upstream/css/cssom/import-namespace-invalid-prelude.html | Adds WPT coverage for dropping invalid @import/@namespace preludes. |
| test/web-platform-tests/to-upstream/css/cssom/grouping-rule-no-nested-declarations.html | Adds WPT coverage for nested declarations wrapping rules depending on nesting context. |
| test/web-platform-tests/to-upstream/css/cssom/cssimportrule-media-identity.html | Adds WPT for CSSImportRule.media object identity vs styleSheet.media. |
| test/web-platform-tests/to-upstream/css/cssom/cssimportrule-layer-media.html | Adds WPT for preserving both layerName and media on @import. |
| test/web-platform-tests/to-upstream/css/cssom/cssimportrule-layer-false-positive.html | Adds WPT for avoiding false-positive layer detection inside supports/media. |
| test/web-platform-tests/to-upstream/css/cssom/cssimportrule-insertRule-styleSheet-parentStyleSheet.html | Adds WPT for @import’s nested stylesheet parentStyleSheet linkage. |
| test/web-platform-tests/to-upstream/css/cssom/StyleSheet-properties.html | Adds WPT for StyleSheet/CSSStyleSheet properties and cleanup on removal. |
| test/web-platform-tests/to-upstream/css/cssom/MediaList-parsing.html | Adds WPT for MediaList parsing/normalization and mutation methods. |
| test/web-platform-tests/to-upstream/css/cssom/CSSSupportsRule-matches.html | Adds WPT for CSSSupportsRule.matches. |
| test/web-platform-tests/to-upstream/css/cssom/CSSStyleRule-selectorText-setter.html | Adds WPT for selectorText setter behavior on valid/invalid selectors. |
| test/web-platform-tests/to-upstream/css/cssom/CSSRule-type.html | Adds WPT for CSSRule.type constants across rule types. |
| test/web-platform-tests/to-upstream/css/cssom/CSSMediaRule-matches.html | Adds WPT for CSSMediaRule.matches behavior. |
| test/web-platform-tests/to-upstream/css/cssom/CSSKeyframesRule-indexed-getter.html | Adds WPT for indexed getter on CSSKeyframesRule. |
| test/web-platform-tests/to-upstream/css/cssom/CSSKeyframeRule-keyText.html | Adds WPT for CSSKeyframeRule.keyText normalization/validation. |
| test/web-platform-tests/to-upstream/css/css-nesting/nesting-braces-in-strings.html | Adds WPTs for nesting parsing when braces appear inside string tokens. |
| test/web-platform-tests/to-upstream/css/css-conditional/container-rule-malformed-prelude.html | Adds WPT verifying malformed @container preludes are dropped. |
| test/web-platform-tests/to-upstream/css/css-cascade/scope-rule-attr-with-colons.html | Adds WPT ensuring @scope parsing accepts :: inside attribute values. |
| test/web-platform-tests/to-upstream/css/css-cascade/layer-rule-invalid-name.html | Adds WPT coverage for rejecting invalid @layer names. |
| test/web-platform-tests/to-run.yaml | Adjusts expected-fail list to reflect new behavior / removed failures. |
| test/api/from-outside.js | Updates an external API test to use deleteRule() for DOMException-instance isolation checks. |
| test/api/css-parsing-errors.js | Updates parsing error expectations (count + cause type). |
| scripts/webidl/convert.js | Switches WebIDL conversion input dir from living/cssom to living/css. |
| package.json | Replaces CSS deps and adds CSS-related build script + tooling deps. |
| lib/jsdom/living/nodes/SVGElement-impl.js | Updates ElementCSSInlineStyle impl import path to new CSS module location. |
| lib/jsdom/living/nodes/Node-impl.js | Moves style cache invalidation import to new computed-style helper. |
| lib/jsdom/living/nodes/HTMLStyleElement-impl.js | Migrates stylesheet creation/add/remove to new CSS helpers API. |
| lib/jsdom/living/nodes/HTMLLinkElement-impl.js | Migrates stylesheet fetch/remove to new CSS helpers API. |
| lib/jsdom/living/nodes/HTMLElement-impl.js | Updates ElementCSSInlineStyle impl import path to new CSS module location. |
| lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js | Removes old cssstyle-backed inline-style implementation. |
| lib/jsdom/living/interfaces.js | Installs CSSOM interfaces via generated IDL wrappers + custom CSSStyleDeclaration export. |
| lib/jsdom/living/helpers/stylesheets.js | Removes old cssom-based stylesheet fetch/parse/add/remove helper. |
| lib/jsdom/living/css/properties/width.js | Adds property descriptor + parsing for width. |
| lib/jsdom/living/css/properties/webkitTextStrokeColor.js | Adds property descriptor + parsing for -webkit-text-stroke-color. |
| lib/jsdom/living/css/properties/webkitTextFillColor.js | Adds property descriptor + parsing for -webkit-text-fill-color. |
| lib/jsdom/living/css/properties/top.js | Adds property descriptor + parsing for top. |
| lib/jsdom/living/css/properties/textEmphasisColor.js | Adds property descriptor + parsing for text-emphasis-color. |
| lib/jsdom/living/css/properties/stopColor.js | Adds property descriptor + parsing for stop-color. |
| lib/jsdom/living/css/properties/right.js | Adds property descriptor + parsing for right. |
| lib/jsdom/living/css/properties/paddingTop.js | Adds longhand descriptor + parsing for padding-top. |
| lib/jsdom/living/css/properties/paddingRight.js | Adds longhand descriptor + parsing for padding-right. |
| lib/jsdom/living/css/properties/paddingLeft.js | Adds longhand descriptor + parsing for padding-left. |
| lib/jsdom/living/css/properties/paddingBottom.js | Adds longhand descriptor + parsing for padding-bottom. |
| lib/jsdom/living/css/properties/padding.js | Adds shorthand descriptor + parsing for padding. |
| lib/jsdom/living/css/properties/outlineColor.js | Adds property descriptor + parsing for outline-color. |
| lib/jsdom/living/css/properties/opacity.js | Adds property descriptor + parsing for opacity. |
| lib/jsdom/living/css/properties/marginTop.js | Adds longhand descriptor + parsing for margin-top. |
| lib/jsdom/living/css/properties/marginRight.js | Adds longhand descriptor + parsing for margin-right. |
| lib/jsdom/living/css/properties/marginLeft.js | Adds longhand descriptor + parsing for margin-left. |
| lib/jsdom/living/css/properties/marginBottom.js | Adds longhand descriptor + parsing for margin-bottom. |
| lib/jsdom/living/css/properties/margin.js | Adds shorthand descriptor + parsing for margin. |
| lib/jsdom/living/css/properties/lineHeight.js | Adds property descriptor + parsing for line-height. |
| lib/jsdom/living/css/properties/lightingColor.js | Adds property descriptor + parsing for lighting-color. |
| lib/jsdom/living/css/properties/left.js | Adds property descriptor + parsing for left. |
| lib/jsdom/living/css/properties/height.js | Adds property descriptor + parsing for height. |
| lib/jsdom/living/css/properties/fontWeight.js | Adds property descriptor + parsing for font-weight. |
| lib/jsdom/living/css/properties/fontVariant.js | Adds property descriptor + parsing for font-variant. |
| lib/jsdom/living/css/properties/fontStyle.js | Adds property descriptor + parsing for font-style. |
| lib/jsdom/living/css/properties/fontSize.js | Adds property descriptor + parsing for font-size. |
| lib/jsdom/living/css/properties/fontFamily.js | Adds property descriptor + parsing for font-family. |
| lib/jsdom/living/css/properties/floodColor.js | Adds property descriptor + parsing for flood-color. |
| lib/jsdom/living/css/properties/float.js | Adds property descriptor + parsing for float. |
| lib/jsdom/living/css/properties/flexShrink.js | Adds property descriptor + parsing for flex-shrink. |
| lib/jsdom/living/css/properties/flexGrow.js | Adds property descriptor + parsing for flex-grow. |
| lib/jsdom/living/css/properties/flexBasis.js | Adds property descriptor + parsing for flex-basis. |
| lib/jsdom/living/css/properties/color.js | Adds property descriptor + parsing for color. |
| lib/jsdom/living/css/properties/clip.js | Adds property descriptor + parsing for deprecated clip. |
| lib/jsdom/living/css/properties/clear.js | Adds property descriptor + parsing for clear. |
| lib/jsdom/living/css/properties/bottom.js | Adds property descriptor + parsing for bottom. |
| lib/jsdom/living/css/properties/borderWidth.js | Adds shorthand descriptor + parsing for border-width. |
| lib/jsdom/living/css/properties/borderTopWidth.js | Adds longhand descriptor + parsing for border-top-width. |
| lib/jsdom/living/css/properties/borderTopStyle.js | Adds longhand descriptor + parsing for border-top-style. |
| lib/jsdom/living/css/properties/borderTopColor.js | Adds longhand descriptor + parsing for border-top-color. |
| lib/jsdom/living/css/properties/borderTop.js | Adds shorthand descriptor + parsing for border-top. |
| lib/jsdom/living/css/properties/borderStyle.js | Adds shorthand descriptor + parsing for border-style. |
| lib/jsdom/living/css/properties/borderSpacing.js | Adds property descriptor + parsing for border-spacing. |
| lib/jsdom/living/css/properties/borderRightWidth.js | Adds longhand descriptor + parsing for border-right-width. |
| lib/jsdom/living/css/properties/borderRightStyle.js | Adds longhand descriptor + parsing for border-right-style. |
| lib/jsdom/living/css/properties/borderRightColor.js | Adds longhand descriptor + parsing for border-right-color. |
| lib/jsdom/living/css/properties/borderRight.js | Adds shorthand descriptor + parsing for border-right. |
| lib/jsdom/living/css/properties/borderLeftWidth.js | Adds longhand descriptor + parsing for border-left-width. |
| lib/jsdom/living/css/properties/borderLeftStyle.js | Adds longhand descriptor + parsing for border-left-style. |
| lib/jsdom/living/css/properties/borderLeftColor.js | Adds longhand descriptor + parsing for border-left-color. |
| lib/jsdom/living/css/properties/borderLeft.js | Adds shorthand descriptor + parsing for border-left. |
| lib/jsdom/living/css/properties/borderInlineStartColor.js | Adds property descriptor + parsing for logical border color longhand. |
| lib/jsdom/living/css/properties/borderInlineEndColor.js | Adds property descriptor + parsing for logical border color longhand. |
| lib/jsdom/living/css/properties/borderColor.js | Adds shorthand descriptor + parsing for border-color. |
| lib/jsdom/living/css/properties/borderCollapse.js | Adds property descriptor + parsing for border-collapse. |
| lib/jsdom/living/css/properties/borderBottomWidth.js | Adds longhand descriptor + parsing for border-bottom-width. |
| lib/jsdom/living/css/properties/borderBottomStyle.js | Adds longhand descriptor + parsing for border-bottom-style. |
| lib/jsdom/living/css/properties/borderBottomColor.js | Adds longhand descriptor + parsing for border-bottom-color. |
| lib/jsdom/living/css/properties/borderBottom.js | Adds shorthand descriptor + parsing for border-bottom. |
| lib/jsdom/living/css/properties/borderBlockStartColor.js | Adds property descriptor + parsing for logical border color longhand. |
| lib/jsdom/living/css/properties/borderBlockEndColor.js | Adds property descriptor + parsing for logical border color longhand. |
| lib/jsdom/living/css/properties/border.js | Adds shorthand descriptor + parsing for border. |
| lib/jsdom/living/css/properties/backgroundSize.js | Adds property descriptor + parsing for background-size. |
| lib/jsdom/living/css/properties/backgroundRepeat.js | Adds property descriptor + parsing for background-repeat. |
| lib/jsdom/living/css/properties/backgroundOrigin.js | Adds property descriptor + parsing for background-origin. |
| lib/jsdom/living/css/properties/backgroundImage.js | Adds property descriptor + parsing for background-image. |
| lib/jsdom/living/css/properties/backgroundColor.js | Adds property descriptor + parsing for background-color. |
| lib/jsdom/living/css/properties/backgroundClip.js | Adds property descriptor + parsing for background-clip. |
| lib/jsdom/living/css/properties/backgroundAttachment.js | Adds property descriptor + parsing for background-attachment. |
| lib/jsdom/living/css/helpers/patched-csstree.js | Introduces a patched csstree fork wrapper and re-exports needed utilities. |
| lib/jsdom/living/css/StyleSheetList.webidl | Adds WebIDL for StyleSheetList. |
| lib/jsdom/living/css/StyleSheetList-impl.js | Adds implementation backing document.styleSheets. |
| lib/jsdom/living/css/StyleSheet.webidl | Adds WebIDL for StyleSheet. |
| lib/jsdom/living/css/StyleSheet-impl.js | Adds base StyleSheet implementation and MediaList creation. |
| lib/jsdom/living/css/MediaList.webidl | Adds WebIDL for MediaList. |
| lib/jsdom/living/css/MediaList-impl.js | Adds MediaList parsing/normalization + matching helpers. |
| lib/jsdom/living/css/ElementCSSInlineStyle.webidl | Adds WebIDL mixin for inline styles and includes it into HTMLElement/SVGElement. |
| lib/jsdom/living/css/ElementCSSInlineStyle-impl.js | Adds inline style impl backed by new CSSStyleDeclaration. |
| lib/jsdom/living/css/CSSSupportsRule.webidl | Adds WebIDL for CSSSupportsRule. |
| lib/jsdom/living/css/CSSSupportsRule-impl.js | Implements CSSSupportsRule.matches and serialization. |
| lib/jsdom/living/css/CSSStyleSheet.webidl | Adds WebIDL for constructed/non-constructed CSSStyleSheet APIs. |
| lib/jsdom/living/css/CSSStyleSheet-impl.js | Implements CSSStyleSheet rule mutation + replace/replaceSync. |
| lib/jsdom/living/css/CSSStyleRule.webidl | Adds WebIDL for CSSStyleRule (nesting-aware via grouping base). |
| lib/jsdom/living/css/CSSStyleRule-impl.js | Implements selectorText validation, style binding, and serialization. |
| lib/jsdom/living/css/CSSScopeRule.webidl | Adds WebIDL for CSSScopeRule. |
| lib/jsdom/living/css/CSSScopeRule-impl.js | Implements @scope serialization. |
| lib/jsdom/living/css/CSSRuleList.webidl | Adds WebIDL for CSSRuleList. |
| lib/jsdom/living/css/CSSRule.webidl | Adds WebIDL for CSSRule plus constants. |
| lib/jsdom/living/css/CSSRule-impl.js | Adds base CSSRule implementation. |
| lib/jsdom/living/css/CSSPageRule.webidl | Adds WebIDL for CSSPageRule. |
| lib/jsdom/living/css/CSSPageRule-impl.js | Implements basic page selector validation + serialization. |
| lib/jsdom/living/css/CSSNestedDeclarations.webidl | Adds WebIDL for CSSNestedDeclarations. |
| lib/jsdom/living/css/CSSNestedDeclarations-impl.js | Implements nested declaration rule wrapper/serialization. |
| lib/jsdom/living/css/CSSNamespaceRule.webidl | Adds WebIDL for CSSNamespaceRule. |
| lib/jsdom/living/css/CSSNamespaceRule-impl.js | Implements @namespace serialization. |
| lib/jsdom/living/css/CSSMediaRule.webidl | Adds WebIDL for CSSMediaRule including .matches. |
| lib/jsdom/living/css/CSSMediaRule-impl.js | Implements MediaList-backed conditionText and .matches. |
| lib/jsdom/living/css/CSSLayerStatementRule.webidl | Adds WebIDL for CSSLayerStatementRule. |
| lib/jsdom/living/css/CSSLayerStatementRule-impl.js | Implements @layer statement serialization and frozen name list. |
| lib/jsdom/living/css/CSSLayerBlockRule.webidl | Adds WebIDL for CSSLayerBlockRule. |
| lib/jsdom/living/css/CSSLayerBlockRule-impl.js | Implements @layer {} block serialization. |
| lib/jsdom/living/css/CSSKeyframesRule.webidl | Adds WebIDL for CSSKeyframesRule including indexed properties. |
| lib/jsdom/living/css/CSSKeyframesRule-impl.js | Implements keyframes rule list, append/delete/find, and serialization. |
| lib/jsdom/living/css/CSSKeyframeRule.webidl | Adds WebIDL for CSSKeyframeRule. |
| lib/jsdom/living/css/CSSKeyframeRule-impl.js | Implements keyText normalization/validation + serialization. |
| lib/jsdom/living/css/CSSImportRule.webidl | Adds WebIDL for CSSImportRule including layer/supports/media/styleSheet. |
| lib/jsdom/living/css/CSSImportRule-impl.js | Implements import rule stylesheet creation and cssText serialization. |
| lib/jsdom/living/css/CSSGroupingRule.webidl | Adds WebIDL for CSSGroupingRule. |
| lib/jsdom/living/css/CSSGroupingRule-impl.js | Implements insert/delete and shared grouping body serialization. |
| lib/jsdom/living/css/CSSFontFaceRule.webidl | Adds WebIDL for CSSFontFaceRule. |
| lib/jsdom/living/css/CSSFontFaceRule-impl.js | Implements font-face style binding and serialization. |
| lib/jsdom/living/css/CSSCounterStyleRule.webidl | Adds WebIDL for CSSCounterStyleRule. |
| lib/jsdom/living/css/CSSCounterStyleRule-impl.js | Implements basic @counter-style serialization for stored descriptors. |
| lib/jsdom/living/css/CSSContainerRule.webidl | Adds WebIDL for CSSContainerRule. |
| lib/jsdom/living/css/CSSContainerRule-impl.js | Implements @container conditionText + serialization. |
| lib/jsdom/living/css/CSSConditionRule.webidl | Adds WebIDL for CSSConditionRule. |
| lib/jsdom/living/css/CSSConditionRule-impl.js | Implements common conditionText storage for conditional grouping rules. |
| lib/jsdom/level2/style.js | Removes old CSSOM wiring that installed cssom/cssstyle classes onto Window. |
| lib/jsdom/browser/Window.js | Updates computed style helper import path to new CSS module location. |
| eslint.config.mjs | Adds restricted requires for css-tree/patch package and local exception for patched wrapper. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…mpl.js Co-authored-by: domenic <617481+domenic@users.noreply.github.com>
…observable The spec says replace() should set the disallow modification flag, then do the parsing "in parallel" before unsetting it and resolving the promise. The previous implementation was an async function that did everything synchronously, so the flag was set and unset in the same microtask and no code could ever observe it as true. Now replace() sets the flag synchronously and defers the actual work (clear rules, parse, unset flag, resolve) to a queueMicrotask callback. This makes insertRule(), deleteRule(), replaceSync(), and another replace() correctly throw/reject NotAllowedError while a replace() is in progress. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verifies that garbage CSS input clears existing rules without throwing, mixed valid/invalid input keeps valid rules, and the sheet remains usable after parse errors. Both methods behave identically (as expected by spec). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Drop @import and @namespace inside grouping rules (they're only valid at stylesheet top level) - Detach old rules (nullify parentRule/parentStyleSheet recursively) when replace()/replaceSync() clears the sheet, via a new CSSRuleList _clear() method - Exempt @layer statement rules from the "other rules exist" check when deleting @namespace, matching the exemption already present for insertion - Detach removed keyframe rules in CSSKeyframesRule deleteRule() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A holdover from cssstyle
Member
Author
|
This is ready. I'll probably merge it tomorrow. Any reviews are welcome. |
cssstyle and replace @acemir/cssom
I guess at some point we weren't validating insertRule()
Test all StyleSheet/CSSStyleSheet properties for <style>, <link>, and @imported sheets, including ownerNode, href, parentStyleSheet, ownerRule, and removal cleanup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…test files Add tests for style.sheet inside shadow roots (known failing, #3645) and programmatically setting title on <style> elements (#3634). Rename tuwpt files to use properly-cased class names (e.g. CSSImportRule- instead of cssimportrule-). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert _constructed, _disallowModification, _keyText, and _selectorText to #private fields since they are only accessed within their own class. Cross-file-accessed properties like _style, _conditionText, and _list remain as underscore-prefixed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the disabled IDL attribute that delegates to the associated stylesheet's disabled flag per the HTML spec. Update WPT expectations with descriptive reasons for tests we can't fix yet. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
As discussed in jsdom/cssstyle#318, over time cssstyle has become increasingly coupled with the internals of jsdom. Ongoing work on improving style resolution, and future work on moving
CSSStyleDeclarationto webidl2js, will only increase this coupling. As such, we merge the cssstyle package into jsdom.Doing so while using
@acemir/cssomdirectly is difficult, since@acemir/cssomhard-codes thecssstylepackage name, and won't properly integrate with a jsdom-internalCSSStyleDeclaration. Additionaly,@acemir/cssomis a package with a lot of historical baggage, including a custom build system, its own parser, an ES5-era codebase, and various nonstandard extensions. As such, this includes fresh reimplementations of all of the CSSOM classes, using webidl2js wrappers, and using the csstree parser instead of a custom parser, with extra work to match the latest specs (or document deviations from them).Some specific improvements over
@acemir/cssom:CSSMediaRule/CSSSupportsRulematchesgettersMediaList(instead of just splitting on commas)CSSKeyframeRulekeyTextgetter/setter with validationCSSStyleRuleselectorTextsetter rejects invalid selectorsCSSStyleSheetreplace()properly defers to a microtask, and the "disallow modification flag" is checked in all methods.StyleSheetownerNode,href, andtitleare set.CSSDocumentRule,CSSHostRule,CSSValue,MatcherList, various parser-related methods).Fixes #690. Fixes #992. Fixes #2974. Fixes #3766. Fixes #3988.
This is not perfect. In particular, csstree does not have a spec-compliant serializer, and its parser needs some hacks to be spec-compliant. (See csstree/csstree#52 and the
css-parser.jsfile.) So the ideal strategy, of parsing, storing AST notes, and serializing, is not possible. Instead, we do our best to preserve the input as strings, and serialize it back out; this gives reasonable results (at least as good as@acemir/cssom). In the future it may be worth investigating other CSS parsers like PostCSS,@adobe/css-tools, or similar. For now, since cssstyle was using csstree, we do so in jsdom.As part of this work, consolidate all CSS-related files into
lib/jsdom/living/css/, moving several fromlib/jsdom/living/helpers/. Many of the files from cssstyle were also renamed as part of the merge.Many new to-upstream web platform tests are included, on an ad-hoc basis: they test things that came up in earlier drafts of this work, and are not an exhaustive test of all CSSOM functionality.
Note that apart from renames, the imported cssstyle code is mostly unchanged; in particular,
CSSStyleDeclarationis still not using webidl2js.