123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484openRpc.TypesopenIdlopenCodegenletget_descriptiondesc=letescape=lettranslate=function(* Escape special XML (and HTML) chars that might become tags *)|'<'->Some"<"|'>'->Some">"|'&'->Some"&"(* Escape some special markdown chars - these are not part of ocamldoc markup language *)|('*'|'_'|'['|']'|'('|')'|'#'|'!')asc->Some("\\"^String.make1c)|_->NoneinInternals.encodetranslateinString.concat" "desc|>escapeletrecstring_of_t:typea.atyp->stringlist=letof_basic:typeb.bbasic->string=function|Int->"int"|Int32->"int32"|Int64->"int64"|Bool->"bool"|Float->"float"|String->"string"|Char->"char"inletprinttxt=[txt]infunction|Basicb->print(of_basicb)|DateTime->print(of_basicString)|Base64->print(of_basicString)|Struct{sname;_}->printsname|Variant{vname;_}->printvname|Arrayt->string_of_tt@print" list"|Listt->string_of_tt@print" list"|Dict(key,v)->print(Printf.sprintf"(%s * "(of_basickey))@string_of_tv@print") list"|Unit->print"unit"|Optionx->string_of_tx@print" option"|Tuple(a,b)->string_of_ta@print" * "@string_of_tb|Tuple3(a,b,c)->string_of_ta@print" * "@string_of_tb@print" * "@string_of_tc|Tuple4(a,b,c,d)->string_of_ta@print" * "@string_of_tb@print" * "@string_of_tc@print" * "@string_of_td|Abstract_->print"<abstract>"letdefinition_of_t:typea.atyp->stringlist=function|Struct_->["struct { ... }"]|Variant_->["variant { ... }"]|ty->string_of_ttyletrecocaml_patt_of_t:typea.atyp->string=funty->letof_basic:typeb.bbasic->string=function|Int->"int"|Int32->"int32"|Int64->"int64"|Bool->"bool"|Float->"float"|String->"str"|Char->"char"inmatchtywith|Basicb->of_basicb|DateTime->"datetime"|Base64->"base64"|Structs->s.Rpc.Types.sname|Variant_->"v"|Arrayt->Printf.sprintf"%s_list"(ocaml_patt_of_tt)|Listt->Printf.sprintf"%s_list"(ocaml_patt_of_tt)|Dict_->"dict"|Unit->"()"|Optionx->Printf.sprintf"%s_opt"(ocaml_patt_of_tx)|Tuple(a,b)->Printf.sprintf"(%s,%s)"(ocaml_patt_of_ta)(ocaml_patt_of_tb)|Tuple3(a,b,c)->Printf.sprintf"(%s,%s,%s)"(ocaml_patt_of_ta)(ocaml_patt_of_tb)(ocaml_patt_of_tc)|Tuple4(a,b,c,d)->Printf.sprintf"(%s,%s,%s,%s)"(ocaml_patt_of_ta)(ocaml_patt_of_tb)(ocaml_patt_of_tc)(ocaml_patt_of_td)|Abstract_->"abstract"letrpc_of:typea.atyp->string->Rpc.t=funtyhint->Rpcmarshal.marshalty(Rpc_genfake.gen_nicetyhint)lettableheadingsrows=(* Slightly more convenient to have columns sometimes. This
also ensures each row has the correct number of entries. *)lettransposemat=letrecinnerr=letsafe_hd=function|hd::_->hd|_->""inletsafe_tl=function|_::tl->tl|_->[]inmatchrwith|[]::_->[]|_->List.(mapsafe_hdr::inner(mapsafe_tlr))ininnermatinletcolumns=transpose(headings::rows)inletall_rows=transposecolumnsinletcol_widths=letcol_widthcol=List.fold_leftmax0colinletwidths=List.mapString.lengthinList.map(funcol->col_width(widthscol))columnsinletpadcns=Printf.sprintf"%s%s"s(String.make(n-String.lengths)c)inletpadfns=List.map(pad' ')col_widthsinletpad_rowrow=List.map2(funfnx->fnx)padfnsrowinletpadded=List.mappad_rowall_rowsinletrow_to_stringrow=Printf.sprintf" %s "(String.concat" | "row)inletseparator=Printf.sprintf"-%s-"(String.concat"-|-"(List.map(funwidth->pad'-'width"")col_widths))inrow_to_string(List.hdpadded)::separator::List.maprow_to_string(List.tlpadded)letlinkuritext=Printf.sprintf"[%s](%s)"texturileth1txt=[Printf.sprintf"# %s"txt](*txt; String.make (String.length txt) '=' ] *)leth2txt=[Printf.sprintf"## %s"txt](*txt; String.make (String.length txt) '-' ] *)leth3txt=[Printf.sprintf"### %s"txt]leth4txt=[Printf.sprintf"#### %s"txt]leth5txt=[Printf.sprintf"##### %s"txt]leth6txt=[Printf.sprintf"###### %s"txt]lethrule=["---"](* Function inputs and outputs in a table *)letof_argsargs=letrow_of_arg(is_in,Param.Boxedarg)=matchis_in,arg.Param.typedef.tywith|false,Unit->[]|_->letname=matcharg.Param.namewith|Somes->s|None->"unnamed"inletdirection=ifis_inthen"in"else"out"inletty=arg.Param.typedef.nameinletdescription=get_descriptionarg.Param.descriptionin[name;direction;ty;description]intable["Name";"Direction";"Type";"Description"](List.filter(funl->List.lengthl>0)(List.maprow_of_argargs))letof_struct_fields:'aboxed_fieldlist->stringlist=funall->letof_row(BoxedFieldf)=letty=string_of_tf.fieldin[f.fname;String.concat""ty;get_descriptionf.fdescription]intable["Name";"Type";"Description"](List.mapof_rowall)letof_variant_tags:'aboxed_taglist->stringlist=funall->letof_row(BoxedTagt)=letty=string_of_tt.tcontentsin[t.tname;String.concat""ty;get_descriptiont.tdescription]intable["Name";"Type";"Description"](List.mapof_rowall)letof_type_decl_(BoxedDeftast')=ifList.memt'default_typesthen[]else(letname=t.nameinletheader=[Printf.sprintf"### %s"name]inletexample_tys=Rpc_genfake.genall0namet.tyinletmarshalled=List.map(funexample->Rpcmarshal.marshalt.tyexample)example_tysinletexample=("```json"::List.map(funx->Jsonrpc.to_stringx|>Yojson.Basic.from_string|>Yojson.Basic.pretty_to_string)marshalled)@["```"]inletdefinition=letdefn=String.concat""(definition_of_tt.ty)inletdescription=get_descriptiont.descriptionin[Printf.sprintf"type `%s` = `%s`"namedefn;description]inletrest=matcht.tywith|Structstructure->h4"Members"@of_struct_fieldsstructure.fields|Variantvariant->h4"Constructors"@of_variant_tagsvariant.variants|_->[]inheader@example@definition@rest)letjson_of_methodnamespace__(Codegen.BoxedFunctionm)=letinputs=Codegen.Method.find_inputsm.Codegen.Method.tyinlet(Idl.Param.Boxedoutput)=Codegen.Method.find_outputm.Codegen.Method.tyinletnamed,unnamed=List.fold_left(fun(named,unnamed)bp->matchbpwith|Idl.Param.Boxedp->letrpc=rpc_ofp.Idl.Param.typedef.Rpc.Types.ty(matchp.Idl.Param.namewith|Somen->n|None->p.Idl.Param.typedef.Rpc.Types.name)in(matchp.Idl.Param.namewith|Somen->(n,rpc)::named,unnamed|None->named,rpc::unnamed))([],[])inputsinletget_wire_namename=matchnamespacewith|Somens->Printf.sprintf"%s.%s"nsname|None->nameinletwire_name=get_wire_namem.Codegen.Method.nameinletargs=matchnamedwith|[]->List.revunnamed|_->Rpc.Dictnamed::List.revunnamedinletcall=Rpc.callwire_nameargsinletinput=Jsonrpc.string_of_callcall|>Yojson.Basic.from_string|>Yojson.Basic.pretty_to_stringinletexample_ty=Rpc_genfake.gen_niceoutput.Idl.Param.typedef.Rpc.Types.ty(matchoutput.Idl.Param.namewith|Somen->n|None->output.Idl.Param.typedef.Rpc.Types.name)inletmarshalled=Rpcmarshal.marshaloutput.Idl.Param.typedef.Rpc.Types.tyexample_tyinletoutput=Jsonrpc.to_stringmarshalled|>Yojson.Basic.from_string|>Yojson.Basic.pretty_to_stringininput,outputletocaml_of_method(Codegen.BoxedFunctionm)=letinputs=Codegen.Method.find_inputsm.Codegen.Method.tyinlet(Idl.Param.Boxedoutput)=Codegen.Method.find_outputm.Codegen.Method.tyinlet(Rpc.Types.BoxedDeferror)=Codegen.Method.find_errorsm.Codegen.Method.tyinletpatt_of_var=function|Rpc.Types.BoxedTagt->Printf.sprintf"%s%s"t.Rpc.Types.tname(matcht.Rpc.Types.tcontentswith|Unit->""|t->Printf.sprintf" %s"(ocaml_patt_of_tt))inleterr_pre,err_post=matcherror.Rpc.Types.tywith|Variantv->letpre="try\n "inletpost=Printf.sprintf"with %s"(String.concat"\n| "(List.map(funv->Printf.sprintf"Exn (%s) -> ..."(patt_of_varv))v.Rpc.Types.variants))inpre,post|_->letpre="try\n "inletpost="with _ -> ..."inpre,postinletgen_argp=matchpwith|Idl.Param.Boxedp->(matchp.Idl.Param.namewith|Somen->n|None->p.Idl.Param.typedef.Rpc.Types.name)inletresult_patt=matchoutput.Idl.Param.typedef.Rpc.Types.tywith|Unit->"()"|_->(matchoutput.Idl.Param.namewith|Somen->n|None->output.Idl.Param.typedef.Rpc.Types.name)inPrintf.sprintf"%slet %s = Client.%s %s in\n ...\n%s\n"err_preresult_pattm.Codegen.Method.name(String.concat" "(List.mapgen_arginputs))err_post(*let ocaml_server_of_method is i (Codegen.BoxedFunction m) = [
Printf.sprintf "module S=%s(Idl.GenServerExn ())" (String.capitalize i.Interface.name);
"";
Printf.sprintf "let %s_impl %s =" (m.Method.name) args;
" let result = %s in";
" result";
"";
"let bind () =";
" S.%s %s_impl"
]*)lettabs_ofnamespaceisim=letjson,json_response=json_of_methodnamespaceisiminletocaml=ocaml_of_methodminletpython=Pythongen.example_stub_userim|>Pythongen.string_of_tsinletpython_server=Pythongen.example_skeleton_userim|>Pythongen.string_of_tsin["> Client";"";Printf.sprintf"```json\n%s\n```"json;"";Printf.sprintf"```ocaml\n%s\n```"ocaml;"";Printf.sprintf"```python\n%s\n```"python;"";"> Server";"";Printf.sprintf"```json\n%s\n```"json_response;"";Printf.sprintf"```ocaml\n%s\n```"ocaml;"";Printf.sprintf"```python\n%s\n```"python_server;""]letof_methodnamespaceisi(Codegen.BoxedFunctionm)=letname=m.Method.nameinletdescription=get_descriptionm.Method.descriptioninh2(Printf.sprintf"Method: `%s`"name)@[description]@[""]@tabs_ofnamespaceisi(Codegen.BoxedFunctionm)@[""]@of_args(List.map(funp->true,p)Method.(find_inputsm.ty)@[(false,Method.(find_outputm.ty))])letall_errorsi=leterrors=List.map(function|BoxedFunctionm->Codegen.Method.find_errorsm.Codegen.Method.ty)i.Interface.methodsinletrecuniqaccerrors=matcherrorswith|e::es->ifList.memeaccthenuniqacceselseuniq(e::acc)es|[]->List.revaccinuniq[]errors(** We also document the nested types that contain useful documentation *)letexpand_typesis=(* These are the types that are helpful to document in the markdown *)letdoc=function|Struct{sname;_}asty->Some{name=sname;description=[];ty}|Variant{vname;_}asty->Some{name=vname;description=[];ty}|_->Noneinletrecexpand:typea.bool->atyp->boxed_deflist=fundocumentedty->letexpandty=expandfalsetyinletdefs=matchtywith|Arrayty->expandty|Listty->expandty|Dict(_,ty)->expandty|Optionty->expandty|Tuple(ty1,ty2)->expandty1@expandty2|Tuple3(ty1,ty2,ty3)->expandty1@expandty2@expandty3|Tuple4(ty1,ty2,ty3,ty4)->expandty1@expandty2@expandty3@expandty4|Struct{fields;_}->List.map(function|BoxedFieldfield->expandfield.field)fields|>List.flatten|Variant{variants;_}->List.map(function|BoxedTagtag->expandtag.tcontents)variants|>List.flatten|_->[]inmatchdocumented,doctywith|false,Somedef->defs@[BoxedDefdef]|_->defsinletsame(BoxedDefdef)(BoxedDefdef')=def'.name=def.namein(* The expanded types will be grouped together before the parameter they were
expanded from, with later ones referencing earlier ones. The ones
already documented earlier won't be repeated. *)List.fold_left(fundocumented_defs(BoxedDef{ty;_}asdef)->letexpanded=(* Each function parameter we expand is already documented *)expandtruety|>List.filter(fund->not(sameddef))inletnot_documentedd=not(List.exists(samed)documented_defs)indocumented_defs@List.filternot_documented(expanded@[def]))[]is.Interfaces.type_declsletof_interfaceisi=letname=i.Interface.details.Idl.Interface.nameinletnamespace=i.Interface.details.Idl.Interface.namespaceinletdescription=get_descriptioni.Interface.details.Idl.Interface.descriptioninh2(Printf.sprintf"Interface: `%s`"name)@[description]@List.concat(List.map(of_methodnamespaceisi)i.Interface.methods)letof_interfacesx=letname=x.Interfaces.nameinletdescription=get_descriptionx.Interfaces.descriptioninh1name@[description]@h2"Type definitions"@List.concat(List.map(of_type_declNone)(expand_typesx))@List.concat(List.map(of_interfacex)x.Interfaces.interfaces)@h2"Errors"@List.concat(List.map(of_type_declNone)(List.flatten(List.mapall_errorsx.Interfaces.interfaces)))letto_stringx=String.concat"\n"(of_interfacesx)