Skip to content

Commit

Permalink
css: add source map entries for generated js names
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jul 25, 2023
1 parent 8abb666 commit 78eefe1
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 23 deletions.
13 changes: 6 additions & 7 deletions internal/bundler/bundler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2062,21 +2062,19 @@ func (s *scanner) processScannedFiles(entryPointMeta []graph.EntryPoint) []scann
stubKey.Text = canonicalFileSystemPathForWindows(stubKey.Text)
}
sourceIndex := s.allocateSourceIndex(stubKey, cache.SourceIndexJSStubForCSS)
source := logger.Source{
Index: sourceIndex,
PrettyPath: otherFile.inputFile.Source.PrettyPath,
IdentifierName: otherFile.inputFile.Source.IdentifierName,
}
source := otherFile.inputFile.Source
source.Index = sourceIndex

// Export all local CSS names for JavaScript to use
exports := js_ast.EObject{}
cssSourceIndex := record.SourceIndex.GetIndex()
for innerIndex, symbol := range css.AST.Symbols {
if symbol.Kind == ast.SymbolLocalCSS {
ref := ast.Ref{SourceIndex: cssSourceIndex, InnerIndex: uint32(innerIndex)}
loc := css.AST.DefineLocs[ref]
exports.Properties = append(exports.Properties, js_ast.Property{
Key: js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(symbol.OriginalName)}},
ValueOrNil: js_ast.Expr{Data: &js_ast.ENameOfSymbol{Ref: ref}},
Key: js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(symbol.OriginalName)}},
ValueOrNil: js_ast.Expr{Loc: loc, Data: &js_ast.ENameOfSymbol{Ref: ref}},
})
}
}
Expand All @@ -2085,6 +2083,7 @@ func (s *scanner) processScannedFiles(entryPointMeta []graph.EntryPoint) []scann
file: scannerFile{
inputFile: graph.InputFile{
Source: source,
Loader: otherFile.inputFile.Loader,
Repr: &graph.JSRepr{
AST: js_parser.LazyExportAST(s.log, source,
js_parser.OptionsFromConfig(&s.options), js_ast.Expr{Data: &exports}, ""),
Expand Down
12 changes: 6 additions & 6 deletions internal/bundler_tests/snapshots/snapshots_css.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1110,13 +1110,13 @@ console.log("file 1", t, l.a);

// dir2/style.css
var e = "n";
var f = {
var n = {
b: "e",
button: e
};

// b.js
console.log("file 2", e, f.b);
console.log("file 2", e, n.b);

---------- /out/entry.css ----------
/* dir1/style.css */
Expand Down Expand Up @@ -1154,7 +1154,7 @@ TestImportLocalCSSFromJSMinifyIdentifiersAvoidGlobalNames

================================================================================
TestMetafileCSSBundleTwoToOne
---------- /out/js/UOATE6K4.js ----------
---------- /out/js/2PSDKYWE.js ----------
// foo/entry.js
console.log("foo");

Expand All @@ -1164,7 +1164,7 @@ body {
color: red;
}

---------- /out/js/6ZCNL5VY.js ----------
---------- /out/js/MA6C7ZBK.js ----------
// bar/entry.js
console.log("bar");
---------- metafile.json ----------
Expand Down Expand Up @@ -1198,7 +1198,7 @@ console.log("bar");
}
},
"outputs": {
"out/js/UOATE6K4.js": {
"out/js/2PSDKYWE.js": {
"imports": [],
"exports": [],
"entryPoint": "foo/entry.js",
Expand All @@ -1222,7 +1222,7 @@ console.log("bar");
},
"bytes": 40
},
"out/js/6ZCNL5VY.js": {
"out/js/MA6C7ZBK.js": {
"imports": [],
"exports": [],
"entryPoint": "bar/entry.js",
Expand Down
4 changes: 2 additions & 2 deletions internal/bundler_tests/snapshots/snapshots_default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1170,13 +1170,13 @@ console.log((init_types(), __toCommonJS(types_exports)));

================================================================================
TestEntryNamesChunkNamesExtPlaceholder
---------- /out/main/js/entry1-L7KI5G7A.js ----------
---------- /out/main/js/entry1-4X3SO762.js ----------
import "../../common/js/chunk-XHGYOYUR.js";

// src/entries/entry1.js
console.log("entry1");

---------- /out/main/js/entry2-KTHKWVT2.js ----------
---------- /out/main/js/entry2-URQRHZS5.js ----------
import "../../common/js/chunk-XHGYOYUR.js";

// src/entries/entry2.js
Expand Down
15 changes: 11 additions & 4 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,17 @@ func (loader Loader) IsTypeScript() bool {
switch loader {
case LoaderTS, LoaderTSNoAmbiguousLessThan, LoaderTSX:
return true
default:
return false
}
return false
}

func (loader Loader) IsCSS() bool {
switch loader {
case
LoaderCSS, LoaderGlobalCSS, LoaderLocalCSS:
return true
}
return false
}

func (loader Loader) CanHaveSourceMap() bool {
Expand All @@ -242,9 +250,8 @@ func (loader Loader) CanHaveSourceMap() bool {
LoaderCSS, LoaderGlobalCSS, LoaderLocalCSS,
LoaderJSON, LoaderText:
return true
default:
return false
}
return false
}

type Format uint8
Expand Down
1 change: 1 addition & 0 deletions internal/css_ast/css_ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type AST struct {
Rules []Rule
SourceMapComment logger.Span
ApproximateLineCount int32
DefineLocs map[ast.Ref]logger.Loc
}

// We create a lot of tokens, so make sure this layout is memory-efficient.
Expand Down
48 changes: 48 additions & 0 deletions internal/css_lexer/css_lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,54 @@ func WouldStartIdentifierWithoutEscapes(text string) bool {
return false
}

func RangeOfIdentifier(source logger.Source, loc logger.Loc) logger.Range {
text := source.Contents[loc.Start:]
if len(text) == 0 {
return logger.Range{Loc: loc, Len: 0}
}

i := 0
n := len(text)

for {
c, width := utf8.DecodeRuneInString(text[i:])
if IsNameContinue(c) {
i += width
continue
}

// Handle an escape
if c == '\\' && i+1 < n && !isNewline(rune(text[i+1])) {
i += width // Skip the backslash
c, width = utf8.DecodeRuneInString(text[i:])
if _, ok := isHex(c); ok {
i += width
c, width = utf8.DecodeRuneInString(text[i:])
for j := 0; j < 5; j++ {
if _, ok := isHex(c); !ok {
break
}
i += width
c, width = utf8.DecodeRuneInString(text[i:])
}
if isWhitespace(c) {
i += width
}
}
continue
}

break
}

// Don't end with a whitespace
if i > 0 && isWhitespace(rune(text[i-1])) {
i--
}

return logger.Range{Loc: loc, Len: int32(i)}
}

func (lexer *lexer) wouldStartNumber() bool {
if lexer.codePoint >= '0' && lexer.codePoint <= '9' {
return true
Expand Down
6 changes: 5 additions & 1 deletion internal/css_parser/css_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type parser struct {
stack []css_lexer.T
importRecords []ast.ImportRecord
symbols []ast.Symbol
defineLocs map[ast.Ref]logger.Loc
localSymbolMap map[string]ast.Ref
globalSymbolMap map[string]ast.Ref
nestingWarnings map[logger.Loc]struct{}
Expand Down Expand Up @@ -125,6 +126,7 @@ func Parse(log logger.Log, source logger.Source, options Options) css_ast.AST {
allComments: result.AllComments,
legalComments: result.LegalComments,
prevError: logger.Loc{Start: -1},
defineLocs: make(map[ast.Ref]logger.Loc),
localSymbolMap: make(map[string]ast.Ref),
globalSymbolMap: make(map[string]ast.Ref),
makeLocalSymbols: options.symbolMode == symbolModeLocal,
Expand All @@ -142,6 +144,7 @@ func Parse(log logger.Log, source logger.Source, options Options) css_ast.AST {
ImportRecords: p.importRecords,
ApproximateLineCount: result.ApproximateLineCount,
SourceMapComment: result.SourceMapComment,
DefineLocs: p.defineLocs,
}
}

Expand Down Expand Up @@ -301,7 +304,7 @@ func (p *parser) unexpected() {
}
}

func (p *parser) symbolForName(name string) ast.Ref {
func (p *parser) symbolForName(loc logger.Loc, name string) ast.Ref {
var kind ast.SymbolKind
var scope map[string]ast.Ref

Expand All @@ -325,6 +328,7 @@ func (p *parser) symbolForName(name string) ast.Ref {
Link: ast.InvalidRef,
})
scope[name] = ref
p.defineLocs[ref] = loc
}

p.symbols[ref.InnerIndex].UseCountEstimate++
Expand Down
4 changes: 2 additions & 2 deletions internal/css_parser/css_parser_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ subclassSelectors:
sel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{
Loc: subclassToken.Range.Loc,
Data: &css_ast.SSHash{
Name: ast.LocRef{Loc: nameLoc, Ref: p.symbolForName(name)},
Name: ast.LocRef{Loc: nameLoc, Ref: p.symbolForName(nameLoc, name)},
},
})
p.advance()
Expand All @@ -378,7 +378,7 @@ subclassSelectors:
sel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{
Loc: subclassToken.Range.Loc,
Data: &css_ast.SSClass{
Name: ast.LocRef{Loc: nameLoc, Ref: p.symbolForName(name)},
Name: ast.LocRef{Loc: nameLoc, Ref: p.symbolForName(nameLoc, name)},
},
})
if !p.expect(css_lexer.TIdent) {
Expand Down
8 changes: 7 additions & 1 deletion internal/linker/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/evanw/esbuild/internal/compat"
"github.com/evanw/esbuild/internal/config"
"github.com/evanw/esbuild/internal/css_ast"
"github.com/evanw/esbuild/internal/css_lexer"
"github.com/evanw/esbuild/internal/css_parser"
"github.com/evanw/esbuild/internal/css_printer"
"github.com/evanw/esbuild/internal/fs"
Expand Down Expand Up @@ -2672,7 +2673,12 @@ func (c *linkerContext) maybeCorrectObviousTypo(repr *graph.JSRepr, name string,
// happen with automatically-generated exports from non-JavaScript files.
note.Text = text
} else {
r := js_lexer.RangeOfIdentifier(importedFile.InputFile.Source, export.NameLoc)
var r logger.Range
if importedFile.InputFile.Loader.IsCSS() {
r = css_lexer.RangeOfIdentifier(importedFile.InputFile.Source, export.NameLoc)
} else {
r = js_lexer.RangeOfIdentifier(importedFile.InputFile.Source, export.NameLoc)
}
note = importedFile.LineColumnTracker().MsgData(r, text)
}
msg.Notes = append(msg.Notes, note)
Expand Down
28 changes: 28 additions & 0 deletions scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -7845,6 +7845,34 @@ tests.push(
}),
)

// Test CSS-related warning ranges
tests.push(
test(['in.js', '--outfile=node.js', '--bundle', '--loader:.css=local-css'], {
'in.js': `
import * as ns from './styles.css'
if (ns.buton !== void 0) throw 'fail'
`,
'styles.css': `
.bu\\74 ton { color: red }
`,
}, {
expectedStderr: `▲ [WARNING] Import "buton" will always be undefined because there is no matching export in "styles.css" [import-is-undefined]
in.js:3:13:
3 │ if (ns.buton !== void 0) throw 'fail'
│ ~~~~~
╵ button
Did you mean to import "button" instead?
styles.css:2:7:
2 │ .bu\\74 ton { color: red }
╵ ~~~~~~~~~
`,
}),
)

// Test writing to stdout
tests.push(
// These should succeed
Expand Down

0 comments on commit 78eefe1

Please sign in to comment.