Skip to content

Commit

Permalink
fix #975: add target env to lowering error
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 15, 2021
1 parent fbdf70d commit d943e89
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@

However, some features can have subtests that each check a different aspect of the feature. In this case the desired version is the minimum version within each individual subtest, but the maximum of those versions across all subtests (since esbuild should only use the feature if it works in all cases). Previously esbuild computed the minimum version across all subtests, but now esbuild computes the maximum version across all subtests. This means esbuild will now lower JavaScript syntax in more cases.

* Mention the configured target environment in error messages ([#975](https://github.com/evanw/esbuild/issues/975))

Using newer JavaScript syntax with an older target environment (e.g. `chrome10`) can cause a build error if esbuild doesn't support transforming that syntax such that it is compatible with that target environment. Previously the error message was generic but with this release, the target environment is called outp explicitly in the error message. This is helpful if esbuild is being wrapped by some other tool since the other tool can obscure what target environment is actually being passed to esbuild.

## 0.9.2

* Fix export name annotations in CommonJS output for node ([#960](https://github.com/evanw/esbuild/issues/960))
Expand Down
20 changes: 20 additions & 0 deletions internal/compat/js_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@ const (
Safari
)

func (e Engine) String() string {
switch e {
case Chrome:
return "chrome"
case Edge:
return "edge"
case ES:
return "es"
case Firefox:
return "firefox"
case IOS:
return "ios"
case Node:
return "node"
case Safari:
return "safari"
}
return ""
}

type JSFeature uint64

const (
Expand Down
4 changes: 4 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ type Options struct {
UnsupportedJSFeatures compat.JSFeature
UnsupportedCSSFeatures compat.CSSFeature

// This is the original information that was used to generate the
// unsupported feature sets above. It's used for error messages.
OriginalTargetEnv string

ExtensionOrder []string
MainFields []string
Conditions []string
Expand Down
2 changes: 2 additions & 0 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ type Options struct {

type optionsThatSupportStructuralEquality struct {
unsupportedJSFeatures compat.JSFeature
originalTargetEnv string

// Byte-sized values go here (gathered together here to keep this object compact)
ts config.TSOptions
Expand All @@ -304,6 +305,7 @@ func OptionsFromConfig(options *config.Options) Options {
defines: options.Defines,
optionsThatSupportStructuralEquality: optionsThatSupportStructuralEquality{
unsupportedJSFeatures: options.UnsupportedJSFeatures,
originalTargetEnv: options.OriginalTargetEnv,
ts: options.TS,
mode: options.Mode,
platform: options.Platform,
Expand Down
4 changes: 4 additions & 0 deletions internal/js_parser/js_parser_lower.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ func (p *parser) markSyntaxFeature(feature compat.JSFeature, r logger.Range) (di
var name string
where := "the configured target environment"

if p.options.originalTargetEnv != "" {
where = fmt.Sprintf("%s (%s)", where, p.options.originalTargetEnv)
}

switch feature {
case compat.DefaultArgument:
name = "default arguments"
Expand Down
27 changes: 23 additions & 4 deletions pkg/api/api_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,9 @@ func validateEngine(value EngineName) compat.Engine {

var versionRegex = regexp.MustCompile(`^([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?$`)

func validateFeatures(log logger.Log, target Target, engines []Engine) (compat.JSFeature, compat.CSSFeature) {
func validateFeatures(log logger.Log, target Target, engines []Engine) (compat.JSFeature, compat.CSSFeature, string) {
constraints := make(map[compat.Engine][]int)
targets := make([]string, 0, 1+len(engines))

switch target {
case ES5:
Expand Down Expand Up @@ -289,7 +290,23 @@ func validateFeatures(log logger.Log, target Target, engines []Engine) (compat.J
log.AddError(nil, logger.Loc{}, fmt.Sprintf("Invalid version: %q", engine.Version))
}

return compat.UnsupportedJSFeatures(constraints), compat.UnsupportedCSSFeatures(constraints)
for engine, version := range constraints {
var text string
switch len(version) {
case 1:
text = fmt.Sprintf("%s%d", engine.String(), version[0])
case 2:
text = fmt.Sprintf("%s%d.%d", engine.String(), version[0], version[1])
case 3:
text = fmt.Sprintf("%s%d.%d.%d", engine.String(), version[0], version[1], version[2])
}
targets = append(targets, fmt.Sprintf("%q", text))
}

sort.Strings(targets)
targetEnv := strings.Join(targets, ", ")

return compat.UnsupportedJSFeatures(constraints), compat.UnsupportedCSSFeatures(constraints), targetEnv
}

func validateGlobalName(log logger.Log, text string) []string {
Expand Down Expand Up @@ -699,14 +716,15 @@ func rebuildImpl(
// This should already have been checked above
panic(err.Error())
}
jsFeatures, cssFeatures := validateFeatures(log, buildOpts.Target, buildOpts.Engines)
jsFeatures, cssFeatures, targetEnv := validateFeatures(log, buildOpts.Target, buildOpts.Engines)
outJS, outCSS := validateOutputExtensions(log, buildOpts.OutExtensions)
bannerJS, bannerCSS := validateBannerOrFooter(log, "banner", buildOpts.Banner)
footerJS, footerCSS := validateBannerOrFooter(log, "footer", buildOpts.Footer)
defines, injectedDefines := validateDefines(log, buildOpts.Define, buildOpts.Pure)
options := config.Options{
UnsupportedJSFeatures: jsFeatures,
UnsupportedCSSFeatures: cssFeatures,
OriginalTargetEnv: targetEnv,
JSX: config.JSXOptions{
Factory: validateJSX(log, buildOpts.JSXFactory, "factory"),
Fragment: validateJSX(log, buildOpts.JSXFragment, "fragment"),
Expand Down Expand Up @@ -1155,11 +1173,12 @@ func transformImpl(input string, transformOpts TransformOptions) TransformResult
}

// Convert and validate the transformOpts
jsFeatures, cssFeatures := validateFeatures(log, transformOpts.Target, transformOpts.Engines)
jsFeatures, cssFeatures, targetEnv := validateFeatures(log, transformOpts.Target, transformOpts.Engines)
defines, injectedDefines := validateDefines(log, transformOpts.Define, transformOpts.Pure)
options := config.Options{
UnsupportedJSFeatures: jsFeatures,
UnsupportedCSSFeatures: cssFeatures,
OriginalTargetEnv: targetEnv,
JSX: jsx,
Defines: defines,
InjectedDefines: injectedDefines,
Expand Down
10 changes: 10 additions & 0 deletions scripts/js-api-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3292,6 +3292,16 @@ let transformTests = {
])
},

async multipleEngineTargetsNotSupported({ esbuild }) {
try {
await esbuild.transform(`0n`, { target: ['chrome1', 'safari2', 'firefox3'] })
throw new Error('Expected an error to be thrown')
} catch (e) {
assert.strictEqual(e.errors[0].text,
'Big integer literals are not available in the configured target environment ("chrome1", "firefox3", "safari2")')
}
},

// Future syntax
forAwait: ({ esbuild }) => futureSyntax(esbuild, 'async function foo() { for await (let x of y) {} }', 'es2017', 'es2018'),
bigInt: ({ esbuild }) => futureSyntax(esbuild, '123n', 'es2019', 'es2020'),
Expand Down

0 comments on commit d943e89

Please sign in to comment.