Lavash.Rx (Lavash v0.4.0-rc.1)

Copy Markdown View Source

A reactive expression that captures AST for isomorphic execution.

The rx/1 macro captures an Elixir expression at compile time, storing both the source string (for JS transpilation) and the transformed AST (for server-side evaluation).

Usage

Use rx() to wrap expressions in calculate declarations:

calculate :tag_count, rx(length(@tags))
calculate :can_add, rx(@max == nil or length(@items) < @max)
calculate :doubled, rx(@count * 2)

Supported Expressions

Expressions that can be transpiled to JavaScript:

  • Arithmetic: @count + 1, @price * @quantity
  • Comparisons: @count > 0, @name == "test"
  • Boolean: @enabled and @visible, not @disabled
  • Conditionals: if(@count > 0, do: "yes", else: "no")
  • List operations: length(@items), @items ++ ["new"]
  • Enum functions: Enum.map/2, Enum.filter/2, Enum.join/2

Reusable Functions with defrx

Use defrx to define functions that can be called within rx() expressions:

defrx valid_expiry?(digits) do
  String.length(digits) == 4 &&
    String.to_integer(String.slice(digits, 0, 2) || "0") >= 1 &&
    String.to_integer(String.slice(digits, 0, 2) || "0") <= 12
end

calculate :expiry_valid, rx(valid_expiry?(@expiry_digits))

The function body is expanded inline at each call site.

Importing defrx functions from other modules

Create a module with reusable defrx functions:

defmodule MyApp.Validators do
  use Lavash.Rx.Functions

  defrx valid_email?(email) do
    String.length(email) > 0 && String.contains?(email, "@")
  end
end

Then import them in your LiveView:

defmodule MyAppWeb.FormLive do
  use Lavash.LiveView
  import Lavash.Rx
  import_rx MyApp.Validators

  calculate :email_valid, rx(valid_email?(@email))
end

Fields

  • :source - The expression as a source string
  • :ast - The transformed AST for server-side evaluation
  • :deps - List of dependency field names (atoms)

Summary

Functions

Defines a reusable reactive function for use in rx() expressions.

Imports defrx functions from another module.

Captures a reactive expression at compile time.

Functions

defrx(arg, list)

(macro)

Defines a reusable reactive function for use in rx() expressions.

This macro registers the function so it's available during JS generation in the ColocatedTransformer.

Examples

defrx valid_expiry?(digits) do
  String.length(digits) == 4 &&
    String.to_integer(String.slice(digits, 0, 2) || "0") >= 1 &&
    String.to_integer(String.slice(digits, 0, 2) || "0") <= 12
end

defrx valid_cvv?(digits, is_amex) do
  if(is_amex, do: String.length(digits) == 4, else: String.length(digits) == 3)
end

Note: defrx bodies must be single expressions. Variable assignments like len = String.length(digits) are not supported.

import_rx(module, opts \\ [])

(macro)

Imports defrx functions from another module.

The imported functions become available for use in rx() expressions in the current module.

Example

defmodule MyApp.Validators do
  use Lavash.Rx.Functions

  defrx valid_email?(email) do
    String.length(email) > 0 && String.contains?(email, "@")
  end
end

defmodule MyAppWeb.UserLive do
  use Lavash.LiveView
  import Lavash.Rx
  import_rx MyApp.Validators

  calculate :email_valid, rx(valid_email?(@email))
end

You can also import only specific functions:

import_rx MyApp.Validators, only: [valid_email?: 1]

rx(body)

(macro)

Captures a reactive expression at compile time.

The expression is stored as both source string (for JS transpilation) and transformed AST (for server-side evaluation). Dependencies are automatically extracted from @field references.

Examples

rx(length(@tags))
rx(@count * @multiplier)
rx(if @active, do: "on", else: "off")