89cbe0f8fa
The current doc generator does not handles path were multiple method are registred. The fix remove the intermediate (compilation) tree.
421 lines
12 KiB
OCaml
421 lines
12 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* Copyright (c) 2014 - 2018. *)
|
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
(* *)
|
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
let protocols = [
|
|
"Alpha", "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" ;
|
|
]
|
|
|
|
module Rst = struct
|
|
|
|
let pp_title ~char ppf title =
|
|
let sub = String.map (fun _ -> char) title in
|
|
Format.fprintf ppf "@[<v 0>%s@ %s@ @ @]" title sub
|
|
|
|
let pp_h1 = pp_title ~char:'#'
|
|
let pp_h2 = pp_title ~char:'*'
|
|
let pp_h3 = pp_title ~char:'='
|
|
let pp_h4 = pp_title ~char:'`'
|
|
|
|
let pp_raw_html ppf str =
|
|
Format.fprintf ppf "@[<v>.. raw:: html@ @ %s@ @ @]"
|
|
(Re.Str.global_replace (Re.Str.regexp "\n") "\n " str)
|
|
|
|
let pp_html ppf f =
|
|
Format.fprintf ppf
|
|
"@[<v 2>.. raw:: html@ @ %a@]@\n@\n"
|
|
(fun ppf () -> f ppf) ()
|
|
|
|
let pp_ref ppf name = Format.fprintf ppf ".. _%s :@\n@\n" name
|
|
|
|
end
|
|
|
|
let pp_name ppf = function
|
|
| [] | [""] -> Format.pp_print_string ppf "/"
|
|
| prefix -> Format.pp_print_string ppf (String.concat "/" prefix)
|
|
|
|
let ref_of_service (prefix, meth) =
|
|
Format.asprintf "%s_%s"
|
|
(Resto.string_of_meth meth)
|
|
(Re.Str.global_replace
|
|
(Re.Str.regexp "<\\([^>]*\\)>")
|
|
"\\1"
|
|
(String.concat "--" prefix))
|
|
|
|
module Index = struct
|
|
|
|
let rec pp prefix ppf dir =
|
|
let open Resto.Description in
|
|
match dir with
|
|
| Empty -> Format.fprintf ppf "Empty"
|
|
| Static { services ; subdirs = None } ->
|
|
pp_services prefix ppf services
|
|
| Static { services ; subdirs = Some (Suffixes map) } ->
|
|
Format.fprintf ppf "@[<v 2>%a@ @ %a@]"
|
|
(pp_services prefix) services
|
|
(Format.pp_print_list
|
|
~pp_sep:(fun ppf () -> Format.fprintf ppf "@ @ ")
|
|
(pp_suffixes prefix))
|
|
(Resto.StringMap.bindings map)
|
|
| Static { services ; subdirs = Some (Arg (arg, dir)) } ->
|
|
let name = Format.asprintf "<%s>" arg.name in
|
|
Format.fprintf ppf "@[<v 2>%a@ @ %a@]"
|
|
(pp_services prefix) services
|
|
(pp_suffixes prefix) (name, dir)
|
|
| Dynamic _ ->
|
|
Format.fprintf ppf "* %a (<dyn>)" pp_name prefix
|
|
|
|
and pp_suffixes prefix ppf (name, dir) =
|
|
pp (prefix @ [name]) ppf dir
|
|
|
|
and pp_services prefix ppf services =
|
|
match (Resto.MethMap.bindings services) with
|
|
| [] ->
|
|
Format.fprintf ppf "* %a" pp_name prefix
|
|
| _ :: _ as services ->
|
|
Format.fprintf ppf "* %a (@[<h>%a@])"
|
|
pp_name prefix
|
|
(Format.pp_print_list
|
|
~pp_sep:Format.pp_print_space
|
|
(pp_service_method prefix)) services
|
|
|
|
and pp_service_method prefix ppf (meth, _service) =
|
|
Format.fprintf ppf "`%s <%s_>`_"
|
|
(Resto.string_of_meth meth)
|
|
(ref_of_service (prefix, meth))
|
|
|
|
end
|
|
|
|
module Description = struct
|
|
|
|
module Query = struct
|
|
|
|
let pp_arg fmt =
|
|
let open RPC_arg in
|
|
function { name ; _ } ->
|
|
Format.fprintf fmt "<%s>" name
|
|
|
|
let pp_title_item ppf =
|
|
let open RPC_description in
|
|
function {name ; kind ; _ } ->
|
|
match kind with
|
|
| Single arg | Optional arg ->
|
|
Format.fprintf ppf "[%s=%a]" name pp_arg arg
|
|
| Flag ->
|
|
Format.fprintf ppf "[%s]" name
|
|
| Multi arg ->
|
|
Format.fprintf ppf "(%s=%a)\\*" name pp_arg arg
|
|
|
|
let pp_title ppf query =
|
|
Format.fprintf ppf "%s%a"
|
|
(if query = [] then "" else "?")
|
|
(Format.pp_print_list
|
|
~pp_sep:(fun ppf () -> Format.fprintf ppf "&")
|
|
pp_title_item) query
|
|
|
|
let pp_html_arg fmt =
|
|
let open RPC_arg in
|
|
function { name ; _ } ->
|
|
Format.fprintf fmt "<%s>" name
|
|
|
|
let pp_item ppf =
|
|
let open RPC_description in
|
|
function { name ; description ; kind } ->
|
|
begin match kind with
|
|
| Single arg
|
|
| Optional arg
|
|
| Multi arg ->
|
|
Format.fprintf ppf
|
|
"<span class=\"query\">%s = %a</span>"
|
|
name pp_html_arg arg
|
|
| Flag ->
|
|
Format.fprintf ppf
|
|
"<span class=\"query\">%s</span>"
|
|
name
|
|
end ;
|
|
begin match description with
|
|
| None -> ()
|
|
| Some descr -> Format.fprintf ppf " : %s" descr
|
|
end
|
|
|
|
let pp ppf query =
|
|
match query with
|
|
| [] -> ()
|
|
| _ :: _ as query ->
|
|
Format.fprintf ppf
|
|
"</p> <p>Optional query arguments :<ul><li>%a</li></ul>"
|
|
(Format.pp_print_list
|
|
~pp_sep:(fun ppf () -> Format.fprintf ppf "</li><li>")
|
|
pp_item)
|
|
query
|
|
|
|
end
|
|
|
|
module Tabs = struct
|
|
|
|
let pp_tab_div ppf f =
|
|
Format.fprintf ppf
|
|
"@[<v 2><div class=\"tab\">%a</div>@]"
|
|
(fun ppf () -> f ppf) ()
|
|
|
|
let pp_tabcontent_div ~id ~class_ ppf f =
|
|
Format.fprintf ppf
|
|
"@[<v 2><div id=\"%s\" class=\"%s tabcontent\">@ \
|
|
%a@ \
|
|
@]</div>@ "
|
|
id class_ (fun ppf () -> f ppf) ()
|
|
|
|
let pp_button ppf ?(default=false) ~shortlabel ~content target_ref =
|
|
Format.fprintf ppf
|
|
"<button class=\"tablinks%s\" onclick=\"showTab(this, '%s', '%s')\">%s</button>@ "
|
|
(if default then " defaultOpen" else "")
|
|
(target_ref ^ shortlabel)
|
|
target_ref
|
|
content
|
|
|
|
let pp_content ppf ~tag ~shortlabel target_ref pp_content content =
|
|
pp_tabcontent_div
|
|
~id:(target_ref ^ shortlabel) ~class_:target_ref ppf
|
|
begin fun ppf ->
|
|
Format.fprintf ppf "<%s>@ %a</%s>" tag pp_content content tag
|
|
end
|
|
|
|
let pp_description ppf (service : _ RPC_description.service) =
|
|
let open RPC_description in
|
|
(* TODO collect and display arg description (in path and in query) *)
|
|
Format.fprintf ppf "%s%a"
|
|
(Option.unopt ~default:"" service.description)
|
|
Query.pp service.query
|
|
|
|
let pp ppf prefix service =
|
|
let open RPC_description in
|
|
let target_ref = ref_of_service (prefix, service.meth) in
|
|
Rst.pp_html ppf begin fun ppf ->
|
|
pp_tab_div ppf begin fun ppf ->
|
|
pp_button ppf
|
|
~default:true ~shortlabel:"descr" ~content:"Description"
|
|
target_ref ;
|
|
Option.iter service.input ~f: begin fun __ ->
|
|
pp_button ppf
|
|
~default:false ~shortlabel:"input" ~content:"Input format"
|
|
target_ref
|
|
end ;
|
|
pp_button ppf
|
|
~default:false ~shortlabel:"output" ~content:"Output format"
|
|
target_ref ;
|
|
end ;
|
|
pp_content ppf
|
|
~tag:"p" ~shortlabel:"descr" target_ref
|
|
pp_description service ;
|
|
Option.iter service.input ~f: begin fun schema ->
|
|
pp_content ppf
|
|
~tag:"pre" ~shortlabel:"input" target_ref
|
|
Json_schema.pp schema ;
|
|
end ;
|
|
pp_content ppf
|
|
~tag:"pre" ~shortlabel:"output" target_ref
|
|
Json_schema.pp service.output ;
|
|
end
|
|
|
|
end
|
|
|
|
let rec pp prefix ppf dir =
|
|
let open Resto.Description in
|
|
match dir with
|
|
| Empty -> ()
|
|
| Static { services ; subdirs = None } ->
|
|
pp_services prefix ppf services
|
|
| Static { services ; subdirs = Some (Suffixes map) } ->
|
|
pp_services prefix ppf services ;
|
|
Format.pp_print_list (pp_suffixes prefix)
|
|
ppf (Resto.StringMap.bindings map)
|
|
| Static { services ; subdirs = Some (Arg (arg, dir)) } ->
|
|
let name = Format.asprintf "<%s>" arg.name in
|
|
pp_services prefix ppf services ;
|
|
pp_suffixes prefix ppf (name, dir)
|
|
| Dynamic _ -> ()
|
|
|
|
and pp_suffixes prefix ppf (name, dir) =
|
|
pp (prefix @ [name]) ppf dir
|
|
|
|
and pp_services prefix ppf services =
|
|
List.iter
|
|
(pp_service prefix ppf)
|
|
(Resto.MethMap.bindings services)
|
|
|
|
and pp_service prefix ppf (meth, service) =
|
|
Rst.pp_ref ppf (ref_of_service (prefix, meth)) ;
|
|
Format.fprintf ppf "**%s %a%a**@\n@\n"
|
|
(Resto.string_of_meth meth)
|
|
pp_name prefix
|
|
Query.pp_title service.query ;
|
|
Tabs.pp ppf prefix service
|
|
|
|
end
|
|
|
|
let style = {css|
|
|
<style>
|
|
.tab {
|
|
overflow: hidden;
|
|
border: 1px solid #ccc;
|
|
background-color: #f1f1f1;
|
|
}
|
|
.tab button {
|
|
background-color: inherit;
|
|
float: left;
|
|
border: none;
|
|
outline: none;
|
|
cursor: pointer;
|
|
padding: 5px 10px;
|
|
}
|
|
.tab button:hover {
|
|
background-color: #ddd;
|
|
}
|
|
.tab button.active {
|
|
background-color: #ccc;
|
|
}
|
|
.tabcontent {
|
|
display: none;
|
|
padding: 6px 12px;
|
|
border: 1px solid #ccc;
|
|
border-top: none;
|
|
max-height: 40ex;
|
|
margin-bottom: 7ex;
|
|
overflow: auto;
|
|
}
|
|
.tabcontent p {
|
|
margin-bottom: 12px;
|
|
}
|
|
pre {
|
|
font-size: 12px
|
|
}
|
|
.rst-content .section ul p {
|
|
margin-bottom: 0;
|
|
}
|
|
span.query {
|
|
font-family: monospace;
|
|
white-space: pre;
|
|
}
|
|
</style>
|
|
|css}
|
|
|
|
let script = {script|
|
|
<script>
|
|
function showTab(elt, tab, ref) {
|
|
var i, tabcontent, tablinks;
|
|
tabcontent = document.getElementsByClassName(ref);
|
|
for (i = 0; i < tabcontent.length; i++) {
|
|
tabcontent[i].style.display = 'none';
|
|
}
|
|
|
|
tablinks = elt.parentNode.children;
|
|
for (i = 0; i < tablinks.length; i++) {
|
|
tablinks[i].className = tablinks[i].className.replace(' active', '');
|
|
}
|
|
|
|
document.getElementById(tab).style.display = 'block';
|
|
elt.className += ' active';
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var a = document.getElementsByClassName('defaultOpen');
|
|
for (i = 0; i < a.length; i++) { a[i].click() }
|
|
})
|
|
</script>
|
|
|script}
|
|
|
|
|
|
let pp_document ppf descriptions =
|
|
(* Style : hack *)
|
|
Format.fprintf ppf "%a@." Rst.pp_raw_html style ;
|
|
(* Script : hack *)
|
|
Format.fprintf ppf "%a@." Rst.pp_raw_html script ;
|
|
(* Page title *)
|
|
Format.fprintf ppf "%a" Rst.pp_h1 "RPC API" ;
|
|
(* include/copy usage.rst from input *)
|
|
let rec loop () =
|
|
let s = read_line () in
|
|
Format.fprintf ppf "%s@\n" s ;
|
|
loop () in
|
|
begin try loop () with End_of_file -> () end ;
|
|
Format.fprintf ppf "@\n" ;
|
|
(* Index *)
|
|
Format.pp_set_margin ppf 10000 ;
|
|
Format.pp_set_max_indent ppf 9000 ;
|
|
List.iter
|
|
(fun (name, prefix, rpc_dir) ->
|
|
Rst.pp_h2 ppf (Format.asprintf "%s RPCs - Index" name) ;
|
|
Format.fprintf ppf "%a@\n@\n" (Index.pp prefix) rpc_dir)
|
|
descriptions ;
|
|
(* Full description *)
|
|
Format.pp_set_margin ppf 80 ;
|
|
Format.pp_set_max_indent ppf 76 ;
|
|
List.iter
|
|
(fun (name, prefix, rpc_dir) ->
|
|
Rst.pp_h2 ppf (Format.asprintf "%s RPCs - Full description" name) ;
|
|
Format.fprintf ppf "%a@\n@\n" (Description.pp prefix) rpc_dir)
|
|
descriptions
|
|
|
|
let genesis : State.Chain.genesis = {
|
|
time =
|
|
Time.of_notation_exn "2018-04-17T11:46:23Z" ;
|
|
block =
|
|
Block_hash.of_b58check_exn
|
|
"BLockGenesisGenesisGenesisGenesisGenesisa52f8bUWPcg" ;
|
|
protocol =
|
|
Protocol_hash.of_b58check_exn
|
|
"ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im" ;
|
|
}
|
|
|
|
let main dir =
|
|
let (/) = Filename.concat in
|
|
let node_config : Node.config = {
|
|
genesis ;
|
|
patch_context = None ;
|
|
store_root = dir / "store" ;
|
|
context_root = dir / "context" ;
|
|
p2p = None ;
|
|
test_chain_max_tll = None ;
|
|
} in
|
|
Node.create
|
|
node_config
|
|
Node.default_peer_validator_limits
|
|
Node.default_block_validator_limits
|
|
Node.default_prevalidator_limits
|
|
Node.default_chain_validator_limits >>=? fun node ->
|
|
let shell_dir = Node.build_rpc_directory node in
|
|
let protocol_dirs =
|
|
List.map
|
|
(fun (name, hash) ->
|
|
let hash = Protocol_hash.of_b58check_exn hash in
|
|
let (module Proto) = Registered_protocol.get_exn hash in
|
|
"Protocol " ^ name,
|
|
[".." ; "<block_id>"] ,
|
|
RPC_directory.map (fun () -> assert false) @@
|
|
Block_directory.build_raw_rpc_directory (module Proto) (module Proto))
|
|
protocols in
|
|
let dirs = ("Shell", [""], shell_dir) :: protocol_dirs in
|
|
Lwt_list.map_p
|
|
(fun (name, path, dir) ->
|
|
RPC_directory.describe_directory ~recurse:true ~arg:() dir >>= fun dir ->
|
|
Lwt.return (name, path, dir))
|
|
dirs >>= fun descriptions ->
|
|
let ppf = Format.std_formatter in
|
|
pp_document ppf descriptions ;
|
|
return ()
|
|
|
|
let () =
|
|
Lwt_main.run begin
|
|
Lwt_utils_unix.with_tempdir "tezos_rpcdoc_" main >>= function
|
|
| Ok _ ->
|
|
Lwt.return_unit
|
|
| Error err ->
|
|
Format.eprintf "%a@." pp_print_error err ;
|
|
Pervasives.exit 1
|
|
end
|