Include preset modules (#11083)
* Prepare preset-env and compat-data for preset-modules
* Add transform-edge-default-parameters from preset-modules
* AUtomatically generate data from compat-table
* Add compat data for other plugins
* Updates after rebase
* Add more bugfixes to preset-env
* Update tests
* Add bugfix/transform-safari-for-shadowing
* Fix build script
* bugfix/transform-safari-block-shadowing
* Fix flow
* Include changes from 7127330f02
* Fix check-compat-data
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
{
|
||||
"transform-regenerator": []
|
||||
}
|
||||
"transform-async-to-generator": [
|
||||
"bugfix/transform-async-arrows-in-class"
|
||||
],
|
||||
"transform-parameters": [
|
||||
"bugfix/transform-edge-default-parameters"
|
||||
],
|
||||
"transform-function-name": [
|
||||
"bugfix/transform-edge-function-name"
|
||||
],
|
||||
"transform-block-scoping": [
|
||||
"bugfix/transform-safari-block-shadowing",
|
||||
"bugfix/transform-safari-for-shadowing"
|
||||
],
|
||||
"transform-template-literals": [
|
||||
"bugfix/transform-tagged-template-caching"
|
||||
]
|
||||
}
|
||||
|
||||
125
packages/babel-compat-data/data/plugin-bugfixes.json
Normal file
125
packages/babel-compat-data/data/plugin-bugfixes.json
Normal file
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"transform-async-to-generator": {
|
||||
"chrome": "55",
|
||||
"edge": "15",
|
||||
"firefox": "52",
|
||||
"safari": "10.1",
|
||||
"node": "7.6",
|
||||
"ios": "10.3",
|
||||
"samsung": "6",
|
||||
"opera": "42",
|
||||
"electron": "1.6"
|
||||
},
|
||||
"bugfix/transform-async-arrows-in-class": {
|
||||
"chrome": "55",
|
||||
"edge": "15",
|
||||
"firefox": "52",
|
||||
"safari": "11",
|
||||
"node": "7.6",
|
||||
"ios": "11",
|
||||
"samsung": "6",
|
||||
"opera": "42",
|
||||
"electron": "1.6"
|
||||
},
|
||||
"transform-parameters": {
|
||||
"chrome": "49",
|
||||
"edge": "15",
|
||||
"firefox": "53",
|
||||
"safari": "10",
|
||||
"node": "6",
|
||||
"ios": "10",
|
||||
"samsung": "5",
|
||||
"opera": "36",
|
||||
"electron": "1"
|
||||
},
|
||||
"bugfix/transform-edge-default-parameters": {
|
||||
"chrome": "49",
|
||||
"edge": "18",
|
||||
"firefox": "52",
|
||||
"safari": "10",
|
||||
"node": "6",
|
||||
"ios": "10",
|
||||
"samsung": "5",
|
||||
"opera": "36",
|
||||
"electron": "1"
|
||||
},
|
||||
"transform-function-name": {
|
||||
"chrome": "51",
|
||||
"edge": "14",
|
||||
"firefox": "53",
|
||||
"safari": "10",
|
||||
"node": "6.5",
|
||||
"ios": "10",
|
||||
"samsung": "5",
|
||||
"opera": "38",
|
||||
"electron": "1.2"
|
||||
},
|
||||
"bugfix/transform-edge-function-name": {
|
||||
"chrome": "51",
|
||||
"edge": "79",
|
||||
"firefox": "53",
|
||||
"safari": "10",
|
||||
"node": "6.5",
|
||||
"ios": "10",
|
||||
"samsung": "5",
|
||||
"opera": "38",
|
||||
"electron": "1.2"
|
||||
},
|
||||
"transform-block-scoping": {
|
||||
"chrome": "49",
|
||||
"edge": "14",
|
||||
"firefox": "51",
|
||||
"safari": "10",
|
||||
"node": "6",
|
||||
"ios": "10",
|
||||
"samsung": "5",
|
||||
"opera": "36",
|
||||
"electron": "1"
|
||||
},
|
||||
"bugfix/transform-safari-block-shadowing": {
|
||||
"chrome": "49",
|
||||
"edge": "12",
|
||||
"firefox": "44",
|
||||
"safari": "11",
|
||||
"node": "6",
|
||||
"ie": "11",
|
||||
"ios": "11",
|
||||
"samsung": "5",
|
||||
"opera": "36",
|
||||
"electron": "1"
|
||||
},
|
||||
"bugfix/transform-safari-for-shadowing": {
|
||||
"chrome": "49",
|
||||
"edge": "12",
|
||||
"firefox": "4",
|
||||
"safari": "11",
|
||||
"node": "6",
|
||||
"ie": "11",
|
||||
"ios": "11",
|
||||
"samsung": "5",
|
||||
"opera": "36",
|
||||
"electron": "1"
|
||||
},
|
||||
"transform-template-literals": {
|
||||
"chrome": "41",
|
||||
"edge": "13",
|
||||
"firefox": "34",
|
||||
"safari": "9",
|
||||
"node": "4",
|
||||
"ios": "9",
|
||||
"samsung": "3.4",
|
||||
"opera": "28",
|
||||
"electron": "0.24"
|
||||
},
|
||||
"bugfix/transform-tagged-template-caching": {
|
||||
"chrome": "41",
|
||||
"edge": "12",
|
||||
"firefox": "34",
|
||||
"safari": "13",
|
||||
"node": "4",
|
||||
"ios": "13",
|
||||
"samsung": "3.4",
|
||||
"opera": "28",
|
||||
"electron": "0.24"
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,11 @@
|
||||
"./native-modules": "./data/native-modules.json",
|
||||
"./corejs2-built-ins": "./data/corejs2-built-ins.json",
|
||||
"./corejs3-shipped-proposals": "./data/corejs3-shipped-proposals",
|
||||
"./overlapping-plugins": "./data/overlapping-plugins.json"
|
||||
"./overlapping-plugins": "./data/overlapping-plugins.json",
|
||||
"./plugin-bugfixes": "./data/plugin-bugfixes.json"
|
||||
},
|
||||
"scripts": {
|
||||
"build-data": "./scripts/download-compat-table.sh; node ./scripts/build-data.js; node ./scripts/build-modules-support.js; node ./scripts/build-overlapping-plugins.js; node ./scripts/build-corejs3-proposals.js"
|
||||
"build-data": "./scripts/download-compat-table.sh; node ./scripts/build-data.js; node ./scripts/build-modules-support.js; node ./scripts/build-bugfixes-targets.js"
|
||||
},
|
||||
"keywords": [
|
||||
"babel",
|
||||
|
||||
4
packages/babel-compat-data/plugin-bugfixes.js
Normal file
4
packages/babel-compat-data/plugin-bugfixes.js
Normal file
@@ -0,0 +1,4 @@
|
||||
// Node < 13.3 doesn't support export maps in package.json.
|
||||
// Use this proxy file as a fallback.
|
||||
|
||||
module.exports = require("./data/plugin-bugfixes.json");
|
||||
77
packages/babel-compat-data/scripts/build-bugfixes-targets.js
Normal file
77
packages/babel-compat-data/scripts/build-bugfixes-targets.js
Normal file
@@ -0,0 +1,77 @@
|
||||
"use strict";
|
||||
|
||||
// NOTE: This script must be run _after_ build-data.js
|
||||
|
||||
const path = require("path");
|
||||
|
||||
const {
|
||||
getLowestImplementedVersion,
|
||||
environments,
|
||||
addOperaAndElectron,
|
||||
writeFile,
|
||||
} = require("./utils-build-data");
|
||||
|
||||
const data = require("./data/plugin-bugfixes");
|
||||
const pluginFeatures = require("./data/plugin-features");
|
||||
|
||||
const generatedTargets = {};
|
||||
const overlappingPlugins = {};
|
||||
|
||||
const allReplacedFeatures = {};
|
||||
|
||||
const has = Function.call.bind(Object.hasOwnProperty);
|
||||
|
||||
for (const [plugin, { replaces, features }] of Object.entries(data)) {
|
||||
if (!has(overlappingPlugins, replaces)) {
|
||||
overlappingPlugins[replaces] = [];
|
||||
generatedTargets[replaces] = {};
|
||||
allReplacedFeatures[replaces] = [];
|
||||
}
|
||||
generatedTargets[plugin] = {};
|
||||
|
||||
allReplacedFeatures[replaces].push(...features);
|
||||
|
||||
overlappingPlugins[replaces].push(plugin);
|
||||
|
||||
for (const env of environments) {
|
||||
const supportedWithBugfix = getLowestImplementedVersion({ features }, env);
|
||||
if (supportedWithBugfix) {
|
||||
generatedTargets[plugin][env] = supportedWithBugfix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [replaced, features] of Object.entries(allReplacedFeatures)) {
|
||||
let replacedFeatures = pluginFeatures[replaced];
|
||||
if (!Array.isArray(replacedFeatures)) {
|
||||
replacedFeatures = replacedFeatures.features;
|
||||
}
|
||||
|
||||
for (const env of environments) {
|
||||
const stillNotSupported = getLowestImplementedVersion(
|
||||
{ features: replacedFeatures },
|
||||
env,
|
||||
name => features.some(feat => name.includes(feat))
|
||||
);
|
||||
|
||||
if (stillNotSupported) {
|
||||
generatedTargets[replaced][env] = stillNotSupported;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const plugin of Object.values(generatedTargets)) {
|
||||
addOperaAndElectron(plugin);
|
||||
}
|
||||
|
||||
for (const [filename, data] of [
|
||||
["plugin-bugfixes", generatedTargets],
|
||||
["overlapping-plugins", overlappingPlugins],
|
||||
]) {
|
||||
const dataPath = path.join(__dirname, `../data/${filename}.json`);
|
||||
|
||||
if (!writeFile(data, dataPath, filename)) {
|
||||
process.exitCode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,293 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const semver = require("semver");
|
||||
const flattenDeep = require("lodash/flattenDeep");
|
||||
const mapValues = require("lodash/mapValues");
|
||||
const pickBy = require("lodash/pickBy");
|
||||
const { unreleasedLabels } = require("@babel/helper-compilation-targets");
|
||||
const electronToChromiumVersions = require("electron-to-chromium").versions;
|
||||
|
||||
const electronToChromiumKeys = Object.keys(
|
||||
electronToChromiumVersions
|
||||
).reverse();
|
||||
|
||||
const chromiumToElectronMap = electronToChromiumKeys.reduce((all, electron) => {
|
||||
all[electronToChromiumVersions[electron]] = +electron;
|
||||
return all;
|
||||
}, {});
|
||||
const chromiumToElectronVersions = Object.keys(chromiumToElectronMap);
|
||||
|
||||
const findClosestElectronVersion = targetVersion => {
|
||||
const chromiumVersionsLength = chromiumToElectronVersions.length;
|
||||
const maxChromium = +chromiumToElectronVersions[chromiumVersionsLength - 1];
|
||||
if (targetVersion > maxChromium) return null;
|
||||
|
||||
const closestChrome = chromiumToElectronVersions.find(
|
||||
version => targetVersion <= version
|
||||
);
|
||||
return chromiumToElectronMap[closestChrome];
|
||||
};
|
||||
|
||||
const chromiumToElectron = chromium =>
|
||||
chromiumToElectronMap[chromium] || findClosestElectronVersion(chromium);
|
||||
|
||||
const renameTests = (tests, getName, category) =>
|
||||
tests.map(test =>
|
||||
Object.assign({}, test, { name: getName(test.name), category })
|
||||
);
|
||||
|
||||
// The following is adapted from compat-table:
|
||||
// https://github.com/kangax/compat-table/blob/gh-pages/build.js
|
||||
//
|
||||
// It parses and interpolates data so environments that "equal" other
|
||||
// environments (node4 and chrome45), as well as familial relationships (edge
|
||||
// and ie11) can be handled properly.
|
||||
|
||||
const envs = require("../build/compat-table/environments");
|
||||
|
||||
const byTestSuite = suite => browser => {
|
||||
return Array.isArray(browser.test_suites)
|
||||
? browser.test_suites.indexOf(suite) > -1
|
||||
: true;
|
||||
};
|
||||
|
||||
const compatSources = ["es5", "es6", "es2016plus", "esnext"].reduce(
|
||||
(result, source) => {
|
||||
const data = require(`../build/compat-table/data-${source}`);
|
||||
data.browsers = pickBy(envs, byTestSuite(source));
|
||||
result.push(data);
|
||||
return result;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const interpolateAllResults = (rawBrowsers, tests) => {
|
||||
const interpolateResults = res => {
|
||||
let browser;
|
||||
let prevBrowser;
|
||||
let result;
|
||||
let prevResult;
|
||||
let prevBid;
|
||||
|
||||
for (const bid in rawBrowsers) {
|
||||
// For browsers that are essentially equal to other browsers,
|
||||
// copy over the results.
|
||||
browser = rawBrowsers[bid];
|
||||
if (browser.equals && res[bid] === undefined) {
|
||||
result = res[browser.equals];
|
||||
res[bid] =
|
||||
browser.ignore_flagged && result === "flagged" ? false : result;
|
||||
// For each browser, check if the previous browser has the same
|
||||
// browser full name (e.g. Firefox) or family name (e.g. Chakra) as this one.
|
||||
} else if (
|
||||
prevBrowser &&
|
||||
(prevBrowser.full.replace(/,.+$/, "") ===
|
||||
browser.full.replace(/,.+$/, "") ||
|
||||
(browser.family !== undefined &&
|
||||
prevBrowser.family === browser.family))
|
||||
) {
|
||||
// For each test, check if the previous browser has a result
|
||||
// that this browser lacks.
|
||||
result = res[bid];
|
||||
prevResult = res[prevBid];
|
||||
if (prevResult !== undefined && result === undefined) {
|
||||
res[bid] = prevResult;
|
||||
}
|
||||
}
|
||||
prevBrowser = browser;
|
||||
prevBid = bid;
|
||||
}
|
||||
};
|
||||
|
||||
// Now print the results.
|
||||
tests.forEach(function(t) {
|
||||
// Calculate the result totals for tests which consist solely of subtests.
|
||||
if ("subtests" in t) {
|
||||
t.subtests.forEach(function(e) {
|
||||
interpolateResults(e.res);
|
||||
});
|
||||
} else {
|
||||
interpolateResults(t.res);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
compatSources.forEach(({ browsers, tests }) =>
|
||||
interpolateAllResults(browsers, tests)
|
||||
);
|
||||
|
||||
// End of compat-table code adaptation
|
||||
|
||||
const environments = [
|
||||
"chrome",
|
||||
"opera",
|
||||
"edge",
|
||||
"firefox",
|
||||
"safari",
|
||||
"node",
|
||||
"ie",
|
||||
"android",
|
||||
"ios",
|
||||
"phantom",
|
||||
"samsung",
|
||||
];
|
||||
|
||||
const compatibilityTests = flattenDeep(
|
||||
compatSources.map(data =>
|
||||
data.tests.map(test => {
|
||||
return test.subtests
|
||||
? [
|
||||
test,
|
||||
renameTests(
|
||||
test.subtests,
|
||||
name => test.name + " / " + name,
|
||||
test.category
|
||||
),
|
||||
]
|
||||
: test;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const getLowestImplementedVersion = ({ features }, env) => {
|
||||
const tests = compatibilityTests
|
||||
.filter(test => {
|
||||
return (
|
||||
features.indexOf(test.name) >= 0 ||
|
||||
// for features === ["DataView"]
|
||||
// it covers "DataView (Int8)" and "DataView (UInt8)"
|
||||
(features.length === 1 && test.name.indexOf(features[0]) === 0)
|
||||
);
|
||||
})
|
||||
.reduce((result, test) => {
|
||||
if (!test.subtests) {
|
||||
result.push({
|
||||
name: test.name,
|
||||
res: test.res,
|
||||
});
|
||||
} else {
|
||||
test.subtests.forEach(subtest =>
|
||||
result.push({
|
||||
name: `${test.name}/${subtest.name}`,
|
||||
res: subtest.res,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
const unreleasedLabelForEnv = unreleasedLabels[env];
|
||||
const envTests = tests.map(({ res: test }, i) => {
|
||||
const reportedVersions = Object.keys(test)
|
||||
.filter(t => t.startsWith(env))
|
||||
.map(t => {
|
||||
const version = t.replace(/_/g, ".").replace(env, "");
|
||||
return {
|
||||
version,
|
||||
semver: semver.coerce(version) || version,
|
||||
// Babel assumes strict mode
|
||||
implements: tests[i].res[t] === true || tests[i].res[t] === "strict",
|
||||
};
|
||||
})
|
||||
// version must be label from the unreleasedLabels (like tp) or number.
|
||||
.filter(
|
||||
version =>
|
||||
unreleasedLabelForEnv === version.version ||
|
||||
!isNaN(parseFloat(version.version))
|
||||
)
|
||||
// Sort in desc order, with unreleasedLabelForEnv coming last.
|
||||
.sort(({ semver: av }, { semver: bv }) => {
|
||||
if (av === unreleasedLabelForEnv) return -1;
|
||||
if (bv === unreleasedLabelForEnv) return 1;
|
||||
if (semver.gt(av, bv)) return -1;
|
||||
if (semver.gt(bv, av)) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Find the lowest version such that all higher versions implement it.
|
||||
// Eg, given { chrome70: true, chrome60: false, chrome50: true }, the
|
||||
// lowest version is chrome70, not chrome50.
|
||||
let lowest = null;
|
||||
for (const version of reportedVersions) {
|
||||
if (!version.implements) {
|
||||
break;
|
||||
}
|
||||
lowest = version;
|
||||
}
|
||||
return lowest;
|
||||
});
|
||||
|
||||
const envFiltered = envTests.filter(t => t);
|
||||
if (envTests.length > envFiltered.length || envTests.length === 0) {
|
||||
// envTests.forEach((test, i) => {
|
||||
// if (!test) {
|
||||
// // print unsupported features
|
||||
// if (env === 'node') {
|
||||
// console.log(`ENV(${env}): ${tests[i].name}`);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
return null;
|
||||
}
|
||||
|
||||
return envFiltered.reduce((a, b) => {
|
||||
if (a.semver === unreleasedLabelForEnv) return a;
|
||||
if (b.semver === unreleasedLabelForEnv) return b;
|
||||
|
||||
return semver.lt(a.semver, b.semver) ? b : a;
|
||||
});
|
||||
};
|
||||
|
||||
const generateData = (environments, features) => {
|
||||
return mapValues(features, options => {
|
||||
if (!options.features) {
|
||||
options = {
|
||||
features: [options],
|
||||
};
|
||||
}
|
||||
|
||||
const plugin = {};
|
||||
|
||||
environments.forEach(env => {
|
||||
const version = getLowestImplementedVersion(options, env);
|
||||
|
||||
if (version !== null) {
|
||||
const versionString = version.version;
|
||||
|
||||
// NOTE(bng): A number of environments in compat-table changed to
|
||||
// include a trailing zero (node10 -> node10_0), so for now stripping
|
||||
// it to be consistent
|
||||
plugin[env] = versionString.endsWith(".0")
|
||||
? versionString.slice(0, -2)
|
||||
: versionString;
|
||||
}
|
||||
});
|
||||
|
||||
if (plugin.chrome) {
|
||||
// add opera
|
||||
if (plugin.chrome >= 28) {
|
||||
plugin.opera = (plugin.chrome - 13).toString();
|
||||
} else if (!plugin.opera) {
|
||||
if (plugin.chrome <= 23) {
|
||||
plugin.opera = "15";
|
||||
} else if (plugin.chrome <= 27) {
|
||||
plugin.opera = "16";
|
||||
}
|
||||
}
|
||||
|
||||
// add electron
|
||||
const electronVersion = chromiumToElectron(plugin.chrome);
|
||||
if (electronVersion) {
|
||||
plugin.electron = electronVersion.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return plugin;
|
||||
});
|
||||
};
|
||||
const { generateData, environments, writeFile } = require("./utils-build-data");
|
||||
|
||||
for (const target of ["plugin", "corejs2-built-in"]) {
|
||||
const newData = generateData(
|
||||
@@ -296,20 +11,8 @@ for (const target of ["plugin", "corejs2-built-in"]) {
|
||||
);
|
||||
const dataPath = path.join(__dirname, `../data/${target}s.json`);
|
||||
|
||||
const stringified = JSON.stringify(newData, null, 2) + "\n";
|
||||
if (process.env.CHECK_COMPAT_DATA) {
|
||||
const currentData = fs.readFileSync(dataPath, "utf8");
|
||||
|
||||
// Compare as JSON strings to also check keys ordering
|
||||
if (currentData !== stringified) {
|
||||
console.error(
|
||||
"The newly generated plugin/built-in data does not match the current " +
|
||||
"files. Re-run `make build-compat-data`."
|
||||
);
|
||||
process.exitCode = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
fs.writeFileSync(dataPath, stringified);
|
||||
if (!writeFile(newData, dataPath, target)) {
|
||||
process.exitCode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const overlappingPlugins = require("./data/overlapping-plugins");
|
||||
|
||||
fs.writeFileSync(
|
||||
__dirname + "/../data/overlapping-plugins.json",
|
||||
JSON.stringify(overlappingPlugins, replacer, 2)
|
||||
);
|
||||
|
||||
function replacer(key, val) {
|
||||
if (val instanceof Set) return Array.from(val);
|
||||
if (val instanceof Map) return Object.fromEntries(val);
|
||||
return val;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = new Map();
|
||||
|
||||
// async -> regenerator is better than async -> generator -> regenerator
|
||||
ifIncluded("transform-regenerator")
|
||||
// Temporarly disabled: https://github.com/babel/babel/issues/10678
|
||||
// .isUnnecessary("transform-async-to-generator");
|
||||
|
||||
function ifIncluded(name) {
|
||||
const set = new Set();
|
||||
module.exports.set(name, set);
|
||||
return {
|
||||
isUnnecessary(name) { set.add(name); return this; },
|
||||
};
|
||||
}
|
||||
38
packages/babel-compat-data/scripts/data/plugin-bugfixes.js
Normal file
38
packages/babel-compat-data/scripts/data/plugin-bugfixes.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/* eslint sort-keys: "error" */
|
||||
|
||||
module.exports = {
|
||||
"bugfix/transform-async-arrows-in-class": {
|
||||
features: ["async functions / async arrow functions in methods, classes"],
|
||||
replaces: "transform-async-to-generator",
|
||||
},
|
||||
"bugfix/transform-edge-default-parameters": {
|
||||
features: [
|
||||
"destructuring, parameters / shorthand defaults, arrow function",
|
||||
],
|
||||
replaces: "transform-parameters",
|
||||
},
|
||||
"bugfix/transform-edge-function-name": {
|
||||
features: ['function "name" property / variables (function)'],
|
||||
replaces: "transform-function-name",
|
||||
},
|
||||
"bugfix/transform-safari-block-shadowing": {
|
||||
features: [
|
||||
"const / scope shadow resolution",
|
||||
"const / scope shadow resolution (strict mode)",
|
||||
"let / scope shadow resolution",
|
||||
"let / scope shadow resolution (strict mode)",
|
||||
],
|
||||
replaces: "transform-block-scoping",
|
||||
},
|
||||
"bugfix/transform-safari-for-shadowing": {
|
||||
features: [
|
||||
"let / for-in loop binding shadowing parameter",
|
||||
"let / for-in loop binding shadowing parameter (strict mode)",
|
||||
],
|
||||
replaces: "transform-block-scoping",
|
||||
},
|
||||
"bugfix/transform-tagged-template-caching": {
|
||||
features: ["template literals / TemplateStrings permanent caching"],
|
||||
replaces: "transform-template-literals",
|
||||
},
|
||||
};
|
||||
318
packages/babel-compat-data/scripts/utils-build-data.js
Normal file
318
packages/babel-compat-data/scripts/utils-build-data.js
Normal file
@@ -0,0 +1,318 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const semver = require("semver");
|
||||
const flattenDeep = require("lodash/flattenDeep");
|
||||
const mapValues = require("lodash/mapValues");
|
||||
const pickBy = require("lodash/pickBy");
|
||||
const { unreleasedLabels } = require("@babel/helper-compilation-targets");
|
||||
const electronToChromiumVersions = require("electron-to-chromium").versions;
|
||||
|
||||
const electronToChromiumKeys = Object.keys(
|
||||
electronToChromiumVersions
|
||||
).reverse();
|
||||
|
||||
const chromiumToElectronMap = electronToChromiumKeys.reduce((all, electron) => {
|
||||
all[electronToChromiumVersions[electron]] = +electron;
|
||||
return all;
|
||||
}, {});
|
||||
chromiumToElectronMap["0"] = "0";
|
||||
const chromiumToElectronVersions = Object.keys(chromiumToElectronMap);
|
||||
|
||||
const findClosestElectronVersion = targetVersion => {
|
||||
const chromiumVersionsLength = chromiumToElectronVersions.length;
|
||||
const maxChromium = +chromiumToElectronVersions[chromiumVersionsLength - 1];
|
||||
if (targetVersion > maxChromium) return null;
|
||||
|
||||
const closestChrome = chromiumToElectronVersions.find(
|
||||
version => targetVersion <= version
|
||||
);
|
||||
return chromiumToElectronMap[closestChrome];
|
||||
};
|
||||
|
||||
exports.chromiumToElectron = chromium =>
|
||||
chromiumToElectronMap[chromium] || findClosestElectronVersion(chromium);
|
||||
|
||||
const renameTests = (tests, getName, category) =>
|
||||
tests.map(test =>
|
||||
Object.assign({}, test, { name: getName(test.name), category })
|
||||
);
|
||||
|
||||
// The following is adapted from compat-table:
|
||||
// https://github.com/kangax/compat-table/blob/gh-pages/build.js
|
||||
//
|
||||
// It parses and interpolates data so environments that "equal" other
|
||||
// environments (node4 and chrome45), as well as familial relationships (edge
|
||||
// and ie11) can be handled properly.
|
||||
|
||||
const envs = require("../build/compat-table/environments");
|
||||
|
||||
const byTestSuite = suite => browser => {
|
||||
return Array.isArray(browser.test_suites)
|
||||
? browser.test_suites.indexOf(suite) > -1
|
||||
: true;
|
||||
};
|
||||
|
||||
const compatSources = ["es5", "es6", "es2016plus", "esnext"].reduce(
|
||||
(result, source) => {
|
||||
const data = require(`../build/compat-table/data-${source}`);
|
||||
data.browsers = pickBy(envs, byTestSuite(source));
|
||||
result.push(data);
|
||||
return result;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const interpolateAllResults = (rawBrowsers, tests) => {
|
||||
const interpolateResults = res => {
|
||||
let browser;
|
||||
let prevBrowser;
|
||||
let result;
|
||||
let prevResult;
|
||||
let prevBid;
|
||||
|
||||
for (const bid in rawBrowsers) {
|
||||
// For browsers that are essentially equal to other browsers,
|
||||
// copy over the results.
|
||||
browser = rawBrowsers[bid];
|
||||
if (browser.equals && res[bid] === undefined) {
|
||||
result = res[browser.equals];
|
||||
res[bid] =
|
||||
browser.ignore_flagged && result === "flagged" ? false : result;
|
||||
// For each browser, check if the previous browser has the same
|
||||
// browser full name (e.g. Firefox) or family name (e.g. Chakra) as this one.
|
||||
} else if (
|
||||
prevBrowser &&
|
||||
(prevBrowser.full.replace(/,.+$/, "") ===
|
||||
browser.full.replace(/,.+$/, "") ||
|
||||
(browser.family !== undefined &&
|
||||
prevBrowser.family === browser.family))
|
||||
) {
|
||||
// For each test, check if the previous browser has a result
|
||||
// that this browser lacks.
|
||||
result = res[bid];
|
||||
prevResult = res[prevBid];
|
||||
if (prevResult !== undefined && result === undefined) {
|
||||
res[bid] = prevResult;
|
||||
}
|
||||
}
|
||||
prevBrowser = browser;
|
||||
prevBid = bid;
|
||||
}
|
||||
};
|
||||
|
||||
// Now print the results.
|
||||
tests.forEach(function(t) {
|
||||
// Calculate the result totals for tests which consist solely of subtests.
|
||||
if ("subtests" in t) {
|
||||
t.subtests.forEach(function(e) {
|
||||
interpolateResults(e.res);
|
||||
});
|
||||
} else {
|
||||
interpolateResults(t.res);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
compatSources.forEach(({ browsers, tests }) =>
|
||||
interpolateAllResults(browsers, tests)
|
||||
);
|
||||
|
||||
// End of compat-table code adaptation
|
||||
|
||||
exports.environments = [
|
||||
"chrome",
|
||||
"opera",
|
||||
"edge",
|
||||
"firefox",
|
||||
"safari",
|
||||
"node",
|
||||
"ie",
|
||||
"android",
|
||||
"ios",
|
||||
"phantom",
|
||||
"samsung",
|
||||
];
|
||||
|
||||
const compatibilityTests = flattenDeep(
|
||||
compatSources.map(data =>
|
||||
data.tests.map(test => {
|
||||
return test.subtests
|
||||
? [
|
||||
test,
|
||||
renameTests(
|
||||
test.subtests,
|
||||
name => test.name + " / " + name,
|
||||
test.category
|
||||
),
|
||||
]
|
||||
: test;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
exports.getLowestImplementedVersion = (
|
||||
{ features },
|
||||
env,
|
||||
exclude = () => false
|
||||
) => {
|
||||
const tests = compatibilityTests
|
||||
.filter(test => {
|
||||
return (
|
||||
(features.indexOf(test.name) >= 0 ||
|
||||
// for features === ["DataView"]
|
||||
// it covers "DataView (Int8)" and "DataView (UInt8)"
|
||||
(features.length === 1 && test.name.indexOf(features[0]) === 0)) &&
|
||||
!exclude(test.name)
|
||||
);
|
||||
})
|
||||
.reduce((result, test) => {
|
||||
if (!test.subtests) {
|
||||
result.push({
|
||||
name: test.name,
|
||||
res: test.res,
|
||||
});
|
||||
} else {
|
||||
test.subtests.forEach(subtest => {
|
||||
if (!exclude(`${test.name} / ${subtest.name}`)) {
|
||||
result.push({
|
||||
name: `${test.name} /${subtest.name}`,
|
||||
res: subtest.res,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
const unreleasedLabelForEnv = unreleasedLabels[env];
|
||||
const envTests = tests.map(({ res: test }, i) => {
|
||||
const reportedVersions = Object.keys(test)
|
||||
.filter(t => t.startsWith(env))
|
||||
.map(t => {
|
||||
const version = t.replace(/_/g, ".").replace(env, "");
|
||||
return {
|
||||
version,
|
||||
semver: semver.coerce(version) || version,
|
||||
// Babel assumes strict mode
|
||||
implements: tests[i].res[t] === true || tests[i].res[t] === "strict",
|
||||
};
|
||||
})
|
||||
// version must be label from the unreleasedLabels (like tp) or number.
|
||||
.filter(
|
||||
version =>
|
||||
unreleasedLabelForEnv === version.version ||
|
||||
!isNaN(parseFloat(version.version))
|
||||
)
|
||||
// Sort in desc order, with unreleasedLabelForEnv coming last.
|
||||
.sort(({ semver: av }, { semver: bv }) => {
|
||||
if (av === unreleasedLabelForEnv) return -1;
|
||||
if (bv === unreleasedLabelForEnv) return 1;
|
||||
if (semver.gt(av, bv)) return -1;
|
||||
if (semver.gt(bv, av)) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Find the lowest version such that all higher versions implement it.
|
||||
// Eg, given { chrome70: true, chrome60: false, chrome50: true }, the
|
||||
// lowest version is chrome70, not chrome50.
|
||||
let lowest = null;
|
||||
for (const version of reportedVersions) {
|
||||
if (!version.implements) {
|
||||
break;
|
||||
}
|
||||
lowest = version;
|
||||
}
|
||||
return lowest;
|
||||
});
|
||||
|
||||
const envFiltered = envTests.filter(t => t);
|
||||
if (envTests.length > envFiltered.length || envTests.length === 0) {
|
||||
// envTests.forEach((test, i) => {
|
||||
// if (!test) {
|
||||
// // print unsupported features
|
||||
// if (env === 'node') {
|
||||
// console.log(`ENV(${env}): ${tests[i].name}`);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = envFiltered.reduce((a, b) => {
|
||||
if (a.semver === unreleasedLabelForEnv) return a;
|
||||
if (b.semver === unreleasedLabelForEnv) return b;
|
||||
|
||||
return semver.lt(a.semver, b.semver) ? b : a;
|
||||
});
|
||||
if (result.version.endsWith(".0")) {
|
||||
// NOTE(bng): A number of environments in compat-table changed to
|
||||
// include a trailing zero (node10 -> node10_0), so for now stripping
|
||||
// it to be consistent
|
||||
return result.version.slice(0, -2);
|
||||
}
|
||||
return result.version;
|
||||
};
|
||||
|
||||
exports.addOperaAndElectron = plugin => {
|
||||
if (plugin.chrome) {
|
||||
// add opera
|
||||
if (plugin.chrome >= 28) {
|
||||
plugin.opera = (plugin.chrome - 13).toString();
|
||||
} else if (!plugin.opera) {
|
||||
if (plugin.chrome <= 23) {
|
||||
plugin.opera = "15";
|
||||
} else if (plugin.chrome <= 27) {
|
||||
plugin.opera = "16";
|
||||
}
|
||||
}
|
||||
|
||||
// add electron
|
||||
const electronVersion = exports.chromiumToElectron(plugin.chrome);
|
||||
if (electronVersion) {
|
||||
plugin.electron = electronVersion.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.generateData = (environments, features) => {
|
||||
return mapValues(features, options => {
|
||||
if (!options.features) {
|
||||
options = {
|
||||
features: [options],
|
||||
};
|
||||
}
|
||||
|
||||
const plugin = {};
|
||||
|
||||
environments.forEach(env => {
|
||||
const version = exports.getLowestImplementedVersion(options, env);
|
||||
if (version) plugin[env] = version;
|
||||
});
|
||||
|
||||
exports.addOperaAndElectron(plugin);
|
||||
|
||||
return plugin;
|
||||
});
|
||||
};
|
||||
|
||||
exports.writeFile = function(data, dataPath, name) {
|
||||
const stringified = JSON.stringify(data, null, 2) + "\n";
|
||||
if (process.env.CHECK_COMPAT_DATA) {
|
||||
const currentData = fs.readFileSync(dataPath, "utf8");
|
||||
|
||||
// Compare as JSON strings to also check keys ordering
|
||||
if (currentData !== stringified) {
|
||||
console.error(
|
||||
`The newly generated ${name} data does not match the current ` +
|
||||
"files. Re-run `make build-compat-data`."
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
fs.writeFileSync(dataPath, stringified);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
Reference in New Issue
Block a user