[d565449] | 1 | /**
|
---|
| 2 | * @fileoverview Rule to flag block statements that do not use the one true brace style
|
---|
| 3 | * @author Ian Christian Myers
|
---|
| 4 | * @deprecated in ESLint v8.53.0
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | "use strict";
|
---|
| 8 |
|
---|
| 9 | const astUtils = require("./utils/ast-utils");
|
---|
| 10 |
|
---|
| 11 | //------------------------------------------------------------------------------
|
---|
| 12 | // Rule Definition
|
---|
| 13 | //------------------------------------------------------------------------------
|
---|
| 14 |
|
---|
| 15 | /** @type {import('../shared/types').Rule} */
|
---|
| 16 | module.exports = {
|
---|
| 17 | meta: {
|
---|
| 18 | deprecated: true,
|
---|
| 19 | replacedBy: [],
|
---|
| 20 | type: "layout",
|
---|
| 21 |
|
---|
| 22 | docs: {
|
---|
| 23 | description: "Enforce consistent brace style for blocks",
|
---|
| 24 | recommended: false,
|
---|
| 25 | url: "https://eslint.org/docs/latest/rules/brace-style"
|
---|
| 26 | },
|
---|
| 27 |
|
---|
| 28 | schema: [
|
---|
| 29 | {
|
---|
| 30 | enum: ["1tbs", "stroustrup", "allman"]
|
---|
| 31 | },
|
---|
| 32 | {
|
---|
| 33 | type: "object",
|
---|
| 34 | properties: {
|
---|
| 35 | allowSingleLine: {
|
---|
| 36 | type: "boolean",
|
---|
| 37 | default: false
|
---|
| 38 | }
|
---|
| 39 | },
|
---|
| 40 | additionalProperties: false
|
---|
| 41 | }
|
---|
| 42 | ],
|
---|
| 43 |
|
---|
| 44 | fixable: "whitespace",
|
---|
| 45 |
|
---|
| 46 | messages: {
|
---|
| 47 | nextLineOpen: "Opening curly brace does not appear on the same line as controlling statement.",
|
---|
| 48 | sameLineOpen: "Opening curly brace appears on the same line as controlling statement.",
|
---|
| 49 | blockSameLine: "Statement inside of curly braces should be on next line.",
|
---|
| 50 | nextLineClose: "Closing curly brace does not appear on the same line as the subsequent block.",
|
---|
| 51 | singleLineClose: "Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.",
|
---|
| 52 | sameLineClose: "Closing curly brace appears on the same line as the subsequent block."
|
---|
| 53 | }
|
---|
| 54 | },
|
---|
| 55 |
|
---|
| 56 | create(context) {
|
---|
| 57 | const style = context.options[0] || "1tbs",
|
---|
| 58 | params = context.options[1] || {},
|
---|
| 59 | sourceCode = context.sourceCode;
|
---|
| 60 |
|
---|
| 61 | //--------------------------------------------------------------------------
|
---|
| 62 | // Helpers
|
---|
| 63 | //--------------------------------------------------------------------------
|
---|
| 64 |
|
---|
| 65 | /**
|
---|
| 66 | * Fixes a place where a newline unexpectedly appears
|
---|
| 67 | * @param {Token} firstToken The token before the unexpected newline
|
---|
| 68 | * @param {Token} secondToken The token after the unexpected newline
|
---|
| 69 | * @returns {Function} A fixer function to remove the newlines between the tokens
|
---|
| 70 | */
|
---|
| 71 | function removeNewlineBetween(firstToken, secondToken) {
|
---|
| 72 | const textRange = [firstToken.range[1], secondToken.range[0]];
|
---|
| 73 | const textBetween = sourceCode.text.slice(textRange[0], textRange[1]);
|
---|
| 74 |
|
---|
| 75 | // Don't do a fix if there is a comment between the tokens
|
---|
| 76 | if (textBetween.trim()) {
|
---|
| 77 | return null;
|
---|
| 78 | }
|
---|
| 79 | return fixer => fixer.replaceTextRange(textRange, " ");
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | /**
|
---|
| 83 | * Validates a pair of curly brackets based on the user's config
|
---|
| 84 | * @param {Token} openingCurly The opening curly bracket
|
---|
| 85 | * @param {Token} closingCurly The closing curly bracket
|
---|
| 86 | * @returns {void}
|
---|
| 87 | */
|
---|
| 88 | function validateCurlyPair(openingCurly, closingCurly) {
|
---|
| 89 | const tokenBeforeOpeningCurly = sourceCode.getTokenBefore(openingCurly);
|
---|
| 90 | const tokenAfterOpeningCurly = sourceCode.getTokenAfter(openingCurly);
|
---|
| 91 | const tokenBeforeClosingCurly = sourceCode.getTokenBefore(closingCurly);
|
---|
| 92 | const singleLineException = params.allowSingleLine && astUtils.isTokenOnSameLine(openingCurly, closingCurly);
|
---|
| 93 |
|
---|
| 94 | if (style !== "allman" && !astUtils.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurly)) {
|
---|
| 95 | context.report({
|
---|
| 96 | node: openingCurly,
|
---|
| 97 | messageId: "nextLineOpen",
|
---|
| 98 | fix: removeNewlineBetween(tokenBeforeOpeningCurly, openingCurly)
|
---|
| 99 | });
|
---|
| 100 | }
|
---|
| 101 |
|
---|
| 102 | if (style === "allman" && astUtils.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurly) && !singleLineException) {
|
---|
| 103 | context.report({
|
---|
| 104 | node: openingCurly,
|
---|
| 105 | messageId: "sameLineOpen",
|
---|
| 106 | fix: fixer => fixer.insertTextBefore(openingCurly, "\n")
|
---|
| 107 | });
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | if (astUtils.isTokenOnSameLine(openingCurly, tokenAfterOpeningCurly) && tokenAfterOpeningCurly !== closingCurly && !singleLineException) {
|
---|
| 111 | context.report({
|
---|
| 112 | node: openingCurly,
|
---|
| 113 | messageId: "blockSameLine",
|
---|
| 114 | fix: fixer => fixer.insertTextAfter(openingCurly, "\n")
|
---|
| 115 | });
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | if (tokenBeforeClosingCurly !== openingCurly && !singleLineException && astUtils.isTokenOnSameLine(tokenBeforeClosingCurly, closingCurly)) {
|
---|
| 119 | context.report({
|
---|
| 120 | node: closingCurly,
|
---|
| 121 | messageId: "singleLineClose",
|
---|
| 122 | fix: fixer => fixer.insertTextBefore(closingCurly, "\n")
|
---|
| 123 | });
|
---|
| 124 | }
|
---|
| 125 | }
|
---|
| 126 |
|
---|
| 127 | /**
|
---|
| 128 | * Validates the location of a token that appears before a keyword (e.g. a newline before `else`)
|
---|
| 129 | * @param {Token} curlyToken The closing curly token. This is assumed to precede a keyword token (such as `else` or `finally`).
|
---|
| 130 | * @returns {void}
|
---|
| 131 | */
|
---|
| 132 | function validateCurlyBeforeKeyword(curlyToken) {
|
---|
| 133 | const keywordToken = sourceCode.getTokenAfter(curlyToken);
|
---|
| 134 |
|
---|
| 135 | if (style === "1tbs" && !astUtils.isTokenOnSameLine(curlyToken, keywordToken)) {
|
---|
| 136 | context.report({
|
---|
| 137 | node: curlyToken,
|
---|
| 138 | messageId: "nextLineClose",
|
---|
| 139 | fix: removeNewlineBetween(curlyToken, keywordToken)
|
---|
| 140 | });
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | if (style !== "1tbs" && astUtils.isTokenOnSameLine(curlyToken, keywordToken)) {
|
---|
| 144 | context.report({
|
---|
| 145 | node: curlyToken,
|
---|
| 146 | messageId: "sameLineClose",
|
---|
| 147 | fix: fixer => fixer.insertTextAfter(curlyToken, "\n")
|
---|
| 148 | });
|
---|
| 149 | }
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | //--------------------------------------------------------------------------
|
---|
| 153 | // Public API
|
---|
| 154 | //--------------------------------------------------------------------------
|
---|
| 155 |
|
---|
| 156 | return {
|
---|
| 157 | BlockStatement(node) {
|
---|
| 158 | if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) {
|
---|
| 159 | validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
|
---|
| 160 | }
|
---|
| 161 | },
|
---|
| 162 | StaticBlock(node) {
|
---|
| 163 | validateCurlyPair(
|
---|
| 164 | sourceCode.getFirstToken(node, { skip: 1 }), // skip the `static` token
|
---|
| 165 | sourceCode.getLastToken(node)
|
---|
| 166 | );
|
---|
| 167 | },
|
---|
| 168 | ClassBody(node) {
|
---|
| 169 | validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
|
---|
| 170 | },
|
---|
| 171 | SwitchStatement(node) {
|
---|
| 172 | const closingCurly = sourceCode.getLastToken(node);
|
---|
| 173 | const openingCurly = sourceCode.getTokenBefore(node.cases.length ? node.cases[0] : closingCurly);
|
---|
| 174 |
|
---|
| 175 | validateCurlyPair(openingCurly, closingCurly);
|
---|
| 176 | },
|
---|
| 177 | IfStatement(node) {
|
---|
| 178 | if (node.consequent.type === "BlockStatement" && node.alternate) {
|
---|
| 179 |
|
---|
| 180 | // Handle the keyword after the `if` block (before `else`)
|
---|
| 181 | validateCurlyBeforeKeyword(sourceCode.getLastToken(node.consequent));
|
---|
| 182 | }
|
---|
| 183 | },
|
---|
| 184 | TryStatement(node) {
|
---|
| 185 |
|
---|
| 186 | // Handle the keyword after the `try` block (before `catch` or `finally`)
|
---|
| 187 | validateCurlyBeforeKeyword(sourceCode.getLastToken(node.block));
|
---|
| 188 |
|
---|
| 189 | if (node.handler && node.finalizer) {
|
---|
| 190 |
|
---|
| 191 | // Handle the keyword after the `catch` block (before `finally`)
|
---|
| 192 | validateCurlyBeforeKeyword(sourceCode.getLastToken(node.handler.body));
|
---|
| 193 | }
|
---|
| 194 | }
|
---|
| 195 | };
|
---|
| 196 | }
|
---|
| 197 | };
|
---|