diff --git a/docs/rules/padded-blocks.md b/docs/rules/padded-blocks.md index d8b855ed37f..85c0a8b9ced 100644 --- a/docs/rules/padded-blocks.md +++ b/docs/rules/padded-blocks.md @@ -27,12 +27,12 @@ The second one is an object option, it can allow exceptions. String option: -* `"always"` (default) requires empty lines at the beginning and ending of block statements and classes -* `"never"` disallows empty lines at the beginning and ending of block statements and classes +* `"always"` (default) requires empty lines at the beginning and ending of block statements, function bodies, class static blocks, classes, and `switch` statements. +* `"never"` disallows empty lines at the beginning and ending of block statements, function bodies, class static blocks, classes, and `switch` statements. Object option: -* `"blocks"` require or disallow padding within block statements +* `"blocks"` require or disallow padding within block statements, function bodies, and class static blocks * `"classes"` require or disallow padding within classes * `"switches"` require or disallow padding within `switch` statements @@ -68,6 +68,12 @@ if (a) { b(); } + +class C { + static { + a(); + } +} ``` Examples of **correct** code for this rule with the default `"always"` option: @@ -93,6 +99,16 @@ if (a) { // comment b(); +} + +class C { + + static { + + a(); + + } + } ``` @@ -124,6 +140,16 @@ if (a) { if (a) { b(); +} + +class C { + + static { + + a(); + + } + } ``` @@ -140,6 +166,12 @@ if (a) { b(); } + +class C { + static { + a(); + } +} ``` ### blocks @@ -174,6 +206,14 @@ if (a) { // comment b(); +} + +class C { + + static { + a(); + } + } ``` @@ -200,6 +240,25 @@ if (a) { // comment b(); +} + +class C { + + static { + + a(); + + } + +} + +class D { + static { + + a(); + + } + } ``` @@ -230,6 +289,14 @@ if (a) { b(); } + +class C { + static { + + a(); + + } +} ``` Examples of **correct** code for this rule with the `{ "blocks": "never" }` option: @@ -245,6 +312,20 @@ if (a) { b(); } + +class C { + static { + a(); + } +} + +class D { + + static { + a(); + } + +} ``` ### classes diff --git a/lib/rules/padded-blocks.js b/lib/rules/padded-blocks.js index ca83f11fc50..de75e8d2d51 100644 --- a/lib/rules/padded-blocks.js +++ b/lib/rules/padded-blocks.js @@ -106,6 +106,12 @@ module.exports = { if (node.type === "SwitchStatement") { return sourceCode.getTokenBefore(node.cases[0]); } + + if (node.type === "StaticBlock") { + return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token + } + + // `BlockStatement` or `ClassBody` return sourceCode.getFirstToken(node); } @@ -172,6 +178,7 @@ module.exports = { function requirePaddingFor(node) { switch (node.type) { case "BlockStatement": + case "StaticBlock": return options.blocks; case "SwitchStatement": return options.switches; @@ -282,6 +289,7 @@ module.exports = { } checkPadding(node); }; + rule.StaticBlock = rule.BlockStatement; } if (Object.prototype.hasOwnProperty.call(options, "classes")) { diff --git a/tests/lib/rules/padded-blocks.js b/tests/lib/rules/padded-blocks.js index 76cfcda51cc..3dd0dc97e18 100644 --- a/tests/lib/rules/padded-blocks.js +++ b/tests/lib/rules/padded-blocks.js @@ -88,7 +88,109 @@ ruleTester.run("padded-blocks", rule, { // Ignore class statements if not configured { code: "class A{\nfoo(){}\n}", options: [{ blocks: "always" }], parserOptions: { ecmaVersion: 6 } }, - { code: "class A{\n\nfoo(){}\n\n}", options: [{ blocks: "never" }], parserOptions: { ecmaVersion: 6 } } + { code: "class A{\n\nfoo(){}\n\n}", options: [{ blocks: "never" }], parserOptions: { ecmaVersion: 6 } }, + + // class static blocks + { + code: "class C {\n\n static {\n\nfoo;\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static {// comment\n\nfoo;\n\n/* comment */} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static {\n\n// comment\nfoo;\n// comment\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static {\n\n// comment\n\nfoo;\n\n// comment\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static { foo; } \n\n}", + options: ["always", { allowSingleLineBlocks: true }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static\n { foo; } \n\n}", + options: ["always", { allowSingleLineBlocks: true }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static {} static {\n} static {\n\n} \n\n}", // empty blocks are ignored + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static\n\n { foo; } \n\n}", + options: ["always", { allowSingleLineBlocks: true }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n\nfoo;\n\n} \n}", + options: [{ blocks: "always", classes: "never" }], // "blocks" applies to static blocks + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {foo;} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static\n {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static\n\n {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static\n\n {foo;} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {// comment\nfoo;\n/* comment */} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n// comment\nfoo;\n// comment\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {} static {\n} static {\n\n} \n}", // empty blocks are ignored + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static {\nfoo;\n} \n\n}", + options: [{ blocks: "never", classes: "always" }], // "blocks" applies to static blocks + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n\n static {\nfoo;\n} static {\n\nfoo;\n\n} \n\n}", + options: [{ classes: "always" }], // if there's no "blocks" in the object option, static blocks are ignored + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\nfoo;\n} static {\n\nfoo;\n\n} \n}", + options: [{ classes: "never" }], // if there's no "blocks" in the object option, static blocks are ignored + parserOptions: { ecmaVersion: 2022 } + } ], invalid: [ @@ -764,6 +866,164 @@ ruleTester.run("padded-blocks", rule, { options: ["never"], parserOptions: { ecmaVersion: 2022 }, errors: [{ messageId: "neverPadBlock" }, { messageId: "neverPadBlock" }] + }, + + // class static blocks + { + code: "class C {\n\n static {\nfoo;\n\n} \n\n}", + output: "class C {\n\n static {\n\nfoo;\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "alwaysPadBlock" }] + }, + { + code: "class C {\n\n static\n {\nfoo;\n\n} \n\n}", + output: "class C {\n\n static\n {\n\nfoo;\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "alwaysPadBlock" }] + }, + { + code: "class C {\n\n static\n\n {\nfoo;\n\n} \n\n}", + output: "class C {\n\n static\n\n {\n\nfoo;\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "alwaysPadBlock" }] + }, + { + code: "class C {\n\n static {\n\nfoo;\n} \n\n}", + output: "class C {\n\n static {\n\nfoo;\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "alwaysPadBlock" }] + }, + { + code: "class C {\n\n static {foo;} \n\n}", + output: "class C {\n\n static {\nfoo;\n} \n\n}", // this is still not padded, the subsequent fix below will add another pair of `\n`. + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "alwaysPadBlock" }, + { messageId: "alwaysPadBlock" } + ] + }, + { + code: "class C {\n\n static {\nfoo;\n} \n\n}", + output: "class C {\n\n static {\n\nfoo;\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "alwaysPadBlock" }, + { messageId: "alwaysPadBlock" } + ] + }, + { + code: "class C {\n\n static {// comment\nfoo;\n/* comment */} \n\n}", + output: "class C {\n\n static {// comment\n\nfoo;\n\n/* comment */} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "alwaysPadBlock" }, + { messageId: "alwaysPadBlock" } + ] + }, + { + code: "class C {\n\n static {\n// comment\nfoo;\n// comment\n} \n\n}", + output: "class C {\n\n static {\n\n// comment\nfoo;\n// comment\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "alwaysPadBlock" }, + { messageId: "alwaysPadBlock" } + ] + }, + { + code: "class C {\n\n static {\n// comment\n\nfoo;\n\n// comment\n} \n\n}", + output: "class C {\n\n static {\n\n// comment\n\nfoo;\n\n// comment\n\n} \n\n}", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "alwaysPadBlock" }, + { messageId: "alwaysPadBlock" } + ] + }, + { + code: "class C {\n static {\nfoo;\n} \n}", + output: "class C {\n static {\n\nfoo;\n\n} \n}", + options: [{ blocks: "always", classes: "never" }], // "blocks" applies to static blocks + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "alwaysPadBlock" }, + { messageId: "alwaysPadBlock" } + ] + }, + { + code: "class C {\n static {\n\nfoo;\n} \n}", + output: "class C {\n static {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "neverPadBlock" }] + }, + { + code: "class C {\n static\n {\n\nfoo;\n} \n}", + output: "class C {\n static\n {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "neverPadBlock" }] + }, + { + code: "class C {\n static\n\n {\n\nfoo;\n} \n}", + output: "class C {\n static\n\n {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "neverPadBlock" }] + }, + { + code: "class C {\n static {\nfoo;\n\n} \n}", + output: "class C {\n static {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "neverPadBlock" }] + }, + { + code: "class C {\n static {\n\nfoo;\n\n} \n}", + output: "class C {\n static {\nfoo;\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "neverPadBlock" }, + { messageId: "neverPadBlock" } + ] + }, + { + code: "class C {\n static {// comment\n\nfoo;\n\n/* comment */} \n}", + output: "class C {\n static {// comment\nfoo;\n/* comment */} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "neverPadBlock" }, + { messageId: "neverPadBlock" } + ] + }, + { + code: "class C {\n static {\n\n// comment\nfoo;\n// comment\n\n} \n}", + output: "class C {\n static {\n// comment\nfoo;\n// comment\n} \n}", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "neverPadBlock" }, + { messageId: "neverPadBlock" } + ] + }, + { + code: "class C {\n\n static {\n\nfoo;\n\n} \n\n}", + output: "class C {\n\n static {\nfoo;\n} \n\n}", + options: [{ blocks: "never", classes: "always" }], // "blocks" applies to static blocks + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "neverPadBlock" }, + { messageId: "neverPadBlock" } + ] } ] });