render.ex (5899B)
1 defmodule Absinthe.Language.Render do 2 @moduledoc false 3 import Inspect.Algebra 4 import Absinthe.Utils.Render 5 6 @line_width 120 7 8 def inspect(term, %{pretty: true}) do 9 term 10 |> render() 11 |> concat(line()) 12 |> format(@line_width) 13 |> to_string 14 end 15 16 def inspect(term, options) do 17 Inspect.Any.inspect(term, options) 18 end 19 20 defp render(bp) 21 22 defp render(%Absinthe.Language.Document{} = doc) do 23 doc.definitions |> Enum.map(&render/1) |> join([line(), line()]) 24 end 25 26 defp render(%Absinthe.Language.OperationDefinition{} = op) do 27 if op.shorthand do 28 concat(operation_definition(op), block(render_list(op.selection_set.selections))) 29 else 30 glue( 31 concat([to_string(op.operation), operation_definition(op)]), 32 block(render_list(op.selection_set.selections)) 33 ) 34 end 35 end 36 37 defp render(%Absinthe.Language.Field{} = field) do 38 case field.selection_set do 39 nil -> 40 field_definition(field) 41 42 selection_set -> 43 concat([ 44 field_definition(field), 45 " ", 46 block(render_list(selection_set.selections)) 47 ]) 48 end 49 end 50 51 defp render(%Absinthe.Language.VariableDefinition{} = variable_definition) do 52 concat([ 53 "$", 54 variable_definition.variable.name, 55 ": ", 56 render(variable_definition.type), 57 default_value(variable_definition) 58 ]) 59 end 60 61 defp render(%Absinthe.Language.NamedType{} = named_type) do 62 named_type.name 63 end 64 65 defp render(%Absinthe.Language.NonNullType{} = non_null) do 66 concat(render(non_null.type), "!") 67 end 68 69 defp render(%Absinthe.Language.Argument{} = argument) do 70 concat([argument.name, ": ", render(argument.value)]) 71 end 72 73 defp render(%Absinthe.Language.Directive{} = directive) do 74 concat([" @", directive.name, arguments(directive.arguments)]) 75 end 76 77 defp render(%Absinthe.Language.FragmentSpread{} = spread) do 78 concat(["...", spread.name, directives(spread.directives)]) 79 end 80 81 defp render(%Absinthe.Language.InlineFragment{} = fragment) do 82 concat([ 83 "...", 84 inline_fragment_name(fragment), 85 directives(fragment.directives), 86 " ", 87 block(render_list(fragment.selection_set.selections)) 88 ]) 89 end 90 91 defp render(%Absinthe.Language.Variable{} = variable) do 92 concat("$", variable.name) 93 end 94 95 defp render(%Absinthe.Language.StringValue{value: value}) do 96 render_string_value(value) 97 end 98 99 defp render(%Absinthe.Language.FloatValue{value: value}) do 100 "#{value}" 101 end 102 103 defp render(%Absinthe.Language.ObjectField{} = object_field) do 104 concat([object_field.name, ": ", render(object_field.value)]) 105 end 106 107 defp render(%Absinthe.Language.ObjectValue{fields: fields}) do 108 fields = fields |> Enum.map(&render(&1)) |> join(", ") 109 110 concat(["{ ", fields, " }"]) 111 end 112 113 defp render(%Absinthe.Language.NullValue{}) do 114 "null" 115 end 116 117 defp render(%Absinthe.Language.ListType{type: type}) do 118 concat(["[", render(type), "]"]) 119 end 120 121 defp render(%Absinthe.Language.ListValue{values: values}) do 122 values = values |> Enum.map(&render(&1)) |> join(", ") 123 124 concat(["[", values, "]"]) 125 end 126 127 defp render(%Absinthe.Language.Fragment{} = fragment) do 128 concat([ 129 "fragment ", 130 fragment.name, 131 " on ", 132 fragment.type_condition.name, 133 directives(fragment.directives) 134 ]) 135 |> block(render_list(fragment.selection_set.selections)) 136 end 137 138 defp render(%{value: value}) do 139 to_string(value) 140 end 141 142 defp operation_definition(%{name: nil} = op) do 143 case op.variable_definitions do 144 [] -> 145 concat( 146 variable_definitions(op.variable_definitions), 147 directives(op.directives) 148 ) 149 150 _ -> 151 operation_definition(%{op | name: ""}) 152 end 153 end 154 155 defp operation_definition(%{name: name} = op) do 156 concat([" ", name, variable_definitions(op.variable_definitions), directives(op.directives)]) 157 end 158 159 defp variable_definitions([]) do 160 empty() 161 end 162 163 defp variable_definitions(definitions) do 164 definitions = Enum.map(definitions, &render(&1)) 165 166 concat([ 167 "(", 168 join(definitions, ", "), 169 ")" 170 ]) 171 end 172 173 defp field_definition(field) do 174 concat([ 175 field_alias(field), 176 field.name, 177 arguments(field.arguments), 178 directives(field.directives) 179 ]) 180 end 181 182 defp default_value(%{default_value: nil}) do 183 empty() 184 end 185 186 defp default_value(%{default_value: value}) do 187 concat(" = ", render(value)) 188 end 189 190 defp directives([]) do 191 empty() 192 end 193 194 defp directives(directives) do 195 directives |> Enum.map(&render(&1)) |> join(" ") 196 end 197 198 defp inline_fragment_name(%{type_condition: nil}) do 199 empty() 200 end 201 202 defp inline_fragment_name(%{type_condition: %{name: name}}) do 203 " on #{name}" 204 end 205 206 defp field_alias(%{alias: nil}) do 207 empty() 208 end 209 210 defp field_alias(%{alias: alias}) do 211 concat(alias, ": ") 212 end 213 214 defp arguments([]) do 215 empty() 216 end 217 218 defp arguments(args) do 219 group( 220 glue( 221 nest( 222 glue( 223 "(", 224 "", 225 render_list(args, ", ") 226 ), 227 2, 228 :break 229 ), 230 "", 231 ")" 232 ) 233 ) 234 end 235 236 # Helpers 237 238 defp block(docs) do 239 do_block(docs) 240 end 241 242 defp block(:doc_nil, docs) do 243 do_block(docs) 244 end 245 246 defp block(name, docs) do 247 glue( 248 name, 249 do_block(docs) 250 ) 251 end 252 253 defp do_block(docs) do 254 group( 255 glue( 256 nest( 257 force_unfit( 258 glue( 259 "{", 260 "", 261 docs 262 ) 263 ), 264 2, 265 :always 266 ), 267 "", 268 "}" 269 ) 270 ) 271 end 272 273 defp render_list(items, separator \\ line()) do 274 List.foldr(items, :doc_nil, fn 275 item, :doc_nil -> render(item) 276 item, acc -> concat([render(item)] ++ [separator] ++ [acc]) 277 end) 278 end 279 end