Merge branch 'feat-system-module-rewrite' of https://github.com/douglasduteil/6to5 into 2.0.0
Conflicts: lib/6to5/transformation/modules/system.js test/fixtures/transformation/es6-modules-system/exports-from/expected.js
This commit is contained in:
commit
987dc0692f
@ -210,7 +210,7 @@ result.ast;
|
||||
|
||||
All subsequent files required by node with the extensions `.es6` and `.js` will
|
||||
be transformed by 6to5. The polyfill specified in [Polyfill](polyfill.md) is
|
||||
also required.
|
||||
also required; but this is automatically loaded when using:
|
||||
|
||||
Source maps are automatically configured so if any errors a thrown then line
|
||||
number info is mapped and you'll get the correct source location.
|
||||
|
||||
@ -1,57 +1,349 @@
|
||||
module.exports = SystemFormatter;
|
||||
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var traverse = require("../../traverse");
|
||||
var _ = require("lodash");
|
||||
|
||||
var SETTER_MODULE_NAMESPACE = t.identifier("m");
|
||||
var NULL_SETTER = t.literal(null);
|
||||
var SETTER_MODULE_NAMESPACE = t.identifier("m");
|
||||
var PRIVATE_MODULE_NAME_IDENTIFIER = t.identifier("__moduleName");
|
||||
var DEFAULT_IDENTIFIER = t.identifier("default");
|
||||
var NULL_SETTER = t.literal(null);
|
||||
|
||||
function SystemFormatter(file) {
|
||||
this.moduleNameLiteral = null;
|
||||
this.exportedStatements = [];
|
||||
this.importedModule = {};
|
||||
this.moduleDependencies = {};
|
||||
this.importedVariables = {};
|
||||
|
||||
this.exportIdentifier = file.generateUidIdentifier("export");
|
||||
this.file = file;
|
||||
|
||||
/**
|
||||
* @type Function
|
||||
* @param {Array} args - The arguments of the "_export(...args)" function
|
||||
* @return {Object} The expression statement with the call expression.
|
||||
*/
|
||||
this._makeExportStatements = _.compose(
|
||||
t.expressionStatement,
|
||||
// will generate the call expression : _export(...args)
|
||||
_.partial(t.callExpression, this.exportIdentifier)
|
||||
);
|
||||
}
|
||||
|
||||
SystemFormatter.prototype.import =
|
||||
SystemFormatter.prototype.export = function (node, nodes) {
|
||||
nodes.push(node);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.importSpecifier =
|
||||
SystemFormatter.prototype.exportSpecifier = function (specifier, node, nodes) {
|
||||
if (!nodes.length) nodes.push(node);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.transform = function (ast) {
|
||||
var program = ast.program;
|
||||
var body = program.body;
|
||||
|
||||
var systemTransform = this;
|
||||
|
||||
// extract the module name
|
||||
var moduleName = this.file.opts.filename
|
||||
.replace(/^.*\//, "").replace(/\..*$/, "");
|
||||
this.moduleNameLiteral = t.literal(
|
||||
this.file.opts.filename.replace(/^.*\//, "").replace(/\..*$/, "")
|
||||
);
|
||||
|
||||
// build an array of module names
|
||||
var dependencies = Object.keys(this.importedModule).map(t.literal);
|
||||
// Post extraction of the import/export declaration
|
||||
traverse(ast, function (node) {
|
||||
var replacementNode = null;
|
||||
|
||||
/**
|
||||
* Process the current node with an extractor.
|
||||
* @param {Function} extractor Extract the node data
|
||||
* @returns {*} Can be a `node` (for replacement), void 0 (for removing)
|
||||
* or false.
|
||||
*/
|
||||
function processTheNode(extractor) {
|
||||
var result = extractor.call(systemTransform, node);
|
||||
result = (result === void 0) ? [] : result;
|
||||
replacementNode = result || replacementNode;
|
||||
return !!replacementNode;
|
||||
}
|
||||
|
||||
_.some([
|
||||
// Import
|
||||
SystemFormatter.prototype._extractImportSpecifiers,
|
||||
SystemFormatter.prototype._extractImport,
|
||||
|
||||
// Export
|
||||
SystemFormatter.prototype._extractExportDefault,
|
||||
SystemFormatter.prototype._extractExportVariableDeclaration,
|
||||
SystemFormatter.prototype._extractExportFunctionDeclaration,
|
||||
SystemFormatter.prototype._extractExportSpecifiers
|
||||
],
|
||||
processTheNode
|
||||
);
|
||||
|
||||
return replacementNode;
|
||||
});
|
||||
|
||||
// Other
|
||||
this._prependImportVariables(ast);
|
||||
this._prependPrivateModuleName(ast);
|
||||
this._appendModuleReturnStatement(ast);
|
||||
this._wrapInSystemRegisterCallExpression(ast);
|
||||
};
|
||||
|
||||
//
|
||||
// Import extraction
|
||||
//
|
||||
|
||||
SystemFormatter.prototype._extractImportSpecifiers = function (node) {
|
||||
|
||||
var systemTransform = this;
|
||||
|
||||
if (!(t.isImportDeclaration(node) && node.specifiers && node.specifiers.length )) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_.each(node.specifiers, function (specifier) {
|
||||
|
||||
var variableName = t.getSpecifierName(specifier);
|
||||
|
||||
if (specifier.default) {
|
||||
specifier.id = DEFAULT_IDENTIFIER;
|
||||
}
|
||||
|
||||
var right = SETTER_MODULE_NAMESPACE;
|
||||
if (!t.isImportBatchSpecifier(specifier)) {
|
||||
right = t.memberExpression(right, specifier.id);
|
||||
}
|
||||
systemTransform.importedVariables[variableName.name] = true;
|
||||
systemTransform._addImportStatement(node.source.value, t.expressionStatement(
|
||||
t.assignmentExpression("=", variableName, right)
|
||||
));
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractImport = function (node) {
|
||||
if (!(t.isImportDeclaration(node))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._addImportStatement(node.source.value);
|
||||
};
|
||||
|
||||
//
|
||||
// Export extraction
|
||||
//
|
||||
|
||||
SystemFormatter.prototype._extractExportDefault = function (node) {
|
||||
if (!(t.isExportDeclaration(node) && node.default)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var declar = node.declaration;
|
||||
var variableName = DEFAULT_IDENTIFIER.name;
|
||||
var returnNode;
|
||||
|
||||
if (t.isFunction(declar)) {
|
||||
if (!declar.id) {
|
||||
declar.id = this.file.generateUidIdentifier("anonymous");
|
||||
}
|
||||
returnNode = t.toStatement(declar);
|
||||
declar = declar.id;
|
||||
}
|
||||
|
||||
this._addToExportStatements(variableName, declar);
|
||||
|
||||
return returnNode;
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractExportVariableDeclaration = function (node) {
|
||||
var systemTransform = this;
|
||||
var declar = node.declaration;
|
||||
|
||||
if (!(t.isExportDeclaration(node) && t.isVariableDeclaration(declar))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function separateDeclarationAndInit(memo, varDeclar) {
|
||||
memo.varDeclaration.push(_.omit(varDeclar, "init"));
|
||||
systemTransform._addToExportStatements(varDeclar.id.name, varDeclar);
|
||||
return memo;
|
||||
}
|
||||
|
||||
var declarationSeparation = _.reduce(
|
||||
declar.declarations,
|
||||
separateDeclarationAndInit,
|
||||
{ varDeclaration: [], varInitialization: [] }
|
||||
);
|
||||
|
||||
return _.assign(declar, { declarations: declarationSeparation.varDeclaration });
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractExportFunctionDeclaration = function (node) {
|
||||
var declar = node.declaration;
|
||||
|
||||
if (!(t.isExportDeclaration(node) && t.isFunctionDeclaration(declar))) {
|
||||
return false;
|
||||
}
|
||||
this._addToExportStatements(declar.id.name, declar.id);
|
||||
return declar;
|
||||
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractExportSpecifiers = function (node) {
|
||||
var systemTransform = this;
|
||||
|
||||
if (!( t.isExportDeclaration(node) && node.specifiers )) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_.each(node.specifiers, function (specifier) {
|
||||
|
||||
// Run each, break when one is true.
|
||||
_.some([
|
||||
SystemFormatter.prototype._extractExportBatch,
|
||||
SystemFormatter.prototype._extractExportFrom,
|
||||
SystemFormatter.prototype._extractExportNamed
|
||||
], function (extractor) {
|
||||
var result = extractor.call(systemTransform, specifier, node);
|
||||
return result === void 0 || result;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Note: here we don't care about the node replacement.
|
||||
// The current node will always be removed.
|
||||
// So no return.
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractExportBatch = function (specifier, node) {
|
||||
|
||||
if (!(node.source && t.isExportBatchSpecifier(specifier))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var exportBatch = this._makeExportWildcard(SETTER_MODULE_NAMESPACE);
|
||||
this._addImportStatement(node.source.value, exportBatch);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractExportFrom = function (specifier, node) {
|
||||
|
||||
// Weak test here...
|
||||
if (!(node.source)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var variableName = t.getSpecifierName(specifier);
|
||||
|
||||
var target = t.memberExpression(
|
||||
SETTER_MODULE_NAMESPACE,
|
||||
specifier.id
|
||||
);
|
||||
|
||||
var exportSelection = this._makeExportStatements([
|
||||
t.literal(variableName.name), target
|
||||
]);
|
||||
|
||||
this._addImportStatement(node.source.value, exportSelection);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractExportNamed = function (specifier) {
|
||||
|
||||
// Last case...
|
||||
// Dunno what to test here...
|
||||
|
||||
var variableName = t.getSpecifierName(specifier);
|
||||
this._addToExportStatements(variableName.name, specifier.id);
|
||||
};
|
||||
|
||||
//
|
||||
// Utils collection handler
|
||||
//
|
||||
|
||||
SystemFormatter.prototype._addToExportStatements = function (name, identifier) {
|
||||
this.exportedStatements.push(
|
||||
this._makeExportStatements([t.literal(name), identifier])
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a export wildcard expression
|
||||
* /!\ this is a hack over the existing "exports-wildcard" template
|
||||
* @param objectIdentifier
|
||||
* @returns the export wildcard expression
|
||||
* @private
|
||||
*/
|
||||
SystemFormatter.prototype._makeExportWildcard = function (objectIdentifier) {
|
||||
|
||||
var exportStatement = util.template("exports-wildcard", {
|
||||
OBJECT: objectIdentifier
|
||||
}, true);
|
||||
|
||||
delete exportStatement.expression.callee.expression._scopeReferences;
|
||||
|
||||
var forStatement = exportStatement.expression.callee.expression.body.body[0];
|
||||
var iteratorIdentifier = forStatement.left.declarations[0].id;
|
||||
var target = t.memberExpression(
|
||||
forStatement.right,
|
||||
iteratorIdentifier,
|
||||
true
|
||||
);
|
||||
|
||||
forStatement.body.body = [
|
||||
this._makeExportStatements([iteratorIdentifier, target])
|
||||
];
|
||||
|
||||
return exportStatement;
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._addImportStatement = function (name, importStatement) {
|
||||
this.moduleDependencies[name] = this.moduleDependencies[name] || [];
|
||||
importStatement && this.moduleDependencies[name].push(importStatement);
|
||||
};
|
||||
|
||||
//
|
||||
// Additional body content
|
||||
//
|
||||
|
||||
SystemFormatter.prototype._prependImportVariables = function (ast) {
|
||||
|
||||
var declaredSetters = _(this.importedVariables).keys().map(function (name) {
|
||||
return _.compose(t.variableDeclarator, t.identifier)(name);
|
||||
}
|
||||
).value();
|
||||
|
||||
if (declaredSetters.length) {
|
||||
ast.program.body.splice(1, 0, t.variableDeclaration("var", declaredSetters));
|
||||
}
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._prependPrivateModuleName = function (ast) {
|
||||
// generate the __moduleName variable
|
||||
var moduleNameVariableNode = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(
|
||||
t.identifier("__moduleName"),
|
||||
t.literal(moduleName)
|
||||
PRIVATE_MODULE_NAME_IDENTIFIER,
|
||||
this.moduleNameLiteral
|
||||
)
|
||||
]);
|
||||
body.splice(1, 0, moduleNameVariableNode);
|
||||
|
||||
// generate an array of import variables
|
||||
ast.program.body.splice(1, 0, moduleNameVariableNode);
|
||||
};
|
||||
|
||||
var declaredSetters = _(this.importedModule)
|
||||
.map()
|
||||
.flatten()
|
||||
.pluck("variableName")
|
||||
.pluck("name")
|
||||
.uniq()
|
||||
.map(t.identifier)
|
||||
.map(function (name) {
|
||||
return t.variableDeclarator(name);
|
||||
})
|
||||
.value();
|
||||
SystemFormatter.prototype._buildSetters = function () {
|
||||
// generate setters array expression elements
|
||||
return _.map(this.moduleDependencies, function (specs) {
|
||||
if (!specs.length) {
|
||||
return NULL_SETTER;
|
||||
}
|
||||
|
||||
if (declaredSetters.length) {
|
||||
body.splice(2, 0, t.variableDeclaration("var", declaredSetters));
|
||||
}
|
||||
return t.functionExpression(
|
||||
null, [SETTER_MODULE_NAMESPACE], t.blockStatement(specs)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._appendModuleReturnStatement = function (ast) {
|
||||
|
||||
// generate the execute function expression
|
||||
var executeFunctionExpression = t.functionExpression(
|
||||
@ -66,12 +358,21 @@ SystemFormatter.prototype.transform = function (ast) {
|
||||
t.property("init", t.identifier("setters"), settersArrayExpression),
|
||||
t.property("init", t.identifier("execute"), executeFunctionExpression)
|
||||
]));
|
||||
body.push(moduleReturnStatement);
|
||||
|
||||
// runner
|
||||
ast.program.body.push(moduleReturnStatement);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._wrapInSystemRegisterCallExpression = function (ast) {
|
||||
var program = ast.program;
|
||||
var body = program.body;
|
||||
|
||||
var moduleDependencyNames = Object
|
||||
.keys(this.moduleDependencies)
|
||||
.map(t.literal);
|
||||
|
||||
var runner = util.template("register", {
|
||||
MODULE_NAME: t.literal(moduleName),
|
||||
MODULE_DEPENDENCIES: t.arrayExpression(dependencies),
|
||||
MODULE_NAME: this.moduleNameLiteral,
|
||||
MODULE_DEPENDENCIES: t.arrayExpression(moduleDependencyNames),
|
||||
MODULE_BODY: t.functionExpression(
|
||||
null,
|
||||
[this.exportIdentifier],
|
||||
@ -81,118 +382,3 @@ SystemFormatter.prototype.transform = function (ast) {
|
||||
|
||||
program.body = [t.expressionStatement(runner)];
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._buildSetters = function () {
|
||||
// generate setters array expression elements
|
||||
return _.map(this.importedModule, function (specs) {
|
||||
if (!specs.length) {
|
||||
return NULL_SETTER;
|
||||
}
|
||||
|
||||
var expressionStatements = _.map(specs, function (spec) {
|
||||
var right = SETTER_MODULE_NAMESPACE;
|
||||
if (!spec.isBatch) {
|
||||
right = t.memberExpression(right, spec.key);
|
||||
}
|
||||
|
||||
return t.expressionStatement(
|
||||
t.assignmentExpression("=", spec.variableName, right
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
return t.functionExpression(
|
||||
null, [SETTER_MODULE_NAMESPACE], t.blockStatement(expressionStatements)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.import = function (node) {
|
||||
var MODULE_NAME = node.source.value;
|
||||
this.importedModule[MODULE_NAME] = this.importedModule[MODULE_NAME] || [];
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.importSpecifier = function (specifier, node) {
|
||||
var variableName = t.getSpecifierName(specifier);
|
||||
|
||||
// import foo from "foo";
|
||||
|
||||
var MODULE_NAME = node.source.value;
|
||||
|
||||
this.importedModule[MODULE_NAME] = this.importedModule[MODULE_NAME] || [];
|
||||
|
||||
this.importedModule[MODULE_NAME].push({
|
||||
variableName: variableName,
|
||||
isBatch: specifier.type === "ImportBatchSpecifier",
|
||||
key: specifier.id
|
||||
});
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._export = function (name, identifier) {
|
||||
this.exportedStatements.push(t.expressionStatement(
|
||||
t.callExpression(this.exportIdentifier, [t.literal(name), identifier])
|
||||
));
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.export = function (node, nodes) {
|
||||
var declar = node.declaration;
|
||||
var variableName, identifier;
|
||||
|
||||
if (node.default) {
|
||||
// export default foo
|
||||
variableName = DEFAULT_IDENTIFIER.name;
|
||||
if (t.isClass(declar) || t.isFunction(declar)) {
|
||||
if (!declar.id) {
|
||||
declar.id = this.file.generateUidIdentifier("anonymous");
|
||||
}
|
||||
|
||||
nodes.push(t.toStatement(declar));
|
||||
declar = declar.id;
|
||||
}
|
||||
|
||||
identifier = declar;
|
||||
} else if (t.isVariableDeclaration(declar)) {
|
||||
// export var foo
|
||||
variableName = declar.declarations[0].id.name;
|
||||
identifier = declar.declarations[0].id;
|
||||
|
||||
nodes.push(declar);
|
||||
} else {
|
||||
// export function foo () {}
|
||||
variableName = declar.id.name;
|
||||
identifier = declar.id;
|
||||
|
||||
nodes.push(declar);
|
||||
}
|
||||
|
||||
this._export(variableName, identifier);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.exportSpecifier = function (specifier, node) {
|
||||
var variableName = t.getSpecifierName(specifier);
|
||||
|
||||
if (node.source) {
|
||||
if (t.isExportBatchSpecifier(specifier)) {
|
||||
// export * from "foo";
|
||||
var exportIdentifier = t.identifier("exports");
|
||||
this.exportedStatements.push(
|
||||
t.variableDeclaration("var", [
|
||||
t.variableDeclarator(exportIdentifier, this.exportIdentifier)
|
||||
])
|
||||
);
|
||||
|
||||
this.exportedStatements.push(util.template("exports-wildcard", {
|
||||
OBJECT: t.identifier(node.source.value)
|
||||
}, true));
|
||||
} else {
|
||||
// export { foo } from "test";
|
||||
this._export(variableName.name, t.memberExpression(
|
||||
t.identifier(node.source.value),
|
||||
specifier.id
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// export { foo };
|
||||
this._export(variableName.name, specifier.id);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
System.register("actual", ["foo"], function (_export) {
|
||||
"use strict";
|
||||
|
||||
var __moduleName = "actual";
|
||||
|
||||
var _localExports = ['foo', 'bar', 'default'];
|
||||
|
||||
return {
|
||||
setters: [
|
||||
function(m) {
|
||||
_export("foo", m.foo);
|
||||
|
||||
_export("foo", m.foo);
|
||||
|
||||
_export("bar", m.bar);
|
||||
|
||||
_export("bar", m.foo);
|
||||
|
||||
_export("default", m.foo);
|
||||
|
||||
_export("default", m.foo);
|
||||
|
||||
_export("bar", m.bar);
|
||||
|
||||
for (var p in m) {
|
||||
if (_localExports.indexOf(i) == -1)
|
||||
_export(p, m[p]);
|
||||
}
|
||||
}
|
||||
],
|
||||
execute: function () {}
|
||||
};
|
||||
});
|
||||
@ -5,10 +5,8 @@ System.register("actual", [], function (_export) {
|
||||
|
||||
function _anonymous() {}
|
||||
var _anonymous2;
|
||||
|
||||
function foo() {}
|
||||
var Foo;
|
||||
|
||||
return {
|
||||
setters: [],
|
||||
execute: function () {
|
||||
@ -1,11 +1,16 @@
|
||||
System.register("actual", [], function (_export) {
|
||||
System.register("actual", ["foo"], function (_export) {
|
||||
"use strict";
|
||||
|
||||
var __moduleName = "actual";
|
||||
|
||||
return {
|
||||
setters: [
|
||||
function(m) {
|
||||
setters: [function (m) {
|
||||
(function (obj) {
|
||||
for (var i in obj) {
|
||||
_export(i, obj[i]);
|
||||
}
|
||||
})(m);
|
||||
|
||||
_export("foo", m.foo);
|
||||
|
||||
_export("foo", m.foo);
|
||||
@ -20,7 +25,6 @@ System.register("actual", [], function (_export) {
|
||||
|
||||
_export("bar", m.bar);
|
||||
}],
|
||||
execute: function () {
|
||||
}
|
||||
execute: function () {}
|
||||
};
|
||||
});
|
||||
24
test/fixtures/transformation/es6-modules-system/exports-named/expected.js
vendored
Normal file
24
test/fixtures/transformation/es6-modules-system/exports-named/expected.js
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
System.register("actual", [], function (_export) {
|
||||
"use strict";
|
||||
|
||||
var __moduleName = "actual";
|
||||
|
||||
return {
|
||||
setters: [],
|
||||
execute: function () {
|
||||
_export("foo", foo);
|
||||
|
||||
_export("foo", foo);
|
||||
|
||||
_export("bar", bar);
|
||||
|
||||
_export("bar", foo);
|
||||
|
||||
_export("default", foo);
|
||||
|
||||
_export("default", foo);
|
||||
|
||||
_export("bar", bar);
|
||||
}
|
||||
};
|
||||
});
|
||||
@ -13,7 +13,6 @@ System.register("actual", [], function (_export) {
|
||||
_export("foo7", foo7);
|
||||
|
||||
var foo8;
|
||||
|
||||
return {
|
||||
setters: [],
|
||||
execute: function () {
|
||||
Loading…
x
Reference in New Issue
Block a user