From ea9c644db3c95cd264fa12f6d85fd67daabb51eb Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Thu, 14 Sep 2023 22:41:06 -0400 Subject: [PATCH] fix #3388: do something with pre-release versions --- CHANGELOG.md | 6 +++ compat-table/src/css_table.ts | 4 +- compat-table/src/js_table.ts | 2 +- internal/bundler_tests/bundler_test.go | 4 +- internal/compat/compat.go | 44 ++++++++++++++---- internal/compat/compat_test.go | 63 ++++++++++++++++++++++++++ internal/compat/css_table.go | 4 +- internal/compat/js_table.go | 2 +- internal/css_parser/css_parser_test.go | 16 +++---- internal/js_parser/js_parser_test.go | 20 ++++---- internal/js_parser/ts_parser_test.go | 16 +++---- internal/js_printer/js_printer_test.go | 16 +++---- pkg/api/api_impl.go | 53 ++++++++-------------- 13 files changed, 166 insertions(+), 84 deletions(-) create mode 100644 internal/compat/compat_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 94013cb851d..34d208d9d33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +* Allow pre-release versions to be passed to `target` ([#3388](https://github.com/evanw/esbuild/issues/3388)) + + People want to be able to pass version numbers for unreleased versions of node (which have extra stuff after the version numbers) to esbuild's `target` setting and have esbuild do something reasonable with them. These version strings are of course not present in esbuild's internal feature compatibility table because an unreleased version has not been released yet (by definition). With this release, esbuild will now attempt to accept these version strings passed to `target` and do something reasonable with them. + ## 0.19.3 * Fix `list-style-type` with the `local-css` loader ([#3325](https://github.com/evanw/esbuild/issues/3325)) diff --git a/compat-table/src/css_table.ts b/compat-table/src/css_table.ts index b2cf28708bf..92196b7aaa5 100644 --- a/compat-table/src/css_table.ts +++ b/compat-table/src/css_table.ts @@ -89,7 +89,7 @@ ${Object.keys(map).sort().map(feature => `\t${feature}: ${cssTableMap(map[featur } // Return all features that are not available in at least one environment -func UnsupportedCSSFeatures(constraints map[Engine][]int) (unsupported CSSFeature) { +func UnsupportedCSSFeatures(constraints map[Engine]Semver) (unsupported CSSFeature) { \tfor feature, engines := range cssTable { \t\tif feature == InlineStyle { \t\t\tcontinue // This is purely user-specified @@ -131,7 +131,7 @@ var cssPrefixTable = map[css_ast.D][]prefixData{ ${Object.keys(prefixes).sort().map(property => `\tcss_ast.${property}: ${cssPrefixMap(prefixes[property as CSSProperty]!)},`).join('\n')} } -func CSSPrefixData(constraints map[Engine][]int) (entries map[css_ast.D]CSSPrefix) { +func CSSPrefixData(constraints map[Engine]Semver) (entries map[css_ast.D]CSSPrefix) { \tfor property, items := range cssPrefixTable { \t\tprefixes := NoPrefix \t\tfor engine, version := range constraints { diff --git a/compat-table/src/js_table.ts b/compat-table/src/js_table.ts index ec5bedc3319..27a1c0bbf04 100644 --- a/compat-table/src/js_table.ts +++ b/compat-table/src/js_table.ts @@ -96,7 +96,7 @@ ${Object.keys(map).sort().map(feature => `\t${feature}: ${jsTableMap(map[feature } // Return all features that are not available in at least one environment -func UnsupportedJSFeatures(constraints map[Engine][]int) (unsupported JSFeature) { +func UnsupportedJSFeatures(constraints map[Engine]Semver) (unsupported JSFeature) { \tfor feature, engines := range jsTable { \t\tif feature == InlineScript { \t\t\tcontinue // This is purely user-specified diff --git a/internal/bundler_tests/bundler_test.go b/internal/bundler_tests/bundler_test.go index 51798197e8f..85b3d6e03d8 100644 --- a/internal/bundler_tests/bundler_test.go +++ b/internal/bundler_tests/bundler_test.go @@ -27,8 +27,8 @@ import ( ) func es(version int) compat.JSFeature { - return compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {version}, + return compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{version}}, }) } diff --git a/internal/compat/compat.go b/internal/compat/compat.go index 6535fdbd2a9..bd2d0ffd1ff 100644 --- a/internal/compat/compat.go +++ b/internal/compat/compat.go @@ -1,6 +1,11 @@ package compat -import "github.com/evanw/esbuild/internal/ast" +import ( + "strconv" + "strings" + + "github.com/evanw/esbuild/internal/ast" +) type v struct { major uint16 @@ -8,26 +13,47 @@ type v struct { patch uint8 } +type Semver struct { + // "1.2.3-alpha" => { Parts: {1, 2, 3}, PreRelease: "-alpha" } + Parts []int + PreRelease string +} + +func (v Semver) String() string { + b := strings.Builder{} + for _, part := range v.Parts { + if b.Len() > 0 { + b.WriteRune('.') + } + b.WriteString(strconv.Itoa(part)) + } + b.WriteString(v.PreRelease) + return b.String() +} + // Returns <0 if "a < b" // Returns 0 if "a == b" // Returns >0 if "a > b" -func compareVersions(a v, b []int) int { +func compareVersions(a v, b Semver) int { diff := int(a.major) - if len(b) > 0 { - diff -= b[0] + if len(b.Parts) > 0 { + diff -= b.Parts[0] } if diff == 0 { diff = int(a.minor) - if len(b) > 1 { - diff -= b[1] + if len(b.Parts) > 1 { + diff -= b.Parts[1] } } if diff == 0 { diff = int(a.patch) - if len(b) > 2 { - diff -= b[2] + if len(b.Parts) > 2 { + diff -= b.Parts[2] } } + if diff == 0 && len(b.PreRelease) != 0 { + return 1 // "1.0.0" > "1.0.0-alpha" + } return diff } @@ -37,7 +63,7 @@ type versionRange struct { end v // Use 0.0.0 for "no end" } -func isVersionSupported(ranges []versionRange, version []int) bool { +func isVersionSupported(ranges []versionRange, version Semver) bool { for _, r := range ranges { if compareVersions(r.start, version) <= 0 && (r.end == (v{}) || compareVersions(r.end, version) > 0) { return true diff --git a/internal/compat/compat_test.go b/internal/compat/compat_test.go new file mode 100644 index 00000000000..8e1cbee5984 --- /dev/null +++ b/internal/compat/compat_test.go @@ -0,0 +1,63 @@ +package compat + +import ( + "fmt" + "testing" + + "github.com/evanw/esbuild/internal/test" +) + +func TestCompareVersions(t *testing.T) { + t.Helper() + + check := func(a v, b Semver, expected rune) { + t.Helper() + + at := fmt.Sprintf("%d.%d.%d", a.major, a.minor, a.patch) + bt := b.String() + + t.Run(fmt.Sprintf("%q ? %q", at, bt), func(t *testing.T) { + observed := '=' + if result := compareVersions(a, b); result < 0 { + observed = '<' + } else if result > 0 { + observed = '>' + } + if observed != expected { + test.AssertEqual(t, fmt.Sprintf("%c", observed), fmt.Sprintf("%c", expected)) + } + }) + } + + check(v{0, 0, 0}, Semver{}, '=') + + check(v{1, 0, 0}, Semver{}, '>') + check(v{0, 1, 0}, Semver{}, '>') + check(v{0, 0, 1}, Semver{}, '>') + + check(v{0, 0, 0}, Semver{Parts: []int{1}}, '<') + check(v{0, 0, 0}, Semver{Parts: []int{0, 1}}, '<') + check(v{0, 0, 0}, Semver{Parts: []int{0, 0, 1}}, '<') + + check(v{0, 4, 0}, Semver{Parts: []int{0, 5, 0}}, '<') + check(v{0, 5, 0}, Semver{Parts: []int{0, 5, 0}}, '=') + check(v{0, 6, 0}, Semver{Parts: []int{0, 5, 0}}, '>') + + check(v{0, 5, 0}, Semver{Parts: []int{0, 5, 1}}, '<') + check(v{0, 5, 0}, Semver{Parts: []int{0, 5, 0}}, '=') + check(v{0, 5, 1}, Semver{Parts: []int{0, 5, 0}}, '>') + + check(v{0, 5, 0}, Semver{Parts: []int{0, 5}}, '=') + check(v{0, 5, 1}, Semver{Parts: []int{0, 5}}, '>') + + check(v{1, 0, 0}, Semver{Parts: []int{1}}, '=') + check(v{1, 1, 0}, Semver{Parts: []int{1}}, '>') + check(v{1, 0, 1}, Semver{Parts: []int{1}}, '>') + + check(v{1, 2, 0}, Semver{Parts: []int{1, 2}, PreRelease: "-pre"}, '>') + check(v{1, 2, 1}, Semver{Parts: []int{1, 2}, PreRelease: "-pre"}, '>') + check(v{1, 1, 0}, Semver{Parts: []int{1, 2}, PreRelease: "-pre"}, '<') + + check(v{1, 2, 3}, Semver{Parts: []int{1, 2, 3}, PreRelease: "-pre"}, '>') + check(v{1, 2, 2}, Semver{Parts: []int{1, 2, 3}, PreRelease: "-pre"}, '<') +} diff --git a/internal/compat/css_table.go b/internal/compat/css_table.go index 9c895150e6d..fa5a731aac1 100644 --- a/internal/compat/css_table.go +++ b/internal/compat/css_table.go @@ -85,7 +85,7 @@ var cssTable = map[CSSFeature]map[Engine][]versionRange{ } // Return all features that are not available in at least one environment -func UnsupportedCSSFeatures(constraints map[Engine][]int) (unsupported CSSFeature) { +func UnsupportedCSSFeatures(constraints map[Engine]Semver) (unsupported CSSFeature) { for feature, engines := range cssTable { if feature == InlineStyle { continue // This is purely user-specified @@ -275,7 +275,7 @@ var cssPrefixTable = map[css_ast.D][]prefixData{ }, } -func CSSPrefixData(constraints map[Engine][]int) (entries map[css_ast.D]CSSPrefix) { +func CSSPrefixData(constraints map[Engine]Semver) (entries map[css_ast.D]CSSPrefix) { for property, items := range cssPrefixTable { prefixes := NoPrefix for engine, version := range constraints { diff --git a/internal/compat/js_table.go b/internal/compat/js_table.go index 3b520e2b075..cabac2e20ae 100644 --- a/internal/compat/js_table.go +++ b/internal/compat/js_table.go @@ -767,7 +767,7 @@ var jsTable = map[JSFeature]map[Engine][]versionRange{ } // Return all features that are not available in at least one environment -func UnsupportedJSFeatures(constraints map[Engine][]int) (unsupported JSFeature) { +func UnsupportedJSFeatures(constraints map[Engine]Semver) (unsupported JSFeature) { for feature, engines := range jsTable { if feature == InlineScript { continue // This is purely user-specified diff --git a/internal/css_parser/css_parser_test.go b/internal/css_parser/css_parser_test.go index 91315e32a72..546d1b4318c 100644 --- a/internal/css_parser/css_parser_test.go +++ b/internal/css_parser/css_parser_test.go @@ -60,14 +60,14 @@ func expectPrintedLowerUnsupported(t *testing.T, unsupportedCSSFeatures compat.C func expectPrintedWithAllPrefixes(t *testing.T, contents string, expected string, expectedLog string) { t.Helper() expectPrintedCommon(t, contents+" [prefixed]", contents, expected, expectedLog, config.LoaderCSS, config.Options{ - CSSPrefixData: compat.CSSPrefixData(map[compat.Engine][]int{ - compat.Chrome: {0}, - compat.Edge: {0}, - compat.Firefox: {0}, - compat.IE: {0}, - compat.IOS: {0}, - compat.Opera: {0}, - compat.Safari: {0}, + CSSPrefixData: compat.CSSPrefixData(map[compat.Engine]compat.Semver{ + compat.Chrome: {Parts: []int{0}}, + compat.Edge: {Parts: []int{0}}, + compat.Firefox: {Parts: []int{0}}, + compat.IE: {Parts: []int{0}}, + compat.IOS: {Parts: []int{0}}, + compat.Opera: {Parts: []int{0}}, + compat.Safari: {Parts: []int{0}}, }), }) } diff --git a/internal/js_parser/js_parser_test.go b/internal/js_parser/js_parser_test.go index 73e9374744c..50833368c73 100644 --- a/internal/js_parser/js_parser_test.go +++ b/internal/js_parser/js_parser_test.go @@ -39,8 +39,8 @@ func expectParseError(t *testing.T, contents string, expected string) { func expectParseErrorTarget(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectParseErrorCommon(t, contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), }) } @@ -108,8 +108,8 @@ func expectPrintedNormalAndMangle(t *testing.T, contents string, normal string, func expectPrintedTarget(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectPrintedCommon(t, contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), }) } @@ -117,8 +117,8 @@ func expectPrintedTarget(t *testing.T, esVersion int, contents string, expected func expectPrintedMangleTarget(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectPrintedCommon(t, contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), MinifySyntax: true, }) @@ -134,8 +134,8 @@ func expectPrintedASCII(t *testing.T, contents string, expected string) { func expectPrintedTargetASCII(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectPrintedCommon(t, contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), ASCIIOnly: true, }) @@ -144,8 +144,8 @@ func expectPrintedTargetASCII(t *testing.T, esVersion int, contents string, expe func expectParseErrorTargetASCII(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectParseErrorCommon(t, contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), ASCIIOnly: true, }) diff --git a/internal/js_parser/ts_parser_test.go b/internal/js_parser/ts_parser_test.go index 6c29de50afb..7df46476aca 100644 --- a/internal/js_parser/ts_parser_test.go +++ b/internal/js_parser/ts_parser_test.go @@ -44,8 +44,8 @@ func expectParseErrorTargetTS(t *testing.T, esVersion int, contents string, expe TS: config.TSOptions{ Parse: true, }, - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), }) } @@ -80,8 +80,8 @@ func expectPrintedAssignSemanticsTargetTS(t *testing.T, esVersion int, contents UseDefineForClassFields: config.False, }, }, - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), }) } @@ -127,8 +127,8 @@ func expectPrintedTargetTS(t *testing.T, esVersion int, contents string, expecte TS: config.TSOptions{ Parse: true, }, - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), }) } @@ -142,8 +142,8 @@ func expectPrintedTargetExperimentalDecoratorTS(t *testing.T, esVersion int, con ExperimentalDecorators: config.True, }, }, - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), }) } diff --git a/internal/js_printer/js_printer_test.go b/internal/js_printer/js_printer_test.go index 1eda0674706..363768df688 100644 --- a/internal/js_printer/js_printer_test.go +++ b/internal/js_printer/js_printer_test.go @@ -93,8 +93,8 @@ func expectPrintedMinifyASCII(t *testing.T, contents string, expected string) { func expectPrintedTarget(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectPrintedCommon(t, contents, contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), }) } @@ -102,8 +102,8 @@ func expectPrintedTarget(t *testing.T, esVersion int, contents string, expected func expectPrintedTargetMinify(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectPrintedCommon(t, contents+" [minified]", contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), MinifyWhitespace: true, }) @@ -112,8 +112,8 @@ func expectPrintedTargetMinify(t *testing.T, esVersion int, contents string, exp func expectPrintedTargetMangle(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectPrintedCommon(t, contents+" [mangled]", contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), MinifySyntax: true, }) @@ -122,8 +122,8 @@ func expectPrintedTargetMangle(t *testing.T, esVersion int, contents string, exp func expectPrintedTargetASCII(t *testing.T, esVersion int, contents string, expected string) { t.Helper() expectPrintedCommon(t, contents+" [ascii]", contents, expected, config.Options{ - UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine][]int{ - compat.ES: {esVersion}, + UnsupportedJSFeatures: compat.UnsupportedJSFeatures(map[compat.Engine]compat.Semver{ + compat.ES: {Parts: []int{esVersion}}, }), ASCIIOnly: true, }) diff --git a/pkg/api/api_impl.go b/pkg/api/api_impl.go index c471d071b71..d8b919758ee 100644 --- a/pkg/api/api_impl.go +++ b/pkg/api/api_impl.go @@ -295,36 +295,35 @@ func validateEngine(value EngineName) compat.Engine { } } -var versionRegex = regexp.MustCompile(`^([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?$`) -var preReleaseVersionRegex = regexp.MustCompile(`^([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?-`) +var versionRegex = regexp.MustCompile(`^([0-9]+)(?:\.([0-9]+))?(?:\.([0-9]+))?(-[A-Za-z0-9]+(?:\.[A-Za-z0-9]+)*)?$`) func validateFeatures(log logger.Log, target Target, engines []Engine) (compat.JSFeature, compat.CSSFeature, map[css_ast.D]compat.CSSPrefix, string) { if target == DefaultTarget && len(engines) == 0 { return 0, 0, nil, "" } - constraints := make(map[compat.Engine][]int) + constraints := make(map[compat.Engine]compat.Semver) targets := make([]string, 0, 1+len(engines)) switch target { case ES5: - constraints[compat.ES] = []int{5} + constraints[compat.ES] = compat.Semver{Parts: []int{5}} case ES2015: - constraints[compat.ES] = []int{2015} + constraints[compat.ES] = compat.Semver{Parts: []int{2015}} case ES2016: - constraints[compat.ES] = []int{2016} + constraints[compat.ES] = compat.Semver{Parts: []int{2016}} case ES2017: - constraints[compat.ES] = []int{2017} + constraints[compat.ES] = compat.Semver{Parts: []int{2017}} case ES2018: - constraints[compat.ES] = []int{2018} + constraints[compat.ES] = compat.Semver{Parts: []int{2018}} case ES2019: - constraints[compat.ES] = []int{2019} + constraints[compat.ES] = compat.Semver{Parts: []int{2019}} case ES2020: - constraints[compat.ES] = []int{2020} + constraints[compat.ES] = compat.Semver{Parts: []int{2020}} case ES2021: - constraints[compat.ES] = []int{2021} + constraints[compat.ES] = compat.Semver{Parts: []int{2021}} case ES2022: - constraints[compat.ES] = []int{2022} + constraints[compat.ES] = compat.Semver{Parts: []int{2022}} case ESNext, DefaultTarget: default: panic("Invalid target") @@ -333,41 +332,29 @@ func validateFeatures(log logger.Log, target Target, engines []Engine) (compat.J for _, engine := range engines { if match := versionRegex.FindStringSubmatch(engine.Version); match != nil { if major, err := strconv.Atoi(match[1]); err == nil { - version := []int{major} + parts := []int{major} if minor, err := strconv.Atoi(match[2]); err == nil { - version = append(version, minor) + parts = append(parts, minor) + if patch, err := strconv.Atoi(match[3]); err == nil { + parts = append(parts, patch) + } } - if patch, err := strconv.Atoi(match[3]); err == nil { - version = append(version, patch) + constraints[convertEngineName(engine.Name)] = compat.Semver{ + Parts: parts, + PreRelease: match[4], } - constraints[convertEngineName(engine.Name)] = version continue } } text := "All version numbers passed to esbuild must be in the format \"X\", \"X.Y\", or \"X.Y.Z\" where X, Y, and Z are non-negative integers." - // Our internal version-to-feature database only includes version triples. - // We don't have any data on pre-release versions, so we don't accept them. - if preReleaseVersionRegex.MatchString(engine.Version) { - text += " Pre-release versions are not supported and cannot be used." - } - log.AddErrorWithNotes(nil, logger.Range{}, fmt.Sprintf("Invalid version: %q", engine.Version), []logger.MsgData{{Text: text}}) } 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, text) + targets = append(targets, engine.String()+version.String()) } if target == ESNext { targets = append(targets, "esnext")