310 lines
8.7 KiB
JavaScript
310 lines
8.7 KiB
JavaScript
import path from "path";
|
|
import fs from "fs";
|
|
import { createRequire } from "module";
|
|
import helpers from "@babel/helpers";
|
|
import babel from "@babel/core";
|
|
import template from "@babel/template";
|
|
import t from "@babel/types";
|
|
import { fileURLToPath } from "url";
|
|
|
|
import transformRuntime from "../lib/index.js";
|
|
import buildCorejs2Definitions from "../lib/runtime-corejs2-definitions.js";
|
|
import buildCorejs3Definitions from "../lib/runtime-corejs3-definitions.js";
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const runtimeVersion = require("@babel/runtime/package.json").version;
|
|
|
|
const corejs2Definitions = buildCorejs2Definitions.default();
|
|
const corejs3Definitions = buildCorejs3Definitions.default();
|
|
|
|
function outputFile(filePath, data) {
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
fs.writeFileSync(filePath, data);
|
|
}
|
|
|
|
writeHelpers("@babel/runtime");
|
|
writeHelpers("@babel/runtime-corejs2", { corejs: 2 });
|
|
writeHelpers("@babel/runtime-corejs3", {
|
|
corejs: { version: 3, proposals: true },
|
|
});
|
|
|
|
writeCoreJS({
|
|
corejs: 2,
|
|
proposals: true,
|
|
definitions: corejs2Definitions,
|
|
paths: [
|
|
"is-iterable",
|
|
"get-iterator",
|
|
// This was previously in definitions, but was removed to work around
|
|
// zloirock/core-js#262. We need to keep it in @babel/runtime-corejs2 to
|
|
// avoid a breaking change there.
|
|
"symbol/async-iterator",
|
|
],
|
|
corejsRoot: "core-js/library/fn",
|
|
});
|
|
writeCoreJS({
|
|
corejs: 3,
|
|
proposals: false,
|
|
definitions: corejs3Definitions,
|
|
paths: [],
|
|
corejsRoot: "core-js-pure/stable",
|
|
});
|
|
writeCoreJS({
|
|
corejs: 3,
|
|
proposals: true,
|
|
definitions: corejs3Definitions,
|
|
paths: ["is-iterable", "get-iterator", "get-iterator-method"],
|
|
corejsRoot: "core-js-pure/features",
|
|
});
|
|
|
|
function writeCoreJS({
|
|
corejs,
|
|
proposals,
|
|
definitions: { BuiltIns, StaticProperties, InstanceProperties },
|
|
paths,
|
|
corejsRoot,
|
|
}) {
|
|
const pkgDirname = getRuntimeRoot(`@babel/runtime-corejs${corejs}`);
|
|
|
|
Object.keys(BuiltIns).forEach(name => {
|
|
const { stable, path } = BuiltIns[name];
|
|
if (stable || proposals) paths.push(path);
|
|
});
|
|
|
|
Object.keys(StaticProperties).forEach(builtin => {
|
|
const props = StaticProperties[builtin];
|
|
Object.keys(props).forEach(name => {
|
|
const { stable, path } = props[name];
|
|
if (stable || proposals) paths.push(path);
|
|
});
|
|
});
|
|
|
|
if (InstanceProperties) {
|
|
Object.keys(InstanceProperties).forEach(name => {
|
|
const { stable, path } = InstanceProperties[name];
|
|
if (stable || proposals) paths.push(`instance/${path}`);
|
|
});
|
|
}
|
|
|
|
const runtimeRoot = proposals ? "core-js" : "core-js-stable";
|
|
paths.forEach(function (corejsPath) {
|
|
outputFile(
|
|
path.join(pkgDirname, runtimeRoot, `${corejsPath}.js`),
|
|
`module.exports = require("${corejsRoot}/${corejsPath}");`
|
|
);
|
|
});
|
|
|
|
writeCorejsExports(pkgDirname, runtimeRoot, paths);
|
|
}
|
|
|
|
function writeCorejsExports(pkgDirname, runtimeRoot, paths) {
|
|
const pkgJsonPath = require.resolve(`${pkgDirname}/package.json`);
|
|
const pkgJson = require(pkgJsonPath);
|
|
const exports = pkgJson.exports;
|
|
// Export `./core-js/` so `import "@babel/runtime-corejs3/core-js/some-feature.js"` works
|
|
exports[`./${runtimeRoot}/`] = `./${runtimeRoot}/`;
|
|
for (const corejsPath of paths) {
|
|
// Export `./core-js/some-feature` so `import "@babel/runtime-corejs3/core-js/some-feature"` also works
|
|
const corejsExportPath = `./${runtimeRoot}/${corejsPath}`;
|
|
exports[corejsExportPath] = corejsExportPath + ".js";
|
|
}
|
|
pkgJson.exports = exports;
|
|
outputFile(pkgJsonPath, JSON.stringify(pkgJson, undefined, 2) + "\n");
|
|
}
|
|
|
|
function writeHelperFile(
|
|
runtimeName,
|
|
pkgDirname,
|
|
helperPath,
|
|
helperName,
|
|
{ esm, corejs }
|
|
) {
|
|
const filePath = path.join(helperPath, esm ? "index.mjs" : "index.js");
|
|
const fullPath = path.join(pkgDirname, filePath);
|
|
|
|
outputFile(
|
|
fullPath,
|
|
buildHelper(runtimeName, pkgDirname, fullPath, helperName, { esm, corejs })
|
|
);
|
|
|
|
return `./${filePath}`;
|
|
}
|
|
|
|
function writeHelperLegacyESMFile(pkgDirname, helperName) {
|
|
const fullPath = path.join(pkgDirname, "helpers", "esm", `${helperName}.js`);
|
|
|
|
outputFile(fullPath, `export { default } from "../${helperName}/index.mjs"`);
|
|
}
|
|
|
|
function writeHelpers(runtimeName, { corejs } = {}) {
|
|
const pkgDirname = getRuntimeRoot(runtimeName);
|
|
const helperSubExports = {};
|
|
for (const helperName of helpers.list) {
|
|
const helperPath = path.join("helpers", helperName);
|
|
helperSubExports[`./${helperPath}`] = {
|
|
module: writeHelperFile(runtimeName, pkgDirname, helperPath, helperName, {
|
|
esm: true,
|
|
corejs,
|
|
}),
|
|
node: writeHelperFile(runtimeName, pkgDirname, helperPath, helperName, {
|
|
esm: false,
|
|
corejs,
|
|
}),
|
|
get default() {
|
|
return this.module;
|
|
},
|
|
};
|
|
writeHelperLegacyESMFile(pkgDirname, helperName);
|
|
}
|
|
|
|
writeHelperExports(runtimeName, helperSubExports);
|
|
}
|
|
|
|
function writeHelperExports(runtimeName, helperSubExports) {
|
|
const exports = {
|
|
...helperSubExports,
|
|
"./package": "./package.json",
|
|
"./package.json": "./package.json",
|
|
"./regenerator": "./regenerator/index.js",
|
|
"./regenerator/*.js": "./regenerator/*.js",
|
|
"./helpers/esm/*": "./helpers/esm/*.js",
|
|
// These patterns are deprecated, but since patterns
|
|
// containing * are not supported in every Node.js
|
|
// version we keep them for better compatibility.
|
|
"./regenerator/": "./regenerator/",
|
|
"./helpers/esm/": "./helpers/esm/",
|
|
};
|
|
const pkgDirname = getRuntimeRoot(runtimeName);
|
|
const pkgJsonPath = require.resolve(`${pkgDirname}/package.json`);
|
|
const pkgJson = require(pkgJsonPath);
|
|
pkgJson.exports = exports;
|
|
outputFile(pkgJsonPath, JSON.stringify(pkgJson, undefined, 2) + "\n");
|
|
}
|
|
|
|
function getRuntimeRoot(runtimeName) {
|
|
return path.resolve(
|
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
"..",
|
|
"..",
|
|
runtimeName.replace(/^@babel\//, "babel-")
|
|
);
|
|
}
|
|
|
|
function buildHelper(
|
|
runtimeName,
|
|
pkgDirname,
|
|
helperFilename,
|
|
helperName,
|
|
{ esm, corejs }
|
|
) {
|
|
const tree = t.program([], [], esm ? "module" : "script");
|
|
const dependencies = {};
|
|
let bindings = null;
|
|
|
|
if (!esm) {
|
|
bindings = [];
|
|
helpers.ensure(helperName, babel.File);
|
|
for (const dep of helpers.getDependencies(helperName)) {
|
|
const id = (dependencies[dep] = t.identifier(t.toIdentifier(dep)));
|
|
tree.body.push(template.statement.ast`
|
|
var ${id} = require("${dep}");
|
|
`);
|
|
bindings.push(id.name);
|
|
}
|
|
}
|
|
|
|
const helper = helpers.get(
|
|
helperName,
|
|
dep => dependencies[dep],
|
|
esm ? null : template.expression.ast`module.exports`,
|
|
bindings
|
|
);
|
|
tree.body.push(...helper.nodes);
|
|
|
|
return babel.transformFromAst(tree, null, {
|
|
filename: helperFilename,
|
|
presets: [
|
|
[
|
|
"@babel/preset-env",
|
|
{ modules: false, exclude: ["@babel/plugin-transform-typeof-symbol"] },
|
|
],
|
|
],
|
|
plugins: [
|
|
[
|
|
transformRuntime,
|
|
{ corejs, useESModules: esm, version: runtimeVersion },
|
|
],
|
|
buildRuntimeRewritePlugin(runtimeName, helperName),
|
|
esm ? null : addDefaultCJSExport,
|
|
].filter(Boolean),
|
|
overrides: [
|
|
{
|
|
exclude: /typeof/,
|
|
plugins: ["@babel/plugin-transform-typeof-symbol"],
|
|
},
|
|
],
|
|
}).code;
|
|
}
|
|
|
|
function buildRuntimeRewritePlugin(runtimeName, helperName) {
|
|
/**
|
|
* rewrite helpers imports to runtime imports
|
|
* @example
|
|
* adjustImportPath(ast`"setPrototypeOf"`)
|
|
* // returns ast`"@babel/runtime/helpers/esm/setPrototypeOf"`
|
|
* @param {*} node The string literal contains import path
|
|
*/
|
|
function adjustImportPath(node) {
|
|
if (helpers.list.includes(node.value)) {
|
|
node.value = `${runtimeName}/helpers/${node.value}`;
|
|
}
|
|
}
|
|
|
|
return {
|
|
pre(file) {
|
|
const original = file.get("helperGenerator");
|
|
file.set("helperGenerator", name => {
|
|
// make sure that helpers won't insert circular references to themselves
|
|
if (name === helperName) return false;
|
|
|
|
return original(name);
|
|
});
|
|
},
|
|
visitor: {
|
|
ImportDeclaration(path) {
|
|
adjustImportPath(path.get("source").node);
|
|
},
|
|
CallExpression(path) {
|
|
if (
|
|
!path.get("callee").isIdentifier({ name: "require" }) ||
|
|
path.get("arguments").length !== 1 ||
|
|
!path.get("arguments")[0].isStringLiteral()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// replace reference to internal helpers with @babel/runtime import path
|
|
adjustImportPath(path.get("arguments")[0].node);
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
function addDefaultCJSExport({ template }) {
|
|
return {
|
|
visitor: {
|
|
Program: {
|
|
exit(path) {
|
|
path.pushContainer(
|
|
"body",
|
|
template.statements.ast`
|
|
module.exports.default = module.exports;
|
|
module.exports.__esModule = true;
|
|
`
|
|
);
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|