@@ -338,7 +338,7 @@ export class ShadowCss {
338
338
* captures how many (if any) leading whitespaces are present or a comma
339
339
* - (?:(?:(['"])((?:\\\\|\\\2|(?!\2).)+)\2)|(-?[A-Za-z][\w\-]*))
340
340
* captures two different possible keyframes, ones which are quoted or ones which are valid css
341
- * indents (custom properties excluded)
341
+ * idents (custom properties excluded)
342
342
* - (?=[,\s;]|$)
343
343
* simply matches the end of the possible keyframe, valid endings are: a comma, a space, a
344
344
* semicolon or the end of the string
@@ -459,7 +459,7 @@ export class ShadowCss {
459
459
*/
460
460
private _scopeCssText ( cssText : string , scopeSelector : string , hostSelector : string ) : string {
461
461
const unscopedRules = this . _extractUnscopedRulesFromCssText ( cssText ) ;
462
- // replace :host and :host-context with -shadowcsshost and -shadowcsshostcontext respectively
462
+ // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively
463
463
cssText = this . _insertPolyfillHostInCssText ( cssText ) ;
464
464
cssText = this . _convertColonHost ( cssText ) ;
465
465
cssText = this . _convertColonHostContext ( cssText ) ;
@@ -539,7 +539,7 @@ export class ShadowCss {
539
539
* .foo<scopeName> .bar { ... }
540
540
*/
541
541
private _convertColonHostContext ( cssText : string ) : string {
542
- return cssText . replace ( _cssColonHostContextReGlobal , ( selectorText , pseudoPrefix ) => {
542
+ return cssText . replace ( _cssColonHostContextReGlobal , ( selectorText ) => {
543
543
// We have captured a selector that contains a `:host-context` rule.
544
544
545
545
// For backward compatibility `:host-context` may contain a comma separated list of selectors.
@@ -594,12 +594,10 @@ export class ShadowCss {
594
594
}
595
595
596
596
// The context selectors now must be combined with each other to capture all the possible
597
- // selectors that `:host-context` can match. See `_combineHostContextSelectors ()` for more
597
+ // selectors that `:host-context` can match. See `combineHostContextSelectors ()` for more
598
598
// info about how this is done.
599
599
return contextSelectorGroups
600
- . map ( ( contextSelectors ) =>
601
- _combineHostContextSelectors ( contextSelectors , selectorText , pseudoPrefix ) ,
602
- )
600
+ . map ( ( contextSelectors ) => combineHostContextSelectors ( contextSelectors , selectorText ) )
603
601
. join ( ', ' ) ;
604
602
} ) ;
605
603
}
@@ -618,12 +616,7 @@ export class ShadowCss {
618
616
let selector = rule . selector ;
619
617
let content = rule . content ;
620
618
if ( rule . selector [ 0 ] !== '@' ) {
621
- selector = this . _scopeSelector ( {
622
- selector,
623
- scopeSelector,
624
- hostSelector,
625
- isParentSelector : true ,
626
- } ) ;
619
+ selector = this . _scopeSelector ( rule . selector , scopeSelector , hostSelector ) ;
627
620
} else if ( scopedAtRuleIdentifiers . some ( ( atRule ) => rule . selector . startsWith ( atRule ) ) ) {
628
621
content = this . _scopeSelectors ( rule . content , scopeSelector , hostSelector ) ;
629
622
} else if ( rule . selector . startsWith ( '@font-face' ) || rule . selector . startsWith ( '@page' ) ) {
@@ -663,44 +656,15 @@ export class ShadowCss {
663
656
} ) ;
664
657
}
665
658
666
- private _safeSelector : SafeSelector | undefined ;
667
- private _shouldScopeIndicator : boolean | undefined ;
668
-
669
- // `isParentSelector` is used to distinguish the selectors which are coming from
670
- // the initial selector string and any nested selectors, parsed recursively,
671
- // for example `selector = 'a:where(.one)'` could be the parent, while recursive call
672
- // would have `selector = '.one'`.
673
- private _scopeSelector ( {
674
- selector,
675
- scopeSelector,
676
- hostSelector,
677
- isParentSelector = false ,
678
- } : {
679
- selector : string ;
680
- scopeSelector : string ;
681
- hostSelector : string ;
682
- isParentSelector ?: boolean ;
683
- } ) : string {
684
- // Split the selector into independent parts by `,` (comma) unless
685
- // comma is within parenthesis, for example `:is(.one, two)`.
686
- // Negative lookup after comma allows not splitting inside nested parenthesis,
687
- // up to three levels (((,))).
688
- const selectorSplitRe =
689
- / ? , (? ! (?: [ ^ ) ( ] * (?: \( [ ^ ) ( ] * (?: \( [ ^ ) ( ] * (?: \( [ ^ ) ( ] * \) [ ^ ) ( ] * ) * \) [ ^ ) ( ] * ) * \) [ ^ ) ( ] * ) * \) ) ) ? / ;
690
-
659
+ private _scopeSelector ( selector : string , scopeSelector : string , hostSelector : string ) : string {
691
660
return selector
692
- . split ( selectorSplitRe )
661
+ . split ( / ? , ? / )
693
662
. map ( ( part ) => part . split ( _shadowDeepSelectors ) )
694
663
. map ( ( deepParts ) => {
695
664
const [ shallowPart , ...otherParts ] = deepParts ;
696
665
const applyScope = ( shallowPart : string ) => {
697
666
if ( this . _selectorNeedsScoping ( shallowPart , scopeSelector ) ) {
698
- return this . _applySelectorScope ( {
699
- selector : shallowPart ,
700
- scopeSelector,
701
- hostSelector,
702
- isParentSelector,
703
- } ) ;
667
+ return this . _applySelectorScope ( shallowPart , scopeSelector , hostSelector ) ;
704
668
} else {
705
669
return shallowPart ;
706
670
}
@@ -733,9 +697,9 @@ export class ShadowCss {
733
697
if ( _polyfillHostRe . test ( selector ) ) {
734
698
const replaceBy = `[${ hostSelector } ]` ;
735
699
return selector
736
- . replace ( _polyfillHostNoCombinatorReGlobal , ( _hnc , selector ) => {
700
+ . replace ( _polyfillHostNoCombinatorRe , ( hnc , selector ) => {
737
701
return selector . replace (
738
- / ( [ ^ : \) ] * ) ( : * ) ( .* ) / ,
702
+ / ( [ ^ : ] * ) ( : * ) ( .* ) / ,
739
703
( _ : string , before : string , colon : string , after : string ) => {
740
704
return before + replaceBy + colon + after ;
741
705
} ,
@@ -749,17 +713,11 @@ export class ShadowCss {
749
713
750
714
// return a selector with [name] suffix on each simple selector
751
715
// e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */
752
- private _applySelectorScope ( {
753
- selector,
754
- scopeSelector,
755
- hostSelector,
756
- isParentSelector,
757
- } : {
758
- selector : string ;
759
- scopeSelector : string ;
760
- hostSelector : string ;
761
- isParentSelector ?: boolean ;
762
- } ) : string {
716
+ private _applySelectorScope (
717
+ selector : string ,
718
+ scopeSelector : string ,
719
+ hostSelector : string ,
720
+ ) : string {
763
721
const isRe = / \[ i s = ( [ ^ \] ] * ) \] / g;
764
722
scopeSelector = scopeSelector . replace ( isRe , ( _ : string , ...parts : string [ ] ) => parts [ 0 ] ) ;
765
723
@@ -774,10 +732,6 @@ export class ShadowCss {
774
732
775
733
if ( p . includes ( _polyfillHostNoCombinator ) ) {
776
734
scopedP = this . _applySimpleSelectorScope ( p , scopeSelector , hostSelector ) ;
777
- if ( _polyfillHostNoCombinatorWithinPseudoFunction . test ( p ) ) {
778
- const [ _ , before , colon , after ] = scopedP . match ( / ( [ ^ : ] * ) ( : * ) ( .* ) / ) ! ;
779
- scopedP = before + attrName + colon + after ;
780
- }
781
735
} else {
782
736
// remove :host since it should be unnecessary
783
737
const t = p . replace ( _polyfillHostRe , '' ) ;
@@ -792,60 +746,13 @@ export class ShadowCss {
792
746
return scopedP ;
793
747
} ;
794
748
795
- // Wraps `_scopeSelectorPart()` to not use it directly on selectors with
796
- // pseudo selector functions like `:where()`. Selectors within pseudo selector
797
- // functions are recursively sent to `_scopeSelector()`.
798
- const _pseudoFunctionAwareScopeSelectorPart = ( selectorPart : string ) => {
799
- let scopedPart = '' ;
800
-
801
- const cssPrefixWithPseudoSelectorFunctionMatch = selectorPart . match (
802
- _cssPrefixWithPseudoSelectorFunction ,
803
- ) ;
804
- if ( cssPrefixWithPseudoSelectorFunctionMatch ) {
805
- const [ cssPseudoSelectorFunction ] = cssPrefixWithPseudoSelectorFunctionMatch ;
806
-
807
- // Unwrap the pseudo selector to scope its contents.
808
- // For example,
809
- // - `:where(selectorToScope)` -> `selectorToScope`;
810
- // - `:is(.foo, .bar)` -> `.foo, .bar`.
811
- const selectorToScope = selectorPart . slice ( cssPseudoSelectorFunction . length , - 1 ) ;
812
-
813
- if ( selectorToScope . includes ( _polyfillHostNoCombinator ) ) {
814
- this . _shouldScopeIndicator = true ;
815
- }
816
-
817
- const scopedInnerPart = this . _scopeSelector ( {
818
- selector : selectorToScope ,
819
- scopeSelector,
820
- hostSelector,
821
- } ) ;
822
-
823
- // Put the result back into the pseudo selector function.
824
- scopedPart = `${ cssPseudoSelectorFunction } ${ scopedInnerPart } )` ;
825
- } else {
826
- this . _shouldScopeIndicator =
827
- this . _shouldScopeIndicator || selectorPart . includes ( _polyfillHostNoCombinator ) ;
828
- scopedPart = this . _shouldScopeIndicator ? _scopeSelectorPart ( selectorPart ) : selectorPart ;
829
- }
830
-
831
- return scopedPart ;
832
- } ;
833
-
834
- if ( isParentSelector ) {
835
- this . _safeSelector = new SafeSelector ( selector ) ;
836
- selector = this . _safeSelector . content ( ) ;
837
- }
749
+ const safeContent = new SafeSelector ( selector ) ;
750
+ selector = safeContent . content ( ) ;
838
751
839
752
let scopedSelector = '' ;
840
753
let startIndex = 0 ;
841
754
let res : RegExpExecArray | null ;
842
- // Combinators aren't used as a delimiter if they are within parenthesis,
843
- // for example `:where(.one .two)` stays intact.
844
- // Similarly to selector separation by comma initially, negative lookahead
845
- // is used here to not break selectors within nested parenthesis up to three
846
- // nested layers.
847
- const sep =
848
- / ( | > | \+ | ~ (? ! = ) ) (? ! ( [ ^ ) ( ] * (?: \( [ ^ ) ( ] * (?: \( [ ^ ) ( ] * (?: \( [ ^ ) ( ] * \) [ ^ ) ( ] * ) * \) [ ^ ) ( ] * ) * \) [ ^ ) ( ] * ) * \) ) ) \s * / g;
755
+ const sep = / ( | > | \+ | ~ (? ! = ) ) \s * / g;
849
756
850
757
// If a selector appears before :host it should not be shimmed as it
851
758
// matches on ancestor elements and not on elements in the host's shadow
@@ -859,13 +766,8 @@ export class ShadowCss {
859
766
// - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a
860
767
// `:host-context(tag)`)
861
768
const hasHost = selector . includes ( _polyfillHostNoCombinator ) ;
862
- // Only scope parts after or on the same level as the first `-shadowcsshost-no-combinator`
863
- // when it is present. The selector has the same level when it is a part of a pseudo
864
- // selector, like `:where()`, for example `:where(:host, .foo)` would result in `.foo`
865
- // being scoped.
866
- if ( isParentSelector || this . _shouldScopeIndicator ) {
867
- this . _shouldScopeIndicator = ! hasHost ;
868
- }
769
+ // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present
770
+ let shouldScope = ! hasHost ;
869
771
870
772
while ( ( res = sep . exec ( selector ) ) !== null ) {
871
773
const separator = res [ 1 ] ;
@@ -884,17 +786,18 @@ export class ShadowCss {
884
786
continue ;
885
787
}
886
788
887
- const scopedPart = _pseudoFunctionAwareScopeSelectorPart ( part ) ;
789
+ shouldScope = shouldScope || part . includes ( _polyfillHostNoCombinator ) ;
790
+ const scopedPart = shouldScope ? _scopeSelectorPart ( part ) : part ;
888
791
scopedSelector += `${ scopedPart } ${ separator } ` ;
889
792
startIndex = sep . lastIndex ;
890
793
}
891
794
892
795
const part = selector . substring ( startIndex ) ;
893
- scopedSelector += _pseudoFunctionAwareScopeSelectorPart ( part ) ;
796
+ shouldScope = shouldScope || part . includes ( _polyfillHostNoCombinator ) ;
797
+ scopedSelector += shouldScope ? _scopeSelectorPart ( part ) : part ;
894
798
895
799
// replace the placeholders with their original values
896
- // using values stored inside the `safeSelector` instance.
897
- return this . _safeSelector ! . restore ( scopedSelector ) ;
800
+ return safeContent . restore ( scopedSelector ) ;
898
801
}
899
802
900
803
private _insertPolyfillHostInCssText ( selector : string ) : string {
@@ -959,8 +862,6 @@ class SafeSelector {
959
862
}
960
863
}
961
864
962
- const _cssScopedPseudoFunctionPrefix = '(:(where|is)\\()?' ;
963
- const _cssPrefixWithPseudoSelectorFunction = / ^ : ( w h e r e | i s ) \( / i;
964
865
const _cssContentNextSelectorRe =
965
866
/ p o l y f i l l - n e x t - s e l e c t o r [ ^ } ] * c o n t e n t : [ \s ] * ?( [ ' " ] ) ( .* ?) \1[ ; \s ] * } ( [ ^ { ] * ?) { / gim;
966
867
const _cssContentRuleRe = / ( p o l y f i l l - r u l e ) [ ^ } ] * ( c o n t e n t : [ \s ] * ( [ ' " ] ) ( .* ?) \3) [ ; \s ] * [ ^ } ] * } / gim;
@@ -971,17 +872,10 @@ const _polyfillHost = '-shadowcsshost';
971
872
const _polyfillHostContext = '-shadowcsscontext' ;
972
873
const _parenSuffix = '(?:\\((' + '(?:\\([^)(]*\\)|[^)(]*)+?' + ')\\))?([^,{]*)' ;
973
874
const _cssColonHostRe = new RegExp ( _polyfillHost + _parenSuffix , 'gim' ) ;
974
- const _cssColonHostContextReGlobal = new RegExp (
975
- _cssScopedPseudoFunctionPrefix + '(' + _polyfillHostContext + _parenSuffix + ')' ,
976
- 'gim' ,
977
- ) ;
875
+ const _cssColonHostContextReGlobal = new RegExp ( _polyfillHostContext + _parenSuffix , 'gim' ) ;
978
876
const _cssColonHostContextRe = new RegExp ( _polyfillHostContext + _parenSuffix , 'im' ) ;
979
877
const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator' ;
980
- const _polyfillHostNoCombinatorWithinPseudoFunction = new RegExp (
981
- `:.*\\(.*${ _polyfillHostNoCombinator } .*\\)` ,
982
- ) ;
983
878
const _polyfillHostNoCombinatorRe = / - s h a d o w c s s h o s t - n o - c o m b i n a t o r ( [ ^ \s ] * ) / ;
984
- const _polyfillHostNoCombinatorReGlobal = new RegExp ( _polyfillHostNoCombinatorRe , 'g' ) ;
985
879
const _shadowDOMSelectorsRe = [
986
880
/ : : s h a d o w / g,
987
881
/ : : c o n t e n t / g,
@@ -1232,11 +1126,7 @@ function unescapeQuotes(str: string, isQuoted: boolean): string {
1232
1126
* @param contextSelectors an array of context selectors that will be combined.
1233
1127
* @param otherSelectors the rest of the selectors that are not context selectors.
1234
1128
*/
1235
- function _combineHostContextSelectors (
1236
- contextSelectors : string [ ] ,
1237
- otherSelectors : string ,
1238
- pseudoPrefix = '' ,
1239
- ) : string {
1129
+ function combineHostContextSelectors ( contextSelectors : string [ ] , otherSelectors : string ) : string {
1240
1130
const hostMarker = _polyfillHostNoCombinator ;
1241
1131
_polyfillHostRe . lastIndex = 0 ; // reset the regex to ensure we get an accurate test
1242
1132
const otherSelectorsHasHost = _polyfillHostRe . test ( otherSelectors ) ;
@@ -1265,8 +1155,8 @@ function _combineHostContextSelectors(
1265
1155
return combined
1266
1156
. map ( ( s ) =>
1267
1157
otherSelectorsHasHost
1268
- ? `${ pseudoPrefix } ${ s } ${ otherSelectors } `
1269
- : `${ pseudoPrefix } ${ s } ${ hostMarker } ${ otherSelectors } , ${ pseudoPrefix } ${ s } ${ hostMarker } ${ otherSelectors } ` ,
1158
+ ? `${ s } ${ otherSelectors } `
1159
+ : `${ s } ${ hostMarker } ${ otherSelectors } , ${ s } ${ hostMarker } ${ otherSelectors } ` ,
1270
1160
)
1271
1161
. join ( ',' ) ;
1272
1162
}
0 commit comments