]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/padded-blocks.js
de75e8d2d51b06d88a8985bb281a6d6e1547b862
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 //------------------------------------------------------------------------------
23 description
: "require or disallow padding within blocks",
25 url
: "https://eslint.org/docs/rules/padded-blocks"
28 fixable
: "whitespace",
34 enum: ["always", "never"]
40 enum: ["always", "never"]
43 enum: ["always", "never"]
46 enum: ["always", "never"]
49 additionalProperties
: false,
57 allowSingleLineBlocks
: {
61 additionalProperties
: false
66 alwaysPadBlock
: "Block must be padded by blank lines.",
67 neverPadBlock
: "Block must not be padded by blank lines."
73 const typeOptions
= context
.options
[0] || "always";
74 const exceptOptions
= context
.options
[1] || {};
76 if (typeof typeOptions
=== "string") {
77 const shouldHavePadding
= typeOptions
=== "always";
79 options
.blocks
= shouldHavePadding
;
80 options
.switches
= shouldHavePadding
;
81 options
.classes
= shouldHavePadding
;
83 if (Object
.prototype.hasOwnProperty
.call(typeOptions
, "blocks")) {
84 options
.blocks
= typeOptions
.blocks
=== "always";
86 if (Object
.prototype.hasOwnProperty
.call(typeOptions
, "switches")) {
87 options
.switches
= typeOptions
.switches
=== "always";
89 if (Object
.prototype.hasOwnProperty
.call(typeOptions
, "classes")) {
90 options
.classes
= typeOptions
.classes
=== "always";
94 if (Object
.prototype.hasOwnProperty
.call(exceptOptions
, "allowSingleLineBlocks")) {
95 options
.allowSingleLineBlocks
= exceptOptions
.allowSingleLineBlocks
=== true;
98 const sourceCode
= context
.getSourceCode();
101 * Gets the open brace token from a given node.
102 * @param {ASTNode} node A BlockStatement or SwitchStatement node from which to get the open brace.
103 * @returns {Token} The token of the open brace.
105 function getOpenBrace(node
) {
106 if (node
.type
=== "SwitchStatement") {
107 return sourceCode
.getTokenBefore(node
.cases
[0]);
110 if (node
.type
=== "StaticBlock") {
111 return sourceCode
.getFirstToken(node
, { skip
: 1 }); // skip the `static` token
114 // `BlockStatement` or `ClassBody`
115 return sourceCode
.getFirstToken(node
);
119 * Checks if the given parameter is a comment node
120 * @param {ASTNode|Token} node An AST node or token
121 * @returns {boolean} True if node is a comment
123 function isComment(node
) {
124 return node
.type
=== "Line" || node
.type
=== "Block";
128 * Checks if there is padding between two tokens
129 * @param {Token} first The first token
130 * @param {Token} second The second token
131 * @returns {boolean} True if there is at least a line between the tokens
133 function isPaddingBetweenTokens(first
, second
) {
134 return second
.loc
.start
.line
- first
.loc
.end
.line
>= 2;
139 * Checks if the given token has a blank line after it.
140 * @param {Token} token The token to check.
141 * @returns {boolean} Whether or not the token is followed by a blank line.
143 function getFirstBlockToken(token
) {
149 first
= sourceCode
.getTokenAfter(first
, { includeComments
: true });
150 } while (isComment(first
) && first
.loc
.start
.line
=== prev
.loc
.end
.line
);
156 * Checks if the given token is preceded by a blank line.
157 * @param {Token} token The token to check
158 * @returns {boolean} Whether or not the token is preceded by a blank line
160 function getLastBlockToken(token
) {
166 last
= sourceCode
.getTokenBefore(last
, { includeComments
: true });
167 } while (isComment(last
) && last
.loc
.end
.line
=== next
.loc
.start
.line
);
173 * Checks if a node should be padded, according to the rule config.
174 * @param {ASTNode} node The AST node to check.
175 * @throws {Error} (Unreachable)
176 * @returns {boolean} True if the node should be padded, false otherwise.
178 function requirePaddingFor(node
) {
180 case "BlockStatement":
182 return options
.blocks
;
183 case "SwitchStatement":
184 return options
.switches
;
186 return options
.classes
;
188 /* istanbul ignore next */
190 throw new Error("unreachable");
195 * Checks the given BlockStatement node to be padded if the block is not empty.
196 * @param {ASTNode} node The AST node of a BlockStatement.
197 * @returns {void} undefined.
199 function checkPadding(node
) {
200 const openBrace
= getOpenBrace(node
),
201 firstBlockToken
= getFirstBlockToken(openBrace
),
202 tokenBeforeFirst
= sourceCode
.getTokenBefore(firstBlockToken
, { includeComments
: true }),
203 closeBrace
= sourceCode
.getLastToken(node
),
204 lastBlockToken
= getLastBlockToken(closeBrace
),
205 tokenAfterLast
= sourceCode
.getTokenAfter(lastBlockToken
, { includeComments
: true }),
206 blockHasTopPadding
= isPaddingBetweenTokens(tokenBeforeFirst
, firstBlockToken
),
207 blockHasBottomPadding
= isPaddingBetweenTokens(lastBlockToken
, tokenAfterLast
);
209 if (options
.allowSingleLineBlocks
&& astUtils
.isTokenOnSameLine(tokenBeforeFirst
, tokenAfterLast
)) {
213 if (requirePaddingFor(node
)) {
215 if (!blockHasTopPadding
) {
219 start
: tokenBeforeFirst
.loc
.start
,
220 end
: firstBlockToken
.loc
.start
223 return fixer
.insertTextAfter(tokenBeforeFirst
, "\n");
225 messageId
: "alwaysPadBlock"
228 if (!blockHasBottomPadding
) {
232 end
: tokenAfterLast
.loc
.start
,
233 start
: lastBlockToken
.loc
.end
236 return fixer
.insertTextBefore(tokenAfterLast
, "\n");
238 messageId
: "alwaysPadBlock"
242 if (blockHasTopPadding
) {
247 start
: tokenBeforeFirst
.loc
.start
,
248 end
: firstBlockToken
.loc
.start
251 return fixer
.replaceTextRange([tokenBeforeFirst
.range
[1], firstBlockToken
.range
[0] - firstBlockToken
.loc
.start
.column
], "\n");
253 messageId
: "neverPadBlock"
257 if (blockHasBottomPadding
) {
262 end
: tokenAfterLast
.loc
.start
,
263 start
: lastBlockToken
.loc
.end
265 messageId
: "neverPadBlock",
267 return fixer
.replaceTextRange([lastBlockToken
.range
[1], tokenAfterLast
.range
[0] - tokenAfterLast
.loc
.start
.column
], "\n");
276 if (Object
.prototype.hasOwnProperty
.call(options
, "switches")) {
277 rule
.SwitchStatement = function(node
) {
278 if (node
.cases
.length
=== 0) {
285 if (Object
.prototype.hasOwnProperty
.call(options
, "blocks")) {
286 rule
.BlockStatement = function(node
) {
287 if (node
.body
.length
=== 0) {
292 rule
.StaticBlock
= rule
.BlockStatement
;
295 if (Object
.prototype.hasOwnProperty
.call(options
, "classes")) {
296 rule
.ClassBody = function(node
) {
297 if (node
.body
.length
=== 0) {