filtrex
A sandboxed expression engine that compiles user-entered filter expressions into safe, fast JavaScript functions.
Repository Health
Technical Analysis
Filtrex lets applications accept arbitrary filter, search, or formula expressions from end users — things like transactions <= 5 and abs(profit) > 20.5 — without resorting to eval(). It defines a small, spreadsheet-like expression language covering arithmetic, comparisons, boolean logic, if/then/else, property access, and a set of built-in math functions, then compiles that language into a real JavaScript function using a Jison-generated parser and template-based code generation.
Because the compiled output only ever calls a fixed, whitelisted set of operators and functions, user expressions cannot reach global scope, constructors, or prototype chains — a guarantee the project backs with an adversarial test suite of prototype-pollution and sandbox-escape attempts. Applications extend the language with their own extraFunctions and constants, and errors are typed (UnknownFunctionError, UnknownPropertyError, etc.) so developer and end-user mistakes are easy to distinguish and surface in a UI.
What You Get
- A single
compileExpression(expression, options)entry point that returns a plain(data) => resultfunction — no classes, no schema definitions, no build step beyondnpm install. - A documented, spreadsheet-familiar expression grammar: arithmetic, comparisons, chained relations,
in/not in, boolean logic,if/then/else, and built-in math functions (abs,round,sqrt,log, etc.). - Extension points for custom functions (
extraFunctions) and constants (constants) so the language can be tailored to an application’s own domain data. - Prebuilt ESM and CommonJS bundles plus hand-written TypeScript type definitions, along with ready-to-use browser bundles in
dist/. - A typed error hierarchy (
UnknownFunctionError,UnknownPropertyError,UnknownOptionError) so invalid user expressions can be caught and reported without throwing during evaluation.
Common Use Cases
- Letting end users type free-form filters into a search or table UI (
transactions <= 5 and abs(profit) > 20.5) instead of building bespoke per-field filter controls. - Driving conditional chart plotting, highlighting, or colorizing rules from a user-supplied expression, as shown in Filtrex’s own example gallery.
- Powering formula fields in a browser-based spreadsheet or form builder where users reference other fields safely.
- Storing business rules (
category == "meal" and calories > 500) as data/config so non-developers can adjust logic without a code deploy.
Under The Hood
Architecture
Filtrex is organized as a small pipeline: generateParser.mjs defines a Jison grammar (lexical rules plus productions) that is fed to a bundled Jison parser generator (src/lib/jison.mjs) at build time via gulpfile.mjs/build.js to produce a generated parser module. filtrex.mjs wires that parser to a shared std runtime object (exposed to the grammar as yy) providing coercion helpers (arr, num, bool from utils.mjs), function-table lookups, and relation-chaining logic (reduceRelation), so parsed expressions compile directly into inline JavaScript template strings rather than being walked by an interpreter. The sole public entry point, compileExpression, parses an expression through the generated parser and wraps the resulting code string in a new Function closing over ops/std/data — meaning safety is enforced by construction in the codegen templates (fixed whitelist of operators/functions) rather than by a runtime sandbox layer, and grammar authoring is fully decoupled from evaluation semantics.
Tech Stack
The runtime itself ships with zero production dependencies — package.json lists no dependencies, only devDependencies for tooling. Babel and Rollup transpile and bundle the ESM source into dist/cjs and dist/esm, Gulp orchestrates the build pipeline, and the vendored Jison parser generator runs only at build time to turn the grammar into a parser module. Tests run on Mocha with Chai assertions against the built dist/cjs output rather than the source, and TypeScript types are hand-written rather than emitted by a compiler (no tsc in devDependencies). The package manager is pinned to a specific pnpm version.
Code Quality
Tests are organized by concern (arithmetic, objects, precedence, security, strict mode, misc, plus browser and ESM smoke tests) and exercise the actual built distributable, catching build regressions as well as logic bugs. test/security.js is a genuinely adversarial suite that attempts prototype-pollution and sandbox-escape payloads and asserts they fail — unusually rigorous for a library this size. Error handling is explicit and typed via a small hierarchy in errors.mjs, each carrying an i18n string key, and compileExpression is documented to throw only at compile time while returning (never throwing) errors during evaluation. No CI configuration or automated linter/type-checker enforcement is visible in the clone; Prettier is used for formatting only.
API Design
The public surface is deliberately minimal: one compileExpression function returning a plain closure, with no setup, schema, or build step required beyond installing the package. Its real technical distinction from ad hoc eval()-based approaches or heavier sandboxing (vm2, isolated-vm, AST interpreters) is compiling a restricted, whitelisted grammar into genuinely native JavaScript functions — getting both sandbox safety and native execution speed rather than trading one for the other.
Used by 2 apps in this directory
Artillery
Devops · Developer Tools
Cloud-scale load testing and functional testing for APIs, WebSockets, gRPC, and headless browsers, distributed across AWS Lambda or Fargate with zero infrastructure to manage.
Continue
Developer Tools · AI Development · AI Code Assistants
Open-source coding agent for VS Code, JetBrains, and CLI with support for 30+ LLM providers.