(** Source element context validation checker. Validates that source attributes are appropriate for the parent context. *) type parent_context = | Picture | Video | Audio | Other type state = { mutable context_stack : parent_context list; } let create () = { context_stack = []; } let reset state = state.context_stack <- [] let current_context state = match state.context_stack with | ctx :: _ -> ctx | [] -> Other let start_element state ~element collector = match element.Element.tag with | Tag.Html `Picture -> state.context_stack <- Picture :: state.context_stack | Tag.Html `Video -> state.context_stack <- Video :: state.context_stack | Tag.Html `Audio -> state.context_stack <- Audio :: state.context_stack | Tag.Html `Source -> let ctx = current_context state in (match ctx with | Video | Audio -> (* These attributes are only valid on source in picture, not audio/video *) Attr_utils.check_disallowed_attrs ~element:"source" ~collector ~attrs:element.raw_attrs ["srcset"; "sizes"; "width"; "height"] | Picture | Other -> ()) | _ -> () let end_element state ~tag _collector = match tag with | Tag.Html (`Picture | `Video | `Audio) -> (match state.context_stack with | _ :: rest -> state.context_stack <- rest | [] -> ()) | _ -> () let checker = Checker.make ~create ~reset ~start_element ~end_element ()