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?: {}): RuleResultExecute 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): voidExtend JsonLang by adding 2 params
- ruleIdentifier: Object
{ name: string, shortcut?: string },name(required) is theRulename, andshortcut(optional) is the shortcut. i.eSumis 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, anddatais the schemaless data check Data in the Execute Section
registerMany(rules: Rules): voidregisterMany 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 theRulehandler/function, their type depends on theRulehandler, 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
Outputfrom 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
Andingoperation, 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
Oringoperation, 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
Equalelement 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 Equalto 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
trueit will returnfalseand 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 Thanelement 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 Thanelement 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 Equalelement 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 Equalelement 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
pathmust follow the dotted stylevar1.var2for 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
pathmust follow the dotted stylevar1.var2for nested fields and brackets with number for arraysvar1.var2[3].var3. If thepathdoes not exist, theSetRule 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
pathmust follow the dotted stylevar1.var2for nested fields and brackets with number for arraysvar1.var2[3].var3. If thepathdoes not exist, theUpdaterule 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
pathmust follow the dotted stylevar1.var2for nested fields and brackets with number for arraysvar1.var2[3].var3. If thepathdoes not exist, theDeleterule 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);
// 136Access 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
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago