package melange-json-native

  1. Overview
  2. Docs

Source file errors.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
exception Of_string_error of string

type of_json_error = Json_error of string | Unexpected_variant of string

exception Of_json_error of of_json_error

let with_buffer f =
  let buffer = Buffer.create 1 in
  f (Buffer.add_string buffer);
  Buffer.contents buffer

let iteri_last f li =
  let rec loop i li =
    match li with
    | [] -> ()
    | [ elt ] -> f ~is_last:true i elt
    | elt :: li ->
        f ~is_last:false i elt;
        loop (i + 1) li
  in
  loop 0 li

let show_json_type json =
  json |> Classify.classify |> function
  | `Assoc _ -> "object"
  | `Bool _ -> "bool"
  | `Float _ -> "float"
  | `Int _ -> "int"
  | `List _ -> "array"
  | `Null -> "null"
  | `String _ -> "string"

let show_json_error ?depth ?width json =
  with_buffer (fun emit ->
      let rec loop ?depth json =
        let json = Classify.classify json in
        let depth = Option.map (fun i -> i - 1) depth in
        match depth with
        | Some 0 -> emit "_"
        | _ -> (
            match json with
            | `Assoc assoc ->
                emit "{";
                iteri_last
                  (fun ~is_last i (k, v) ->
                    match width with
                    | Some width when i = width -> emit "..."
                    | Some width when i > width -> ()
                    | _ ->
                        emit {|"|};
                        emit k;
                        emit {|": |};
                        let depth = Option.map (fun i -> i - 1) depth in
                        loop ?depth v;
                        if not is_last then emit {|, |})
                  assoc;
                emit "}"
            | `Bool bool -> emit (if bool then "true" else "false")
            | `Float float -> emit (string_of_float float)
            | `Int int -> emit (string_of_int int)
            | `List li ->
                emit "[";
                iteri_last
                  (fun ~is_last i elt ->
                    match width with
                    | Some width when i = width -> emit "..."
                    | Some width when i > width -> ()
                    | _ ->
                        loop ?depth elt;
                        if not is_last then emit ", ")
                  li;
                emit "]"
            | `Null -> emit "null"
            | `String str -> (
                let len = String.length str in
                match width with
                | Some width
                  when len > (width * 2) + 5
                       (* I add 5 to account for the [" ... "] I am adding in that case *)
                  ->
                    emit {|"|};
                    emit (String.escaped (String.sub str 0 width));
                    emit " ... ";
                    emit {|"|}
                | _ ->
                    emit {|"|};
                    emit (String.escaped str);
                    emit {|"|}))
      in

      (loop ?depth:(Option.map (fun i -> i + 1) depth)) json)

let of_json_msg_error msg = raise (Of_json_error (Json_error msg))

let of_json_error ?(depth = 2) ?(width = 8) ~json msg =
  of_json_msg_error
    (with_buffer (fun emit ->
         emit msg;
         emit " but got ";
         emit (show_json_error ~depth ~width json)))

let of_json_msg_unexpected_variant msg = raise (Of_json_error (Unexpected_variant msg))

let of_json_unexpected_variant ?(depth = 2) ?(width = 8) ~json msg =
  of_json_msg_unexpected_variant
    (with_buffer (fun emit ->
         emit msg;
         emit " but got ";
         emit (show_json_error ~depth ~width json)))

(* only use for cases where we need granular handling of the error (e.g. arr)*)
let dangerous_of_json_error ?(depth = 2) ?(width = 8) ~json msg =
  of_json_msg_error
    (with_buffer (fun emit ->
         emit msg;
         emit " but got ";
         emit (show_json_error ~depth ~width json)))

let of_json_error_type_mismatch json expected =
  of_json_msg_error
    (with_buffer (fun emit ->
         emit "expected ";
         emit expected;
         emit " but got ";
         emit (show_json_type json);
         emit ": ";
         emit (show_json_error ~depth:2 ~width:8 json)))
OCaml

Innovation. Community. Security.