npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@antv/expr

v1.0.2

Published

A secure, high-performance expression evaluator for dynamic chart rendering

Downloads

295,406

Readme

Lightweight JavaScript expression parser and evaluator, safety and high-performance. 🚀

gzip size Build Status npm Version npm Download

Used to parse a mathematical expressions to JavaScript function safely. For example, in @antv/g2, we can set the style with an expressions.

{
  // Equivalent to function: `d => d.value > 100 ? 'red' : 'green'`
  fill: "{ d.value > 100 ? 'red' : 'green' }",
}

✨ Features

  • 🔒 Secure by default - No access to global objects or prototype chain, does not use eval or new Function.
  • 🚀 High performance - Supports pre-compilation of expressions for improved performance with repeated evaluations.
  • 🛠️ Extensible - Register custom functions to easily extend functionality.
  • 🪩 Lightweight - Zero dependencies, small footprint, before gzip it was less than 8 Kb.

📥 Installation

npm install @antv/expr
# or
yarn add @antv/expr
# or
pnpm add @antv/expr

🔨 Usage

Synchronous Expression Evaluation

import { evaluate } from '@antv/expr';

// Basic evaluation
const result = evaluate('x + y', { x: 10, y: 20 }); // returns 30

// Using dot notation and array access
const data = {
  values: [1, 2, 3],
  status: 'active'
};

const result = evaluate('data.values[0] + data.values[1]', { data }); // returns 3

Pre-compiling Expressions

import { compile } from '@antv/expr';

// Compile an expression
const evaluator = compile('price * quantity');
const result1 = evaluator({ price: 10, quantity: 5 }); // returns 50
const result2 = evaluator({ price: 20, quantity: 3 }); // returns 60

Registering and Calling Functions

import { register, evaluate } from '@antv/expr';

// Register functions
register('formatCurrency', (amount) => `$${amount.toFixed(2)}`);

// Function call with arguments
const result = evaluate('@max(a, b, c)', { a: 5, b: 9, c: 2 }); // returns 9

// Expression as function arguments
const result = evaluate('@formatCurrency(price * quantity)', { 
  price: 10.5, quantity: 3 
}); // returns '$31.50'

Build-in Functions: abs, ceil, floor, round, sqrt, pow, max, min.

Variable References

// Simple variable reference
const result = evaluate('x', { x: 42 }); // returns 42

// Nested property access with dot notation
const result = evaluate('user.profile.name', { 
  user: { profile: { name: 'John' } } 
}); // returns 'John'

// Array access with bracket notation
const result = evaluate('items[0]', { items: [10, 20, 30] }); // returns 10

// Mixed dot and bracket notation
const result = evaluate('data.items[0].value', { 
  data: { items: [{ value: 42 }] } 
}); // returns 42

Arithmetic Operations

// Basic arithmetic
const result = evaluate('a + b * c', { a: 5, b: 3, c: 2 }); // returns 11

// Using parentheses for grouping
const result = evaluate('(a + b) * c', { a: 5, b: 3, c: 2 }); // returns 16

// Modulo operation
const result = evaluate('a % b', { a: 10, b: 3 }); // returns 1

Comparison and Logical Operations

// Comparison operators
const result = evaluate('age >= 18', { age: 20 }); // returns true

// Logical AND
const result = evaluate('isActive && !isDeleted', { 
  isActive: true, isDeleted: false 
}); // returns true

// Logical OR
const result = evaluate('status === "active" || status === "pending"', { 
  status: 'pending' 
}); // returns true

Conditional (Ternary) Expressions

// Simple ternary expression
const result = evaluate('age >= 18 ? "adult" : "minor"', { 
  age: 20 
}); // returns 'adult'

// Nested ternary expressions
const result = evaluate('score >= 90 ? "A" : score >= 80 ? "B" : "C"', { 
  score: 85 
}); // returns 'B'

Timeout Handling

You can implement timeout handling by wrapping your evaluation in a Promise.race with a timeout:

import { evaluate } from "@antv/expr";

// Create a function that evaluates with a timeout
function evaluateWithTimeout(expr, context, timeoutMs) {
  const evaluationPromise = new Promise((resolve) => {
    resolve(evaluate(expr, context));
  });

  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(
      () => reject(new Error(`Evaluation timed out after ${timeoutMs}ms`)),
      timeoutMs,
    );
  });

  return Promise.race([evaluationPromise, timeoutPromise]);
}

🚀Benchmarks

Performance comparison of different evaluation methods: (baseline: new Function)

| Expression Type | new Function vs evaluate after compile | new Function vs evaluate without compile | new Function vs expr-eval Parser | |-----------------------|----------------------------------------|------------------------------------------|----------------------------------| | Simple Expressions | 1.59x faster | 6.36x faster | 23.94x faster | | Medium Expressions | 2.16x faster | 9.81x faster | 37.81x faster | | Complex Expressions | 1.59x faster | 4.89x faster | 32.74x faster |

gantt
    title Performance Comparison (Baseline: new Function) * 100
    dateFormat  X
    axisFormat %s

    section Simple
    expr evaluate after compile    :done, 0, 159
    expr evaluate without compile  :done, 0, 636
    expr-eval Parser          :done, 0, 2394

    section Medium
    expr evaluate after compile    :done, 0, 216
    expr evaluate without compile  :done, 0, 981
    expr-eval Parser          :done, 0, 3781

    section Complex
    expr evaluate after compile    :done, 0, 159
    expr evaluate without compile  :done, 0, 489
    expr-eval Parser          :done, 0, 3274

📮API Reference

evaluate(expression: string, context?: object): any

Synchronously evaluates an expression and returns the result.

  • expression: The expression string to evaluate
  • context: An object containing variables used in the expression (optional)
  • Returns: The result of the expression evaluation

compile(expression: string): (context?: object) => any

Synchronously compiles an expression, returning a function that can be used multiple times.

  • expression: The expression string to compile
  • Returns: A function that accepts a context object and returns the evaluation result

register(name: string, fn: Function): void

Registers a custom function that can be used in expressions.

  • name: Function name (used with @ prefix in expressions)
  • fn: Function implementation

All evaluation errors throw an ExpressionError type exception with detailed error information.

License

MIT