2 * @fileoverview A rule to ensure whitespace before blocks.
3 * @author Mathias Schreck <https://github.com/lo1tuma>
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
19 * Checks whether the given node represents the body of a function.
20 * @param {ASTNode} node the node to check.
21 * @returns {boolean} `true` if the node is function body.
23 function isFunctionBody(node
) {
24 const parent
= node
.parent
;
27 node
.type
=== "BlockStatement" &&
28 astUtils
.isFunction(parent
) &&
33 //------------------------------------------------------------------------------
35 //------------------------------------------------------------------------------
42 description
: "enforce consistent spacing before blocks",
44 url
: "https://eslint.org/docs/rules/space-before-blocks"
47 fixable
: "whitespace",
53 enum: ["always", "never"]
59 enum: ["always", "never", "off"]
62 enum: ["always", "never", "off"]
65 enum: ["always", "never", "off"]
68 additionalProperties
: false
75 unexpectedSpace
: "Unexpected space before opening brace.",
76 missingSpace
: "Missing space before opening brace."
81 const config
= context
.options
[0],
82 sourceCode
= context
.getSourceCode();
83 let alwaysFunctions
= true,
84 alwaysKeywords
= true,
86 neverFunctions
= false,
87 neverKeywords
= false,
90 if (typeof config
=== "object") {
91 alwaysFunctions
= config
.functions
=== "always";
92 alwaysKeywords
= config
.keywords
=== "always";
93 alwaysClasses
= config
.classes
=== "always";
94 neverFunctions
= config
.functions
=== "never";
95 neverKeywords
= config
.keywords
=== "never";
96 neverClasses
= config
.classes
=== "never";
97 } else if (config
=== "never") {
98 alwaysFunctions
= false;
99 alwaysKeywords
= false;
100 alwaysClasses
= false;
101 neverFunctions
= true;
102 neverKeywords
= true;
107 * Checks whether the spacing before the given block is already controlled by another rule:
108 * - `arrow-spacing` checks spaces after `=>`.
109 * - `keyword-spacing` checks spaces after keywords in certain contexts.
110 * - `switch-colon-spacing` checks spaces after `:` of switch cases.
111 * @param {Token} precedingToken first token before the block.
112 * @param {ASTNode|Token} node `BlockStatement` node or `{` token of a `SwitchStatement` node.
113 * @returns {boolean} `true` if requiring or disallowing spaces before the given block could produce conflicts with other rules.
115 function isConflicted(precedingToken
, node
) {
117 astUtils
.isArrowToken(precedingToken
) ||
119 astUtils
.isKeywordToken(precedingToken
) &&
120 !isFunctionBody(node
)
123 astUtils
.isColonToken(precedingToken
) &&
125 node
.parent
.type
=== "SwitchCase" &&
126 precedingToken
=== astUtils
.getSwitchCaseColonToken(node
.parent
, sourceCode
)
132 * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line.
133 * @param {ASTNode|Token} node The AST node of a BlockStatement.
134 * @returns {void} undefined.
136 function checkPrecedingSpace(node
) {
137 const precedingToken
= sourceCode
.getTokenBefore(node
);
139 if (precedingToken
&& !isConflicted(precedingToken
, node
) && astUtils
.isTokenOnSameLine(precedingToken
, node
)) {
140 const hasSpace
= sourceCode
.isSpaceBetweenTokens(precedingToken
, node
);
144 if (isFunctionBody(node
)) {
145 requireSpace
= alwaysFunctions
;
146 requireNoSpace
= neverFunctions
;
147 } else if (node
.type
=== "ClassBody") {
148 requireSpace
= alwaysClasses
;
149 requireNoSpace
= neverClasses
;
151 requireSpace
= alwaysKeywords
;
152 requireNoSpace
= neverKeywords
;
155 if (requireSpace
&& !hasSpace
) {
158 messageId
: "missingSpace",
160 return fixer
.insertTextBefore(node
, " ");
163 } else if (requireNoSpace
&& hasSpace
) {
166 messageId
: "unexpectedSpace",
168 return fixer
.removeRange([precedingToken
.range
[1], node
.range
[0]]);
176 * Checks if the CaseBlock of an given SwitchStatement node has a preceding space.
177 * @param {ASTNode} node The node of a SwitchStatement.
178 * @returns {void} undefined.
180 function checkSpaceBeforeCaseBlock(node
) {
181 const cases
= node
.cases
;
184 if (cases
.length
> 0) {
185 openingBrace
= sourceCode
.getTokenBefore(cases
[0]);
187 openingBrace
= sourceCode
.getLastToken(node
, 1);
190 checkPrecedingSpace(openingBrace
);
194 BlockStatement
: checkPrecedingSpace
,
195 ClassBody
: checkPrecedingSpace
,
196 SwitchStatement
: checkSpaceBeforeCaseBlock