From b52d0340f1e5074c70ce8bef3287d0484f930313 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Mon, 10 Mar 2025 14:42:37 -0700 Subject: [PATCH 01/14] reason-react-ppx: upgrade ppxlib to 0.36 --- .ocamlformat | 2 +- dune-project | 2 +- ppx/reason_react_ppx.ml | 297 +++++++++++++++++++++------------------- reason-react-ppx.opam | 2 +- 4 files changed, 160 insertions(+), 143 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index ed7d4b31d..9ed4c2620 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1 +1 @@ -version = 0.26.0 +version = 0.27.0 diff --git a/dune-project b/dune-project index 2dd82d324..0f8d95b68 100644 --- a/dune-project +++ b/dune-project @@ -59,7 +59,7 @@ (reason (>= 3.12.0)) (ppxlib - (and (>= 0.33.0) (< 0.36.0))) + (>= 0.36.0)) (merlin :with-test) (ocamlformat (and diff --git a/ppx/reason_react_ppx.ml b/ppx/reason_react_ppx.ml index f37c7be83..3c4ddeba5 100644 --- a/ppx/reason_react_ppx.ml +++ b/ppx/reason_react_ppx.ml @@ -108,7 +108,7 @@ let constantString ~loc str = let safeTypeFromValue valueStr = match getLabel valueStr with - | Some valueStr when String.sub valueStr 0 1 = "_" -> ("T" ^ valueStr) + | Some valueStr when String.sub valueStr 0 1 = "_" -> "T" ^ valueStr | Some valueStr -> valueStr | None -> "" @@ -229,8 +229,10 @@ let hasAttrOnBinding { pvb_attributes; _ } = let getFnName binding = match binding with | { pvb_pat = { ppat_desc = Ppat_var { txt; _ }; _ }; _ } -> txt - | { pvb_loc; _} -> - Location.raise_errorf ~loc:pvb_loc "[@react.component] cannot be used with a destructured binding. Please use it on a `let make = ...` binding instead." + | { pvb_loc; _ } -> + Location.raise_errorf ~loc:pvb_loc + "[@react.component] cannot be used with a destructured binding. Please \ + use it on a `let make = ...` binding instead." let makeNewBinding binding expression newName = match binding with @@ -243,7 +245,9 @@ let makeNewBinding binding expression newName = pvb_attributes = [ merlinFocus ]; } | { pvb_loc; _ } -> - Location.raise_errorf ~loc:pvb_loc "[@react.component] cannot be used with a destructured binding. Please use it on a `let make = ...` binding instead." + Location.raise_errorf ~loc:pvb_loc + "[@react.component] cannot be used with a destructured binding. Please \ + use it on a `let make = ...` binding instead." (* Lookup the value of `props` otherwise raise errorf *) let getPropsNameValue _acc (loc, expr) = @@ -252,7 +256,9 @@ let getPropsNameValue _acc (loc, expr) = { pexp_desc = Pexp_ident { txt = Lident str; _ }; _ } ) -> { propsName = str } | { txt; loc }, _ -> - Location.raise_errorf ~loc "[@react.component] only accepts 'props' as a field, given: %s" (Longident.last_exn txt) + Location.raise_errorf ~loc + "[@react.component] only accepts 'props' as a field, given: %s" + (Longident.last_exn txt) (* Lookup the `props` record or string as part of [@react.component] and store the name for use when rewriting *) @@ -261,22 +267,22 @@ let getPropsAttr payload = match payload with | Some (PStr - ({ - pstr_desc = - Pstr_eval ({ pexp_desc = Pexp_record (recordFields, None); _ }, _); - _; - } - :: _rest)) -> + ({ + pstr_desc = + Pstr_eval ({ pexp_desc = Pexp_record (recordFields, None); _ }, _); + _; + } + :: _rest)) -> List.fold_left getPropsNameValue defaultProps recordFields | Some (PStr - ({ - pstr_desc = - Pstr_eval - ({ pexp_desc = Pexp_ident { txt = Lident "props"; _ }; _ }, _); - _; - } - :: _rest)) -> + ({ + pstr_desc = + Pstr_eval + ({ pexp_desc = Pexp_ident { txt = Lident "props"; _ }; _ }, _); + _; + } + :: _rest)) -> { propsName = "props" } | Some (PStr ({ pstr_desc = Pstr_eval (_, _); pstr_loc; _ } :: _rest)) -> Location.raise_errorf ~loc:pstr_loc @@ -575,6 +581,7 @@ let jsxMapper = pvb_expr = mapper#expression ctxt key; pvb_attributes = []; pvb_loc = loc; + pvb_constraint = None (* TODO(anmonteiro): check constraint *); }; ] (Builder.pexp_apply ~loc:parentExpLoc ~attrs jsxExpr @@ -628,6 +635,7 @@ let jsxMapper = pvb_expr = mapper#expression ctxt key; pvb_attributes = []; pvb_loc = loc; + pvb_constraint = None (* TODO(anmonteiro): check constraint *); }; ] (Builder.pexp_apply ~loc ~attrs jsxExpr @@ -640,58 +648,79 @@ let jsxMapper = | None -> Builder.pexp_apply ~loc ~attrs jsxExpr [ component; props ] in - let rec recursivelyTransformNamedArgsForMake ~ctxt mapper expr list = - let expr = mapper#expression ctxt expr in - match expr.pexp_desc with - | Pexp_fun (Labelled "key", _, _, _) | Pexp_fun (Optional "key", _, _, _) -> - Location.raise_errorf ~loc:expr.pexp_loc - ("~key cannot be accessed from the component props. Please set the key where the component is being used.") - | Pexp_fun - ( ((Optional label | Labelled label) as arg), - default, - pattern, - expression ) -> - let alias = - match pattern with - | { ppat_desc = Ppat_alias (_, { txt; _ }) | Ppat_var { txt; _ }; _ } - -> - txt - | { ppat_desc = Ppat_any; _ } -> "_" - | _ -> label - in - let type_ = - match pattern with - | { ppat_desc = Ppat_constraint (_, type_); _ } -> Some type_ - | _ -> None - in - - recursivelyTransformNamedArgsForMake ~ctxt mapper expression - ((arg, default, pattern, alias, pattern.ppat_loc, type_) :: list) - | Pexp_fun - ( Nolabel, - _, - { - ppat_desc = Ppat_construct ({ txt = Lident "()"; _ }, _) | Ppat_any; - _; - }, - _expression ) -> - (list, None) - | Pexp_fun - ( Nolabel, - _, - { - ppat_desc = - ( Ppat_var { txt; _ } - | Ppat_constraint ({ ppat_desc = Ppat_var { txt; _ }; _ }, _) ); - _; - }, - _expression ) -> - (list, Some txt) - | Pexp_fun (Nolabel, _, pattern, _expression) -> - Location.raise_errorf ~loc:pattern.ppat_loc - "reason-react-ppx: react.component refs only support plain arguments \ - and type annotations." - | _ -> (list, None) + let recursivelyTransformNamedArgsForMake ~ctxt mapper expr = + let rec process_pexp_fun_args acc ~ctxt mapper params expr = + match params with + | [] -> (acc, None) + | { pparam_desc = Pparam_newtype _; _ } :: params -> + (* TODO(anmonteiro): do we need to handle `Pparam_newtype`? *) + process_pexp_fun_args acc ~ctxt mapper params expr + | { pparam_desc = Pparam_val (arg_label, default, arg); _ } :: params -> ( + match (arg_label, default, arg) with + | (Labelled "key" | Optional "key"), _, _ -> + Location.raise_errorf ~loc:expr.pexp_loc + "~key cannot be accessed from the component props. Please set \ + the key where the component is being used." + | ((Optional label | Labelled label) as arg_label), default, arg -> + let alias = + match arg with + | { + ppat_desc = Ppat_alias (_, { txt; _ }) | Ppat_var { txt; _ }; + _; + } -> + txt + | { ppat_desc = Ppat_any; _ } -> "_" + | _ -> label + in + let type_ = + match arg with + | { ppat_desc = Ppat_constraint (_, type_); _ } -> Some type_ + | _ -> None + in + let acc = + (arg_label, default, arg, alias, arg.ppat_loc, type_) :: acc + in + process_pexp_fun_args acc ~ctxt mapper params expr + | ( Nolabel, + _, + { + ppat_desc = + Ppat_construct ({ txt = Lident "()"; _ }, _) | Ppat_any; + _; + } ) -> ( + match params with + | _ :: _ -> + assert false + (* TODO(anmonteiro): forward ref as the non-last arg? *) + | [] -> (acc, None)) + | ( Nolabel, + _, + { + ppat_desc = + ( Ppat_var { txt; _ } + | Ppat_constraint ({ ppat_desc = Ppat_var { txt; _ }; _ }, _) + ); + _; + } ) -> ( + match params with + | _ :: _ -> + assert false + (* TODO(anmonteiro): forward ref as the non-last arg? *) + | [] -> (acc, Some txt)) + | Nolabel, _, arg -> + Location.raise_errorf ~loc:arg.ppat_loc + "reason-react-ppx: react.component refs only support plain \ + arguments and type annotations.") + and process_pexp_fun acc ~ctxt mapper expr = + let expr = mapper#expression ctxt expr in + match expr.pexp_desc with + | Pexp_function (params, _, Pfunction_body body) -> ( + match process_pexp_fun_args acc ~ctxt mapper params body with + | new_init, None -> process_pexp_fun new_init ~ctxt mapper body + | (_, Some _) as ret -> ret) + | _ -> (acc, None) + in + process_pexp_fun [] ~ctxt mapper expr in let argToType types (name, default, _noLabelName, _alias, loc, type_) = @@ -850,7 +879,7 @@ let jsxMapper = let rec spelunkForFunExpression expression = match expression with (* let make = (~prop) => ... *) - | { pexp_desc = Pexp_fun _; _ } -> expression + | { pexp_desc = Pexp_function _; _ } -> expression (* let make = {let foo = bar in (~prop) => ...} *) | { pexp_desc = Pexp_let (_recursive, _vbs, returnExpression); @@ -913,71 +942,71 @@ let jsxMapper = in (* TODO: there is a long-tail of unsupported features inside of blocks - Pexp_letmodule , Pexp_letexception , Pexp_ifthenelse *) + let rec hasFinalUnit = + let rec inner params = + match params with + | [] -> false + | { pparam_desc = Pparam_newtype _; _ } :: params + | { + pparam_desc = Pparam_val ((Labelled _ | Optional _), _, _); + _; + } + :: params -> + inner params + | [ + { + pparam_desc = + Pparam_val + ( Nolabel, + _, + { + ppat_desc = + ( Ppat_construct ({ txt = Lident "()"; _ }, _) + | Ppat_any ); + _; + } ); + _; + }; + ] -> + true + | { pparam_desc = Pparam_val (Nolabel, _, arg); _ } :: _ -> + if hasApplication.contents then false + else + Location.raise_errorf ~loc:arg.ppat_loc + "reason-react-ppx: props need to be labelled \ + arguments.\n\ + \ If you are working with refs be sure to wrap with \ + React.forwardRef.\n\ + \ If your component doesn't have any props, use () \ + (unit) or _ (wildcard) instead of a name." + in + fun params body -> + match body.pexp_desc with + | Pexp_function (params', _, Pfunction_body body) -> + (not (inner params)) && hasFinalUnit params' body + | _ -> inner params + in let rec spelunkForFunExpression expression = match expression with (* let make = (~prop) => ... with no final unit *) - | { - pexp_desc = - Pexp_fun - ( ((Labelled _ | Optional _) as label), - default, - pattern, - ({ pexp_desc = Pexp_fun _; _ } as internalExpression) ); - _; - } -> - let wrap, hasUnit, exp = - spelunkForFunExpression internalExpression - in - ( wrap, - hasUnit, - unerasableIgnoreExp - { - expression with - pexp_desc = Pexp_fun (label, default, pattern, exp); - } ) (* let make = (()) => ... *) (* let make = (_) => ... *) - | { - pexp_desc = - Pexp_fun - ( Nolabel, - _default, - { - ppat_desc = - ( Ppat_construct ({ txt = Lident "()"; _ }, _) - | Ppat_any ); - _; - }, - _internalExpression ); - _; - } -> - ((fun a -> a), true, expression) (* let make = (~prop) => ... *) - | { - pexp_desc = - Pexp_fun - ( (Labelled _ | Optional _), - _default, - _pattern, - _internalExpression ); - _; - } -> - ((fun a -> a), false, unerasableIgnoreExp expression) (* let make = (prop) => ... *) | { pexp_desc = - Pexp_fun (_nolabel, _default, pattern, _internalExpression); + Pexp_function (params, constraint_, Pfunction_body body); _; } -> - if hasApplication.contents then - ((fun a -> a), false, unerasableIgnoreExp expression) - else - Location.raise_errorf ~loc:pattern.ppat_loc - "reason-react-ppx: props need to be labelled arguments.\n\ - \ If you are working with refs be sure to wrap with \ - React.forwardRef.\n\ - \ If your component doesn't have any props, use () \ - (unit) or _ (wildcard) instead of a name." + ( (fun a -> a), + hasFinalUnit params body, + unerasableIgnoreExp + { + expression with + pexp_desc = + Pexp_function + (params, constraint_, Pfunction_body body); + } ) (* let make = {let foo = bar in (~prop) => ...} *) | { pexp_desc = Pexp_let (recursive, vbs, internalExpression); @@ -1047,7 +1076,6 @@ let jsxMapper = let namedArgList, forwardRef = recursivelyTransformNamedArgsForMake ~ctxt mapper (modifiedBindingOld binding) - [] in let namedArgListWithKeyAndRef = ( optional "key", @@ -1133,20 +1161,9 @@ let jsxMapper = let innerExpressionWithRef = match forwardRef with | Some txt -> - { - innerExpression with - pexp_desc = - Pexp_fun - ( nolabel, - None, - { - ppat_desc = Ppat_var { txt; loc = gloc }; - ppat_loc = gloc; - ppat_loc_stack = []; - ppat_attributes = []; - }, - innerExpression ); - } + Builder.pexp_fun ~loc:innerExpression.pexp_loc nolabel None + (Builder.ppat_var ~loc:gloc { txt; loc = gloc }) + innerExpression | None -> innerExpression in let fullExpression = diff --git a/reason-react-ppx.opam b/reason-react-ppx.opam index fd1eef7f7..628c09401 100644 --- a/reason-react-ppx.opam +++ b/reason-react-ppx.opam @@ -17,7 +17,7 @@ depends: [ "dune" {>= "3.9"} "ocaml" {>= "4.14"} "reason" {>= "3.12.0"} - "ppxlib" {>= "0.33.0" & < "0.36.0"} + "ppxlib" {>= "0.36.0"} "merlin" {with-test} "ocamlformat" {= "0.27.0" & with-dev-setup} "odoc" {with-doc} From 9d812a6207b642b94b9d191947889269f961c85d Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sun, 15 Jun 2025 15:11:24 -0700 Subject: [PATCH 02/14] update --- flake.lock | 14 +++++++------- flake.nix | 28 ++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 3bc86dfbb..7816f05db 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1743885887, - "narHash": "sha256-m7/Dlkq+sS9d+Ypg0tg7MIK+UupfRvtLMdtY4JVWc1Q=", + "lastModified": 1750024818, + "narHash": "sha256-VQm07EEDCsb/e7B3Pn1HaqqEEwzlRdaP1QoQGzs5YqQ=", "owner": "nix-ocaml", "repo": "nix-overlays", - "rev": "475a35ae7f8d96254cdb57ee5ccd042c74390562", + "rev": "ed97fe90a3328860f3584bf5ccdbbe4ee5378068", "type": "github" }, "original": { @@ -20,17 +20,17 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1743862455, - "narHash": "sha256-I/QXtrqznq1321mYR9TyMPX/zCWb9iAH64hO+pEBY00=", + "lastModified": 1749984698, + "narHash": "sha256-y6frNvpXfbFWfzcCXs1WTRb0ynRbov0sWT9XJPBe+gQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "06f3516b0397bd241bde2daefc8538fc886c5467", + "rev": "68eb4789b2a9881bcaad2f88fb3771bc7c7f24fa", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "06f3516b0397bd241bde2daefc8538fc886c5467", + "rev": "68eb4789b2a9881bcaad2f88fb3771bc7c7f24fa", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 517e6d960..601ca3dd4 100644 --- a/flake.nix +++ b/flake.nix @@ -11,8 +11,32 @@ let pkgs = nixpkgs.legacyPackages.${system}.extend (self: super: { ocamlPackages = super.ocaml-ng.ocamlPackages_5_3.overrideScope (oself: osuper: { - ppxlib = osuper.ppxlib.overrideAttrs (o: { - propagatedBuildInputs = o.propagatedBuildInputs ++ [ osuper.stdio ]; + pp = osuper.pp.overrideAttrs (_: { + doCheck = false; + }); + reason = osuper.reason.overrideAttrs (_: { + src = builtins.fetchurl { + url = "https://github.com/reasonml/reason/releases/download/3.16.0/reason-3.16.0.tbz"; + sha256 = "0kinqmc1al8n30f8mv7k9zyvkfsgbbn4pasq0s2jm3ilglxf9c27"; + }; + doCheck = false; + patches = [ ]; + }); + ppxlib = osuper.ppxlib.overrideAttrs (_: { + src = builtins.fetchurl { + url = "https://github.com/ocaml-ppx/ppxlib/releases/download/0.36.0/ppxlib-0.36.0.tbz"; + sha256 = "0d54j19vi1khzmw0ffngs8xzjjq07n20q49h85hhhcf52k71pfjs"; + }; + }); + + melange = osuper.melange.overrideAttrs (_: { + src = super.fetchFromGitHub { + owner = "melange-re"; + repo = "melange"; + rev = "70f9593acac50a60179ee963ae3dd57ec832e28c"; + hash = "sha256-+cfxb1yolkhCJicGK5a/r3moLQ3lyAgh37SmpzLTqu4="; + fetchSubmodules = true; + }; }); }); }); From 646519b2865359a6bfae83b039ec66ad9728fd22 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sat, 26 Jul 2025 21:57:47 -0700 Subject: [PATCH 03/14] update ppxlib to 0.36.1 --- flake.lock | 14 +++++++------- flake.nix | 5 ++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 7816f05db..24ab12ae4 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1750024818, - "narHash": "sha256-VQm07EEDCsb/e7B3Pn1HaqqEEwzlRdaP1QoQGzs5YqQ=", + "lastModified": 1753591130, + "narHash": "sha256-+78D0rks7YEGYeT86gkOfRE0f2p+nvbd2GrTDKdMZMI=", "owner": "nix-ocaml", "repo": "nix-overlays", - "rev": "ed97fe90a3328860f3584bf5ccdbbe4ee5378068", + "rev": "b56be97e1b013295fd609297a2f10f93d51fb1b3", "type": "github" }, "original": { @@ -20,17 +20,17 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1749984698, - "narHash": "sha256-y6frNvpXfbFWfzcCXs1WTRb0ynRbov0sWT9XJPBe+gQ=", + "lastModified": 1753549186, + "narHash": "sha256-Znl7rzuxKg/Mdm6AhimcKynM7V3YeNDIcLjBuoBcmNs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "68eb4789b2a9881bcaad2f88fb3771bc7c7f24fa", + "rev": "17f6bd177404d6d43017595c5264756764444ab8", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "68eb4789b2a9881bcaad2f88fb3771bc7c7f24fa", + "rev": "17f6bd177404d6d43017595c5264756764444ab8", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 601ca3dd4..78d13385e 100644 --- a/flake.nix +++ b/flake.nix @@ -24,11 +24,10 @@ }); ppxlib = osuper.ppxlib.overrideAttrs (_: { src = builtins.fetchurl { - url = "https://github.com/ocaml-ppx/ppxlib/releases/download/0.36.0/ppxlib-0.36.0.tbz"; - sha256 = "0d54j19vi1khzmw0ffngs8xzjjq07n20q49h85hhhcf52k71pfjs"; + url = "https://github.com/ocaml-ppx/ppxlib/releases/download/0.36.1/ppxlib-0.36.1.tbz"; + sha256 = "1czgf474himz3wj3qqmy8zrsn0m40yj2z9imlhb491d1xv1vllk1"; }; }); - melange = osuper.melange.overrideAttrs (_: { src = super.fetchFromGitHub { owner = "melange-re"; From adc1d9a68d9f9f492057bde2047751c1db03f629 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sat, 1 Nov 2025 20:43:13 -0700 Subject: [PATCH 04/14] update flake --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 24ab12ae4..c6802698d 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1753591130, - "narHash": "sha256-+78D0rks7YEGYeT86gkOfRE0f2p+nvbd2GrTDKdMZMI=", + "lastModified": 1762036426, + "narHash": "sha256-Club0sjHqjmU3J/DKHlbGxeh8B+OXIMy9LGrWdk0Tjo=", "owner": "nix-ocaml", "repo": "nix-overlays", - "rev": "b56be97e1b013295fd609297a2f10f93d51fb1b3", + "rev": "bf8a7cd43456f70577af1f6b69b5925b32f410e6", "type": "github" }, "original": { @@ -20,17 +20,17 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1753549186, - "narHash": "sha256-Znl7rzuxKg/Mdm6AhimcKynM7V3YeNDIcLjBuoBcmNs=", + "lastModified": 1761994314, + "narHash": "sha256-IOZofbuQ+gnM4t/nkN9wc1LvRDLKNhEftLILRBa+1Gc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "17f6bd177404d6d43017595c5264756764444ab8", + "rev": "1e0996604d71646c3061842452df7f03f3eb26ab", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "17f6bd177404d6d43017595c5264756764444ab8", + "rev": "1e0996604d71646c3061842452df7f03f3eb26ab", "type": "github" } }, From db7376d76aa45c1202e424da1ba978090612ddfb Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sat, 1 Nov 2025 20:44:09 -0700 Subject: [PATCH 05/14] remove overrides --- flake.nix | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/flake.nix b/flake.nix index 78d13385e..1d833dfb6 100644 --- a/flake.nix +++ b/flake.nix @@ -10,34 +10,7 @@ forAllSystems = f: nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (system: let pkgs = nixpkgs.legacyPackages.${system}.extend (self: super: { - ocamlPackages = super.ocaml-ng.ocamlPackages_5_3.overrideScope (oself: osuper: { - pp = osuper.pp.overrideAttrs (_: { - doCheck = false; - }); - reason = osuper.reason.overrideAttrs (_: { - src = builtins.fetchurl { - url = "https://github.com/reasonml/reason/releases/download/3.16.0/reason-3.16.0.tbz"; - sha256 = "0kinqmc1al8n30f8mv7k9zyvkfsgbbn4pasq0s2jm3ilglxf9c27"; - }; - doCheck = false; - patches = [ ]; - }); - ppxlib = osuper.ppxlib.overrideAttrs (_: { - src = builtins.fetchurl { - url = "https://github.com/ocaml-ppx/ppxlib/releases/download/0.36.1/ppxlib-0.36.1.tbz"; - sha256 = "1czgf474himz3wj3qqmy8zrsn0m40yj2z9imlhb491d1xv1vllk1"; - }; - }); - melange = osuper.melange.overrideAttrs (_: { - src = super.fetchFromGitHub { - owner = "melange-re"; - repo = "melange"; - rev = "70f9593acac50a60179ee963ae3dd57ec832e28c"; - hash = "sha256-+cfxb1yolkhCJicGK5a/r3moLQ3lyAgh37SmpzLTqu4="; - fetchSubmodules = true; - }; - }); - }); + ocamlPackages = super.ocaml-ng.ocamlPackages_5_3; }); in f pkgs); From 65be910a73abc6d3a796eee5ec34212088d59d17 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sat, 1 Nov 2025 20:49:46 -0700 Subject: [PATCH 06/14] 5.3 --- .github/workflows/opam.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/opam.yml b/.github/workflows/opam.yml index 74489f6b6..6e1d7a515 100644 --- a/.github/workflows/opam.yml +++ b/.github/workflows/opam.yml @@ -24,7 +24,7 @@ jobs: # disabling this for now ocaml-compiler: - - ocaml-base-compiler.5.2.0 + - ocaml-base-compiler.5.3.0 runs-on: ${{ matrix.os }} From 50dd207de2cd2fe0b1cbbd789d4929ca6d612956 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Thu, 11 Dec 2025 00:53:44 -0800 Subject: [PATCH 07/14] update flake --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index c6802698d..d261bb852 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1762036426, - "narHash": "sha256-Club0sjHqjmU3J/DKHlbGxeh8B+OXIMy9LGrWdk0Tjo=", + "lastModified": 1765046834, + "narHash": "sha256-wkpUdgsz82kr3KEhTREXmP4OqlDjc+wk0k81C1QyQek=", "owner": "nix-ocaml", "repo": "nix-overlays", - "rev": "bf8a7cd43456f70577af1f6b69b5925b32f410e6", + "rev": "5907e1cd3e4615151d4a4777de2ce4f422da7932", "type": "github" }, "original": { @@ -20,17 +20,17 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1761994314, - "narHash": "sha256-IOZofbuQ+gnM4t/nkN9wc1LvRDLKNhEftLILRBa+1Gc=", + "lastModified": 1764547213, + "narHash": "sha256-pGXM6frMKLRJmeMcQ228O1QQBuNEUjzmWx9uBd+CbXM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1e0996604d71646c3061842452df7f03f3eb26ab", + "rev": "64de27c1c985895c1a9f92aaeaab4e6a4c0960f5", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "1e0996604d71646c3061842452df7f03f3eb26ab", + "rev": "64de27c1c985895c1a9f92aaeaab4e6a4c0960f5", "type": "github" } }, From 11a188e9f4c12ba017ae15a00017f361c0f1bdc4 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Thu, 11 Dec 2025 01:04:00 -0800 Subject: [PATCH 08/14] melange 6 --- dune-project | 2 +- reason-react.opam | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dune-project b/dune-project index 0f8d95b68..b15524429 100644 --- a/dune-project +++ b/dune-project @@ -34,7 +34,7 @@ "reason-react helps you use Reason to build React components with deeply integrated, strong, static type safety.\n\nIt is designed and built by people using Reason and React in large, mission critical production React codebases.") (depends ocaml - (melange (<= 5.1.0)) + (melange (>= 6.0.0)) (reason-react-ppx (= :version)) (reason diff --git a/reason-react.opam b/reason-react.opam index 0bfcf8c3e..43262c720 100644 --- a/reason-react.opam +++ b/reason-react.opam @@ -19,7 +19,7 @@ bug-reports: "https://github.com/reasonml/reason-react/issues" depends: [ "dune" {>= "3.9"} "ocaml" - "melange" {<= "5.1.0"} + "melange" {>= "6.0.0"} "reason-react-ppx" {= version} "reason" {>= "3.12.0"} "ocaml-lsp-server" {with-dev-setup} From 170f95550a93df24e89955bc41f7c57db9dcb6ca Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Fri, 12 Dec 2025 22:24:54 -0800 Subject: [PATCH 09/14] upgrade opam-check-npm-deps --- flake.lock | 14 +++++++------- flake.nix | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index d261bb852..a22555bf3 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1765046834, - "narHash": "sha256-wkpUdgsz82kr3KEhTREXmP4OqlDjc+wk0k81C1QyQek=", + "lastModified": 1765606732, + "narHash": "sha256-mKZOKNpt6nu1anRiYzW+DSucN9nnTazTHJABTzfdb1A=", "owner": "nix-ocaml", "repo": "nix-overlays", - "rev": "5907e1cd3e4615151d4a4777de2ce4f422da7932", + "rev": "232c8143c568cd46c71d99199477d752d5cb634b", "type": "github" }, "original": { @@ -20,17 +20,17 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1764547213, - "narHash": "sha256-pGXM6frMKLRJmeMcQ228O1QQBuNEUjzmWx9uBd+CbXM=", + "lastModified": 1765403794, + "narHash": "sha256-bOk4vZjzk419pIkmMWrr8PTg0fK2Oph/owZUAPHWwIE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "64de27c1c985895c1a9f92aaeaab4e6a4c0960f5", + "rev": "6f313d8e9be4d7db523962ecc3ce97c951bacb1f", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "64de27c1c985895c1a9f92aaeaab4e6a4c0960f5", + "rev": "6f313d8e9be4d7db523962ecc3ce97c951bacb1f", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 1d833dfb6..e237ca131 100644 --- a/flake.nix +++ b/flake.nix @@ -85,7 +85,7 @@ ]); propagatedBuildInputs = with pkgs.ocamlPackages; [ merlin ]; }; - packages = self.packages.${pkgs.system}; + packages = self.packages.${pkgs.stdenv.hostPlatform.system}; in { default = makeDevShell { inherit packages; }; From 97f06e4c19d861293943c972374371638250dcf5 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sat, 20 Dec 2025 20:49:55 -0800 Subject: [PATCH 10/14] check-npm-deps --- package-lock.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package-lock.json b/package-lock.json index 8917e8778..c0f0812d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -128,6 +128,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.20.tgz", "integrity": "sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", @@ -1582,6 +1583,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001517", "electron-to-chromium": "^1.4.477", @@ -4924,6 +4926,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -4933,6 +4936,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "dev": true, + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, From cf2abdaddf0ca00a0d5b0b39fc362c799791d4d2 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 23 Dec 2025 13:14:29 -0800 Subject: [PATCH 11/14] update flakes --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index a22555bf3..fd3b953f2 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1765606732, - "narHash": "sha256-mKZOKNpt6nu1anRiYzW+DSucN9nnTazTHJABTzfdb1A=", + "lastModified": 1766482245, + "narHash": "sha256-EoXpMYCUPBjvjbjd2gOMqXJg4zAmVUW0t+sUeQwPbG4=", "owner": "nix-ocaml", "repo": "nix-overlays", - "rev": "232c8143c568cd46c71d99199477d752d5cb634b", + "rev": "b0e1699cda4b43223a58d2d1964da80b727e009e", "type": "github" }, "original": { @@ -20,17 +20,17 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1765403794, - "narHash": "sha256-bOk4vZjzk419pIkmMWrr8PTg0fK2Oph/owZUAPHWwIE=", + "lastModified": 1766427476, + "narHash": "sha256-KHgJHYGYuHUtJPBjczN0kFrWHmdfUXPa0Km6Yq/ELEE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6f313d8e9be4d7db523962ecc3ce97c951bacb1f", + "rev": "6dd5b55337d892a8a441aaad31bf1a4165b453bc", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "6f313d8e9be4d7db523962ecc3ce97c951bacb1f", + "rev": "6dd5b55337d892a8a441aaad31bf1a4165b453bc", "type": "github" } }, From b921996363a1b8cd711a957df4916a22f3ad1699 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 23 Dec 2025 13:16:13 -0800 Subject: [PATCH 12/14] promote tests --- ppx/test/component-without-make.t/run.t | 13 ++++-- ppx/test/component.t/run.t | 60 ++++++++++++------------- ppx/test/functor.t/run.t | 7 ++- ppx/test/key-as-prop-error.t/run.t | 4 +- ppx/test/locations-check.t | 2 +- ppx/test/lower.t/run.t | 2 +- ppx/test/signature.t/run.t | 8 ++-- 7 files changed, 48 insertions(+), 48 deletions(-) diff --git a/ppx/test/component-without-make.t/run.t b/ppx/test/component-without-make.t/run.t index b15353338..90a1a36e9 100644 --- a/ppx/test/component-without-make.t/run.t +++ b/ppx/test/component-without-make.t/run.t @@ -4,7 +4,10 @@ We need to output ML syntax here, otherwise refmt could not parse it. module X_as_main_function = struct external xProps : ?key:string -> unit -> < > Js.t = ""[@@mel.obj ] - let x () = ReactDOM.jsx "div" (((ReactDOM.domProps)[@merlin.hide ]) ()) + let x = + ((fun () -> + ReactDOM.jsx "div" (((ReactDOM.domProps)[@merlin.hide ]) ())) + [@warning "-16"]) let x = let Output$X_as_main_function$x (Props : < > Js.t) = x () in Output$X_as_main_function$x @@ -44,9 +47,11 @@ We need to output ML syntax here, otherwise refmt could not parse it. module Valid_case = struct external makeProps : ?key:string -> unit -> < > Js.t = ""[@@mel.obj ] - let make () = - React.jsx Component_with_x_as_main_function.x - (Component_with_x_as_main_function.xProps ()) + let make = + ((fun () -> + React.jsx Component_with_x_as_main_function.x + (Component_with_x_as_main_function.xProps ())) + [@warning "-16"]) let make = let Output$Valid_case (Props : < > Js.t) = make () in Output$Valid_case diff --git a/ppx/test/component.t/run.t b/ppx/test/component.t/run.t index 22e4bcbf5..e4abb74f5 100644 --- a/ppx/test/component.t/run.t +++ b/ppx/test/component.t/run.t @@ -54,11 +54,10 @@ We need to output ML syntax here, otherwise refmt could not parse it. ""[@@mel.obj ] let make = ((fun ~children -> - ((fun ~buttonRef -> - ReactDOM.jsx "button" - (((ReactDOM.domProps)[@merlin.hide ]) ~children - ~ref:buttonRef ~className:"FancyButton" ())) - [@warning "-16"])) + fun ~buttonRef -> + ReactDOM.jsx "button" + (((ReactDOM.domProps)[@merlin.hide ]) ~children ~ref:buttonRef + ~className:"FancyButton" ())) [@warning "-16"]) let make = React.forwardRef @@ -77,11 +76,10 @@ We need to output ML syntax here, otherwise refmt could not parse it. = ""[@@mel.obj ] let make = ((fun ~children -> - ((fun ~ref -> - ReactDOM.jsx "button" - (((ReactDOM.domProps)[@merlin.hide ]) ~children ~ref - ~className:"FancyButton" ())) - [@warning "-16"])) + fun ~ref -> + ReactDOM.jsx "button" + (((ReactDOM.domProps)[@merlin.hide ]) ~children ~ref + ~className:"FancyButton" ())) [@warning "-16"]) let make = let Output$Ref_as_prop @@ -99,12 +97,11 @@ We need to output ML syntax here, otherwise refmt could not parse it. = ""[@@mel.obj ] let make = ((fun ~name -> - ((fun ?isDisabled -> - let onClick event = Js.log event in - ReactDOM.jsx "button" - (((ReactDOM.domProps)[@merlin.hide ]) ~name ~onClick - ~disabled:isDisabled ())) - [@warning "-16"])) + fun ?isDisabled -> + let onClick event = Js.log event in + ReactDOM.jsx "button" + (((ReactDOM.domProps)[@merlin.hide ]) ~name ~onClick + ~disabled:isDisabled ())) [@warning "-16"]) let make = let Output$Onclick_handler_button @@ -141,22 +138,22 @@ We need to output ML syntax here, otherwise refmt could not parse it. ""[@@mel.obj ] let make = ((fun ~children -> - ((fun ~moreProps -> - ReactDOM.jsxs "html" - (((ReactDOM.domProps)[@merlin.hide ]) - ~children:(React.array - [|(ReactDOM.jsx "head" - (((ReactDOM.domProps)[@merlin.hide ]) - ~children:(ReactDOM.jsx "title" - (((ReactDOM.domProps) - [@merlin.hide ]) - ~children:(React.string - ("SSR React " + fun ~moreProps -> + ReactDOM.jsxs "html" + (((ReactDOM.domProps)[@merlin.hide ]) + ~children:(React.array + [|(ReactDOM.jsx "head" + (((ReactDOM.domProps)[@merlin.hide ]) + ~children:(ReactDOM.jsx "title" + (((ReactDOM.domProps) + [@merlin.hide ]) + ~children:(React.string + ("SSR React " ^ moreProps)) - ())) ()));(ReactDOM.jsxs - "body" - (((ReactDOM.domProps) + ())) ()));(ReactDOM.jsxs + "body" + (((ReactDOM.domProps) [@merlin.hide ]) ~children:( @@ -178,8 +175,7 @@ We need to output ML syntax here, otherwise refmt could not parse it. ~src:"/static/client.js" ()))|]) ()))|]) - ())) - [@warning "-16"])) + ())) [@warning "-16"]) let make = let Output$Uppercase_with_SSR_components diff --git a/ppx/test/functor.t/run.t b/ppx/test/functor.t/run.t index 8fc49a45c..f9eeca3ad 100644 --- a/ppx/test/functor.t/run.t +++ b/ppx/test/functor.t/run.t @@ -10,10 +10,9 @@ We need to output ML syntax here, otherwise refmt could not parse it. [@@mel.obj ] let make = ((fun ~a -> - ((fun ~b -> - print_endline "This function should be named `Test$Func`" M.x; - ReactDOM.jsx "div" (((ReactDOM.domProps)[@merlin.hide ]) ())) - [@warning "-16"])) + fun ~b -> + print_endline "This function should be named `Test$Func`" M.x; + ReactDOM.jsx "div" (((ReactDOM.domProps)[@merlin.hide ]) ())) [@warning "-16"]) let make = let Output$Func (Props : < a: 'a ;b: 'b > Js.t) = diff --git a/ppx/test/key-as-prop-error.t/run.t b/ppx/test/key-as-prop-error.t/run.t index 99bac040b..a4bbab3cc 100644 --- a/ppx/test/key-as-prop-error.t/run.t +++ b/ppx/test/key-as-prop-error.t/run.t @@ -15,8 +15,8 @@ Test some locations in reason-react components > EOF $ dune build - File "component.re", line 2, characters 11-51: + File "component.re", line 2, characters 21-51: 2 | let make = (~key) =>
key->React.string
; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: ~key cannot be accessed from the component props. Please set the key where the component is being used. [1] diff --git a/ppx/test/locations-check.t b/ppx/test/locations-check.t index 0520bb96e..2540c5845 100644 --- a/ppx/test/locations-check.t +++ b/ppx/test/locations-check.t @@ -11,7 +11,7 @@ With no annotations (ppx does nothing) > EOF $ reason-react-ppx -check -locations-check input.ml - let make ~foo ~bar = + let make ~foo ~bar = div ~children:[React.string foo; (bar |> string_of_int) |> React.string] () With JSX annotation diff --git a/ppx/test/lower.t/run.t b/ppx/test/lower.t/run.t index 808a6a190..fcb12ab62 100644 --- a/ppx/test/lower.t/run.t +++ b/ppx/test/lower.t/run.t @@ -14,7 +14,7 @@ ReactDOM.jsx( "div", ([@merlin.hide] ReactDOM.domProps)( - ~dangerouslySetInnerHTML={"__html": text}, + ~dangerouslySetInnerHTML={ "__html": text }, (), ), ); diff --git a/ppx/test/signature.t/run.t b/ppx/test/signature.t/run.t index 268a4ea9b..f398d249f 100644 --- a/ppx/test/signature.t/run.t +++ b/ppx/test/signature.t/run.t @@ -41,17 +41,17 @@ module MyPropIsOptionBool = { [@mel.obj] external makeProps: - (~myProp: bool=?, ~key: string=?, unit) => {. "myProp": option(bool)}; + (~myProp: bool=?, ~key: string=?, unit) => {. "myProp": option(bool) }; external make: - React.componentLike({. "myProp": option(bool)}, React.element) = + React.componentLike({. "myProp": option(bool) }, React.element) = "A"; }; module MyPropIsOptionOptionBool = { [@mel.obj] external makeProps: (~myProp: option(bool)=?, ~key: string=?, unit) => - {. "myProp": option(option(bool))}; + {. "myProp": option(option(bool)) }; external make: - React.componentLike({. "myProp": option(option(bool))}, React.element) = + React.componentLike({. "myProp": option(option(bool)) }, React.element) = "B"; }; From 4af252731ee812a5f32872f4aaa643b25b8a9078 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 23 Dec 2025 14:37:07 -0800 Subject: [PATCH 13/14] 5.2 again --- .github/workflows/opam.yml | 2 +- flake.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/opam.yml b/.github/workflows/opam.yml index 6e1d7a515..74489f6b6 100644 --- a/.github/workflows/opam.yml +++ b/.github/workflows/opam.yml @@ -24,7 +24,7 @@ jobs: # disabling this for now ocaml-compiler: - - ocaml-base-compiler.5.3.0 + - ocaml-base-compiler.5.2.0 runs-on: ${{ matrix.os }} diff --git a/flake.nix b/flake.nix index e237ca131..32da479e8 100644 --- a/flake.nix +++ b/flake.nix @@ -10,7 +10,7 @@ forAllSystems = f: nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (system: let pkgs = nixpkgs.legacyPackages.${system}.extend (self: super: { - ocamlPackages = super.ocaml-ng.ocamlPackages_5_3; + ocamlPackages = super.ocaml-ng.ocamlPackages_5_2; }); in f pkgs); From dca49d7b6ce6b1305d1e5ecd127ea46fb0fe53a4 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 23 Dec 2025 14:43:06 -0800 Subject: [PATCH 14/14] works --- flake.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 32da479e8..db901e100 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ packages = forAllSystems (pkgs: let inherit (pkgs.ocamlPackages) - buildDunePackage melange merlin ppxlib reason; + buildDunePackage melange merlin ppxlib_gt_0_37 reason; packages = rec { reason-react-ppx = buildDunePackage { pname = "reason-react-ppx"; @@ -40,7 +40,7 @@ # Due to a Reason version mismatch, the generated OCaml PPX diff # looks different doCheck = false; - propagatedBuildInputs = [ ppxlib ]; + propagatedBuildInputs = [ ppxlib_gt_0_37 ]; }; reason-react = buildDunePackage { @@ -72,7 +72,7 @@ let makeDevShell = { packages, release-mode ? false }: pkgs.mkShell { - # dontDetectOcamlConflicts = true; + dontDetectOcamlConflicts = true; inputsFrom = pkgs.lib.attrValues packages; nativeBuildInputs = with pkgs.ocamlPackages; [ ocamlformat pkgs.nodejs_latest ]