123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132(* Part of this code is based on the furl project and
Copyright (c) 2015 Gabriel Radanne <drupyo@zoho.com>
SPDX-License-Identifier: MIT
Copyright (c) 2025 Romain Calascibetta <romain.calascibetta@gmail.com>
*)type('e,'a)atom=('e,'a)Tyre.ttype('e,'fu,'return)path=|Host:string->('e,'r,'r)path|Rel:('e,'r,'r)path|Path_const:('e,'f,'r)path*string->('e,'f,'r)path|Path_atom:('e,'f,'a->'r)path*('e,'a)atom->('e,'f,'r)pathtype('e,'fu,'return)query=|Nil:('e,'r,'r)query|Any:('e,'r,'r)query|Query_atom:string*('e,'a)atom*('e,'f,'r)query->('e,'a->'f,'r)querytypeslash=Slash|No_slash|Maybe_slashtype('e,'f,'r)t=|Url:slash*('e,'f,'x)path*('e,'x,'r)query->('e,'f,'r)tmodulePath=structlethoststr=Hoststrletrelative=Relletaddpathstr=Path_const(path,str)letadd_atompathatom=Path_atom(path,atom)letrec_concat:typeefrx.(e,f,x)path->(e,x,r)path->(e,f,r)path=funp1p2->matchp2with|Host_->p1|Rel->p1|Path_const(p,str)->Path_const(_concatp1p,str)|Path_atom(p,a)->Path_atom(_concatp1p,a)endmoduleQuery=structletnil:_query=Nilletany=Anyletaddnxquery=Query_atom(n,x,query)letrecmake_any:typeefr.(e,f,r)query->(e,f,r)query=function|Nil->Any|Any->Any|Query_atom(n,x,q)->Query_atom(n,x,make_anyq)letrec_concat:typeefrx.(e,f,x)query->(e,x,r)query->(e,f,r)query=funq1q2->matchq1with|Nil->q2|Any->make_anyq2|Query_atom(n,x,q)->Query_atom(n,x,_concatqq2)endmoduleUrl=structletmake?(slash=No_slash)pathquery:_t=Url(slash,path,query)endletnil=Query.nilletany=Query.anylet(**)(n,x)q=Query.addnxqlethost=Path.hostletrel=Path.relativelet(/)=Path.addlet(/%)=Path.add_atomlet(/?)pathquery=Url.make~slash:No_slashpathquerylet(//?)pathquery=Url.make~slash:Slashpathquerylet(/??)pathquery=Url.make~slash:Maybe_slashpathqueryleteval_atompx=Tyre.(eval(Internal.to_tp)x)leteval_top_atom:typea.(Tyre.evaluable,a)Tyre.Internal.raw->a->stringlist=function|Optp->(functionNone->[]|Somex->[eval_atompx])|Repp->funl->List.of_seq(Seq.map(eval_atomp)l)|e->funx->[eval_atomex]letreceval_path:typerf.(Tyre.evaluable,f,r)path->(stringoption->stringlist->r)->f=funpk->matchpwith|Hoststr->k(Somestr)[]|Rel->kNone[]|Path_const(p,str)->eval_pathp(funhr->kh(str::r))|Path_atom(p,a)->letfnhrx=kh(eval_top_atom(Tyre.Internal.from_ta)x@r)ineval_pathpfnletreceval_query:typerf.(Tyre.evaluable,f,r)query->((string*stringlist)list->r)->f=funqk->matchqwith|Nil->k[]|Any->k[]|Query_atom(n,a,q)->funx->letfnr=k((n,eval_top_atom(Tyre.Internal.from_ta)x)::r)ineval_queryqfnletkeval:?slash:bool->(Tyre.evaluable,'a,'b)t->(string->'b)->'a=fun?slash:(force=false)(Url(slash,p,q))k->eval_pathp@@funhostpath->eval_queryq@@funquery->letpath=matchslashwithSlash->""::path|No_slash|Maybe_slash->pathinlethost=Option.value~default:""hostinletpath=matchpathwith|[]whenforce->["";""]|[]->[]|path->""::List.revpathinletpath=String.concat"/"pathinletpath=Pct.encode_pathpathinletquery=Pct.encode_queryqueryink(host^path^query)leteval?slasht=keval?slashtFun.idtype'ahandler='aHttpcats_core.handlertyperesponse=Httpcats_core.responsetypeerror=Httpcats_core.error(* TODO *)(* let request ~fn a t = keval t @@ fun uri -> Httpcats.request ~fn ~uri a *)