diff --git a/flake8_idom_hooks/utils.py b/flake8_idom_hooks/utils.py index ec2331a..450c00e 100644 --- a/flake8_idom_hooks/utils.py +++ b/flake8_idom_hooks/utils.py @@ -1,6 +1,6 @@ import ast from contextlib import contextmanager -from typing import List, Tuple, Iterator, Any +from typing import Any, Iterator, List, Tuple @contextmanager @@ -28,11 +28,16 @@ def is_hook_def(node: ast.FunctionDef) -> bool: def is_component_def(node: ast.FunctionDef) -> bool: - return is_component_function_name(node.name) + return any( + is_idom_component_decorator(decorator) for decorator in node.decorator_list + ) -def is_component_function_name(name: str) -> bool: - return name[0].upper() == name[0] and "_" not in name +def is_idom_component_decorator(node: Any) -> bool: + return getattr(node, "id", None) == "component" or ( + getattr(getattr(node, "value", None), "id", None) == "idom" + and getattr(node, "attr", None) == "component" + ) def is_hook_function_name(name: str) -> bool: diff --git a/tests/hook_usage_test_cases.py b/tests/hook_usage_test_cases.py index 696b86c..76a8367 100644 --- a/tests/hook_usage_test_cases.py +++ b/tests/hook_usage_test_cases.py @@ -1,9 +1,15 @@ +import idom +from idom import component + + +@component def HookInIf(): if True: # error: ROH102 hook 'use_state' used inside if statement use_state +@component def HookInElif(): if False: pass @@ -12,6 +18,7 @@ def HookInElif(): use_state +@component def HookInElse(): if False: pass @@ -20,6 +27,7 @@ def HookInElse(): use_state +@component def HookInIfExp(): ( # error: ROH102 hook 'use_state' used inside inline if expression @@ -29,6 +37,7 @@ def HookInIfExp(): ) +@component def HookInElseOfIfExp(): ( None @@ -39,6 +48,7 @@ def HookInElseOfIfExp(): ) +@component def HookInTry(): try: # error: ROH102 hook 'use_state' used inside try statement @@ -47,6 +57,7 @@ def HookInTry(): pass +@component def HookInExcept(): try: raise ValueError() @@ -55,6 +66,7 @@ def HookInExcept(): use_state +@component def HookInFinally(): try: pass @@ -63,12 +75,14 @@ def HookInFinally(): use_state +@component def HookInForLoop(): for i in range(3): # error: ROH102 hook 'use_state' used inside for loop use_state +@component def HookInWhileLoop(): while True: # error: ROH102 hook 'use_state' used inside while loop @@ -82,18 +96,27 @@ def use_state(): def generic_function(): + # error: ROH101 hook 'use_state' used outside component or hook definition use_state +@component def use_state(): use_other +@component def Component(): use_state +@idom.component +def IdomLongImportComponent(): + use_state + + +@component def use_custom_hook(): use_state @@ -110,6 +133,7 @@ def not_hook_or_component(): use_state +@component def CheckEffects(): x = 1 y = 2 @@ -205,8 +229,10 @@ def impropper_usage_of_effect_as_decorator(): ) +@component def make_component(): # nested component definitions are ok. + @component def NestedComponent(): use_state @@ -214,6 +240,7 @@ def NestedComponent(): some_global_variable +@component def Component(): # referencing a global variable is OK use_effect(lambda: some_global_variable, []) @@ -221,9 +248,11 @@ def Component(): if True: + @component def Component(): # this is ok since the conditional is outside the component use_state + @component def use_other(): use_state