package react-rules-of-hooks-ppx
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
This ppx validates the rules of React hooks in reason-react components
Install
dune-project
Dependency
Authors
Maintainers
Sources
react-rules-of-hooks-ppx-1.4.0.tbz
sha256=75f5e3d4926ee92c9b95765e29208f1ae81c7130871a26914867d21d6829d719
sha512=13bfdf55f90e7201657188b84dcedafb1cc4b8f2f2a173fdb53cd98ddf427e43bb9e94aa105cd20576ebbd31fc680dd367835d78d06941e84a607793b2bc5086
doc/src/react_rules_of_hooks_ppx/hook.ml.html
Source file hook.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123open Ppxlib let is_hook_name name = let len = String.length name in if len = 3 then name = "use" else len >= 4 && name.[0] = 'u' && name.[1] = 's' && name.[2] = 'e' && ((name.[3] >= 'A' && name.[3] <= 'Z') || name.[3] = '_' || name.[3] = '\'' || (name.[3] >= '0' && name.[3] <= '9')) let last_component (longident : Longident.t) = match longident with Lident l -> Some l | Ldot (_, l) -> Some l | _ -> None let is_hook_ident longident = match last_component longident with | Some name -> is_hook_name name | None -> false let has_attribute name (attrs : attributes) = attrs |> List.exists (fun { attr_name; _ } -> attr_name.txt = name) let is_jsx = has_attribute "JSX" let call_ident (expr : Parsetree.expression) : Longident.t option = match expr.pexp_desc with | Pexp_apply ({ pexp_desc = Pexp_ident { txt; _ }; _ }, _) when not (is_jsx expr.pexp_attributes) -> Some txt | _ -> None let hook_call (expr : Parsetree.expression) : Longident.t option = match call_ident expr with | Some lident when is_hook_ident lident -> Some lident | _ -> None exception Hook_found let hook_scanner = object inherit Ast_traverse.iter as super method! expression e = match hook_call e with | Some _ -> raise Hook_found | None -> super#expression e end let contains_hook_call scan = try scan hook_scanner; false with Hook_found -> true let expression_has_hook_calls expr = contains_hook_call (fun scanner -> scanner#expression expr) let structure_has_hook_calls structure = contains_hook_call (fun scanner -> scanner#structure structure) module With_deps = struct type t = { prefix : string; base : string; variant : int option } let bases = [ "useEffect"; "useLayoutEffect"; "useInsertionEffect"; "useCallback"; "useMemo"; ] let prefixes = [ "React."; "" ] let decode (name : string) : t option = let try_parse prefix base = let full_base = prefix ^ base in if String.starts_with ~prefix:full_base name then let suffix = String.sub name (String.length full_base) (String.length name - String.length full_base) in match suffix with | "" -> Some { prefix; base; variant = None } | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" -> Some { prefix; base; variant = Some (int_of_string suffix) } | _ -> None else None in List.find_map (fun base -> List.find_map (fun prefix -> try_parse prefix base) prefixes) bases let with_variant t variant = t.prefix ^ t.base ^ string_of_int variant type call = { name : string; info : t; fn_loc : Location.t; callback_arg : (arg_label * Parsetree.expression) option; deps_arg : (arg_label * Parsetree.expression) option; } let call (expr : Parsetree.expression) : call option = match expr.pexp_desc with | Pexp_apply ({ pexp_desc = Pexp_ident { txt; _ }; pexp_loc = fn_loc; _ }, args) -> let name = Longident.name txt in decode name |> Option.map (fun info -> { name; info; fn_loc; callback_arg = List.nth_opt args 0; deps_arg = List.nth_opt args 1; }) | _ -> None end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>