Skip to content

Commit 2781eb2

Browse files
committed
WIP: dune build @doc-json
The `odoc` tool supports a `--as-json` flag. When used in `odoc html-generate`, it will output `.html.json` files instead of `.html` files. These files contain HTML fragments that can be used by external tools to generate HTML documents using a different pipeline. This is exposed in Dune by defining a new `@doc-json` alias that works like `@doc` (it builds the documentation for public packages) but emits JSON files. Signed-off-by: Etienne Millon <me@emillon.org>
1 parent 78f803f commit 2781eb2

File tree

4 files changed

+115
-30
lines changed

4 files changed

+115
-30
lines changed

src/dune_engine/alias.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ let install = make_standard Name.install
107107

108108
let doc = make_standard (Name.of_string "doc")
109109

110+
(** XXX is there anything to do to make a new standard alias? document it? *)
111+
let doc_json = make_standard (Name.of_string "doc-json")
112+
110113
let private_doc = make_standard (Name.of_string "doc-private")
111114

112115
let lint = make_standard (Name.of_string "lint")

src/dune_engine/alias.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ val install : dir:Path.Build.t -> t
5252

5353
val doc : dir:Path.Build.t -> t
5454

55+
val doc_json : dir:Path.Build.t -> t
56+
5557
val private_doc : dir:Path.Build.t -> t
5658

5759
val lint : dir:Path.Build.t -> t

src/dune_rules/odoc.ml

Lines changed: 86 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ type odoc_artefact =
7272
{ odoc_file : Path.Build.t
7373
; odocl_file : Path.Build.t
7474
; html_file : Path.Build.t
75+
; json_file : Path.Build.t
7576
}
7677

7778
let add_rule sctx =
@@ -112,11 +113,40 @@ module Paths = struct
112113
let toplevel_index ctx = html_root ctx ++ "index.html"
113114
end
114115

116+
module Format = struct
117+
type t =
118+
| Html
119+
| Json
120+
121+
let all = [ Html; Json ]
122+
123+
let extension = function
124+
| Html -> ".html"
125+
| Json -> ".html.json"
126+
127+
let args = function
128+
| Html -> Command.Args.empty
129+
| Json -> A "--as-json"
130+
131+
let target format odoc_file =
132+
match format with
133+
| Html -> odoc_file.html_file
134+
| Json -> odoc_file.json_file
135+
136+
let alias format ~dir =
137+
match format with
138+
| Html -> Alias.doc ~dir
139+
| Json -> Alias.doc_json ~dir
140+
end
141+
115142
module Dep : sig
116143
(** [html_alias ctx target] returns the alias that depends on all html targets
117144
produced by odoc for [target] *)
118145
val html_alias : Context.t -> target -> Alias.t
119146

147+
(** XXX doc *)
148+
val format_alias : Format.t -> Context.t -> target -> Alias.t
149+
120150
(** [deps ctx pkg libraries] returns all odoc dependencies of [libraries]. If
121151
[libraries] are all part of a package [pkg], then the odoc dependencies of
122152
the package are also returned*)
@@ -130,7 +160,9 @@ module Dep : sig
130160
These dependencies may be used using the [deps] function *)
131161
val setup_deps : Context.t -> target -> Path.Set.t -> unit Memo.t
132162
end = struct
133-
let html_alias ctx m = Alias.doc ~dir:(Paths.html ctx m)
163+
let format_alias f ctx m = Format.alias f ~dir:(Paths.html ctx m)
164+
165+
let html_alias = format_alias Html
134166

135167
let alias = Alias.make (Alias.Name.of_string ".odoc-all")
136168

@@ -335,7 +367,7 @@ let setup_library_odoc_rules cctx (local_lib : Lib.Local.t) =
335367
Dep.setup_deps ctx (Lib local_lib)
336368
(Path.Set.of_list_map modules_and_odoc_files ~f:(fun (_, p) -> Path.build p))
337369

