0.6.5 • Published 1 year ago

jsonlang-js v0.6.5

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

👋 JsonLang

https://jsonlang.dev

Deprecated

This package is deprecated. Use @jsonlang/core instead

It is a Typescript package that provides a simple JSON Programming Language, allowing you to execute a safe logic in Frontend or Backend (NodeJS). Furthermore, it can be stored in the database and rendered to the Frontend-Side to execute/run some business logic.

JsonLang is designed to be extendable. You can define new rules with sync/async handlers.

npm version install size npm downloads Vulnerabilities codecov Maintenance Build Programming Language License FOSSA Status Github Sponsor

Installation

npm install jsonlang-js

🎉 Features

  1. Typescript. It's a strongly typed npm package
  2. the JsonLang structure is Simple and Optimized. Its structure and rules have a shortcut to make your JSON in a small size.
  3. Its structure is always Consistent. i.e. {"$R": "R1", "$I": ["value1", "value2", {"$R": "R2", "$I": [...] }, ...] }.
  4. Safe & Secure. Each Rule has a secure handler.
  5. Extendable. Easy to add new rules.
  6. Sync/Async. All rules in JsonLang are sync rules, but you can extend it and add async rules.
  7. DRY. You can pass any rule result in a variable to be used in another rule which makes JsonLang JSON more optimized

🛠️ Methods

Execute

   execute = (jsonLang: IJsonLangParams, data?: {}): RuleResult

Execute is used to run the JsonLang and takes two parameters.

  1. JsonLang: check the Structure
  2. Data: schemaless data object to read/write to it. To get data use the Rule Data

Execute is the Sync version of JsonLang, use it to run all builtin rules and any extended Sync Rules

  executeAsync = async (jsonLang: IJsonLangParams, data?: {}): Promise<RuleResult>

Execute is the Async version of JsonLang, use it to run all builtin rules and any extended Sync or Async Rules

Extend

registerOne = (ruleIdentifier: RuleIdentifier, ruleHandler: RuleHandler): void

Extend JsonLang by adding 2 params

  1. ruleIdentifier: Object { name: string, shortcut?: string }, name(required) is the Rule name, and shortcut(optional) is the shortcut. i.e Sum is the name, and + is the shortcut.
  2. ruleHandler: Sync/Async Function (...inputs: RuleInput[]) => RuleResult), inputs(required) is array of all inputs needs for the handler check Input in Structure, and data is the schemaless data check Data in the Execute Section
registerMany(rules: Rules): void

registerMany allows registering a Map() of rules. The Map key is RuleIdentifier, and the Map value is the RuleHandler

🏗️ Structure

JsonLang have three main parameters:

  1. $R: (String) is the rule name itself. i.e. and, or, ==, >.
  2. $I: (any[]) is an array of inputs which will be passed to the Rule handler/function, their type depends on the Rule handler, or it can be a nested rule
  3. $O?: (Symbol [Optional]), is an optional field, it accept a name of variable which used to save the Rule result in a variable and can be called in any other rule by { "$R": "Var": "$I": ["variableX"] }. The output value should be unique. If you define the same value more than once, the last one will override the value of the previous one.

⚒️ Builtin Rules

Core

  • Var

    • Input[]: Array (Size: 1), for the Variable name of the Output.
    • Output: Any (depends on the output value).
    • Description: used to get the value of any Output from any rules, Check the Output part.
  • Data

    • Input[]?: Array (Size: 1) Enum of "Global" or "Local", defaulted with "Global".
    • Output: any.
    • Description: if the Input is ["Global"] it will return the schemaless data object which you pass it to the execute method, else if the input is ["Local"], it will return the value passed from the parent rule like filter in array rules.

Logical

  • And or &&

    • Input[]: Array (Size: Unlimited).
    • Output: Boolean (true or false).
    • Description: Do the Anding operation, if any value in Input[] has a value of (null, 0, false), it will return false, else it will return true.
  • Or or ||

    • Input[]: Array (Size: Unlimited).
    • Output: Boolean (true or false).
    • Description: Do the Oring operation, if all values in Input[] has a value of (null, 0, false), it will return false, else it will return true .
  • Equal or ==

    • Input[]: Array (Size: 2).
    • Output: Boolean (true or false).
    • Description: It takes an array of 2 inputs to compare if element one Equal element two or not.
  • NotEqual or =

    • Input[]: Array (Size: 2).
    • Output: Boolean (true or false).
    • Description: It takes an array of 2 inputs to compare if element one Not Equal to element two or not.
  • Not or !

    • Input[]: Array (Size: 1).
    • Output: Boolean (true or false).
    • Description: It takes an array of 1 input inverts its value. If it true it will return false and vice versa.
  • GreaterThan or >

    • Input[]: Array (Size: 2).
    • Output: Boolean (true or false).
    • Description: It takes an array of 2 inputs to compare if element one Greater Than element two or not.
  • LessThan or <

    • Input[]: Array (Size: 2).
    • Output: Boolean (true or false).
    • Description: It takes an array of 2 inputs to compare if element one Less Than element two or not.
  • GreaterThanOrEqual or >=

    • Input[]: Array (Size: 2).
    • Output: Boolean (true or false).
    • Description: It takes an array of 2 inputs to compare if element one Greater Than or Equal element two or not.
  • LessThanOrEqual or <=

    • Input[]: Array (Size: 2).
    • Output: Boolean (true or false).
    • Description: It takes an array of 2 inputs to compare if element one Less Than or Equal element two or not.

