···
|> then(&Recase.Enumerable.atomize_keys/1)
|> then(&Atex.Lexicon.Schema.lexicon!/1)
27
-
# TODO: support returning typedefs
|> Enum.flat_map(fn {def_name, def} -> def_to_schema(lexicon.id, def_name, def) end)
31
-
|> Enum.map(fn {schema_key, quoted_schema} ->
30
+
|> Enum.map(fn {schema_key, quoted_schema, quoted_type} ->
32
+
if schema_key === :main do
34
+
@type t() :: unquote(quoted_type)
39
+
@type unquote(schema_key)() :: unquote(quoted_type)
40
+
unquote(identity_type)
defschema unquote(schema_key), unquote(quoted_schema)
···
44
-
# TODO: generate typedefs
@spec def_to_schema(nsid :: String.t(), def_name :: String.t(), lexicon_def :: map()) ::
46
-
list({key :: atom(), quoted :: term()})
54
+
list({key :: atom(), quoted_schema :: term(), quoted_type :: term()})
defp def_to_schema(nsid, def_name, %{type: "record", record: record}) do
# TODO: record rkey format validator
def_to_schema(nsid, def_name, record)
61
+
# TODO: add `$type` field. It's just a string though.
···
|> Enum.map(fn {key, field} ->
66
-
field_to_schema(field, nsid)
68
-
&if key in nullable, do: quote(do: {:either, {{:literal, nil}, unquote(&1)}}), else: &1
70
-
|> then(&if key in required, do: quote(do: {:required, unquote(&1)}), else: &1)
75
+
{quoted_schema, quoted_type} = field_to_schema(field, nsid)
76
+
is_nullable = key in nullable
77
+
is_required = key in required
82
+
&if is_nullable, do: quote(do: {:either, {{:literal, nil}, unquote(&1)}}), else: &1
84
+
|> then(&if is_required, do: quote(do: {:required, unquote(&1)}), else: &1)
87
+
key_type = if is_required, do: :required, else: :optional
98
+
|> then(&{{key_type, [], [key]}, &1})
100
+
{quoted_schema, quoted_type}
102
+
|> Enum.reduce({[], []}, fn {quoted_schema, quoted_type}, {schemas, types} ->
103
+
{[quoted_schema | schemas], [quoted_type | types]}
73
-
|> then(&{:%{}, [], &1})
74
-
|> then(&[{atomise(def_name), &1}])
105
+
|> then(fn {quoted_schemas, quoted_types} ->
106
+
[{atomise(def_name), {:%{}, [], quoted_schemas}, {:%{}, [], quoted_types}}]
# TODO: validating errors?
···
defp def_to_schema(_nsid, def_name, %{type: "token"}) do
# TODO: make it a validator that expects the nsid + key.
157
-
[{atomise(def_name), :string}]
defp def_to_schema(nsid, def_name, %{type: type} = def)
···
171
-
[{atomise(def_name), field_to_schema(def, nsid)}]
212
+
{quoted_schema, quoted_type} = field_to_schema(def, nsid)
213
+
[{atomise(def_name), quoted_schema, quoted_type}]
174
-
@spec field_to_schema(field_def :: %{type: String.t()}, nsid :: String.t()) :: Peri.schema_def()
216
+
@spec field_to_schema(field_def :: %{type: String.t()}, nsid :: String.t()) ::
217
+
{quoted_schema :: term(), quoted_typespec :: term()}
defp field_to_schema(%{type: "string"} = field, _nsid) do
fixed_schema = const_or_enum(field)
···
|> Enum.map(fn {k, v} -> {Recase.to_snake(k), v} end)
|> then(&{:custom, {Validators.String, :validate, [&1]}})
192
-
|> then(&Macro.escape/1)
236
+
&{Macro.escape(&1),
defp field_to_schema(%{type: "boolean"} = field, _nsid) do
(const(field) || :boolean)
199
-
|> then(&Macro.escape/1)
248
+
&{Macro.escape(&1),
defp field_to_schema(%{type: "integer"} = field, _nsid) do
···
|> then(&{:custom, {Validators.Integer, [&1]}})
214
-
|> then(&Macro.escape/1)
270
+
# TODO: turn into range definition based on maximum/minimum
defp field_to_schema(%{type: "array", items: items} = field, nsid) do
218
-
inner_schema = field_to_schema(items, nsid)
279
+
{inner_schema, inner_type} = field_to_schema(items, nsid)
|> Map.take([:maxLength, :minLength])
···
{inner_schema, _} = Code.eval_quoted(quoted_inner_schema)
{:custom, {:{}, c, [Validators.Array, :validate, [inner_schema | args]]}}
295
+
list(unquote(inner_type))
defp field_to_schema(%{type: "blob"} = field, _nsid) do
···
|> Map.take([:accept, :maxSize])
|> Enum.map(fn {k, v} -> {Recase.to_snake(k), v} end)
238
-
|> then(&Macro.escape/1)
306
+
&{Macro.escape(&1),
defp field_to_schema(%{type: "bytes"} = field, _nsid) do
···
|> Map.take([:maxLength, :minLength])
|> Enum.map(fn {k, v} -> {Recase.to_snake(k), v} end)
246
-
|> then(&Macro.escape/1)
319
+
&{Macro.escape(&1),
defp field_to_schema(%{type: "cid-link"}, _nsid) do
251
-
|> then(&Macro.escape/1)
329
+
&{Macro.escape(&1),
331
+
Validators.cid_link()
# TODO: do i need to make sure these two deal with brands? Check objects in atp.tools
···
|> Atex.NSID.expand_possible_fragment_shorthand(ref)
|> Atex.NSID.to_atom_with_fragment()
262
-
unquote(nsid).get_schema(unquote(fragment))
344
+
unquote(nsid).get_schema(unquote(fragment))
347
+
unquote(nsid).unquote(fragment)()
defp field_to_schema(%{type: "union", refs: refs}, nsid) do
···
|> Atex.NSID.expand_possible_fragment_shorthand(ref)
|> Atex.NSID.to_atom_with_fragment()
276
-
unquote(nsid).get_schema(unquote(fragment))
360
+
unquote(nsid).get_schema(unquote(fragment))
363
+
unquote(nsid).unquote(fragment)()
281
-
{:oneof, unquote(&1)}
366
+
|> Enum.reduce({[], []}, fn {quoted_schema, quoted_type}, {schemas, types} ->
367
+
{[quoted_schema | schemas], [quoted_type | types]}
369
+
|> then(fn {schemaa, types} ->
371
+
{:oneof, unquote(schemaa)}
374
+
unquote(join_with_pipe(types))
# TODO: apparently should be a data object, not a primitive?
defp field_to_schema(%{type: "unknown"}, _nsid) do
291
-
defp field_to_schema(_field_def, _nsid), do: nil
387
+
defp field_to_schema(_field_def, _nsid), do: {nil, nil}
defp maybe_default(schema, field) do
if field[:default] != nil,
···
defp atomise(x) when is_atom(x), do: x
defp atomise(x) when is_binary(x), do: String.to_atom(x)
406
+
defp join_with_pipe(list) when is_list(list) do
407
+
[piped] = do_join_with_pipe(list)
411
+
defp do_join_with_pipe([head]), do: [head]
412
+
defp do_join_with_pipe([head | tail]), do: [{:|, [], [head | do_join_with_pipe(tail)]}]
413
+
defp do_join_with_pipe([]), do: []