Packages
absinthe
1.4.13
1.11.0
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.8
1.6.7
retired
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.5.0-beta.2
1.5.0-beta.1
1.5.0-beta.0
1.5.0-alpha.4
1.5.0-alpha.3
1.5.0-alpha.2
1.5.0-alpha.1
1.5.0-alpha.0
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
retired
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.4.0-beta.5
1.4.0-beta.4
1.4.0-beta.3
1.4.0-beta.2
1.4.0-beta.1
1.3.2
1.3.1
1.3.0
1.3.0-rc.0
1.3.0-beta.2
1.3.0-beta.1
1.3.0-beta.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.2.0-beta.0
1.2.0-alpha0
1.2.0-alpha.2
1.2.0-alpha.1
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.2.3
0.2.2
0.2.1
0.1.0
GraphQL for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/absinthe/schema/notation/writer.ex
defmodule Absinthe.Schema.Notation.Writer do
@moduledoc false
defstruct [
:env,
type_map: %{},
directive_map: %{},
errors: [],
type_functions: [],
directive_functions: [],
exports: [],
implementors: %{}
]
defmacro __before_compile__(env) do
info = build_info(env)
errors = Macro.escape(info.errors)
exports = Macro.escape(info.exports)
type_map = Macro.escape(info.type_map)
implementors = Macro.escape(info.implementors)
directive_map = Macro.escape(info.directive_map)
[
quote do
def __absinthe_types__, do: unquote(type_map)
end,
info.type_functions,
quote do
def __absinthe_type__(_), do: nil
end,
quote do
def __absinthe_directives__, do: unquote(directive_map)
end,
info.directive_functions,
quote do
def __absinthe_directive__(_), do: nil
end,
quote do
def __absinthe_errors__, do: unquote(errors)
def __absinthe_interface_implementors__, do: unquote(implementors)
def __absinthe_exports__, do: unquote(exports)
end
]
end
defp init_implementors(nil) do
%{}
end
defp init_implementors(modules) do
modules
|> Enum.map(& &1.__absinthe_interface_implementors__)
|> Enum.reduce(%{}, fn implementors, acc ->
Map.merge(implementors, acc, fn _k, v1, v2 ->
v1 ++ v2
end)
end)
end
def build_info(env) do
implementors =
env.module
|> Module.get_attribute(:absinthe_imports)
|> init_implementors
descriptions =
env.module
|> Module.get_attribute(:absinthe_descriptions)
|> Map.new()
definitions =
env.module
|> Module.get_attribute(:absinthe_definitions)
|> Enum.map(&update_description(&1, descriptions))
{definitions, errors} =
{definitions, []}
|> Absinthe.Schema.Rule.FieldImportsExist.check()
|> Absinthe.Schema.Rule.NoCircularFieldImports.check()
info = %__MODULE__{
env: env,
errors: errors,
implementors: implementors
}
Enum.reduce(definitions, info, &do_build_info/2)
end
defp type_functions(definition) do
ast = build(:type, definition)
identifier = definition.identifier
name = definition.attrs[:name]
result = [
quote(do: def(__absinthe_type__(unquote(name)), do: __absinthe_type__(unquote(identifier))))
]
if definition.builder == Absinthe.Type.Object do
[
quote do
def __absinthe_type__(unquote(identifier)) do
unquote(ast)
end
end,
result
]
else
[
quote do
def __absinthe_type__(unquote(identifier)), do: unquote(ast)
end,
result
]
end
end
defp directive_functions(definition) do
ast = build(:directive, definition)
identifier = definition.identifier
name = definition.attrs[:name]
quote do
def __absinthe_directive__(unquote(identifier)), do: unquote(ast)
def __absinthe_directive__(unquote(name)), do: __absinthe_directive__(unquote(identifier))
end
end
# Type import reference
defp build(:type, %{source: source, builder: nil} = definition) do
quote bind_quoted: [source: source, identifier: definition.identifier] do
source.__absinthe_type__(identifier)
end
end
# Directive import reference
defp build(:directive, %{source: source, builder: nil} = definition) do
quote bind_quoted: [source: source, identifier: definition.identifier] do
source.__absinthe_directive__(identifier)
end
end
# Type/Directive definition
defp build(_, %{source: nil, builder: builder} = definition) do
builder.build(definition)
end
defp directive_name_error(definition) do
%{
rule: Absinthe.Schema.Rule.TypeNamesAreUnique,
location: %{file: definition.file, line: definition.line},
data: %{artifact: "Absinthe directive identifier", value: definition.identifier}
}
end
defp type_name_error(artifact, value, definition) do
%{
rule: Absinthe.Schema.Rule.TypeNamesAreUnique,
location: %{file: definition.file, line: definition.line},
data: %{artifact: artifact, value: value}
}
end
defp directive_errors(definition, state) do
case Map.has_key?(state.directive_map, definition.identifier) do
true ->
[directive_name_error(definition)]
false ->
[]
end
end
defp type_errors(definition, state) do
[
if Map.has_key?(state.type_map, definition.identifier) do
type_name_error("Absinthe type identifier", definition.identifier, definition)
end,
if Enum.member?(Map.values(state.type_map), definition.attrs[:name]) do
type_name_error("Type name", definition.attrs[:name], definition)
end
]
|> Enum.reject(&is_nil/1)
end
defp update_description(definition, descriptions) do
case Map.get(descriptions, definition.identifier) do
nil -> definition
desc -> Map.update!(definition, :attrs, &Keyword.put(&1, :description, desc))
end
end
defp do_build_info(%{category: :directive} = definition, info) do
errors = directive_errors(definition, info)
info
|> update_directive_map(definition)
|> update_directive_functions(definition, errors)
|> update_exports(definition)
|> update_errors(errors)
end
defp do_build_info(%{category: :type} = definition, info) do
errors = type_errors(definition, info)
info
|> update_type_map(definition)
|> update_type_functions(definition, errors)
|> update_implementors(definition)
|> update_exports(definition)
|> update_errors(errors)
end
defp update_directive_map(info, definition) do
Map.update!(
info,
:directive_map,
&Map.put(&1, definition.identifier, definition.attrs[:name])
)
end
defp update_directive_functions(info, definition, []) do
Map.update!(info, :directive_functions, &[directive_functions(definition) | &1])
end
defp update_type_map(info, definition) do
Map.update!(info, :type_map, &Map.put(&1, definition.identifier, definition.attrs[:name]))
end
defp update_type_functions(info, definition, []) do
Map.update!(info, :type_functions, &[type_functions(definition) | &1])
end
defp update_type_functions(info, _definition, _errors), do: info
defp update_implementors(info, definition) do
implementors =
definition.attrs[:interfaces]
|> List.wrap()
|> Enum.reduce(info.implementors, fn iface, implementors ->
Map.update(implementors, iface, [definition.identifier], &[definition.identifier | &1])
end)
%{info | implementors: implementors}
end
defp update_exports(info, definition) do
exports =
if Keyword.get(definition.opts, :export, definition.source != Absinthe.Type.BuiltIns) do
[definition.identifier | info.exports]
else
info.exports
end
%{info | exports: exports}
end
defp update_errors(info, errors) do
%{info | errors: errors ++ info.errors}
end
end