338-
let setup_html sctx (odoc_file : odoc_artefact) =
370+
let setup_generate sctx (odoc_file : odoc_artefact) format =
339371
let ctx = Super_context.context sctx in
340372
let open Memo.O in
341373
let odoc_support_path = Paths.odoc_support ctx in
@@ -350,11 +382,15 @@ let setup_html sctx (odoc_file : odoc_artefact) =
350382
; A "--theme-uri"
351383
; Path (Path.build odoc_support_path)
352384
; Dep (Path.build odoc_file.odocl_file)
353-
; Hidden_targets [ odoc_file.html_file ]
385+
; Format.args format
386+
; Hidden_targets [ Format.target format odoc_file ]
354387
]
355388
in
356389
add_rule sctx run_odoc
357390

391+
let setup_generate_all sctx odoc_file =
392+
Memo.parallel_iter Format.all ~f:(setup_generate sctx odoc_file)
393+
358394
let setup_css_rule sctx =
359395
let open Memo.O in
360396
let ctx = Super_context.context sctx in
@@ -453,15 +489,18 @@ let create_odoc ctx ~target odoc_file =
453489
match target with
454490
| Lib _ ->
455491
let html_dir = html_base ++ Stdune.String.capitalize basename in
456-
{ odoc_file; odocl_file; html_file = html_dir ++ "index.html" }
492+
let file format =
493+
html_dir ++ "index"
494+
|> Path.Build.extend_basename ~suffix:(Format.extension format)
495+
in
496+
{ odoc_file; odocl_file; html_file = file Html; json_file = file Json }
457497
| Pkg _ ->
458-
{ odoc_file
459-
; odocl_file
460-
; html_file =
461-
html_base
462-
++ sprintf "%s.html"
463-
(basename |> String.drop_prefix ~prefix:"page-" |> Option.value_exn)
464-
}
498+
let file format =
499+
html_base
500+
++ (basename |> String.drop_prefix ~prefix:"page-" |> Option.value_exn)
501+
|> Path.Build.extend_basename ~suffix:(Format.extension format)
502+
in
503+
{ odoc_file; odocl_file; html_file = file Html; json_file = file Json }
465504

466505
let static_html ctx =
467506
let open Paths in
@@ -580,6 +619,20 @@ let setup_pkg_odocl_rules_def =
580619
let setup_pkg_odocl_rules sctx ~pkg : unit Memo.t =
581620
Memo.With_implicit_output.exec setup_pkg_odocl_rules_def (sctx, pkg)
582621

622+
let out_file (format : Format.t) odoc =
623+
match format with
624+
| Html -> odoc.html_file
625+
| Json -> odoc.json_file
626+
627+
let out_files ctx (format : Format.t) odocs =
628+
let extra_files =
629+
match format with
630+
| Html -> List.map ~f:Path.build (static_html ctx)
631+
| Json -> []
632+
in
633+
List.rev_append extra_files
634+
(List.map odocs ~f:(fun odoc -> Path.build (out_file format odoc)))
635+
583636
let setup_lib_html_rules_def =
584637
let module Input = struct
585638
module Super_context = Super_context.As_memo_key
@@ -596,12 +649,14 @@ let setup_lib_html_rules_def =
596649
let f (sctx, lib) =
597650
let ctx = Super_context.context sctx in
598651
let* odocs = odoc_artefacts sctx (Lib lib) in
599-
let* () = Memo.parallel_iter odocs ~f:(fun odoc -> setup_html sctx odoc) in
600-
let html_files = List.map ~f:(fun o -> Path.build o.html_file) odocs in
601-
let static_html = List.map ~f:Path.build (static_html ctx) in
602-
Rules.Produce.Alias.add_deps
603-
(Dep.html_alias ctx (Lib lib))
604-
(Action_builder.paths (List.rev_append static_html html_files))
652+
let* () =
653+
Memo.parallel_iter odocs ~f:(fun odoc -> setup_generate_all sctx odoc)
654+
in
655+
Memo.parallel_iter Format.all ~f:(fun format ->
656+
let paths = out_files ctx format odocs in
657+
Rules.Produce.Alias.add_deps
658+
(Dep.format_alias format ctx (Lib lib))
659+
(Action_builder.paths paths))
605660
in
606661
Memo.With_implicit_output.create "setup-library-html-rules"
607662
~implicit_output:Rules.implicit_output
@@ -618,40 +673,41 @@ let setup_pkg_html_rules_def =
618673
let* () = Memo.parallel_iter libs ~f:(setup_lib_html_rules sctx)
619674
and* pkg_odocs =
620675
let* pkg_odocs = odoc_artefacts sctx (Pkg pkg) in
621-
let+ () = Memo.parallel_iter pkg_odocs ~f:(fun o -> setup_html sctx o) in
676+
let+ () = Memo.parallel_iter pkg_odocs ~f:(setup_generate_all sctx) in
622677
pkg_odocs
623678
and* lib_odocs =
624679
Memo.parallel_map libs ~f:(fun lib -> odoc_artefacts sctx (Lib lib))
625680
in
626681
let odocs = List.concat (pkg_odocs :: lib_odocs) in
627-
let html_files = List.map ~f:(fun o -> Path.build o.html_file) odocs in
628-
let static_html = List.map ~f:Path.build (static_html ctx) in
629-
Rules.Produce.Alias.add_deps
630-
(Dep.html_alias ctx (Pkg pkg))
631-
(Action_builder.paths (List.rev_append static_html html_files))
682+
Memo.parallel_iter Format.all ~f:(fun format ->
683+
let paths = out_files ctx format odocs in
684+
Rules.Produce.Alias.add_deps
685+
(Dep.format_alias format ctx (Pkg pkg))
686+
(Action_builder.paths paths))
632687
in
633688
setup_pkg_rules_def "setup-package-html-rules" f
634689

