Fix "module" external helpers output (#6377)

* Move namespace init.

* Move call to helper generation.

* Generate named module exports properly.

* Ensure that helper names are valid identifiers.
This commit is contained in:
Logan Smyth 2017-10-03 13:58:47 -07:00 committed by GitHub
parent 68182bd69f
commit 5ea54f6cac

View File

@ -3,8 +3,6 @@ import generator from "babel-generator";
import template from "babel-template"; import template from "babel-template";
import * as t from "babel-types"; import * as t from "babel-types";
const keywordHelpers = ["typeof", "extends", "instanceof"];
const buildUmdWrapper = template(` const buildUmdWrapper = template(`
(function (root, factory) { (function (root, factory) {
if (typeof define === "function" && define.amd) { if (typeof define === "function" && define.amd) {
@ -19,7 +17,9 @@ const buildUmdWrapper = template(`
}); });
`); `);
function buildGlobal(namespace, builder) { function buildGlobal(whitelist) {
const namespace = t.identifier("babelHelpers");
const body = []; const body = [];
const container = t.functionExpression( const container = t.functionExpression(
null, null,
@ -56,55 +56,30 @@ function buildGlobal(namespace, builder) {
]), ]),
); );
builder(body); buildHelpers(body, namespace, whitelist);
return tree; return tree;
} }
function buildModule(namespace, builder) { function buildModule(whitelist) {
const body = []; const body = [];
builder(body); const refs = buildHelpers(body, null, whitelist);
const module = body.map(helperNode => { body.unshift(
const possibleAssignment = t.isExpressionStatement(helperNode) t.exportNamedDeclaration(
? helperNode.expression null,
: helperNode; Object.keys(refs).map(name => {
return t.exportSpecifier(t.clone(refs[name]), t.identifier(name));
}),
),
);
const isExportedHelper = return t.program(body, [], "module");
t.isAssignmentExpression(possibleAssignment) &&
t.isMemberExpression(possibleAssignment.left) &&
possibleAssignment.left.object.name === namespace.name;
if (!isExportedHelper) {
return helperNode;
}
const exportedHelper = possibleAssignment;
const identifier = exportedHelper.left.property.name;
const isKeywordHelper = keywordHelpers.indexOf(identifier) !== -1;
if (isKeywordHelper) {
return t.exportNamedDeclaration(null, [
t.exportSpecifier(
t.identifier(`_${identifier}`),
t.identifier(identifier),
),
]);
}
return t.exportNamedDeclaration(
t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(identifier), exportedHelper.right),
]),
[],
);
});
return t.program(module);
} }
function buildUmd(namespace, builder) { function buildUmd(whitelist) {
const namespace = t.identifier("babelHelpers");
const body = []; const body = [];
body.push( body.push(
t.variableDeclaration("var", [ t.variableDeclaration("var", [
@ -112,7 +87,7 @@ function buildUmd(namespace, builder) {
]), ]),
); );
builder(body); buildHelpers(body, namespace, whitelist);
return t.program([ return t.program([
buildUmdWrapper({ buildUmdWrapper({
@ -130,7 +105,9 @@ function buildUmd(namespace, builder) {
]); ]);
} }
function buildVar(namespace, builder) { function buildVar(whitelist) {
const namespace = t.identifier("babelHelpers");
const body = []; const body = [];
body.push( body.push(
t.variableDeclaration("var", [ t.variableDeclaration("var", [
@ -138,37 +115,34 @@ function buildVar(namespace, builder) {
]), ]),
); );
const tree = t.program(body); const tree = t.program(body);
builder(body); buildHelpers(body, namespace, whitelist);
body.push(t.expressionStatement(namespace)); body.push(t.expressionStatement(namespace));
return tree; return tree;
} }
function buildHelpers(body, namespace, whitelist) { function buildHelpers(body, namespace, whitelist) {
const getHelperReference = name => const getHelperReference = name => {
t.memberExpression(namespace, t.identifier(name)); return namespace
? t.memberExpression(namespace, t.identifier(name))
: t.identifier(`_${name}`);
};
const refs = {};
helpers.list.forEach(function(name) { helpers.list.forEach(function(name) {
if (whitelist && whitelist.indexOf(name) < 0) return; if (whitelist && whitelist.indexOf(name) < 0) return;
const { nodes } = helpers.get( const ref = (refs[name] = getHelperReference(name));
name,
getHelperReference, const { nodes } = helpers.get(name, getHelperReference, ref);
getHelperReference(name),
);
body.push(...nodes); body.push(...nodes);
}); });
return refs;
} }
export default function( export default function(
whitelist?: Array<string>, whitelist?: Array<string>,
outputType: "global" | "module" | "umd" | "var" = "global", outputType: "global" | "module" | "umd" | "var" = "global",
) { ) {
const namespace = t.identifier("babelHelpers");
const builder = function(body) {
return buildHelpers(body, namespace, whitelist);
};
let tree; let tree;
const build = { const build = {
@ -179,7 +153,7 @@ export default function(
}[outputType]; }[outputType];
if (build) { if (build) {
tree = build(namespace, builder); tree = build(whitelist);
} else { } else {
throw new Error(`Unsupported output type ${outputType}`); throw new Error(`Unsupported output type ${outputType}`);
} }