OCaml HTML5 parser/serialiser based on Python's JustHTML
1(** Typed error codes for HTML5 validation messages. 2 3 This module defines a comprehensive hierarchy of validation errors using 4 polymorphic variants, organized by error category. Each error type is 5 documented with the specific HTML5 conformance requirement it represents. 6 7 The error hierarchy is: 8 - {!t} is the top-level type containing all errors wrapped by category 9 - Each category (e.g., {!attr_error}, {!aria_error}) groups related errors 10 - Inline descriptors like [[\`Attr of string]] provide self-documenting parameters 11 12 {2 Example Usage} 13 14 {[ 15 (* Category-level matching *) 16 let is_accessibility_error = function 17 | `Aria _ | `Li_role _ -> true 18 | _ -> false 19 20 (* Fine-grained matching *) 21 match err with 22 | `Attr (`Duplicate_id (`Id id)) -> handle_duplicate id 23 | `Img `Missing_alt -> suggest_alt_text () 24 | _ -> default_handler err 25 ]} 26*) 27 28(** {1 Severity} *) 29 30(** Severity level of a validation message. 31 - [Error]: Conformance error that must be fixed 32 - [Warning]: Likely problem that should be reviewed 33 - [Info]: Suggestion for best practices *) 34type severity = Error | Warning | Info 35 36(** {1 Attribute Errors} 37 38 Errors related to HTML attributes: disallowed attributes, missing required 39 attributes, invalid attribute values, and duplicate IDs. *) 40 41(** Attribute-related validation errors. 42 43 These errors occur when attributes violate HTML5 content model rules: 44 - Attributes used on elements where they're not allowed 45 - Required attributes that are missing 46 - Attribute values that don't match expected formats 47 - Duplicate ID attributes within a document *) 48type attr_error = [ 49 | `Not_allowed of [`Attr of string] * [`Elem of string] 50 (** Attribute is not in the set of allowed attributes for this element. 51 Per HTML5 spec, each element has a defined set of content attributes; 52 using attributes outside this set is a conformance error. 53 Example: [type] attribute on a [<div>] element. *) 54 55 | `Not_allowed_here of [`Attr of string] 56 (** Attribute is valid on this element type but not in this context. 57 Some attributes are only allowed under specific conditions, such as 58 the [download] attribute which requires specific ancestor elements. *) 59 60 | `Not_allowed_when of [`Attr of string] * [`Elem of string] * [`Condition of string] 61 (** Attribute conflicts with another attribute or element state. 62 Example: [readonly] and [disabled] together, or [multiple] on 63 certain input types where it's not supported. *) 64 65 | `Missing of [`Elem of string] * [`Attr of string] 66 (** Element is missing a required attribute. 67 Per HTML5, certain elements have required attributes for conformance. 68 Example: [<img>] requires [src] or [srcset], [<input>] requires [type]. *) 69 70 | `Missing_one_of of [`Elem of string] * [`Attrs of string list] 71 (** Element must have at least one of the listed attributes. 72 Some elements require at least one from a set of attributes. 73 Example: [<base>] needs [href] or [target] (or both). *) 74 75 | `Bad_value of [`Elem of string] * [`Attr of string] * [`Value of string] * [`Reason of string] 76 (** Attribute value doesn't match the expected format or enumeration. 77 HTML5 defines specific value spaces for many attributes (enumerations, 78 URLs, integers, etc.). This error indicates the value is malformed. *) 79 80 | `Bad_value_generic of [`Message of string] 81 (** Generic bad attribute value with custom message. 82 Used when the specific validation failure requires a custom explanation 83 that doesn't fit the standard bad value template. *) 84 85 | `Duplicate_id of [`Id of string] 86 (** Document contains multiple elements with the same ID. 87 Per HTML5, the [id] attribute must be unique within a document. 88 Duplicate IDs cause problems with fragment navigation, label 89 association, and JavaScript DOM queries. *) 90 91 | `Data_invalid_name of [`Reason of string] 92 (** Custom data attribute name violates naming rules. 93 [data-*] attribute names must be valid XML NCNames (no colons, 94 must start with letter or underscore). The reason explains 95 the specific naming violation. *) 96 97 | `Data_uppercase 98 (** Custom data attribute name contains uppercase letters. 99 [data-*] attribute names must not contain ASCII uppercase letters 100 (A-Z) per HTML5. Use lowercase with hyphens instead. *) 101] 102 103(** {1 Element Structure Errors} 104 105 Errors related to element usage, nesting, and content models. *) 106 107(** Element structure validation errors. 108 109 These errors occur when elements violate HTML5 content model rules: 110 - Obsolete elements that should be replaced 111 - Elements used in wrong contexts (invalid parent/child relationships) 112 - Missing required child elements 113 - Empty elements that must have content *) 114type element_error = [ 115 | `Obsolete of [`Elem of string] * [`Suggestion of string] 116 (** Element is obsolete and should not be used. 117 HTML5 obsoletes certain elements from HTML4 (e.g., [<font>], [<center>]). 118 The suggestion provides the recommended modern alternative. *) 119 120 | `Obsolete_attr of [`Elem of string] * [`Attr of string] * [`Suggestion of string option] 121 (** Attribute on this element is obsolete. 122 Some attributes are obsolete on specific elements but may be valid 123 elsewhere. Example: [align] on [<table>] (use CSS instead). *) 124 125 | `Obsolete_global_attr of [`Attr of string] * [`Suggestion of string] 126 (** Global attribute is obsolete on all elements. 127 Attributes like [bgcolor] are obsolete everywhere in HTML5. *) 128 129 | `Not_allowed_as_child of [`Child of string] * [`Parent of string] 130 (** Element cannot be a child of the specified parent. 131 HTML5 defines content models for each element specifying which 132 children are allowed. Example: [<div>] inside [<p>] is invalid. *) 133 134 | `Unknown of [`Elem of string] 135 (** Element name is not recognized. 136 The element is not defined in HTML5, SVG, or MathML specs. 137 May be a typo or a custom element without hyphen. *) 138 139 | `Must_not_descend of [`Elem of string] * [`Attr of string option] * [`Ancestor of string] 140 (** Element must not appear as descendant of the specified ancestor. 141 Some elements have restrictions on their ancestry regardless of 142 direct parent. Example: [<form>] cannot be nested inside [<form>]. 143 The optional attribute indicates a conditional restriction. *) 144 145 | `Missing_child of [`Parent of string] * [`Child of string] 146 (** Parent element is missing a required child element. 147 Some elements must contain specific children for conformance. 148 Example: [<dl>] requires [<dt>] and [<dd>] children. *) 149 150 | `Missing_child_one_of of [`Parent of string] * [`Children of string list] 151 (** Parent must contain at least one of the listed child elements. 152 Example: [<ruby>] must contain [<rt>] or [<rp>]. *) 153 154 | `Missing_child_generic of [`Parent of string] 155 (** Parent is missing an unspecified required child. 156 Used when the required child depends on context. *) 157 158 | `Must_not_be_empty of [`Elem of string] 159 (** Element must have content and cannot be empty. 160 Some elements require text or child element content. 161 Example: [<title>] must not be empty. *) 162 163 | `Text_not_allowed of [`Parent of string] 164 (** Text content is not allowed in this element. 165 Some elements only allow element children, not text. 166 Example: [<table>] cannot contain direct text children. *) 167] 168 169(** {1 Tag and Parse Errors} 170 171 Errors from the parsing phase related to tags and document structure. *) 172 173(** Tag-level parse errors. 174 175 These errors occur during HTML parsing when the parser encounters 176 problematic tag structures or reaches end-of-file unexpectedly. *) 177type tag_error = [ 178 | `Stray_start of [`Tag of string] 179 (** Start tag appears in a position where it's not allowed. 180 The parser encountered an opening tag that cannot appear in 181 the current insertion mode. Example: [<tr>] outside [<table>]. *) 182 183 | `Stray_end of [`Tag of string] 184 (** End tag appears without a matching start tag. 185 The parser encountered a closing tag with no corresponding 186 open element in scope. *) 187 188 | `End_for_void of [`Tag of string] 189 (** End tag for a void element that cannot have one. 190 Void elements ([<br>], [<img>], etc.) cannot have end tags 191 in HTML5. Example: [</br>] is invalid. *) 192 193 | `Self_closing_non_void 194 (** Self-closing syntax [/>] used on non-void HTML element. 195 In HTML5, [/>] is only meaningful on void elements and 196 foreign (SVG/MathML) elements. On other elements it's ignored. *) 197 198 | `Not_in_scope of [`Tag of string] 199 (** End tag seen but no matching element in scope. 200 The parser found a closing tag but the element isn't in the 201 current scope (may be blocked by formatting elements). *) 202 203 | `End_implied_open of [`Tag of string] 204 (** End tag implied closing of other open elements. 205 The parser had to implicitly close elements to process this 206 end tag, indicating mismatched nesting. *) 207 208 | `Start_in_table of [`Tag of string] 209 (** Start tag appeared inside table where it's foster-parented. 210 When certain tags appear in table context, they're moved 211 outside the table (foster parenting), indicating malformed markup. *) 212 213 | `Bad_start_in of [`Tag of string] * [`Context of string] 214 (** Start tag appeared in invalid context. 215 Generic error for tags in wrong parsing contexts. *) 216 217 | `Eof_with_open 218 (** End of file reached with unclosed elements. 219 The document ended with elements still open on the stack, 220 indicating missing closing tags. *) 221] 222 223(** Character reference errors. 224 225 These errors occur when character references (like [&amp;] or [&#65;]) 226 expand to problematic Unicode code points. *) 227type char_ref_error = [ 228 | `Forbidden_codepoint of [`Codepoint of int] 229 (** Character reference expands to a forbidden code point. 230 Certain code points are forbidden in HTML documents (e.g., 231 NULL U+0000, noncharacters). These cannot appear even via 232 character references. *) 233 234 | `Control_char of [`Codepoint of int] 235 (** Character reference expands to a control character. 236 C0 and C1 control characters (except tab, newline, etc.) 237 are problematic and trigger this warning. *) 238 239 | `Non_char of [`Codepoint of int] * [`Astral of bool] 240 (** Character reference expands to a Unicode noncharacter. 241 Noncharacters (like U+FFFE, U+FFFF) are reserved and 242 should not appear in documents. Astral flag indicates 243 if it's in the supplementary planes. *) 244 245 | `Unassigned 246 (** Character reference expands to permanently unassigned code point. 247 The referenced code point will never be assigned a character. *) 248 249 | `Zero 250 (** Character reference expands to U+0000 (NULL). 251 NULL is replaced with U+FFFD (replacement character) per HTML5. *) 252 253 | `Out_of_range 254 (** Character reference value exceeds Unicode maximum. 255 Numeric character references must be <= U+10FFFF. *) 256 257 | `Carriage_return 258 (** Numeric character reference expanded to carriage return. 259 CR (U+000D) via numeric reference is replaced with LF. *) 260] 261 262(** {1 ARIA and Accessibility Errors} 263 264 Errors related to WAI-ARIA attributes and accessibility conformance. *) 265 266(** ARIA and role validation errors. 267 268 These errors ensure proper usage of WAI-ARIA attributes and roles 269 for accessibility. Incorrect ARIA can make content less accessible 270 than having no ARIA at all. *) 271type aria_error = [ 272 | `Unnecessary_role of [`Role of string] * [`Elem of string] * [`Reason of string] 273 (** Role is redundant because element has implicit role. 274 Many HTML elements have implicit ARIA roles; explicitly setting 275 the same role is unnecessary. Example: [role="button"] on [<button>]. *) 276 277 | `Bad_role of [`Elem of string] * [`Role of string] 278 (** Role value is invalid or not allowed on this element. 279 The role is either not a valid ARIA role token or is not 280 permitted on this particular element type. *) 281 282 | `Must_not_specify of [`Attr of string] * [`Elem of string] * [`Condition of string] 283 (** ARIA attribute must not be specified in this situation. 284 Some ARIA attributes are prohibited on certain elements unless 285 specific conditions are met. *) 286 287 | `Must_not_use of [`Attr of string] * [`Elem of string] * [`Condition of string] 288 (** ARIA attribute must not be used with this element configuration. 289 The attribute conflicts with another attribute or state of the element. *) 290 291 | `Should_not_use of [`Attr of string] * [`Role of string] 292 (** ARIA attribute should not be used with this role (warning). 293 While not strictly invalid, the attribute is discouraged 294 with this role as it may cause confusion. *) 295 296 | `Hidden_on_body 297 (** [aria-hidden="true"] used on body element. 298 Hiding the entire document from assistive technology is 299 almost certainly an error. *) 300 301 | `Unrecognized_role of [`Token of string] 302 (** Unrecognized role token was discarded. 303 The role attribute contained a token that isn't a valid 304 ARIA role. Browsers ignore unknown role tokens. *) 305 306 | `Tab_without_tabpanel 307 (** Tab element has no corresponding tabpanel. 308 Each [role="tab"] should control a [role="tabpanel"]. 309 Missing tabpanels indicate incomplete tab interface. *) 310 311 | `Multiple_main 312 (** Document has multiple visible main landmarks. 313 Only one visible [role="main"] or [<main>] should exist 314 per document for proper landmark navigation. *) 315 316 | `Accessible_name_prohibited of [`Attr of string] * [`Elem of string] 317 (** Accessible name attribute not allowed on element with generic role. 318 Elements with implicit [role="generic"] (or no role) cannot have 319 [aria-label], [aria-labelledby], or [aria-braillelabel] unless 320 they have an explicit role that supports accessible names. *) 321] 322 323(** List item role constraint errors. 324 325 Special ARIA role restrictions on [<li>] elements and [<div>] 326 children of [<dl>] elements. *) 327type li_role_error = [ 328 | `Div_in_dl_bad_role 329 (** [<div>] child of [<dl>] has invalid role. 330 When [<div>] is used to group [<dt>]/[<dd>] pairs in a [<dl>], 331 it may only have [role="presentation"] or [role="none"]. *) 332 333 | `Li_bad_role_in_menu 334 (** [<li>] in menu/menubar has invalid role. 335 [<li>] descendants of [role="menu"] or [role="menubar"] must 336 have roles like [menuitem], [menuitemcheckbox], etc. *) 337 338 | `Li_bad_role_in_tablist 339 (** [<li>] in tablist has invalid role. 340 [<li>] descendants of [role="tablist"] must have [role="tab"]. *) 341 342 | `Li_bad_role_in_list 343 (** [<li>] in list context has invalid role. 344 [<li>] in [<ul>], [<ol>], [<menu>], or [role="list"] must 345 have [role="listitem"] or no explicit role. *) 346] 347 348(** {1 Table Errors} 349 350 Errors in HTML table structure and cell spanning. *) 351 352(** Table structure validation errors. 353 354 These errors indicate problems with table structure that may 355 cause incorrect rendering or accessibility issues. *) 356type table_error = [ 357 | `Row_no_cells of [`Row of int] 358 (** Table row has no cells starting on it. 359 The specified row number (1-indexed) in an implicit row group 360 has no cells beginning on that row, possibly due to rowspan. *) 361 362 | `Cell_overlap 363 (** Table cells overlap due to spanning. 364 A cell's rowspan/colspan causes it to overlap with another cell, 365 making the table structure ambiguous. *) 366 367 | `Cell_spans_rowgroup 368 (** Cell's rowspan extends past its row group. 369 A cell's rowspan would extend beyond the [<tbody>], [<thead>], 370 or [<tfoot>] containing it; the span is clipped. *) 371 372 | `Column_no_cells of [`Column of int] * [`Elem of string] 373 (** Table column has no cells. 374 A column established by [<col>] or [<colgroup>] has no cells 375 beginning in it, indicating mismatched column definitions. *) 376] 377 378(** {1 Internationalization Errors} 379 380 Errors related to language declaration and text direction. *) 381 382(** Language and internationalization validation errors. 383 384 These errors help ensure documents properly declare their language 385 and text direction for accessibility and correct rendering. *) 386type i18n_error = [ 387 | `Missing_lang 388 (** Document has no language declaration. 389 The [<html>] element should have a [lang] attribute declaring 390 the document's primary language for accessibility. *) 391 392 | `Wrong_lang of [`Detected of string] * [`Declared of string] * [`Suggested of string] 393 (** Declared language doesn't match detected content language. 394 Automatic language detection suggests the [lang] attribute 395 value is incorrect for the actual content. *) 396 397 | `Missing_dir_rtl of [`Language of string] 398 (** RTL language content lacks [dir="rtl"]. 399 Content detected as a right-to-left language should have 400 explicit direction declaration. *) 401 402 | `Wrong_dir of [`Language of string] * [`Declared of string] 403 (** Text direction doesn't match detected language direction. 404 The [dir] attribute value conflicts with the detected 405 language's natural direction. *) 406 407 | `Xml_lang_without_lang 408 (** [xml:lang] present but [lang] is missing. 409 When [xml:lang] is specified (for XHTML compatibility), 410 the [lang] attribute must also be present with the same value. *) 411 412 | `Xml_lang_mismatch 413 (** [xml:lang] and [lang] attribute values don't match. 414 Both attributes must have identical values when present. *) 415 416 | `Not_nfc of [`Replacement of string] 417 (** Text is not in Unicode Normalization Form C. 418 HTML5 requires NFC normalization. The replacement string 419 shows the correctly normalized form. *) 420] 421 422(** {1 Import Map Errors} 423 424 Errors in [<script type="importmap">] JSON content. *) 425 426(** Import map validation errors. 427 428 These errors occur when validating the JSON content of 429 [<script type="importmap">] elements per the Import Maps spec. *) 430type importmap_error = [ 431 | `Invalid_json 432 (** Import map content is not valid JSON. 433 The script content must be parseable as JSON. *) 434 435 | `Invalid_root 436 (** Import map root is not a valid object. 437 The JSON must be an object with only [imports], [scopes], 438 and [integrity] properties. *) 439 440 | `Imports_not_object 441 (** The [imports] property is not a JSON object. 442 [imports] must be an object mapping specifiers to URLs. *) 443 444 | `Empty_key 445 (** Specifier map contains an empty string key. 446 Module specifier keys must be non-empty strings. *) 447 448 | `Non_string_value 449 (** Specifier map contains a non-string value. 450 All values in the specifier map must be strings (URLs). *) 451 452 | `Key_trailing_slash 453 (** Specifier with trailing [/] maps to URL without trailing [/]. 454 When a specifier key ends with [/], its value must also 455 end with [/] for proper prefix matching. *) 456 457 | `Scopes_not_object 458 (** The [scopes] property is not a JSON object. 459 [scopes] must be an object with URL keys. *) 460 461 | `Scopes_values_not_object 462 (** A [scopes] entry value is not a JSON object. 463 Each scope must map to a specifier map object. *) 464 465 | `Scopes_invalid_url 466 (** A [scopes] key is not a valid URL. 467 Scope keys must be valid URL strings. *) 468 469 | `Scopes_value_invalid_url 470 (** A specifier value in [scopes] is not a valid URL. 471 URL values in scope specifier maps must be valid. *) 472] 473 474(** {1 Element-Specific Errors} 475 476 Validation errors specific to particular HTML elements. *) 477 478(** Image element ([<img>]) validation errors. *) 479type img_error = [ 480 | `Missing_alt 481 (** Image lacks [alt] attribute for accessibility. 482 Per WCAG and HTML5, images must have [alt] text describing 483 their content, or [alt=""] for decorative images. *) 484 485 | `Missing_src_or_srcset 486 (** Image has neither [src] nor [srcset]. 487 An [<img>] must have at least one image source specified. *) 488 489 | `Empty_alt_with_role 490 (** Image with [alt=""] has a [role] attribute. 491 Decorative images (empty [alt]) must not have [role] because 492 they should be hidden from assistive technology. *) 493 494 | `Ismap_needs_href 495 (** Image with [ismap] lacks [<a href>] ancestor. 496 Server-side image maps require a link wrapper to function. *) 497] 498 499(** Link element ([<link>]) validation errors. *) 500type link_error = [ 501 | `Missing_href 502 (** [<link>] has no [href] or [imagesrcset]. 503 A link element must have a resource to link to. *) 504 505 | `As_requires_preload 506 (** [<link as="...">] used without [rel="preload"]. 507 The [as] attribute is only meaningful for preload/modulepreload. *) 508 509 | `Imagesrcset_requires_as_image 510 (** [<link imagesrcset>] used without [as="image"]. 511 Image srcset preloading requires [as="image"]. *) 512] 513 514(** Label element ([<label>]) validation errors. *) 515type label_error = [ 516 | `Too_many_labelable 517 (** Label contains multiple labelable descendants. 518 A [<label>] should associate with exactly one form control. *) 519 520 | `For_id_mismatch 521 (** Label's [for] doesn't match descendant input's [id]. 522 When a [<label>] has both [for] and a descendant input, 523 the input's [id] must match the [for] value. *) 524 525 | `Role_on_ancestor 526 (** [<label>] with role is ancestor of labelable element. 527 Adding [role] to a label that wraps a form control 528 breaks the implicit label association. *) 529 530 | `Aria_label_on_ancestor 531 (** [<label>] with [aria-label] is ancestor of labelable element. 532 [aria-label] on a label that wraps a form control creates 533 conflicting accessible names. *) 534 535 | `Role_on_for 536 (** [<label>] with role uses [for] association. 537 Labels with explicit [for] association must not have [role]. *) 538 539 | `Aria_label_on_for 540 (** [<label>] with [aria-label] uses [for] association. 541 [aria-label] on a label associated via [for] creates 542 conflicting accessible names. *) 543] 544 545(** Input element ([<input>]) validation errors. *) 546type input_error = [ 547 | `Checkbox_needs_aria_pressed 548 (** Checkbox with [role="button"] lacks [aria-pressed]. 549 When a checkbox is styled as a toggle button, it needs 550 [aria-pressed] to convey the toggle state. *) 551 552 | `Value_constraint of [`Constraint of string] 553 (** Input [value] doesn't meet type-specific constraints. 554 Different input types have different value format requirements 555 (dates, numbers, emails, etc.). *) 556 557 | `List_not_allowed 558 (** [list] attribute used on incompatible input type. 559 The [list] attribute for datalist binding is only valid 560 on certain input types (text, search, url, etc.). *) 561 562 | `List_requires_datalist 563 (** [list] attribute doesn't reference a [<datalist>]. 564 The [list] attribute must contain the ID of a datalist element. *) 565] 566 567(** Responsive image ([srcset]/[sizes]) validation errors. *) 568type srcset_error = [ 569 | `Sizes_without_srcset 570 (** [sizes] used without [srcset]. 571 The [sizes] attribute is meaningless without [srcset]. *) 572 573 | `Imagesizes_without_imagesrcset 574 (** [imagesizes] used without [imagesrcset]. 575 On [<link>], [imagesizes] requires [imagesrcset]. *) 576 577 | `W_without_sizes 578 (** [srcset] with width descriptors lacks [sizes]. 579 When using width descriptors ([w]) in [srcset], the [sizes] 580 attribute must specify the rendered size. *) 581 582 | `Source_missing_srcset 583 (** [<source>] in [<picture>] lacks [srcset]. 584 Picture source elements must have a srcset. *) 585 586 | `Source_needs_media_or_type 587 (** [<source>] needs [media] or [type] to differentiate. 588 When multiple sources exist, each must have selection criteria. *) 589 590 | `Picture_missing_img 591 (** [<picture>] lacks required [<img>] child. 592 A picture element must contain an img as the fallback. *) 593] 594 595(** SVG element validation errors. *) 596type svg_error = [ 597 | `Deprecated_attr of [`Attr of string] * [`Elem of string] 598 (** SVG attribute is deprecated. 599 Certain SVG presentation attributes are deprecated in 600 favor of CSS properties. *) 601 602 | `Missing_attr of [`Elem of string] * [`Attr of string] 603 (** SVG element missing required attribute. 604 Some SVG elements have required attributes for valid rendering. *) 605] 606 607(** Miscellaneous element-specific errors. 608 609 These errors are specific to individual elements that don't 610 warrant their own category. *) 611type misc_error = [ 612 | `Option_empty_without_label 613 (** [<option>] without [label] attribute is empty. 614 Options need either text content or a label attribute. *) 615 616 | `Bdo_missing_dir 617 (** [<bdo>] element lacks required [dir] attribute. 618 The bidirectional override element must specify direction. *) 619 620 | `Bdo_dir_auto 621 (** [<bdo>] has [dir="auto"] which is invalid. 622 BDO requires explicit [ltr] or [rtl], not auto-detection. *) 623 624 | `Base_missing_href_or_target 625 (** [<base>] has neither [href] nor [target]. 626 A base element must specify at least one of these. *) 627 628 | `Base_after_link_script 629 (** [<base>] appears after [<link>] or [<script>]. 630 The base URL must be established before other URL resolution. *) 631 632 | `Map_id_name_mismatch 633 (** [<map>] [id] and [name] attributes don't match. 634 For image maps, both attributes must have the same value. *) 635 636 | `Summary_missing_role 637 (** Non-default [<summary>] lacks [role] attribute. 638 Custom summary content outside details needs explicit role. *) 639 640 | `Summary_missing_attrs 641 (** Non-default [<summary>] missing required ARIA attributes. 642 Custom summary implementations need proper ARIA. *) 643 644 | `Summary_role_not_allowed 645 (** [<summary>] for its parent [<details>] has [role]. 646 Default summary for details must not override its role. *) 647 648 | `Autocomplete_webauthn_on_select 649 (** [<select>] has [autocomplete] containing [webauthn]. 650 WebAuthn autocomplete tokens are not valid for select elements. *) 651 652 | `Commandfor_invalid_target 653 (** [commandfor] doesn't reference a valid element ID. 654 The invoker must reference an element in the same tree. *) 655 656 | `Style_type_invalid 657 (** [<style type>] has value other than [text/css]. 658 HTML5 only supports CSS in style elements. *) 659 660 | `Headingoffset_invalid 661 (** [headingoffset] value is out of range. 662 Must be an integer between 0 and 8. *) 663 664 | `Media_empty 665 (** [media] attribute is empty string. 666 Media queries must be non-empty if the attribute is present. *) 667 668 | `Media_all 669 (** [media] attribute is just ["all"]. 670 Using [media="all"] is pointless; omit the attribute instead. *) 671 672 | `Multiple_h1 673 (** Document contains multiple [<h1>] elements. 674 Best practice is one [<h1>] per document unless using 675 [headingoffset] to indicate sectioning. *) 676 677 | `Multiple_autofocus 678 (** Multiple elements have [autofocus] in same scope. 679 Only one element should have autofocus per scoping root. *) 680] 681 682(** {1 Top-Level Error Type} *) 683 684(** All HTML5 validation errors, organized by category. 685 686 Pattern match on the outer constructor to handle error categories, 687 or match through to specific errors as needed. 688 689 {[ 690 let severity_of_category = function 691 | `Aria _ -> may_be_warning 692 | `I18n _ -> usually_info_or_warning 693 | _ -> usually_error 694 ]} *) 695type t = [ 696 | `Attr of attr_error 697 (** Attribute validation errors *) 698 | `Element of element_error 699 (** Element structure errors *) 700 | `Tag of tag_error 701 (** Tag-level parse errors *) 702 | `Char_ref of char_ref_error 703 (** Character reference errors *) 704 | `Aria of aria_error 705 (** ARIA and accessibility errors *) 706 | `Li_role of li_role_error 707 (** List item role constraints *) 708 | `Table of table_error 709 (** Table structure errors *) 710 | `I18n of i18n_error 711 (** Language and direction errors *) 712 | `Importmap of importmap_error 713 (** Import map JSON errors *) 714 | `Img of img_error 715 (** Image element errors *) 716 | `Link of link_error 717 (** Link element errors *) 718 | `Label of label_error 719 (** Label element errors *) 720 | `Input of input_error 721 (** Input element errors *) 722 | `Srcset of srcset_error 723 (** Responsive image errors *) 724 | `Svg of svg_error 725 (** SVG-specific errors *) 726 | `Misc of misc_error 727 (** Miscellaneous element errors *) 728 | `Generic of string 729 (** Fallback for messages without specific error codes *) 730] 731 732(** {1 Functions} *) 733 734(** Get the severity level for an error. 735 Most errors are [Error]; some ARIA and i18n issues are [Warning] or [Info]. *) 736val severity : t -> severity 737 738(** Get a short categorization code string. 739 Useful for filtering, grouping, or machine-readable output. 740 Example: ["disallowed-attribute"], ["missing-alt"], ["aria-not-allowed"]. *) 741val code_string : t -> string 742 743(** Convert error to human-readable message. 744 Produces messages matching the Nu HTML Validator format with 745 proper Unicode curly quotes around identifiers. *) 746val to_message : t -> string 747 748(** Format a string with Unicode curly quotes. 749 Wraps the string in U+201C and U+201D ("..."). *) 750val q : string -> string 751 752(** {1 Error Construction Helpers} 753 754 These functions simplify creating common error types. *) 755 756(** Create a bad attribute value error. 757 Example: [bad_value ~element:"img" ~attr:"src" ~value:"" ~reason:"URL cannot be empty"] *) 758val bad_value : element:string -> attr:string -> value:string -> reason:string -> t 759 760(** Create a bad attribute value error with just a message. 761 Example: [bad_value_msg "The value must be a valid URL"] *) 762val bad_value_msg : string -> t 763 764(** Create a missing required attribute error. 765 Example: [missing_attr ~element:"img" ~attr:"alt"] *) 766val missing_attr : element:string -> attr:string -> t 767 768(** Create an attribute not allowed error. 769 Example: [attr_not_allowed ~element:"span" ~attr:"href"] *) 770val attr_not_allowed : element:string -> attr:string -> t 771 772(** Create an element not allowed as child error. 773 Example: [not_allowed_as_child ~child:"div" ~parent:"p"] *) 774val not_allowed_as_child : child:string -> parent:string -> t 775 776(** Create a must not be empty error. 777 Example: [must_not_be_empty ~element:"title"] *) 778val must_not_be_empty : element:string -> t