heavily simplify system module formatter and share common code between them all
This commit is contained in:
@@ -1 +0,0 @@
|
||||
exports.VARIABLE_NAME = OBJECT.KEY;
|
||||
@@ -1 +0,0 @@
|
||||
exports.default = VALUE;
|
||||
@@ -1 +1,6 @@
|
||||
System.register(MODULE_NAME, MODULE_DEPENDENCIES, MODULE_BODY);
|
||||
System.register(MODULE_NAME, MODULE_DEPENDENCIES, function (EXPORT_IDENTIFIER) {
|
||||
return {
|
||||
setters: SETTERS,
|
||||
execute: EXECUTE
|
||||
};
|
||||
});
|
||||
|
||||
@@ -5,11 +5,11 @@ var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
function DefaultFormatter(file, illegalRemapping) {
|
||||
function DefaultFormatter(file) {
|
||||
this.file = file;
|
||||
|
||||
this.localExports = this.getLocalExports();
|
||||
this.remapAssignments(illegalRemapping);
|
||||
this.remapAssignments();
|
||||
}
|
||||
|
||||
DefaultFormatter.prototype.getLocalExports = function () {
|
||||
@@ -27,20 +27,21 @@ DefaultFormatter.prototype.getLocalExports = function () {
|
||||
return localExports;
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.remapAssignments = function (illegal) {
|
||||
var localExports = this.localExports;
|
||||
DefaultFormatter.prototype.remapExportAssignment = function (node) {
|
||||
return t.assignmentExpression(
|
||||
"=",
|
||||
node.left,
|
||||
t.assignmentExpression(
|
||||
node.operator,
|
||||
t.memberExpression(t.identifier("exports"), node.left),
|
||||
node.right
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
var remap = function (node) {
|
||||
return t.assignmentExpression(
|
||||
"=",
|
||||
node.left,
|
||||
t.assignmentExpression(
|
||||
node.operator,
|
||||
t.memberExpression(t.identifier("exports"), node.left),
|
||||
node.right
|
||||
)
|
||||
);
|
||||
};
|
||||
DefaultFormatter.prototype.remapAssignments = function () {
|
||||
var localExports = this.localExports;
|
||||
var self = this;
|
||||
|
||||
var throwIllegal = function (node) {
|
||||
// todo!!
|
||||
@@ -56,14 +57,8 @@ DefaultFormatter.prototype.remapAssignments = function (illegal) {
|
||||
enter: function (node, parent, scope) {
|
||||
if (t.isExportDeclaration(node)) return false;
|
||||
|
||||
if (t.isAssignmentExpression(node)) {
|
||||
if (isLocalReference(node, scope)) {
|
||||
if (illegal) {
|
||||
throwIllegal(node);
|
||||
} else {
|
||||
return remap(node);
|
||||
}
|
||||
}
|
||||
if (t.isAssignmentExpression(node) && isLocalReference(node, scope)) {
|
||||
return self.remapExportAssignment(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -124,33 +119,40 @@ DefaultFormatter.prototype._exportSpecifier = function (getRef, specifier, node,
|
||||
if (node.source) {
|
||||
if (t.isExportBatchSpecifier(specifier)) {
|
||||
// export * from "foo";
|
||||
nodes.push(util.template("exports-wildcard", {
|
||||
OBJECT: getRef()
|
||||
}, true));
|
||||
nodes.push(this._exportsWildcard(getRef()));
|
||||
} else {
|
||||
// export { foo } from "test";
|
||||
nodes.push(util.template("exports-assign-key", {
|
||||
VARIABLE_NAME: variableName,
|
||||
OBJECT: getRef(),
|
||||
KEY: specifier.id
|
||||
}, true));
|
||||
nodes.push(this._exportsAssign(
|
||||
t.getSpecifierName(specifier),
|
||||
t.memberExpression(getRef(), specifier.id)
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// export { foo };
|
||||
nodes.push(util.template("exports-assign", {
|
||||
VALUE: specifier.id,
|
||||
KEY: variableName
|
||||
}, true));
|
||||
nodes.push(this._exportsAssign(t.getSpecifierName(specifier), specifier.id));
|
||||
}
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype._exportsWildcard = function (objectIdentifier) {
|
||||
return util.template("exports-wildcard", {
|
||||
OBJECT: objectIdentifier
|
||||
}, true);
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype._exportsAssign = function (id, init) {
|
||||
return util.template("exports-assign", {
|
||||
VALUE: init,
|
||||
KEY: id
|
||||
}, true);
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.exportDeclaration = function (node, nodes) {
|
||||
var declar = node.declaration;
|
||||
|
||||
if (node.default) {
|
||||
nodes.push(util.template("exports-default", {
|
||||
VALUE: this._pushStatement(declar, nodes)
|
||||
}, true));
|
||||
nodes.push(
|
||||
this._exportsAssign(t.identifier("default"), this._pushStatement(declar, nodes))
|
||||
);
|
||||
} else {
|
||||
var assign;
|
||||
|
||||
@@ -158,20 +160,14 @@ DefaultFormatter.prototype.exportDeclaration = function (node, nodes) {
|
||||
for (var i in declar.declarations) {
|
||||
var decl = declar.declarations[i];
|
||||
|
||||
decl.init = util.template("exports-assign", {
|
||||
VALUE: decl.init,
|
||||
KEY: decl.id
|
||||
});
|
||||
decl.init = this._exportsAssign(decl.id, decl.init).expression;
|
||||
|
||||
var newDeclar = t.variableDeclaration(declar.kind, [decl]);
|
||||
if (i == 0) t.inherits(newDeclar, declar);
|
||||
nodes.push(newDeclar);
|
||||
}
|
||||
} else {
|
||||
assign = util.template("exports-assign", {
|
||||
VALUE: declar.id,
|
||||
KEY: declar.id
|
||||
}, true);
|
||||
assign = this._exportsAssign(declar.id, declar.id);
|
||||
|
||||
nodes.push(t.toStatement(declar));
|
||||
nodes.push(assign);
|
||||
|
||||
@@ -12,6 +12,14 @@ function AMDFormatter(file) {
|
||||
|
||||
util.inherits(AMDFormatter, DefaultFormatter);
|
||||
|
||||
AMDFormatter.prototype.buildDependencyLiterals = function () {
|
||||
var names = [];
|
||||
for (var name in this.ids) {
|
||||
names.push(t.literal(name));
|
||||
}
|
||||
return names;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the entire body in a `define` wrapper.
|
||||
*/
|
||||
@@ -22,10 +30,7 @@ AMDFormatter.prototype.transform = function (ast) {
|
||||
|
||||
// build an array of module names
|
||||
|
||||
var names = [t.literal("exports")];
|
||||
for (var name in this.ids) {
|
||||
names.push(t.literal(name));
|
||||
}
|
||||
var names = [t.literal("exports")].concat(this.buildDependencyLiterals());
|
||||
names = t.arrayExpression(names);
|
||||
|
||||
// build up define container
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module.exports = SystemFormatter;
|
||||
|
||||
var DefaultFormatter = require("./_default");
|
||||
var AMDFormatter = require("./amd");
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
@@ -11,235 +12,17 @@ var PRIVATE_MODULE_NAME_IDENTIFIER = t.identifier("__moduleName");
|
||||
var NULL_SETTER = t.literal(null);
|
||||
|
||||
function SystemFormatter(file) {
|
||||
DefaultFormatter.call(this, file, true);
|
||||
AMDFormatter.apply(this, arguments);
|
||||
|
||||
this.exportedStatements = [];
|
||||
this.moduleDependencies = {};
|
||||
this.importedVariables = {};
|
||||
this.moduleNameLiteral = t.literal(this.getModuleName());
|
||||
this.exportIdentifier = file.generateUidIdentifier("export");
|
||||
this.moduleNameLiteral = t.literal(this.getModuleName());
|
||||
this.exportIdentifier = file.generateUidIdentifier("export");
|
||||
}
|
||||
|
||||
util.inherits(SystemFormatter, DefaultFormatter);
|
||||
util.inherits(SystemFormatter, AMDFormatter);
|
||||
|
||||
SystemFormatter.prototype.importDeclaration =
|
||||
SystemFormatter.prototype.exportDeclaration = function (node, nodes) {
|
||||
nodes.push(node);
|
||||
};
|
||||
SystemFormatter.prototype.getModuleName = DefaultFormatter.prototype.getModuleName;
|
||||
|
||||
SystemFormatter.prototype.importSpecifier =
|
||||
SystemFormatter.prototype.exportSpecifier = function (specifier, node, nodes) {
|
||||
if (!nodes.length) nodes.push(node);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._makeExportStatements = function (args) {
|
||||
return t.expressionStatement(t.callExpression(this.exportIdentifier, args));
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.transform = function (ast) {
|
||||
var self = this;
|
||||
|
||||
// Post extraction of the import/export declaration
|
||||
traverse(ast, {
|
||||
enter: 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), undefined (for removing) or false.
|
||||
*/
|
||||
|
||||
function processTheNode(extractor) {
|
||||
var result = extractor.call(self, node);
|
||||
result = (result === undefined) ? [] : 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 self = this;
|
||||
|
||||
if (!(t.isImportDeclaration(node) && node.specifiers && node.specifiers.length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_.each(node.specifiers, function (specifier) {
|
||||
var variableName = t.getSpecifierName(specifier);
|
||||
|
||||
var right = SETTER_MODULE_NAMESPACE;
|
||||
if (!t.isImportBatchSpecifier(specifier)) {
|
||||
right = t.memberExpression(right, specifier.id);
|
||||
}
|
||||
self.importedVariables[variableName.name] = true;
|
||||
self._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 returnNode;
|
||||
|
||||
if (t.isFunction(declar)) {
|
||||
if (!declar.id) {
|
||||
declar.id = this.file.generateUidIdentifier("anonymous");
|
||||
}
|
||||
returnNode = t.toStatement(declar);
|
||||
declar = declar.id;
|
||||
}
|
||||
|
||||
this._addToExportStatements("default", declar);
|
||||
|
||||
return returnNode;
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._extractExportVariableDeclaration = function (node) {
|
||||
var self = this;
|
||||
var declar = node.declaration;
|
||||
|
||||
if (!(t.isExportDeclaration(node) && t.isVariableDeclaration(declar))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function separateDeclarationAndInit(memo, varDeclar) {
|
||||
memo.varDeclaration.push(_.omit(varDeclar, "init"));
|
||||
self._addToExportStatements(varDeclar.id.name, t.assignmentExpression("=", varDeclar.id, varDeclar.init));
|
||||
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 self = 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(self, specifier, node);
|
||||
return result === undefined || 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])
|
||||
);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._makeExportWildcard = function (objectIdentifier) {
|
||||
SystemFormatter.prototype._exportsWildcard = function (objectIdentifier) {
|
||||
var leftIdentifier = t.identifier("i");
|
||||
var valIdentifier = t.memberExpression(objectIdentifier, leftIdentifier, true);
|
||||
|
||||
@@ -256,83 +39,50 @@ SystemFormatter.prototype._makeExportWildcard = function (objectIdentifier) {
|
||||
return t.forInStatement(left, right, block);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._addImportStatement = function (name, importStatement) {
|
||||
this.moduleDependencies[name] = this.moduleDependencies[name] || [];
|
||||
importStatement && this.moduleDependencies[name].push(importStatement);
|
||||
SystemFormatter.prototype._exportsAssign = function (id, init, isExpression) {
|
||||
return this.buildExportCall(id.name, init, true);
|
||||
};
|
||||
|
||||
// Additional body content
|
||||
SystemFormatter.prototype.remapExportAssignment = function (node) {
|
||||
return this.buildExportCall(node.left.name, node);
|
||||
};
|
||||
|
||||
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.buildExportCall = function (id, init, isStatement) {
|
||||
var call = t.callExpression(this.exportIdentifier, [t.literal(id), init]);
|
||||
if (isStatement) {
|
||||
return t.expressionStatement(call);
|
||||
} else {
|
||||
return call;
|
||||
}
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._prependPrivateModuleName = function (ast) {
|
||||
// generate the __moduleName variable
|
||||
var moduleNameVariableNode = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(
|
||||
PRIVATE_MODULE_NAME_IDENTIFIER,
|
||||
this.moduleNameLiteral
|
||||
)
|
||||
]);
|
||||
SystemFormatter.prototype.buildRunnerSetters = function () {
|
||||
return t.arrayExpression(_.map(this.ids, function (uid) {
|
||||
var moduleIdentifier = t.identifier("m");
|
||||
|
||||
ast.program.body.splice(1, 0, moduleNameVariableNode);
|
||||
return t.functionExpression(null, [moduleIdentifier], t.blockStatement([
|
||||
t.assignmentExpression("=", uid, moduleIdentifier)
|
||||
]));
|
||||
}));
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._buildSetters = function () {
|
||||
// generate setters array expression elements
|
||||
return _.map(this.moduleDependencies, function (specs) {
|
||||
if (!specs.length) {
|
||||
return NULL_SETTER;
|
||||
}
|
||||
|
||||
return t.functionExpression(
|
||||
null, [SETTER_MODULE_NAMESPACE], t.blockStatement(specs)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._appendModuleReturnStatement = function (ast) {
|
||||
// generate the execute function expression
|
||||
var executeFunctionExpression = t.functionExpression(
|
||||
null, [], t.blockStatement(this.exportedStatements)
|
||||
);
|
||||
|
||||
// generate the execute function expression
|
||||
var settersArrayExpression = t.arrayExpression(this._buildSetters());
|
||||
|
||||
// generate the return statement
|
||||
var moduleReturnStatement = t.returnStatement(t.objectExpression([
|
||||
t.property("init", t.identifier("setters"), settersArrayExpression),
|
||||
t.property("init", t.identifier("execute"), executeFunctionExpression)
|
||||
]));
|
||||
|
||||
ast.program.body.push(moduleReturnStatement);
|
||||
};
|
||||
|
||||
SystemFormatter.prototype._wrapInSystemRegisterCallExpression = function (ast) {
|
||||
SystemFormatter.prototype.transform = function (ast) {
|
||||
var program = ast.program;
|
||||
var body = program.body;
|
||||
|
||||
var moduleDependencyNames = Object
|
||||
.keys(this.moduleDependencies)
|
||||
.map(t.literal);
|
||||
|
||||
var runner = util.template("system", {
|
||||
MODULE_NAME: this.moduleNameLiteral,
|
||||
MODULE_DEPENDENCIES: t.arrayExpression(moduleDependencyNames),
|
||||
MODULE_BODY: t.functionExpression(
|
||||
null,
|
||||
[this.exportIdentifier],
|
||||
t.blockStatement(body)
|
||||
)
|
||||
MODULE_DEPENDENCIES: t.arrayExpression(this.buildDependencyLiterals()),
|
||||
EXPORT_IDENTIFIER: this.exportIdentifier,
|
||||
SETTERS: this.buildRunnerSetters(),
|
||||
EXECUTE: t.functionExpression(null, [], t.blockStatement(program.body))
|
||||
}, true);
|
||||
|
||||
if (!_.isEmpty(this.ids)) {
|
||||
var handlerBody = runner.expression.arguments[2].body.body;
|
||||
handlerBody.unshift(t.variableDeclaration("var", _.map(this.ids, function (uid) {
|
||||
return t.variableDeclarator(uid);
|
||||
})));
|
||||
}
|
||||
|
||||
program.body = [runner];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user