264 lines
6.7 KiB
JavaScript

module.exports = DefaultFormatter;
var traverse = require("../../traverse");
var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
function DefaultFormatter(file) {
this.file = file;
this.localExports = this.getLocalExports();
this.localImports = this.getLocalImports();
this.remapAssignments();
this.checkImportAssignments();
}
DefaultFormatter.prototype.getLocalExports = function () {
var localExports = {};
traverse(this.file.ast, {
enter: function (node) {
var declar = node && node.declaration;
if (t.isExportDeclaration(node) && declar && t.isStatement(declar)) {
_.extend(localExports, t.getIds(declar, true));
}
}
});
return localExports;
};
DefaultFormatter.prototype.getLocalImports = function () {
var localImports = {};
traverse(this.file.ast, {
enter: function (node) {
if (t.isImportDeclaration(node)) {
_.extend(localImports, t.getIds(node, true));
}
}
});
return localImports;
};
DefaultFormatter.prototype.checkImportAssignments = function () {
var localImports = this.localImports;
var file = this.file;
var isLocalReference = function (node, scope) {
var localImport = localImports[node.name];
return t.isIdentifier(node) && localImport && localImport !== node;
};
var check = function (node) {
if (isLocalReference(node)) {
throw file.errorWithNode(node, "Illegal assignment of module import");
}
};
traverse(file.ast, {
enter: function (node, parent, scope) {
if (t.isAssignmentExpression(node)) {
var left = node.left;
if (t.isMemberExpression(left)) {
while (left.object) left = left.object;
}
check(left);
} if (t.isDeclaration(node)) {
_.each(t.getIds(node, true), check);
}
}
});
};
DefaultFormatter.prototype.remapExportAssignment = 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 isLocalReference = function (node, scope) {
var name = node.name;
return t.isIdentifier(node) && localExports[name] && localExports[name] === scope.get(name, true);
};
traverse(this.file.ast, {
enter: function (node, parent, scope) {
if (t.isUpdateExpression(node) && isLocalReference(node.argument, scope)) {
this.skip();
// expand to long file assignment expression
var assign = t.assignmentExpression(node.operator[0] + "=", node.argument, t.literal(1));
// remap this assignment expression
var remapped = self.remapExportAssignment(assign);
// we don't need to change the result
if (t.isExpressionStatement(parent) || node.prefix) {
return remapped;
}
var nodes = [];
nodes.push(remapped);
var operator;
if (node.operator === "--") {
operator = "+";
} else { // "++"
operator = "-";
}
nodes.push(t.binaryExpression(operator, node.argument, t.literal(1)));
return t.sequenceExpression(nodes);
}
if (t.isAssignmentExpression(node) && isLocalReference(node.left, scope)) {
this.skip();
return self.remapExportAssignment(node);
}
}
});
};
DefaultFormatter.prototype.getModuleName = function () {
var opts = this.file.opts;
var filenameRelative = opts.filenameRelative;
var moduleName = "";
if (opts.moduleRoot) {
moduleName = opts.moduleRoot + "/";
}
if (!opts.filenameRelative) {
return moduleName + opts.filename.replace(/^\//, "");
}
if (opts.sourceRoot) {
// remove sourceRoot from filename
var sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?");
filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
}
// remove extension
filenameRelative = filenameRelative.replace(/\.(.*?)$/, "");
moduleName += filenameRelative;
return moduleName;
};
DefaultFormatter.prototype._pushStatement = function (ref, nodes) {
if (t.isClass(ref) || t.isFunction(ref)) {
if (ref.id) {
nodes.push(t.toStatement(ref));
ref = ref.id;
}
}
return ref;
};
DefaultFormatter.prototype._hoistExport = function (declar, assign, priority) {
if (t.isFunctionDeclaration(declar)) {
assign._blockHoist = priority || 2;
}
return assign;
};
DefaultFormatter.prototype._exportSpecifier = function (getRef, specifier, node, nodes) {
var inherits = false;
if (node.specifiers.length === 1) inherits = node;
if (node.source) {
if (t.isExportBatchSpecifier(specifier)) {
// export * from "foo";
nodes.push(this._exportsWildcard(getRef(), node));
} else {
var ref;
if (t.isSpecifierDefault(specifier) && !this.noInteropRequire) {
// importing a default so we need to normalise it
ref = t.callExpression(this.file.addHelper("interop-require"), [getRef()]);
} else {
ref = t.memberExpression(getRef(), specifier.id);
}
// export { foo } from "test";
nodes.push(this._exportsAssign(
t.getSpecifierName(specifier),
ref,
node
));
}
} else {
// export { foo };
nodes.push(this._exportsAssign(t.getSpecifierName(specifier), specifier.id, node));
}
};
DefaultFormatter.prototype._exportsWildcard = function (objectIdentifier) {
return t.expressionStatement(t.callExpression(this.file.addHelper("exports-wildcard"), [
t.callExpression(this.file.addHelper("interop-require-wildcard"), [objectIdentifier])
]));
};
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;
var id = declar.id;
if (node.default) {
id = t.identifier("default");
}
var assign;
if (t.isVariableDeclaration(declar)) {
for (var i in declar.declarations) {
var decl = declar.declarations[i];
decl.init = this._exportsAssign(decl.id, decl.init, node).expression;
var newDeclar = t.variableDeclaration(declar.kind, [decl]);
if (i === "0") t.inherits(newDeclar, declar);
nodes.push(newDeclar);
}
} else {
var ref = declar;
if (t.isFunctionDeclaration(declar) || t.isClassDeclaration(declar)) {
ref = declar.id;
nodes.push(declar);
}
assign = this._exportsAssign(id, ref, node);
nodes.push(assign);
this._hoistExport(declar, assign);
}
};