# `FrappeUIPhx.Installer`
[🔗](https://github.com/moacirbishopcamata/frappe_ui_phx/blob/v0.3.1/lib/frappe_ui_phx/installer.ex#L1)

Edições idempotentes nos arquivos do app host (CSS, JS, `mix.exs`), em funções
puras `conteúdo -> {:ok, novo, mudou?} | {:error, motivo}`. A task
`mix frappe_ui_phx.install` só lê/escreve arquivos em volta delas.

Idempotência é a pós-condição principal: aplicar duas vezes devolve o mesmo
conteúdo e `mudou? == false` na segunda.

# `result`

```elixir
@type result() :: {:ok, String.t(), boolean()} | {:error, atom()}
```

# `check_compilers`

```elixir
@spec check_compilers(String.t()) :: :ok | {:missing, String.t()}
```

O `mix.exs` do host compila com `:phoenix_live_view` (necessário para extrair os
hooks colocated)? Não edita o arquivo; devolve `:ok` ou `{:missing, instrução}`.

# `patch_css`

```elixir
@spec patch_css(String.t(), String.t()) :: result()
```

Acrescenta os `@import` do CSS de tokens e o `@source` dos componentes
logo depois de `@import "tailwindcss"`. `rel` é o caminho da dependência a partir
do `app.css` (ex.: `"../../deps/frappe_ui_phx"`).

# `patch_js`

```elixir
@spec patch_js(String.t()) :: result()
```

Importa os hooks colocated da biblioteca e os junta ao objeto `hooks:` do
`LiveSocket` (acompanha o `colocatedHooks` do Phoenix 1.8 quando existe).

# `relative`

```elixir
@spec relative(String.t(), String.t()) :: String.t()
```

Caminho da dependência relativo a `from_dir` (ambos absolutos).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
