defmodule AbsintheSortingCodec do @moduledoc """ Convert the JSON output of an introspection query into deterministic JSON with types ordered alphabetically. ## Example ``` AbsintheSortingCodec.encode!(Jason.decode!("swapi.json")) ``` Can be used to convert an Absinthe schema to a sorted, deterministic ordering by using AbsintheSortingCodec as the JSON encoder. ## Example ```bash mix absinthe.schema.json --schema MySchema --json-codec AbsintheSortingCodec --pretty true ``` """ @doc """ Generates a JSON GraphQL schema in a deterministic format, with lists of objects sorted by their `name` property, if they have one. `schema` is the Elixir representation of the JSON result of an introspection query (as generated by Absinthe). Uses [Jason](https://github.com/michalmuskala/jason) for encoding into JSON. """ def encode(schema, opts \\ []) do schema |> sorted_objects() |> Jason.encode(opts) end def encode!(schema, opts \\ []) do case encode(schema, opts) do {:ok, content} -> content {:error, reason} -> raise reason end end defp sorted_objects(value) defp sorted_objects(map) when is_map(map) do for {key, val} <- map, into: %{}, do: {key, sorted_objects(val)} end defp sorted_objects(list) when is_list(list) do list |> Enum.sort_by(&list_sorting_value/1) |> Enum.map(&sorted_objects/1) end defp sorted_objects(value), do: value defp list_sorting_value(%{name: name}), do: name defp list_sorting_value(%{"name" => name}), do: name defp list_sorting_value(value), do: value end