donmccurdy / expression-eval Goto Github PK
View Code? Open in Web Editor NEWJavaScript expression parsing and evaluation.
License: MIT License
JavaScript expression parsing and evaluation.
License: MIT License
I'm creating an application that lets me declare variables and assign them expressions. I'd like to be able to support expressions like random.int(min,max)
or random.guid()
and have it evaluate as you might expect.
Unfortunately, the evaluation engine ignores nodes of type CallExpression.
Is there any reason why it would be a bad idea for me to initialize certain names to functions so that they can be used in an expression?
It would be nice if we can disable execution of CallExpression type for better security reason, in case we can't absolutely control data object functions. Function creates through Func() for example.
Using the latest version (3.1.0) the following typescript errors are generated from simple app.
$ tsc
node_modules/expression-eval/index.d.ts:7:41 - error TS1138: Parameter declaration expected.
7 declare function addUnaryOp(op: string, (a: any) => any): void;
node_modules/expression-eval/index.d.ts:7:56 - error TS1005: ';' expected.
7 declare function addUnaryOp(op: string, (a: any) => any): void;
node_modules/expression-eval/index.d.ts:7:57 - error TS1128: Declaration or statement expected.
7 declare function addUnaryOp(op: string, (a: any) => any): void;
node_modules/expression-eval/index.d.ts:7:63 - error TS1109: Expression expected.
7 declare function addUnaryOp(op: string, (a: any) => any): void;
node_modules/expression-eval/index.d.ts:8:42 - error TS1138: Parameter declaration expected.
8 declare function addBinaryOp(op: string, (a: any, b: any) => any): void;
node_modules/expression-eval/index.d.ts:8:65 - error TS1005: ';' expected.
8 declare function addBinaryOp(op: string, (a: any, b: any) => any): void;
node_modules/expression-eval/index.d.ts:8:66 - error TS1128: Declaration or statement expected.
8 declare function addBinaryOp(op: string, (a: any, b: any) => any): void;
node_modules/expression-eval/index.d.ts:8:72 - error TS1109: Expression expected.
8 declare function addBinaryOp(op: string, (a: any, b: any) => any): void;
Found 8 errors.
error Command failed with exit code 2.
Here is the project
ts-example.zip
This change in index.d.ts fixed the compile errors:
type ff = (a: any) => any
declare function addUnaryOp(op: string, ff): void;
type fff = (a: any, b: any) => any
declare function addBinaryOp(op: string, fff): void;
In line (https://github.com/donmccurdy/expression-eval/blob/master/index.js#L80), when is time to evaluate an identifier, the context is assumed to be a hash (object). It would be useful to give as an option that context could be a function:
expr.eval(ast, function(identifier) {
// here use whatever strategy to evaluate identifier
})
I can make the tests and PR if you like.
Repository field is pretty useful, it allows to open github page right from npm page.
Also it helpful for people who wants to contribute.
npm WARN [email protected] No repository field.
When there are || conditions, can we have the evaluation not evaluate the right side of || if left is already true?
Thanks for this good project! In my scenario, I need to put async functions into expression. But I don't know how to do this. It seems that jsep doesn't support sync functions?
The following code generates async functions which will be injected into the expression:
The following code shows how the above async functions are injected:
Althrough we have decleared in the README.MD that do not use this package with user-provided inputs, but after i exam some project with this project, i found that many developers still use in that way, which may lead to some serious security problem. So I think that we still need to do some basic thing to prevent some dangerous action in the package itself.
I have made a tiny fix to prevent access prototype on object, which may prevent all prototype pollution and code execution.
Should we use this fix or just ignore the possible vuln?
Hello, I've noticed that the result of my expressions seems wrong when using the exponent symbol (^):
const foo = { a: 1, b: 2, c: 3 };
console.log(evaluate(parse("10 + (2 ^ a)"), foo)); // expected: 12, result: 13
console.log(evaluate(parse("10 + (2 ^ b)"), foo)); // expected: 14, result: 10
console.log(evaluate(parse("10 + (2 ^ c)"), foo)); // expected: 18, result: 11
Reproducible codesandbox: https://codesandbox.io/s/expression-eval-exponent-zof7gt?file=/src/index.js:0-350
First of all, thanks for the library @donmccurdy It's nice 💪
But I got an issue with it.
You have made ES5-compatible code in 1.2.1
but that work is not done yet.
1) let
and const
operator usage in the code
44 | const object = evaluate(node.object, context);
63 | let caller, fn;
Use var
instead, because let
and const
was introduced as part of ES6 specification.
2) Destructors usage
Destructors are also part of ES6 spec. The only usage is here:
65 | [ caller, fn ] = evaluateMember( node.callee, context );
Compare code with and without ES6 here: https://www.diffchecker.com/fDsmMQV5
I've made ES6->ES5 using Bublé: https://buble.surge.sh
If you'd like to use ES6 in your code let's precompile it with babel
. I can help you with that if you wish :)
Hi!
Is there a way to use expression-eval
to generate the expression from an AST
? Unparsing? To perform the reverse of a parse operation?
Thanks!
The processing of floating-point numbers failed
console.log('---------tesst');
const ast4 = parse('a * b +c *9.9');
const value4 = eval(ast4, {a: 5, b: 2, c: 4.9});
console.log(ast4);
console.log(value4);
----------------result---------
How do we ensure that floating-point number calculations are normal digits
there is an additional comma at line 151. it cause build error when I use this lib in Angular project
"in" is something like: https://casbin.org/docs/en/syntax-for-models#speical-grammer
r.sub.Name in (r.obj.Admins)
Is it possible to support it? Thanks!
Including the dist/
folder in source control is a regular source of confusion for new contributors, because the files are modified when building or testing changes, but shouldn't be included in PRs. These files cannot be reviewed easily, and are meant to be rebuilt by an author when publishing a new release. To avoid this confusion, the dist/
folder should be added to .gitignore
and explicitly added to the published files in package.json
. Because it's published to NPM, it will still be available from CDNs like Unpkg.
Do you consider parse to be safe enough to run on the server? The use-case is to run expression-eval parse but not eval before vm2 does parsing and evaluating. The purpose is to ensure the server-side expressions are only valid if they are valid on the client, and also to help reduce the chance of hitting a security vulnerability in vm2.
I found the need for accessing deep properties on the context which may be undefined. This module currently will throw when trying to access those properties; a behavior that treats the deep object access similar to an optional chain seemed like a good solution.
Writing this to highlight the PR (#48) I submitted a couple days ago, in the event it was missed, or anybody not checking out the PRs wanted to chime in.
Thanks for the great project here!
The addBinaryOp
in expression-eval doesn't set the precedence
parameter when it calls addBinaryOp
in jsep, which will make some valid expressions raise an exception while parsing. This can be worked around by calling jsep.addBinaryOp as well, but it would be better to not have to do that.
Reproduction:
> ee = require('expression-eval')
> ee.parse('(1 + 2 + 3)') // This returns a valid AST
> ee.addBinaryOp('+', (a, b) => a + b + 1)
> ee.parse('(1 + 2 + 3)') // This raises an exception about a missing close paren
> ee.parse.addBinaryOp('+', 9)
> ee.parse('(1 + 2 + 3)') // This returns a valid AST again
Unfortunately from glancing at the jsep source it looks like the binary_ops dictionary is stuck inside a closure so there isn't an easy way to use it as a source of default precedence values.
From TypeScript ('esnext' module), when trying to use expression-eval:
import {parse} from "expression-eval";
evalVariable(varName: string) {
let ast = parse(varName);
console.log("ast=" + ast);
}
I get the following error in the console:
Uncaught SyntaxError: The requested module '../../jsep/build/jsep.js' does not provide an export named 'default'
Just saw that the version bumps to 4.0.0. Is there any breaking change compared to v3.1.2?
expr.eval('a + b / c', {a: 2, b: 2, c: 5}); // 0.8
Line 102 in 6611345
evaluate
accept a node
instead of a string. I'm not sure which is correct.
In the change to the readme 28feab5 you show destructuring the functions instead of leaving it in an object. This would cause expression-eval eval()
to replace the native eval()
.
I've been helping to update jsep (PR) to allow for plugins to extend it further. It's not quite released yet, but it adds the option of numerous supplied plugins, so that it can support things like arrow-function, template-literals, objects, etc.
I wonder if expression-eval could be made extensible to support new node types? I was thinking that one option might be converting the switch statement to a map of { [key: keyof ExpressionType]: (node: Expression, context?: object) => any
perhaps? Or perhaps another way to allow users to add evaluators for arbitrary node types?
I could also help with support for some of the new node types if wanted?
const expr = require("expression-eval");
console.log(expr.compile("a.slice()")({a: "foo"}));
Result:
D:\Dev\node-test\node_modules\expression-eval\index.js:56
return fn.apply( null, evaluate_array( node.arguments, context ) );
^
TypeError: String.prototype.slice called on null or undefined
at slice (native)
at evaluate (D:\Dev\node-test\node_modules\expression-eval\index.js:56:19)
at Object.<anonymous> (D:\Dev\node-test\test.js:2:38)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:423:7)
Hello,
I need to use this package to evaluate expression for vue.js schema form builder.
My question is how can I set context of the expression? I mean to access to data model for example.
I've tried the following and it works
const fn = compile("value.source=='ldap'")
fn({ value : this.value })
but do it possible to a set default context like this ?
const fn = compile("source=='ldap'")
fn({ undefined : this.value })
Regards
I have an expression that retrieves the String stored in an index of an Array. The index is obtained as a result of a function call...
User.address[ User.getCurrentAddressIndex() ]
The evaluator fails in the described scenario, returning undefined.
const expr = require('expression-eval');
const ast = expr.parse( 'User.address[ User.getCurrentAddressIndex() ]' );
const User:{
address:[
'mystreet, num 23',
'myOtherStreet, num 222',
],
getCurrentAddressIndex: function(){ return 1 }
}
const address = expr.eval(ast, {User : User} );
// Expected : 'myOtherStreet, num 222'
// Returned : undefined
First thanks for this amazing project! Node-Casbin uses expression-eval as the expression evaluator. Our recent GitHub Actions failed owing to a expression-eval issue, can you take a look? Thanks!
casbin/node-casbin#231 (comment)
https://github.com/casbin/node-casbin/runs/1783266710?check_suite_focus=true
Hello,
I try use on firefox change to ${index-1} - ${name}${ext}, and images downloaded with name like this:
undefined - EmbeddedRelated_smalltab.jpg
How i can fix, to change start from 0, or something else number?
0 - EmbeddedRelated_smalltab.jpg
100 - EmbeddedRelated_smalltab.jpg
Sorry for my pure english.
const ast = parse('object.id === 1');
const context = {object: null};//
console.log( eval(ast, context)); // Error: cannot read property
Some fields in context may be null, because you can form it dynamic.
Maybe it better use optional-chaining operator in eval method
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.