mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
7.6 KiB
205 lines
7.6 KiB
10 years ago
|
/**
|
||
|
* @fileoverview Rule to flag block statements that do not use the one true brace style
|
||
|
* @author Ian Christian Myers
|
||
|
*/
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Rule Definition
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
module.exports = function(context) {
|
||
|
var style = context.options[0] || "1tbs";
|
||
|
var params = context.options[1] || {};
|
||
|
|
||
|
var OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.",
|
||
|
BODY_MESSAGE = "Statement inside of curly braces should be on next line.",
|
||
|
CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.",
|
||
|
CLOSE_MESSAGE_SINGLE = "Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.",
|
||
|
CLOSE_MESSAGE_STROUSTRUP = "Closing curly brace appears on the same line as the subsequent block.";
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// Helpers
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Determines if a given node is a block statement.
|
||
|
* @param {ASTNode} node The node to check.
|
||
|
* @returns {boolean} True if the node is a block statement, false if not.
|
||
|
* @private
|
||
|
*/
|
||
|
function isBlock(node) {
|
||
|
return node && node.type === "BlockStatement";
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Binds a list of properties to a function that verifies that the opening
|
||
|
* curly brace is on the same line as its controlling statement of a given
|
||
|
* node.
|
||
|
* @param {...string} The properties to check on the node.
|
||
|
* @returns {Function} A function that will perform the check on a node
|
||
|
* @private
|
||
|
*/
|
||
|
function checkBlock() {
|
||
|
var blockProperties = arguments;
|
||
|
|
||
|
return function(node) {
|
||
|
[].forEach.call(blockProperties, function(blockProp) {
|
||
|
var block = node[blockProp], previousToken, curlyToken, curlyTokenEnd, curlyTokensOnSameLine;
|
||
|
block = node[blockProp];
|
||
|
|
||
|
if (isBlock(block)) {
|
||
|
|
||
|
previousToken = context.getTokenBefore(block);
|
||
|
curlyToken = context.getFirstToken(block);
|
||
|
curlyTokenEnd = context.getLastToken(block);
|
||
|
curlyTokensOnSameLine = curlyToken.loc.start.line === curlyTokenEnd.loc.start.line;
|
||
|
|
||
|
if (previousToken.loc.start.line !== curlyToken.loc.start.line) {
|
||
|
context.report(node, OPEN_MESSAGE);
|
||
|
} else if (block.body.length && params.allowSingleLine) {
|
||
|
|
||
|
if (curlyToken.loc.start.line === block.body[0].loc.start.line && !curlyTokensOnSameLine) {
|
||
|
context.report(block.body[0], BODY_MESSAGE);
|
||
|
} else if (curlyTokenEnd.loc.start.line === block.body[block.body.length - 1].loc.start.line && !curlyTokensOnSameLine) {
|
||
|
context.report(block.body[block.body.length - 1], CLOSE_MESSAGE_SINGLE);
|
||
|
}
|
||
|
|
||
|
} else if (block.body.length && curlyToken.loc.start.line === block.body[0].loc.start.line) {
|
||
|
context.report(block.body[0], BODY_MESSAGE);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enforces the configured brace style on IfStatements
|
||
|
* @param {ASTNode} node An IfStatement node.
|
||
|
* @returns {void}
|
||
|
* @private
|
||
|
*/
|
||
|
function checkIfStatement(node) {
|
||
|
var tokens,
|
||
|
alternateIsBlock = false,
|
||
|
alternateIsIfBlock = false;
|
||
|
|
||
|
checkBlock("consequent", "alternate")(node);
|
||
|
|
||
|
if (node.alternate) {
|
||
|
|
||
|
alternateIsBlock = isBlock(node.alternate);
|
||
|
alternateIsIfBlock = node.alternate.type === "IfStatement" && isBlock(node.alternate.consequent);
|
||
|
|
||
|
if (alternateIsBlock || alternateIsIfBlock) {
|
||
|
tokens = context.getTokensBefore(node.alternate, 2);
|
||
|
|
||
|
if (style === "1tbs") {
|
||
|
if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
|
||
|
context.report(node.alternate, CLOSE_MESSAGE);
|
||
|
}
|
||
|
} else if (style === "stroustrup") {
|
||
|
if (tokens[0].loc.start.line === tokens[1].loc.start.line) {
|
||
|
context.report(node.alternate, CLOSE_MESSAGE_STROUSTRUP);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enforces the configured brace style on TryStatements
|
||
|
* @param {ASTNode} node A TryStatement node.
|
||
|
* @returns {void}
|
||
|
* @private
|
||
|
*/
|
||
|
function checkTryStatement(node) {
|
||
|
var tokens;
|
||
|
|
||
|
checkBlock("block", "finalizer")(node);
|
||
|
|
||
|
if (isBlock(node.finalizer)) {
|
||
|
tokens = context.getTokensBefore(node.finalizer, 2);
|
||
|
if (style === "1tbs") {
|
||
|
if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
|
||
|
context.report(node.finalizer, CLOSE_MESSAGE);
|
||
|
}
|
||
|
} else if (style === "stroustrup") {
|
||
|
if (tokens[0].loc.start.line === tokens[1].loc.start.line) {
|
||
|
context.report(node.finalizer, CLOSE_MESSAGE_STROUSTRUP);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enforces the configured brace style on CatchClauses
|
||
|
* @param {ASTNode} node A CatchClause node.
|
||
|
* @returns {void}
|
||
|
* @private
|
||
|
*/
|
||
|
function checkCatchClause(node) {
|
||
|
var previousToken = context.getTokenBefore(node),
|
||
|
firstToken = context.getFirstToken(node);
|
||
|
|
||
|
checkBlock("body")(node);
|
||
|
|
||
|
if (isBlock(node.body)) {
|
||
|
if (style === "1tbs") {
|
||
|
if (previousToken.loc.start.line !== firstToken.loc.start.line) {
|
||
|
context.report(node, CLOSE_MESSAGE);
|
||
|
}
|
||
|
} else if (style === "stroustrup") {
|
||
|
if (previousToken.loc.start.line === firstToken.loc.start.line) {
|
||
|
context.report(node, CLOSE_MESSAGE_STROUSTRUP);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enforces the configured brace style on SwitchStatements
|
||
|
* @param {ASTNode} node A SwitchStatement node.
|
||
|
* @returns {void}
|
||
|
* @private
|
||
|
*/
|
||
|
function checkSwitchStatement(node) {
|
||
|
var tokens;
|
||
|
if (node.cases && node.cases.length) {
|
||
|
tokens = context.getTokensBefore(node.cases[0], 2);
|
||
|
if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
|
||
|
context.report(node, OPEN_MESSAGE);
|
||
|
}
|
||
|
} else {
|
||
|
tokens = context.getLastTokens(node, 3);
|
||
|
if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
|
||
|
context.report(node, OPEN_MESSAGE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// Public API
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
return {
|
||
|
"FunctionDeclaration": checkBlock("body"),
|
||
|
"FunctionExpression": checkBlock("body"),
|
||
|
"ArrowFunctionExpression": checkBlock("body"),
|
||
|
"IfStatement": checkIfStatement,
|
||
|
"TryStatement": checkTryStatement,
|
||
|
"CatchClause": checkCatchClause,
|
||
|
"DoWhileStatement": checkBlock("body"),
|
||
|
"WhileStatement": checkBlock("body"),
|
||
|
"WithStatement": checkBlock("body"),
|
||
|
"ForStatement": checkBlock("body"),
|
||
|
"ForInStatement": checkBlock("body"),
|
||
|
"ForOfStatement": checkBlock("body"),
|
||
|
"SwitchStatement": checkSwitchStatement
|
||
|
};
|
||
|
|
||
|
};
|