From 9b666e0682bacf44d2a5afa0023874b8b131b5f5 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Wed, 17 Nov 2021 02:32:19 +0100 Subject: [PATCH] feat: update padding-line-between-statements for class static blocks (#15318) Updates the `padding-line-between-statements` rule to apply to the top level of class static blocks. Refs #15016 --- docs/rules/padding-line-between-statements.md | 16 ++ lib/rules/padding-line-between-statements.js | 2 + lib/rules/utils/ast-utils.js | 2 +- .../rules/padding-line-between-statements.js | 219 ++++++++++++++++++ 4 files changed, 238 insertions(+), 1 deletion(-) diff --git a/docs/rules/padding-line-between-statements.md b/docs/rules/padding-line-between-statements.md index 2f2f67ee07c..065c7d937c9 100644 --- a/docs/rules/padding-line-between-statements.md +++ b/docs/rules/padding-line-between-statements.md @@ -147,6 +147,13 @@ function foo() { const a = 0; bar(); } + +class C { + static { + let a = 0; + bar(); + } +} ``` Examples of **correct** code for the `[{ blankLine: "always", prev: ["const", "let", "var"], next: "*"}, { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]}]` configuration: @@ -178,6 +185,15 @@ function foo() { bar(); } + +class C { + static { + let a = 0; + let b = 0; + + bar(); + } +} ``` ---- diff --git a/lib/rules/padding-line-between-statements.js b/lib/rules/padding-line-between-statements.js index 073940a40eb..42859dd38b0 100644 --- a/lib/rules/padding-line-between-statements.js +++ b/lib/rules/padding-line-between-statements.js @@ -618,9 +618,11 @@ module.exports = { Program: enterScope, BlockStatement: enterScope, SwitchStatement: enterScope, + StaticBlock: enterScope, "Program:exit": exitScope, "BlockStatement:exit": exitScope, "SwitchStatement:exit": exitScope, + "StaticBlock:exit": exitScope, ":statement": verify, diff --git a/lib/rules/utils/ast-utils.js b/lib/rules/utils/ast-utils.js index 1d02d8a753a..17ab533b366 100644 --- a/lib/rules/utils/ast-utils.js +++ b/lib/rules/utils/ast-utils.js @@ -35,7 +35,7 @@ const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|g const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]); // A set of node types that can contain a list of statements -const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]); +const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "StaticBlock", "SwitchCase"]); const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u; diff --git a/tests/lib/rules/padding-line-between-statements.js b/tests/lib/rules/padding-line-between-statements.js index 931cdd24ccb..51ddf0eb3b5 100644 --- a/tests/lib/rules/padding-line-between-statements.js +++ b/tests/lib/rules/padding-line-between-statements.js @@ -2626,6 +2626,114 @@ ruleTester.run("padding-line-between-statements", rule, { options: [ { blankLine: "always", prev: "block-like", next: "block-like" } ] + }, + + // class static blocks + { + code: "class C {\n static {\n let x;\n\n foo();\n }\n }", + options: [ + { blankLine: "always", prev: "let", next: "expression" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n let x;\n foo();\n }\n }", + options: [ + { blankLine: "never", prev: "let", next: "expression" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n let x;\n foo();\n\n const y = 1;\n }\n }", + options: [ + { blankLine: "always", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n let x;\n foo();\n const y = 1;\n }\n }", + options: [ + { blankLine: "never", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n let x;\n foo();\n\n const y = 1;\n const z = 1;\n }\n }", + options: [ + { blankLine: "always", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n let x;\n foo();\n const y = 1;\n const z = 1;\n }\n }", + options: [ + { blankLine: "never", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C {\n static {\n let a = 0;\n let b =0;\n\n bar();\n }\n }", + options: [ + { blankLine: "always", prev: ["const", "let", "var"], next: "*" }, + { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"] } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let x; { let y; } let z; } }", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { method() { let x; } static { let y; } }", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let y; } method() { let x; } }", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let x; } static { let y; } }", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "let x; class C { static { let y; } }", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let x; } } let y;", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let x; } }", + options: [ + { blankLine: "always", prev: "class", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { 'use strict'; let x; } }", // 'use strict'; is "espression", because class static blocks don't have directives + options: [ + { blankLine: "always", prev: "directive", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 } } ], invalid: [ @@ -4976,6 +5084,117 @@ ruleTester.run("padding-line-between-statements", rule, { { messageId: "expectedBlankLine" }, { messageId: "expectedBlankLine" } ] + }, + + // class static blocks + { + code: "class C {\n static {\n let x;\n foo();\n }\n }", + output: "class C {\n static {\n let x;\n\n foo();\n }\n }", + options: [ + { blankLine: "always", prev: "let", next: "expression" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C {\n static {\n let x;\n\n foo();\n }\n }", + output: "class C {\n static {\n let x;\n foo();\n }\n }", + options: [ + { blankLine: "never", prev: "let", next: "expression" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "unexpectedBlankLine" }] + }, + { + code: "class C {\n static {\n let x;\n foo();\n const y = 1;\n }\n }", + output: "class C {\n static {\n let x;\n foo();\n\n const y = 1;\n }\n }", + options: [ + { blankLine: "always", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C {\n static {\n let x;\n foo();\n\n const y = 1;\n }\n }", + output: "class C {\n static {\n let x;\n foo();\n const y = 1;\n }\n }", + options: [ + { blankLine: "never", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "unexpectedBlankLine" }] + }, + { + code: "class C {\n static {\n let x;\n foo();\n const y = 1;\n const z = 1;\n }\n }", + output: "class C {\n static {\n let x;\n foo();\n\n const y = 1;\n const z = 1;\n }\n }", + options: [ + { blankLine: "always", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C {\n static {\n let x;\n foo();\n\n const y = 1;\n const z = 1;\n }\n }", + output: "class C {\n static {\n let x;\n foo();\n const y = 1;\n const z = 1;\n }\n }", + options: [ + { blankLine: "never", prev: "expression", next: "const" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "unexpectedBlankLine" }] + }, + { + code: "class C {\n static {\n let a = 0;\n bar();\n }\n }", + output: "class C {\n static {\n let a = 0;\n\n bar();\n }\n }", + options: [ + { blankLine: "always", prev: ["const", "let", "var"], next: "*" }, + { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"] } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C { static { let x; { let y; let z; } let q; } }", + output: "class C { static { let x; { let y;\n\n let z; } let q; } }", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C { static { { let x; } let y; let z; } }", + output: "class C { static { { let x; } let y;\n\n let z; } }", + options: [ + { blankLine: "always", prev: "let", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C { static { foo(); if (bar) {} } }", + output: "class C { static { foo();\n\n if (bar) {} } }", + options: [ + { blankLine: "always", prev: "expression", next: "block-like" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C { static { let x; } } let y;", + output: "class C { static { let x; } }\n\n let y;", + options: [ + { blankLine: "always", prev: "class", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] + }, + { + code: "class C { static { 'use strict'; let x; } }", // 'use strict'; is "espression", because class static blocks don't have directives + output: "class C { static { 'use strict';\n\n let x; } }", + options: [ + { blankLine: "always", prev: "expression", next: "let" } + ], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "expectedBlankLine" }] } ] });