rescript-compiler
rescript-compiler copied to clipboard
Automatic Documentation Generation
Opening this issue for tracking purposes and discussion 🗣
Context
Documenting a project that builds with bsb
right now is a fragmented experience. You can use:
-
docre/redoc
, - you can manually drive
odoc
from the terminal or with a script, - you can use
bsdoc
, or - you can even set up a
dune
project around your sources so it compiles the documentation for you.
I believe this, among other reasons, to aid in the scarcity and scattering of documentations for libraries in the wild. If bsb
worked with a blessed documentation tool out of the box, we could get several benefits in the small, and in the big.
In the small, people writing docs will get a consistent experience when documenting. No longer having to go around asking "What can I use to document?" and consolidating both knowledge and docs styles across the community.
In the big, complete catalogs of documentation for packages can be generated since they all work with the same tool — imagine Rust docs (https://docs.rs), or Hoogle (https://www.haskell.org/hoogle) but for Reason/BuckleScript.
odoc
odoc
has established itself as the documentation tool for the OCaml ecosystem, with first class support from dune
, and a number of auxiliary tools around it (such as odig
). It is in heavy industry usage, has a sophisticated cross-referencer, and has been backported to work with OCaml 4.02.3+buckle-master. This meant we can start using it with BuckleScript.
However, because odoc
is a low level tool, it requires orchestration, which led me to create a package that does such orchestration for you:
MyProject $ yarn add bsdoc --dev
MyProject $ yarn build
MyProject $ yarn run bsdoc support-files --output-dir=./docs
yarn run v1.12.3
$ ./node_modules/.bin/bsdoc support-files
info: Copying support files (CSS, JS) into ./docs
info: Done ✅
✨ Done in 0.60s.
MyProject $ yarn run bsdoc build MyProject
yarn run v1.12.3
$ ./node_modules/.bin/bsdoc build MyProject
info: Compiling documentation for package "MyProject"...
info: Generating .html files...
info: Done ✅
✨ Done in 0.45s.
bsdoc
simply orchestrates calls to odoc
. Which means it on a working version of odoc
available, which it turn requires the right opam
switch with the package installed.
So there we have it:
[ build-tool ] --orchestration--> [ odoc ]
Proposal
I'd like for the bs-platform
to support the following use-cases:
- [ ] New project should always be documentation-ready
- [ ] In watch mode, saving a file should update the documentation (and show any warnings if the documentation is broken: e.g., a type was renamed in a module, but not in the docs)
- [ ] When only building once, all necessary documentation should be generated
- [ ] It should be possible to regenerate the support-files without starting a new project / copy pasting from another place
I do not include locally serving documentation as a use case, given the ubiquitous nature of static file servers that people can use for it.
To support those use-cases, I'd like the bs-platform
package to include:
-
odoc
in some shape of form, perhaps as a binary, -
bsdoc
to setup support files (theme, js, etc), building the whole documentation, and future workflows -
bsb
to include rebuilding documentation on every compilation unit change. -
bsb -init
template to include documentation setup
Naturally, this last list is much less important than catering for the use-cases of the first one. So it matters less to me that we have a binary odoc
, or that we include bsdoc
at all. We could perhaps bundle both into bsb
and that should be okay too.
/cc @bobzhang @rizo @aantron
Relevant Issues
https://github.com/ocaml/odoc/issues/209 — In the past we've seen problems with automatic namespacing. This could mean making BuckleScript namespacing valid OCaml namespaces. Something to figure out.
https://github.com/ocaml/odoc/issues/275 — @nikgraf has raised that the external
keyword output needs improvement.
Thanks @ostera!
I just wanted to state that we are interested in providing first-class support for Reason syntax. In fact I'm currently working on integrating odoc with Reason+esy projects (https://github.com/esy-ocaml/hello-reason/issues/13).
Let me know if there's anything I can help with.
Crosslinking external output issue from odoc
here: https://github.com/ocaml/odoc/issues/275
I've spent the last few days investigating how we can embed odoc
into bs-platform
.
The two approaches I've listed down are:
- Embed as a single file, in the same spirit as
refmt
is embedded, - Build with esy
1. Embed as a single file
This would clearly be "easier", given that the approach is already in use in the bs-platform
, and is the option that would have the least impact in dependencies of bs-platform
overall.
Unfortunately, some idiosyncrasies from bspack
do not let me pack the dune
project easily. I've gone down a rabbit hole of module renaming and library packaging, but it did not yield good results. Mostly due to bspack
not following dune
conventions, which is unfortunate.
Roughly speaking, duplicate modules, and the automatic namespacing that dune
features break bspack
.
To proceed with this I'd have to adapt bspack
to understand these dune
conventions and make it possible to pack odoc
automatically (so updating it isn't a slow, error prone, manual chore).
As an advantage, other projects may also be easy to pack and include with bs-platform
.
2. Build with esy
Alternatively, given that BuckleScript is already using esy
, we could include the esy
toolchain as part of the bs-platform
build step. This would allow us to build odoc
verbatim from source.
It would also serve as a platform for building bs-platform
with esy, slowly getting rid of the ad-hoc build tooling it currently has.
I'll start looking into this now to see what needs to be done there.
Any thoughts?
/cc @bobzhang @chenglou @nikgraf @ryypyy
After exploring more building with esy, we'd need:
- To bake an
esy
binary intobs-platform
, which may not be ideal. - Include a
odoc.exe
target intolib/body.ninja
that shells out toesy
to build everything in isolation, and copy the executable back.
I haven't looked at how to preserve the paths to the static files that odoc
expects, but this could be trivial (place them by the executable), or can be fixed in odoc
by crunching the assets into an ML module.
Currently talking to @jordwalke about 1 again.
Note we don't depend on esy. In the short/mid term, bs-platform will be self-contained. One thing worth exploring is to make bspack more capable to pack those stuff
@bobzhang can you ellaborate on bs-platform
being self container?
Could there be a possibility of splitting out a BuckleScript-compatible odoc into a separate npm package, e.g. bs-platform-odoc
? Then we could modify the project templates to create projects with that (dev) dependency and a run script e.g. npm run doc
that calls that package's odoc.
@yawaramin we could pack odoc
for npm consumption. It is doable, we just haven't done it. There's 2 arguments to be made against it.
Firstly, odoc
needs to be compiled with a matching version of the compiler you are compiling your project with. This means the versioning of the npm
package will have to include the version of the compiler as well.
That is, if you are using BuckleScript 4.0.18, which builds on OCaml 4.02.3+BS, you need odoc
compiled with OCaml 4.02.3+BS. Like in yarn install [email protected]+BS
where 1.3.1
is the odoc
version.
If you update to a newer version of BuckleScript, 5.x, that builds on OCaml 4.06+BS, you'll need a different version installed.
Because of this, I think a better developer experience, that prevents compiler mismatches and package version headaches, bundles and builds odoc
with whatever compiler is shipped in the version of bs-platform
that you are using.
Secondly, we want to introduce documentation flows to the standard bsb
build flows. To do this, bsb
must be able to invoke odoc
reliably as part of the build process, and packing it would let us do tighter integrations.
If the internals of bsb
change so that artefacts (.cmti files, etc) are stored somewhere else, then the odoc
package on npm, which was expecting artefacts to appear in a particular place, will fail. We don't want this either.
Hopefully this illustrates better why I'm pursuing an embed of the tool rather than an out-of-band integration (like bsdoc
currently has).
Firstly,
odoc
needs to be compiled with a matching version of the compiler you are compiling your project with. This means the versioning of thenpm
package will have to include the version of the compiler as well.
Then your only real hope is to embed it into bs-platform as you are pursuing. Esy can generate prebuilt binaries for every platform including windows but it looks like bs-platform currently needs to compile on host for some platforms. If bs-platform ever goes full prebuilt binaries for everything, then you could use esy to pack up prebuilts of odoc
, and then include those with bs-platform
.
If bs-platform won't move to 100% prebuilt binaries, then you'd need to either improve bspack to understand dune, or fork bs-platform into an esy package that models a compiler dependency. Ultimately, at some point I think bs-platform is going to actually benefit from modelling a compiler dependency because then people can properly build ppx plugins (it could even be a prebuilt compiler version as long as it is modeled).
Alternatively, you could just have a separate prebuilt odoc npm package. I know it's tough to keep the compiler versions in sync since bs-platform doesn't model a dependency on the compiler, but still - odoc would be a devDependency and that simplifies a lot of things here.
@ostera self contained means bs-platform could be built from source without extra deps. bs-platform is a compiler, technically it does not depend on the ocaml compiler(we have a vendored one, the user does not need to known about the internals).
For the version mismatch problem, the philosophy is quite different from ocaml native, I wish it would be mitigated to some extent given that we only have one major version maintained and maybe upgrade (changing cmt/cmti format) in every one and half an year.
Having odoc bspacked is the ideal solution, or we could spend major effort in shipping 4.06 for odoc
@ostera I took a little time to digest your points :-) perhaps we can simplify some things. Suppose we go with a bs-platform-odoc
separate package. We can version it to target specifically the version of BuckleScript it should work with. BuckleScript releases are not frequent enough that this should be a major pain. Plus, for each BuckleScript version, its OCaml version is fixed, and we know what it is (e.g. 4.02.3+BS now).
For example, current stable version of bs-platform
is 4.0.18 (as of today); if we have a bs-platform-odoc
targeting that version, we could give it exactly the same version number (4.0.18) and build it with exactly the same OCaml version (4.02.3+BS). And users don't need to install it separately. The bsb
scaffolding feature can set up a project with it as a dev dependency with exactly the same version as bs-platform
:
$ bsb -init myproj
Output package.json
:
...
"scripts": {
"docs": "odoc ..."
},
...
"devDependencies": {
"bs-platform": "^4.0.18",
"bs-platform-odoc": "^4.0.18"
}
...
After that, users would be just an npm install
away from having full documentation generation. This seems like the best of both worlds.
up, what is the state of it ? What is the current best way to manage documentation generation ? Kind of lost..
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.