lib/open_api_spex/schemax/parser.ex

defmodule OpenApiSpex.Schemax.Parser do
  @moduledoc """
  This module is Parser for `OpenApiSpex.Schemax.schema/2` macro.

  In case of `:property`, this module converts camelCase fields
  of `OpenApiSpex.Schema` struct to snake_case fields.

  We will change this module to support more advanced parsing.
  """
  def parse_body({:__block__, _, lines}), do: parse_lines(lines)
  def parse_body(nil), do: parse_lines([])
  def parse_body(line), do: parse_lines([line])

  def parse_lines(lines) do
    Enum.map(lines, &parse_line(&1))
  end

  defp parse_line({:property, meta, [name, type]}) when is_atom(type),
    do: parse_line({:property, meta, [name, type, []]})

  defp parse_line({:property, _, [name, :array, opts]}) do
    items = opts[:items] || raise ArgumentError, "`:array` type must come with `:items` option"
    opts = Keyword.delete(opts, :items)
    {:property, {name, [type: :array] ++ opts, items}}
  end

  defp parse_line({:property, _, [name, type, opts]}) do
    {:property, {name, [type: type] ++ opts}}
  end

  defp parse_line({:property, _, [name, other]}) do
    {:property, {name, other}}
  end

  defp parse_line({:description, _, [description]}) do
    {:description, description}
  end

  defp parse_line({:schema_type, _, [type]}) do
    {:type, type}
  end

  defp parse_line({:read_only, _, [value]}) do
    {:readOnly, value}
  end

  defp parse_line({:additional_properties, _, [v]}) do
    {:additionalProperties, v}
  end

  defp parse_line({:all_of, _, [v]}) do
    {:allOf, v}
  end

  defp parse_line({:one_of, _, [v]}) do
    {:oneOf, v}
  end

  defp parse_line({:any_of, _, [v]}) do
    {:anyOf, v}
  end

  defp parse_line({:multiple_of, _, [v]}) do
    {:multipleOf, v}
  end

  defp parse_line({:max_items, _, [v]}) do
    {:maxItems, v}
  end

  defp parse_line({:min_items, _, [v]}) do
    {:minItems, v}
  end

  defp parse_line({:max_properties, _, [v]}) do
    {:maxProperties, v}
  end

  defp parse_line({:min_properties, _, [v]}) do
    {:minProperties, v}
  end

  defp parse_line({:exclusive_minimum, _, [v]}) do
    {:exclusiveMinimum, v}
  end

  defp parse_line({:exclusive_maximum, _, [v]}) do
    {:exclusiveMaximum, v}
  end

  defp parse_line({:max_length, _, [v]}) do
    {:maxLength, v}
  end

  defp parse_line({:min_length, _, [v]}) do
    {:minLength, v}
  end

  defp parse_line({:unique_items, _, [v]}) do
    {:uniqueItems, v}
  end

  defp parse_line({:external_docs, _, [v]}) do
    {:externalDocs, v}
  end

  defp parse_line({:validate, _, [v]}) do
    {:"x-validate", v}
  end

  defp parse_line({key, _, [value]}) do
    {key, value}
  end

  defp parse_line(other) do
    raise ArgumentError, "unknown field. #{inspect(other)}"
  end
end