From 69ca75d36dfb0e1fef213db08078e43f1ab9b791 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 25 Apr 2016 23:32:35 -0700 Subject: [PATCH 1/2] test,tools: adjust function argument alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for a lint rule enforcing function argument alignment, adjust function arguments to be aligned. PR-URL: https://github.com/nodejs/node/pull/7100 Refs: https://github.com/nodejs/node/pull/6390 Reviewed-By: James M Snell Reviewed-By: Johan Bergström Reviewed-By: Brian White Reviewed-By: Imran Iqbal Reviewed-By: Ben Noordhuis Reviewed-By: Ryan Graham --- .../test-dgram-multicast-multi-process.js | 2 +- test/parallel/test-assert.js | 2 +- test/parallel/test-buffer.js | 36 ++++++++++++------- test/parallel/test-cluster-basic.js | 4 +-- test/parallel/test-crypto-binary-default.js | 7 ++-- test/parallel/test-crypto-hash.js | 7 ++-- .../test-domain-exit-dispose-again.js | 2 +- ...n-throw-from-uncaught-exception-handler.js | 8 ++--- test/parallel/test-domain-timers.js | 4 +-- ...in-top-level-error-handler-clears-stack.js | 2 +- test/parallel/test-file-write-stream2.js | 4 +-- test/parallel/test-file-write-stream3.js | 4 +-- test/parallel/test-fs-realpath.js | 8 ++--- .../parallel/test-http-agent-error-on-idle.js | 2 +- test/parallel/test-http-agent-keepalive.js | 2 +- test/parallel/test-http-agent-maxsockets.js | 2 +- .../test-http-destroyed-socket-write2.js | 4 +-- test/parallel/test-http-parser-bad-ref.js | 2 ++ test/parallel/test-http-url.parse-post.js | 2 +- test/parallel/test-require-process.js | 2 +- test/parallel/test-timers-ordering.js | 2 +- ...st-timers-reset-process-domain-on-throw.js | 4 +-- .../parallel/test-zlib-convenience-methods.js | 16 ++++----- test/parallel/test-zlib-flush-drain.js | 8 ++--- tools/doc/html.js | 10 +++--- 25 files changed, 83 insertions(+), 63 deletions(-) diff --git a/test/internet/test-dgram-multicast-multi-process.js b/test/internet/test-dgram-multicast-multi-process.js index 040b89e0b2cd04..dfbe9a3077b94a 100644 --- a/test/internet/test-dgram-multicast-multi-process.js +++ b/test/internet/test-dgram-multicast-multi-process.js @@ -91,7 +91,7 @@ function launchChildProcess(index) { worker.pid, count); assert.strictEqual(count, messages.length, - 'A worker received an invalid multicast message'); + 'A worker received an invalid multicast message'); }); clearTimeout(timer); diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 460829a16ea884..80af439e7f36ec 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -461,7 +461,7 @@ try { } catch (e) { assert.equal(e.toString().split('\n')[0], 'AssertionError: oh no'); assert.equal(e.generatedMessage, false, - 'Message incorrectly marked as generated'); + 'Message incorrectly marked as generated'); } // Verify that throws() and doesNotThrow() throw on non-function block diff --git a/test/parallel/test-buffer.js b/test/parallel/test-buffer.js index db2b0ae7a22b57..d0ebe64db9453a 100644 --- a/test/parallel/test-buffer.js +++ b/test/parallel/test-buffer.js @@ -571,18 +571,30 @@ assert.equal(new Buffer('KioqKioqKioqKioqKioqKioqKio', 'base64').toString(), '********************'); // handle padding graciously, multiple-of-4 or not -assert.equal(new Buffer('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw==', - 'base64').length, 32); -assert.equal(new Buffer('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw=', - 'base64').length, 32); -assert.equal(new Buffer('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw', - 'base64').length, 32); -assert.equal(new Buffer('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', - 'base64').length, 31); -assert.equal(new Buffer('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', - 'base64').length, 31); -assert.equal(new Buffer('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', - 'base64').length, 31); +assert.equal( + new Buffer('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw==', 'base64').length, + 32 +); +assert.equal( + new Buffer('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw=', 'base64').length, + 32 +); +assert.equal( + new Buffer('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw', 'base64').length, + 32 +); +assert.equal( + new Buffer('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', 'base64').length, + 31 +); +assert.equal( + new Buffer('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', 'base64').length, + 31 +); +assert.equal( + new Buffer('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', 'base64').length, + 31 +); // This string encodes single '.' character in UTF-16 var dot = new Buffer('//4uAA==', 'base64'); diff --git a/test/parallel/test-cluster-basic.js b/test/parallel/test-cluster-basic.js index 60bd27b24eee89..5a5efabbab821a 100644 --- a/test/parallel/test-cluster-basic.js +++ b/test/parallel/test-cluster-basic.js @@ -4,7 +4,7 @@ var assert = require('assert'); var cluster = require('cluster'); assert.equal('NODE_UNIQUE_ID' in process.env, false, - 'NODE_UNIQUE_ID should be removed on startup'); + 'NODE_UNIQUE_ID should be removed on startup'); function forEach(obj, fn) { Object.keys(obj).forEach(function(name, index) { @@ -93,7 +93,7 @@ else if (cluster.isMaster) { worker = cluster.fork(); assert.equal(worker.id, 1); assert.ok(worker instanceof cluster.Worker, - 'the worker is not a instance of the Worker constructor'); + 'the worker is not a instance of the Worker constructor'); //Check event forEach(checks.worker.events, function(bool, name, index) { diff --git a/test/parallel/test-crypto-binary-default.js b/test/parallel/test-crypto-binary-default.js index d2554ab6ec4d4d..129bbcacef151e 100644 --- a/test/parallel/test-crypto-binary-default.js +++ b/test/parallel/test-crypto-binary-default.js @@ -347,8 +347,11 @@ var a4 = crypto.createHash('sha1').update('Test123').digest('buffer'); if (!common.hasFipsCrypto) { var a0 = crypto.createHash('md5').update('Test123').digest('binary'); - assert.equal(a0, 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca' + - '\u00bd\u008c', 'Test MD5 as binary'); + assert.equal( + a0, + 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca\u00bd\u008c', + 'Test MD5 as binary' + ); } assert.equal(a1, '8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'Test SHA1'); diff --git a/test/parallel/test-crypto-hash.js b/test/parallel/test-crypto-hash.js index aec035afe184f4..8272aedcc51e1f 100644 --- a/test/parallel/test-crypto-hash.js +++ b/test/parallel/test-crypto-hash.js @@ -39,8 +39,11 @@ a8 = a8.read(); if (!common.hasFipsCrypto) { var a0 = crypto.createHash('md5').update('Test123').digest('binary'); - assert.equal(a0, 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca' + - '\u00bd\u008c', 'Test MD5 as binary'); + assert.equal( + a0, + 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca\u00bd\u008c', + 'Test MD5 as binary' + ); } assert.equal(a1, '8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'Test SHA1'); assert.equal(a2, '2bX1jws4GYKTlxhloUB09Z66PoJZW+y+hq5R8dnx9l4=', diff --git a/test/parallel/test-domain-exit-dispose-again.js b/test/parallel/test-domain-exit-dispose-again.js index 7360e79412296d..0928addd9ace55 100644 --- a/test/parallel/test-domain-exit-dispose-again.js +++ b/test/parallel/test-domain-exit-dispose-again.js @@ -38,7 +38,7 @@ setTimeout(function firstTimer() { d.dispose(); console.error(err); console.error('in domain error handler', - process.domain, process.domain === d); + process.domain, process.domain === d); }); d.run(function() { diff --git a/test/parallel/test-domain-throw-error-then-throw-from-uncaught-exception-handler.js b/test/parallel/test-domain-throw-error-then-throw-from-uncaught-exception-handler.js index 499988107dae27..ae86ef2cdf20d3 100644 --- a/test/parallel/test-domain-throw-error-then-throw-from-uncaught-exception-handler.js +++ b/test/parallel/test-domain-throw-error-then-throw-from-uncaught-exception-handler.js @@ -62,8 +62,8 @@ function runTestWithoutAbortOnUncaughtException() { 'include domain\'s error\'s message'); assert.notEqual(err.code, 0, - 'child process should have exited with a non-zero exit code, ' + - 'but did not'); + 'child process should have exited with a non-zero ' + + 'exit code, but did not'); }); } @@ -72,8 +72,8 @@ function runTestWithAbortOnUncaughtException() { withAbortOnUncaughtException: true }), function onTestDone(err, stdout, stderr) { assert.notEqual(err.code, RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE, - 'child process should not have run its uncaughtException event ' + - 'handler'); + 'child process should not have run its uncaughtException ' + + 'event handler'); assert(common.nodeProcessAborted(err.code, err.signal), 'process should have aborted, but did not'); }); diff --git a/test/parallel/test-domain-timers.js b/test/parallel/test-domain-timers.js index a97b300da02d31..58989e812bba50 100644 --- a/test/parallel/test-domain-timers.js +++ b/test/parallel/test-domain-timers.js @@ -34,7 +34,7 @@ timeout = setTimeout(function() {}, 10 * 1000); process.on('exit', function() { assert.equal(timeout_err.message, 'Timeout UNREFd', - 'Domain should catch timer error'); + 'Domain should catch timer error'); assert.equal(immediate_err.message, 'Immediate Error', - 'Domain should catch immediate error'); + 'Domain should catch immediate error'); }); diff --git a/test/parallel/test-domain-top-level-error-handler-clears-stack.js b/test/parallel/test-domain-top-level-error-handler-clears-stack.js index a5fec1f65ef029..f2095f09b7836c 100644 --- a/test/parallel/test-domain-top-level-error-handler-clears-stack.js +++ b/test/parallel/test-domain-top-level-error-handler-clears-stack.js @@ -23,7 +23,7 @@ d.on('error', common.mustCall(function() { // call to process._fatalException, and so on recursively and // indefinitely. console.error('domains stack length should be 1, but instead is:', - domain._stack.length); + domain._stack.length); process.exit(1); } }); diff --git a/test/parallel/test-file-write-stream2.js b/test/parallel/test-file-write-stream2.js index e95760bc2d9a4e..e11f7e7815f1d0 100644 --- a/test/parallel/test-file-write-stream2.js +++ b/test/parallel/test-file-write-stream2.js @@ -24,8 +24,8 @@ process.on('exit', function() { console.log(' expected: %j', cb_expected); console.log(' occurred: %j', cb_occurred); assert.strictEqual(cb_occurred, cb_expected, - 'events missing or out of order: "' + - cb_occurred + '" !== "' + cb_expected + '"'); + 'events missing or out of order: "' + + cb_occurred + '" !== "' + cb_expected + '"'); } else { console.log('ok'); } diff --git a/test/parallel/test-file-write-stream3.js b/test/parallel/test-file-write-stream3.js index caa0f106f4d91e..55806e8d22774c 100644 --- a/test/parallel/test-file-write-stream3.js +++ b/test/parallel/test-file-write-stream3.js @@ -24,8 +24,8 @@ process.on('exit', function() { console.log(' expected: %j', cb_expected); console.log(' occurred: %j', cb_occurred); assert.strictEqual(cb_occurred, cb_expected, - 'events missing or out of order: "' + - cb_occurred + '" !== "' + cb_expected + '"'); + 'events missing or out of order: "' + + cb_occurred + '" !== "' + cb_expected + '"'); } }); diff --git a/test/parallel/test-fs-realpath.js b/test/parallel/test-fs-realpath.js index bbe8c26d120f0e..d627c01487c2c2 100644 --- a/test/parallel/test-fs-realpath.js +++ b/test/parallel/test-fs-realpath.js @@ -338,14 +338,14 @@ function test_escape_cwd(cb) { console.log('test_escape_cwd'); asynctest(fs.realpath, ['..'], cb, function(er, uponeActual) { assert.equal(upone, uponeActual, - 'realpath("..") expected: ' + path.resolve(upone) + - ' actual:' + uponeActual); + 'realpath("..") expected: ' + path.resolve(upone) + + ' actual:' + uponeActual); }); } var uponeActual = fs.realpathSync('..'); assert.equal(upone, uponeActual, - 'realpathSync("..") expected: ' + path.resolve(upone) + - ' actual:' + uponeActual); + 'realpathSync("..") expected: ' + path.resolve(upone) + + ' actual:' + uponeActual); // going up with .. multiple times diff --git a/test/parallel/test-http-agent-error-on-idle.js b/test/parallel/test-http-agent-error-on-idle.js index e3388ee0dcbd96..f609efc8d59b6d 100644 --- a/test/parallel/test-http-agent-error-on-idle.js +++ b/test/parallel/test-http-agent-error-on-idle.js @@ -47,7 +47,7 @@ server.listen(common.PORT, function() { function done() { assert.equal(Object.keys(agent.freeSockets).length, 0, - 'expect the freeSockets pool to be empty'); + 'expect the freeSockets pool to be empty'); agent.destroy(); server.close(); diff --git a/test/parallel/test-http-agent-keepalive.js b/test/parallel/test-http-agent-keepalive.js index 6800e893e329da..85c0ad5dbc2b4f 100644 --- a/test/parallel/test-http-agent-keepalive.js +++ b/test/parallel/test-http-agent-keepalive.js @@ -74,7 +74,7 @@ function remoteClose() { setTimeout(function() { assert.equal(agent.sockets[name], undefined); assert.equal(agent.freeSockets[name], undefined, - 'freeSockets is not empty'); + 'freeSockets is not empty'); remoteError(); }, common.platformTimeout(200)); }); diff --git a/test/parallel/test-http-agent-maxsockets.js b/test/parallel/test-http-agent-maxsockets.js index e11aa2addad746..11f8d28a7389e2 100644 --- a/test/parallel/test-http-agent-maxsockets.js +++ b/test/parallel/test-http-agent-maxsockets.js @@ -30,7 +30,7 @@ function done() { } var freepool = agent.freeSockets[Object.keys(agent.freeSockets)[0]]; assert.equal(freepool.length, 2, - 'expect keep 2 free sockets, but got ' + freepool.length); + 'expect keep 2 free sockets, but got ' + freepool.length); agent.destroy(); server.close(); } diff --git a/test/parallel/test-http-destroyed-socket-write2.js b/test/parallel/test-http-destroyed-socket-write2.js index fd58892350bc2a..7588393840f2cc 100644 --- a/test/parallel/test-http-destroyed-socket-write2.js +++ b/test/parallel/test-http-destroyed-socket-write2.js @@ -42,8 +42,8 @@ server.listen(common.PORT, function() { default: assert.strictEqual(er.code, - 'ECONNRESET', - 'Writing to a torn down client should RESET or ABORT'); + 'ECONNRESET', + 'Write to a torn down client should RESET or ABORT'); break; } diff --git a/test/parallel/test-http-parser-bad-ref.js b/test/parallel/test-http-parser-bad-ref.js index 545a9c1fef11c4..01179641175e02 100644 --- a/test/parallel/test-http-parser-bad-ref.js +++ b/test/parallel/test-http-parser-bad-ref.js @@ -75,10 +75,12 @@ demoBug('POST /1', '/22 HTTP/1.1\r\n' + 'Content-Length: 4\r\n\r\n' + 'pong'); +/* eslint-disable align-function-arguments */ demoBug('POST /1/22 HTTP/1.1\r\n' + 'Content-Type: tex', 't/plain\r\n' + 'Content-Length: 4\r\n\r\n' + 'pong'); +/* eslint-enable align-function-arguments */ process.on('exit', function() { assert.equal(2, headersComplete); diff --git a/test/parallel/test-http-url.parse-post.js b/test/parallel/test-http-url.parse-post.js index b6a0fdeb255235..7611b0856320a6 100644 --- a/test/parallel/test-http-url.parse-post.js +++ b/test/parallel/test-http-url.parse-post.js @@ -14,7 +14,7 @@ function check(request) { assert.strictEqual(request.url, '/asdf?qwer=zxcv'); //the host header should use the url.parse.hostname assert.strictEqual(request.headers.host, - testURL.hostname + ':' + testURL.port); + testURL.hostname + ':' + testURL.port); } var server = http.createServer(function(request, response) { diff --git a/test/parallel/test-require-process.js b/test/parallel/test-require-process.js index 33634930b4e614..4e5821add13183 100644 --- a/test/parallel/test-require-process.js +++ b/test/parallel/test-require-process.js @@ -4,4 +4,4 @@ var assert = require('assert'); var nativeProcess = require('process'); assert.strictEqual(nativeProcess, process, - 'require("process") should return a reference to global process'); + 'require("process") should return global process reference'); diff --git a/test/parallel/test-timers-ordering.js b/test/parallel/test-timers-ordering.js index cef91e58e78c3d..c23af9d8307e9a 100644 --- a/test/parallel/test-timers-ordering.js +++ b/test/parallel/test-timers-ordering.js @@ -19,7 +19,7 @@ var f = function(i) { var now = Timer.now(); console.log(i, now); assert(now >= last_ts + 1, - 'current ts ' + now + ' < prev ts ' + last_ts + ' + 1'); + 'current ts ' + now + ' < prev ts ' + last_ts + ' + 1'); last_ts = now; // schedule next iteration diff --git a/test/parallel/test-timers-reset-process-domain-on-throw.js b/test/parallel/test-timers-reset-process-domain-on-throw.js index ab3ffd3596ed53..55e7ef57dcafc4 100644 --- a/test/parallel/test-timers-reset-process-domain-on-throw.js +++ b/test/parallel/test-timers-reset-process-domain-on-throw.js @@ -36,8 +36,8 @@ function secondTimer() { // secondTimer was scheduled before any domain had been created, so its // callback should not have any active domain set when it runs. if (process.domain !== null) { - console.log('process.domain should be null in this timer callback, but ' + - 'instead is:', process.domain); + console.log('process.domain should be null in this timer callback, but is:', + process.domain); // Do not use assert here, as it throws errors and if a domain with an error // handler is active, then asserting wouldn't make the test fail. process.exit(1); diff --git a/test/parallel/test-zlib-convenience-methods.js b/test/parallel/test-zlib-convenience-methods.js index 70c102efd2862c..ccb3347266a9b4 100644 --- a/test/parallel/test-zlib-convenience-methods.js +++ b/test/parallel/test-zlib-convenience-methods.js @@ -23,8 +23,8 @@ var opts = { zlib[method[0]](expect, opts, function(err, result) { zlib[method[1]](result, opts, function(err, result) { assert.equal(result, expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' with options.'); + 'Should get original string after ' + + method[0] + '/' + method[1] + ' with options.'); hadRun++; }); }); @@ -32,8 +32,8 @@ var opts = { zlib[method[0]](expect, function(err, result) { zlib[method[1]](result, function(err, result) { assert.equal(result, expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' without options.'); + 'Should get original string after ' + + method[0] + '/' + method[1] + ' without options.'); hadRun++; }); }); @@ -41,15 +41,15 @@ var opts = { var result = zlib[method[0] + 'Sync'](expect, opts); result = zlib[method[1] + 'Sync'](result, opts); assert.equal(result, expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' with options.'); + 'Should get original string after ' + + method[0] + '/' + method[1] + ' with options.'); hadRun++; result = zlib[method[0] + 'Sync'](expect); result = zlib[method[1] + 'Sync'](result); assert.equal(result, expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' without options.'); + 'Should get original string after ' + + method[0] + '/' + method[1] + ' without options.'); hadRun++; }); diff --git a/test/parallel/test-zlib-flush-drain.js b/test/parallel/test-zlib-flush-drain.js index 14a42e76cc3874..fcc17ad589d11f 100644 --- a/test/parallel/test-zlib-flush-drain.js +++ b/test/parallel/test-zlib-flush-drain.js @@ -38,11 +38,11 @@ deflater.on('drain', function() { process.once('exit', function() { assert.equal(beforeFlush, true, - 'before calling flush the writable stream should need to drain'); + 'before calling flush, writable stream should need to drain'); assert.equal(afterFlush, false, - 'after calling flush the writable stream should not need to drain'); + 'after calling flush, writable stream should not need to drain'); assert.equal(drainCount, 1, - 'the deflater should have emitted a single drain event'); + 'the deflater should have emitted a single drain event'); assert.equal(flushCount, 2, - 'flush should be called twice'); + 'flush should be called twice'); }); diff --git a/tools/doc/html.js b/tools/doc/html.js index feb99cd810415c..a232117439bbc7 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -11,11 +11,11 @@ module.exports = toHTML; // TODO(chrisdickinson): never stop vomitting / fix this. var gtocPath = path.resolve(path.join( __dirname, - '..', - '..', - 'doc', - 'api', - '_toc.markdown' + '..', + '..', + 'doc', + 'api', + '_toc.markdown' )); var gtocLoading = null; var gtocData = null; From 6c46eee06775939b6dfa1356187b87544602dd8d Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 18 Apr 2016 21:44:30 -0700 Subject: [PATCH 2/2] tools: lint for function argument alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function calls that span multiple lines, apply a custom lint rule to enforce argument alignment. With this rule, the following code will be flagged as an error by the linter because the arguments on the second line start in a different column than on the first line: myFunction(a, b, c, d); The following code will not be flagged as an error by the linter: myFunction(a, b, c, d); PR-URL: https://github.com/nodejs/node/pull/7100 Refs: https://github.com/nodejs/node/pull/6390 Reviewed-By: James M Snell Reviewed-By: Johan Bergström Reviewed-By: Brian White Reviewed-By: Imran Iqbal Reviewed-By: Ben Noordhuis Reviewed-By: Ryan Graham --- .eslintrc | 3 +- .../eslint-rules/align-function-arguments.js | 70 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tools/eslint-rules/align-function-arguments.js diff --git a/.eslintrc b/.eslintrc index af0e6ddc15670f..59f9f06e8baa0d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -85,9 +85,10 @@ rules: prefer-const: 2 # Custom rules in tools/eslint-rules + align-function-arguments: 2 + align-multiline-assignment: 2 assert-fail-single-argument: 2 new-with-error: [2, "Error", "RangeError", "TypeError", "SyntaxError", "ReferenceError"] - align-multiline-assignment: 2 # Global scoped method and vars globals: diff --git a/tools/eslint-rules/align-function-arguments.js b/tools/eslint-rules/align-function-arguments.js new file mode 100644 index 00000000000000..a8cd71660d7d60 --- /dev/null +++ b/tools/eslint-rules/align-function-arguments.js @@ -0,0 +1,70 @@ +/** + * @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) + }; +};