Current section

Files

Jump to
surface lib surface compiler variants.ex
Raw

lib/surface/compiler/variants.ex

defmodule Surface.Compiler.Variants do
@moduledoc false
@enum_types [:list, :keyword, :map, :mapset]
@choice_types [:string, :atom, :integer]
def generate(specs) do
for spec <- Enum.reverse(specs), css_variant = spec.opts[:css_variant], reduce: {[], []} do
{variants, data_variants} ->
variant_opts = if css_variant == true, do: [], else: css_variant
data_name = normalize_variant_name(spec.name)
assign_ast = {:@, [], [{spec.name, [], nil}]}
{type, all_variants, variants_specs} =
case {spec.type, spec.opts[:values] || spec.opts[:values!]} do
{:boolean, _} ->
true_name = variant_opts[true] || data_name
false_name = variant_opts[false] || "not-#{data_name}"
{:boolean, [true_name, false_name | variants],
[
{:data_present, true_name},
{:data_not_present, false_name}
]}
{type, _} when type in @enum_types ->
has_items_name = variant_opts[:has_items] || "has-#{data_name}"
no_items_name = variant_opts[:no_items] || "no-#{data_name}"
{:enum, [has_items_name, no_items_name | variants],
[
{:data_present, has_items_name},
{:data_not_present, no_items_name}
]}
{type, [_ | _] = values} when type in @choice_types ->
prefix = variant_opts[:prefix] || "#{data_name}-"
{variants_names, variants_specs} =
values
|> Enum.reverse()
|> Enum.reduce({variants, []}, fn value, {variants_names, variants_specs} ->
name = "#{prefix}#{value}"
{[name | variants_names], [{:data_with_value, name, value} | variants_specs]}
end)
{:choice, variants_names, variants_specs}
{_type, _} ->
not_nil_name = variant_opts[:not_nil] || data_name
nil_name = variant_opts[nil] || "no-#{data_name}"
{:other, [not_nil_name, nil_name | variants],
[
{:data_present, not_nil_name},
{:data_not_present, nil_name}
]}
end
{all_variants, [{type, spec.func, spec.name, data_name, assign_ast, variants_specs} | data_variants]}
end
end
def enum_types, do: @enum_types
def choice_types, do: @choice_types
defp normalize_variant_name(name) when is_atom(name) do
name
|> to_string()
|> String.replace(["_", "!", "?"], fn
"_" -> "-"
_ -> ""
end)
end
end