159 lines
4.1 KiB
JavaScript

"use strict";
const path = require("path");
const outputFile = require("output-file-sync");
const helpers = require("@babel/helpers");
const babel = require("@babel/core");
const template = require("@babel/template");
const t = require("@babel/types");
const transformRuntime = require("../");
const corejs2Definitions = require("../lib/definitions").default;
writeHelpers("@babel/runtime");
writeCoreJS2("@babel/runtime-corejs2");
writeHelpers("@babel/runtime-corejs2", { corejs: 2 });
function writeCoreJS2(runtimeName) {
const pkgDirname = getRuntimeRoot(runtimeName);
const paths = ["is-iterable", "get-iterator"];
Object.keys(corejs2Definitions.builtins).forEach(key => {
const path = corejs2Definitions.builtins[key];
paths.push(path);
});
Object.keys(corejs2Definitions.methods).forEach(key => {
const props = corejs2Definitions.methods[key];
Object.keys(props).forEach(key2 => {
paths.push(props[key2]);
});
});
paths.forEach(function(corePath) {
outputFile(
path.join(pkgDirname, "core-js", `${corePath}.js`),
`module.exports = require("core-js/library/fn/${corePath}");`
);
});
}
function writeHelpers(runtimeName, { corejs } = {}) {
writeHelperFiles(runtimeName, { corejs, esm: false });
writeHelperFiles(runtimeName, { corejs, esm: true });
}
function writeHelperFiles(runtimeName, { esm, corejs }) {
const pkgDirname = getRuntimeRoot(runtimeName);
for (const helperName of helpers.list) {
const helperFilename = path.join(
pkgDirname,
"helpers",
esm ? "esm" : "",
`${helperName}.js`
);
outputFile(
helperFilename,
buildHelper(runtimeName, pkgDirname, helperFilename, helperName, {
esm,
corejs,
})
);
}
}
function getRuntimeRoot(runtimeName) {
return path.resolve(
__dirname,
"..",
"..",
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 = [];
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, {
presets: [[require("@babel/preset-env"), { modules: false }]],
plugins: [
[transformRuntime, { corejs, useESModules: esm }],
buildRuntimeRewritePlugin(
runtimeName,
path.relative(path.dirname(helperFilename), pkgDirname),
helperName
),
],
}).code;
}
function buildRuntimeRewritePlugin(runtimeName, relativePath, helperName) {
function adjustImportPath(node, relativePath) {
node.value =
helpers.list.indexOf(node.value) !== -1
? `./${node.value}`
: node.value.replace(runtimeName + "/", relativePath + "/");
}
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, relativePath);
},
CallExpression(path) {
if (
!path.get("callee").isIdentifier({ name: "require" }) ||
path.get("arguments").length !== 1 ||
!path.get("arguments")[0].isStringLiteral()
) {
return;
}
// replace any reference to @babel/runtime and other helpers
// with a relative path
adjustImportPath(path.get("arguments")[0].node, relativePath);
},
},
};
}