diff --git a/lib/rules/require-aligned-multiline-params.js b/lib/rules/require-aligned-multiline-params.js index 5774b6554..c087c2e1c 100644 --- a/lib/rules/require-aligned-multiline-params.js +++ b/lib/rules/require-aligned-multiline-params.js @@ -58,6 +58,23 @@ var assert = require('assert'); +function getNodeColumn(node) { + var currentToken = node.getFirstToken().getPreviousToken(); + var indentationLevel = 0; + while (currentToken) { + if (currentToken.getNewlineCount() > 0) { + var sourceCodeLines = currentToken.getSourceCodeLines(); + indentationLevel += sourceCodeLines[sourceCodeLines.length - 1].length; + break; + } + + indentationLevel += currentToken.getSourceCodeLength(); + + currentToken = currentToken.getPreviousToken(); + } + return indentationLevel; +} + module.exports = function() { }; @@ -97,12 +114,12 @@ module.exports.prototype = { return; } - var currentLine = params[0].getLoc().start.line; + var firstParam = params[0]; var referenceColumn; var body; if (_this._alignWithFirstParam) { - referenceColumn = params[0].getLoc().start.column; + referenceColumn = getNodeColumn(firstParam); } else { body = node.body.body[0]; @@ -115,19 +132,21 @@ module.exports.prototype = { referenceColumn = body.getLoc().start.column + _this._indentationLevel; } - params.forEach(function(param) { - if (param.getLoc().start.line !== currentLine) { - if (param.getLoc().start.column !== referenceColumn) { + var previousParam = firstParam; + params.slice(1).forEach(function(param) { + if (!file.isOnTheSameLine(previousParam, param)) { + var paramColumn = getNodeColumn(param); + if (paramColumn !== referenceColumn) { errors.assert.indentation({ - lineNumber: param.getLoc().start.line, - actual: param.getLoc().start.column, + token: param.getFirstToken(), + actual: paramColumn, expected: referenceColumn, indentChar: ' ', silent: false }); } - currentLine = param.getLoc().start.line; + previousParam = param; } }); diff --git a/lib/token-assert.js b/lib/token-assert.js index b40557365..1455e71f2 100644 --- a/lib/token-assert.js +++ b/lib/token-assert.js @@ -121,13 +121,14 @@ TokenAssert.prototype.spacesBetween = function(options) { * Requires the specified line to have the expected indentation. * * @param {Object} options - * @param {Number} options.lineNumber * @param {Number} options.actual * @param {Number} options.expected * @param {String} options.indentChar + * @param {String} options.token * @param {Boolean} [options.silent] if true, will suppress error emission but still fix whitespace */ TokenAssert.prototype.indentation = function(options) { + var token = options.token; var lineNumber = options.lineNumber; var actual = options.actual; var expected = options.expected; @@ -146,19 +147,10 @@ TokenAssert.prototype.indentation = function(options) { }); } - var token = this._file.getFirstTokenOnLine(lineNumber, { - includeComments: true - }); var newWhitespace = (new Array(expected + 1)).join(indentChar); - if (!token) { - this._setEmptyLineIndentation(lineNumber, newWhitespace); - return; - } - this._updateWhitespaceByLine(token, function(lines) { lines[lines.length - 1] = newWhitespace; - return lines; }); @@ -210,33 +202,6 @@ TokenAssert.prototype._updateCommentWhitespace = function(token, indentChar, act token.parentElement.replaceChild(newComment, token); }; -/** - * Fixes the indentation of a line that has no tokens on it - * - * @param {Number} lineNumber - * @param {String} newWhitespace - */ -TokenAssert.prototype._setEmptyLineIndentation = function(lineNumber, newWhitespace) { - var token; - do { - token = this._file.getFirstTokenOnLine(++lineNumber, { - includeComments: true - }); - } while (!token); - - this._updateWhitespaceByLine(token, function(lines) { - if (lines[0] !== '') { - lines[0] = newWhitespace; - } - - for (var i = 1; i < lines.length; i++) { - lines[i] = newWhitespace; - } - - return lines; - }); -}; - /** * Requires tokens to be on the same line. * diff --git a/test/specs/token-assert.js b/test/specs/token-assert.js index 9f1359a2f..1cfee3ea5 100644 --- a/test/specs/token-assert.js +++ b/test/specs/token-assert.js @@ -1216,7 +1216,7 @@ describe('token-assert', function() { }); }); - describe('indentation', function() { + describe.only('indentation', function() { it('should not trigger on correct indentation', function() { var file = createJsFile('x=y;'); @@ -1225,7 +1225,7 @@ describe('token-assert', function() { tokenAssert.on('error', onError); tokenAssert.indentation({ - lineNumber: 1, + token: file.getProgram().getFirstToken(), actual: 0, expected: 0, indentChar: ' ' @@ -1242,7 +1242,7 @@ describe('token-assert', function() { tokenAssert.on('error', onError); tokenAssert.indentation({ - lineNumber: 1, + token: file.getProgram().getFirstToken().getNextCodeToken(), actual: 2, expected: 0, indentChar: ' ' @@ -1259,7 +1259,7 @@ describe('token-assert', function() { tokenAssert.on('error', onError); tokenAssert.indentation({ - lineNumber: 1, + token: file.getProgram().getFirstToken().getNextCodeToken(), actual: 2, expected: 0, indentChar: ' ', @@ -1277,7 +1277,7 @@ describe('token-assert', function() { tokenAssert.on('error', onError); tokenAssert.indentation({ - lineNumber: 1, + token: file.getProgram().getFirstToken().getNextCodeToken(), actual: 2, expected: 0, indentChar: ' ' @@ -1286,42 +1286,6 @@ describe('token-assert', function() { expect(file.getWhitespaceBefore(file.getFirstToken())).to.equal(''); }); - it('should fix whitespace on incorrect indentation for the second token', function() { - var file = createJsFile('x=y;'); - - var tokenAssert = new TokenAssert(file); - var onError = sinon.spy(); - tokenAssert.on('error', onError); - - tokenAssert.indentation({ - lineNumber: 1, - actual: 0, - expected: 2, - indentChar: ' ' - }); - - var token = file.getFirstToken().getNextToken(); - expect(file.getWhitespaceBefore(token)).to.equal(' '); - }); - - it('should fix empty line whitespace on incorrect indentation', function() { - var file = createJsFile(' \n \nx=y;'); - - var tokenAssert = new TokenAssert(file); - var onError = sinon.spy(); - tokenAssert.on('error', onError); - - tokenAssert.indentation({ - lineNumber: 1, - actual: 2, - expected: 0, - indentChar: ' ' - }); - - var token = file.findNextToken(file.getFirstToken(), 'Identifier', 'x'); - expect(file.getWhitespaceBefore(token)).to.equal('\n\n'); - }); - it('should fix docblock on incorrect overindentation', function() { var file = createJsFile(' /*\n *\n */\nx=y;'); @@ -1330,7 +1294,7 @@ describe('token-assert', function() { tokenAssert.on('error', onError); tokenAssert.indentation({ - lineNumber: 1, + token: file.getProgram().getFirstToken().getNextNonWhitespaceToken(), actual: 2, expected: 0, indentChar: ' ' @@ -1349,7 +1313,7 @@ describe('token-assert', function() { tokenAssert.on('error', onError); tokenAssert.indentation({ - lineNumber: 1, + token: file.getProgram().getFirstToken().getNextNonWhitespaceToken(), actual: 2, expected: 4, indentChar: ' ' @@ -1359,41 +1323,5 @@ describe('token-assert', function() { expect(file.getWhitespaceBefore(newToken)).to.equal(' '); expect(newToken.value).to.equal('\n *\n '); }); - - it('should fix whitespace after docblock on incorrect indentation', function() { - var file = createJsFile('/**/\n \nx=y;'); - - var tokenAssert = new TokenAssert(file); - var onError = sinon.spy(); - var token = file.getFirstTokenOnLine(3); - tokenAssert.on('error', onError); - - tokenAssert.indentation({ - lineNumber: 2, - actual: 2, - expected: 0, - indentChar: ' ' - }); - - expect(file.getWhitespaceBefore(token)).to.equal('\n\n'); - }); - - it('should not lose lines with mixed line endings', function() { - var file = createJsFile(' \r\n \r\n \nx=y;'); - - var tokenAssert = new TokenAssert(file); - var onError = sinon.spy(); - var token = file.getFirstTokenOnLine(4); - tokenAssert.on('error', onError); - - tokenAssert.indentation({ - lineNumber: 1, - actual: 2, - expected: 0, - indentChar: ' ' - }); - - expect(file.getWhitespaceBefore(token)).to.equal('\r\n\r\n\r\n'); - }); }); });