{0 Contributing to [odoc]}

Please ask any questions you have about [odoc], {{:https://github.com/ocaml/odoc/issues}open any issues},
{{:https://github.com/ocaml/odoc#contact}offer feedback}, etc. All of these are valued contributions :)

If you'd like specifically to work on the code of [odoc], we hope that you will
find the information in this file helpful.

{1 Quick start: HTML and CSS}

The [odoc] CSS is found at {{:https://github.com/ocaml/odoc/blob/master/src/odoc/etc/odoc.css}[src/odoc/etc/odoc.css]}. It
still needs work, and PRs are very welcome. You can edit CSS using your browser's {{:https://developer.mozilla.org/en-US/docs/Tools}developer}
{{:https://developer.chrome.com/docs/devtools/}tools}. Then send us a PR for the same changes made to this file.

Working on the HTML is more involved. The main HTML generator is in {{:https://github.com/ocaml/odoc/blob/master/src/html/generator.ml}[src/html/generator.ml]}.
It operates on the types defined in {!module-Odoc_document.Types}, which is an intermediate representation used by all output renderers. The type that
describes an individual HTML page is {!Odoc_document.Types.Page.t}.

To make edits to the HTML generation, run the following commands:

{ol
{- Install requirements:
{ul 
{- A recent version of {{:http://www.html-tidy.org/}HTML tidy} (used for HTML validity testing) is required:
{[
# On MacOS (should be version 5.6.0 by the date of this writing)
brew install tidy-html5     
# Debian / Ubuntu
sudo apt-get install tidy
]}}
{- A recent version of {{:https://github.com/stedolan/jq}jq} is required.
{[
# On MacOS
brew install jq

# Debian / Ubuntu
sudo apt-get install jq
]}}}}
{- Set up for development:
{[
git clone https://github.com/ocaml/odoc.git
cd odoc
opam pin add --no-action odoc .
opam install --with-test --deps-only odoc
]}}
{- Make changes to the code. To compile it,
{[
make
]}
and then to run the tests,
{[
make test
]}
Changes to the HTML are likely to cause the tests to fail. See the section on {{!testing}testing} below to understand how to update them.
}
{- To test [odoc] against your own project, install it
{[
make clean
opam install odoc
]}
   Since [odoc] is pinned, this installs your modified version. Then you can run
   [odoc] in your project as normal:
{[
dune build @doc
]}
}

{- If all looks good, send odoc a PR :)
}
}

{1:testing Testing}

[odoc] uses a variety of different test types. We are slowly converging on using
Dune's {{:https://dune.readthedocs.io/en/stable/tests.html#cram-tests}cram tests},
though we still have many tests that aren't yet converted.

{2 Cram Tests}

The tests extensively use these for the model layer and are found in
{{:https://github.com/ocaml/odoc/blob/master/test/xref2}[test/xref2]}. These consist
of a directory called [something.t], containing a file [run.t]. This file has 
shell-like syntax and usually runs [odoc] on some carefully crafted
input files. For tests of the model layer it's often useful to use the binary
[odoc_print] which can dump [.odoc] and [.odocl] files as JSON. This output can
then be piped through [jq] to verify that values are as expected.

We try to make these test files describe the test and what's expected, which
helps when the output isn’t what the test expected. This also means that
the tests can serve as documentation of how things work. As an example, see
the file {{:https://github.com/ocaml/odoc/blob/master/test/xref2/multi_file_module_type_of.t/run.t}[test/xref2/multi_file_module_type_of.t/run.t]}

The tests work by executing the shell script snippets and then comparing the
actual output with those in the [run.t] files. If these {e don't}
match, the difference is rendered as a diff. For example, if I change the
way [type] declarations are printed and run [dune runtest], I get the
following output:

{[
------ test/xref2/module_type_of.t/run.t
++++++ test/xref2/module_type_of.t/run.t.corrected
File "test/xref2/module_type_of.t/run.t", line 95, characters 0-1:
 |                ]
 |              },
 |              "T"
 |            ]
 |          },
 |          "Z"
 |        ]
 |      }
 |    }
 |  ]
 |
 |Check that the expansion of 'T.Y' contains only 1 type
 |
 |  $ jq ".[0].ModuleType.expr.Some.TypeOf.t_expansion.Some.Signature.items" < T_sig.json > T.Y_sig.json
 |  $ odoc_print m.odocl | jq "map(keys | .[0])" < T.Y_sig.json
 |  [
-|    "Type"
+|    "Toupe"
 |  ]
 |
]}

The intended response to this is:

+ Check the diff. If the [-] line is correct, the code is broken. If the [+]
  line is correct, the test is broken.
+ If the test is broken, run [dune promote] to replace the expected output
  with the current output.

{2 Other Expect-Tests}

Many of [odoc]'s older tests are {b custom Expect-tests}, similar to those
run in the Cram test above, but that don't use Dune's [promote] workflow.
As an example the parser tests in [test/parser] work in the following way:

+ The tests run some code, e.g., the [odoc] parser on the string [{e foo}].
+ They take the output, in this case an AST representing "emphasized [foo],"
  and convert that output to a string, which will be an S-expression
  roughly like [(emphasis (foo))].
+ There is an {b expected} copy of this S-expression in a file somewhere in the
  repo. If the S-expression from the code doesn't match the expected one, the
  test fails.

When one of these Expect-tests fail, the output is saved, so
the developer can choose to {b replace} the now-incorrect expected string.
For these custom Expect-tests, the results may look like:

{[
-- bold.000 [basic.] Failed --
in _build/_tests/bold.000.output:

{e foo}

--- expect/bold/basic.txt       2018-04-15 14:42:32.356895400 -0500
+++ _actual/bold/basic.txt      2018-04-15 17:36:26.812747400 -0500
@@ -2,5 +2,5 @@
   (ok
    (((f.ml (1 0) (1 7))
      (paragraph
-      (((f.ml (1 0) (1 7)) (bold (((f.ml (1 3) (1 6)) (word foo)))))))))))
+      (((f.ml (1 0) (1 7)) (emphasis (((f.ml (1 3) (1 6)) (word foo)))))))))))
  (warnings ()))

To replace expected output with actual, run

bash _build/default/test/parser/_actual/replace.sh
]}

As with the Cram tests, the idea is to examine the diff to see if your code
is broken or the test is broken. If the test is broken, the actual results
may be promoted to the expected results by running the suggested command. If
your code is broken, go and fix it!

We are slowly shifting these custom Expect-tests over to the Dune [promote]
workflow.

{1 Coverage Analysis}

The [odoc] repo is set up for coverage analysis. This is most useful if you're
writing new tests, and want to know what they’re actually touching. 

To use it,

+ Run [make coverage]. This will run the tests as normal, except at the end you’ll get a message like
{[
    See _coverage/index.html
]}
   You can then open [_coverage/index.html] and see the coverage of the code you’d like your new test to reach. However, it’s possible that it’s already covered
   "accidentally" by tests that are checking other properties. In which
   case, coverage analysis won’t be very useful :)
+ Write new tests.
+ Check coverage again.

{1 CI Tests}

[odoc] is tested by {{:https://ci.ocamllabs.io/}ocaml-ci} and by GitHub workflows.
One of these also does a coverage build, so we have up-to-date coverage stats
on {{:https://coveralls.io/github/ocaml/odoc}Coveralls}.

The tests cover Esy and Opam builds on Windows, macOS, and Linux. The Linux
tests cover all supported versions of OCaml. We strive to retain compatibility
back as far as we can (currently 4.02) which is important for supporting
{{:https://ocaml.org/docs/}ocaml.org/docs}.

{1 API Reference}

{2 Loading}

The library {{!page-odoc_loader}odoc.loader} is responsible for converting
from the OCaml {!module-Typedtree} representations to the
{{!Odoc_model.Lang}internal representation}.

{2 Model}

The library {{!page-odoc_model}odoc.model} contains definitions of
the internal types used to represent OCaml interfaces.

{2 Resolution and Expansion}

Resolution of Paths, Fragments and References, and Expansion of Modules and
Module Types are handled by the {{!page-odoc_xref2}odoc.xref2 library}.

{2 Intermediate Representation and Renderers}
The generic documentation intermediate format is defined in the
{{!page-odoc_document}odoc.document library}.

The three current renderers are implemented within the following libraries
{{!page-odoc_html}odoc.html}, {{!page-odoc_latex}odoc.latex}, and {{!page-odoc_manpage}odoc.manpage}.

{2 CLI and Driver}

The CLI for [odoc] and various helper functions for driving the process are contained in the
{{!page-odoc_odoc}odoc.odoc library}.

{2 Test and Internal Libraries}

There are a couple of libraries used internally for testing - {{!page-odoc_xref_test}odoc.xref_test}
and {{!page-odoc_model_desc}odoc.model_desc}.

{1 Dependency Libraries}

There are several {{!page-deps}dependency libraries} that [odoc] uses, whose functions,
type, and module declarations are essential for understanding how [odoc] works. See the
{{!page-driver}driver} page for details on how the documentation for these 
libraries are included.

