From 1ee61b06715fcc750be2c923034a1e59ba663287 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 02:52:55 +0200 Subject: [PATCH] Update: enforceForClassMembers computed-property-spacing (fixes #12049) (#12214) --- docs/rules/computed-property-spacing.md | 55 ++- lib/rules/computed-property-spacing.js | 19 +- tests/lib/rules/computed-property-spacing.js | 438 ++++++++++++++++++- 3 files changed, 508 insertions(+), 4 deletions(-) diff --git a/docs/rules/computed-property-spacing.md b/docs/rules/computed-property-spacing.md index 89b1c775e06..9641ee089e5 100644 --- a/docs/rules/computed-property-spacing.md +++ b/docs/rules/computed-property-spacing.md @@ -25,11 +25,17 @@ This rule does not apply to brackets that are separated from the adjacent value ## Options -This rule has a string option: +This rule has two options, a string option and an object option. + +String option: * `"never"` (default) disallows spaces inside computed property brackets * `"always"` requires one or more spaces inside computed property brackets +Object option: + +* `"enforceForClassMembers": true` additionally applies this rule to class members (default is `false`) + ### never Examples of **incorrect** code for this rule with the default `"never"` option: @@ -84,6 +90,53 @@ var x = {[ b ]: a} obj[ foo[ bar ] ] ``` +#### enforceForClassMembers + +By default, this rule does not check class declarations and class expressions, +as the default value for `enforceForClassMembers` is `false`. + +When `enforceForClassMembers` is set to `true`, the rule will also disallow/enforce spaces inside of +computed keys of class methods, getters and setters. + +Examples of **incorrect** code for this rule with `"never"` and `{ "enforceForClassMembers": true }`: + +```js +/*eslint computed-property-spacing: ["error", "never", { "enforceForClassMembers": true }]*/ +/*eslint-env es6*/ + +class Foo { + [a ]() {} + get [b ]() {} + set [b ](value) {} +} + +const Bar = class { + [ a](){} + static [ b]() {} + static get [ c ]() {} + static set [ c ](value) {} +} +``` + +Examples of **correct** code for this rule with `"never"` and `{ "enforceForClassMembers": true }`: + +```js +/*eslint computed-property-spacing: ["error", "never", { "enforceForClassMembers": true }]*/ +/*eslint-env es6*/ + +class Foo { + [a]() {} + get [b]() {} + set [b](value) {} +} + +const Bar = class { + [a](){} + static [b]() {} + static get [c]() {} + static set [c](value) {} +} +``` ## When Not To Use It diff --git a/lib/rules/computed-property-spacing.js b/lib/rules/computed-property-spacing.js index 91b7d28963f..33f7c9401a9 100644 --- a/lib/rules/computed-property-spacing.js +++ b/lib/rules/computed-property-spacing.js @@ -26,6 +26,16 @@ module.exports = { schema: [ { enum: ["always", "never"] + }, + { + type: "object", + properties: { + enforceForClassMembers: { + type: "boolean", + default: false + } + }, + additionalProperties: false } ], @@ -41,6 +51,7 @@ module.exports = { create(context) { const sourceCode = context.getSourceCode(); const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" + const enforceForClassMembers = context.options[1] && context.options[1].enforceForClassMembers; //-------------------------------------------------------------------------- // Helpers @@ -178,10 +189,16 @@ module.exports = { // Public //-------------------------------------------------------------------------- - return { + const listeners = { Property: checkSpacing("key"), MemberExpression: checkSpacing("property") }; + if (enforceForClassMembers) { + listeners.MethodDefinition = checkSpacing("key"); + } + + return listeners; + } }; diff --git a/tests/lib/rules/computed-property-spacing.js b/tests/lib/rules/computed-property-spacing.js index fa1ca38f48a..3901d8c3fb3 100644 --- a/tests/lib/rules/computed-property-spacing.js +++ b/tests/lib/rules/computed-property-spacing.js @@ -72,7 +72,118 @@ ruleTester.run("computed-property-spacing", rule, { // never - unrelated cases { code: "var foo = {};", options: ["never"] }, - { code: "var foo = [];", options: ["never"] } + { code: "var foo = [];", options: ["never"] }, + + //------------------------------------------------------------------------------ + // Classes + //------------------------------------------------------------------------------ + + // test default settings + { + code: "class A { [ a ](){} }", + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["never"], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["never", {}], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [a](){} }", + options: ["always"], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + options: ["always"], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + options: ["always", {}], + parserOptions: { ecmaVersion: 6 } + }, + + // explicitly disabled option + { + code: "class A { [ a ](){} }", + options: ["never", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["never", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [a](){} }", + options: ["always", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} }", + options: ["always", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + + // valid spacing + { + code: "A = class { [a](){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a] ( ) { } }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ \n a \n ](){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [ a ](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [ a ](){}[ b ](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [\na\n](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // non-computed + { + code: "class A { a ( ) { } get b(){} set b ( foo ){} static c (){} static get d() {} static set d( bar ) {} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class {a(){}get b(){}set b(foo){}static c(){}static get d(){}static set d(bar){}}", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + } ], invalid: [ @@ -322,7 +433,330 @@ ruleTester.run("computed-property-spacing", rule, { line: 1 } ] - } + }, + + //------------------------------------------------------------------------------ + // Classes + //------------------------------------------------------------------------------ + + // never + { + code: "class A { [ a](){} }", + output: "class A { [a](){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 11, + line: 1 + } + ] + }, + { + code: "A = class { [a](){} b(){} static [c ](){} static [d](){}}", + output: "A = class { [a](){} b(){} static [c](){} static [d](){}}", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 37, + line: 1 + } + ] + }, + { + code: "class A { get [a ](){} set [ a](foo){} get b(){} static set b(bar){} static get [ a](){} static set [a ](baz){} }", + output: "class A { get [a](){} set [a](foo){} get b(){} static set b(bar){} static get [a](){} static set [a](baz){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 18, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 28, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 81, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 104, + line: 1 + } + ] + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + output: "A = class { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 13, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 17, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 27, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 31, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 41, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 45, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 61, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 65, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 82, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 86, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 103, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 107, + line: 1 + } + ] + }, + // always + { + code: "class A { [ a](){} }", + output: "class A { [ a ](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 14, + line: 1 + } + ] + }, + { + code: "A = class { [ a ](){} b(){} static [c ](){} static [ d ](){}}", + output: "A = class { [ a ](){} b(){} static [ c ](){} static [ d ](){}}", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 36, + line: 1 + } + ] + }, + { + code: "class A { get [a ](){} set [ a](foo){} get b(){} static set b(bar){} static get [ a](){} static set [a ](baz){} }", + output: "class A { get [ a ](){} set [ a ](foo){} get b(){} static set b(bar){} static get [ a ](){} static set [ a ](baz){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 15, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 31, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 84, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 101, + line: 1 + } + ] + }, + { + code: "A = class { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + output: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 13, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 15, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 25, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 27, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 37, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 39, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 55, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 57, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 74, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 76, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 93, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 95, + line: 1 + } + ] + } ] });