123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423openPpxlibmoduleBuilder=Ast_builder.Defaultletis_melange_attr{attr_name={txt=attr}}=letlen=4inString.lengthattr>4&&String.equal(String.subattr0len)"mel."letis_send_pipepval_attributes=List.exists(fun{attr_name={txt=attr}}->String.equalattr"mel.send.pipe")pval_attributesletget_function_namepattern=letrecgopattern=matchpatternwith|Ppat_var{txt=name;_}->Somename|Ppat_constraint(pattern,_)->gopattern.ppat_desc|_->Noneingopatternletget_label=function|Ptyp_constr({txt=Lidentlabel;_},_)->Somelabel|_->None(* Extract the `t` from [@mel.send.pipe: t] *)letget_send_pipepval_attributes=ifis_send_pipepval_attributesthenletfirst_attribute=List.hdpval_attributesinmatchfirst_attribute.attr_payloadwith|PTypcore_type->Somecore_type|_->NoneelseNonelethas_mel_module_attrpval_attributes=List.existsis_melange_attrpval_attributeslethas_ptyp_attributeptyp_attributesattribute=List.exists(fun{attr_name={txt=attr}}->attr=attribute)ptyp_attributesletis_mel_ascore_type=matchcore_typewith|{ptyp_desc=Ptyp_any;ptyp_attributes;_}->has_ptyp_attributeptyp_attributes"mel.as"|_->falseletextract_args_labels_typesaccpval_type=letrecgoacc=function(* In case of being mel.as, ignore those *)|{ptyp_desc=Ptyp_arrow(_label,t1,_t2);_}whenis_mel_ast1->acc|{ptyp_desc=Ptyp_arrow(_label,_t1,t2);_}whenis_mel_ast2->acc|{ptyp_desc=Ptyp_arrow(_label,t1,t2);_}whenis_mel_ast1&&is_mel_ast2->acc|{ptyp_desc=Ptyp_arrow(label,t1,t2);_}->letpattern=Builder.ppat_var~loc:t1.ptyp_loc{loc=t1.ptyp_loc;txt="_"}ingo((label,pattern,t1)::acc)t2|_->accingoaccpval_type(* Insert send_pipe_core_type as a last argument of the function, but not the return type *)letconstruct_pval_with_send_pipesend_pipe_core_typepval_type=letrecinsert_core_type_in_arrowcore_type=matchcore_typewith(* Handle only ptyp and constr.
Missing `| Ptyp_any | Ptyp_var | Ptyp_arrow | Ptyp_tuple | Ptyp_constr
| Ptyp_object | Ptyp_class | Ptyp_alias | Ptyp_variant
| Ptyp_poly | Ptyp_package | Ptyp_extension`
The aren't used in most bindings.
*)|{ptyp_desc=Ptyp_arrow(label,t1,t2);_}->(match(t1.ptyp_desc,t2.ptyp_desc)with(* `constr -> arrow (constr -> constr)` gets transformed into
`constr -> constr -> t -> constr` *)|Ptyp_constr_,Ptyp_arrow(_inner_label,_p1,_p2)->Builder.ptyp_arrow~loc:t1.ptyp_loclabelt1(insert_core_type_in_arrowt2)(* `constr -> constr` gets transformed into `constr -> t -> constr` *)(* `arrow (constr -> constr) -> constr` gets transformed into,
`arrow (constr -> constr) -> t -> constr` *)|_,_->Builder.ptyp_arrow~loc:t2.ptyp_loclabelt1(Builder.ptyp_arrow~loc:t2.ptyp_locNolabelsend_pipe_core_typet2))(* In case of being a single ptyp_* turn into ptyp_* -> t *)|{ptyp_desc=Ptyp_constr({txt=_;loc},_);_}|{ptyp_desc=Ptyp_var_;ptyp_loc=loc;_}->Builder.ptyp_arrow~locNolabelcore_typesend_pipe_core_type(* Here we ignore the Ptyp_any *)|_->core_typeininsert_core_type_in_arrowpval_typeletinject_send_pipe_as_last_argumentpipe_typeargs_labels=matchpipe_typewith|None->args_labels|Somepipe_core_type->pipe_core_type::args_labelsletis_mel_rawexpr=matchexprwith|Pexp_extension({txt="mel.raw";_},_)->true|_->falseletexpression_has_mel_rawexpr=letrecgoexpr=matchexprwith|Pexp_extension({txt="mel.raw";_},_)aspexp_desc->is_mel_rawpexp_desc|Pexp_constraint(expr,_)->is_mel_rawexpr.pexp_desc|Pexp_fun(_,_,_,expr)->goexpr.pexp_desc|_->falseingoexprletraise_failure~locname=[%exprlet()=Printf.printf{|
There is a Melange's external (for example: [@mel.get]) call from native code.
Melange externals are bindings to JavaScript code, which can't run on the server and should be wrapped with browser_only ppx or only run it only on the client side. If there's any issue, try wrapping the expression with a try/catch as a workaround.
|}inraise(Runtime.fail_impossible_action_in_ssr[%eBuilder.pexp_constant~loc(Pconst_string(name,loc,None))])]letmake_implementation~locarity=letrecmake_fun~locarity=matcharitywith|0->[%exprObj.magic()]|_->Builder.pexp_fun~locNolabelNone(Builder.ppat_var~loc{loc;txt="_"})(make_fun~loc(arity-1))inmake_fun~locarityletbrowser_only_alert_mel_raw_message="Since it's a [%mel.raw ...]. This expression is marked to only run on the \
browser where JavaScript can run. You can only use it inside a \
let%browser_only function."letbrowser_only_alert~locstr={attr_name={txt="alert";loc};attr_payload=PStr[[%stribrowser_only[%eBuilder.pexp_constant~loc(Pconst_string(str,loc,None))]];];attr_loc=loc;}letget_function_aritypattern=letrecgoarity=function|Pexp_fun(_,_,_,expr)->go(arity+1)expr.pexp_desc|_->arityingo0patternlettransform_external_arrow~locpval_namepval_attributespval_type=letpipe_type=matchget_send_pipepval_attributeswith|Somecore_type->letpattern=Builder.ppat_var~loc:core_type.ptyp_loc{loc=core_type.ptyp_loc;txt="_"}inSome(Nolabel,pattern,core_type)|None->Noneinletargs_labels_types=extract_args_labels_types[]pval_typeinletfunction_core_type=Builder.ppat_var~loc:pval_name.loc{loc=pval_name.loc;txt=pval_name.txt}inletpval_type_piped=matchpipe_typewith|None->pval_type|Some(_,_,pipe_type)->construct_pval_with_send_pipepipe_typepval_typeinletpat=Builder.ppat_constraint~loc:pval_type.ptyp_locfunction_core_type(Builder.ptyp_poly~loc:pval_type.ptyp_loc[]pval_type_piped)inletarg_labels=inject_send_pipe_as_last_argumentpipe_typeargs_labels_typesinletfunction_expression=List.fold_left(funacc(label,arg_pat,arg_type)->Builder.pexp_fun~loc:arg_type.ptyp_loclabelNonearg_patacc)(raise_failure~loc:pval_type.ptyp_locpval_name.txt)arg_labelsinletvb=Builder.value_binding~loc~pat~expr:function_expressioninAst_helper.Str.valueNonrecursive[vb]letptyp_humanize=function|Ptyp_tuple_->"Tuples"|Ptyp_object_->"Objects"|Ptyp_class_->"Classes"|Ptyp_variant_->"Variants"|Ptyp_extension_->"Extensions"|Ptyp_alias_->"Alias"|Ptyp_poly_->"Polyvariants"|Ptyp_package_->"Packages"|Ptyp_any->"Any"|Ptyp_var_->"Var"|Ptyp_arrow_->"Arrow"|Ptyp_constr_->"Constr"lettransform_externalpval_namepval_attributespval_locpval_type=letloc=pval_locinmatchpval_type.ptyp_descwith|Ptyp_arrow_->transform_external_arrow~locpval_namepval_attributespval_type|Ptyp_var_|Ptyp_any|Ptyp_constr_->(* When mel.send.pipe is used, it's treated as a funcion *)ifOption.is_some(get_send_pipepval_attributes)thentransform_external_arrow~locpval_namepval_attributespval_typeelseletfunction_core_type=Builder.ppat_var~loc{loc;txt=pval_name.txt}inletpattern=Builder.ppat_constraint~locfunction_core_type(Builder.ptyp_poly~loc[]pval_type)inletpattern={patternwithppat_attributes=[browser_only_alert~loc"This expression is marked to only run on the browser where \
JavaScript can run. You can only use it inside a \
let%browser_only function.";];}in[%strilet[%ppattern]=Obj.magic()]|_->[%stri[%%ocaml.error"[server-reason-react.melange_ppx] %s are not supported in native \
externals the same way as melange.ppx support them."(ptyp_humanizepval_type.ptyp_desc)]]lettranform_record_to_object~locrecord=letfields=List.map(fun(label,expression)->Builder.pcf_method~loc(Builder.Located.mklabel~loc,Public,Cfk_concrete(Fresh,expression)))recordinBuilder.pexp_object~loc(Builder.class_structure~self:(Builder.ppat_any~loc)~fields)letvalidate_record_labels~locrecord=List.fold_left(funacc(longident,expression)->matchaccwith|Error_aserror->error|Okacc->(matchlongident.txtwith|Lidentlabel->Ok((label,expression)::acc)|Ldot_|Lapply_->Error(Location.error_extensionf~loc"[server-reason-react.melange_ppx] Js.t objects only \
support labels as keys")))(Ok[])recordclassraise_exception_mapper=object(_self)inheritAst_traverse.mapassupermethod!expressionexpr=matchexpr.pexp_descwith|Pexp_extension({txt="mel.obj";_},PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_record(record,None);pexp_loc},_);_;};])->(matchvalidate_record_labels~loc:pexp_locrecordwith|Okrecord->tranform_record_to_object~loc:pexp_locrecord|Errorextension->Builder.pexp_extension~loc:pexp_locextension)|Pexp_extension({txt="mel.obj";loc},_)->Builder.pexp_extension~loc(Location.error_extensionf~loc:expr.pexp_loc"[server-reason-react.melange_ppx] Js.t objects requires a \
record literal")|_->super#expressionexprmethod!structure_itemitem=matchitem.pstr_descwith(* [%%mel.raw ...] *)|Pstr_extension(({txt="mel.raw";loc},_),_)->[%stri()](* let a _ = [%mel.raw ...] *)|Pstr_value(Nonrecursive,[{pvb_expr={pexp_desc=Pexp_fun(_arg_label,_arg_expression,_fun_pattern,expression);}aspvb_expr;pvb_pat={ppat_desc=Ppat_var{txt=_function_name;_}}aspvb_pattern;pvb_attributes=_;pvb_loc=_;};])whenexpression_has_mel_rawexpression.pexp_desc->letloc=item.pstr_locinletfunction_arity=get_function_aritypvb_expr.pexp_descinletimplementation=make_implementation~locfunction_arityinletfn_pattern={pvb_patternwithppat_attributes=[browser_only_alert~locbrowser_only_alert_mel_raw_message];}in[%strilet[%pfn_pattern]=[%eimplementation]](* let a = [%mel.raw ...] *)|Pstr_value(Nonrecursive,[{pvb_expr=expression;pvb_pat={ppat_desc=Ppat_var{txt=_function_name;_}}aspattern;pvb_attributes=_;pvb_loc=_;};])whenexpression_has_mel_rawexpression.pexp_desc->letloc=item.pstr_locinletfn_pattern={patternwithppat_attributes=[browser_only_alert~locbrowser_only_alert_mel_raw_message];}inletfunction_arity=get_function_arityexpression.pexp_descinletimplementation=make_implementation~locfunction_arityin[%strilet[%pfn_pattern]=[%eimplementation]](* let a: t = [%mel.raw ...] *)|Pstr_value(Nonrecursive,[{pvb_expr=expression;pvb_pat={ppat_desc=Ppat_constraint(constrain_pattern,_constrain_type);};pvb_attributes=_;pvb_loc=_;};])whenexpression_has_mel_rawexpression.pexp_desc->letloc=item.pstr_locinletfn_pattern={constrain_patternwithppat_attributes=[browser_only_alert~locbrowser_only_alert_mel_raw_message];}inletfunction_arity=get_function_arityexpression.pexp_descinletimplementation=make_implementation~locfunction_arityin[%strilet[%pfn_pattern]=[%eimplementation]](* %mel. *)(* external foo: t = "{{JavaScript}}" *)|Pstr_primitive{pval_name;pval_attributes;pval_loc;pval_type}->transform_externalpval_namepval_attributespval_locpval_type|_->super#structure_itemitemendletstructure_mappers=(newraise_exception_mapper)#structuresmoduleDebug=structletrule=letextractor=Ast_pattern.(__')inlethandler~ctxt:_{loc}=[%expr()]inContext_free.Rule.extension(Extension.V3.declare"debug"Extension.Context.expressionextractorhandler)endlet()=Driver.register_transformation~impl:structure_mapper~rules:[Pipe_first.rule;Regex.rule;Double_hash.rule;Debug.rule]"melange-native-ppx"