Math

  • IsNumber

    • Input[]: Array (Size: 1).
    • Output: Boolean (true or false).
    • Description: Check if the value dataType is a number or not.
  • Sum or +

    • Input[]: Array (Size: unlimited).
    • Output: number.
    • Description: Used to Sum all values. i.e. Input1 + Input2 + .... + InputN.
  • Subtract or -

    • Input[]: Array (Size: unlimited).
    • Output: number.
    • Description: Used to Subtract all values. i.e. Input1 - Input2 - .... - InputN.
  • Multiply or *

    • Input[]: Array (Size: unlimited).
    • Output: number.
    • Description: Used to Multiply all values. i.e. Input1 * Input2 * .... * InputN.
  • Divide or /

    • Input[]: Array (Size: unlimited).
    • Output: number.
    • Description: Used to Divide all values. i.e. Input1 / Input2 / .... / InputN.

Object

  • Get In Progress

    • Input[]: Array (Size: 3) {path: string, defaultValue?: any, data:{}}.
    • Output: Any.
    • Description: It accepts two inputs, the 1st one (required) is a path to get the Data, and the 2nd one (optional) is a default value of the path is not found. the path must follow the dotted style var1.var2 for nested fields and brackets with number for arrays var1.var2[3].var3
  • Set In Progress

    • Input[]: Array (Size: 3) {path: string, value: any, data:{}}.
    • Output: Any.
    • Description: It accepts two inputs. The 1st one (required) is a path to update/mutate the Data, and the 2nd one is the value to set. the path must follow the dotted style var1.var2 for nested fields and brackets with number for arrays var1.var2[3].var3. If the path does not exist, the Set Rule will create it.
  • Update In Progress

    • Input[]: Array (Size: 3) {path: string, value: any, data:{}}.
    • Output: Any.
    • Description: It accepts two inputs. The 1st one (required) is a path to update/mutate the Data, and the 2nd one is the value to update. the path must follow the dotted style var1.var2 for nested fields and brackets with number for arrays var1.var2[3].var3. If the path does not exist, the Update rule won't do anything.
  • Delete In Progress

    • Input[]: Array (Size: 2) {path: string, data:{}}.
    • Output: Any.
    • Description: It accepts two inputs, a path to mutate the Data by deleting a field in the request path. the path must follow the dotted style var1.var2 for nested fields and brackets with number for arrays var1.var2[3].var3. If the path does not exist, the Delete rule won't do anything.

Array

  • All

    • Input[]: Array (Size: Unlimited).
    • Output: Array (Size: Unlimited).
    • Description: It takes an array of inputs and returns them again. It is used to run a list of nested Rules.
  • Filter

    • Input[]: Array (Size: 2) {elements: any[], rule: IJsonLangParams}.
    • Output: Any[].
    • Description: It accepts array of elements with any type to filter them using nested/inner rules, the filter rule will pass each elements as a Data with scope Local, to access it by the inner rules, you will need to use Data Rule with scope local, check this example.
  • Map

    • Input[]: Array (Size: 2) {elements: any[], rule: IJsonLangParams}.
    • Output: Any[].
    • Description: It accepts array of elements with any type to map them using nested/inner rules, the filter rule will pass each elements as a Data with scope Local, to access it by the inner rules, you will need to use Data Rule with scope local.
  • Foreach

    • Input[]: Array (Size: 2) {elements: any[], rule: IJsonLangParams}.
    • Output: true.
    • Description: It accepts array of elements with any type to iterate over them using nested/inner rules, the filter rule will pass each elements as a Data with scope Local, to access it by the inner rules, you will need to use Data Rule with scope local.
  • Flatten

    • Input[]: Array (Size: 2) {elements: any[], level?: number}.
    • Output: true.
    • Description: It accepts array of elements with any type to flatten this array with any level.

💻Examples

