Skip to content

Commit

Permalink
compat table: use the maximum across all subtests
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 15, 2021
1 parent 5e6528d commit 29b7c3f
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 52 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
98 changes: 49 additions & 49 deletions internal/compat/js_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,30 @@ 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: {
Chrome: {55},
Edge: {15},
ES: {2017},
Firefox: {52},
IOS: {10, 3},
IOS: {11},
Node: {7, 6},
Safari: {10, 1},
Safari: {11},
},
AsyncGenerator: {
Chrome: {63},
Expand All @@ -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},
Expand All @@ -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: {
Expand All @@ -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},
Expand Down Expand Up @@ -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: {
Expand All @@ -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},
Expand All @@ -278,7 +278,7 @@ var jsTable = map[JSFeature]map[Engine][]int{
},
NewTarget: {
Chrome: {46},
Edge: {13},
Edge: {14},
ES: {2015},
Firefox: {41},
IOS: {10},
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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},
Expand All @@ -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},
Expand Down
22 changes: 19 additions & 3 deletions scripts/compat-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,37 @@ 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)
if (match) {
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
Expand Down

0 comments on commit 29b7c3f

Please sign in to comment.