# `ExGram.FSM.States`
[🔗](https://github.com/rockneurotiko/ex_gram_fsm/blob/v0.1.0/lib/ex_gram/fsm/states.ex#L1)

Behaviour for declaring FSM states and allowed transitions.

Implement this behaviour to enable transition validation (both compile-time
warnings and runtime enforcement via the `on_invalid_transition` policy).

## DSL approach (recommended)

Use `defstates/1` for a concise declaration:

    defmodule MyBot.States do
      use ExGram.FSM.States

      defstates do
        state :idle, to: [:get_name]
        state :get_name, to: [:get_email, :idle]
        state :get_email, to: [:confirm, :get_name]
        state :confirm, to: [:idle]
      end
    end

## Direct behaviour implementation (escape hatch)

For dynamic or programmatic state/transition definitions:

    defmodule MyBot.States do
      @behaviour ExGram.FSM.States

      @impl true
      def states, do: [:idle, :get_name, :get_email, :confirm]

      @impl true
      def transitions do
        %{
          idle: [:get_name],
          get_name: [:get_email, :idle],
          get_email: [:confirm, :get_name],
          confirm: [:idle]
        }
      end
    end

## No-transition-restriction mode

To declare states without restricting transitions (useful for documentation
purposes only), omit `:to` from all states:

    defstates do
      state :idle
      state :working
      state :done
    end
    # transitions/0 returns :any - all transitions allowed

# `states`

```elixir
@callback states() :: [atom()]
```

Returns the list of all valid state atoms.

# `transitions`

```elixir
@callback transitions() :: %{required(atom()) =&gt; [atom()]} | :any
```

Returns the allowed transitions map, or `:any` if all transitions are allowed.

When returning a map, keys are source states and values are lists of
allowed target states. Transitions not listed in the map are considered invalid.

# `defstates`
*macro* 

Declares all FSM states and their allowed transitions.

## Example

    defstates do
      state :idle, to: [:working]
      state :working, to: [:done, :idle]
      state :done, to: [:idle]
    end

# `state`
*macro* 

Declares a state inside a `defstates/1` block.

## Options

- `:to` - list of allowed target states from this state

## Examples

    state :idle, to: [:get_name]      # can only go to :get_name
    state :idle                         # no transition restriction (when mixed, :any is NOT used)

---

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