From f03cd146a97ed312d635ac7b53ba0f8d01aa8b47 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 19 Nov 2021 11:58:30 +0100 Subject: [PATCH] feat: update lines-around-comment for class static blocks (#15323) Updates the `lines-around-comment` rule so that options `"allowBlockStart"` and `"allowBlockEnd"` apply to class static blocks. Refs #15016 --- docs/rules/lines-around-comment.md | 85 +++- lib/rules/lines-around-comment.js | 61 ++- tests/lib/rules/lines-around-comment.js | 491 +++++++++++++++++++++++- 3 files changed, 627 insertions(+), 10 deletions(-) diff --git a/docs/rules/lines-around-comment.md b/docs/rules/lines-around-comment.md index ae543bd837b..fb016110272 100644 --- a/docs/rules/lines-around-comment.md +++ b/docs/rules/lines-around-comment.md @@ -15,8 +15,8 @@ This rule has an object option: * `"afterBlockComment": true` requires an empty line after block comments * `"beforeLineComment": true` requires an empty line before line comments * `"afterLineComment": true` requires an empty line after line comments -* `"allowBlockStart": true` allows comments to appear at the start of block statements -* `"allowBlockEnd": true` allows comments to appear at the end of block statements +* `"allowBlockStart": true` allows comments to appear at the start of block statements, function bodies, classes, and class static blocks +* `"allowBlockEnd": true` allows comments to appear at the end of block statements, function bodies, classes, and class static blocks * `"allowObjectStart": true` allows comments to appear at the start of object literals * `"allowObjectEnd": true` allows comments to appear at the end of object literals * `"allowArrayStart": true` allows comments to appear at the start of array literals @@ -133,6 +133,25 @@ function foo(){ var day = "great" return day; } + +if (bar) { + // what a great and wonderful day + foo(); +} + +class C { + // what a great and wonderful day + + method() { + // what a great and wonderful day + foo(); + } + + static { + // what a great and wonderful day + foo(); + } +} ``` Examples of **correct** code for this rule with the `{ "beforeBlockComment": true, "allowBlockStart": true }` options: @@ -145,6 +164,25 @@ function foo(){ var day = "great" return day; } + +if (bar) { + /* what a great and wonderful day */ + foo(); +} + +class C { + /* what a great and wonderful day */ + + method() { + /* what a great and wonderful day */ + foo(); + } + + static { + /* what a great and wonderful day */ + foo(); + } +} ``` ### allowBlockEnd @@ -159,6 +197,26 @@ function foo(){ return day; // what a great and wonderful day } + +if (bar) { + foo(); + // what a great and wonderful day +} + +class C { + + method() { + foo(); + // what a great and wonderful day + } + + static { + foo(); + // what a great and wonderful day + } + + // what a great and wonderful day +} ``` Examples of **correct** code for this rule with the `{ "afterBlockComment": true, "allowBlockEnd": true }` option: @@ -172,6 +230,29 @@ function foo(){ /* what a great and wonderful day */ } + +if (bar) { + foo(); + + /* what a great and wonderful day */ +} + +class C { + + method() { + foo(); + + /* what a great and wonderful day */ + } + + static { + foo(); + + /* what a great and wonderful day */ + } + + /* what a great and wonderful day */ +} ``` ### allowClassStart diff --git a/lib/rules/lines-around-comment.js b/lib/rules/lines-around-comment.js index 79bcbb7fc19..513d196224e 100644 --- a/lib/rules/lines-around-comment.js +++ b/lib/rules/lines-around-comment.js @@ -185,10 +185,39 @@ module.exports = { /** * Returns the parent node that contains the given token. * @param {token} token The token to check. - * @returns {ASTNode} The parent node that contains the given token. + * @returns {ASTNode|null} The parent node that contains the given token. */ function getParentNodeOfToken(token) { - return sourceCode.getNodeByRangeIndex(token.range[0]); + const node = sourceCode.getNodeByRangeIndex(token.range[0]); + + /* + * For the purpose of this rule, the comment token is in a `StaticBlock` node only + * if it's inside the braces of that `StaticBlock` node. + * + * Example where this function returns `null`: + * + * static + * // comment + * { + * } + * + * Example where this function returns `StaticBlock` node: + * + * static + * { + * // comment + * } + * + */ + if (node && node.type === "StaticBlock") { + const openingBrace = sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token + + return token.range[0] >= openingBrace.range[0] + ? node + : null; + } + + return node; } /** @@ -200,8 +229,15 @@ module.exports = { function isCommentAtParentStart(token, nodeType) { const parent = getParentNodeOfToken(token); - return parent && isParentNodeType(parent, nodeType) && - token.loc.start.line - parent.loc.start.line === 1; + if (parent && isParentNodeType(parent, nodeType)) { + const parentStartNodeOrToken = parent.type === "StaticBlock" + ? sourceCode.getFirstToken(parent, { skip: 1 }) // opening brace of the static block + : parent; + + return token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1; + } + + return false; } /** @@ -213,7 +249,7 @@ module.exports = { function isCommentAtParentEnd(token, nodeType) { const parent = getParentNodeOfToken(token); - return parent && isParentNodeType(parent, nodeType) && + return !!parent && isParentNodeType(parent, nodeType) && parent.loc.end.line - token.loc.end.line === 1; } @@ -223,7 +259,12 @@ module.exports = { * @returns {boolean} True if the comment is at block start. */ function isCommentAtBlockStart(token) { - return isCommentAtParentStart(token, "ClassBody") || isCommentAtParentStart(token, "BlockStatement") || isCommentAtParentStart(token, "SwitchCase"); + return ( + isCommentAtParentStart(token, "ClassBody") || + isCommentAtParentStart(token, "BlockStatement") || + isCommentAtParentStart(token, "StaticBlock") || + isCommentAtParentStart(token, "SwitchCase") + ); } /** @@ -232,7 +273,13 @@ module.exports = { * @returns {boolean} True if the comment is at block end. */ function isCommentAtBlockEnd(token) { - return isCommentAtParentEnd(token, "ClassBody") || isCommentAtParentEnd(token, "BlockStatement") || isCommentAtParentEnd(token, "SwitchCase") || isCommentAtParentEnd(token, "SwitchStatement"); + return ( + isCommentAtParentEnd(token, "ClassBody") || + isCommentAtParentEnd(token, "BlockStatement") || + isCommentAtParentEnd(token, "StaticBlock") || + isCommentAtParentEnd(token, "SwitchCase") || + isCommentAtParentEnd(token, "SwitchStatement") + ); } /** diff --git a/tests/lib/rules/lines-around-comment.js b/tests/lib/rules/lines-around-comment.js index a4fd3dd70e2..2687f1458aa 100644 --- a/tests/lib/rules/lines-around-comment.js +++ b/tests/lib/rules/lines-around-comment.js @@ -9,7 +9,8 @@ //------------------------------------------------------------------------------ const rule = require("../../../lib/rules/lines-around-comment"), - { RuleTester } = require("../../../lib/rule-tester"); + { RuleTester } = require("../../../lib/rule-tester"), + { unIndent } = require("../../_utils"); //------------------------------------------------------------------------------ // Tests @@ -262,6 +263,106 @@ ruleTester.run("lines-around-comment", rule, { allowBlockStart: true }] }, + { + code: unIndent` + class C { + static { + // line comment + } + + static { + // line comment + foo(); + } + }`, + options: [{ + beforeLineComment: true, + allowBlockStart: true + }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: unIndent` + class C { + static + { + // line comment + } + + static + { + // line comment + foo(); + } + }`, + options: [{ + beforeLineComment: true, + allowBlockStart: true + }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: unIndent` + class C { + static { + /* block comment */ + } + + static { + /* block + comment */ + } + + static { + /* block comment */ + foo(); + } + + static { + /* block + comment */ + foo(); + } + }`, + options: [{ + beforeBlockComment: true, + allowBlockStart: true + }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: unIndent` + class C { + static + { + /* block comment */ + } + + static + { + /* block + comment */ + } + + static + { + /* block comment */ + foo(); + } + + static + { + /* block + comment */ + foo(); + } + }`, + options: [{ + beforeBlockComment: true, + allowBlockStart: true + }], + parserOptions: { ecmaVersion: 2022 } + }, // check for block end comments { @@ -472,6 +573,54 @@ ruleTester.run("lines-around-comment", rule, { allowBlockEnd: true }] }, + { + code: unIndent` + class C { + static { + // line comment + } + + static { + foo(); + // line comment + } + }`, + options: [{ + afterLineComment: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: unIndent` + class C { + static { + /* block comment */ + } + + static { + /* block + comment */ + } + + static { + foo(); + /* block comment */ + } + + static { + foo(); + /* block + comment */ + } + }`, + options: [{ + beforeBlockComment: false, // default is `true` + afterBlockComment: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 } + }, // check for object start comments { @@ -1049,6 +1198,346 @@ ruleTester.run("lines-around-comment", rule, { }], errors: [{ messageId: "after", type: "Line", line: 8 }] }, + { + code: unIndent` + class C { + // line comment + static{} + }`, + output: unIndent` + class C { + // line comment + + static{} + }`, + options: [{ + beforeLineComment: true, + afterLineComment: true, + allowBlockStart: true, + allowBlockEnd: true, + allowClassStart: true, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "after", type: "Line", line: 2 } + ] + }, + { + code: unIndent` + class C { + /* block + comment */ + static{} + }`, + output: unIndent` + class C { + /* block + comment */ + + static{} + }`, + options: [{ + beforeBlockComment: true, + afterBlockComment: true, + allowBlockStart: true, + allowBlockEnd: true, + allowClassStart: true, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "after", type: "Block", line: 2 } + ] + }, + { + code: unIndent` + class C { + static + // line comment + {} + }`, + output: unIndent` + class C { + static + + // line comment + + {} + }`, + options: [{ + beforeLineComment: true, + afterLineComment: true, + allowBlockStart: true, + allowBlockEnd: true, + allowClassStart: true, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Line", line: 3 }, + { messageId: "after", type: "Line", line: 3 } + ] + }, + { + code: unIndent` + class C { + static + /* block + comment */ + {} + }`, + output: unIndent` + class C { + static + + /* block + comment */ + + {} + }`, + options: [{ + beforeBlockComment: true, + afterBlockComment: true, + allowBlockStart: true, + allowBlockEnd: true, + allowClassStart: true, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Block", line: 3 }, + { messageId: "after", type: "Block", line: 3 } + ] + }, + { + code: unIndent` + class C { + static { + // line comment + foo(); + } + }`, + output: unIndent` + class C { + static { + // line comment + + foo(); + } + }`, + options: [{ + beforeLineComment: true, + afterLineComment: true, + allowBlockStart: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "after", type: "Line", line: 3 } + ] + }, + { + code: unIndent` + class C { + static { + /* block + comment */ + foo(); + } + }`, + output: unIndent` + class C { + static { + /* block + comment */ + + foo(); + } + }`, + options: [{ + beforeBlockComment: true, + afterBlockComment: true, + allowBlockStart: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "after", type: "Block", line: 3 } + ] + }, + { + code: unIndent` + class C { + static { + foo(); + // line comment + } + }`, + output: unIndent` + class C { + static { + foo(); + + // line comment + } + }`, + options: [{ + beforeLineComment: true, + afterLineComment: true, + allowBlockStart: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Line", line: 4 } + ] + }, + { + code: unIndent` + class C { + static { + foo(); + /* block + comment */ + } + }`, + output: unIndent` + class C { + static { + foo(); + + /* block + comment */ + } + }`, + options: [{ + beforeBlockComment: true, + afterBlockComment: true, + allowBlockStart: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Block", line: 4 } + ] + }, + { + code: unIndent` + class C { + static { + foo(); + // line comment + bar(); + } + }`, + output: unIndent` + class C { + static { + foo(); + + // line comment + + bar(); + } + }`, + options: [{ + beforeLineComment: true, + afterLineComment: true, + allowBlockStart: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Line", line: 4 }, + { messageId: "after", type: "Line", line: 4 } + ] + }, + { + code: unIndent` + class C { + static { + foo(); + /* block + comment */ + bar(); + } + }`, + output: unIndent` + class C { + static { + foo(); + + /* block + comment */ + + bar(); + } + }`, + options: [{ + beforeBlockComment: true, + afterBlockComment: true, + allowBlockStart: true, + allowBlockEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Block", line: 4 }, + { messageId: "after", type: "Block", line: 4 } + ] + }, + { + code: unIndent` + class C { + static{} + // line comment + }`, + output: unIndent` + class C { + static{} + + // line comment + }`, + options: [{ + beforeLineComment: true, + afterLineComment: true, + allowBlockStart: true, + allowBlockEnd: true, + allowClassStart: true, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Line", line: 3 } + ] + }, + { + code: unIndent` + class C { + static{} + /* block + comment */ + }`, + output: unIndent` + class C { + static{} + + /* block + comment */ + }`, + options: [{ + beforeBlockComment: true, + afterBlockComment: true, + allowBlockStart: true, + allowBlockEnd: true, + allowClassStart: true, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "before", type: "Block", line: 3 } + ] + }, // object start comments {