qanna-rsa/expression-engine

A small, fast expression language for evaluating dynamic values against structured data -- dot-path access, list filtering/mapping, chainable string/number/date methods, and {{ }} template interpolation for Laravel workflows, forms, and low-code automations.

Maintainers

Package info

github.com/qanna-rsa/expression-engine

pkg:composer/qanna-rsa/expression-engine

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.0.1 2026-08-07 23:27 UTC

This package is not auto-updated.

Last update: 2026-08-08 21:38:51 UTC


README

A small, fast expression language for evaluating dynamic values against structured data — dot-path lookups, list filtering/mapping, string/number/date manipulation, and template interpolation, all from a single string.

Overview

Built for low-code surfaces — workflow automations, dynamic forms, templated configs — anywhere you'd reach for a spreadsheet formula or a Zapier/Make-style expression, but need it embedded in your own PHP/Laravel app. Wrap an expression in {{ }} inside any string, or evaluate one directly and get a real typed value back.

trigger.items.filter(current.active).map(current.name.upper()).first()

Features

  • Dot-path accesstrigger.user.email, with safe navigation (?.) and null-coalescing (??) for data that might not exist
  • Chainable methods on strings, numbers, arrays, and dates — trigger.name.upper().trim(), now().addDays(5).format('Y-m-d')
  • List operationsfilter(), map(), sort(), any(), every(), groupBy(), using current for the item in scope; chains and nests cleanly
  • Full operator set — arithmetic, comparison, logical (&& || !), ternary (? :), null-coalescing (??)
  • Template interpolationresolve() replaces every {{ expr }} in a string; a single bare expression keeps its real type (int, array, bool…), mixed text stringifies
  • Code blocks — multi-line sequences via run(), sharing state between lines with set() / get()
  • Extensible — register your own functions and chainable methods without touching the engine
  • Introspection APIavailableMethods(), availableFunctions(), suggestMethods(), suggestKeys(), for building autocomplete on top of the language
  • Interactive playgroundphp artisan expression:playground, a tinker-style REPL with live context editing, Eloquent factory / Faker data generation, and inline parse-error diagnostics
  • Strict or forgiving — configurable: unresolved paths either throw or quietly resolve to null

Installation

composer require qanna-rsa/expression-engine

Laravel auto-discovers the service provider and facade. Optionally publish the config:

php artisan vendor:publish --tag=expression-engine-config

Quick Start

use Qanna\ExpressionEngine\Engine;

$engine = new Engine(config('expression-engine'));

// Fill a template
$engine->resolve('Hello {{ trigger.name }}', [
    'trigger' => ['name' => 'John'],
]);
// → "Hello John"

// Evaluate an expression and get a real typed value back
$engine->evaluate('trigger.items.filter(current.active).map(current.name)', [
    'trigger' => ['items' => [
        ['name' => 'Widget', 'active' => true],
        ['name' => 'Gadget', 'active' => false],
    ]],
]);
// → ["Widget"]

Playground

php artisan expression:playground drops you into a REPL against a live Engine + Context — no PHP file needed to try an expression:

$ php artisan expression:playground

expr › /fake
Fake context generated under "trigger". Try: trigger.items.filter(current.active).map(current.name)

expr › trigger.items.filter(current.active).map(current.name)
=> ["voluptatibus tenetur","placeat odio","eum et"]  (array, 3.12ms)
   chainable: all, any, avg, chunk, contains, count, diff …+30 more

expr › trigger.name.upper(
ParserException: Unexpected token '' at position 19.
  trigger.name.upper(
                     ^
  • /fake seeds realistic demo data instantly; /factory App\Models\Order pulls from your app's real Eloquent factories instead (->make() only — it never touches the database)
  • /set trigger.age 21 and /context build up and inspect context by hand
  • /block tests multi-line set()/get() code blocks like run()
  • /suggest <expr>, /methods, /functions introspect the language live — the same API you'd use to build autocomplete
  • Every result shows its type and timing, plus what you can chain next; parse errors point at the exact character that broke