From 15eaef43f6864c6b206ca4d9e43843be50ebc92a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 23 Aug 2017 00:33:26 +0800 Subject: [PATCH 01/25] New: rule lines-between-class-methods(fixes #5949). --- conf/eslint-recommended.js | 1 + docs/rules/lines-between-class-methods.md | 5 + lib/rules/lines-between-class-methods.js | 106 ++++++++++++++++++ .../lib/rules/lines-between-class-methods.js | 35 ++++++ 4 files changed, 147 insertions(+) create mode 100644 docs/rules/lines-between-class-methods.md create mode 100644 lib/rules/lines-between-class-methods.js create mode 100644 tests/lib/rules/lines-between-class-methods.js diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js index a6fc9adf561..6a5a78d0598 100755 --- a/conf/eslint-recommended.js +++ b/conf/eslint-recommended.js @@ -63,6 +63,7 @@ module.exports = { "linebreak-style": "off", "lines-around-comment": "off", "lines-around-directive": "off", + "lines-between-class-methods": "off", "max-depth": "off", "max-len": "off", "max-lines": "off", diff --git a/docs/rules/lines-between-class-methods.md b/docs/rules/lines-between-class-methods.md new file mode 100644 index 00000000000..6b94108d12c --- /dev/null +++ b/docs/rules/lines-between-class-methods.md @@ -0,0 +1,5 @@ +# enforce lines between class methods (lines-between-class-methods) + +## Rule Details + +## Options \ No newline at end of file diff --git a/lib/rules/lines-between-class-methods.js b/lib/rules/lines-between-class-methods.js new file mode 100644 index 00000000000..e1d5fef64ab --- /dev/null +++ b/lib/rules/lines-between-class-methods.js @@ -0,0 +1,106 @@ +/** + * @fileoverview Rule to enforce lines between class methods + * @author 薛定谔的猫 + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +// const astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + + +module.exports = { + meta: { + docs: { + description: "enforce lines between class methods", + category: "Stylistic Issues", + recommended: false + }, + + fixable: null, + + schema: [ + { + oneOf: [ + { + enum: ["always", "never"] + }, + { + type: "object", + properties: { + multiLine: { + enum: ["always", "never"] + }, + singleLine: { + enum: ["always", "never"] + } + }, + additionalProperties: false, + minProperties: 1 + } + ] + } + ] + }, + + create(context) { + + // const options = {}; + const config = context.options[0] || "always"; + + const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; + const NEVER_MESSAGE = "Methods must not be padded by blank lines."; + + const sourceCode = context.getSourceCode(); + + /** + * Checks if there is padding between two tokens + * @param {Token} first The first token + * @param {Token} second The second token + * @returns {boolean} True if there is at least a line between the tokens + */ + function isPaddingBetweenTokens(first, second) { + return second.loc.start.line - first.loc.end.line >= 2; + } + + /** + * Checks the given BlockStatement node to be padded if the block is not empty. + * @param {ASTNode} node The AST node of a BlockStatement. + * @returns {void} undefined. + */ + function checkPadding(node) { + for (let i = 0; i < node.body.length - 1; i++) { + const prev = sourceCode.getLastToken(node.body[i]); + const next = sourceCode.getFirstToken(node.body[i + 1]); + const padded = isPaddingBetweenTokens(prev, next); + + if (config === "always" && !padded) { + context.report({ + node, + message: ALWAYS_MESSAGE + }); + } else if (config === "never" && padded) { + context.report({ + node, + message: NEVER_MESSAGE + }); + } + } + } + + return { + ClassBody: checkPadding + }; + + } +}; diff --git a/tests/lib/rules/lines-between-class-methods.js b/tests/lib/rules/lines-between-class-methods.js new file mode 100644 index 00000000000..472d4afc1a8 --- /dev/null +++ b/tests/lib/rules/lines-between-class-methods.js @@ -0,0 +1,35 @@ +/** + * @fileoverview Tests for lines-between-class-methods rule. + * @author 薛定谔的猫 + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/lines-between-class-methods"); +const RuleTester = require("../../../lib/testers/rule-tester"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ +const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; +const NEVER_MESSAGE = "Methods must not be padded by blank lines."; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +ruleTester.run("lines-between-class-methods", rule, { + valid: [ + "class foo{ bar(){}\n\nbaz(){}}" + ], + invalid: [ + { code: "class foo{ bar(){}baz(){}}", output: null, errors: [{ message: ALWAYS_MESSAGE }] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", output: null, options: ["never"], errors: [{ message: NEVER_MESSAGE }] } + ] +}); From b7a73d5ba23cc555c65508fd3b20c81a4bccdeda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 26 Aug 2017 00:52:06 +0800 Subject: [PATCH 02/25] add options: multiline & singleline. --- lib/rules/lines-between-class-methods.js | 47 ++++++++++--------- .../lib/rules/lines-between-class-methods.js | 8 +++- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/rules/lines-between-class-methods.js b/lib/rules/lines-between-class-methods.js index e1d5fef64ab..334c3237ffa 100644 --- a/lib/rules/lines-between-class-methods.js +++ b/lib/rules/lines-between-class-methods.js @@ -4,21 +4,10 @@ */ "use strict"; -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -// const astUtils = require("../ast-utils"); - -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ - module.exports = { meta: { docs: { @@ -55,9 +44,16 @@ module.exports = { create(context) { - // const options = {}; + const options = {}; const config = context.options[0] || "always"; + if (typeof config === "object") { + options.multiLine = config.multiLine === "always"; + options.singleLine = config.singleLine === "always"; + } else { + options.multiLine = options.singleLine = config === "always"; + } + const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; const NEVER_MESSAGE = "Methods must not be padded by blank lines."; @@ -79,20 +75,25 @@ module.exports = { * @returns {void} undefined. */ function checkPadding(node) { - for (let i = 0; i < node.body.length - 1; i++) { - const prev = sourceCode.getLastToken(node.body[i]); - const next = sourceCode.getFirstToken(node.body[i + 1]); - const padded = isPaddingBetweenTokens(prev, next); + const body = node.body; - if (config === "always" && !padded) { - context.report({ - node, - message: ALWAYS_MESSAGE - }); - } else if (config === "never" && padded) { + for (let i = 0; i < body.length - 1; i++) { + + // only check padding between methods definition. + if (body[i].type !== "MethodDefinition" || body[i + 1].type !== "MethodDefinition") { + break; + } + + const cur = sourceCode.getLastToken(body[i]); + const next = sourceCode.getFirstToken(body[i + 1]); + const isPadded = isPaddingBetweenTokens(cur, next); + const isMulti = body[i].range[1].line - body[i].range[0].line > 1; + const shouldPadded = isMulti ? options.multiLine : options.singleLine; + + if (shouldPadded !== isPadded) { context.report({ node, - message: NEVER_MESSAGE + message: shouldPadded ? ALWAYS_MESSAGE : NEVER_MESSAGE }); } } diff --git a/tests/lib/rules/lines-between-class-methods.js b/tests/lib/rules/lines-between-class-methods.js index 472d4afc1a8..7dc5882fd01 100644 --- a/tests/lib/rules/lines-between-class-methods.js +++ b/tests/lib/rules/lines-between-class-methods.js @@ -26,10 +26,16 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run("lines-between-class-methods", rule, { valid: [ - "class foo{ bar(){}\n\nbaz(){}}" + "class foo{}", + "class foo{\n\n}", + "class foo{\nconstructor(){}\n\n}", + "class foo{ bar(){}\n\nbaz(){}}", + { code: "class foo{}", options: ["never"] }, + { code: "class foo{ bar(){}baz(){}}", options: ["never"] } ], invalid: [ { code: "class foo{ bar(){}baz(){}}", output: null, errors: [{ message: ALWAYS_MESSAGE }] }, + { code: "class foo{ bar(){}\nbaz(){}}", output: null, options: ["always"], errors: [{ message: ALWAYS_MESSAGE }] }, { code: "class foo{ bar(){}\n\nbaz(){}}", output: null, options: ["never"], errors: [{ message: NEVER_MESSAGE }] } ] }); From 3c969b03532c844e4a751585c5364bdcd9a17fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 27 Aug 2017 20:32:55 +0800 Subject: [PATCH 03/25] add --fix --- lib/rules/lines-between-class-methods.js | 27 ++++++++++++------- .../lib/rules/lines-between-class-methods.js | 20 +++++++++----- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/lib/rules/lines-between-class-methods.js b/lib/rules/lines-between-class-methods.js index 334c3237ffa..9e97d115829 100644 --- a/lib/rules/lines-between-class-methods.js +++ b/lib/rules/lines-between-class-methods.js @@ -16,7 +16,7 @@ module.exports = { recommended: false }, - fixable: null, + fixable: "whitespace", schema: [ { @@ -47,11 +47,13 @@ module.exports = { const options = {}; const config = context.options[0] || "always"; - if (typeof config === "object") { - options.multiLine = config.multiLine === "always"; - options.singleLine = config.singleLine === "always"; + // "always" => {multiLine: "always", singleLine: "always"} + // "never" => {multiLine: "never", singleLine: "never"} + if (typeof config === "string") { + options.multiLine = options.singleLine = config; } else { - options.multiLine = options.singleLine = config === "always"; + options.multiLine = config.multiLine; + options.singleLine = config.singleLine; } const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; @@ -70,11 +72,12 @@ module.exports = { } /** - * Checks the given BlockStatement node to be padded if the block is not empty. - * @param {ASTNode} node The AST node of a BlockStatement. + * Checks the given MethodDefinition node to be padded. + * @param {ASTNode} node The AST node of a MethodDefinition. * @returns {void} undefined. */ function checkPadding(node) { + const body = node.body; for (let i = 0; i < body.length - 1; i++) { @@ -88,12 +91,16 @@ module.exports = { const next = sourceCode.getFirstToken(body[i + 1]); const isPadded = isPaddingBetweenTokens(cur, next); const isMulti = body[i].range[1].line - body[i].range[0].line > 1; - const shouldPadded = isMulti ? options.multiLine : options.singleLine; - if (shouldPadded !== isPadded) { + if (isMulti && (options.multiLine === "always") !== isPadded || !isMulti && (options.singleLine === "always") !== isPadded) { context.report({ node, - message: shouldPadded ? ALWAYS_MESSAGE : NEVER_MESSAGE + message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, + fix(fixer) { + return isPadded + ? fixer.replaceTextRange([cur.range[1], next.range[0]], "\n") + : fixer.insertTextAfter(cur, "\n"); + } }); } } diff --git a/tests/lib/rules/lines-between-class-methods.js b/tests/lib/rules/lines-between-class-methods.js index 7dc5882fd01..edc4c303004 100644 --- a/tests/lib/rules/lines-between-class-methods.js +++ b/tests/lib/rules/lines-between-class-methods.js @@ -15,6 +15,7 @@ const RuleTester = require("../../../lib/testers/rule-tester"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ + const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; const NEVER_MESSAGE = "Methods must not be padded by blank lines."; @@ -28,14 +29,21 @@ ruleTester.run("lines-between-class-methods", rule, { valid: [ "class foo{}", "class foo{\n\n}", - "class foo{\nconstructor(){}\n\n}", + "class foo{constructor(){}\n}", + "class foo{\nconstructor(){}}", "class foo{ bar(){}\n\nbaz(){}}", - { code: "class foo{}", options: ["never"] }, - { code: "class foo{ bar(){}baz(){}}", options: ["never"] } + { code: "class foo{ bar(){}\nbaz(){}}", options: ["never"] } ], invalid: [ - { code: "class foo{ bar(){}baz(){}}", output: null, errors: [{ message: ALWAYS_MESSAGE }] }, - { code: "class foo{ bar(){}\nbaz(){}}", output: null, options: ["always"], errors: [{ message: ALWAYS_MESSAGE }] }, - { code: "class foo{ bar(){}\n\nbaz(){}}", output: null, options: ["never"], errors: [{ message: NEVER_MESSAGE }] } + { + code: "class foo{ bar(){}\nbaz(){}}", + output: "class foo{ bar(){}\n\nbaz(){}}", + errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){}\n\nbaz(){}}", + output: "class foo{ bar(){}\nbaz(){}}", + options: ["never"], + errors: [{ message: NEVER_MESSAGE }] + } ] }); From 0b9fbb6c4992f2cb56abbaf2231bbe19c8a648ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 4 Sep 2017 15:20:57 +0800 Subject: [PATCH 04/25] rename variable & add more tests. --- lib/rules/lines-between-class-methods.js | 17 +++++++----- .../lib/rules/lines-between-class-methods.js | 27 ++++++++++++++++++- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/lib/rules/lines-between-class-methods.js b/lib/rules/lines-between-class-methods.js index 9e97d115829..901ead9dd12 100644 --- a/lib/rules/lines-between-class-methods.js +++ b/lib/rules/lines-between-class-methods.js @@ -4,6 +4,8 @@ */ "use strict"; +const astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -87,19 +89,20 @@ module.exports = { break; } - const cur = sourceCode.getLastToken(body[i]); - const next = sourceCode.getFirstToken(body[i + 1]); - const isPadded = isPaddingBetweenTokens(cur, next); - const isMulti = body[i].range[1].line - body[i].range[0].line > 1; + const curFirst = sourceCode.getFirstToken(body[i]); + const curLast = sourceCode.getLastToken(body[i]); + const nextFirst = sourceCode.getFirstToken(body[i + 1]); + const isPadded = isPaddingBetweenTokens(curLast, nextFirst); + const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); - if (isMulti && (options.multiLine === "always") !== isPadded || !isMulti && (options.singleLine === "always") !== isPadded) { + if ((isMulti && (options.multiLine === "always") !== isPadded) || !isMulti && (options.singleLine === "always") !== isPadded) { context.report({ node, message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, fix(fixer) { return isPadded - ? fixer.replaceTextRange([cur.range[1], next.range[0]], "\n") - : fixer.insertTextAfter(cur, "\n"); + ? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n") + : fixer.insertTextAfter(curLast, "\n"); } }); } diff --git a/tests/lib/rules/lines-between-class-methods.js b/tests/lib/rules/lines-between-class-methods.js index edc4c303004..c44ac1efd0a 100644 --- a/tests/lib/rules/lines-between-class-methods.js +++ b/tests/lib/rules/lines-between-class-methods.js @@ -32,7 +32,12 @@ ruleTester.run("lines-between-class-methods", rule, { "class foo{constructor(){}\n}", "class foo{\nconstructor(){}}", "class foo{ bar(){}\n\nbaz(){}}", - { code: "class foo{ bar(){}\nbaz(){}}", options: ["never"] } + { code: "class foo{ bar(){}\nbaz(){}}", options: ["never"] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", options: ["always"] }, + { code: "class foo{ bar(){\n}\n\nbaz(){}}", options: [{ multiLine: "always" }] }, + { code: "class foo{ bar(){\n}\nbaz(){}}", options: [{ multiLine: "never" }] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ singleLine: "always" }] }, + { code: "class foo{ bar(){}\nbaz(){}}", options: [{ singleLine: "never" }] } ], invalid: [ { @@ -44,6 +49,26 @@ ruleTester.run("lines-between-class-methods", rule, { output: "class foo{ bar(){}\nbaz(){}}", options: ["never"], errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\nbaz(){}}", + output: "class foo{ bar(){\n}\n\nbaz(){}}", + options: [{ multiLine: "always" }], + errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\n\nbaz(){}}", + output: "class foo{ bar(){\n}\nbaz(){}}", + options: [{ multiLine: "never" }], + errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){}\nbaz(){}}", + output: "class foo{ bar(){}\n\nbaz(){}}", + options: [{ singleLine: "always" }], + errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){}\n\nbaz(){}}", + output: "class foo{ bar(){}\nbaz(){}}", + options: [{ singleLine: "never" }], + errors: [{ message: NEVER_MESSAGE }] } ] }); From f46a8d123fc5636a1bfb5a224e5d89192043d030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 4 Sep 2017 16:07:04 +0800 Subject: [PATCH 05/25] Docs: lines-between-class-methods --- docs/rules/lines-between-class-methods.md | 149 +++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/docs/rules/lines-between-class-methods.md b/docs/rules/lines-between-class-methods.md index 6b94108d12c..77b247ea05d 100644 --- a/docs/rules/lines-between-class-methods.md +++ b/docs/rules/lines-between-class-methods.md @@ -1,5 +1,152 @@ # enforce lines between class methods (lines-between-class-methods) +This rule is to improve readability by enforce lines between class methods. + ## Rule Details -## Options \ No newline at end of file +Examples of **incorrect** code for this rule: + +```js +/* eslint lines-between-class-methods: ["error", "always"]*/ +class MyClass { + foo() { + //... + } + bar() { + //... + } +} +``` + +Examples of **correct** code for this rule: + +```js +/* eslint lines-between-class-methods: ["error", "always"]*/ +class MyClass { + foo() { + //... + } + + bar() { + //... + } +} +``` + +### Options + +This rule has one option, which can be a string option or an object option. + +String option: + +* `"always"`(default) requires line breaks between methods +* `"never"` disallows line breaks between methods + +Object option: + +* `"multiline": always` requires line breaks if the method is multiline +* `"multiline": never` disallow line breaks if the method is multiline +* `"singleline": always` requires line breaks if the method is singleline +* `"singleline": never` disallow line breaks if the method is singleline + +Examples of **incorrect** code for this rule with the string option: + +```js +/* eslint lines-between-class-methods: ["error", "always"]*/ +class Foo{ + bar(){} + baz(){} +} + +/* eslint lines-between-class-methods: ["error", "never"]*/ +class Foo{ + bar(){} + + baz(){} +} +``` + +Examples of **correct** code for this rule with the string option: + +```js +/* eslint lines-between-class-methods: ["error", "always"]*/ +class Foo{ + bar(){} + + baz(){} +} + +/* eslint lines-between-class-methods: ["error", "never"]*/ +class Foo{ + bar(){} + baz(){} +} +``` + +Examples of **incorrect** code for this rule with the object option: + +```js +/* eslint lines-between-class-methods: ["error", { multiline: "always" }]*/ +class Foo{ + bar(){ + bar(); + } + baz(){} +} + +/* eslint lines-between-class-methods: ["error", { multiline: "never" }]*/ +class Foo{ + bar(){ + bar(); + } + + baz(){} +} + +/* eslint lines-between-class-methods: ["error", { singleline: "always" }]*/ +class Foo{ + bar(){} + baz(){} +} + +/* eslint lines-between-class-methods: ["error", { singleline: "never" }]*/ +class Foo{ + bar(){} + + baz(){} +} +``` + +Examples of **correct** code for this rule with the object option: + +```js +/* eslint lines-between-class-methods: ["error", { multiline: "always" }]*/ +class Foo{ + bar(){ + bar(); + } + + baz(){} +} + +/* eslint lines-between-class-methods: ["error", { multiline: "never" }]*/ +class Foo{ + bar(){ + bar(); + } + baz(){} +} + +/* eslint lines-between-class-methods: ["error", { singleline: "always" }]*/ +class Foo{ + bar(){} + + baz(){} +} + +/* eslint lines-between-class-methods: ["error", { singleline: "never" }]*/ +class Foo{ + bar(){} + baz(){} +} +``` \ No newline at end of file From 02c85233e40a943f272d494f23297e47d5123a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 4 Sep 2017 17:19:25 +0800 Subject: [PATCH 06/25] multiLine => multiline. --- lib/rules/lines-between-class-methods.js | 16 ++++++++-------- tests/lib/rules/lines-between-class-methods.js | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/rules/lines-between-class-methods.js b/lib/rules/lines-between-class-methods.js index 901ead9dd12..db91afe9f24 100644 --- a/lib/rules/lines-between-class-methods.js +++ b/lib/rules/lines-between-class-methods.js @@ -29,10 +29,10 @@ module.exports = { { type: "object", properties: { - multiLine: { + multiline: { enum: ["always", "never"] }, - singleLine: { + singleline: { enum: ["always", "never"] } }, @@ -49,13 +49,13 @@ module.exports = { const options = {}; const config = context.options[0] || "always"; - // "always" => {multiLine: "always", singleLine: "always"} - // "never" => {multiLine: "never", singleLine: "never"} + // "always" => {multiline: "always", singleline: "always"} + // "never" => {multiline: "never", singleline: "never"} if (typeof config === "string") { - options.multiLine = options.singleLine = config; + options.multiline = options.singleline = config; } else { - options.multiLine = config.multiLine; - options.singleLine = config.singleLine; + options.multiline = config.multiline; + options.singleline = config.singleline; } const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; @@ -95,7 +95,7 @@ module.exports = { const isPadded = isPaddingBetweenTokens(curLast, nextFirst); const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); - if ((isMulti && (options.multiLine === "always") !== isPadded) || !isMulti && (options.singleLine === "always") !== isPadded) { + if ((isMulti && (options.multiline === "always") !== isPadded) || !isMulti && (options.singleline === "always") !== isPadded) { context.report({ node, message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, diff --git a/tests/lib/rules/lines-between-class-methods.js b/tests/lib/rules/lines-between-class-methods.js index c44ac1efd0a..1107cf4fda6 100644 --- a/tests/lib/rules/lines-between-class-methods.js +++ b/tests/lib/rules/lines-between-class-methods.js @@ -34,10 +34,10 @@ ruleTester.run("lines-between-class-methods", rule, { "class foo{ bar(){}\n\nbaz(){}}", { code: "class foo{ bar(){}\nbaz(){}}", options: ["never"] }, { code: "class foo{ bar(){}\n\nbaz(){}}", options: ["always"] }, - { code: "class foo{ bar(){\n}\n\nbaz(){}}", options: [{ multiLine: "always" }] }, - { code: "class foo{ bar(){\n}\nbaz(){}}", options: [{ multiLine: "never" }] }, - { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ singleLine: "always" }] }, - { code: "class foo{ bar(){}\nbaz(){}}", options: [{ singleLine: "never" }] } + { code: "class foo{ bar(){\n}\n\nbaz(){}}", options: [{ multiline: "always" }] }, + { code: "class foo{ bar(){\n}\nbaz(){}}", options: [{ multiline: "never" }] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ singleline: "always" }] }, + { code: "class foo{ bar(){}\nbaz(){}}", options: [{ singleline: "never" }] } ], invalid: [ { @@ -52,22 +52,22 @@ ruleTester.run("lines-between-class-methods", rule, { }, { code: "class foo{ bar(){\n}\nbaz(){}}", output: "class foo{ bar(){\n}\n\nbaz(){}}", - options: [{ multiLine: "always" }], + options: [{ multiline: "always" }], errors: [{ message: ALWAYS_MESSAGE }] }, { code: "class foo{ bar(){\n}\n\nbaz(){}}", output: "class foo{ bar(){\n}\nbaz(){}}", - options: [{ multiLine: "never" }], + options: [{ multiline: "never" }], errors: [{ message: NEVER_MESSAGE }] }, { code: "class foo{ bar(){}\nbaz(){}}", output: "class foo{ bar(){}\n\nbaz(){}}", - options: [{ singleLine: "always" }], + options: [{ singleline: "always" }], errors: [{ message: ALWAYS_MESSAGE }] }, { code: "class foo{ bar(){}\n\nbaz(){}}", output: "class foo{ bar(){}\nbaz(){}}", - options: [{ singleLine: "never" }], + options: [{ singleline: "never" }], errors: [{ message: NEVER_MESSAGE }] } ] From 04e3786d85c9b33aceff95785b41b5ca23ac3558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Tue, 5 Sep 2017 10:36:49 +0800 Subject: [PATCH 07/25] Update lines-between-class-methods.js --- lib/rules/lines-between-class-methods.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/lines-between-class-methods.js b/lib/rules/lines-between-class-methods.js index db91afe9f24..1264a5877a2 100644 --- a/lib/rules/lines-between-class-methods.js +++ b/lib/rules/lines-between-class-methods.js @@ -86,7 +86,7 @@ module.exports = { // only check padding between methods definition. if (body[i].type !== "MethodDefinition" || body[i + 1].type !== "MethodDefinition") { - break; + continue; } const curFirst = sourceCode.getFirstToken(body[i]); From 979582fcec2896673cd2fd813351e8251b9b2be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 01:11:56 +0800 Subject: [PATCH 08/25] rename rulename. --- conf/eslint-recommended.js | 2 +- ...-between-class-methods.md => lines-between-class-members.md} | 0 ...-between-class-methods.js => lines-between-class-members.js} | 0 ...-between-class-methods.js => lines-between-class-members.js} | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename docs/rules/{lines-between-class-methods.md => lines-between-class-members.md} (100%) rename lib/rules/{lines-between-class-methods.js => lines-between-class-members.js} (100%) rename tests/lib/rules/{lines-between-class-methods.js => lines-between-class-members.js} (97%) diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js index 6a5a78d0598..5d7f4d33c00 100755 --- a/conf/eslint-recommended.js +++ b/conf/eslint-recommended.js @@ -63,7 +63,7 @@ module.exports = { "linebreak-style": "off", "lines-around-comment": "off", "lines-around-directive": "off", - "lines-between-class-methods": "off", + "lines-between-class-members": "off", "max-depth": "off", "max-len": "off", "max-lines": "off", diff --git a/docs/rules/lines-between-class-methods.md b/docs/rules/lines-between-class-members.md similarity index 100% rename from docs/rules/lines-between-class-methods.md rename to docs/rules/lines-between-class-members.md diff --git a/lib/rules/lines-between-class-methods.js b/lib/rules/lines-between-class-members.js similarity index 100% rename from lib/rules/lines-between-class-methods.js rename to lib/rules/lines-between-class-members.js diff --git a/tests/lib/rules/lines-between-class-methods.js b/tests/lib/rules/lines-between-class-members.js similarity index 97% rename from tests/lib/rules/lines-between-class-methods.js rename to tests/lib/rules/lines-between-class-members.js index 1107cf4fda6..007746f25fc 100644 --- a/tests/lib/rules/lines-between-class-methods.js +++ b/tests/lib/rules/lines-between-class-members.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/lines-between-class-methods"); +const rule = require("../../../lib/rules/lines-between-class-members"); const RuleTester = require("../../../lib/testers/rule-tester"); //------------------------------------------------------------------------------ From 0d86820f211fd1cb8cad125a2a7337adf9daf23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 02:19:59 +0800 Subject: [PATCH 09/25] Fix: should consider comments before methods. --- lib/rules/lines-between-class-members.js | 7 +- .../lib/rules/lines-between-class-members.js | 81 ++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index 1264a5877a2..99fd156dc44 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -91,7 +91,12 @@ module.exports = { const curFirst = sourceCode.getFirstToken(body[i]); const curLast = sourceCode.getLastToken(body[i]); - const nextFirst = sourceCode.getFirstToken(body[i + 1]); + let nextFirst = sourceCode.getFirstToken(body[i + 1]); + const comments = sourceCode.getCommentsBefore(nextFirst); + + if (comments.length) { + nextFirst = comments[0]; + } const isPadded = isPaddingBetweenTokens(curLast, nextFirst); const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); diff --git a/tests/lib/rules/lines-between-class-members.js b/tests/lib/rules/lines-between-class-members.js index 007746f25fc..976769718ce 100644 --- a/tests/lib/rules/lines-between-class-members.js +++ b/tests/lib/rules/lines-between-class-members.js @@ -31,44 +31,123 @@ ruleTester.run("lines-between-class-methods", rule, { "class foo{\n\n}", "class foo{constructor(){}\n}", "class foo{\nconstructor(){}}", + "class foo{ bar(){}\n\nbaz(){}}", + "class foo{ bar(){}\n\n/*comments*/baz(){}}", + "class foo{ bar(){}\n\n//comments\nbaz(){}}", + { code: "class foo{ bar(){}\nbaz(){}}", options: ["never"] }, + { code: "class foo{ bar(){}\n/*comments*/baz(){}}", options: ["never"] }, + { code: "class foo{ bar(){}\n//comments\nbaz(){}}", options: ["never"] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", options: ["always"] }, + { code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", options: ["always"] }, + { code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", options: ["always"] }, + { code: "class foo{ bar(){\n}\n\nbaz(){}}", options: [{ multiline: "always" }] }, + { code: "class foo{ bar(){\n}\n\n/*comments*/baz(){}}", options: [{ multiline: "always" }] }, + { code: "class foo{ bar(){\n}\n\n//comments\nbaz(){}}", options: [{ multiline: "always" }] }, + { code: "class foo{ bar(){\n}\nbaz(){}}", options: [{ multiline: "never" }] }, + { code: "class foo{ bar(){\n}\n/*comments*/baz(){}}", options: [{ multiline: "never" }] }, + { code: "class foo{ bar(){\n}\n//comments\nbaz(){}}", options: [{ multiline: "never" }] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ singleline: "always" }] }, - { code: "class foo{ bar(){}\nbaz(){}}", options: [{ singleline: "never" }] } + { code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", options: [{ singleline: "always" }] }, + { code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", options: [{ singleline: "always" }] }, + + { code: "class foo{ bar(){}\nbaz(){}}", options: [{ singleline: "never" }] }, + { code: "class foo{ bar(){}\n/*comments*/baz(){}}", options: [{ singleline: "never" }] }, + { code: "class foo{ bar(){}\n//comments\nbaz(){}}", options: [{ singleline: "never" }] } ], invalid: [ { code: "class foo{ bar(){}\nbaz(){}}", output: "class foo{ bar(){}\n\nbaz(){}}", errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){}\n/*comments*/baz(){}}", + output: "class foo{ bar(){}\n\n/*comments*/baz(){}}", + errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){}\n//comments\nbaz(){}}", + output: "class foo{ bar(){}\n\n//comments\nbaz(){}}", + errors: [{ message: ALWAYS_MESSAGE }] }, { code: "class foo{ bar(){}\n\nbaz(){}}", output: "class foo{ bar(){}\nbaz(){}}", options: ["never"], errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", + output: "class foo{ bar(){}\n/*comments*/baz(){}}", + options: ["never"], + errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", + output: "class foo{ bar(){}\n//comments\nbaz(){}}", + options: ["never"], + errors: [{ message: NEVER_MESSAGE }] }, { code: "class foo{ bar(){\n}\nbaz(){}}", output: "class foo{ bar(){\n}\n\nbaz(){}}", options: [{ multiline: "always" }], errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\n/*comments*/baz(){}}", + output: "class foo{ bar(){\n}\n\n/*comments*/baz(){}}", + options: [{ multiline: "always" }], + errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\n//comments\nbaz(){}}", + output: "class foo{ bar(){\n}\n\n//comments\nbaz(){}}", + options: [{ multiline: "always" }], + errors: [{ message: ALWAYS_MESSAGE }] }, { code: "class foo{ bar(){\n}\n\nbaz(){}}", output: "class foo{ bar(){\n}\nbaz(){}}", options: [{ multiline: "never" }], errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\n\n/*comments*/baz(){}}", + output: "class foo{ bar(){\n}\n/*comments*/baz(){}}", + options: [{ multiline: "never" }], + errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\n\n//comments\nbaz(){}}", + output: "class foo{ bar(){\n}\n//comments\nbaz(){}}", + options: [{ multiline: "never" }], + errors: [{ message: NEVER_MESSAGE }] }, { code: "class foo{ bar(){}\nbaz(){}}", output: "class foo{ bar(){}\n\nbaz(){}}", options: [{ singleline: "always" }], errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){}\n/*comments*/baz(){}}", + output: "class foo{ bar(){}\n\n/*comments*/baz(){}}", + options: [{ singleline: "always" }], + errors: [{ message: ALWAYS_MESSAGE }] + }, { + code: "class foo{ bar(){}\n//comments\nbaz(){}}", + output: "class foo{ bar(){}\n\n//comments\nbaz(){}}", + options: [{ singleline: "always" }], + errors: [{ message: ALWAYS_MESSAGE }] }, { code: "class foo{ bar(){}\n\nbaz(){}}", output: "class foo{ bar(){}\nbaz(){}}", options: [{ singleline: "never" }], errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", + output: "class foo{ bar(){}\n/*comments*/baz(){}}", + options: [{ singleline: "never" }], + errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", + output: "class foo{ bar(){}\n//comments\nbaz(){}}", + options: [{ singleline: "never" }], + errors: [{ message: NEVER_MESSAGE }] } ] }); From 7fa4d8449c5669da3e72d677019db5b7b4312095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 02:24:55 +0800 Subject: [PATCH 10/25] opt. --- lib/rules/lines-between-class-members.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index 99fd156dc44..4e921722de0 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -91,12 +91,8 @@ module.exports = { const curFirst = sourceCode.getFirstToken(body[i]); const curLast = sourceCode.getLastToken(body[i]); - let nextFirst = sourceCode.getFirstToken(body[i + 1]); - const comments = sourceCode.getCommentsBefore(nextFirst); - - if (comments.length) { - nextFirst = comments[0]; - } + const comments = sourceCode.getCommentsBefore(body[i + 1]); + const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]); const isPadded = isPaddingBetweenTokens(curLast, nextFirst); const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); From 71517eac17ceda07fb611f757896407e4d336aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 02:43:23 +0800 Subject: [PATCH 11/25] Update lines-between-class-members.md --- docs/rules/lines-between-class-members.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md index 77b247ea05d..75e04cb2a59 100644 --- a/docs/rules/lines-between-class-members.md +++ b/docs/rules/lines-between-class-members.md @@ -1,4 +1,4 @@ -# enforce lines between class methods (lines-between-class-methods) +# enforce lines between class methods (lines-between-class-members) This rule is to improve readability by enforce lines between class methods. @@ -149,4 +149,4 @@ class Foo{ bar(){} baz(){} } -``` \ No newline at end of file +``` From 3f9d1631550081a031da06d6d2dbebab3a84b271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 02:55:55 +0800 Subject: [PATCH 12/25] rename rulename. --- docs/rules/lines-between-class-members.md | 30 +++++++++---------- lib/rules/lines-between-class-members.js | 4 +-- .../lib/rules/lines-between-class-members.js | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md index 75e04cb2a59..bc9ff003aad 100644 --- a/docs/rules/lines-between-class-members.md +++ b/docs/rules/lines-between-class-members.md @@ -1,4 +1,4 @@ -# enforce lines between class methods (lines-between-class-members) +# enforce lines between class members (lines-between-class-members) This rule is to improve readability by enforce lines between class methods. @@ -7,7 +7,7 @@ This rule is to improve readability by enforce lines between class methods. Examples of **incorrect** code for this rule: ```js -/* eslint lines-between-class-methods: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class MyClass { foo() { //... @@ -21,7 +21,7 @@ class MyClass { Examples of **correct** code for this rule: ```js -/* eslint lines-between-class-methods: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class MyClass { foo() { //... @@ -52,13 +52,13 @@ Object option: Examples of **incorrect** code for this rule with the string option: ```js -/* eslint lines-between-class-methods: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class Foo{ bar(){} baz(){} } -/* eslint lines-between-class-methods: ["error", "never"]*/ +/* eslint lines-between-class-members: ["error", "never"]*/ class Foo{ bar(){} @@ -69,14 +69,14 @@ class Foo{ Examples of **correct** code for this rule with the string option: ```js -/* eslint lines-between-class-methods: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class Foo{ bar(){} baz(){} } -/* eslint lines-between-class-methods: ["error", "never"]*/ +/* eslint lines-between-class-members: ["error", "never"]*/ class Foo{ bar(){} baz(){} @@ -86,7 +86,7 @@ class Foo{ Examples of **incorrect** code for this rule with the object option: ```js -/* eslint lines-between-class-methods: ["error", { multiline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ class Foo{ bar(){ bar(); @@ -94,7 +94,7 @@ class Foo{ baz(){} } -/* eslint lines-between-class-methods: ["error", { multiline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ class Foo{ bar(){ bar(); @@ -103,13 +103,13 @@ class Foo{ baz(){} } -/* eslint lines-between-class-methods: ["error", { singleline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ class Foo{ bar(){} baz(){} } -/* eslint lines-between-class-methods: ["error", { singleline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ class Foo{ bar(){} @@ -120,7 +120,7 @@ class Foo{ Examples of **correct** code for this rule with the object option: ```js -/* eslint lines-between-class-methods: ["error", { multiline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ class Foo{ bar(){ bar(); @@ -129,7 +129,7 @@ class Foo{ baz(){} } -/* eslint lines-between-class-methods: ["error", { multiline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ class Foo{ bar(){ bar(); @@ -137,14 +137,14 @@ class Foo{ baz(){} } -/* eslint lines-between-class-methods: ["error", { singleline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ class Foo{ bar(){} baz(){} } -/* eslint lines-between-class-methods: ["error", { singleline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ class Foo{ bar(){} baz(){} diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index 4e921722de0..7b7a7f962d7 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -1,5 +1,5 @@ /** - * @fileoverview Rule to enforce lines between class methods + * @fileoverview Rule to enforce lines between class members * @author 薛定谔的猫 */ "use strict"; @@ -13,7 +13,7 @@ const astUtils = require("../ast-utils"); module.exports = { meta: { docs: { - description: "enforce lines between class methods", + description: "enforce lines between class members", category: "Stylistic Issues", recommended: false }, diff --git a/tests/lib/rules/lines-between-class-members.js b/tests/lib/rules/lines-between-class-members.js index 976769718ce..8b7a3fe1d3a 100644 --- a/tests/lib/rules/lines-between-class-members.js +++ b/tests/lib/rules/lines-between-class-members.js @@ -1,5 +1,5 @@ /** - * @fileoverview Tests for lines-between-class-methods rule. + * @fileoverview Tests for lines-between-class-members rule. * @author 薛定谔的猫 */ From bdc5da7de1b84c46c85b46cfe81e44d5d6e024dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 04:36:16 +0800 Subject: [PATCH 13/25] Fix: accept review suggestions. --- docs/rules/lines-between-class-members.md | 10 +++++----- lib/rules/lines-between-class-members.js | 3 ++- tests/lib/rules/lines-between-class-members.js | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md index bc9ff003aad..12c6d512051 100644 --- a/docs/rules/lines-between-class-members.md +++ b/docs/rules/lines-between-class-members.md @@ -1,6 +1,6 @@ # enforce lines between class members (lines-between-class-members) -This rule is to improve readability by enforce lines between class methods. +This rule improves readability by enforcing lines between class members. ## Rule Details @@ -44,10 +44,10 @@ String option: Object option: -* `"multiline": always` requires line breaks if the method is multiline -* `"multiline": never` disallow line breaks if the method is multiline -* `"singleline": always` requires line breaks if the method is singleline -* `"singleline": never` disallow line breaks if the method is singleline +* `"multiline": "always"` requires line breaks if the method is multiline +* `"multiline": "never"` disallow line breaks if the method is multiline +* `"singleline": "always"` requires line breaks if the method is singleline +* `"singleline": "never"` disallow line breaks if the method is singleline Examples of **incorrect** code for this rule with the string option: diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index 7b7a7f962d7..91c4ee57571 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -96,7 +96,8 @@ module.exports = { const isPadded = isPaddingBetweenTokens(curLast, nextFirst); const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); - if ((isMulti && (options.multiline === "always") !== isPadded) || !isMulti && (options.singleline === "always") !== isPadded) { + if ((isMulti && options.multiline && (options.multiline === "always") !== isPadded) || + !isMulti && options.singleline && (options.singleline === "always") !== isPadded) { context.report({ node, message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, diff --git a/tests/lib/rules/lines-between-class-members.js b/tests/lib/rules/lines-between-class-members.js index 8b7a3fe1d3a..b8e6e0df87d 100644 --- a/tests/lib/rules/lines-between-class-members.js +++ b/tests/lib/rules/lines-between-class-members.js @@ -47,10 +47,14 @@ ruleTester.run("lines-between-class-methods", rule, { { code: "class foo{ bar(){\n}\n\nbaz(){}}", options: [{ multiline: "always" }] }, { code: "class foo{ bar(){\n}\n\n/*comments*/baz(){}}", options: [{ multiline: "always" }] }, { code: "class foo{ bar(){\n}\n\n//comments\nbaz(){}}", options: [{ multiline: "always" }] }, + { code: "class foo{ bar(){}\nbaz(){}}", options: [{ multiline: "always" }] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ multiline: "always" }] }, { code: "class foo{ bar(){\n}\nbaz(){}}", options: [{ multiline: "never" }] }, { code: "class foo{ bar(){\n}\n/*comments*/baz(){}}", options: [{ multiline: "never" }] }, { code: "class foo{ bar(){\n}\n//comments\nbaz(){}}", options: [{ multiline: "never" }] }, + { code: "class foo{ bar(){}\nbaz(){}}", options: [{ multiline: "never" }] }, + { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ multiline: "never" }] }, { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ singleline: "always" }] }, { code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", options: [{ singleline: "always" }] }, @@ -148,6 +152,16 @@ ruleTester.run("lines-between-class-methods", rule, { output: "class foo{ bar(){}\n//comments\nbaz(){}}", options: [{ singleline: "never" }], errors: [{ message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\nbaz(){}\n\nfn(){}}", + output: "class foo{ bar(){\n}\n\nbaz(){}\nfn(){}}", + options: [{ multiline: "always", singleline: "never" }], + errors: [{ message: ALWAYS_MESSAGE }, { message: NEVER_MESSAGE }] + }, { + code: "class foo{ bar(){\n}\n\nbaz(){}\nfn(){}}", + output: "class foo{ bar(){\n}\nbaz(){}\n\nfn(){}}", + options: [{ multiline: "never", singleline: "always" }], + errors: [{ message: NEVER_MESSAGE }, { message: ALWAYS_MESSAGE }] } ] }); From 9696eb46d0a1683ed85664edc272b61af02a8a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 05:08:39 +0800 Subject: [PATCH 14/25] update reporting node. --- lib/rules/lines-between-class-members.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index 91c4ee57571..7cbbbd36f02 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -99,7 +99,7 @@ module.exports = { if ((isMulti && options.multiline && (options.multiline === "always") !== isPadded) || !isMulti && options.singleline && (options.singleline === "always") !== isPadded) { context.report({ - node, + node: body[i + 1], message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, fix(fixer) { return isPadded From 11414a0172a02722154f4f964b2a7ece84dbe39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 9 Sep 2017 01:39:39 +0800 Subject: [PATCH 15/25] rename to padding-after-class-members. --- conf/eslint-recommended.js | 2 +- docs/rules/lines-between-class-members.md | 152 ------------------ .../rules/padding-line-after-class-members.md | 152 ++++++++++++++++++ ...js => padding-line-after-class-members.js} | 8 +- ...js => padding-line-after-class-members.js} | 8 +- 5 files changed, 161 insertions(+), 161 deletions(-) delete mode 100644 docs/rules/lines-between-class-members.md create mode 100644 docs/rules/padding-line-after-class-members.md rename lib/rules/{lines-between-class-members.js => padding-line-after-class-members.js} (92%) rename tests/lib/rules/{lines-between-class-members.js => padding-line-after-class-members.js} (96%) diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js index 5d7f4d33c00..a37ee4862ba 100755 --- a/conf/eslint-recommended.js +++ b/conf/eslint-recommended.js @@ -63,7 +63,6 @@ module.exports = { "linebreak-style": "off", "lines-around-comment": "off", "lines-around-directive": "off", - "lines-between-class-members": "off", "max-depth": "off", "max-len": "off", "max-lines": "off", @@ -222,6 +221,7 @@ module.exports = { "operator-assignment": "off", "operator-linebreak": "off", "padded-blocks": "off", + "padding-line-after-class-members": "off", "padding-line-between-statements": "off", "prefer-arrow-callback": "off", "prefer-const": "off", diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md deleted file mode 100644 index 12c6d512051..00000000000 --- a/docs/rules/lines-between-class-members.md +++ /dev/null @@ -1,152 +0,0 @@ -# enforce lines between class members (lines-between-class-members) - -This rule improves readability by enforcing lines between class members. - -## Rule Details - -Examples of **incorrect** code for this rule: - -```js -/* eslint lines-between-class-members: ["error", "always"]*/ -class MyClass { - foo() { - //... - } - bar() { - //... - } -} -``` - -Examples of **correct** code for this rule: - -```js -/* eslint lines-between-class-members: ["error", "always"]*/ -class MyClass { - foo() { - //... - } - - bar() { - //... - } -} -``` - -### Options - -This rule has one option, which can be a string option or an object option. - -String option: - -* `"always"`(default) requires line breaks between methods -* `"never"` disallows line breaks between methods - -Object option: - -* `"multiline": "always"` requires line breaks if the method is multiline -* `"multiline": "never"` disallow line breaks if the method is multiline -* `"singleline": "always"` requires line breaks if the method is singleline -* `"singleline": "never"` disallow line breaks if the method is singleline - -Examples of **incorrect** code for this rule with the string option: - -```js -/* eslint lines-between-class-members: ["error", "always"]*/ -class Foo{ - bar(){} - baz(){} -} - -/* eslint lines-between-class-members: ["error", "never"]*/ -class Foo{ - bar(){} - - baz(){} -} -``` - -Examples of **correct** code for this rule with the string option: - -```js -/* eslint lines-between-class-members: ["error", "always"]*/ -class Foo{ - bar(){} - - baz(){} -} - -/* eslint lines-between-class-members: ["error", "never"]*/ -class Foo{ - bar(){} - baz(){} -} -``` - -Examples of **incorrect** code for this rule with the object option: - -```js -/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ -class Foo{ - bar(){ - bar(); - } - baz(){} -} - -/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ -class Foo{ - bar(){ - bar(); - } - - baz(){} -} - -/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ -class Foo{ - bar(){} - baz(){} -} - -/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ -class Foo{ - bar(){} - - baz(){} -} -``` - -Examples of **correct** code for this rule with the object option: - -```js -/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ -class Foo{ - bar(){ - bar(); - } - - baz(){} -} - -/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ -class Foo{ - bar(){ - bar(); - } - baz(){} -} - -/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ -class Foo{ - bar(){} - - baz(){} -} - -/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ -class Foo{ - bar(){} - baz(){} -} -``` diff --git a/docs/rules/padding-line-after-class-members.md b/docs/rules/padding-line-after-class-members.md new file mode 100644 index 00000000000..da0813ffc0e --- /dev/null +++ b/docs/rules/padding-line-after-class-members.md @@ -0,0 +1,152 @@ +# require or disallow an empty line after after class members (padding-line-after-class-members) + +This rule improves readability by enforcing lines after class members. + +## Rule Details + +Examples of **incorrect** code for this rule: + +```js +/* eslint padding-line-after-class-members: ["error", "always"]*/ +class MyClass { + foo() { + //... + } + bar() { + //... + } +} +``` + +Examples of **correct** code for this rule: + +```js +/* eslint padding-line-after-class-members: ["error", "always"]*/ +class MyClass { + foo() { + //... + } + + bar() { + //... + } +} +``` + +### Options + +This rule has one option, which can be a string option or an object option. + +String option: + +* `"always"`(default) require an empty line after after class members +* `"never"` disallows an empty line after after class members + +Object option: + +* `"multiline": "always"` require an empty line after after multiline class members +* `"multiline": "never"` disallows an empty line after after multiline class members +* `"singleline": "always"` require an empty line after after singleline class members +* `"singleline": "never"` disallows an empty line after after singleline class members + +Examples of **incorrect** code for this rule with the string option: + +```js +/* eslint padding-line-after-class-members: ["error", "always"]*/ +class Foo{ + bar(){} + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", "never"]*/ +class Foo{ + bar(){} + + baz(){} +} +``` + +Examples of **correct** code for this rule with the string option: + +```js +/* eslint padding-line-after-class-members: ["error", "always"]*/ +class Foo{ + bar(){} + + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", "never"]*/ +class Foo{ + bar(){} + baz(){} +} +``` + +Examples of **incorrect** code for this rule with the object option: + +```js +/* eslint padding-line-after-class-members: ["error", { multiline: "always" }]*/ +class Foo{ + bar(){ + bar(); + } + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", { multiline: "never" }]*/ +class Foo{ + bar(){ + bar(); + } + + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", { singleline: "always" }]*/ +class Foo{ + bar(){} + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", { singleline: "never" }]*/ +class Foo{ + bar(){} + + baz(){} +} +``` + +Examples of **correct** code for this rule with the object option: + +```js +/* eslint padding-line-after-class-members: ["error", { multiline: "always" }]*/ +class Foo{ + bar(){ + bar(); + } + + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", { multiline: "never" }]*/ +class Foo{ + bar(){ + bar(); + } + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", { singleline: "always" }]*/ +class Foo{ + bar(){} + + baz(){} +} + +/* eslint padding-line-after-class-members: ["error", { singleline: "never" }]*/ +class Foo{ + bar(){} + baz(){} +} +``` diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/padding-line-after-class-members.js similarity index 92% rename from lib/rules/lines-between-class-members.js rename to lib/rules/padding-line-after-class-members.js index 7cbbbd36f02..4ba99ef93e4 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/padding-line-after-class-members.js @@ -1,5 +1,5 @@ /** - * @fileoverview Rule to enforce lines between class members + * @fileoverview Rule to check empty newline after class members * @author 薛定谔的猫 */ "use strict"; @@ -13,7 +13,7 @@ const astUtils = require("../ast-utils"); module.exports = { meta: { docs: { - description: "enforce lines between class members", + description: "require or disallow an empty line after after class members", category: "Stylistic Issues", recommended: false }, @@ -58,8 +58,8 @@ module.exports = { options.singleline = config.singleline; } - const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; - const NEVER_MESSAGE = "Methods must not be padded by blank lines."; + const ALWAYS_MESSAGE = "Expected blank line after class members."; + const NEVER_MESSAGE = "Unexpected blank line after class members."; const sourceCode = context.getSourceCode(); diff --git a/tests/lib/rules/lines-between-class-members.js b/tests/lib/rules/padding-line-after-class-members.js similarity index 96% rename from tests/lib/rules/lines-between-class-members.js rename to tests/lib/rules/padding-line-after-class-members.js index b8e6e0df87d..dd01bc33458 100644 --- a/tests/lib/rules/lines-between-class-members.js +++ b/tests/lib/rules/padding-line-after-class-members.js @@ -1,5 +1,5 @@ /** - * @fileoverview Tests for lines-between-class-members rule. + * @fileoverview Tests for padding-line-after-class-members rule. * @author 薛定谔的猫 */ @@ -9,15 +9,15 @@ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/lines-between-class-members"); +const rule = require("../../../lib/rules/padding-line-after-class-members"); const RuleTester = require("../../../lib/testers/rule-tester"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -const ALWAYS_MESSAGE = "Methods must be padded by blank lines."; -const NEVER_MESSAGE = "Methods must not be padded by blank lines."; +const ALWAYS_MESSAGE = "Expected blank line after class members."; +const NEVER_MESSAGE = "Unexpected blank line after class members."; //------------------------------------------------------------------------------ // Tests From 6fb4dcfe3e3fbb35d496145b726a0b5418794732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 9 Sep 2017 23:34:56 +0800 Subject: [PATCH 16/25] update: only check padding lines after methods def. --- lib/rules/padding-line-after-class-members.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rules/padding-line-after-class-members.js b/lib/rules/padding-line-after-class-members.js index 4ba99ef93e4..f0df7123be9 100644 --- a/lib/rules/padding-line-after-class-members.js +++ b/lib/rules/padding-line-after-class-members.js @@ -84,8 +84,8 @@ module.exports = { for (let i = 0; i < body.length - 1; i++) { - // only check padding between methods definition. - if (body[i].type !== "MethodDefinition" || body[i + 1].type !== "MethodDefinition") { + // only check padding lines after methods definition. + if (body[i] && body[i].type !== "MethodDefinition") { continue; } From 8a376d093f75c865936a41312ad7148ff6cec9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 9 Sep 2017 23:56:52 +0800 Subject: [PATCH 17/25] Docs: update rule doc related to padded-blocks. --- docs/rules/padding-line-after-class-members.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/padding-line-after-class-members.md b/docs/rules/padding-line-after-class-members.md index da0813ffc0e..3b914c8af49 100644 --- a/docs/rules/padding-line-after-class-members.md +++ b/docs/rules/padding-line-after-class-members.md @@ -1,6 +1,6 @@ # require or disallow an empty line after after class members (padding-line-after-class-members) -This rule improves readability by enforcing lines after class members. +This rule improves readability by enforcing lines after class members. it will not check empty lines before the first method and after the last method, since that is already taken care of by padded-blocks. ## Rule Details From 80cb47e5c532a2a4cd905fdb3a450e5c911dfc43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 10 Sep 2017 00:00:55 +0800 Subject: [PATCH 18/25] Update padding-line-after-class-members.md --- docs/rules/padding-line-after-class-members.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/padding-line-after-class-members.md b/docs/rules/padding-line-after-class-members.md index 3b914c8af49..83806f056ac 100644 --- a/docs/rules/padding-line-after-class-members.md +++ b/docs/rules/padding-line-after-class-members.md @@ -1,6 +1,6 @@ # require or disallow an empty line after after class members (padding-line-after-class-members) -This rule improves readability by enforcing lines after class members. it will not check empty lines before the first method and after the last method, since that is already taken care of by padded-blocks. +This rule improves readability by enforcing lines after class members. it will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks. ## Rule Details From 0f24f9a1b5658bf992a9f162d3b67b2927c53a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Thu, 14 Sep 2017 20:40:19 +0800 Subject: [PATCH 19/25] rename rulename. --- ...bers.md => lines-between-class-members.md} | 32 +++++++++---------- ...bers.js => lines-between-class-members.js} | 8 ++--- ...bers.js => lines-between-class-members.js} | 8 ++--- 3 files changed, 24 insertions(+), 24 deletions(-) rename docs/rules/{padding-line-after-class-members.md => lines-between-class-members.md} (55%) rename lib/rules/{padding-line-after-class-members.js => lines-between-class-members.js} (92%) rename tests/lib/rules/{padding-line-after-class-members.js => lines-between-class-members.js} (96%) diff --git a/docs/rules/padding-line-after-class-members.md b/docs/rules/lines-between-class-members.md similarity index 55% rename from docs/rules/padding-line-after-class-members.md rename to docs/rules/lines-between-class-members.md index 83806f056ac..fecd30be085 100644 --- a/docs/rules/padding-line-after-class-members.md +++ b/docs/rules/lines-between-class-members.md @@ -1,13 +1,13 @@ -# require or disallow an empty line after after class members (padding-line-after-class-members) +# require or disallow an empty line after after class members (lines-between-class-members) -This rule improves readability by enforcing lines after class members. it will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks. +This rule improves readability by enforcing lines between class members. it will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks. ## Rule Details Examples of **incorrect** code for this rule: ```js -/* eslint padding-line-after-class-members: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class MyClass { foo() { //... @@ -21,7 +21,7 @@ class MyClass { Examples of **correct** code for this rule: ```js -/* eslint padding-line-after-class-members: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class MyClass { foo() { //... @@ -52,13 +52,13 @@ Object option: Examples of **incorrect** code for this rule with the string option: ```js -/* eslint padding-line-after-class-members: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class Foo{ bar(){} baz(){} } -/* eslint padding-line-after-class-members: ["error", "never"]*/ +/* eslint lines-between-class-members: ["error", "never"]*/ class Foo{ bar(){} @@ -69,14 +69,14 @@ class Foo{ Examples of **correct** code for this rule with the string option: ```js -/* eslint padding-line-after-class-members: ["error", "always"]*/ +/* eslint lines-between-class-members: ["error", "always"]*/ class Foo{ bar(){} baz(){} } -/* eslint padding-line-after-class-members: ["error", "never"]*/ +/* eslint lines-between-class-members: ["error", "never"]*/ class Foo{ bar(){} baz(){} @@ -86,7 +86,7 @@ class Foo{ Examples of **incorrect** code for this rule with the object option: ```js -/* eslint padding-line-after-class-members: ["error", { multiline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ class Foo{ bar(){ bar(); @@ -94,7 +94,7 @@ class Foo{ baz(){} } -/* eslint padding-line-after-class-members: ["error", { multiline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ class Foo{ bar(){ bar(); @@ -103,13 +103,13 @@ class Foo{ baz(){} } -/* eslint padding-line-after-class-members: ["error", { singleline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ class Foo{ bar(){} baz(){} } -/* eslint padding-line-after-class-members: ["error", { singleline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ class Foo{ bar(){} @@ -120,7 +120,7 @@ class Foo{ Examples of **correct** code for this rule with the object option: ```js -/* eslint padding-line-after-class-members: ["error", { multiline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ class Foo{ bar(){ bar(); @@ -129,7 +129,7 @@ class Foo{ baz(){} } -/* eslint padding-line-after-class-members: ["error", { multiline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ class Foo{ bar(){ bar(); @@ -137,14 +137,14 @@ class Foo{ baz(){} } -/* eslint padding-line-after-class-members: ["error", { singleline: "always" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ class Foo{ bar(){} baz(){} } -/* eslint padding-line-after-class-members: ["error", { singleline: "never" }]*/ +/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ class Foo{ bar(){} baz(){} diff --git a/lib/rules/padding-line-after-class-members.js b/lib/rules/lines-between-class-members.js similarity index 92% rename from lib/rules/padding-line-after-class-members.js rename to lib/rules/lines-between-class-members.js index f0df7123be9..cf02aa3034d 100644 --- a/lib/rules/padding-line-after-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -1,5 +1,5 @@ /** - * @fileoverview Rule to check empty newline after class members + * @fileoverview Rule to check empty newline between class members * @author 薛定谔的猫 */ "use strict"; @@ -13,7 +13,7 @@ const astUtils = require("../ast-utils"); module.exports = { meta: { docs: { - description: "require or disallow an empty line after after class members", + description: "require or disallow an empty line between class members", category: "Stylistic Issues", recommended: false }, @@ -58,8 +58,8 @@ module.exports = { options.singleline = config.singleline; } - const ALWAYS_MESSAGE = "Expected blank line after class members."; - const NEVER_MESSAGE = "Unexpected blank line after class members."; + const ALWAYS_MESSAGE = "Expected blank line between class members."; + const NEVER_MESSAGE = "Unexpected blank line between class members."; const sourceCode = context.getSourceCode(); diff --git a/tests/lib/rules/padding-line-after-class-members.js b/tests/lib/rules/lines-between-class-members.js similarity index 96% rename from tests/lib/rules/padding-line-after-class-members.js rename to tests/lib/rules/lines-between-class-members.js index dd01bc33458..7e51c09f5a2 100644 --- a/tests/lib/rules/padding-line-after-class-members.js +++ b/tests/lib/rules/lines-between-class-members.js @@ -1,5 +1,5 @@ /** - * @fileoverview Tests for padding-line-after-class-members rule. + * @fileoverview Tests for lines-between-class-members rule. * @author 薛定谔的猫 */ @@ -9,15 +9,15 @@ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/padding-line-after-class-members"); +const rule = require("../../../lib/rules/lines-between-class-members"); const RuleTester = require("../../../lib/testers/rule-tester"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -const ALWAYS_MESSAGE = "Expected blank line after class members."; -const NEVER_MESSAGE = "Unexpected blank line after class members."; +const ALWAYS_MESSAGE = "Expected blank line between class members."; +const NEVER_MESSAGE = "Unexpected blank line between class members."; //------------------------------------------------------------------------------ // Tests From af58efcee583831923e1b7836cb08ac6086824dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Fri, 15 Sep 2017 19:19:06 +0800 Subject: [PATCH 20/25] update options. --- lib/rules/lines-between-class-members.js | 36 +++++++++--------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index cf02aa3034d..ba95ba5ba3f 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -22,24 +22,17 @@ module.exports = { schema: [ { - oneOf: [ - { - enum: ["always", "never"] - }, - { - type: "object", - properties: { - multiline: { - enum: ["always", "never"] - }, - singleline: { - enum: ["always", "never"] - } - }, - additionalProperties: false, - minProperties: 1 + enum: ["always", "never"] + }, + { + type: "object", + properties: { + exceptAfterSingleLine: { + enum: [true, false] } - ] + }, + additionalProperties: false, + minProperties: 0 } ] }, @@ -49,13 +42,12 @@ module.exports = { const options = {}; const config = context.options[0] || "always"; - // "always" => {multiline: "always", singleline: "always"} - // "never" => {multiline: "never", singleline: "never"} if (typeof config === "string") { options.multiline = options.singleline = config; - } else { - options.multiline = config.multiline; - options.singleline = config.singleline; + } + + if (context.options[1].exceptAfterSingleLine) { + options.singleline = "never"; } const ALWAYS_MESSAGE = "Expected blank line between class members."; From 42ea9eefdb26508551b9f9e173c064949da94b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Fri, 15 Sep 2017 19:42:01 +0800 Subject: [PATCH 21/25] modify options & update docs. --- conf/eslint-recommended.js | 2 +- docs/rules/lines-between-class-members.md | 77 +++---------- docs/rules/padded-blocks.md | 5 + lib/rules/lines-between-class-members.js | 65 +++++------ .../lib/rules/lines-between-class-members.js | 109 +----------------- 5 files changed, 54 insertions(+), 204 deletions(-) diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js index a37ee4862ba..5d7f4d33c00 100755 --- a/conf/eslint-recommended.js +++ b/conf/eslint-recommended.js @@ -63,6 +63,7 @@ module.exports = { "linebreak-style": "off", "lines-around-comment": "off", "lines-around-directive": "off", + "lines-between-class-members": "off", "max-depth": "off", "max-len": "off", "max-lines": "off", @@ -221,7 +222,6 @@ module.exports = { "operator-assignment": "off", "operator-linebreak": "off", "padded-blocks": "off", - "padding-line-after-class-members": "off", "padding-line-between-statements": "off", "prefer-arrow-callback": "off", "prefer-const": "off", diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md index fecd30be085..8acdcbbb7e4 100644 --- a/docs/rules/lines-between-class-members.md +++ b/docs/rules/lines-between-class-members.md @@ -1,6 +1,6 @@ -# require or disallow an empty line after after class members (lines-between-class-members) +# require or disallow an empty line between class members (lines-between-class-members) -This rule improves readability by enforcing lines between class members. it will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks. +This rule improves readability by enforcing lines between class members. It will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks. ## Rule Details @@ -35,7 +35,7 @@ class MyClass { ### Options -This rule has one option, which can be a string option or an object option. +This rule has a string option and an object option. String option: @@ -44,10 +44,8 @@ String option: Object option: -* `"multiline": "always"` require an empty line after after multiline class members -* `"multiline": "never"` disallows an empty line after after multiline class members -* `"singleline": "always"` require an empty line after after singleline class members -* `"singleline": "never"` disallows an empty line after after singleline class members +* `"exceptAfterSingleLine": "false"`(default) **do not** skip checking empty lines after singleline class members +* `"exceptAfterSingleLine": "true"` skip checking empty lines after singleline class members Examples of **incorrect** code for this rule with the string option: @@ -83,70 +81,23 @@ class Foo{ } ``` -Examples of **incorrect** code for this rule with the object option: +Examples of **correct** code for this rule with the object option: ```js -/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ -class Foo{ - bar(){ - bar(); - } - baz(){} -} - -/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ -class Foo{ - bar(){ - bar(); - } - - baz(){} -} - -/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ -class Foo{ - bar(){} - baz(){} -} - -/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ +/* eslint lines-between-class-members: ["error", "always", { exceptAfterSingleLine: true }]*/ class Foo{ bar(){} - baz(){} } ``` -Examples of **correct** code for this rule with the object option: - -```js -/* eslint lines-between-class-members: ["error", { multiline: "always" }]*/ -class Foo{ - bar(){ - bar(); - } - - baz(){} -} - -/* eslint lines-between-class-members: ["error", { multiline: "never" }]*/ -class Foo{ - bar(){ - bar(); - } - baz(){} -} +## When Not To Use It -/* eslint lines-between-class-members: ["error", { singleline: "always" }]*/ -class Foo{ - bar(){} +If you don't want enforce empty lines between class members, you can disable this rule. - baz(){} -} +## Related Rules -/* eslint lines-between-class-members: ["error", { singleline: "never" }]*/ -class Foo{ - bar(){} - baz(){} -} -``` +* [padded-blocks](padded-blocks.md) +* [padding-line-between-statement](padding-line-between-statement.md) +* [requirePaddingNewLinesAfterBlocks](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks) +* [disallowPaddingNewLinesAfterBlocks](http://jscs.info/rule/disallowPaddingNewLinesAfterBlocks) diff --git a/docs/rules/padded-blocks.md b/docs/rules/padded-blocks.md index 1ea3b11990a..dd2c68ccb22 100644 --- a/docs/rules/padded-blocks.md +++ b/docs/rules/padded-blocks.md @@ -354,3 +354,8 @@ if (a) { ## When Not To Use It You can turn this rule off if you are not concerned with the consistency of padding within blocks. + +## Related Rules + +* [lines-between-class-members](lines-between-class-members.md) +* [padding-line-between-statement](padding-line-between-statement.md) diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index ba95ba5ba3f..48d16395bf8 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -28,27 +28,20 @@ module.exports = { type: "object", properties: { exceptAfterSingleLine: { - enum: [true, false] + type: "boolean" } }, - additionalProperties: false, - minProperties: 0 + additionalProperties: false } ] }, create(context) { - const options = {}; - const config = context.options[0] || "always"; + const options = []; - if (typeof config === "string") { - options.multiline = options.singleline = config; - } - - if (context.options[1].exceptAfterSingleLine) { - options.singleline = "never"; - } + options[0] = context.options[0] || "always"; + options[1] = context.options[1] || { exceptAfterSingleLine: false }; const ALWAYS_MESSAGE = "Expected blank line between class members."; const NEVER_MESSAGE = "Unexpected blank line between class members."; @@ -71,34 +64,34 @@ module.exports = { * @returns {void} undefined. */ function checkPadding(node) { - const body = node.body; for (let i = 0; i < body.length - 1; i++) { - // only check padding lines after methods definition. - if (body[i] && body[i].type !== "MethodDefinition") { - continue; - } - - const curFirst = sourceCode.getFirstToken(body[i]); - const curLast = sourceCode.getLastToken(body[i]); - const comments = sourceCode.getCommentsBefore(body[i + 1]); - const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]); - const isPadded = isPaddingBetweenTokens(curLast, nextFirst); - const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); - - if ((isMulti && options.multiline && (options.multiline === "always") !== isPadded) || - !isMulti && options.singleline && (options.singleline === "always") !== isPadded) { - context.report({ - node: body[i + 1], - message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, - fix(fixer) { - return isPadded - ? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n") - : fixer.insertTextAfter(curLast, "\n"); - } - }); + // only check padding lines after class members(skip empty). + if (body[i]) { + + const curFirst = sourceCode.getFirstToken(body[i]); + const curLast = sourceCode.getLastToken(body[i]); + const comments = sourceCode.getCommentsBefore(body[i + 1]); + const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]); + const isPadded = isPaddingBetweenTokens(curLast, nextFirst); + const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); + const skip = !isMulti && options[1].exceptAfterSingleLine; + + + if ((options[0] === "always" && !skip && !isPadded) || + (options[0] === "never" && isPadded)) { + context.report({ + node: body[i + 1], + message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, + fix(fixer) { + return isPadded + ? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n") + : fixer.insertTextAfter(curLast, "\n"); + } + }); + } } } } diff --git a/tests/lib/rules/lines-between-class-members.js b/tests/lib/rules/lines-between-class-members.js index 7e51c09f5a2..dfa17670b64 100644 --- a/tests/lib/rules/lines-between-class-members.js +++ b/tests/lib/rules/lines-between-class-members.js @@ -25,7 +25,7 @@ const NEVER_MESSAGE = "Unexpected blank line between class members."; const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); -ruleTester.run("lines-between-class-methods", rule, { +ruleTester.run("lines-between-class-members", rule, { valid: [ "class foo{}", "class foo{\n\n}", @@ -44,124 +44,25 @@ ruleTester.run("lines-between-class-methods", rule, { { code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", options: ["always"] }, { code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", options: ["always"] }, - { code: "class foo{ bar(){\n}\n\nbaz(){}}", options: [{ multiline: "always" }] }, - { code: "class foo{ bar(){\n}\n\n/*comments*/baz(){}}", options: [{ multiline: "always" }] }, - { code: "class foo{ bar(){\n}\n\n//comments\nbaz(){}}", options: [{ multiline: "always" }] }, - { code: "class foo{ bar(){}\nbaz(){}}", options: [{ multiline: "always" }] }, - { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ multiline: "always" }] }, - - { code: "class foo{ bar(){\n}\nbaz(){}}", options: [{ multiline: "never" }] }, - { code: "class foo{ bar(){\n}\n/*comments*/baz(){}}", options: [{ multiline: "never" }] }, - { code: "class foo{ bar(){\n}\n//comments\nbaz(){}}", options: [{ multiline: "never" }] }, - { code: "class foo{ bar(){}\nbaz(){}}", options: [{ multiline: "never" }] }, - { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ multiline: "never" }] }, - - { code: "class foo{ bar(){}\n\nbaz(){}}", options: [{ singleline: "always" }] }, - { code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", options: [{ singleline: "always" }] }, - { code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", options: [{ singleline: "always" }] }, - - { code: "class foo{ bar(){}\nbaz(){}}", options: [{ singleline: "never" }] }, - { code: "class foo{ bar(){}\n/*comments*/baz(){}}", options: [{ singleline: "never" }] }, - { code: "class foo{ bar(){}\n//comments\nbaz(){}}", options: [{ singleline: "never" }] } + { code: "class foo{ bar(){}\nbaz(){}}", options: ["always", { exceptAfterSingleLine: true }] }, + { code: "class foo{ bar(){\n}\n\nbaz(){}}", options: ["always", { exceptAfterSingleLine: true }] } ], invalid: [ { code: "class foo{ bar(){}\nbaz(){}}", output: "class foo{ bar(){}\n\nbaz(){}}", - errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){}\n/*comments*/baz(){}}", - output: "class foo{ bar(){}\n\n/*comments*/baz(){}}", - errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){}\n//comments\nbaz(){}}", - output: "class foo{ bar(){}\n\n//comments\nbaz(){}}", + options: ["always"], errors: [{ message: ALWAYS_MESSAGE }] }, { code: "class foo{ bar(){}\n\nbaz(){}}", output: "class foo{ bar(){}\nbaz(){}}", options: ["never"], errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", - output: "class foo{ bar(){}\n/*comments*/baz(){}}", - options: ["never"], - errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", - output: "class foo{ bar(){}\n//comments\nbaz(){}}", - options: ["never"], - errors: [{ message: NEVER_MESSAGE }] }, { code: "class foo{ bar(){\n}\nbaz(){}}", output: "class foo{ bar(){\n}\n\nbaz(){}}", - options: [{ multiline: "always" }], - errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){\n}\n/*comments*/baz(){}}", - output: "class foo{ bar(){\n}\n\n/*comments*/baz(){}}", - options: [{ multiline: "always" }], - errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){\n}\n//comments\nbaz(){}}", - output: "class foo{ bar(){\n}\n\n//comments\nbaz(){}}", - options: [{ multiline: "always" }], + options: ["always", { exceptAfterSingleLine: true }], errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){\n}\n\nbaz(){}}", - output: "class foo{ bar(){\n}\nbaz(){}}", - options: [{ multiline: "never" }], - errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){\n}\n\n/*comments*/baz(){}}", - output: "class foo{ bar(){\n}\n/*comments*/baz(){}}", - options: [{ multiline: "never" }], - errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){\n}\n\n//comments\nbaz(){}}", - output: "class foo{ bar(){\n}\n//comments\nbaz(){}}", - options: [{ multiline: "never" }], - errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){}\nbaz(){}}", - output: "class foo{ bar(){}\n\nbaz(){}}", - options: [{ singleline: "always" }], - errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){}\n/*comments*/baz(){}}", - output: "class foo{ bar(){}\n\n/*comments*/baz(){}}", - options: [{ singleline: "always" }], - errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){}\n//comments\nbaz(){}}", - output: "class foo{ bar(){}\n\n//comments\nbaz(){}}", - options: [{ singleline: "always" }], - errors: [{ message: ALWAYS_MESSAGE }] - }, { - code: "class foo{ bar(){}\n\nbaz(){}}", - output: "class foo{ bar(){}\nbaz(){}}", - options: [{ singleline: "never" }], - errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", - output: "class foo{ bar(){}\n/*comments*/baz(){}}", - options: [{ singleline: "never" }], - errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){}\n\n//comments\nbaz(){}}", - output: "class foo{ bar(){}\n//comments\nbaz(){}}", - options: [{ singleline: "never" }], - errors: [{ message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){\n}\nbaz(){}\n\nfn(){}}", - output: "class foo{ bar(){\n}\n\nbaz(){}\nfn(){}}", - options: [{ multiline: "always", singleline: "never" }], - errors: [{ message: ALWAYS_MESSAGE }, { message: NEVER_MESSAGE }] - }, { - code: "class foo{ bar(){\n}\n\nbaz(){}\nfn(){}}", - output: "class foo{ bar(){\n}\nbaz(){}\n\nfn(){}}", - options: [{ multiline: "never", singleline: "always" }], - errors: [{ message: NEVER_MESSAGE }, { message: ALWAYS_MESSAGE }] } ] }); From 86011631882e2f5315f96fd7f3d805f2cbb1b104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 16 Sep 2017 12:13:59 +0800 Subject: [PATCH 22/25] update docs. --- docs/rules/lines-between-class-members.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md index 8acdcbbb7e4..b79ec686971 100644 --- a/docs/rules/lines-between-class-members.md +++ b/docs/rules/lines-between-class-members.md @@ -86,8 +86,12 @@ Examples of **correct** code for this rule with the object option: ```js /* eslint lines-between-class-members: ["error", "always", { exceptAfterSingleLine: true }]*/ class Foo{ - bar(){} - baz(){} + bar(){} // single line class member + baz(){ + // multi line class member + } + + qux(){} } ``` From 286d1aeb7c5a13bcbbe7e3088586f91319f45fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 16 Sep 2017 12:20:57 +0800 Subject: [PATCH 23/25] finished.:) --- lib/rules/lines-between-class-members.js | 68 +++++++++++------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index 48d16395bf8..9ae7d34e018 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -58,47 +58,39 @@ module.exports = { return second.loc.start.line - first.loc.end.line >= 2; } - /** - * Checks the given MethodDefinition node to be padded. - * @param {ASTNode} node The AST node of a MethodDefinition. - * @returns {void} undefined. - */ - function checkPadding(node) { - const body = node.body; - - for (let i = 0; i < body.length - 1; i++) { - - // only check padding lines after class members(skip empty). - if (body[i]) { - - const curFirst = sourceCode.getFirstToken(body[i]); - const curLast = sourceCode.getLastToken(body[i]); - const comments = sourceCode.getCommentsBefore(body[i + 1]); - const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]); - const isPadded = isPaddingBetweenTokens(curLast, nextFirst); - const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); - const skip = !isMulti && options[1].exceptAfterSingleLine; - - - if ((options[0] === "always" && !skip && !isPadded) || - (options[0] === "never" && isPadded)) { - context.report({ - node: body[i + 1], - message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, - fix(fixer) { - return isPadded - ? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n") - : fixer.insertTextAfter(curLast, "\n"); - } - }); + return { + ClassBody(node) { + const body = node.body; + + for (let i = 0; i < body.length - 1; i++) { + + // only check padding lines after class members(skip empty). + if (body[i]) { + + const curFirst = sourceCode.getFirstToken(body[i]); + const curLast = sourceCode.getLastToken(body[i]); + const comments = sourceCode.getCommentsBefore(body[i + 1]); + const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]); + const isPadded = isPaddingBetweenTokens(curLast, nextFirst); + const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); + const skip = !isMulti && options[1].exceptAfterSingleLine; + + + if ((options[0] === "always" && !skip && !isPadded) || + (options[0] === "never" && isPadded)) { + context.report({ + node: body[i + 1], + message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, + fix(fixer) { + return isPadded + ? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n") + : fixer.insertTextAfter(curLast, "\n"); + } + }); + } } } } - } - - return { - ClassBody: checkPadding }; - } }; From 971e15db40d00cb850723ab73080026695df893e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 16 Sep 2017 13:36:29 +0800 Subject: [PATCH 24/25] Update lines-between-class-members.md --- docs/rules/lines-between-class-members.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md index b79ec686971..6beeae6eaf9 100644 --- a/docs/rules/lines-between-class-members.md +++ b/docs/rules/lines-between-class-members.md @@ -97,7 +97,7 @@ class Foo{ ## When Not To Use It -If you don't want enforce empty lines between class members, you can disable this rule. +If you don't want to enforce empty lines between class members, you can disable this rule. ## Related Rules From 870e2e5709f2de6a420a514de83a345fa33cb606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 30 Sep 2017 08:11:00 +0800 Subject: [PATCH 25/25] Chore: rm unused check & add tests. --- lib/rules/lines-between-class-members.js | 45 +++++++++---------- .../lib/rules/lines-between-class-members.js | 4 ++ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js index 9ae7d34e018..85e8c69358c 100644 --- a/lib/rules/lines-between-class-members.js +++ b/lib/rules/lines-between-class-members.js @@ -63,31 +63,26 @@ module.exports = { const body = node.body; for (let i = 0; i < body.length - 1; i++) { - - // only check padding lines after class members(skip empty). - if (body[i]) { - - const curFirst = sourceCode.getFirstToken(body[i]); - const curLast = sourceCode.getLastToken(body[i]); - const comments = sourceCode.getCommentsBefore(body[i + 1]); - const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]); - const isPadded = isPaddingBetweenTokens(curLast, nextFirst); - const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); - const skip = !isMulti && options[1].exceptAfterSingleLine; - - - if ((options[0] === "always" && !skip && !isPadded) || - (options[0] === "never" && isPadded)) { - context.report({ - node: body[i + 1], - message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, - fix(fixer) { - return isPadded - ? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n") - : fixer.insertTextAfter(curLast, "\n"); - } - }); - } + const curFirst = sourceCode.getFirstToken(body[i]); + const curLast = sourceCode.getLastToken(body[i]); + const comments = sourceCode.getCommentsBefore(body[i + 1]); + const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]); + const isPadded = isPaddingBetweenTokens(curLast, nextFirst); + const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast); + const skip = !isMulti && options[1].exceptAfterSingleLine; + + + if ((options[0] === "always" && !skip && !isPadded) || + (options[0] === "never" && isPadded)) { + context.report({ + node: body[i + 1], + message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE, + fix(fixer) { + return isPadded + ? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n") + : fixer.insertTextAfter(curLast, "\n"); + } + }); } } } diff --git a/tests/lib/rules/lines-between-class-members.js b/tests/lib/rules/lines-between-class-members.js index dfa17670b64..1304d719a48 100644 --- a/tests/lib/rules/lines-between-class-members.js +++ b/tests/lib/rules/lines-between-class-members.js @@ -28,6 +28,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); ruleTester.run("lines-between-class-members", rule, { valid: [ "class foo{}", + "class foo{;;}", "class foo{\n\n}", "class foo{constructor(){}\n}", "class foo{\nconstructor(){}}", @@ -36,6 +37,9 @@ ruleTester.run("lines-between-class-members", rule, { "class foo{ bar(){}\n\n/*comments*/baz(){}}", "class foo{ bar(){}\n\n//comments\nbaz(){}}", + "class foo{ bar(){}\n\n;;baz(){}}", + "class foo{ bar(){};\n\nbaz(){}}", + { code: "class foo{ bar(){}\nbaz(){}}", options: ["never"] }, { code: "class foo{ bar(){}\n/*comments*/baz(){}}", options: ["never"] }, { code: "class foo{ bar(){}\n//comments\nbaz(){}}", options: ["never"] },