Module Cmarkit.Mapper

Abstract syntax tree mappers.

Mappers help with pushing abstract syntax tree transformations in every node with a minimal amount of code by defaulting the cases you don't handle. The default map maps leaves to themselves and otherwise propagates the map to all childrens.

This map has the form of List.filter_map, however it is akin to List.concat_map as it allows:

See an example.

Map results

type 'a filter_map = 'a option

The type for maps. None is for node deletion. Some n is a map to n.

type 'a result = [
  1. | `Default

    Do the default map.

  2. | `Map of 'a filter_map

The type for mapper results.

val default : 'a result

default is `Default.

val delete : 'a result

delete is `Map None.

val ret : 'a -> 'a result

ret v is `Map (Some v).


type t

The type for abstract syntax tree mappers.

type 'a map = t -> 'a -> 'a filter_map

The type for maps on values of type 'a.

type 'a mapper = t -> 'a -> 'a result

The type for mappers on values of type 'a.

This is what you specify. Return `Default if you are not interested in handling the given case. Use map_inline or map_block with the given mapper if you need to call the mapper recursively.

val make : ?inline_ext_default:Inline.t map -> ?block_ext_default:Block.t map -> ?inline:Inline.t mapper -> ?block:Block.t mapper -> unit -> t

make ?inline ?block () is a mapper using inline and block to map the abstract syntax tree. Both default to fun _ _ -> `Default.

The mapper knows how to default the built-in abstract syntax tree and the built-in extensions. It maps them in document and depth-first order.

If you extend the abstract syntax tree you need to indicate how to default these new cases by providing inline_ext_default or block_ext_default functions. By default these functions raise Invalid_argument.


val map_inline : Inline.t map

map_inline m i maps i with m.

val map_block : Block.t map

map_block m b maps b with m.

val map_doc : t -> Doc.t -> Doc.t

map_doc m d maps Doc.block d with m. If the document block maps to None is replaced by Block.empty.

Warning unstable. The following may change in the future. This function also maps the blocks present Block.Footnote.Def label definitions but will not map inline or block data in Label.def cases unknown to Cmarkit. If the block maps to None for the footnote it is replaced by Block.empty.

Also note that if these label definitions were defined in d's abstract syntax tree, they will also already be mapped in Block.Link_reference_definition and Block.Ext_footnote_definition cases. It is possible to collect these mapped definitions via Block.defs on the resulting document's block.


val inline_mapper : t -> Inline.t mapper

inline m is the inline mapper of m.

val block_mapper : t -> Block.t mapper

block m is the block mapper of m.

val inline_ext_default : t -> Inline.t map

inline_ext_default m is the inline extensions defaulter of m

val block_ext_default : t -> Block.t map

block_ext_default m is the block extensions defaulter of m.


This example sets all code blocks of document doc without info string to lang.

let set_unknown_code_block_lang ~lang doc =
  let open Cmarkit in
  let default = lang, Meta.none in
  let block m = function
  | Block.Code_block (cb, meta)
    when Option.is_none (Block.Code_block.info_string cb) ->
      let layout = Block.Code_block.layout cb in
      let code = Block.Code_block.code cb in
      let cb = Block.Code_block.make ~layout ~info_string:default code in
      Mapper.ret (Block.Code_block (cb, meta))
  | _ ->
      Mapper.default (* let the mapper thread the map *)
  let mapper = Mapper.make ~block () in
  Mapper.map_doc mapper doc