[POC] `ocamlmark` – An `ocamldoc` to CommonMark bi-directional translation

Hello,

As a show-off for the recently announced cmarkit. I have devised ocamlmark, a bi-directional translation between ocamldoc and CommonMark with the least amount of CommonMark extensions possible.

It is defined in this document.

This unreasonable hack benefited from a grant of the OCaml Software Foundation. It was however not solicited by The Foundation and does not represent any endorsement by The Foundation.

A fully functional proof of concept[1] implementation on odoc-parser can be found in this PR. If you want to try it you should be able to:

opam pin odoc --dev
opam pin add cmarkit https://erratique.ch/repos/cmarkit.git # or opam install cmarkit
opam pin add odoc-parser https://github.com/dbuenzli/odoc-parser#ocamlmark

It allows you to write your OCaml docstrings and .mld files in ocamlmark. Both ocamlmark and ocamldoc syntaxes are supported transparently by sniffing each comment for a syntax.

If ocamlmark is detected, cmarkit is used to parse the comment and the resulting abstract syntax tree is translated to ocamldoc’s one. Thanks to precise source location tracking on both sides all errors reported by odoc should be reported correctly in ocamlmark constructs.

This shows how to use cmarkit’s label resolvers to good effect. Namely to provide the counter part to ocamldoc extensive cross-reference linking capabilities by allowing to specify them with
the same syntax – save for the braces – in CommonMark’s link labels.

Personally I’m not really convinced it’s a good idea, doc QA and readability are concerns, see the tradeoffs. But I’d just thought I’d put that on the table for discussion; sometimes it’s better to
think we could have it rather than have it ;–)


  1. Except for missing support for @-tags and odoc latest addition (math and tables, but they are supported by cmarkit) it is reasonably complete. ↩︎

16 Likes

This is timely. I’m working through my own POC for OCaml documentation that involves Markdown. It complements what you did in your POC.

Briefly, I have a goal (or more accurately: an aspiration) to write lots of documentation in a mix of .mld, .mli and .md files, and host + customize it using an ordinary static site generator (“SSG”). That documentation would include testable copy-and-paste examples (not just OCaml!), blog posts, and tutorials. And it should be easy for others to make edits. To do that, I have been building a pipeline based on odig, dkml-dune-dsl and odoc-sandbox … but it is only 75% ready today.

One thing I would like to share is how useful frontmatter has been with Markdown. Here are some partial examples of auto-generated intermediate Markdown files from my pipeline:

  • odig-logs-index.md

    source-provider: |-
      github
    source-url: |-
      https://github.com/dune-universe/logs
    source-ref: |-
      master
    findlib-provides: |-
      logs logs.cli logs.fmt logs.lwt logs.threaded logs.top
    findlib-requires: ""
    
  • Logs_cli.md

    source-opam-package-ver: |-
      logs.0.7.0+dune2
    source-path: |-
      src/logs_cli.mli
    findlib-provides: ""
    findlib-requires: |-
      logs.cli
    
  • Unix-LargeFile.md

    source-provider: |-
      github
    source-url: |-
      https://github.com/ocaml/ocaml
    source-ref: |-
      trunk
    source-opam-package-ver: |-
      ocaml-base-compiler.4.14.0
    source-path: |-
      otherlibs/unix/unix.mli
    findlib-provides: ""
    findlib-requires: |-
      unix
    

Notice how there is already enough information in the frontmatter to make a nice documentation site (ex. v3.ocaml.org) using SSGs. In particular, the readers (especially beginners!) could get the following:

  1. Which opam install (ex. opam install logs) command to use
  2. What line to put into an .opam file (ex. "logs" = "0.7.0+dune2")
  3. What line to put into dune-project (ex. (logs (= 0.7.0+dune2)))
  4. What link will let the reader do an edit and submit a PR (ex. https://github.com/dune-universe/logs/edit/master/src/logs.mli)
  5. What line to put into dune to use a particular module (ex. (executable (name your_exe) (libraries logs.cli)))

I’ll study your POC in more detail in a few weeks. Thanks!!