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 | };
|
---|