github.com/evanw/esbuild@v0.21.4/internal/css_parser/css_decls_list_style.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  // list-style-image: <image> | none
    11  // <image>: <url> | <gradient>
    12  // <url>: <url()> | <src()>
    13  // <gradient>: <linear-gradient()> | <repeating-linear-gradient()> | <radial-gradient()> | <repeating-radial-gradient()>
    14  //
    15  // list-style-type: <counter-style> | <string> | none (where the string is a literal bullet marker)
    16  // <counter-style>: <counter-style-name> | <symbols()>
    17  // <counter-style-name>: not: decimal | disc | square | circle | disclosure-open | disclosure-closed | <wide keyword>
    18  // when parsing a <custom-ident> with conflicts, only parse one if no other thing can claim it
    19  
    20  func (p *parser) processListStyleShorthand(tokens []css_ast.Token) {
    21  	if len(tokens) < 1 || len(tokens) > 3 {
    22  		return
    23  	}
    24  
    25  	foundImage := false
    26  	foundPosition := false
    27  	typeIndex := -1
    28  	noneCount := 0
    29  
    30  	for i, t := range tokens {
    31  		switch t.Kind {
    32  		case css_lexer.TString:
    33  			// "list-style-type" is definitely not a <custom-ident>
    34  			return
    35  
    36  		case css_lexer.TURL:
    37  			if !foundImage {
    38  				foundImage = true
    39  				continue
    40  			}
    41  
    42  		case css_lexer.TFunction:
    43  			if !foundImage {
    44  				switch strings.ToLower(t.Text) {
    45  				case "src", "linear-gradient", "repeating-linear-gradient", "radial-gradient", "radial-linear-gradient":
    46  					foundImage = true
    47  					continue
    48  				}
    49  			}
    50  
    51  		case css_lexer.TIdent:
    52  			lower := strings.ToLower(t.Text)
    53  
    54  			// Note: If "none" is present, it's ambiguous whether it applies to
    55  			// "list-style-image" or "list-style-type". To resolve ambiguity it's
    56  			// applied at the end to whichever property isn't otherwise set.
    57  			if lower == "none" {
    58  				noneCount++
    59  				continue
    60  			}
    61  
    62  			if !foundPosition && (lower == "inside" || lower == "outside") {
    63  				foundPosition = true
    64  				continue
    65  			}
    66  
    67  			if typeIndex == -1 {
    68  				if cssWideAndReservedKeywords[lower] || predefinedCounterStyles[lower] {
    69  					// "list-style-type" is definitely not a <custom-ident>
    70  					return
    71  				}
    72  				typeIndex = i
    73  				continue
    74  			}
    75  		}
    76  
    77  		// Bail if we hit an unexpected token
    78  		return
    79  	}
    80  
    81  	if typeIndex != -1 {
    82  		// The first "none" applies to "list-style-image" if it's missing
    83  		if !foundImage && noneCount > 0 {
    84  			noneCount--
    85  		}
    86  
    87  		if noneCount > 0 {
    88  			// "list-style-type" is "none", not a <custom-ident>
    89  			return
    90  		}
    91  
    92  		if t := &tokens[typeIndex]; t.Kind == css_lexer.TIdent {
    93  			t.Kind = css_lexer.TSymbol
    94  			t.PayloadIndex = p.symbolForName(t.Loc, t.Text).Ref.InnerIndex
    95  		}
    96  	}
    97  }
    98  
    99  func (p *parser) processListStyleType(t *css_ast.Token) {
   100  	if t.Kind == css_lexer.TIdent {
   101  		if lower := strings.ToLower(t.Text); lower != "none" && !cssWideAndReservedKeywords[lower] && !predefinedCounterStyles[lower] {
   102  			t.Kind = css_lexer.TSymbol
   103  			t.PayloadIndex = p.symbolForName(t.Loc, t.Text).Ref.InnerIndex
   104  		}
   105  	}
   106  }
   107  
   108  // https://drafts.csswg.org/css-counter-styles-3/#predefined-counters
   109  var predefinedCounterStyles = map[string]bool{
   110  	// 6.1. Numeric:
   111  	"arabic-indic":         true,
   112  	"armenian":             true,
   113  	"bengali":              true,
   114  	"cambodian":            true,
   115  	"cjk-decimal":          true,
   116  	"decimal-leading-zero": true,
   117  	"decimal":              true,
   118  	"devanagari":           true,
   119  	"georgian":             true,
   120  	"gujarati":             true,
   121  	"gurmukhi":             true,
   122  	"hebrew":               true,
   123  	"kannada":              true,
   124  	"khmer":                true,
   125  	"lao":                  true,
   126  	"lower-armenian":       true,
   127  	"lower-roman":          true,
   128  	"malayalam":            true,
   129  	"mongolian":            true,
   130  	"myanmar":              true,
   131  	"oriya":                true,
   132  	"persian":              true,
   133  	"tamil":                true,
   134  	"telugu":               true,
   135  	"thai":                 true,
   136  	"tibetan":              true,
   137  	"upper-armenian":       true,
   138  	"upper-roman":          true,
   139  
   140  	// 6.2. Alphabetic:
   141  	"hiragana-iroha": true,
   142  	"hiragana":       true,
   143  	"katakana-iroha": true,
   144  	"katakana":       true,
   145  	"lower-alpha":    true,
   146  	"lower-greek":    true,
   147  	"lower-latin":    true,
   148  	"upper-alpha":    true,
   149  	"upper-latin":    true,
   150  
   151  	// 6.3. Symbolic:
   152  	"circle":            true,
   153  	"disc":              true,
   154  	"disclosure-closed": true,
   155  	"disclosure-open":   true,
   156  	"square":            true,
   157  
   158  	// 6.4. Fixed:
   159  	"cjk-earthly-branch": true,
   160  	"cjk-heavenly-stem":  true,
   161  
   162  	// 7.1.1. Japanese:
   163  	"japanese-formal":   true,
   164  	"japanese-informal": true,
   165  
   166  	// 7.1.2. Korean:
   167  	"korean-hangul-formal":  true,
   168  	"korean-hanja-formal":   true,
   169  	"korean-hanja-informal": true,
   170  
   171  	// 7.1.3. Chinese:
   172  	"simp-chinese-formal":   true,
   173  	"simp-chinese-informal": true,
   174  	"trad-chinese-formal":   true,
   175  	"trad-chinese-informal": true,
   176  
   177  	// 7.2. Ethiopic Numeric Counter Style:
   178  	"ethiopic-numeric": true,
   179  }