commits
The scrollycode JS runtime was embedded as an inline <script> in the
page body, which the SPA navigator never executes. Moved it to a
registered support file (extensions/scrollycode.js) loaded via Js_url
in <head>, with a MutationObserver to detect new containers inserted
by SPA content swaps.
Added a new "Writing Extensions" doc page to odoc covering the
extension API, resource types, the SPA navigation pitfall, and the
scrollycode fix as a case study.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- odoc extension API: add link-phase enrichment support for extensions
- odoc-jons-plugins: new site shell with nav bar, recent posts with
featured card layout, and updated CSS
- site-builder: support projects/ directory and improved rule generation
- site: redesigned homepage with hero section and recent posts cards
- site: updated blog index layout
- onnxrt docs: minor .mld cleanup
- New blog images and content (weeknotes, examination map, fungus svg)
- Add mockup.html for design iteration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
# dune-project
# odoc-bench.opam
# odoc.opam
# src/xref2/errors.ml
Previously, resolution failures in Errors.report used
Lookup_failures.report_internal which hardcoded non_fatal:true, meaning
they would never cause a build failure even when --warn-error was passed.
Switch to Lookup_failures.report_warning so that all resolution failures
(modules, types, references, etc.) respect --warn-error. Root errors
(missing dependencies) retain their own separate handling via report_root.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The unresolved reference warning during link is always non-fatal,
so --warn-error has no effect on it. This test demonstrates the bug:
the warning is not promoted to an error and the exit code is 0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When compiling with -no-alias-deps, module aliases produce imports without
digests. Previously, resolve_imports would eagerly look up these modules in
the include path, potentially finding stale .odoc artifacts from a previous
build. This would associate the wrong digest with the import, breaking
incremental rebuilds.
Skip resolution for Unresolved (_, None) imports, leaving them unresolved
in the output .odoc file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When compiling with -no-alias-deps, module aliases produce imports
without digests. This test demonstrates that odoc currently resolves
these imports by looking them up in the include path, which can find
stale artifacts from a previous build and associate the wrong digest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sidebar kindBadge: map leaf-page→pg, module-type→MT, etc. (was
showing "L" for leaf-page entries)
- Stop escaping sidebar content HTML (entries contain <code> tags)
- Fix inline sidebar JSON: use Html.cdata_script instead of Html.txt
to prevent HTML-escaping inside <script> tags
- Add --xo-* CSS custom properties for x-ocaml cells in light/dark themes
- Fix support file registration: use 'opam var share' instead of
'opam var x-ocaml:share' (works without x-ocaml being an opam package)
- Suppress empty <li> from config-only extension tags (@x-ocaml.*)
- Add worker_url field to jtw opam findlib_index.json
- Refactor x-ocaml.js worker URL discovery to support both direct
worker_url and day10-style version/content_hash paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove 12 JS stubs from js_top_worker that are already provided by
basement/runtime.js and base/runtime.js (blocking_mutex, blocking_condition,
thread_yield, basement_dynamic, basement_alloc_stack_bind, caml_ml_domain_index)
- Keep caml_make_local_vect as it's needed by OxCaml compiler-libs and base
is not a transitive dependency
- Fix free-variables warnings by using proper //Provides/Requires pattern
for domain TLS shared state
- Add (link_flags (-linkall)) to odoc-scrollycode-extension test binary so
Html_page's side-effect shell registration is linked (matches real odoc binary)
- Promote test expected outputs for OCaml 5.4.1 and scrollycode extension changes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Consolidate js_top_worker and odoc dual-compiler stanzas into single
library stanzas with cppo rules generating impl.ml from impl.cppo.ml
- Per-package findlib_index.json with relative universe paths (../dep)
and implicit stdlib dependency injection
- Add find_stdlib_dcs to Impl.S interface for stdlib CMI lookup via
findlib metadata instead of hardcoded URLs
- Replace jsoo Json.output/Json.unsafe_input with plain JSON.stringify/
JSON.parse for cross-jsoo-version compatibility (6.0.1+ox vs 6.2.0)
- Cross-origin worker support: set __global_rel_url in blob worker,
skip URL rewriting for absolute http(s) URLs
- Fix odoc doc comments and ocamlformat-ignore for cppo files
- Add demo docs, helper scripts, and x-ocaml package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend the odoc shell plugin interface with a sidebar_data field that
provides the raw Odoc_document.Sidebar.t alongside the pre-rendered HTML
sidebar. This allows shell plugins to generate custom sidebar UIs from
structured data rather than being limited to the default HTML rendering.
Create the odoc-docsite shell plugin (--shell docsite) that generates a
docs.rs-inspired documentation website with a fixed header, interactive
sidebar with package selector, full-text search, SPA navigation, dark
mode, and responsive layout. The sidebar JSON is embedded inline in each
page for client-side rendering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
# odoc-scrollycode-extension/src/scrollycode_extension.ml
- Bump root dune-project to (lang dune 3.21) for odoc v3 rules
- Remove (package odoc) from odoc_model_semantics_test library
- Remove (package js_top_worker_rpc_def) to work around directory-targets
bug in dune's doc generation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Escape curly braces and fix odoc reference syntax to eliminate warnings
with (warnings fatal):
- Replace {dir}, {pkg}, {hash} etc with [dir], [<pkg>], [<hash>] or
{[ code blocks ]} as appropriate
- Fix {!Stdlib.Out_channel.with_open_gen} -> [Out_channel.with_open_gen]
in sherlodoc type_polarity.mli
- Fix @scrolly.<theme> -> [@scrolly.<theme>] in scrollycode extension
- Fix JSON format in findlibish.ml doc comment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support files can now either embed inline string content (Inline) or
reference a file path on disk to copy (Copy_from). This enables large
binary-like files such as x-ocaml.js (~16MB) to be managed via
`odoc support-files` without embedding them as OCaml string literals.
The scrollycode extension's x-ocaml script URLs are now configurable
via ODOC_X_OCAML_JS and ODOC_X_OCAML_WORKER environment variables,
and ODOC_X_OCAML_JS_PATH registers the file as a Copy_from support file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three-layer architecture separating content, theme, and renderer:
Phase 1 — Scrollycode refactor:
- Strip ~1030 lines of embedded theme CSS from scrollycode_extension.ml
- Create scrollycode_css.ml with structural CSS using CSS custom properties
- Create scrollycode_themes.ml with three theme files (warm/dark/notebook)
registered as support files
- Simplify @scrolly tag: theme suffix now ignored (CSS concern, not content)
- Playground overlay styled via --xo-* custom properties on x-ocaml element
Phase 2 — Extra CSS support:
- Add --extra-css flag to odoc html-generate for injecting additional
<link> tags (used for per-page theme selection)
Phase 3 — Shell plugin system:
- Add Html_shell module with Shell interface and hashtable registry
- Register "default" shell in html_page.ml, "json" shell in
html_fragment_json.ml
- Replace hardcoded if/else in generator.ml with shell registry lookup
- Add --shell NAME flag (--as-json kept as backward-compat alias)
x-ocaml theming:
- Replace hardcoded colors in style.css with var(--xo-*, fallback)
covering editor, gutter, buttons, tooltips, and output areas
- CSS custom properties inherit through shadow DOM boundary, so
consumers theme x-ocaml with pure CSS — no JS injection needed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a doc_markdown field to Entry.t, populated at index time using
odoc's markdown renderer. The CLI gains --print-docstring for markdown
output (useful for LLM consumption and terminal display) while the
existing HTML output moves to --print-docstring-html.
Also exports Odoc_markdown.Generator.block for external use and adds
the UnboxedField case to url.ml's name_aux (needed after cherry-picked
fully-qualified-paths changes).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add extract_all_text helper that properly handles all inline renderer
elements (Text, Code_span, Inlines, Emphasis, etc.) instead of only
handling Text nodes. Fixes record fields losing their type annotations
in the unified code block output.
Cherry-picked from jonludlam/odoc@f303d8e69
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regenerate markdown reference files for the full generator test suite
to match the new unified code block and fully-qualified-paths output.
Cherry-picked from jonludlam/odoc@c19ca211f
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Properly handle trailing code items (like closing brackets for
polymorphic variants) by appending them to the unified code block.
Cherry-picked from jonludlam/odoc@55fea14a2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of rendering each constructor as a separate code block with
interleaved prose documentation, combine them into a single code block
with inline doc comments ((** ... *)). This produces much more coherent
output for LLM consumption.
Cherry-picked from jonludlam/odoc@6ed5e8ea9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests for variant types, polymorphic variants, and module includes
to validate the fully-qualified-paths markdown output.
Cherry-picked from jonludlam/odoc@c372810a5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use full_ident_name instead of Identifier.name to render complete
module-qualified paths in markdown output (e.g. Foo.Bar.t instead of
just t). This makes the markdown output much more useful for LLMs
that need unambiguous type references.
Cherry-picked from jonludlam/odoc@0220c2e06
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port fix from avsm/oxmono@1618948: when a module type path is replaced
during substitution, raise Invalidated instead of assert false, and
handle it in signature_fragment by unresolving the fragment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add missing source_loc_jane fields to Module and ModuleType records
in tools.ml (required by oxcaml's extended Component types)
- Add Strengthen case to is_elidable_with_u pattern matches in
compile.ml and link.ml (oxcaml adds this variant to U.expr)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
As well as during loading, we also have to handle `includes` with
potentially duplicate identifiers during `lang_of.ml`. This commit
moves the 'synthetic parent' functions into path.ml and uses them
both in cmti.ml and lang_of.ml
The fix for #930 has revealed another pre-existing issue. The problem is
again that we've got more valid way to specify an item that ends up with
the same Identifier. In particular, when we `include` an explicit
`sig`, these items have the same parent as the sibling items of the include.
See the test for an example of the problem.
The fix applies inline TypeSubstitution items during include expansion. When
a module type containing a TypeSubstitution (like `type 'a t := unit`) is
included elsewhere, the substitution is now applied at that point rather than
being preserved as-is.
Key changes:
- Add `apply_inner_substs` function in tools.ml that processes TypeSubstitution,
ModuleSubstitution, and ModuleTypeSubstitution items during include expansion
- Add `is_elidable_with_u` optimization to skip recompilation for pure signatures
- Add assertion for arity mismatch in type substitution to aid debugging
- Add `Subst.pp` for debugging substitution maps
This matches OCaml's behavior where destructive substitutions are applied to
produce a simplified signature when included.
Fixes #930, #1385
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This test demonstrates that odoc crashes with Invalid_argument("List.fold_left2")
when a signature has a destructive type substitution followed by an include that
re-introduces a type with the same name but different arity.
The next commit will fix this crash.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix duplicate install rule in doc/dune (logo installed by both
documentation and install stanzas)
- Add OxCaml cppo rule to test/xref2/lib/dune passing -D OXCAML flag
- Update common.cppo.ml for OxCaml Typemod API changes
(type_interface, type_implementation signatures) and add
source_loc_jane field
- Add Strengthen pattern to odoc_print.ml signature_of_module_type_expr
- Fix cram test expected indentation in oxcaml_modes.t
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extends OxCaml mode/layout support in odoc with three new features:
1. Return-side mode annotations on arrows (e.g. `string -> int @ local`)
- Arrow type extended from 4-tuple to 5-tuple with ret_modes
- Both cmi and cmti loaders extract return modes from mret
2. TypeDecl parameter jkinds (e.g. `type ('a : float64) t`)
- param_desc.Var extended with optional jkind string
- cmi path extracts from Tvar's jkind, cmti from parsetree annotation
- Renderer shows `('a : jkind)` syntax in format_params
3. Value modalities (e.g. `val x : int @@ portable`)
- Value.t extended with modalities string list
- extract_modalities replicates compiler's implied-modality filtering
- Renderer shows `@@ modality` after type annotation
Includes cram test (OxCaml-only, gated with enabled_if) verifying HTML
output for all three features. Test infrastructure has pre-existing
OxCaml compat issues preventing `dune runtest`; assertions verified
via manual simulation.
Builds cleanly with both standard OCaml and OxCaml compilers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Jkind.Desc.t field access: use `layout` instead of `base` (the
type is `layout_and_axes`, not `base_and_axes`)
- Fix Jkind layout pattern matching: remove non-existent `Layout`,
`Univar`, and `Kconstr` constructors to match actual compiler API
- Fix Parsetree.jkind_annotation field: use `pjkind_desc` instead of
`pjka_desc`, and handle `Pjk_abbreviation of string` (not Longident)
- Extract arrow modes from cmti path by reading underlying Types.type_expr
- Expose Cmi.extract_arg_modes in .mli for use by cmti.ml
Verified end-to-end: modes render correctly for both .cmi and .cmti
inputs (e.g., `val f : string @ local unique -> int`), and jkind
annotations appear on type variables (e.g., `('a : float64)`).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Var with jkind: renders ('a : float64) with parentheses and colon
- Arrow with modes: renders src @ local unique -> dst after the arg type
- RawOptional arrows left unchanged (error display)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- cmi.ml: Extract argument modes from Tarrow via Mode.Alloc.zap_to_legacy
and diff against legacy defaults (replicating Printtyp.tree_of_modes logic)
- cmi.ml: Extract jkind/layout from Tvar/Tunivar via Jkind.get descriptor
- cmti.ml: Extract jkind annotation from Ttyp_var's Parsetree annotation
- All extraction is cppo-guarded with OXCAML; standard OCaml passes []/None
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend Lang.TypeExpr and Component.TypeExpr with:
- Arrow: string list for argument mode annotations (e.g., ["local", "unique"])
- Var: string option for jkind/layout annotations (e.g., Some "float64")
All construction sites currently pass [] and None respectively.
The loader will be updated next to capture actual values from OxCaml.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for building js_top_worker and odoc with both the standard
OCaml 5.4 compiler and the OxCaml 5.2.0+ox compiler using cppo
conditional compilation and dual dune stanzas.
js_top_worker changes:
- Bump dune-project to 3.21 for %{ocaml-config:ox} support
- Add dual library stanzas gated by (enabled_if %{ocaml-config:ox})
- Add cppo guards for OxCaml API differences:
- Compilation_unit.Name.t vs string for persistent loader
- Env.report_error ~level:0 (extra parameter)
- Language_extension.set_universe_and_enable_all (oxcaml-only)
- Unit_info.make ~for_pack_prefix (extra parameter)
- Typemod.type_implementation (extra Compilation_unit arg)
- Gate ppx_deriving_rpc with (not %{ocaml-config:ox})
odoc changes:
- Apply upstream oxcaml PR #1399 (art-w/upstream-oxcaml)
- Bump dune-project to 3.21
- Add dual stanzas in loader, model, xref2, odoc, syntax_highlighter
- Add cppo OXCAML guards for compiler API differences
- Support OxCaml features: modes, layouts, labeled tuples, iarray,
unboxed records, module type strengthening, polymorphic arguments,
call position arguments, Import_info.t, Compilation_unit.t
Verified end-to-end: scrollycode demos generate HTML and the
interactive playground evaluates OCaml code in the browser with
both compiler switches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move scrollycode extension from odoc/src/extensions/scrollycode/ into
its own top-level package following the pattern of other odoc extensions
like odoc-admonition-extension. The package provides @scrolly.warm,
@scrolly.dark, and @scrolly.notebook tags for scroll-driven code
tutorials in odoc documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements a scrollycode extension for odoc's custom tag system that renders
scroll-driven code tutorials from .mld files. Three visual themes demonstrate
the flexibility of the extension plugin approach:
- warm: Earthy bookish aesthetic (JSON parser tutorial)
- dark: Cinematic terminal aesthetic (REPL tutorial)
- notebook: Clean editorial aesthetic (test framework tutorial)
Each demo uses @scrolly.<theme> custom tags with ordered lists where each
list item is a tutorial step. The extension extracts steps, applies OCaml
syntax highlighting, and generates HTML with IntersectionObserver-based
scroll tracking for step transitions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
# dune-project
# src/document/comment.ml
# src/extension_api/odoc_extension_api.ml
# src/extension_registry/odoc_extension_registry.ml
# src/model_desc/comment_desc.ml
# src/odoc/bin/dune
# src/odoc/bin/main.ml
# test/integration/extension_plugins.t/run.t
Previously, custom extension tags like @admonition.note and @rfc were
only allowed in OCaml documentation comments, not in standalone .mld
pages. This made it impossible to demonstrate extensions in their own
documentation.
Change tags_allowed from false to true when parsing .mld page content,
enabling extension tags to work in standalone documentation pages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a page uses the same extension multiple times (e.g., multiple
mermaid diagrams), the extension's resources (JS/CSS) were being
included once per use. This caused duplicate script and stylesheet
tags in the HTML output.
Add a deduplicate_resources helper that removes duplicates while
preserving order (keeping first occurrence) before rendering
resources to HTML.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
odoc-docsite:
- Rename CSS classes to align with stock odoc conventions
- Use odoc-nav, odoc-content, odoc-tocs for compatibility
- Prefix docsite-specific features with docsite-* (header, sidebar, etc.)
- Add class="odoc" to body element
odoc extensions:
- Add blocks_of_nestable_elements to extension API for preserving refs
- Fix admonition extension to render cross-references properly
- Fix MSC extension resource handling for nested module pages
- Fix Mermaid extension dark mode styling
Documentation:
- Improve JMAP docs with diagrams, admonitions, and better organization
- Fix IMAP state diagram (remove confusing logout from NotAuthenticated)
- Add JMAP dependency on ocaml-imap for cross-package references
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When an extension handles a custom tag, use an empty key in the
Description output so the tag name isn't shown twice. The extension's
output in the definition is self-describing.
Also remove redundant install stanza from deprecated/dune since the
parent doc/dune now handles these files via glob_files.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This reverts commit dcda8e8d329551c8b6e41927ef9147eabad53964.
- Add CSS styles for @admonition.note, @admonition.warning,
@admonition.tip, and @admonition.important tags
- Styles include colored backgrounds and left borders:
- Note: blue (#2196F3)
- Warning: orange (#FF9800)
- Tip: green (#4CAF50)
- Important: red (#F44336)
- Remove redundant install stanza from deprecated/dune since the
parent doc/dune now handles these files via glob_files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use glob_files instead of glob_files_rec to avoid including driver/
directory (which has its own documentation stanza for odoc-driver)
- Explicitly include deprecated/*.mld for the deprecated section
- Add all library directories and main_index to @children_order to
suppress warnings about unlisted children
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use glob_files_rec for mld files to include the deprecated/ directory
- Add odoc-parser, odoc-md, and sherlodoc to odoc package's documentation
dependencies to resolve cross-package references in main_index.mld
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extensions are now properly loaded via dune-site plugin mechanism,
so tests expecting "No extensions installed" have been updated to
expect "Installed extensions:" instead.
Also enhanced extension_plugins.t to verify extension-styled output:
- Check for rfc-reference class from rfc extension
- Check for rfc-editor.org links
- Check for admonition-warning class from admonition extension
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When Dynlink tried to load extension plugins (like rfc_extension.cmxs),
they failed with "undefined symbol: camlOdoc_extension_api" because the
odoc binary didn't export symbols needed by the plugins.
Adding -linkall to the odoc executable ensures all modules (including
odoc_extension_api) are linked into the binary and their symbols are
available for dynamic linking.
This enables extension plugins loaded via dune-site to work correctly.
Tag handlers (rfc, admonition) and code block handlers (dot, mermaid, msc)
now load and process tags during HTML/JSON generation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- odoc JSON output now includes resources (CSS/JS) and assets (binary files)
in the JSON schema, enabling extensions to contribute styling to docsites
- odoc-docsite parses and handles resources from JSON:
- Injects CSS/JS links into generated HTML pages
- Writes base64-decoded binary assets to output directory
- Copies extension support files from HTML output's extensions/ directory
- Fix resource path resolution to use proper relative paths from page to root
This enables odoc extension plugins (RFC, admonition, MSC, Mermaid, DOT) to
provide their CSS/JS resources when documentation is built via the JSON
pipeline and rendered with odoc-docsite.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The scrollycode JS runtime was embedded as an inline <script> in the
page body, which the SPA navigator never executes. Moved it to a
registered support file (extensions/scrollycode.js) loaded via Js_url
in <head>, with a MutationObserver to detect new containers inserted
by SPA content swaps.
Added a new "Writing Extensions" doc page to odoc covering the
extension API, resource types, the SPA navigation pitfall, and the
scrollycode fix as a case study.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- odoc extension API: add link-phase enrichment support for extensions
- odoc-jons-plugins: new site shell with nav bar, recent posts with
featured card layout, and updated CSS
- site-builder: support projects/ directory and improved rule generation
- site: redesigned homepage with hero section and recent posts cards
- site: updated blog index layout
- onnxrt docs: minor .mld cleanup
- New blog images and content (weeknotes, examination map, fungus svg)
- Add mockup.html for design iteration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, resolution failures in Errors.report used
Lookup_failures.report_internal which hardcoded non_fatal:true, meaning
they would never cause a build failure even when --warn-error was passed.
Switch to Lookup_failures.report_warning so that all resolution failures
(modules, types, references, etc.) respect --warn-error. Root errors
(missing dependencies) retain their own separate handling via report_root.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When compiling with -no-alias-deps, module aliases produce imports without
digests. Previously, resolve_imports would eagerly look up these modules in
the include path, potentially finding stale .odoc artifacts from a previous
build. This would associate the wrong digest with the import, breaking
incremental rebuilds.
Skip resolution for Unresolved (_, None) imports, leaving them unresolved
in the output .odoc file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When compiling with -no-alias-deps, module aliases produce imports
without digests. This test demonstrates that odoc currently resolves
these imports by looking them up in the include path, which can find
stale artifacts from a previous build and associate the wrong digest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sidebar kindBadge: map leaf-page→pg, module-type→MT, etc. (was
showing "L" for leaf-page entries)
- Stop escaping sidebar content HTML (entries contain <code> tags)
- Fix inline sidebar JSON: use Html.cdata_script instead of Html.txt
to prevent HTML-escaping inside <script> tags
- Add --xo-* CSS custom properties for x-ocaml cells in light/dark themes
- Fix support file registration: use 'opam var share' instead of
'opam var x-ocaml:share' (works without x-ocaml being an opam package)
- Suppress empty <li> from config-only extension tags (@x-ocaml.*)
- Add worker_url field to jtw opam findlib_index.json
- Refactor x-ocaml.js worker URL discovery to support both direct
worker_url and day10-style version/content_hash paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove 12 JS stubs from js_top_worker that are already provided by
basement/runtime.js and base/runtime.js (blocking_mutex, blocking_condition,
thread_yield, basement_dynamic, basement_alloc_stack_bind, caml_ml_domain_index)
- Keep caml_make_local_vect as it's needed by OxCaml compiler-libs and base
is not a transitive dependency
- Fix free-variables warnings by using proper //Provides/Requires pattern
for domain TLS shared state
- Add (link_flags (-linkall)) to odoc-scrollycode-extension test binary so
Html_page's side-effect shell registration is linked (matches real odoc binary)
- Promote test expected outputs for OCaml 5.4.1 and scrollycode extension changes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Consolidate js_top_worker and odoc dual-compiler stanzas into single
library stanzas with cppo rules generating impl.ml from impl.cppo.ml
- Per-package findlib_index.json with relative universe paths (../dep)
and implicit stdlib dependency injection
- Add find_stdlib_dcs to Impl.S interface for stdlib CMI lookup via
findlib metadata instead of hardcoded URLs
- Replace jsoo Json.output/Json.unsafe_input with plain JSON.stringify/
JSON.parse for cross-jsoo-version compatibility (6.0.1+ox vs 6.2.0)
- Cross-origin worker support: set __global_rel_url in blob worker,
skip URL rewriting for absolute http(s) URLs
- Fix odoc doc comments and ocamlformat-ignore for cppo files
- Add demo docs, helper scripts, and x-ocaml package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend the odoc shell plugin interface with a sidebar_data field that
provides the raw Odoc_document.Sidebar.t alongside the pre-rendered HTML
sidebar. This allows shell plugins to generate custom sidebar UIs from
structured data rather than being limited to the default HTML rendering.
Create the odoc-docsite shell plugin (--shell docsite) that generates a
docs.rs-inspired documentation website with a fixed header, interactive
sidebar with package selector, full-text search, SPA navigation, dark
mode, and responsive layout. The sidebar JSON is embedded inline in each
page for client-side rendering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Escape curly braces and fix odoc reference syntax to eliminate warnings
with (warnings fatal):
- Replace {dir}, {pkg}, {hash} etc with [dir], [<pkg>], [<hash>] or
{[ code blocks ]} as appropriate
- Fix {!Stdlib.Out_channel.with_open_gen} -> [Out_channel.with_open_gen]
in sherlodoc type_polarity.mli
- Fix @scrolly.<theme> -> [@scrolly.<theme>] in scrollycode extension
- Fix JSON format in findlibish.ml doc comment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support files can now either embed inline string content (Inline) or
reference a file path on disk to copy (Copy_from). This enables large
binary-like files such as x-ocaml.js (~16MB) to be managed via
`odoc support-files` without embedding them as OCaml string literals.
The scrollycode extension's x-ocaml script URLs are now configurable
via ODOC_X_OCAML_JS and ODOC_X_OCAML_WORKER environment variables,
and ODOC_X_OCAML_JS_PATH registers the file as a Copy_from support file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three-layer architecture separating content, theme, and renderer:
Phase 1 — Scrollycode refactor:
- Strip ~1030 lines of embedded theme CSS from scrollycode_extension.ml
- Create scrollycode_css.ml with structural CSS using CSS custom properties
- Create scrollycode_themes.ml with three theme files (warm/dark/notebook)
registered as support files
- Simplify @scrolly tag: theme suffix now ignored (CSS concern, not content)
- Playground overlay styled via --xo-* custom properties on x-ocaml element
Phase 2 — Extra CSS support:
- Add --extra-css flag to odoc html-generate for injecting additional
<link> tags (used for per-page theme selection)
Phase 3 — Shell plugin system:
- Add Html_shell module with Shell interface and hashtable registry
- Register "default" shell in html_page.ml, "json" shell in
html_fragment_json.ml
- Replace hardcoded if/else in generator.ml with shell registry lookup
- Add --shell NAME flag (--as-json kept as backward-compat alias)
x-ocaml theming:
- Replace hardcoded colors in style.css with var(--xo-*, fallback)
covering editor, gutter, buttons, tooltips, and output areas
- CSS custom properties inherit through shadow DOM boundary, so
consumers theme x-ocaml with pure CSS — no JS injection needed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a doc_markdown field to Entry.t, populated at index time using
odoc's markdown renderer. The CLI gains --print-docstring for markdown
output (useful for LLM consumption and terminal display) while the
existing HTML output moves to --print-docstring-html.
Also exports Odoc_markdown.Generator.block for external use and adds
the UnboxedField case to url.ml's name_aux (needed after cherry-picked
fully-qualified-paths changes).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add extract_all_text helper that properly handles all inline renderer
elements (Text, Code_span, Inlines, Emphasis, etc.) instead of only
handling Text nodes. Fixes record fields losing their type annotations
in the unified code block output.
Cherry-picked from jonludlam/odoc@f303d8e69
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of rendering each constructor as a separate code block with
interleaved prose documentation, combine them into a single code block
with inline doc comments ((** ... *)). This produces much more coherent
output for LLM consumption.
Cherry-picked from jonludlam/odoc@6ed5e8ea9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use full_ident_name instead of Identifier.name to render complete
module-qualified paths in markdown output (e.g. Foo.Bar.t instead of
just t). This makes the markdown output much more useful for LLMs
that need unambiguous type references.
Cherry-picked from jonludlam/odoc@0220c2e06
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add missing source_loc_jane fields to Module and ModuleType records
in tools.ml (required by oxcaml's extended Component types)
- Add Strengthen case to is_elidable_with_u pattern matches in
compile.ml and link.ml (oxcaml adds this variant to U.expr)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The fix for #930 has revealed another pre-existing issue. The problem is
again that we've got more valid way to specify an item that ends up with
the same Identifier. In particular, when we `include` an explicit
`sig`, these items have the same parent as the sibling items of the include.
See the test for an example of the problem.
The fix applies inline TypeSubstitution items during include expansion. When
a module type containing a TypeSubstitution (like `type 'a t := unit`) is
included elsewhere, the substitution is now applied at that point rather than
being preserved as-is.
Key changes:
- Add `apply_inner_substs` function in tools.ml that processes TypeSubstitution,
ModuleSubstitution, and ModuleTypeSubstitution items during include expansion
- Add `is_elidable_with_u` optimization to skip recompilation for pure signatures
- Add assertion for arity mismatch in type substitution to aid debugging
- Add `Subst.pp` for debugging substitution maps
This matches OCaml's behavior where destructive substitutions are applied to
produce a simplified signature when included.
Fixes #930, #1385
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This test demonstrates that odoc crashes with Invalid_argument("List.fold_left2")
when a signature has a destructive type substitution followed by an include that
re-introduces a type with the same name but different arity.
The next commit will fix this crash.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix duplicate install rule in doc/dune (logo installed by both
documentation and install stanzas)
- Add OxCaml cppo rule to test/xref2/lib/dune passing -D OXCAML flag
- Update common.cppo.ml for OxCaml Typemod API changes
(type_interface, type_implementation signatures) and add
source_loc_jane field
- Add Strengthen pattern to odoc_print.ml signature_of_module_type_expr
- Fix cram test expected indentation in oxcaml_modes.t
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extends OxCaml mode/layout support in odoc with three new features:
1. Return-side mode annotations on arrows (e.g. `string -> int @ local`)
- Arrow type extended from 4-tuple to 5-tuple with ret_modes
- Both cmi and cmti loaders extract return modes from mret
2. TypeDecl parameter jkinds (e.g. `type ('a : float64) t`)
- param_desc.Var extended with optional jkind string
- cmi path extracts from Tvar's jkind, cmti from parsetree annotation
- Renderer shows `('a : jkind)` syntax in format_params
3. Value modalities (e.g. `val x : int @@ portable`)
- Value.t extended with modalities string list
- extract_modalities replicates compiler's implied-modality filtering
- Renderer shows `@@ modality` after type annotation
Includes cram test (OxCaml-only, gated with enabled_if) verifying HTML
output for all three features. Test infrastructure has pre-existing
OxCaml compat issues preventing `dune runtest`; assertions verified
via manual simulation.
Builds cleanly with both standard OCaml and OxCaml compilers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Jkind.Desc.t field access: use `layout` instead of `base` (the
type is `layout_and_axes`, not `base_and_axes`)
- Fix Jkind layout pattern matching: remove non-existent `Layout`,
`Univar`, and `Kconstr` constructors to match actual compiler API
- Fix Parsetree.jkind_annotation field: use `pjkind_desc` instead of
`pjka_desc`, and handle `Pjk_abbreviation of string` (not Longident)
- Extract arrow modes from cmti path by reading underlying Types.type_expr
- Expose Cmi.extract_arg_modes in .mli for use by cmti.ml
Verified end-to-end: modes render correctly for both .cmi and .cmti
inputs (e.g., `val f : string @ local unique -> int`), and jkind
annotations appear on type variables (e.g., `('a : float64)`).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- cmi.ml: Extract argument modes from Tarrow via Mode.Alloc.zap_to_legacy
and diff against legacy defaults (replicating Printtyp.tree_of_modes logic)
- cmi.ml: Extract jkind/layout from Tvar/Tunivar via Jkind.get descriptor
- cmti.ml: Extract jkind annotation from Ttyp_var's Parsetree annotation
- All extraction is cppo-guarded with OXCAML; standard OCaml passes []/None
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend Lang.TypeExpr and Component.TypeExpr with:
- Arrow: string list for argument mode annotations (e.g., ["local", "unique"])
- Var: string option for jkind/layout annotations (e.g., Some "float64")
All construction sites currently pass [] and None respectively.
The loader will be updated next to capture actual values from OxCaml.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for building js_top_worker and odoc with both the standard
OCaml 5.4 compiler and the OxCaml 5.2.0+ox compiler using cppo
conditional compilation and dual dune stanzas.
js_top_worker changes:
- Bump dune-project to 3.21 for %{ocaml-config:ox} support
- Add dual library stanzas gated by (enabled_if %{ocaml-config:ox})
- Add cppo guards for OxCaml API differences:
- Compilation_unit.Name.t vs string for persistent loader
- Env.report_error ~level:0 (extra parameter)
- Language_extension.set_universe_and_enable_all (oxcaml-only)
- Unit_info.make ~for_pack_prefix (extra parameter)
- Typemod.type_implementation (extra Compilation_unit arg)
- Gate ppx_deriving_rpc with (not %{ocaml-config:ox})
odoc changes:
- Apply upstream oxcaml PR #1399 (art-w/upstream-oxcaml)
- Bump dune-project to 3.21
- Add dual stanzas in loader, model, xref2, odoc, syntax_highlighter
- Add cppo OXCAML guards for compiler API differences
- Support OxCaml features: modes, layouts, labeled tuples, iarray,
unboxed records, module type strengthening, polymorphic arguments,
call position arguments, Import_info.t, Compilation_unit.t
Verified end-to-end: scrollycode demos generate HTML and the
interactive playground evaluates OCaml code in the browser with
both compiler switches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move scrollycode extension from odoc/src/extensions/scrollycode/ into
its own top-level package following the pattern of other odoc extensions
like odoc-admonition-extension. The package provides @scrolly.warm,
@scrolly.dark, and @scrolly.notebook tags for scroll-driven code
tutorials in odoc documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements a scrollycode extension for odoc's custom tag system that renders
scroll-driven code tutorials from .mld files. Three visual themes demonstrate
the flexibility of the extension plugin approach:
- warm: Earthy bookish aesthetic (JSON parser tutorial)
- dark: Cinematic terminal aesthetic (REPL tutorial)
- notebook: Clean editorial aesthetic (test framework tutorial)
Each demo uses @scrolly.<theme> custom tags with ordered lists where each
list item is a tutorial step. The extension extracts steps, applies OCaml
syntax highlighting, and generates HTML with IntersectionObserver-based
scroll tracking for step transitions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, custom extension tags like @admonition.note and @rfc were
only allowed in OCaml documentation comments, not in standalone .mld
pages. This made it impossible to demonstrate extensions in their own
documentation.
Change tags_allowed from false to true when parsing .mld page content,
enabling extension tags to work in standalone documentation pages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a page uses the same extension multiple times (e.g., multiple
mermaid diagrams), the extension's resources (JS/CSS) were being
included once per use. This caused duplicate script and stylesheet
tags in the HTML output.
Add a deduplicate_resources helper that removes duplicates while
preserving order (keeping first occurrence) before rendering
resources to HTML.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
odoc-docsite:
- Rename CSS classes to align with stock odoc conventions
- Use odoc-nav, odoc-content, odoc-tocs for compatibility
- Prefix docsite-specific features with docsite-* (header, sidebar, etc.)
- Add class="odoc" to body element
odoc extensions:
- Add blocks_of_nestable_elements to extension API for preserving refs
- Fix admonition extension to render cross-references properly
- Fix MSC extension resource handling for nested module pages
- Fix Mermaid extension dark mode styling
Documentation:
- Improve JMAP docs with diagrams, admonitions, and better organization
- Fix IMAP state diagram (remove confusing logout from NotAuthenticated)
- Add JMAP dependency on ocaml-imap for cross-package references
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When an extension handles a custom tag, use an empty key in the
Description output so the tag name isn't shown twice. The extension's
output in the definition is self-describing.
Also remove redundant install stanza from deprecated/dune since the
parent doc/dune now handles these files via glob_files.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CSS styles for @admonition.note, @admonition.warning,
@admonition.tip, and @admonition.important tags
- Styles include colored backgrounds and left borders:
- Note: blue (#2196F3)
- Warning: orange (#FF9800)
- Tip: green (#4CAF50)
- Important: red (#F44336)
- Remove redundant install stanza from deprecated/dune since the
parent doc/dune now handles these files via glob_files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use glob_files instead of glob_files_rec to avoid including driver/
directory (which has its own documentation stanza for odoc-driver)
- Explicitly include deprecated/*.mld for the deprecated section
- Add all library directories and main_index to @children_order to
suppress warnings about unlisted children
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extensions are now properly loaded via dune-site plugin mechanism,
so tests expecting "No extensions installed" have been updated to
expect "Installed extensions:" instead.
Also enhanced extension_plugins.t to verify extension-styled output:
- Check for rfc-reference class from rfc extension
- Check for rfc-editor.org links
- Check for admonition-warning class from admonition extension
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When Dynlink tried to load extension plugins (like rfc_extension.cmxs),
they failed with "undefined symbol: camlOdoc_extension_api" because the
odoc binary didn't export symbols needed by the plugins.
Adding -linkall to the odoc executable ensures all modules (including
odoc_extension_api) are linked into the binary and their symbols are
available for dynamic linking.
This enables extension plugins loaded via dune-site to work correctly.
Tag handlers (rfc, admonition) and code block handlers (dot, mermaid, msc)
now load and process tags during HTML/JSON generation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- odoc JSON output now includes resources (CSS/JS) and assets (binary files)
in the JSON schema, enabling extensions to contribute styling to docsites
- odoc-docsite parses and handles resources from JSON:
- Injects CSS/JS links into generated HTML pages
- Writes base64-decoded binary assets to output directory
- Copies extension support files from HTML output's extensions/ directory
- Fix resource path resolution to use proper relative paths from page to root
This enables odoc extension plugins (RFC, admonition, MSC, Mermaid, DOT) to
provide their CSS/JS resources when documentation is built via the JSON
pipeline and rendered with odoc-docsite.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>