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  }