/** * @fileoverview Align arguments in multiline function calls * @author Rich Trott */ 'use strict'; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ function checkArgumentAlignment(context, node) { function isNodeFirstInLine(node, byEndLocation) { const firstToken = byEndLocation === true ? context.getLastToken(node, 1) : context.getTokenBefore(node); const startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line; const endLine = firstToken ? firstToken.loc.end.line : -1; return startLine !== endLine; } if (node.arguments.length === 0) return; var msg = ''; const first = node.arguments[0]; var currentLine = first.loc.start.line; const firstColumn = first.loc.start.column; const ignoreTypes = [ 'ArrowFunctionExpression', 'CallExpression', 'FunctionExpression', 'ObjectExpression', 'TemplateLiteral' ]; const args = node.arguments; // For now, don't bother trying to validate potentially complicating things // like closures. Different people will have very different ideas and it's // probably best to implement configuration options. if (args.some((node) => { return ignoreTypes.indexOf(node.type) !== -1; })) { return; } if (!isNodeFirstInLine(node)) { return; } args.slice(1).forEach((argument) => { if (argument.loc.start.line === currentLine + 1) { if (argument.loc.start.column !== firstColumn) { msg = 'Function called with argument in column ' + `${argument.loc.start.column}, expected in ${firstColumn}`; } } currentLine = argument.loc.start.line; }); if (msg) context.report(node, msg); } module.exports = function(context) { return { 'CallExpression': (node) => checkArgumentAlignment(context, node) }; };