···11+ISC License
22+33+Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>
44+55+Permission to use, copy, modify, and distribute this software for any
66+purpose with or without fee is hereby granted, provided that the above
77+copyright notice and this permission notice appear in all copies.
88+99+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+62
README.md
···11+# yamlt - YAML codec using Jsont type descriptions
22+33+Yamlt provides YAML streaming encode/decode that interprets Jsont.t type descriptions, allowing the same codec definitions to work for both JSON and YAML.
44+55+## Key Features
66+77+- Use the same Jsont.t codec for both JSON and YAML formats
88+- Streaming encode/decode with configurable depth and node limits
99+- Support for YAML-specific features (scalars, sequences, mappings)
1010+- Billion laughs protection with configurable limits
1111+- Multiple output formats (block, flow, layout preservation)
1212+1313+## Usage
1414+1515+```ocaml
1616+(* Define a codec once using Jsont *)
1717+module Config = struct
1818+ type t = { name: string; port: int }
1919+ let make name port = { name; port }
2020+ let jsont =
2121+ Jsont.Object.map ~kind:"Config" make
2222+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
2323+ |> Jsont.Object.mem "port" Jsont.int ~enc:(fun c -> c.port)
2424+ |> Jsont.Object.finish
2525+end
2626+2727+(* Use the same codec for both JSON and YAML *)
2828+let from_json = Jsont_bytesrw.decode_string Config.jsont json_str
2929+let from_yaml = Yamlt.decode_string Config.jsont yaml_str
3030+```
3131+3232+For encoding:
3333+3434+```ocaml
3535+(* Encode to YAML with different formats *)
3636+let config = Config.make "server" 8080
3737+3838+(* Block style (default) *)
3939+let yaml_block = Yamlt.encode_string Config.jsont config
4040+4141+(* Flow style (JSON-like) *)
4242+let yaml_flow = Yamlt.encode_string ~format:Flow Config.jsont config
4343+```
4444+4545+## Installation
4646+4747+```
4848+opam install yamlt
4949+```
5050+5151+## Documentation
5252+5353+API documentation is available at https://tangled.org/@anil.recoil.org/ocaml-yamlt or via:
5454+5555+```
5656+opam install yamlt
5757+odig doc yamlt
5858+```
5959+6060+## License
6161+6262+ISC
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566open Bytesrw
77open Jsont.Repr
···2626 meta_none : Jsont.Meta.t;
2727}
28282929-let make_decoder
3030- ?(locs = false) ?(layout = false) ?(file = "-")
2929+let make_decoder ?(locs = false) ?(layout = false) ?(file = "-")
3130 ?(max_depth = 100) ?(max_nodes = 10_000_000) parser =
3231 let meta_none = Jsont.Meta.make (Jsont.Textloc.(set_file none) file) in
3333- { parser; file; locs; _layout = layout; max_depth; max_nodes;
3434- node_count = 0; current = None;
3535- _anchors = Hashtbl.create 16; meta_none }
3232+ {
3333+ parser;
3434+ file;
3535+ locs;
3636+ _layout = layout;
3737+ max_depth;
3838+ max_nodes;
3939+ node_count = 0;
4040+ current = None;
4141+ _anchors = Hashtbl.create 16;
4242+ meta_none;
4343+ }
36443745(* Decoder helpers *)
38463947let check_depth d ~nest =
4048 if nest > d.max_depth then
4141- Jsont.Error.msgf Jsont.Meta.none "Maximum nesting depth %d exceeded" d.max_depth
4949+ Jsont.Error.msgf Jsont.Meta.none "Maximum nesting depth %d exceeded"
5050+ d.max_depth
42514352let check_nodes d =
4453 d.node_count <- d.node_count + 1;
4554 if d.node_count > d.max_nodes then
4646- Jsont.Error.msgf Jsont.Meta.none "Maximum node count %d exceeded" d.max_nodes
5555+ Jsont.Error.msgf Jsont.Meta.none "Maximum node count %d exceeded"
5656+ d.max_nodes
47574858let meta_of_span d span =
4949- if not d.locs then d.meta_none else
5050- let start = span.Span.start and stop = span.Span.stop in
5151- let first_byte = start.Position.index in
5252- let last_byte = max first_byte (stop.Position.index - 1) in
5353- (* line_pos is (line_number, byte_position_of_line_start) *)
5454- let first_line = (start.Position.line, start.Position.index - start.Position.column + 1) in
5555- let last_line = (stop.Position.line, stop.Position.index - stop.Position.column + 1) in
5656- let textloc = Jsont.Textloc.make ~file:d.file
5757- ~first_byte ~last_byte ~first_line ~last_line in
5858- Jsont.Meta.make textloc
5959+ if not d.locs then d.meta_none
6060+ else
6161+ let start = span.Span.start and stop = span.Span.stop in
6262+ let first_byte = start.Position.index in
6363+ let last_byte = max first_byte (stop.Position.index - 1) in
6464+ (* line_pos is (line_number, byte_position_of_line_start) *)
6565+ let first_line =
6666+ (start.Position.line, start.Position.index - start.Position.column + 1)
6767+ in
6868+ let last_line =
6969+ (stop.Position.line, stop.Position.index - stop.Position.column + 1)
7070+ in
7171+ let textloc =
7272+ Jsont.Textloc.make ~file:d.file ~first_byte ~last_byte ~first_line
7373+ ~last_line
7474+ in
7575+ Jsont.Meta.make textloc
59766077let next_event d =
6178 d.current <- Parser.next d.parser;
6279 d.current
63806481let peek_event d =
6565- match d.current with
6666- | Some _ -> d.current
6767- | None -> next_event d
8282+ match d.current with Some _ -> d.current | None -> next_event d
68836969-let skip_event d =
7070- d.current <- None
8484+let skip_event d = d.current <- None
71857286let _expect_event d pred name =
7387 match peek_event d with
7474- | Some ev when pred ev.Event.event -> skip_event d; ev
8888+ | Some ev when pred ev.Event.event ->
8989+ skip_event d;
9090+ ev
7591 | Some ev ->
7692 let span = ev.Event.span in
7793 let meta = meta_of_span d span in
7878- Jsont.Error.msgf meta "Expected %s but found %a" name Event.pp ev.Event.event
9494+ Jsont.Error.msgf meta "Expected %s but found %a" name Event.pp
9595+ ev.Event.event
7996 | None ->
8080- Jsont.Error.msgf Jsont.Meta.none "Expected %s but reached end of stream" name
9797+ Jsont.Error.msgf Jsont.Meta.none "Expected %s but reached end of stream"
9898+ name
819982100(* Error helpers *)
83101···8710588106let err_type_mismatch d span t ~fnd =
89107 let meta = meta_of_span d span in
9090- Jsont.Error.msgf meta "Expected %s but found %s"
9191- (Jsont.Repr.kinded_sort t) fnd
108108+ Jsont.Error.msgf meta "Expected %s but found %s" (Jsont.Repr.kinded_sort t)
109109+ fnd
9211093111(* YAML scalar resolution *)
9411295113let is_null_scalar s =
9696- s = "" || s = "~" ||
9797- s = "null" || s = "Null" || s = "NULL"
114114+ s = "" || s = "~" || s = "null" || s = "Null" || s = "NULL"
9811599116let bool_of_scalar_opt s =
100117 match s with
101101- | "true" | "True" | "TRUE"
102102- | "yes" | "Yes" | "YES"
103103- | "on" | "On" | "ON" -> Some true
104104- | "false" | "False" | "FALSE"
105105- | "no" | "No" | "NO"
106106- | "off" | "Off" | "OFF" -> Some false
118118+ | "true" | "True" | "TRUE" | "yes" | "Yes" | "YES" | "on" | "On" | "ON" ->
119119+ Some true
120120+ | "false" | "False" | "FALSE" | "no" | "No" | "NO" | "off" | "Off" | "OFF" ->
121121+ Some false
107122 | _ -> None
108123109124let float_of_scalar_opt s =
···113128 | "+.inf" | "+.Inf" | "+.INF" -> Some Float.infinity
114129 | "-.inf" | "-.Inf" | "-.INF" -> Some Float.neg_infinity
115130 | ".nan" | ".NaN" | ".NAN" -> Some Float.nan
116116- | _ ->
131131+ | _ -> (
117132 (* Try parsing as number, allowing underscores *)
118133 let s' = String.concat "" (String.split_on_char '_' s) in
119134 (* Try int first (supports 0o, 0x, 0b) then float *)
120135 match int_of_string_opt s' with
121136 | Some i -> Some (float_of_int i)
122122- | None -> float_of_string_opt s'
137137+ | None -> float_of_string_opt s')
123138124139let _int_of_scalar_opt s =
125140 (* Handle hex, octal, and regular integers with underscores *)
···127142 int_of_string_opt s'
128143129144(* Decode a scalar value according to expected type *)
130130-let rec decode_scalar_as :
131131- type a. decoder -> Event.spanned -> string -> Scalar_style.t -> a t -> a =
132132- fun d ev value style t ->
145145+let rec decode_scalar_as : type a.
146146+ decoder -> Event.spanned -> string -> Scalar_style.t -> a t -> a =
147147+ fun d ev value style t ->
133148 check_nodes d;
134149 let meta = meta_of_span d ev.Event.span in
135150 match t with
136151 | Null map ->
137152 if is_null_scalar value then map.dec meta ()
138153 else err_type_mismatch d ev.span t ~fnd:("scalar " ^ value)
139139- | Bool map ->
140140- (match bool_of_scalar_opt value with
141141- | Some b -> map.dec meta b
142142- | None ->
143143- (* For explicitly quoted strings, fail *)
144144- if style <> `Plain then
145145- err_type_mismatch d ev.span t ~fnd:("string " ^ value)
146146- else
147147- err_type_mismatch d ev.span t ~fnd:("scalar " ^ value))
148148- | Number map ->
149149- (* Handle null -> nan mapping like jsont *)
150150- if is_null_scalar value then map.dec meta Float.nan
154154+ | Bool map -> (
155155+ match bool_of_scalar_opt value with
156156+ | Some b -> map.dec meta b
157157+ | None ->
158158+ (* For explicitly quoted strings, fail *)
159159+ if style <> `Plain then
160160+ err_type_mismatch d ev.span t ~fnd:("string " ^ value)
161161+ else err_type_mismatch d ev.span t ~fnd:("scalar " ^ value))
162162+ | Number map -> (
163163+ if
164164+ (* Handle null -> nan mapping like jsont *)
165165+ is_null_scalar value
166166+ then map.dec meta Float.nan
151167 else
152152- (match float_of_scalar_opt value with
153153- | Some f -> map.dec meta f
154154- | None -> err_type_mismatch d ev.span t ~fnd:("scalar " ^ value))
168168+ match float_of_scalar_opt value with
169169+ | Some f -> map.dec meta f
170170+ | None -> err_type_mismatch d ev.span t ~fnd:("scalar " ^ value))
155171 | String map ->
156172 (* Don't decode null values as strings - they should fail so outer combinators
157173 like 'option' or 'any' can handle them properly.
···168184 | Rec lazy_t ->
169185 (* Handle recursive types *)
170186 decode_scalar_as d ev value style (Lazy.force lazy_t)
171171- | _ ->
172172- err_type_mismatch d ev.span t ~fnd:"scalar"
187187+ | _ -> err_type_mismatch d ev.span t ~fnd:"scalar"
173188174189(* Forward declaration for mutual recursion *)
175190let rec decode : type a. decoder -> nest:int -> a t -> a =
176176- fun d ~nest t ->
191191+ fun d ~nest t ->
177192 check_depth d ~nest;
178193 match peek_event d with
179194 | None -> Jsont.Error.msgf Jsont.Meta.none "Unexpected end of YAML stream"
180180- | Some ev ->
181181- match ev.Event.event, t with
195195+ | Some ev -> (
196196+ match (ev.Event.event, t) with
182197 (* Scalar events *)
183198 | Event.Scalar { value; style; anchor; _ }, _ ->
184199 skip_event d;
185200 let result = decode_scalar d ~nest ev value style t in
186201 (* Store anchor if present - TODO: implement anchor storage *)
187202 (match anchor with
188188- | Some _name ->
189189- (* We need generic JSON for anchors - decode as json and convert back *)
190190- ()
191191- | None -> ());
203203+ | Some _name ->
204204+ (* We need generic JSON for anchors - decode as json and convert back *)
205205+ ()
206206+ | None -> ());
192207 result
193193-194208 (* Alias *)
195209 | Event.Alias { anchor }, _ ->
196210 skip_event d;
197211 decode_alias d ev anchor t
198198-199212 (* Map combinator - must come before specific event matches *)
200200- | _, Map m ->
201201- m.dec (decode d ~nest m.dom)
202202-213213+ | _, Map m -> m.dec (decode d ~nest m.dom)
203214 (* Recursive types - must come before specific event matches *)
204204- | _, Rec lazy_t ->
205205- decode d ~nest (Lazy.force lazy_t)
206206-215215+ | _, Rec lazy_t -> decode d ~nest (Lazy.force lazy_t)
207216 (* Sequence -> Array *)
208208- | Event.Sequence_start _, Array map ->
209209- decode_array d ~nest ev map
210210-211211- | Event.Sequence_start _, Any map ->
212212- decode_any_sequence d ~nest ev t map
213213-217217+ | Event.Sequence_start _, Array map -> decode_array d ~nest ev map
218218+ | Event.Sequence_start _, Any map -> decode_any_sequence d ~nest ev t map
214219 | Event.Sequence_start _, _ ->
215220 err_type_mismatch d ev.span t ~fnd:"sequence"
216216-217221 (* Mapping -> Object *)
218218- | Event.Mapping_start _, Object map ->
219219- decode_object d ~nest ev map
220220-221221- | Event.Mapping_start _, Any map ->
222222- decode_any_mapping d ~nest ev t map
223223-224224- | Event.Mapping_start _, _ ->
225225- err_type_mismatch d ev.span t ~fnd:"mapping"
226226-222222+ | Event.Mapping_start _, Object map -> decode_object d ~nest ev map
223223+ | Event.Mapping_start _, Any map -> decode_any_mapping d ~nest ev t map
224224+ | Event.Mapping_start _, _ -> err_type_mismatch d ev.span t ~fnd:"mapping"
227225 (* Unexpected events *)
228226 | Event.Sequence_end, _ ->
229227 Jsont.Error.msgf (meta_of_span d ev.span) "Unexpected sequence end"
···236234 | Event.Stream_start _, _ ->
237235 Jsont.Error.msgf (meta_of_span d ev.span) "Unexpected stream start"
238236 | Event.Stream_end, _ ->
239239- Jsont.Error.msgf (meta_of_span d ev.span) "Unexpected stream end"
237237+ Jsont.Error.msgf (meta_of_span d ev.span) "Unexpected stream end")
240238241241-and decode_scalar : type a. decoder -> nest:int -> Event.spanned -> string -> Scalar_style.t -> a t -> a =
242242- fun d ~nest ev value style t ->
239239+and decode_scalar : type a.
240240+ decoder -> nest:int -> Event.spanned -> string -> Scalar_style.t -> a t -> a
241241+ =
242242+ fun d ~nest ev value style t ->
243243 match t with
244244 | Any map -> decode_any_scalar d ev value style t map
245245 | Map m -> m.dec (decode_scalar d ~nest ev value style m.dom)
246246 | Rec lazy_t -> decode_scalar d ~nest ev value style (Lazy.force lazy_t)
247247 | _ -> decode_scalar_as d ev value style t
248248249249-and decode_any_scalar : type a. decoder -> Event.spanned -> string -> Scalar_style.t -> a t -> a any_map -> a =
250250- fun d ev value style t map ->
249249+and decode_any_scalar : type a.
250250+ decoder ->
251251+ Event.spanned ->
252252+ string ->
253253+ Scalar_style.t ->
254254+ a t ->
255255+ a any_map ->
256256+ a =
257257+ fun d ev value style t map ->
251258 check_nodes d;
252259 (* Determine which decoder to use based on scalar content *)
253260 if is_null_scalar value then
254261 match map.dec_null with
255262 | Some t' -> decode_scalar_as d ev value style t'
256256- | None -> Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Null
263263+ | None ->
264264+ Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Null
257265 else if style = `Plain then
258266 (* Try bool, then number, then string *)
259267 match bool_of_scalar_opt value with
260260- | Some _ ->
261261- (match map.dec_bool with
262262- | Some t' -> decode_scalar_as d ev value style t'
263263- | None ->
264264- match map.dec_string with
265265- | Some t' -> decode_scalar_as d ev value style t'
266266- | None -> Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Bool)
267267- | None ->
268268+ | Some _ -> (
269269+ match map.dec_bool with
270270+ | Some t' -> decode_scalar_as d ev value style t'
271271+ | None -> (
272272+ match map.dec_string with
273273+ | Some t' -> decode_scalar_as d ev value style t'
274274+ | None ->
275275+ Jsont.Repr.type_error (meta_of_span d ev.span) t
276276+ ~fnd:Jsont.Sort.Bool))
277277+ | None -> (
268278 match float_of_scalar_opt value with
269269- | Some _ ->
270270- (match map.dec_number with
271271- | Some t' -> decode_scalar_as d ev value style t'
272272- | None ->
273273- match map.dec_string with
274274- | Some t' -> decode_scalar_as d ev value style t'
275275- | None -> Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Number)
276276- | None ->
279279+ | Some _ -> (
280280+ match map.dec_number with
281281+ | Some t' -> decode_scalar_as d ev value style t'
282282+ | None -> (
283283+ match map.dec_string with
284284+ | Some t' -> decode_scalar_as d ev value style t'
285285+ | None ->
286286+ Jsont.Repr.type_error (meta_of_span d ev.span) t
287287+ ~fnd:Jsont.Sort.Number))
288288+ | None -> (
277289 (* Plain scalar that's not bool/number -> string *)
278290 match map.dec_string with
279291 | Some t' -> decode_scalar_as d ev value style t'
280280- | None -> Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.String
292292+ | None ->
293293+ Jsont.Repr.type_error (meta_of_span d ev.span) t
294294+ ~fnd:Jsont.Sort.String))
281295 else
282296 (* Quoted scalars are strings *)
283297 match map.dec_string with
284298 | Some t' -> decode_scalar_as d ev value style t'
285285- | None -> Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.String
299299+ | None ->
300300+ Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.String
286301287302and decode_alias : type a. decoder -> Event.spanned -> string -> a t -> a =
288288- fun d ev anchor t ->
303303+ fun d ev anchor t ->
289304 check_nodes d;
290305 match Hashtbl.find_opt d._anchors anchor with
291306 | None ->
292307 let meta = meta_of_span d ev.span in
293308 Jsont.Error.msgf meta "Unknown anchor: %s" anchor
294294- | Some json ->
309309+ | Some json -> (
295310 (* Decode the stored JSON value through the type *)
296311 let t' = Jsont.Repr.unsafe_to_t t in
297312 match Jsont.Json.decode' t' json with
298313 | Ok v -> v
299299- | Error e -> raise (Jsont.Error e)
314314+ | Error e -> raise (Jsont.Error e))
300315301301-and decode_array : type a elt b. decoder -> nest:int -> Event.spanned -> (a, elt, b) array_map -> a =
302302- fun d ~nest start_ev map ->
303303- skip_event d; (* consume Sequence_start *)
316316+and decode_array : type a elt b.
317317+ decoder -> nest:int -> Event.spanned -> (a, elt, b) array_map -> a =
318318+ fun d ~nest start_ev map ->
319319+ skip_event d;
320320+ (* consume Sequence_start *)
304321 check_nodes d;
305322 let meta = meta_of_span d start_ev.span in
306323 let builder = ref (map.dec_empty ()) in
···316333 (try
317334 if map.dec_skip i !builder then begin
318335 (* Skip this element by decoding as ignore *)
319319- let _ : unit = decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.ignore) in
336336+ let _ : unit =
337337+ decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.ignore)
338338+ in
320339 ()
321321- end else begin
340340+ end
341341+ else begin
322342 let elt = decode d ~nest:(nest + 1) map.elt in
323343 builder := map.dec_add i elt !builder
324344 end
···327347 Jsont.Repr.error_push_array meta map (i, imeta) e);
328348 incr idx;
329349 loop ()
330330- | None ->
331331- Jsont.Error.msgf meta "Unclosed sequence"
350350+ | None -> Jsont.Error.msgf meta "Unclosed sequence"
332351 in
333352 loop ()
334353335335-and decode_any_sequence : type a. decoder -> nest:int -> Event.spanned -> a t -> a any_map -> a =
336336- fun d ~nest ev t map ->
354354+and decode_any_sequence : type a.
355355+ decoder -> nest:int -> Event.spanned -> a t -> a any_map -> a =
356356+ fun d ~nest ev t map ->
337357 match map.dec_array with
338338- | Some t' ->
358358+ | Some t' -> (
339359 (* The t' decoder might be wrapped (e.g., Map for option types)
340360 Directly decode the array and let the wrapper handle it *)
341341- (match t' with
342342- | Array array_map ->
343343- decode_array d ~nest ev array_map
344344- | _ ->
345345- (* For wrapped types like Map (Array ...), use full decode *)
346346- decode d ~nest t')
347347- | None -> Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Array
361361+ match t' with
362362+ | Array array_map -> decode_array d ~nest ev array_map
363363+ | _ ->
364364+ (* For wrapped types like Map (Array ...), use full decode *)
365365+ decode d ~nest t')
366366+ | None ->
367367+ Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Array
348368349349-and decode_object : type o. decoder -> nest:int -> Event.spanned -> (o, o) object_map -> o =
350350- fun d ~nest start_ev map ->
351351- skip_event d; (* consume Mapping_start *)
369369+and decode_object : type o.
370370+ decoder -> nest:int -> Event.spanned -> (o, o) object_map -> o =
371371+ fun d ~nest start_ev map ->
372372+ skip_event d;
373373+ (* consume Mapping_start *)
352374 check_nodes d;
353375 let meta = meta_of_span d start_ev.span in
354354- let dict = decode_object_members d ~nest meta map String_map.empty Dict.empty in
376376+ let dict =
377377+ decode_object_members d ~nest meta map String_map.empty Dict.empty
378378+ in
355379 let dict = Dict.add object_meta_arg meta dict in
356380 apply_dict map.dec dict
357381358382and decode_object_members : type o.
359359- decoder -> nest:int -> Jsont.Meta.t -> (o, o) object_map ->
360360- mem_dec String_map.t -> Dict.t -> Dict.t =
361361- fun d ~nest obj_meta map mem_miss dict ->
383383+ decoder ->
384384+ nest:int ->
385385+ Jsont.Meta.t ->
386386+ (o, o) object_map ->
387387+ mem_dec String_map.t ->
388388+ Dict.t ->
389389+ Dict.t =
390390+ fun d ~nest obj_meta map mem_miss dict ->
362391 (* Merge expected member decoders *)
363392 let u _ _ _ = assert false in
364393 let mem_miss = String_map.union u mem_miss map.mem_decs in
···371400 decode_object_cases d ~nest obj_meta map umems cases mem_miss [] dict
372401373402and decode_object_basic : type o mems builder.
374374- decoder -> nest:int -> Jsont.Meta.t -> (o, o) object_map ->
375375- (o, mems, builder) unknown_mems ->
376376- mem_dec String_map.t -> Dict.t -> Dict.t =
377377- fun d ~nest obj_meta map umems mem_miss dict ->
378378- let ubuilder = ref (match umems with
379379- | Unknown_skip | Unknown_error -> Obj.magic ()
380380- | Unknown_keep (mmap, _) -> mmap.dec_empty ()) in
403403+ decoder ->
404404+ nest:int ->
405405+ Jsont.Meta.t ->
406406+ (o, o) object_map ->
407407+ (o, mems, builder) unknown_mems ->
408408+ mem_dec String_map.t ->
409409+ Dict.t ->
410410+ Dict.t =
411411+ fun d ~nest obj_meta map umems mem_miss dict ->
412412+ let ubuilder =
413413+ ref
414414+ (match umems with
415415+ | Unknown_skip | Unknown_error -> Obj.magic ()
416416+ | Unknown_keep (mmap, _) -> mmap.dec_empty ())
417417+ in
381418 let mem_miss = ref mem_miss in
382419 let dict = ref dict in
383420 let rec loop () =
···391428 let name, name_meta = decode_mapping_key d ev in
392429 (* Look up member decoder *)
393430 (match String_map.find_opt name map.mem_decs with
394394- | Some (Mem_dec mem) ->
395395- mem_miss := String_map.remove name !mem_miss;
396396- (try
397397- let v = decode d ~nest:(nest + 1) mem.type' in
398398- dict := Dict.add mem.id v !dict
399399- with Jsont.Error e ->
400400- Jsont.Repr.error_push_object obj_meta map (name, name_meta) e)
401401- | None ->
402402- (* Unknown member *)
403403- match umems with
404404- | Unknown_skip ->
405405- let _ : unit = decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.ignore) in
406406- ()
407407- | Unknown_error ->
408408- Jsont.Repr.unexpected_mems_error obj_meta map ~fnd:[(name, name_meta)]
409409- | Unknown_keep (mmap, _) ->
410410- (try
411411- let v = decode d ~nest:(nest + 1) mmap.mems_type in
412412- ubuilder := mmap.dec_add name_meta name v !ubuilder
413413- with Jsont.Error e ->
414414- Jsont.Repr.error_push_object obj_meta map (name, name_meta) e));
431431+ | Some (Mem_dec mem) -> (
432432+ mem_miss := String_map.remove name !mem_miss;
433433+ try
434434+ let v = decode d ~nest:(nest + 1) mem.type' in
435435+ dict := Dict.add mem.id v !dict
436436+ with Jsont.Error e ->
437437+ Jsont.Repr.error_push_object obj_meta map (name, name_meta) e)
438438+ | None -> (
439439+ (* Unknown member *)
440440+ match umems with
441441+ | Unknown_skip ->
442442+ let _ : unit =
443443+ decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.ignore)
444444+ in
445445+ ()
446446+ | Unknown_error ->
447447+ Jsont.Repr.unexpected_mems_error obj_meta map
448448+ ~fnd:[ (name, name_meta) ]
449449+ | Unknown_keep (mmap, _) -> (
450450+ try
451451+ let v = decode d ~nest:(nest + 1) mmap.mems_type in
452452+ ubuilder := mmap.dec_add name_meta name v !ubuilder
453453+ with Jsont.Error e ->
454454+ Jsont.Repr.error_push_object obj_meta map (name, name_meta) e)
455455+ ));
415456 loop ()
416416- | None ->
417417- Jsont.Error.msgf obj_meta "Unclosed mapping"
457457+ | None -> Jsont.Error.msgf obj_meta "Unclosed mapping"
418458 in
419459 loop ()
420460421461and finish_object : type o mems builder.
422422- Jsont.Meta.t -> (o, o) object_map -> (o, mems, builder) unknown_mems ->
423423- builder -> mem_dec String_map.t -> Dict.t -> Dict.t =
424424- fun meta map umems ubuilder mem_miss dict ->
462462+ Jsont.Meta.t ->
463463+ (o, o) object_map ->
464464+ (o, mems, builder) unknown_mems ->
465465+ builder ->
466466+ mem_dec String_map.t ->
467467+ Dict.t ->
468468+ Dict.t =
469469+ fun meta map umems ubuilder mem_miss dict ->
425470 let dict = Dict.add object_meta_arg meta dict in
426426- let dict = match umems with
471471+ let dict =
472472+ match umems with
427473 | Unknown_skip | Unknown_error -> dict
428428- | Unknown_keep (mmap, _) -> Dict.add mmap.id (mmap.dec_finish meta ubuilder) dict
474474+ | Unknown_keep (mmap, _) ->
475475+ Dict.add mmap.id (mmap.dec_finish meta ubuilder) dict
429476 in
430477 (* Check for missing required members *)
431478 let add_default _ (Mem_dec mem_map) dict =
···440487 Jsont.Repr.missing_mems_error meta map ~exp ~fnd:[]
441488442489and decode_object_cases : type o cases tag.
443443- decoder -> nest:int -> Jsont.Meta.t -> (o, o) object_map ->
444444- unknown_mems_option ->
445445- (o, cases, tag) object_cases ->
446446- mem_dec String_map.t -> (Jsont.name * Jsont.json) list -> Dict.t -> Dict.t =
447447- fun d ~nest obj_meta map umems cases mem_miss delayed dict ->
490490+ decoder ->
491491+ nest:int ->
492492+ Jsont.Meta.t ->
493493+ (o, o) object_map ->
494494+ unknown_mems_option ->
495495+ (o, cases, tag) object_cases ->
496496+ mem_dec String_map.t ->
497497+ (Jsont.name * Jsont.json) list ->
498498+ Dict.t ->
499499+ Dict.t =
500500+ fun d ~nest obj_meta map umems cases mem_miss delayed dict ->
448501 match peek_event d with
449449- | Some { Event.event = Event.Mapping_end; _ } ->
502502+ | Some { Event.event = Event.Mapping_end; _ } -> (
450503 skip_event d;
451504 (* No tag found - use dec_absent if available *)
452452- (match cases.tag.dec_absent with
453453- | Some tag ->
454454- decode_with_case_tag d ~nest obj_meta map umems cases tag mem_miss delayed dict
455455- | None ->
456456- (* Missing required case tag *)
457457- let exp = String_map.singleton cases.tag.name (Mem_dec cases.tag) in
458458- let fnd = List.map (fun ((n, _), _) -> n) delayed in
459459- Jsont.Repr.missing_mems_error obj_meta map ~exp ~fnd)
505505+ match cases.tag.dec_absent with
506506+ | Some tag ->
507507+ decode_with_case_tag d ~nest obj_meta map umems cases tag mem_miss
508508+ delayed dict
509509+ | None ->
510510+ (* Missing required case tag *)
511511+ let exp = String_map.singleton cases.tag.name (Mem_dec cases.tag) in
512512+ let fnd = List.map (fun ((n, _), _) -> n) delayed in
513513+ Jsont.Repr.missing_mems_error obj_meta map ~exp ~fnd)
460514 | Some ev ->
461515 let name, name_meta = decode_mapping_key d ev in
462516 if String.equal name cases.tag.name then begin
463517 (* Found the case tag *)
464518 let tag = decode d ~nest:(nest + 1) cases.tag.type' in
465465- decode_with_case_tag d ~nest obj_meta map umems cases tag mem_miss delayed dict
466466- end else begin
519519+ decode_with_case_tag d ~nest obj_meta map umems cases tag mem_miss
520520+ delayed dict
521521+ end
522522+ else begin
467523 (* Not the case tag - check if known member or delay *)
468524 match String_map.find_opt name map.mem_decs with
469469- | Some (Mem_dec mem) ->
525525+ | Some (Mem_dec mem) -> (
470526 let mem_miss = String_map.remove name mem_miss in
471471- (try
472472- let v = decode d ~nest:(nest + 1) mem.type' in
473473- let dict = Dict.add mem.id v dict in
474474- decode_object_cases d ~nest obj_meta map umems cases mem_miss delayed dict
475475- with Jsont.Error e ->
476476- Jsont.Repr.error_push_object obj_meta map (name, name_meta) e)
527527+ try
528528+ let v = decode d ~nest:(nest + 1) mem.type' in
529529+ let dict = Dict.add mem.id v dict in
530530+ decode_object_cases d ~nest obj_meta map umems cases mem_miss
531531+ delayed dict
532532+ with Jsont.Error e ->
533533+ Jsont.Repr.error_push_object obj_meta map (name, name_meta) e)
477534 | None ->
478535 (* Unknown member - decode as generic JSON and delay *)
479536 let v = decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.json) in
480537 let delayed = ((name, name_meta), v) :: delayed in
481481- decode_object_cases d ~nest obj_meta map umems cases mem_miss delayed dict
538538+ decode_object_cases d ~nest obj_meta map umems cases mem_miss
539539+ delayed dict
482540 end
483483- | None ->
484484- Jsont.Error.msgf obj_meta "Unclosed mapping"
541541+ | None -> Jsont.Error.msgf obj_meta "Unclosed mapping"
485542486543and decode_with_case_tag : type o cases tag.
487487- decoder -> nest:int -> Jsont.Meta.t -> (o, o) object_map ->
488488- unknown_mems_option ->
489489- (o, cases, tag) object_cases -> tag ->
490490- mem_dec String_map.t -> (Jsont.name * Jsont.json) list -> Dict.t -> Dict.t =
491491- fun d ~nest obj_meta map umems cases tag mem_miss delayed dict ->
544544+ decoder ->
545545+ nest:int ->
546546+ Jsont.Meta.t ->
547547+ (o, o) object_map ->
548548+ unknown_mems_option ->
549549+ (o, cases, tag) object_cases ->
550550+ tag ->
551551+ mem_dec String_map.t ->
552552+ (Jsont.name * Jsont.json) list ->
553553+ Dict.t ->
554554+ Dict.t =
555555+ fun d ~nest obj_meta map umems cases tag mem_miss delayed dict ->
492556 let eq_tag (Case c) = cases.tag_compare c.tag tag = 0 in
493557 match List.find_opt eq_tag cases.cases with
494494- | None ->
495495- Jsont.Repr.unexpected_case_tag_error obj_meta map cases tag
558558+ | None -> Jsont.Repr.unexpected_case_tag_error obj_meta map cases tag
496559 | Some (Case case) ->
497560 (* Continue decoding with the case's object map *)
498498- let case_dict = decode_case_remaining d ~nest obj_meta case.object_map
499499- umems mem_miss delayed dict in
561561+ let case_dict =
562562+ decode_case_remaining d ~nest obj_meta case.object_map umems mem_miss
563563+ delayed dict
564564+ in
500565 let case_value = apply_dict case.object_map.dec case_dict in
501566 Dict.add cases.id (case.dec case_value) dict
502567503568and decode_case_remaining : type o.
504504- decoder -> nest:int -> Jsont.Meta.t -> (o, o) object_map ->
505505- unknown_mems_option ->
506506- mem_dec String_map.t -> (Jsont.name * Jsont.json) list -> Dict.t -> Dict.t =
507507- fun d ~nest obj_meta case_map _umems mem_miss delayed dict ->
569569+ decoder ->
570570+ nest:int ->
571571+ Jsont.Meta.t ->
572572+ (o, o) object_map ->
573573+ unknown_mems_option ->
574574+ mem_dec String_map.t ->
575575+ (Jsont.name * Jsont.json) list ->
576576+ Dict.t ->
577577+ Dict.t =
578578+ fun d ~nest obj_meta case_map _umems mem_miss delayed dict ->
508579 (* First, process delayed members against the case map *)
509580 let u _ _ _ = assert false in
510581 let mem_miss = String_map.union u mem_miss case_map.mem_decs in
511511- let dict, mem_miss = List.fold_left (fun (dict, mem_miss) ((name, meta), json) ->
512512- match String_map.find_opt name case_map.mem_decs with
513513- | Some (Mem_dec mem) ->
514514- let t' = Jsont.Repr.unsafe_to_t mem.type' in
515515- (match Jsont.Json.decode' t' json with
516516- | Ok v ->
517517- let dict = Dict.add mem.id v dict in
518518- let mem_miss = String_map.remove name mem_miss in
519519- (dict, mem_miss)
520520- | Error e ->
521521- Jsont.Repr.error_push_object obj_meta case_map (name, meta) e)
522522- | None ->
523523- (* Unknown for case too - skip them *)
524524- (dict, mem_miss)
525525- ) (dict, mem_miss) delayed in
582582+ let dict, mem_miss =
583583+ List.fold_left
584584+ (fun (dict, mem_miss) ((name, meta), json) ->
585585+ match String_map.find_opt name case_map.mem_decs with
586586+ | Some (Mem_dec mem) -> (
587587+ let t' = Jsont.Repr.unsafe_to_t mem.type' in
588588+ match Jsont.Json.decode' t' json with
589589+ | Ok v ->
590590+ let dict = Dict.add mem.id v dict in
591591+ let mem_miss = String_map.remove name mem_miss in
592592+ (dict, mem_miss)
593593+ | Error e ->
594594+ Jsont.Repr.error_push_object obj_meta case_map (name, meta) e)
595595+ | None ->
596596+ (* Unknown for case too - skip them *)
597597+ (dict, mem_miss))
598598+ (dict, mem_miss) delayed
599599+ in
526600 (* Then continue reading remaining members using case's own unknown handling *)
527601 match case_map.shape with
528602 | Object_basic case_umems ->
···531605 (* Nested cases shouldn't happen - use skip for safety *)
532606 decode_object_basic d ~nest obj_meta case_map Unknown_skip mem_miss dict
533607534534-and decode_any_mapping : type a. decoder -> nest:int -> Event.spanned -> a t -> a any_map -> a =
535535- fun d ~nest ev t map ->
608608+and decode_any_mapping : type a.
609609+ decoder -> nest:int -> Event.spanned -> a t -> a any_map -> a =
610610+ fun d ~nest ev t map ->
536611 match map.dec_object with
537612 | Some t' -> decode d ~nest t'
538538- | None -> Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Object
613613+ | None ->
614614+ Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Object
539615540616and decode_mapping_key : decoder -> Event.spanned -> string * Jsont.Meta.t =
541541- fun d ev ->
617617+ fun d ev ->
542618 match ev.Event.event with
543619 | Event.Scalar { value; _ } ->
544620 skip_event d;
···553629let skip_to_content d =
554630 let rec loop () =
555631 match peek_event d with
556556- | Some { Event.event = Event.Stream_start _; _ } -> skip_event d; loop ()
557557- | Some { Event.event = Event.Document_start _; _ } -> skip_event d; loop ()
632632+ | Some { Event.event = Event.Stream_start _; _ } ->
633633+ skip_event d;
634634+ loop ()
635635+ | Some { Event.event = Event.Document_start _; _ } ->
636636+ skip_event d;
637637+ loop ()
558638 | _ -> ()
559639 in
560640 loop ()
···562642let skip_end_wrappers d =
563643 let rec loop () =
564644 match peek_event d with
565565- | Some { Event.event = Event.Document_end _; _ } -> skip_event d; loop ()
566566- | Some { Event.event = Event.Stream_end; _ } -> skip_event d; loop ()
645645+ | Some { Event.event = Event.Document_end _; _ } ->
646646+ skip_event d;
647647+ loop ()
648648+ | Some { Event.event = Event.Stream_end; _ } ->
649649+ skip_event d;
650650+ loop ()
567651 | None -> ()
568652 | Some ev ->
569653 let meta = meta_of_span d ev.span in
570570- Jsont.Error.msgf meta "Expected end of document but found %a" Event.pp ev.event
654654+ Jsont.Error.msgf meta "Expected end of document but found %a" Event.pp
655655+ ev.event
571656 in
572657 loop ()
573658···608693 scalar_style : Scalar_style.t;
609694}
610695611611-let make_encoder
612612- ?(format = Block) ?(indent = 2) ?(explicit_doc = false)
696696+let make_encoder ?(format = Block) ?(indent = 2) ?(explicit_doc = false)
613697 ?(scalar_style = `Any) emitter =
614698 { emitter; format; _indent = indent; explicit_doc; scalar_style }
615699···627711628712(* Encode null *)
629713let encode_null e _meta =
630630- Emitter.emit e.emitter (Event.Scalar {
631631- anchor = None;
632632- tag = None;
633633- value = "null";
634634- plain_implicit = true;
635635- quoted_implicit = true;
636636- style = `Plain;
637637- })
714714+ Emitter.emit e.emitter
715715+ (Event.Scalar
716716+ {
717717+ anchor = None;
718718+ tag = None;
719719+ value = "null";
720720+ plain_implicit = true;
721721+ quoted_implicit = true;
722722+ style = `Plain;
723723+ })
638724639725(* Encode boolean *)
640726let encode_bool e _meta b =
641641- Emitter.emit e.emitter (Event.Scalar {
642642- anchor = None;
643643- tag = None;
644644- value = if b then "true" else "false";
645645- plain_implicit = true;
646646- quoted_implicit = true;
647647- style = `Plain;
648648- })
727727+ Emitter.emit e.emitter
728728+ (Event.Scalar
729729+ {
730730+ anchor = None;
731731+ tag = None;
732732+ value = (if b then "true" else "false");
733733+ plain_implicit = true;
734734+ quoted_implicit = true;
735735+ style = `Plain;
736736+ })
649737650738(* Encode number *)
651739let encode_number e _meta f =
···654742 | FP_nan -> ".nan"
655743 | FP_infinite -> if f > 0.0 then ".inf" else "-.inf"
656744 | _ ->
657657- if Float.is_integer f && Float.abs f < 1e15 then
658658- Printf.sprintf "%.0f" f
659659- else
660660- Printf.sprintf "%g" f
745745+ if Float.is_integer f && Float.abs f < 1e15 then Printf.sprintf "%.0f" f
746746+ else Printf.sprintf "%g" f
661747 in
662662- Emitter.emit e.emitter (Event.Scalar {
663663- anchor = None;
664664- tag = None;
665665- value;
666666- plain_implicit = true;
667667- quoted_implicit = true;
668668- style = `Plain;
669669- })
748748+ Emitter.emit e.emitter
749749+ (Event.Scalar
750750+ {
751751+ anchor = None;
752752+ tag = None;
753753+ value;
754754+ plain_implicit = true;
755755+ quoted_implicit = true;
756756+ style = `Plain;
757757+ })
670758671759(* Encode string *)
672760let encode_string e _meta s =
673761 let style = choose_scalar_style ~preferred:e.scalar_style s in
674674- Emitter.emit e.emitter (Event.Scalar {
675675- anchor = None;
676676- tag = None;
677677- value = s;
678678- plain_implicit = true;
679679- quoted_implicit = true;
680680- style;
681681- })
762762+ Emitter.emit e.emitter
763763+ (Event.Scalar
764764+ {
765765+ anchor = None;
766766+ tag = None;
767767+ value = s;
768768+ plain_implicit = true;
769769+ quoted_implicit = true;
770770+ style;
771771+ })
682772683773let rec encode : type a. encoder -> a t -> a -> unit =
684684- fun e t v ->
774774+ fun e t v ->
685775 match t with
686776 | Null map ->
687777 let meta = map.enc_meta v in
688778 let () = map.enc v in
689779 encode_null e meta
690690-691780 | Bool map ->
692781 let meta = map.enc_meta v in
693782 let b = map.enc v in
694783 encode_bool e meta b
695695-696784 | Number map ->
697785 let meta = map.enc_meta v in
698786 let f = map.enc v in
699787 encode_number e meta f
700700-701788 | String map ->
702789 let meta = map.enc_meta v in
703790 let s = map.enc v in
704791 encode_string e meta s
705705-706706- | Array map ->
707707- encode_array e map v
708708-709709- | Object map ->
710710- encode_object e map v
711711-792792+ | Array map -> encode_array e map v
793793+ | Object map -> encode_object e map v
712794 | Any map ->
713795 let t' = map.enc v in
714796 encode e t' v
715715-716716- | Map m ->
717717- encode e m.dom (m.enc v)
718718-719719- | Rec lazy_t ->
720720- encode e (Lazy.force lazy_t) v
797797+ | Map m -> encode e m.dom (m.enc v)
798798+ | Rec lazy_t -> encode e (Lazy.force lazy_t) v
721799722800and encode_array : type a elt b. encoder -> (a, elt, b) array_map -> a -> unit =
723723- fun e map v ->
801801+ fun e map v ->
724802 let style = layout_style_of_format e.format in
725725- Emitter.emit e.emitter (Event.Sequence_start {
726726- anchor = None;
727727- tag = None;
728728- implicit = true;
729729- style;
730730- });
731731- let _ = map.enc (fun () _idx elt ->
732732- encode e map.elt elt;
733733- ()
734734- ) () v in
803803+ Emitter.emit e.emitter
804804+ (Event.Sequence_start { anchor = None; tag = None; implicit = true; style });
805805+ let _ =
806806+ map.enc
807807+ (fun () _idx elt ->
808808+ encode e map.elt elt;
809809+ ())
810810+ () v
811811+ in
735812 Emitter.emit e.emitter Event.Sequence_end
736813737814and encode_object : type o. encoder -> (o, o) object_map -> o -> unit =
738738- fun e map v ->
815815+ fun e map v ->
739816 let style = layout_style_of_format e.format in
740740- Emitter.emit e.emitter (Event.Mapping_start {
741741- anchor = None;
742742- tag = None;
743743- implicit = true;
744744- style;
745745- });
817817+ Emitter.emit e.emitter
818818+ (Event.Mapping_start { anchor = None; tag = None; implicit = true; style });
746819 (* Encode each member *)
747747- List.iter (fun (Mem_enc mem) ->
748748- let mem_v = mem.enc v in
749749- if not (mem.enc_omit mem_v) then begin
750750- (* Emit key *)
751751- Emitter.emit e.emitter (Event.Scalar {
752752- anchor = None;
753753- tag = None;
754754- value = mem.name;
755755- plain_implicit = true;
756756- quoted_implicit = true;
757757- style = `Plain;
758758- });
759759- (* Emit value *)
760760- encode e mem.type' mem_v
761761- end
762762- ) map.mem_encs;
820820+ List.iter
821821+ (fun (Mem_enc mem) ->
822822+ let mem_v = mem.enc v in
823823+ if not (mem.enc_omit mem_v) then begin
824824+ (* Emit key *)
825825+ Emitter.emit e.emitter
826826+ (Event.Scalar
827827+ {
828828+ anchor = None;
829829+ tag = None;
830830+ value = mem.name;
831831+ plain_implicit = true;
832832+ quoted_implicit = true;
833833+ style = `Plain;
834834+ });
835835+ (* Emit value *)
836836+ encode e mem.type' mem_v
837837+ end)
838838+ map.mem_encs;
763839 (* Handle case objects *)
764840 (match map.shape with
765765- | Object_basic _ -> ()
766766- | Object_cases (_, cases) ->
767767- let Case_value (case_map, case_v) = cases.enc_case (cases.enc v) in
768768- (* Emit case tag *)
769769- if not (cases.tag.enc_omit (case_map.tag)) then begin
770770- Emitter.emit e.emitter (Event.Scalar {
771771- anchor = None;
772772- tag = None;
773773- value = cases.tag.name;
774774- plain_implicit = true;
775775- quoted_implicit = true;
776776- style = `Plain;
777777- });
778778- encode e cases.tag.type' case_map.tag
779779- end;
780780- (* Emit case members *)
781781- List.iter (fun (Mem_enc mem) ->
782782- let mem_v = mem.enc case_v in
783783- if not (mem.enc_omit mem_v) then begin
784784- Emitter.emit e.emitter (Event.Scalar {
785785- anchor = None;
786786- tag = None;
787787- value = mem.name;
788788- plain_implicit = true;
789789- quoted_implicit = true;
790790- style = `Plain;
791791- });
792792- encode e mem.type' mem_v
793793- end
794794- ) case_map.object_map.mem_encs);
841841+ | Object_basic _ -> ()
842842+ | Object_cases (_, cases) ->
843843+ let (Case_value (case_map, case_v)) = cases.enc_case (cases.enc v) in
844844+ (* Emit case tag *)
845845+ if not (cases.tag.enc_omit case_map.tag) then begin
846846+ Emitter.emit e.emitter
847847+ (Event.Scalar
848848+ {
849849+ anchor = None;
850850+ tag = None;
851851+ value = cases.tag.name;
852852+ plain_implicit = true;
853853+ quoted_implicit = true;
854854+ style = `Plain;
855855+ });
856856+ encode e cases.tag.type' case_map.tag
857857+ end;
858858+ (* Emit case members *)
859859+ List.iter
860860+ (fun (Mem_enc mem) ->
861861+ let mem_v = mem.enc case_v in
862862+ if not (mem.enc_omit mem_v) then begin
863863+ Emitter.emit e.emitter
864864+ (Event.Scalar
865865+ {
866866+ anchor = None;
867867+ tag = None;
868868+ value = mem.name;
869869+ plain_implicit = true;
870870+ quoted_implicit = true;
871871+ style = `Plain;
872872+ });
873873+ encode e mem.type' mem_v
874874+ end)
875875+ case_map.object_map.mem_encs);
795876 Emitter.emit e.emitter Event.Mapping_end
796877797878(* Public encode API *)
798879799880let encode' ?buf:_ ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer =
800800- let config = {
801801- Emitter.default_config with
802802- indent = Option.value ~default:2 indent;
803803- layout_style = (match format with
804804- | Some Flow -> `Flow
805805- | _ -> `Block);
806806- } in
881881+ let config =
882882+ {
883883+ Emitter.default_config with
884884+ indent = Option.value ~default:2 indent;
885885+ layout_style = (match format with Some Flow -> `Flow | _ -> `Block);
886886+ }
887887+ in
807888 let emitter = Emitter.of_writer ~config writer in
808889 let e = make_encoder ?format ?indent ?explicit_doc ?scalar_style emitter in
809890 try
810891 Emitter.emit e.emitter (Event.Stream_start { encoding = `Utf8 });
811811- Emitter.emit e.emitter (Event.Document_start {
812812- version = None;
813813- implicit = not e.explicit_doc;
814814- });
892892+ Emitter.emit e.emitter
893893+ (Event.Document_start { version = None; implicit = not e.explicit_doc });
815894 let t' = Jsont.Repr.of_t t in
816895 encode e t' v;
817817- Emitter.emit e.emitter (Event.Document_end { implicit = not e.explicit_doc });
896896+ Emitter.emit e.emitter
897897+ (Event.Document_end { implicit = not e.explicit_doc });
818898 Emitter.emit e.emitter Event.Stream_end;
819899 if eod then Emitter.flush e.emitter;
820900 Ok ()
···831911let encode_string' ?buf ?format ?indent ?explicit_doc ?scalar_style t v =
832912 let b = Buffer.create 256 in
833913 let writer = Bytes.Writer.of_buffer b in
834834- match encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod:true writer with
914914+ match
915915+ encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod:true
916916+ writer
917917+ with
835918 | Ok () -> Ok (Buffer.contents b)
836919 | Error e -> Error e
837920···841924842925(* Recode *)
843926844844-let recode ?layout ?locs ?file ?max_depth ?max_nodes
845845- ?buf ?format ?indent ?explicit_doc ?scalar_style t reader writer ~eod =
846846- let format = match layout, format with
847847- | Some true, None -> Some Layout
848848- | _, f -> f
927927+let recode ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent
928928+ ?explicit_doc ?scalar_style t reader writer ~eod =
929929+ let format =
930930+ match (layout, format) with Some true, None -> Some Layout | _, f -> f
849931 in
850850- let layout = match layout, format with
851851- | None, Some Layout -> Some true
852852- | l, _ -> l
932932+ let layout =
933933+ match (layout, format) with None, Some Layout -> Some true | l, _ -> l
853934 in
854935 match decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader with
855855- | Ok v -> encode ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer
936936+ | Ok v ->
937937+ encode ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer
856938 | Error e -> Error (Jsont.Error.to_string e)
857939858858-let recode_string ?layout ?locs ?file ?max_depth ?max_nodes
859859- ?buf ?format ?indent ?explicit_doc ?scalar_style t s =
860860- let format = match layout, format with
861861- | Some true, None -> Some Layout
862862- | _, f -> f
940940+let recode_string ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent
941941+ ?explicit_doc ?scalar_style t s =
942942+ let format =
943943+ match (layout, format) with Some true, None -> Some Layout | _, f -> f
863944 in
864864- let layout = match layout, format with
865865- | None, Some Layout -> Some true
866866- | l, _ -> l
945945+ let layout =
946946+ match (layout, format) with None, Some Layout -> Some true | l, _ -> l
867947 in
868948 match decode_string' ?layout ?locs ?file ?max_depth ?max_nodes t s with
869949 | Ok v -> encode_string ?buf ?format ?indent ?explicit_doc ?scalar_style t v
+149-91
lib/yamlt.mli
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566(** YAML codec using Jsont type descriptions.
7788- This module provides YAML streaming encode/decode that interprets
99- {!Jsont.t} type descriptions, allowing the same codec definitions
1010- to work for both JSON and YAML.
88+ This module provides YAML streaming encode/decode that interprets {!Jsont.t}
99+ type descriptions, allowing the same codec definitions to work for both JSON
1010+ and YAML.
11111212 {b Example:}
1313 {[
1414 (* Define a codec once using Jsont *)
1515 module Config = struct
1616- type t = { name: string; port: int }
1616+ type t = { name : string; port : int }
1717+1718 let make name port = { name; port }
1919+1820 let jsont =
1921 Jsont.Object.map ~kind:"Config" make
2022 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
···2830 ]}
29313032 See notes about {{!yaml_mapping}YAML to JSON mapping} and
3131- {{!yaml_scalars}YAML scalar resolution}.
3232-*)
3333+ {{!yaml_scalars}YAML scalar resolution}. *)
33343435open Bytesrw
35363637(** {1:decode Decode} *)
37383839val decode :
3939- ?layout:bool -> ?locs:bool -> ?file:Jsont.Textloc.fpath ->
4040- ?max_depth:int -> ?max_nodes:int ->
4141- 'a Jsont.t -> Bytes.Reader.t -> ('a, string) result
4040+ ?layout:bool ->
4141+ ?locs:bool ->
4242+ ?file:Jsont.Textloc.fpath ->
4343+ ?max_depth:int ->
4444+ ?max_nodes:int ->
4545+ 'a Jsont.t ->
4646+ Bytes.Reader.t ->
4747+ ('a, string) result
4248(** [decode t r] decodes a value from YAML reader [r] according to type [t].
4343- {ul
4444- {- If [layout] is [true], style information is preserved in {!Jsont.Meta.t}
4545- values (for potential round-tripping). Defaults to [false].}
4646- {- If [locs] is [true], source locations are preserved in {!Jsont.Meta.t}
4747- values and error messages are precisely located. Defaults to [false].}
4848- {- [file] is the file path for error messages.
4949- Defaults to {!Jsont.Textloc.file_none}.}
5050- {- [max_depth] limits nesting depth to prevent stack overflow
5151- (billion laughs protection). Defaults to [100].}
5252- {- [max_nodes] limits total decoded nodes
5353- (billion laughs protection). Defaults to [10_000_000].}}
4949+ - If [layout] is [true], style information is preserved in {!Jsont.Meta.t}
5050+ values (for potential round-tripping). Defaults to [false].
5151+ - If [locs] is [true], source locations are preserved in {!Jsont.Meta.t}
5252+ values and error messages are precisely located. Defaults to [false].
5353+ - [file] is the file path for error messages. Defaults to
5454+ {!Jsont.Textloc.file_none}.
5555+ - [max_depth] limits nesting depth to prevent stack overflow (billion laughs
5656+ protection). Defaults to [100].
5757+ - [max_nodes] limits total decoded nodes (billion laughs protection).
5858+ Defaults to [10_000_000].
54595555- The YAML input must contain exactly one document. Multi-document
5656- streams are not supported; use {!decode_all} for those. *)
6060+ The YAML input must contain exactly one document. Multi-document streams are
6161+ not supported; use {!decode_all} for those. *)
57625863val decode' :
5959- ?layout:bool -> ?locs:bool -> ?file:Jsont.Textloc.fpath ->
6060- ?max_depth:int -> ?max_nodes:int ->
6161- 'a Jsont.t -> Bytes.Reader.t -> ('a, Jsont.Error.t) result
6464+ ?layout:bool ->
6565+ ?locs:bool ->
6666+ ?file:Jsont.Textloc.fpath ->
6767+ ?max_depth:int ->
6868+ ?max_nodes:int ->
6969+ 'a Jsont.t ->
7070+ Bytes.Reader.t ->
7171+ ('a, Jsont.Error.t) result
6272(** [decode'] is like {!val-decode} but preserves the error structure. *)
63736474val decode_string :
6565- ?layout:bool -> ?locs:bool -> ?file:Jsont.Textloc.fpath ->
6666- ?max_depth:int -> ?max_nodes:int ->
6767- 'a Jsont.t -> string -> ('a, string) result
7575+ ?layout:bool ->
7676+ ?locs:bool ->
7777+ ?file:Jsont.Textloc.fpath ->
7878+ ?max_depth:int ->
7979+ ?max_nodes:int ->
8080+ 'a Jsont.t ->
8181+ string ->
8282+ ('a, string) result
6883(** [decode_string] is like {!val-decode} but decodes directly from a string. *)
69847085val decode_string' :
7171- ?layout:bool -> ?locs:bool -> ?file:Jsont.Textloc.fpath ->
7272- ?max_depth:int -> ?max_nodes:int ->
7373- 'a Jsont.t -> string -> ('a, Jsont.Error.t) result
7474-(** [decode_string'] is like {!val-decode'} but decodes directly from a string. *)
8686+ ?layout:bool ->
8787+ ?locs:bool ->
8888+ ?file:Jsont.Textloc.fpath ->
8989+ ?max_depth:int ->
9090+ ?max_nodes:int ->
9191+ 'a Jsont.t ->
9292+ string ->
9393+ ('a, Jsont.Error.t) result
9494+(** [decode_string'] is like {!val-decode'} but decodes directly from a string.
9595+*)
75967697(** {1:encode Encode} *)
77987899(** YAML output format. *)
79100type yaml_format =
8080- | Block (** Block style (indented) - default. Clean, readable YAML. *)
8181- | Flow (** Flow style (JSON-like). Compact, single-line collections. *)
101101+ | Block (** Block style (indented) - default. Clean, readable YAML. *)
102102+ | Flow (** Flow style (JSON-like). Compact, single-line collections. *)
82103 | Layout (** Preserve layout from {!Jsont.Meta.t} when available. *)
8310484105val encode :
8585- ?buf:Stdlib.Bytes.t -> ?format:yaml_format -> ?indent:int ->
8686- ?explicit_doc:bool -> ?scalar_style:Yamlrw.Scalar_style.t ->
8787- 'a Jsont.t -> 'a -> eod:bool -> Bytes.Writer.t -> (unit, string) result
106106+ ?buf:Stdlib.Bytes.t ->
107107+ ?format:yaml_format ->
108108+ ?indent:int ->
109109+ ?explicit_doc:bool ->
110110+ ?scalar_style:Yamlrw.Scalar_style.t ->
111111+ 'a Jsont.t ->
112112+ 'a ->
113113+ eod:bool ->
114114+ Bytes.Writer.t ->
115115+ (unit, string) result
88116(** [encode t v w] encodes value [v] according to type [t] to YAML on [w].
8989- {ul
9090- {- If [buf] is specified, it is used as a buffer for output slices.
9191- Defaults to a buffer of length {!Bytesrw.Bytes.Writer.slice_length}[ w].}
9292- {- [format] controls the output style. Defaults to {!Block}.}
9393- {- [indent] is the indentation width in spaces. Defaults to [2].}
9494- {- [explicit_doc] if [true], emits explicit document markers
9595- ([---] and [...]). Defaults to [false].}
9696- {- [scalar_style] is the preferred style for string scalars.
9797- Defaults to [`Any] (auto-detect based on content).}
9898- {- [eod] indicates whether {!Bytesrw.Bytes.Slice.eod} should be
9999- written on [w] after encoding.}} *)
117117+ - If [buf] is specified, it is used as a buffer for output slices. Defaults
118118+ to a buffer of length {!Bytesrw.Bytes.Writer.slice_length}[ w].
119119+ - [format] controls the output style. Defaults to {!Block}.
120120+ - [indent] is the indentation width in spaces. Defaults to [2].
121121+ - [explicit_doc] if [true], emits explicit document markers ([---] and
122122+ [...]). Defaults to [false].
123123+ - [scalar_style] is the preferred style for string scalars. Defaults to
124124+ [`Any] (auto-detect based on content).
125125+ - [eod] indicates whether {!Bytesrw.Bytes.Slice.eod} should be written on
126126+ [w] after encoding. *)
100127101128val encode' :
102102- ?buf:Stdlib.Bytes.t -> ?format:yaml_format -> ?indent:int ->
103103- ?explicit_doc:bool -> ?scalar_style:Yamlrw.Scalar_style.t ->
104104- 'a Jsont.t -> 'a -> eod:bool -> Bytes.Writer.t -> (unit, Jsont.Error.t) result
129129+ ?buf:Stdlib.Bytes.t ->
130130+ ?format:yaml_format ->
131131+ ?indent:int ->
132132+ ?explicit_doc:bool ->
133133+ ?scalar_style:Yamlrw.Scalar_style.t ->
134134+ 'a Jsont.t ->
135135+ 'a ->
136136+ eod:bool ->
137137+ Bytes.Writer.t ->
138138+ (unit, Jsont.Error.t) result
105139(** [encode'] is like {!val-encode} but preserves the error structure. *)
106140107141val encode_string :
108108- ?buf:Stdlib.Bytes.t -> ?format:yaml_format -> ?indent:int ->
109109- ?explicit_doc:bool -> ?scalar_style:Yamlrw.Scalar_style.t ->
110110- 'a Jsont.t -> 'a -> (string, string) result
142142+ ?buf:Stdlib.Bytes.t ->
143143+ ?format:yaml_format ->
144144+ ?indent:int ->
145145+ ?explicit_doc:bool ->
146146+ ?scalar_style:Yamlrw.Scalar_style.t ->
147147+ 'a Jsont.t ->
148148+ 'a ->
149149+ (string, string) result
111150(** [encode_string] is like {!val-encode} but writes to a string. *)
112151113152val encode_string' :
114114- ?buf:Stdlib.Bytes.t -> ?format:yaml_format -> ?indent:int ->
115115- ?explicit_doc:bool -> ?scalar_style:Yamlrw.Scalar_style.t ->
116116- 'a Jsont.t -> 'a -> (string, Jsont.Error.t) result
153153+ ?buf:Stdlib.Bytes.t ->
154154+ ?format:yaml_format ->
155155+ ?indent:int ->
156156+ ?explicit_doc:bool ->
157157+ ?scalar_style:Yamlrw.Scalar_style.t ->
158158+ 'a Jsont.t ->
159159+ 'a ->
160160+ (string, Jsont.Error.t) result
117161(** [encode_string'] is like {!val-encode'} but writes to a string. *)
118162119163(** {1:recode Recode}
120164121165 The defaults in these functions are those of {!val-decode} and
122122- {!val-encode}, except if [layout] is [true], [format] defaults to
123123- {!Layout} and vice-versa. *)
166166+ {!val-encode}, except if [layout] is [true], [format] defaults to {!Layout}
167167+ and vice-versa. *)
124168125169val recode :
126126- ?layout:bool -> ?locs:bool -> ?file:Jsont.Textloc.fpath ->
127127- ?max_depth:int -> ?max_nodes:int ->
128128- ?buf:Stdlib.Bytes.t -> ?format:yaml_format -> ?indent:int ->
129129- ?explicit_doc:bool -> ?scalar_style:Yamlrw.Scalar_style.t ->
130130- 'a Jsont.t -> Bytes.Reader.t -> Bytes.Writer.t -> eod:bool ->
170170+ ?layout:bool ->
171171+ ?locs:bool ->
172172+ ?file:Jsont.Textloc.fpath ->
173173+ ?max_depth:int ->
174174+ ?max_nodes:int ->
175175+ ?buf:Stdlib.Bytes.t ->
176176+ ?format:yaml_format ->
177177+ ?indent:int ->
178178+ ?explicit_doc:bool ->
179179+ ?scalar_style:Yamlrw.Scalar_style.t ->
180180+ 'a Jsont.t ->
181181+ Bytes.Reader.t ->
182182+ Bytes.Writer.t ->
183183+ eod:bool ->
131184 (unit, string) result
132185(** [recode t r w] is {!val-decode} followed by {!val-encode}. *)
133186134187val recode_string :
135135- ?layout:bool -> ?locs:bool -> ?file:Jsont.Textloc.fpath ->
136136- ?max_depth:int -> ?max_nodes:int ->
137137- ?buf:Stdlib.Bytes.t -> ?format:yaml_format -> ?indent:int ->
138138- ?explicit_doc:bool -> ?scalar_style:Yamlrw.Scalar_style.t ->
139139- 'a Jsont.t -> string -> (string, string) result
188188+ ?layout:bool ->
189189+ ?locs:bool ->
190190+ ?file:Jsont.Textloc.fpath ->
191191+ ?max_depth:int ->
192192+ ?max_nodes:int ->
193193+ ?buf:Stdlib.Bytes.t ->
194194+ ?format:yaml_format ->
195195+ ?indent:int ->
196196+ ?explicit_doc:bool ->
197197+ ?scalar_style:Yamlrw.Scalar_style.t ->
198198+ 'a Jsont.t ->
199199+ string ->
200200+ (string, string) result
140201(** [recode_string] is like {!val-recode} but operates on strings. *)
141202142203(** {1:yaml_mapping YAML to JSON Mapping}
143204144144- YAML is a superset of JSON. This module maps YAML structures to
145145- the JSON data model that {!Jsont.t} describes:
205205+ YAML is a superset of JSON. This module maps YAML structures to the JSON
206206+ data model that {!Jsont.t} describes:
146207147147- {ul
148148- {- YAML scalars map to JSON null, boolean, number, or string
149149- depending on content and the expected type}
150150- {- YAML sequences map to JSON arrays}
151151- {- YAML mappings map to JSON objects (keys must be strings)}
152152- {- YAML aliases are resolved during decoding}
153153- {- YAML tags are used to guide type resolution when present}}
208208+ - YAML scalars map to JSON null, boolean, number, or string depending on
209209+ content and the expected type
210210+ - YAML sequences map to JSON arrays
211211+ - YAML mappings map to JSON objects (keys must be strings)
212212+ - YAML aliases are resolved during decoding
213213+ - YAML tags are used to guide type resolution when present
154214155215 {b Limitations:}
156156- {ul
157157- {- Only string keys are supported in mappings (JSON object compatibility)}
158158- {- Anchors and aliases are resolved; the alias structure is not preserved}
159159- {- Multi-document streams require {!decode_all}}} *)
216216+ - Only string keys are supported in mappings (JSON object compatibility)
217217+ - Anchors and aliases are resolved; the alias structure is not preserved
218218+ - Multi-document streams require {!decode_all} *)
160219161220(** {1:yaml_scalars YAML Scalar Resolution}
162221···164223165224 {b Null:} [null], [Null], [NULL], [~], or empty string
166225167167- {b Boolean:} [true], [True], [TRUE], [false], [False], [FALSE],
168168- [yes], [Yes], [YES], [no], [No], [NO], [on], [On], [ON],
169169- [off], [Off], [OFF]
226226+ {b Boolean:} [true], [True], [TRUE], [false], [False], [FALSE], [yes],
227227+ [Yes], [YES], [no], [No], [NO], [on], [On], [ON], [off], [Off], [OFF]
170228171229 {b Number:} Decimal integers, floats, hex ([0x...]), octal ([0o...]),
172230 infinity ([.inf], [-.inf]), NaN ([.nan])
173231174232 {b String:} Anything else, or explicitly quoted scalars
175233176176- When decoding against a specific {!Jsont.t} type, the expected type
177177- takes precedence over automatic resolution. For example, decoding
178178- ["yes"] against {!Jsont.string} yields the string ["yes"], not [true]. *)
234234+ When decoding against a specific {!Jsont.t} type, the expected type takes
235235+ precedence over automatic resolution. For example, decoding ["yes"] against
236236+ {!Jsont.string} yields the string ["yes"], not [true]. *)
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566(** Test edge cases with Yamlt *)
77···2727(* Test: Very large numbers *)
2828let test_large_numbers file =
2929 let module M = struct
3030- type numbers = { large_int: float; large_float: float; small_float: float }
3030+ type numbers = {
3131+ large_int : float;
3232+ large_float : float;
3333+ small_float : float;
3434+ }
31353236 let numbers_codec =
3337 Jsont.Object.map ~kind:"Numbers" (fun large_int large_float small_float ->
3434- { large_int; large_float; small_float })
3838+ { large_int; large_float; small_float })
3539 |> Jsont.Object.mem "large_int" Jsont.number ~enc:(fun n -> n.large_int)
3636- |> Jsont.Object.mem "large_float" Jsont.number ~enc:(fun n -> n.large_float)
3737- |> Jsont.Object.mem "small_float" Jsont.number ~enc:(fun n -> n.small_float)
4040+ |> Jsont.Object.mem "large_float" Jsont.number ~enc:(fun n ->
4141+ n.large_float)
4242+ |> Jsont.Object.mem "small_float" Jsont.number ~enc:(fun n ->
4343+ n.small_float)
3844 |> Jsont.Object.finish
39454046 let show n =
4147 Printf.sprintf "large_int=%.0f, large_float=%e, small_float=%e"
4248 n.large_int n.large_float n.small_float
4349 end in
4444-4550 let yaml = read_file file in
4651 let json = read_file (file ^ ".json") in
4752 let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
···5459(* Test: Special characters in strings *)
5560let test_special_chars file =
5661 let module M = struct
5757- type text = { content: string }
6262+ type text = { content : string }
58635964 let text_codec =
6065 Jsont.Object.map ~kind:"Text" (fun content -> { content })
···6772 (String.contains t.content '\n')
6873 (String.contains t.content '\t')
6974 end in
7070-7175 let yaml = read_file file in
7276 let json = read_file (file ^ ".json") in
7377 let json_result = Jsont_bytesrw.decode_string M.text_codec json in
···8084(* Test: Unicode strings *)
8185let test_unicode file =
8286 let module M = struct
8383- type text = { emoji: string; chinese: string; rtl: string }
8787+ type text = { emoji : string; chinese : string; rtl : string }
84888589 let text_codec =
8686- Jsont.Object.map ~kind:"Text" (fun emoji chinese rtl -> { emoji; chinese; rtl })
9090+ Jsont.Object.map ~kind:"Text" (fun emoji chinese rtl ->
9191+ { emoji; chinese; rtl })
8792 |> Jsont.Object.mem "emoji" Jsont.string ~enc:(fun t -> t.emoji)
8893 |> Jsont.Object.mem "chinese" Jsont.string ~enc:(fun t -> t.chinese)
8994 |> Jsont.Object.mem "rtl" Jsont.string ~enc:(fun t -> t.rtl)
···9297 let show t =
9398 Printf.sprintf "emoji=%S, chinese=%S, rtl=%S" t.emoji t.chinese t.rtl
9499 end in
9595-96100 let yaml = read_file file in
97101 let json = read_file (file ^ ".json") in
98102 let json_result = Jsont_bytesrw.decode_string M.text_codec json in
···105109(* Test: Empty collections *)
106110let test_empty_collections file =
107111 let module M = struct
108108- type data = { empty_array: int array; empty_object_array: unit array }
112112+ type data = { empty_array : int array; empty_object_array : unit array }
109113110114 let data_codec =
111115 Jsont.Object.map ~kind:"Data" (fun empty_array empty_object_array ->
112112- { empty_array; empty_object_array })
113113- |> Jsont.Object.mem "empty_array" (Jsont.array Jsont.int) ~enc:(fun d -> d.empty_array)
114114- |> Jsont.Object.mem "empty_object_array" (Jsont.array (Jsont.null ())) ~enc:(fun d -> d.empty_object_array)
116116+ { empty_array; empty_object_array })
117117+ |> Jsont.Object.mem "empty_array" (Jsont.array Jsont.int) ~enc:(fun d ->
118118+ d.empty_array)
119119+ |> Jsont.Object.mem "empty_object_array"
120120+ (Jsont.array (Jsont.null ()))
121121+ ~enc:(fun d -> d.empty_object_array)
115122 |> Jsont.Object.finish
116123117124 let show d =
···119126 (Stdlib.Array.length d.empty_array)
120127 (Stdlib.Array.length d.empty_object_array)
121128 end in
122122-123129 let yaml = read_file file in
124130 let json = read_file (file ^ ".json") in
125131 let json_result = Jsont_bytesrw.decode_string M.data_codec json in
···138144 | Ok _ -> "not_object"
139145 | Error _ -> "decode_error"
140146 end in
141141-142147 let yaml = read_file file in
143148 let json = read_file (file ^ ".json") in
144149 let json_result = Jsont_bytesrw.decode_string (Jsont.any ()) json in
···151156(* Test: Single-element arrays *)
152157let test_single_element file =
153158 let module M = struct
154154- type data = { single: int array }
159159+ type data = { single : int array }
155160156161 let data_codec =
157162 Jsont.Object.map ~kind:"Data" (fun single -> { single })
158158- |> Jsont.Object.mem "single" (Jsont.array Jsont.int) ~enc:(fun d -> d.single)
163163+ |> Jsont.Object.mem "single" (Jsont.array Jsont.int) ~enc:(fun d ->
164164+ d.single)
159165 |> Jsont.Object.finish
160166161167 let show d =
···163169 (Stdlib.Array.length d.single)
164170 (if Stdlib.Array.length d.single > 0 then d.single.(0) else 0)
165171 end in
166166-167172 let yaml = read_file file in
168173 let json = read_file (file ^ ".json") in
169174 let json_result = Jsont_bytesrw.decode_string M.data_codec json in
···184189 match Sys.argv.(1) with
185190 | "large-numbers" when Stdlib.Array.length Sys.argv = 3 ->
186191 test_large_numbers Sys.argv.(2)
187187-188192 | "special-chars" when Stdlib.Array.length Sys.argv = 3 ->
189193 test_special_chars Sys.argv.(2)
190190-191191- | "unicode" when Stdlib.Array.length Sys.argv = 3 ->
192192- test_unicode Sys.argv.(2)
193193-194194+ | "unicode" when Stdlib.Array.length Sys.argv = 3 -> test_unicode Sys.argv.(2)
194195 | "empty-collections" when Stdlib.Array.length Sys.argv = 3 ->
195196 test_empty_collections Sys.argv.(2)
196196-197197 | "special-keys" when Stdlib.Array.length Sys.argv = 3 ->
198198 test_special_keys Sys.argv.(2)
199199-200199 | "single-element" when Stdlib.Array.length Sys.argv = 3 ->
201200 test_single_element Sys.argv.(2)
202202-203201 | _ ->
204202 prerr_endline usage;
205203 prerr_endline "Commands:";
206204 prerr_endline " large-numbers <file> - Test very large numbers";
207207- prerr_endline " special-chars <file> - Test special characters in strings";
205205+ prerr_endline
206206+ " special-chars <file> - Test special characters in strings";
208207 prerr_endline " unicode <file> - Test Unicode strings";
209208 prerr_endline " empty-collections <file> - Test empty collections";
210210- prerr_endline " special-keys <file> - Test special characters in keys";
209209+ prerr_endline
210210+ " special-keys <file> - Test special characters in keys";
211211 prerr_endline " single-element <file> - Test single-element arrays";
212212 exit 1
+4-2
tests/bin/test_flow_newline.ml
···55 |> Jsont.Object.mem "values" (Jsont.array Jsont.number) ~enc:snd
66 |> Jsont.Object.finish
77 in
88-99- match Yamlt.encode_string ~format:Flow encode_codec ("test", [|1.; 2.; 3.|]) with
88+99+ match
1010+ Yamlt.encode_string ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |])
1111+ with
1012 | Ok yaml_flow ->
1113 Printf.printf "Length: %d\n" (String.length yaml_flow);
1214 Printf.printf "Repr: %S\n" yaml_flow;
+40-52
tests/bin/test_formats.ml
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566(** Test format-specific features with Yamlt *)
77···2727(* Test: Multi-line strings - literal style *)
2828let test_literal_string file =
2929 let module M = struct
3030- type text = { content: string }
3030+ type text = { content : string }
31313232 let text_codec =
3333 Jsont.Object.map ~kind:"Text" (fun content -> { content })
···3939 (List.length (String.split_on_char '\n' t.content))
4040 (String.length t.content)
4141 end in
4242-4342 let yaml = read_file file in
4443 let json = read_file (file ^ ".json") in
4544 let json_result = Jsont_bytesrw.decode_string M.text_codec json in
···5251(* Test: Multi-line strings - folded style *)
5352let test_folded_string file =
5453 let module M = struct
5555- type text = { content: string }
5454+ type text = { content : string }
56555756 let text_codec =
5857 Jsont.Object.map ~kind:"Text" (fun content -> { content })
···6059 |> Jsont.Object.finish
61606261 let show t =
6363- Printf.sprintf "length=%d, newlines=%d"
6464- (String.length t.content)
6565- (List.length (List.filter (fun c -> c = '\n')
6666- (List.init (String.length t.content) (String.get t.content))))
6262+ Printf.sprintf "length=%d, newlines=%d" (String.length t.content)
6363+ (List.length
6464+ (List.filter
6565+ (fun c -> c = '\n')
6666+ (List.init (String.length t.content) (String.get t.content))))
6767 end in
6868-6968 let yaml = read_file file in
7069 let json = read_file (file ^ ".json") in
7170 let json_result = Jsont_bytesrw.decode_string M.text_codec json in
···7877(* Test: Number formats - hex, octal, binary *)
7978let test_number_formats file =
8079 let module M = struct
8181- type numbers = { hex: float; octal: float; binary: float }
8080+ type numbers = { hex : float; octal : float; binary : float }
82818382 let numbers_codec =
8484- Jsont.Object.map ~kind:"Numbers" (fun hex octal binary -> { hex; octal; binary })
8383+ Jsont.Object.map ~kind:"Numbers" (fun hex octal binary ->
8484+ { hex; octal; binary })
8585 |> Jsont.Object.mem "hex" Jsont.number ~enc:(fun n -> n.hex)
8686 |> Jsont.Object.mem "octal" Jsont.number ~enc:(fun n -> n.octal)
8787 |> Jsont.Object.mem "binary" Jsont.number ~enc:(fun n -> n.binary)
···9090 let show n =
9191 Printf.sprintf "hex=%.0f, octal=%.0f, binary=%.0f" n.hex n.octal n.binary
9292 end in
9393-9493 let yaml = read_file file in
9594 let json = read_file (file ^ ".json") in
9695 let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
···103102(* Test: Block vs Flow style encoding *)
104103let test_encode_styles () =
105104 let module M = struct
106106- type data = {
107107- name: string;
108108- values: int array;
109109- nested: nested_data;
110110- }
111111- and nested_data = {
112112- enabled: bool;
113113- count: int;
114114- }
105105+ type data = { name : string; values : int array; nested : nested_data }
106106+ and nested_data = { enabled : bool; count : int }
115107116108 let nested_codec =
117109 Jsont.Object.map ~kind:"Nested" (fun enabled count -> { enabled; count })
···120112 |> Jsont.Object.finish
121113122114 let data_codec =
123123- Jsont.Object.map ~kind:"Data" (fun name values nested -> { name; values; nested })
115115+ Jsont.Object.map ~kind:"Data" (fun name values nested ->
116116+ { name; values; nested })
124117 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun d -> d.name)
125125- |> Jsont.Object.mem "values" (Jsont.array Jsont.int) ~enc:(fun d -> d.values)
118118+ |> Jsont.Object.mem "values" (Jsont.array Jsont.int) ~enc:(fun d ->
119119+ d.values)
126120 |> Jsont.Object.mem "nested" nested_codec ~enc:(fun d -> d.nested)
127121 |> Jsont.Object.finish
128122 end in
129129-130130- let data = {
131131- M.name = "test";
132132- values = [|1; 2; 3|];
133133- nested = { enabled = true; count = 5 };
134134- } in
123123+ let data =
124124+ {
125125+ M.name = "test";
126126+ values = [| 1; 2; 3 |];
127127+ nested = { enabled = true; count = 5 };
128128+ }
129129+ in
135130136131 (* Encode to YAML Block style *)
137132 (match Yamlt.encode_string ~format:Yamlt.Block M.data_codec data with
138138- | Ok s -> Printf.printf "YAML Block:\n%s\n" s
139139- | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
133133+ | Ok s -> Printf.printf "YAML Block:\n%s\n" s
134134+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
140135141136 (* Encode to YAML Flow style *)
142142- (match Yamlt.encode_string ~format:Yamlt.Flow M.data_codec data with
143143- | Ok s -> Printf.printf "YAML Flow:\n%s\n" s
144144- | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
137137+ match Yamlt.encode_string ~format:Yamlt.Flow M.data_codec data with
138138+ | Ok s -> Printf.printf "YAML Flow:\n%s\n" s
139139+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
145140146141(* Test: Comments in YAML (should be ignored) *)
147142let test_comments file =
148143 let module M = struct
149149- type config = { host: string; port: int; debug: bool }
144144+ type config = { host : string; port : int; debug : bool }
150145151146 let config_codec =
152152- Jsont.Object.map ~kind:"Config" (fun host port debug -> { host; port; debug })
147147+ Jsont.Object.map ~kind:"Config" (fun host port debug ->
148148+ { host; port; debug })
153149 |> Jsont.Object.mem "host" Jsont.string ~enc:(fun c -> c.host)
154150 |> Jsont.Object.mem "port" Jsont.int ~enc:(fun c -> c.port)
155151 |> Jsont.Object.mem "debug" Jsont.bool ~enc:(fun c -> c.debug)
···158154 let show c =
159155 Printf.sprintf "host=%S, port=%d, debug=%b" c.host c.port c.debug
160156 end in
161161-162157 let yaml = read_file file in
163158 let yaml_result = Yamlt.decode_string M.config_codec yaml in
164159···169164(* Test: Empty documents and null documents *)
170165let test_empty_document file =
171166 let module M = struct
172172- type wrapper = { value: string option }
167167+ type wrapper = { value : string option }
173168174169 let wrapper_codec =
175170 Jsont.Object.map ~kind:"Wrapper" (fun value -> { value })
176176- |> Jsont.Object.mem "value" (Jsont.some Jsont.string) ~enc:(fun w -> w.value)
171171+ |> Jsont.Object.mem "value" (Jsont.some Jsont.string) ~enc:(fun w ->
172172+ w.value)
177173 |> Jsont.Object.finish
178174179175 let show w =
···181177 | None -> "value=None"
182178 | Some s -> Printf.sprintf "value=Some(%S)" s
183179 end in
184184-185180 let yaml = read_file file in
186181 let json = read_file (file ^ ".json") in
187182 let json_result = Jsont_bytesrw.decode_string M.wrapper_codec json in
···194189(* Test: Explicit typing with tags (if supported) *)
195190let test_explicit_tags file =
196191 let module M = struct
197197- type value_holder = { data: string }
192192+ type value_holder = { data : string }
198193199194 let value_codec =
200195 Jsont.Object.map ~kind:"ValueHolder" (fun data -> { data })
···203198204199 let show v = Printf.sprintf "data=%S" v.data
205200 end in
206206-207201 let yaml = read_file file in
208202 let yaml_result = Yamlt.decode_string M.value_codec yaml in
209203···222216 match Sys.argv.(1) with
223217 | "literal" when Stdlib.Array.length Sys.argv = 3 ->
224218 test_literal_string Sys.argv.(2)
225225-226219 | "folded" when Stdlib.Array.length Sys.argv = 3 ->
227220 test_folded_string Sys.argv.(2)
228228-229221 | "number-formats" when Stdlib.Array.length Sys.argv = 3 ->
230222 test_number_formats Sys.argv.(2)
231231-232223 | "encode-styles" when Stdlib.Array.length Sys.argv = 2 ->
233224 test_encode_styles ()
234234-235225 | "comments" when Stdlib.Array.length Sys.argv = 3 ->
236226 test_comments Sys.argv.(2)
237237-238227 | "empty-doc" when Stdlib.Array.length Sys.argv = 3 ->
239228 test_empty_document Sys.argv.(2)
240240-241229 | "explicit-tags" when Stdlib.Array.length Sys.argv = 3 ->
242230 test_explicit_tags Sys.argv.(2)
243243-244231 | _ ->
245232 prerr_endline usage;
246233 prerr_endline "Commands:";
247234 prerr_endline " literal <file> - Test literal multi-line strings";
248235 prerr_endline " folded <file> - Test folded multi-line strings";
249249- prerr_endline " number-formats <file> - Test hex/octal/binary number formats";
236236+ prerr_endline
237237+ " number-formats <file> - Test hex/octal/binary number formats";
250238 prerr_endline " encode-styles - Test block vs flow encoding";
251239 prerr_endline " comments <file> - Test YAML with comments";
252240 prerr_endline " empty-doc <file> - Test empty documents";
+65-61
tests/bin/test_locations.ml
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566(** Test location and layout preservation options with Yamlt codec *)
77···44444545 (* Nested object codec *)
4646 let address_codec =
4747- Jsont.Object.map ~kind:"Address" (fun street city zip -> (street, city, zip))
4848- |> Jsont.Object.mem "street" Jsont.string ~enc:(fun (s,_,_) -> s)
4949- |> Jsont.Object.mem "city" Jsont.string ~enc:(fun (_,c,_) -> c)
5050- |> Jsont.Object.mem "zip" Jsont.int ~enc:(fun (_,_,z) -> z)
4747+ Jsont.Object.map ~kind:"Address" (fun street city zip ->
4848+ (street, city, zip))
4949+ |> Jsont.Object.mem "street" Jsont.string ~enc:(fun (s, _, _) -> s)
5050+ |> Jsont.Object.mem "city" Jsont.string ~enc:(fun (_, c, _) -> c)
5151+ |> Jsont.Object.mem "zip" Jsont.int ~enc:(fun (_, _, z) -> z)
5152 |> Jsont.Object.finish
5253 in
5354···989999100 Printf.printf "=== Without layout (default) ===\n";
100101 (match Yamlt.decode_string ~layout:false codec yaml with
101101- | Ok (host, port) ->
102102- Printf.printf "Decoded: host=%s, port=%d\n" host port;
103103- Printf.printf "Meta preserved: no\n"
104104- | Error e -> Printf.printf "Error: %s\n" e);
102102+ | Ok (host, port) ->
103103+ Printf.printf "Decoded: host=%s, port=%d\n" host port;
104104+ Printf.printf "Meta preserved: no\n"
105105+ | Error e -> Printf.printf "Error: %s\n" e);
105106106107 Printf.printf "\n=== With layout=true ===\n";
107107- (match Yamlt.decode_string ~layout:true codec yaml with
108108- | Ok (host, port) ->
109109- Printf.printf "Decoded: host=%s, port=%d\n" host port;
110110- Printf.printf "Meta preserved: yes (style info available for round-tripping)\n"
111111- | Error e -> Printf.printf "Error: %s\n" e)
108108+ match Yamlt.decode_string ~layout:true codec yaml with
109109+ | Ok (host, port) ->
110110+ Printf.printf "Decoded: host=%s, port=%d\n" host port;
111111+ Printf.printf
112112+ "Meta preserved: yes (style info available for round-tripping)\n"
113113+ | Error e -> Printf.printf "Error: %s\n" e
112114113115(* Test: Round-trip with layout preservation *)
114116let test_roundtrip_layout file =
···125127126128 Printf.printf "\n=== Decode without layout, re-encode ===\n";
127129 (match Yamlt.decode_string ~layout:false codec yaml with
128128- | Ok items ->
129129- (match Yamlt.encode_string ~format:Yamlt.Block codec items with
130130- | Ok yaml_out -> Printf.printf "%s" yaml_out
131131- | Error e -> Printf.printf "Encode error: %s\n" e)
132132- | Error e -> Printf.printf "Decode error: %s\n" e);
130130+ | Ok items -> (
131131+ match Yamlt.encode_string ~format:Yamlt.Block codec items with
132132+ | Ok yaml_out -> Printf.printf "%s" yaml_out
133133+ | Error e -> Printf.printf "Encode error: %s\n" e)
134134+ | Error e -> Printf.printf "Decode error: %s\n" e);
133135134134- Printf.printf "\n=== Decode with layout=true, re-encode with Layout format ===\n";
135135- (match Yamlt.decode_string ~layout:true codec yaml with
136136- | Ok items ->
137137- (match Yamlt.encode_string ~format:Yamlt.Layout codec items with
138138- | Ok yaml_out -> Printf.printf "%s" yaml_out
139139- | Error e -> Printf.printf "Encode error: %s\n" e)
140140- | Error e -> Printf.printf "Decode error: %s\n" e)
136136+ Printf.printf
137137+ "\n=== Decode with layout=true, re-encode with Layout format ===\n";
138138+ match Yamlt.decode_string ~layout:true codec yaml with
139139+ | Ok items -> (
140140+ match Yamlt.encode_string ~format:Yamlt.Layout codec items with
141141+ | Ok yaml_out -> Printf.printf "%s" yaml_out
142142+ | Error e -> Printf.printf "Encode error: %s\n" e)
143143+ | Error e -> Printf.printf "Decode error: %s\n" e
141144142145(* Test: File path in error messages *)
143146let test_file_path () =
···164167165168 let codec =
166169 Jsont.Object.map ~kind:"Complete" (fun a b c -> (a, b, c))
167167- |> Jsont.Object.mem "field_a" Jsont.string ~enc:(fun (a,_,_) -> a)
168168- |> Jsont.Object.mem "field_b" Jsont.int ~enc:(fun (_,b,_) -> b)
169169- |> Jsont.Object.mem "field_c" Jsont.bool ~enc:(fun (_,_,c) -> c)
170170+ |> Jsont.Object.mem "field_a" Jsont.string ~enc:(fun (a, _, _) -> a)
171171+ |> Jsont.Object.mem "field_b" Jsont.int ~enc:(fun (_, b, _) -> b)
172172+ |> Jsont.Object.mem "field_c" Jsont.bool ~enc:(fun (_, _, c) -> c)
170173 |> Jsont.Object.finish
171174 in
172175···183186 let yaml = read_file file in
184187185188 let codec =
186186- Jsont.Object.map ~kind:"Settings" (fun timeout retries -> (timeout, retries))
189189+ Jsont.Object.map ~kind:"Settings" (fun timeout retries ->
190190+ (timeout, retries))
187191 |> Jsont.Object.mem "timeout" Jsont.int ~enc:fst
188192 |> Jsont.Object.mem "retries" Jsont.int ~enc:snd
189193 |> Jsont.Object.finish
···191195192196 Printf.printf "=== locs=false, layout=false (defaults) ===\n";
193197 (match Yamlt.decode_string ~locs:false ~layout:false codec yaml with
194194- | Ok (timeout, retries) ->
195195- Printf.printf "OK: timeout=%d, retries=%d\n" timeout retries
196196- | Error e -> Printf.printf "Error: %s\n" e);
198198+ | Ok (timeout, retries) ->
199199+ Printf.printf "OK: timeout=%d, retries=%d\n" timeout retries
200200+ | Error e -> Printf.printf "Error: %s\n" e);
197201198202 Printf.printf "\n=== locs=true, layout=false ===\n";
199203 (match Yamlt.decode_string ~locs:true ~layout:false codec yaml with
200200- | Ok (timeout, retries) ->
201201- Printf.printf "OK: timeout=%d, retries=%d (with precise locations)\n" timeout retries
202202- | Error e -> Printf.printf "Error: %s\n" e);
204204+ | Ok (timeout, retries) ->
205205+ Printf.printf "OK: timeout=%d, retries=%d (with precise locations)\n"
206206+ timeout retries
207207+ | Error e -> Printf.printf "Error: %s\n" e);
203208204209 Printf.printf "\n=== locs=false, layout=true ===\n";
205210 (match Yamlt.decode_string ~locs:false ~layout:true codec yaml with
206206- | Ok (timeout, retries) ->
207207- Printf.printf "OK: timeout=%d, retries=%d (with layout metadata)\n" timeout retries
208208- | Error e -> Printf.printf "Error: %s\n" e);
211211+ | Ok (timeout, retries) ->
212212+ Printf.printf "OK: timeout=%d, retries=%d (with layout metadata)\n"
213213+ timeout retries
214214+ | Error e -> Printf.printf "Error: %s\n" e);
209215210216 Printf.printf "\n=== locs=true, layout=true (both enabled) ===\n";
211211- (match Yamlt.decode_string ~locs:true ~layout:true codec yaml with
212212- | Ok (timeout, retries) ->
213213- Printf.printf "OK: timeout=%d, retries=%d (with locations and layout)\n" timeout retries
214214- | Error e -> Printf.printf "Error: %s\n" e)
217217+ match Yamlt.decode_string ~locs:true ~layout:true codec yaml with
218218+ | Ok (timeout, retries) ->
219219+ Printf.printf "OK: timeout=%d, retries=%d (with locations and layout)\n"
220220+ timeout retries
221221+ | Error e -> Printf.printf "Error: %s\n" e
215222216223let () =
217224 let usage = "Usage: test_locations <command> [args...]" in
···224231 match Sys.argv.(1) with
225232 | "error-precision" when Array.length Sys.argv = 3 ->
226233 test_error_precision Sys.argv.(2)
227227-228234 | "nested-error" when Array.length Sys.argv = 3 ->
229235 test_nested_error Sys.argv.(2)
230230-231236 | "array-error" when Array.length Sys.argv = 3 ->
232237 test_array_error Sys.argv.(2)
233233-234238 | "layout" when Array.length Sys.argv = 3 ->
235239 test_layout_preservation Sys.argv.(2)
236236-237240 | "roundtrip" when Array.length Sys.argv = 3 ->
238241 test_roundtrip_layout Sys.argv.(2)
239239-240240- | "file-path" ->
241241- test_file_path ()
242242-242242+ | "file-path" -> test_file_path ()
243243 | "missing-field" when Array.length Sys.argv = 3 ->
244244 test_missing_field Sys.argv.(2)
245245-246245 | "combined" when Array.length Sys.argv = 3 ->
247246 test_combined_options Sys.argv.(2)
248248-249247 | _ ->
250248 prerr_endline usage;
251249 prerr_endline "Commands:";
252252- prerr_endline " error-precision <file> - Compare error messages with/without locs";
253253- prerr_endline " nested-error <file> - Test error locations in nested objects";
254254- prerr_endline " array-error <file> - Test error locations in arrays";
250250+ prerr_endline
251251+ " error-precision <file> - Compare error messages with/without locs";
252252+ prerr_endline
253253+ " nested-error <file> - Test error locations in nested objects";
254254+ prerr_endline
255255+ " array-error <file> - Test error locations in arrays";
255256 prerr_endline " layout <file> - Test layout preservation";
256256- prerr_endline " roundtrip <file> - Test round-tripping with layout";
257257- prerr_endline " file-path - Test file path in error messages";
258258- prerr_endline " missing-field <file> - Test missing field errors with locs";
257257+ prerr_endline
258258+ " roundtrip <file> - Test round-tripping with layout";
259259+ prerr_endline
260260+ " file-path - Test file path in error messages";
261261+ prerr_endline
262262+ " missing-field <file> - Test missing field errors with locs";
259263 prerr_endline " combined <file> - Test locs and layout together";
260264 exit 1
+13-9
tests/bin/test_null_complete.ml
···88 |> Object.finish
99 in
1010 (match Yamlt.decode_string codec1 yaml1 with
1111- | Ok v -> Printf.printf "Result: %s\n" (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
1212- | Error e -> Printf.printf "Error: %s\n" e);
1111+ | Ok v ->
1212+ Printf.printf "Result: %s\n"
1313+ (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
1414+ | Error e -> Printf.printf "Error: %s\n" e);
13151416 Printf.printf "\n=== Test 2: Jsont.option with YAML string ===\n";
1517 (match Yamlt.decode_string codec1 "value: hello" with
1616- | Ok v -> Printf.printf "Result: %s\n" (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
1717- | Error e -> Printf.printf "Error: %s\n" e);
1818+ | Ok v ->
1919+ Printf.printf "Result: %s\n"
2020+ (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
2121+ | Error e -> Printf.printf "Error: %s\n" e);
18221923 Printf.printf "\n=== Test 3: Jsont.string with YAML null (should error) ===\n";
2024 let codec2 =
···2428 |> Object.finish
2529 in
2630 (match Yamlt.decode_string codec2 "value: null" with
2727- | Ok v -> Printf.printf "Result: %s\n" v
2828- | Error e -> Printf.printf "Error (expected): %s\n" e);
3131+ | Ok v -> Printf.printf "Result: %s\n" v
3232+ | Error e -> Printf.printf "Error (expected): %s\n" e);
29333034 Printf.printf "\n=== Test 4: Jsont.string with YAML string ===\n";
3131- (match Yamlt.decode_string codec2 "value: hello" with
3232- | Ok v -> Printf.printf "Result: %s\n" v
3333- | Error e -> Printf.printf "Error: %s\n" e)
3535+ match Yamlt.decode_string codec2 "value: hello" with
3636+ | Ok v -> Printf.printf "Result: %s\n" v
3737+ | Error e -> Printf.printf "Error: %s\n" e
+17-16
tests/bin/test_null_fix.ml
···2233let () =
44 let module M = struct
55- type data = { value: string option }
66-55+ type data = { value : string option }
66+77 let data_codec =
88 Jsont.Object.map ~kind:"Data" (fun value -> { value })
99- |> Jsont.Object.mem "value" (Jsont.option Jsont.string) ~enc:(fun d -> d.value)
99+ |> Jsont.Object.mem "value" (Jsont.option Jsont.string) ~enc:(fun d ->
1010+ d.value)
1011 |> Jsont.Object.finish
1112 end in
1212-1313 let yaml_null = "value: null" in
14141515 Printf.printf "Testing YAML null handling with Jsont.option Jsont.string:\n\n";
16161717 match Yamlt.decode_string M.data_codec yaml_null with
1818- | Ok data ->
1919- (match data.M.value with
2020- | None -> Printf.printf "YAML: value=None (CORRECT)\n"
2121- | Some s -> Printf.printf "YAML: value=Some(%S) (BUG!)\n" s)
2222- | Error e -> Printf.printf "YAML ERROR: %s\n" e;
1818+ | Ok data -> (
1919+ match data.M.value with
2020+ | None -> Printf.printf "YAML: value=None (CORRECT)\n"
2121+ | Some s -> Printf.printf "YAML: value=Some(%S) (BUG!)\n" s)
2222+ | Error e -> (
2323+ Printf.printf "YAML ERROR: %s\n" e;
23242424- let json_null = "{\"value\": null}" in
2525- match Jsont_bytesrw.decode_string M.data_codec json_null with
2626- | Ok data ->
2727- (match data.M.value with
2828- | None -> Printf.printf "JSON: value=None (CORRECT)\n"
2929- | Some s -> Printf.printf "JSON: value=Some(%S) (BUG!)\n" s)
3030- | Error e -> Printf.printf "JSON ERROR: %s\n" e
2525+ let json_null = "{\"value\": null}" in
2626+ match Jsont_bytesrw.decode_string M.data_codec json_null with
2727+ | Ok data -> (
2828+ match data.M.value with
2929+ | None -> Printf.printf "JSON: value=None (CORRECT)\n"
3030+ | Some s -> Printf.printf "JSON: value=Some(%S) (BUG!)\n" s)
3131+ | Error e -> Printf.printf "JSON ERROR: %s\n" e)
+54-65
tests/bin/test_objects.ml
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566(** Test object codec functionality with Yamlt *)
77···2727(* Test: Simple object with required fields *)
2828let test_simple_object file =
2929 let module M = struct
3030- type person = { name: string; age: int }
3030+ type person = { name : string; age : int }
31313232 let person_codec =
3333 Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
···37373838 let show p = Printf.sprintf "{name=%S; age=%d}" p.name p.age
3939 end in
4040-4140 let yaml = read_file file in
4241 let json = read_file (file ^ ".json") in
4342 let json_result = Jsont_bytesrw.decode_string M.person_codec json in
···5049(* Test: Object with optional fields *)
5150let test_optional_fields file =
5251 let module M = struct
5353- type config = { host: string; port: int option; debug: bool option }
5252+ type config = { host : string; port : int option; debug : bool option }
54535554 let config_codec =
5656- Jsont.Object.map ~kind:"Config"
5757- (fun host port debug -> { host; port; debug })
5555+ Jsont.Object.map ~kind:"Config" (fun host port debug ->
5656+ { host; port; debug })
5857 |> Jsont.Object.mem "host" Jsont.string ~enc:(fun c -> c.host)
5958 |> Jsont.Object.opt_mem "port" Jsont.int ~enc:(fun c -> c.port)
6059 |> Jsont.Object.opt_mem "debug" Jsont.bool ~enc:(fun c -> c.debug)
6160 |> Jsont.Object.finish
62616362 let show c =
6464- Printf.sprintf "{host=%S; port=%s; debug=%s}"
6565- c.host
6666- (match c.port with None -> "None" | Some p -> Printf.sprintf "Some %d" p)
6767- (match c.debug with None -> "None" | Some b -> Printf.sprintf "Some %b" b)
6363+ Printf.sprintf "{host=%S; port=%s; debug=%s}" c.host
6464+ (match c.port with
6565+ | None -> "None"
6666+ | Some p -> Printf.sprintf "Some %d" p)
6767+ (match c.debug with
6868+ | None -> "None"
6969+ | Some b -> Printf.sprintf "Some %b" b)
6870 end in
6969-7071 let yaml = read_file file in
7172 let json = read_file (file ^ ".json") in
7273 let json_result = Jsont_bytesrw.decode_string M.config_codec json in
···7980(* Test: Object with default values *)
8081let test_default_values file =
8182 let module M = struct
8282- type settings = { timeout: int; retries: int; verbose: bool }
8383+ type settings = { timeout : int; retries : int; verbose : bool }
83848485 let settings_codec =
8585- Jsont.Object.map ~kind:"Settings"
8686- (fun timeout retries verbose -> { timeout; retries; verbose })
8787- |> Jsont.Object.mem "timeout" Jsont.int ~enc:(fun s -> s.timeout) ~dec_absent:30
8888- |> Jsont.Object.mem "retries" Jsont.int ~enc:(fun s -> s.retries) ~dec_absent:3
8989- |> Jsont.Object.mem "verbose" Jsont.bool ~enc:(fun s -> s.verbose) ~dec_absent:false
8686+ Jsont.Object.map ~kind:"Settings" (fun timeout retries verbose ->
8787+ { timeout; retries; verbose })
8888+ |> Jsont.Object.mem "timeout" Jsont.int
8989+ ~enc:(fun s -> s.timeout)
9090+ ~dec_absent:30
9191+ |> Jsont.Object.mem "retries" Jsont.int
9292+ ~enc:(fun s -> s.retries)
9393+ ~dec_absent:3
9494+ |> Jsont.Object.mem "verbose" Jsont.bool
9595+ ~enc:(fun s -> s.verbose)
9696+ ~dec_absent:false
9097 |> Jsont.Object.finish
91989299 let show s =
9393- Printf.sprintf "{timeout=%d; retries=%d; verbose=%b}"
9494- s.timeout s.retries s.verbose
100100+ Printf.sprintf "{timeout=%d; retries=%d; verbose=%b}" s.timeout s.retries
101101+ s.verbose
95102 end in
9696-97103 let yaml = read_file file in
98104 let json = read_file (file ^ ".json") in
99105 let json_result = Jsont_bytesrw.decode_string M.settings_codec json in
···106112(* Test: Nested objects *)
107113let test_nested_objects file =
108114 let module M = struct
109109- type address = { street: string; city: string; zip: string }
110110- type employee = { name: string; address: address }
115115+ type address = { street : string; city : string; zip : string }
116116+ type employee = { name : string; address : address }
111117112118 let address_codec =
113113- Jsont.Object.map ~kind:"Address"
114114- (fun street city zip -> { street; city; zip })
119119+ Jsont.Object.map ~kind:"Address" (fun street city zip ->
120120+ { street; city; zip })
115121 |> Jsont.Object.mem "street" Jsont.string ~enc:(fun a -> a.street)
116122 |> Jsont.Object.mem "city" Jsont.string ~enc:(fun a -> a.city)
117123 |> Jsont.Object.mem "zip" Jsont.string ~enc:(fun a -> a.zip)
118124 |> Jsont.Object.finish
119125120126 let employee_codec =
121121- Jsont.Object.map ~kind:"Employee"
122122- (fun name address -> { name; address })
127127+ Jsont.Object.map ~kind:"Employee" (fun name address -> { name; address })
123128 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun e -> e.name)
124129 |> Jsont.Object.mem "address" address_codec ~enc:(fun e -> e.address)
125130 |> Jsont.Object.finish
126131127132 let show e =
128128- Printf.sprintf "{name=%S; address={street=%S; city=%S; zip=%S}}"
129129- e.name e.address.street e.address.city e.address.zip
133133+ Printf.sprintf "{name=%S; address={street=%S; city=%S; zip=%S}}" e.name
134134+ e.address.street e.address.city e.address.zip
130135 end in
131131-132136 let yaml = read_file file in
133137 let json = read_file (file ^ ".json") in
134138 let json_result = Jsont_bytesrw.decode_string M.employee_codec json in
···141145(* Test: Unknown member handling - error *)
142146let test_unknown_members_error file =
143147 let module M = struct
144144- type strict = { name: string }
148148+ type strict = { name : string }
145149146150 let strict_codec =
147151 Jsont.Object.map ~kind:"Strict" (fun name -> { name })
148152 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun s -> s.name)
149153 |> Jsont.Object.finish
150154 end in
151151-152155 let yaml = read_file file in
153156 let result = Yamlt.decode_string M.strict_codec yaml in
154157 match result with
···158161(* Test: Unknown member handling - keep *)
159162let test_unknown_members_keep file =
160163 let module M = struct
161161- type flexible = { name: string; extra: Jsont.json }
164164+ type flexible = { name : string; extra : Jsont.json }
162165163166 let flexible_codec =
164167 Jsont.Object.map ~kind:"Flexible" (fun name extra -> { name; extra })
···166169 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun f -> f.extra)
167170 |> Jsont.Object.finish
168171169169- let show f =
170170- Printf.sprintf "{name=%S; has_extra=true}" f.name
172172+ let show f = Printf.sprintf "{name=%S; has_extra=true}" f.name
171173 end in
172172-173174 let yaml = read_file file in
174175 let json = read_file (file ^ ".json") in
175176 let json_result = Jsont_bytesrw.decode_string M.flexible_codec json in
···182183(* Test: Object cases (discriminated unions) - simplified version *)
183184let test_object_cases file =
184185 let module M = struct
185185- type circle = { type_: string; radius: float }
186186+ type circle = { type_ : string; radius : float }
186187187188 let circle_codec =
188189 Jsont.Object.map ~kind:"Circle" (fun type_ radius -> { type_; radius })
···190191 |> Jsont.Object.mem "radius" Jsont.number ~enc:(fun c -> c.radius)
191192 |> Jsont.Object.finish
192193193193- let show c =
194194- Printf.sprintf "Circle{radius=%.2f}" c.radius
194194+ let show c = Printf.sprintf "Circle{radius=%.2f}" c.radius
195195 end in
196196-197196 let yaml = read_file file in
198197 let json = read_file (file ^ ".json") in
199198 let json_result = Jsont_bytesrw.decode_string M.circle_codec json in
···206205(* Test: Missing required field error *)
207206let test_missing_required file =
208207 let module M = struct
209209- type required = { name: string; age: int }
208208+ type required = { name : string; age : int }
210209211210 let required_codec =
212211 Jsont.Object.map ~kind:"Required" (fun name age -> { name; age })
···214213 |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age)
215214 |> Jsont.Object.finish
216215 end in
217217-218216 let yaml = read_file file in
219217 let result = Yamlt.decode_string M.required_codec yaml in
220218 match result with
···224222(* Test: Encoding objects to different formats *)
225223let test_encode_object () =
226224 let module M = struct
227227- type person = { name: string; age: int; active: bool }
225225+ type person = { name : string; age : int; active : bool }
228226229227 let person_codec =
230230- Jsont.Object.map ~kind:"Person" (fun name age active -> { name; age; active })
228228+ Jsont.Object.map ~kind:"Person" (fun name age active ->
229229+ { name; age; active })
231230 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
232231 |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
233232 |> Jsont.Object.mem "active" Jsont.bool ~enc:(fun p -> p.active)
234233 |> Jsont.Object.finish
235234 end in
236236-237235 let person = M.{ name = "Alice"; age = 30; active = true } in
238236239237 (* Encode to JSON *)
240238 (match Jsont_bytesrw.encode_string M.person_codec person with
241241- | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
242242- | Error e -> Printf.printf "JSON ERROR: %s\n" e);
239239+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
240240+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
243241244242 (* Encode to YAML Block *)
245243 (match Yamlt.encode_string ~format:Yamlt.Block M.person_codec person with
246246- | Ok s -> Printf.printf "YAML Block:\n%s" s
247247- | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
244244+ | Ok s -> Printf.printf "YAML Block:\n%s" s
245245+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
248246249247 (* Encode to YAML Flow *)
250250- (match Yamlt.encode_string ~format:Yamlt.Flow M.person_codec person with
251251- | Ok s -> Printf.printf "YAML Flow: %s" s
252252- | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
248248+ match Yamlt.encode_string ~format:Yamlt.Flow M.person_codec person with
249249+ | Ok s -> Printf.printf "YAML Flow: %s" s
250250+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
253251254252let () =
255253 let usage = "Usage: test_objects <command> [args...]" in
···262260 match Sys.argv.(1) with
263261 | "simple" when Stdlib.Array.length Sys.argv = 3 ->
264262 test_simple_object Sys.argv.(2)
265265-266263 | "optional" when Stdlib.Array.length Sys.argv = 3 ->
267264 test_optional_fields Sys.argv.(2)
268268-269265 | "defaults" when Stdlib.Array.length Sys.argv = 3 ->
270266 test_default_values Sys.argv.(2)
271271-272267 | "nested" when Stdlib.Array.length Sys.argv = 3 ->
273268 test_nested_objects Sys.argv.(2)
274274-275269 | "unknown-error" when Stdlib.Array.length Sys.argv = 3 ->
276270 test_unknown_members_error Sys.argv.(2)
277277-278271 | "unknown-keep" when Stdlib.Array.length Sys.argv = 3 ->
279272 test_unknown_members_keep Sys.argv.(2)
280280-281273 | "cases" when Stdlib.Array.length Sys.argv = 3 ->
282274 test_object_cases Sys.argv.(2)
283283-284275 | "missing-required" when Stdlib.Array.length Sys.argv = 3 ->
285276 test_missing_required Sys.argv.(2)
286286-287287- | "encode" when Stdlib.Array.length Sys.argv = 2 ->
288288- test_encode_object ()
289289-277277+ | "encode" when Stdlib.Array.length Sys.argv = 2 -> test_encode_object ()
290278 | _ ->
291279 prerr_endline usage;
292280 prerr_endline "Commands:";
···297285 prerr_endline " unknown-error <file> - Test unknown member error";
298286 prerr_endline " unknown-keep <file> - Test keeping unknown members";
299287 prerr_endline " cases <file> - Test object cases (unions)";
300300- prerr_endline " missing-required <file> - Test missing required field error";
288288+ prerr_endline
289289+ " missing-required <file> - Test missing required field error";
301290 prerr_endline " encode - Test encoding objects";
302291 exit 1
+6-5
tests/bin/test_opt_array.ml
···11let () =
22 let codec =
33 Jsont.Object.map ~kind:"Test" (fun arr -> arr)
44- |> Jsont.Object.opt_mem "values" (Jsont.array Jsont.string) ~enc:(fun arr -> arr)
44+ |> Jsont.Object.opt_mem "values" (Jsont.array Jsont.string) ~enc:(fun arr ->
55+ arr)
56 |> Jsont.Object.finish
67 in
78···9101011 Printf.printf "Testing optional array field:\n";
1112 match Yamlt.decode_string codec yaml with
1212- | Ok arr ->
1313- (match arr with
1414- | None -> Printf.printf "Result: None\n"
1515- | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
1313+ | Ok arr -> (
1414+ match arr with
1515+ | None -> Printf.printf "Result: None\n"
1616+ | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
1617 | Error e -> Printf.printf "Error: %s\n" e
+134-88
tests/bin/test_roundtrip.ml
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566(** Test roundtrip encoding/decoding with Yamlt *)
7788(* Test: Roundtrip scalars *)
99let test_scalar_roundtrip () =
1010 let module M = struct
1111- type data = { s: string; n: float; b: bool; nul: unit }
1111+ type data = { s : string; n : float; b : bool; nul : unit }
12121313 let data_codec =
1414 Jsont.Object.map ~kind:"Data" (fun s n b nul -> { s; n; b; nul })
···2121 let equal d1 d2 =
2222 d1.s = d2.s && d1.n = d2.n && d1.b = d2.b && d1.nul = d2.nul
2323 end in
2424-2524 let original = { M.s = "hello"; n = 42.5; b = true; nul = () } in
26252726 (* JSON roundtrip *)
2827 let json_encoded = Jsont_bytesrw.encode_string M.data_codec original in
2929- let json_decoded = Result.bind json_encoded (Jsont_bytesrw.decode_string M.data_codec) in
2828+ let json_decoded =
2929+ Result.bind json_encoded (Jsont_bytesrw.decode_string M.data_codec)
3030+ in
3031 (match json_decoded with
3131- | Ok decoded when M.equal original decoded -> Printf.printf "JSON roundtrip: PASS\n"
3232- | Ok _ -> Printf.printf "JSON roundtrip: FAIL (data mismatch)\n"
3333- | Error e -> Printf.printf "JSON roundtrip: FAIL (%s)\n" e);
3232+ | Ok decoded when M.equal original decoded ->
3333+ Printf.printf "JSON roundtrip: PASS\n"
3434+ | Ok _ -> Printf.printf "JSON roundtrip: FAIL (data mismatch)\n"
3535+ | Error e -> Printf.printf "JSON roundtrip: FAIL (%s)\n" e);
34363537 (* YAML Block roundtrip *)
3636- let yaml_block_encoded = Yamlt.encode_string ~format:Yamlt.Block M.data_codec original in
3737- let yaml_block_decoded = Result.bind yaml_block_encoded (Yamlt.decode_string M.data_codec) in
3838+ let yaml_block_encoded =
3939+ Yamlt.encode_string ~format:Yamlt.Block M.data_codec original
4040+ in
4141+ let yaml_block_decoded =
4242+ Result.bind yaml_block_encoded (Yamlt.decode_string M.data_codec)
4343+ in
3844 (match yaml_block_decoded with
3939- | Ok decoded when M.equal original decoded -> Printf.printf "YAML Block roundtrip: PASS\n"
4040- | Ok _ -> Printf.printf "YAML Block roundtrip: FAIL (data mismatch)\n"
4141- | Error e -> Printf.printf "YAML Block roundtrip: FAIL (%s)\n" e);
4545+ | Ok decoded when M.equal original decoded ->
4646+ Printf.printf "YAML Block roundtrip: PASS\n"
4747+ | Ok _ -> Printf.printf "YAML Block roundtrip: FAIL (data mismatch)\n"
4848+ | Error e -> Printf.printf "YAML Block roundtrip: FAIL (%s)\n" e);
42494350 (* YAML Flow roundtrip *)
4444- let yaml_flow_encoded = Yamlt.encode_string ~format:Yamlt.Flow M.data_codec original in
4545- let yaml_flow_decoded = Result.bind yaml_flow_encoded (Yamlt.decode_string M.data_codec) in
4646- (match yaml_flow_decoded with
4747- | Ok decoded when M.equal original decoded -> Printf.printf "YAML Flow roundtrip: PASS\n"
4848- | Ok _ -> Printf.printf "YAML Flow roundtrip: FAIL (data mismatch)\n"
4949- | Error e -> Printf.printf "YAML Flow roundtrip: FAIL (%s)\n" e)
5151+ let yaml_flow_encoded =
5252+ Yamlt.encode_string ~format:Yamlt.Flow M.data_codec original
5353+ in
5454+ let yaml_flow_decoded =
5555+ Result.bind yaml_flow_encoded (Yamlt.decode_string M.data_codec)
5656+ in
5757+ match yaml_flow_decoded with
5858+ | Ok decoded when M.equal original decoded ->
5959+ Printf.printf "YAML Flow roundtrip: PASS\n"
6060+ | Ok _ -> Printf.printf "YAML Flow roundtrip: FAIL (data mismatch)\n"
6161+ | Error e -> Printf.printf "YAML Flow roundtrip: FAIL (%s)\n" e
50625163(* Test: Roundtrip arrays *)
5264let test_array_roundtrip () =
5365 let module M = struct
5454- type data = { items: int array; nested: float array array }
6666+ type data = { items : int array; nested : float array array }
55675668 let data_codec =
5769 Jsont.Object.map ~kind:"Data" (fun items nested -> { items; nested })
5858- |> Jsont.Object.mem "items" (Jsont.array Jsont.int) ~enc:(fun d -> d.items)
5959- |> Jsont.Object.mem "nested" (Jsont.array (Jsont.array Jsont.number)) ~enc:(fun d -> d.nested)
7070+ |> Jsont.Object.mem "items" (Jsont.array Jsont.int) ~enc:(fun d ->
7171+ d.items)
7272+ |> Jsont.Object.mem "nested"
7373+ (Jsont.array (Jsont.array Jsont.number))
7474+ ~enc:(fun d -> d.nested)
6075 |> Jsont.Object.finish
61766262- let equal d1 d2 =
6363- d1.items = d2.items && d1.nested = d2.nested
7777+ let equal d1 d2 = d1.items = d2.items && d1.nested = d2.nested
6478 end in
6565-6666- let original = { M.items = [|1; 2; 3; 4; 5|]; nested = [|[|1.0; 2.0|]; [|3.0; 4.0|]|] } in
7979+ let original =
8080+ {
8181+ M.items = [| 1; 2; 3; 4; 5 |];
8282+ nested = [| [| 1.0; 2.0 |]; [| 3.0; 4.0 |] |];
8383+ }
8484+ in
67856886 (* JSON roundtrip *)
6969- let json_result = Result.bind
7070- (Jsont_bytesrw.encode_string M.data_codec original)
7171- (Jsont_bytesrw.decode_string M.data_codec) in
8787+ let json_result =
8888+ Result.bind
8989+ (Jsont_bytesrw.encode_string M.data_codec original)
9090+ (Jsont_bytesrw.decode_string M.data_codec)
9191+ in
7292 (match json_result with
7373- | Ok decoded when M.equal original decoded -> Printf.printf "JSON array roundtrip: PASS\n"
7474- | Ok _ -> Printf.printf "JSON array roundtrip: FAIL (data mismatch)\n"
7575- | Error e -> Printf.printf "JSON array roundtrip: FAIL (%s)\n" e);
9393+ | Ok decoded when M.equal original decoded ->
9494+ Printf.printf "JSON array roundtrip: PASS\n"
9595+ | Ok _ -> Printf.printf "JSON array roundtrip: FAIL (data mismatch)\n"
9696+ | Error e -> Printf.printf "JSON array roundtrip: FAIL (%s)\n" e);
76977798 (* YAML roundtrip *)
7878- let yaml_result = Result.bind
7979- (Yamlt.encode_string M.data_codec original)
8080- (Yamlt.decode_string M.data_codec) in
8181- (match yaml_result with
8282- | Ok decoded when M.equal original decoded -> Printf.printf "YAML array roundtrip: PASS\n"
8383- | Ok _ -> Printf.printf "YAML array roundtrip: FAIL (data mismatch)\n"
8484- | Error e -> Printf.printf "YAML array roundtrip: FAIL (%s)\n" e)
9999+ let yaml_result =
100100+ Result.bind
101101+ (Yamlt.encode_string M.data_codec original)
102102+ (Yamlt.decode_string M.data_codec)
103103+ in
104104+ match yaml_result with
105105+ | Ok decoded when M.equal original decoded ->
106106+ Printf.printf "YAML array roundtrip: PASS\n"
107107+ | Ok _ -> Printf.printf "YAML array roundtrip: FAIL (data mismatch)\n"
108108+ | Error e -> Printf.printf "YAML array roundtrip: FAIL (%s)\n" e
8510986110(* Test: Roundtrip objects *)
87111let test_object_roundtrip () =
88112 let module M = struct
8989- type person = { p_name: string; age: int; active: bool }
9090- type company = { c_name: string; employees: person array }
113113+ type person = { p_name : string; age : int; active : bool }
114114+ type company = { c_name : string; employees : person array }
9111592116 let person_codec =
9393- Jsont.Object.map ~kind:"Person" (fun p_name age active -> { p_name; age; active })
117117+ Jsont.Object.map ~kind:"Person" (fun p_name age active ->
118118+ { p_name; age; active })
94119 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.p_name)
95120 |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
96121 |> Jsont.Object.mem "active" Jsont.bool ~enc:(fun p -> p.active)
97122 |> Jsont.Object.finish
9812399124 let company_codec =
100100- Jsont.Object.map ~kind:"Company" (fun c_name employees -> { c_name; employees })
125125+ Jsont.Object.map ~kind:"Company" (fun c_name employees ->
126126+ { c_name; employees })
101127 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.c_name)
102102- |> Jsont.Object.mem "employees" (Jsont.array person_codec) ~enc:(fun c -> c.employees)
128128+ |> Jsont.Object.mem "employees" (Jsont.array person_codec) ~enc:(fun c ->
129129+ c.employees)
103130 |> Jsont.Object.finish
104131105132 let person_equal p1 p2 =
106133 p1.p_name = p2.p_name && p1.age = p2.age && p1.active = p2.active
107134108135 let equal c1 c2 =
109109- c1.c_name = c2.c_name &&
110110- Stdlib.Array.length c1.employees = Stdlib.Array.length c2.employees &&
111111- Stdlib.Array.for_all2 person_equal c1.employees c2.employees
136136+ c1.c_name = c2.c_name
137137+ && Stdlib.Array.length c1.employees = Stdlib.Array.length c2.employees
138138+ && Stdlib.Array.for_all2 person_equal c1.employees c2.employees
112139 end in
113113-114114- let original = {
115115- M.c_name = "Acme Corp";
116116- employees = [|
117117- { p_name = "Alice"; age = 30; active = true };
118118- { p_name = "Bob"; age = 25; active = false };
119119- |]
120120- } in
140140+ let original =
141141+ {
142142+ M.c_name = "Acme Corp";
143143+ employees =
144144+ [|
145145+ { p_name = "Alice"; age = 30; active = true };
146146+ { p_name = "Bob"; age = 25; active = false };
147147+ |];
148148+ }
149149+ in
121150122151 (* JSON roundtrip *)
123123- let json_result = Result.bind
124124- (Jsont_bytesrw.encode_string M.company_codec original)
125125- (Jsont_bytesrw.decode_string M.company_codec) in
152152+ let json_result =
153153+ Result.bind
154154+ (Jsont_bytesrw.encode_string M.company_codec original)
155155+ (Jsont_bytesrw.decode_string M.company_codec)
156156+ in
126157 (match json_result with
127127- | Ok decoded when M.equal original decoded -> Printf.printf "JSON object roundtrip: PASS\n"
128128- | Ok _ -> Printf.printf "JSON object roundtrip: FAIL (data mismatch)\n"
129129- | Error e -> Printf.printf "JSON object roundtrip: FAIL (%s)\n" e);
158158+ | Ok decoded when M.equal original decoded ->
159159+ Printf.printf "JSON object roundtrip: PASS\n"
160160+ | Ok _ -> Printf.printf "JSON object roundtrip: FAIL (data mismatch)\n"
161161+ | Error e -> Printf.printf "JSON object roundtrip: FAIL (%s)\n" e);
130162131163 (* YAML roundtrip *)
132132- let yaml_result = Result.bind
133133- (Yamlt.encode_string M.company_codec original)
134134- (Yamlt.decode_string M.company_codec) in
135135- (match yaml_result with
136136- | Ok decoded when M.equal original decoded -> Printf.printf "YAML object roundtrip: PASS\n"
137137- | Ok _ -> Printf.printf "YAML object roundtrip: FAIL (data mismatch)\n"
138138- | Error e -> Printf.printf "YAML object roundtrip: FAIL (%s)\n" e)
164164+ let yaml_result =
165165+ Result.bind
166166+ (Yamlt.encode_string M.company_codec original)
167167+ (Yamlt.decode_string M.company_codec)
168168+ in
169169+ match yaml_result with
170170+ | Ok decoded when M.equal original decoded ->
171171+ Printf.printf "YAML object roundtrip: PASS\n"
172172+ | Ok _ -> Printf.printf "YAML object roundtrip: FAIL (data mismatch)\n"
173173+ | Error e -> Printf.printf "YAML object roundtrip: FAIL (%s)\n" e
139174140175(* Test: Roundtrip with optionals *)
141176let test_optional_roundtrip () =
142177 let module M = struct
143143- type data = { required: string; optional: int option; nullable: string option }
178178+ type data = {
179179+ required : string;
180180+ optional : int option;
181181+ nullable : string option;
182182+ }
144183145184 let data_codec =
146146- Jsont.Object.map ~kind:"Data" (fun required optional nullable -> { required; optional; nullable })
185185+ Jsont.Object.map ~kind:"Data" (fun required optional nullable ->
186186+ { required; optional; nullable })
147187 |> Jsont.Object.mem "required" Jsont.string ~enc:(fun d -> d.required)
148188 |> Jsont.Object.opt_mem "optional" Jsont.int ~enc:(fun d -> d.optional)
149149- |> Jsont.Object.mem "nullable" (Jsont.some Jsont.string) ~enc:(fun d -> d.nullable)
189189+ |> Jsont.Object.mem "nullable" (Jsont.some Jsont.string) ~enc:(fun d ->
190190+ d.nullable)
150191 |> Jsont.Object.finish
151192152193 let equal d1 d2 =
153153- d1.required = d2.required && d1.optional = d2.optional && d1.nullable = d2.nullable
194194+ d1.required = d2.required && d1.optional = d2.optional
195195+ && d1.nullable = d2.nullable
154196 end in
155155-156197 let original = { M.required = "test"; optional = Some 42; nullable = None } in
157198158199 (* JSON roundtrip *)
159159- let json_result = Result.bind
160160- (Jsont_bytesrw.encode_string M.data_codec original)
161161- (Jsont_bytesrw.decode_string M.data_codec) in
200200+ let json_result =
201201+ Result.bind
202202+ (Jsont_bytesrw.encode_string M.data_codec original)
203203+ (Jsont_bytesrw.decode_string M.data_codec)
204204+ in
162205 (match json_result with
163163- | Ok decoded when M.equal original decoded -> Printf.printf "JSON optional roundtrip: PASS\n"
164164- | Ok _ -> Printf.printf "JSON optional roundtrip: FAIL (data mismatch)\n"
165165- | Error e -> Printf.printf "JSON optional roundtrip: FAIL (%s)\n" e);
206206+ | Ok decoded when M.equal original decoded ->
207207+ Printf.printf "JSON optional roundtrip: PASS\n"
208208+ | Ok _ -> Printf.printf "JSON optional roundtrip: FAIL (data mismatch)\n"
209209+ | Error e -> Printf.printf "JSON optional roundtrip: FAIL (%s)\n" e);
166210167211 (* YAML roundtrip *)
168168- let yaml_result = Result.bind
169169- (Yamlt.encode_string M.data_codec original)
170170- (Yamlt.decode_string M.data_codec) in
171171- (match yaml_result with
172172- | Ok decoded when M.equal original decoded -> Printf.printf "YAML optional roundtrip: PASS\n"
173173- | Ok _ -> Printf.printf "YAML optional roundtrip: FAIL (data mismatch)\n"
174174- | Error e -> Printf.printf "YAML optional roundtrip: FAIL (%s)\n" e)
212212+ let yaml_result =
213213+ Result.bind
214214+ (Yamlt.encode_string M.data_codec original)
215215+ (Yamlt.decode_string M.data_codec)
216216+ in
217217+ match yaml_result with
218218+ | Ok decoded when M.equal original decoded ->
219219+ Printf.printf "YAML optional roundtrip: PASS\n"
220220+ | Ok _ -> Printf.printf "YAML optional roundtrip: FAIL (data mismatch)\n"
221221+ | Error e -> Printf.printf "YAML optional roundtrip: FAIL (%s)\n" e
175222176223let () =
177224 let usage = "Usage: test_roundtrip <command>" in
···186233 | "array" -> test_array_roundtrip ()
187234 | "object" -> test_object_roundtrip ()
188235 | "optional" -> test_optional_roundtrip ()
189189-190236 | _ ->
191237 prerr_endline usage;
192238 prerr_endline "Commands:";
+80-93
tests/bin/test_scalars.ml
···11(*---------------------------------------------------------------------------
22- Copyright (c) 2024 The yamlrw programmers. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
5566(** Test scalar type resolution with Yamlt codec *)
77···121121 let result = Yamlt.decode_string number_codec yaml in
122122 match result with
123123 | Ok f ->
124124- if Float.is_nan f then
125125- Printf.printf "value: NaN\n"
126126- else if f = Float.infinity then
127127- Printf.printf "value: +Infinity\n"
128128- else if f = Float.neg_infinity then
129129- Printf.printf "value: -Infinity\n"
130130- else
131131- Printf.printf "value: %.17g\n" f
132132- | Error e ->
133133- Printf.printf "ERROR: %s\n" e
124124+ if Float.is_nan f then Printf.printf "value: NaN\n"
125125+ else if f = Float.infinity then Printf.printf "value: +Infinity\n"
126126+ else if f = Float.neg_infinity then Printf.printf "value: -Infinity\n"
127127+ else Printf.printf "value: %.17g\n" f
128128+ | Error e -> Printf.printf "ERROR: %s\n" e
134129135130(* Test: Type mismatch errors *)
136131let test_type_mismatch file expected_type =
137132 let yaml = read_file file in
138133139134 match expected_type with
140140- | "bool" ->
141141- let codec =
142142- Jsont.Object.map ~kind:"BoolTest" (fun b -> b)
143143- |> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
144144- |> Jsont.Object.finish
145145- in
146146- let result = Yamlt.decode_string codec yaml in
147147- (match result with
148148- | Ok _ -> Printf.printf "Unexpected success\n"
149149- | Error e -> Printf.printf "Expected error: %s\n" e)
150150- | "number" ->
151151- let codec =
152152- Jsont.Object.map ~kind:"NumberTest" (fun n -> n)
153153- |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
154154- |> Jsont.Object.finish
155155- in
156156- let result = Yamlt.decode_string codec yaml in
157157- (match result with
158158- | Ok _ -> Printf.printf "Unexpected success\n"
159159- | Error e -> Printf.printf "Expected error: %s\n" e)
160160- | "null" ->
161161- let codec =
162162- Jsont.Object.map ~kind:"NullTest" (fun n -> n)
163163- |> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
164164- |> Jsont.Object.finish
165165- in
166166- let result = Yamlt.decode_string codec yaml in
167167- (match result with
168168- | Ok _ -> Printf.printf "Unexpected success\n"
169169- | Error e -> Printf.printf "Expected error: %s\n" e)
170170- | _ -> failwith "unknown type"
135135+ | "bool" -> (
136136+ let codec =
137137+ Jsont.Object.map ~kind:"BoolTest" (fun b -> b)
138138+ |> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
139139+ |> Jsont.Object.finish
140140+ in
141141+ let result = Yamlt.decode_string codec yaml in
142142+ match result with
143143+ | Ok _ -> Printf.printf "Unexpected success\n"
144144+ | Error e -> Printf.printf "Expected error: %s\n" e)
145145+ | "number" -> (
146146+ let codec =
147147+ Jsont.Object.map ~kind:"NumberTest" (fun n -> n)
148148+ |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
149149+ |> Jsont.Object.finish
150150+ in
151151+ let result = Yamlt.decode_string codec yaml in
152152+ match result with
153153+ | Ok _ -> Printf.printf "Unexpected success\n"
154154+ | Error e -> Printf.printf "Expected error: %s\n" e)
155155+ | "null" -> (
156156+ let codec =
157157+ Jsont.Object.map ~kind:"NullTest" (fun n -> n)
158158+ |> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
159159+ |> Jsont.Object.finish
160160+ in
161161+ let result = Yamlt.decode_string codec yaml in
162162+ match result with
163163+ | Ok _ -> Printf.printf "Unexpected success\n"
164164+ | Error e -> Printf.printf "Expected error: %s\n" e)
165165+ | _ -> failwith "unknown type"
171166172167(* Test: Decode with Jsont.json to see auto-resolution *)
173168let test_any_resolution file =
···191186(* Test: Encoding to different formats *)
192187let test_encode_formats value_type value =
193188 match value_type with
194194- | "bool" ->
189189+ | "bool" -> (
195190 let codec =
196191 Jsont.Object.map ~kind:"BoolTest" (fun b -> b)
197192 |> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
···199194 in
200195 let v = bool_of_string value in
201196 (match Jsont_bytesrw.encode_string codec v with
202202- | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
203203- | Error e -> Printf.printf "JSON ERROR: %s\n" e);
197197+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
198198+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
204199 (match Yamlt.encode_string ~format:Yamlt.Block codec v with
205205- | Ok s -> Printf.printf "YAML Block:\n%s" s
206206- | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
207207- (match Yamlt.encode_string ~format:Yamlt.Flow codec v with
208208- | Ok s -> Printf.printf "YAML Flow: %s" s
209209- | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
210210- | "number" ->
200200+ | Ok s -> Printf.printf "YAML Block:\n%s" s
201201+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
202202+ match Yamlt.encode_string ~format:Yamlt.Flow codec v with
203203+ | Ok s -> Printf.printf "YAML Flow: %s" s
204204+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
205205+ | "number" -> (
211206 let codec =
212207 Jsont.Object.map ~kind:"NumberTest" (fun n -> n)
213208 |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
···215210 in
216211 let v = float_of_string value in
217212 (match Jsont_bytesrw.encode_string codec v with
218218- | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
219219- | Error e -> Printf.printf "JSON ERROR: %s\n" e);
213213+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
214214+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
220215 (match Yamlt.encode_string ~format:Yamlt.Block codec v with
221221- | Ok s -> Printf.printf "YAML Block:\n%s" s
222222- | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
223223- (match Yamlt.encode_string ~format:Yamlt.Flow codec v with
224224- | Ok s -> Printf.printf "YAML Flow: %s" s
225225- | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
226226- | "string" ->
216216+ | Ok s -> Printf.printf "YAML Block:\n%s" s
217217+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
218218+ match Yamlt.encode_string ~format:Yamlt.Flow codec v with
219219+ | Ok s -> Printf.printf "YAML Flow: %s" s
220220+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
221221+ | "string" -> (
227222 let codec =
228223 Jsont.Object.map ~kind:"StringTest" (fun s -> s)
229224 |> Jsont.Object.mem "value" Jsont.string ~enc:(fun s -> s)
···231226 in
232227 let v = value in
233228 (match Jsont_bytesrw.encode_string codec v with
234234- | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
235235- | Error e -> Printf.printf "JSON ERROR: %s\n" e);
229229+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
230230+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
236231 (match Yamlt.encode_string ~format:Yamlt.Block codec v with
237237- | Ok s -> Printf.printf "YAML Block:\n%s" s
238238- | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
239239- (match Yamlt.encode_string ~format:Yamlt.Flow codec v with
240240- | Ok s -> Printf.printf "YAML Flow: %s" s
241241- | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
242242- | "null" ->
232232+ | Ok s -> Printf.printf "YAML Block:\n%s" s
233233+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
234234+ match Yamlt.encode_string ~format:Yamlt.Flow codec v with
235235+ | Ok s -> Printf.printf "YAML Flow: %s" s
236236+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
237237+ | "null" -> (
243238 let codec =
244239 Jsont.Object.map ~kind:"NullTest" (fun n -> n)
245240 |> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
···247242 in
248243 let v = () in
249244 (match Jsont_bytesrw.encode_string codec v with
250250- | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
251251- | Error e -> Printf.printf "JSON ERROR: %s\n" e);
245245+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
246246+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
252247 (match Yamlt.encode_string ~format:Yamlt.Block codec v with
253253- | Ok s -> Printf.printf "YAML Block:\n%s" s
254254- | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
255255- (match Yamlt.encode_string ~format:Yamlt.Flow codec v with
256256- | Ok s -> Printf.printf "YAML Flow: %s" s
257257- | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
248248+ | Ok s -> Printf.printf "YAML Block:\n%s" s
249249+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
250250+ match Yamlt.encode_string ~format:Yamlt.Flow codec v with
251251+ | Ok s -> Printf.printf "YAML Flow: %s" s
252252+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
258253 | _ -> failwith "unknown type"
259254260255let () =
···266261 end;
267262268263 match Sys.argv.(1) with
269269- | "null" when Array.length Sys.argv = 3 ->
270270- test_null_resolution Sys.argv.(2)
271271-272272- | "bool" when Array.length Sys.argv = 3 ->
273273- test_bool_resolution Sys.argv.(2)
274274-264264+ | "null" when Array.length Sys.argv = 3 -> test_null_resolution Sys.argv.(2)
265265+ | "bool" when Array.length Sys.argv = 3 -> test_bool_resolution Sys.argv.(2)
275266 | "number" when Array.length Sys.argv = 3 ->
276267 test_number_resolution Sys.argv.(2)
277277-278268 | "string" when Array.length Sys.argv = 3 ->
279269 test_string_resolution Sys.argv.(2)
280280-281270 | "special-float" when Array.length Sys.argv = 3 ->
282271 test_special_floats Sys.argv.(2)
283283-284272 | "type-mismatch" when Array.length Sys.argv = 4 ->
285273 test_type_mismatch Sys.argv.(2) Sys.argv.(3)
286286-287287- | "any" when Array.length Sys.argv = 3 ->
288288- test_any_resolution Sys.argv.(2)
289289-274274+ | "any" when Array.length Sys.argv = 3 -> test_any_resolution Sys.argv.(2)
290275 | "encode" when Array.length Sys.argv = 4 ->
291276 test_encode_formats Sys.argv.(2) Sys.argv.(3)
292292-293277 | _ ->
294278 prerr_endline usage;
295279 prerr_endline "Commands:";
296280 prerr_endline " null <file> - Test null resolution";
297297- prerr_endline " bool <file> - Test bool vs string resolution";
281281+ prerr_endline
282282+ " bool <file> - Test bool vs string resolution";
298283 prerr_endline " number <file> - Test number resolution";
299284 prerr_endline " string <file> - Test string resolution";
300285 prerr_endline " special-float <file> - Test .inf, .nan, etc.";
301301- prerr_endline " type-mismatch <file> <type> - Test error on type mismatch";
302302- prerr_endline " any <file> - Test Jsont.any auto-resolution";
286286+ prerr_endline
287287+ " type-mismatch <file> <type> - Test error on type mismatch";
288288+ prerr_endline
289289+ " any <file> - Test Jsont.any auto-resolution";
303290 prerr_endline " encode <type> <value> - Test encoding to JSON/YAML";
304291 exit 1
+17-13
tests/bin/test_some_vs_option.ml
···22 (* Using Jsont.some like opt_mem does *)
33 let codec1 =
44 Jsont.Object.map ~kind:"Test" (fun arr -> arr)
55- |> Jsont.Object.mem "values" (Jsont.some (Jsont.array Jsont.string)) ~enc:(fun arr -> arr)
55+ |> Jsont.Object.mem "values"
66+ (Jsont.some (Jsont.array Jsont.string))
77+ ~enc:(fun arr -> arr)
68 |> Jsont.Object.finish
79 in
810···10121113 Printf.printf "Test 1: Jsont.some (Jsont.array) - like opt_mem:\n";
1214 (match Yamlt.decode_string codec1 yaml with
1313- | Ok arr ->
1414- (match arr with
1515- | None -> Printf.printf "Result: None\n"
1616- | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
1717- | Error e -> Printf.printf "Error: %s\n" e);
1515+ | Ok arr -> (
1616+ match arr with
1717+ | None -> Printf.printf "Result: None\n"
1818+ | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
1919+ | Error e -> Printf.printf "Error: %s\n" e);
18201921 (* Using Jsont.option *)
2022 let codec2 =
2123 Jsont.Object.map ~kind:"Test" (fun arr -> arr)
2222- |> Jsont.Object.mem "values" (Jsont.option (Jsont.array Jsont.string)) ~enc:(fun arr -> arr)
2424+ |> Jsont.Object.mem "values"
2525+ (Jsont.option (Jsont.array Jsont.string))
2626+ ~enc:(fun arr -> arr)
2327 |> Jsont.Object.finish
2428 in
25292630 Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n";
2727- (match Yamlt.decode_string codec2 yaml with
2828- | Ok arr ->
2929- (match arr with
3030- | None -> Printf.printf "Result: None\n"
3131- | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
3232- | Error e -> Printf.printf "Error: %s\n" e)
3131+ match Yamlt.decode_string codec2 yaml with
3232+ | Ok arr -> (
3333+ match arr with
3434+ | None -> Printf.printf "Result: None\n"
3535+ | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
3636+ | Error e -> Printf.printf "Error: %s\n" e
+5
yamlt.opam
···33synopsis: "YAML codec using Jsont type descriptions"
44description:
55 "Allows the same Jsont.t codec definitions to work for both JSON and YAML"
66+maintainer: ["Anil Madhavapeddy <anil@recoil.org>"]
77+authors: ["Anil Madhavapeddy"]
88+license: "ISC"
99+homepage: "https://tangled.org/@anil.recoil.org/ocaml-yamlt"
1010+bug-reports: "https://tangled.org/@anil.recoil.org/ocaml-yamlt/issues"
611depends: [
712 "dune" {>= "3.18"}
813 "ocaml" {>= "4.14.0"}