diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index 0db6cffdf6867..5b0a14aa7e0cc 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -508,6 +508,10 @@ impl RuleRunner for crate::rules::eslint::no_useless_catch::NoUselessCatch { const NODE_TYPES: Option<&AstTypesBitset> = None; } +impl RuleRunner for crate::rules::eslint::no_useless_computed_key::NoUselessComputedKey { + const NODE_TYPES: Option<&AstTypesBitset> = None; +} + impl RuleRunner for crate::rules::eslint::no_useless_concat::NoUselessConcat { const NODE_TYPES: Option<&AstTypesBitset> = None; } diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 8571a09f8de50..e829278b1a511 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -159,6 +159,7 @@ pub(crate) mod eslint { pub mod no_useless_backreference; pub mod no_useless_call; pub mod no_useless_catch; + pub mod no_useless_computed_key; pub mod no_useless_concat; pub mod no_useless_constructor; pub mod no_useless_escape; @@ -655,6 +656,7 @@ oxc_macros::declare_all_lint_rules! { eslint::max_nested_callbacks, eslint::max_params, eslint::new_cap, + eslint::no_useless_computed_key, eslint::no_unassigned_vars, eslint::no_extra_bind, eslint::no_alert, diff --git a/crates/oxc_linter/src/rules/eslint/no_useless_computed_key.rs b/crates/oxc_linter/src/rules/eslint/no_useless_computed_key.rs new file mode 100644 index 0000000000000..e5ca2745fb4c3 --- /dev/null +++ b/crates/oxc_linter/src/rules/eslint/no_useless_computed_key.rs @@ -0,0 +1,354 @@ +use oxc_ast::{AstKind, ast::Expression}; +use oxc_diagnostics::OxcDiagnostic; +use oxc_macros::declare_oxc_lint; +use oxc_span::{Atom, GetSpan, Span}; +use serde_json::Value; + +use crate::{AstNode, context::LintContext, rule::Rule}; + +fn no_useless_computed_key_diagnostic(span: Span, raw: Option) -> OxcDiagnostic { + // false positive, if we remove the closure, `borrowed data escapes outside of function `raw` escapes the function body here` + #[expect(clippy::redundant_closure)] + let key = raw.unwrap_or_else(|| Atom::empty()); + OxcDiagnostic::warn(format!("Unnecessarily computed property `{key}` found.")) + .with_help("Replace the computed property with a plain identifier or string literal") + .with_label(span) +} + +#[derive(Debug, Clone)] +pub struct NoUselessComputedKey { + enforce_for_class_members: bool, +} + +impl Default for NoUselessComputedKey { + fn default() -> Self { + Self { enforce_for_class_members: true } + } +} + +declare_oxc_lint!( + /// ### What it does + /// + /// Disallow unnecessary computed property keys in objects and classes + /// + /// ### Why is this bad? + /// + /// It’s unnecessary to use computed properties with literals such as: + /// ```js + /// const foo = {["a"]: "b"}; + /// ``` + /// + /// The code can be rewritten as: + /// ```js + /// const foo = {"a": "b"}; + /// ``` + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```js + /// const a = { ['0']: 0 }; + /// const b = { ['0+1,234']: 0 }; + /// const c = { [0]: 0 }; + /// const e = { ['x']() {} }; + /// + /// class Foo { + /// ["foo"] = "bar"; + /// [0]() {} + /// static ["foo"] = "bar"; + /// get ['b']() {} + /// set ['c'](value) {} + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```js + /// const a = { 'a': 0 }; + /// const b = { 0: 0 }; + /// const c = { x() {} }; + /// const e = { '0+1,234': 0 }; + /// + /// class Foo { + /// "foo" = "bar"; + /// 0() {} + /// 'a'() {} + /// static "foo" = "bar"; + /// } + /// ``` + /// + /// Examples of additional **correct** code for this rule: + /// ```js + /// + /// const c = { + /// "__proto__": foo, // defines object's prototype + /// ["__proto__"]: bar // defines a property named "__proto__" + /// }; + /// class Foo { + /// ["constructor"]; // instance field named "constructor" + /// "constructor"() {} // the constructor of this class + /// static ["constructor"]; // static field named "constructor" + /// static ["prototype"]; // runtime error, it would be a parsing error without `[]` + /// } + /// ``` + /// + /// ### Options + /// + /// #### enforceForClassMembers + /// + /// `{ type: boolean, default: true }` + /// + /// The `enforceForClassMembers` option controls whether the rule applies to + /// class members (methods and properties). + /// + /// Examples of **correct** code for this rule with the `{ "enforceForClassMembers": false }` option: + /// ```js + /// class SomeClass { + /// ["foo"] = "bar"; + /// [42] = "baz"; + /// get ['b']() {} + /// set ['c'](value) {} + /// static ["foo"] = "bar"; + /// } + /// ``` + NoUselessComputedKey, + eslint, + style, + pending +); + +impl Rule for NoUselessComputedKey { + fn from_configuration(value: Value) -> Self { + let obj = value.get(0); + Self { + enforce_for_class_members: obj + .and_then(|v| v.get("enforceForClassMembers")) + .and_then(Value::as_bool) + .unwrap_or(true), + } + } + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + match node.kind() { + AstKind::ObjectProperty(property) if property.computed => { + if let Some(expr) = + property.key.as_expression().map(Expression::get_inner_expression) + { + check_computed_class_member( + ctx, + property.key.span(), + expr, + false, + &[], + &["__proto__"], + ); + } + } + AstKind::BindingProperty(binding_prop) if binding_prop.computed => { + if let Some(expr) = + binding_prop.key.as_expression().map(Expression::get_inner_expression) + { + check_computed_class_member(ctx, binding_prop.span, expr, false, &[], &[]); + } + } + AstKind::PropertyDefinition(prop_def) + if self.enforce_for_class_members && prop_def.computed => + { + if let Some(expr) = + prop_def.key.as_expression().map(Expression::get_inner_expression) + { + check_computed_class_member( + ctx, + prop_def.key.span(), + expr, + prop_def.r#static, + &["prototype", "constructor"], + &["constructor"], + ); + } + } + AstKind::MethodDefinition(method_def) + if self.enforce_for_class_members && method_def.computed => + { + if let Some(expr) = + method_def.key.as_expression().map(Expression::get_inner_expression) + { + check_computed_class_member( + ctx, + method_def.span, + expr, + method_def.r#static, + &["prototype"], + &["constructor"], + ); + } + } + _ => {} + } + } +} + +fn check_computed_class_member( + ctx: &LintContext<'_>, + span: Span, + expr: &Expression, + is_static: bool, + allow_static: &[&str], + allow_non_static: &[&str], +) { + match expr { + Expression::StringLiteral(lit) => { + let key_name = lit.value.as_str(); + let allowed = if is_static { + allow_static.contains(&key_name) + } else { + allow_non_static.contains(&key_name) + }; + if !allowed { + ctx.diagnostic(no_useless_computed_key_diagnostic(span, lit.raw)); + } + } + Expression::NumericLiteral(number_lit) => { + ctx.diagnostic(no_useless_computed_key_diagnostic(span, number_lit.raw)); + } + _ => {} + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + ("({ 'a': 0, b(){} })", None), + ("({ [x]: 0 });", None), + ("({ a: 0, [b](){} })", None), + ("({ ['__proto__']: [] })", None), + ("var { 'a': foo } = obj", None), + ("var { [a]: b } = obj;", None), + ("var { a } = obj;", None), + ("var { a: a } = obj;", None), + ("var { a: b } = obj;", None), + ("class Foo { a() {} }", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ("class Foo { 'a'() {} }", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ("class Foo { [x]() {} }", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ( + "class Foo { ['constructor']() {} }", + Some(serde_json::json!([{ "enforceForClassMembers": true }])), + ), + ( + "class Foo { static ['prototype']() {} }", + Some(serde_json::json!([{ "enforceForClassMembers": true }])), + ), + ("(class { 'a'() {} })", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ("(class { [x]() {} })", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ( + "(class { ['constructor']() {} })", + Some(serde_json::json!([{ "enforceForClassMembers": true }])), + ), + ( + "(class { static ['prototype']() {} })", + Some(serde_json::json!([{ "enforceForClassMembers": true }])), + ), + ("class Foo { 'x'() {} }", None), + ("(class { [x]() {} })", None), + ("class Foo { static constructor() {} }", None), + ("class Foo { prototype() {} }", None), + ( + "class Foo { ['x']() {} }", + Some(serde_json::json!([{ "enforceForClassMembers": false }])), + ), + ("(class { ['x']() {} })", Some(serde_json::json!([{ "enforceForClassMembers": false }]))), + ( + "class Foo { static ['constructor']() {} }", + Some(serde_json::json!([{ "enforceForClassMembers": false }])), + ), + ( + "class Foo { ['prototype']() {} }", + Some(serde_json::json!([{ "enforceForClassMembers": false }])), + ), + ("class Foo { a }", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ( + "class Foo { ['constructor'] }", + Some(serde_json::json!([{ "enforceForClassMembers": true }])), + ), + ( + "class Foo { static ['constructor'] }", + Some(serde_json::json!([{ "enforceForClassMembers": true }])), + ), + ( + "class Foo { static ['prototype'] }", + Some(serde_json::json!([{ "enforceForClassMembers": true }])), + ), + ("({ [99999999999999999n]: 0 })", None), // { "ecmaVersion": 2020 } + ]; + + let fail = vec![ + ("({ ['0']: 0 })", None), + ("var { ['0']: a } = obj", None), + ("({ ['0+1,234']: 0 })", None), + ("({ [0]: 0 })", None), + ("var { [0]: a } = obj", None), + ("({ ['x']: 0 })", None), + ("var { ['x']: a } = obj", None), + ("var { ['__proto__']: a } = obj", None), + ("({ ['x']() {} })", None), + ("({ [/* this comment prevents a fix */ 'x']: 0 })", None), + ("({ ['x' /* this comment also prevents a fix */]: 0 })", None), + ("({ [('x')]: 0 })", None), + ("var { [('x')]: a } = obj", None), + ("({ *['x']() {} })", None), + ("({ async ['x']() {} })", None), // { "ecmaVersion": 8 }, + ("({ get[.2]() {} })", None), + ("({ set[.2](value) {} })", None), + ("({ async[.2]() {} })", None), // { "ecmaVersion": 8 }, + ("({ [2]() {} })", None), + ("({ get [2]() {} })", None), + ("({ set [2](value) {} })", None), + ("({ async [2]() {} })", None), // { "ecmaVersion": 8 }, + ("({ get[2]() {} })", None), + ("({ set[2](value) {} })", None), + ("({ async[2]() {} })", None), // { "ecmaVersion": 8 }, + ("({ get['foo']() {} })", None), + ("({ *[2]() {} })", None), + ("({ async*[2]() {} })", None), + ("({ ['constructor']: 1 })", None), + ("({ ['prototype']: 1 })", None), + ("class Foo { ['0']() {} }", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ("class Foo { ['0+1,234']() {} }", Some(serde_json::json!([{}]))), + ("class Foo { ['x']() {} }", Some(serde_json::json!([{ "enforceForClassMembers": true }]))), + ("class Foo { [/* this comment prevents a fix */ 'x']() {} }", None), + ("class Foo { ['x' /* this comment also prevents a fix */]() {} }", None), + ("class Foo { [('x')]() {} }", None), + ("class Foo { *['x']() {} }", None), + ("class Foo { async ['x']() {} }", None), // { "ecmaVersion": 8 }, + ("class Foo { get[.2]() {} }", None), + ("class Foo { set[.2](value) {} }", None), + ("class Foo { async[.2]() {} }", None), // { "ecmaVersion": 8 }, + ("class Foo { [2]() {} }", None), + ("class Foo { get [2]() {} }", None), + ("class Foo { set [2](value) {} }", None), + ("class Foo { async [2]() {} }", None), // { "ecmaVersion": 8 }, + ("class Foo { get[2]() {} }", None), + ("class Foo { set[2](value) {} }", None), + ("class Foo { async[2]() {} }", None), // { "ecmaVersion": 8 }, + ("class Foo { get['foo']() {} }", None), + ("class Foo { *[2]() {} }", None), + ("class Foo { async*[2]() {} }", None), + ("class Foo { static ['constructor']() {} }", None), + ("class Foo { ['prototype']() {} }", None), + ("(class { ['x']() {} })", None), + ("(class { ['__proto__']() {} })", None), + ("(class { static ['__proto__']() {} })", None), + ("(class { static ['constructor']() {} })", None), + ("(class { ['prototype']() {} })", None), + ("class Foo { ['0'] }", None), + ("class Foo { ['0'] = 0 }", None), + ("class Foo { static[0] }", None), + ("class Foo { ['#foo'] }", None), + ("(class { ['__proto__'] })", None), + ("(class { static ['__proto__'] })", None), + ("(class { ['prototype'] })", None), + ]; + + Tester::new(NoUselessComputedKey::NAME, NoUselessComputedKey::PLUGIN, pass, fail) + .test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/eslint_no_useless_computed_key.snap b/crates/oxc_linter/src/snapshots/eslint_no_useless_computed_key.snap new file mode 100644 index 0000000000000..0edeccf21f1f5 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/eslint_no_useless_computed_key.snap @@ -0,0 +1,457 @@ +--- +source: crates/oxc_linter/src/tester.rs +--- + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'0'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ ['0']: 0 }) + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'0'` found. + ╭─[no_useless_computed_key.tsx:1:7] + 1 │ var { ['0']: a } = obj + · ──────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'0+1,234'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ ['0+1,234']: 0 }) + · ───────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `0` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ [0]: 0 }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `0` found. + ╭─[no_useless_computed_key.tsx:1:7] + 1 │ var { [0]: a } = obj + · ────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ ['x']: 0 }) + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:7] + 1 │ var { ['x']: a } = obj + · ──────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'__proto__'` found. + ╭─[no_useless_computed_key.tsx:1:7] + 1 │ var { ['__proto__']: a } = obj + · ──────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ ['x']() {} }) + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:39] + 1 │ ({ [/* this comment prevents a fix */ 'x']: 0 }) + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ ['x' /* this comment also prevents a fix */]: 0 }) + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ [('x')]: 0 }) + · ───── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:7] + 1 │ var { [('x')]: a } = obj + · ────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:6] + 1 │ ({ *['x']() {} }) + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:11] + 1 │ ({ async ['x']() {} }) + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `.2` found. + ╭─[no_useless_computed_key.tsx:1:8] + 1 │ ({ get[.2]() {} }) + · ── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `.2` found. + ╭─[no_useless_computed_key.tsx:1:8] + 1 │ ({ set[.2](value) {} }) + · ── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `.2` found. + ╭─[no_useless_computed_key.tsx:1:10] + 1 │ ({ async[.2]() {} }) + · ── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ [2]() {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:9] + 1 │ ({ get [2]() {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:9] + 1 │ ({ set [2](value) {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:11] + 1 │ ({ async [2]() {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:8] + 1 │ ({ get[2]() {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:8] + 1 │ ({ set[2](value) {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:10] + 1 │ ({ async[2]() {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'foo'` found. + ╭─[no_useless_computed_key.tsx:1:8] + 1 │ ({ get['foo']() {} }) + · ───── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:6] + 1 │ ({ *[2]() {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:11] + 1 │ ({ async*[2]() {} }) + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'constructor'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ ['constructor']: 1 }) + · ───────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'prototype'` found. + ╭─[no_useless_computed_key.tsx:1:5] + 1 │ ({ ['prototype']: 1 }) + · ─────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'0'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { ['0']() {} } + · ────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'0+1,234'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { ['0+1,234']() {} } + · ──────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { ['x']() {} } + · ────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { [/* this comment prevents a fix */ 'x']() {} } + · ──────────────────────────────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { ['x' /* this comment also prevents a fix */]() {} } + · ───────────────────────────────────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { [('x')]() {} } + · ──────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { *['x']() {} } + · ─────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { async ['x']() {} } + · ──────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `.2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { get[.2]() {} } + · ──────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `.2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { set[.2](value) {} } + · ───────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `.2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { async[.2]() {} } + · ────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { [2]() {} } + · ──────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { get [2]() {} } + · ──────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { set [2](value) {} } + · ───────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { async [2]() {} } + · ────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { get[2]() {} } + · ─────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { set[2](value) {} } + · ──────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { async[2]() {} } + · ───────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'foo'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { get['foo']() {} } + · ─────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { *[2]() {} } + · ───────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `2` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { async*[2]() {} } + · ────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'constructor'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { static ['constructor']() {} } + · ─────────────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'prototype'` found. + ╭─[no_useless_computed_key.tsx:1:13] + 1 │ class Foo { ['prototype']() {} } + · ────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'x'` found. + ╭─[no_useless_computed_key.tsx:1:10] + 1 │ (class { ['x']() {} }) + · ────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'__proto__'` found. + ╭─[no_useless_computed_key.tsx:1:10] + 1 │ (class { ['__proto__']() {} }) + · ────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'__proto__'` found. + ╭─[no_useless_computed_key.tsx:1:10] + 1 │ (class { static ['__proto__']() {} }) + · ───────────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'constructor'` found. + ╭─[no_useless_computed_key.tsx:1:10] + 1 │ (class { static ['constructor']() {} }) + · ─────────────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'prototype'` found. + ╭─[no_useless_computed_key.tsx:1:10] + 1 │ (class { ['prototype']() {} }) + · ────────────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'0'` found. + ╭─[no_useless_computed_key.tsx:1:14] + 1 │ class Foo { ['0'] } + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'0'` found. + ╭─[no_useless_computed_key.tsx:1:14] + 1 │ class Foo { ['0'] = 0 } + · ─── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `0` found. + ╭─[no_useless_computed_key.tsx:1:20] + 1 │ class Foo { static[0] } + · ─ + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'#foo'` found. + ╭─[no_useless_computed_key.tsx:1:14] + 1 │ class Foo { ['#foo'] } + · ────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'__proto__'` found. + ╭─[no_useless_computed_key.tsx:1:11] + 1 │ (class { ['__proto__'] }) + · ─────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'__proto__'` found. + ╭─[no_useless_computed_key.tsx:1:18] + 1 │ (class { static ['__proto__'] }) + · ─────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal + + ⚠ eslint(no-useless-computed-key): Unnecessarily computed property `'prototype'` found. + ╭─[no_useless_computed_key.tsx:1:11] + 1 │ (class { ['prototype'] }) + · ─────────── + ╰──── + help: Replace the computed property with a plain identifier or string literal