]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/block-spacing.js
990b441e34dd8a7636b9d32c1bb245c8cd35e9bc
[pve-eslint.git] / eslint / lib / rules / block-spacing.js
1 /**
2 * @fileoverview A rule to disallow or enforce spaces inside of single line blocks.
3 * @author Toru Nagashima
4 */
5
6 "use strict";
7
8 const util = require("./utils/ast-utils");
9
10 //------------------------------------------------------------------------------
11 // Rule Definition
12 //------------------------------------------------------------------------------
13
14 module.exports = {
15 meta: {
16 type: "layout",
17
18 docs: {
19 description: "disallow or enforce spaces inside of blocks after opening block and before closing block",
20 recommended: false,
21 url: "https://eslint.org/docs/rules/block-spacing"
22 },
23
24 fixable: "whitespace",
25
26 schema: [
27 { enum: ["always", "never"] }
28 ],
29
30 messages: {
31 missing: "Requires a space {{location}} '{{token}}'.",
32 extra: "Unexpected space(s) {{location}} '{{token}}'."
33 }
34 },
35
36 create(context) {
37 const always = (context.options[0] !== "never"),
38 messageId = always ? "missing" : "extra",
39 sourceCode = context.getSourceCode();
40
41 /**
42 * Gets the open brace token from a given node.
43 * @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to get.
44 * @returns {Token} The token of the open brace.
45 */
46 function getOpenBrace(node) {
47 if (node.type === "SwitchStatement") {
48 if (node.cases.length > 0) {
49 return sourceCode.getTokenBefore(node.cases[0]);
50 }
51 return sourceCode.getLastToken(node, 1);
52 }
53
54 if (node.type === "StaticBlock") {
55 return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
56 }
57
58 // "BlockStatement"
59 return sourceCode.getFirstToken(node);
60 }
61
62 /**
63 * Checks whether or not:
64 * - given tokens are on same line.
65 * - there is/isn't a space between given tokens.
66 * @param {Token} left A token to check.
67 * @param {Token} right The token which is next to `left`.
68 * @returns {boolean}
69 * When the option is `"always"`, `true` if there are one or more spaces between given tokens.
70 * When the option is `"never"`, `true` if there are not any spaces between given tokens.
71 * If given tokens are not on same line, it's always `true`.
72 */
73 function isValid(left, right) {
74 return (
75 !util.isTokenOnSameLine(left, right) ||
76 sourceCode.isSpaceBetweenTokens(left, right) === always
77 );
78 }
79
80 /**
81 * Checks and reports invalid spacing style inside braces.
82 * @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to check.
83 * @returns {void}
84 */
85 function checkSpacingInsideBraces(node) {
86
87 // Gets braces and the first/last token of content.
88 const openBrace = getOpenBrace(node);
89 const closeBrace = sourceCode.getLastToken(node);
90 const firstToken = sourceCode.getTokenAfter(openBrace, { includeComments: true });
91 const lastToken = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
92
93 // Skip if the node is invalid or empty.
94 if (openBrace.type !== "Punctuator" ||
95 openBrace.value !== "{" ||
96 closeBrace.type !== "Punctuator" ||
97 closeBrace.value !== "}" ||
98 firstToken === closeBrace
99 ) {
100 return;
101 }
102
103 // Skip line comments for option never
104 if (!always && firstToken.type === "Line") {
105 return;
106 }
107
108 // Check.
109 if (!isValid(openBrace, firstToken)) {
110 let loc = openBrace.loc;
111
112 if (messageId === "extra") {
113 loc = {
114 start: openBrace.loc.end,
115 end: firstToken.loc.start
116 };
117 }
118
119 context.report({
120 node,
121 loc,
122 messageId,
123 data: {
124 location: "after",
125 token: openBrace.value
126 },
127 fix(fixer) {
128 if (always) {
129 return fixer.insertTextBefore(firstToken, " ");
130 }
131
132 return fixer.removeRange([openBrace.range[1], firstToken.range[0]]);
133 }
134 });
135 }
136 if (!isValid(lastToken, closeBrace)) {
137 let loc = closeBrace.loc;
138
139 if (messageId === "extra") {
140 loc = {
141 start: lastToken.loc.end,
142 end: closeBrace.loc.start
143 };
144 }
145 context.report({
146 node,
147 loc,
148 messageId,
149 data: {
150 location: "before",
151 token: closeBrace.value
152 },
153 fix(fixer) {
154 if (always) {
155 return fixer.insertTextAfter(lastToken, " ");
156 }
157
158 return fixer.removeRange([lastToken.range[1], closeBrace.range[0]]);
159 }
160 });
161 }
162 }
163
164 return {
165 BlockStatement: checkSpacingInsideBraces,
166 StaticBlock: checkSpacingInsideBraces,
167 SwitchStatement: checkSpacingInsideBraces
168 };
169 }
170 };