@@ -705,8 +705,8 @@ next:
705705 // Mangle non-top-level rules using a back-to-front pass. Top-level rules
706706 // will be mangled by the linker instead for cross-file rule mangling.
707707 if ! isTopLevel {
708- remover := MakeDuplicateRuleMangler (ast.SymbolMap {})
709- mangledRules = remover .RemoveDuplicateRulesInPlace (p .source .Index , mangledRules , p .importRecords )
708+ remover := MakeDeadRuleMangler (ast.SymbolMap {})
709+ mangledRules = remover .RemoveDeadRulesInPlace (p .source .Index , mangledRules , p .importRecords )
710710 }
711711
712712 return mangledRules
@@ -726,20 +726,20 @@ type callEntry struct {
726726 sourceIndex uint32
727727}
728728
729- type DuplicateRuleRemover struct {
729+ type DeadRuleRemover struct {
730730 entries map [uint32 ]hashEntry
731731 calls []callEntry
732732 check css_ast.CrossFileEqualityCheck
733733}
734734
735- func MakeDuplicateRuleMangler (symbols ast.SymbolMap ) DuplicateRuleRemover {
736- return DuplicateRuleRemover {
735+ func MakeDeadRuleMangler (symbols ast.SymbolMap ) DeadRuleRemover {
736+ return DeadRuleRemover {
737737 entries : make (map [uint32 ]hashEntry ),
738738 check : css_ast.CrossFileEqualityCheck {Symbols : symbols },
739739 }
740740}
741741
742- func (remover * DuplicateRuleRemover ) RemoveDuplicateRulesInPlace (sourceIndex uint32 , rules []css_ast.Rule , importRecords []ast.ImportRecord ) []css_ast.Rule {
742+ func (remover * DeadRuleRemover ) RemoveDeadRulesInPlace (sourceIndex uint32 , rules []css_ast.Rule , importRecords []ast.ImportRecord ) []css_ast.Rule {
743743 // The caller may call this function multiple times, each with a different
744744 // set of import records. Remember each set of import records for equality
745745 // checks later.
@@ -758,6 +758,11 @@ skipRule:
758758 for i := n - 1 ; i >= 0 ; i -- {
759759 rule := rules [i ]
760760
761+ // Remove rules with selectors that don't apply to anything (e.g. ":is()")
762+ if r , ok := rule .Data .(* css_ast.RSelector ); ok && allSelectorsAreDead (r .Selectors ) {
763+ continue skipRule
764+ }
765+
761766 // For duplicate rules, omit all but the last copy
762767 if hash , ok := rule .Data .Hash (); ok {
763768 entry := remover .entries [hash ]
@@ -795,6 +800,28 @@ skipRule:
795800 return rules [start :]
796801}
797802
803+ func containsDeadSelectors (selectors []css_ast.CompoundSelector ) bool {
804+ for _ , sel := range selectors {
805+ for _ , ss := range sel .SubclassSelectors {
806+ if pseudo , ok := ss .Data .(* css_ast.SSPseudoClassWithSelectorList ); ok && len (pseudo .Selectors ) == 0 &&
807+ (pseudo .Kind == css_ast .PseudoClassIs || pseudo .Kind == css_ast .PseudoClassWhere ) {
808+ // ":is()" and ":where()" never match anything when empty
809+ return true
810+ }
811+ }
812+ }
813+ return false
814+ }
815+
816+ func allSelectorsAreDead (selectors []css_ast.ComplexSelector ) bool {
817+ for _ , sel := range selectors {
818+ if ! containsDeadSelectors (sel .Selectors ) {
819+ return false
820+ }
821+ }
822+ return true
823+ }
824+
798825// Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element
799826var nonDeprecatedElementsSupportedByIE7 = map [string ]bool {
800827 "a" : true ,
0 commit comments