(** Shared document AST and renderer for prose formats. Format-specific parsing is supplied by the {!format} type; the renderer, TOC generation, and anchor management are format-independent. Every text fragment is emitted through {!Ui}, ensuring safe escaping of repository content. *) (** {1 Document AST} *) type inline = | Text of string | Code of string | Verbatim of string | Link of { href : string; text : string } (** Inline markup elements. *) type block = | Heading of int * string | Paragraph of string | Unordered_list of string list | Ordered_list of string list | Definition_list of (string * string) list | Code_block of string option * string (** Block-level document elements. *) type document = { title : string option; metadata : (string * string) list; blocks : block list; } (** A parsed document with optional title, metadata, and body blocks. *) (** {1 Format interface} *) type format = { name : string; css_class : string; parse : string -> document; inline : string -> Ui.node list; } (** A documentation format provides parsing and inline markup rendering. *) (** {1 Shared utilities} *) val first_word : string -> string option (** Extract the first whitespace-delimited word from a string. *) val is_continuation : string -> bool (** [true] when a line is indented and non-blank, indicating it continues the previous list item. *) val take_continuations : string list -> string list * string list (** Split off leading continuation lines from the remaining input. *) val take_until : (string -> bool) -> string list -> string list -> string list * string list (** [take_until close collected lines] collects lines until [close] returns [true], returning the collected lines and the remainder after the closing line. *) (** {1 Shared list-item classifiers} *) val unordered_item : string -> string option (** Recognise an unordered list item ([-], [+], or indented [*]). *) val ordered_item : string -> string option (** Recognise an ordered list item ([1.], [2)], etc.). *) val is_boundary_common : string -> bool (** [true] when a line starts a new block (blank, or a list item). *) (** {1 Rendering} *) val render : format -> string -> Ui.node (** Render document content using the given format. Handles parsing, TOC generation, and block rendering. *)