object-bee
v1.0.0
Published
Lightweight, flexible library for manipulating plain-object data in JavaScript.
Downloads
4
Readme
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 -S
CDN 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; // true
Context 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
:undefined
returned by function will be ignore, If you want replace the original value withundefined
, you should returnthis.$UNDEFINED
instead, 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
#data
and#root
can 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() });
#mirror
can accept apath
to 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
#match
has lowest priority than action of certain key.#glob
: like#match
method, except it matches keys by wildcard charactersbee({ letterA: '', letterB: '' }, { [bee.glob('letter*')] () { return 'Z'; } }); // => { letterA: 'Z', letterB: 'Z' }
default action provided by
#glob
has 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.