diff --git a/CHANGELOG.md b/CHANGELOG.md index be4f2516c5..81557b99d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ #### :rocket: New Feature -- experimental support of tagged template literals, eg ```sql`select * from ${table}```. https://github.com/rescript-lang/rescript-compiler/pull/6250 +- Experimental support of tagged template literals, eg ```sql`select * from ${table}```. https://github.com/rescript-lang/rescript-compiler/pull/6250 +- Experimental support for generic/custom JSX transforms. https://github.com/rescript-lang/rescript-compiler/pull/6565 #### :bug: Bug Fix diff --git a/jscomp/bsb/bsb_jsx.ml b/jscomp/bsb/bsb_jsx.ml index b4a66de189..b9fbd08661 100644 --- a/jscomp/bsb/bsb_jsx.ml +++ b/jscomp/bsb/bsb_jsx.ml @@ -1,5 +1,5 @@ type version = Jsx_v3 | Jsx_v4 -type module_ = React +type module_ = React | Generic of {moduleName: string} type mode = Classic | Automatic type dependencies = string list @@ -15,7 +15,7 @@ let encode_no_nl jsx = | None -> "" | Some Jsx_v3 -> "3" | Some Jsx_v4 -> "4") - ^ (match jsx.module_ with None -> "" | Some React -> "React") + ^ (match jsx.module_ with None -> "" | Some React -> "React" | Some Generic {moduleName} -> moduleName) ^ match jsx.mode with | None -> "" @@ -55,10 +55,10 @@ let from_map map = `Obj (fun m -> match m.?(Bsb_build_schemas.jsx_module) with - | Some (Str { loc; str }) -> ( + | Some (Str { str }) -> ( match str with | "react" -> module_ := Some React - | _ -> Bsb_exception.errorf ~loc "Unsupported jsx module %s" str) + | moduleName -> module_ := Some (Generic {moduleName})) | Some x -> Bsb_exception.config_error x "Unexpected input (jsx module name) for jsx module" diff --git a/jscomp/bsb/bsb_ninja_rule.ml b/jscomp/bsb/bsb_ninja_rule.ml index 829a8f5bfe..1103a3ac4c 100644 --- a/jscomp/bsb/bsb_ninja_rule.ml +++ b/jscomp/bsb/bsb_ninja_rule.ml @@ -169,7 +169,8 @@ let make_custom_rules ~(gentype_config : Bsb_config_types.gentype_config) | None, None -> ()); (match jsx.module_ with | None -> () - | Some React -> Ext_buffer.add_string buf " -bs-jsx-module react"); + | Some React -> Ext_buffer.add_string buf " -bs-jsx-module react" + | Some Generic {moduleName} -> Ext_buffer.add_string buf (" -bs-jsx-module " ^ moduleName)); (match jsx.mode with | None -> () | Some Classic -> Ext_buffer.add_string buf " -bs-jsx-mode classic" diff --git a/jscomp/bsc/rescript_compiler_main.ml b/jscomp/bsc/rescript_compiler_main.ml index 6a4d63173c..0307e1f708 100644 --- a/jscomp/bsc/rescript_compiler_main.ml +++ b/jscomp/bsc/rescript_compiler_main.ml @@ -251,7 +251,6 @@ let buckle_script_flags : (string * Bsc_args.spec * string) array = "*internal* Set jsx version"; "-bs-jsx-module", string_call (fun i -> - (if i <> "react" then Bsc_args.bad_arg (" Not supported jsx-module : " ^ i)); Js_config.jsx_module := Js_config.jsx_module_of_string i), "*internal* Set jsx module"; diff --git a/jscomp/common/js_config.ml b/jscomp/common/js_config.ml index ef3ad90b60..7602c681e2 100644 --- a/jscomp/common/js_config.ml +++ b/jscomp/common/js_config.ml @@ -25,7 +25,7 @@ (** Browser is not set via command line only for internal use *) type jsx_version = Jsx_v3 | Jsx_v4 -type jsx_module = React +type jsx_module = React | Generic of {moduleName: string} type jsx_mode = Classic | Automatic let no_version_header = ref false @@ -64,6 +64,7 @@ let int_of_jsx_version = function let string_of_jsx_module = function | React -> "react" +| Generic {moduleName} -> moduleName let string_of_jsx_mode = function | Classic -> "classic" @@ -76,7 +77,7 @@ let jsx_version_of_int = function let jsx_module_of_string = function | "react" -> React -| _ -> React +| moduleName -> Generic {moduleName} let jsx_mode_of_string = function | "classic" -> Classic diff --git a/jscomp/common/js_config.mli b/jscomp/common/js_config.mli index f5df0349d3..fd9df5785a 100644 --- a/jscomp/common/js_config.mli +++ b/jscomp/common/js_config.mli @@ -23,7 +23,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) type jsx_version = Jsx_v3 | Jsx_v4 -type jsx_module = React +type jsx_module = React | Generic of {moduleName: string} type jsx_mode = Classic | Automatic (* val get_packages_info : diff --git a/jscomp/frontend/ppx_entry.ml b/jscomp/frontend/ppx_entry.ml index 7f73ef8414..67d50bb61c 100644 --- a/jscomp/frontend/ppx_entry.ml +++ b/jscomp/frontend/ppx_entry.ml @@ -35,7 +35,7 @@ let rewrite_signature (ast : Parsetree.signature) : Parsetree.signature = let jsxVersion = int_of_jsx_version jsxVersion in let jsxModule = string_of_jsx_module !jsx_module in let jsxMode = string_of_jsx_mode !jsx_mode in - Reactjs_jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode ast + Jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode ast in if !Js_config.no_builtin_ppx then ast else @@ -55,7 +55,7 @@ let rewrite_implementation (ast : Parsetree.structure) : Parsetree.structure = let jsxVersion = int_of_jsx_version jsxVersion in let jsxModule = string_of_jsx_module !jsx_module in let jsxMode = string_of_jsx_mode !jsx_mode in - Reactjs_jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode ast + Jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode ast in if !Js_config.no_builtin_ppx then ast else diff --git a/jscomp/syntax/cli/res_cli.ml b/jscomp/syntax/cli/res_cli.ml index bcc4024259..23d9006f35 100644 --- a/jscomp/syntax/cli/res_cli.ml +++ b/jscomp/syntax/cli/res_cli.ml @@ -284,7 +284,7 @@ module CliArgProcessor = struct else exit 1) else let parsetree = - Reactjs_jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode + Jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode parseResult.parsetree in printEngine.printInterface ~width ~filename @@ -300,7 +300,7 @@ module CliArgProcessor = struct else exit 1) else let parsetree = - Reactjs_jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode + Jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode parseResult.parsetree in printEngine.printImplementation ~width ~filename diff --git a/jscomp/syntax/src/react_jsx_common.ml b/jscomp/syntax/src/jsx_common.ml similarity index 88% rename from jscomp/syntax/src/react_jsx_common.ml rename to jscomp/syntax/src/jsx_common.ml index 51c4711032..4281f0580a 100644 --- a/jscomp/syntax/src/react_jsx_common.ml +++ b/jscomp/syntax/src/jsx_common.ml @@ -6,11 +6,14 @@ type jsxConfig = { mutable module_: string; mutable mode: string; mutable nestedModules: string list; - mutable hasReactComponent: bool; + mutable hasComponent: bool; } (* Helper method to look up the [@react.component] attribute *) -let hasAttr (loc, _) = loc.txt = "react.component" +let hasAttr (loc, _) = + match loc.txt with + | "react.component" | "jsx.component" -> true + | _ -> false (* Iterate over the attributes and try to find the [@react.component] attribute *) let hasAttrOnBinding {pvb_attributes} = @@ -20,7 +23,7 @@ let coreTypeOfAttrs attributes = List.find_map (fun ({txt}, payload) -> match (txt, payload) with - | "react.component", PTyp coreType -> Some coreType + | ("react.component" | "jsx.component"), PTyp coreType -> Some coreType | _ -> None) attributes @@ -37,7 +40,7 @@ let typVarsOfCoreType {ptyp_desc} = let raiseError ~loc msg = Location.raise_errorf ~loc msg -let raiseErrorMultipleReactComponent ~loc = +let raiseErrorMultipleComponent ~loc = raiseError ~loc "Only one component definition is allowed for each module. Move to a \ submodule or other file if necessary." diff --git a/jscomp/syntax/src/reactjs_jsx_ppx.ml b/jscomp/syntax/src/jsx_ppx.ml similarity index 88% rename from jscomp/syntax/src/reactjs_jsx_ppx.ml rename to jscomp/syntax/src/jsx_ppx.ml index f6449a6cc1..e362a9c0a5 100644 --- a/jscomp/syntax/src/reactjs_jsx_ppx.ml +++ b/jscomp/syntax/src/jsx_ppx.ml @@ -50,8 +50,8 @@ let updateConfig config payload = let fields = getPayloadFields payload in (match getInt ~key:"version" fields with | None -> () - | Some i -> config.React_jsx_common.version <- i); - (match getString ~key:"module" fields with + | Some i -> config.Jsx_common.version <- i); + (match getString ~key:"module_" fields with | None -> () | Some s -> config.module_ <- s); match getString ~key:"mode" fields with @@ -68,7 +68,7 @@ let getMapper ~config = Reactjs_jsx_v3.jsxMapper ~config in let expr4, module_binding4, transformSignatureItem4, transformStructureItem4 = - Reactjs_jsx_v4.jsxMapper ~config + Jsx_v4.jsxMapper ~config in let expr mapper e = @@ -89,18 +89,18 @@ let getMapper ~config = version = config.version; module_ = config.module_; mode = config.mode; - hasReactComponent = config.hasReactComponent; + hasComponent = config.hasComponent; } in let restoreConfig oldConfig = - config.version <- oldConfig.React_jsx_common.version; + config.version <- oldConfig.Jsx_common.version; config.module_ <- oldConfig.module_; config.mode <- oldConfig.mode; - config.hasReactComponent <- oldConfig.hasReactComponent + config.hasComponent <- oldConfig.hasComponent in let signature mapper items = let oldConfig = saveConfig () in - config.hasReactComponent <- false; + config.hasComponent <- false; let result = List.map (fun item -> @@ -119,7 +119,7 @@ let getMapper ~config = in let structure mapper items = let oldConfig = saveConfig () in - config.hasReactComponent <- false; + config.hasComponent <- false; let result = List.map (fun item -> @@ -143,11 +143,11 @@ let rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode (code : Parsetree.structure) : Parsetree.structure = let config = { - React_jsx_common.version = jsxVersion; + Jsx_common.version = jsxVersion; module_ = jsxModule; mode = jsxMode; nestedModules = []; - hasReactComponent = false; + hasComponent = false; } in let mapper = getMapper ~config in @@ -157,11 +157,11 @@ let rewrite_signature ~jsxVersion ~jsxModule ~jsxMode (code : Parsetree.signature) : Parsetree.signature = let config = { - React_jsx_common.version = jsxVersion; + Jsx_common.version = jsxVersion; module_ = jsxModule; mode = jsxMode; nestedModules = []; - hasReactComponent = false; + hasComponent = false; } in let mapper = getMapper ~config in diff --git a/jscomp/syntax/src/reactjs_jsx_ppx.mli b/jscomp/syntax/src/jsx_ppx.mli similarity index 100% rename from jscomp/syntax/src/reactjs_jsx_ppx.mli rename to jscomp/syntax/src/jsx_ppx.mli diff --git a/jscomp/syntax/src/reactjs_jsx_v4.ml b/jscomp/syntax/src/jsx_v4.ml similarity index 90% rename from jscomp/syntax/src/reactjs_jsx_v4.ml rename to jscomp/syntax/src/jsx_v4.ml index e62054d80f..5246bbd31c 100644 --- a/jscomp/syntax/src/reactjs_jsx_v4.ml +++ b/jscomp/syntax/src/jsx_v4.ml @@ -4,6 +4,8 @@ open Asttypes open Parsetree open Longident +let moduleAccessName config = String.capitalize_ascii config.Jsx_common.module_ + let nolabel = Nolabel let labelled str = Labelled str @@ -27,7 +29,7 @@ let getLabel str = | Optional str | Labelled str -> str | Nolabel -> "" -let optionalAttrs = [React_jsx_common.optionalAttr] +let optionalAttrs = [Jsx_common.optionalAttr] let constantString ~loc str = Ast_helper.Exp.constant ~loc (Pconst_string (str, None)) @@ -93,7 +95,7 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren = | [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] -> acc | (Nolabel, {pexp_loc}) :: _rest -> - React_jsx_common.raiseError ~loc:pexp_loc + Jsx_common.raiseError ~loc:pexp_loc "JSX: found non-labelled argument before the last position" | arg :: rest -> allButLast_ rest (arg :: acc) in @@ -110,13 +112,16 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren = | [(_, childrenExpr)], props -> (childrenExpr, if removeLastPositionUnit then allButLast props else props) | _ -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: somehow there's more than one `children` label" let merlinFocus = ({loc = Location.none; txt = "merlin.focus"}, PStr []) (* Helper method to filter out any attribute that isn't [@react.component] *) -let otherAttrsPure (loc, _) = loc.txt <> "react.component" +let otherAttrsPure (loc, _) = + match loc.txt with + | "react.component" | "jsx.component" -> false + | _ -> true (* Finds the name of the variable the binding is assigned to, otherwise raises Invalid_argument *) let rec getFnName binding = @@ -124,8 +129,8 @@ let rec getFnName binding = | {ppat_desc = Ppat_var {txt}} -> txt | {ppat_desc = Ppat_constraint (pat, _)} -> getFnName pat | {ppat_loc} -> - React_jsx_common.raiseError ~loc:ppat_loc - "react.component calls cannot be destructured." + Jsx_common.raiseError ~loc:ppat_loc + "JSX component calls cannot be destructured." let makeNewBinding binding expression newName = match binding with @@ -138,8 +143,8 @@ let makeNewBinding binding expression newName = pvb_attributes = [merlinFocus]; } | {pvb_loc} -> - React_jsx_common.raiseError ~loc:pvb_loc - "react.component calls cannot be destructured." + Jsx_common.raiseError ~loc:pvb_loc + "JSX component calls cannot be destructured." (* Lookup the filename from the location information on the AST node and turn it into a valid module identifier *) let filenameFromLoc (pstr_loc : Location.t) = @@ -184,7 +189,7 @@ let recordFromProps ~loc ~removeKey callArguments = | [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] -> acc | (Nolabel, {pexp_loc}) :: _rest -> - React_jsx_common.raiseError ~loc:pexp_loc + Jsx_common.raiseError ~loc:pexp_loc "JSX: found non-labelled argument before the last position" | ((Labelled txt, {pexp_loc}) as prop) :: rest | ((Optional txt, {pexp_loc}) as prop) :: rest -> @@ -192,7 +197,7 @@ let recordFromProps ~loc ~removeKey callArguments = match acc with | [] -> removeLastPositionUnitAux rest (prop :: acc) | _ -> - React_jsx_common.raiseError ~loc:pexp_loc + Jsx_common.raiseError ~loc:pexp_loc "JSX: use {...p} {x: v} not {x: v} {...p} \n\ \ multiple spreads {...p} {...p} not allowed." else removeLastPositionUnitAux rest (prop :: acc) @@ -297,8 +302,7 @@ let makeLabelDecls namedTypeList = | hd :: tl -> if mem_label hd tl then let _, label, _, loc, _ = hd in - React_jsx_common.raiseError ~loc "JSX: found the duplicated prop `%s`" - label + Jsx_common.raiseError ~loc "JSX: found the duplicated prop `%s`" label else checkDuplicatedLabel tl in let () = namedTypeList |> List.rev |> checkDuplicatedLabel in @@ -374,13 +378,16 @@ let transformUppercaseCall3 ~config modulePath mapper jsxExprLoc callExprLoc | ListLiteral expression -> ( (* this is a hack to support react components that introspect into their children *) childrenArg := Some expression; - match config.React_jsx_common.mode with + match config.Jsx_common.mode with | "automatic" -> [ ( labelled "children", Exp.apply (Exp.ident - {txt = Ldot (Lident "React", "array"); loc = Location.none}) + { + txt = Ldot (Lident (moduleAccessName config), "array"); + loc = Location.none; + }) [(Nolabel, expression)] ); ] | _ -> @@ -424,16 +431,31 @@ let transformUppercaseCall3 ~config modulePath mapper jsxExprLoc callExprLoc match (!childrenArg, keyProp) with | None, key :: _ -> ( Exp.ident - {loc = Location.none; txt = Ldot (Lident "React", "jsxKeyed")}, + { + loc = Location.none; + txt = Ldot (Lident (moduleAccessName config), "jsxKeyed"); + }, [key; (nolabel, unitExpr ~loc:Location.none)] ) | None, [] -> - (Exp.ident {loc = Location.none; txt = Ldot (Lident "React", "jsx")}, []) + ( Exp.ident + { + loc = Location.none; + txt = Ldot (Lident (moduleAccessName config), "jsx"); + }, + [] ) | Some _, key :: _ -> ( Exp.ident - {loc = Location.none; txt = Ldot (Lident "React", "jsxsKeyed")}, + { + loc = Location.none; + txt = Ldot (Lident (moduleAccessName config), "jsxsKeyed"); + }, [key; (nolabel, unitExpr ~loc:Location.none)] ) | Some _, [] -> - ( Exp.ident {loc = Location.none; txt = Ldot (Lident "React", "jsxs")}, + ( Exp.ident + { + loc = Location.none; + txt = Ldot (Lident (moduleAccessName config), "jsxs"); + }, [] ) in Exp.apply ~loc:jsxExprLoc ~attrs jsxExpr @@ -474,9 +496,15 @@ let transformUppercaseCall3 ~config modulePath mapper jsxExprLoc callExprLoc let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs callArguments id = let componentNameExpr = constantString ~loc:callExprLoc id in - match config.React_jsx_common.mode with + match config.Jsx_common.mode with (* the new jsx transform *) | "automatic" -> + let elementBinding = + match moduleAccessName config with + | "React" -> Lident "ReactDOM" + | generic -> Ldot (Lident generic, "DOM") + in + let children, nonChildrenProps = extractChildren ~removeLastPositionUnit:true ~loc:jsxExprLoc callArguments in @@ -498,7 +526,7 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs Exp.apply ~attrs:optionalAttrs (Exp.ident { - txt = Ldot (Lident "ReactDOM", "someElement"); + txt = Ldot (elementBinding, "someElement"); loc = Location.none; }) [(Nolabel, children)] ); @@ -511,7 +539,10 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs ( labelled "children", Exp.apply (Exp.ident - {txt = Ldot (Lident "React", "array"); loc = Location.none}) + { + txt = Ldot (Lident (moduleAccessName config), "array"); + loc = Location.none; + }) [(Nolabel, expression)] ); ] in @@ -531,17 +562,16 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs match (!childrenArg, keyProp) with | None, key :: _ -> ( Exp.ident - {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxKeyed")}, + {loc = Location.none; txt = Ldot (elementBinding, "jsxKeyed")}, [key; (nolabel, unitExpr ~loc:Location.none)] ) | None, [] -> - ( Exp.ident {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsx")}, - [] ) + (Exp.ident {loc = Location.none; txt = Ldot (elementBinding, "jsx")}, []) | Some _, key :: _ -> ( Exp.ident - {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxsKeyed")}, + {loc = Location.none; txt = Ldot (elementBinding, "jsxsKeyed")}, [key; (nolabel, unitExpr ~loc:Location.none)] ) | Some _, [] -> - ( Exp.ident {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxs")}, + ( Exp.ident {loc = Location.none; txt = Ldot (elementBinding, "jsxs")}, [] ) in Exp.apply ~loc:jsxExprLoc ~attrs jsxExpr @@ -562,7 +592,7 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs "createDOMElementVariadic" (* [@JSX] div(~children= value), coming from
...(value)
*) | {pexp_loc} -> - React_jsx_common.raiseError ~loc:pexp_loc + Jsx_common.raiseError ~loc:pexp_loc "A spread as a DOM element's children don't make sense written \ together. You can simply remove the spread." in @@ -601,11 +631,11 @@ let rec recursivelyTransformNamedArgsForMake expr args newtypes coreType = match expr.pexp_desc with (* TODO: make this show up with a loc. *) | Pexp_fun (Labelled "key", _, _, _) | Pexp_fun (Optional "key", _, _, _) -> - React_jsx_common.raiseError ~loc:expr.pexp_loc + Jsx_common.raiseError ~loc:expr.pexp_loc "Key cannot be accessed inside of a component. Don't worry - you can \ always key a component from its parent!" | Pexp_fun (Labelled "ref", _, _, _) | Pexp_fun (Optional "ref", _, _, _) -> - React_jsx_common.raiseError ~loc:expr.pexp_loc + Jsx_common.raiseError ~loc:expr.pexp_loc "Ref cannot be passed as a normal prop. Please use `forwardRef` API \ instead." | Pexp_fun (arg, default, pattern, expression) @@ -721,18 +751,18 @@ let argToConcreteType types (name, attrs, loc, type_) = let check_string_int_attribute_iter = let attribute _ ({txt; loc}, _) = if txt = "string" || txt = "int" then - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "@string and @int attributes not supported. See \ https://github.com/rescript-lang/rescript-compiler/issues/5724" in {Ast_iterator.default_iterator with attribute} -let checkMultipleReactComponents ~config ~loc = - (* If there is another @react.component, throw error *) - if config.React_jsx_common.hasReactComponent then - React_jsx_common.raiseErrorMultipleReactComponent ~loc - else config.hasReactComponent <- true +let checkMultipleComponents ~config ~loc = + (* If there is another component, throw error *) + if config.Jsx_common.hasComponent then + Jsx_common.raiseErrorMultipleComponent ~loc + else config.hasComponent <- true let modifiedBindingOld binding = let expression = binding.pvb_expr in @@ -757,9 +787,9 @@ let modifiedBindingOld binding = | {pexp_desc = Pexp_constraint (innerFunctionExpression, _typ)} -> spelunkForFunExpression innerFunctionExpression | {pexp_loc} -> - React_jsx_common.raiseError ~loc:pexp_loc - "react.component calls can only be on function definitions or \ - component wrappers (forwardRef, memo)." + Jsx_common.raiseError ~loc:pexp_loc + "JSX component calls can only be on function definitions or component \ + wrappers (forwardRef, memo)." in spelunkForFunExpression expression @@ -882,15 +912,13 @@ let vbMatchExpr namedArgList expr = aux (List.rev namedArgList) let mapBinding ~config ~emptyLoc ~pstr_loc ~fileName ~recFlag binding = - if React_jsx_common.hasAttrOnBinding binding then ( - checkMultipleReactComponents ~config ~loc:pstr_loc; - let binding = React_jsx_common.removeArity binding in - let coreTypeOfAttr = - React_jsx_common.coreTypeOfAttrs binding.pvb_attributes - in + if Jsx_common.hasAttrOnBinding binding then ( + checkMultipleComponents ~config ~loc:pstr_loc; + let binding = Jsx_common.removeArity binding in + let coreTypeOfAttr = Jsx_common.coreTypeOfAttrs binding.pvb_attributes in let typVarsOfCoreType = coreTypeOfAttr - |> Option.map React_jsx_common.typVarsOfCoreType + |> Option.map Jsx_common.typVarsOfCoreType |> Option.value ~default:[] in let bindingLoc = binding.pvb_loc in @@ -947,7 +975,7 @@ let mapBinding ~config ~emptyLoc ~pstr_loc ~fileName ~recFlag binding = (Typ.constr (Location.mknoloc @@ Lident "props") [Typ.any ()]) in let innerExpression = - React_jsx_common.async_component ~async:isAsync innerExpression + Jsx_common.async_component ~async:isAsync innerExpression in let fullExpression = (* React component name should start with uppercase letter *) @@ -1129,17 +1157,17 @@ let transformStructureItem ~config item = pstr_desc = Pstr_primitive ({pval_attributes; pval_type} as value_description); } as pstr -> ( - match List.filter React_jsx_common.hasAttr pval_attributes with + match List.filter Jsx_common.hasAttr pval_attributes with | [] -> [item] | [_] -> - checkMultipleReactComponents ~config ~loc:pstr_loc; + checkMultipleComponents ~config ~loc:pstr_loc; check_string_int_attribute_iter.structure_item check_string_int_attribute_iter item; - let pval_type = React_jsx_common.extractUncurried pval_type in - let coreTypeOfAttr = React_jsx_common.coreTypeOfAttrs pval_attributes in + let pval_type = Jsx_common.extractUncurried pval_type in + let coreTypeOfAttr = Jsx_common.coreTypeOfAttrs pval_attributes in let typVarsOfCoreType = coreTypeOfAttr - |> Option.map React_jsx_common.typVarsOfCoreType + |> Option.map Jsx_common.typVarsOfCoreType |> Option.value ~default:[] in let rec getPropTypes types @@ -1175,7 +1203,10 @@ let transformStructureItem ~config item = (* can't be an arrow because it will defensively uncurry *) let newExternalType = Ptyp_constr - ( {loc = pstr_loc; txt = Ldot (Lident "React", "componentLike")}, + ( { + loc = pstr_loc; + txt = Ldot (Lident (moduleAccessName config), "componentLike"); + }, [retPropsType; innerType] ) in let newStructure = @@ -1192,8 +1223,8 @@ let transformStructureItem ~config item = in [propsRecordType; newStructure] | _ -> - React_jsx_common.raiseError ~loc:pstr_loc - "Only one react.component call can exist on a component at one time") + Jsx_common.raiseError ~loc:pstr_loc + "Only one JSX component call can exist on a component at one time") (* let component = ... *) | {pstr_loc; pstr_desc = Pstr_value (recFlag, valueBindings)} -> ( let fileName = filenameFromLoc pstr_loc in @@ -1232,18 +1263,18 @@ let transformSignatureItem ~config item = psig_loc; psig_desc = Psig_value ({pval_attributes; pval_type} as psig_desc); } as psig -> ( - match List.filter React_jsx_common.hasAttr pval_attributes with + match List.filter Jsx_common.hasAttr pval_attributes with | [] -> [item] | [_] -> - checkMultipleReactComponents ~config ~loc:psig_loc; - let pval_type = React_jsx_common.extractUncurried pval_type in + checkMultipleComponents ~config ~loc:psig_loc; + let pval_type = Jsx_common.extractUncurried pval_type in check_string_int_attribute_iter.signature_item check_string_int_attribute_iter item; let hasForwardRef = ref false in - let coreTypeOfAttr = React_jsx_common.coreTypeOfAttrs pval_attributes in + let coreTypeOfAttr = Jsx_common.coreTypeOfAttrs pval_attributes in let typVarsOfCoreType = coreTypeOfAttr - |> Option.map React_jsx_common.typVarsOfCoreType + |> Option.map Jsx_common.typVarsOfCoreType |> Option.value ~default:[] in let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) = @@ -1290,7 +1321,10 @@ let transformSignatureItem ~config item = (* can't be an arrow because it will defensively uncurry *) let newExternalType = Ptyp_constr - ( {loc = psig_loc; txt = Ldot (Lident "React", "componentLike")}, + ( { + loc = psig_loc; + txt = Ldot (Lident (moduleAccessName config), "componentLike"); + }, [retPropsType; innerType] ) in let newStructure = @@ -1307,8 +1341,8 @@ let transformSignatureItem ~config item = in [propsRecordType; newStructure] | _ -> - React_jsx_common.raiseError ~loc:psig_loc - "Only one react.component call can exist on a component at one time") + Jsx_common.raiseError ~loc:psig_loc + "Only one JSX component call can exist on a component at one time") | _ -> [item] let transformJsxCall ~config mapper callExpression callArguments jsxExprLoc @@ -1317,7 +1351,7 @@ let transformJsxCall ~config mapper callExpression callArguments jsxExprLoc | Pexp_ident caller -> ( match caller with | {txt = Lident "createElement"; loc} -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: `createElement` should be preceeded by a module name." (* Foo.createElement(~prop1=foo, ~prop2=bar, ~children=[], ()) *) | {loc; txt = Ldot (modulePath, ("createElement" | "make"))} -> @@ -1330,18 +1364,18 @@ let transformJsxCall ~config mapper callExpression callArguments jsxExprLoc transformLowercaseCall3 ~config mapper jsxExprLoc loc attrs callArguments id | {txt = Ldot (_, anythingNotCreateElementOrMake); loc} -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: the JSX attribute should be attached to a \ `YourModuleName.createElement` or `YourModuleName.make` call. We saw \ `%s` instead" anythingNotCreateElementOrMake | {txt = Lapply _; loc} -> (* don't think there's ever a case where this is reached *) - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: encountered a weird case while processing the code. Please \ report this!") | _ -> - React_jsx_common.raiseError ~loc:callExpression.pexp_loc + Jsx_common.raiseError ~loc:callExpression.pexp_loc "JSX: `createElement` should be preceeded by a simple, direct module \ name." @@ -1385,7 +1419,8 @@ let expr ~config mapper expression = let fragment = match config.mode with | "automatic" -> - Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsxFragment")} + Exp.ident ~loc + {loc; txt = Ldot (Lident (moduleAccessName config), "jsxFragment")} | "classic" | _ -> Exp.ident ~loc {loc; txt = Ldot (Lident "React", "fragment")} in @@ -1393,10 +1428,13 @@ let expr ~config mapper expression = let recordOfChildren children = Exp.record [(Location.mknoloc (Lident "children"), children)] None in - let applyReactArray expr = + let applyJsxArray expr = Exp.apply (Exp.ident - {txt = Ldot (Lident "React", "array"); loc = Location.none}) + { + txt = Ldot (Lident (moduleAccessName config), "array"); + loc = Location.none; + }) [(Nolabel, expr)] in let countOfChildren = function @@ -1411,11 +1449,11 @@ let expr ~config mapper expression = | [child] -> recordOfChildren child | _ -> ( match config.mode with - | "automatic" -> recordOfChildren @@ applyReactArray childrenExpr + | "automatic" -> recordOfChildren @@ applyJsxArray childrenExpr | "classic" | _ -> emptyRecord ~loc:Location.none)) | _ -> ( match config.mode with - | "automatic" -> recordOfChildren @@ applyReactArray childrenExpr + | "automatic" -> recordOfChildren @@ applyJsxArray childrenExpr | "classic" | _ -> emptyRecord ~loc:Location.none) in let args = @@ -1434,8 +1472,11 @@ let expr ~config mapper expression = (match config.mode with | "automatic" -> if countOfChildren childrenExpr > 1 then - Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsxs")} - else Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsx")} + Exp.ident ~loc + {loc; txt = Ldot (Lident (moduleAccessName config), "jsxs")} + else + Exp.ident ~loc + {loc; txt = Ldot (Lident (moduleAccessName config), "jsx")} | "classic" | _ -> if countOfChildren childrenExpr > 1 then Exp.ident ~loc @@ -1446,8 +1487,7 @@ let expr ~config mapper expression = (* Delegate to the default mapper, a deep identity traversal *) | e -> default_mapper.expr mapper e -let module_binding ~(config : React_jsx_common.jsxConfig) mapper module_binding - = +let module_binding ~(config : Jsx_common.jsxConfig) mapper module_binding = config.nestedModules <- module_binding.pmb_name.txt :: config.nestedModules; let mapped = default_mapper.module_binding mapper module_binding in let () = diff --git a/jscomp/syntax/src/reactjs_jsx_v3.ml b/jscomp/syntax/src/reactjs_jsx_v3.ml index 0ecbb4cf43..83316c9d5c 100644 --- a/jscomp/syntax/src/reactjs_jsx_v3.ml +++ b/jscomp/syntax/src/reactjs_jsx_v3.ml @@ -87,7 +87,7 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren = | [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] -> acc | (Nolabel, {pexp_loc}) :: _rest -> - React_jsx_common.raiseError ~loc:pexp_loc + Jsx_common.raiseError ~loc:pexp_loc "JSX: found non-labelled argument before the last position" | arg :: rest -> allButLast_ rest (arg :: acc) in @@ -104,7 +104,7 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren = | [(_, childrenExpr)], props -> (childrenExpr, if removeLastPositionUnit then allButLast props else props) | _ -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: somehow there's more than one `children` label" let unerasableIgnore loc = @@ -122,7 +122,7 @@ let rec getFnName binding = | {ppat_desc = Ppat_var {txt}} -> txt | {ppat_desc = Ppat_constraint (pat, _)} -> getFnName pat | {ppat_loc} -> - React_jsx_common.raiseError ~loc:ppat_loc + Jsx_common.raiseError ~loc:ppat_loc "react.component calls cannot be destructured." let makeNewBinding binding expression newName = @@ -136,7 +136,7 @@ let makeNewBinding binding expression newName = pvb_attributes = [merlinFocus]; } | {pvb_loc} -> - React_jsx_common.raiseError ~loc:pvb_loc + Jsx_common.raiseError ~loc:pvb_loc "react.component calls cannot be destructured." (* Lookup the value of `props` otherwise raise Invalid_argument error *) @@ -145,7 +145,7 @@ let getPropsNameValue _acc (loc, exp) = | {txt = Lident "props"}, {pexp_desc = Pexp_ident {txt = Lident str}} -> {propsName = str} | {txt; loc}, _ -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "react.component only accepts props as an option, given: { %s }" (Longident.last txt) @@ -170,7 +170,7 @@ let getPropsAttr payload = :: _rest)) -> {propsName = "props"} | Some (PStr ({pstr_desc = Pstr_eval (_, _); pstr_loc} :: _rest)) -> - React_jsx_common.raiseError ~loc:pstr_loc + Jsx_common.raiseError ~loc:pstr_loc "react.component accepts a record config with props as an options." | _ -> defaultProps @@ -368,7 +368,7 @@ let jsxMapper ~config = | Lident path -> Lident (path ^ "Props") | Ldot (ident, path) -> Ldot (ident, path ^ "Props") | _ -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX name can't be the result of function applications" in let props = @@ -407,7 +407,7 @@ let jsxMapper ~config = "createDOMElementVariadic" (* [@JSX] div(~children= value), coming from
...(value)
*) | {pexp_loc} -> - React_jsx_common.raiseError ~loc:pexp_loc + Jsx_common.raiseError ~loc:pexp_loc "A spread as a DOM element's children don't make sense written \ together. You can simply remove the spread." in @@ -450,11 +450,11 @@ let jsxMapper ~config = match expr.pexp_desc with (* TODO: make this show up with a loc. *) | Pexp_fun (Labelled "key", _, _, _) | Pexp_fun (Optional "key", _, _, _) -> - React_jsx_common.raiseError ~loc:expr.pexp_loc + Jsx_common.raiseError ~loc:expr.pexp_loc "Key cannot be accessed inside of a component. Don't worry - you can \ always key a component from its parent!" | Pexp_fun (Labelled "ref", _, _, _) | Pexp_fun (Optional "ref", _, _, _) -> - React_jsx_common.raiseError ~loc:expr.pexp_loc + Jsx_common.raiseError ~loc:expr.pexp_loc "Ref cannot be passed as a normal prop. Either give the prop a \ different name or use the `forwardRef` API instead." | Pexp_fun (arg, default, pattern, expression) @@ -594,10 +594,10 @@ let jsxMapper ~config = ({pval_name = {txt = fnName}; pval_attributes; pval_type} as value_description); } as pstr -> ( - match List.filter React_jsx_common.hasAttr pval_attributes with + match List.filter Jsx_common.hasAttr pval_attributes with | [] -> [item] | [_] -> - let pval_type = React_jsx_common.extractUncurried pval_type in + let pval_type = Jsx_common.extractUncurried pval_type in let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) = match ptyp_desc with | Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest)) @@ -641,15 +641,15 @@ let jsxMapper ~config = in [externalPropsDecl; newStructure] | _ -> - React_jsx_common.raiseError ~loc:pstr_loc + Jsx_common.raiseError ~loc:pstr_loc "Only one react.component call can exist on a component at one time") (* let component = ... *) | {pstr_loc; pstr_desc = Pstr_value (recFlag, valueBindings)} -> ( let fileName = filenameFromLoc pstr_loc in let emptyLoc = Location.in_file fileName in let mapBinding binding = - if React_jsx_common.hasAttrOnBinding binding then - let binding = React_jsx_common.removeArity binding in + if Jsx_common.hasAttrOnBinding binding then + let binding = Jsx_common.removeArity binding in let bindingLoc = binding.pvb_loc in let bindingPatLoc = binding.pvb_pat.ppat_loc in let binding = @@ -689,7 +689,7 @@ let jsxMapper ~config = | {pexp_desc = Pexp_constraint (innerFunctionExpression, _typ)} -> spelunkForFunExpression innerFunctionExpression | {pexp_loc} -> - React_jsx_common.raiseError ~loc:pexp_loc + Jsx_common.raiseError ~loc:pexp_loc "react.component calls can only be on function definitions \ or component wrappers (forwardRef, memo)." in @@ -814,7 +814,7 @@ let jsxMapper ~config = in let bindingWrapper, hasUnit, expression = modifiedBinding binding in let reactComponentAttribute = - try Some (List.find React_jsx_common.hasAttr binding.pvb_attributes) + try Some (List.find Jsx_common.hasAttr binding.pvb_attributes) with Not_found -> None in let _attr_loc, payload = @@ -1037,10 +1037,10 @@ let jsxMapper ~config = ({pval_name = {txt = fnName}; pval_attributes; pval_type} as psig_desc); } as psig -> ( - match List.filter React_jsx_common.hasAttr pval_attributes with + match List.filter Jsx_common.hasAttr pval_attributes with | [] -> [item] | [_] -> - let pval_type = React_jsx_common.extractUncurried pval_type in + let pval_type = Jsx_common.extractUncurried pval_type in let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) = match ptyp_desc with | Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest)) @@ -1084,7 +1084,7 @@ let jsxMapper ~config = in [externalPropsDecl; newStructure] | _ -> - React_jsx_common.raiseError ~loc:psig_loc + Jsx_common.raiseError ~loc:psig_loc "Only one react.component call can exist on a component at one time") | _ -> [item] in @@ -1094,37 +1094,35 @@ let jsxMapper ~config = | Pexp_ident caller -> ( match caller with | {txt = Lident "createElement"; loc} -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: `createElement` should be preceeded by a module name." (* Foo.createElement(~prop1=foo, ~prop2=bar, ~children=[], ()) *) | {loc; txt = Ldot (modulePath, ("createElement" | "make"))} -> ( - match config.React_jsx_common.version with + match config.Jsx_common.version with | 3 -> transformUppercaseCall3 modulePath mapper loc attrs callExpression callArguments - | _ -> - React_jsx_common.raiseError ~loc "JSX: the JSX version must be 3") + | _ -> Jsx_common.raiseError ~loc "JSX: the JSX version must be 3") (* div(~prop1=foo, ~prop2=bar, ~children=[bla], ()) *) (* turn that into ReactDOMRe.createElement(~props=ReactDOMRe.props(~props1=foo, ~props2=bar, ()), [|bla|]) *) | {loc; txt = Lident id} -> ( match config.version with | 3 -> transformLowercaseCall3 mapper loc attrs callArguments id - | _ -> React_jsx_common.raiseError ~loc "JSX: the JSX version must be 3" - ) + | _ -> Jsx_common.raiseError ~loc "JSX: the JSX version must be 3") | {txt = Ldot (_, anythingNotCreateElementOrMake); loc} -> - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: the JSX attribute should be attached to a \ `YourModuleName.createElement` or `YourModuleName.make` call. We \ saw `%s` instead" anythingNotCreateElementOrMake | {txt = Lapply _; loc} -> (* don't think there's ever a case where this is reached *) - React_jsx_common.raiseError ~loc + Jsx_common.raiseError ~loc "JSX: encountered a weird case while processing the code. Please \ report this!") | _ -> - React_jsx_common.raiseError ~loc:callExpression.pexp_loc + Jsx_common.raiseError ~loc:callExpression.pexp_loc "JSX: `createElement` should be preceeded by a simple, direct module \ name." in