πͺ Handy object manipulation tools
before/afterhooks on each method.get/set/has/deletewith nested path support.- deep iteration.
- deep clone.
- deep merge.
- Everything while keeping direct access to original js object (no constrains on using
HobjAPI for every operation).
With NPM:
npm install --save hobjWithout:
<script src="https://unpkg.com/lucagez/hobj/dist/hobj.umd.js"></script>Hobj will provide hooks to execute functions before/after a method is executed.
This is done by executing in order:
=> BEFORE queue
=> fulfilled promise executing AFTER queue
=> called METHODA micro-task is scheduled thanks to the already fulfilled promise.
So, the AFTER queue will always be executed after the called METHOD. Precisely on nextTick.
This will guarantee the order:
- BEFORE
- METHOD
- AFTER
You can create a new Hobj instance passing an existing js object.
const Hobj = require('hobj');
const obj = new Hobj();
const obj1 = new Hobj({
hello: 'world',
});The object that is mutated thanks to Hobj methods lives in the store property.
const obj = new Hobj(); // Hobj instance
obj.store // {}The store property can be manipulated exactly like any other js object.
NOTE: This means that you don't have to rely only on the Hobj methods to mutate the object.
const test = { hello: 'world' };
const obj = new Hobj();
// Example operation.
obj.store = {
...test,
a: 'b',
};Every Hobj method that take a path as argument supports dot-notation.
e.g.
const obj = new Hobj();
obj.store // {}
obj.set('a.b.c', 'd'); // { a: { b: { c: 'd' } } }For each Hobj method there are two variations:
- Normal =>
obj.[method]=> ALWAYS executes before/after hooks. - Pure =>
obj.[_method]=> Pure method. No hooks.
NOTE: Normal methods can be used also if hooks are not defined.
const obj = new Hobj();
obj.before('set', () => console.log('Setting'));
// NORMAL
obj.set('a.b', 'c');
// Setting
// { a: { b: 'c' } }
// PURE => no hooks are invoked
obj._set('d', 'e');
// { a: { b: 'c' }, d: 'e' }Hooks can be defined calling on a Hobj instance a before/after method.
Passing the method to hook and a function responsible for that particular hook.
const obj = new Hobj();
// Example using an arbitrary method. You can hook every method defined
// in the `METHODS` section.
obj.before('set', () => {
console.log('Setting 0');
});
// You can hook with how many functions you like.
// They will be executed in insertion order.
obj.before('set', () => {
console.log('Setting 1');
});
obj.set('a', 'b');
// Setting 0
// Setting 1
// [Actually setting the property]The same is true for after hook.
const obj = new Hobj();
obj.before('set', () => {
console.log('Setting');
});
obj.after('set', () => {
console.log('Success π');
});
obj.set('a', 'b');
// Setting
// [Actually setting the property]
// Success πEvery before function will be invoked with the exact same arguments as the invoked method.
const obj = new Hobj();
// Hooked function will be invoked with TWO arguments
// as the `set` method accepts TWO arguments.
obj.before('set', (prop, value) => {
console.log(`Setting ${prop} equal to ${value}`);
});
obj.set('a', 'b');
// Setting a equal to b
// [Actually setting the property]
// Hooked function will be invoked with ONE argument
// as the `set` method accepts ONE argument.
obj.before('has', (value) => {
console.log(`Checking if ${value} is in obj`);
});
obj.has('a');
// Checking if a is in obj
// TRUEEvery after function will be invoked with arguments used on the invoked method PLUS the result of the actual invoked method.
const obj = new Hobj();
// Hooked function will be invoked with TWO arguments
// as the `set` method accepts TWO arguments.
obj.before('set', (prop, value) => {
console.log(`Setting ${prop} equal to ${value}`);
});
obj.after('set', (prop, value, result) => {
console.log('The object is now', result);
});
obj.set('a', 'b');
// Setting a equal to b
// [Actually setting the property]
// The object is now { a: 'b' }For each Hobj method there are two variations:
- Normal => obj.[method] => ALWAYS executes before/after hooks.
- Pure => obj.[_method] => Pure method. No hooks.
Not a method. The object on which the mutations are operated will live inside this property.
obj.storeobj.has(path)Checks if a (nested) path exists in the object.
RETURNS: true/false
| param | type | default | required |
|---|---|---|---|
| path | string | undefined | no |
obj.get(path)Returns object belonging to a (nested) path.
RETURNS:
objectif a path is providedundefinedif the provided path does not exists
| param | type | default | required |
|---|---|---|---|
| path | string | undefined | no |
obj.set(path, value)Set property at (nested) path.
RETURNS: store
| param | type | default | required |
|---|---|---|---|
| path | string | undefined | no |
| value | any | undefined | no |
obj.delete(path)Delete (nested) property.
RETURNS: true/false. Deletion is successful or not.
| param | type | default | required |
|---|---|---|---|
| path | string | undefined | no |
obj.sub([path])Returns a completely new object belonging to a (nested) path.
NOTE: when retrieving a property using get, a reference is returned. Using sub you are creating a totally new instance.
RETURNS:
objectif a path is providedundefinedif the provided path does not existsstore(a cloned instance of) if no path is provided
| param | type | default | required |
|---|---|---|---|
| path | string | '' | no |
obj.for([path])(callback)Iterate each top-level property starting at deep level (path)
If no path is provided, the iteration will be at top level.
RETURNS: undefined.
for:
| param | type | default | required |
|---|---|---|---|
| path | string | '' | no |
callback:
| param | type |
|---|---|
| prop | string |
| value | any |
example:
const obj = new Hobj({
a: {
b: 0,
c: 0,
},
d: 0,
});
// No `path` provided => iterating at top level
obj.for()((prop, value) => {
console.log(prop, value);
});
// a, { b: 0, c: 0 }
// d, 0
// Providing starting `path`
obj.for('a')((prop, value) => {
console.log(prop, value);
});
// b, 0
// c, 0obj.forDeep([path[, end]])(callback)Iterate EACH property starting at deep level (path).
If no path is provided, the iteration will start at top level.
The end (end property) let's you define if you want to iterate over properties that have no descendants or not.
RETURNS: undefined.
for:
| param | type | default | required |
|---|---|---|---|
| path | string | '' | no |
| end | boolean | true | no |
callback:
| param | type |
|---|---|
| path | string |
| value | any |
example:
const obj = new Hobj({
a: {
b: 0,
c: 0,
},
d: 0,
});
// No `path` provided => starting iteration from top level
obj.forDeep()((path, value) => {
console.log(path, value);
});
// a.b, 0
// a.c, 0
// d, 0
// specifying iteration on **EACH** property.
obj.forDeep('', false)((path, value) => {
console.log(path, value);
});
// '', { a: { b: 0, c: 0 }, d: 0 }
// a, { b: 0, c: 0 }
// a.b, 0
// a.c, 0
// d, 0
// Providing starting `path`
obj.forDeep('a')((path, value) => {
console.log(path, value);
});
// b, 0
// c, 0obj.size([path])Returns the number of properties at defined deep level. If no path is provided, it will be returned the number of properties at top level.
RETURNS: number
| param | type | default | required |
|---|---|---|---|
| path | string | '' | no |
obj.sizeDeep([path[, end]])Returns the number of EVERY property contained in the object at specified deep level.
The end param will define if the number should take into account properties that are objects or only end properties.
RETURNS: number
| param | type | default | required |
|---|---|---|---|
| path | string | '' | no |
| end | boolean | true | no |
obj.merge(obj)(Deeply) merge the provided object with the current store.
RETURNS: store
| param | type | default | required |
|---|---|---|---|
| obj | object | {} | no |
obj.keys([path])Returns an array containing every top-level property at specified deepness.
RETURNS: array
| param | type | default | required |
|---|---|---|---|
| path | string | '' | no |
obj.entries([path])Returns an array with the following structure: [prop, value]. Created at the specified deepness.
RETURNS: array
| param | type | default | required |
|---|---|---|---|
| path | string | '' | no |
obj.clear(when, method)If invoked with no params => initialize store to empty object. If invoked with params => clear queue.
RETURNS: undefined
MIT
Author: Luca Gesmundo