]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/padded-blocks.js
2 * @fileoverview A rule to ensure blank lines within blocks.
3 * @author Mathias Schreck <https://github.com/lo1tuma>
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
18 /** @type {import('../shared/types').Rule} */
24 description
: "Require or disallow padding within blocks",
26 url
: "https://eslint.org/docs/rules/padded-blocks"
29 fixable
: "whitespace",
35 enum: ["always", "never"]
41 enum: ["always", "never"]
44 enum: ["always", "never"]
47 enum: ["always", "never"]
50 additionalProperties
: false,
58 allowSingleLineBlocks
: {
62 additionalProperties
: false
67 alwaysPadBlock
: "Block must be padded by blank lines.",
68 neverPadBlock
: "Block must not be padded by blank lines."
74 const typeOptions
= context
.options
[0] || "always";
75 const exceptOptions
= context
.options
[1] || {};
77 if (typeof typeOptions
=== "string") {
78 const shouldHavePadding
= typeOptions
=== "always";
80 options
.blocks
= shouldHavePadding
;
81 options
.switches
= shouldHavePadding
;
82 options
.classes
= shouldHavePadding
;
84 if (Object
.prototype.hasOwnProperty
.call(typeOptions
, "blocks")) {
85 options
.blocks
= typeOptions
.blocks
=== "always";
87 if (Object
.prototype.hasOwnProperty
.call(typeOptions
, "switches")) {
88 options
.switches
= typeOptions
.switches
=== "always";
90 if (Object
.prototype.hasOwnProperty
.call(typeOptions
, "classes")) {
91 options
.classes
= typeOptions
.classes
=== "always";
95 if (Object
.prototype.hasOwnProperty
.call(exceptOptions
, "allowSingleLineBlocks")) {
96 options
.allowSingleLineBlocks
= exceptOptions
.allowSingleLineBlocks
=== true;
99 const sourceCode
= context
.getSourceCode();
102 * Gets the open brace token from a given node.
103 * @param {ASTNode} node A BlockStatement or SwitchStatement node from which to get the open brace.
104 * @returns {Token} The token of the open brace.
106 function getOpenBrace(node
) {
107 if (node
.type
=== "SwitchStatement") {
108 return sourceCode
.getTokenBefore(node
.cases
[0]);
111 if (node
.type
=== "StaticBlock") {
112 return sourceCode
.getFirstToken(node
, { skip
: 1 }); // skip the `static` token
115 // `BlockStatement` or `ClassBody`
116 return sourceCode
.getFirstToken(node
);
120 * Checks if the given parameter is a comment node
121 * @param {ASTNode|Token} node An AST node or token
122 * @returns {boolean} True if node is a comment
124 function isComment(node
) {
125 return node
.type
=== "Line" || node
.type
=== "Block";
129 * Checks if there is padding between two tokens
130 * @param {Token} first The first token
131 * @param {Token} second The second token
132 * @returns {boolean} True if there is at least a line between the tokens
134 function isPaddingBetweenTokens(first
, second
) {
135 return second
.loc
.start
.line
- first
.loc
.end
.line
>= 2;
140 * Checks if the given token has a blank line after it.
141 * @param {Token} token The token to check.
142 * @returns {boolean} Whether or not the token is followed by a blank line.
144 function getFirstBlockToken(token
) {
150 first
= sourceCode
.getTokenAfter(first
, { includeComments
: true });
151 } while (isComment(first
) && first
.loc
.start
.line
=== prev
.loc
.end
.line
);
157 * Checks if the given token is preceded by a blank line.
158 * @param {Token} token The token to check
159 * @returns {boolean} Whether or not the token is preceded by a blank line
161 function getLastBlockToken(token
) {
167 last
= sourceCode
.getTokenBefore(last
, { includeComments
: true });
168 } while (isComment(last
) && last
.loc
.end
.line
=== next
.loc
.start
.line
);
174 * Checks if a node should be padded, according to the rule config.
175 * @param {ASTNode} node The AST node to check.
176 * @throws {Error} (Unreachable)
177 * @returns {boolean} True if the node should be padded, false otherwise.
179 function requirePaddingFor(node
) {
181 case "BlockStatement":
183 return options
.blocks
;
184 case "SwitchStatement":
185 return options
.switches
;
187 return options
.classes
;
191 throw new Error("unreachable");
196 * Checks the given BlockStatement node to be padded if the block is not empty.
197 * @param {ASTNode} node The AST node of a BlockStatement.
198 * @returns {void} undefined.
200 function checkPadding(node
) {
201 const openBrace
= getOpenBrace(node
),
202 firstBlockToken
= getFirstBlockToken(openBrace
),
203 tokenBeforeFirst
= sourceCode
.getTokenBefore(firstBlockToken
, { includeComments
: true }),
204 closeBrace
= sourceCode
.getLastToken(node
),
205 lastBlockToken
= getLastBlockToken(closeBrace
),
206 tokenAfterLast
= sourceCode
.getTokenAfter(lastBlockToken
, { includeComments
: true }),
207 blockHasTopPadding
= isPaddingBetweenTokens(tokenBeforeFirst
, firstBlockToken
),
208 blockHasBottomPadding
= isPaddingBetweenTokens(lastBlockToken
, tokenAfterLast
);
210 if (options
.allowSingleLineBlocks
&& astUtils
.isTokenOnSameLine(tokenBeforeFirst
, tokenAfterLast
)) {
214 if (requirePaddingFor(node
)) {
216 if (!blockHasTopPadding
) {
220 start
: tokenBeforeFirst
.loc
.start
,
221 end
: firstBlockToken
.loc
.start
224 return fixer
.insertTextAfter(tokenBeforeFirst
, "\n");
226 messageId
: "alwaysPadBlock"
229 if (!blockHasBottomPadding
) {
233 end
: tokenAfterLast
.loc
.start
,
234 start
: lastBlockToken
.loc
.end
237 return fixer
.insertTextBefore(tokenAfterLast
, "\n");
239 messageId
: "alwaysPadBlock"
243 if (blockHasTopPadding
) {
248 start
: tokenBeforeFirst
.loc
.start
,
249 end
: firstBlockToken
.loc
.start
252 return fixer
.replaceTextRange([tokenBeforeFirst
.range
[1], firstBlockToken
.range
[0] - firstBlockToken
.loc
.start
.column
], "\n");
254 messageId
: "neverPadBlock"
258 if (blockHasBottomPadding
) {
263 end
: tokenAfterLast
.loc
.start
,
264 start
: lastBlockToken
.loc
.end
266 messageId
: "neverPadBlock",
268 return fixer
.replaceTextRange([lastBlockToken
.range
[1], tokenAfterLast
.range
[0] - tokenAfterLast
.loc
.start
.column
], "\n");
277 if (Object
.prototype.hasOwnProperty
.call(options
, "switches")) {
278 rule
.SwitchStatement = function(node
) {
279 if (node
.cases
.length
=== 0) {
286 if (Object
.prototype.hasOwnProperty
.call(options
, "blocks")) {
287 rule
.BlockStatement = function(node
) {
288 if (node
.body
.length
=== 0) {
293 rule
.StaticBlock
= rule
.BlockStatement
;
296 if (Object
.prototype.hasOwnProperty
.call(options
, "classes")) {
297 rule
.ClassBody = function(node
) {
298 if (node
.body
.length
=== 0) {