Skip to main content

lib/shadix/generator.ex

defmodule Shadix.Generator do
  @moduledoc """
  Pure helpers for the Shadix generator tooling.

  Provides namespace rewriting, default namespace derivation, and default
  target directory derivation. Kept separate from Mix tasks so it is
  unit-testable without invoking Mix machinery.
  """

  @doc """
  Rewrites canonical `Shadix.*` module references in `source` to use `namespace`
  as the new base.

  Three ordered replacements are applied:
  1. `Shadix.Components` → `namespace`
  2. `Shadix.Cn` → `namespace <> ".Cn"`
  3. `Shadix.Form` → `namespace <> ".Form"`

  The order matters: `Shadix.Components` is replaced first so the substring
  `Shadix.Cn` is never accidentally matched inside a `Shadix.Components.*` name.

      iex> Shadix.Generator.rewrite_namespace("import Shadix.Cn", "Demo.UI")
      "import Demo.UI.Cn"
  """
  @spec rewrite_namespace(String.t(), String.t()) :: String.t()
  def rewrite_namespace(source, namespace) do
    source
    |> String.replace("Shadix.Components", namespace)
    |> String.replace("Shadix.Cn", namespace <> ".Cn")
    |> String.replace("Shadix.Form", namespace <> ".Form")
  end

  @doc """
  Returns the default target namespace for the current Mix project.

  Derived as `<CamelizedApp>Web.Components.UI`.

      iex> Shadix.Generator.default_namespace()
      "ShadixWeb.Components.UI"
  """
  @spec default_namespace() :: String.t()
  def default_namespace do
    app = Mix.Project.config()[:app]
    Macro.camelize(to_string(app)) <> "Web.Components.UI"
  end

  @doc """
  Returns the default target directory for a given namespace.

  Derived as `lib/<underscored_namespace>`.

      iex> Shadix.Generator.default_dir("MyAppWeb.Components.UI")
      "lib/my_app_web/components/ui"
  """
  @spec default_dir(String.t()) :: String.t()
  def default_dir(namespace) do
    underscored = Macro.underscore(namespace)
    "lib/#{underscored}"
  end
end