mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 20:28:58 +00:00
feat(linter/react): add the rules_of_hooks rule. (#3071)
[RulesOfHooks](https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js), [docs](https://react.dev/reference/rules/rules-of-hooks), [npm](https://www.npmjs.com/package/eslint-plugin-react-hooks) This one sounds like something straight out of `Mortal Kombat`!
This commit is contained in:
parent
8519a0ab05
commit
1f135ce4ce
5 changed files with 2102 additions and 12 deletions
|
|
@ -209,6 +209,7 @@ mod react {
|
||||||
pub mod no_unknown_property;
|
pub mod no_unknown_property;
|
||||||
pub mod react_in_jsx_scope;
|
pub mod react_in_jsx_scope;
|
||||||
pub mod require_render_return;
|
pub mod require_render_return;
|
||||||
|
pub mod rules_of_hooks;
|
||||||
pub mod void_dom_elements_no_children;
|
pub mod void_dom_elements_no_children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -639,6 +640,7 @@ oxc_macros::declare_all_lint_rules! {
|
||||||
react::no_is_mounted,
|
react::no_is_mounted,
|
||||||
react::no_unknown_property,
|
react::no_unknown_property,
|
||||||
react::require_render_return,
|
react::require_render_return,
|
||||||
|
react::rules_of_hooks,
|
||||||
react::void_dom_elements_no_children,
|
react::void_dom_elements_no_children,
|
||||||
react_perf::jsx_no_jsx_as_prop,
|
react_perf::jsx_no_jsx_as_prop,
|
||||||
react_perf::jsx_no_new_array_as_prop,
|
react_perf::jsx_no_new_array_as_prop,
|
||||||
|
|
|
||||||
1445
crates/oxc_linter/src/rules/react/rules_of_hooks.rs
Normal file
1445
crates/oxc_linter/src/rules/react/rules_of_hooks.rs
Normal file
File diff suppressed because it is too large
Load diff
596
crates/oxc_linter/src/snapshots/rules_of_hooks.snap
Normal file
596
crates/oxc_linter/src/snapshots/rules_of_hooks.snap
Normal file
|
|
@ -0,0 +1,596 @@
|
||||||
|
---
|
||||||
|
source: crates/oxc_linter/src/tester.rs
|
||||||
|
expression: rules_of_hooks
|
||||||
|
---
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ });
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ });
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ });
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ });
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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) {
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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;
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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;
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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;
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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(); };
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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(); };
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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(); };
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 {}
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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)
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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) {
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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: '/',
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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(); }});
|
||||||
|
· ──────────
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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(); }});
|
||||||
|
· ──────────
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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(); }});
|
||||||
|
· ──────────
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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(); }});
|
||||||
|
· ──────────
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× eslint-plugin-react-hooks(rules-of-hooks): message: `React Hook "Anonymous" cannot be called in an async function.
|
||||||
|
╭─[rules_of_hooks.tsx:2:40]
|
||||||
|
1 │
|
||||||
|
2 │ ╭─▶ const AsyncComponent = async () => {
|
||||||
|
3 │ │ useState();
|
||||||
|
4 │ ╰─▶ }
|
||||||
|
5 │
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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);
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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() {
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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();
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │ }
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │
|
||||||
|
╰────
|
||||||
|
|
||||||
|
× 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 │
|
||||||
|
╰────
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use oxc_ast::{
|
use oxc_ast::{
|
||||||
ast::{
|
ast::{
|
||||||
CallExpression, Expression, JSXAttributeItem, JSXAttributeName, JSXAttributeValue,
|
CallExpression, Expression, JSXAttributeItem, JSXAttributeName, JSXAttributeValue,
|
||||||
JSXChild, JSXElement, JSXElementName, JSXExpression, JSXOpeningElement,
|
JSXChild, JSXElement, JSXElementName, JSXExpression, JSXOpeningElement, MemberExpression,
|
||||||
},
|
},
|
||||||
AstKind,
|
match_member_expression, AstKind,
|
||||||
};
|
};
|
||||||
use oxc_semantic::{AstNode, SymbolFlags};
|
use oxc_semantic::{AstNode, SymbolFlags};
|
||||||
|
|
||||||
|
|
@ -273,3 +273,56 @@ pub fn parse_jsx_value(value: &JSXAttributeValue) -> Result<f64, ()> {
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether the `name` follows the official conventions of React Hooks.
|
||||||
|
///
|
||||||
|
/// Identifies `use(...)` as a valid hook.
|
||||||
|
///
|
||||||
|
/// Hook names must start with use followed by a capital letter,
|
||||||
|
/// like useState (built-in) or useOnlineStatus (custom).
|
||||||
|
pub fn is_react_hook_name(name: &str) -> bool {
|
||||||
|
name.starts_with("use") && name.chars().nth(3).map_or(true, char::is_uppercase)
|
||||||
|
// uncomment this check if react decided to drop the idea of `use` hook.
|
||||||
|
// <https://react.dev/reference/react/use> It is currently in `Canary` builds.
|
||||||
|
// name.starts_with("use") && name.chars().nth(3).is_some_and(char::is_uppercase)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether the `name` follows the official conventions of React Hooks.
|
||||||
|
///
|
||||||
|
/// Identifies `use(...)` as a valid hook.
|
||||||
|
///
|
||||||
|
/// Hook names must start with use followed by a capital letter,
|
||||||
|
/// like useState (built-in) or useOnlineStatus (custom).
|
||||||
|
pub fn is_react_hook(expr: &Expression) -> bool {
|
||||||
|
match expr {
|
||||||
|
match_member_expression!(Expression) => {
|
||||||
|
// SAFETY: We already have checked that `expr` is a member expression using the
|
||||||
|
// `match_member_expression` macro.
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
let expr = unsafe { expr.as_member_expression().unwrap_unchecked() };
|
||||||
|
let MemberExpression::StaticMemberExpression(static_expr) = expr else { return false };
|
||||||
|
let is_valid_namespace = match &static_expr.object {
|
||||||
|
Expression::Identifier(ident) => {
|
||||||
|
ident.name.chars().next().is_some_and(char::is_uppercase)
|
||||||
|
}
|
||||||
|
Expression::ThisExpression(_) | Expression::Super(_) => false,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
is_valid_namespace && expr.static_property_name().is_some_and(is_react_hook_name)
|
||||||
|
}
|
||||||
|
Expression::Identifier(ident) => is_react_hook_name(ident.name.as_str()),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the node is a React component name. React component names must
|
||||||
|
/// always start with an uppercase letter.
|
||||||
|
pub fn is_react_component_name(name: &str) -> bool {
|
||||||
|
name.chars().next().is_some_and(|c| c.is_ascii_uppercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the node is a React component name or React hook,
|
||||||
|
/// `is_react_component_name`, `is_react_hook_name`
|
||||||
|
pub fn is_react_component_or_hook_name(name: &str) -> bool {
|
||||||
|
is_react_component_name(name) || is_react_hook_name(name)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,7 @@
|
||||||
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef, Direction, Graph};
|
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef, Direction, Graph};
|
||||||
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
pub fn neighbors_filtered_by_edge_weight<
|
pub fn neighbors_filtered_by_edge_weight<State: Default + Clone, NodeWeight, EdgeWeight, F, G>(
|
||||||
State: Default + Copy + Clone,
|
|
||||||
NodeWeight,
|
|
||||||
EdgeWeight,
|
|
||||||
F,
|
|
||||||
G,
|
|
||||||
>(
|
|
||||||
graph: &Graph<NodeWeight, EdgeWeight>,
|
graph: &Graph<NodeWeight, EdgeWeight>,
|
||||||
node: NodeIndex,
|
node: NodeIndex,
|
||||||
edge_filter: &F,
|
edge_filter: &F,
|
||||||
|
|
@ -37,11 +31,11 @@ where
|
||||||
} else {
|
} else {
|
||||||
let opposite_dir_of_edge_graph_ix = edge.target();
|
let opposite_dir_of_edge_graph_ix = edge.target();
|
||||||
let (new_state, keep_walking_this_path) =
|
let (new_state, keep_walking_this_path) =
|
||||||
visitor(&opposite_dir_of_edge_graph_ix, state);
|
visitor(&opposite_dir_of_edge_graph_ix, state.clone());
|
||||||
if keep_walking_this_path {
|
if keep_walking_this_path {
|
||||||
q.push((opposite_dir_of_edge_graph_ix, new_state));
|
q.push((opposite_dir_of_edge_graph_ix, new_state.clone()));
|
||||||
} else {
|
} else {
|
||||||
final_states.push(new_state);
|
final_states.push(new_state.clone());
|
||||||
}
|
}
|
||||||
edges += 1;
|
edges += 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue