Giter VIP home page Giter VIP logo

json-logic-engine's Introduction

Hey there ๐Ÿ‘‹

I'm Jesse! I'm a Software Architect & a total tech geek! I specialize in cloud architecture & back-end systems, but I love working on dev tools to make life better for other devs.

My GitHub is not necessarily a showcase of my cleanest code (I work on some of these side projects in my spare time), but it is a portfolio of some of my passion projects.

Some of my โค๏ธ projects are:

If you're looking for some of my cleaner projects:

  • Doczen is designed with plugins to sync your documentation from your repo to other services,
  • deejay-file-query is a tool similar to jq that allows you to use Deejay (a scripting language I developed) to remix your data.
  • simple-password-rules is a simple declarative library for defining password rules. It pairs well with JSON Logic Engine.
  • plural-squirrel is a boring pluralization library ๐Ÿ˜‰

There are a handful of other libraries and utilities on my GitHub like nspdh, DiscreteCrypt, and json-power-query, but they may not be as actively maintained / showcase as well.

json-logic-engine's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

json-logic-engine's Issues

[Feature Request] Get Function From Logic

Hi,

Loving this library, been very helpful for our use case.

Am wondering though if it is possible to get the string output of a function to be run from the JSON logic?

Example:

const engine = new LogicEngine();
engine.addModule('', Math, { deterministic: true, sync: true });

    const logic = {
      abs: {
        '/': [
          {
            '+': [{ '*': [-1, { var: 'test' }] }, 2000]
          },
          20
        ]
      }
    }

// Maybe Something Like, Which Would Print --> abs(-test+2000 / 20)
console.log(engine.getFunction(logic));

Combine and/or to create more complex models

Hey,

I am currently working on a project, in which I am trying to build rules models (a bit like rules for a firewall) and I did not find, in the docs, an answer to some of my questions :

  • Is it possible to combine or / and ? For example to make a rule which would be: the variable (a > 0 and b < 4) OR (b == 5 and a < 10) with multiples rules (here just two, but we can imagine more OR here)

  • Do you use any standard that can be parsed in another language ? For example, generate the json using JS/react, but apply rules with data/schema in Golang ?

  • Do you known if there is a compact and good UI generator to output this kind of schema (if the schema match some standards) or do I need to recreate something my myself ?

Hope you can help me to choose the right library !

[bug] Conditional then/else only works with primitives

@TotalTechGeek awesome job with the traversal stuff! We made the switch to this library for that functionality.

if/and/or works as expected if it returns a string, number, or boolean. However, if the if conditional returns an object, it returns undefined because https://github.com/TotalTechGeek/json-logic-engine/blob/master/defaultMethods.js#L53 returns this as a context for another rule. It seems to me that the expected behavior would be that if the context is not a rule, it should just return the object.

TLDR; If I use JSON logic conditional that returns an object that is not a rule then I get the object back, if I use JSON Logic Engine I do not.

This might all be fixed if _parse would just return data if not satisfied.

Quick way to reproduce the issue is:

 
    const data = {
      first_name: true
    }

    const rule = {
      if: [
        {
          "===": [
            {
              var: "first_name"
            },
            true
          ]
        },
        { first_name: "scott" },
        { first_name: "no idea" }
      ]
    }

    const result = logic.run(rule, data)

    console.log(result) // 'undefined'

Accessing variables in Object with key containing a dot

I encountered an issue related to accessing variables within an object where the key contains a dot. The logical query looks like this:

{
    "var": "hello.world"
}

And the payload is:

{
    "hello": {
        "world": "i'm here!"
    },
    "hello.world": "ups!"
}

Currently, there is no access to the hello.world variable. I believe it would be beneficial to adopt the convention used in the dot-prop package, where access to such a key is possible by including a double backslash before the dot in the key. Therefore, for the mentioned query, it should look like this:

{
    "var": "hello\\.world"
}

Direct `eval` gives warnings when being bundled with esbuild

This library's use of direct eval gives warnings when bundled with esbuild:

