defmodule TailwindFormatter do @external_resource "README.md" @moduledoc "README.md" |> File.read!() |> String.split("") |> Enum.fetch!(1) alias TailwindFormatter.Defaults if Version.match?(System.version(), ">= 1.13.0") do @behaviour Mix.Tasks.Format end def features(_opts) do [sigils: [:H], extensions: [".heex"]] end def format(contents, _opts) do Regex.replace(Defaults.regex_pattern(), contents, fn original, _split, classes -> class_list = String.split(classes) sorted_list = sort(class_list) |> Enum.join(" ") String.replace(original, ~r/"([^"]*)"/, "\"" <> sorted_list <> "\"") end) end defp sort([]) do end defp sort(class_list) do {base_classes, variants} = separate(class_list) base_sorted = sort_base_classes(base_classes) variant_sorted = sort_variant_classes(variants) base_sorted ++ variant_sorted end defp sort_base_classes(base_classes) do Enum.map(base_classes, fn class -> sort_number = Map.get(Defaults.class_order(), class, -1) {sort_number, class} end) |> Enum.sort(&(elem(&1, 0) <= elem(&2, 0))) |> Enum.map(&elem(&1, 1)) |> List.flatten() end defp separate(class_list) do class_list |> Enum.reduce({[], []}, fn class, tuple -> if variant?(class) do put_elem(tuple, 1, [class | elem(tuple, 1)]) else put_elem(tuple, 0, [class | elem(tuple, 0)]) end end) end defp variant?(class) do String.contains?(class, ":") end defp sort_variant_classes(variants) do variants |> group_by_variant() |> sort_by_variant_order() |> sort_classes_per_variant() |> grouped_variants_to_list() end defp group_by_variant(variants) do variants |> Enum.map(&String.split(&1, ":", parts: 2)) |> Enum.group_by(&List.first/1, &List.last/1) end defp sort_by_variant_order(variant_groups) do variant_groups |> Enum.map(fn variant_group -> variant = elem(variant_group, 0) sort_number = Map.get(Defaults.variant_order(), variant, -1) {sort_number, variant_group} end) |> Enum.sort(&(elem(&1, 0) <= elem(&2, 0))) |> Enum.map(&elem(&1, 1)) end defp sort_classes_per_variant(grouped_variants) do Enum.map(grouped_variants, fn variant_group -> {variant, base_classes} = variant_group {variant, sort(base_classes)} end) end defp grouped_variants_to_list(grouped_variants) do Enum.map(grouped_variants, fn variant_group -> {variant, base_classes} = variant_group Enum.map(base_classes, fn class -> "#{variant}:#{class}" end) end) |> List.flatten() end end