From e3f6eb8da51dc7a628b7c776f9ecb83b59809977 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Sun, 16 Jul 2023 20:09:28 -0400 Subject: [PATCH] css: emit mappings for tokens --- .../snapshots/snapshots_loader.txt | 4 +-- internal/css_ast/css_ast.go | 3 ++ internal/css_parser/css_decls.go | 3 +- .../css_parser/css_decls_border_radius.go | 16 +++++---- internal/css_parser/css_decls_box.go | 15 ++++---- internal/css_parser/css_decls_color.go | 34 +++++++++---------- internal/css_parser/css_decls_font_family.go | 1 + internal/css_parser/css_parser.go | 1 + internal/css_printer/css_printer.go | 10 +++--- scripts/js-api-tests.js | 2 +- 10 files changed, 50 insertions(+), 39 deletions(-) diff --git a/internal/bundler_tests/snapshots/snapshots_loader.txt b/internal/bundler_tests/snapshots/snapshots_loader.txt index dbf6aecbfb6..c259fab12f5 100644 --- a/internal/bundler_tests/snapshots/snapshots_loader.txt +++ b/internal/bundler_tests/snapshots/snapshots_loader.txt @@ -17,7 +17,7 @@ TestEmptyLoaderCSS "version": 3, "sources": ["entry.css"], "sourcesContent": ["\n\t\t\t\t@import 'a.empty';\n\t\t\t\ta { background: url(b.empty) }\n\t\t\t"], - "mappings": ";AAEI;AAAA,EAAI;AAAyB;", + "mappings": ";AAEI;AAAA,EAAI,YAAY;AAAa;", "names": [] } @@ -58,7 +58,7 @@ a { "imports": [], "exports": [], "inputs": {}, - "bytes": 204 + "bytes": 208 }, "entry.css": { "imports": [ diff --git a/internal/css_ast/css_ast.go b/internal/css_ast/css_ast.go index 7856dee3156..bea3372928a 100644 --- a/internal/css_ast/css_ast.go +++ b/internal/css_ast/css_ast.go @@ -46,6 +46,9 @@ type Token struct { // contains the decoded string contents for "TString" tokens. Text string // 16 bytes + // The source location at the start of the token + Loc logger.Loc // 4 bytes + // URL tokens have an associated import record at the top-level of the AST. // This index points to that import record. ImportRecordIndex uint32 // 4 bytes diff --git a/internal/css_parser/css_decls.go b/internal/css_parser/css_decls.go index 4d16dae122b..9b94538473b 100644 --- a/internal/css_parser/css_decls.go +++ b/internal/css_parser/css_decls.go @@ -7,8 +7,9 @@ import ( "github.com/evanw/esbuild/internal/logger" ) -func (p *parser) commaToken() css_ast.Token { +func (p *parser) commaToken(loc logger.Loc) css_ast.Token { t := css_ast.Token{ + Loc: loc, Kind: css_lexer.TComma, Text: ",", } diff --git a/internal/css_parser/css_decls_border_radius.go b/internal/css_parser/css_decls_border_radius.go index 9b40dbfdb01..cddc66e77c4 100644 --- a/internal/css_parser/css_decls_border_radius.go +++ b/internal/css_parser/css_decls_border_radius.go @@ -189,6 +189,7 @@ func (borderRadius *borderRadiusTracker) compactRules(rules []css_ast.Rule, keyR whitespace = css_ast.WhitespaceBefore | css_ast.WhitespaceAfter } tokens = append(tokens, css_ast.Token{ + Loc: tokens[len(tokens)-1].Loc, Kind: css_lexer.TDelimSlash, Text: "/", Whitespace: whitespace, @@ -197,17 +198,20 @@ func (borderRadius *borderRadiusTracker) compactRules(rules []css_ast.Rule, keyR } // Remove all of the existing declarations - rules[borderRadius.corners[0].ruleIndex] = css_ast.Rule{} - rules[borderRadius.corners[1].ruleIndex] = css_ast.Rule{} - rules[borderRadius.corners[2].ruleIndex] = css_ast.Rule{} - rules[borderRadius.corners[3].ruleIndex] = css_ast.Rule{} + var minLoc logger.Loc + for i, corner := range borderRadius.corners { + if loc := rules[corner.ruleIndex].Loc; i == 0 || loc.Start < minLoc.Start { + minLoc = loc + } + rules[corner.ruleIndex] = css_ast.Rule{} + } // Insert the combined declaration where the last rule was - rules[borderRadius.corners[3].ruleIndex].Data = &css_ast.RDeclaration{ + rules[borderRadius.corners[3].ruleIndex] = css_ast.Rule{Loc: minLoc, Data: &css_ast.RDeclaration{ Key: css_ast.DBorderRadius, KeyText: "border-radius", Value: tokens, KeyRange: keyRange, Important: borderRadius.important, - } + }} } diff --git a/internal/css_parser/css_decls_box.go b/internal/css_parser/css_decls_box.go index ba60672f088..f53bf00f0af 100644 --- a/internal/css_parser/css_decls_box.go +++ b/internal/css_parser/css_decls_box.go @@ -180,17 +180,20 @@ func (box *boxTracker) compactRules(rules []css_ast.Rule, keyRange logger.Range, ) // Remove all of the existing declarations - rules[box.sides[0].ruleIndex] = css_ast.Rule{} - rules[box.sides[1].ruleIndex] = css_ast.Rule{} - rules[box.sides[2].ruleIndex] = css_ast.Rule{} - rules[box.sides[3].ruleIndex] = css_ast.Rule{} + var minLoc logger.Loc + for i, side := range box.sides { + if loc := rules[side.ruleIndex].Loc; i == 0 || loc.Start < minLoc.Start { + minLoc = loc + } + rules[side.ruleIndex] = css_ast.Rule{} + } // Insert the combined declaration where the last rule was - rules[box.sides[3].ruleIndex].Data = &css_ast.RDeclaration{ + rules[box.sides[3].ruleIndex] = css_ast.Rule{Loc: minLoc, Data: &css_ast.RDeclaration{ Key: box.key, KeyText: box.keyText, Value: tokens, KeyRange: keyRange, Important: box.important, - } + }} } diff --git a/internal/css_parser/css_decls_color.go b/internal/css_parser/css_decls_color.go index 8129aa69e1d..2e29c1475fb 100644 --- a/internal/css_parser/css_decls_color.go +++ b/internal/css_parser/css_decls_color.go @@ -289,12 +289,12 @@ func (p *parser) lowerColor(token css_ast.Token) css_ast.Token { hex = expandHex(hex) token.Kind = css_lexer.TFunction token.Text = "rgba" - commaToken := p.commaToken() + commaToken := p.commaToken(token.Loc) token.Children = &[]css_ast.Token{ - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: floatToStringForColor(float64(hexA(hex)) / 255)}, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: floatToStringForColor(float64(hexA(hex)) / 255)}, } } @@ -303,12 +303,12 @@ func (p *parser) lowerColor(token css_ast.Token) css_ast.Token { if hex, ok := parseHex(text); ok { token.Kind = css_lexer.TFunction token.Text = "rgba" - commaToken := p.commaToken() + commaToken := p.commaToken(token.Loc) token.Children = &[]css_ast.Token{ - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: floatToStringForColor(float64(hexA(hex)) / 255)}, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: floatToStringForColor(float64(hexA(hex)) / 255)}, } } } @@ -346,7 +346,7 @@ func (p *parser) lowerColor(token css_ast.Token) css_ast.Token { removeAlpha = true args[0].Whitespace = 0 args[1].Whitespace = 0 - commaToken := p.commaToken() + commaToken := p.commaToken(token.Loc) token.Children = &[]css_ast.Token{ args[0], commaToken, args[1], commaToken, @@ -372,7 +372,7 @@ func (p *parser) lowerColor(token css_ast.Token) css_ast.Token { args[0].Whitespace = 0 args[1].Whitespace = 0 args[2].Whitespace = 0 - commaToken := p.commaToken() + commaToken := p.commaToken(token.Loc) token.Children = &[]css_ast.Token{ args[0], commaToken, args[1], commaToken, @@ -632,17 +632,17 @@ func (p *parser) mangleColor(token css_ast.Token, hex uint32) css_ast.Token { } else { token.Kind = css_lexer.TFunction token.Text = "rgba" - commaToken := p.commaToken() + commaToken := p.commaToken(token.Loc) index := hexA(hex) * 4 alpha := alphaFractionTable[index : index+4] if space := strings.IndexByte(alpha, ' '); space != -1 { alpha = alpha[:space] } token.Children = &[]css_ast.Token{ - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken, - {Kind: css_lexer.TNumber, Text: alpha}, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken, + {Loc: token.Loc, Kind: css_lexer.TNumber, Text: alpha}, } } diff --git a/internal/css_parser/css_decls_font_family.go b/internal/css_parser/css_decls_font_family.go index 9fc2407a4cb..8c403821b27 100644 --- a/internal/css_parser/css_decls_font_family.go +++ b/internal/css_parser/css_decls_font_family.go @@ -102,6 +102,7 @@ func (p *parser) mangleFamilyNameOrGenericName(result []css_ast.Token, tokens [] whitespace = css_ast.WhitespaceBefore } result = append(result, css_ast.Token{ + Loc: t.Loc, Kind: css_lexer.TIdent, Text: name, Whitespace: whitespace, diff --git a/internal/css_parser/css_parser.go b/internal/css_parser/css_parser.go index 0ff7f1e43c7..3f886b170dd 100644 --- a/internal/css_parser/css_parser.go +++ b/internal/css_parser/css_parser.go @@ -1523,6 +1523,7 @@ loop: break loop } token := css_ast.Token{ + Loc: t.Range.Loc, Kind: t.Kind, Text: t.DecodedText(p.source.Contents), Whitespace: nextWhitespace, diff --git a/internal/css_printer/css_printer.go b/internal/css_printer/css_printer.go index a7ded502aff..3bcb6cfdbd9 100644 --- a/internal/css_printer/css_printer.go +++ b/internal/css_printer/css_printer.go @@ -263,9 +263,6 @@ func (p *printer) printRule(rule css_ast.Rule, indent int32, omitTrailingSemicol p.printRuleBlock(r.Rules, indent, r.CloseBraceLoc) case *css_ast.RQualified: - if p.options.AddSourceMappings { - p.builder.AddSourceMapping(rule.Loc, "", p.css) - } hasWhitespaceAfter := p.printTokens(r.Prelude, printTokensOpts{}) if !hasWhitespaceAfter && !p.options.MinifyWhitespace { p.print(" ") @@ -293,9 +290,6 @@ func (p *printer) printRule(rule css_ast.Rule, indent int32, omitTrailingSemicol } case *css_ast.RBadDeclaration: - if p.options.AddSourceMappings { - p.builder.AddSourceMapping(rule.Loc, "", p.css) - } p.printTokens(r.Tokens, printTokensOpts{}) if !omitTrailingSemicolon { p.print(";") @@ -934,6 +928,10 @@ func (p *printer) printTokens(tokens []css_ast.Token, opts printTokensOpts) bool whitespace = canDiscardWhitespaceAfter } + if p.options.AddSourceMappings { + p.builder.AddSourceMapping(t.Loc, "", p.css) + } + switch t.Kind { case css_lexer.TIdent: p.printIdent(t.Text, identNormal, whitespace) diff --git a/scripts/js-api-tests.js b/scripts/js-api-tests.js index aaa7064f58f..9f26d45697a 100644 --- a/scripts/js-api-tests.js +++ b/scripts/js-api-tests.js @@ -1576,7 +1576,7 @@ body { }, }, [makePath(output + '.map')]: { - bytes: 325, + bytes: 335, exports: [], imports: [], inputs: {},