โ–ฒ [WARNING] Using direct eval with a bundler is not recommended and may cause problems [direct-eval]

    vendor/json-logic-engine.js:672:21:
      672 โ”‚   return declareSync(eval(final)(state, values, methods, gen, notTraversed, Override, asyncIterators), !buildStat...
          โ•ต                      ~~~~

  You can read more about direct eval and bundling here: https://esbuild.github.io/link/direct-eval

Explanation:

Although the expression eval(x) looks like a normal function call, it actually takes on special behavior in JavaScript. Using eval in this way means that the evaluated code stored in x can reference any variable in any containing scope by name.

Example of the different behavior of direct vs indirect eval:

function direct() {
    const x = 123
    return eval('x')
}

direct() // 123

function indirect() {
    const x = 123
    return globalThis.eval('x')
}

indirect() // Uncaught ReferenceError: x is not defined

Content Security Policy of your site blocks the use of 'eval' in JavaScipt

Hi,

I am currently working on an Angular (v16.2.9) application that uses the json-logic-engine library.

While implementing a Content Security Policy (CSP), I discovered that the library's use of eval is causing a violation of the CSP guidelines.

Is there any possibility that the library could be refactored to eliminate the use of eval?

The repository includes two instances of the eval function:

https://github.com/TotalTechGeek/json-logic-engine/blob/master/utilities/chainingSupported.js

const getIsOptionalChainingSupported = () => {
  ...  
    const isUndefined = globalThis.eval('(test) => test?.foo?.bar')(test)
  ...
}

and:

https://github.com/TotalTechGeek/json-logic-engine/blob/master/compiler.js

function processBuiltString (method, str, buildState) {
  ...
  return declareSync(globalThis.eval(final)(state, values, methods, gen, notTraversed, Override, asyncIterators, r, rAsync), !buildState.asyncDetected)
}

Any help would be greatly appreciated.

[Feature Request] Generate Logic From Input

Hi,

Feel free to close this if not relevant or outside the scope of this library, but would it be possible given an input formula to return the json logic? Similar to libraries such as mr-parser?

Right now on the client facing side for generating a formula we essentially have building blocks of allowable functions/parameters which they can compose and we generate the logic with, but if this would be non-trivial to add then that would be great.

For Example:

engine.generateLogic('abs(-test+2000 / 20)')

/*
Would Return:
{
      abs: {
        '/': [
          {
            '+': [{ '*': [-1, { var: 'test' }] }, 2000]
          },
          20
        ]
      }
    }

*/

Help others discover this library

After evaluating a number of options I luckily found your repo.

With the .build() method execution time went down significantly thus I'm quite happy with your library so far.

For my use case, a combination of https://github.com/mithunsatheesh/node-rules and https://github.com/TotalTechGeek/json-logic-engine makes up quite a robust rules engine.

[Bug] Yield is a reserved word

The use of the class Yield causes an error when building in some instances where strict mode is enabled. (https://stackoverflow.com/questions/33316765/why-is-es6-yield-a-reserved-word-when-called-in-this-context)

or instance, my react native apps keeps failing to build because of it:

error ./node_modules/json-logic-engine/dist/cjs/index.js: Yield cannot be used as identifier inside generators in file ./node_modules/json-logic-engine/dist/cjs/index.js at 683:16.
Error: Yield cannot be used as identifier inside generators in file ./node_modules/json-logic-engine/dist/cjs/index.js at 683:16
    at minifyCode (/node_modules/metro-transform-worker/src/index.js:100:13)
    at transformJS (/node_modules/metro-transform-worker/src/index.js:321:28)
    at transformJSWithBabel (/node_modules/metro-transform-worker/src/index.js:412:16)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Object.transform (/node_modules/metro-transform-worker/src/index.js:573:12)

Expand the get method, add support for 'var' in the second parameter

Description:
Currently, the get functionality works correctly, but in cases where the second parameter is provided as a string, I need to use other logical blocks as well.

test('get operator w/ object key as string', async () => {
  const f = await logic.build({ get: [{ var: 'selected' }, 'b'] })

  expect(await f({
    selected: {
      b: 2
    }
  })).toEqual(2)
})

test('get operator w/ object key as var', async () => {
  const f = await logic.build({ get: [{ var: 'selected' }, { var: 'key' }] })

  expect(await f({
    selected: {
      b: 2
    },
    key: 'b'
  })).toEqual(2)
})
โœ“ get operator w/ object key as string (3 ms)
โœ• get operator w/ object key as var (1 ms)

I have attempted to modify the get method to include additional conditions in the second parameter, but due to its complexity, I have not been successful. This enhancement would provide more flexibility and allow for the use of various logical blocks in the second parameter.

In my use case, I have an object where the keys represent variant IDs, and the values represent the selected variants. During page rendering, I need to dynamically determine which variant is selected to obtain a true or false value. Therefore, it's crucial for the second parameter of the get method to accept a variable rather than a static value.

Additionally, I believe that some methods can be optimized. For example, the defaultValue, key or obj variables are declared (in get method) but only used when data is an array; otherwise, it is unnecessary. If you don't mind, I can work on this in my free time.

Question: Scope regarding custom method

I'm new to this package, so please be gentle.

My use case is to inject certain metadata (Record<string,unknown> or similar) for all compiled logic executions to be accessible by custom methods. I thought I may be able to access the function's data via the context. I do see the data in my debugger, but it's the value of a json_logic_override symbol, so I wanted to inquire about it.

What would be a good pattern to allow the custom method access to the data passed to the function returned from compiled logic (or at least some property that is populated during the logic compilation?)

Matching documents in array

There is some operator that iterates over an array.

var: ''

Empty var: '' is confusing, a special character like $this could make it more explicit.

test('some true', () => {
      const answer = logic.run({
        some: [
          [1, 2, 3],
          {
            '>': [
              {
                var: '$this'
              },
              2
            ]
          }
        ]
      })

      expect(answer).toBe(true)
    })

Regarding the nested object, I'd expect something like this:

test('some true', () => {
      const answer = logic.run({
        some: [
          [{ a: 5 }, { a: 1 }],
          {
            '>': [
              {
                var: '$this.a'
              },
              2
            ]
          }
        ]
      })

      expect(answer).toBe(true)
    })

What do you think?

Can't get json-logic-engine to work with this logic

Hi there! I am evaluating json-logic-engine and I am finding that the following logic compiles but crashes at runtime. Same rule/data works in json-logic-js.

Logic:

{
    "map": [
        {
            "var": ""
        },
        {
            "*": {
                "cat": [
                    {
                        "var": "a"
                    },
                    " ",
                    {
                        "var": "b"
                    }
                ]
            }
        }
    ]
}

Data:

[
    {
        "a": "foo",
        "b": "bar"
    },
    {
        "a": "fizz",
        "b": "buzz"
    }
]

Error:

Uncaught TypeError: ("" + ((intermediate value) ?? null) + " " + ((intermediate value) ?? null)).reduce is not a function

Inconsistent behavior when using the "in" string operation

Overview

There's an inconsistency between the json-logic-js and json-logic-engine when using the 'in' string operation. It appears to be undefined behavior according to https://jsonlogic.com/tests.json but the way json-logic-js behaves is more in line with what I expected the results to be.

Steps to reproduce

JsonLogic JS

  1. Go to the JsonLogic playground
  2. Add the rule: {"in":["Spring", { "var": "city" }]}
  3. Do not define data
  4. Click "Compute"

You should see "false" as the output. Adding { "city": "Springfield" } as Data and recomputing returns "true".

JSON Logic Engine

  1. Go to the JSON Logic Engine playground
  2. Add the logic section: {"in":["Spring", { "var": "city" }]}
  3. Remove the predefined data. (this isn't required but makes for an easier comparison)
  4. Click "Execute"

You should see "true" as the output and an expected error in the dev console. Adding { "city": "test" } as Data and recomputing returns "false" with no errors. Adding { "city": "Springfield" } as Data and recomputing returns "true".

The console error is:

main.3cfcfd21.js:2 Uncaught TypeError: Cannot read properties of null (reading 'includes')
    at eval (eval at processBuiltString (common.78e4810e.js:1:68555), <anonymous>:1:90)
    at Object.built (VM161 common.78e4810e.js:1:436054)
    at g (VM161 common.78e4810e.js:1:60808)
    at Object.He (main.3cfcfd21.js:2:81052)
    at Ye (main.3cfcfd21.js:2:81206)
    at main.3cfcfd21.js:2:99391
    at Cr (main.3cfcfd21.js:2:99485)
    at Or (main.3cfcfd21.js:2:99899)
    at main.3cfcfd21.js:2:105547
    at ze (main.3cfcfd21.js:2:181021)

Summary

JSON Logic Engine isn't validating the runtime input type from user supplied context. JsonLogic tends to return a falsy value when user supplied context is invalid for a given ruleset. This is important for our use case because the people writing the rules may not be the ones defining the context.

Supply an ESM Version

Since the JS ecosystem is moving towards the standardized ESModules, it would be great if this library could supply a version that is compatible with the standard.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.