0.0.81 • Published 5 months ago

nbrc-picker v0.0.81

Weekly downloads
-
License
ISC
Repository
-
Last release
5 months ago

Usage

Picker Rule

Multiple Instance

As a front-end developer, we often need to get remote JSON data from third parties. In order to ensure the correctness of the data, we need to validate and convert complex-structured JSON data for processing, storage or rendering to the UI.

If we were to validate every property of the JSON and do the necessary processing, it would be very time consuming. nbrc-picker can validate and process JSON data at the same time by defining a rule.

When the remote data changes, you can clearly know what changes have occurred in the remote json.

Usage

Pick data from a json to build a new json base on defined rule

import picker from "nbrc-picker";
// oldJson = somejson1...
// rule = somejson2...
let newJson = picker.pick(oldJson, rule, [input]);

oldJson: JSON. Original json data

rule: JSON. Describe how to create a new json

input: JSON. Optional. Dynamic data that rule depend on

Picker Rule

Picker Rule is a json that describes how to create a new json:

  1. Structure: Structure of New Json
  2. Value Path: The property path in the oldJson where to get the value for a newJson property
  3. Default Value: (Optional) The Default Value of property ( if the defined value doesn't exist in oldJson)
  4. Set Value: (Optional) Set a value for a property in newJson
  5. Value Processor: (Optional) how to process the Picked Value

For example:

import picker from "nbrc-picker"

let oldJson = {
    name: {
        first: "alice",
        last: "carter"
    },
    gender: 0,
    hobby: ["skating", "reading", "dancing"]
};
let rule = {
    firstname: 'name.first?{""}:{[ ".toUpperCase" ]}',
    lastname: "name.last",
    gender: "gender",
    hobby: {
        "1st":"hobby.0",
        "2nd":"hobby.1",
        "3rd":'hobby.2?{""}',
	"4th":'#{"Art"}'
    }
};
let newJson = picker.pick(oldJson, rule, [input]);
// structure of the rule is also the structure of newJson
// name.first is the path in oldJson where to get value for a property in newJson
// ?{""} is Default_Value definition
// #{"Art"} is Set_Value definition
// :{[ ".toUpperCase" ]} is Value_Processor definition

Value Path

Value Path is a part of the Picker Rule.

It's a property path in oldJson Where to get value for newJson property.

Pick to Create Object

import picker from "nbrc-picker"

let oldJson = {
    name: {
        first: "alice",
        last: "carter"
    },
    gender: 0,
    hobby: ["skating", "reading", "dancing"]
};
// define a rule to create New Json
let rule = {
    firstname: "name.first", // "name.first" is property path in oldJson where to get value for "firstname" property in newJson
    lastname: "name.last",
    gender: "gender",
    hobby: {
        "1st":"hobby.0", // "hobby.0" is property path in oldJson where to get value for "hobby.1st" property in newJson
        "2nd":"hobby.1",
        "3rd":"hobby.2"
    }
};
let newJson = picker.pick(oldJson,rule);
console.log(newJson);

// Output:
/**
{
    "firstname": "alice",
    "lastname": "carter",
    "gender": 0,
    "hobby": {
        "1st": "skating",
        "2nd": "reading",
        "3rd": "dancing"
    }
}
*/

Pick to Create Array

import picker from "nbrc-picker"

let oldJson = [
    {
        name: {
            first: "alice",
            last: "carter"
        },
        gender: 0,
        hobby: ["skating", "reading", "dancing"]
    },
    {
        name: {
            first: "william",
            last: "Davis"
        },
        gender: 1,
        hobby: ["football", "puzzles", "riding"]
    }
];

// Loop through items in oldJson array
let rule = [{
    firstname: "[].name.first",
    lastname: "[].name.last",
    gender: "[].gender",
    hobby: {
        "1st": "[].hobby.0",// "[].hobby.0" is property path in oldJson where to get value for "hobby.1st" property in newJson
        "2nd": "[].hobby.1",
        "3rd": "[].hobby.2"
    }
}];
let newJson = picker.pick(oldJson, rule);
console.log(newJson);

// Output:
/**
[
    {
        "firstname": "alice",
        "lastname": "carter",
        "gender": 0,
        "hobby": {
            "1st": "skating",
            "2nd": "reading",
            "3rd": "dancing"
        }
    },
    {
        "firstname": "william",
        "lastname": "Davis",
        "gender": 1,
        "hobby": {
            "1st": "football",
            "2nd": "puzzles",
            "3rd": "riding"
        }
    }
]
*/

Conditional Array Value Path

Used to specify one or more items in the oldJson Array

Example 1: Get the first person’s name whose gender is 1

import picker from 'nbrc-picker'
let oldJson = [
    {
        name: "alice carter",
        gender: 0,
        hobby: ["skating", "reading", "dancing"]
    },
    {
        name: "william Davis",
        gender: 1,
        hobby: ["football", "puzzles", "riding"]
    }
];
let rule = '[{"gender": 1}].name';
let newJson = picker.pick(oldJson, rule);
console.log(newJson);

// Output
/**
  william Davis
*/

Example 2: Get the first person whose gender is 1

import picker from 'nbrc-picker'
let oldJson = [
    {
        name: "alice carter",
        gender: 0,
        hobby: ["skating", "reading", "dancing"]
    },
    {
        name: "william Davis",
        gender: 1,
        hobby: ["football", "puzzles", "riding"]
    }
];
let rule = '[{"gender": 1}]';
let newJson = picker.pick(oldJson, rule);
console.log(newJson);

// Output
/**
{
    "name": "william Davis",
    "gender": 1,
    "hobby": [
        "football",
        "puzzles",
        "riding"
    ]
}
*/

Example 3: Get all persons whose gender are 0

import picker from 'nbrc-picker'
let oldJson = [
    {
        name: "alice carter",
        gender: 0,
        hobby: ["skating", "reading", "dancing"]
    },
    {
        name: "william Davis",
        gender: 1,
        hobby: ["football", "puzzles", "riding"]
    },
    {
        name: "Ava Julia",
        gender: 0,
        hobby: ["skating", "dancing", "riding"]
    }
];
let rule = '[{"gender": 0}][]';
let newJson = picker.pick(oldJson, rule);
console.log(newJson);

// Output
/**
[
    {
        "name": "alice carter",
        "gender": 0,
        "hobby": [
            "skating",
            "reading",
            "dancing"
        ]
    },
    {
        "name": "Ava Julia",
        "gender": 0,
        "hobby": [
            "skating",
            "dancing",
            "riding"
        ]
    }
]
*/

Default Value

if the defined path in rule doesn't exist in oldJson, you can set a default value for current property in newJson.

?{default_value}

default_value is a JSON string

nbrc-picker use JSON.parse() to parse default_value

Examples: ?{0} , ?{"a string"} , ?{undefined}

import picker from "nbrc-picker"

let oldJson = {
    name: {
        first: "alice",
        last: "carter"
    },
    gender: 0,
    hobby: ["skating", "reading"] // let's remove "hobby.2" from oldJson
};

// if "hobby.2" doesn't exist in oldJson, an error will be thrown,
// at this point, you can know the structure of oldJson has changed.
// but you can set a default value for "hobby.3rd" property in newJson
// to avoid error being thrown
let rule = {
    firstname: "name.first",
    lastname: "name.last",
    gender: "gender",
    hobby: {
        "1st":"hobby.0",
        "2nd":"hobby.1",
        "3rd":'hobby.2?{""}' // set a default value(empty string) for "hobby.3rd" property in newJson( if hobby.2 doesn't exist in oldJson ), "default value" is optional.
    }
};
let newJson = picker.pick(oldJson,rule);
console.log(newJson);

// Output:
/**
{
    "firstname": "alice",
    "lastname": "carter",
    "gender": 0,
    "hobby": {
        "1st": "skating",
        "2nd": "reading",
        "3rd": ""
    }
}
*/

Set Value

set a constant value for a property in newJson

#{constant_value}

constant_value is a JSON string

nbrc-picker use JSON.parse() to parse constant_value

Examples: #{1} , #{"a string"} , #{undefined}, #{true}

import picker from "nbrc-picker"

let oldJson = {
    name: {
        first: "alice",
        last: "carter"
    },
    gender: 0,
    hobby: ["skating", "reading"] // let's remove "hobby.2" from oldJson
};

// add "grade" property in newJson and set to 1
let rule = {
    firstname: "name.first",
    lastname: "name.last",
    gender: "gender",
    hobby: {
        "1st":"hobby.0",
        "2nd":"hobby.1",
        "3rd":'hobby.2?{""}'
    },
    grade:"#{1}" // add "grade" property in newJson and set to 1
};
let newJson = picker.pick(oldJson,rule);
console.log(newJson);

// Output:
/**
{
    "firstname": "alice",
    "lastname": "carter",
    "gender": 0,
    "hobby": {
        "1st": "skating",
        "2nd": "reading",
        "3rd": "dancing"
    },
    "grade": 1
}
*/

Value Processor

process the picked value in newJson.

:{value_processor}

A value_processor is a JSON string of array [ processor_name , parameter1 , parameter2…… ]

and nbrc-picker use JSON.parse() to parse each value_processor

processor_name : a javascript built-in Function , Method or custom Object Method,

for example: [ “.concat” , “ “ , “world“ ] or [ “Math.ceil“ ]or [ “my.func“ ]

1.if processor is a built-in Function or custom Method, example: “Number.parseFloat“ or “my.func“

a. defaultly, the picked value will pass to processor as the first parameter.

For example:user.power:{ [ “Math.pow“,2 ] }

assuming user.powerin source json is 3 , nbrc-picker will process like this Math.pow(3,2)

b. Change the position of Picked Value as a parameter of Processor.

user.power:{ [ “Math.pow.1“,2 ] }

assuming user.powerin source json is 3 , nbrc-picker will process like this Math.pow(2,3)

2.if processor is a built-in Object Method, example: “.concat”

picked value will invoke this method.

For example: greeting:{ [ “.concat“, “ “, “World“ ] }

assuming greeting in oldJson is “Hello“ , nbrc-picker will process like this ”Hello“.concat(“ “, “World“)

Built-in Processor

use built-in javascript functions or methods to process the picked value in newJson

let's say you want to concat the First Name and Last Name as "name" in newJson, you can use built-in processor to accomplish.

import picker from "nbrc-picker"

let oldJson = {
    name: {
        first: "alice",
        last: "carter"
    },
    gender: 0,
    hobby: [
        "skating", 
        "reading", 
        // "dancing"
    ]
};
// let's add a value processor for "name" property in newJson
let rule = {
    name: 'name.first:{[".concat"," ","!{name.last}"]}', // add a value processor :{[".concat"," ","!{name.last}"]}'
    gender: "gender",
    hobby: {
        "1st": "hobby.0",
        "2nd": "hobby.1",
        "3rd": 'hobby.2?{""}'
    }
};
let newJson = picker.pick(oldJson, rule);
console.log(newJson);

// Output:
/**
{
    "name": "alice carter",
    "gender": 0,
    "hobby": {
        "1st": "skating",
        "2nd": "reading",
        "3rd": ""
    }
}
*/

Custom Processor

Built-in Processor use the built-in javascript functions and methods.

If your scenario is more complicated, you can customize the value processor.

What about if you want to capitalize the first letter of first name and last name, at the sometime map the gender value(0->Female 1->Male)?

Let's do it with custom processor!

import picker from "nbrc-picker"

// custom processor
let myProcessor = {
    cap: (str) => {
        return str.split(' ').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(" ")
    },
    gender: (idx) => {
        let gs = { 0: "Female", 1: "Male" };
        return gs[idx] ?? "Unknown"
    }
};
// pass your processor to Picker, and name the processor "p" (You can name it whatever you want)
picker.setProcessor({ p: myProcessor });
// let's remove the 3rd hobby from oldJson
let oldJson = {
    name: {
        first: "alice",
        last: "carter"
    },
    gender: 0,
    hobby: [
        "skating",
        "reading",
        // "dancing"
    ]
};
// let's add a value processor for "name" property in new Json
let rule = {
    // add value processors for "name",you can chain multiple processors
    // :{[".concat"," ","!{name.last}"],["p.cap"]}
    // ["p.cap"] is your custom processor
    name: 'name.first:{[".concat"," ","!{name.last}"],["p.cap"]}', 
    gender: 'gender:{["p.gender"]}',
    hobby: {
        "1st": "hobby.0",
        "2nd": "hobby.1",
        "3rd": 'hobby.2?{""}' // defined default value by adding ?{""}
    }
};
let newJson = picker.pick(oldJson, rule);
console.log(newJson);

// Output:
/**
{
    "name": "Alice Carter",
    "gender": "Female",
    "hobby": {
        "1st": "skating",
        "2nd": "reading",
        "3rd": ""
    }
}
*/

Dynamic Processor Parameter

Processor Parameters are not always constants. it can be another rule or user input

  1. Another Rule !{rule}

    In the above example,we concat first name and last name by the flowing rule:

    name: 'name.first:{[".concat"," ","!{name.last}"],["p.cap"]}'

    the 2nd parameter for .concat Processor is "!{name.last}"

    it’s a dynamic parameter, it’s also a rule.

  2. User Input *{input_path}

    If user input alice keyword to search persons whose name contains alice,and the keyword in name are higthlighted in HTML UI:

    import picker from "nbrc-picker"
    
    let myProcessor = {
        highLight: (str, keyword = "", caseSensitive = false, color = '#000', bgColor = 'rgb(255,255,15)') => {
            keyword = keyword.trim();
            if (keyword === '') { return str; }
            return str.replaceAll(
                new RegExp(keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), caseSensitive ? 'g' : 'ig'),
                (...ms) => `<span style="color:${color};background-color:${bgColor}">${ms[0]}</span>`
            );
        }
    };
    picker.setProcessor({ p: myProcessor });
    let oldJson = [
        {
            name: "alice carter",
            gender: 0,
            hobby: ["skating", "reading", "dancing"]
        },
        {
            name: "william Davis",
            gender: 1,
            hobby: ["football", "puzzles", "riding"]
        }
    ];
    
    let newJson = picker.pick(oldJson, [{
        name: '[].name:{["p.highLight","*{keyword}"]}'
    }], { keyword: 'alice' });
    
    console.log(newJson);
    
    // Output:
    /**
    [
        {
            "name": "<span style=\"color:#000;background-color:rgb(255,255,15)\">alice</span> carter"
        },
        {
            "name": "william Davis"
        }
    ]
    */

