Skip to content

Commit

Permalink
fix #1448: add source mappings for certain tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 3, 2022
1 parent b6648af commit c4d45e6
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 124 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## Unreleased

* Add source mapping information for some non-executable tokens ([#1448](https://github.com/evanw/esbuild/issues/1448))

Code coverage tools can generate reports that tell you if any code exists that has not been run (or "covered") during your tests. You can use this information to add additional tests for code that isn't currently covered.

Some popular JavaScript code coverage tools have bugs where they incorrectly consider lines without any executable code as uncovered, even though there's no test you could possibly write that would cause those lines to be executed. For example, they apparently complain about the lines that only contain the trailing `}` token of an object literal.

With this release, esbuild now generates source mappings for some of these trailing non-executable tokens. This may not successfully work around bugs in code coverage tools because there are many non-executable tokens in JavaScript and esbuild doesn't map them all (the drawback of mapping these extra tokens is that esbuild will use more memory, build more slowly, and output a bigger source map). The true solution is to fix the bugs in the code coverage tools in the first place.

## 0.14.24

* Allow `es2022` as a target environment ([#2012](https://github.com/evanw/esbuild/issues/2012))
Expand Down
14 changes: 7 additions & 7 deletions internal/bundler/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -1959,7 +1959,7 @@ func (c *linkerContext) createExportsForFile(sourceIndex uint32) {

// Add a getter property
var getter js_ast.Expr
body := js_ast.FnBody{Stmts: []js_ast.Stmt{{Loc: value.Loc, Data: &js_ast.SReturn{ValueOrNil: value}}}}
body := js_ast.FnBody{Block: js_ast.SBlock{Stmts: []js_ast.Stmt{{Loc: value.Loc, Data: &js_ast.SReturn{ValueOrNil: value}}}}}
if c.options.UnsupportedJSFeatures.Has(compat.Arrow) {
getter = js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: body}}}
} else {
Expand Down Expand Up @@ -3879,14 +3879,14 @@ func (c *linkerContext) generateCodeForFileInChunkJS(
cjsArgs = []js_ast.Expr{{Data: &js_ast.EObject{Properties: []js_ast.Property{{
IsMethod: !c.options.UnsupportedJSFeatures.Has(compat.ObjectExtensions),
Key: js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(file.InputFile.Source.PrettyPath)}},
ValueOrNil: js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Args: args, Body: js_ast.FnBody{Stmts: stmts}}}},
ValueOrNil: js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Args: args, Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}}}},
}}}}}
} else if c.options.UnsupportedJSFeatures.Has(compat.Arrow) {
// "__commonJS(function (exports, module) { ... })"
cjsArgs = []js_ast.Expr{{Data: &js_ast.EFunction{Fn: js_ast.Fn{Args: args, Body: js_ast.FnBody{Stmts: stmts}}}}}
cjsArgs = []js_ast.Expr{{Data: &js_ast.EFunction{Fn: js_ast.Fn{Args: args, Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}}}}}
} else {
// "__commonJS((exports, module) => { ... })"
cjsArgs = []js_ast.Expr{{Data: &js_ast.EArrow{Args: args, Body: js_ast.FnBody{Stmts: stmts}}}}
cjsArgs = []js_ast.Expr{{Data: &js_ast.EArrow{Args: args, Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}}}}
}
value := js_ast.Expr{Data: &js_ast.ECall{
Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.cjsRuntimeRef}},
Expand Down Expand Up @@ -3947,14 +3947,14 @@ func (c *linkerContext) generateCodeForFileInChunkJS(
esmArgs = []js_ast.Expr{{Data: &js_ast.EObject{Properties: []js_ast.Property{{
IsMethod: !c.options.UnsupportedJSFeatures.Has(compat.ObjectExtensions),
Key: js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(file.InputFile.Source.PrettyPath)}},
ValueOrNil: js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: js_ast.FnBody{Stmts: stmts}, IsAsync: isAsync}}},
ValueOrNil: js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}, IsAsync: isAsync}}},
}}}}}
} else if c.options.UnsupportedJSFeatures.Has(compat.Arrow) {
// "__esm(function () { ... })"
esmArgs = []js_ast.Expr{{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: js_ast.FnBody{Stmts: stmts}, IsAsync: isAsync}}}}
esmArgs = []js_ast.Expr{{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}, IsAsync: isAsync}}}}
} else {
// "__esm(() => { ... })"
esmArgs = []js_ast.Expr{{Data: &js_ast.EArrow{Body: js_ast.FnBody{Stmts: stmts}, IsAsync: isAsync}}}
esmArgs = []js_ast.Expr{{Data: &js_ast.EArrow{Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}, IsAsync: isAsync}}}
}
value := js_ast.Expr{Data: &js_ast.ECall{
Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.esmRuntimeRef}},
Expand Down
52 changes: 29 additions & 23 deletions internal/js_ast/js_ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ const (
)

