Skip to content

Commit c9b24d8

Browse files
committedSep 18, 2022
fix #2555: parse @keyframes with string namems
1 parent 93e068d commit c9b24d8

File tree

4 files changed

+17
-11
lines changed

4 files changed

+17
-11
lines changed
 

‎CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@
9393
9494
However, the compilation had a subtle bug where the automatically-generated function-level symbols for multible hoisted block-level function declarations in the same block a sloppy-mode context were generated in a random order if the output was in strict mode, which could be the case if TypeScript's `alwaysStrict` setting was set to true. This lead to non-determinism in the output as the minifier would randomly exchange the generated names for these symbols on different runs. This bug has been fixed by sorting the keys of the unordered map before iterating over them.
9595
96+
* Fix parsing of `@keyframes` with string identifiers ([#2555](https://github.com/evanw/esbuild/issues/2555))
97+
98+
Firefox supports `@keyframes` with string identifier names. Previously this was treated as a syntax error by esbuild as it doesn't work in any other browser. The specification allows for this however, so it's technically not a syntax error (even though it would be unwise to use this feature at the moment). There was also a bug where esbuild would remove the identifier name in this case as the syntax wasn't recognized.
99+
100+
This release changes esbuild's parsing of `@keyframes` to now consider this case to be an unrecognized CSS rule. That means it will be passed through unmodified (so you can now use esbuild to bundle this Firefox-specific CSS) but the CSS will not be pretty-printed or minified. I don't think it makes sense for esbuild to have special code to handle this Firefox-specific syntax at this time. This decision can be revisited in the future if other browsers add support for this feature.
101+
96102
## 0.15.7
97103
98104
* Add `--watch=forever` to allow esbuild to never terminate ([#1511](https://github.com/evanw/esbuild/issues/1511), [#1885](https://github.com/evanw/esbuild/issues/1885))

‎internal/css_parser/css_parser.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -832,10 +832,13 @@ abortRuleParser:
832832
if p.peek(css_lexer.TIdent) {
833833
name = p.decoded()
834834
p.advance()
835-
} else if !p.expect(css_lexer.TIdent) && !p.eat(css_lexer.TString) && !p.peek(css_lexer.TOpenBrace) {
836-
// Consider string names a syntax error even though they are allowed by
837-
// the specification and they work in Firefox because they do not work in
838-
// Chrome or Safari.
835+
} else if p.eat(css_lexer.TString) {
836+
// Consider string names to be an unknown rule even though they are allowed
837+
// by the specification and they work in Firefox because they do not work in
838+
// Chrome or Safari. We don't take the effort to support this Firefox-only
839+
// feature natively. Instead, we just pass the syntax through unmodified.
840+
break
841+
} else if !p.expect(css_lexer.TIdent) {
839842
break
840843
}
841844

‎internal/css_parser/css_parser_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,8 @@ func TestLegalComment(t *testing.T) {
10111011
}
10121012

10131013
func TestAtKeyframes(t *testing.T) {
1014-
expectPrinted(t, "@keyframes {}", "@keyframes \"\" {\n}\n")
1014+
expectPrinted(t, "@keyframes {}", "@keyframes {}\n")
1015+
expectPrinted(t, "@keyframes 'name' {}", "@keyframes \"name\" {}\n")
10151016
expectPrinted(t, "@keyframes name{}", "@keyframes name {\n}\n")
10161017
expectPrinted(t, "@keyframes name {}", "@keyframes name {\n}\n")
10171018
expectPrinted(t, "@keyframes name{0%,50%{color:red}25%,75%{color:blue}}",
@@ -1034,7 +1035,7 @@ func TestAtKeyframes(t *testing.T) {
10341035
expectPrinted(t, "@-o-keyframes name {}", "@-o-keyframes name {\n}\n")
10351036

10361037
expectParseError(t, "@keyframes {}", "<stdin>: WARNING: Expected identifier but found \"{\"\n")
1037-
expectParseError(t, "@keyframes 'name' {}", "<stdin>: WARNING: Expected identifier but found \"'name'\"\n")
1038+
expectParseError(t, "@keyframes 'name' {}", "") // This is allowed as it's technically possible to use in Firefox (but in no other browser)
10381039
expectParseError(t, "@keyframes name { 0% 100% {} }", "<stdin>: WARNING: Expected \",\" but found \"100%\"\n")
10391040
expectParseError(t, "@keyframes name { {} 0% {} }", "<stdin>: WARNING: Expected percentage but found \"{\"\n")
10401041
expectParseError(t, "@keyframes name { 100 {} }", "<stdin>: WARNING: Expected percentage but found \"100\"\n")

‎internal/css_printer/css_printer.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,7 @@ func (p *printer) printRule(rule css_ast.Rule, indent int32, omitTrailingSemicol
108108
p.print("@")
109109
p.printIdent(r.AtToken, identNormal, mayNeedWhitespaceAfter)
110110
p.print(" ")
111-
if r.Name == "" {
112-
p.print("\"\"")
113-
} else {
114-
p.printIdent(r.Name, identNormal, canDiscardWhitespaceAfter)
115-
}
111+
p.printIdent(r.Name, identNormal, canDiscardWhitespaceAfter)
116112
if !p.options.MinifyWhitespace {
117113
p.print(" ")
118114
}

0 commit comments

Comments
 (0)
Please sign in to comment.