expression-eval
Advanced tools
Comparing version 1.4.0 to 2.0.0
import * as jsep from "jsep"; | ||
declare function compile(expression: string | jsep.Expression): (context: object) => any; | ||
declare function compileAsync(expression: string | jsep.Expression): (context: object) => Promise<any>; | ||
declare function evaluate(node: jsep.Expression, context: object): any; | ||
declare function evaluateAsync(node: jsep.Expression, context: object): Promise<any>; | ||
export { compile, jsep as parse, evaluate as eval }; | ||
export { compile, compileAsync, jsep as parse, evaluate as eval, evaluateAsync as evalAsync }; |
112
index.js
@@ -1,2 +0,2 @@ | ||
var jsep = require('jsep'); | ||
const jsep = require('jsep'); | ||
@@ -8,3 +8,3 @@ /** | ||
var binops = { | ||
const binops = { | ||
'||': function (a, b) { return a || b; }, | ||
@@ -33,3 +33,3 @@ '&&': function (a, b) { return a && b; }, | ||
var unops = { | ||
const unops = { | ||
'-' : function (a) { return -a; }, | ||
@@ -45,4 +45,9 @@ '+' : function (a) { return a; }, | ||
async function evaluateArrayAsync( list, context ) { | ||
const res = await Promise.all(list.map((v) => evaluateAsync(v, context))); | ||
return res; | ||
} | ||
function evaluateMember ( node, context ) { | ||
var object = evaluate(node.object, context); | ||
const object = evaluate(node.object, context); | ||
if ( node.computed ) { | ||
@@ -55,2 +60,11 @@ return [object, object[evaluate(node.property, context)]]; | ||
async function evaluateMemberAsync( node, context ) { | ||
const object = await evaluateAsync(node.object, context); | ||
if ( node.computed) { | ||
return [object, object[await evaluateAsync(node.property, context)]]; | ||
} else { | ||
return [object, object[node.property.name]]; | ||
} | ||
} | ||
function evaluate ( node, context ) { | ||
@@ -67,3 +81,3 @@ | ||
case 'CallExpression': | ||
var caller, fn, assign; | ||
let caller, fn, assign; | ||
if (node.callee.type === 'MemberExpression') { | ||
@@ -93,3 +107,3 @@ assign = evaluateMember( node.callee, context ); | ||
return evaluate( node.left, context ) || evaluate( node.right, context ); | ||
} else if (node.operator === '&&') { | ||
} else if (node.operator === '&&') { | ||
return evaluate( node.left, context ) && evaluate( node.right, context ); | ||
@@ -114,2 +128,80 @@ } | ||
async function evaluateAsync( node, context ) { | ||
switch ( node.type ) { | ||
case 'ArrayExpression': | ||
return await evaluateArrayAsync( node.elements, context ); | ||
case 'BinaryExpression': { | ||
const [left, right] = await Promise.all([ | ||
evaluateAsync( node.left, context ), | ||
evaluateAsync( node.right, context ) | ||
]); | ||
return binops[ node.operator ]( left, right ); | ||
} | ||
case 'CallExpression': | ||
let caller, fn, assign; | ||
if (node.callee.type === 'MemberExpression') { | ||
assign = await evaluateMemberAsync( node.callee, context ); | ||
caller = assign[0]; | ||
fn = assign[1]; | ||
} else { | ||
fn = await evaluateAsync( node.callee, context ); | ||
} | ||
if (typeof fn !== 'function') { | ||
return undefined; | ||
} | ||
return await fn.apply( | ||
caller, | ||
await evaluateArrayAsync( node.arguments, context ), | ||
); | ||
case 'ConditionalExpression': | ||
return (await evaluateAsync( node.test, context )) | ||
? await evaluateAsync( node.consequent, context ) | ||
: await evaluateAsync( node.alternate, context ); | ||
case 'Identifier': | ||
return context[node.name]; | ||
case 'Literal': | ||
return node.value; | ||
case 'LogicalExpression': { | ||
if (node.operator === '||') { | ||
return ( | ||
(await evaluateAsync( node.left, context )) || | ||
(await evaluateAsync( node.right, context )) | ||
); | ||
} else if (node.operator === '&&') { | ||
return ( | ||
(await evaluateAsync( node.left, context )) && | ||
(await evaluateAsync( node.right, context )) | ||
); | ||
} | ||
const [left, right] = await Promise.all([ | ||
evaluateAsync( node.left, context ), | ||
evaluateAsync( node.right, context ) | ||
]); | ||
return binops[ node.operator ]( left, right ); | ||
} | ||
case 'MemberExpression': | ||
return (await evaluateMemberAsync(node, context))[1]; | ||
case 'ThisExpression': | ||
return context; | ||
case 'UnaryExpression': | ||
return unops[ node.operator ](await evaluateAsync( node.argument, context )); | ||
default: | ||
return undefined; | ||
} | ||
} | ||
function compile (expression) { | ||
@@ -119,6 +211,12 @@ return evaluate.bind(null, jsep(expression)); | ||
function compileAsync(expression) { | ||
return evaluateAsync.bind(null, jsep(expression)); | ||
} | ||
module.exports = { | ||
parse: jsep, | ||
eval: evaluate, | ||
compile: compile | ||
evalAsync: evaluateAsync, | ||
compile: compile, | ||
compileAsync: compileAsync | ||
}; |
{ | ||
"name": "expression-eval", | ||
"version": "1.4.0", | ||
"version": "2.0.0", | ||
"description": "JavaScript expression parsing and evaluation.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
# expression-eval | ||
[![Latest NPM release](https://img.shields.io/npm/v/expression-eval.svg)](https://www.npmjs.com/package/expression-eval) | ||
[![Minzipped size](https://badgen.net/bundlephobia/minzip/expression-eval)](https://bundlephobia.com/result?p=expression-eval) | ||
[![License](https://img.shields.io/npm/l/expression-eval.svg)](https://github.com/donmccurdy/expression-eval/blob/master/LICENSE) | ||
@@ -52,2 +53,4 @@ [![Build Status](https://travis-ci.com/donmccurdy/expression-eval.svg?branch=master)](https://travis-ci.com/donmccurdy/expression-eval) | ||
Alternatively, use `evalAsync` for asynchronous evaluation. | ||
### Compilation | ||
@@ -61,2 +64,4 @@ | ||
Alternatively, use `compileAsync` for asynchronous compilation. | ||
## Security | ||
@@ -63,0 +68,0 @@ |
35
test.js
@@ -119,2 +119,35 @@ const expr = require('./'); | ||
console.log('%s/%s tests passed.', passed, tests); | ||
async function testAsync() { | ||
const asyncContext = context; | ||
asyncContext.asyncFunc = async function(a, b) { | ||
return await a + b; | ||
}; | ||
asyncContext.promiseFunc = function(a, b) { | ||
return new Promise((resolve, reject) => { | ||
setTimeout(() => resolve(a + b), 1000); | ||
}) | ||
} | ||
const asyncFixtures = fixtures; | ||
asyncFixtures.push({ | ||
expr: 'asyncFunc(one, two)', | ||
expected: 3, | ||
}, { | ||
expr: 'promiseFunc(one, two)', | ||
expected: 3, | ||
}); | ||
for (let o of asyncFixtures) { | ||
tests++; | ||
try { | ||
var val = await expr.compileAsync(o.expr)(asyncContext); | ||
} catch (e) { | ||
console.error(`Error: ${o.expr}, expected ${o.expected}`); | ||
throw e; | ||
} | ||
assert.equal(val, o.expected, `Failed: ${o.expr} (${val}) === ${o.expected}`); | ||
passed++; | ||
} | ||
} | ||
testAsync().then(() => { | ||
console.log('%s/%s tests passed.', passed, tests); | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15607
315
86