# `Mutare.Phoenix`
[🔗](https://github.com/foxbenjaminfox/mutare_phoenix/blob/v0.3.1/lib/mutare/phoenix.ex#L1)

Custom [Mutare](https://hex.pm/packages/mutare) mutators for the Phoenix server-side
surface — the `Phoenix.Controller` calls a controller action performs on the conn, the
`Phoenix.Channel` replies and outbound messages, `Phoenix.PubSub`, and `Phoenix.Token` —
plus macro routing that excludes Phoenix's compile-time macros from mutation to prevent
metamutant compilation failures.

This package builds on `mutare_plug` the way `phoenix` builds on `plug`: it depends on it,
so the `Plug.Conn` families (`Mutare.Plug.all/0`) are on your code path too, ready to
compose.

## Usage

Add `mutare_phoenix` to your deps, then list the families in `.mutare.exs` and this module
under `:extensions`. Setting `:mutators` replaces Mutare's default set, so include the
`:builtins` family to keep the built-ins on:

    # .mutare.exs
    [
      mutators: [:builtins] ++ Mutare.Plug.all() ++ Mutare.Phoenix.all(),
      extensions: [Mutare.Phoenix]
    ]

`all/0` returns this package's seven families:

  * `Mutare.Phoenix.Redirect` — `:redirect_status`, swaps the explicit atom
    `:status` option of `Phoenix.Controller.redirect/2` for a redirect-status sibling.
  * `Mutare.Phoenix.Body` — `:controller_body`, blanks the body of
    `Phoenix.Controller.json/2` (to `%{}`), `text/2`, and `html/2` (to `""`).
  * `Mutare.Phoenix.Download` — `:download_disposition`, flips the explicit
    `:disposition` option of `Phoenix.Controller.send_download/3` between
    `:attachment` and `:inline`.
  * `Mutare.Phoenix.ChannelReply` — `:channel_reply`, drops the reply element of a
    `Phoenix.Channel` callback return (`{:ok, reply, socket}` → `{:ok, socket}`,
    `{:reply, reply, socket}` → `{:noreply, socket}`, `{:stop, reason, reply, socket}` →
    `{:stop, reason, socket}`), gated on `@behaviour Phoenix.Channel`.
  * `Mutare.Phoenix.ChannelMessage` — `:channel_message`, removes a `Phoenix.Channel`
    outbound message — `broadcast/3` and its `!`/`_from` siblings, `push/3`, `reply/2` —
    collapsing the call to `:ok`.
  * `Mutare.Phoenix.PubSub` — `:pubsub`, removes a `Phoenix.PubSub` `subscribe`,
    `unsubscribe`, or broadcast call, collapsing it to `:ok`.
  * `Mutare.Phoenix.Token` — `:token`, swaps a `Phoenix.Token` call for its sibling
    scheme (`sign` ↔ `encrypt`, `verify` ↔ `decrypt`), blanks a generated token's payload to
    `nil`, and turns an explicit `max_age:` into `:infinity`.

It does **not** include the `mutare_plug` families; compose `Mutare.Plug.all/0` explicitly
as shown above. Each call family matches its call written directly
(`Phoenix.Controller.redirect(conn, ...)`), aliased, or bare-imported
(`redirect(conn, ...)`, the form `use MyAppWeb, :controller` produces; `broadcast(socket,
...)`, the form `use Phoenix.Channel` produces).

## The `:extensions` entry

This module is also a `Mutare.CallRouting` extension. Listed under `:extensions`, it
routes Phoenix's compile-time-only macro calls `:skip` — the whole call is an inert leaf, so
Mutare neither descends into their arguments nor rewrites the calls themselves:

  * the `Phoenix.Router` DSL (`get`/`post`/`scope`/…), because route definitions run once
    at compile time under Mutare's compile-once model — a mutation there could never
    activate;
  * `Phoenix.Component.sigil_H/2` (`~H`), because HEEx sigil arguments must remain
    compile-time literals — left unregistered, Mutare's imported-call witness would splice
    an unreachable `sigil_H(arg1, arg2)` that Phoenix rejects at compile time, failing the
    whole metamutant build before poison recovery can isolate a single mutant.

Mutations *around* a `~H` expression (for example a `render/1` `:return_value` mutant)
remain available; only the sigil's own arguments are opaque.

# `all`

```elixir
@spec all() :: [module()]
```

This package's mutator families, for splicing into `:mutators` (see the module docs for
the `Mutare.Plug.all/0` and `:builtins` pairing).

    iex> Mutare.Phoenix.all()
    [Mutare.Phoenix.Redirect, Mutare.Phoenix.Body, Mutare.Phoenix.Download,
     Mutare.Phoenix.ChannelReply, Mutare.Phoenix.ChannelMessage, Mutare.Phoenix.PubSub,
     Mutare.Phoenix.Token]

---

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