View Source Funx.Monad.Either.Dsl.Transformer behaviour (funx v0.3.0)

Behaviour for transforming Either DSL pipelines after parsing.

Transformers allow post-parse optimization and validation of the pipeline. They receive a list of Step structs and can modify, validate, or optimize them.

Compile-Time Dependencies

⚠️ Transformers run at compile time and create compile-time dependencies.

When you use a transformer:

either user_id, transformers: [MyTransformer] do
  bind GetUser
end

The MyTransformer.transform/2 function is called during macro expansion. This means:

  • The transformer output is baked into the compiled code
  • Changes to the transformer may require recompiling modules that use it
  • Run mix clean && mix compile if transformer changes aren't reflected

This is intentional and allows for compile-time optimization. The DSL uses Code.ensure_compiled!/1 to track these dependencies, so most changes will trigger automatic recompilation.

Example

defmodule ValidateNoBareModules do
  @behaviour Funx.Monad.Either.Dsl.Transformer

  alias Funx.Monad.Either.Dsl.Step

  @impl true
  def transform(steps, _opts) do
    # Validate that no steps use bare module atoms without options
    case find_bare_module(steps) do
      nil -> {:ok, steps}
      bad_step -> {:error, "Step #{inspect(bad_step)} should use {Module, opts} syntax"}
    end
  end

  defp find_bare_module(steps) do
    Enum.find(steps, fn
      %Step.Bind{operation: op} when is_atom(op) -> true
      %Step.Map{operation: op} when is_atom(op) -> true
      _ -> false
    end)
  end
end

Built-in Transformers

Currently, no built-in transformers are provided. Transformers are opt-in and can be created for project-specific optimizations or validations.

Usage

Transformers are applied automatically during pipeline compilation. They can be configured via the :transformers option:

either input, transformers: [MyTransformer] do
  bind SomeModule
end

Summary

Callbacks

Transform a list of Step structs.

Functions

Apply a list of transformers to steps in order.

Types

Callbacks

@callback transform(steps(), opts()) :: {:ok, steps()} | error()

Transform a list of Step structs.

Receives the parsed steps and any user options, and returns either:

  • {:ok, transformed_steps} - Modified steps
  • {:error, message} - Validation error (raises CompileError)

The transformer can:

  • Optimize steps (remove redundant operations)
  • Validate cross-step constraints
  • Add implicit steps
  • Rewrite patterns into more efficient forms

Functions

Link to this function

apply_transformers(steps, transformers, opts \\ [])

View Source
@spec apply_transformers(steps(), [module()], opts()) :: {:ok, steps()} | error()

Apply a list of transformers to steps in order.

Returns {:ok, steps} if all transformers succeed, or the first error.