(** Common attribute utilities used across checkers. *) type attrs = (string * string) list let has_attr name attrs = List.exists (fun (n, _) -> Astring.String.Ascii.lowercase n = name) attrs let get_attr name attrs = List.find_map (fun (n, v) -> if Astring.String.Ascii.lowercase n = name then Some v else None ) attrs let get_attr_or name ~default attrs = Option.value ~default (get_attr name attrs) let is_non_empty_attr name attrs = match get_attr name attrs with | Some v -> String.trim v <> "" | None -> false (** Create a unit hashtable from a list of keys for O(1) membership testing. *) let hashtbl_of_list items = let tbl = Hashtbl.create (List.length items) in List.iter (fun x -> Hashtbl.add tbl x ()) items; tbl (** Check a list of attributes and report errors for any that are present. *) let check_disallowed_attrs ~element ~collector ~attrs disallowed = List.iter (fun attr -> if has_attr attr attrs then Message_collector.add_typed collector (`Attr (`Not_allowed (`Attr attr, `Elem element))) ) disallowed