Skip to content

Commit 0231961

Browse files
committed
fix #4232: support empty :is() and :where()
1 parent cbd81f2 commit 0231961

File tree

3 files changed

+28
-9
lines changed

3 files changed

+28
-9
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
Calling `rebuild()` followed by `cancel()` in rapid succession could previously leak memory. The bundler uses a producer/consumer model internally, and the resource leak was caused by the consumer being termianted while there were still remaining unreceived results from a producer. To avoid the leak, the consumer now waits for all producers to finish before terminating.
88

9+
* Support empty `:is()` and `:where()` syntax in CSS ([#4232](https://github.com/evanw/esbuild/issues/4232))
10+
11+
Previously using these selectors with esbuild would generate a warning. That warning has been removed in this release for these cases.
12+
913
* Consider negated bigints to have no side effects
1014

1115
While esbuild currently considers `1`, `-1`, and `1n` to all have no side effects, it didn't previously consider `-1n` to have no side effects. This is because esbuild does constant folding with numbers but not bigints. However, it meant that unused negative bigint constants were not tree-shaken. With this release, esbuild will now consider these expressions to also be side-effect free:

internal/css_parser/css_parser_selector.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,22 @@ import (
1010
)
1111

1212
type parseSelectorOpts struct {
13-
composesContext *composesContext
14-
pseudoClassKind css_ast.PseudoClassKind
15-
isDeclarationContext bool
16-
stopOnCloseParen bool
17-
onlyOneComplexSelector bool
18-
noLeadingCombinator bool
13+
composesContext *composesContext
14+
pseudoClassKind css_ast.PseudoClassKind
15+
isDeclarationContext bool
16+
stopOnCloseParen bool
17+
onlyOneComplexSelector bool
18+
isForgivingSelectorList bool
19+
noLeadingCombinator bool
1920
}
2021

2122
func (p *parser) parseSelectorList(opts parseSelectorOpts) (list []css_ast.ComplexSelector, ok bool) {
23+
// Potentially parse an empty list for ":is()" and ":where()"
24+
if opts.isForgivingSelectorList && opts.stopOnCloseParen && p.current().Kind == css_lexer.TCloseParen {
25+
ok = true
26+
return
27+
}
28+
2229
// Parse the first selector
2330
sel, good := p.parseComplexSelector(parseComplexSelectorOpts{
2431
parseSelectorOpts: opts,
@@ -699,9 +706,10 @@ func (p *parser) parsePseudoClassSelector(loc logger.Loc, isElement bool) (css_a
699706
oldLocal := p.makeLocalSymbols
700707
p.makeLocalSymbols = local
701708
selectors, ok := p.parseSelectorList(parseSelectorOpts{
702-
pseudoClassKind: kind,
703-
stopOnCloseParen: true,
704-
onlyOneComplexSelector: kind == css_ast.PseudoClassGlobal || kind == css_ast.PseudoClassLocal,
709+
pseudoClassKind: kind,
710+
stopOnCloseParen: true,
711+
onlyOneComplexSelector: kind == css_ast.PseudoClassGlobal || kind == css_ast.PseudoClassLocal,
712+
isForgivingSelectorList: kind == css_ast.PseudoClassIs || kind == css_ast.PseudoClassWhere,
705713
})
706714
p.makeLocalSymbols = oldLocal
707715

internal/css_parser/css_parser_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,13 @@ func TestSelector(t *testing.T) {
986986
expectPrinted(t, "a:is( c ) {}", "a:is(c) {\n}\n", "")
987987
expectPrinted(t, "a:is( c , d ) {}", "a:is(c, d) {\n}\n", "")
988988

989+
// Check an empty <forgiving-selector-list> (see https://github.com/evanw/esbuild/issues/4232)
990+
expectPrinted(t, ":is() {}", ":is() {\n}\n", "")
991+
expectPrinted(t, ":where() {}", ":where() {\n}\n", "")
992+
expectPrinted(t, ":not(:is()) {}", ":not(:is()) {\n}\n", "")
993+
expectPrinted(t, ":not(:where()) {}", ":not(:where()) {\n}\n", "")
994+
expectPrinted(t, ":not() {}", ":not() {\n}\n", "<stdin>: WARNING: Unexpected \")\"\n")
995+
989996
// These test cases previously caused a hang (see https://github.com/evanw/esbuild/issues/2276)
990997
expectPrinted(t, ":x(", ":x() {\n}\n", "<stdin>: WARNING: Unexpected end of file\n")
991998
expectPrinted(t, ":x( {}", ":x({}) {\n}\n", "<stdin>: WARNING: Expected \")\" to go with \"(\"\n<stdin>: NOTE: The unbalanced \"(\" is here:\n")

0 commit comments

Comments
 (0)