Current section
Files
Jump to
Current section
Files
lib/open_api/generator/typing.ex
defmodule OpenAPI.Generator.Typing do
@moduledoc false
alias OpenAPI.Generator.Naming
alias OpenAPI.Spec
@typedoc "Runtime type annotation"
@type t ::
:binary
| :boolean
| :integer
| :map
| :number
| :string
| :null
| :unknown
| {:array, t}
| {:union, [t]}
| {:nullable, t}
| {module, atom}
@doc """
Determine the runtime type annotation of the given `schema`.
## Options
* `:original`: When `true`, the original module and type will be returned for named schemas.
This can be useful if the caller does not need to process merge, ignore, and group settings.
Defaults to `false`.
"""
@spec schema_to_type(State.t(), Spec.Schema.t(), keyword) :: t
def schema_to_type(state, schema, opts \\ [])
def schema_to_type(_state, %Spec.Schema{type: "boolean"}, _opts), do: :boolean
def schema_to_type(_state, %Spec.Schema{type: "integer"}, _opts), do: :integer
def schema_to_type(_state, %Spec.Schema{type: "number"}, _opts), do: :number
def schema_to_type(_state, %Spec.Schema{type: "string"}, _opts), do: :string
def schema_to_type(_state, %Spec.Schema{type: "null"}, _opts), do: :null
def schema_to_type(state, %Spec.Schema{type: "array", items: items}, opts) do
{:array, schema_to_type(state, items, opts)}
end
def schema_to_type(state, %Spec.Schema{type: types} = schema, opts) when is_list(types) do
nullable? = Enum.any?(types, &(&1 == "null"))
union =
types
|> Enum.reject(&(&1 == "null"))
|> Enum.map(fn type ->
schema_to_type(state, %Spec.Schema{schema | type: type}, opts)
end)
cond do
nullable? and length(union) == 0 -> :null
not nullable? and length(union) == 1 -> List.first(union)
nullable? and length(union) == 1 -> {:nullable, List.first(union)}
not nullable? -> {:union, union}
nullable? -> {:nullable, {:union, union}}
end
end
def schema_to_type(state, %Spec.Schema{any_of: any_of}, opts) when is_list(any_of) do
types = Enum.map(any_of, &schema_to_type(state, &1, opts)) |> Enum.uniq()
nullable? = Enum.any?(types, &(&1 == :null))
union = Enum.reject(types, &(&1 == :null))
cond do
not nullable? and length(union) == 1 -> List.first(union)
nullable? and length(union) == 1 -> {:nullable, List.first(union)}
not nullable? -> {:union, union}
nullable? -> {:nullable, {:union, union}}
end
end
def schema_to_type(state, %Spec.Schema{one_of: one_of}, opts) when is_list(one_of) do
types = Enum.map(one_of, &schema_to_type(state, &1, opts)) |> Enum.uniq()
nullable? = Enum.any?(types, &(&1 == :null))
union = Enum.reject(types, &(&1 == :null))
cond do
not nullable? and length(union) == 1 -> List.first(union)
nullable? and length(union) == 1 -> {:nullable, List.first(union)}
not nullable? -> {:union, union}
nullable? -> {:nullable, {:union, union}}
end
end
def schema_to_type(state, %Spec.Schema{type: "object"} = schema, opts) do
if opts[:original] do
Naming.original_name(schema)
else
Naming.referenced_name(state, schema)
end
|> case do
{name, type} -> {Module.concat(state.config.base_module, name), type}
_else -> :map
end
end
def schema_to_type(_state, %Spec.Schema{type: nil, properties: props}, _opts)
when is_map(props) do
:map
end
def schema_to_type(_state, %Spec.Schema{type: nil}, _opts), do: :unknown
end