From 556ccff5ce75adf40ca8e41642a403a187e0594d Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 9 Nov 2022 13:56:37 +0100 Subject: [PATCH 1/4] fix(rome_js_analyze): Assert `React` symbols resolve to `react` module ## Summary The `is_react_call_api` in some situations didn't test if the method name is the tested for method name. For example, `is_react_call_api(..., "cloneElement")` returned true for `React.clone` or just `clone`. I fixed the same issue in `jsx_member_name_is_react_fragment` ## Test Plan I added some new tests veryfing that the logic correctly verifies the member name. --- crates/rome_js_analyze/src/react.rs | 119 ++++---- .../correctness/no_array_index_key.rs | 32 +-- .../reactCreateElementInvalid.js | 2 + .../reactCreateElementInvalid.js.snap | 44 +-- .../specs/a11y/useButtonType/inObject.js | 2 + .../specs/a11y/useButtonType/inObject.js.snap | 52 ++-- .../specs/correctness/noArrayIndexKey.jsx | 4 +- .../correctness/noArrayIndexKey.jsx.snap | 267 +++++++++--------- .../noChildrenProp/noChildrenPropInvalid.jsx | 3 + .../noChildrenPropInvalid.jsx.snap | 35 +-- .../noChildrenProp/noChildrenPropValid.jsx | 6 + .../noChildrenPropValid.jsx.snap | 6 + .../noUselessFragments/noChildren.jsx | 3 +- .../noUselessFragments/noChildren.jsx.snap | 41 +-- .../noUselessFragments/withChildren.jsx | 2 + .../noUselessFragments/withChildren.jsx.snap | 42 +-- .../createElement.js | 4 +- .../createElement.js.snap | 30 +- .../reactCreateElement.js | 4 +- .../reactCreateElement.js.snap | 12 +- .../createElement.js | 4 +- .../createElement.js.snap | 53 ++-- 22 files changed, 410 insertions(+), 357 deletions(-) diff --git a/crates/rome_js_analyze/src/react.rs b/crates/rome_js_analyze/src/react.rs index e105e11e9e6..a688b2b2e58 100644 --- a/crates/rome_js_analyze/src/react.rs +++ b/crates/rome_js_analyze/src/react.rs @@ -2,7 +2,7 @@ pub mod hooks; -use rome_js_semantic::SemanticModel; +use rome_js_semantic::{Binding, SemanticModel}; use rome_js_syntax::{ JsAnyCallArgument, JsAnyExpression, JsAnyNamedImportSpecifier, JsCallExpression, JsIdentifierBinding, JsImport, JsImportNamedClause, JsNamedImportSpecifierList, @@ -247,46 +247,42 @@ pub(crate) fn is_react_call_api( ) -> Option { // we bail straight away if the API doesn't exists in React debug_assert!(VALID_REACT_API.contains(&api_name)); + Some(match expression { JsAnyExpression::JsStaticMemberExpression(node) => { - let object = node.object().ok()?; let member = node.member().ok()?; let member = member.as_js_name()?; + + if member.value_token().ok()?.text_trimmed() != api_name { + return Some(false); + } + + let object = node.object().ok()?; let identifier = object.as_js_identifier_expression()?.name().ok()?; - let mut maybe_from_react = identifier.syntax().text_trimmed() == "React" - && member.syntax().text_trimmed() == api_name; + return model.declaration(&identifier).and_then(|binding| { + let binding_identifier = JsIdentifierBinding::cast_ref(binding.syntax())?; - if let Some(binding_identifier) = model.declaration(&identifier) { - let binding_identifier = - JsIdentifierBinding::cast_ref(binding_identifier.syntax())?; if let Some(js_import) = binding_identifier .syntax() .ancestors() .find_map(|ancestor| JsImport::cast_ref(&ancestor)) { - maybe_from_react = js_import.source_is("react").ok()?; + js_import.source_is("react").ok() + } else { + Some(false) } - } - maybe_from_react + }); } JsAnyExpression::JsIdentifierExpression(identifier) => { let name = identifier.name().ok()?; - let mut maybe_react = identifier.syntax().text_trimmed() == api_name; - if let Some(identifier_binding) = model.declaration(&name) { - let binding_identifier = - JsIdentifierBinding::cast_ref(identifier_binding.syntax())?; - if let Some(js_import) = binding_identifier - .syntax() - .ancestors() - .find_map(|ancestor| JsImport::cast_ref(&ancestor)) - { - maybe_react = js_import.source_is("react").ok()?; - } - } - maybe_react + + model + .declaration(&name) + .and_then(|binding| is_react_export(binding, api_name)) + .unwrap_or(false) } - _ => return None, + _ => false, }) } @@ -303,24 +299,22 @@ pub(crate) fn jsx_member_name_is_react_fragment( let object = member_name.object().ok()?; let member = member_name.member().ok()?; let object = object.as_jsx_reference_identifier()?; - let mut maybe_react_fragment = object.value_token().ok()?.text_trimmed() == "React" - && member.value_token().ok()?.text_trimmed() == "Fragment"; - if let Some(reference) = model.declaration(object) { - if let Some(js_import) = reference + + if member.value_token().ok()?.text_trimmed() != "Fragment" { + return Some(false); + } + + model.declaration(object).and_then(|declaration| { + if let Some(js_import) = declaration .syntax() .ancestors() .find_map(|ancestor| JsImport::cast_ref(&ancestor)) { - let source_is_react = js_import.source_is("react").ok()?; - maybe_react_fragment = - source_is_react && member.value_token().ok()?.text_trimmed() == "Fragment"; + js_import.source_is("react").ok() } else { - // `React.Fragment` is a binding but it doesn't come from the "react" package - maybe_react_fragment = false; + Some(false) } - } - - Some(maybe_react_fragment) + }) } /// Checks if the node `JsxReferenceIdentifier` is a react fragment. @@ -334,33 +328,7 @@ pub(crate) fn jsx_reference_identifier_is_fragment( model: &SemanticModel, ) -> Option { match model.declaration(name) { - Some(reference) => { - let ident = JsIdentifierBinding::cast_ref(reference.syntax())?; - - let import_specifier = ident.parent::()?; - let name_token = match &import_specifier { - JsAnyNamedImportSpecifier::JsNamedImportSpecifier(named_import) => { - named_import.name().ok()?.value().ok()? - } - JsAnyNamedImportSpecifier::JsShorthandNamedImportSpecifier(_) => { - ident.name_token().ok()? - } - JsAnyNamedImportSpecifier::JsUnknownNamedImportSpecifier(_) => { - return None; - } - }; - - if name_token.text_trimmed() != "Fragment" { - return Some(false); - } - - let import_specifier_list = import_specifier.parent::()?; - let import_specifiers = import_specifier_list.parent::()?; - let import_clause = import_specifiers.parent::()?; - let import = import_clause.parent::()?; - import.source_is("react").ok() - } - + Some(reference) => is_react_export(reference, "Fragment"), None => { let value_token = name.value_token().ok()?; let is_fragment = value_token.text_trimmed() == "Fragment"; @@ -368,3 +336,28 @@ pub(crate) fn jsx_reference_identifier_is_fragment( } } } + +fn is_react_export(binding: Binding, name: &str) -> Option { + let ident = JsIdentifierBinding::cast_ref(binding.syntax())?; + let import_specifier = ident.parent::()?; + let name_token = match &import_specifier { + JsAnyNamedImportSpecifier::JsNamedImportSpecifier(named_import) => { + named_import.name().ok()?.value().ok()? + } + JsAnyNamedImportSpecifier::JsShorthandNamedImportSpecifier(_) => ident.name_token().ok()?, + JsAnyNamedImportSpecifier::JsUnknownNamedImportSpecifier(_) => { + return Some(false); + } + }; + + if name_token.text_trimmed() != name { + return Some(false); + } + + let import_specifier_list = import_specifier.parent::()?; + let import_specifiers = import_specifier_list.parent::()?; + let import_clause = import_specifiers.parent::()?; + let import = import_clause.parent::()?; + + import.source_is("react").ok() +} diff --git a/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_array_index_key.rs b/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_array_index_key.rs index 04ad77e429c..1ca2a3c2257 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_array_index_key.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_array_index_key.rs @@ -5,8 +5,8 @@ use rome_analyze::{declare_rule, Rule, RuleDiagnostic}; use rome_console::markup; use rome_js_semantic::SemanticModel; use rome_js_syntax::{ - JsArrowFunctionExpression, JsCallExpression, JsExpressionStatement, JsFunctionDeclaration, - JsFunctionExpression, JsIdentifierBinding, JsIdentifierExpression, JsMethodClassMember, + JsAnyCallArgument, JsArrowFunctionExpression, JsCallExpression, JsExpressionStatement, + JsFunctionDeclaration, JsFunctionExpression, JsIdentifierBinding, JsMethodClassMember, JsMethodObjectMember, JsParameterList, JsPropertyObjectMember, JsReferenceIdentifier, JsxAttribute, JsxOpeningElement, JsxSelfClosingElement, }; @@ -326,28 +326,24 @@ fn find_react_children_function_argument( "forEach" | "map" ); - let object = member_expression.object().ok()?; - - let mut is_react_children = false; - // case we have `Children` - if let Some(identifier) = JsIdentifierExpression::cast_ref(object.syntax()) { - if identifier.name().ok()?.value_token().ok()?.text_trimmed() == "Children" { - is_react_children = array_call; - } - } else { - // case we have `React.Children` - is_react_children = is_react_call_api(&object, model, "Children")? && array_call; + if !array_call { + return None; } - if is_react_children { + let object = member_expression.object().ok()?; + + // React.Children.forEach/map or Children.forEach/map + if is_react_call_api(&object, model, "Children")? { let arguments = call_expression.arguments().ok()?; let arguments = arguments.args(); let mut arguments = arguments.into_iter(); - let _ = arguments.next()?.ok()?; - let second_argument = arguments.next()?.ok()?; - let second_argument = second_argument.as_js_any_expression()?; - FunctionLike::cast(second_argument.clone().into_syntax()) + match (arguments.next(), arguments.next(), arguments.next()) { + (Some(_), Some(Ok(JsAnyCallArgument::JsAnyExpression(second_argument))), None) => { + FunctionLike::cast(second_argument.into_syntax()) + } + _ => None, + } } else { None } diff --git a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js index 46f5363f95c..214915e8580 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js +++ b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js @@ -1,3 +1,5 @@ +import React from "react"; + React.createElement("div", { tabIndex: '1' }) React.createElement("div", { tabIndex: 1 }) React.createElement("div", { tabIndex: +1 }) diff --git a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap index 3550c9842a0..ef28022dc82 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap @@ -4,6 +4,8 @@ expression: reactCreateElementInvalid.js --- # Input ```js +import React from "react"; + React.createElement("div", { tabIndex: '1' }) React.createElement("div", { tabIndex: 1 }) React.createElement("div", { tabIndex: +1 }) @@ -13,14 +15,16 @@ React.createElement("div", { tabIndex: +01 }) # Diagnostics ``` -reactCreateElementInvalid.js:1:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:3:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - > 1 │ React.createElement("div", { tabIndex: '1' }) + 1 │ import React from "react"; + 2 │ + > 3 │ React.createElement("div", { tabIndex: '1' }) │ ^^^ - 2 │ React.createElement("div", { tabIndex: 1 }) - 3 │ React.createElement("div", { tabIndex: +1 }) + 4 │ React.createElement("div", { tabIndex: 1 }) + 5 │ React.createElement("div", { tabIndex: +1 }) i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. @@ -28,15 +32,15 @@ reactCreateElementInvalid.js:1:40 lint/a11y/noPositiveTabindex ━━━━━ ``` ``` -reactCreateElementInvalid.js:2:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:4:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - 1 │ React.createElement("div", { tabIndex: '1' }) - > 2 │ React.createElement("div", { tabIndex: 1 }) + 3 │ React.createElement("div", { tabIndex: '1' }) + > 4 │ React.createElement("div", { tabIndex: 1 }) │ ^ - 3 │ React.createElement("div", { tabIndex: +1 }) - 4 │ React.createElement("div", { tabIndex: +01 }) + 5 │ React.createElement("div", { tabIndex: +1 }) + 6 │ React.createElement("div", { tabIndex: +01 }) i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. @@ -44,16 +48,16 @@ reactCreateElementInvalid.js:2:40 lint/a11y/noPositiveTabindex ━━━━━ ``` ``` -reactCreateElementInvalid.js:3:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:5:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - 1 │ React.createElement("div", { tabIndex: '1' }) - 2 │ React.createElement("div", { tabIndex: 1 }) - > 3 │ React.createElement("div", { tabIndex: +1 }) + 3 │ React.createElement("div", { tabIndex: '1' }) + 4 │ React.createElement("div", { tabIndex: 1 }) + > 5 │ React.createElement("div", { tabIndex: +1 }) │ ^^ - 4 │ React.createElement("div", { tabIndex: +01 }) - 5 │ + 6 │ React.createElement("div", { tabIndex: +01 }) + 7 │ i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. @@ -61,15 +65,15 @@ reactCreateElementInvalid.js:3:40 lint/a11y/noPositiveTabindex ━━━━━ ``` ``` -reactCreateElementInvalid.js:4:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:6:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - 2 │ React.createElement("div", { tabIndex: 1 }) - 3 │ React.createElement("div", { tabIndex: +1 }) - > 4 │ React.createElement("div", { tabIndex: +01 }) + 4 │ React.createElement("div", { tabIndex: 1 }) + 5 │ React.createElement("div", { tabIndex: +1 }) + > 6 │ React.createElement("div", { tabIndex: +01 }) │ ^^^ - 5 │ + 7 │ i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. diff --git a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js index 05afca94d10..90bf0e5cbe4 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js +++ b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js @@ -1,3 +1,5 @@ +import React from "react"; + // invalid React.createElement('button'); React.createElement('button', { diff --git a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap index 527aebe073a..bded5ef61d5 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap +++ b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap @@ -4,6 +4,8 @@ expression: inObject.js --- # Input ```js +import React from "react"; + // invalid React.createElement('button'); React.createElement('button', { @@ -23,15 +25,15 @@ React.createElement('button', { # Diagnostics ``` -inObject.js:2:21 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:4:21 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide an explicit type prop for the button element. - 1 │ // invalid - > 2 │ React.createElement('button'); + 3 │ // invalid + > 4 │ React.createElement('button'); │ ^^^^^^^^ - 3 │ React.createElement('button', { - 4 │ "type": "bar" + 5 │ React.createElement('button', { + 6 │ "type": "bar" i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. @@ -41,16 +43,16 @@ inObject.js:2:21 lint/a11y/useButtonType ━━━━━━━━━━━━━ ``` ``` -inObject.js:4:13 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:6:13 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide a valid type prop for the button element. - 2 │ React.createElement('button'); - 3 │ React.createElement('button', { - > 4 │ "type": "bar" + 4 │ React.createElement('button'); + 5 │ React.createElement('button', { + > 6 │ "type": "bar" │ ^^^^^ - 5 │ }); - 6 │ React.createElement('button', { + 7 │ }); + 8 │ React.createElement('button', { i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. @@ -60,19 +62,19 @@ inObject.js:4:13 lint/a11y/useButtonType ━━━━━━━━━━━━━ ``` ``` -inObject.js:6:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:8:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide a valid type prop for the button element. - 4 │ "type": "bar" - 5 │ }); - > 6 │ React.createElement('button', { + 6 │ "type": "bar" + 7 │ }); + > 8 │ React.createElement('button', { │ ^ - > 7 │ "style": "background: red" - > 8 │ }); + > 9 │ "style": "background: red" + > 10 │ }); │ ^ - 9 │ React.createElement('button', {}); - 10 │ + 11 │ React.createElement('button', {}); + 12 │ i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. @@ -82,16 +84,16 @@ inObject.js:6:31 lint/a11y/useButtonType ━━━━━━━━━━━━━ ``` ``` -inObject.js:9:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:11:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide a valid type prop for the button element. - 7 │ "style": "background: red" - 8 │ }); - > 9 │ React.createElement('button', {}); + 9 │ "style": "background: red" + 10 │ }); + > 11 │ React.createElement('button', {}); │ ^^ - 10 │ - 11 │ // valid + 12 │ + 13 │ // valid i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. diff --git a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx index 488f9ace4bb..8b9ab1ce045 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx @@ -1,3 +1,5 @@ +import React, {Children, cloneElement} from "react"; + // invalid something.forEach((Element, index) => { foo @@ -57,4 +59,4 @@ something.forEach((element, index) => { something.forEach((element, index) => { -}); \ No newline at end of file +}); diff --git a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap index 702ceaa1d11..977244da801 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap @@ -4,6 +4,8 @@ expression: noArrayIndexKey.jsx --- # Input ```js +import React, {Children, cloneElement} from "react"; + // invalid something.forEach((Element, index) => { foo @@ -64,28 +66,29 @@ something.forEach((element, index) => { }); + ``` # Diagnostics ``` -noArrayIndexKey.jsx:3:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:5:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 1 │ // invalid - 2 │ something.forEach((Element, index) => { - > 3 │ foo + 3 │ // invalid + 4 │ something.forEach((Element, index) => { + > 5 │ foo │ ^^^^^ - 4 │ }); - 5 │ something.forEach((element, index, array) => { + 6 │ }); + 7 │ something.forEach((element, index, array) => { i This is the source of the key value. - 1 │ // invalid - > 2 │ something.forEach((Element, index) => { + 3 │ // invalid + > 4 │ something.forEach((Element, index) => { │ ^^^^^ - 3 │ foo - 4 │ }); + 5 │ foo + 6 │ }); i The order of the items may change, and this also affects performances and component state. @@ -95,25 +98,25 @@ noArrayIndexKey.jsx:3:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:6:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:8:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 4 │ }); - 5 │ something.forEach((element, index, array) => { - > 6 │ foo - │ ^^^^^ - 7 │ }); - 8 │ things.filter((thing, index) => { + 6 │ }); + 7 │ something.forEach((element, index, array) => { + > 8 │ foo + │ ^^^^^ + 9 │ }); + 10 │ things.filter((thing, index) => { i This is the source of the key value. - 3 │ foo - 4 │ }); - > 5 │ something.forEach((element, index, array) => { + 5 │ foo + 6 │ }); + > 7 │ something.forEach((element, index, array) => { │ ^^^^^ - 6 │ foo - 7 │ }); + 8 │ foo + 9 │ }); i The order of the items may change, and this also affects performances and component state. @@ -123,25 +126,25 @@ noArrayIndexKey.jsx:6:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:9:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:11:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 7 │ }); - 8 │ things.filter((thing, index) => { - > 9 │ otherThings.push(foo); + 9 │ }); + 10 │ things.filter((thing, index) => { + > 11 │ otherThings.push(foo); │ ^^^^^ - 10 │ }); - 11 │ + 12 │ }); + 13 │ i This is the source of the key value. - 6 │ foo - 7 │ }); - > 8 │ things.filter((thing, index) => { + 8 │ foo + 9 │ }); + > 10 │ things.filter((thing, index) => { │ ^^^^^ - 9 │ otherThings.push(foo); - 10 │ }); + 11 │ otherThings.push(foo); + 12 │ }); i The order of the items may change, and this also affects performances and component state. @@ -151,24 +154,24 @@ noArrayIndexKey.jsx:9:34 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:13:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:15:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 12 │ something.forEach((Element, index) => { - > 13 │ + 14 │ something.forEach((Element, index) => { + > 15 │ │ ^^^^^ - 14 │ }); - 15 │ something.forEach((element, index, array) => { + 16 │ }); + 17 │ something.forEach((element, index, array) => { i This is the source of the key value. - 10 │ }); - 11 │ - > 12 │ something.forEach((Element, index) => { + 12 │ }); + 13 │ + > 14 │ something.forEach((Element, index) => { │ ^^^^^ - 13 │ - 14 │ }); + 15 │ + 16 │ }); i The order of the items may change, and this also affects performances and component state. @@ -178,25 +181,25 @@ noArrayIndexKey.jsx:13:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:16:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:18:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 14 │ }); - 15 │ something.forEach((element, index, array) => { - > 16 │ + 16 │ }); + 17 │ something.forEach((element, index, array) => { + > 18 │ │ ^^^^^ - 17 │ }); - 18 │ things.filter((thing, index) => { + 19 │ }); + 20 │ things.filter((thing, index) => { i This is the source of the key value. - 13 │ - 14 │ }); - > 15 │ something.forEach((element, index, array) => { + 15 │ + 16 │ }); + > 17 │ something.forEach((element, index, array) => { │ ^^^^^ - 16 │ - 17 │ }); + 18 │ + 19 │ }); i The order of the items may change, and this also affects performances and component state. @@ -206,25 +209,25 @@ noArrayIndexKey.jsx:16:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:19:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:21:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 17 │ }); - 18 │ things.filter((thing, index) => { - > 19 │ otherThings.push(); + 19 │ }); + 20 │ things.filter((thing, index) => { + > 21 │ otherThings.push(); │ ^^^^^ - 20 │ }); - 21 │ things.reduce((collection, thing, index) => ( + 22 │ }); + 23 │ things.reduce((collection, thing, index) => ( i This is the source of the key value. - 16 │ - 17 │ }); - > 18 │ things.filter((thing, index) => { + 18 │ + 19 │ }); + > 20 │ things.filter((thing, index) => { │ ^^^^^ - 19 │ otherThings.push(); - 20 │ }); + 21 │ otherThings.push(); + 22 │ }); i The order of the items may change, and this also affects performances and component state. @@ -234,25 +237,25 @@ noArrayIndexKey.jsx:19:34 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:22:35 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:24:35 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 20 │ }); - 21 │ things.reduce((collection, thing, index) => ( - > 22 │ collection.concat() + 22 │ }); + 23 │ things.reduce((collection, thing, index) => ( + > 24 │ collection.concat() │ ^^^^^ - 23 │ ), []); - 24 │ + 25 │ ), []); + 26 │ i This is the source of the key value. - 19 │ otherThings.push(); - 20 │ }); - > 21 │ things.reduce((collection, thing, index) => ( + 21 │ otherThings.push(); + 22 │ }); + > 23 │ things.reduce((collection, thing, index) => ( │ ^^^^^ - 22 │ collection.concat() - 23 │ ), []); + 24 │ collection.concat() + 25 │ ), []); i The order of the items may change, and this also affects performances and component state. @@ -262,24 +265,24 @@ noArrayIndexKey.jsx:22:35 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:26:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:28:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 25 │ React.Children.map(this.props.children, (child, index) => ( - > 26 │ React.cloneElement(child, { key: index }) + 27 │ React.Children.map(this.props.children, (child, index) => ( + > 28 │ React.cloneElement(child, { key: index }) │ ^^^^^ - 27 │ )) - 28 │ + 29 │ )) + 30 │ i This is the source of the key value. - 23 │ ), []); - 24 │ - > 25 │ React.Children.map(this.props.children, (child, index) => ( + 25 │ ), []); + 26 │ + > 27 │ React.Children.map(this.props.children, (child, index) => ( │ ^^^^^ - 26 │ React.cloneElement(child, { key: index }) - 27 │ )) + 28 │ React.cloneElement(child, { key: index }) + 29 │ )) i The order of the items may change, and this also affects performances and component state. @@ -289,24 +292,24 @@ noArrayIndexKey.jsx:26:38 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:30:45 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:32:45 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 29 │ React.Children.forEach(this.props.children, function (child, index) { - > 30 │ return React.cloneElement(child, { key: index }) + 31 │ React.Children.forEach(this.props.children, function (child, index) { + > 32 │ return React.cloneElement(child, { key: index }) │ ^^^^^ - 31 │ }) - 32 │ + 33 │ }) + 34 │ i This is the source of the key value. - 27 │ )) - 28 │ - > 29 │ React.Children.forEach(this.props.children, function (child, index) { + 29 │ )) + 30 │ + > 31 │ React.Children.forEach(this.props.children, function (child, index) { │ ^^^^^ - 30 │ return React.cloneElement(child, { key: index }) - 31 │ }) + 32 │ return React.cloneElement(child, { key: index }) + 33 │ }) i The order of the items may change, and this also affects performances and component state. @@ -316,22 +319,22 @@ noArrayIndexKey.jsx:30:45 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:35:32 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:37:32 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 34 │ Children.map(this.props.children, (child, index) => ( - > 35 │ cloneElement(child, { key: index }) + 36 │ Children.map(this.props.children, (child, index) => ( + > 37 │ cloneElement(child, { key: index }) │ ^^^^^ - 36 │ )) - 37 │ + 38 │ )) + 39 │ i This is the source of the key value. - > 34 │ Children.map(this.props.children, (child, index) => ( + > 36 │ Children.map(this.props.children, (child, index) => ( │ ^^^^^ - 35 │ cloneElement(child, { key: index }) - 36 │ )) + 37 │ cloneElement(child, { key: index }) + 38 │ )) i The order of the items may change, and this also affects performances and component state. @@ -341,24 +344,24 @@ noArrayIndexKey.jsx:35:32 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:39:39 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:41:39 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 38 │ Children.forEach(this.props.children, function (child, index) { - > 39 │ return cloneElement(child, { key: index }) + 40 │ Children.forEach(this.props.children, function (child, index) { + > 41 │ return cloneElement(child, { key: index }) │ ^^^^^ - 40 │ }) - 41 │ + 42 │ }) + 43 │ i This is the source of the key value. - 36 │ )) - 37 │ - > 38 │ Children.forEach(this.props.children, function (child, index) { + 38 │ )) + 39 │ + > 40 │ Children.forEach(this.props.children, function (child, index) { │ ^^^^^ - 39 │ return cloneElement(child, { key: index }) - 40 │ }) + 41 │ return cloneElement(child, { key: index }) + 42 │ }) i The order of the items may change, and this also affects performances and component state. @@ -368,24 +371,24 @@ noArrayIndexKey.jsx:39:39 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:43:44 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:45:44 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 42 │ Children.forEach(this.props.children, function (child, index) { - > 43 │ const foo = cloneElement(child, { key: index }) + 44 │ Children.forEach(this.props.children, function (child, index) { + > 45 │ const foo = cloneElement(child, { key: index }) │ ^^^^^ - 44 │ return foo; - 45 │ }) + 46 │ return foo; + 47 │ }) i This is the source of the key value. - 40 │ }) - 41 │ - > 42 │ Children.forEach(this.props.children, function (child, index) { + 42 │ }) + 43 │ + > 44 │ Children.forEach(this.props.children, function (child, index) { │ ^^^^^ - 43 │ const foo = cloneElement(child, { key: index }) - 44 │ return foo; + 45 │ const foo = cloneElement(child, { key: index }) + 46 │ return foo; i The order of the items may change, and this also affects performances and component state. @@ -395,22 +398,22 @@ noArrayIndexKey.jsx:43:44 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:49:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:51:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 48 │ things.map((thing, index) => ( - > 49 │ React.cloneElement(thing, { key: index }) + 50 │ things.map((thing, index) => ( + > 51 │ React.cloneElement(thing, { key: index }) │ ^^^^^ - 50 │ )); - 51 │ + 52 │ )); + 53 │ i This is the source of the key value. - > 48 │ things.map((thing, index) => ( + > 50 │ things.map((thing, index) => ( │ ^^^^^ - 49 │ React.cloneElement(thing, { key: index }) - 50 │ )); + 51 │ React.cloneElement(thing, { key: index }) + 52 │ )); i The order of the items may change, and this also affects performances and component state. diff --git a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx index 02c39406f0e..2a0b829b2bc 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx @@ -1,3 +1,6 @@ +import {createElement} from "react"; +import React from "react"; + <> diff --git a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap index f35e7d29f7e..7c5df246fe4 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap @@ -4,6 +4,9 @@ expression: noChildrenPropInvalid.jsx --- # Input ```js +import {createElement} from "react"; +import React from "react"; + <> @@ -20,15 +23,15 @@ React.createElement('div', { # Diagnostics ``` -noChildrenPropInvalid.jsx:2:16 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildrenPropInvalid.jsx:5:16 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing children using a prop - 1 │ <> - > 2 │ + 4 │ <> + > 5 │ │ ^^^^^^^^ - 3 │ - 4 │ + 6 │ + 7 │ i The canonical way to pass children in React is to use JSX elements @@ -36,15 +39,15 @@ noChildrenPropInvalid.jsx:2:16 lint/correctness/noChildrenProp ━━━━━ ``` ``` -noChildrenPropInvalid.jsx:6:5 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildrenPropInvalid.jsx:9:5 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing children using a prop - 5 │ createElement('div', { - > 6 │ children: 'foo' - │ ^^^^^^^^ - 7 │ }) - 8 │ + 8 │ createElement('div', { + > 9 │ children: 'foo' + │ ^^^^^^^^ + 10 │ }) + 11 │ i The canonical way to pass children in React is to use additional arguments to React.createElement @@ -52,15 +55,15 @@ noChildrenPropInvalid.jsx:6:5 lint/correctness/noChildrenProp ━━━━━━ ``` ``` -noChildrenPropInvalid.jsx:10:5 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildrenPropInvalid.jsx:13:5 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing children using a prop - 9 │ React.createElement('div', { - > 10 │ children: 'foo' + 12 │ React.createElement('div', { + > 13 │ children: 'foo' │ ^^^^^^^^ - 11 │ }) - 12 │ + 14 │ }) + 15 │ i The canonical way to pass children in React is to use additional arguments to React.createElement diff --git a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx index b5ea51268e0..bf0efd8dbd5 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx @@ -1,3 +1,6 @@ +import { cloneElement } from "react"; +import React from "react"; + <> @@ -7,3 +10,6 @@ createElement('div', {}, 'foo') + +cloneElement('div', { children:
}); +React.cloneElement('div', { children:
}); diff --git a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx.snap index 4523817da33..d193e41a1ee 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropValid.jsx.snap @@ -4,6 +4,9 @@ expression: noChildrenPropValid.jsx --- # Input ```js +import { cloneElement } from "react"; +import React from "react"; + <> @@ -14,6 +17,9 @@ expression: noChildrenPropValid.jsx createElement('div', {}, 'foo') +cloneElement('div', { children:
}); +React.cloneElement('div', { children:
}); + ``` diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx index 2be0a35fa56..845a15dd0fe 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx @@ -1,7 +1,8 @@ +import React, { Fragment } from "react"; // invalid <> <> - \ No newline at end of file + diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap index 0c8caa8df96..64ac87635e4 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap @@ -4,6 +4,7 @@ expression: noChildren.jsx --- # Input ```js +import React, { Fragment } from "react"; // invalid <> @@ -11,60 +12,62 @@ expression: noChildren.jsx + ``` # Diagnostics ``` -noChildren.jsx:4:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildren.jsx:5:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 3 │ <> - > 4 │ <> + 4 │ <> + > 5 │ <> │ ^^^^^ - 5 │ - 6 │ + 6 │ + 7 │ i Suggested fix: Remove the Fragment - 4 │ ····<> + 5 │ ····<> │ ----- ``` ``` -noChildren.jsx:5:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildren.jsx:6:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 3 │ <> - 4 │ <> - > 5 │ + 4 │ <> + 5 │ <> + > 6 │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 6 │ - 7 │ + 7 │ + 8 │ i Suggested fix: Remove the Fragment - 5 │ ···· + 6 │ ···· │ --------------------------------- ``` ``` -noChildren.jsx:6:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildren.jsx:7:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 4 │ <> - 5 │ - > 6 │ + 5 │ <> + 6 │ + > 7 │ │ ^^^^^^^^^^^^^^^^^^^^^ - 7 │ + 8 │ + 9 │ i Suggested fix: Remove the Fragment - 6 │ ···· + 7 │ ···· │ --------------------- ``` diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx index 6f662e94435..e352600cb88 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx @@ -1,3 +1,5 @@ +import React, { Fragment, StrictMode } from "react"; + <> <>foo foo diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap index 054ae2b1867..7ec989c0277 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap @@ -4,6 +4,8 @@ expression: withChildren.jsx --- # Input ```js +import React, { Fragment, StrictMode } from "react"; + <> <>foo foo @@ -16,57 +18,57 @@ expression: withChildren.jsx # Diagnostics ``` -withChildren.jsx:2:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +withChildren.jsx:4:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 1 │ <> - > 2 │ <>foo + 3 │ <> + > 4 │ <>foo │ ^^^^^^^^ - 3 │ foo - 4 │ foo + 5 │ foo + 6 │ foo i Suggested fix: Remove the Fragment - 2 │ ····<>foo + 4 │ ····<>foo │ -- --- ``` ``` -withChildren.jsx:3:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +withChildren.jsx:5:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 1 │ <> - 2 │ <>foo - > 3 │ foo + 3 │ <> + 4 │ <>foo + > 5 │ foo │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 4 │ foo - 5 │ {/* valid */} + 6 │ foo + 7 │ {/* valid */} i Suggested fix: Remove the Fragment - 3 │ ····foo + 5 │ ····foo │ ---------------- ----------------- ``` ``` -withChildren.jsx:4:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +withChildren.jsx:6:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 2 │ <>foo - 3 │ foo - > 4 │ foo + 4 │ <>foo + 5 │ foo + > 6 │ foo │ ^^^^^^^^^^^^^^^^^^^^^^^^ - 5 │ {/* valid */} - 6 │ + 7 │ {/* valid */} + 8 │ i Suggested fix: Remove the Fragment - 4 │ ····foo + 6 │ ····foo │ ---------- ----------- ``` diff --git a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js index 45fd0486666..bec5c1d08ac 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js +++ b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js @@ -1,4 +1,4 @@ - +import React from "react"; React.createElement('img', { someProp: "bar" @@ -6,4 +6,4 @@ React.createElement('img', { React.createElement('img', { dangerouslySetInnerHTML: "text" -}) \ No newline at end of file +}) diff --git a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap index 51e6774c7a8..b3db1f65883 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap @@ -1,11 +1,10 @@ --- source: crates/rome_js_analyze/tests/spec_tests.rs -assertion_line: 99 expression: createElement.js --- # Input ```js - +import React from "react"; React.createElement('img', { someProp: "bar" @@ -14,6 +13,7 @@ React.createElement('img', { React.createElement('img', { dangerouslySetInnerHTML: "text" }) + ``` # Diagnostics @@ -22,6 +22,8 @@ createElement.js:3:1 lint/correctness/noVoidElementsWithChildren FIXABLE ━ ! img is a void element tag and must not have children. + 1 │ import React from "react"; + 2 │ > 3 │ React.createElement('img', { │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > 4 │ someProp: "bar" @@ -42,20 +44,22 @@ createElement.js:7:1 lint/correctness/noVoidElementsWithChildren FIXABLE ━ ! img is a void element tag and must not have the dangerouslySetInnerHTML prop. - 5 │ }, 'child') - 6 │ - > 7 │ React.createElement('img', { - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - > 8 │ dangerouslySetInnerHTML: "text" - > 9 │ }) - │ ^^ + 5 │ }, 'child') + 6 │ + > 7 │ React.createElement('img', { + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + > 8 │ dangerouslySetInnerHTML: "text" + > 9 │ }) + │ ^^ + 10 │ i Suggested fix: Remove the dangerouslySetInnerHTML prop. - 6 6 │ - 7 7 │ React.createElement('img', { - 8 │ - ····dangerouslySetInnerHTML:·"text" - 9 8 │ }) + 6 6 │ + 7 7 │ React.createElement('img', { + 8 │ - ····dangerouslySetInnerHTML:·"text" + 9 8 │ }) + 10 9 │ ``` diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js index bfd30c586cb..86af9c2d220 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js @@ -1,3 +1,5 @@ +import React from "react"; + React.createElement('div', { dangerouslySetInnerHTML: { __html: 'child' } -}); \ No newline at end of file +}); diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap index f697f49b28e..74f486dfde4 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap @@ -4,21 +4,25 @@ expression: reactCreateElement.js --- # Input ```js +import React from "react"; + React.createElement('div', { dangerouslySetInnerHTML: { __html: 'child' } }); + ``` # Diagnostics ``` -reactCreateElement.js:2:5 lint/security/noDangerouslySetInnerHtml ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElement.js:4:5 lint/security/noDangerouslySetInnerHtml ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing content using the dangerouslySetInnerHTML prop. - 1 │ React.createElement('div', { - > 2 │ dangerouslySetInnerHTML: { __html: 'child' } + 3 │ React.createElement('div', { + > 4 │ dangerouslySetInnerHTML: { __html: 'child' } │ ^^^^^^^^^^^^^^^^^^^^^^^ - 3 │ }); + 5 │ }); + 6 │ ! Setting content using code can expose users to cross-site scripting (XSS) attacks diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js index 5cbae195554..bf7bdb69b30 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js @@ -1,3 +1,5 @@ +import React from "react"; + React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') -React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) \ No newline at end of file +React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap index aa21f4378da..0586ad56fa5 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap @@ -4,28 +4,35 @@ expression: createElement.js --- # Input ```js +import React from "react"; + React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + ``` # Diagnostics ``` -createElement.js:1:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ +createElement.js:3:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing both children and the dangerouslySetInnerHTML prop. - > 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + 1 │ import React from "react"; + 2 │ + > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) i This is the source of the children prop - > 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + 1 │ import React from "react"; + 2 │ + > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) │ ^^^^^^^^^^^^ - 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) i Setting HTML content will inadvertently override any passed children in React @@ -33,21 +40,23 @@ createElement.js:1:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━ ``` ``` -createElement.js:2:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ +createElement.js:4:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing both children and the dangerouslySetInnerHTML prop. - 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - > 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + > 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 6 │ i This is the source of the children prop - 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - > 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + > 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') │ ^^^^^^^^^^ - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 6 │ i Setting HTML content will inadvertently override any passed children in React @@ -55,21 +64,23 @@ createElement.js:2:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━ ``` ``` -createElement.js:3:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ +createElement.js:5:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing both children and the dangerouslySetInnerHTML prop. - 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + > 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 │ i This is the source of the children prop - 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + > 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) │ ^^^^^^^^^^^^^^^^^^^^ + 6 │ i Setting HTML content will inadvertently override any passed children in React From 9927363fd48ce4cb664ce86d6c20eacdff5c3998 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 9 Nov 2022 14:38:26 +0100 Subject: [PATCH 2/4] Support `React` global --- crates/rome_js_analyze/src/lib.rs | 5 +- crates/rome_js_analyze/src/react.rs | 51 ++-- .../reactCreateElementInvalid.js | 2 - .../reactCreateElementInvalid.js.snap | 44 ++- .../specs/a11y/useButtonType/inObject.js | 2 - .../specs/a11y/useButtonType/inObject.js.snap | 52 ++-- .../specs/correctness/noArrayIndexKey.jsx | 2 - .../correctness/noArrayIndexKey.jsx.snap | 289 +++++++----------- .../noChildrenProp/noChildrenPropInvalid.jsx | 8 +- .../noChildrenPropInvalid.jsx.snap | 40 +-- .../noUselessFragments/noChildren.jsx | 1 - .../noUselessFragments/noChildren.jsx.snap | 41 ++- .../noUselessFragments/withChildren.jsx | 2 - .../noUselessFragments/withChildren.jsx.snap | 42 ++- .../createElement.js | 2 +- .../createElement.js.snap | 4 +- .../reactCreateElement.js | 2 - .../reactCreateElement.js.snap | 12 +- .../createElement.js | 2 - .../createElement.js.snap | 56 ++-- 20 files changed, 281 insertions(+), 378 deletions(-) diff --git a/crates/rome_js_analyze/src/lib.rs b/crates/rome_js_analyze/src/lib.rs index a4a99671a2f..3455220b3c7 100644 --- a/crates/rome_js_analyze/src/lib.rs +++ b/crates/rome_js_analyze/src/lib.rs @@ -141,8 +141,9 @@ mod tests { String::from_utf8(buffer).unwrap() } - const SOURCE: &str = r#" - "#; + const SOURCE: &str = r#"React.createElement("div", { tabIndex: '1' }) +React.createElement("div", { tabIndex: 1 }) +React.createElement("div", { tabIndex: +1 })"#; let parsed = parse(SOURCE, FileId::zero(), SourceType::jsx()); diff --git a/crates/rome_js_analyze/src/react.rs b/crates/rome_js_analyze/src/react.rs index a688b2b2e58..dbede90cd8a 100644 --- a/crates/rome_js_analyze/src/react.rs +++ b/crates/rome_js_analyze/src/react.rs @@ -260,20 +260,24 @@ pub(crate) fn is_react_call_api( let object = node.object().ok()?; let identifier = object.as_js_identifier_expression()?.name().ok()?; - return model.declaration(&identifier).and_then(|binding| { - let binding_identifier = JsIdentifierBinding::cast_ref(binding.syntax())?; - - if let Some(js_import) = binding_identifier - .syntax() - .ancestors() - .find_map(|ancestor| JsImport::cast_ref(&ancestor)) - { - js_import.source_is("react").ok() - } else { - Some(false) + match model.declaration(&identifier) { + Some(binding) => { + let binding_identifier = JsIdentifierBinding::cast_ref(binding.syntax())?; + + if let Some(js_import) = binding_identifier + .syntax() + .ancestors() + .find_map(|ancestor| JsImport::cast_ref(&ancestor)) + { + js_import.source_is("react").ok()? + } else { + false + } } - }); + None => identifier.has_name("React"), + } } + JsAnyExpression::JsIdentifierExpression(identifier) => { let name = identifier.name().ok()?; @@ -304,17 +308,20 @@ pub(crate) fn jsx_member_name_is_react_fragment( return Some(false); } - model.declaration(object).and_then(|declaration| { - if let Some(js_import) = declaration - .syntax() - .ancestors() - .find_map(|ancestor| JsImport::cast_ref(&ancestor)) - { - js_import.source_is("react").ok() - } else { - Some(false) + match model.declaration(object) { + Some(declaration) => { + if let Some(js_import) = declaration + .syntax() + .ancestors() + .find_map(|ancestor| JsImport::cast_ref(&ancestor)) + { + js_import.source_is("react").ok() + } else { + Some(false) + } } - }) + None => Some(object.value_token().ok()?.text_trimmed() == "React"), + } } /// Checks if the node `JsxReferenceIdentifier` is a react fragment. diff --git a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js index 214915e8580..46f5363f95c 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js +++ b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js @@ -1,5 +1,3 @@ -import React from "react"; - React.createElement("div", { tabIndex: '1' }) React.createElement("div", { tabIndex: 1 }) React.createElement("div", { tabIndex: +1 }) diff --git a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap index ef28022dc82..3550c9842a0 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/a11y/noPositiveTabindex/reactCreateElementInvalid.js.snap @@ -4,8 +4,6 @@ expression: reactCreateElementInvalid.js --- # Input ```js -import React from "react"; - React.createElement("div", { tabIndex: '1' }) React.createElement("div", { tabIndex: 1 }) React.createElement("div", { tabIndex: +1 }) @@ -15,16 +13,14 @@ React.createElement("div", { tabIndex: +01 }) # Diagnostics ``` -reactCreateElementInvalid.js:3:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:1:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - 1 │ import React from "react"; - 2 │ - > 3 │ React.createElement("div", { tabIndex: '1' }) + > 1 │ React.createElement("div", { tabIndex: '1' }) │ ^^^ - 4 │ React.createElement("div", { tabIndex: 1 }) - 5 │ React.createElement("div", { tabIndex: +1 }) + 2 │ React.createElement("div", { tabIndex: 1 }) + 3 │ React.createElement("div", { tabIndex: +1 }) i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. @@ -32,15 +28,15 @@ reactCreateElementInvalid.js:3:40 lint/a11y/noPositiveTabindex ━━━━━ ``` ``` -reactCreateElementInvalid.js:4:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:2:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - 3 │ React.createElement("div", { tabIndex: '1' }) - > 4 │ React.createElement("div", { tabIndex: 1 }) + 1 │ React.createElement("div", { tabIndex: '1' }) + > 2 │ React.createElement("div", { tabIndex: 1 }) │ ^ - 5 │ React.createElement("div", { tabIndex: +1 }) - 6 │ React.createElement("div", { tabIndex: +01 }) + 3 │ React.createElement("div", { tabIndex: +1 }) + 4 │ React.createElement("div", { tabIndex: +01 }) i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. @@ -48,16 +44,16 @@ reactCreateElementInvalid.js:4:40 lint/a11y/noPositiveTabindex ━━━━━ ``` ``` -reactCreateElementInvalid.js:5:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:3:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - 3 │ React.createElement("div", { tabIndex: '1' }) - 4 │ React.createElement("div", { tabIndex: 1 }) - > 5 │ React.createElement("div", { tabIndex: +1 }) + 1 │ React.createElement("div", { tabIndex: '1' }) + 2 │ React.createElement("div", { tabIndex: 1 }) + > 3 │ React.createElement("div", { tabIndex: +1 }) │ ^^ - 6 │ React.createElement("div", { tabIndex: +01 }) - 7 │ + 4 │ React.createElement("div", { tabIndex: +01 }) + 5 │ i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. @@ -65,15 +61,15 @@ reactCreateElementInvalid.js:5:40 lint/a11y/noPositiveTabindex ━━━━━ ``` ``` -reactCreateElementInvalid.js:6:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElementInvalid.js:4:40 lint/a11y/noPositiveTabindex ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid positive values for the tabIndex prop. - 4 │ React.createElement("div", { tabIndex: 1 }) - 5 │ React.createElement("div", { tabIndex: +1 }) - > 6 │ React.createElement("div", { tabIndex: +01 }) + 2 │ React.createElement("div", { tabIndex: 1 }) + 3 │ React.createElement("div", { tabIndex: +1 }) + > 4 │ React.createElement("div", { tabIndex: +01 }) │ ^^^ - 7 │ + 5 │ i Elements with a positive tabIndex override natural page content order. This causes elements without a positive tab index to come last when navigating using a keyboard. diff --git a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js index 90bf0e5cbe4..05afca94d10 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js +++ b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js @@ -1,5 +1,3 @@ -import React from "react"; - // invalid React.createElement('button'); React.createElement('button', { diff --git a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap index bded5ef61d5..527aebe073a 100644 --- a/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap +++ b/crates/rome_js_analyze/tests/specs/a11y/useButtonType/inObject.js.snap @@ -4,8 +4,6 @@ expression: inObject.js --- # Input ```js -import React from "react"; - // invalid React.createElement('button'); React.createElement('button', { @@ -25,15 +23,15 @@ React.createElement('button', { # Diagnostics ``` -inObject.js:4:21 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:2:21 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide an explicit type prop for the button element. - 3 │ // invalid - > 4 │ React.createElement('button'); + 1 │ // invalid + > 2 │ React.createElement('button'); │ ^^^^^^^^ - 5 │ React.createElement('button', { - 6 │ "type": "bar" + 3 │ React.createElement('button', { + 4 │ "type": "bar" i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. @@ -43,16 +41,16 @@ inObject.js:4:21 lint/a11y/useButtonType ━━━━━━━━━━━━━ ``` ``` -inObject.js:6:13 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:4:13 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide a valid type prop for the button element. - 4 │ React.createElement('button'); - 5 │ React.createElement('button', { - > 6 │ "type": "bar" + 2 │ React.createElement('button'); + 3 │ React.createElement('button', { + > 4 │ "type": "bar" │ ^^^^^ - 7 │ }); - 8 │ React.createElement('button', { + 5 │ }); + 6 │ React.createElement('button', { i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. @@ -62,19 +60,19 @@ inObject.js:6:13 lint/a11y/useButtonType ━━━━━━━━━━━━━ ``` ``` -inObject.js:8:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:6:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide a valid type prop for the button element. - 6 │ "type": "bar" - 7 │ }); - > 8 │ React.createElement('button', { + 4 │ "type": "bar" + 5 │ }); + > 6 │ React.createElement('button', { │ ^ - > 9 │ "style": "background: red" - > 10 │ }); + > 7 │ "style": "background: red" + > 8 │ }); │ ^ - 11 │ React.createElement('button', {}); - 12 │ + 9 │ React.createElement('button', {}); + 10 │ i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. @@ -84,16 +82,16 @@ inObject.js:8:31 lint/a11y/useButtonType ━━━━━━━━━━━━━ ``` ``` -inObject.js:11:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +inObject.js:9:31 lint/a11y/useButtonType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Provide a valid type prop for the button element. - 9 │ "style": "background: red" - 10 │ }); - > 11 │ React.createElement('button', {}); + 7 │ "style": "background: red" + 8 │ }); + > 9 │ React.createElement('button', {}); │ ^^ - 12 │ - 13 │ // valid + 10 │ + 11 │ // valid i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application. diff --git a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx index 8b9ab1ce045..81cc1c17ad6 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx @@ -1,5 +1,3 @@ -import React, {Children, cloneElement} from "react"; - // invalid something.forEach((Element, index) => { foo diff --git a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap index 977244da801..704239b044f 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap @@ -4,8 +4,6 @@ expression: noArrayIndexKey.jsx --- # Input ```js -import React, {Children, cloneElement} from "react"; - // invalid something.forEach((Element, index) => { foo @@ -71,24 +69,24 @@ something.forEach((element, index) => { # Diagnostics ``` -noArrayIndexKey.jsx:5:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:3:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 3 │ // invalid - 4 │ something.forEach((Element, index) => { - > 5 │ foo + 1 │ // invalid + 2 │ something.forEach((Element, index) => { + > 3 │ foo │ ^^^^^ - 6 │ }); - 7 │ something.forEach((element, index, array) => { + 4 │ }); + 5 │ something.forEach((element, index, array) => { i This is the source of the key value. - 3 │ // invalid - > 4 │ something.forEach((Element, index) => { + 1 │ // invalid + > 2 │ something.forEach((Element, index) => { │ ^^^^^ - 5 │ foo - 6 │ }); + 3 │ foo + 4 │ }); i The order of the items may change, and this also affects performances and component state. @@ -98,25 +96,25 @@ noArrayIndexKey.jsx:5:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:8:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:6:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 6 │ }); - 7 │ something.forEach((element, index, array) => { - > 8 │ foo - │ ^^^^^ - 9 │ }); - 10 │ things.filter((thing, index) => { + 4 │ }); + 5 │ something.forEach((element, index, array) => { + > 6 │ foo + │ ^^^^^ + 7 │ }); + 8 │ things.filter((thing, index) => { i This is the source of the key value. - 5 │ foo - 6 │ }); - > 7 │ something.forEach((element, index, array) => { + 3 │ foo + 4 │ }); + > 5 │ something.forEach((element, index, array) => { │ ^^^^^ - 8 │ foo - 9 │ }); + 6 │ foo + 7 │ }); i The order of the items may change, and this also affects performances and component state. @@ -126,25 +124,25 @@ noArrayIndexKey.jsx:8:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:11:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:9:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 9 │ }); - 10 │ things.filter((thing, index) => { - > 11 │ otherThings.push(foo); + 7 │ }); + 8 │ things.filter((thing, index) => { + > 9 │ otherThings.push(foo); │ ^^^^^ - 12 │ }); - 13 │ + 10 │ }); + 11 │ i This is the source of the key value. - 8 │ foo - 9 │ }); - > 10 │ things.filter((thing, index) => { + 6 │ foo + 7 │ }); + > 8 │ things.filter((thing, index) => { │ ^^^^^ - 11 │ otherThings.push(foo); - 12 │ }); + 9 │ otherThings.push(foo); + 10 │ }); i The order of the items may change, and this also affects performances and component state. @@ -154,24 +152,24 @@ noArrayIndexKey.jsx:11:34 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:15:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:13:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 14 │ something.forEach((Element, index) => { - > 15 │ + 12 │ something.forEach((Element, index) => { + > 13 │ │ ^^^^^ - 16 │ }); - 17 │ something.forEach((element, index, array) => { + 14 │ }); + 15 │ something.forEach((element, index, array) => { i This is the source of the key value. - 12 │ }); - 13 │ - > 14 │ something.forEach((Element, index) => { + 10 │ }); + 11 │ + > 12 │ something.forEach((Element, index) => { │ ^^^^^ - 15 │ - 16 │ }); + 13 │ + 14 │ }); i The order of the items may change, and this also affects performances and component state. @@ -181,25 +179,25 @@ noArrayIndexKey.jsx:15:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:18:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:16:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 16 │ }); - 17 │ something.forEach((element, index, array) => { - > 18 │ + 14 │ }); + 15 │ something.forEach((element, index, array) => { + > 16 │ │ ^^^^^ - 19 │ }); - 20 │ things.filter((thing, index) => { + 17 │ }); + 18 │ things.filter((thing, index) => { i This is the source of the key value. - 15 │ - 16 │ }); - > 17 │ something.forEach((element, index, array) => { + 13 │ + 14 │ }); + > 15 │ something.forEach((element, index, array) => { │ ^^^^^ - 18 │ - 19 │ }); + 16 │ + 17 │ }); i The order of the items may change, and this also affects performances and component state. @@ -209,25 +207,25 @@ noArrayIndexKey.jsx:18:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:21:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:19:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 19 │ }); - 20 │ things.filter((thing, index) => { - > 21 │ otherThings.push(); + 17 │ }); + 18 │ things.filter((thing, index) => { + > 19 │ otherThings.push(); │ ^^^^^ - 22 │ }); - 23 │ things.reduce((collection, thing, index) => ( + 20 │ }); + 21 │ things.reduce((collection, thing, index) => ( i This is the source of the key value. - 18 │ - 19 │ }); - > 20 │ things.filter((thing, index) => { + 16 │ + 17 │ }); + > 18 │ things.filter((thing, index) => { │ ^^^^^ - 21 │ otherThings.push(); - 22 │ }); + 19 │ otherThings.push(); + 20 │ }); i The order of the items may change, and this also affects performances and component state. @@ -237,25 +235,25 @@ noArrayIndexKey.jsx:21:34 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:24:35 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:22:35 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 22 │ }); - 23 │ things.reduce((collection, thing, index) => ( - > 24 │ collection.concat() + 20 │ }); + 21 │ things.reduce((collection, thing, index) => ( + > 22 │ collection.concat() │ ^^^^^ - 25 │ ), []); - 26 │ + 23 │ ), []); + 24 │ i This is the source of the key value. - 21 │ otherThings.push(); - 22 │ }); - > 23 │ things.reduce((collection, thing, index) => ( + 19 │ otherThings.push(); + 20 │ }); + > 21 │ things.reduce((collection, thing, index) => ( │ ^^^^^ - 24 │ collection.concat() - 25 │ ), []); + 22 │ collection.concat() + 23 │ ), []); i The order of the items may change, and this also affects performances and component state. @@ -265,24 +263,24 @@ noArrayIndexKey.jsx:24:35 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:28:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:26:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 27 │ React.Children.map(this.props.children, (child, index) => ( - > 28 │ React.cloneElement(child, { key: index }) + 25 │ React.Children.map(this.props.children, (child, index) => ( + > 26 │ React.cloneElement(child, { key: index }) │ ^^^^^ - 29 │ )) - 30 │ + 27 │ )) + 28 │ i This is the source of the key value. - 25 │ ), []); - 26 │ - > 27 │ React.Children.map(this.props.children, (child, index) => ( + 23 │ ), []); + 24 │ + > 25 │ React.Children.map(this.props.children, (child, index) => ( │ ^^^^^ - 28 │ React.cloneElement(child, { key: index }) - 29 │ )) + 26 │ React.cloneElement(child, { key: index }) + 27 │ )) i The order of the items may change, and this also affects performances and component state. @@ -292,103 +290,24 @@ noArrayIndexKey.jsx:28:38 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:32:45 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:30:45 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 31 │ React.Children.forEach(this.props.children, function (child, index) { - > 32 │ return React.cloneElement(child, { key: index }) + 29 │ React.Children.forEach(this.props.children, function (child, index) { + > 30 │ return React.cloneElement(child, { key: index }) │ ^^^^^ - 33 │ }) - 34 │ + 31 │ }) + 32 │ i This is the source of the key value. - 29 │ )) - 30 │ - > 31 │ React.Children.forEach(this.props.children, function (child, index) { + 27 │ )) + 28 │ + > 29 │ React.Children.forEach(this.props.children, function (child, index) { │ ^^^^^ - 32 │ return React.cloneElement(child, { key: index }) - 33 │ }) - - i The order of the items may change, and this also affects performances and component state. - - i Check the React documentation. - - -``` - -``` -noArrayIndexKey.jsx:37:32 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Avoid using the index of an array as key property in an element. - - 36 │ Children.map(this.props.children, (child, index) => ( - > 37 │ cloneElement(child, { key: index }) - │ ^^^^^ - 38 │ )) - 39 │ - - i This is the source of the key value. - - > 36 │ Children.map(this.props.children, (child, index) => ( - │ ^^^^^ - 37 │ cloneElement(child, { key: index }) - 38 │ )) - - i The order of the items may change, and this also affects performances and component state. - - i Check the React documentation. - - -``` - -``` -noArrayIndexKey.jsx:41:39 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Avoid using the index of an array as key property in an element. - - 40 │ Children.forEach(this.props.children, function (child, index) { - > 41 │ return cloneElement(child, { key: index }) - │ ^^^^^ - 42 │ }) - 43 │ - - i This is the source of the key value. - - 38 │ )) - 39 │ - > 40 │ Children.forEach(this.props.children, function (child, index) { - │ ^^^^^ - 41 │ return cloneElement(child, { key: index }) - 42 │ }) - - i The order of the items may change, and this also affects performances and component state. - - i Check the React documentation. - - -``` - -``` -noArrayIndexKey.jsx:45:44 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Avoid using the index of an array as key property in an element. - - 44 │ Children.forEach(this.props.children, function (child, index) { - > 45 │ const foo = cloneElement(child, { key: index }) - │ ^^^^^ - 46 │ return foo; - 47 │ }) - - i This is the source of the key value. - - 42 │ }) - 43 │ - > 44 │ Children.forEach(this.props.children, function (child, index) { - │ ^^^^^ - 45 │ const foo = cloneElement(child, { key: index }) - 46 │ return foo; + 30 │ return React.cloneElement(child, { key: index }) + 31 │ }) i The order of the items may change, and this also affects performances and component state. @@ -398,22 +317,22 @@ noArrayIndexKey.jsx:45:44 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:51:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:49:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 50 │ things.map((thing, index) => ( - > 51 │ React.cloneElement(thing, { key: index }) + 48 │ things.map((thing, index) => ( + > 49 │ React.cloneElement(thing, { key: index }) │ ^^^^^ - 52 │ )); - 53 │ + 50 │ )); + 51 │ i This is the source of the key value. - > 50 │ things.map((thing, index) => ( + > 48 │ things.map((thing, index) => ( │ ^^^^^ - 51 │ React.cloneElement(thing, { key: index }) - 52 │ )); + 49 │ React.cloneElement(thing, { key: index }) + 50 │ )); i The order of the items may change, and this also affects performances and component state. diff --git a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx index 2a0b829b2bc..a39b478ae12 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx @@ -1,5 +1,4 @@ -import {createElement} from "react"; -import React from "react"; +import { createElement as aliased } from "react"; <> @@ -12,3 +11,8 @@ createElement('div', { React.createElement('div', { children: 'foo' }) + + +aliased('div', { + children: 'foo' +}) diff --git a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap index 7c5df246fe4..2873d60944c 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noChildrenProp/noChildrenPropInvalid.jsx.snap @@ -4,8 +4,7 @@ expression: noChildrenPropInvalid.jsx --- # Input ```js -import {createElement} from "react"; -import React from "react"; +import { createElement as aliased } from "react"; <> @@ -19,19 +18,24 @@ React.createElement('div', { children: 'foo' }) + +aliased('div', { + children: 'foo' +}) + ``` # Diagnostics ``` -noChildrenPropInvalid.jsx:5:16 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildrenPropInvalid.jsx:4:16 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing children using a prop - 4 │ <> - > 5 │ + 3 │ <> + > 4 │ │ ^^^^^^^^ - 6 │ - 7 │ + 5 │ + 6 │ i The canonical way to pass children in React is to use JSX elements @@ -39,15 +43,15 @@ noChildrenPropInvalid.jsx:5:16 lint/correctness/noChildrenProp ━━━━━ ``` ``` -noChildrenPropInvalid.jsx:9:5 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildrenPropInvalid.jsx:12:5 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing children using a prop - 8 │ createElement('div', { - > 9 │ children: 'foo' + 11 │ React.createElement('div', { + > 12 │ children: 'foo' │ ^^^^^^^^ - 10 │ }) - 11 │ + 13 │ }) + 14 │ i The canonical way to pass children in React is to use additional arguments to React.createElement @@ -55,15 +59,15 @@ noChildrenPropInvalid.jsx:9:5 lint/correctness/noChildrenProp ━━━━━━ ``` ``` -noChildrenPropInvalid.jsx:13:5 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildrenPropInvalid.jsx:17:2 lint/correctness/noChildrenProp ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing children using a prop - 12 │ React.createElement('div', { - > 13 │ children: 'foo' - │ ^^^^^^^^ - 14 │ }) - 15 │ + 16 │ aliased('div', { + > 17 │ children: 'foo' + │ ^^^^^^^^ + 18 │ }) + 19 │ i The canonical way to pass children in React is to use additional arguments to React.createElement diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx index 845a15dd0fe..85ad76e5730 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx @@ -1,4 +1,3 @@ -import React, { Fragment } from "react"; // invalid <> diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap index 64ac87635e4..e2b12e7221a 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/noChildren.jsx.snap @@ -4,7 +4,6 @@ expression: noChildren.jsx --- # Input ```js -import React, { Fragment } from "react"; // invalid <> @@ -17,57 +16,57 @@ import React, { Fragment } from "react"; # Diagnostics ``` -noChildren.jsx:5:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildren.jsx:4:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 4 │ <> - > 5 │ <> + 3 │ <> + > 4 │ <> │ ^^^^^ - 6 │ - 7 │ + 5 │ + 6 │ i Suggested fix: Remove the Fragment - 5 │ ····<> + 4 │ ····<> │ ----- ``` ``` -noChildren.jsx:6:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildren.jsx:5:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 4 │ <> - 5 │ <> - > 6 │ + 3 │ <> + 4 │ <> + > 5 │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 7 │ - 8 │ + 6 │ + 7 │ i Suggested fix: Remove the Fragment - 6 │ ···· + 5 │ ···· │ --------------------------------- ``` ``` -noChildren.jsx:7:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noChildren.jsx:6:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 5 │ <> - 6 │ - > 7 │ + 4 │ <> + 5 │ + > 6 │ │ ^^^^^^^^^^^^^^^^^^^^^ - 8 │ - 9 │ + 7 │ + 8 │ i Suggested fix: Remove the Fragment - 7 │ ···· + 6 │ ···· │ --------------------- ``` diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx index e352600cb88..6f662e94435 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx @@ -1,5 +1,3 @@ -import React, { Fragment, StrictMode } from "react"; - <> <>foo foo diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap index 7ec989c0277..054ae2b1867 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/withChildren.jsx.snap @@ -4,8 +4,6 @@ expression: withChildren.jsx --- # Input ```js -import React, { Fragment, StrictMode } from "react"; - <> <>foo foo @@ -18,57 +16,57 @@ import React, { Fragment, StrictMode } from "react"; # Diagnostics ``` -withChildren.jsx:4:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +withChildren.jsx:2:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 3 │ <> - > 4 │ <>foo + 1 │ <> + > 2 │ <>foo │ ^^^^^^^^ - 5 │ foo - 6 │ foo + 3 │ foo + 4 │ foo i Suggested fix: Remove the Fragment - 4 │ ····<>foo + 2 │ ····<>foo │ -- --- ``` ``` -withChildren.jsx:5:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +withChildren.jsx:3:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 3 │ <> - 4 │ <>foo - > 5 │ foo + 1 │ <> + 2 │ <>foo + > 3 │ foo │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 6 │ foo - 7 │ {/* valid */} + 4 │ foo + 5 │ {/* valid */} i Suggested fix: Remove the Fragment - 5 │ ····foo + 3 │ ····foo │ ---------------- ----------------- ``` ``` -withChildren.jsx:6:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +withChildren.jsx:4:5 lint/correctness/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using unnecessary Fragment. - 4 │ <>foo - 5 │ foo - > 6 │ foo + 2 │ <>foo + 3 │ foo + > 4 │ foo │ ^^^^^^^^^^^^^^^^^^^^^^^^ - 7 │ {/* valid */} - 8 │ + 5 │ {/* valid */} + 6 │ i Suggested fix: Remove the Fragment - 6 │ ····foo + 4 │ ····foo │ ---------- ----------- ``` diff --git a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js index bec5c1d08ac..9a524163ac5 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js +++ b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js @@ -1,4 +1,4 @@ -import React from "react"; + React.createElement('img', { someProp: "bar" diff --git a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap index b3db1f65883..c538cfc609f 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noVoidElementsWithChildren/createElement.js.snap @@ -4,7 +4,7 @@ expression: createElement.js --- # Input ```js -import React from "react"; + React.createElement('img', { someProp: "bar" @@ -22,8 +22,6 @@ createElement.js:3:1 lint/correctness/noVoidElementsWithChildren FIXABLE ━ ! img is a void element tag and must not have children. - 1 │ import React from "react"; - 2 │ > 3 │ React.createElement('img', { │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > 4 │ someProp: "bar" diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js index 86af9c2d220..4d78eab0fd6 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js @@ -1,5 +1,3 @@ -import React from "react"; - React.createElement('div', { dangerouslySetInnerHTML: { __html: 'child' } }); diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap index 74f486dfde4..684283d21eb 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtml/reactCreateElement.js.snap @@ -4,8 +4,6 @@ expression: reactCreateElement.js --- # Input ```js -import React from "react"; - React.createElement('div', { dangerouslySetInnerHTML: { __html: 'child' } }); @@ -14,15 +12,15 @@ React.createElement('div', { # Diagnostics ``` -reactCreateElement.js:4:5 lint/security/noDangerouslySetInnerHtml ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +reactCreateElement.js:2:5 lint/security/noDangerouslySetInnerHtml ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing content using the dangerouslySetInnerHTML prop. - 3 │ React.createElement('div', { - > 4 │ dangerouslySetInnerHTML: { __html: 'child' } + 1 │ React.createElement('div', { + > 2 │ dangerouslySetInnerHTML: { __html: 'child' } │ ^^^^^^^^^^^^^^^^^^^^^^^ - 5 │ }); - 6 │ + 3 │ }); + 4 │ ! Setting content using code can expose users to cross-site scripting (XSS) attacks diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js index bf7bdb69b30..6411485fc1a 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js @@ -1,5 +1,3 @@ -import React from "react"; - React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) diff --git a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap index 0586ad56fa5..2fd650c30c7 100644 --- a/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap +++ b/crates/rome_js_analyze/tests/specs/security/noDangerouslySetInnerHtmlWithChildren/createElement.js.snap @@ -4,8 +4,6 @@ expression: createElement.js --- # Input ```js -import React from "react"; - React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) @@ -14,25 +12,21 @@ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, childr # Diagnostics ``` -createElement.js:3:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ +createElement.js:1:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing both children and the dangerouslySetInnerHTML prop. - 1 │ import React from "react"; - 2 │ - > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + > 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) i This is the source of the children prop - 1 │ import React from "react"; - 2 │ - > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + > 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) │ ^^^^^^^^^^^^ - 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) i Setting HTML content will inadvertently override any passed children in React @@ -40,23 +34,23 @@ createElement.js:3:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━ ``` ``` -createElement.js:4:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ +createElement.js:2:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing both children and the dangerouslySetInnerHTML prop. - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - > 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + > 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) - 6 │ + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 4 │ i This is the source of the children prop - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - > 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + > 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') │ ^^^^^^^^^^ - 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) - 6 │ + 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 4 │ i Setting HTML content will inadvertently override any passed children in React @@ -64,23 +58,23 @@ createElement.js:4:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━ ``` ``` -createElement.js:5:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ +createElement.js:3:30 lint/security/noDangerouslySetInnerHtmlWithChildren ━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid passing both children and the dangerouslySetInnerHTML prop. - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - > 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 6 │ + 4 │ i This is the source of the children prop - 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) - 4 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') - > 5 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) + 1 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, ['children']) + 2 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' } }, 'children') + > 3 │ React.createElement('div', { dangerouslySetInnerHTML: { __html: 'HTML' }, children: 'children' }) │ ^^^^^^^^^^^^^^^^^^^^ - 6 │ + 4 │ i Setting HTML content will inadvertently override any passed children in React From 806a4d9a124df0b488a8162400782b64862af1ea Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 9 Nov 2022 14:39:49 +0100 Subject: [PATCH 3/4] Restore lib.rs --- crates/rome_js_analyze/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/rome_js_analyze/src/lib.rs b/crates/rome_js_analyze/src/lib.rs index 3455220b3c7..a4a99671a2f 100644 --- a/crates/rome_js_analyze/src/lib.rs +++ b/crates/rome_js_analyze/src/lib.rs @@ -141,9 +141,8 @@ mod tests { String::from_utf8(buffer).unwrap() } - const SOURCE: &str = r#"React.createElement("div", { tabIndex: '1' }) -React.createElement("div", { tabIndex: 1 }) -React.createElement("div", { tabIndex: +1 })"#; + const SOURCE: &str = r#" + "#; let parsed = parse(SOURCE, FileId::zero(), SourceType::jsx()); From d37b9918e20478959018e80e7d6cb45a2be1eb86 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 9 Nov 2022 14:44:23 +0100 Subject: [PATCH 4/4] Fix `noArrayIndexKey` test --- .../specs/correctness/noArrayIndexKey.jsx | 2 + .../correctness/noArrayIndexKey.jsx.snap | 289 +++++++++++------- 2 files changed, 187 insertions(+), 104 deletions(-) diff --git a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx index 81cc1c17ad6..efa70cb986b 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx +++ b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx @@ -1,3 +1,5 @@ +import { Children, cloneElement } from "react"; + // invalid something.forEach((Element, index) => { foo diff --git a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap index 704239b044f..682b1d94dec 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noArrayIndexKey.jsx.snap @@ -4,6 +4,8 @@ expression: noArrayIndexKey.jsx --- # Input ```js +import { Children, cloneElement } from "react"; + // invalid something.forEach((Element, index) => { foo @@ -69,24 +71,24 @@ something.forEach((element, index) => { # Diagnostics ``` -noArrayIndexKey.jsx:3:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:5:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 1 │ // invalid - 2 │ something.forEach((Element, index) => { - > 3 │ foo + 3 │ // invalid + 4 │ something.forEach((Element, index) => { + > 5 │ foo │ ^^^^^ - 4 │ }); - 5 │ something.forEach((element, index, array) => { + 6 │ }); + 7 │ something.forEach((element, index, array) => { i This is the source of the key value. - 1 │ // invalid - > 2 │ something.forEach((Element, index) => { + 3 │ // invalid + > 4 │ something.forEach((Element, index) => { │ ^^^^^ - 3 │ foo - 4 │ }); + 5 │ foo + 6 │ }); i The order of the items may change, and this also affects performances and component state. @@ -96,25 +98,25 @@ noArrayIndexKey.jsx:3:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:6:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:8:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 4 │ }); - 5 │ something.forEach((element, index, array) => { - > 6 │ foo - │ ^^^^^ - 7 │ }); - 8 │ things.filter((thing, index) => { + 6 │ }); + 7 │ something.forEach((element, index, array) => { + > 8 │ foo + │ ^^^^^ + 9 │ }); + 10 │ things.filter((thing, index) => { i This is the source of the key value. - 3 │ foo - 4 │ }); - > 5 │ something.forEach((element, index, array) => { + 5 │ foo + 6 │ }); + > 7 │ something.forEach((element, index, array) => { │ ^^^^^ - 6 │ foo - 7 │ }); + 8 │ foo + 9 │ }); i The order of the items may change, and this also affects performances and component state. @@ -124,25 +126,25 @@ noArrayIndexKey.jsx:6:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:9:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:11:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 7 │ }); - 8 │ things.filter((thing, index) => { - > 9 │ otherThings.push(foo); + 9 │ }); + 10 │ things.filter((thing, index) => { + > 11 │ otherThings.push(foo); │ ^^^^^ - 10 │ }); - 11 │ + 12 │ }); + 13 │ i This is the source of the key value. - 6 │ foo - 7 │ }); - > 8 │ things.filter((thing, index) => { + 8 │ foo + 9 │ }); + > 10 │ things.filter((thing, index) => { │ ^^^^^ - 9 │ otherThings.push(foo); - 10 │ }); + 11 │ otherThings.push(foo); + 12 │ }); i The order of the items may change, and this also affects performances and component state. @@ -152,24 +154,24 @@ noArrayIndexKey.jsx:9:34 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:13:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:15:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 12 │ something.forEach((Element, index) => { - > 13 │ + 14 │ something.forEach((Element, index) => { + > 15 │ │ ^^^^^ - 14 │ }); - 15 │ something.forEach((element, index, array) => { + 16 │ }); + 17 │ something.forEach((element, index, array) => { i This is the source of the key value. - 10 │ }); - 11 │ - > 12 │ something.forEach((Element, index) => { + 12 │ }); + 13 │ + > 14 │ something.forEach((Element, index) => { │ ^^^^^ - 13 │ - 14 │ }); + 15 │ + 16 │ }); i The order of the items may change, and this also affects performances and component state. @@ -179,25 +181,25 @@ noArrayIndexKey.jsx:13:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:16:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:18:21 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 14 │ }); - 15 │ something.forEach((element, index, array) => { - > 16 │ + 16 │ }); + 17 │ something.forEach((element, index, array) => { + > 18 │ │ ^^^^^ - 17 │ }); - 18 │ things.filter((thing, index) => { + 19 │ }); + 20 │ things.filter((thing, index) => { i This is the source of the key value. - 13 │ - 14 │ }); - > 15 │ something.forEach((element, index, array) => { + 15 │ + 16 │ }); + > 17 │ something.forEach((element, index, array) => { │ ^^^^^ - 16 │ - 17 │ }); + 18 │ + 19 │ }); i The order of the items may change, and this also affects performances and component state. @@ -207,25 +209,25 @@ noArrayIndexKey.jsx:16:21 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:19:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:21:34 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 17 │ }); - 18 │ things.filter((thing, index) => { - > 19 │ otherThings.push(); + 19 │ }); + 20 │ things.filter((thing, index) => { + > 21 │ otherThings.push(); │ ^^^^^ - 20 │ }); - 21 │ things.reduce((collection, thing, index) => ( + 22 │ }); + 23 │ things.reduce((collection, thing, index) => ( i This is the source of the key value. - 16 │ - 17 │ }); - > 18 │ things.filter((thing, index) => { + 18 │ + 19 │ }); + > 20 │ things.filter((thing, index) => { │ ^^^^^ - 19 │ otherThings.push(); - 20 │ }); + 21 │ otherThings.push(); + 22 │ }); i The order of the items may change, and this also affects performances and component state. @@ -235,25 +237,25 @@ noArrayIndexKey.jsx:19:34 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:22:35 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:24:35 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 20 │ }); - 21 │ things.reduce((collection, thing, index) => ( - > 22 │ collection.concat() + 22 │ }); + 23 │ things.reduce((collection, thing, index) => ( + > 24 │ collection.concat() │ ^^^^^ - 23 │ ), []); - 24 │ + 25 │ ), []); + 26 │ i This is the source of the key value. - 19 │ otherThings.push(); - 20 │ }); - > 21 │ things.reduce((collection, thing, index) => ( + 21 │ otherThings.push(); + 22 │ }); + > 23 │ things.reduce((collection, thing, index) => ( │ ^^^^^ - 22 │ collection.concat() - 23 │ ), []); + 24 │ collection.concat() + 25 │ ), []); i The order of the items may change, and this also affects performances and component state. @@ -263,24 +265,24 @@ noArrayIndexKey.jsx:22:35 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:26:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:28:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 25 │ React.Children.map(this.props.children, (child, index) => ( - > 26 │ React.cloneElement(child, { key: index }) + 27 │ React.Children.map(this.props.children, (child, index) => ( + > 28 │ React.cloneElement(child, { key: index }) │ ^^^^^ - 27 │ )) - 28 │ + 29 │ )) + 30 │ i This is the source of the key value. - 23 │ ), []); - 24 │ - > 25 │ React.Children.map(this.props.children, (child, index) => ( + 25 │ ), []); + 26 │ + > 27 │ React.Children.map(this.props.children, (child, index) => ( │ ^^^^^ - 26 │ React.cloneElement(child, { key: index }) - 27 │ )) + 28 │ React.cloneElement(child, { key: index }) + 29 │ )) i The order of the items may change, and this also affects performances and component state. @@ -290,24 +292,103 @@ noArrayIndexKey.jsx:26:38 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:30:45 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:32:45 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 29 │ React.Children.forEach(this.props.children, function (child, index) { - > 30 │ return React.cloneElement(child, { key: index }) + 31 │ React.Children.forEach(this.props.children, function (child, index) { + > 32 │ return React.cloneElement(child, { key: index }) │ ^^^^^ - 31 │ }) - 32 │ + 33 │ }) + 34 │ i This is the source of the key value. - 27 │ )) - 28 │ - > 29 │ React.Children.forEach(this.props.children, function (child, index) { + 29 │ )) + 30 │ + > 31 │ React.Children.forEach(this.props.children, function (child, index) { │ ^^^^^ - 30 │ return React.cloneElement(child, { key: index }) - 31 │ }) + 32 │ return React.cloneElement(child, { key: index }) + 33 │ }) + + i The order of the items may change, and this also affects performances and component state. + + i Check the React documentation. + + +``` + +``` +noArrayIndexKey.jsx:37:32 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Avoid using the index of an array as key property in an element. + + 36 │ Children.map(this.props.children, (child, index) => ( + > 37 │ cloneElement(child, { key: index }) + │ ^^^^^ + 38 │ )) + 39 │ + + i This is the source of the key value. + + > 36 │ Children.map(this.props.children, (child, index) => ( + │ ^^^^^ + 37 │ cloneElement(child, { key: index }) + 38 │ )) + + i The order of the items may change, and this also affects performances and component state. + + i Check the React documentation. + + +``` + +``` +noArrayIndexKey.jsx:41:39 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Avoid using the index of an array as key property in an element. + + 40 │ Children.forEach(this.props.children, function (child, index) { + > 41 │ return cloneElement(child, { key: index }) + │ ^^^^^ + 42 │ }) + 43 │ + + i This is the source of the key value. + + 38 │ )) + 39 │ + > 40 │ Children.forEach(this.props.children, function (child, index) { + │ ^^^^^ + 41 │ return cloneElement(child, { key: index }) + 42 │ }) + + i The order of the items may change, and this also affects performances and component state. + + i Check the React documentation. + + +``` + +``` +noArrayIndexKey.jsx:45:44 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Avoid using the index of an array as key property in an element. + + 44 │ Children.forEach(this.props.children, function (child, index) { + > 45 │ const foo = cloneElement(child, { key: index }) + │ ^^^^^ + 46 │ return foo; + 47 │ }) + + i This is the source of the key value. + + 42 │ }) + 43 │ + > 44 │ Children.forEach(this.props.children, function (child, index) { + │ ^^^^^ + 45 │ const foo = cloneElement(child, { key: index }) + 46 │ return foo; i The order of the items may change, and this also affects performances and component state. @@ -317,22 +398,22 @@ noArrayIndexKey.jsx:30:45 lint/correctness/noArrayIndexKey ━━━━━━━ ``` ``` -noArrayIndexKey.jsx:49:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +noArrayIndexKey.jsx:51:38 lint/correctness/noArrayIndexKey ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Avoid using the index of an array as key property in an element. - 48 │ things.map((thing, index) => ( - > 49 │ React.cloneElement(thing, { key: index }) + 50 │ things.map((thing, index) => ( + > 51 │ React.cloneElement(thing, { key: index }) │ ^^^^^ - 50 │ )); - 51 │ + 52 │ )); + 53 │ i This is the source of the key value. - > 48 │ things.map((thing, index) => ( + > 50 │ things.map((thing, index) => ( │ ^^^^^ - 49 │ React.cloneElement(thing, { key: index }) - 50 │ )); + 51 │ React.cloneElement(thing, { key: index }) + 52 │ )); i The order of the items may change, and this also affects performances and component state.