zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

absinthe.schema.json.ex (4214B)


      1 defmodule Mix.Tasks.Absinthe.Schema.Json do
      2   require Logger
      3   use Mix.Task
      4   import Mix.Generator
      5 
      6   @shortdoc "Generate a schema.json file for an Absinthe schema"
      7 
      8   @default_filename "./schema.json"
      9 
     10   @moduledoc """
     11   Generate a `schema.json` file
     12 
     13   ## Usage
     14 
     15       mix absinthe.schema.json [OPTIONS] [FILENAME]
     16 
     17   The JSON codec to be used needs to be included in your `mix.exs` dependencies. If using the default codec,
     18   see the Jason [installation instructions](https://hexdocs.pm/jason).
     19 
     20   ## Options
     21 
     22   * `--schema` - The name of the `Absinthe.Schema` module defining the schema to be generated.
     23      Default: As [configured](https://hexdocs.pm/mix/Mix.Config.html) for `:absinthe` `:schema`
     24   * `--json-codec` - Codec to use to generate the JSON file (see [Custom Codecs](#module-custom-codecs)).
     25      Default: [`Jason`](https://hexdocs.pm/jason/)
     26   * `--pretty` - Whether to pretty-print.
     27      Default: `false`
     28 
     29   ## Examples
     30 
     31   Write to default path `#{@default_filename}` using the `:schema` configured for the `:absinthe` application:
     32 
     33       mix absinthe.schema.json
     34 
     35   Write to default path `#{@default_filename}` using the `MySchema` schema:
     36 
     37       mix absinthe.schema.json --schema MySchema
     38 
     39   Write to path `/path/to/schema.json` using the `MySchema` schema, with pretty-printing:
     40 
     41       mix absinthe.schema.json --schema MySchema --pretty /path/to/schema.json
     42 
     43   Write to default path `#{@default_filename}` using the `MySchema` schema and a custom JSON codec, `MyCodec`:
     44 
     45       mix absinthe.schema.json --schema MySchema --json-codec MyCodec
     46 
     47 
     48   ## Custom Codecs
     49 
     50   Any module that provides `encode!/2` can be used as a custom codec:
     51 
     52       encode!(value, options)
     53 
     54   * `value` will be provided as a Map containing the generated schema.
     55   * `options` will be a keyword list with a `:pretty` boolean, indicating whether the user requested pretty-printing.
     56 
     57   The function should return a string to be written to the output file.
     58   """
     59 
     60   defmodule Options do
     61     @moduledoc false
     62 
     63     defstruct filename: nil, schema: nil, json_codec: nil, pretty: false
     64 
     65     @type t() :: %__MODULE__{
     66             filename: String.t(),
     67             schema: module(),
     68             json_codec: module(),
     69             pretty: boolean()
     70           }
     71   end
     72 
     73   @doc "Callback implementation for `Mix.Task.run/1`, which receives a list of command-line args."
     74   @spec run(argv :: [binary()]) :: any()
     75   def run(argv) do
     76     Application.ensure_all_started(:absinthe)
     77 
     78     Mix.Task.run("loadpaths", argv)
     79     Mix.Task.run("compile", argv)
     80 
     81     opts = parse_options(argv)
     82 
     83     case generate_schema(opts) do
     84       {:ok, content} -> write_schema(content, opts.filename)
     85       {:error, error} -> raise error
     86     end
     87   end
     88 
     89   @doc false
     90   @spec generate_schema(Options.t()) :: {:error, binary()} | {:ok, String.t()}
     91   def generate_schema(%Options{
     92         pretty: pretty,
     93         schema: schema,
     94         json_codec: json_codec
     95       }) do
     96     with {:ok, result} <- Absinthe.Schema.introspect(schema) do
     97       content = json_codec.encode!(result, pretty: pretty)
     98       {:ok, content}
     99     else
    100       {:error, reason} -> {:error, reason}
    101       error -> {:error, error}
    102     end
    103   end
    104 
    105   @doc false
    106   @spec parse_options([String.t()]) :: Options.t()
    107   def parse_options(argv) do
    108     parse_options = [strict: [schema: :string, json_codec: :string, pretty: :boolean]]
    109     {opts, args, _} = OptionParser.parse(argv, parse_options)
    110 
    111     %Options{
    112       filename: args |> List.first() || @default_filename,
    113       schema: find_schema(opts),
    114       json_codec: json_codec_as_atom(opts),
    115       pretty: Keyword.get(opts, :pretty, false)
    116     }
    117   end
    118 
    119   defp json_codec_as_atom(opts) do
    120     opts
    121     |> Keyword.fetch(:json_codec)
    122     |> case do
    123       {:ok, codec} -> Module.concat([codec])
    124       _ -> Jason
    125     end
    126   end
    127 
    128   defp find_schema(opts) do
    129     case Keyword.get(opts, :schema, Application.get_env(:absinthe, :schema)) do
    130       nil ->
    131         raise "No --schema given or :schema configured for the :absinthe application"
    132 
    133       value ->
    134         [value] |> Module.safe_concat()
    135     end
    136   end
    137 
    138   defp write_schema(content, filename) do
    139     create_directory(Path.dirname(filename))
    140     create_file(filename, content, force: true)
    141   end
    142 end