From f65b0d99556daa1f18ddfdea895500a91b09320c Mon Sep 17 00:00:00 2001 From: Victorien ELVINGER Date: Tue, 4 Jul 2023 23:31:08 +0200 Subject: [PATCH] refactor(rome_js_analyze): improve consistency of rules about globals (#4654) --- CHANGELOG.md | 8 + .../src/analyzers/complexity/use_flat_map.rs | 48 +- .../complexity/use_optional_chain.rs | 166 ++----- .../no_invalid_constructor_super.rs | 3 +- .../correctness/no_string_case_mismatch.rs | 9 +- .../rome_js_analyze/src/analyzers/nursery.rs | 3 +- .../src/analyzers/nursery/no_for_each.rs | 32 +- .../style/use_exponentiation_operator.rs | 51 +- .../analyzers/style/use_numeric_literals.rs | 24 +- .../suspicious/no_prototype_builtins.rs | 52 +- crates/rome_js_analyze/src/react.rs | 10 +- crates/rome_js_analyze/src/react/hooks.rs | 27 +- .../correctness/no_global_object_calls.rs | 88 ++-- .../src/semantic_analyzers/nursery.rs | 3 +- .../nursery/no_accumulating_spread.rs | 27 +- .../nursery/no_console_log.rs | 27 +- .../nursery/no_global_is_finite.rs | 50 +- .../nursery/no_global_is_nan.rs | 50 +- .../nursery/use_is_nan.rs | 95 ++-- .../suspicious/no_array_index_key.rs | 21 +- .../noGlobalObjectCalls/invalid.js.snap | 443 +++++++++--------- .../specs/nursery/noGlobalIsFinite/invalid.js | 2 + .../nursery/noGlobalIsFinite/invalid.js.snap | 94 ++-- .../specs/nursery/noGlobalIsNan/invalid.js | 2 + .../nursery/noGlobalIsNan/invalid.js.snap | 94 ++-- .../tests/specs/nursery/useIsNan/invalid.js | 4 + .../specs/nursery/useIsNan/invalid.js.snap | 357 ++++++++------ .../specs/nursery/useIsNan/valid.js.snap | 1 - .../specs/style/useNumericLiterals/invalid.js | 8 + .../style/useNumericLiterals/invalid.js.snap | 200 +++++++- crates/rome_js_syntax/src/expr_ext.rs | 137 +++++- crates/rome_js_syntax/src/static_value.rs | 38 +- .../pages/lint/rules/noGlobalObjectCalls.md | 34 +- 33 files changed, 1147 insertions(+), 1061 deletions(-) rename crates/rome_js_analyze/src/{analyzers => semantic_analyzers}/nursery/use_is_nan.rs (68%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba9c7572674..287fa011f57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,14 @@ multiple files: - [`noRedeclare`](https://docs.rome.tools/lint/rules/noredeclare/): allow redeclare of index signatures are in different type members [#4478](https://github.com/rome/tools/issues/4478) +- Improve [`noConsoleLog`](https://docs.rome.tools/lint/rules/noconsolelog/), [`noGlobalObjectCalls`](https://docs.rome.tools/lint/rules/noglobalobjectcalls/), [`useIsNan`](https://docs.rome.tools/lint/rules/useisnan/), and [`useNumericLiterals`](https://docs.rome.tools/lint/rules/usenumericliterals/) by handling `globalThis` and `window` namespaces. + + For instance, the following code is now reported by `noConsoleLog`: + + ```js + globalThis.console.log("log") + ``` + - Fix a crash in the [`NoParameterAssign`](https://docs.rome.tools/lint/rules/noparameterassign/) rule that occurred when there was a bogus binding. [#4323](https://github.com/rome/tools/issues/4323) - Fix [`useExhaustiveDependencies`](https://docs.rome.tools/lint/rules/useexhaustivedependencies/) rule in the following cases [#4330](https://github.com/rome/tools/issues/4330) diff --git a/crates/rome_js_analyze/src/analyzers/complexity/use_flat_map.rs b/crates/rome_js_analyze/src/analyzers/complexity/use_flat_map.rs index f25689017e0..f0c5e2e4cbe 100644 --- a/crates/rome_js_analyze/src/analyzers/complexity/use_flat_map.rs +++ b/crates/rome_js_analyze/src/analyzers/complexity/use_flat_map.rs @@ -4,7 +4,7 @@ use rome_analyze::{declare_rule, ActionCategory, Ast, Rule, RuleDiagnostic}; use rome_console::markup; use rome_diagnostics::Applicability; use rome_js_factory::make::{ident, js_name}; -use rome_js_syntax::{AnyJsExpression, AnyJsName, JsCallExpression}; +use rome_js_syntax::{AnyJsExpression, AnyJsMemberExpression, AnyJsName, JsCallExpression}; use rome_rowan::{AstNode, AstSeparatedList, BatchMutationExt}; declare_rule! { @@ -46,8 +46,8 @@ impl Rule for UseFlatMap { type Options = (); fn run(ctx: &RuleContext) -> Self::Signals { - let node = ctx.query(); - let arguments = node.arguments().ok()?.args(); + let flat_call = ctx.query(); + let arguments = flat_call.arguments().ok()?.args(); // Probably not a `flat` call. if arguments.len() > 1 { return None; @@ -63,39 +63,19 @@ impl Rule for UseFlatMap { return None; } } - let static_member_expression = node.callee().ok()?; - let static_member_expression = static_member_expression.as_js_static_member_expression()?; - let flat_member_name = static_member_expression - .member() - .ok()? - .as_js_name()? - .value_token() - .ok()?; - if flat_member_name.text_trimmed() == "flat" { - let call_expression = static_member_expression.object().ok()?; - let call_expression = call_expression.as_js_call_expression()?; - let map_call_arguments = call_expression.arguments().ok()?.args(); - - // probably not a `.map` all coming from an array - if map_call_arguments.len() > 2 || map_call_arguments.len() < 1 { - return None; - } - - let map_static_member_expression = call_expression.callee().ok()?; - let map_static_member_expression = - map_static_member_expression.as_js_static_member_expression()?; - let map_member_name = map_static_member_expression - .member() - .ok()? - .as_js_name()? - .value_token() - .ok()?; - - if map_member_name.text_trimmed() == "map" { - return Some(call_expression.clone()); + let flat_member_expression = + AnyJsMemberExpression::cast_ref(flat_call.callee().ok()?.syntax())?; + if flat_member_expression.member_name()?.text() == "flat" { + let object = flat_member_expression.object().ok()?; + let map_call = object.as_js_call_expression()?; + let map_call_arguments = map_call.arguments().ok()?.args(); + let map_member_expression = + AnyJsMemberExpression::cast_ref(map_call.callee().ok()?.syntax())?; + if map_member_expression.member_name()?.text() == "map" && map_call_arguments.len() == 1 + { + return Some(map_call.clone()); } } - None } diff --git a/crates/rome_js_analyze/src/analyzers/complexity/use_optional_chain.rs b/crates/rome_js_analyze/src/analyzers/complexity/use_optional_chain.rs index 6013be624ab..307a596005d 100644 --- a/crates/rome_js_analyze/src/analyzers/complexity/use_optional_chain.rs +++ b/crates/rome_js_analyze/src/analyzers/complexity/use_optional_chain.rs @@ -3,10 +3,10 @@ use rome_console::markup; use rome_diagnostics::Applicability; use rome_js_factory::make; use rome_js_syntax::{ - AnyJsExpression, AnyJsName, JsComputedMemberExpression, JsLogicalExpression, JsLogicalOperator, - JsStaticMemberExpression, OperatorPrecedence, T, + AnyJsExpression, AnyJsMemberExpression, AnyJsName, JsLogicalExpression, JsLogicalOperator, + OperatorPrecedence, T, }; -use rome_rowan::{declare_node_union, AstNode, AstNodeExt, BatchMutationExt, SyntaxResult}; +use rome_rowan::{AstNode, AstNodeExt, BatchMutationExt, SyntaxResult}; use std::cmp::Ordering; use std::collections::VecDeque; use std::iter; @@ -91,19 +91,14 @@ impl Rule for UseOptionalChain { fn run(ctx: &RuleContext) -> Option { let logical = ctx.query(); let operator = logical.operator().ok()?; - match operator { JsLogicalOperator::LogicalAnd => { let head = logical.right().ok()?; - let chain = LogicalAndChain::from_expression(head).ok()?; - if chain.is_inside_another_chain().ok()? { return None; } - let optional_chain_expression_nodes = chain.optional_chain_expression_nodes()?; - Some(UseOptionalChainState::LogicalAnd( optional_chain_expression_nodes, )) @@ -114,7 +109,6 @@ impl Rule for UseOptionalChain { if chain.is_inside_another_chain() { return None; } - Some(UseOptionalChainState::LogicalOrLike(chain)) } } @@ -125,7 +119,6 @@ impl Rule for UseOptionalChain { UseOptionalChainState::LogicalAnd(_) => ctx.query().range(), UseOptionalChainState::LogicalOrLike(state) => state.member.range(), }; - Some(RuleDiagnostic::new( rule_category!(), range, @@ -140,7 +133,6 @@ impl Rule for UseOptionalChain { match state { UseOptionalChainState::LogicalAnd(optional_chain_expression_nodes) => { let mut prev_expression = None; - for expression in optional_chain_expression_nodes { let next_expression = prev_expression .take() @@ -150,7 +142,6 @@ impl Rule for UseOptionalChain { .replace_node(prev_expression, new_expression) }) .unwrap_or_else(|| expression.clone()); - let next_expression = match next_expression { AnyJsExpression::JsCallExpression(call_expression) => { let mut call_expression_builder = make::js_call_expression( @@ -158,19 +149,15 @@ impl Rule for UseOptionalChain { call_expression.arguments().ok()?, ) .with_optional_chain_token(make::token(T![?.])); - if let Some(type_arguments) = call_expression.type_arguments() { call_expression_builder = call_expression_builder.with_type_arguments(type_arguments); } - let call_expression = call_expression_builder.build(); - AnyJsExpression::from(call_expression) } AnyJsExpression::JsStaticMemberExpression(member_expression) => { let operator_token = member_expression.operator_token().ok()?; - AnyJsExpression::from(make::js_static_member_expression( member_expression.object().ok()?, make::token(T![?.]) @@ -190,7 +177,6 @@ impl Rule for UseOptionalChain { .with_trailing_trivia_pieces(token.trailing_trivia().pieces()), None => make::token(T![?.]), }; - AnyJsExpression::from( make::js_computed_member_expression( member_expression.object().ok()?, @@ -204,12 +190,9 @@ impl Rule for UseOptionalChain { } _ => return None, }; - prev_expression = Some((expression.clone(), next_expression)); } - let (prev_expression, new_expression) = prev_expression?; - let logical = ctx.query(); let next_right = logical .right() @@ -218,9 +201,7 @@ impl Rule for UseOptionalChain { .unwrap_or(new_expression); let mut mutation = ctx.root().begin(); - mutation.replace_node(AnyJsExpression::from(logical.clone()), next_right); - Some(JsRuleAction { category: ActionCategory::QuickFix, applicability: Applicability::MaybeIncorrect, @@ -230,32 +211,24 @@ impl Rule for UseOptionalChain { } UseOptionalChainState::LogicalOrLike(chain) => { let chain = chain.optional_chain_expression_nodes(); - let mut prev_chain: Option<(AnyJsMemberExpression, AnyJsMemberExpression)> = None; - - for (left, member) in chain { - let left = if let Some((prev_member, next_member)) = prev_chain.take() { - left.replace_node(prev_member, next_member.clone()) - .unwrap_or_else(|| next_member.into()) - } else { - left - }; - - let left = trim_trailing_space(left)?; + for (mut left, member) in chain { + if let Some((prev_member, next_member)) = prev_chain.take() { + left = left + .replace_node(prev_member, next_member.clone()) + .unwrap_or_else(|| next_member.into()); + } + left = trim_trailing_space(left)?; let need_parenthesis = left.precedence().ok()? < OperatorPrecedence::LeftHandSide; - - let left = if need_parenthesis { - make::js_parenthesized_expression( + if need_parenthesis { + left = make::js_parenthesized_expression( make::token(T!['(']), left, make::token(T![')']), ) - .into() - } else { - left - }; - + .into(); + } let next_member = match member.clone() { AnyJsMemberExpression::JsStaticMemberExpression(expression) => { let static_member_expression = make::js_static_member_expression( @@ -274,20 +247,14 @@ impl Rule for UseOptionalChain { ) .with_optional_chain_token(make::token(T![?.])) .build(); - computed_member_expression.into() } }; - prev_chain = Some((member, next_member)); } - let (prev_member, new_member) = prev_chain?; - let mut mutation = ctx.root().begin(); - mutation.replace_node(prev_member, new_member); - Some(JsRuleAction { category: ActionCategory::QuickFix, applicability: Applicability::MaybeIncorrect, @@ -375,43 +342,34 @@ impl LogicalAndChain { /// `[JsReferenceIdentifier, JsStaticMemberExpression, JsComputedMemberExpression]` fn collect_chain(expression: AnyJsExpression) -> SyntaxResult> { let mut buf = VecDeque::new(); - let mut current_expression = Some(expression); - while let Some(expression) = current_expression.take() { current_expression = match &expression { AnyJsExpression::JsStaticMemberExpression(member_expression) => { let object = member_expression.object()?; buf.push_front(expression); - Some(object) } AnyJsExpression::JsComputedMemberExpression(member_expression) => { let object = member_expression.object()?; buf.push_front(expression); - Some(object) } AnyJsExpression::JsCallExpression(call_expression) => { let callee = call_expression.callee()?; buf.push_front(expression); - Some(callee) } AnyJsExpression::JsIdentifierExpression(_) => { buf.push_front(expression); - return Ok(buf); } _ => return Ok(buf), }; } - Ok(buf) } - let buf = collect_chain(head.clone())?; - Ok(LogicalAndChain { head, buf }) } @@ -426,22 +384,17 @@ impl LogicalAndChain { if let Some(parent) = self.head.parent::() { if let Some(grand_parent) = parent.parent::() { let grand_parent_operator = grand_parent.operator()?; - if !matches!(grand_parent_operator, JsLogicalOperator::LogicalAnd) { return Ok(false); } - let grand_parent_logical_left = grand_parent.left()?; - // Here we check that we came from the left side of the logical expression. // Because only the left-hand parts can be sub-chains. if grand_parent_logical_left.as_js_logical_expression() == Some(&parent) { let grand_parent_right_chain = LogicalAndChain::from_expression( normalized_optional_chain_like(grand_parent.right()?)?, )?; - let result = grand_parent_right_chain.cmp_chain(self)?; - return match result { LogicalAndChainOrdering::SubChain | LogicalAndChainOrdering::Equal => { Ok(true) @@ -462,7 +415,6 @@ impl LogicalAndChain { Ordering::Equal => LogicalAndChainOrdering::Equal, Ordering::Greater => LogicalAndChainOrdering::SubChain, }; - for (main_expression, branch_expression) in self.buf.iter().zip(&other.buf) { let (main_expression, branch_expression) = match (&main_expression, &branch_expression) { @@ -472,7 +424,6 @@ impl LogicalAndChain { ) => (main_expression.callee()?, branch_expression.callee()?), _ => (main_expression.clone(), branch_expression.clone()), }; - let (main_value_token, branch_value_token) = match (main_expression, branch_expression) { ( @@ -517,26 +468,22 @@ impl LogicalAndChain { ), _ => return Ok(LogicalAndChainOrdering::Different), }; - if main_value_token.token_text_trimmed() != branch_value_token.token_text_trimmed() { return Ok(LogicalAndChainOrdering::Different); } } - Ok(chain_ordering) } /// This function returns a list of `JsAnyExpression` which we need to transform into an option chain expression. fn optional_chain_expression_nodes(mut self) -> Option> { let mut optional_chain_expression_nodes = VecDeque::with_capacity(self.buf.len()); - // Take a head of a next sub-chain // E.g. `foo && foo.bar && foo.bar.baz` // The head is `foo.bar.baz` expression. // The parent of the head is a logical expression `foo && foo.bar && foo.bar.baz`. // The next chain head is a left part of the logical expression `foo && foo.bar` let mut next_chain_head = self.head.parent::()?.left().ok(); - while let Some(expression) = next_chain_head.take() { let expression = match expression { // Extract a left `JsAnyExpression` from `JsBinaryExpression` if it's optional chain like @@ -553,13 +500,11 @@ impl LogicalAndChain { .then_some(expression.left().ok()?)?, expression => expression, }; - let head = match expression { AnyJsExpression::JsLogicalExpression(logical) => { if matches!(logical.operator().ok()?, JsLogicalOperator::LogicalAnd) { // Here we move our sub-chain head over the chains of logical expression next_chain_head = logical.left().ok(); - logical.right().ok()? } else { return None; @@ -571,11 +516,9 @@ impl LogicalAndChain { | AnyJsExpression::JsCallExpression(_) => expression, _ => return None, }; - let branch = LogicalAndChain::from_expression(normalized_optional_chain_like(head).ok()?) .ok()?; - match self.cmp_chain(&branch).ok()? { LogicalAndChainOrdering::SubChain => { // Here we reduce our main `JsAnyExpression` buffer by splitting the main buffer. @@ -584,7 +527,6 @@ impl LogicalAndChain { // After splitting the main buffer will be `[foo]` and the tail will be `[bar, baz]`. // It means that we need to transform `bar` (first tail expression) into the optional one. let mut tail = self.buf.split_off(branch.buf.len()); - if let Some(part) = tail.pop_front() { optional_chain_expression_nodes.push_front(part) }; @@ -593,11 +535,9 @@ impl LogicalAndChain { LogicalAndChainOrdering::Different => return None, } } - if optional_chain_expression_nodes.is_empty() { return None; } - Some(optional_chain_expression_nodes) } } @@ -643,14 +583,11 @@ impl LogicalOrLikeChain { .omit_parentheses() .as_js_object_expression()? .is_empty(); - if !is_right_empty_object { return None; } - let member = LogicalOrLikeChain::get_chain_parent_member(AnyJsExpression::from(logical.clone()))?; - Some(LogicalOrLikeChain { member }) } @@ -658,21 +595,18 @@ impl LogicalOrLikeChain { /// E.g. /// `(foo ?? {}).bar` is inside `((foo ?? {}).bar || {}).baz;` fn is_inside_another_chain(&self) -> bool { - LogicalOrLikeChain::get_chain_parent(AnyJsExpression::from(self.member.clone())).map_or( - false, - |parent| { - parent - .as_js_logical_expression() - .filter(|parent_expression| { - matches!( - parent_expression.operator(), - Ok(JsLogicalOperator::NullishCoalescing | JsLogicalOperator::LogicalOr) - ) - }) - .and_then(LogicalOrLikeChain::from_expression) - .is_some() - }, - ) + LogicalOrLikeChain::get_chain_parent(self.member.clone()).map_or(false, |parent| { + parent + .as_js_logical_expression() + .filter(|parent_expression| { + matches!( + parent_expression.operator(), + Ok(JsLogicalOperator::NullishCoalescing | JsLogicalOperator::LogicalOr) + ) + }) + .and_then(LogicalOrLikeChain::from_expression) + .is_some() + }) } /// This function returns a list of pairs `(JsAnyExpression, JsAnyMemberExpression)` which we need to transform into an option chain expression. @@ -680,20 +614,16 @@ impl LogicalOrLikeChain { &self, ) -> VecDeque<(AnyJsExpression, AnyJsMemberExpression)> { let mut chain = VecDeque::new(); - // Start from the topmost member expression let mut next_member_chain = Some(self.member.clone()); - while let Some(member) = next_member_chain.take() { let object = match member.object() { Ok(object) => object, _ => return chain, }; - // Handle case when a object expression is inside parentheses // E.g. (((foo || {}))).bar; let object = object.omit_parentheses(); - if let AnyJsExpression::JsLogicalExpression(logical) = object { let is_valid_operator = logical.operator().map_or(false, |operator| { matches!( @@ -701,11 +631,9 @@ impl LogicalOrLikeChain { JsLogicalOperator::NullishCoalescing | JsLogicalOperator::LogicalOr ) }); - if !is_valid_operator { return chain; } - let is_right_empty_object = logical .right() .ok() @@ -718,27 +646,22 @@ impl LogicalOrLikeChain { .map(|object| object.is_empty()) }) .unwrap_or(false); - if !is_right_empty_object { return chain; } - let left = match logical.left() { Ok(left) => left, Err(_) => return chain, }; - // Set next member expression from the left part // Find next member expression // E.g. `((foo || {}).baz() || {}).bar` // If current member chain is `bar` the next member chain is baz. // Need to downward traversal to find first `JsAnyExpression` which we can't include in chain next_member_chain = LogicalOrLikeChain::get_member(left.clone()); - chain.push_front((left, member)) } } - chain } @@ -768,7 +691,7 @@ impl LogicalOrLikeChain { /// Traversal by parent to find the parent of a chain. /// This function is opposite to the `get_member` function. - fn get_chain_parent(expression: AnyJsExpression) -> Option { + fn get_chain_parent(expression: AnyJsMemberExpression) -> Option { iter::successors(expression.parent::(), |expression| { if matches!( expression, @@ -808,7 +731,6 @@ impl LogicalOrLikeChain { _ => None, }) .last()?; - let expression = match expression { AnyJsExpression::JsComputedMemberExpression(expression) => { AnyJsMemberExpression::from(expression) @@ -818,39 +740,13 @@ impl LogicalOrLikeChain { } _ => return None, }; - Some(expression) } } fn trim_trailing_space(node: AnyJsExpression) -> Option { - if let Some(last_token_of_left_syntax) = node.syntax().last_token() { - let next_token_of_left_syntax = - last_token_of_left_syntax.with_trailing_trivia(std::iter::empty()); - node.replace_token_discard_trivia(last_token_of_left_syntax, next_token_of_left_syntax) - } else { - Some(node) - } -} - -declare_node_union! { - pub (crate) AnyJsMemberExpression = JsComputedMemberExpression | JsStaticMemberExpression -} - -impl From for AnyJsExpression { - fn from(expression: AnyJsMemberExpression) -> Self { - match expression { - AnyJsMemberExpression::JsComputedMemberExpression(expression) => expression.into(), - AnyJsMemberExpression::JsStaticMemberExpression(expression) => expression.into(), - } - } -} - -impl AnyJsMemberExpression { - fn object(&self) -> SyntaxResult { - match self { - AnyJsMemberExpression::JsComputedMemberExpression(expression) => expression.object(), - AnyJsMemberExpression::JsStaticMemberExpression(expression) => expression.object(), - } - } + let Some(last_token_of_left_syntax) = node.syntax().last_token() else { return Some(node) }; + let next_token_of_left_syntax = + last_token_of_left_syntax.with_trailing_trivia(std::iter::empty()); + node.replace_token_discard_trivia(last_token_of_left_syntax, next_token_of_left_syntax) } diff --git a/crates/rome_js_analyze/src/analyzers/correctness/no_invalid_constructor_super.rs b/crates/rome_js_analyze/src/analyzers/correctness/no_invalid_constructor_super.rs index d010aa01907..39083e2992c 100644 --- a/crates/rome_js_analyze/src/analyzers/correctness/no_invalid_constructor_super.rs +++ b/crates/rome_js_analyze/src/analyzers/correctness/no_invalid_constructor_super.rs @@ -166,8 +166,7 @@ fn is_valid_constructor(expression: AnyJsExpression) -> Option { | AnyJsExpression::JsStaticMemberExpression(_) | AnyJsExpression::JsClassExpression(_) => Some(true), AnyJsExpression::JsIdentifierExpression(identifier) => { - let name = identifier.name().ok()?; - return Some(name.value_token().ok()?.text_trimmed() != "undefined"); + Some(!identifier.name().ok()?.is_undefined()) } AnyJsExpression::JsAssignmentExpression(assignment) => { let operator = assignment.operator().ok()?; diff --git a/crates/rome_js_analyze/src/analyzers/correctness/no_string_case_mismatch.rs b/crates/rome_js_analyze/src/analyzers/correctness/no_string_case_mismatch.rs index d3b1620188a..79404dac213 100644 --- a/crates/rome_js_analyze/src/analyzers/correctness/no_string_case_mismatch.rs +++ b/crates/rome_js_analyze/src/analyzers/correctness/no_string_case_mismatch.rs @@ -178,17 +178,16 @@ impl ExpectedStringCase { if call.arguments().ok()?.args().len() != 0 { return None; } - let callee = call.callee().ok()?; let member_expr = AnyJsMemberExpression::cast_ref(callee.syntax())?; - if member_expr.has_member_name("toLowerCase") { + let member_name = member_expr.member_name()?; + let member_name = member_name.text(); + if member_name == "toLowerCase" { return Some(Self::Lower); } - - if member_expr.has_member_name("toUpperCase") { + if member_name == "toUpperCase" { return Some(Self::Upper); } - None } diff --git a/crates/rome_js_analyze/src/analyzers/nursery.rs b/crates/rome_js_analyze/src/analyzers/nursery.rs index f6faf621e06..87809cd1d77 100644 --- a/crates/rome_js_analyze/src/analyzers/nursery.rs +++ b/crates/rome_js_analyze/src/analyzers/nursery.rs @@ -11,8 +11,7 @@ pub(crate) mod no_void; pub(crate) mod use_arrow_function; pub(crate) mod use_grouped_type_import; pub(crate) mod use_heading_content; -pub(crate) mod use_is_nan; pub(crate) mod use_literal_enum_members; pub(crate) mod use_literal_keys; pub(crate) mod use_simple_number_keys; -declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_confusing_arrow :: NoConfusingArrow , self :: no_duplicate_jsx_props :: NoDuplicateJsxProps , self :: no_for_each :: NoForEach , self :: no_nonoctal_decimal_escape :: NoNonoctalDecimalEscape , self :: no_self_assign :: NoSelfAssign , self :: no_static_only_class :: NoStaticOnlyClass , self :: no_void :: NoVoid , self :: use_arrow_function :: UseArrowFunction , self :: use_grouped_type_import :: UseGroupedTypeImport , self :: use_heading_content :: UseHeadingContent , self :: use_is_nan :: UseIsNan , self :: use_literal_enum_members :: UseLiteralEnumMembers , self :: use_literal_keys :: UseLiteralKeys , self :: use_simple_number_keys :: UseSimpleNumberKeys ,] } } +declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_confusing_arrow :: NoConfusingArrow , self :: no_duplicate_jsx_props :: NoDuplicateJsxProps , self :: no_for_each :: NoForEach , self :: no_nonoctal_decimal_escape :: NoNonoctalDecimalEscape , self :: no_self_assign :: NoSelfAssign , self :: no_static_only_class :: NoStaticOnlyClass , self :: no_void :: NoVoid , self :: use_arrow_function :: UseArrowFunction , self :: use_grouped_type_import :: UseGroupedTypeImport , self :: use_heading_content :: UseHeadingContent , self :: use_literal_enum_members :: UseLiteralEnumMembers , self :: use_literal_keys :: UseLiteralKeys , self :: use_simple_number_keys :: UseSimpleNumberKeys ,] } } diff --git a/crates/rome_js_analyze/src/analyzers/nursery/no_for_each.rs b/crates/rome_js_analyze/src/analyzers/nursery/no_for_each.rs index f005b6985f6..c816f4c50a3 100644 --- a/crates/rome_js_analyze/src/analyzers/nursery/no_for_each.rs +++ b/crates/rome_js_analyze/src/analyzers/nursery/no_for_each.rs @@ -1,6 +1,6 @@ use rome_analyze::{context::RuleContext, declare_rule, Ast, Rule, RuleDiagnostic}; use rome_console::markup; -use rome_js_syntax::{AnyJsExpression, JsCallExpression}; +use rome_js_syntax::{AnyJsMemberExpression, JsCallExpression}; use rome_rowan::AstNode; declare_rule! { @@ -55,33 +55,9 @@ impl Rule for NoForEach { fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); - - let is_for_each = match node.callee().ok()?.omit_parentheses() { - AnyJsExpression::JsStaticMemberExpression(expression) => { - expression - .member() - .ok()? - .as_js_name()? - .value_token() - .ok()? - .text_trimmed() - == "forEach" - } - AnyJsExpression::JsComputedMemberExpression(expression) => { - expression - .member() - .ok()? - .as_any_js_literal_expression()? - .as_js_string_literal_expression()? - .inner_string_text() - .ok()? - .text() - == "forEach" - } - _ => return None, - }; - - is_for_each.then_some(()) + let member_expression = + AnyJsMemberExpression::cast_ref(node.callee().ok()?.omit_parentheses().syntax())?; + (member_expression.member_name()?.text() == "forEach").then_some(()) } fn diagnostic(ctx: &RuleContext, _state: &Self::State) -> Option { diff --git a/crates/rome_js_analyze/src/analyzers/style/use_exponentiation_operator.rs b/crates/rome_js_analyze/src/analyzers/style/use_exponentiation_operator.rs index ab5c3162363..a261868ceb9 100644 --- a/crates/rome_js_analyze/src/analyzers/style/use_exponentiation_operator.rs +++ b/crates/rome_js_analyze/src/analyzers/style/use_exponentiation_operator.rs @@ -6,8 +6,8 @@ use rome_console::markup; use rome_diagnostics::Applicability; use rome_js_factory::{make, syntax::T}; use rome_js_syntax::{ - AnyJsExpression, JsBinaryOperator, JsCallExpression, JsClassDeclaration, JsClassExpression, - JsExtendsClause, JsInExpression, OperatorPrecedence, + global_identifier, AnyJsExpression, AnyJsMemberExpression, JsBinaryOperator, JsCallExpression, + JsClassDeclaration, JsClassExpression, JsExtendsClause, JsInExpression, OperatorPrecedence, }; use rome_rowan::{AstNode, AstSeparatedList, BatchMutationExt}; @@ -106,42 +106,17 @@ impl Rule for UseExponentiationOperator { fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); let model = ctx.model(); - - let object = match node.callee().ok()?.omit_parentheses() { - AnyJsExpression::JsStaticMemberExpression(static_member_expr) => { - if static_member_expr - .member() - .ok()? - .as_js_name()? - .value_token() - .ok()? - .token_text_trimmed() - != "pow" - { - return None; - } - - static_member_expr.object() - } - AnyJsExpression::JsComputedMemberExpression(computed_member_expr) => { - if !computed_member_expr - .member() - .ok()? - .is_string_constant("pow") - { - return None; - } - - computed_member_expr.object() - } - _ => return None, - }; - - let reference = object.ok()?.omit_parentheses().as_reference_identifier()?; - - // verifies that the Math reference is not a local variable - let has_math_pow = reference.has_name("Math") && model.binding(&reference).is_none(); - has_math_pow.then_some(()) + let callee = node.callee().ok()?.omit_parentheses(); + let member_expr = AnyJsMemberExpression::cast_ref(callee.syntax())?; + if member_expr.member_name()?.text() != "pow" { + return None; + } + let object = member_expr.object().ok()?.omit_parentheses(); + let (reference, name) = global_identifier(&object)?; + if name.text() != "Math" { + return None; + } + model.binding(&reference).is_none().then_some(()) } fn diagnostic(ctx: &RuleContext, _: &Self::State) -> Option { diff --git a/crates/rome_js_analyze/src/analyzers/style/use_numeric_literals.rs b/crates/rome_js_analyze/src/analyzers/style/use_numeric_literals.rs index 0aa0c42d51e..5ecdb1c17e2 100644 --- a/crates/rome_js_analyze/src/analyzers/style/use_numeric_literals.rs +++ b/crates/rome_js_analyze/src/analyzers/style/use_numeric_literals.rs @@ -7,7 +7,8 @@ use rome_diagnostics::Applicability; use rome_js_factory::make; use rome_js_semantic::SemanticModel; use rome_js_syntax::{ - AnyJsExpression, AnyJsLiteralExpression, AnyJsMemberExpression, JsCallExpression, JsSyntaxToken, + global_identifier, AnyJsExpression, AnyJsLiteralExpression, AnyJsMemberExpression, + JsCallExpression, JsSyntaxToken, }; use rome_rowan::{AstNode, AstSeparatedList, BatchMutationExt}; @@ -83,10 +84,8 @@ impl Rule for UseNumericLiterals { fn action(ctx: &RuleContext, call: &Self::State) -> Option { let node = ctx.query(); let mut mutation = ctx.root().begin(); - let number = call.to_numeric_literal()?; let number = ast_utils::token_with_source_trivia(number, node); - mutation.replace_node_discard_trivia( AnyJsExpression::JsCallExpression(node.clone()), AnyJsExpression::AnyJsLiteralExpression( @@ -127,7 +126,6 @@ impl CallInfo { .as_js_number_literal_expression()? .as_number()?; let callee = get_callee(expr, model)?; - Some(CallInfo { callee, text, @@ -145,21 +143,21 @@ impl CallInfo { fn get_callee(expr: &JsCallExpression, model: &SemanticModel) -> Option<&'static str> { let callee = expr.callee().ok()?.omit_parentheses(); - if let Some(id) = callee.as_reference_identifier() { - if id.has_name("parseInt") && model.binding(&id).is_none() { + if let Some((reference, name)) = global_identifier(&callee) { + if name.text() == "parseInt" && model.binding(&reference).is_none() { return Some("parseInt()"); } + return None; } - let callee = AnyJsMemberExpression::cast_ref(callee.syntax())?; - let object = callee.get_object_reference_identifier()?; - if object.has_name("Number") - && model.binding(&object).is_none() - && callee.has_member_name("parseInt") - { + if callee.member_name()?.text() != "parseInt" { + return None; + } + let object = callee.object().ok()?.omit_parentheses(); + let (reference, name) = global_identifier(&object)?; + if name.text() == "Number" && model.binding(&reference).is_none() { return Some("Number.parseInt()"); } - None } diff --git a/crates/rome_js_analyze/src/analyzers/suspicious/no_prototype_builtins.rs b/crates/rome_js_analyze/src/analyzers/suspicious/no_prototype_builtins.rs index 92a2b5e9b57..74f95741edd 100644 --- a/crates/rome_js_analyze/src/analyzers/suspicious/no_prototype_builtins.rs +++ b/crates/rome_js_analyze/src/analyzers/suspicious/no_prototype_builtins.rs @@ -1,7 +1,7 @@ use rome_analyze::{context::RuleContext, declare_rule, Ast, Rule, RuleDiagnostic}; use rome_console::markup; -use rome_js_syntax::{AnyJsExpression, JsCallExpression, TextRange}; -use rome_rowan::AstNodeList; +use rome_js_syntax::{AnyJsMemberExpression, JsCallExpression, TextRange}; +use rome_rowan::AstNode; declare_rule! { /// Disallow direct use of `Object.prototype` builtins. @@ -60,47 +60,15 @@ impl Rule for NoPrototypeBuiltins { fn run(ctx: &RuleContext) -> Self::Signals { let call_expr = ctx.query(); let callee = call_expr.callee().ok()?.omit_parentheses(); - - match callee { - AnyJsExpression::JsComputedMemberExpression(expr) => { - let expr = expr.member().ok()?; - match expr { - AnyJsExpression::AnyJsLiteralExpression(expr) => { - let literal_expr = expr.as_js_string_literal_expression()?; - let token_text = literal_expr.inner_string_text().ok()?; - let token = literal_expr.value_token().ok()?; - - is_prototype_builtins(token_text.text()).then_some(RuleState { - prototype_builtins_method_name: token_text.to_string(), - text_range: token.text_range(), - }) - } - AnyJsExpression::JsTemplateExpression(expr) => { - let template_element = expr.as_fields().elements.first()?; - let template_chunk_token = template_element - .as_js_template_chunk_element()? - .template_chunk_token() - .ok()?; - let token_text = template_chunk_token.text(); - is_prototype_builtins(token_text).then_some(RuleState { - prototype_builtins_method_name: token_text.to_string(), - text_range: template_chunk_token.text_trimmed_range(), - }) - } - _ => None, - } - } - AnyJsExpression::JsStaticMemberExpression(expr) => { - let member = expr.as_fields().member.ok()?; - let value_token = member.as_js_name()?.value_token().ok()?; - let token_text = value_token.text(); - is_prototype_builtins(token_text).then_some(RuleState { - prototype_builtins_method_name: token_text.to_string(), - text_range: value_token.text_range(), - }) - } - _ => None, + if let Some(member_expr) = AnyJsMemberExpression::cast_ref(callee.syntax()) { + let member_name = member_expr.member_name()?; + let member_name_text = member_name.text(); + return is_prototype_builtins(member_name_text).then_some(RuleState { + prototype_builtins_method_name: member_name_text.to_string(), + text_range: member_name.token().text_trimmed_range(), + }); } + None } fn diagnostic(_ctx: &RuleContext, state: &Self::State) -> Option { diff --git a/crates/rome_js_analyze/src/react.rs b/crates/rome_js_analyze/src/react.rs index cf4a27b6f39..18844e9ff38 100644 --- a/crates/rome_js_analyze/src/react.rs +++ b/crates/rome_js_analyze/src/react.rs @@ -191,13 +191,15 @@ pub(crate) fn is_react_call_api( let expr = expression.omit_parentheses(); if let Some(callee) = AnyJsMemberExpression::cast_ref(expr.syntax()) { - let Some(object) = callee.get_object_reference_identifier() else { return false }; - if !callee.has_member_name(api_name) { + let Some(object) = callee.object().ok() else { return false }; + let Some(reference) = object.omit_parentheses().as_reference_identifier() else { return false }; + let Some(member_name) = callee.member_name() else { return false }; + if member_name.text() != api_name { return false; } - return match model.binding(&object) { + return match model.binding(&reference) { Some(decl) => is_react_export(decl, lib), - None => object.has_name(lib.global_name()), + None => reference.has_name(lib.global_name()), }; } diff --git a/crates/rome_js_analyze/src/react/hooks.rs b/crates/rome_js_analyze/src/react/hooks.rs index 26ac2b16b22..b1aa463e5d2 100644 --- a/crates/rome_js_analyze/src/react/hooks.rs +++ b/crates/rome_js_analyze/src/react/hooks.rs @@ -3,9 +3,10 @@ use std::collections::{HashMap, HashSet}; use rome_js_semantic::{Capture, Closure, ClosureExtensions, SemanticModel}; use rome_js_syntax::{ - binding_ext::AnyJsIdentifierBinding, AnyJsExpression, JsArrayBindingPattern, - JsArrayBindingPatternElementList, JsArrowFunctionExpression, JsCallExpression, - JsFunctionExpression, JsVariableDeclarator, TextRange, + binding_ext::AnyJsIdentifierBinding, static_value::StaticStringValue, AnyJsExpression, + AnyJsMemberExpression, JsArrayBindingPattern, JsArrayBindingPatternElementList, + JsArrowFunctionExpression, JsCallExpression, JsFunctionExpression, JsVariableDeclarator, + TextRange, }; use rome_rowan::AstNode; use serde::{Deserialize, Serialize}; @@ -139,17 +140,17 @@ pub(crate) fn react_hook_with_dependency( model: &SemanticModel, ) -> Option { let expression = call.callee().ok()?; - let name = match &expression { - AnyJsExpression::JsIdentifierExpression(identifier) => { - Some(identifier.name().ok()?.value_token().ok()?) - } - AnyJsExpression::JsStaticMemberExpression(member) => { - Some(member.member().ok()?.as_js_name()?.value_token().ok()?) - } - _ => None, + let name = if let AnyJsExpression::JsIdentifierExpression(identifier) = expression.clone() { + Some(StaticStringValue::Unquoted( + identifier.name().ok()?.value_token().ok()?, + )) + } else if let Some(member_expr) = AnyJsMemberExpression::cast_ref(expression.syntax()) { + Some(member_expr.member_name()?) + } else { + None }?; - let function_name_range = name.text_trimmed_range(); - let name = name.text_trimmed(); + let function_name_range = name.token().text_trimmed_range(); + let name = name.text(); // check if the hooks api is imported from the react library if HOOKS_WITH_DEPS_API.contains(&name) diff --git a/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_global_object_calls.rs b/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_global_object_calls.rs index 26c63b7cafc..a4190b965c2 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_global_object_calls.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/correctness/no_global_object_calls.rs @@ -1,9 +1,9 @@ use crate::semantic_services::Semantic; use rome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic}; use rome_console::markup; -use rome_js_syntax::{AnyJsExpression, JsCallExpression, JsNewExpression, JsSyntaxToken}; -use rome_rowan::{declare_node_union, AstNode, SyntaxResult}; -use std::str::FromStr; +use rome_js_syntax::{global_identifier, AnyJsExpression, JsCallExpression, JsNewExpression}; +use rome_rowan::{declare_node_union, SyntaxResult, TextRange}; +use std::{fmt::Display, str::FromStr}; declare_rule! { /// Disallow calling global object properties as functions @@ -92,70 +92,31 @@ declare_rule! { impl Rule for NoGlobalObjectCalls { type Query = Semantic; - type State = JsSyntaxToken; + type State = (NonCallableGlobals, TextRange); type Signals = Option; type Options = (); fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); let model = ctx.model(); - let callee = node.callee().ok()?.omit_parentheses(); - - match callee { - AnyJsExpression::JsIdentifierExpression(expression) => { - let reference = expression.name().ok()?; - let token = reference.value_token().ok()?; - - // verifies that the reference is not a local variable - let is_global_call = is_non_callable_globals(token.text_trimmed()) - && model.binding(&reference).is_none(); - is_global_call.then_some(reference.value_token().ok()?) - } - AnyJsExpression::JsStaticMemberExpression(expression) => { - let object = expression.object().ok()?.omit_parentheses(); - let reference = object.as_reference_identifier()?; - - let member = expression.member().ok()?; - let name = member.as_js_name()?; - let token = name.value_token().ok()?; - - // verifies that the reference is not a local variable - let is_global_call = is_non_callable_globals(token.text_trimmed()) - && reference.is_global_this() - && model.binding(&reference).is_none(); - - is_global_call.then_some(token) - } - AnyJsExpression::JsComputedMemberExpression(expression) => { - let object = expression.object().ok()?.omit_parentheses(); - let reference = object.as_reference_identifier()?; - let member = expression.member().ok()?.omit_parentheses(); - let literal = member - .as_any_js_literal_expression()? - .as_js_string_literal_expression()?; - let name = literal.inner_string_text().ok()?; - - // verifies that the reference is not a local variable - let is_global_call = is_non_callable_globals(name.text()) - && reference.is_global_this() - && model.binding(&reference).is_none(); - - is_global_call.then_some(literal.value_token().ok()?) - } - _ => None, - } + let (reference, name) = global_identifier(&callee)?; + let non_callable = NonCallableGlobals::from_str(name.text()).ok()?; + model + .binding(&reference) + .is_none() + .then_some((non_callable, name.token().text_trimmed_range())) } - fn diagnostic(ctx: &RuleContext, token: &Self::State) -> Option { - let node = ctx.query(); - let name = token.text_trimmed(); - + fn diagnostic( + _: &RuleContext, + (non_callable, range): &Self::State, + ) -> Option { Some(RuleDiagnostic::new( rule_category!(), - node.syntax().text_trimmed_range(), + range, markup! { - {name}" is not a function." + {non_callable.to_string()}" is not a function." }, )) } @@ -175,8 +136,8 @@ impl QueryNode { } } -#[derive(Debug, Eq, PartialEq)] -enum NonCallableGlobals { +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) enum NonCallableGlobals { Atomics, Json, Math, @@ -198,6 +159,15 @@ impl FromStr for NonCallableGlobals { } } -fn is_non_callable_globals(text: &str) -> bool { - NonCallableGlobals::from_str(text).is_ok() +impl Display for NonCallableGlobals { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let repr = match self { + NonCallableGlobals::Atomics => "Atomics", + NonCallableGlobals::Json => "Json", + NonCallableGlobals::Math => "Math", + NonCallableGlobals::Reflect => "Reflect", + NonCallableGlobals::Intl => "Intl", + }; + write!(f, "{}", repr) + } } diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs index ad7d15d5be7..1dfcf927e41 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs @@ -10,5 +10,6 @@ pub(crate) mod no_global_is_nan; pub(crate) mod use_camel_case; pub(crate) mod use_exhaustive_dependencies; pub(crate) mod use_hook_at_top_level; +pub(crate) mod use_is_nan; pub(crate) mod use_naming_convention; -declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_accumulating_spread :: NoAccumulatingSpread , self :: no_banned_types :: NoBannedTypes , self :: no_console_log :: NoConsoleLog , self :: no_constant_condition :: NoConstantCondition , self :: no_global_is_finite :: NoGlobalIsFinite , self :: no_global_is_nan :: NoGlobalIsNan , self :: use_camel_case :: UseCamelCase , self :: use_exhaustive_dependencies :: UseExhaustiveDependencies , self :: use_hook_at_top_level :: UseHookAtTopLevel , self :: use_naming_convention :: UseNamingConvention ,] } } +declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_accumulating_spread :: NoAccumulatingSpread , self :: no_banned_types :: NoBannedTypes , self :: no_console_log :: NoConsoleLog , self :: no_constant_condition :: NoConstantCondition , self :: no_global_is_finite :: NoGlobalIsFinite , self :: no_global_is_nan :: NoGlobalIsNan , self :: use_camel_case :: UseCamelCase , self :: use_exhaustive_dependencies :: UseExhaustiveDependencies , self :: use_hook_at_top_level :: UseHookAtTopLevel , self :: use_is_nan :: UseIsNan , self :: use_naming_convention :: UseNamingConvention ,] } } diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_accumulating_spread.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_accumulating_spread.rs index 9ff018173fe..291bab181ad 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_accumulating_spread.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_accumulating_spread.rs @@ -2,8 +2,8 @@ use rome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic}; use rome_console::markup; use rome_js_semantic::SemanticModel; use rome_js_syntax::{ - AnyJsFunction, JsCallArgumentList, JsCallArguments, JsCallExpression, JsFormalParameter, - JsParameterList, JsParameters, JsSpread, + AnyJsFunction, AnyJsMemberExpression, JsCallArgumentList, JsCallArguments, JsCallExpression, + JsFormalParameter, JsParameterList, JsParameters, JsSpread, }; use rome_rowan::AstNode; @@ -89,7 +89,6 @@ fn is_known_accumulator(node: &JsSpread, model: &SemanticModel) -> Option .as_js_identifier_expression()? .name() .ok()?; - let parameter = model .binding(&reference) .and_then(|declaration| declaration.syntax().parent()) @@ -102,21 +101,11 @@ fn is_known_accumulator(node: &JsSpread, model: &SemanticModel) -> Option .parent::() .and_then(|arguments| arguments.parent::()) .and_then(|arguments| arguments.parent::())?; - - let name = call_expression - .callee() - .ok()? - .as_js_static_member_expression()? - .member() - .ok()? - .as_js_name()? - .value_token() - .ok()?; - let name = name.text_trimmed(); - - if matches!(name, "reduce" | "reduceRight") { - Some(parameter.syntax().index() == 0) - } else { - None + let callee = call_expression.callee().ok()?; + let member_expression = AnyJsMemberExpression::cast_ref(callee.syntax())?; + let member_name = member_expression.member_name()?; + if !matches!(member_name.text(), "reduce" | "reduceRight") { + return None; } + Some(parameter.syntax().index() == 0) } diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_console_log.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_console_log.rs index ae4e354beb3..0dfa27a4bb5 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_console_log.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_console_log.rs @@ -1,7 +1,7 @@ use crate::semantic_services::Semantic; use rome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic}; use rome_console::markup; -use rome_js_syntax::JsCallExpression; +use rome_js_syntax::{global_identifier, AnyJsMemberExpression, JsCallExpression}; use rome_rowan::AstNode; declare_rule! { @@ -44,23 +44,16 @@ impl Rule for NoConsoleLog { let call_expression = ctx.query(); let model = ctx.model(); let callee = call_expression.callee().ok()?; - let callee = callee.as_js_static_member_expression()?; - - let member = callee.member().ok()?; - let object = callee.object().ok()?; - let object = object.as_js_identifier_expression()?; - - if member.as_js_name()?.value_token().ok()?.text_trimmed() == "log" - && object.name().ok()?.value_token().ok()?.text_trimmed() == "console" - { - let binding = object.name().ok()?; - let reference_binding = model.binding(&binding); - if reference_binding.is_none() { - return Some(()); - } + let member_expression = AnyJsMemberExpression::cast_ref(callee.syntax())?; + if member_expression.member_name()?.text() != "log" { + return None; } - - None + let object = member_expression.object().ok()?; + let (reference, name) = global_identifier(&object)?; + if name.text() != "console" { + return None; + } + model.binding(&reference).is_none().then_some(()) } fn diagnostic(ctx: &RuleContext, _: &Self::State) -> Option { diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_finite.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_finite.rs index bf1577d26e6..95f6614c866 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_finite.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_finite.rs @@ -3,7 +3,7 @@ use rome_analyze::{context::RuleContext, declare_rule, ActionCategory, Rule, Rul use rome_console::markup; use rome_diagnostics::Applicability; use rome_js_factory::make; -use rome_js_syntax::{AnyJsExpression, T}; +use rome_js_syntax::{global_identifier, AnyJsExpression, T}; use rome_rowan::{AstNode, BatchMutationExt}; declare_rule! { @@ -43,51 +43,11 @@ impl Rule for NoGlobalIsFinite { fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); let model = ctx.model(); - match node { - AnyJsExpression::JsIdentifierExpression(expression) => { - let name = expression.name().ok()?; - if name.has_name("isFinite") && model.binding(&name).is_none() { - return Some(()); - } - } - AnyJsExpression::JsStaticMemberExpression(expression) => { - let object_name = expression - .object() - .ok()? - .omit_parentheses() - .as_js_identifier_expression()? - .name() - .ok()?; - let member = expression.member().ok()?; - if object_name.is_global_this() - && model.binding(&object_name).is_none() - && member.as_js_name()?.value_token().ok()?.text_trimmed() == "isFinite" - { - return Some(()); - } - } - AnyJsExpression::JsComputedMemberExpression(expression) => { - let object_name = expression - .object() - .ok()? - .omit_parentheses() - .as_js_identifier_expression()? - .name() - .ok()?; - let member = expression.member().ok()?.omit_parentheses(); - let member = member - .as_any_js_literal_expression()? - .as_js_string_literal_expression()?; - if object_name.is_global_this() - && model.binding(&object_name).is_none() - && member.inner_string_text().ok()?.text() == "isFinite" - { - return Some(()); - } - } - _ => (), + let (reference, name) = global_identifier(node)?; + if name.text() != "isFinite" { + return None; } - None + model.binding(&reference).is_none().then_some(()) } fn diagnostic(ctx: &RuleContext, _: &Self::State) -> Option { diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_nan.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_nan.rs index f34fecf98c4..e409eb75888 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_nan.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_global_is_nan.rs @@ -3,7 +3,7 @@ use rome_analyze::{context::RuleContext, declare_rule, ActionCategory, Rule, Rul use rome_console::markup; use rome_diagnostics::Applicability; use rome_js_factory::make; -use rome_js_syntax::{AnyJsExpression, T}; +use rome_js_syntax::{global_identifier, AnyJsExpression, T}; use rome_rowan::{AstNode, BatchMutationExt}; declare_rule! { @@ -44,51 +44,11 @@ impl Rule for NoGlobalIsNan { fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); let model = ctx.model(); - match node { - AnyJsExpression::JsIdentifierExpression(expression) => { - let name = expression.name().ok()?; - if name.has_name("isNaN") && model.binding(&name).is_none() { - return Some(()); - } - } - AnyJsExpression::JsStaticMemberExpression(expression) => { - let object_name = expression - .object() - .ok()? - .omit_parentheses() - .as_js_identifier_expression()? - .name() - .ok()?; - let member = expression.member().ok()?; - if object_name.is_global_this() - && model.binding(&object_name).is_none() - && member.as_js_name()?.value_token().ok()?.text_trimmed() == "isNaN" - { - return Some(()); - } - } - AnyJsExpression::JsComputedMemberExpression(expression) => { - let object_name = expression - .object() - .ok()? - .omit_parentheses() - .as_js_identifier_expression()? - .name() - .ok()?; - let member = expression.member().ok()?.omit_parentheses(); - let member = member - .as_any_js_literal_expression()? - .as_js_string_literal_expression()?; - if object_name.is_global_this() - && model.binding(&object_name).is_none() - && member.inner_string_text().ok()?.text() == "isNaN" - { - return Some(()); - } - } - _ => (), + let (reference, name) = global_identifier(node)?; + if name.text() != "isNaN" { + return None; } - None + model.binding(&reference).is_none().then_some(()) } fn diagnostic(ctx: &RuleContext, _: &Self::State) -> Option { diff --git a/crates/rome_js_analyze/src/analyzers/nursery/use_is_nan.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery/use_is_nan.rs similarity index 68% rename from crates/rome_js_analyze/src/analyzers/nursery/use_is_nan.rs rename to crates/rome_js_analyze/src/semantic_analyzers/nursery/use_is_nan.rs index f3287a0a615..63e48846496 100644 --- a/crates/rome_js_analyze/src/analyzers/nursery/use_is_nan.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery/use_is_nan.rs @@ -1,10 +1,14 @@ use rome_analyze::context::RuleContext; -use rome_analyze::{declare_rule, Ast, Rule, RuleDiagnostic}; +use rome_analyze::{declare_rule, Rule, RuleDiagnostic}; +use rome_js_semantic::SemanticModel; use rome_js_syntax::{ - AnyJsExpression, JsBinaryExpression, JsCaseClause, JsSwitchStatement, TextRange, + global_identifier, AnyJsExpression, AnyJsMemberExpression, JsBinaryExpression, JsCaseClause, + JsSwitchStatement, TextRange, }; use rome_rowan::{declare_node_union, AstNode}; +use crate::semantic_services::Semantic; + declare_rule! { /// Require calls to `isNaN()` when checking for `NaN`. /// @@ -87,18 +91,19 @@ impl Message { } impl Rule for UseIsNan { - type Query = Ast; + type Query = Semantic; type State = RuleState; type Signals = Option; type Options = (); fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); - + let model = ctx.model(); match node { UseIsNanQuery::JsBinaryExpression(bin_expr) => { if bin_expr.is_comparison_operator() - && (has_nan(&bin_expr.left().ok()?)? || has_nan(&bin_expr.right().ok()?)?) + && (has_nan(bin_expr.left().ok()?, model) + || has_nan(bin_expr.right().ok()?, model)) { return Some(RuleState { message_id: Message::BinaryExpression, @@ -108,26 +113,25 @@ impl Rule for UseIsNan { } UseIsNanQuery::JsCaseClause(case_clause) => { let test = case_clause.test().ok()?; - - if has_nan(&test)? { + let range = test.range(); + if has_nan(test, model) { return Some(RuleState { message_id: Message::CaseClause, - range: test.range(), + range, }); } } UseIsNanQuery::JsSwitchStatement(switch_stmt) => { let discriminant = switch_stmt.discriminant().ok()?; - - if has_nan(&discriminant)? { + let range = discriminant.range(); + if has_nan(discriminant, model) { return Some(RuleState { message_id: Message::SwitchCase, - range: discriminant.range(), + range, }); } } } - None } @@ -141,48 +145,27 @@ impl Rule for UseIsNan { } /// Checks whether an expression has `NaN`, `Number.NaN`, or `Number['NaN']`. -fn has_nan(expr: &AnyJsExpression) -> Option { - Some(match expr.clone().omit_parentheses() { - AnyJsExpression::JsIdentifierExpression(id_expr) => { - id_expr.name().ok()?.value_token().ok()?.text_trimmed() == "NaN" - } - AnyJsExpression::JsStaticMemberExpression(member_expr) => { - let is_number_object = member_expr - .object() - .ok()? - .as_js_identifier_expression()? - .name() - .ok()? - .value_token() - .ok()? - .text_trimmed() - == "Number"; - let is_nan = member_expr - .member() - .ok()? - .as_js_name()? - .value_token() - .ok()? - .text_trimmed() - == "NaN"; - - is_number_object && is_nan - } - AnyJsExpression::JsComputedMemberExpression(member_expr) => { - let is_number_object = member_expr - .object() - .ok()? - .as_js_identifier_expression()? - .name() - .ok()? - .value_token() - .ok()? - .text_trimmed() - == "Number"; - let is_member_nan = member_expr.member().ok()?.is_string_constant("NaN"); - - is_number_object && is_member_nan - } - _ => false, - }) +fn has_nan(expr: AnyJsExpression, model: &SemanticModel) -> bool { + (|| { + let expr = expr.omit_parentheses(); + let reference = if let Some((reference, name)) = global_identifier(&expr) { + if name.text() != "NaN" { + return None; + } + reference + } else { + let member_expr = AnyJsMemberExpression::cast_ref(expr.syntax())?; + if member_expr.member_name()?.text() != "NaN" { + return None; + } + let member_object = member_expr.object().ok()?.omit_parentheses(); + let (reference, name) = global_identifier(&member_object.omit_parentheses())?; + if name.text() != "Number" { + return None; + } + reference + }; + model.binding(&reference).is_none().then_some(()) + })() + .is_some() } diff --git a/crates/rome_js_analyze/src/semantic_analyzers/suspicious/no_array_index_key.rs b/crates/rome_js_analyze/src/semantic_analyzers/suspicious/no_array_index_key.rs index bfb69145eb1..7ac025d73f5 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/suspicious/no_array_index_key.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/suspicious/no_array_index_key.rs @@ -4,9 +4,9 @@ use rome_analyze::context::RuleContext; use rome_analyze::{declare_rule, Rule, RuleDiagnostic}; use rome_console::markup; use rome_js_syntax::{ - AnyJsFunction, JsCallArgumentList, JsCallArguments, JsCallExpression, JsFormalParameter, - JsIdentifierBinding, JsObjectExpression, JsObjectMemberList, JsParameterList, JsParameters, - JsPropertyObjectMember, JsReferenceIdentifier, JsxAttribute, + AnyJsFunction, AnyJsMemberExpression, JsCallArgumentList, JsCallArguments, JsCallExpression, + JsFormalParameter, JsIdentifierBinding, JsObjectExpression, JsObjectMemberList, + JsParameterList, JsParameters, JsPropertyObjectMember, JsReferenceIdentifier, JsxAttribute, }; use rome_rowan::{declare_node_union, AstNode}; @@ -211,17 +211,10 @@ fn is_array_method_index( parameter: &JsFormalParameter, call_expression: &JsCallExpression, ) -> Option { - let name = call_expression - .callee() - .ok()? - .as_js_static_member_expression()? - .member() - .ok()? - .as_js_name()? - .value_token() - .ok()?; - let name = name.text_trimmed(); - + let member_expression = + AnyJsMemberExpression::cast_ref(call_expression.callee().ok()?.syntax())?; + let name = member_expression.member_name()?; + let name = name.text(); if matches!( name, "map" | "flatMap" | "from" | "forEach" | "filter" | "some" | "every" | "find" | "findIndex" diff --git a/crates/rome_js_analyze/tests/specs/correctness/noGlobalObjectCalls/invalid.js.snap b/crates/rome_js_analyze/tests/specs/correctness/noGlobalObjectCalls/invalid.js.snap index 0e692a4ee71..5243c5128b1 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noGlobalObjectCalls/invalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noGlobalObjectCalls/invalid.js.snap @@ -1,6 +1,5 @@ --- source: crates/rome_js_analyze/tests/spec_tests.rs -assertion_line: 96 expression: invalid.js --- # Input @@ -126,7 +125,7 @@ invalid.js:1:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ! Atomics is not a function. > 1 │ Atomics(); - │ ^^^^^^^^^ + │ ^^^^^^^ 2 │ JSON(); 3 │ Math(); @@ -136,11 +135,11 @@ invalid.js:1:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` invalid.js:2:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 1 │ Atomics(); > 2 │ JSON(); - │ ^^^^^^ + │ ^^^^ 3 │ Math(); 4 │ Reflect(); @@ -155,7 +154,7 @@ invalid.js:3:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ 1 │ Atomics(); 2 │ JSON(); > 3 │ Math(); - │ ^^^^^^ + │ ^^^^ 4 │ Reflect(); 5 │ Intl(); @@ -170,7 +169,7 @@ invalid.js:4:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ 2 │ JSON(); 3 │ Math(); > 4 │ Reflect(); - │ ^^^^^^^^^ + │ ^^^^^^^ 5 │ Intl(); 6 │ @@ -185,7 +184,7 @@ invalid.js:5:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ 3 │ Math(); 4 │ Reflect(); > 5 │ Intl(); - │ ^^^^^^ + │ ^^^^ 6 │ 7 │ (Atomics)(); @@ -193,14 +192,14 @@ invalid.js:5:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:7:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:7:2 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 5 │ Intl(); 6 │ > 7 │ (Atomics)(); - │ ^^^^^^^^^^^ + │ ^^^^^^^ 8 │ (JSON)(); 9 │ (Math)(); @@ -208,13 +207,13 @@ invalid.js:7:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:8:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:8:2 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 7 │ (Atomics)(); > 8 │ (JSON)(); - │ ^^^^^^^^ + │ ^^^^ 9 │ (Math)(); 10 │ (Reflect)(); @@ -222,14 +221,14 @@ invalid.js:8:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:9:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:9:2 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 7 │ (Atomics)(); 8 │ (JSON)(); > 9 │ (Math)(); - │ ^^^^^^^^ + │ ^^^^ 10 │ (Reflect)(); 11 │ (Intl)(); @@ -237,14 +236,14 @@ invalid.js:9:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:10:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:10:2 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 8 │ (JSON)(); 9 │ (Math)(); > 10 │ (Reflect)(); - │ ^^^^^^^^^^^ + │ ^^^^^^^ 11 │ (Intl)(); 12 │ @@ -252,14 +251,14 @@ invalid.js:10:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:11:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:11:2 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 9 │ (Math)(); 10 │ (Reflect)(); > 11 │ (Intl)(); - │ ^^^^^^^^ + │ ^^^^ 12 │ 13 │ new Atomics(); @@ -267,14 +266,14 @@ invalid.js:11:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:13:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:13:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 11 │ (Intl)(); 12 │ > 13 │ new Atomics(); - │ ^^^^^^^^^^^^^ + │ ^^^^^^^ 14 │ new JSON(); 15 │ new Math(); @@ -282,13 +281,13 @@ invalid.js:13:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:14:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:14:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 13 │ new Atomics(); > 14 │ new JSON(); - │ ^^^^^^^^^^ + │ ^^^^ 15 │ new Math(); 16 │ new Reflect(); @@ -296,14 +295,14 @@ invalid.js:14:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:15:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:15:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 13 │ new Atomics(); 14 │ new JSON(); > 15 │ new Math(); - │ ^^^^^^^^^^ + │ ^^^^ 16 │ new Reflect(); 17 │ new Intl(); @@ -311,14 +310,14 @@ invalid.js:15:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:16:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:16:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 14 │ new JSON(); 15 │ new Math(); > 16 │ new Reflect(); - │ ^^^^^^^^^^^^^ + │ ^^^^^^^ 17 │ new Intl(); 18 │ @@ -326,14 +325,14 @@ invalid.js:16:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:17:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:17:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 15 │ new Math(); 16 │ new Reflect(); > 17 │ new Intl(); - │ ^^^^^^^^^^ + │ ^^^^ 18 │ 19 │ new (Atomics)(); @@ -341,14 +340,14 @@ invalid.js:17:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:19:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:19:6 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 17 │ new Intl(); 18 │ > 19 │ new (Atomics)(); - │ ^^^^^^^^^^^^^^^ + │ ^^^^^^^ 20 │ new (JSON)(); 21 │ new (Math)(); @@ -356,13 +355,13 @@ invalid.js:19:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:20:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:20:6 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 19 │ new (Atomics)(); > 20 │ new (JSON)(); - │ ^^^^^^^^^^^^ + │ ^^^^ 21 │ new (Math)(); 22 │ new (Reflect)(); @@ -370,14 +369,14 @@ invalid.js:20:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:21:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:21:6 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 19 │ new (Atomics)(); 20 │ new (JSON)(); > 21 │ new (Math)(); - │ ^^^^^^^^^^^^ + │ ^^^^ 22 │ new (Reflect)(); 23 │ new (Intl)(); @@ -385,14 +384,14 @@ invalid.js:21:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:22:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:22:6 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 20 │ new (JSON)(); 21 │ new (Math)(); > 22 │ new (Reflect)(); - │ ^^^^^^^^^^^^^^^ + │ ^^^^^^^ 23 │ new (Intl)(); 24 │ @@ -400,14 +399,14 @@ invalid.js:22:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:23:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:23:6 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 21 │ new (Math)(); 22 │ new (Reflect)(); > 23 │ new (Intl)(); - │ ^^^^^^^^^^^^ + │ ^^^^ 24 │ 25 │ new Atomics; @@ -415,14 +414,14 @@ invalid.js:23:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:25:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:25:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 23 │ new (Intl)(); 24 │ > 25 │ new Atomics; - │ ^^^^^^^^^^^ + │ ^^^^^^^ 26 │ new JSON; 27 │ new Math; @@ -430,13 +429,13 @@ invalid.js:25:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:26:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:26:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 25 │ new Atomics; > 26 │ new JSON; - │ ^^^^^^^^ + │ ^^^^ 27 │ new Math; 28 │ new Reflect; @@ -444,14 +443,14 @@ invalid.js:26:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:27:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:27:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 25 │ new Atomics; 26 │ new JSON; > 27 │ new Math; - │ ^^^^^^^^ + │ ^^^^ 28 │ new Reflect; 29 │ new Intl; @@ -459,14 +458,14 @@ invalid.js:27:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:28:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:28:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 26 │ new JSON; 27 │ new Math; > 28 │ new Reflect; - │ ^^^^^^^^^^^ + │ ^^^^^^^ 29 │ new Intl; 30 │ @@ -474,14 +473,14 @@ invalid.js:28:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:29:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:29:5 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 27 │ new Math; 28 │ new Reflect; > 29 │ new Intl; - │ ^^^^^^^^ + │ ^^^^ 30 │ 31 │ // globalThis static member @@ -489,13 +488,13 @@ invalid.js:29:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:32:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:32:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 31 │ // globalThis static member > 32 │ globalThis.Atomics(); - │ ^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 33 │ globalThis.JSON(); 34 │ globalThis.Math(); @@ -503,14 +502,14 @@ invalid.js:32:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:33:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:33:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 31 │ // globalThis static member 32 │ globalThis.Atomics(); > 33 │ globalThis.JSON(); - │ ^^^^^^^^^^^^^^^^^ + │ ^^^^ 34 │ globalThis.Math(); 35 │ globalThis.Reflect(); @@ -518,14 +517,14 @@ invalid.js:33:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:34:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:34:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 32 │ globalThis.Atomics(); 33 │ globalThis.JSON(); > 34 │ globalThis.Math(); - │ ^^^^^^^^^^^^^^^^^ + │ ^^^^ 35 │ globalThis.Reflect(); 36 │ globalThis.Intl(); @@ -533,14 +532,14 @@ invalid.js:34:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:35:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:35:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 33 │ globalThis.JSON(); 34 │ globalThis.Math(); > 35 │ globalThis.Reflect(); - │ ^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 36 │ globalThis.Intl(); 37 │ @@ -548,14 +547,14 @@ invalid.js:35:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:36:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:36:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 34 │ globalThis.Math(); 35 │ globalThis.Reflect(); > 36 │ globalThis.Intl(); - │ ^^^^^^^^^^^^^^^^^ + │ ^^^^ 37 │ 38 │ (globalThis).Atomics(); @@ -563,14 +562,14 @@ invalid.js:36:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:38:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:38:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 36 │ globalThis.Intl(); 37 │ > 38 │ (globalThis).Atomics(); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 39 │ (globalThis).JSON(); 40 │ (globalThis).Math(); @@ -578,13 +577,13 @@ invalid.js:38:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:39:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:39:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 38 │ (globalThis).Atomics(); > 39 │ (globalThis).JSON(); - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 40 │ (globalThis).Math(); 41 │ (globalThis).Reflect(); @@ -592,14 +591,14 @@ invalid.js:39:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:40:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:40:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 38 │ (globalThis).Atomics(); 39 │ (globalThis).JSON(); > 40 │ (globalThis).Math(); - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 41 │ (globalThis).Reflect(); 42 │ (globalThis).Intl(); @@ -607,14 +606,14 @@ invalid.js:40:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:41:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:41:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 39 │ (globalThis).JSON(); 40 │ (globalThis).Math(); > 41 │ (globalThis).Reflect(); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 42 │ (globalThis).Intl(); 43 │ @@ -622,14 +621,14 @@ invalid.js:41:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:42:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:42:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 40 │ (globalThis).Math(); 41 │ (globalThis).Reflect(); > 42 │ (globalThis).Intl(); - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 43 │ 44 │ (globalThis.Atomics)(); @@ -637,14 +636,14 @@ invalid.js:42:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:44:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:44:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 42 │ (globalThis).Intl(); 43 │ > 44 │ (globalThis.Atomics)(); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 45 │ (globalThis.JSON)(); 46 │ (globalThis.Math)(); @@ -652,13 +651,13 @@ invalid.js:44:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:45:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:45:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 44 │ (globalThis.Atomics)(); > 45 │ (globalThis.JSON)(); - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 46 │ (globalThis.Math)(); 47 │ (globalThis.Reflect)(); @@ -666,14 +665,14 @@ invalid.js:45:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:46:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:46:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 44 │ (globalThis.Atomics)(); 45 │ (globalThis.JSON)(); > 46 │ (globalThis.Math)(); - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 47 │ (globalThis.Reflect)(); 48 │ (globalThis.Intl)(); @@ -681,14 +680,14 @@ invalid.js:46:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:47:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:47:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 45 │ (globalThis.JSON)(); 46 │ (globalThis.Math)(); > 47 │ (globalThis.Reflect)(); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 48 │ (globalThis.Intl)(); 49 │ @@ -696,14 +695,14 @@ invalid.js:47:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:48:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:48:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 46 │ (globalThis.Math)(); 47 │ (globalThis.Reflect)(); > 48 │ (globalThis.Intl)(); - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 49 │ 50 │ new globalThis.Atomics(); @@ -711,14 +710,14 @@ invalid.js:48:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:50:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:50:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 48 │ (globalThis.Intl)(); 49 │ > 50 │ new globalThis.Atomics(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 51 │ new globalThis.JSON(); 52 │ new globalThis.Math(); @@ -726,13 +725,13 @@ invalid.js:50:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:51:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:51:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 50 │ new globalThis.Atomics(); > 51 │ new globalThis.JSON(); - │ ^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 52 │ new globalThis.Math(); 53 │ new globalThis.Reflect(); @@ -740,14 +739,14 @@ invalid.js:51:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:52:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:52:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 50 │ new globalThis.Atomics(); 51 │ new globalThis.JSON(); > 52 │ new globalThis.Math(); - │ ^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 53 │ new globalThis.Reflect(); 54 │ new globalThis.Intl(); @@ -755,14 +754,14 @@ invalid.js:52:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:53:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:53:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 51 │ new globalThis.JSON(); 52 │ new globalThis.Math(); > 53 │ new globalThis.Reflect(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 54 │ new globalThis.Intl(); 55 │ @@ -770,14 +769,14 @@ invalid.js:53:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:54:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:54:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 52 │ new globalThis.Math(); 53 │ new globalThis.Reflect(); > 54 │ new globalThis.Intl(); - │ ^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 55 │ 56 │ new (globalThis.Atomics)(); @@ -785,14 +784,14 @@ invalid.js:54:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:56:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:56:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 54 │ new globalThis.Intl(); 55 │ > 56 │ new (globalThis.Atomics)(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 57 │ new (globalThis.JSON)(); 58 │ new (globalThis.Math)(); @@ -800,13 +799,13 @@ invalid.js:56:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:57:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:57:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 56 │ new (globalThis.Atomics)(); > 57 │ new (globalThis.JSON)(); - │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 58 │ new (globalThis.Math)(); 59 │ new (globalThis.Reflect)(); @@ -814,14 +813,14 @@ invalid.js:57:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:58:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:58:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 56 │ new (globalThis.Atomics)(); 57 │ new (globalThis.JSON)(); > 58 │ new (globalThis.Math)(); - │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 59 │ new (globalThis.Reflect)(); 60 │ new (globalThis.Intl)(); @@ -829,14 +828,14 @@ invalid.js:58:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:59:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:59:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 57 │ new (globalThis.JSON)(); 58 │ new (globalThis.Math)(); > 59 │ new (globalThis.Reflect)(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 60 │ new (globalThis.Intl)(); 61 │ @@ -844,14 +843,14 @@ invalid.js:59:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:60:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:60:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 58 │ new (globalThis.Math)(); 59 │ new (globalThis.Reflect)(); > 60 │ new (globalThis.Intl)(); - │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 61 │ 62 │ new globalThis.Atomics; @@ -859,14 +858,14 @@ invalid.js:60:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:62:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:62:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Atomics is not a function. 60 │ new (globalThis.Intl)(); 61 │ > 62 │ new globalThis.Atomics; - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 63 │ new globalThis.JSON; 64 │ new globalThis.Math; @@ -874,13 +873,13 @@ invalid.js:62:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:63:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:63:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! JSON is not a function. + ! Json is not a function. 62 │ new globalThis.Atomics; > 63 │ new globalThis.JSON; - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 64 │ new globalThis.Math; 65 │ new globalThis.Reflect; @@ -888,14 +887,14 @@ invalid.js:63:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:64:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:64:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Math is not a function. 62 │ new globalThis.Atomics; 63 │ new globalThis.JSON; > 64 │ new globalThis.Math; - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 65 │ new globalThis.Reflect; 66 │ new globalThis.Intl; @@ -903,14 +902,14 @@ invalid.js:64:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:65:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:65:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Reflect is not a function. 63 │ new globalThis.JSON; 64 │ new globalThis.Math; > 65 │ new globalThis.Reflect; - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^ 66 │ new globalThis.Intl; 67 │ @@ -918,14 +917,14 @@ invalid.js:65:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:66:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:66:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Intl is not a function. 64 │ new globalThis.Math; 65 │ new globalThis.Reflect; > 66 │ new globalThis.Intl; - │ ^^^^^^^^^^^^^^^^^^^ + │ ^^^^ 67 │ 68 │ // globalThis computed member @@ -933,13 +932,13 @@ invalid.js:66:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:69:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:69:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Atomics' is not a function. + ! Atomics is not a function. 68 │ // globalThis computed member > 69 │ globalThis['Atomics'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 70 │ globalThis['JSON'](); 71 │ globalThis['Math'](); @@ -947,14 +946,14 @@ invalid.js:69:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:70:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:70:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'JSON' is not a function. + ! Json is not a function. 68 │ // globalThis computed member 69 │ globalThis['Atomics'](); > 70 │ globalThis['JSON'](); - │ ^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 71 │ globalThis['Math'](); 72 │ globalThis['Reflect'](); @@ -962,14 +961,14 @@ invalid.js:70:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:71:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:71:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Math' is not a function. + ! Math is not a function. 69 │ globalThis['Atomics'](); 70 │ globalThis['JSON'](); > 71 │ globalThis['Math'](); - │ ^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 72 │ globalThis['Reflect'](); 73 │ globalThis['Intl'](); @@ -977,14 +976,14 @@ invalid.js:71:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:72:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:72:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Reflect' is not a function. + ! Reflect is not a function. 70 │ globalThis['JSON'](); 71 │ globalThis['Math'](); > 72 │ globalThis['Reflect'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 73 │ globalThis['Intl'](); 74 │ @@ -992,14 +991,14 @@ invalid.js:72:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:73:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:73:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Intl' is not a function. + ! Intl is not a function. 71 │ globalThis['Math'](); 72 │ globalThis['Reflect'](); > 73 │ globalThis['Intl'](); - │ ^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 74 │ 75 │ (globalThis)['Atomics'](); @@ -1007,14 +1006,14 @@ invalid.js:73:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:75:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:75:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Atomics' is not a function. + ! Atomics is not a function. 73 │ globalThis['Intl'](); 74 │ > 75 │ (globalThis)['Atomics'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 76 │ (globalThis)['JSON'](); 77 │ (globalThis)['Math'](); @@ -1022,13 +1021,13 @@ invalid.js:75:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:76:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:76:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'JSON' is not a function. + ! Json is not a function. 75 │ (globalThis)['Atomics'](); > 76 │ (globalThis)['JSON'](); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 77 │ (globalThis)['Math'](); 78 │ (globalThis)['Reflect'](); @@ -1036,14 +1035,14 @@ invalid.js:76:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:77:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:77:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Math' is not a function. + ! Math is not a function. 75 │ (globalThis)['Atomics'](); 76 │ (globalThis)['JSON'](); > 77 │ (globalThis)['Math'](); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 78 │ (globalThis)['Reflect'](); 79 │ (globalThis)['Intl'](); @@ -1051,14 +1050,14 @@ invalid.js:77:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:78:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:78:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Reflect' is not a function. + ! Reflect is not a function. 76 │ (globalThis)['JSON'](); 77 │ (globalThis)['Math'](); > 78 │ (globalThis)['Reflect'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 79 │ (globalThis)['Intl'](); 80 │ @@ -1066,14 +1065,14 @@ invalid.js:78:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:79:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:79:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Intl' is not a function. + ! Intl is not a function. 77 │ (globalThis)['Math'](); 78 │ (globalThis)['Reflect'](); > 79 │ (globalThis)['Intl'](); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 80 │ 81 │ (globalThis['Atomics'])(); @@ -1081,14 +1080,14 @@ invalid.js:79:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:81:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:81:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Atomics' is not a function. + ! Atomics is not a function. 79 │ (globalThis)['Intl'](); 80 │ > 81 │ (globalThis['Atomics'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 82 │ (globalThis['JSON'])(); 83 │ (globalThis['Math'])(); @@ -1096,13 +1095,13 @@ invalid.js:81:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:82:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:82:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'JSON' is not a function. + ! Json is not a function. 81 │ (globalThis['Atomics'])(); > 82 │ (globalThis['JSON'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 83 │ (globalThis['Math'])(); 84 │ (globalThis['Reflect'])(); @@ -1110,14 +1109,14 @@ invalid.js:82:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:83:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:83:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Math' is not a function. + ! Math is not a function. 81 │ (globalThis['Atomics'])(); 82 │ (globalThis['JSON'])(); > 83 │ (globalThis['Math'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 84 │ (globalThis['Reflect'])(); 85 │ (globalThis['Intl'])(); @@ -1125,14 +1124,14 @@ invalid.js:83:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:84:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:84:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Reflect' is not a function. + ! Reflect is not a function. 82 │ (globalThis['JSON'])(); 83 │ (globalThis['Math'])(); > 84 │ (globalThis['Reflect'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 85 │ (globalThis['Intl'])(); 86 │ @@ -1140,14 +1139,14 @@ invalid.js:84:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:85:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:85:13 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Intl' is not a function. + ! Intl is not a function. 83 │ (globalThis['Math'])(); 84 │ (globalThis['Reflect'])(); > 85 │ (globalThis['Intl'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 86 │ 87 │ (globalThis[('Atomics')])(); @@ -1155,14 +1154,14 @@ invalid.js:85:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:87:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:87:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Atomics' is not a function. + ! Atomics is not a function. 85 │ (globalThis['Intl'])(); 86 │ > 87 │ (globalThis[('Atomics')])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 88 │ (globalThis[('JSON')])(); 89 │ (globalThis[('Math')])(); @@ -1170,13 +1169,13 @@ invalid.js:87:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:88:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:88:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'JSON' is not a function. + ! Json is not a function. 87 │ (globalThis[('Atomics')])(); > 88 │ (globalThis[('JSON')])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 89 │ (globalThis[('Math')])(); 90 │ (globalThis[('Reflect')])(); @@ -1184,14 +1183,14 @@ invalid.js:88:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:89:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:89:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Math' is not a function. + ! Math is not a function. 87 │ (globalThis[('Atomics')])(); 88 │ (globalThis[('JSON')])(); > 89 │ (globalThis[('Math')])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 90 │ (globalThis[('Reflect')])(); 91 │ (globalThis[('Intl')])(); @@ -1199,14 +1198,14 @@ invalid.js:89:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:90:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:90:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Reflect' is not a function. + ! Reflect is not a function. 88 │ (globalThis[('JSON')])(); 89 │ (globalThis[('Math')])(); > 90 │ (globalThis[('Reflect')])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 91 │ (globalThis[('Intl')])(); 92 │ @@ -1214,14 +1213,14 @@ invalid.js:90:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:91:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:91:14 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Intl' is not a function. + ! Intl is not a function. 89 │ (globalThis[('Math')])(); 90 │ (globalThis[('Reflect')])(); > 91 │ (globalThis[('Intl')])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 92 │ 93 │ new globalThis['Atomics'](); @@ -1229,14 +1228,14 @@ invalid.js:91:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:93:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:93:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Atomics' is not a function. + ! Atomics is not a function. 91 │ (globalThis[('Intl')])(); 92 │ > 93 │ new globalThis['Atomics'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 94 │ new globalThis['JSON'](); 95 │ new globalThis['Math'](); @@ -1244,13 +1243,13 @@ invalid.js:93:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:94:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:94:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'JSON' is not a function. + ! Json is not a function. 93 │ new globalThis['Atomics'](); > 94 │ new globalThis['JSON'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 95 │ new globalThis['Math'](); 96 │ new globalThis['Reflect'](); @@ -1258,14 +1257,14 @@ invalid.js:94:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:95:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:95:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Math' is not a function. + ! Math is not a function. 93 │ new globalThis['Atomics'](); 94 │ new globalThis['JSON'](); > 95 │ new globalThis['Math'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 96 │ new globalThis['Reflect'](); 97 │ new globalThis['Intl'](); @@ -1273,14 +1272,14 @@ invalid.js:95:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:96:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:96:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Reflect' is not a function. + ! Reflect is not a function. 94 │ new globalThis['JSON'](); 95 │ new globalThis['Math'](); > 96 │ new globalThis['Reflect'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 97 │ new globalThis['Intl'](); 98 │ @@ -1288,14 +1287,14 @@ invalid.js:96:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:97:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:97:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Intl' is not a function. + ! Intl is not a function. 95 │ new globalThis['Math'](); 96 │ new globalThis['Reflect'](); > 97 │ new globalThis['Intl'](); - │ ^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 98 │ 99 │ new (globalThis['Atomics'])(); @@ -1303,14 +1302,14 @@ invalid.js:97:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:99:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:99:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Atomics' is not a function. + ! Atomics is not a function. 97 │ new globalThis['Intl'](); 98 │ > 99 │ new (globalThis['Atomics'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 100 │ new (globalThis['JSON'])(); 101 │ new (globalThis['Math'])(); @@ -1318,13 +1317,13 @@ invalid.js:99:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━ ``` ``` -invalid.js:100:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:100:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'JSON' is not a function. + ! Json is not a function. 99 │ new (globalThis['Atomics'])(); > 100 │ new (globalThis['JSON'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 101 │ new (globalThis['Math'])(); 102 │ new (globalThis['Reflect'])(); @@ -1332,14 +1331,14 @@ invalid.js:100:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:101:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:101:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Math' is not a function. + ! Math is not a function. 99 │ new (globalThis['Atomics'])(); 100 │ new (globalThis['JSON'])(); > 101 │ new (globalThis['Math'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 102 │ new (globalThis['Reflect'])(); 103 │ new (globalThis['Intl'])(); @@ -1347,14 +1346,14 @@ invalid.js:101:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:102:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:102:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Reflect' is not a function. + ! Reflect is not a function. 100 │ new (globalThis['JSON'])(); 101 │ new (globalThis['Math'])(); > 102 │ new (globalThis['Reflect'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 103 │ new (globalThis['Intl'])(); 104 │ @@ -1362,14 +1361,14 @@ invalid.js:102:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:103:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:103:17 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Intl' is not a function. + ! Intl is not a function. 101 │ new (globalThis['Math'])(); 102 │ new (globalThis['Reflect'])(); > 103 │ new (globalThis['Intl'])(); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 104 │ 105 │ new globalThis['Atomics']; @@ -1377,14 +1376,14 @@ invalid.js:103:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:105:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:105:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Atomics' is not a function. + ! Atomics is not a function. 103 │ new (globalThis['Intl'])(); 104 │ > 105 │ new globalThis['Atomics']; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 106 │ new globalThis['JSON']; 107 │ new globalThis['Math']; @@ -1392,13 +1391,13 @@ invalid.js:105:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:106:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:106:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'JSON' is not a function. + ! Json is not a function. 105 │ new globalThis['Atomics']; > 106 │ new globalThis['JSON']; - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 107 │ new globalThis['Math']; 108 │ new globalThis['Reflect']; @@ -1406,14 +1405,14 @@ invalid.js:106:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:107:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:107:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Math' is not a function. + ! Math is not a function. 105 │ new globalThis['Atomics']; 106 │ new globalThis['JSON']; > 107 │ new globalThis['Math']; - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 108 │ new globalThis['Reflect']; 109 │ new globalThis['Intl']; @@ -1421,14 +1420,14 @@ invalid.js:107:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:108:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:108:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Reflect' is not a function. + ! Reflect is not a function. 106 │ new globalThis['JSON']; 107 │ new globalThis['Math']; > 108 │ new globalThis['Reflect']; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^ 109 │ new globalThis['Intl']; 110 │ @@ -1436,14 +1435,14 @@ invalid.js:108:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━ ``` ``` -invalid.js:109:1 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:109:16 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! 'Intl' is not a function. + ! Intl is not a function. 107 │ new globalThis['Math']; 108 │ new globalThis['Reflect']; > 109 │ new globalThis['Intl']; - │ ^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 110 │ diff --git a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js index e5e5b1a285a..70f98b31165 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js +++ b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js @@ -6,6 +6,8 @@ globalThis.isFinite({}); (globalThis).isFinite({}); +globalThis.globalThis.window.isFinite({}); + globalThis["isFinite"]({}); (globalThis)[("isFinite")]({}); diff --git a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js.snap index 0a6743c4072..4c429055b8d 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsFinite/invalid.js.snap @@ -12,6 +12,8 @@ globalThis.isFinite({}); (globalThis).isFinite({}); +globalThis.globalThis.window.isFinite({}); + globalThis["isFinite"]({}); (globalThis)[("isFinite")]({}); @@ -109,7 +111,7 @@ invalid.js:7:1 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━ > 7 │ (globalThis).isFinite({}); │ ^^^^^^^^^^^^^^^^^^^^^ 8 │ - 9 │ globalThis["isFinite"]({}); + 9 │ globalThis.globalThis.window.isFinite({}); i See the MDN documentation for more details. @@ -120,7 +122,7 @@ invalid.js:7:1 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━ 7 │ - (globalThis).isFinite({}); 7 │ + (globalThis).Number.isFinite({}); 8 8 │ - 9 9 │ globalThis["isFinite"]({}); + 9 9 │ globalThis.globalThis.window.isFinite({}); ``` @@ -132,10 +134,10 @@ invalid.js:9:1 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━ 7 │ (globalThis).isFinite({}); 8 │ - > 9 │ globalThis["isFinite"]({}); - │ ^^^^^^^^^^^^^^^^^^^^^^ + > 9 │ globalThis.globalThis.window.isFinite({}); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10 │ - 11 │ (globalThis)[("isFinite")]({}); + 11 │ globalThis["isFinite"]({}); i See the MDN documentation for more details. @@ -143,10 +145,10 @@ invalid.js:9:1 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━ 7 7 │ (globalThis).isFinite({}); 8 8 │ - 9 │ - globalThis["isFinite"]({}); - 9 │ + globalThis.Number["isFinite"]({}); + 9 │ - globalThis.globalThis.window.isFinite({}); + 9 │ + globalThis.globalThis.window.Number.isFinite({}); 10 10 │ - 11 11 │ (globalThis)[("isFinite")]({}); + 11 11 │ globalThis["isFinite"]({}); ``` @@ -156,67 +158,93 @@ invalid.js:11:1 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━ ! isFinite is unsafe. It attempts a type coercion. Use Number.isFinite instead. - 9 │ globalThis["isFinite"]({}); + 9 │ globalThis.globalThis.window.isFinite({}); 10 │ - > 11 │ (globalThis)[("isFinite")]({}); - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + > 11 │ globalThis["isFinite"]({}); + │ ^^^^^^^^^^^^^^^^^^^^^^ + 12 │ + 13 │ (globalThis)[("isFinite")]({}); + + i See the MDN documentation for more details. + + i Suggested fix: Use Number.isFinite instead. + + 9 9 │ globalThis.globalThis.window.isFinite({}); + 10 10 │ + 11 │ - globalThis["isFinite"]({}); + 11 │ + globalThis.Number["isFinite"]({}); + 12 12 │ + 13 13 │ (globalThis)[("isFinite")]({}); + + +``` + +``` +invalid.js:13:1 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! isFinite is unsafe. It attempts a type coercion. Use Number.isFinite instead. + + 11 │ globalThis["isFinite"]({}); 12 │ - 13 │ function localIsNaN(isFinite) { + > 13 │ (globalThis)[("isFinite")]({}); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 14 │ + 15 │ function localIsNaN(isFinite) { i See the MDN documentation for more details. i Suggested fix: Use Number.isFinite instead. - 11 │ (globalThis).Number[("isFinite")]({}); + 13 │ (globalThis).Number[("isFinite")]({}); │ +++++++ ``` ``` -invalid.js:14:5 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:16:5 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! isFinite is unsafe. It attempts a type coercion. Use Number.isFinite instead. - 13 │ function localIsNaN(isFinite) { - > 14 │ globalThis.isFinite({}); + 15 │ function localIsNaN(isFinite) { + > 16 │ globalThis.isFinite({}); │ ^^^^^^^^^^^^^^^^^^^ - 15 │ } - 16 │ + 17 │ } + 18 │ i See the MDN documentation for more details. i Suggested fix: Use Number.isFinite instead. - 12 12 │ - 13 13 │ function localIsNaN(isFinite) { - 14 │ - ····globalThis.isFinite({}); - 14 │ + ····globalThis.Number.isFinite({}); - 15 15 │ } - 16 16 │ + 14 14 │ + 15 15 │ function localIsNaN(isFinite) { + 16 │ - ····globalThis.isFinite({}); + 16 │ + ····globalThis.Number.isFinite({}); + 17 17 │ } + 18 18 │ ``` ``` -invalid.js:17:12 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:19:12 lint/nursery/noGlobalIsFinite FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! isFinite is unsafe. It attempts a type coercion. Use Number.isFinite instead. - 15 │ } - 16 │ - > 17 │ localIsNaN(isFinite); - │ ^^^^^^^^ + 17 │ } 18 │ + > 19 │ localIsNaN(isFinite); + │ ^^^^^^^^ + 20 │ i See the MDN documentation for more details. i Suggested fix: Use Number.isFinite instead. - 15 15 │ } - 16 16 │ - 17 │ - localIsNaN(isFinite); - 17 │ + localIsNaN(Number.isFinite); + 17 17 │ } 18 18 │ + 19 │ - localIsNaN(isFinite); + 19 │ + localIsNaN(Number.isFinite); + 20 20 │ ``` diff --git a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js index 72cb6eda3e3..6ce78e14793 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js +++ b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js @@ -6,6 +6,8 @@ globalThis.isNaN({}); (globalThis).isNaN({}); +globalThis.globalThis.window.isNaN({}); + globalThis["isNaN"]({}); (globalThis)[("isNaN")]({}); diff --git a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js.snap index dfdcb4b98ab..9e29c43fc7f 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noGlobalIsNan/invalid.js.snap @@ -12,6 +12,8 @@ globalThis.isNaN({}); (globalThis).isNaN({}); +globalThis.globalThis.window.isNaN({}); + globalThis["isNaN"]({}); (globalThis)[("isNaN")]({}); @@ -109,7 +111,7 @@ invalid.js:7:1 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━ > 7 │ (globalThis).isNaN({}); │ ^^^^^^^^^^^^^^^^^^ 8 │ - 9 │ globalThis["isNaN"]({}); + 9 │ globalThis.globalThis.window.isNaN({}); i See the MDN documentation for more details. @@ -120,7 +122,7 @@ invalid.js:7:1 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━ 7 │ - (globalThis).isNaN({}); 7 │ + (globalThis).Number.isNaN({}); 8 8 │ - 9 9 │ globalThis["isNaN"]({}); + 9 9 │ globalThis.globalThis.window.isNaN({}); ``` @@ -132,10 +134,10 @@ invalid.js:9:1 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━ 7 │ (globalThis).isNaN({}); 8 │ - > 9 │ globalThis["isNaN"]({}); - │ ^^^^^^^^^^^^^^^^^^^ + > 9 │ globalThis.globalThis.window.isNaN({}); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10 │ - 11 │ (globalThis)[("isNaN")]({}); + 11 │ globalThis["isNaN"]({}); i See the MDN documentation for more details. @@ -143,10 +145,10 @@ invalid.js:9:1 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━ 7 7 │ (globalThis).isNaN({}); 8 8 │ - 9 │ - globalThis["isNaN"]({}); - 9 │ + globalThis.Number["isNaN"]({}); + 9 │ - globalThis.globalThis.window.isNaN({}); + 9 │ + globalThis.globalThis.window.Number.isNaN({}); 10 10 │ - 11 11 │ (globalThis)[("isNaN")]({}); + 11 11 │ globalThis["isNaN"]({}); ``` @@ -156,67 +158,93 @@ invalid.js:11:1 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━ ! isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead. - 9 │ globalThis["isNaN"]({}); + 9 │ globalThis.globalThis.window.isNaN({}); 10 │ - > 11 │ (globalThis)[("isNaN")]({}); - │ ^^^^^^^^^^^^^^^^^^^^^^^ + > 11 │ globalThis["isNaN"]({}); + │ ^^^^^^^^^^^^^^^^^^^ + 12 │ + 13 │ (globalThis)[("isNaN")]({}); + + i See the MDN documentation for more details. + + i Suggested fix: Use Number.isNaN instead. + + 9 9 │ globalThis.globalThis.window.isNaN({}); + 10 10 │ + 11 │ - globalThis["isNaN"]({}); + 11 │ + globalThis.Number["isNaN"]({}); + 12 12 │ + 13 13 │ (globalThis)[("isNaN")]({}); + + +``` + +``` +invalid.js:13:1 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead. + + 11 │ globalThis["isNaN"]({}); 12 │ - 13 │ function localIsNaN(isNaN) { + > 13 │ (globalThis)[("isNaN")]({}); + │ ^^^^^^^^^^^^^^^^^^^^^^^ + 14 │ + 15 │ function localIsNaN(isNaN) { i See the MDN documentation for more details. i Suggested fix: Use Number.isNaN instead. - 11 │ (globalThis).Number[("isNaN")]({}); + 13 │ (globalThis).Number[("isNaN")]({}); │ +++++++ ``` ``` -invalid.js:14:5 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:16:5 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead. - 13 │ function localIsNaN(isNaN) { - > 14 │ globalThis.isNaN({}); + 15 │ function localIsNaN(isNaN) { + > 16 │ globalThis.isNaN({}); │ ^^^^^^^^^^^^^^^^ - 15 │ } - 16 │ + 17 │ } + 18 │ i See the MDN documentation for more details. i Suggested fix: Use Number.isNaN instead. - 12 12 │ - 13 13 │ function localIsNaN(isNaN) { - 14 │ - ····globalThis.isNaN({}); - 14 │ + ····globalThis.Number.isNaN({}); - 15 15 │ } - 16 16 │ + 14 14 │ + 15 15 │ function localIsNaN(isNaN) { + 16 │ - ····globalThis.isNaN({}); + 16 │ + ····globalThis.Number.isNaN({}); + 17 17 │ } + 18 18 │ ``` ``` -invalid.js:17:12 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:19:12 lint/nursery/noGlobalIsNan FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead. - 15 │ } - 16 │ - > 17 │ localIsNaN(isNaN); - │ ^^^^^ + 17 │ } 18 │ + > 19 │ localIsNaN(isNaN); + │ ^^^^^ + 20 │ i See the MDN documentation for more details. i Suggested fix: Use Number.isNaN instead. - 15 15 │ } - 16 16 │ - 17 │ - localIsNaN(isNaN); - 17 │ + localIsNaN(Number.isNaN); + 17 17 │ } 18 18 │ + 19 │ - localIsNaN(isNaN); + 19 │ + localIsNaN(Number.isNaN); + 20 20 │ ``` diff --git a/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js b/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js index 6c41ede391d..1b691f71f6d 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js +++ b/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js @@ -33,6 +33,10 @@ Number.NaN >= "abc"; x === Number?.NaN; x === Number['NaN']; +123 == globalThis.NaN; +123 == window.NaN; +123 == globalThis.Number.NaN; + // switch-case switch(NaN) { case foo: break; } switch(NaN) {} diff --git a/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js.snap b/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js.snap index 9f4e99c87e9..0c8e40a78f4 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/useIsNan/invalid.js.snap @@ -1,6 +1,5 @@ --- source: crates/rome_js_analyze/tests/spec_tests.rs -assertion_line: 92 expression: invalid.js --- # Input @@ -40,6 +39,10 @@ Number.NaN >= "abc"; x === Number?.NaN; x === Number['NaN']; +123 == globalThis.NaN; +123 == window.NaN; +123 == globalThis.Number.NaN; + // switch-case switch(NaN) { case foo: break; } switch(NaN) {} @@ -569,394 +572,438 @@ invalid.js:34:1 lint/nursery/useIsNan ━━━━━━━━━━━━━━ > 34 │ x === Number['NaN']; │ ^^^^^^^^^^^^^^^^^^^ 35 │ - 36 │ // switch-case + 36 │ 123 == globalThis.NaN; + + +``` + +``` +invalid.js:36:1 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use the Number.isNaN function to compare with NaN. + + 34 │ x === Number['NaN']; + 35 │ + > 36 │ 123 == globalThis.NaN; + │ ^^^^^^^^^^^^^^^^^^^^^ + 37 │ 123 == window.NaN; + 38 │ 123 == globalThis.Number.NaN; + + +``` + +``` +invalid.js:37:1 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use the Number.isNaN function to compare with NaN. + + 36 │ 123 == globalThis.NaN; + > 37 │ 123 == window.NaN; + │ ^^^^^^^^^^^^^^^^^ + 38 │ 123 == globalThis.Number.NaN; + 39 │ + + +``` + +``` +invalid.js:38:1 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use the Number.isNaN function to compare with NaN. + + 36 │ 123 == globalThis.NaN; + 37 │ 123 == window.NaN; + > 38 │ 123 == globalThis.Number.NaN; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 39 │ + 40 │ // switch-case ``` ``` -invalid.js:37:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:41:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 36 │ // switch-case - > 37 │ switch(NaN) { case foo: break; } + 40 │ // switch-case + > 41 │ switch(NaN) { case foo: break; } │ ^^^ - 38 │ switch(NaN) {} - 39 │ switch(foo) { case NaN: break; } + 42 │ switch(NaN) {} + 43 │ switch(foo) { case NaN: break; } ``` ``` -invalid.js:38:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:42:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 36 │ // switch-case - 37 │ switch(NaN) { case foo: break; } - > 38 │ switch(NaN) {} + 40 │ // switch-case + 41 │ switch(NaN) { case foo: break; } + > 42 │ switch(NaN) {} │ ^^^ - 39 │ switch(foo) { case NaN: break; } - 40 │ switch(NaN) { default: break; } + 43 │ switch(foo) { case NaN: break; } + 44 │ switch(NaN) { default: break; } ``` ``` -invalid.js:39:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:43:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 37 │ switch(NaN) { case foo: break; } - 38 │ switch(NaN) {} - > 39 │ switch(foo) { case NaN: break; } + 41 │ switch(NaN) { case foo: break; } + 42 │ switch(NaN) {} + > 43 │ switch(foo) { case NaN: break; } │ ^^^ - 40 │ switch(NaN) { default: break; } - 41 │ switch(NaN) { case foo: break; default: break; } + 44 │ switch(NaN) { default: break; } + 45 │ switch(NaN) { case foo: break; default: break; } ``` ``` -invalid.js:40:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:44:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 38 │ switch(NaN) {} - 39 │ switch(foo) { case NaN: break; } - > 40 │ switch(NaN) { default: break; } + 42 │ switch(NaN) {} + 43 │ switch(foo) { case NaN: break; } + > 44 │ switch(NaN) { default: break; } │ ^^^ - 41 │ switch(NaN) { case foo: break; default: break; } - 42 │ switch(foo) { case NaN: } + 45 │ switch(NaN) { case foo: break; default: break; } + 46 │ switch(foo) { case NaN: } ``` ``` -invalid.js:41:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:45:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 39 │ switch(foo) { case NaN: break; } - 40 │ switch(NaN) { default: break; } - > 41 │ switch(NaN) { case foo: break; default: break; } + 43 │ switch(foo) { case NaN: break; } + 44 │ switch(NaN) { default: break; } + > 45 │ switch(NaN) { case foo: break; default: break; } │ ^^^ - 42 │ switch(foo) { case NaN: } - 43 │ switch(foo) { case (NaN): break; } + 46 │ switch(foo) { case NaN: } + 47 │ switch(foo) { case (NaN): break; } ``` ``` -invalid.js:42:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:46:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 40 │ switch(NaN) { default: break; } - 41 │ switch(NaN) { case foo: break; default: break; } - > 42 │ switch(foo) { case NaN: } + 44 │ switch(NaN) { default: break; } + 45 │ switch(NaN) { case foo: break; default: break; } + > 46 │ switch(foo) { case NaN: } │ ^^^ - 43 │ switch(foo) { case (NaN): break; } - 44 │ switch(foo) { case bar: break; case NaN: break; default: break; } + 47 │ switch(foo) { case (NaN): break; } + 48 │ switch(foo) { case bar: break; case NaN: break; default: break; } ``` ``` -invalid.js:43:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:47:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 41 │ switch(NaN) { case foo: break; default: break; } - 42 │ switch(foo) { case NaN: } - > 43 │ switch(foo) { case (NaN): break; } + 45 │ switch(NaN) { case foo: break; default: break; } + 46 │ switch(foo) { case NaN: } + > 47 │ switch(foo) { case (NaN): break; } │ ^^^^^ - 44 │ switch(foo) { case bar: break; case NaN: break; default: break; } - 45 │ switch(foo) { case bar: case NaN: default: break; } + 48 │ switch(foo) { case bar: break; case NaN: break; default: break; } + 49 │ switch(foo) { case bar: case NaN: default: break; } ``` ``` -invalid.js:44:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:48:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 42 │ switch(foo) { case NaN: } - 43 │ switch(foo) { case (NaN): break; } - > 44 │ switch(foo) { case bar: break; case NaN: break; default: break; } + 46 │ switch(foo) { case NaN: } + 47 │ switch(foo) { case (NaN): break; } + > 48 │ switch(foo) { case bar: break; case NaN: break; default: break; } │ ^^^ - 45 │ switch(foo) { case bar: case NaN: default: break; } - 46 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } + 49 │ switch(foo) { case bar: case NaN: default: break; } + 50 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } ``` ``` -invalid.js:45:30 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:49:30 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 43 │ switch(foo) { case (NaN): break; } - 44 │ switch(foo) { case bar: break; case NaN: break; default: break; } - > 45 │ switch(foo) { case bar: case NaN: default: break; } + 47 │ switch(foo) { case (NaN): break; } + 48 │ switch(foo) { case bar: break; case NaN: break; default: break; } + > 49 │ switch(foo) { case bar: case NaN: default: break; } │ ^^^ - 46 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } - 47 │ switch(NaN) { case NaN: break; } + 50 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } + 51 │ switch(NaN) { case NaN: break; } ``` ``` -invalid.js:46:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:50:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 44 │ switch(foo) { case bar: break; case NaN: break; default: break; } - 45 │ switch(foo) { case bar: case NaN: default: break; } - > 46 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } + 48 │ switch(foo) { case bar: break; case NaN: break; default: break; } + 49 │ switch(foo) { case bar: case NaN: default: break; } + > 50 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } │ ^^^ - 47 │ switch(NaN) { case NaN: break; } - 48 │ switch(foo) { case Number.NaN: break; } + 51 │ switch(NaN) { case NaN: break; } + 52 │ switch(foo) { case Number.NaN: break; } ``` ``` -invalid.js:46:71 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:50:71 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 44 │ switch(foo) { case bar: break; case NaN: break; default: break; } - 45 │ switch(foo) { case bar: case NaN: default: break; } - > 46 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } + 48 │ switch(foo) { case bar: break; case NaN: break; default: break; } + 49 │ switch(foo) { case bar: case NaN: default: break; } + > 50 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } │ ^^^ - 47 │ switch(NaN) { case NaN: break; } - 48 │ switch(foo) { case Number.NaN: break; } + 51 │ switch(NaN) { case NaN: break; } + 52 │ switch(foo) { case Number.NaN: break; } ``` ``` -invalid.js:47:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:51:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 45 │ switch(foo) { case bar: case NaN: default: break; } - 46 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } - > 47 │ switch(NaN) { case NaN: break; } + 49 │ switch(foo) { case bar: case NaN: default: break; } + 50 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } + > 51 │ switch(NaN) { case NaN: break; } │ ^^^ - 48 │ switch(foo) { case Number.NaN: break; } - 49 │ switch(Number.NaN) { case foo: break; } + 52 │ switch(foo) { case Number.NaN: break; } + 53 │ switch(Number.NaN) { case foo: break; } ``` ``` -invalid.js:47:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:51:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 45 │ switch(foo) { case bar: case NaN: default: break; } - 46 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } - > 47 │ switch(NaN) { case NaN: break; } + 49 │ switch(foo) { case bar: case NaN: default: break; } + 50 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } + > 51 │ switch(NaN) { case NaN: break; } │ ^^^ - 48 │ switch(foo) { case Number.NaN: break; } - 49 │ switch(Number.NaN) { case foo: break; } + 52 │ switch(foo) { case Number.NaN: break; } + 53 │ switch(Number.NaN) { case foo: break; } ``` ``` -invalid.js:48:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:52:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 46 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } - 47 │ switch(NaN) { case NaN: break; } - > 48 │ switch(foo) { case Number.NaN: break; } + 50 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case NaN: break; } + 51 │ switch(NaN) { case NaN: break; } + > 52 │ switch(foo) { case Number.NaN: break; } │ ^^^^^^^^^^ - 49 │ switch(Number.NaN) { case foo: break; } - 50 │ switch(Number.NaN) {} + 53 │ switch(Number.NaN) { case foo: break; } + 54 │ switch(Number.NaN) {} ``` ``` -invalid.js:49:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:53:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 47 │ switch(NaN) { case NaN: break; } - 48 │ switch(foo) { case Number.NaN: break; } - > 49 │ switch(Number.NaN) { case foo: break; } + 51 │ switch(NaN) { case NaN: break; } + 52 │ switch(foo) { case Number.NaN: break; } + > 53 │ switch(Number.NaN) { case foo: break; } │ ^^^^^^^^^^ - 50 │ switch(Number.NaN) {} - 51 │ switch(Number.NaN) { default: break; } + 54 │ switch(Number.NaN) {} + 55 │ switch(Number.NaN) { default: break; } ``` ``` -invalid.js:50:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:54:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 48 │ switch(foo) { case Number.NaN: break; } - 49 │ switch(Number.NaN) { case foo: break; } - > 50 │ switch(Number.NaN) {} + 52 │ switch(foo) { case Number.NaN: break; } + 53 │ switch(Number.NaN) { case foo: break; } + > 54 │ switch(Number.NaN) {} │ ^^^^^^^^^^ - 51 │ switch(Number.NaN) { default: break; } - 52 │ switch(Number.NaN) { case foo: break; default: break; } + 55 │ switch(Number.NaN) { default: break; } + 56 │ switch(Number.NaN) { case foo: break; default: break; } ``` ``` -invalid.js:51:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:55:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 49 │ switch(Number.NaN) { case foo: break; } - 50 │ switch(Number.NaN) {} - > 51 │ switch(Number.NaN) { default: break; } + 53 │ switch(Number.NaN) { case foo: break; } + 54 │ switch(Number.NaN) {} + > 55 │ switch(Number.NaN) { default: break; } │ ^^^^^^^^^^ - 52 │ switch(Number.NaN) { case foo: break; default: break; } - 53 │ switch(foo) { case Number.NaN: } + 56 │ switch(Number.NaN) { case foo: break; default: break; } + 57 │ switch(foo) { case Number.NaN: } ``` ``` -invalid.js:52:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:56:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 50 │ switch(Number.NaN) {} - 51 │ switch(Number.NaN) { default: break; } - > 52 │ switch(Number.NaN) { case foo: break; default: break; } + 54 │ switch(Number.NaN) {} + 55 │ switch(Number.NaN) { default: break; } + > 56 │ switch(Number.NaN) { case foo: break; default: break; } │ ^^^^^^^^^^ - 53 │ switch(foo) { case Number.NaN: } - 54 │ switch(foo) { case (Number.NaN): break; } + 57 │ switch(foo) { case Number.NaN: } + 58 │ switch(foo) { case (Number.NaN): break; } ``` ``` -invalid.js:53:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:57:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 51 │ switch(Number.NaN) { default: break; } - 52 │ switch(Number.NaN) { case foo: break; default: break; } - > 53 │ switch(foo) { case Number.NaN: } + 55 │ switch(Number.NaN) { default: break; } + 56 │ switch(Number.NaN) { case foo: break; default: break; } + > 57 │ switch(foo) { case Number.NaN: } │ ^^^^^^^^^^ - 54 │ switch(foo) { case (Number.NaN): break; } - 55 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } + 58 │ switch(foo) { case (Number.NaN): break; } + 59 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } ``` ``` -invalid.js:54:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:58:20 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 52 │ switch(Number.NaN) { case foo: break; default: break; } - 53 │ switch(foo) { case Number.NaN: } - > 54 │ switch(foo) { case (Number.NaN): break; } + 56 │ switch(Number.NaN) { case foo: break; default: break; } + 57 │ switch(foo) { case Number.NaN: } + > 58 │ switch(foo) { case (Number.NaN): break; } │ ^^^^^^^^^^^^ - 55 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } - 56 │ switch(foo) { case bar: case Number.NaN: default: break; } + 59 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } + 60 │ switch(foo) { case bar: case Number.NaN: default: break; } ``` ``` -invalid.js:55:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:59:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 53 │ switch(foo) { case Number.NaN: } - 54 │ switch(foo) { case (Number.NaN): break; } - > 55 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } + 57 │ switch(foo) { case Number.NaN: } + 58 │ switch(foo) { case (Number.NaN): break; } + > 59 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } │ ^^^^^^^^^^ - 56 │ switch(foo) { case bar: case Number.NaN: default: break; } - 57 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } + 60 │ switch(foo) { case bar: case Number.NaN: default: break; } + 61 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } ``` ``` -invalid.js:56:30 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:60:30 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 54 │ switch(foo) { case (Number.NaN): break; } - 55 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } - > 56 │ switch(foo) { case bar: case Number.NaN: default: break; } + 58 │ switch(foo) { case (Number.NaN): break; } + 59 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } + > 60 │ switch(foo) { case bar: case Number.NaN: default: break; } │ ^^^^^^^^^^ - 57 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } - 58 │ switch(Number.NaN) { case Number.NaN: break; } + 61 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } + 62 │ switch(Number.NaN) { case Number.NaN: break; } ``` ``` -invalid.js:57:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:61:37 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 55 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } - 56 │ switch(foo) { case bar: case Number.NaN: default: break; } - > 57 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } + 59 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } + 60 │ switch(foo) { case bar: case Number.NaN: default: break; } + > 61 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } │ ^^^ - 58 │ switch(Number.NaN) { case Number.NaN: break; } - 59 │ + 62 │ switch(Number.NaN) { case Number.NaN: break; } + 63 │ ``` ``` -invalid.js:57:71 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:61:71 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 55 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } - 56 │ switch(foo) { case bar: case Number.NaN: default: break; } - > 57 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } + 59 │ switch(foo) { case bar: break; case Number.NaN: break; default: break; } + 60 │ switch(foo) { case bar: case Number.NaN: default: break; } + > 61 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } │ ^^^^^^^^^^ - 58 │ switch(Number.NaN) { case Number.NaN: break; } - 59 │ + 62 │ switch(Number.NaN) { case Number.NaN: break; } + 63 │ ``` ``` -invalid.js:58:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:62:8 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'switch(NaN)' can never match a case clause. Use Number.isNaN instead of the switch. - 56 │ switch(foo) { case bar: case Number.NaN: default: break; } - 57 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } - > 58 │ switch(Number.NaN) { case Number.NaN: break; } + 60 │ switch(foo) { case bar: case Number.NaN: default: break; } + 61 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } + > 62 │ switch(Number.NaN) { case Number.NaN: break; } │ ^^^^^^^^^^ - 59 │ + 63 │ ``` ``` -invalid.js:58:27 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:62:27 lint/nursery/useIsNan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! 'case NaN' can never match. Use Number.isNaN before the switch. - 56 │ switch(foo) { case bar: case Number.NaN: default: break; } - 57 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } - > 58 │ switch(Number.NaN) { case Number.NaN: break; } + 60 │ switch(foo) { case bar: case Number.NaN: default: break; } + 61 │ switch(foo) { case bar: break; case NaN: break; case baz: break; case Number.NaN: break; } + > 62 │ switch(Number.NaN) { case Number.NaN: break; } │ ^^^^^^^^^^ - 59 │ + 63 │ ``` diff --git a/crates/rome_js_analyze/tests/specs/nursery/useIsNan/valid.js.snap b/crates/rome_js_analyze/tests/specs/nursery/useIsNan/valid.js.snap index 795ca6dbeac..4f041396331 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/useIsNan/valid.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/useIsNan/valid.js.snap @@ -1,6 +1,5 @@ --- source: crates/rome_js_analyze/tests/spec_tests.rs -assertion_line: 92 expression: valid.js --- # Input diff --git a/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js b/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js index 44a8766857c..aab9c3e49b5 100644 --- a/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js +++ b/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js @@ -63,3 +63,11 @@ parseInt('1_0', 2); Number.parseInt('5_000', 8); parseInt('0_1', 16); Number.parseInt('0_0', 16); +globalThis.parseInt('11'/**/, 2); +globalThis.Number.parseInt('11'/**/, 2); +globalThis.globalThis.parseInt('11'/**/, 2); +globalThis.globalThis.Number.parseInt('11'/**/, 2); +window.parseInt('11'/**/, 2); +window.Number.parseInt('11'/**/, 2); +window.window.parseInt('11'/**/, 2); +window.window.Number.parseInt('11'/**/, 2); \ No newline at end of file diff --git a/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js.snap b/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js.snap index b7bd05cac22..4f926bf536b 100644 --- a/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/style/useNumericLiterals/invalid.js.snap @@ -69,7 +69,14 @@ parseInt('1_0', 2); Number.parseInt('5_000', 8); parseInt('0_1', 16); Number.parseInt('0_0', 16); - +globalThis.parseInt('11'/**/, 2); +globalThis.Number.parseInt('11'/**/, 2); +globalThis.globalThis.parseInt('11'/**/, 2); +globalThis.globalThis.Number.parseInt('11'/**/, 2); +window.parseInt('11'/**/, 2); +window.Number.parseInt('11'/**/, 2); +window.window.parseInt('11'/**/, 2); +window.window.Number.parseInt('11'/**/, 2); ``` # Diagnostics @@ -1364,7 +1371,7 @@ invalid.js:64:1 lint/style/useNumericLiterals ━━━━━━━━━━━ > 64 │ parseInt('0_1', 16); │ ^^^^^^^^^^^^^^^^^^^ 65 │ Number.parseInt('0_0', 16); - 66 │ + 66 │ globalThis.parseInt('11'/**/, 2); ``` @@ -1378,7 +1385,194 @@ invalid.js:65:1 lint/style/useNumericLiterals ━━━━━━━━━━━ 64 │ parseInt('0_1', 16); > 65 │ Number.parseInt('0_0', 16); │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ - 66 │ + 66 │ globalThis.parseInt('11'/**/, 2); + 67 │ globalThis.Number.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:66:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of parseInt() + + 64 │ parseInt('0_1', 16); + 65 │ Number.parseInt('0_0', 16); + > 66 │ globalThis.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 67 │ globalThis.Number.parseInt('11'/**/, 2); + 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + + i Suggested fix: Replace with binary literals + + 64 64 │ parseInt('0_1', 16); + 65 65 │ Number.parseInt('0_0', 16); + 66 │ - globalThis.parseInt('11'/**/,·2); + 66 │ + 0b11; + 67 67 │ globalThis.Number.parseInt('11'/**/, 2); + 68 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:67:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of Number.parseInt() + + 65 │ Number.parseInt('0_0', 16); + 66 │ globalThis.parseInt('11'/**/, 2); + > 67 │ globalThis.Number.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + + i Suggested fix: Replace with binary literals + + 65 65 │ Number.parseInt('0_0', 16); + 66 66 │ globalThis.parseInt('11'/**/, 2); + 67 │ - globalThis.Number.parseInt('11'/**/,·2); + 67 │ + 0b11; + 68 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + 69 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:68:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of parseInt() + + 66 │ globalThis.parseInt('11'/**/, 2); + 67 │ globalThis.Number.parseInt('11'/**/, 2); + > 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + 70 │ window.parseInt('11'/**/, 2); + + i Suggested fix: Replace with binary literals + + 66 66 │ globalThis.parseInt('11'/**/, 2); + 67 67 │ globalThis.Number.parseInt('11'/**/, 2); + 68 │ - globalThis.globalThis.parseInt('11'/**/,·2); + 68 │ + 0b11; + 69 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + 70 70 │ window.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:69:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of Number.parseInt() + + 67 │ globalThis.Number.parseInt('11'/**/, 2); + 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + > 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 70 │ window.parseInt('11'/**/, 2); + 71 │ window.Number.parseInt('11'/**/, 2); + + i Suggested fix: Replace with binary literals + + 67 67 │ globalThis.Number.parseInt('11'/**/, 2); + 68 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + 69 │ - globalThis.globalThis.Number.parseInt('11'/**/,·2); + 69 │ + 0b11; + 70 70 │ window.parseInt('11'/**/, 2); + 71 71 │ window.Number.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:70:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of parseInt() + + 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + > 70 │ window.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 71 │ window.Number.parseInt('11'/**/, 2); + 72 │ window.window.parseInt('11'/**/, 2); + + i Suggested fix: Replace with binary literals + + 68 68 │ globalThis.globalThis.parseInt('11'/**/, 2); + 69 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + 70 │ - window.parseInt('11'/**/,·2); + 70 │ + 0b11; + 71 71 │ window.Number.parseInt('11'/**/, 2); + 72 72 │ window.window.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:71:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of Number.parseInt() + + 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + 70 │ window.parseInt('11'/**/, 2); + > 71 │ window.Number.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 72 │ window.window.parseInt('11'/**/, 2); + 73 │ window.window.Number.parseInt('11'/**/, 2); + + i Suggested fix: Replace with binary literals + + 69 69 │ globalThis.globalThis.Number.parseInt('11'/**/, 2); + 70 70 │ window.parseInt('11'/**/, 2); + 71 │ - window.Number.parseInt('11'/**/,·2); + 71 │ + 0b11; + 72 72 │ window.window.parseInt('11'/**/, 2); + 73 73 │ window.window.Number.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:72:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of parseInt() + + 70 │ window.parseInt('11'/**/, 2); + 71 │ window.Number.parseInt('11'/**/, 2); + > 72 │ window.window.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 73 │ window.window.Number.parseInt('11'/**/, 2); + + i Suggested fix: Replace with binary literals + + 70 70 │ window.parseInt('11'/**/, 2); + 71 71 │ window.Number.parseInt('11'/**/, 2); + 72 │ - window.window.parseInt('11'/**/,·2); + 72 │ + 0b11; + 73 73 │ window.window.Number.parseInt('11'/**/, 2); + + +``` + +``` +invalid.js:73:1 lint/style/useNumericLiterals FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use binary literals instead of Number.parseInt() + + 71 │ window.Number.parseInt('11'/**/, 2); + 72 │ window.window.parseInt('11'/**/, 2); + > 73 │ window.window.Number.parseInt('11'/**/, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + i Suggested fix: Replace with binary literals + + 71 71 │ window.Number.parseInt('11'/**/, 2); + 72 72 │ window.window.parseInt('11'/**/, 2); + 73 │ - window.window.Number.parseInt('11'/**/,·2); + 73 │ + 0b11; ``` diff --git a/crates/rome_js_syntax/src/expr_ext.rs b/crates/rome_js_syntax/src/expr_ext.rs index 76cce721f3c..4e039b1405d 100644 --- a/crates/rome_js_syntax/src/expr_ext.rs +++ b/crates/rome_js_syntax/src/expr_ext.rs @@ -1,6 +1,6 @@ //! Extensions for things which are not easily generated in ast expr nodes use crate::numbers::parse_js_number; -use crate::static_value::{QuotedString, StaticValue}; +use crate::static_value::{QuotedString, StaticStringValue, StaticValue}; use crate::{ AnyJsCallArgument, AnyJsExpression, AnyJsLiteralExpression, AnyJsTemplateElement, JsArrayExpression, JsArrayHole, JsAssignmentExpression, JsBinaryExpression, JsCallExpression, @@ -18,6 +18,9 @@ use rome_rowan::{ }; use std::collections::HashSet; +const GLOBAL_THIS: &str = "globalThis"; +const WINDOW: &str = "window"; + impl JsReferenceIdentifier { /// Returns `true` if this identifier refers to the `undefined` symbol. /// @@ -44,7 +47,7 @@ impl JsReferenceIdentifier { /// assert!(!js_reference_identifier(ident("x")).is_global_this()); /// ``` pub fn is_global_this(&self) -> bool { - self.has_name("globalThis") + self.has_name(GLOBAL_THIS) } /// Returns `true` if this identifier has the given name. @@ -859,33 +862,119 @@ declare_node_union! { } impl AnyJsMemberExpression { - /// Check if the given expression is a static or computed member expression - /// and returns the object reference identifier. - pub fn get_object_reference_identifier(&self) -> Option { + pub fn object(&self) -> SyntaxResult { match self { - Self::JsStaticMemberExpression(e) => e - .object() - .ok() - .and_then(|it| it.omit_parentheses().as_reference_identifier()), - Self::JsComputedMemberExpression(e) => e - .object() - .ok() - .and_then(|it| it.omit_parentheses().as_reference_identifier()), + AnyJsMemberExpression::JsStaticMemberExpression(expr) => expr.object(), + AnyJsMemberExpression::JsComputedMemberExpression(expr) => expr.object(), } } - /// Check if the given expression is a static or computed member expression - /// and has the given member name. - pub fn has_member_name(&self, name: &str) -> bool { - match self { - Self::JsStaticMemberExpression(e) => e - .member() - .ok() - .and_then(|it| it.as_js_name().and_then(|it| it.value_token().ok())) - .map_or(false, |it| it.text_trimmed() == name), - Self::JsComputedMemberExpression(e) => { - e.member().map_or(false, |it| it.is_string_constant(name)) + /// Returns the member name of `self` if `self` is a static member or a computed member with a literal string. + /// + /// ## Examples + /// + /// ``` + /// use rome_js_syntax::{AnyJsExpression, AnyJsLiteralExpression, AnyJsMemberExpression, T}; + /// use rome_js_factory::make; + /// use rome_js_syntax::static_value::{QuotedString, StaticStringValue}; + /// + /// let math_id = make::js_reference_identifier(make::ident("Math")); + /// let math_id = make::js_identifier_expression(math_id); + /// let pow_ident_token = make::ident("pow"); + /// let pow_name = make::js_name(pow_ident_token); + /// let static_member = make::js_static_member_expression(math_id.clone().into(), make::token(T![.]), pow_name.into()); + /// let static_member: AnyJsMemberExpression = static_member.into(); + /// let member_name = static_member.member_name().unwrap(); + /// assert_eq!(member_name.text(), "pow"); + /// + /// let pow_str_token = make::js_string_literal("pow"); + /// let pow_str_literal = make::js_string_literal_expression(pow_str_token.clone()); + /// let pow_str_literal = AnyJsExpression::AnyJsLiteralExpression(AnyJsLiteralExpression::from(pow_str_literal)); + /// let computed_member = make::js_computed_member_expression(math_id.into(), make::token(T!['[']), pow_str_literal, make::token(T![']'])).build(); + /// let computed_member: AnyJsMemberExpression = computed_member.into(); + /// let member_name = computed_member.member_name().unwrap(); + /// assert_eq!(member_name.text(), "pow"); + /// ``` + pub fn member_name(&self) -> Option { + let value = match self { + AnyJsMemberExpression::JsStaticMemberExpression(e) => { + StaticStringValue::Unquoted(e.member().ok()?.as_js_name()?.value_token().ok()?) } + AnyJsMemberExpression::JsComputedMemberExpression(e) => { + let member = e.member().ok()?.omit_parentheses(); + match member.as_static_value()? { + StaticValue::String(quoted_str) => StaticStringValue::Quoted(quoted_str), + StaticValue::TemplateChunk(Some(template_chunk)) => { + StaticStringValue::Unquoted(template_chunk) + } + _ => return None, + } + } + }; + Some(value) + } +} + +/// Check if `expr` refers to a name that is directly referenced or indirectly via `globalThis` or `window`. +/// Returns the reference and the name. +/// +/// ### Examples +/// +/// ``` +/// use rome_js_syntax::{AnyJsExpression, AnyJsLiteralExpression, AnyJsMemberExpression, global_identifier, T}; +/// use rome_js_factory::make; +/// use rome_js_syntax::static_value::{QuotedString, StaticStringValue}; +/// +/// let math_reference = make::js_reference_identifier(make::ident("Math")); +/// let math_id = make::js_identifier_expression(math_reference.clone()); +/// let math_id = AnyJsExpression::from(math_id); +/// let (reference, name) = global_identifier(&math_id).unwrap(); +/// assert_eq!(name.text(), "Math"); +/// assert_eq!(reference, math_reference); +/// +/// let global_this_reference = make::js_reference_identifier(make::ident("globalThis")); +/// let global_this_id = make::js_identifier_expression(global_this_reference.clone()); +/// let global_this_id = AnyJsExpression::from(global_this_id); +/// +/// let math_ident_token = make::ident("Math"); +/// let math_name = make::js_name(math_ident_token); +/// let static_member = make::js_static_member_expression(global_this_id.clone().into(), make::token(T![.]), math_name.into()); +/// let static_member = AnyJsExpression::from(static_member); +/// let (reference, name) = global_identifier(&static_member).unwrap(); +/// assert_eq!(name.text(), "Math"); +/// assert_eq!(reference, global_this_reference); +/// ``` +pub fn global_identifier( + expr: &AnyJsExpression, +) -> Option<(JsReferenceIdentifier, StaticStringValue)> { + if let AnyJsExpression::JsIdentifierExpression(id_expr) = expr { + let reference = id_expr.name().ok()?; + let name = StaticStringValue::Unquoted(reference.value_token().ok()?); + return Some((reference, name)); + } + let Some(member_expr) = AnyJsMemberExpression::cast_ref(expr.syntax()) else { return None; }; + let name: StaticStringValue = member_expr.member_name()?; + let mut expr = member_expr.object().ok()?.omit_parentheses(); + while let Some(member_expr) = AnyJsMemberExpression::cast_ref(expr.syntax()) { + if !matches!(member_expr.member_name()?.text(), GLOBAL_THIS | WINDOW) { + return None; + } + expr = member_expr.object().ok()?.omit_parentheses(); + } + if let AnyJsExpression::JsIdentifierExpression(id_expr) = expr { + let reference = id_expr.name().ok()?; + if reference.has_name(GLOBAL_THIS) || reference.has_name(WINDOW) { + return Some((reference, name)); + } + } + None +} + +impl From for AnyJsExpression { + fn from(expression: AnyJsMemberExpression) -> Self { + match expression { + AnyJsMemberExpression::JsComputedMemberExpression(expr) => expr.into(), + AnyJsMemberExpression::JsStaticMemberExpression(expr) => expr.into(), } } } diff --git a/crates/rome_js_syntax/src/static_value.rs b/crates/rome_js_syntax/src/static_value.rs index c4278b09693..16fa9f3f150 100644 --- a/crates/rome_js_syntax/src/static_value.rs +++ b/crates/rome_js_syntax/src/static_value.rs @@ -2,7 +2,7 @@ use crate::JsSyntaxToken; use std::ops::Deref; -#[derive(PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct QuotedString(JsSyntaxToken); /// A string literal that is wrapped in quotes @@ -55,6 +55,42 @@ impl Deref for QuotedString { } } +/// Represent a JavaScript name which is either an identifier (unquoted string) +/// or a literal string (quoted string), or even a template chuck (unquoted string). +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum StaticStringValue { + Quoted(QuotedString), + Unquoted(JsSyntaxToken), +} + +impl StaticStringValue { + /// Return a string of the static value + /// + /// ## Examples + /// + /// ``` + /// use rome_js_syntax::static_value::{QuotedString, StaticStringValue}; + /// use rome_js_factory::make; + /// + /// let quoted_str = QuotedString::new(make::js_string_literal("str")); + /// assert_eq!(StaticStringValue::Quoted(quoted_str).text(), "str"); + /// ``` + pub fn text(&self) -> &str { + match self { + StaticStringValue::Quoted(quoted_string) => quoted_string.text(), + StaticStringValue::Unquoted(token) => token.text_trimmed(), + } + } + + pub fn token(&self) -> &JsSyntaxToken { + match self { + StaticStringValue::Quoted(token) => &token.0, + StaticStringValue::Unquoted(token) => token, + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] /// static values defined in JavaScript's expressions pub enum StaticValue { Boolean(JsSyntaxToken), diff --git a/website/src/pages/lint/rules/noGlobalObjectCalls.md b/website/src/pages/lint/rules/noGlobalObjectCalls.md index d5e8bbb6f65..0a5ba0ef23c 100644 --- a/website/src/pages/lint/rules/noGlobalObjectCalls.md +++ b/website/src/pages/lint/rules/noGlobalObjectCalls.md @@ -37,7 +37,7 @@ var math = Math(); Math is not a function. > 1 │ var math = Math(); - ^^^^^^ + ^^^^ 2 │ @@ -46,12 +46,12 @@ var math = Math(); var newMath = new Math(); ``` -
correctness/noGlobalObjectCalls.js:1:15 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
+
correctness/noGlobalObjectCalls.js:1:19 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
 
    Math is not a function.
   
   > 1 │ var newMath = new Math();
-                 ^^^^^^^^^^
+                     ^^^^
     2 │ 
   
 
@@ -62,10 +62,10 @@ var json = JSON();
correctness/noGlobalObjectCalls.js:1:12 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
 
-   JSON is not a function.
+   Json is not a function.
   
   > 1 │ var json = JSON();
-              ^^^^^^
+              ^^^^
     2 │ 
   
 
@@ -74,12 +74,12 @@ var json = JSON(); var newJSON = new JSON(); ``` -
correctness/noGlobalObjectCalls.js:1:15 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
+
correctness/noGlobalObjectCalls.js:1:19 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
 
-   JSON is not a function.
+   Json is not a function.
   
   > 1 │ var newJSON = new JSON();
-                 ^^^^^^^^^^
+                     ^^^^
     2 │ 
   
 
@@ -93,7 +93,7 @@ var reflect = Reflect(); Reflect is not a function. > 1 │ var reflect = Reflect(); - ^^^^^^^^^ + ^^^^^^^ 2 │
@@ -102,12 +102,12 @@ var reflect = Reflect(); var newReflect = new Reflect(); ``` -
correctness/noGlobalObjectCalls.js:1:18 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
+
correctness/noGlobalObjectCalls.js:1:22 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
 
    Reflect is not a function.
   
   > 1 │ var newReflect = new Reflect();
-                    ^^^^^^^^^^^^^
+                        ^^^^^^^
     2 │ 
   
 
@@ -121,7 +121,7 @@ var atomics = Atomics(); Atomics is not a function. > 1 │ var atomics = Atomics(); - ^^^^^^^^^ + ^^^^^^^ 2 │
@@ -130,12 +130,12 @@ var atomics = Atomics(); var newAtomics = new Atomics(); ``` -
correctness/noGlobalObjectCalls.js:1:18 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
+
correctness/noGlobalObjectCalls.js:1:22 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
 
    Atomics is not a function.
   
   > 1 │ var newAtomics = new Atomics();
-                    ^^^^^^^^^^^^^
+                        ^^^^^^^
     2 │ 
   
 
@@ -149,7 +149,7 @@ var intl = Intl(); Intl is not a function. > 1 │ var intl = Intl(); - ^^^^^^ + ^^^^ 2 │
@@ -158,12 +158,12 @@ var intl = Intl(); var newIntl = new Intl(); ``` -
correctness/noGlobalObjectCalls.js:1:15 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
+
correctness/noGlobalObjectCalls.js:1:19 lint/correctness/noGlobalObjectCalls ━━━━━━━━━━━━━━━━━━━━━━━
 
    Intl is not a function.
   
   > 1 │ var newIntl = new Intl();
-                 ^^^^^^^^^^
+                     ^^^^
     2 │