635690
let setup_pkg_html_rules sctx ~pkg : unit Memo.t =
636691
Memo.With_implicit_output.exec setup_pkg_html_rules_def (sctx, pkg)
637692

638-
let setup_package_aliases sctx (pkg : Package.t) =
693+
let setup_package_aliases_format sctx (pkg : Package.t) (format : Format.t) =
639694
let ctx = Super_context.context sctx in
640695
let name = Package.name pkg in
641696
let alias =
642697
let pkg_dir = Package.dir pkg in
643698
let dir = Path.Build.append_source ctx.build_dir pkg_dir in
644-
Alias.doc ~dir
645-
in
646-
let* libs =
647-
libs_of_pkg ctx ~pkg:name
648-
>>| List.map ~f:(fun lib -> Dep.html_alias ctx (Lib lib))
699+
Format.alias format ~dir
649700
in
650-
Dep.html_alias ctx (Pkg name) :: libs
701+
let* libs = libs_of_pkg ctx ~pkg:name >>| List.map ~f:(fun lib -> Lib lib) in
702+
Pkg name :: libs
703+
|> List.map ~f:(Dep.format_alias format ctx)
651704
|> Dune_engine.Dep.Set.of_list_map ~f:(fun f -> Dune_engine.Dep.alias f)
652705
|> Action_builder.deps
653706
|> Rules.Produce.Alias.add_deps alias
654707

708+
let setup_package_aliases sctx (pkg : Package.t) =
709+
Memo.parallel_iter Format.all ~f:(setup_package_aliases_format sctx pkg)
710+
655711
let default_index ~pkg entry_modules =
656712
let b = Buffer.create 512 in
657713
Printf.bprintf b "{0 %s index}\n" (Package.Name.to_string pkg);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
$ cat > dune-project << EOF
2+
> (lang dune 3.10)
3+
>
4+
> (package
5+
> (name l))
6+
> EOF
7+
8+
$ cat > dune << EOF
9+
> (library
10+
> (public_name l))
11+
> EOF
12+
13+
$ cat > l.ml << EOF
14+
> module M = struct
15+
> type t = int
16+
> end
17+
> EOF
18+
19+
$ dune build @doc-json
20+
21+
$ find _build/default/_doc/_html/ -name '*.html' -o -name '*.html.json'
22+
_build/default/_doc/_html/l/index.html.json
23+
_build/default/_doc/_html/l/L/M/index.html.json
24+
_build/default/_doc/_html/l/L/index.html.json

0 commit comments

Comments
 (0)