One Level Example

import { JsonLang } from 'jsonlang-js';

const jsonLang = new JsonLang();

jsonLang.execute( { "$R": "LessThan" , "$I": [10, 20] } ); // true

// or for short
jsonLang.execute( { "$R": "<" , "$I": [10, 20] } ); // true

// or use the async function
jsonLang.executeAsync( { "$R": "<" , "$I": [10, 20] } )
  .then(result => {
    console.log(result); // true
  }); 

Nested Levels Example

import { JsonLang } from 'jsonlang-js';

const jsonLang = new JsonLang();

const result = jsonLang.execute({ 
  $R: '+',
  $I: [
    {
      $R: '+',
      $I: [
        1,
        { $R: '*', $I: [2, 3] },
        5
      ]
    },
    {
      $R: '+',
      $I: [
        1,
        { $R: '*', $I: [3, 3], $O: 'x' },
        5
      ]
    },
    { $R: 'Var', $I: ['x'] },
    { $R: 'Get', $I: ['user.age', null, { $R: 'Data', $I: ['Global'] }] }
  ]
}, { user: { name: 'test', age: 100 } });

console.log(result);
// 136

Access Inner Data

import { JsonLang } from 'jsonlang-js';

const jsonLang = new JsonLang();

const result = jsonLang.execute({ $R: 'All', $I: [
  { 
    $R: 'Filter',
    $I: [[1, 3, 5], { $R: '>', $I: [{ $R: 'Data', $I: ['Local'] }, 2] }]
  },
  { 
    $R: 'Filter',
    $I: [
      { $R: 'Get', $I: ['data.test', null, { $R: 'Data', $I: ['Global'] }] },
      { $R: '<', $I: [{ $R: 'Data', $I: ['Local'] }, 500] }
    ]
  }
] }, { data: { id: 'test', test: [100, 300, 700] } });

console.log(result);

// [ [ 3, 5 ], [ 100, 300 ] ]

Extend Rules Example

import { JsonLang } from 'jsonlang-js';

const jsonLang = new JsonLang();

jsonLang.registerOne({ name: 'Test', shortcut: 't' }, (input: any) => {
  return `${input} Test`
});

const result = jsonLang.execute({ 
  $R: 'Test',
  $I: [
    { $R: 'Get', $I: ['user.age', null, { $R: 'Data' }] }
  ]
}, { user: { name: 'test', age: 100 } });

console.log(result);
// 100 Test

🧱 Customization

You can extend JsonLang and add any logic you want from well-known sync/async packages like lodash, moment, ajv, axios, mysql, mongoose, ...etc.

Just use the register functions and follow its structure to add whatever you want.

⚠️ Warnings

JsonLang can be extended with any function, and you can override the existing rules, but make sure that any method you will add won't:

  1. Have any security issue
  2. Async method without timeout or with unhandled errors
  3. Block the event loop in backend nodejs https://nodejs.org/en/docs/guides/dont-block-the-event-loop/
  4. abuse the CPU or the memory

🔌 Compatibility

This library uses Array.map and Array.reduce, so it's not exactly Internet Explorer 8 friendly.

📗 What's Next?

  • Adding more math, logic, object, array, date, and casting extensions.
  • Allow importing packages to extend JsonLang easily.
  • Provide plugins/extensions to wrap well-known packages like MathJs, Jsonata, Axios, Lodash, MomentJs, ...etc.
  • Make a UI Editor generate the JSON of JsonLang.
  • Support building tasks & workflows can be run in the frontend or backend.
  • Support logger and logger view to show you the workflow progress and its incidents.
  • Support connectors to allow you to create your own tasks in any place, and jsonlang flow can call it by connectors (HTTP, Pub-Sub, grpc, ...etc)
  • Support a scalable workflow engine with builder and auditing built on top of JsonLang can save logs, and allow users to retry workflow instances and resolve incidents.
  • Public website has good documentation. For example, the playground to try JsonLang, use-cases session has many ideas for using JsonLang.

📜 License

JsonLang is MIT licensed

0.6.5

1 year ago

0.6.4

1 year ago

0.6.3

1 year ago

0.6.2

1 year ago

0.6.1

1 year ago

0.6.0

1 year ago

0.5.5

1 year ago

0.6.1-rc.0

1 year ago

0.5.4

1 year ago

0.5.3

1 year ago

0.5.2

1 year ago

0.5.1

2 years ago

0.5.0

2 years ago

0.4.0

2 years ago

0.3.0

2 years ago

0.2.6

2 years ago

0.2.5

2 years ago

0.2.4

2 years ago

0.2.3

2 years ago

0.2.2

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago

0.0.1

2 years ago