type ClassStaticBlock struct {
Stmts []Stmt
Block SBlock
Loc logger.Loc
}

Expand Down Expand Up @@ -334,17 +334,18 @@ type Fn struct {
}

type FnBody struct {
Stmts []Stmt
Block SBlock
Loc logger.Loc
}

type Class struct {
TSDecorators []Expr
Name *LocRef
ExtendsOrNil Expr
Properties []Property
ClassKeyword logger.Range
BodyLoc logger.Loc
TSDecorators []Expr
Name *LocRef
ExtendsOrNil Expr
Properties []Property
ClassKeyword logger.Range
BodyLoc logger.Loc
CloseBraceLoc logger.Loc
}

type ArrayBinding struct {
Expand Down Expand Up @@ -432,6 +433,7 @@ func (*EImportCall) isExpr() {}
type EArray struct {
Items []Expr
CommaAfterSpread logger.Loc
CloseBracketLoc logger.Loc
IsSingleLine bool
IsParenthesized bool
}
Expand Down Expand Up @@ -476,8 +478,9 @@ var EUndefinedShared = &EUndefined{}
var EThisShared = &EThis{}

type ENew struct {
Target Expr
Args []Expr
Target Expr
Args []Expr
CloseParenLoc logger.Loc

// True if there is a comment containing "@__PURE__" or "#__PURE__" preceding
// this call expression. See the comment inside ECall for more details.
Expand All @@ -501,6 +504,7 @@ const (
type ECall struct {
Target Expr
Args []Expr
CloseParenLoc logger.Loc
OptionalChain OptionalChain
IsDirectEval bool

Expand Down Expand Up @@ -653,6 +657,7 @@ type EBigInt struct{ Value string }
type EObject struct {
Properties []Property
CommaAfterSpread logger.Loc
CloseBraceLoc logger.Loc
IsSingleLine bool
IsParenthesized bool
}
Expand Down Expand Up @@ -1079,7 +1084,8 @@ func (*SBreak) isStmt() {}
func (*SContinue) isStmt() {}

type SBlock struct {
Stmts []Stmt
Stmts []Stmt
CloseBraceLoc logger.Loc
}

type SEmpty struct{}
Expand Down Expand Up @@ -1231,21 +1237,21 @@ type SWith struct {

type Catch struct {
BindingOrNil Binding
Body []Stmt
Block SBlock
Loc logger.Loc
BodyLoc logger.Loc
BlockLoc logger.Loc
}

type Finally struct {
Stmts []Stmt
Block SBlock
Loc logger.Loc
}

type STry struct {
Catch *Catch
Finally *Finally
Body []Stmt
BodyLoc logger.Loc
Catch *Catch
Finally *Finally
Block SBlock
BlockLoc logger.Loc
}

type Case struct {
Expand Down Expand Up @@ -2829,7 +2835,7 @@ func SimplifyUnusedExpr(expr Expr, isUnbound func(Ref) bool) Expr {
}

// Just delete "(function() {})()" completely
if len(target.Fn.Body.Stmts) == 0 {
if len(target.Fn.Body.Block.Stmts) == 0 {
return Expr{}
}

Expand All @@ -2839,19 +2845,19 @@ func SimplifyUnusedExpr(expr Expr, isUnbound func(Ref) bool) Expr {
}

// Just delete "(() => {})()" completely
if len(target.Body.Stmts) == 0 {
if len(target.Body.Block.Stmts) == 0 {
return Expr{}
}

if len(target.Body.Stmts) == 1 {
switch s := target.Body.Stmts[0].Data.(type) {
if len(target.Body.Block.Stmts) == 1 {
switch s := target.Body.Block.Stmts[0].Data.(type) {
case *SExpr:
if !target.IsAsync {
// Replace "(() => { foo() })()" with "foo()"
return s.Value
} else {
// Replace "(async () => { foo() })()" with "(async () => foo())()"
target.Body.Stmts[0].Data = &SReturn{ValueOrNil: s.Value}
target.Body.Block.Stmts[0].Data = &SReturn{ValueOrNil: s.Value}
target.PreferExpr = true
}

Expand Down

0 comments on commit c4d45e6

Please sign in to comment.