diff --git a/CHANGELOG.md b/CHANGELOG.md index 618a8a3a6a4f..90769fef7c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -295,6 +295,17 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b Contributed by @Conaclos +- [complexity/useLiteralKeys](https://biomejs.dev/linter/rules/use-literal-keys/) no longer report computed properties named `__proto__` ([#2430](https://github.com/biomejs/biome/issues/2430)). + + In JavaScript, `{["__proto__"]: null}` and `{__proto__: null}` have not the same semantic. + The first code set a regular property to `null`. + The second one set the prototype of the object to `null`. + See the [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) for more details. + + The rule now ignores computed properties named `__proto__`. + + Contributed by @Conaclos + #### Bug fixes - Lint rules `useNodejsImportProtocol`, `useNodeAssertStrict`, `noRestrictedImports`, `noNodejsModules` will no longer check `declare module` statements anymore. Contributed by @Sec-ant diff --git a/crates/biome_js_analyze/src/lint/complexity/use_literal_keys.rs b/crates/biome_js_analyze/src/lint/complexity/use_literal_keys.rs index 50f3f96ceb34..5fb4164fb1c3 100644 --- a/crates/biome_js_analyze/src/lint/complexity/use_literal_keys.rs +++ b/crates/biome_js_analyze/src/lint/complexity/use_literal_keys.rs @@ -10,9 +10,8 @@ use biome_js_factory::make::{ js_static_member_expression, token, }; use biome_js_syntax::{ - AnyJsAssignment, AnyJsComputedMember, AnyJsExpression, AnyJsLiteralExpression, - AnyJsMemberExpression, AnyJsName, AnyJsObjectMemberName, JsComputedMemberName, - JsLiteralMemberName, JsSyntaxKind, T, + AnyJsAssignment, AnyJsComputedMember, AnyJsMemberExpression, AnyJsName, AnyJsObjectMemberName, + JsComputedMemberName, JsLiteralMemberName, JsSyntaxKind, T, }; use biome_rowan::{declare_node_union, AstNode, BatchMutationExt, TextRange}; use biome_unicode_table::is_js_ident; @@ -82,28 +81,19 @@ impl Rule for UseLiteralKeys { } AnyJsMember::JsComputedMemberName(member) => member.expression().ok()?, }; - match inner_expression { - AnyJsExpression::AnyJsLiteralExpression( - AnyJsLiteralExpression::JsStringLiteralExpression(string_literal), - ) => { - let value = string_literal.inner_string_text().ok()?; - // A computed property `["something"]` can always be simplified to a string literal "something". - if matches!(node, AnyJsMember::JsComputedMemberName(_)) || is_js_ident(&value) { - return Some((string_literal.range(), value.to_string())); - } - } - AnyJsExpression::JsTemplateExpression(template_expression) => { - let mut value = String::new(); - for element in template_expression.elements() { - let chunk = element.as_js_template_chunk_element()?; - value.push_str(chunk.template_chunk_token().ok()?.text_trimmed()); - } - // A computed property ``[`something`]`` can always be simplified to a string literal "something". - if matches!(node, AnyJsMember::JsComputedMemberName(_)) || is_js_ident(&value) { - return Some((template_expression.range(), value)); - } - } - _ => {} + let value = inner_expression.as_static_value()?; + let value = value.as_string_constant()?; + // `{["__proto__"]: null }` and `{"__proto__": null}`/`{"__proto__": null}` + // have different semantic. + // The first is a regular property. + // The second is a specical property that changes the object prototype. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto + if matches!(node, AnyJsMember::JsComputedMemberName(_)) && value == "__proto__" { + return None; + } + // A computed property `["something"]` can always be simplified to a string literal "something". + if matches!(node, AnyJsMember::JsComputedMemberName(_)) || is_js_ident(&value) { + return Some((inner_expression.range(), value.to_string())); } None } diff --git a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js index edf226760b81..b5b96184492f 100644 --- a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js +++ b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js @@ -36,6 +36,9 @@ a = { a = { [""]: 2 } +a = { + "__proto__": null, +} // optional chain a?.["b"]?.['c']?.d?.e?.["f"] diff --git a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js.snap b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js.snap index d8c98034e1b2..8d36b4743fcc 100644 --- a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js.snap +++ b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/invalid.js.snap @@ -42,6 +42,9 @@ a = { a = { [""]: 2 } +a = { + "__proto__": null, +} // optional chain a?.["b"]?.['c']?.d?.e?.["f"] @@ -641,7 +644,7 @@ invalid.js:37:3 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━ > 37 │ [""]: 2 │ ^^ 38 │ } - 39 │ + 39 │ a = { i Unsafe fix: Use a literal key instead. @@ -651,54 +654,71 @@ invalid.js:37:3 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━ ``` ``` -invalid.js:41:5 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:40:2 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! The computed expression can be simplified without the use of a string literal. - 40 │ // optional chain - > 41 │ a?.["b"]?.['c']?.d?.e?.["f"] - │ ^^^ + 38 │ } + 39 │ a = { + > 40 │ "__proto__": null, + │ ^^^^^^^^^^^ + 41 │ } 42 │ i Unsafe fix: Use a literal key instead. - 41 │ a?.["b"]?.['c']?.d?.e?.["f"] + 40 │ → "__proto__":·null, + │ - - + +``` + +``` +invalid.js:44:5 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! The computed expression can be simplified without the use of a string literal. + + 43 │ // optional chain + > 44 │ a?.["b"]?.['c']?.d?.e?.["f"] + │ ^^^ + 45 │ + + i Unsafe fix: Use a literal key instead. + + 44 │ a?.["b"]?.['c']?.d?.e?.["f"] │ -- -- ``` ``` -invalid.js:41:12 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:44:12 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! The computed expression can be simplified without the use of a string literal. - 40 │ // optional chain - > 41 │ a?.["b"]?.['c']?.d?.e?.["f"] + 43 │ // optional chain + > 44 │ a?.["b"]?.['c']?.d?.e?.["f"] │ ^^^ - 42 │ + 45 │ i Unsafe fix: Use a literal key instead. - 41 │ a?.["b"]?.['c']?.d?.e?.["f"] + 44 │ a?.["b"]?.['c']?.d?.e?.["f"] │ -- -- ``` ``` -invalid.js:41:25 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:44:25 lint/complexity/useLiteralKeys FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! The computed expression can be simplified without the use of a string literal. - 40 │ // optional chain - > 41 │ a?.["b"]?.['c']?.d?.e?.["f"] + 43 │ // optional chain + > 44 │ a?.["b"]?.['c']?.d?.e?.["f"] │ ^^^ - 42 │ + 45 │ i Unsafe fix: Use a literal key instead. - 41 │ a?.["b"]?.['c']?.d?.e?.["f"] + 44 │ a?.["b"]?.['c']?.d?.e?.["f"] │ -- -- ``` - - diff --git a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js index 404fcbe23239..8c9bc04a3017 100644 --- a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js +++ b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js @@ -18,3 +18,6 @@ class C { a = 0 } class C { a(){} } class C { get a(){} } class C { set a(x){} } +a = { + ["__proto__"]: null, +} \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js.snap b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js.snap index 1136d4ea3d8b..47f731ea5dfc 100644 --- a/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js.snap +++ b/crates/biome_js_analyze/tests/specs/complexity/useLiteralKeys/valid.js.snap @@ -24,7 +24,7 @@ class C { a = 0 } class C { a(){} } class C { get a(){} } class C { set a(x){} } - +a = { + ["__proto__"]: null, +} ``` - - diff --git a/website/src/content/docs/internals/changelog.md b/website/src/content/docs/internals/changelog.md index 2ecb79b3cf58..bf1f7e29c8d9 100644 --- a/website/src/content/docs/internals/changelog.md +++ b/website/src/content/docs/internals/changelog.md @@ -301,6 +301,17 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b Contributed by @Conaclos +- [complexity/useLiteralKeys](https://biomejs.dev/linter/rules/use-literal-keys/) no longer report computed properties named `__proto__` ([#2430](https://github.com/biomejs/biome/issues/2430)). + + In JavaScript, `{["__proto__"]: null}` and `{__proto__: null}` have not the same semantic. + The first code set a regular property to `null`. + The second one set the prototype of the object to `null`. + See the [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) for more details. + + The rule now ignores computed properties named `__proto__`. + + Contributed by @Conaclos + #### Bug fixes - Lint rules `useNodejsImportProtocol`, `useNodeAssertStrict`, `noRestrictedImports`, `noNodejsModules` will no longer check `declare module` statements anymore. Contributed by @Sec-ant