diff --git a/lib/source-code/source-code.js b/lib/source-code/source-code.js index 5d7ccdaf1e3e..347cb7bd80da 100644 --- a/lib/source-code/source-code.js +++ b/lib/source-code/source-code.js @@ -412,7 +412,7 @@ class SourceCode extends TokenStore { /** * Determines if two nodes or tokens have at least one whitespace character - * between them. + * between them. Return false if the given nodes or tokens overlap. * @param {ASTNode|Token} first The node or token to check after. * @param {ASTNode|Token} second The node or token to check before. * @returns {boolean} True if there is a whitespace character between @@ -420,8 +420,19 @@ class SourceCode extends TokenStore { * @public */ isSpaceBetweenTokens(first, second) { - const finalToken = this.getFirstToken(second) || second; - let currentToken = this.getLastToken(first) || first; + + // Arguments are overlapping. + if (first.range[0] <= second.range[0] && first.range[1] >= second.range[0] || + second.range[0] <= first.range[0] && second.range[1] >= first.range[0]) { + return false; + } + + const nodesAreReversed = second.range[1] <= first.range[0]; + const startingNodeOrToken = nodesAreReversed ? second : first; + const endingNodeOrToken = nodesAreReversed ? first : second; + const firstToken = this.getLastToken(startingNodeOrToken) || startingNodeOrToken; + const finalToken = this.getFirstToken(endingNodeOrToken) || endingNodeOrToken; + let currentToken = firstToken; while (currentToken !== finalToken) { const nextToken = this.getTokenAfter(currentToken, { includeComments: true }); diff --git a/tests/lib/source-code/source-code.js b/tests/lib/source-code/source-code.js index c7d67c705572..d4d1dd4dd27d 100644 --- a/tests/lib/source-code/source-code.js +++ b/tests/lib/source-code/source-code.js @@ -1798,16 +1798,34 @@ describe("SourceCode", () => { ["let/**/foo", false], ["let/*\n*/foo", false] ], (code, expected) => { - it(code, () => { - const ast = espree.parse(code, DEFAULT_CONFIG), - sourceCode = new SourceCode(code, ast); + describe("when the first given is located before the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.tokens[0], + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1] + ), + expected + ); + }); + }); - assert.strictEqual( - sourceCode.isSpaceBetweenTokens( - sourceCode.ast.tokens[0], sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1] - ), - expected - ); + describe("when the first given is located after the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1], + sourceCode.ast.tokens[0] + ), + expected + ); + }); }); }); @@ -1844,16 +1862,34 @@ describe("SourceCode", () => { ["a/* */+` /*\n*/ ` /* */+c", true], ["a/* */+ ` /*\n*/ ` /* */+c", true] ], (code, expected) => { - it(code, () => { - const ast = espree.parse(code, DEFAULT_CONFIG), - sourceCode = new SourceCode(code, ast); + describe("when the first given is located before the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.tokens[0], + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 2] + ), + expected + ); + }); + }); - assert.strictEqual( - sourceCode.isSpaceBetweenTokens( - sourceCode.ast.tokens[0], sourceCode.ast.tokens[sourceCode.ast.tokens.length - 2] - ), - expected - ); + describe("when the first given is located after the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 2], + sourceCode.ast.tokens[0] + ), + expected + ); + }); }); }); }); @@ -1888,16 +1924,34 @@ describe("SourceCode", () => { [";\n/**/\nlet foo = bar", true], [";\n/* */\nlet foo = bar", true] ], (code, expected) => { - it(code, () => { - const ast = espree.parse(code, DEFAULT_CONFIG), - sourceCode = new SourceCode(code, ast); + describe("when the first given is located before the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.tokens[0], + sourceCode.ast.body[sourceCode.ast.body.length - 1] + ), + expected + ); + }); + }); - assert.strictEqual( - sourceCode.isSpaceBetweenTokens( - sourceCode.ast.tokens[0], sourceCode.ast.body[sourceCode.ast.body.length - 1] - ), - expected - ); + describe("when the first given is located after the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.body[sourceCode.ast.body.length - 1], + sourceCode.ast.tokens[0] + ), + expected + ); + }); }); }); }); @@ -1932,16 +1986,34 @@ describe("SourceCode", () => { ["let foo = bar;\n/**/\n;", true], ["let foo = bar;\n/* */\n;", true] ], (code, expected) => { - it(code, () => { - const ast = espree.parse(code, DEFAULT_CONFIG), - sourceCode = new SourceCode(code, ast); + describe("when the first given is located before the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.body[0], + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1] + ), + expected + ); + }); + }); - assert.strictEqual( - sourceCode.isSpaceBetweenTokens( - sourceCode.ast.body[0], sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1] - ), - expected - ); + describe("when the first given is located after the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1], + sourceCode.ast.body[0] + ), + expected + ); + }); }); }); }); @@ -1973,6 +2045,42 @@ describe("SourceCode", () => { ["let foo = bar;\n/**/\nlet baz = qux;", true], ["let foo = bar;\n/* */\nlet baz = qux;", true], ["let foo = 1;let foo2 = 2; let foo3 = 3;", true] + ], (code, expected) => { + describe("when the first given is located before the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.body[0], + sourceCode.ast.body[sourceCode.ast.body.length - 1] + ), + expected + ); + }); + }); + + describe("when the first given is located after the second", () => { + it(code, () => { + const ast = espree.parse(code, DEFAULT_CONFIG), + sourceCode = new SourceCode(code, ast); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.body[sourceCode.ast.body.length - 1], + sourceCode.ast.body[0] + ), + expected + ); + }); + }); + }); + }); + + describe("should return false either of the arguments' location is inside the other one", () => { + leche.withData([ + ["let foo = bar;", false] ], (code, expected) => { it(code, () => { const ast = espree.parse(code, DEFAULT_CONFIG), @@ -1980,7 +2088,32 @@ describe("SourceCode", () => { assert.strictEqual( sourceCode.isSpaceBetweenTokens( - sourceCode.ast.body[0], sourceCode.ast.body[sourceCode.ast.body.length - 1] + sourceCode.ast.tokens[0], + sourceCode.ast.body[0] + ), + expected + ); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1], + sourceCode.ast.body[0] + ), + expected + ); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.body[0], + sourceCode.ast.tokens[0] + ), + expected + ); + + assert.strictEqual( + sourceCode.isSpaceBetweenTokens( + sourceCode.ast.body[0], + sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1] ), expected );