Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jonschlinkert/eval-estree-expression

Safely evaluate JavaScript (estree) expressions, sync and async.
https://github.com/jonschlinkert/eval-estree-expression

ast babel babeljs context escodegen esprima estree eval evaluate evaluate-expressions evaluation evaluator expression expression-evaluator parse parser

Last synced: 2 months ago
JSON representation

Safely evaluate JavaScript (estree) expressions, sync and async.

Awesome Lists containing this project

README

        

# eval-estree-expression [![NPM version](https://img.shields.io/npm/v/eval-estree-expression.svg?style=flat)](https://www.npmjs.com/package/eval-estree-expression) [![NPM monthly downloads](https://img.shields.io/npm/dm/eval-estree-expression.svg?style=flat)](https://npmjs.org/package/eval-estree-expression) [![NPM total downloads](https://img.shields.io/npm/dt/eval-estree-expression.svg?style=flat)](https://npmjs.org/package/eval-estree-expression) [![Tests](https://github.com/jonschlinkert/eval-estree-expression/actions/workflows/main.yml/badge.svg)](https://github.com/jonschlinkert/eval-estree-expression/actions/workflows/main.yml)

> Safely evaluate JavaScript (estree) expressions, sync and async.

Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.

- [Install](#install)
- [Usage](#usage)
* [Usage with Babel](#usage-with-babel)
* [Usage with Esprima](#usage-with-esprima)
- [API](#api)
* [.evaluate](#evaluate)
* [.evaluate.sync](#evaluatesync)
* [.variables](#variables)
- [Options](#options)
* [booleanLogicalOperators](#booleanlogicaloperators)
* [functions](#functions)
* [generate](#generate)
* [regexOperator](#regexoperator)
* [strict](#strict)
* [withMembers](#withmembers)
- [Examples](#examples)
* [Operators](#operators)
- [About](#about)

_(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_

## Install

Install with [npm](https://www.npmjs.com/):

```sh
$ npm install --save eval-estree-expression
```

## Usage

Requires [Node.js](https://nodejs.org/en/download/) version 14 or greater.

Evaluates an [estree](https://github.com/estree/estree) expression from [@babel/parser][], [esprima](http://esprima.org), [acorn](https://github.com/acornjs/acorn), or any other library that parses and returns a valid `estree` expression.

```js
const { evaluate } = require('eval-estree-expression');

evaluate(expressionTree[, context]); // async
evaluate.sync(expressionTree[, context]); // sync
```

See the [unit tests](./test) for hundreds of additional usage examples.

**Params**

The `evaluate` function takes the following arguments:

* `expressionTree` **{object}** - a valid [estree](https://github.com/estree/estree) expression AST.
* `context` **{object}** - a data object with values to replace variables in expressions

### Usage with Babel

Most of the examples in this document assume the following setup code is used:

```js
const { evaluate } = require('eval-estree-expression');
const { parseExpression } = require('@babel/parser');

// parse your JavaScript expression
const ast = parseExpression('1 + 2');

// evaluate synchronously
console.log(evaluate.sync(ast)); //=> 3

// or asynchronously
console.log(await evaluate(ast)); //=> 3
```

### Usage with Esprima

[Esprima][esprimar] doesn't have a "parseExpression" method like @babel/parser, so you'll need to return the expression from the AST, like so:

```js
const { parse } = require('esprima');
const { evaluate } = require('eval-estree-expression');
const ast = parse('[1, 2, 3].map(n => n * x);').body[0].expression;

// evaluate synchronously
console.log(evaluate.sync(ast)); // =>, [2, 4, 6]

// or asynchronously
console.log(await evaluate(ast)); // =>, [2, 4, 6]
```

## API

### .evaluate

Evaluate expresssions asynchronously.

```js
console.log(await evaluate(parse('1 + 2'))); //=> 3
console.log(await evaluate(parse('5 * 2'))); //=> 10
console.log(await evaluate(parse('1 > 2'))); //=> false
console.log(await evaluate(parse('1 < 2'))); //=> true

// with context object
console.log(await evaluate(parse('page.title === "home"'), { page: { title: 'home' } })); //=> true
```

### .evaluate.sync

Evaluate expresssions synchronously.

```js
console.log(evaluate.sync(parse('1 + 2'))); //=> 3
console.log(evaluate.sync(parse('5 * 2'))); //=> 10
console.log(evaluate.sync(parse('1 > 2'))); //=> false
console.log(evaluate.sync(parse('1 < 2'))); //=> true

// with context object
console.log(evaluate.sync(parse('page.title === "home"'), { page: { title: 'home' } })); //=> true
```

### .variables

Get an array of variables from an expression:

```js
const { parseExpression } = require('@babel/parser');
const { variables } = require('eval-estree-expression');

console.log(variables(parseExpression('x * (y * 3) + z.y.x'))); //=> ['x', 'y', 'z']
console.log(variables(parseExpression('(a || b) ? c + d : e * f'))); //=> ['a', 'b', 'c', 'd', 'e', 'f']

```

## Options

### booleanLogicalOperators

Type: `boolean`
Default: `undefined`

Force logical operators to return a boolean result.

```js
console.log(await evaluate(parse('a && b'), { a: undefined, b: true })); //=> undefined
console.log(await evaluate(parse('a && b'), { a: undefined, b: false })); //=> undefined
console.log(await evaluate(parse('a || b'), { a: false, b: null })); //=> null
console.log(await evaluate(parse('a || b'), { a: false, b: undefined })); //=> undefined

//
// With booleanLogicalOperators enabled
//

const options = {
booleanLogicalOperators: true
};

console.log(await evaluate(parse('a || b'), { a: false, b: null }, options)); //=> false
console.log(await evaluate(parse('a && b'), { a: undefined, b: true }, options)); //=> false
console.log(await evaluate(parse('a && b'), { a: undefined, b: false }, options)); //=> false
console.log(await evaluate(parse('a || b'), { a: false, b: undefined }, options)); //=> false
```

### functions

Type: `boolean`
Default: `false`

Allow function calls to be evaluated. This is unsafe, please enable this option at your own risk.

**Example**

```js
const { parse } = require('esprima');
const { generate } = require('escodegen');
const { evaluate } = require('eval-estree-expression');

const options = {
functions: true
};

// works with native methods
console.log(evaluate.sync(parse('/([a-z]+)/.exec(" foo ")'), { x: 2 }, options));
//=> [ 'foo', 'foo', index: 1, input: ' foo ', groups: undefined ]

// and functions defined on the context
console.log(evaluate.sync('a.upper("b")', { a: { upper: v => v.toUpperCase() } }, options);
//=> 'B'
```

However, this does NOT support function expressions or function statements.
To enable function statements and expressions (not just function calls) to be evaluated, you must also use the [generate](#generate) option.

### generate

Type: `boolean`
Default: `undefined`

Enable support for function statements and expressions by enabling the [functions](#functions) option AND by passing the `.generate()` function from the [escodegen](http://github.com/estools/escodegen) library.

**Example**

```js
const escodegen = require('escodegen');
const { parse } = require('esprima');
const { evaluate } = require('eval-estree-expression');

const options = {
functions: true,
generate: escodegen.generate
};

console.log(await evaluate(parse('[1, 2, 3].map(n => n * x);'), { x: 2 }, options))); // =>, [2, 4, 6]
```

### regexOperator

Type: `boolean`
Default: `true`

Enable the `=~` regex operator to support testing values without using functions (example `name =~ /^a.*c$/`).

**Why is this needed?**

In expressions, if you wish to test a value using a regular expression, you have two options:

1. Enable function support so that you can use methods like `.test()` and `.match()`, or
2. Use this option, which uses a special syntax to match against regular expressions _without evaluating an functions_.

In other words, instead of having to do this:

```js
console.log(evaluate.sync(parse('/^ab+c$/ig.test("abbbbbc")'), {}, { functions: true }));
```

You can do this:

```js
console.log(evaluate.sync(parse('name =~ /^a.*c$/'), { name: 'abc' }));
console.log(evaluate.sync(parse('name =~ regex'), { name: 'abc', regex: /^a.*c$/ }));
```

### strict

Type: `boolean`
Default: `false`

Throw an error when variables are undefined.

### withMembers

Type: `boolean`
Default: `undefined`

Used with the [variables](#variables) method to return nested variables (e.g. variables with dot notation, like `foo.bar.baz`).

## Examples

### Operators

Supports all JavaScript operators with the exception of assignment operators (`=`, `+=`, etc):

```js
// Arithmetic operators
evaluate('a + b');
evaluate('a - b');
evaluate('a / b');
evaluate('a * b');
evaluate('a % b');
evaluate('a ** b');

// Relational operators
evaluate('a instanceof b');
evaluate('a < b');
evaluate('a > b');
evaluate('a <= b');
evaluate('a >= b');

// Equality operators
evaluate('a !== b');
evaluate('a === b');
evaluate('a != b');
evaluate('a == b');

// Bitwise shift operators
evaluate('a << b');
evaluate('a >> b');
evaluate('a >>> b');

// Binary bitwise operators
evaluate('a & b');
evaluate('a | b');
evaluate('a ^ b');

// Binary logical operators
evaluate('a && b'); // Logical AND.
evaluate('a || b'); // Logical OR.
evaluate('a ?? b'); // Nullish Coalescing Operator.
```

## About

Contributing

Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).

Running Tests

Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:

```sh
$ npm install && npm test
```

Building docs

_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_

To generate the readme, run the following command:

```sh
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```

### Related projects

You might also be interested in these projects:

[whence](https://www.npmjs.com/package/whence): Add context awareness to your apps and frameworks by safely evaluating user-defined conditional expressions. Useful… [more](https://github.com/jonschlinkert/whence) | [homepage](https://github.com/jonschlinkert/whence "Add context awareness to your apps and frameworks by safely evaluating user-defined conditional expressions. Useful for evaluating expressions in config files, prompts, key bindings, completions, templates, and many other user cases.")

### Contributors

| **Commits** | **Contributor** |
| --- | --- |
| 30 | [jonschlinkert](https://github.com/jonschlinkert) |
| 1 | [6utt3rfly](https://github.com/6utt3rfly) |

### Author

**Jon Schlinkert**

* [GitHub Profile](https://github.com/jonschlinkert)
* [Twitter Profile](https://twitter.com/jonschlinkert)
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)

### License

Copyright © 2021, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).

***

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on September 25, 2021._