jsonlang-js v0.6.5
👋 JsonLang
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.
⏬ Installation
npm install jsonlang-js
🎉 Features
- Typescript. It's a strongly typed npm package
- the JsonLang structure is Simple and Optimized. Its structure and rules have a shortcut to make your JSON in a small size.
- Its structure is always Consistent. i.e.
{"$R": "R1", "$I": ["value1", "value2", {"$R": "R2", "$I": [...] }, ...] }
. - Safe & Secure. Each Rule has a secure handler.
- Extendable. Easy to add new rules.
- Sync/Async. All rules in JsonLang are sync rules, but you can extend it and add async rules.
- 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.
- JsonLang: check the Structure
- 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
- ruleIdentifier: Object
{ name: string, shortcut?: string }
,name
(required) is theRule
name, andshortcut
(optional) is the shortcut. i.eSum
is thename
, and+
is theshortcut
. - ruleHandler: Sync/Async Function
(...inputs: RuleInput[]) => RuleResult)
,inputs
(required) is array of all inputs needs for the handler check Input in Structure, anddata
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:
- $R: (
String
) is the rule name itself. i.e.and
,or
,==
,>
. - $I: (
any[]
) is an array of inputs which will be passed to theRule
handler/function, their type depends on theRule
handler, or it can be a nested rule - $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 inInput[]
has a value of (null, 0, false), it will returnfalse
, else it will returntrue
.
Or or ||
- Input[]: Array (Size: Unlimited).
- Output: Boolean (true or false).
- Description: Do the
Oring
operation, if all values inInput[]
has a value of (null, 0, false), it will returnfalse
, else it will returntrue
.
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 returnfalse
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 stylevar1.var2
for nested fields and brackets with number for arraysvar1.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 stylevar1.var2
for nested fields and brackets with number for arraysvar1.var2[3].var3
. If thepath
does not exist, theSet
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 stylevar1.var2
for nested fields and brackets with number for arraysvar1.var2[3].var3
. If thepath
does not exist, theUpdate
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 stylevar1.var2
for nested fields and brackets with number for arraysvar1.var2[3].var3
. If thepath
does not exist, theDelete
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:
- Have any security issue
- Async method without timeout or with unhandled errors
- Block the event loop in backend nodejs https://nodejs.org/en/docs/guides/dont-block-the-event-loop/
- 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
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago