absinthe.schema.sdl.ex (2587B)
1 defmodule Mix.Tasks.Absinthe.Schema.Sdl do 2 use Mix.Task 3 import Mix.Generator 4 5 @shortdoc "Generate a schema.graphql file for an Absinthe schema" 6 7 @default_filename "./schema.graphql" 8 9 @moduledoc """ 10 Generate a `schema.graphql` file. 11 12 ## Usage 13 14 mix absinthe.schema.sdl [OPTIONS] [FILENAME] 15 16 ## Options 17 18 * `--schema` - The name of the `Absinthe.Schema` module defining the schema to be generated. 19 Default: As [configured](https://hexdocs.pm/mix/Mix.Config.html) for `:absinthe` `:schema` 20 21 ## Examples 22 23 Write to default path `#{@default_filename}` using the `:schema` configured for the `:absinthe` application: 24 25 mix absinthe.schema.sdl 26 27 Write to path `/path/to/schema.graphql` using the `MySchema` schema 28 29 mix absinthe.schema.sdl --schema MySchema /path/to/schema.graphql 30 31 """ 32 33 defmodule Options do 34 @moduledoc false 35 defstruct filename: nil, schema: nil 36 37 @type t() :: %__MODULE__{ 38 filename: String.t(), 39 schema: module() 40 } 41 end 42 43 @impl Mix.Task 44 def run(argv) do 45 Application.ensure_all_started(:absinthe) 46 47 Mix.Task.run("loadpaths", argv) 48 Mix.Task.run("compile", argv) 49 50 opts = parse_options(argv) 51 52 case generate_schema(opts) do 53 {:ok, content} -> write_schema(content, opts.filename) 54 {:error, error} -> raise error 55 end 56 end 57 58 def generate_schema(%Options{schema: schema}) do 59 pipeline = 60 schema 61 |> Absinthe.Pipeline.for_schema(prototype_schema: schema.__absinthe_prototype_schema__()) 62 |> Absinthe.Pipeline.upto({Absinthe.Phase.Schema.Validation.Result, pass: :final}) 63 |> Absinthe.Schema.apply_modifiers(schema) 64 65 with {:ok, blueprint, _phases} <- 66 Absinthe.Pipeline.run( 67 schema.__absinthe_blueprint__(), 68 pipeline 69 ) do 70 {:ok, inspect(blueprint, pretty: true)} 71 else 72 _ -> {:error, "Failed to render schema"} 73 end 74 end 75 76 defp write_schema(content, filename) do 77 create_directory(Path.dirname(filename)) 78 create_file(filename, content, force: true) 79 end 80 81 def parse_options(argv) do 82 {opts, args, _} = OptionParser.parse(argv, strict: [schema: :string]) 83 84 %Options{ 85 filename: args |> List.first() || @default_filename, 86 schema: find_schema(opts) 87 } 88 end 89 90 defp find_schema(opts) do 91 case Keyword.get(opts, :schema, Application.get_env(:absinthe, :schema)) do 92 nil -> 93 raise "No --schema given or :schema configured for the :absinthe application" 94 95 value -> 96 [value] |> Module.safe_concat() 97 end 98 end 99 end