dry up array comprehension and arrow functions by introducing an alias-functions transformer

This commit is contained in:
Sebastian McKenzie
2014-10-13 05:35:26 +11:00
parent a6ffde6e9b
commit 3d2c41bb5a
10 changed files with 132 additions and 81 deletions

View File

@@ -0,0 +1,77 @@
var traverse = require("../traverse");
var util = require("../util");
var b = require("ast-types").builders;
var go = function (getBody, node, file) {
var argumentsId;
var thisId;
var getArgumentsId = function () {
return argumentsId = argumentsId || b.identifier(file.generateUid("arguments"));
};
var getThisId = function () {
return thisId = thisId || b.identifier(file.generateUid("this"));
};
// traverse the function and find all alias functions so we can alias
// arguments and this if neccesary
traverse(node, function (node) {
if (!node._aliasFunction) {
if (traverse.isFunction(node)) {
// stop traversal of this node as it'll be hit again by this transformer
return false;
} else {
return;
}
}
// traverse all child nodes of this function and find arguments and this
traverse(node, function (node, parent) {
var getId;
if (node.type === "Identifier" && node.name === "arguments") {
getId = getArgumentsId;
} else if (node.type === "ThisExpression") {
getId = getThisId;
} else {
return;
}
if (util.isReferenced(node, parent)) return getId();
}, node._aliasFunctionStopNonArrowFunctions && ["FunctionExpression", "FunctionDeclaration"]);
return false;
});
var body;
var pushDeclaration = function (id, init) {
body = body || getBody();
body.unshift(b.variableDeclaration("var", [
b.variableDeclarator(id, init)
]));
};
if (argumentsId) {
pushDeclaration(argumentsId, b.identifier("arguments"));
}
if (thisId) {
pushDeclaration(thisId, b.identifier("this"));
}
};
exports.Program = function (node, parent, file) {
go(function () {
return node.body;
}, node, file);
};
exports.FunctionDeclaration =
exports.FunctionExpression = function (node, parent, file) {
go(function () {
util.ensureBlock(node);
return node.body.body;
}, node, file);
};

View File

@@ -9,12 +9,14 @@ var single = function (node) {
var templateName = "array-comprehension-map";
if (node.filter) templateName = "array-comprehension-filter";
return util.template(templateName, {
var result = util.template(templateName, {
STATEMENT: node.body,
FILTER: node.filter,
ARRAY: block.right,
KEY: block.left
});
result._aliasFunction = true;
return result;
};
var multiple = function (node, file) {
@@ -23,6 +25,7 @@ var multiple = function (node, file) {
var container = util.template("array-comprehension-container", {
KEY: uid
});
container._aliasFunction = true;
var block = container.callee.body;
var body = block.body;
@@ -47,7 +50,10 @@ var multiple = function (node, file) {
var filter = util.template("if", {
STATEMENT: node.filter
});
// set if body
filter.consequent.body = [child];
child = filter;
}
}
@@ -56,7 +62,10 @@ var multiple = function (node, file) {
ARRAY: self.right,
KEY: self.left
}, true);
// set function body
container2.expression.arguments[0].body.body = [child];
return container2;
};

View File

@@ -1,58 +1,12 @@
var traverse = require("../traverse");
var util = require("../util");
var b = require("ast-types").builders;
var util = require("../util");
exports.ArrowFunctionExpression = function (node, parent, file) {
exports.ArrowFunctionExpression = function (node) {
util.ensureBlock(node);
node._aliasFunction = true;
node._aliasFunctionStopNonArrowFunctions = true;
node.expression = false;
node.type = "FunctionExpression";
if (traverse.hasType(node, "ThisExpression")) {
return util.template("function-bind-this", {
FUNCTION: node
});
} else {
return node;
}
};
exports.FunctionDeclaration =
exports.FunctionExpression = function (node, parent, file) {
var argumentsId;
var isArgumentIdentifier = function (node) {
return node.type === "Identifier" && node.name === "arguments";
};
var getId = function () {
return argumentsId = argumentsId || b.identifier(file.generateUid("arguments"));
};
// traverse the function and find all arrow functions so we can alias
// arguments if neccesary
traverse(node, function (node) {
if (node.type !== "ArrowFunctionExpression") return;
// traverse all child nodes of this arrow function and find a sole arguments
// identifier
traverse(node, function (node, parent) {
if (isArgumentIdentifier(node) && parent.type !== "MemberExpression") {
return getId();
} else if (node.type === "MemberExpression" && isArgumentIdentifier(node.object)) {
node.object = getId();
} else {
return;
}
}, traverse.FUNCTION_TYPES);
return false;
}, ["FunctionDeclaration", "FunctionExpression"]);
if (argumentsId) {
util.ensureBlock(node);
node.body.body.unshift(b.variableDeclaration("var", [
b.variableDeclarator(argumentsId, b.identifier("arguments"))
]));
}
return node;
};

View File

@@ -23,19 +23,7 @@ exports.VariableDeclaration = function (node, parent, file) {
var id = ids[node.name];
if (!id) return;
// we're a property key
if (parent.type === "Property" && parent.key === node) return;
var isMemberExpression = parent.type === "MemberExpression";
// we're in a member expression and we're the computed property so we're referenced
var isComputedProperty = isMemberExpression && parent.property === node && parent.computed;
// we're in a member expression and we're the object so we're referenced
var isObject = isMemberExpression && parent.object === node;
// we are referenced
if (!isMemberExpression || isComputedProperty || isObject) return id;
if (util.isReferenced(node, parent)) return id;
};
var replace = function (node, parent) {
@@ -55,7 +43,7 @@ exports.VariableDeclaration = function (node, parent, file) {
b.returnStatement(node)
]
)
), letReferences)
), letReferences);
} else {
return false;
}