Skip to content

Commit

Permalink
use anyOf insteaf of oneOf to encore variants
Browse files Browse the repository at this point in the history
To be compatible with openai's structured outputs requirements.
  • Loading branch information
Khady committed Sep 25, 2024
1 parent 46b18c5 commit b832a23
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 63 deletions.
36 changes: 21 additions & 15 deletions src/ppx_deriving_jsonschema.ml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ module Schema = struct

let oneOf ~loc values = [%expr `Assoc [ "oneOf", `List [%e elist ~loc values] ]]

let anyOf ~loc values = [%expr `Assoc [ "anyOf", `List [%e elist ~loc values] ]]

let array_ ~loc ?min_items ?max_items element_type =
let fields =
List.filter_map
Expand Down Expand Up @@ -100,28 +102,32 @@ module Schema = struct
end

let variant_as_string ~loc constrs =
Schema.oneOf ~loc
Schema.anyOf ~loc
(List.map
(function
| `Tag (name, _typs) -> Schema.const ~loc name
| `Inherit typ -> typ)
constrs)

let variant_as_array ~loc constrs = Schema.array_ ~loc ~min_items:1 ~max_items:1 (variant_as_string ~loc constrs)

let variant ~loc ~config values =
match config.variant_as_array with
| true -> variant_as_array ~loc values
| false -> variant_as_string ~loc values

let variant_with_payload ~loc constrs =
Schema.oneOf ~loc
let variant_as_array ~loc constrs =
Schema.anyOf ~loc
(List.map
(function
| `Tag (name, typs) -> Schema.tuple ~loc (Schema.const ~loc name :: typs)
| `Inherit typ -> typ)
constrs)

let variant ~loc ~config constrs =
Schema.anyOf ~loc
(List.map
(function
| `Inherit typ -> typ
| `Tag (name, typs) ->
match config.variant_as_array with
| true -> Schema.tuple ~loc (Schema.const ~loc name :: typs)
| false -> Schema.const ~loc name)
constrs)

let value_name_pattern ~loc type_name = ppat_var ~loc { txt = type_name ^ "_jsonschema"; loc }

let create_value ~loc name value =
Expand Down Expand Up @@ -174,7 +180,7 @@ let rec type_of_core ~loc ~config core_type =
(* todo: raise an error if encoding is as string and constructor has a payload *)
let v =
match config.variant_as_array with
| true -> variant_with_payload ~loc constrs
| true -> variant_as_array ~loc constrs
| false -> variant_as_string ~loc constrs
in
v
Expand Down Expand Up @@ -215,9 +221,9 @@ let object_ ~loc ~config fields =
"required", `List [%e elist ~loc required];
]]

let derive_jsonschema ~ctxt ast variant_as_array =
let derive_jsonschema ~ctxt ast flag_variant_as_array =
let loc = Expansion_context.Deriver.derived_item_loc ctxt in
let config = { variant_as_array } in
let config = { variant_as_array = flag_variant_as_array } in
match ast with
| _, [ { ptype_name = { txt = type_name; _ }; ptype_kind = Ptype_variant variants; _ } ] ->
let variants =
Expand All @@ -239,8 +245,8 @@ let derive_jsonschema ~ctxt ast variant_as_array =
in
let v =
(* todo: raise an error if encoding is as string and constructor has a payload *)
match variant_as_array with
| true -> variant_with_payload ~loc variants
match config.variant_as_array with
| true -> variant_as_array ~loc variants
| false -> variant_as_string ~loc variants
in
let jsonschema_expr = create_value ~loc type_name v in
Expand Down
32 changes: 16 additions & 16 deletions test/test.expected.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module Mod1 =
struct
let m_1_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "A"))];
`Assoc [("const", (`String "B"))]]))][@@warning "-32-39"]
Expand All @@ -27,7 +27,7 @@ module Mod1 =
struct
let m_2_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "C"))];
`Assoc [("const", (`String "D"))]]))][@@warning
Expand Down Expand Up @@ -58,7 +58,7 @@ include
struct
let kind_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "Success"))];
`Assoc [("const", (`String "Error"))];
Expand All @@ -73,7 +73,7 @@ include
struct
let kind_as_array_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc
[("type", (`String "array"));
Expand Down Expand Up @@ -103,7 +103,7 @@ include
struct
let poly_kind_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "Aaa"))];
`Assoc [("const", (`String "Bbb"))];
Expand All @@ -117,7 +117,7 @@ include
struct
let poly_kind_as_array_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc
[("type", (`String "array"));
Expand Down Expand Up @@ -149,7 +149,7 @@ include
struct
let poly_kind_with_payload_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "Aaa"))];
`Assoc [("const", (`String "Bbb"))];
Expand All @@ -164,7 +164,7 @@ include
struct
let poly_kind_with_payload_as_array_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc
[("type", (`String "array"));
Expand Down Expand Up @@ -207,7 +207,7 @@ include
struct
let poly_inherit_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "New_one"))];
`Assoc [("const", (`String "Second_one"))];
Expand All @@ -222,7 +222,7 @@ include
struct
let poly_inherit_as_array_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc
[("type", (`String "array"));
Expand Down Expand Up @@ -275,7 +275,7 @@ include
("maxLength", (`Int 1))]));
("t",
(`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "Foo"))];
`Assoc [("const", (`String "Bar"))];
Expand Down Expand Up @@ -419,7 +419,7 @@ type 'param2 poly2 =
include
struct
let poly2_jsonschema =
`Assoc [("oneOf", (`List [`Assoc [("const", (`String "C"))]]))]
`Assoc [("anyOf", (`List [`Assoc [("const", (`String "C"))]]))]
[@@warning "-32-39"]
end[@@ocaml.doc "@inline"][@@merlin.hide ]
let () = print_schema poly2_jsonschema
Expand All @@ -429,7 +429,7 @@ include
struct
let poly2_as_array_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc
[("type", (`String "array"));
Expand All @@ -453,7 +453,7 @@ include
(`List
[`Assoc [("type", (`String "integer"))];
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc [("const", (`String "A"))];
`Assoc [("const", (`String "second_cstr"))]]))]]));
Expand Down Expand Up @@ -576,7 +576,7 @@ include
struct
let variant_inline_record_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc
[("type", (`String "array"));
Expand Down Expand Up @@ -617,7 +617,7 @@ include
struct
let variant_with_payload_jsonschema =
`Assoc
[("oneOf",
[("anyOf",
(`List
[`Assoc
[("type", (`String "array"));
Expand Down
Loading

0 comments on commit b832a23

Please sign in to comment.