Module Cmarkit.Label

Labels.

Labels are used by reference links to refer to the definitions of link reference definitions, footnote definitions and your own interpretations.

Labels

type key = string

The type for label keys. These are link labels normalized for matching.

type t

The type for link labels.

val make : ?meta:Meta.t -> key:string -> Block_line.tight list -> t

make key text is a label with key id and unormalized text text.

val with_meta : Meta.t -> t -> t

with_meta m l is l with meta m.

val meta : t -> Meta.t

meta k is metadata for k.

val key : t -> key

key_id l is the label's key. If l comes out of a parse this l's normalized text.

val text : t -> Block_line.tight list

text l is the text of l.

val text_to_string : t -> string

text_to_string l is the lines of text separated by spaces. In contrast to key this has not gone throught normalization.

val compare : t -> t -> int

compare l0 l1 is String.compare (key l0) (key l1).

Definitions

A label definition is the content referenced by its key.

Labels are defined in documents via footnotes and link reference definitions. Additional label definitions can be added before parsing starts by using the defs argument of Doc.of_string. They can also be manipulated and created on the fly during parsing by using a resolver.

type def = ..

The type for label definitions. See for example Link_definition.Def or Block.Footnote.Def.

module Map : Stdlib.Map.S with type key := key

Label key maps.

type defs = def Map.t

The type for label definitions. Maps label keys to their definition.

Resolvers

To have more control over the label definitions used in a document, the defs argument of Doc.of_string can be specified to pre-populate the label definitions used during parsing; for example with those of a previously parsed document.

In addition the resolver argument can be specified to:

  1. Alter or suppress label definitions made by link reference definitions and footnote definitions. It can also be used to warn, by side effect, on multiple label definitions.
  2. Alter, or suppress label references on reference links and images – which happen after all label definitions have been made. You can define the actual label that will be used for resolving the reference to its definition.

In particular 2. can be used to create synthetic label definitions on undefined label references. This provides the ability to treat the very liberal link label syntax as a domain specific language of yours (e.g. for data binding).

Note that parsing is not finished when resolvers are invoked this is the reason why you don't get access to the definition's data during resolution.

See an example.

type context = [
  1. | `Def of t option * t
    (*

    Label definitions

    *)
  2. | `Ref of [ `Link | `Image ] * t * t option
    (*

    Label references

    *)
]

The type for resolver contexts. See resolver.

type resolver = context -> t option

The type for resolvers. context is:

  • `Def (prev, current) when we just hit a link reference definition or footnote definition that defines the label current. If there is already a definition for current's key it is provided in prev (whose meta has the location of the definition if you parse with locations). If None is returned the current definition is ignored, and definition prev (if any) is kept for the document. If Some l is returned l's key will be bound to the parsed definition for current in Doc.defs at the end of parsing. The result of the resolver is stored in the abstract syntax tree and available via Link_definition.defined_label and Block.Footnote.defined_label.
  • `Ref (kind, ref, def) when we just hit a link or image referencing label ref. def is the label defining ref's key in the document (if any). The result of the resolver is the label stored for resolving the reference to its definition in the resulting Inline.Link node; None means that label is undefined and the inline becomes Inline.Text like in CommonMark.

See an example and the default_resolver.

val default_resolver : resolver

default_resolver is the default resolver.

This resolves according to the CommonMark specification. The first label definition always takes over subsequent ones and resolution is left untouched (i.e. a label has to be defined in the document to be used):

let default_resolver = function
| `Def (None, l) -> Some l
| `Def (Some _, _) -> None (* Previous takes over *)
| `Ref (_, _, def) -> def

Resolver example

In this example we assume references to undefined labels denote links to pages or media in our wiki and want to process them them later via a tree transformation or in a renderer extension.

We devise a resolver to create synthetic labels on any undefined label so that the CommonMark parser does not turn them into text.

let wikilink = Cmarkit.Meta.key () (* A meta key to recognize them *)

let make_wikilink label = (* Just a placeholder label definition *)
  let meta = Cmarkit.Meta.tag wikilink (Cmarkit.Label.meta label) in
  Cmarkit.Label.with_meta meta label

let with_wikilinks = function
| `Def _ as ctx -> Cmarkit.Label.default_resolver ctx
| `Ref (_, _, (Some _ as def)) -> def (* As per doc definition *)
| `Ref (_, ref, None) -> Some (make_wikilink ref)