@@ -18,6 +18,10 @@ import 'package:tuple/tuple.dart';
1818import '../ast/selector.dart' ;
1919import '../utils.dart' ;
2020
21+ /// Pseudo-selectors that can only meaningfully appear in the first component of
22+ /// a complex selector.
23+ final _rootishPseudoClasses = {'root' , 'scope' , 'host' , 'host-context' };
24+
2125/// Returns the contents of a [SelectorList] that matches only elements that are
2226/// matched by every complex selector in [complexes] .
2327///
@@ -231,19 +235,22 @@ Iterable<ComplexSelector>? _weaveParents(
231235 var trailingCombinators = _mergeTrailingCombinators (queue1, queue2);
232236 if (trailingCombinators == null ) return null ;
233237
234- // Make sure there's at most one `:root` in the output.
235- var root1 = _firstIfRoot (queue1);
236- var root2 = _firstIfRoot (queue2);
237- if (root1 != null && root2 != null ) {
238- var root =
239- unifyCompound (root1.selector.components, root2.selector.components);
240- if (root == null ) return null ;
241- queue1.addFirst (ComplexSelectorComponent (root, root1.combinators));
242- queue2.addFirst (ComplexSelectorComponent (root, root2.combinators));
243- } else if (root1 != null ) {
244- queue2.addFirst (root1);
245- } else if (root2 != null ) {
246- queue1.addFirst (root2);
238+ // Make sure all selectors that are required to be at the root
239+ var rootish1 = _firstIfRootish (queue1);
240+ var rootish2 = _firstIfRootish (queue2);
241+ if (rootish1 != null && rootish2 != null ) {
242+ var rootish =
243+ unifyCompound (rootish1.selector.components, rootish2.selector.components);
244+ if (rootish == null ) return null ;
245+ queue1.addFirst (ComplexSelectorComponent (rootish, rootish1.combinators));
246+ queue2.addFirst (ComplexSelectorComponent (rootish, rootish2.combinators));
247+ } else if (rootish1 != null || rootish2 != null ) {
248+ // If there's only one rootish selector, it should only appear in the first
249+ // position of the resulting selector. We can ensure that happens by adding
250+ // it to the beginning of _both_ queues.
251+ var rootish = (rootish1 ?? rootish2)! ;
252+ queue1.addFirst (rootish);
253+ queue2.addFirst (rootish);
247254 }
248255
249256 var groups1 = _groupSelectors (queue1);
@@ -289,14 +296,19 @@ Iterable<ComplexSelector>? _weaveParents(
289296 ];
290297}
291298
292- /// If the first element of [queue] has a `:root` selector, removes and returns
293- /// that element.
294- ComplexSelectorComponent ? _firstIfRoot (Queue <ComplexSelectorComponent > queue) {
299+ /// If the first element of [queue] has a selector like `:root` that can only
300+ /// appear in a complex selector's first component, removes and returns that
301+ /// element.
302+ ComplexSelectorComponent ? _firstIfRootish (Queue <ComplexSelectorComponent > queue) {
295303 if (queue.isEmpty) return null ;
296304 var first = queue.first;
297- if (! _hasRoot (first.selector)) return null ;
298- queue.removeFirst ();
299- return first;
305+ for (var simple in first.selector.components) {
306+ if (simple is PseudoSelector && simple.isClass && _rootishPseudoClasses.contains (simple.normalizedName)) {
307+ queue.removeFirst ();
308+ return first;
309+ }
310+ }
311+ return null ;
300312}
301313
302314/// Returns a leading combinator list that's compatible with both [combinators1]
@@ -543,12 +555,6 @@ QueueList<List<ComplexSelectorComponent>> _groupSelectors(
543555 return groups;
544556}
545557
546- /// Returns whether or not [compound] contains a `::root` selector.
547- bool _hasRoot (CompoundSelector compound) => compound.components.any ((simple) =>
548- simple is PseudoSelector &&
549- simple.isClass &&
550- simple.normalizedName == 'root' );
551-
552558/// Returns whether [list1] is a superselector of [list2] .
553559///
554560/// That is, whether [list1] matches every element that [list2] matches, as well
0 commit comments