system hoisting and export refinements (#8104)

This commit is contained in:
Guy Bedford 2018-06-12 19:45:53 +02:00 committed by Henry Zhu
parent 3c46e75b8f
commit 036c429ce1
22 changed files with 219 additions and 180 deletions

View File

@ -29,7 +29,7 @@ const visitor = {
}
for (const name in declar.getBindingIdentifiers()) {
state.emit(t.identifier(name), name);
state.emit(t.identifier(name), name, declar.node.init !== null);
}
}

View File

@ -21,6 +21,81 @@ const buildExportAll = template(`
}
`);
function constructExportCall(
path,
exportIdent,
exportNames,
exportValues,
exportStarTarget,
) {
const statements = [];
if (exportNames.length === 1) {
statements.push(
t.expressionStatement(
t.callExpression(exportIdent, [
t.stringLiteral(exportNames[0]),
exportValues[0],
]),
),
);
} else if (!exportStarTarget) {
const objectProperties = [];
for (let i = 0; i < exportNames.length; i++) {
const exportName = exportNames[i];
const exportValue = exportValues[i];
objectProperties.push(
t.objectProperty(t.identifier(exportName), exportValue),
);
}
statements.push(
t.expressionStatement(
t.callExpression(exportIdent, [t.objectExpression(objectProperties)]),
),
);
} else {
const exportObj = path.scope.generateUid("exportObj");
statements.push(
t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(exportObj), t.objectExpression([])),
]),
);
statements.push(
buildExportAll({
KEY: path.scope.generateUidIdentifier("key"),
EXPORT_OBJ: t.identifier(exportObj),
TARGET: exportStarTarget,
}),
);
for (let i = 0; i < exportNames.length; i++) {
const exportName = exportNames[i];
const exportValue = exportValues[i];
statements.push(
t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(
t.identifier(exportObj),
t.identifier(exportName),
),
exportValue,
),
),
);
}
statements.push(
t.expressionStatement(
t.callExpression(exportIdent, [t.identifier(exportObj)]),
),
);
}
return statements;
}
const TYPE_IMPORT = "Import";
export default declare((api, options) => {
@ -35,6 +110,25 @@ export default declare((api, options) => {
path.node[IGNORE_REASSIGNMENT_SYMBOL] = true;
const arg = path.get(path.isAssignmentExpression() ? "left" : "argument");
if (arg.isObjectPattern() || arg.isArrayPattern()) {
const exprs = [path.node];
for (const name in arg.getBindingIdentifiers()) {
if (this.scope.getBinding(name) !== path.scope.getBinding(name)) {
return;
}
const exportedNames = this.exports[name];
if (!exportedNames) return;
for (const exportedName of exportedNames) {
exprs.push(
this.buildCall(exportedName, t.identifier(name)).expression,
);
}
}
path.replaceWith(t.sequenceExpression(exprs));
return;
}
if (!arg.isIdentifier()) return;
const name = arg.node.name;
@ -163,17 +257,8 @@ export default declare((api, options) => {
const body: Array<Object> = path.get("body");
let canHoist = true;
for (let path of body) {
if (path.isExportDeclaration()) path = path.get("declaration");
if (path.isVariableDeclaration() && path.node.kind !== "var") {
canHoist = false;
break;
}
}
for (const path of body) {
if (canHoist && path.isFunctionDeclaration()) {
if (path.isFunctionDeclaration()) {
beforeBody.push(path.node);
removedPaths.push(path);
} else if (path.isImportDeclaration()) {
@ -206,7 +291,7 @@ export default declare((api, options) => {
);
}
if (!canHoist || declar.isClassDeclaration()) {
if (declar.isClassDeclaration()) {
path.replaceWithMultiple(nodes);
} else {
beforeBody = beforeBody.concat(nodes);
@ -221,29 +306,22 @@ export default declare((api, options) => {
if (declar.node) {
path.replaceWith(declar);
const nodes = [];
let bindingIdentifiers;
if (path.isFunction()) {
const node = declar.node;
const name = node.id.name;
if (canHoist) {
addExportName(name, name);
beforeBody.push(node);
beforeBody.push(
buildExportCall(name, t.cloneNode(node.id)),
);
beforeBody.push(buildExportCall(name, t.cloneNode(node.id)));
removedPaths.push(path);
} else {
bindingIdentifiers = { [name]: node.id };
}
} else {
bindingIdentifiers = declar.getBindingIdentifiers();
}
for (const name in bindingIdentifiers) {
} else if (path.isClass()) {
const name = declar.node.id.name;
addExportName(name, name);
path.insertAfter([buildExportCall(name, t.identifier(name))]);
} else {
for (const name in declar.getBindingIdentifiers()) {
addExportName(name, name);
nodes.push(buildExportCall(name, t.identifier(name)));
}
path.insertAfter(nodes);
}
} else {
const specifiers = path.node.specifiers;
if (specifiers && specifiers.length) {
@ -254,12 +332,15 @@ export default declare((api, options) => {
const nodes = [];
for (const specifier of specifiers) {
// only globals exported this way
if (!path.scope.getBinding(specifier.local.name)) {
nodes.push(
buildExportCall(
specifier.exported.name,
specifier.local,
),
);
}
addExportName(
specifier.local.name,
specifier.exported.name,
@ -274,7 +355,7 @@ export default declare((api, options) => {
}
modules.forEach(function(specifiers) {
const setterBody = [];
let setterBody = [];
const target = path.scope.generateUid(specifiers.key);
for (let specifier of specifiers.imports) {
@ -312,49 +393,30 @@ export default declare((api, options) => {
}
if (specifiers.exports.length) {
const exportObj = path.scope.generateUid("exportObj");
setterBody.push(
t.variableDeclaration("var", [
t.variableDeclarator(
t.identifier(exportObj),
t.objectExpression([]),
),
]),
);
const exportNames = [];
const exportValues = [];
let hasExportStar = false;
for (const node of specifiers.exports) {
if (t.isExportAllDeclaration(node)) {
setterBody.push(
buildExportAll({
KEY: path.scope.generateUidIdentifier("key"),
EXPORT_OBJ: t.identifier(exportObj),
TARGET: t.identifier(target),
}),
);
hasExportStar = true;
} else if (t.isExportSpecifier(node)) {
setterBody.push(
t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(
t.identifier(exportObj),
node.exported,
),
exportNames.push(node.exported.name);
exportValues.push(
t.memberExpression(t.identifier(target), node.local),
),
),
);
} else {
// todo
}
}
setterBody.push(
t.expressionStatement(
t.callExpression(t.identifier(exportIdent), [
t.identifier(exportObj),
]),
setterBody = setterBody.concat(
constructExportCall(
path,
t.identifier(exportIdent),
exportNames,
exportValues,
hasExportStar ? t.identifier(target) : null,
),
);
}
@ -372,9 +434,17 @@ export default declare((api, options) => {
let moduleName = this.getModuleName();
if (moduleName) moduleName = t.stringLiteral(moduleName);
if (canHoist) {
hoistVariables(path, id => variableIds.push(id));
const uninitializedVars = [];
hoistVariables(
path,
(id, name, hasInit) => {
variableIds.push(id);
if (!hasInit) {
uninitializedVars.push(name);
}
},
null,
);
if (variableIds.length) {
beforeBody.unshift(
@ -385,6 +455,23 @@ export default declare((api, options) => {
);
}
if (uninitializedVars.length) {
const undefinedValues = [];
const undefinedIdent = path.scope.buildUndefinedNode();
for (let i = 0; i < uninitializedVars.length; i++) {
undefinedValues[i] = undefinedIdent;
}
beforeBody = beforeBody.concat(
constructExportCall(
path,
t.identifier(exportIdent),
uninitializedVars,
undefinedValues,
null,
),
);
}
path.traverse(reassignmentVisitor, {
exports: exportNames,
buildCall: buildExportCall,

View File

@ -1,14 +1,11 @@
System.register([], function (_export, _context) {
"use strict";
var foo, bar;
return {
setters: [],
execute: function () {
const [foo, bar = 2] = [];
_export("foo", foo);
_export("bar", bar);
[foo, bar = 2] = [], _export("foo", foo), _export("bar", bar);
}
};
});

View File

@ -1,16 +1,11 @@
System.register([], function (_export, _context) {
"use strict";
var foo, bar, baz;
return {
setters: [],
execute: function () {
const [foo, bar, ...baz] = [];
_export("foo", foo);
_export("bar", bar);
_export("baz", baz);
[foo, bar, ...baz] = [], _export("foo", foo), _export("bar", bar), _export("baz", baz);
}
};
});

View File

@ -1,14 +1,11 @@
System.register([], function (_export, _context) {
"use strict";
var foo, bar;
return {
setters: [],
execute: function () {
const [foo, bar] = [];
_export("foo", foo);
_export("bar", bar);
[foo, bar] = [], _export("foo", foo), _export("bar", bar);
}
};
});

View File

@ -1,18 +1,15 @@
System.register([], function (_export, _context) {
"use strict";
var baz, qux;
return {
setters: [],
execute: function () {
const {
({
foo: {
bar: [baz, qux]
}
} = {};
_export("baz", baz);
_export("qux", qux);
} = {}), _export("baz", baz), _export("qux", qux);
}
};
});

View File

@ -1,17 +1,14 @@
System.register([], function (_export, _context) {
"use strict";
var foo, bar;
return {
setters: [],
execute: function () {
const {
({
foo,
bar = 1
} = {};
_export("foo", foo);
_export("bar", bar);
} = {}), _export("foo", foo), _export("bar", bar);
}
};
});

View File

@ -1,17 +1,14 @@
System.register([], function (_export, _context) {
"use strict";
var foo, bar;
return {
setters: [],
execute: function () {
const {
({
foo,
...bar
} = {};
_export("foo", foo);
_export("bar", bar);
} = {}), _export("foo", foo), _export("bar", bar);
}
};
});

View File

@ -1,17 +1,14 @@
System.register([], function (_export, _context) {
"use strict";
var bar, baz;
return {
setters: [],
execute: function () {
const {
({
foo: bar,
baz
} = {};
_export("bar", bar);
_export("baz", baz);
} = {}), _export("bar", bar), _export("baz", baz);
}
};
});

View File

@ -3,10 +3,7 @@ System.register(["foo"], function (_export, _context) {
return {
setters: [function (_foo) {
var _exportObj = {};
_exportObj.foo = _foo.foo;
_export(_exportObj);
_export("foo", _foo.foo);
}],
execute: function () {}
};

View File

@ -3,11 +3,10 @@ System.register(["foo"], function (_export, _context) {
return {
setters: [function (_foo) {
var _exportObj = {};
_exportObj.foo = _foo.foo;
_exportObj.bar = _foo.bar;
_export(_exportObj);
_export({
foo: _foo.foo,
bar: _foo.bar
});
}],
execute: function () {}
};

View File

@ -3,10 +3,7 @@ System.register(["foo"], function (_export, _context) {
return {
setters: [function (_foo) {
var _exportObj = {};
_exportObj.bar = _foo.foo;
_export(_exportObj);
_export("bar", _foo.foo);
}],
execute: function () {}
};

View File

@ -3,10 +3,7 @@ System.register(["foo"], function (_export, _context) {
return {
setters: [function (_foo) {
var _exportObj = {};
_exportObj.default = _foo.foo;
_export(_exportObj);
_export("default", _foo.foo);
}],
execute: function () {}
};

View File

@ -3,11 +3,10 @@ System.register(["foo"], function (_export, _context) {
return {
setters: [function (_foo) {
var _exportObj = {};
_exportObj.default = _foo.foo;
_exportObj.bar = _foo.bar;
_export(_exportObj);
_export({
default: _foo.foo,
bar: _foo.bar
});
}],
execute: function () {}
};

View File

@ -0,0 +1,12 @@
System.register([], function (_export, _context) {
"use strict";
var m;
_export("m", void 0);
return {
setters: [],
execute: function () {}
};
});

View File

@ -1,37 +1,28 @@
System.register([], function (_export, _context) {
"use strict";
return {
setters: [],
execute: function () {
var foo = 1;
_export("foo", foo);
var foo2 = function () {};
_export("foo2", foo2);
var foo3;
_export("foo3", foo3);
let foo4 = 2;
_export("foo4", foo4);
let foo5;
_export("foo5", foo5);
const foo6 = 3;
_export("foo6", foo6);
var foo, foo2, foo3, foo4, foo5, foo6;
function foo7() {}
_export("foo7", foo7);
_export({
foo3: void 0,
foo5: void 0
});
return {
setters: [],
execute: function () {
_export("foo", foo = 1);
_export("foo2", foo2 = function () {});
_export("foo4", foo4 = 2);
_export("foo6", foo6 = 3);
class foo8 {}
_export("foo8", foo8);

View File

@ -9,6 +9,8 @@ System.register(["./evens"], function (_export, _context) {
_export("nextOdd", nextOdd);
_export("a", void 0);
return {
setters: [function (_evens) {
isEven = _evens.isEven;
@ -16,8 +18,6 @@ System.register(["./evens"], function (_export, _context) {
execute: function () {
_export("p", p = 5);
_export("p", p);
for (a in b);
for (i = 0, j = 0;;);
@ -27,8 +27,6 @@ System.register(["./evens"], function (_export, _context) {
return !isEven(n);
};
}(isEven));
_export("isOdd", isOdd);
}
};
});

View File

@ -19,8 +19,6 @@ System.register([], function (_export, _context) {
execute: function () {
_export("c", c = 5);
_export("c", c);
b();
}
};

View File

@ -6,8 +6,6 @@ System.register([], function (_export, _context) {
setters: [],
execute: function () {
_export("name", name = _context.id);
_export("name", name);
}
};
});

View File

@ -14,8 +14,6 @@ System.register(["foo", "foo-bar", "./directory/foo-bar"], function (_export, _c
_export("test2", test2 = 5);
_export("test2", test2);
_export("default", test);
}
};

View File

@ -7,8 +7,6 @@ System.register([], function (_export, _context) {
execute: function () {
_export("test", test = 2);
_export("test", test);
_export("test", test = 5);
_export("test", +test + 1), test++;
@ -21,22 +19,14 @@ System.register([], function (_export, _context) {
_export("a", a = 2);
_export("a", a);
_export("a", a = 3);
_export("c", b = 2);
_export("c", b);
_export("c", b = 3);
_export("f", _export("e", d = 3));
_export("e", d);
_export("f", d);
_export("f", _export("e", d = 4));
}
};