···527527 let tok = current_token t in
528528 match tok.token with
529529 | Token.Flow_mapping_end ->
530530- t.state <- Flow_mapping_key;
531531- empty_scalar_event ~anchor:None ~tag:None tok.span
530530+ (* Trailing comma case - don't emit empty scalar, just return to key state *)
531531+ skip_token t;
532532+ t.state <- pop_state t;
533533+ Event.Mapping_end, tok.span
532534 | Token.Key ->
533535 skip_token t;
534536 if check t (function
···575577 parse_stream_start t
576578577579 | Implicit_document_start ->
578578- if check t (function
579579- | Token.Version_directive _ | Token.Tag_directive _
580580- | Token.Document_start | Token.Stream_end -> true
581581- | _ -> false)
582582- then begin
583583- if check t (function Token.Stream_end -> true | _ -> false) then begin
584584- let tok = current_token t in
585585- skip_token t;
586586- t.state <- End;
587587- t.finished <- true;
588588- Event.Stream_end, tok.span
589589- end else begin
590590- parse_document_start t ~implicit:false
591591- end
592592- end else
593593- parse_document_start t ~implicit:true
580580+ let tok = current_token t in
581581+ (match tok.token with
582582+ | Token.Stream_end ->
583583+ skip_token t;
584584+ t.state <- End;
585585+ t.finished <- true;
586586+ Event.Stream_end, tok.span
587587+ | Token.Version_directive _ | Token.Tag_directive _ | Token.Document_start ->
588588+ parse_document_start t ~implicit:false
589589+ (* These tokens are invalid at document start - they indicate leftover junk *)
590590+ | Token.Flow_sequence_end | Token.Flow_mapping_end | Token.Flow_entry
591591+ | Token.Block_end | Token.Value ->
592592+ Error.raise_span tok.span (Unexpected_token "unexpected token at document start")
593593+ | _ ->
594594+ parse_document_start t ~implicit:true)
594595595596 | Document_start ->
596597 parse_document_start t ~implicit:false
+44-5
yaml/ocaml-yamle/lib/scanner.ml
···367367 (Invalid_escape_sequence (Printf.sprintf "\\%c" c)));
368368 loop ()
369369 | Some '\n' | Some '\r' ->
370370+ (* Per YAML spec: discard trailing whitespace before line break *)
371371+ let len = Buffer.length buf in
372372+ let rec trim_end i =
373373+ if i < 0 then 0
374374+ else match Buffer.nth buf i with
375375+ | ' ' | '\t' -> trim_end (i - 1)
376376+ | _ -> i + 1
377377+ in
378378+ Buffer.truncate buf (trim_end (len - 1));
370379 Input.consume_break t.input;
371371- (* Fold to space *)
372372- Buffer.add_char buf ' ';
373373- (* Skip leading whitespace *)
374374- while Input.next_is_blank t.input do
375375- ignore (Input.next t.input)
380380+ (* Count consecutive line breaks (empty lines) *)
381381+ let empty_lines = ref 0 in
382382+ let continue = ref true in
383383+ while !continue do
384384+ (* Skip blanks (spaces/tabs) on the line *)
385385+ while Input.next_is_blank t.input do
386386+ ignore (Input.next t.input)
387387+ done;
388388+ (* Check if we hit another line break (empty line) *)
389389+ if Input.next_is_break t.input then begin
390390+ Input.consume_break t.input;
391391+ incr empty_lines
392392+ end else
393393+ continue := false
376394 done;
395395+ (* Per YAML spec: single break = space, break + empty lines = newlines *)
396396+ if !empty_lines > 0 then begin
397397+ (* Empty lines: output N newlines where N = number of empty lines *)
398398+ for _ = 1 to !empty_lines do
399399+ Buffer.add_char buf '\n'
400400+ done
401401+ end else
402402+ (* Single break folds to space *)
403403+ Buffer.add_char buf ' ';
377404 loop ()
378405 | Some c ->
379406 Buffer.add_char buf c;
···469496470497 scan_lines ();
471498 let value = Buffer.contents buf in
499499+ (* Trim trailing whitespace (spaces and tabs) *)
500500+ let value =
501501+ let len = String.length value in
502502+ let rec find_end i =
503503+ if i < 0 then 0
504504+ else match value.[i] with
505505+ | ' ' | '\t' -> find_end (i - 1)
506506+ | _ -> i + 1
507507+ in
508508+ let end_pos = find_end (len - 1) in
509509+ String.sub value 0 end_pos
510510+ in
472511 let span = Span.make ~start ~stop:(Input.mark t.input) in
473512 (value, span)
474513