{"id":28631065,"url":"https://github.com/antvis/expr","last_synced_at":"2025-06-12T13:09:59.526Z","repository":{"id":276964506,"uuid":"930225735","full_name":"antvis/expr","owner":"antvis","description":"🚀 JavaScript Expression parser and evaluator, safety and high-performance.","archived":false,"fork":false,"pushed_at":"2025-03-28T11:06:46.000Z","size":137,"stargazers_count":22,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-08T09:24:51.036Z","etag":null,"topics":["expr","expression","visualization"],"latest_commit_sha":null,"homepage":"https://github.com/antvis/expr","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antvis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-10T09:37:01.000Z","updated_at":"2025-06-06T05:14:38.000Z","dependencies_parsed_at":"2025-02-11T12:25:33.398Z","dependency_job_id":"fc47268b-7b1b-4132-85c3-27012cdd564f","html_url":"https://github.com/antvis/expr","commit_stats":null,"previous_names":["bqxbqx/graph-secure-eval","bqxbqx/super-spec","bqxbqx/expr","antvis/expr"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/antvis/expr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fexpr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fexpr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fexpr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fexpr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antvis","download_url":"https://codeload.github.com/antvis/expr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fexpr/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259470956,"owners_count":22862999,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["expr","expression","visualization"],"created_at":"2025-06-12T13:09:56.294Z","updated_at":"2025-06-12T13:09:59.507Z","avatar_url":"https://github.com/antvis.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003ch1\u003e@antv/expr: Mathematical Expression Parser\u003c/h1\u003e\n\nLightweight JavaScript expression parser and evaluator, safety and high-performance. 🚀\n\n![gzip size](https://img.badgesize.io/https://unpkg.com/@antv/expr/dist/index.esm.js?compression=gzip)\n[![Build Status](https://github.com/antvis/expr/actions/workflows/build.yml/badge.svg)](https://github.com/antvis/expr/actions/workflows/build.yml)\n[![npm Version](https://img.shields.io/npm/v/@antv/expr.svg)](https://www.npmjs.com/package/@antv/expr)\n[![npm Download](https://img.shields.io/npm/dm/@antv/expr.svg)](https://www.npmjs.com/package/@antv/expr)\n\n\u003c/div\u003e\n\nUsed to parse a _mathematical expressions_ to _JavaScript function_ safely. For example, in [@antv/g2](https://github.com/antvis/expr), we can set the style with an expressions.\n\n```ts\n{\n  // Equivalent to function: `d =\u003e d.value \u003e 100 ? 'red' : 'green'`\n  fill: \"{ d.value \u003e 100 ? 'red' : 'green' }\",\n}\n```\n\n\n## ✨ Features\n\n- 🔒 **Secure by default** - No access to global objects or prototype chain, does not use `eval` or `new Function`.\n- 🚀 **High performance** - Supports pre-compilation of expressions for improved performance with repeated evaluations.\n- 🛠️ **Extensible** - Register custom functions to easily extend functionality.\n- 🪩 **Lightweight** - Zero dependencies, small footprint, before gzip it was less than `8 Kb`.\n\n\n## 📥 Installation\n\n```bash\nnpm install @antv/expr\n# or\nyarn add @antv/expr\n# or\npnpm add @antv/expr\n```\n\n\n## 🔨 Usage\n\n- [Synchronous Expression Evaluation](#synchronous-expression-evaluation)\n- [Pre-compiling Expressions](#pre-compiling-expressions)\n- [Registering and Calling Functions](#registering-and-calling-functions)\n- [Variable References](#variable-references)\n- [Arithmetic Operations](#arithmetic-operations)\n- [Comparison and Logical Operations](#comparison-and-logical-operations)\n- [Conditional (Ternary) Expressions](#conditional-ternary-expressions)\n- [Timeout Handling](#timeout-handling)\n\n### Synchronous Expression Evaluation\n\n```typescript\nimport { evaluate } from '@antv/expr';\n\n// Basic evaluation\nconst result = evaluate('x + y', { x: 10, y: 20 }); // returns 30\n\n// Using dot notation and array access\nconst data = {\n  values: [1, 2, 3],\n  status: 'active'\n};\n\nconst result = evaluate('data.values[0] + data.values[1]', { data }); // returns 3\n```\n\n### Pre-compiling Expressions\n\n```typescript\nimport { compile } from '@antv/expr';\n\n// Compile an expression\nconst evaluator = compile('price * quantity');\nconst result1 = evaluator({ price: 10, quantity: 5 }); // returns 50\nconst result2 = evaluator({ price: 20, quantity: 3 }); // returns 60\n```\n\n### Registering and Calling Functions\n\n```typescript\nimport { register, evaluate } from '@antv/expr';\n\n// Register functions\nregister('formatCurrency', (amount) =\u003e `$${amount.toFixed(2)}`);\n\n// Function call with arguments\nconst result = evaluate('@max(a, b, c)', { a: 5, b: 9, c: 2 }); // returns 9\n\n// Expression as function arguments\nconst result = evaluate('@formatCurrency(price * quantity)', { \n  price: 10.5, quantity: 3 \n}); // returns '$31.50'\n```\nBuild-in Functions: `abs`, `ceil`, `floor`, `round`, `sqrt`, `pow`, `max`, `min`.\n\n### Variable References\n\n```typescript\n// Simple variable reference\nconst result = evaluate('x', { x: 42 }); // returns 42\n\n// Nested property access with dot notation\nconst result = evaluate('user.profile.name', { \n  user: { profile: { name: 'John' } } \n}); // returns 'John'\n\n// Array access with bracket notation\nconst result = evaluate('items[0]', { items: [10, 20, 30] }); // returns 10\n\n// Mixed dot and bracket notation\nconst result = evaluate('data.items[0].value', { \n  data: { items: [{ value: 42 }] } \n}); // returns 42\n```\n\n### Arithmetic Operations\n\n```typescript\n// Basic arithmetic\nconst result = evaluate('a + b * c', { a: 5, b: 3, c: 2 }); // returns 11\n\n// Using parentheses for grouping\nconst result = evaluate('(a + b) * c', { a: 5, b: 3, c: 2 }); // returns 16\n\n// Modulo operation\nconst result = evaluate('a % b', { a: 10, b: 3 }); // returns 1\n```\n\n### Comparison and Logical Operations\n\n```typescript\n// Comparison operators\nconst result = evaluate('age \u003e= 18', { age: 20 }); // returns true\n\n// Logical AND\nconst result = evaluate('isActive \u0026\u0026 !isDeleted', { \n  isActive: true, isDeleted: false \n}); // returns true\n\n// Logical OR\nconst result = evaluate('status === \"active\" || status === \"pending\"', { \n  status: 'pending' \n}); // returns true\n```\n\n### Conditional (Ternary) Expressions\n\n```typescript\n// Simple ternary expression\nconst result = evaluate('age \u003e= 18 ? \"adult\" : \"minor\"', { \n  age: 20 \n}); // returns 'adult'\n\n// Nested ternary expressions\nconst result = evaluate('score \u003e= 90 ? \"A\" : score \u003e= 80 ? \"B\" : \"C\"', { \n  score: 85 \n}); // returns 'B'\n```\n\n### Timeout Handling\n\nYou can implement timeout handling by wrapping your evaluation in a `Promise.race` with a timeout:\n\n```typescript\nimport { evaluate } from \"@antv/expr\";\n\n// Create a function that evaluates with a timeout\nfunction evaluateWithTimeout(expr, context, timeoutMs) {\n  const evaluationPromise = new Promise((resolve) =\u003e {\n    resolve(evaluate(expr, context));\n  });\n\n  const timeoutPromise = new Promise((_, reject) =\u003e {\n    setTimeout(\n      () =\u003e reject(new Error(`Evaluation timed out after ${timeoutMs}ms`)),\n      timeoutMs,\n    );\n  });\n\n  return Promise.race([evaluationPromise, timeoutPromise]);\n}\n```\n\n\n## 🚀Benchmarks\n\nPerformance comparison of different evaluation methods: (baseline: new Function)\n\n| Expression Type       | new Function vs evaluate after compile | new Function vs evaluate without compile | new Function vs [expr-eval](https://www.npmjs.com/package/expr-eval?activeTab=readme) Parser |\n|-----------------------|----------------------------------------|------------------------------------------|----------------------------------|\n| Simple Expressions    | 1.59x faster                          | 6.36x faster                             | 23.94x faster                    |\n| Medium Expressions    | 2.16x faster                          | 9.81x faster                            | 37.81x faster                    |\n| Complex Expressions   | 1.59x faster                          | 4.89x faster                             | 32.74x faster                    |\n\n```mermaid\ngantt\n    title Performance Comparison (Baseline: new Function) * 100\n    dateFormat  X\n    axisFormat %s\n\n    section Simple\n    expr evaluate after compile    :done, 0, 159\n    expr evaluate without compile  :done, 0, 636\n    expr-eval Parser          :done, 0, 2394\n\n    section Medium\n    expr evaluate after compile    :done, 0, 216\n    expr evaluate without compile  :done, 0, 981\n    expr-eval Parser          :done, 0, 3781\n\n    section Complex\n    expr evaluate after compile    :done, 0, 159\n    expr evaluate without compile  :done, 0, 489\n    expr-eval Parser          :done, 0, 3274\n```\n\n\n## 📮API Reference\n\n#### `evaluate(expression: string, context?: object): any`\n\nSynchronously evaluates an expression and returns the result.\n\n- `expression`: The expression string to evaluate\n- `context`: An object containing variables used in the expression (optional)\n- Returns: The result of the expression evaluation\n\n#### `compile(expression: string): (context?: object) =\u003e any`\n\nSynchronously compiles an expression, returning a function that can be used multiple times.\n\n- `expression`: The expression string to compile\n- Returns: A function that accepts a context object and returns the evaluation result\n\n#### `register(name: string, fn: Function): void`\n\nRegisters a custom function that can be used in expressions.\n\n- `name`: Function name (used with @ prefix in expressions)\n- `fn`: Function implementation\n\nAll evaluation errors throw an `ExpressionError` type exception with detailed error information.\n\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantvis%2Fexpr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantvis%2Fexpr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantvis%2Fexpr/lists"}