From fcbb1ddf8f4be09df845811fdd0acfe79a6ed70b Mon Sep 17 00:00:00 2001 From: rzvxa Date: Fri, 10 May 2024 17:16:40 +0330 Subject: [PATCH] fix: add error messages. --- .../src/rules/react/rules_of_hooks.rs | 130 +++++-- .../src/snapshots/rules_of_hooks.snap | 322 ++++++------------ 2 files changed, 206 insertions(+), 246 deletions(-) diff --git a/crates/oxc_linter/src/rules/react/rules_of_hooks.rs b/crates/oxc_linter/src/rules/react/rules_of_hooks.rs index 6472da13ac4a5..04a96cf5c7414 100644 --- a/crates/oxc_linter/src/rules/react/rules_of_hooks.rs +++ b/crates/oxc_linter/src/rules/react/rules_of_hooks.rs @@ -13,7 +13,7 @@ use oxc_semantic::{ pg::neighbors_filtered_by_edge_weight, AstNodeId, AstNodes, BasicBlockElement, EdgeType, Register, }; -use oxc_span::{Atom, GetSpan, Span}; +use oxc_span::{Atom, CompactStr, Span}; use crate::{ context::LintContext, @@ -26,38 +26,87 @@ use crate::{ enum RulesOfHooksDiagnostic { #[error( "eslint-plugin-react-hooks(rules-of-hooks): \ - React Hook \"{hook:?}\" is called in function \"{func:?}\" that is neither \ - a React function component nor a custom React Hook function. \ - React component names must start with an uppercase letter. \ - React Hook names must start with the word \"use\"." + React Hook {hook_name:?} is called in function {func_name:?} that is neither \ + a React function component nor a custom React Hook function. \ + React component names must start with an uppercase letter. \ + React Hook names must start with the word \"use\"." )] - #[diagnostic(severity(warning), help("TODO: FunctionError"))] + #[diagnostic(severity(error))] FunctionError { #[label] span: Span, + hook_name: CompactStr, + func_name: CompactStr, + }, + #[error( + "eslint-plugin-react-hooks(rules-of-hooks): \ + React Hook {hook_name:?} is called conditionally. React Hooks must be \ + called in the exact same order in every component render." + )] + #[diagnostic(severity(error))] + ConditionalHook { + #[label] + span: Span, + hook_name: CompactStr, + }, + #[error( + "eslint-plugin-react-hooks(rules-of-hooks): \ + React Hook {hook_name:?} may be executed more than once. Possibly \ + because it is called in a loop. React Hooks must be called in the \ + exact same order in every component render." + )] + #[diagnostic(severity(error))] + LoopHook { + #[label] + span: Span, + hook_name: CompactStr, + }, + #[error( + "eslint-plugin-react-hooks(rules-of-hooks): \ + React Hook {hook_name:?} cannot be called at the top level. React Hooks \ + must be called in a React function component or a custom React \ + Hook function." + )] + #[diagnostic(severity(error))] + TopLevelHook { + #[label] + span: Span, + hook_name: CompactStr, + }, + #[error( + "eslint-plugin-react-hooks(rules-of-hooks): \ + message: `React Hook {func_name:?} cannot be called in an async function. " + )] + #[diagnostic(severity(error))] + AsyncComponent { + #[label] + span: Span, + func_name: CompactStr, + }, + #[error( + "eslint-plugin-react-hooks(rules-of-hooks): \ + React Hook {hook_name:?} cannot be called in a class component. React Hooks \ + must be called in a React function component or a custom React \ + Hook function." + )] + #[diagnostic(severity(error))] + ClassComponent { #[label] - hook: Span, + span: Span, + hook_name: CompactStr, + }, + #[error( + "eslint-plugin-react-hooks(rules-of-hooks): \ + React Hook {hook_name:?} cannot be called inside a callback. React Hooks \ + must be called in a React function component or a custom React \ + Hook function." + )] + #[diagnostic(severity(error))] + GenericError { #[label] - func: Span, + span: Span, + hook_name: CompactStr, }, - #[error("eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook")] - #[diagnostic(severity(warning), help("TODO: ConditionalHook"))] - ConditionalHook(#[label] Span), - #[error("eslint-plugin-react-hooks(rules-of-hooks): TODO: LoopHook")] - #[diagnostic(severity(warning), help("TODO: LoopHook"))] - LoopHook(#[label] Span), - #[error("eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook")] - #[diagnostic(severity(warning), help("TODO: TopLevelHook"))] - TopLevelHook(#[label] Span), - #[error("eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent")] - #[diagnostic(severity(warning), help("TODO: AsyncComponent"))] - AsyncComponent(#[label] Span), - #[error("eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent")] - #[diagnostic(severity(warning), help("TODO: ClassComponent"))] - ClassComponent(#[label] Span), - #[error("eslint-plugin-react-hooks(rules-of-hooks): TODO: GenericError")] - #[diagnostic(severity(warning), help("TODO: GenericError"))] - GenericError(#[label] Span), } #[derive(Debug, Default, Clone)] @@ -81,12 +130,16 @@ impl Rule for RulesOfHooks { if !is_react_hook(&call.callee) { return; } + let span = call.span; + let hook_name = CompactStr::from( + call.callee_name().expect("We identify hooks using their names so it should be named."), + ); let semantic = ctx.semantic(); let nodes = semantic.nodes(); let Some(parent_func) = parent_func(nodes, node) else { - return ctx.diagnostic(RulesOfHooksDiagnostic::TopLevelHook(call.span)); + return ctx.diagnostic(RulesOfHooksDiagnostic::TopLevelHook { span, hook_name }); }; // Check if our parent function is part of a class. @@ -98,10 +151,10 @@ impl Rule for RulesOfHooks { | AstKind::PropertyDefinition(_) ) ) { - return ctx.diagnostic(RulesOfHooksDiagnostic::ClassComponent(call.span)); + return ctx.diagnostic(RulesOfHooksDiagnostic::ClassComponent { span, hook_name }); } - let is_use = call.callee_name().is_some_and(|name| name == "use"); + let is_use = hook_name == "use"; match parent_func.kind() { // We are in a named function that isn't a hook or component, which is illegal @@ -110,13 +163,16 @@ impl Rule for RulesOfHooks { { return ctx.diagnostic(RulesOfHooksDiagnostic::FunctionError { span: id.span, - hook: call.callee.span(), - func: id.span, + hook_name, + func_name: id.name.to_compact_str(), }); } // Hooks can't be called from async function. AstKind::Function(Function { id: Some(id), r#async: true, .. }) => { - return ctx.diagnostic(RulesOfHooksDiagnostic::AsyncComponent(id.span)); + return ctx.diagnostic(RulesOfHooksDiagnostic::AsyncComponent { + span: id.span, + func_name: id.name.to_compact_str(), + }); } // Hooks are allowed inside of unnamed functions used as arguments. As long as they are // not used as a callback inside of components or hooks. @@ -125,7 +181,7 @@ impl Rule for RulesOfHooks { { // This rules doesn't apply to `use(...)`. if !is_use && is_somewhere_inside_component_or_hook(nodes, parent_func.id()) { - ctx.diagnostic(RulesOfHooksDiagnostic::GenericError(call.span)); + ctx.diagnostic(RulesOfHooksDiagnostic::GenericError { span, hook_name }); } return; } @@ -166,8 +222,8 @@ impl Rule for RulesOfHooks { { return ctx.diagnostic(RulesOfHooksDiagnostic::FunctionError { span: *span, - hook: call.callee.span(), - func: *span, + hook_name, + func_name: "Anonymous".into(), }); } } @@ -204,14 +260,14 @@ impl Rule for RulesOfHooks { // Is this node cyclic? if self.is_cyclic(ctx, node_cfg_ix) { - return ctx.diagnostic(RulesOfHooksDiagnostic::LoopHook(call.span)); + return ctx.diagnostic(RulesOfHooksDiagnostic::LoopHook { span, hook_name }); } if self.is_conditional(ctx, func_cfg_ix, node_cfg_ix) || self.breaks_early(ctx, func_cfg_ix, node_cfg_ix) { #[allow(clippy::needless_return)] - return ctx.diagnostic(RulesOfHooksDiagnostic::ConditionalHook(call.span)); + return ctx.diagnostic(RulesOfHooksDiagnostic::ConditionalHook { span, hook_name }); } } } diff --git a/crates/oxc_linter/src/snapshots/rules_of_hooks.snap b/crates/oxc_linter/src/snapshots/rules_of_hooks.snap index b6197fd1b6d5e..34cf5befb8cb1 100644 --- a/crates/oxc_linter/src/snapshots/rules_of_hooks.snap +++ b/crates/oxc_linter/src/snapshots/rules_of_hooks.snap @@ -2,682 +2,586 @@ source: crates/oxc_linter/src/tester.rs expression: rules_of_hooks --- - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:15] 3 │ if (a) return; 4 │ useState(); · ────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:9:15] 8 │ } 9 │ useState(); · ────────── 10 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:7:15] 6 │ 7 │ useHook(); · ───────── 8 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useConditionalHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:18] 3 │ if (cond) { 4 │ useConditionalHook(); · ──────────────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:2:13] 1 │ 2 │ Hook.useState(); · ─────────────── 3 │ Hook._useState(); ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:5:13] 4 │ Hook.use42(); 5 │ Hook.useHook(); · ────────────── 6 │ Hook.use_hook(); ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:22] 3 │ m() { 4 │ This.useHook(); · ────────────── 5 │ Super.useHook(); ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:5:22] 4 │ This.useHook(); 5 │ Super.useHook(); · ─────────────── 6 │ } ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useFeatureFlag" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:5:25] 4 │ if (cond) { 5 │ FooStore.useFeatureFlag(); · ───────────────────────── 6 │ } ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useConditionalHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:21] 3 │ if (cond) { 4 │ Namespace.useConditionalHook(); · ────────────────────────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useConditionalHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:5:29] 4 │ if (cond) { 5 │ useConditionalHook(); · ──────────────────── 6 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useConditionalHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:25] 3 │ if (cond) { 4 │ useConditionalHook(); · ──────────────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useConditionalHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:5:29] 4 │ if (cond) { 5 │ useConditionalHook(); · ──────────────────── 6 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useTernaryHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:3:28] 2 │ function ComponentWithTernaryHook() { 3 │ cond ? useTernaryHook() : null; · ──────────────── 4 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: GenericError + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideCallback" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:25] 3 │ useEffect(() => { 4 │ useHookInsideCallback(); · ─────────────────────── 5 │ }); ╰──── - help: TODO: GenericError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: GenericError + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideCallback" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:5:29] 4 │ useEffect(() => { 5 │ useHookInsideCallback(); · ─────────────────────── 6 │ }); ╰──── - help: TODO: GenericError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: GenericError + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideCallback" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:25] 3 │ useEffect(() => { 4 │ useHookInsideCallback(); · ─────────────────────── 5 │ }); ╰──── - help: TODO: GenericError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: GenericError + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideCallback" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:25] 3 │ useEffect(() => { 4 │ useHookInsideCallback(); · ─────────────────────── 5 │ }); ╰──── - help: TODO: GenericError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 131, end: 139 }" is called in function "Span { start: 91, end: 102 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "handleClick" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:3:30] 2 │ function ComponentWithHookInsideCallback() { 3 │ function handleClick() { - · ──────────── + · ─────────── 4 │ useState(); - · ──────── - 5 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 195, end: 203 }" is called in function "Span { start: 151, end: 162 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "handleClick" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:4:34] 3 │ return function ComponentWithHookInsideCallback() { 4 │ function handleClick() { - · ──────────── + · ─────────── 5 │ useState(); - · ──────── - 6 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: LoopHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideLoop" may be executed more than once. Possibly because it is called in a loop. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:25] 3 │ while (cond) { 4 │ useHookInsideLoop(); · ─────────────────── 5 │ } ╰──── - help: TODO: LoopHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 61, end: 69 }" is called in function "Span { start: 26, end: 36 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "renderItem" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:26] 1 │ 2 │ function renderItem() { - · ─────────── + · ────────── 3 │ useState(); - · ──────── - 4 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 73, end: 100 }" is called in function "Span { start: 26, end: 48 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideNormalFunction" is called in function "normalFunctionWithHook" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:26] 1 │ 2 │ function normalFunctionWithHook() { - · ─────────────────────── + · ────────────────────── 3 │ useHookInsideNormalFunction(); - · ─────────────────────────── - 4 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 74, end: 101 }" is called in function "Span { start: 26, end: 49 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideNormalFunction" is called in function "_normalFunctionWithHook" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:26] 1 │ 2 │ function _normalFunctionWithHook() { - · ──────────────────────── + · ─────────────────────── 3 │ useHookInsideNormalFunction(); - · ─────────────────────────── - 4 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 185, end: 212 }" is called in function "Span { start: 148, end: 160 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideNormalFunction" is called in function "_useNotAHook" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:5:26] 4 │ } 5 │ function _useNotAHook() { - · ───────────── + · ──────────── 6 │ useHookInsideNormalFunction(); - · ─────────────────────────── - 7 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 120, end: 147 }" is called in function "Span { start: 26, end: 59 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHookInsideNormalFunction" is called in function "normalFunctionWithConditionalHook" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:26] 1 │ 2 │ function normalFunctionWithConditionalHook() { - · ────────────────────────────────── + · ───────────────────────────────── 3 │ if (cond) { - 4 │ useHookInsideNormalFunction(); - · ─────────────────────────── - 5 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: LoopHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook1" may be executed more than once. Possibly because it is called in a loop. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:25] 3 │ while (a) { 4 │ useHook1(); · ────────── 5 │ if (b) return; ╰──── - help: TODO: LoopHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook2" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:6:25] 5 │ if (b) return; 6 │ useHook2(); · ────────── 7 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: LoopHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook3" may be executed more than once. Possibly because it is called in a loop. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:9:25] 8 │ while (c) { 9 │ useHook3(); · ────────── 10 │ if (d) return; ╰──── - help: TODO: LoopHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook4" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:11:25] 10 │ if (d) return; 11 │ useHook4(); · ────────── 12 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: LoopHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook1" may be executed more than once. Possibly because it is called in a loop. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:21] 3 │ while (a) { 4 │ useHook1(); · ────────── 5 │ if (b) continue; ╰──── - help: TODO: LoopHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook2" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:6:21] 5 │ if (b) continue; 6 │ useHook2(); · ────────── 7 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:5:25] 4 │ if (a) break label; 5 │ useHook(); · ───────── 6 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 28, end: 36 }" is called in function "Span { start: 22, end: 23 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "a" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:22] 1 │ 2 │ function a() { useState(); } - · ── ──────── + · ─ 3 │ const whatever = function b() { useState(); }; ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 86, end: 94 }" is called in function "Span { start: 80, end: 81 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "b" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:3:39] 2 │ function a() { useState(); } 3 │ const whatever = function b() { useState(); }; - · ── ──────── + · ─ 4 │ const c = () => { useState(); }; ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 131, end: 139 }" is called in function "Span { start: 123, end: 144 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:4:23] 3 │ const whatever = function b() { useState(); }; 4 │ const c = () => { useState(); }; - · ─────────────────────── + · ───────────────────── 5 │ let d = () => useState(); ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 172, end: 180 }" is called in function "Span { start: 166, end: 182 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:5:21] 4 │ const c = () => { useState(); }; 5 │ let d = () => useState(); - · ────────────────── + · ──────────────── 6 │ e = () => { useState(); }; ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:21] 3 │ if (a) return; 4 │ useState(); · ────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:9:21] 8 │ } 9 │ useState(); · ────────── 10 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:9:21] 8 │ if (a) return; 9 │ useState(); · ────────── 10 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook1" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:3:26] 2 │ function useHook() { 3 │ a && useHook1(); · ────────── 4 │ b && useHook2(); ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook2" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:26] 3 │ a && useHook1(); 4 │ b && useHook2(); · ────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:5:25] 4 │ f(); 5 │ useState(); · ────────── 6 │ } catch {} ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:3:39] 2 │ function useHook({ bar }) { 3 │ let foo1 = bar && useState(); · ────────── 4 │ let foo2 = bar || useState(); ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:39] 3 │ let foo1 = bar && useState(); 4 │ let foo2 = bar || useState(); · ────────── 5 │ let foo3 = bar ?? useState(); ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:5:39] 4 │ let foo2 = bar || useState(); 5 │ let foo3 = bar ?? useState(); · ────────── 6 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useCustomHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:25] 3 │ if (props.fancy) { 4 │ useCustomHook(); · ─────────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useCustomHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:25] 3 │ if (props.fancy) { 4 │ useCustomHook(); · ─────────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: ConditionalHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useCustomHook" is called conditionally. React Hooks must be called in the exact same order in every component render. ╭─[rules_of_hooks.tsx:4:25] 3 │ if (props.fancy) { 4 │ useCustomHook(); · ─────────────── 5 │ } ╰──── - help: TODO: ConditionalHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 94, end: 110 }" is called in function "Span { start: 48, end: 61 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useProbablyAHook" is called in function "notAComponent" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:48] 1 │ 2 │ React.unknownFunction(function notAComponent(foo, bar) { - · ────────────── + · ───────────── 3 │ useProbablyAHook(bar) - · ──────────────── - 4 │ }); ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:2:13] 1 │ 2 │ useState(); · ────────── 3 │ if (foo) { ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useCallback" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:29] 3 │ if (foo) { 4 │ const foo = React.useCallback(() => {}); · ─────────────────────────── 5 │ } ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useCustomHook" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:6:13] 5 │ } 6 │ useCustomHook(); · ─────────────── 7 │ ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useBasename" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:3:36] 2 │ const {createHistory, useBasename} = require('history-2.1.2'); 3 │ const browserHistory = useBasename(createHistory)({ · ────────────────────────── 4 │ basename: '/', ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useFeatureFlag" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:5:29] 4 │ if (foo) { 5 │ useFeatureFlag(); · ──────────────── 6 │ } ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:25] 3 │ render() { 4 │ React.useState(); · ──────────────── 5 │ } ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:1:27] 1 │ (class {useHook = () => { useState(); }}); · ────────── ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:1:21] 1 │ (class {useHook() { useState(); }}); · ────────── ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:1:21] 1 │ (class {h = () => { useState(); }}); · ────────── ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:1:15] 1 │ (class {i() { useState(); }}); · ────────── ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): message: `React Hook "AsyncComponent" cannot be called in an async function. ╭─[rules_of_hooks.tsx:2:32] 1 │ 2 │ async function AsyncComponent() { · ────────────── 3 │ useState(); ╰──── - help: TODO: AsyncComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): message: `React Hook "useAsyncHook" cannot be called in an async function. ╭─[rules_of_hooks.tsx:2:32] 1 │ 2 │ async function useAsyncHook() { · ──────────── 3 │ useState(); ╰──── - help: TODO: AsyncComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "use" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:2:13] 1 │ 2 │ Hook.use(); · ────────── 3 │ Hook._use(); ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:13] 3 │ Hook._use(); 4 │ Hook.useState(); · ─────────────── 5 │ Hook._useState(); ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useHook" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:7:13] 6 │ Hook.use42(); 7 │ Hook.useHook(); · ────────────── 8 │ Hook.use_hook(); ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 64, end: 67 }" is called in function "Span { start: 26, end: 39 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "use" is called in function "notAComponent" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:26] 1 │ 2 │ function notAComponent() { - · ────────────── + · ───────────── 3 │ use(promise); - · ─── - 4 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: TopLevelHook + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "use" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:2:26] 1 │ 2 │ const text = use(promise); · ──────────── 3 │ function App() { ╰──── - help: TODO: TopLevelHook - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "use" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function. ╭─[rules_of_hooks.tsx:4:21] 3 │ m() { 4 │ use(promise); · ──────────── 5 │ } ╰──── - help: TODO: ClassComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): TODO: AsyncComponent + × eslint-plugin-react-hooks(rules-of-hooks): message: `React Hook "AsyncComponent" cannot be called in an async function. ╭─[rules_of_hooks.tsx:2:28] 1 │ 2 │ async function AsyncComponent() { · ────────────── 3 │ use(); ╰──── - help: TODO: AsyncComponent - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 101, end: 109 }" is called in function "Span { start: 73, end: 128 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:3:24] - 2 │ export const notAComponent = () => { - 3 │ ╭──▶ return () => { - 4 │ ││ useState(); - · ││ ──────── - 5 │ ╰──▶ } - 6 │ } + 2 │ export const notAComponent = () => { + 3 │ ╭─▶ return () => { + 4 │ │ useState(); + 5 │ ╰─▶ } + 6 │ } ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 59, end: 67 }" is called in function "Span { start: 35, end: 84 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:35] - 1 │ - 2 │ ╭──▶ const notAComponent = () => { - 3 │ ││ useState(); - · ││ ──────── - 4 │ ╰──▶ } - 5 │ + 1 │ + 2 │ ╭─▶ const notAComponent = () => { + 3 │ │ useState(); + 4 │ ╰─▶ } + 5 │ ╰──── - help: TODO: FunctionError - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 85, end: 93 }" is called in function "Span { start: 28, end: 129 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:28] - 1 │ - 2 │ ╭──▶ export default () => { - 3 │ ││ if (isVal) { - 4 │ ││ useState(0); - · ││ ──────── - 5 │ ││ } - 6 │ ╰──▶ } - 7 │ - ╰──── - help: TODO: FunctionError - - ⚠ eslint-plugin-react-hooks(rules-of-hooks): React Hook "Span { start: 90, end: 98 }" is called in function "Span { start: 28, end: 134 }" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". + 1 │ + 2 │ ╭─▶ export default () => { + 3 │ │ if (isVal) { + 4 │ │ useState(0); + 5 │ │ } + 6 │ ╰─▶ } + 7 │ + ╰──── + + × eslint-plugin-react-hooks(rules-of-hooks): React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". ╭─[rules_of_hooks.tsx:2:28] - 1 │ - 2 │ ╭──▶ export default function() { - 3 │ ││ if (isVal) { - 4 │ ││ useState(0); - · ││ ──────── - 5 │ ││ } - 6 │ ╰──▶ } - 7 │ - ╰──── - help: TODO: FunctionError + 1 │ + 2 │ ╭─▶ export default function() { + 3 │ │ if (isVal) { + 4 │ │ useState(0); + 5 │ │ } + 6 │ ╰─▶ } + 7 │ + ╰────