mirror of
https://github.com/hanzoai/babel.git
synced 2026-09-24 16:56:45 +00:00
220 lines
5.9 KiB
JavaScript
220 lines
5.9 KiB
JavaScript
import fs from "node:fs";
|
|
import { addElectronSupportFromChromium } from "./chromium-to-electron.mjs";
|
|
|
|
import envs from "../build/compat-table/environments.json" with { type: "json" };
|
|
import parseEnvsVersions from "../build/compat-table/build-utils/parse-envs-versions.js";
|
|
import interpolateAllResults from "../build/compat-table/build-utils/interpolate-all-results.js";
|
|
import compareVersions from "../build/compat-table/build-utils/compare-versions.js";
|
|
import legacyPluginAliases from "./data/legacy-plugin-aliases.mjs";
|
|
|
|
import * as es5CompatSources from "../build/compat-table/data-es5.js";
|
|
import * as es6CompatSources from "../build/compat-table/data-es6.js";
|
|
import * as es2016PlusCompatSources from "../build/compat-table/data-es2016plus.js";
|
|
import * as esnextCompatSources from "../build/compat-table/data-esnext.js";
|
|
|
|
const envsVersions = parseEnvsVersions(envs);
|
|
|
|
const compatSources = [
|
|
es5CompatSources,
|
|
es6CompatSources,
|
|
es2016PlusCompatSources,
|
|
esnextCompatSources,
|
|
].map(data => {
|
|
interpolateAllResults(data.tests, envs);
|
|
return data;
|
|
});
|
|
|
|
// End of compat-table code adaptation
|
|
|
|
export const environments = [
|
|
"chrome",
|
|
"opera",
|
|
"edge",
|
|
"firefox",
|
|
"safari",
|
|
"node",
|
|
"deno",
|
|
"ie",
|
|
"android",
|
|
"ios",
|
|
"phantom",
|
|
"samsung",
|
|
"rhino",
|
|
"opera_mobile",
|
|
];
|
|
|
|
const compatibilityTests = compatSources.flatMap(data =>
|
|
data.tests.flatMap(test => {
|
|
if (!test.subtests) return test;
|
|
|
|
return test.subtests.map(subtest =>
|
|
Object.assign({}, subtest, {
|
|
name: test.name + " / " + subtest.name,
|
|
group: test.name,
|
|
})
|
|
);
|
|
})
|
|
);
|
|
|
|
const getLowestImplementedVersion = (
|
|
{ features },
|
|
env,
|
|
exclude = () => false
|
|
) => {
|
|
const tests = compatibilityTests.filter(test => {
|
|
let ok = features.includes(test.name);
|
|
ok ||= test.group && features.includes(test.group);
|
|
ok ||= features.length === 1 && test.name.startsWith(features[0]);
|
|
ok &&= !exclude(test.name);
|
|
return ok;
|
|
});
|
|
|
|
const envTests = tests.map(({ res }) => {
|
|
const versions = envsVersions[env];
|
|
let i = versions.length - 1;
|
|
|
|
// Find the last not-implemented version
|
|
for (; i >= 0; i--) {
|
|
const { id } = versions[i];
|
|
// Babel assumes strict mode
|
|
if (res[id] !== true && res[id] !== "strict") {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return envsVersions[env][i + 1];
|
|
});
|
|
|
|
if (envTests.length === 0 || envTests.some(t => !t)) return null;
|
|
|
|
const result = envTests.reduce((a, b) => {
|
|
return compareVersions(a, b) > 0 ? a : b;
|
|
});
|
|
|
|
// 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.join(".").replace(/\.0$/, "");
|
|
};
|
|
|
|
const expandFeatures = features =>
|
|
features.flatMap(feat => {
|
|
if (feat.includes("/")) return [feat];
|
|
let excludedTests = [];
|
|
if (Array.isArray(feat)) {
|
|
[feat, { exclude: excludedTests }] = feat;
|
|
}
|
|
return compatibilityTests
|
|
.filter(
|
|
test =>
|
|
test.name === feat ||
|
|
(test.group === feat &&
|
|
!excludedTests.includes(test.name.split(" / ")[1]))
|
|
)
|
|
.map(test => test.name);
|
|
});
|
|
|
|
export function generateData(environments, features) {
|
|
const data = {};
|
|
|
|
/**
|
|
* @type Map<string, string[]>
|
|
* Normalized map from plugin name to a list of feature names
|
|
*/
|
|
const normalized = new Map();
|
|
for (const [key, options] of Object.entries(features)) {
|
|
if (options.overwrite) {
|
|
if (!options.replaces || options.features) {
|
|
throw new Error(
|
|
`.overwrite is only supported when using .replace and not defining .features (${key})`
|
|
);
|
|
}
|
|
options.features = features[options.replaces].features;
|
|
}
|
|
if (!options.features) {
|
|
normalized.set(key, {
|
|
features: expandFeatures([options]),
|
|
});
|
|
} else {
|
|
normalized.set(key, {
|
|
...options,
|
|
features: expandFeatures(options.features),
|
|
});
|
|
}
|
|
}
|
|
|
|
const overlapping = {};
|
|
|
|
// Apply bugfixes
|
|
for (const [key, { features, replaces, overwrite }] of normalized.entries()) {
|
|
if (replaces) {
|
|
const replaceValue = normalized.get(replaces);
|
|
if (replaceValue.replaces) {
|
|
throw new Error(`Transitive replacement is not supported (${key})`);
|
|
}
|
|
|
|
if (overwrite) {
|
|
normalized.set(key, {
|
|
features: replaceValue.features,
|
|
overwrite,
|
|
});
|
|
} else {
|
|
replaceValue.features = replaceValue.features.filter(
|
|
feat => !features.includes(feat)
|
|
);
|
|
}
|
|
|
|
if (!overlapping[replaces]) overlapping[replaces] = [];
|
|
overlapping[replaces].push(key);
|
|
}
|
|
}
|
|
|
|
for (const [key, options] of normalized.entries()) {
|
|
const plugin = {};
|
|
|
|
environments.forEach(env => {
|
|
const version = getLowestImplementedVersion(options, env);
|
|
if (version) plugin[env] = version;
|
|
});
|
|
addElectronSupportFromChromium(plugin);
|
|
|
|
if (options.overwrite) Object.assign(plugin, options.overwrite);
|
|
|
|
data[key] = plugin;
|
|
}
|
|
|
|
return { data, overlapping };
|
|
}
|
|
|
|
export function writeFile(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;
|
|
}
|
|
|
|
export function maybeDefineLegacyPluginAliases(data) {
|
|
// We create a new object to inject legacy aliases in the correct
|
|
// order, rather than all at the end.
|
|
const result = {};
|
|
for (const key in data) {
|
|
result[key] = data[key];
|
|
if (key in legacyPluginAliases) {
|
|
result[legacyPluginAliases[key]] = data[key];
|
|
}
|
|
}
|
|
return result;
|
|
}
|