object-bee v1.0.0
object-bee.js is a lightweight, flexible library for manipulating plain-object data in JavaScript.
Why?
Manipulating data may need a lot of conditional judgment in usual, and it would bring a great costs of maintenance to the our project, as below:
function fixData (data) {
if (data && data.info && data.info.name) { // mess!
data.info['modify-name'] = data.info.name;
delete data.info.name;
}
if (data && data.info && data.info.person && data.info.person.age) { // mess!
delete data.info.person.age;
}
}To help improving maintainability and readability, object-bee access data by the structure of data itself, and deal with the value inner data only when the value exists —— just like bee finding flower :)
Rewrite the code above by object-bee:
const bee = require('object-bee');
function fixData (data) {
bee(data, {
info: {
name: bee.rename('modify-name'),
person: {
age: bee.remove()
}
}
});
}The code becomes more meaningful and readable.
Installation
NPM install
npm install object-bee -SCDN provided by unpkg:
<script src="https://unpkg.com/object-bee/dist/object-bee.min.js"></script>
Usage
Using function to manipulate data can contain more complex logic.
As object-bee iterating over all of key / value pairs, Handler function accepts each value and key as arguments, like function (value, key) {}, and the return value would replace the original value of data.
const bee = require('object-bee');
data = {
a: 1,
b: 2,
sum: -1
};
bee(data, {
sum () {
return this.a + this.b;
}
});
data.detail.sum === 3; // trueContext provide those features as below:
this: a reference to current datathis.$root: a reference to root datalet data = { name: 'object-bee', detail: { bar: 'woo' } }; bee(data, { detail: { foo () { this.bar === 'woo'; // true this.$root.name === 'object-bee'; // true this.$root.detail.bar === this.bar; // true } } })this.$UNDEFINED:undefinedreturned by function will be ignore, If you want replace the original value withundefined, you should returnthis.$UNDEFINEDinstead, for examples:let data = { foo: 1, bar: 2 }; bee(data, { // no modify foo () {}, // return 'this.$UNDEFINED' explicitly to assign undefined to data.bar bar () { return this.$UNDEFINED; } }) // => { foo: 1, bar: undefined }this.$config: specify config inner function:bee(data, { info () { this.$config({ name: bee.rename('foo') }); } });this.$remove(): support to remove data, see action.remove below.this.$rename(newName): support to rename, see action.rename below.this.$ensure(): ensure current key to exist, see action.ensure below.this.$mirror([path]): reuse config, see action.mirror below.bee(data, { foo () { this.$rename('bar'); this.$remove(); this.$ensure(); this.$mirror(); } });
Actions
object-bee provide several shorthand to simplify the usage of function. There are 3 types of actions, use in value place, key place, or normal place.
In value place
#remove: remove current key from data.bee(data, { unnecessaryKey: bee.remove() });#ensure: ensure the key exist no matter whether it is undefined or being removed.bee({}, { newKey: bee.ensure() }); // => { newKey: undefined } bee({}, { newKey: bee.ensure().remove() // #ensure has higher priority }); // => { newKey: undefined }#rename: rename the keybee(data, { bar: bee.rename('foo') });#root: get value by path string related to root data.#data: get value by path string related to current data:let data = { info: { detail: { name: 'object-bee', }, foo: '', bar: '' } }; bee(data, { foo: bee.root('info.detail.name'), bar: bee.data('detail.name') });Valid paths for
#dataand#rootcan be:path path.path.path list[2].path.path[0]#mirror([path]): reuse config for recursive data, such as tree data, of which nodes have similar data structure. At this case, we can reuse config:let treeData = { name: 'root', child: { name: 'node', child: { name: 'leaf' } } }; bee(treeData, { name () { return 'foo'; } child: bee.mirror() });#mirrorcan accept apathto specify target config.#noop: no-operation function used for placeholder.
In key place
#keep: same as#ensure, except it is used in computed keybee({}, { [bee.keep('newKey')] () { return 'bar'; } }); // => { newKey: 'bar' } bee({}, { [bee.keep('newKey')]: bee.remove() // #keep has higher priority }); // => { newKey: undefined }#match: match key by RegExp and String. It would apply default action to corresponding data of matching key.bee({ num1: 1, num2: 2 }, { [bee.match(/^num\d$/)] () { return 0; } }); // => { num1: 0, num2: 0 }default action provided by
#matchhas lowest priority than action of certain key.#glob: like#matchmethod, except it matches keys by wildcard charactersbee({ letterA: '', letterB: '' }, { [bee.glob('letter*')] () { return 'Z'; } }); // => { letterA: 'Z', letterB: 'Z' }default action provided by
#globhas lowest priority than action of certain key.
Normal action
#create: by this method, object-bee would clone a new data, so original data would not be modified.let newData = bee(data, {}); newData !== data; // true
Combination
All kinds of actions support to chain:
bee(data, {
foo: bee.remove().ensure().rename('bar')
});As all actions has its corresponding method inner function , it is recommend to use function to deal with more complex logic:
bee(data, {
foo () {
this.$ensure();
this.$rename('bar');
if (...) {
this.$remove();
}
}
});Applying actions and setting config at the same time:
let data = {
detail: {}
};
bee(data, {
detail () {
this.$rename('info');
this.$config({
foo: bee.ensure()
});
}
});
// => { info: { foo: undefined } }The code above may be suspected of messing up structure. If we want to keep the structure readable, we can use bee.CONFIG in computed key and assign action to it:
bee(data, {
detail: {
[bee.CONFIG]: bee.rename('info'),
foo: bee.ensure();
}
});
// or function
bee(data, {
detail: {
[bee.CONFIG] () {
this.$rename('info')
},
foo: bee.ensure();
}
});This code do same thing as last code.
8 years ago