defmodule OpenAPI.Spec.Path.Parameter do @moduledoc "Raw path parameter from the OpenAPI spec" import OpenAPI.Reader.State alias OpenAPI.Spec alias OpenAPI.Spec.Schema alias OpenAPI.Spec.Schema.Example alias OpenAPI.Spec.Schema.Media @type t :: %__MODULE__{ name: String.t(), in: String.t(), description: String.t() | nil, required: boolean, deprecated: boolean, allow_empty_value: boolean, style: String.t() | nil, explode: boolean, allow_reserved: boolean, schema: Schema.t() | Spec.ref() | nil, example: any, examples: %{optional(String.t()) => Example.t()}, content: %{optional(String.t()) => Media.t()} } defstruct [ :name, :in, :description, :required, :deprecated, :allow_empty_value, :style, :explode, :allow_reserved, :schema, :example, :examples, :content ] @doc false @spec decode(map, map) :: {map, t} def decode(state, yaml) do {state, content} = decode_content(state, yaml) {state, examples} = decode_examples(state, yaml) {state, schema} = decode_schema(state, yaml) parameter = %__MODULE__{ name: Map.fetch!(yaml, "name"), in: Map.fetch!(yaml, "in"), description: Map.get(yaml, "description"), required: Map.get(yaml, "required", false), deprecated: Map.get(yaml, "deprecated", false), allow_empty_value: Map.get(yaml, "allowEmptyValue", false), style: Map.get(yaml, "style"), explode: Map.get(yaml, "explode"), allow_reserved: Map.get(yaml, "allowReserved", false), schema: schema, example: Map.get(yaml, "example"), examples: examples, content: content } |> default_style() |> default_explode() {state, parameter} end defp default_style(%__MODULE__{in: "query", style: nil} = spec), do: %{spec | style: "form"} defp default_style(%__MODULE__{in: "path", style: nil} = spec), do: %{spec | style: "simple"} defp default_style(%__MODULE__{in: "header", style: nil} = spec), do: %{spec | style: "simple"} defp default_style(%__MODULE__{in: "cookie", style: nil} = spec), do: %{spec | style: "form"} defp default_style(spec), do: spec defp default_explode(%__MODULE__{style: "form", explode: nil} = spec), do: %{spec | explode: true} defp default_explode(%__MODULE__{explode: nil} = spec), do: %{spec | explode: false} defp default_explode(spec), do: %{spec | explode: false} @spec decode_content(map, map) :: {map, %{optional(String.t()) => Media.t()}} def decode_content(state, %{"content" => content}) do with_path(state, content, "content", fn state, content -> Enum.reduce(content, {state, %{}}, fn {key, content_item}, {state, content} -> {state, content_item} = with_path(state, content_item, key, fn state, content_item -> with_ref(state, content_item, &Media.decode/2) end) {state, Map.put(content, key, content_item)} end) end) end def decode_content(state, _yaml), do: {state, %{}} @spec decode_examples(map, map) :: {map, %{optional(String.t()) => Example.t()}} def decode_examples(state, %{"examples" => examples}) do with_path(state, examples, "examples", fn state, examples -> Enum.reduce(examples, {state, %{}}, fn {key, example}, {state, examples} -> {state, example} = with_path(state, example, key, fn state, example -> with_ref(state, example, &Example.decode/2) end) {state, Map.put(examples, key, example)} end) end) end def decode_examples(state, _yaml), do: {state, %{}} @spec decode_schema(map, map) :: {map, Schema.t() | nil} def decode_schema(state, %{"schema" => schema}) do with_path(state, schema, "schema", fn state, schema -> with_schema_ref(state, schema, &Schema.decode/2) end) end def decode_schema(state, _yaml), do: {state, nil} end