diff --git a/docs/rules/lines-around-comment.md b/docs/rules/lines-around-comment.md index f0b5c22576a..ae8ef4de778 100644 --- a/docs/rules/lines-around-comment.md +++ b/docs/rules/lines-around-comment.md @@ -172,6 +172,101 @@ function foo(){ } ``` +### allowClassStart + +Examples of **incorrect** code for this rule with the `{ "beforeLineComment": true, "allowClassStart": false }` option: + +```js +/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowClassStart": false }]*/ + +class foo { + // what a great and wonderful day + day() {} +}; +``` + +Examples of **correct** code for this rule with the `{ "beforeLineComment": true, "allowClassStart": false }` option: + +```js +/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowClassStart": false }]*/ + +class foo { + + // what a great and wonderful day + day() {} +}; +``` + +Examples of **correct** code for this rule with the `{ "beforeLineComment": true, "allowClassStart": true }` option: + +```js +/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowClassStart": true }]*/ + +class foo { + // what a great and wonderful day + day() {} +}; +``` + +Examples of **incorrect** code for this rule with the `{ "beforeBlockComment": true, "allowClassStart": false }` option: + +```js +/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowClassStart": false }]*/ + +class foo { + /* what a great and wonderful day */ + day() {} +}; +``` + +Examples of **correct** code for this rule with the `{ "beforeBlockComment": true, "allowClassStart": false }` option: + +```js +/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowClassStart": false }]*/ + +class foo { + + /* what a great and wonderful day */ + day() {} +}; +``` + +Examples of **correct** code for this rule with the `{ "beforeBlockComment": true, "allowClassStart": true }` option: + +```js +/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowClassStart": true }]*/ + +class foo { + /* what a great and wonderful day */ + day() {} +}; +``` + +### allowClassEnd + +Examples of **correct** code for this rule with the `{ "afterLineComment": true, "allowClassEnd": true }` option: + +```js +/*eslint lines-around-comment: ["error", { "afterLineComment": true, "allowClassEnd": true }]*/ + +class foo { + day() {} + // what a great and wonderful day +}; +``` + +Examples of **correct** code for this rule with the `{ "afterBlockComment": true, "allowClassEnd": true }` option: + +```js +/*eslint lines-around-comment: ["error", { "afterBlockComment": true, "allowClassEnd": true }]*/ + +class foo { + day() {} + + /* what a great and wonderful day */ +}; +``` + ### allowObjectStart Examples of **correct** code for this rule with the `{ "beforeLineComment": true, "allowObjectStart": true }` option: diff --git a/lib/rules/lines-around-comment.js b/lib/rules/lines-around-comment.js index 5b4cd8ebe92..6c130c22b22 100644 --- a/lib/rules/lines-around-comment.js +++ b/lib/rules/lines-around-comment.js @@ -82,6 +82,12 @@ module.exports = { allowBlockEnd: { type: "boolean" }, + allowClassStart: { + type: "boolean" + }, + allowClassEnd: { + type: "boolean" + }, allowObjectStart: { type: "boolean" }, @@ -224,6 +230,24 @@ module.exports = { return isCommentAtParentEnd(token, "ClassBody") || isCommentAtParentEnd(token, "BlockStatement") || isCommentAtParentEnd(token, "SwitchCase") || isCommentAtParentEnd(token, "SwitchStatement"); } + /** + * Returns whether or not comments are at the class start or not. + * @param {token} token The Comment token. + * @returns {boolean} True if the comment is at class start. + */ + function isCommentAtClassStart(token) { + return isCommentAtParentStart(token, "ClassBody"); + } + + /** + * Returns whether or not comments are at the class end or not. + * @param {token} token The Comment token. + * @returns {boolean} True if the comment is at class end. + */ + function isCommentAtClassEnd(token) { + return isCommentAtParentEnd(token, "ClassBody"); + } + /** * Returns whether or not comments are at the object start or not. * @param {token} token The Comment token. @@ -284,15 +308,17 @@ module.exports = { nextLineNum = token.loc.end.line + 1, commentIsNotAlone = codeAroundComment(token); - const blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(token), - blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(token), + const blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(token) && !(options.allowClassStart === false && isCommentAtClassStart(token)), + blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(token) && !(options.allowClassEnd === false && isCommentAtClassEnd(token)), + classStartAllowed = options.allowClassStart && isCommentAtClassStart(token), + classEndAllowed = options.allowClassEnd && isCommentAtClassEnd(token), objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(token), objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(token), arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(token), arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(token); - const exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed; - const exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed; + const exceptionStartAllowed = blockStartAllowed || classStartAllowed || objectStartAllowed || arrayStartAllowed; + const exceptionEndAllowed = blockEndAllowed || classEndAllowed || objectEndAllowed || arrayEndAllowed; // ignore top of the file and bottom of the file if (prevLineNum < 1) { diff --git a/tests/lib/rules/lines-around-comment.js b/tests/lib/rules/lines-around-comment.js index b47f74401bc..07fea8ea8e2 100644 --- a/tests/lib/rules/lines-around-comment.js +++ b/tests/lib/rules/lines-around-comment.js @@ -221,12 +221,24 @@ ruleTester.run("lines-around-comment", rule, { }, { code: "class A {\n/**\n* hi\n */\nconstructor() {}\n}", - options: [{ allowBlockStart: true }], + options: [{ + allowBlockStart: true + }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A {\n/**\n* hi\n */\nconstructor() {}\n}", + options: [{ + allowClassStart: true + }], parserOptions: { ecmaVersion: 6 } }, { - code: "class A {\nconstructor() {\n/**\n* hi\n */\n}\n}", - options: [{ allowBlockStart: true }], + code: "class A {\n/**\n* hi\n */\nconstructor() {}\n}", + options: [{ + allowBlockStart: false, + allowClassStart: true + }], parserOptions: { ecmaVersion: 6 } }, { @@ -418,6 +430,23 @@ ruleTester.run("lines-around-comment", rule, { }], parserOptions: { ecmaVersion: 6 } }, + { + code: "class B {\nconstructor() {}\n\n/**\n* hi\n */\n}", + options: [{ + afterBlockComment: true, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class B {\nconstructor() {}\n\n/**\n* hi\n */\n}", + options: [{ + afterBlockComment: true, + allowBlockEnd: false, + allowClassEnd: true + }], + parserOptions: { ecmaVersion: 6 } + }, { code: "switch ('foo'){\ncase 'foo':\nvar g = 1;\n\n/* block comment at switch case end */\n}", options: [{ @@ -967,6 +996,46 @@ ruleTester.run("lines-around-comment", rule, { }], errors: [{ message: beforeMessage, type: "Line", line: 2 }] }, + { + code: "class A {\n// line at class start\nconstructor() {}\n}", + output: "class A {\n\n// line at class start\nconstructor() {}\n}", + options: [{ + beforeLineComment: true + }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: beforeMessage, type: "Line", line: 2 }] + }, + { + code: "class A {\n// line at class start\nconstructor() {}\n}", + output: "class A {\n\n// line at class start\nconstructor() {}\n}", + options: [{ + allowBlockStart: true, + allowClassStart: false, + beforeLineComment: true + }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: beforeMessage, type: "Line", line: 2 }] + }, + { + code: "class B {\nconstructor() {}\n\n// line at class end\n}", + output: "class B {\nconstructor() {}\n\n// line at class end\n\n}", + options: [{ + afterLineComment: true + }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: afterMessage, type: "Line", line: 4 }] + }, + { + code: "class B {\nconstructor() {}\n\n// line at class end\n}", + output: "class B {\nconstructor() {}\n\n// line at class end\n\n}", + options: [{ + afterLineComment: true, + allowBlockEnd: true, + allowClassEnd: false + }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: afterMessage, type: "Line", line: 4 }] + }, { code: "switch ('foo'){\ncase 'foo':\nvar g = 1;\n\n// line at switch case end\n}", output: "switch ('foo'){\ncase 'foo':\nvar g = 1;\n\n// line at switch case end\n\n}",