From bfe1dc4e614640cb69032afbb5851c1493f537e3 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 14 Feb 2020 16:37:54 +0100 Subject: [PATCH] Breaking: no-dupe-class-members checks some computed keys (fixes #12808) (#12837) * Breaking: no-dupe-class-members checks some computed keys (fixes #12808) * Fix constructor, add more tests --- lib/rules/no-dupe-class-members.js | 5 +- tests/lib/rules/no-dupe-class-members.js | 139 ++++++++++++++++++++++- 2 files changed, 141 insertions(+), 3 deletions(-) diff --git a/lib/rules/no-dupe-class-members.js b/lib/rules/no-dupe-class-members.js index 55639746b27..b12939d57bc 100644 --- a/lib/rules/no-dupe-class-members.js +++ b/lib/rules/no-dupe-class-members.js @@ -74,11 +74,12 @@ module.exports = { // Reports the node if its name has been declared already. MethodDefinition(node) { - if (node.computed) { + const name = astUtils.getStaticPropertyName(node); + + if (name === null || node.kind === "constructor") { return; } - const name = astUtils.getStaticPropertyName(node) || ""; const state = getState(name, node.static); let isDuplicate = false; diff --git a/tests/lib/rules/no-dupe-class-members.js b/tests/lib/rules/no-dupe-class-members.js index cbbc7b8015b..a1a534d2da9 100644 --- a/tests/lib/rules/no-dupe-class-members.js +++ b/tests/lib/rules/no-dupe-class-members.js @@ -29,7 +29,29 @@ ruleTester.run("no-dupe-class-members", rule, { "class A { 'foo'() {} 'bar'() {} baz() {} }", "class A { *'foo'() {} *'bar'() {} *baz() {} }", "class A { get 'foo'() {} get 'bar'() {} get baz() {} }", - "class A { 1() {} 2() {} }" + "class A { 1() {} 2() {} }", + "class A { ['foo']() {} ['bar']() {} }", + "class A { [`foo`]() {} [`bar`]() {} }", + "class A { [12]() {} [123]() {} }", + "class A { [1.0]() {} ['1.0']() {} }", + "class A { [0x1]() {} [`0x1`]() {} }", + "class A { [null]() {} ['']() {} }", + "class A { get ['foo']() {} set ['foo'](value) {} }", + "class A { ['foo']() {} static ['foo']() {} }", + + // computed "constructor" key doesn't create constructor + "class A { ['constructor']() {} constructor() {} }", + "class A { 'constructor'() {} [`constructor`]() {} }", + "class A { constructor() {} get [`constructor`]() {} }", + "class A { 'constructor'() {} set ['constructor'](value) {} }", + + // not assumed to be statically-known values + "class A { ['foo' + '']() {} ['foo']() {} }", + "class A { [`foo${''}`]() {} [`foo`]() {} }", + "class A { [-1]() {} ['-1']() {} }", + + // not supported by this rule + "class A { [foo]() {} [foo]() {} }" ], invalid: [ { @@ -56,6 +78,121 @@ ruleTester.run("no-dupe-class-members", rule, { { type: "MethodDefinition", line: 1, column: 19, messageId: "unexpected", data: { name: "10" } } ] }, + { + code: "class A { ['foo']() {} ['foo']() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 24, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { static ['foo']() {} static foo() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 31, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { set 'foo'(value) {} set ['foo'](val) {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 31, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { ''() {} ['']() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 19, messageId: "unexpected", data: { name: "" } } + ] + }, + { + code: "class A { [`foo`]() {} [`foo`]() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 24, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { static get [`foo`]() {} static get ['foo']() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 35, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { foo() {} [`foo`]() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 20, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { get [`foo`]() {} 'foo'() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 28, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { static 'foo'() {} static [`foo`]() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 29, messageId: "unexpected", data: { name: "foo" } } + ] + }, + { + code: "class A { ['constructor']() {} ['constructor']() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 32, messageId: "unexpected", data: { name: "constructor" } } + ] + }, + { + code: "class A { static [`constructor`]() {} static constructor() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 39, messageId: "unexpected", data: { name: "constructor" } } + ] + }, + { + code: "class A { static constructor() {} static 'constructor'() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 35, messageId: "unexpected", data: { name: "constructor" } } + ] + }, + { + code: "class A { [123]() {} [123]() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 22, messageId: "unexpected", data: { name: "123" } } + ] + }, + { + code: "class A { [0x10]() {} 16() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 23, messageId: "unexpected", data: { name: "16" } } + ] + }, + { + code: "class A { [100]() {} [1e2]() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 22, messageId: "unexpected", data: { name: "100" } } + ] + }, + { + code: "class A { [123.00]() {} [`123`]() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 25, messageId: "unexpected", data: { name: "123" } } + ] + }, + { + code: "class A { static '65'() {} static [0o101]() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 28, messageId: "unexpected", data: { name: "65" } } + ] + }, + { + code: "class A { [123n]() {} 123() {} }", + parserOptions: { ecmaVersion: 2020 }, + errors: [ + { type: "MethodDefinition", line: 1, column: 23, messageId: "unexpected", data: { name: "123" } } + ] + }, + { + code: "class A { [null]() {} 'null'() {} }", + errors: [ + { type: "MethodDefinition", line: 1, column: 23, messageId: "unexpected", data: { name: "null" } } + ] + }, { code: "class A { foo() {} foo() {} foo() {} }", errors: [