github.com/evanw/esbuild@v0.21.4/internal/css_parser/css_decls_composes.go (about)

     1  package css_parser
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/evanw/esbuild/internal/ast"
     8  	"github.com/evanw/esbuild/internal/css_ast"
     9  	"github.com/evanw/esbuild/internal/css_lexer"
    10  	"github.com/evanw/esbuild/internal/logger"
    11  )
    12  
    13  type composesContext struct {
    14  	parentRefs   []ast.Ref
    15  	parentRange  logger.Range
    16  	problemRange logger.Range
    17  }
    18  
    19  func (p *parser) handleComposesPragma(context composesContext, tokens []css_ast.Token) {
    20  	type nameWithLoc struct {
    21  		loc  logger.Loc
    22  		text string
    23  	}
    24  	var names []nameWithLoc
    25  	fromGlobal := false
    26  
    27  	for i, t := range tokens {
    28  		if t.Kind == css_lexer.TIdent {
    29  			// Check for a "from" clause at the end
    30  			if strings.EqualFold(t.Text, "from") && i+2 == len(tokens) {
    31  				last := tokens[i+1]
    32  
    33  				// A string or a URL is an external file
    34  				if last.Kind == css_lexer.TString || last.Kind == css_lexer.TURL {
    35  					var importRecordIndex uint32
    36  					if last.Kind == css_lexer.TString {
    37  						importRecordIndex = uint32(len(p.importRecords))
    38  						p.importRecords = append(p.importRecords, ast.ImportRecord{
    39  							Kind:  ast.ImportComposesFrom,
    40  							Path:  logger.Path{Text: last.Text},
    41  							Range: p.source.RangeOfString(last.Loc),
    42  						})
    43  					} else {
    44  						importRecordIndex = last.PayloadIndex
    45  						p.importRecords[importRecordIndex].Kind = ast.ImportComposesFrom
    46  					}
    47  					for _, parentRef := range context.parentRefs {
    48  						composes := p.composes[parentRef]
    49  						for _, name := range names {
    50  							composes.ImportedNames = append(composes.ImportedNames, css_ast.ImportedComposesName{
    51  								ImportRecordIndex: importRecordIndex,
    52  								Alias:             name.text,
    53  								AliasLoc:          name.loc,
    54  							})
    55  						}
    56  					}
    57  					return
    58  				}
    59  
    60  				// An identifier must be "global"
    61  				if last.Kind == css_lexer.TIdent {
    62  					if strings.EqualFold(last.Text, "global") {
    63  						fromGlobal = true
    64  						break
    65  					}
    66  
    67  					p.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, css_lexer.RangeOfIdentifier(p.source, last.Loc),
    68  						fmt.Sprintf("\"composes\" declaration uses invalid location %q", last.Text))
    69  					p.prevError = t.Loc
    70  					return
    71  				}
    72  			}
    73  
    74  			names = append(names, nameWithLoc{t.Loc, t.Text})
    75  			continue
    76  		}
    77  
    78  		// Any unexpected tokens are a syntax error
    79  		var text string
    80  		switch t.Kind {
    81  		case css_lexer.TURL, css_lexer.TBadURL, css_lexer.TString, css_lexer.TUnterminatedString:
    82  			text = fmt.Sprintf("Unexpected %s", t.Kind.String())
    83  		default:
    84  			text = fmt.Sprintf("Unexpected %q", t.Text)
    85  		}
    86  		p.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, logger.Range{Loc: t.Loc}, text)
    87  		p.prevError = t.Loc
    88  		return
    89  	}
    90  
    91  	// If we get here, all of these names are not references to another file
    92  	old := p.makeLocalSymbols
    93  	if fromGlobal {
    94  		p.makeLocalSymbols = false
    95  	}
    96  	for _, parentRef := range context.parentRefs {
    97  		composes := p.composes[parentRef]
    98  		for _, name := range names {
    99  			composes.Names = append(composes.Names, p.symbolForName(name.loc, name.text))
   100  		}
   101  	}
   102  	p.makeLocalSymbols = old
   103  }