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