1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
package css_parser
import (
"strings"
"github.com/evanw/esbuild/internal/css_ast"
"github.com/evanw/esbuild/internal/css_lexer"
)
// Scan for animation names in the "animation" shorthand property
func (p *parser) processAnimationShorthand(tokens []css_ast.Token) {
type foundFlags struct {
timingFunction bool
iterationCount bool
direction bool
fillMode bool
playState bool
name bool
}
found := foundFlags{}
for i, t := range tokens {
switch t.Kind {
case css_lexer.TComma:
// Reset the flags when we encounter a comma
found = foundFlags{}
case css_lexer.TNumber:
if !found.iterationCount {
found.iterationCount = true
continue
}
case css_lexer.TIdent:
if !found.timingFunction {
switch strings.ToLower(t.Text) {
case "linear", "ease", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end":
found.timingFunction = true
continue
}
}
if !found.iterationCount && strings.ToLower(t.Text) == "infinite" {
found.iterationCount = true
continue
}
if !found.direction {
switch strings.ToLower(t.Text) {
case "normal", "reverse", "alternate", "alternate-reverse":
found.direction = true
continue
}
}
if !found.fillMode {
switch strings.ToLower(t.Text) {
case "none", "forwards", "backwards", "both":
found.fillMode = true
continue
}
}
if !found.playState {
switch strings.ToLower(t.Text) {
case "running", "paused":
found.playState = true
continue
}
}
if !found.name {
p.handleSingleAnimationName(&tokens[i])
found.name = true
continue
}
case css_lexer.TString:
if !found.name {
p.handleSingleAnimationName(&tokens[i])
found.name = true
continue
}
}
}
}
func (p *parser) processAnimationName(tokens []css_ast.Token) {
for i, t := range tokens {
if t.Kind == css_lexer.TIdent || t.Kind == css_lexer.TString {
p.handleSingleAnimationName(&tokens[i])
}
}
}
func (p *parser) handleSingleAnimationName(token *css_ast.Token) {
// Do not transform CSS keywords into symbols because they have special
// meaning in declarations. For example, "animation-name: none" clears
// the animation name. It does not set it to the animation named "none".
// You need to use "animation-name: 'none'" to do that.
//
// Also don't transform strings containing CSS keywords into global symbols
// because global symbols are passed through without being renamed, which
// will print them as keywords. However, we still want to unconditionally
// transform strings into local symbols because local symbols are always
// renamed, so they will never be printed as keywords.
if (token.Kind == css_lexer.TIdent || (token.Kind == css_lexer.TString && !p.makeLocalSymbols)) && isInvalidAnimationName(token.Text) {
return
}
token.Kind = css_lexer.TSymbol
token.PayloadIndex = p.symbolForName(token.Loc, token.Text).Ref.InnerIndex
}
func isInvalidAnimationName(text string) bool {
lower := strings.ToLower(text)
return lower == "none" || cssWideAndReservedKeywords[lower]
}
|