defmodule OpenApiSpex.ExportSpec do
@moduledoc """
Export spec in specified encoding
"""
require Mix.Generator
defmodule Options do
@moduledoc false
defstruct filename: nil, spec: nil, pretty: false, vendor_extensions: true
end
def call(argv, encode_spec, default_filename) do
opts = parse_options(argv, default_filename)
opts
|> generate_spec()
|> encode_spec.(opts)
|> write_spec(opts.filename)
end
defp generate_spec(%{spec: spec, vendor_extensions: vendor_extensions}) do
case Code.ensure_compiled(spec) do
{:module, _} ->
if function_exported?(spec, :spec, 0) do
OpenApiSpex.OpenApi.to_map(spec.spec(), vendor_extensions: vendor_extensions)
else
Mix.raise(
"module #{inspect(spec)} is not a OpenApiSpex.Spec. " <>
"Please pass a spec with the --spec option."
)
end
{:error, error} ->
Mix.raise(
"could not load #{inspect(spec)}, error: #{inspect(error)}. " <>
"Please pass a spec with the --spec option."
)
end
end
defp parse_options(argv, default_filename) do
parse_options = [
strict: [spec: :string, endpoint: :string, pretty: :boolean, vendor_extensions: :boolean]
]
{opts, args, _} = OptionParser.parse(argv, parse_options)
%Options{
filename: args |> List.first() || default_filename,
spec: find_spec(opts),
pretty: Keyword.get(opts, :pretty, false),
vendor_extensions: Keyword.get(opts, :vendor_extensions, true)
}
end
defp write_spec(content, filename) do
case Path.dirname(filename) do
"." -> true
dir -> Mix.Generator.create_directory(dir)
end
Mix.Generator.create_file(filename, content, force: true)
end
defp find_spec(opts) do
if spec = Keyword.get(opts, :spec) do
Module.concat([spec])
else
Mix.raise("No spec available. Please pass a spec with the --spec option")
end
end
end