diff --git a/CHANGELOG.md b/CHANGELOG.md index f16ffefba09..8a265a95dc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,12 @@ This problem occurs because this package doesn't provide an import path for ESM code using the `import` condition and also doesn't provide a fallback import path using the `default` condition. +* Raise certain VM versions in the JavaScript feature compatibility table + + JavaScript VM feature compatibility data is derived from this dataset: https://kangax.github.io/compat-table/. The scripts that process the dataset expand the data to include all VM versions that support a given feature (e.g. `chrome44`, `chrome45`, `chrome46`, ...) so esbuild takes the minimum observed version as the first version for which the feature is supported. + + 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. + ## 0.9.2 * Fix export name annotations in CommonJS output for node ([#960](https://github.com/evanw/esbuild/issues/960)) diff --git a/internal/compat/js_table.go b/internal/compat/js_table.go index c07548f3b8a..ff4671d5038 100644 --- a/internal/compat/js_table.go +++ b/internal/compat/js_table.go @@ -64,20 +64,20 @@ func (features JSFeature) Has(feature JSFeature) bool { var jsTable = map[JSFeature]map[Engine][]int{ ArraySpread: { Chrome: {46}, - Edge: {12}, + Edge: {13}, ES: {2015}, - Firefox: {27}, - IOS: {8}, + Firefox: {36}, + IOS: {10}, Node: {5}, - Safari: {7, 1}, + Safari: {10}, }, Arrow: { - Chrome: {45}, - Edge: {12}, + Chrome: {49}, + Edge: {13}, ES: {2015}, - Firefox: {22}, + Firefox: {45}, IOS: {10}, - Node: {4}, + Node: {6}, Safari: {10}, }, AsyncAwait: { @@ -85,9 +85,9 @@ var jsTable = map[JSFeature]map[Engine][]int{ Edge: {15}, ES: {2017}, Firefox: {52}, - IOS: {10, 3}, + IOS: {11}, Node: {7, 6}, - Safari: {10, 1}, + Safari: {11}, }, AsyncGenerator: { Chrome: {63}, @@ -112,12 +112,12 @@ var jsTable = map[JSFeature]map[Engine][]int{ Edge: {13}, ES: {2015}, Firefox: {45}, - IOS: {9}, + IOS: {10}, Node: {6}, - Safari: {9}, + Safari: {10}, }, ClassField: { - Chrome: {72}, + Chrome: {73}, Edge: {79}, Firefox: {69}, IOS: {14}, @@ -130,9 +130,9 @@ var jsTable = map[JSFeature]map[Engine][]int{ Node: {14, 6}, }, ClassPrivateField: { - Chrome: {74}, - Edge: {79}, - Node: {12, 0}, + Chrome: {84}, + Edge: {84}, + Node: {14, 6}, Safari: {14, 1}, }, ClassPrivateMethod: { @@ -157,38 +157,38 @@ var jsTable = map[JSFeature]map[Engine][]int{ Node: {14, 6}, }, ClassStaticField: { - Chrome: {72}, + Chrome: {73}, Edge: {79}, Firefox: {75}, Node: {12, 0}, Safari: {14, 1}, }, Const: { - Chrome: {5}, - Edge: {12}, + Chrome: {49}, + Edge: {14}, ES: {2015}, - Firefox: {3}, - IOS: {6}, - Node: {0, 12}, - Safari: {3, 1}, + Firefox: {51}, + IOS: {11}, + Node: {6}, + Safari: {11}, }, DefaultArgument: { Chrome: {49}, Edge: {14}, ES: {2015}, - Firefox: {15}, + Firefox: {53}, IOS: {10}, Node: {6}, Safari: {10}, }, Destructuring: { - Chrome: {49}, - Edge: {14}, + Chrome: {51}, + Edge: {18}, ES: {2015}, - Firefox: {2}, - IOS: {8}, - Node: {6}, - Safari: {7, 1}, + Firefox: {53}, + IOS: {10}, + Node: {6, 5}, + Safari: {10}, }, ExponentOperator: { Chrome: {52}, @@ -216,21 +216,21 @@ var jsTable = map[JSFeature]map[Engine][]int{ Safari: {12}, }, ForOf: { - Chrome: {38}, - Edge: {12}, + Chrome: {51}, + Edge: {15}, ES: {2015}, - Firefox: {13}, - IOS: {8}, - Node: {0, 12}, - Safari: {7, 1}, + Firefox: {53}, + IOS: {10}, + Node: {6, 5}, + Safari: {10}, }, Generator: { - Chrome: {39}, + Chrome: {50}, Edge: {13}, ES: {2015}, - Firefox: {27}, + Firefox: {53}, IOS: {10}, - Node: {4}, + Node: {6}, Safari: {10}, }, Hashbang: { @@ -252,12 +252,12 @@ var jsTable = map[JSFeature]map[Engine][]int{ }, Let: { Chrome: {49}, - Edge: {12}, + Edge: {14}, ES: {2015}, - Firefox: {44}, - IOS: {10}, + Firefox: {51}, + IOS: {11}, Node: {6}, - Safari: {10}, + Safari: {11}, }, LogicalAssignment: { Chrome: {85}, @@ -278,7 +278,7 @@ var jsTable = map[JSFeature]map[Engine][]int{ }, NewTarget: { Chrome: {46}, - Edge: {13}, + Edge: {14}, ES: {2015}, Firefox: {41}, IOS: {10}, @@ -308,9 +308,9 @@ var jsTable = map[JSFeature]map[Engine][]int{ Edge: {12}, ES: {2015}, Firefox: {34}, - IOS: {8}, + IOS: {10}, Node: {4}, - Safari: {7, 1}, + Safari: {10}, }, ObjectRestSpread: { ES: {2018}, @@ -340,14 +340,14 @@ var jsTable = map[JSFeature]map[Engine][]int{ Chrome: {47}, Edge: {12}, ES: {2015}, - Firefox: {15}, + Firefox: {43}, IOS: {10}, Node: {6}, Safari: {10}, }, TemplateLiteral: { Chrome: {41}, - Edge: {12}, + Edge: {13}, ES: {2015}, Firefox: {34}, IOS: {9}, @@ -359,7 +359,7 @@ var jsTable = map[JSFeature]map[Engine][]int{ Chrome: {44}, Edge: {12}, ES: {2015}, - Firefox: {40}, + Firefox: {53}, IOS: {9}, Node: {4}, Safari: {9}, diff --git a/scripts/compat-table.js b/scripts/compat-table.js index 1b9ee7fe5c1..1697f8a0a37 100644 --- a/scripts/compat-table.js +++ b/scripts/compat-table.js @@ -85,7 +85,12 @@ const engines = [ ] function mergeVersions(target, res) { - const map = versions[target] || (versions[target] = {}) + // The original data set will contain something like "chrome44: true" for a + // given feature. And the interpolation script will expand this to something + // like "chrome44: true, chrome45: true, chrome46: true, ..." so we want to + // take the minimum version to find the boundary. + const lowestVersionMap = {} + for (const key in res) { if (res[key] === true) { const match = /^([a-z_]+)[0-9_]+$/.exec(key) @@ -93,13 +98,24 @@ function mergeVersions(target, res) { const engine = match[1] if (engines.indexOf(engine) >= 0) { const version = parseEnvsVersions({ [key]: true })[engine][0].version - if (!map[engine] || compareVersions(version, map[engine]) < 0) { - map[engine] = version + if (!lowestVersionMap[engine] || compareVersions({ version }, { version: lowestVersionMap[engine] }) < 0) { + lowestVersionMap[engine] = version } } } } } + + // The original data set can sometimes contain many subtests. We only want to + // support a given feature if the version is greater than the maximum version + // for all subtests. This is the inverse of the minimum test below. + const highestVersionMap = versions[target] || (versions[target] = {}) + for (const engine in lowestVersionMap) { + const version = lowestVersionMap[engine] + if (!highestVersionMap[engine] || compareVersions({ version }, { version: highestVersionMap[engine] }) > 0) { + highestVersionMap[engine] = version + } + } } // ES5 features