| /** | |
|  * @fileoverview A rule to ensure whitespace before blocks. | |
|  * @author Mathias Schreck <https://github.com/lo1tuma> | |
|  * @deprecated in ESLint v8.53.0 | |
|  */ | |
| 
 | |
| "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 | |
| //------------------------------------------------------------------------------ | |
|  | |
| /** @type {import('../shared/types').Rule} */ | |
| module.exports = { | |
|     meta: { | |
|         deprecated: true, | |
|         replacedBy: [], | |
|         type: "layout", | |
| 
 | |
|         docs: { | |
|             description: "Enforce consistent spacing before blocks", | |
|             recommended: false, | |
|             url: "https://eslint.org/docs/latest/rules/space-before-blocks" | |
|         }, | |
| 
 | |
|         fixable: "whitespace", | |
| 
 | |
|         schema: [ | |
|             { | |
|                 oneOf: [ | |
|                     { | |
|                         enum: ["always", "never"] | |
|                     }, | |
|                     { | |
|                         type: "object", | |
|                         properties: { | |
|                             keywords: { | |
|                                 enum: ["always", "never", "off"] | |
|                             }, | |
|                             functions: { | |
|                                 enum: ["always", "never", "off"] | |
|                             }, | |
|                             classes: { | |
|                                 enum: ["always", "never", "off"] | |
|                             } | |
|                         }, | |
|                         additionalProperties: false | |
|                     } | |
|                 ] | |
|             } | |
|         ], | |
| 
 | |
|         messages: { | |
|             unexpectedSpace: "Unexpected space before opening brace.", | |
|             missingSpace: "Missing space before opening brace." | |
|         } | |
|     }, | |
| 
 | |
|     create(context) { | |
|         const config = context.options[0], | |
|             sourceCode = context.sourceCode; | |
|         let alwaysFunctions = true, | |
|             alwaysKeywords = true, | |
|             alwaysClasses = true, | |
|             neverFunctions = false, | |
|             neverKeywords = false, | |
|             neverClasses = false; | |
| 
 | |
|         if (typeof config === "object") { | |
|             alwaysFunctions = config.functions === "always"; | |
|             alwaysKeywords = config.keywords === "always"; | |
|             alwaysClasses = config.classes === "always"; | |
|             neverFunctions = config.functions === "never"; | |
|             neverKeywords = config.keywords === "never"; | |
|             neverClasses = config.classes === "never"; | |
|         } else if (config === "never") { | |
|             alwaysFunctions = false; | |
|             alwaysKeywords = false; | |
|             alwaysClasses = false; | |
|             neverFunctions = true; | |
|             neverKeywords = true; | |
|             neverClasses = true; | |
|         } | |
| 
 | |
|         /** | |
|          * 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. | |
|          * - `switch-colon-spacing` checks spaces after `:` of switch cases. | |
|          * @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(precedingToken, node) { | |
|             return ( | |
|                 astUtils.isArrowToken(precedingToken) || | |
|                 ( | |
|                     astUtils.isKeywordToken(precedingToken) && | |
|                     !isFunctionBody(node) | |
|                 ) || | |
|                 ( | |
|                     astUtils.isColonToken(precedingToken) && | |
|                     node.parent && | |
|                     node.parent.type === "SwitchCase" && | |
|                     precedingToken === astUtils.getSwitchCaseColonToken(node.parent, sourceCode) | |
|                 ) | |
|             ); | |
|         } | |
| 
 | |
|         /** | |
|          * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line. | |
|          * @param {ASTNode|Token} node The AST node of a BlockStatement. | |
|          * @returns {void} undefined. | |
|          */ | |
|         function checkPrecedingSpace(node) { | |
|             const precedingToken = sourceCode.getTokenBefore(node); | |
| 
 | |
|             if (precedingToken && !isConflicted(precedingToken, node) && astUtils.isTokenOnSameLine(precedingToken, node)) { | |
|                 const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node); | |
|                 let requireSpace; | |
|                 let requireNoSpace; | |
| 
 | |
|                 if (isFunctionBody(node)) { | |
|                     requireSpace = alwaysFunctions; | |
|                     requireNoSpace = neverFunctions; | |
|                 } else if (node.type === "ClassBody") { | |
|                     requireSpace = alwaysClasses; | |
|                     requireNoSpace = neverClasses; | |
|                 } else { | |
|                     requireSpace = alwaysKeywords; | |
|                     requireNoSpace = neverKeywords; | |
|                 } | |
| 
 | |
|                 if (requireSpace && !hasSpace) { | |
|                     context.report({ | |
|                         node, | |
|                         messageId: "missingSpace", | |
|                         fix(fixer) { | |
|                             return fixer.insertTextBefore(node, " "); | |
|                         } | |
|                     }); | |
|                 } else if (requireNoSpace && hasSpace) { | |
|                     context.report({ | |
|                         node, | |
|                         messageId: "unexpectedSpace", | |
|                         fix(fixer) { | |
|                             return fixer.removeRange([precedingToken.range[1], node.range[0]]); | |
|                         } | |
|                     }); | |
|                 } | |
|             } | |
|         } | |
| 
 | |
|         /** | |
|          * Checks if the CaseBlock of an given SwitchStatement node has a preceding space. | |
|          * @param {ASTNode} node The node of a SwitchStatement. | |
|          * @returns {void} undefined. | |
|          */ | |
|         function checkSpaceBeforeCaseBlock(node) { | |
|             const cases = node.cases; | |
|             let openingBrace; | |
| 
 | |
|             if (cases.length > 0) { | |
|                 openingBrace = sourceCode.getTokenBefore(cases[0]); | |
|             } else { | |
|                 openingBrace = sourceCode.getLastToken(node, 1); | |
|             } | |
| 
 | |
|             checkPrecedingSpace(openingBrace); | |
|         } | |
| 
 | |
|         return { | |
|             BlockStatement: checkPrecedingSpace, | |
|             ClassBody: checkPrecedingSpace, | |
|             SwitchStatement: checkSpaceBeforeCaseBlock | |
|         }; | |
| 
 | |
|     } | |
| };
 |