···2233 Validates that text content is in Unicode Normalization Form C (NFC). *)
4455-type state = unit [@@warning "-34"]
55+type state = {
66+ mutable in_raw_text : int; (** Depth inside style/script elements *)
77+}
6877-let create () = ()
88-let reset _state = ()
99+let create () = { in_raw_text = 0 }
1010+let reset state = state.in_raw_text <- 0
1111+1212+(** Elements whose text content is raw text and should be skipped *)
1313+let is_raw_text_element name =
1414+ name = "style" || name = "script" || name = "xmp" || name = "textarea"
9151016(** Normalize a string to NFC form using uunf. *)
1117let normalize_nfc text =
···4046 if end_pos = len then s
4147 else String.sub s 0 end_pos
42484343-let start_element _state ~element:_ _collector = ()
4949+let start_element state ~element _collector =
5050+ let name = Tag.tag_to_string element.Element.tag in
5151+ if is_raw_text_element name then
5252+ state.in_raw_text <- state.in_raw_text + 1
44534545-let end_element _state ~tag:_ _collector = ()
5454+let end_element state ~tag _collector =
5555+ let name = Tag.tag_to_string tag in
5656+ if is_raw_text_element name && state.in_raw_text > 0 then
5757+ state.in_raw_text <- state.in_raw_text - 1
46584747-let characters _state text collector =
5959+let characters state text collector =
6060+ (* Skip text inside raw text elements like style/script *)
6161+ if state.in_raw_text > 0 then () else
4862 (* Skip empty text or whitespace-only text *)
4963 let text_trimmed = String.trim text in
5064 if String.length text_trimmed = 0 then ()
+6-1
test/test_roundtrip.ml
···129129 Printf.printf "Running roundtrip tests...\n%!";
130130131131 (* Run tests *)
132132- let results = List.map test_file test_files in
132132+ let total = List.length test_files in
133133+ let results = List.mapi (fun i path ->
134134+ Printf.printf "\r[%d/%d] %s%!" (i + 1) total (Filename.basename path);
135135+ test_file path
136136+ ) test_files in
137137+ Printf.printf "\n%!";
133138134139 (* Categorize results *)
135140 let isvalid_tests = List.filter (fun r -> r.test_type = "isvalid") results in
+6-1
test/test_validator.ml
···426426 Printf.printf "Found %d test files\n%!" (List.length tests);
427427428428 Printf.printf "Running tests...\n%!";
429429- let results = List.map (run_test messages) tests in
429429+ let total = List.length tests in
430430+ let results = List.mapi (fun i test ->
431431+ Printf.printf "\r[%d/%d] %s%!" (i + 1) total test.relative_path;
432432+ run_test messages test
433433+ ) tests in
434434+ Printf.printf "\n%!";
430435431436 (* Print failing isvalid tests *)
432437 let failing_isvalid = List.filter (fun r ->