move whitespace and parentheses generation logic into separate files

This commit is contained in:
Sebastian McKenzie
2014-11-12 00:11:34 +11:00
parent b5bdba46f1
commit 3d5d170eff
4 changed files with 303 additions and 294 deletions

View File

@@ -0,0 +1,93 @@
module.exports = Node;
var whitespace = require("./whitespace");
var parens = require("./parentheses");
var t = require("../../types");
var _ = require("lodash");
var find = function (obj, node, parent) {
var result;
_.each(obj, function (fn, type) {
if (t["is" + type](node)) {
result = fn(node, parent);
if (result != null) return false;
}
});
return result;
};
function Node(node, parent) {
this.parent = parent;
this.node = node;
}
Node.prototype.isUserWhitespacable = function () {
//var parent = this.parent;
var node = this.node;
if (t.isUserWhitespacable(node)) {
return true;
}
//if (t.isArrayExpression(parent)) {
// return true;
//}
return false;
};
Node.prototype.needsWhitespace = function (type) {
var parent = this.parent;
var node = this.node;
if (!node) return 0;
if (t.isExpressionStatement(node)) {
node = node.expression;
}
var lines = find(whitespace[type].nodes, node, parent);
if (lines) return lines;
_.each(find(whitespace[type].list, node, parent), function (expr) {
lines = Node.needsWhitespace(expr, node, type);
if (lines) return false;
});
if (lines) return lines;
var opts = whitespace.static[node.type];
return (opts && opts[type]) || 0;
};
Node.prototype.needsWhitespaceBefore = function () {
return this.needsWhitespace("before");
};
Node.prototype.needsWhitespaceAfter = function () {
return this.needsWhitespace("after");
};
Node.prototype.needsParens = function () {
var parent = this.parent;
var node = this.node;
if (!parent) return false;
if (t.isNewExpression(parent) && parent.callee === node) {
return t.isCallExpression(node) || _.some(node, function (val) {
return t.isCallExpression(val);
});
}
return find(parens, node, parent);
};
_.each(Node.prototype, function (fn, key) {
Node[key] = function (node, parent) {
var n = new Node(node, parent);
var args = _.toArray(arguments).slice(2);
return n[key].apply(n, args);
};
});

View File

@@ -0,0 +1,151 @@
var Node = require("./index");
var t = require("../../types");
var _ = require("lodash");
var PRECEDENCE = {};
_.each([
["||"],
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%"]
], function (tier, i) {
_.each(tier, function (op) {
PRECEDENCE[op] = i;
});
});
exports.Binary = function (node, parent) {
if (t.isCallExpression(parent) && parent.callee === node) {
return true;
}
if (t.isUnaryLike(parent)) {
return true;
}
if (t.isMemberExpression(parent) && parent.object === node) {
return true;
}
if (t.isBinary(parent)) {
var parentOp = parent.operator;
var parentPos = PRECEDENCE[parentOp];
var nodeOp = node.operator;
var nodePos = PRECEDENCE[nodeOp];
if (parentPos > nodePos) {
return true;
}
if (parentPos === nodePos && parent.right === node) {
return true;
}
}
};
exports.BinaryExpression = function (node, parent) {
if (node.operator === "in") {
// var i = (1 in []);
if (t.isVariableDeclarator(parent)) {
return true;
}
// for ((1 in []);;);
if (t.isFor(parent)) {
return true;
}
}
};
exports.SequenceExpression = function (node, parent) {
if (t.isForStatement(parent)) {
// Although parentheses wouldn't hurt around sequence
// expressions in the head of for loops, traditional style
// dictates that e.g. i++, j++ should not be wrapped with
// parentheses.
return false;
}
if (t.isExpressionStatement(parent) && parent.expression === node) {
return false;
}
// Otherwise err on the side of overparenthesization, adding
// explicit exceptions above if this proves overzealous.
return true;
};
exports.YieldExpression = function (node, parent) {
return t.isBinary(parent) ||
t.isUnaryLike(parent) ||
t.isCallExpression(parent) ||
t.isMemberExpression(parent) ||
t.isNewExpression(parent) ||
t.isConditionalExpression(parent) ||
t.isYieldExpression(parent);
};
exports.Literal = function (node, parent) {
// (1).valueOf()
if (_.isNumber(node.value) && t.isMemberExpression(parent) && parent.object === node) {
return true;
}
};
exports.ClassExpression = function (node, parent) {
return t.isExpressionStatement(parent);
};
exports.UnaryLike = function (node, parent) {
return t.isMemberExpression(parent) && parent.object === node;
};
exports.FunctionExpression = function (node, parent) {
// function () {};
if (t.isExpressionStatement(parent)) {
return true;
}
// (function test() {}).name;
if (t.isMemberExpression(parent) && parent.object === node) {
return true;
}
// (function () {})();
if (t.isCallExpression(parent) && parent.callee === node) {
return true;
}
};
exports.AssignmentExpression =
exports.ConditionalExpression = function (node, parent) {
if (t.isUnaryLike(parent)) {
return true;
}
if (t.isBinary(parent)) {
return true;
}
if (t.isCallExpression(parent) && parent.callee === node) {
return true;
}
if (t.isConditionalExpression(parent) && parent.test === node) {
return true;
}
if (t.isMemberExpression(parent) && parent.object === node) {
return true;
}
return false;
};

View File

@@ -0,0 +1,59 @@
var _ = require("lodash");
var t = require("../../types");
exports.static = {
FunctionExpression: 1,
FunctionStatement: 1,
ClassExpression: 1,
ClassStatement: 1,
ForOfStatement: 1,
ForInStatement: 1,
ForStatement: 1,
SwitchStatement: 1,
IfStatement: { before: 1 },
CallExpression: { after: 1 },
Literal: { after: 1 }
};
_.each(exports.static, function (amounts, type) {
if (_.isNumber(amounts)) amounts = { after: amounts, before: amounts };
exports.static[type] = amounts;
});
exports.before = {
nodes: {
Property: function (node, parent) {
if (parent.properties[0] === node) {
return 1;
}
},
SwitchCase: function (node, parent) {
if (parent.cases[0] === node) {
return 1;
}
},
CallExpression: function (node, parent) {
if (t.isFunction(node.callee)) {
return 1;
}
}
}
};
exports.after = {
list: {
VariableDeclaration: function (node) {
return _.map(node.declarations, "init");;
},
ArrayExpression: function (node) {
return node.elements;
},
ObjectExpression: function (node) {
return node.properties;
}
}
};