jon.recoil.org

Module Odoc_extension_registrySource

Odoc Extension Registry

This module provides a minimal registry for odoc tag extensions. It is kept separate to avoid circular dependencies between odoc_document and odoc_extension_api.

Sourcemodule Comment = Odoc_model.Comment
Sourcemodule Location_ = Odoc_model.Location_
Sourcetype resource =
  1. | Js_url of string
  2. | Css_url of string
  3. | Js_inline of string
  4. | Css_inline of string

Page Resources

Resources that an extension requests to be injected into the HTML <head>. The shell plugin is responsible for rendering these; the behaviour described below applies to the docsite shell shipped with odoc-docsite.

Execution timing

On the initial full page load every resource listed by every extension present on that page is emitted into <head> in order. External scripts (Js_url) are loaded via a normal <script src="…"> tag and execute when the browser fetches them. Inline scripts (Js_inline) execute synchronously in document order.

SPA (single-page app) navigation

The docsite shell intercepts link clicks and fetches pages via fetch() instead of a full reload. After swapping the page content it reconciles <head> resources:

  • Js_url / Css_url: Compared by resolved absolute URL. Resources already present in the live document are skipped; new ones are appended to <head> and (for scripts) their onload events are awaited before continuing.
  • Js_inline: Each inline script is stamped at HTML-generation time with a data-spa-inline attribute containing a hash of its content. On SPA navigation the shell checks whether a <script> with the same data-spa-inline value already exists in <head>. If so it is not re-executed. This means inline scripts run exactly once across SPA navigations — the first time a page carrying that script is visited.
  • Css_inline: Injected into <head> on every navigation (CSS is additive and idempotent, so duplicates are harmless).

Guidance for extension authors

  • Prefer Js_url for library code (e.g. the mermaid runtime). The deduplication-by-URL ensures it is loaded exactly once.
  • Use Js_inline for one-time initialisation that must run after the library is loaded (e.g. registering a global observer). It will execute once; on subsequent SPA navigations the library and observer are still alive.
  • If your extension needs to re-process content on every SPA navigation, set up a MutationObserver or listen for the "popstate" event in your Js_inline init script rather than relying on the script being re-executed.
  • Do not gate initialisation on DOMContentLoaded inside a Js_inline script — that event does not re-fire during SPA navigation.
Sourcetype support_file_content =
  1. | Inline of string
  2. | Copy_from of string
    (*

    Absolute path to source file

    *)

Content of a support file: either inline string or path to copy from disk

Sourcetype support_file = {
  1. filename : string;
    (*

    Relative path, e.g., "extensions/admonition.css"

    *)
  2. content : Odoc_extension_registry.support_file_content;
}

Support files that extensions want to output

Sourcetype asset = {
  1. asset_filename : string;
    (*

    Filename for the asset, e.g., "diagram-1.png"

    *)
  2. asset_content : bytes;
    (*

    Binary content

    *)
}

Binary asset generated by an extension (e.g., rendered PNG)

Sourcetype option_doc = {
  1. opt_name : string;
    (*

    Option name, e.g., "width"

    *)
  2. opt_description : string;
    (*

    What the option does

    *)
  3. opt_default : string option;
    (*

    Default value if any

    *)
}

Documentation for an extension option

Sourcetype extension_info = {
  1. info_kind : [ `Tag | `Code_block ];
    (*

    Type of extension

    *)
  2. info_prefix : string;
    (*

    The prefix this extension handles

    *)
  3. info_description : string;
    (*

    Short description of what it does

    *)
  4. info_options : Odoc_extension_registry.option_doc list;
    (*

    Supported options

    *)
  5. info_example : string option;
    (*

    Example usage

    *)
}

Documentation/metadata for an extension

Sourcetype 'block extension_result = {
  1. content : 'block;
  2. overrides : (string * string) list;
  3. resources : Odoc_extension_registry.resource list;
  4. assets : Odoc_extension_registry.asset list;
    (*

    Binary assets to write alongside the HTML output. Use __ODOC_ASSET__filename__ placeholder in content to reference.

    *)
}

Result of processing a custom tag. We use a record with a polymorphic content type that gets instantiated with the actual Block.t by odoc_document.

Type of handler functions stored in the registry. The handler takes a tag name and content, returns an optional result. If None, the tag is handled by the default mechanism.

Sourceval handlers : (string, Stdlib.Obj.t) Stdlib.Hashtbl.t

The registry stores handlers indexed by prefix

Sourceval prefixes : (string, unit) Stdlib.Hashtbl.t

Registered prefixes for listing

Support files registered by extensions

Sourceval register_handler : prefix:string -> 'block Odoc_extension_registry.handler -> unit
Sourceval register_support_file : prefix:string -> Odoc_extension_registry.support_file -> unit
Sourceval find_handler : prefix:string -> 'block Odoc_extension_registry.handler option
Sourceval list_prefixes : unit -> Stdlib.String.t list
Sourceval list_support_files : unit -> Odoc_extension_registry.support_file list
Sourceval prefix_of_tag : string -> string

Extract the prefix from a tag name (part before the first dot)

Code Block Handlers

Similar to custom tag handlers, but for code blocks like {@dot[...]}. Handlers can transform code blocks based on language and metadata.

Sourcetype code_block_meta = {
  1. language : string;
  2. tags : Odoc_parser.Ast.code_block_tag list;
}

Metadata for code blocks, extracted from parser AST

Sourcetype 'block code_block_handler = Odoc_extension_registry.code_block_meta -> string -> 'block Odoc_extension_registry.extension_result option

Type of code block handler functions. Takes metadata and code content, returns optional transformed result.

Sourceval code_block_handlers : (string, Stdlib.Obj.t) Stdlib.Hashtbl.t

Registry for code block handlers, indexed by language prefix

Sourceval code_block_prefixes : (string, unit) Stdlib.Hashtbl.t

Registered code block prefixes

Sourceval register_code_block_handler : prefix:string -> 'block Odoc_extension_registry.code_block_handler -> unit
Sourceval find_code_block_handler : prefix:string -> 'block Odoc_extension_registry.code_block_handler option
Sourceval list_code_block_prefixes : unit -> Stdlib.String.t list
Sourceval prefix_of_language : string -> string

Extract the prefix from a language tag (part before the first dot)

Extension Documentation

Extensions can register documentation that describes their options and usage. This is displayed by odoc extensions.

Registry for extension documentation

Sourceval register_extension_info : Odoc_extension_registry.extension_info -> unit
Sourceval list_extension_infos : unit -> Odoc_extension_registry.extension_info list

Extensions can register a link handler that runs during the linking phase with access to the cross-reference environment. The handler receives the tag name, the environment (as Obj.t to avoid a dependency on odoc_xref2 here), and already-resolved content. It returns transformed content.