Shared generator plumbing used by the styled (mix mishka.ui.gen.component(s)) and
headless (mix mishka.ui.gen.headless(.components)) tasks.
This is the reusable foundation the mix tasks build on: library priv/ resolution,
catalog discovery/validation, component naming, the EEx assign skeleton, generated-file
tracking and prefix persistence. Each mix task stays a thin front-end over these helpers.
Larger, more specialized concerns live in sibling modules of the same namespace:
MishkaChelekom.Generators.Preflight, .Assets, .Multi and .ImportMacro.
Summary
Functions
Every available component name for a layer (sorted, unique basenames of the .eex files).
Appends [flag, value] to args when value is present (not nil/empty).
Prints the Mishka owl banner in color, optionally with a subtitle line beneath it.
Verifies Phoenix >= 1.8.0 and Tailwind >= 4.0.0, adding an issue per problem found. Returns the (possibly annotated) igniter.
Turns a component name string into an atom (used to index a catalog .exs).
Converts a CSV string or list of values into a trimmed list of strings.
Builds the EEx assigns shared by both layers: nil-fills every declared catalog arg, then
merges :module, :web_module, :component_prefix and :module_prefix_camel.
Creates the sample priv/mishka_chelekom/config.exs if it does not exist yet (idempotent).
Composes task once per component in list, prepending each name to extra_args.
Resolves a component's .eex template and sibling .exs catalog, reads and validates it.
Joins a sub-path onto the library priv/ dir.
Returns the absolute path to the library's priv/ directory.
Persists --component-prefix/--module-prefix to the user config unless this is a sub
generation (--sub) or saving is disabled (--no-save).
Turns a dotted, lower-case string into a module atom ("a_b.c" -> :"AB.C").
Like module_atom/1 but keeps only the last segment ("a.b.c" -> :C).
Resolves the component list to generate for a plural task.
The catalog template directory for a layer.
Records a generated file in igniter_exs[:dont_move_files] so Igniter does not relocate it.
Validates that a loaded catalog config has the minimal expected shape, returning
{:ok, config} or {:error, reason}.
Functions
Every available component name for a layer (sorted, unique basenames of the .eex files).
:styled also discovers host-app custom templates under
priv/mishka_chelekom/{components,templates,presets}.
Appends [flag, value] to args when value is present (not nil/empty).
Prints the Mishka owl banner in color, optionally with a subtitle line beneath it.
Verifies Phoenix >= 1.8.0 and Tailwind >= 4.0.0, adding an issue per problem found. Returns the (possibly annotated) igniter.
Turns a component name string into an atom (used to index a catalog .exs).
Converts a CSV string or list of values into a trimmed list of strings.
Builds the EEx assigns shared by both layers: nil-fills every declared catalog arg, then
merges :module, :web_module, :component_prefix and :module_prefix_camel.
opts:
:values- already-validated arg values to seed (styled); defaults to[](headless):component_prefix- resolved public-function prefix (ornil):module_prefix- resolved module-name prefix used to derivemodule_prefix_camel
Creates the sample priv/mishka_chelekom/config.exs if it does not exist yet (idempotent).
Shared by the styled and headless setup so both layers handle the config file the same way.
Composes task once per component in list, prepending each name to extra_args.
@spec fetch_catalog(Igniter.t(), String.t(), :styled | :headless) :: {:ok, %{component: String.t(), path: String.t(), config: keyword()}} | {:error, {:not_found, String.t()} | {:bad_catalog, String.t(), String.t()}}
Resolves a component's .eex template and sibling .exs catalog, reads and validates it.
Returns {:ok, %{component, path, config}} (the underscored name, the template path and the
validated catalog) or a structured error the caller turns into a user-facing message:
{:error, {:not_found, path}}{:error, {:bad_catalog, reason, config_path}}
For :styled, names prefixed component_/preset_/template_ resolve against the host
app's priv/mishka_chelekom/{components,presets,templates}; everything else (and all
:headless names) resolves against the library priv/.
Joins a sub-path onto the library priv/ dir.
iex> MishkaChelekom.Generators.Core.lib_priv("components/button.eex")
@spec lib_priv_dir() :: String.t()
Returns the absolute path to the library's priv/ directory.
Prefers :code.priv_dir(:mishka_chelekom) (works for hex deps, path deps, and umbrellas),
falling back to the legacy "deps/mishka_chelekom/priv" string only if the app priv dir
is unavailable.
Persists --component-prefix/--module-prefix to the user config unless this is a sub
generation (--sub) or saving is disabled (--no-save).
Turns a dotted, lower-case string into a module atom ("a_b.c" -> :"AB.C").
Like module_atom/1 but keeps only the last segment ("a.b.c" -> :C).
@spec resolve_components( Igniter.t(), String.t() | nil, :styled | :headless, map(), [String.t()] | nil ) :: [String.t()]
Resolves the component list to generate for a plural task.
An empty request (or one containing "all") expands to every component of layer; otherwise
the requested names are used. Names in the user config :exclude_components or cli_exclude
are removed.
@spec template_dir(:styled | :headless) :: String.t()
The catalog template directory for a layer.
:styled→priv/components:headless→priv/headless
Records a generated file in igniter_exs[:dont_move_files] so Igniter does not relocate it.
Validates that a loaded catalog config has the minimal expected shape, returning
{:ok, config} or {:error, reason}.