Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: skip keyword check for fns in space-before-blocks (fixes #13553) #13712

Merged
merged 1 commit into from Oct 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 34 additions & 9 deletions lib/rules/space-before-blocks.js
Expand Up @@ -5,8 +5,31 @@

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
* Checks whether the given node represents the body of a function.
* @param {ASTNode} node the node to check.
* @returns {boolean} `true` if the node is function body.
*/
function isFunctionBody(node) {
const parent = node.parent;

return (
node.type === "BlockStatement" &&
astUtils.isFunction(parent) &&
parent.body === node
);
}

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
Expand Down Expand Up @@ -82,13 +105,16 @@ module.exports = {
}

/**
* Checks whether or not a given token is an arrow operator (=>) or a keyword
* in order to avoid to conflict with `arrow-spacing` and `keyword-spacing`.
* @param {Token} token A token to check.
* @returns {boolean} `true` if the token is an arrow operator.
* Checks whether the spacing before the given block is already controlled by another rule:
* - `arrow-spacing` checks spaces after `=>`.
* - `keyword-spacing` checks spaces after keywords in certain contexts.
* @param {Token} precedingToken first token before the block.
* @param {ASTNode|Token} node `BlockStatement` node or `{` token of a `SwitchStatement` node.
* @returns {boolean} `true` if requiring or disallowing spaces before the given block could produce conflicts with other rules.
*/
function isConflicted(token) {
return (token.type === "Punctuator" && token.value === "=>") || token.type === "Keyword";
function isConflicted(precedingToken, node) {
return astUtils.isArrowToken(precedingToken) ||
astUtils.isKeywordToken(precedingToken) && !isFunctionBody(node);
}

/**
Expand All @@ -99,13 +125,12 @@ module.exports = {
function checkPrecedingSpace(node) {
const precedingToken = sourceCode.getTokenBefore(node);

if (precedingToken && !isConflicted(precedingToken) && astUtils.isTokenOnSameLine(precedingToken, node)) {
if (precedingToken && !isConflicted(precedingToken, node) && astUtils.isTokenOnSameLine(precedingToken, node)) {
const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
const parent = context.getAncestors().pop();
let requireSpace;
let requireNoSpace;

if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") {
if (isFunctionBody(node)) {
requireSpace = alwaysFunctions;
requireNoSpace = neverFunctions;
} else if (node.type === "ClassBody") {
Expand Down
206 changes: 206 additions & 0 deletions tests/fixtures/parsers/space-before-blocks/return-type-keyword-1.js
@@ -0,0 +1,206 @@
"use strict";

/**
* Parser: @typescript-eslint/parser@4.2.0
* Source code:
* class A { foo(bar: string): void{} }
*/

exports.parse = () => ({
type: "Program",
body: [
{
type: "ClassDeclaration",
id: {
type: "Identifier",
name: "A",
range: [6, 7],
loc: { start: { line: 1, column: 6 }, end: { line: 1, column: 7 } },
},
body: {
type: "ClassBody",
body: [
{
type: "MethodDefinition",
key: {
type: "Identifier",
name: "foo",
range: [10, 13],
loc: {
start: { line: 1, column: 10 },
end: { line: 1, column: 13 },
},
},
value: {
type: "FunctionExpression",
id: null,
generator: false,
expression: false,
async: false,
body: {
type: "BlockStatement",
body: [],
range: [32, 34],
loc: {
start: { line: 1, column: 32 },
end: { line: 1, column: 34 },
},
},
range: [13, 34],
params: [
{
type: "Identifier",
name: "bar",
range: [14, 25],
loc: {
start: { line: 1, column: 14 },
end: { line: 1, column: 25 },
},
typeAnnotation: {
type: "TSTypeAnnotation",
loc: {
start: { line: 1, column: 17 },
end: { line: 1, column: 25 },
},
range: [17, 25],
typeAnnotation: {
type: "TSStringKeyword",
range: [19, 25],
loc: {
start: { line: 1, column: 19 },
end: { line: 1, column: 25 },
},
},
},
},
],
loc: {
start: { line: 1, column: 13 },
end: { line: 1, column: 34 },
},
returnType: {
type: "TSTypeAnnotation",
loc: {
start: { line: 1, column: 26 },
end: { line: 1, column: 32 },
},
range: [26, 32],
typeAnnotation: {
type: "TSVoidKeyword",
range: [28, 32],
loc: {
start: { line: 1, column: 28 },
end: { line: 1, column: 32 },
},
},
},
},
computed: false,
static: false,
kind: "method",
range: [10, 34],
loc: {
start: { line: 1, column: 10 },
end: { line: 1, column: 34 },
},
},
],
range: [8, 36],
loc: { start: { line: 1, column: 8 }, end: { line: 1, column: 36 } },
},
superClass: null,
range: [0, 36],
loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 36 } },
},
],
sourceType: "script",
range: [0, 36],
loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 36 } },
tokens: [
{
type: "Keyword",
value: "class",
range: [0, 5],
loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 5 } },
},
{
type: "Identifier",
value: "A",
range: [6, 7],
loc: { start: { line: 1, column: 6 }, end: { line: 1, column: 7 } },
},
{
type: "Punctuator",
value: "{",
range: [8, 9],
loc: { start: { line: 1, column: 8 }, end: { line: 1, column: 9 } },
},
{
type: "Identifier",
value: "foo",
range: [10, 13],
loc: { start: { line: 1, column: 10 }, end: { line: 1, column: 13 } },
},
{
type: "Punctuator",
value: "(",
range: [13, 14],
loc: { start: { line: 1, column: 13 }, end: { line: 1, column: 14 } },
},
{
type: "Identifier",
value: "bar",
range: [14, 17],
loc: { start: { line: 1, column: 14 }, end: { line: 1, column: 17 } },
},
{
type: "Punctuator",
value: ":",
range: [17, 18],
loc: { start: { line: 1, column: 17 }, end: { line: 1, column: 18 } },
},
{
type: "Identifier",
value: "string",
range: [19, 25],
loc: { start: { line: 1, column: 19 }, end: { line: 1, column: 25 } },
},
{
type: "Punctuator",
value: ")",
range: [25, 26],
loc: { start: { line: 1, column: 25 }, end: { line: 1, column: 26 } },
},
{
type: "Punctuator",
value: ":",
range: [26, 27],
loc: { start: { line: 1, column: 26 }, end: { line: 1, column: 27 } },
},
{
type: "Keyword",
value: "void",
range: [28, 32],
loc: { start: { line: 1, column: 28 }, end: { line: 1, column: 32 } },
},
{
type: "Punctuator",
value: "{",
range: [32, 33],
loc: { start: { line: 1, column: 32 }, end: { line: 1, column: 33 } },
},
{
type: "Punctuator",
value: "}",
range: [33, 34],
loc: { start: { line: 1, column: 33 }, end: { line: 1, column: 34 } },
},
{
type: "Punctuator",
value: "}",
range: [35, 36],
loc: { start: { line: 1, column: 35 }, end: { line: 1, column: 36 } },
},
],
comments: [],
});
@@ -0,0 +1,98 @@
"use strict";

