OCaml HTML5 parser/serialiser based on Python's JustHTML
1(** Reusable context/ancestor tracking for checkers. 2 3 Many checkers need to track element ancestors, depth, or maintain 4 context stacks during DOM traversal. This module provides common 5 utilities to reduce duplication across checkers. 6 7 {2 Available Trackers} 8 9 - {!Stack}: Generic stack for any context type 10 - {!Depth}: Simple integer depth counter 11 - {!Ancestors}: String-based element ancestor tracking *) 12 13(** {2 Generic Stack} *) 14 15(** Generic stack-based context tracker. 16 17 Use this when you need to track complex state at each nesting level. 18 For example, tracking whether each ancestor has certain attributes. *) 19module Stack : sig 20 type 'a t 21 22 (** Create an empty context stack. *) 23 val create : unit -> 'a t 24 25 (** Reset the stack to empty. *) 26 val reset : 'a t -> unit 27 28 (** Push a context onto the stack. *) 29 val push : 'a t -> 'a -> unit 30 31 (** Pop a context from the stack. Returns None if empty. *) 32 val pop : 'a t -> 'a option 33 34 (** Get the current (top) context without removing it. *) 35 val current : 'a t -> 'a option 36 37 (** Get current depth (number of items on stack). *) 38 val depth : 'a t -> int 39 40 (** Check if stack is empty. *) 41 val is_empty : 'a t -> bool 42 43 (** Get all ancestors (bottom to top). *) 44 val to_list : 'a t -> 'a list 45 46 (** Check if any ancestor satisfies predicate. *) 47 val exists : 'a t -> ('a -> bool) -> bool 48 49 (** Find first ancestor satisfying predicate (top to bottom). *) 50 val find : 'a t -> ('a -> bool) -> 'a option 51 52 (** Iterate over all contexts (top to bottom). *) 53 val iter : 'a t -> ('a -> unit) -> unit 54end 55 56(** {2 Depth Counter} *) 57 58(** Simple depth counter for tracking nesting level. 59 60 Use this when you only need to know if you're inside a certain 61 element type, not the full context at each level. *) 62module Depth : sig 63 type t 64 65 (** Create a depth counter starting at 0. *) 66 val create : unit -> t 67 68 (** Reset depth to 0. *) 69 val reset : t -> unit 70 71 (** Increment depth (entering element). *) 72 val enter : t -> unit 73 74 (** Decrement depth (leaving element). Returns false if was already 0. *) 75 val leave : t -> bool 76 77 (** Get current depth. *) 78 val get : t -> int 79 80 (** Check if inside (depth > 0). *) 81 val is_inside : t -> bool 82end 83 84(** {2 Ancestor Tracker} *) 85 86(** Element name stack for tracking ancestors by name. 87 88 Use this when you need to check if certain elements are ancestors, 89 but don't need complex context at each level. *) 90module Ancestors : sig 91 type t 92 93 (** Create an empty ancestor tracker. *) 94 val create : unit -> t 95 96 (** Reset to empty. *) 97 val reset : t -> unit 98 99 (** Push an element name onto the ancestor stack. *) 100 val push : t -> string -> unit 101 102 (** Pop an element from the ancestor stack. *) 103 val pop : t -> unit 104 105 (** Get the immediate parent element name. *) 106 val parent : t -> string option 107 108 (** Check if an element name is an ancestor. *) 109 val has_ancestor : t -> string -> bool 110 111 (** Get depth (number of ancestors). *) 112 val depth : t -> int 113 114 (** Get all ancestor names (outermost first). *) 115 val to_list : t -> string list 116end