TomFrost / Jexl

Javascript Expression Language: Powerful context-based expression parser and evaluator
MIT License
561 stars 92 forks source link

Version 2.0 #39

Closed johannesschobel closed 5 years ago

johannesschobel commented 6 years ago

Dear @TomFrost and community,

i recently stumbled upon this library, as i was searching for a javascript'y solution for JEXL known from Java (e.g., http://commons.apache.org/proper/commons-jexl/ )

I must admit - this package looks awesome and i really like the approach. However, before using this package in my own project, i would like to ask some questions, which may be crucial for the application i am building:

1) How far away is version 2.0 of this package? I found respective branch (and PR) on GitHub. Yet, the master and 2.0 branch are last updated in September 2017. I also found a comment (from October '17), where you stated that you are approx 95% finish with the 2.0..

2) Is there support for "common" functions, like min / max / avg / sum / count / ... in rules?

3) Is it possible to "extend" the functionality to add own "functions" (cf. Question 2)? For example, i want to have a checkIfXpplies(a, b, c, d) function that may contain a more sophisticated logic.

Thank you very much for your time and effort on this project. I know, that providing open-source software (and its maintanance) may be quite frustrating - but keep the good work up! This package is really awesome and i can really see its use in various applications :+1:

Cheers from Germany

TomFrost commented 6 years ago

Hey Johannes!

Believe it or not, I wrote and named this Jexl before ever learning about Apache Jexl. Teaches me to pick a name without googling it first ;-).

Let me start by answering your questions:

  1. I actually changed jobs in September 2017 and went from having 1-2 weeks of work remaining to finalize Jexl 2, to "Let's pause this while I focus on diving into new challenges at my new company". I'm still not ready to pick up where I left off tomorrow, but I have a very active need for Jexl starting next month, and will certainly push out 2.0 then. Until then, Jexl in its current form is used by many individuals and companies large and small that I've heard from, so 2.0 is not going to change the expression language at all. The only breaking changes will be very, very deep and not felt by most users.

  2. Jexl, at this point, does not bake in any transforms by default. Those functions are very very easy one-liners to add from userland using the transforms system, they just don't come with Jexl out of the box. I've been considering changing this, but frankly, Jexl has become fairly popular and this request is incredibly rare. It appears most folks prefer to plug in only the transforms they need.

  3. Yep, that's what transforms and custom operators are! Jexl does not have the concept of anonymous functions, but almost any anonymous function you think you need can be re-interpreted as a transform. For example, if you wanted to sum up all the numbers in an array, you could define a sum transform like this:

jexl.addTransform('sum', (ary) => ary.reduce((acc, num) => acc + num, 0))

And then use it like this:

const result = await jexl.eval('[1, 2, 3]|sum')
// result === 6

...of course you could replace the literal array with a reference to an array variable too. Transforms can return a value synchronously, or return a promise if you're pulling the result from a database or api call.

Please don't hesitate to let me know if you have any other questions or concerns!

johannesschobel commented 6 years ago

Hey Tom,

wow, thank you very much for your detailled response regarding my questions.

I knew (Apache) JEXL from another project and was quite happy, that i found a "JavaScript Clone" with your package, haha..

Regarding 1) To summarize, jexl 2.0 will be out by end of April or something like this? So we may start with 1.x and then easily move to 2.0? Or would you suggest waiting till the 2.0 is out? How about the currently pending PRs? Especially the one with the $ in front of variable names might be quite important for me.. Are there plans to implement these pending requests?

Regarding 2 & 3) Ok, i see.. I didn't know that you would use Transformers in order to cope with this requirement. However, in my specific application scenario, this may not be applicable, because of the following reasons: We have a quite complex application that generates rules (e.g., in the form like this:

max($a, $b, $c) > 5

in order to check, if the max-value of respective variables is higher than 5, or

withinBounds($x, $y, $x1, $x2, $y1, $y2);

to check if a point [$x, $y] is within the bounds [x1-x2; y1-y2] and so on..

Unfortunately, the application that generates these rules cannot be adapted to change the use a format like this

[$a, $b, $c]|max

Do you have any suggestions for this specific use-case? I am pretty sure that others will also have the need for such rules that may use other functions.

Thank you very much for your time and effort!

All the best, Johannes

TomFrost commented 6 years ago

Yep, Jexl 2.0 will be out in the next couple months, but all the planned breaking changes will be deep under the hood -- for example, I'm looking to change the - negative sign from something the lexer has to specifically recognize to a unary operator, which will produce small changes in how the parser handles tokens that can be either unary or binary. Unless you are deeply customizing Jexl, I am not expecting any major breaking changes that will impact the API calls used to evaluate expressions, or the expressions themselves.

I am looking to address most of the open issues/PRs in 2.0; many of them are simple/easy to get out now (such as the $ one), but I'd prefer not to put any more code into 1.x as porting those changes to 2.0 produces annoying conflicts.

To your 2), unfortunately I have no plans for Jexl to support anonymous functions in 2.0. But, please keep in mind that transforms can have arguments. So for your withinBounds function, for example, you could do this: [x, y]|withinBounds(x1, x2, y1, y2). You simply add more arguments to the transform function once you set it. The first argument will always be the value being operated on (in this case [x, y]), and the follow arguments will be the arguments passed to the transform in the expression. So defining that transform would look like:

jexl.addTransform('withinBounds', ([x, y], x1, x2, y1, y2) => { /* ... */ })

If writing your max function as a no-argument transform function for an array doesn't work, you could do this instead... but it would not be quite as beautiful:

jexl.addTransform('max', (...args) => Math.max(...args))

jexl.eval('0|max(a, b, c)').then( /* ... */ )

What do you think?

johannesschobel commented 6 years ago

Dear Tom,

thank you (again) for your detailled answer and explanation. I can totally see your point in "not merging" the pending PRs, but wait for the v2.0 and then implement them on the new code base.

I have seen the "arguments" for transformers - however, this may not be flexible enough.. Same with the 0|max(...) approach - this might not be flexible enough..

Consider the following example: We have a rule that may look like this (this example is rather constructed, but you'll get the point)

(max(a, b, avg(c, d, e), f) > 7) && (x == true)

As far as i have understood, every function call (i.e., that would be a transformer!) must be written with a "prefix" (e.g., 0|) that is passed to the transformer.. In given example above, this would look like this:

((0|max(a, b, 0|avg(c, d, e), f) > 7) && (x == true))

Is this correct? Or would

((0|max(a, b, avg(c, d, e), f) > 7) && (x == true))

also be valid? Problem is specifically with "nested" function-calls.. I am a little bit confused :dizzy:

Thanks for your help and kind regards, Johannes

rajat27 commented 6 years ago

Hi Tom,

Thank you very much for JavaScript Jexl. The package is great! After reading the above comments, I just wanted to know when the v2.0 is expected?

By-the-way, I am just curious (for my own sake), will you update the name too so it isn't same as the Java Jexl? ;)

Thanks again for your work and effort into this.

Cheers, Rajat

TomFrost commented 5 years ago

Hi everyone! It's a bit later than I'd planned, but v2.0 of Jexl is now out. No Earth-shattering new features in this release, but the breaking changes allowed a big modernization of the codebase and dropping support for versions of Node that have fallen off the LTS schedule. It should now be easier for myself and others to add new features :)