diff --git a/Makefile b/Makefile index 730629a38f1..eb1c54c656e 100644 --- a/Makefile +++ b/Makefile @@ -177,6 +177,16 @@ parcel2/node_modules: scripts/node_modules: cd scripts && npm ci +################################################################################ +# This downloads the kangax compat-table and generates browser support mappings + +github/compat-table: + mkdir -p github/compat-table + git clone --depth 1 https://github.com/kangax/compat-table.git github/compat-table + +compat-table: | github/compat-table + node scripts/compat-table.js + ################################################################################ # This runs the test262 official JavaScript test suite through esbuild diff --git a/internal/compat/table.go b/internal/compat/table.go new file mode 100644 index 00000000000..f59c691ebc0 --- /dev/null +++ b/internal/compat/table.go @@ -0,0 +1,153 @@ +// This file was automatically generated by "compat-table.js" + +package compat + +type Engine uint8 + +const ( + Android Engine = iota + Chrome + Edge + Firefox + Ios + Node + Safari +) + +type Feature uint8 + +const ( + Async Feature = iota + AsyncIter + BigInt + ClassField + ClassPrivateField + ClassPrivateMethod + ClassPrivateStaticField + ClassPrivateStaticMethod + ClassStaticField + ExponentOperator + Hashbang + LogicalAssignment + NestedRestBinding + NullishCoalescing + ObjectRestSpread + OptionalCatchBinding + OptionalChain +) + +var Table = map[Feature]map[Engine]float32{ + Async: map[Engine]float32{ + Chrome: 55, + Edge: 15, + Firefox: 52, + Ios: 10.3, + Node: 7.6, + Safari: 10.1, + }, + AsyncIter: map[Engine]float32{ + Chrome: 63, + Edge: 79, + Firefox: 57, + Ios: 12, + Node: 10, + Safari: 12, + }, + BigInt: map[Engine]float32{ + Chrome: 67, + Edge: 79, + Firefox: 68, + Node: 10.4, + Safari: 14, + }, + ClassField: map[Engine]float32{ + Chrome: 72, + Edge: 79, + Firefox: 69, + Node: 12, + Safari: 14, + }, + ClassPrivateField: map[Engine]float32{ + Chrome: 74, + Edge: 79, + Node: 12, + }, + ClassPrivateMethod: map[Engine]float32{ + Chrome: 84, + }, + ClassPrivateStaticField: map[Engine]float32{ + Chrome: 74, + Edge: 79, + Node: 12, + }, + ClassPrivateStaticMethod: map[Engine]float32{ + Chrome: 84, + }, + ClassStaticField: map[Engine]float32{ + Chrome: 72, + Edge: 79, + Firefox: 75, + Node: 12, + }, + ExponentOperator: map[Engine]float32{ + Chrome: 52, + Edge: 14, + Firefox: 52, + Ios: 10.3, + Node: 7, + Safari: 10.1, + }, + Hashbang: map[Engine]float32{ + Chrome: 74, + Edge: 79, + Firefox: 67, + Ios: 13.4, + Node: 12, + Safari: 13.1, + }, + LogicalAssignment: map[Engine]float32{ + Chrome: 85, + Firefox: 79, + Safari: 14, + }, + NestedRestBinding: map[Engine]float32{ + Chrome: 49, + Edge: 14, + Firefox: 47, + Ios: 10.3, + Node: 6, + Safari: 10.1, + }, + NullishCoalescing: map[Engine]float32{ + Chrome: 80, + Edge: 80, + Firefox: 72, + Ios: 13.4, + Node: 14, + Safari: 13.1, + }, + ObjectRestSpread: map[Engine]float32{ + Chrome: 60, + Edge: 79, + Firefox: 55, + Ios: 11.3, + Node: 8.1, + Safari: 11.1, + }, + OptionalCatchBinding: map[Engine]float32{ + Chrome: 66, + Edge: 79, + Firefox: 58, + Ios: 11.3, + Node: 10, + Safari: 11.1, + }, + OptionalChain: map[Engine]float32{ + Chrome: 80, + Edge: 80, + Firefox: 74, + Ios: 13.4, + Node: 14, + Safari: 13.1, + }, +} diff --git a/scripts/compat-table.js b/scripts/compat-table.js new file mode 100644 index 00000000000..dd0e78354b8 --- /dev/null +++ b/scripts/compat-table.js @@ -0,0 +1,132 @@ +// Run this using "make compat-table" +const fs = require('fs') +const path = require('path') +const stage1to3 = require('../github/compat-table/data-esnext') +const stage4 = require('../github/compat-table/data-es2016plus') +const environments = require('../github/compat-table/environments.json') +const interpolateAllResults = require('../github/compat-table/build-utils/interpolate-all-results') + +interpolateAllResults(stage1to3.tests, environments) +interpolateAllResults(stage4.tests, environments) + +const features = { + 'exponentiation (**) operator': { target: 'ExponentOperator' }, + 'nested rest destructuring, declarations': { target: 'NestedRestBinding' }, + 'nested rest destructuring, parameters': { target: 'NestedRestBinding' }, + 'async functions': { target: 'Async' }, + 'object rest/spread properties': { target: 'ObjectRestSpread' }, + 'Asynchronous Iterators': { target: 'AsyncIter' }, + 'optional catch binding': { target: 'OptionalCatchBinding' }, + 'BigInt: basic functionality': { target: 'BigInt' }, + 'optional chaining operator (?.)': { target: 'OptionalChain' }, + 'nullish coalescing operator (??)': { target: 'NullishCoalescing' }, + 'Logical Assignment': { target: 'LogicalAssignment' }, + 'Hashbang Grammar': { target: 'Hashbang' }, + + // Public fields + 'instance class fields: public instance class fields': { target: 'ClassField' }, + 'instance class fields: computed instance class fields': { target: 'ClassField' }, + 'static class fields: public static class fields': { target: 'ClassStaticField' }, + 'static class fields: computed static class fields': { target: 'ClassStaticField' }, + + // Private fields + 'instance class fields: private instance class fields basic support': { target: 'ClassPrivateField' }, + 'instance class fields: private instance class fields initializers': { target: 'ClassPrivateField' }, + 'instance class fields: optional private instance class fields access': { target: 'ClassPrivateField' }, + 'instance class fields: optional deep private instance class fields access': { target: 'ClassPrivateField' }, + 'static class fields: private static class fields': { target: 'ClassPrivateStaticField' }, + + // Private methods + 'private class methods: private instance methods': { target: 'ClassPrivateMethod' }, + 'private class methods: private accessor properties': { target: 'ClassPrivateMethod' }, + 'private class methods: private static methods': { target: 'ClassPrivateStaticMethod' }, + 'private class methods: private static accessor properties': { target: 'ClassPrivateStaticMethod' }, +} + +const versions = {} +const engines = [ + 'android', + 'chrome', + 'edge', + 'firefox', + 'ios', + 'node', + 'safari', +] + +function mergeVersions(target, res) { + const map = versions[target] || (versions[target] = {}) + for (const key in res) { + if (res[key] === true) { + const engine = /^[a-z]*/.exec(key)[0] + if (engines.indexOf(engine) >= 0) { + const version = +key.slice(engine.length).replace('_', '.') + map[engine] = Math.min(version, map[engine] || Infinity) + } + } + } +} + +for (const test of stage4.tests.concat(stage1to3.tests)) { + const feature = features[test.name] + if (feature) { + feature.found = true + if (test.subtests) { + for (const subtest of test.subtests) { + mergeVersions(feature.target, subtest.res) + } + } else { + mergeVersions(feature.target, test.res) + } + } else if (test.subtests) { + for (const subtest of test.subtests) { + const feature = features[`${test.name}: ${subtest.name}`] + if (feature) { + feature.found = true + mergeVersions(feature.target, subtest.res) + } + } + } +} + +for (const feature in features) { + if (!features[feature].found) { + throw new Error(`Did not find ${feature}`) + } +} + +function upperFirstLetter(text) { + return text[0].toUpperCase() + text.slice(1) +} + +function writeInnerMap(obj) { + const keys = Object.keys(obj).sort() + const maxLength = keys.reduce((a, b) => Math.max(a, b.length + 1), 0) + return keys.map(x => `\t\t${(upperFirstLetter(x) + ':').padEnd(maxLength)} ${obj[x]},`).join('\n') +} + +fs.writeFileSync(__dirname + '/../internal/compat/table.go', + `// This file was automatically generated by "${path.basename(__filename)}" + +package compat + +type Engine uint8 + +const ( +${engines.map((x, i) => `\t${upperFirstLetter(x)}${i ? '' : ' Engine = iota'}`).join('\n')} +) + +type Feature uint8 + +const ( +${Object.keys(versions).sort().map((x, i) => `\t${x}${i ? '' : ' Feature = iota'}`).join('\n')} +) + +var Table = map[Feature]map[Engine]float32{ +${Object.keys(versions).sort().map(x => `\t${x}: map[Engine]float32{ +${writeInnerMap(versions[x])} +\t},`).join('\n')} +} +`) + +// console.log(versions)