Packages
ash
1.52.0-rc.15
3.29.3
3.29.2
3.29.1
3.29.0
3.28.0
3.27.8
3.27.7
3.27.6
3.27.5
3.27.4
3.27.3
3.27.2
3.27.1
3.27.0
3.26.0
3.25.2
3.25.1
3.25.0
retired
3.24.7
3.24.6
3.24.5
3.24.4
3.24.3
3.24.2
3.24.1
3.24.0
3.23.1
3.23.0
3.22.2
3.22.1
3.22.0
3.21.3
3.21.2
3.21.1
3.21.0
3.20.0
3.19.3
3.19.2
3.19.1
3.19.0
3.18.0
3.17.1
3.17.0
3.16.0
3.15.0
3.14.1
3.14.0
retired
3.13.2
3.13.1
3.13.0
3.12.0
3.11.3
3.11.2
3.11.1
3.11.0
3.10.1
3.10.0
3.9.0
3.8.0
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
retired
3.6.3
retired
3.6.2
3.6.1
3.6.0
3.5.43
3.5.42
3.5.41
3.5.40
3.5.39
3.5.38
3.5.37
3.5.36
3.5.35
3.5.34
3.5.33
3.5.32
3.5.31
3.5.30
3.5.29
3.5.28
3.5.27
3.5.26
3.5.25
3.5.24
3.5.23
3.5.22
3.5.21
3.5.20
3.5.19
3.5.18
3.5.17
3.5.16
3.5.15
3.5.14
3.5.13
3.5.12
3.5.11
3.5.10
3.5.9
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.4.74
retired
3.4.73
3.4.72
3.4.71
3.4.70
3.4.69
3.4.68
3.4.67
3.4.66
3.4.65
3.4.64
3.4.63
3.4.62
3.4.61
3.4.60
3.4.59
3.4.58
3.4.57
3.4.56
3.4.55
3.4.54
3.4.53
3.4.52
3.4.51
3.4.50
3.4.49
3.4.48
3.4.47
3.4.46
3.4.45
3.4.44
3.4.43
3.4.42
3.4.41
3.4.40
3.4.39
3.4.38
3.4.37
3.4.36
3.4.35
3.4.34
3.4.33
3.4.32
3.4.31
3.4.30
3.4.29
3.4.28
3.4.27
3.4.26
3.4.25
3.4.24
3.4.23
3.4.22
3.4.21
3.4.20
3.4.19
3.4.18
3.4.17
3.4.16
3.4.15
3.4.14
3.4.13
3.4.12
3.4.11
3.4.10
3.4.9
3.4.8
3.4.7
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.3
3.3.2
3.3.1
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.16
3.0.15
3.0.14
3.0.13
3.0.12
3.0.11
3.0.10
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.46
3.0.0-rc.45
3.0.0-rc.44
3.0.0-rc.43
3.0.0-rc.42
3.0.0-rc.41
3.0.0-rc.40
3.0.0-rc.39
3.0.0-rc.38
3.0.0-rc.37
3.0.0-rc.36
3.0.0-rc.35
3.0.0-rc.34
3.0.0-rc.33
3.0.0-rc.32
3.0.0-rc.31
3.0.0-rc.29
3.0.0-rc.28
3.0.0-rc.27
3.0.0-rc.26
3.0.0-rc.25
3.0.0-rc.24
3.0.0-rc.23
3.0.0-rc.22
3.0.0-rc.21
3.0.0-rc.20
3.0.0-rc.19
3.0.0-rc.18
3.0.0-rc.17
3.0.0-rc.16
3.0.0-rc.15
3.0.0-rc.14
3.0.0-rc.13
3.0.0-rc.12
3.0.0-rc.11
3.0.0-rc.10
3.0.0-rc.9
3.0.0-rc.8
3.0.0-rc.7
3.0.0-rc.6
3.0.0-rc.5
3.0.0-rc.4
3.0.0-rc.3
3.0.0-rc.1
3.0.0-rc.0
2.21.15
2.21.14
2.21.13
2.21.12
2.21.11
2.21.10
2.21.9
2.21.8
2.21.7
2.21.6
2.21.5
2.21.4
2.21.3
2.21.2
2.21.1
2.21.0
2.20.3
2.20.2
2.20.1
2.20.0
2.19.14
2.19.13
2.19.12
2.19.11
2.19.10
2.19.9
2.19.8
2.19.7
2.19.6
2.19.5
2.19.4
2.19.3
retired
2.19.2
retired
2.19.1
retired
2.19.0
retired
2.18.2
2.18.1
2.18.0
2.17.24
2.17.23
2.17.22
2.17.21
2.17.20
2.17.19
2.17.18
2.17.17
2.17.16
2.17.15
2.17.14
2.17.13
2.17.12
2.17.11
2.17.10
2.17.9
2.17.8
2.17.7
2.17.6
2.17.5
2.17.4
2.17.3
2.17.2
2.17.1
2.17.0
2.16.1
2.16.0
2.15.20
2.15.19
2.15.18
2.15.17
2.15.16
2.15.15
2.15.14
2.15.13
2.15.12
2.15.11
2.15.10
2.15.9
2.15.8
2.15.7
2.15.6
2.15.5
2.15.4
2.15.2
2.15.1
2.15.0
2.14.21
2.14.20
2.14.19
2.14.18
2.14.17
2.14.16
2.14.15
2.14.14
2.14.13
2.14.12
2.14.11
2.14.10
2.14.9
2.14.8
2.14.7
2.14.6
2.14.5
2.14.4
2.14.3
2.14.2
2.14.1
2.14.0
2.13.4
retired
2.13.3
2.13.2
2.13.1
2.13.0
2.12.1
2.12.0
2.11.11
2.11.10
2.11.9
2.11.8
2.11.7
2.11.6
2.11.5
2.11.4
2.11.3
2.11.2
2.11.1
2.11.0
2.11.0-rc.3
2.11.0-rc.2
2.11.0-rc.1
2.11.0-rc.0
2.10.2
2.10.1
2.10.0
2.9.29
2.9.28
2.9.27
2.9.26
2.9.25
2.9.24
2.9.23
2.9.22
2.9.21
2.9.20
2.9.19
2.9.18
2.9.17
2.9.16
2.9.15
2.9.14
2.9.13
2.9.12
2.9.11
2.9.10
2.9.9
2.9.8
2.9.7
2.9.6
2.9.5
2.9.4
2.9.3
2.9.2
2.9.1
2.9.0
2.8.1
2.8.0
2.7.1
2.7.0
2.6.31
2.6.30
2.6.29
2.6.28
2.6.27
2.6.26
2.6.25
2.6.24
2.6.23
2.6.22
2.6.21
2.6.20
2.6.19
2.6.18
2.6.17
2.6.16
2.6.15
2.6.14
2.6.13
2.6.11
2.6.10
2.6.9
2.6.8
2.6.7
2.6.6
2.6.5
2.6.4
2.6.3
2.6.2
2.6.1
2.6.0
2.5.16
2.5.15
2.5.14
2.5.13
2.5.12
2.5.11
2.5.10
2.5.9
2.5.8
2.5.7
2.5.6
2.5.5
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.5.0-rc.6
2.5.0-rc.5
2.5.0-rc.4
2.5.0-rc.3
2.5.0-rc.2
2.5.0-rc.1
2.5.0-rc.0
2.4.30
2.4.29
2.4.28
2.4.27
2.4.26
2.4.25
2.4.24
2.4.23
2.4.22
2.4.21
2.4.20
2.4.19
2.4.18
2.4.17
2.4.16
2.4.15
2.4.14
2.4.13
2.4.12
2.4.11
2.4.10
2.4.9
2.4.8
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
2.0.0-rc.15
2.0.0-rc.14
2.0.0-rc.13
2.0.0-rc.12
2.0.0-rc.11
2.0.0-rc.10
2.0.0-rc.9
2.0.0-rc.8
2.0.0-rc.7
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-pre.8
2.0.0-pre.7
2.0.0-pre.6
2.0.0-pre.5
2.0.0-pre.4
2.0.0-pre.3
2.0.0-pre.2
2.0.0-pre.1
2.0.0-pre.0
1.53.3
1.53.2
1.53.0
1.52.0-rc.22
1.52.0-rc.21
1.52.0-rc.20
1.52.0-rc.19
1.52.0-rc.18
1.52.0-rc.17
1.52.0-rc.16
1.52.0-rc.15
1.52.0-rc.14
1.52.0-rc.13
1.52.0-rc.12
1.52.0-rc.11
1.52.0-rc.10
1.52.0-rc.9
1.52.0-rc.8
1.52.0-rc.7
1.52.0-rc.6
1.52.0-rc.5
1.52.0-rc.4
1.52.0-rc.3
1.52.0-rc.2
1.52.0-rc.1
1.52.0-rc.0
1.51.2
1.51.1
retired
1.51.0
1.50.21
1.50.20
1.50.19
1.50.18
1.50.17
1.50.16
1.50.15
1.50.14
1.50.13
1.50.12
1.50.11
1.50.10
1.50.9
1.50.8
1.50.7
1.50.6
1.50.5
1.50.4
1.50.3
1.50.2
1.50.1
1.50.0
1.49.0
1.48.0-rc.30
1.48.0-rc.29
1.48.0-rc.28
1.48.0-rc.27
1.48.0-rc.26
1.48.0-rc.25
1.48.0-rc.24
1.48.0-rc.23
1.48.0-rc.22
1.48.0-rc.21
1.48.0-rc.20
1.48.0-rc.19
1.48.0-rc.18
1.48.0-rc.17
1.48.0-rc.16
1.48.0-rc.15
1.48.0-rc.14
1.48.0-rc.13
1.48.0-rc.12
1.48.0-rc.11
1.48.0-rc.10
1.48.0-rc.9
1.48.0-rc.8
1.48.0-rc.7
1.48.0-rc.6
1.48.0-rc.5
1.48.0-rc.4
1.48.0-rc.3
1.48.0-rc.2
1.48.0-rc.1
1.48.0-rc.0
1.47.12
1.47.11
1.47.10
1.47.9
1.47.8
1.47.7
1.47.6
1.47.5
1.47.4
1.47.3
1.47.2
1.47.1
1.47.0
1.46.13
1.46.12
1.46.11
1.46.10
1.46.9
1.46.8
1.46.7
1.46.6
1.46.5
1.46.4
1.46.3
1.46.2
1.46.1
1.46.0
1.45.0-rc9
1.45.0-rc8
1.45.0-rc7
1.45.0-rc6
1.45.0-rc5
1.45.0-rc4
1.45.0-rc3
1.45.0-rc20
1.45.0-rc2
1.45.0-rc19
1.45.0-rc18
1.45.0-rc17
1.45.0-rc16
1.45.0-rc15
1.45.0-rc14
1.45.0-rc13
1.45.0-rc12
1.45.0-rc11
1.45.0-rc10
1.45.0-rc1
1.45.0-rc0
1.44.13
1.44.12
1.44.11
1.44.10
1.44.9
1.44.8
1.44.7
1.44.6
1.44.5
1.44.4
1.44.3
1.44.2
1.44.1
1.44.0
1.43.12
1.43.11
1.43.10
1.43.9
1.43.8
1.43.7
1.43.6
1.43.5
1.43.4
1.43.3
1.43.2
1.43.1
1.43.0
1.42.0
1.41.12
1.41.11
1.41.10
1.41.9
1.41.8
1.41.7
1.41.6
1.41.5
1.41.4
1.41.3
1.41.2
1.41.1
1.41.0
1.40.0
1.39.7
1.39.6
1.39.5
1.39.4
1.39.3
1.39.2
1.39.1
1.39.0
1.38.0
1.37.2
1.37.1
1.37.0
1.36.22
1.36.21
1.36.19
1.36.18
1.36.17
1.36.16
1.36.15
1.36.14
1.36.13
1.36.12
1.36.11
1.36.10
1.36.9
1.36.8
1.36.7
1.36.6
1.36.5
1.36.4
1.36.3
1.36.2
1.36.0
1.35.1
1.35.0
1.34.9
1.34.8
1.34.7
1.34.6
1.34.5
1.34.4
1.34.3
1.34.2
1.34.1
1.34.0
1.33.0
1.32.2
1.32.1
1.32.0
1.31.1
1.31.0
1.30.2
1.30.1
1.29.0-rc1
1.29.0-rc0
1.28.1
1.28.0
1.27.1
1.27.0
1.26.13
1.26.12
1.26.11
1.26.10
1.26.9
1.26.8
1.26.7
1.26.6
1.26.5
1.26.4
1.26.2
1.26.1
1.26.0
1.25.8
1.25.7
1.25.6
1.25.5
1.25.4
1.25.3
1.25.2
1.25.1
1.25.0
1.24.2
1.24.1
1.24.0
1.23.3
1.23.2
1.23.1
1.23.0
1.22.1
1.22.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.1
1.18.0
1.17.1
1.17.0
1.16.2
1.15.1
1.15.0
1.14.0
1.13.4
1.13.3
1.13.2
1.13.1
1.13.0
1.12.0
1.11.1
1.11.0
1.10.0
1.9.0
1.8.0
1.7.0
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.1
1.4.0
1.3.1
1.3.0
1.2.1
1.2.0
1.1.3
1.1.2
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
0.13.1
0.13.0
0.12.0
0.10.0
0.9.1
0.9.0
0.8.0
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.9
0.1.8
0.1.3
0.1.1
0.1.0
A declarative, extensible framework for building Elixir applications.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash/elixir_sense/plugin.ex
if Code.ensure_loaded?(ElixirSense.Plugin) do
defmodule Ash.ElixirSense.Plugin do
@moduledoc false
@behaviour ElixirSense.Plugin
use ElixirSense.Providers.Suggestion.GenericReducer
alias Ash.ElixirSense.Resource
alias Ash.ElixirSense.Types
alias ElixirSense.Providers.Suggestion.Matcher
def suggestions(hint, {_, function_call, arg_index, info}, _chain, opts) do
option = info.option || get_option(opts.cursor_context.text_before)
if option do
get_suggestions(hint, opts, [function_call], {:value, option})
else
get_suggestions(hint, opts, [function_call], {:arg, arg_index})
end
end
def suggestions(hint, opts) do
option = get_section_option(opts.cursor_context.text_before)
if option do
get_suggestions(hint, opts, [], {:value, option})
else
get_suggestions(hint, opts)
end
end
def get_suggestions(hint, opts, opt_path \\ [], type \\ nil) do
with true <- Enum.any?(opts.env.attributes, &(&1.name == :ash_is)),
dsl_mod when not is_nil(dsl_mod) <-
Enum.find(opts.env.requires, &ash_extension?/1) do
extension_kinds =
List.flatten(dsl_mod.module_info[:attributes][:ash_extension_kinds] || [])
extensions = default_extensions(dsl_mod) ++ parse_extensions(opts, extension_kinds)
scopes_to_lines =
Enum.reduce(opts.buffer_metadata.lines_to_env, %{}, fn {line, env}, acc ->
line = line - 1
Map.update(acc, env.scope_id, line, fn existing ->
if existing < line do
existing
else
line
end
end)
end)
scope_path = get_scope_path(opts, scopes_to_lines, nil, opt_path)
case get_constructors(extensions, scope_path, hint, type) do
[] ->
:ignore
constructors ->
suggestions =
case find_option(constructors, type) do
{key, config} ->
option_values(key, config, hint, opts)
_ ->
# Check for an edge case where we are editing the first argument of a constructor
with {:value, option} <- type,
entity when not is_nil(entity) <-
find_building_entity(constructors, option),
[arg | _] <- entity.args,
config when not is_nil(config) <- entity.schema[arg] do
option_values(arg, config, hint, opts)
else
_ ->
hint =
case type do
{:value, val} when not is_nil(val) ->
to_string(val)
_ ->
nil
end
Enum.map(constructors, fn
{key, config} ->
option_suggestions(key, config, type)
%{__struct__: Ash.Dsl.Entity} = entity ->
entity_suggestions(entity)
%{__struct__: Ash.Dsl.Section} = section ->
section_suggestions(section)
end)
|> filter_matches(hint)
end
end
{:override, List.flatten(suggestions)}
end
else
_ ->
:ignore
end
end
defp filter_matches(hints, match) do
if match do
Enum.filter(hints, fn %{label: label} ->
Matcher.match?(label, match)
end)
else
hints
end
end
defp find_building_entity(constructors, option) do
Enum.find(constructors, fn
%{__struct__: Ash.Dsl.Entity, name: ^option} ->
true
_ ->
false
end)
end
defp find_option(constructors, {:value, option}) do
Enum.find_value(constructors, fn
{^option, _} = opt ->
opt
%{__struct__: Ash.Dsl.Entity, name: ^option, args: [arg | _], schema: schema} ->
{arg, schema[arg]}
_ ->
false
end)
end
defp find_option(constructors, {:arg, arg_index}) do
Enum.find(constructors, fn
{_option, config} ->
config[:arg_index] == arg_index
_ ->
false
end)
end
defp find_option(_, _), do: nil
defp section_suggestions(section) do
snippet = Map.get(section, :snippet)
snippet =
if snippet && snippet != "" do
snippet
else
"$0"
end
%{
type: :generic,
kind: :function,
label: to_string(section.name),
snippet: "#{section.name} do\n #{snippet}\nend",
detail: "Dsl Section",
documentation: Map.get(section, :docs) || ""
}
end
defp entity_suggestions(entity) do
snippet = Map.get(entity, :snippet)
snippet =
if snippet && snippet != "" do
snippet
else
"$0"
end
%{
type: :generic,
kind: :function,
label: to_string(entity.name),
snippet: "#{entity.name} #{args(entity)}do\n #{snippet}\nend",
detail: "Dsl Entity",
documentation: Map.get(entity, :docs) || ""
}
end
defp option_suggestions(key, config, type) do
snippet =
if config[:snippet] && config[:snippet] != "" do
config[:snippet]
else
default_snippet(config)
end
snippet =
case type do
:option ->
"#{key}: #{snippet}"
{:arg, _} ->
"#{key}: #{snippet}"
_ ->
"#{key} #{snippet}"
end
%{
type: :generic,
kind: :function,
label: to_string(key),
snippet: snippet,
detail: "Option",
documentation: config[:doc]
}
end
defp get_option(text) when is_binary(text) do
case Regex.named_captures(~r/\s(?<option>[^\s]*):[[:blank:]]*$/, text) do
%{"option" => option} when option != "" ->
try do
String.to_existing_atom(option)
rescue
_ ->
nil
end
_ ->
nil
end
end
defp get_option(_), do: nil
defp get_section_option(text) when is_binary(text) do
case Regex.named_captures(~r/\n[[:blank:]]+(?<option>[^\s]*)[[:blank:]]*$/, text) do
%{"option" => option} when option != "" ->
try do
String.to_existing_atom(option)
rescue
_ ->
nil
end
_ ->
nil
end
end
defp get_section_option(_), do: nil
defp option_values(key, config, hint, opts) do
case config[:type] do
:boolean ->
enum_suggestion([true, false], hint, "boolean")
{:one_of, values} ->
enum_suggestion(values, hint, to_string(key))
{:in, values} ->
enum_suggestion(values, hint, to_string(key))
:ash_type ->
builtin_types = Types.find_builtin_types(hint, opts.cursor_context)
custom_types = Types.find_custom_types(hint, opts.module_store)
builtin_types ++ custom_types
:ash_resource ->
Resource.find_resources(hint)
{:ash_behaviour, behaviour, builtins} ->
Resource.find_ash_behaviour_impls(behaviour, builtins, hint, opts.module_store)
{:behaviour, behaviour} ->
Resource.find_ash_behaviour_impls(behaviour, nil, hint, opts.module_store)
{:ash_behaviour, behaviour} ->
Resource.find_ash_behaviour_impls(behaviour, nil, hint, opts.module_store)
_ ->
[]
end
end
defp enum_suggestion(values, hint, label) do
Enum.flat_map(values, fn v ->
inspected = inspect(v)
if Matcher.match?(inspected, hint) do
[
%{
type: :generic,
kind: :type_parameter,
label: label,
insert_text: inspect(v),
snippet: inspect(v),
documentation: inspect(v),
priority: 0
}
]
else
[]
end
end)
end
defp default_snippet(config) do
cond do
config[:type] == :boolean && config[:default] in [true, false] ->
"#{to_string(!config[:default])}"
config[:type] == :string ->
"\"$0\""
match?({:list, {:in, _list}}, config[:type]) ->
if config[:default] do
inspect(config[:default])
else
"$0"
end
match?({:list, _}, config[:type]) ->
"[$0]"
match?({:in, _}, config[:type]) ->
if config[:default] do
inspect(config[:default])
else
{:in, list} = config[:type]
inspect(Enum.at(list, 0))
end
match?({:one_of, _}, config[:type]) ->
if config[:default] do
inspect(config[:default])
else
{:one_of, list} = config[:type]
inspect(Enum.at(list, 0))
end
config[:type] == :atom ->
":$0"
config[:type] == :mfa ->
"{${1:module}, :${2:function}, [${3:args}]}"
config[:type] == :keyword_list ->
"[$0]"
true ->
"$0"
end
end
defp args(entity) do
case entity.args || [] do
[] ->
""
args ->
args
|> Enum.with_index()
|> Enum.map(fn {arg, index} ->
"${#{index + 1}:#{arg}}"
end)
|> Enum.intersperse(", ")
|> Enum.join()
|> Kernel.<>(" ")
end
end
defp get_constructors(extensions, [], hint, _type) do
Enum.flat_map(
extensions,
fn extension ->
try do
Enum.filter(extension.sections(), fn section ->
Matcher.match?(to_string(section.name), hint)
end)
rescue
_ ->
[]
end
end
)
end
defp get_constructors(extensions, [first | rest], hint, type) do
Enum.flat_map(
extensions,
fn extension ->
try do
Enum.flat_map(extension.sections(), fn section ->
if section.name == first do
do_find_constructors(section, rest, hint, type)
else
[]
end
end)
rescue
_ ->
[]
end
end
)
end
defp do_find_constructors(entity_or_section, path, hint, type, recursives \\ [])
defp do_find_constructors(%{__struct__: Ash.Dsl.Entity} = entity, [], hint, type, recursives) do
case type do
{:value, _value} ->
entity.schema ++
Enum.flat_map(entity.entities || [], &elem(&1, 1)) ++
Enum.uniq(recursives ++ List.wrap(recursive_for(entity)))
{:arg, arg_index} ->
if arg_index >= Enum.count(entity.args || []) do
find_opt_hints(entity, hint) ++
find_entity_hints(entity, hint, recursives)
else
Enum.map(entity.schema, fn {key, value} ->
arg_index = Enum.find_index(entity.args || [], &(&1 == key))
if arg_index do
{key, Keyword.put(value, :arg_index, arg_index)}
else
{key, value}
end
end) ++
Enum.uniq(
recursives ++
List.wrap(recursive_for(entity))
)
end
_ ->
find_opt_hints(entity, hint) ++
find_entity_hints(entity, hint, recursives)
end
end
defp do_find_constructors(section, [], hint, _type, recursives) do
find_opt_hints(section, hint) ++
find_entity_hints(section, hint, []) ++
Enum.filter(section.sections, fn section ->
Matcher.match?(to_string(section.name), hint)
end) ++ recursives
end
defp do_find_constructors(
%{__struct__: Ash.Dsl.Entity} = entity,
[next | rest],
hint,
type,
recursives
) do
entity.entities
|> Kernel.||([])
|> Enum.flat_map(&elem(&1, 1))
|> Enum.concat(recursives)
|> Enum.concat(List.wrap(recursive_for(entity)))
|> Enum.filter(&(&1.name == next))
|> Enum.flat_map(
&do_find_constructors(
&1,
rest,
hint,
type,
Enum.uniq(recursives ++ List.wrap(recursive_for(entity)))
)
)
|> Enum.uniq()
end
defp do_find_constructors(section, [first | rest], hint, type, recursives) do
Enum.flat_map(section.entities, fn entity ->
if entity.name == first do
do_find_constructors(entity, rest, hint, type)
else
[]
end
end) ++
Enum.flat_map(section.sections, fn section ->
if section.name == first do
do_find_constructors(section, rest, hint, type)
else
[]
end
end) ++ recursives
end
defp recursive_for(entity) do
if entity.recursive_as do
entity
end
end
defp find_opt_hints(%{__struct__: Ash.Dsl.Entity} = entity, hint) do
Enum.flat_map(entity.schema, fn {key, value} ->
if Matcher.match?(to_string(key), hint) do
arg_index = Enum.find_index(entity.args || [], &(&1 == key))
if arg_index do
[{key, Keyword.put(value, :arg_index, arg_index)}]
else
[{key, value}]
end
else
[]
end
end)
end
defp find_opt_hints(section, hint) do
Enum.filter(section.schema, fn {key, _value} ->
Matcher.match?(to_string(key), hint)
end)
end
defp find_entity_hints(%{__struct__: Ash.Dsl.Entity} = entity, hint, recursives) do
entity.entities
|> Keyword.values()
|> Enum.concat(recursives)
|> Enum.concat(List.wrap(recursive_for(entity)))
|> List.flatten()
|> Enum.filter(fn entity ->
Matcher.match?(to_string(entity.name), hint)
end)
end
defp find_entity_hints(section, hint, _recursives) do
Enum.filter(section.entities, fn entity ->
Matcher.match?(to_string(entity.name), hint)
end)
end
defp get_scope_path(opts, scopes_to_lines, env, path) do
env = env || opts.env
with earliest_line when not is_nil(earliest_line) <-
scopes_to_lines[env.scope_id],
[%{func: func}] when func != :defmodule <-
opts.buffer_metadata.calls[earliest_line],
next_env when not is_nil(next_env) <-
opts.buffer_metadata.lines_to_env[earliest_line] do
get_scope_path(opts, scopes_to_lines, next_env, [func | path])
else
_ ->
path
end
end
defp ash_extension?(module) do
true in List.wrap(module.module_info()[:attributes][:ash_dsl])
rescue
_ -> false
end
defp default_extensions(dsl_mod) do
dsl_mod.module_info[:attributes][:ash_default_extensions]
|> List.wrap()
|> List.flatten()
end
defp parse_extensions(opts, extension_kinds) do
Enum.flat_map([:extensions | extension_kinds], fn extension_kind ->
case Regex.named_captures(
~r/#{extension_kind}:\s+?(?<extensions>(\[[^\]]*\])|([^\s]*))?[\,\s$]/,
opts.cursor_context.text_before
) do
%{"extensions" => extensions} when extensions != "" ->
extensions
|> String.replace("[", "")
|> String.replace("]", "")
|> String.split(",")
|> Enum.map(&String.trim/1)
_ ->
[]
end
end)
|> Enum.uniq()
|> Enum.map(&Module.concat([&1]))
|> Enum.filter(&Code.ensure_loaded?/1)
end
end
end