/**
* Parser: @typescript-eslint/parser@4.2.0
* Source code:
* function foo(): null {}
*/

exports.parse = () => ({
type: "Program",
body: [
{
type: "FunctionDeclaration",
id: {
type: "Identifier",
name: "foo",
range: [9, 12],
loc: { start: { line: 1, column: 9 }, end: { line: 1, column: 12 } },
},
generator: false,
expression: false,
async: false,
params: [],
body: {
type: "BlockStatement",
body: [],
range: [21, 23],
loc: { start: { line: 1, column: 21 }, end: { line: 1, column: 23 } },
},
range: [0, 23],
loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 23 } },
returnType: {
type: "TSTypeAnnotation",
loc: { start: { line: 1, column: 14 }, end: { line: 1, column: 20 } },
range: [14, 20],
typeAnnotation: {
type: "TSNullKeyword",
range: [16, 20],
loc: { start: { line: 1, column: 16 }, end: { line: 1, column: 20 } },
},
},
},
],
sourceType: "script",
range: [0, 23],
loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 23 } },
tokens: [
{
type: "Keyword",
value: "function",
range: [0, 8],
loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 8 } },
},
{
type: "Identifier",
value: "foo",
range: [9, 12],
loc: { start: { line: 1, column: 9 }, end: { line: 1, column: 12 } },
},
{
type: "Punctuator",
value: "(",
range: [12, 13],
loc: { start: { line: 1, column: 12 }, end: { line: 1, column: 13 } },
},
{
type: "Punctuator",
value: ")",
range: [13, 14],
loc: { start: { line: 1, column: 13 }, end: { line: 1, column: 14 } },
},
{
type: "Punctuator",
value: ":",
range: [14, 15],
loc: { start: { line: 1, column: 14 }, end: { line: 1, column: 15 } },
},
{
type: "Keyword",
value: "null",
range: [16, 20],
loc: { start: { line: 1, column: 16 }, end: { line: 1, column: 20 } },
},
{
type: "Punctuator",
value: "{",
range: [21, 22],
loc: { start: { line: 1, column: 21 }, end: { line: 1, column: 22 } },
},
{
type: "Punctuator",
value: "}",
range: [22, 23],
loc: { start: { line: 1, column: 22 }, end: { line: 1, column: 23 } },
},
],
comments: [],
});