json-logic-js icon indicating copy to clipboard operation
json-logic-js copied to clipboard

Any thoughts on Javascript -> json logic conversion?

Open ben-pr-p opened this issue 8 years ago • 15 comments

I believe it should be possible to programmatically serialize a subset of Javascript (a function that returns a Number or Boolean and contains no loops or external function calls) into json logic, no?

This would make storing and sandboxed execution of simple things nice.

Any thoughts before I begin work?

ben-pr-p avatar Dec 12 '16 18:12 ben-pr-p

I can't quite visualize it. Could you show me some pseudocode what you'd like to be able to accomplish with it?

jwadhams avatar Dec 13 '16 06:12 jwadhams

const isEvenJS = `(num) => num % 2 == 0` // this could come from a user as well

const isEvenJSON = proposedModule.serialize(isEvenJS)

console.log(isEvenJSON)
// prints {"==": [{"%": [{"var":"num"}, 2]}, 0]}

You'd traverse the AST produced by Babel or another parser and convert it to JSON Logic

ben-pr-p avatar Dec 13 '16 15:12 ben-pr-p

WOW. That would be cool. Having never worked on a parser before, I was happy to just hand write things into a syntax tree, but there sure are cases where just writing something in JavaScript syntax, then storing, transmitting, or manipulating it as JSON would be awesome.

I can think of two examples I've heard of subsetting JavaScript: Doug Crockford's AdSafe subset and I know John Resig is doing some neat things at Khan Academy but I can't find the article I dimly remember from ~5 years ago where he talks about neat tricks using the with statement...

I wonder if variable reference is going to need to get more sophisticated than the current implementation of var. E.g., in the trivial example I'm not clear in my own mind whether "num," as a formal parameter, should be obfuscated or normalized in some way that clearly differentiates it from "num" as a property on the expected data object. Trivial example doesn't need to care, but is that sustainable?

A different trivial example that plays to JsonLogic's current strengths might be:

const isEvenJS = `data.num % 2 === 0` // this could come from a user as well

const isEvenJSON = proposedModule.serialize(isEvenJS)

console.log(isEvenJSON)
// prints {"===": [{"%": [{"var":"num"}, 2]}, 0]}

Where serialize is cool with properties and array indices on data, but consistently forbids things like num or window.location

jwadhams avatar Dec 13 '16 17:12 jwadhams

My understanding from the documentation is that data that is not object-like (objects + arrays) cannot be a parameter to apply – so for example some logic.apply(rules, 4) is prohibited. If my understanding is correct, I will be sure to preserve that requirement when parsing input Javascript (the function cannot access the parameter directly, but must access either a property or index).

Is there a reason, however, you decided against logic.apply(rules, 4) cases? I suppose it would require a reserved parameter name like input or data or something which could make things tricky.

ben-pr-p avatar Dec 13 '16 17:12 ben-pr-p

And yeah, I'm pretty sure any JS serialized would either fail or be safe since any non-safety either requires some global variable access (will fail) or a while (1) {} style thing which will also fail

ben-pr-p avatar Dec 13 '16 17:12 ben-pr-p

Ideas for simple names for this companion library? js-to-json-logic feels a bit wordy

ben-pr-p avatar Dec 13 '16 17:12 ben-pr-p

I just haven't had a case where I needed something like logic.apply(rules, 4) in production. I suspect it would be easy to modify var so this worked:

jsonLogic.apply({"var":""}, 4) // want to return 4

(I'm a little surprised it doesn't accidentally work, based on how I remember implementing the dot-notation code)

Would js2json be a reasonable library name?

jwadhams avatar Dec 13 '16 20:12 jwadhams

Turns out js2json is taken on NPM: https://www.npmjs.com/package/js2json

jwadhams avatar Dec 13 '16 20:12 jwadhams

This is a really interesting topic, hope we can get it done!

jasonslyvia avatar Feb 04 '17 08:02 jasonslyvia

Is this being worked on? I'm asking it because recently I implemented something similar (but with fewer operations for now). The user can input a data and a logic using infix notation. Then I convert the infix logic to a proper JSON and display it for the user. I also show the result of the logic being applied to the data for debuging reasons. Below are some screenshots of what I've got:

  1. Simple multiplication: image

  2. Maps the [1,2,3] array to [2,4,6], filters to get only [4,6] and reduces it to (6*(4*(0+1)+1)) image

With what I have, I currently support the following operators (ordered by precedency): *, /, %; +, -, cat, in, substr; ===, !==, ==, !=, <, >, <=, >=, or, and; ? followed by :, filter, map, reduce followed by initial, method followed by arguments.

With my approach, only if, reduce and method are currently supporting three arguments. The rest uses only 2. I'm also parsing arrays, objects, and strings (but only strings that don't contain any spaces for now); the rest are treated as variables. E.g: image image

Is there any interest on joining this with jsonLogic? Has anyone started anything similar?

lucas2595 avatar Jun 10 '19 17:06 lucas2595

@lucas2595 that looks great! I think it's very close to what the OP was proposing. It would be amazing if you could share your code.

felix-last avatar Nov 25 '19 23:11 felix-last

@felix-last here you go: https://github.com/lucas2595/js2jl

lucas2595 avatar Nov 28 '19 02:11 lucas2595

@lucas2595 great, thank you! I will look into it and see if our use case may yield some PRs as well.

felix-last avatar Nov 28 '19 13:11 felix-last

I managed to build a Node.js module that uses Babel to parse JavaScript expressions and then turn the AST into into JSON Logic rules. Repo here: https://github.com/krismuniz/js-to-json-logic

krismuniz avatar Jan 13 '20 00:01 krismuniz

Is there any package that can covert functions in JS to JSON Logic?

CuriousLearner avatar Apr 27 '21 10:04 CuriousLearner