Processor Chain

You can concat multiple value processors :{ processor1 , processor2… }saperated by comma(,)

for example: product.amount:{ [ “Number.parseFloat“ ] , [ “.toFixed“ , 2 ] }

Picked value will be passed to the first processor, and the result will be passed to the next and so on

Default Value

We pick data from old json by path. If the path does not exist, an Error will be thrown:

Data does not exist(name.first) and no default value provided(name)

At this point, you can know that the original json structure has changed.

If you don't want the error to be thrown, you can set a default value for a specific Path

?{default_value}

import picker from "nbrc-picker"

// let's remove the 3rd hobby from oldJson
let oldJson = {
    name: {
        first: "alice",
        last: "carter"
    },
    gender: 0,
    hobby: [
        "skating", 
        "reading", 
        // "dancing"
    ]
};
let rule = {
    firstname: "[].name.first",
    lastname: "[].name.last",
    gender: "gender",
    hobby: {
        "1st": "hobby.0",
        "2nd": "hobby.1",
        "3rd": 'hobby.2?{""}' // defined default value by adding ?{""}
    }
};
let newJson = picker.pick(oldJson, rule);
console.log(newJson);

// Output:
/**
{
    "firstname": "alice",
    "lastname": "carter",
    "gender": 0,
    "hobby": {
        "1st": "skating",
        "2nd": "reading",
        "3rd": ""
    }
}
*/

Combination of Default Value,Set Value and Value Processor

You can combine "Default Value","Set Value" and "Value Processor"

But it must be arranged in the following order:

?{devault_value}#{set_value}:{value_processor}

Multiple Instance

nbrc-picker is a global instance, If you need an independent instance, use createInstance method:

let newPicker = picker.createInstance();

If you need custom value processor:

let newPicker = picker.createInstance( processor );

or

let newPicker = picker.createInstance();
newPicker.setProcessor(processor);
0.0.80

5 months ago

0.0.81

5 months ago

0.0.79

5 months ago

0.0.750

5 months ago

0.0.73

5 months ago

0.0.75

5 months ago

0.0.76

5 months ago

0.0.77

5 months ago

0.0.78

5 months ago

0.0.71

5 months ago

0.0.72

5 months ago

0.0.68

5 months ago

0.0.69

5 months ago

0.0.70

5 months ago

0.0.62

5 months ago

0.0.63

5 months ago

0.0.65

5 months ago

0.0.66

5 months ago

0.0.67

5 months ago

0.0.61

5 months ago

0.0.6

5 months ago

0.0.5

5 months ago

0.0.4

5 months ago

0.0.3

7 months ago

0.0.2

7 months ago

0.0.1

7 months ago