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.
 
 
 
 
 
 

113 lines
3.4 KiB

/**
* @fileoverview Rule to ensure newline per method call when chaining calls
* @author Rajendra Patil
* @copyright 2016 Rajendra Patil. All rights reserved.
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = function(context) {
var options = context.options[0] || {},
codeStateMap = {},
ignoreChainWithDepth = options.ignoreChainWithDepth || 2;
/**
* Check and Capture State if the chained calls/members
* @param {ASTNode} node The node to check
* @param {object} codeState The state of the code current code to be filled
* @returns {void}
*/
function checkAndCaptureStateRecursively(node, codeState) {
var valid = false,
objectLineNumber,
propertyLineNumber;
if (node.callee) {
node = node.callee;
codeState.hasFunctionCall = true;
}
if (node.object) {
codeState.depth++;
objectLineNumber = node.object.loc.end.line;
propertyLineNumber = node.property.loc.end.line;
valid = node.computed || propertyLineNumber > objectLineNumber;
if (!valid) {
codeState.reports.push({
node: node,
text: "Expected line break after `{{code}}`.",
depth: codeState.depth
});
}
// Recurse
checkAndCaptureStateRecursively(node.object, codeState);
}
}
/**
* Verify and report the captured state report
* @param {object} codeState contains the captured state with `hasFunctionCall, reports and depth`
* @returns {void}
*/
function reportState(codeState) {
var report;
if (codeState.hasFunctionCall && codeState.depth > ignoreChainWithDepth && codeState.reports) {
while (codeState.reports.length) {
report = codeState.reports.shift();
context.report(report.node, report.text, {
code: context.getSourceCode().getText(report.node.object).replace(/\r\n|\r|\n/g, "\\n") // Not to print newlines in error report
});
}
}
}
/**
* Initialize the node state object with default values.
* @returns {void}
*/
function initializeState() {
return {
visited: false,
hasFunctionCall: false,
depth: 1,
reports: []
};
}
/**
* Process the said node and recurse internally
* @param {ASTNode} node The node to check
* @returns {void}
*/
function processNode(node) {
var stateKey = [node.loc.start.line, node.loc.start.column].join("@"),
codeState = codeStateMap[stateKey] = (codeStateMap[stateKey] || initializeState());
if (!codeState.visited) {
codeState.visited = true;
checkAndCaptureStateRecursively(node, codeState);
}
reportState(codeState);
}
return {
"CallExpression": processNode,
"MemberExpression": processNode
};
};
module.exports.schema = [{
"type": "object",
"properties": {
"ignoreChainWithDepth": {
"type": "integer",
"minimum": 1,
"maximum": 10
}
},
"additionalProperties": false
}];