Hobj
🔪 Handy object manipulation tools
Features
before/after
hooks on each method.get/set/has/delete
with nested path support.- deep iteration.
- deep clone.
- deep merge.
- Everything while keeping direct access to original js object (no constrains on using
Hobj
API for every operation).
TOC
Installation
With NPM:
npm install --save hobj
Without:
How hooks work
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 METHOD
A 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
Usage
Init Hobj
You can create a new Hobj
instance passing an existing js object.
const Hobj = ; const obj = ; const obj1 = hello: 'world';
Store
The object that is mutated thanks to Hobj
methods lives in the store
property.
const obj = ; // Hobj instance objstore // {}
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 = ; // Example operation.objstore = ...test a: 'b';
Paths
Every Hobj
method that take a path
as argument supports dot-notation.
e.g.
const obj = ; objstore // {} obj; // { a: { b: { c: 'd' } } }
Calling a method
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 = ; obj; // NORMALobj; // Setting// { a: { b: 'c' } } // PURE => no hooks are invokedobj; // { a: { b: 'c' }, d: 'e' }
Defining hooks
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 = ; // Example using an arbitrary method. You can hook every method defined// in the `METHODS` section.obj; // You can hook with how many functions you like.// They will be executed in insertion order.obj; obj; // Setting 0// Setting 1// [Actually setting the property]
The same is true for after
hook.
const obj = ; obj; obj; obj; // Setting// [Actually setting the property]// Success 🎉
Every before
function will be invoked with the exact same arguments as the invoked method.
const obj = ; // Hooked function will be invoked with TWO arguments// as the `set` method accepts TWO arguments.obj; obj; // 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; obj; // Checking if a is in obj// TRUE
Every after
function will be invoked with arguments used on the invoked method PLUS the result of the actual invoked method.
const obj = ; // Hooked function will be invoked with TWO arguments// as the `set` method accepts TWO arguments.obj; obj; obj; // Setting a equal to b// [Actually setting the property]// The object is now { a: 'b' }
METHODS
For each Hobj
method there are two variations:
- Normal => obj.[method] => ALWAYS executes before/after hooks.
- Pure => obj.[_method] => Pure method. No hooks.
store
Not a method. The object on which the mutations are operated will live inside this property.
obj.store
has / _has
obj.has
Checks if a (nested) path exists in the object.
RETURNS: true/false
param | type | default | required |
---|---|---|---|
path | string | undefined | no |
get / _get
obj.get
Returns object belonging to a (nested) path.
RETURNS:
object
if a path is providedundefined
if the provided path does not exists
param | type | default | required |
---|---|---|---|
path | string | undefined | no |
set / _set
obj.set
Set property at (nested) path.
RETURNS: store
param | type | default | required |
---|---|---|---|
path | string | undefined | no |
value | any | undefined | no |
delete / _delete
obj.delete
Delete (nested) property.
RETURNS: true/false
. Deletion is successful or not.
param | type | default | required |
---|---|---|---|
path | string | undefined | no |
sub / _sub
obj.sub
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:
object
if a path is providedundefined
if the provided path does not existsstore
(a cloned instance of) if no path is provided
param | type | default | required |
---|---|---|---|
path | string | '' | no |
for / _for
obj.for
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 = a: b: 0 c: 0 d: 0; // No `path` provided => iterating at top levelobj { console;};// a, { b: 0, c: 0 }// d, 0 // Providing starting `path`obj { console;};// b, 0// c, 0
forDeep / _forDeep
obj.forDeep
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 = a: b: 0 c: 0 d: 0; // No `path` provided => starting iteration from top levelobj { console;};// a.b, 0// a.c, 0// d, 0 // specifying iteration on **EACH** property.obj { console;};// '', { a: { b: 0, c: 0 }, d: 0 }// a, { b: 0, c: 0 }// a.b, 0// a.c, 0// d, 0 // Providing starting `path`obj { console;};// b, 0// c, 0
size / _size
obj.size
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 |
sizeDeep / _sizeDeep
obj.sizeDeep
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 |
merge / _merge
obj.merge
(Deeply) merge the provided object with the current store.
RETURNS: store
param | type | default | required |
---|---|---|---|
obj | object | {} | no |
keys / _keys
obj.keys
Returns an array containing every top-level property at specified deepness.
RETURNS: array
param | type | default | required |
---|---|---|---|
path | string | '' | no |
entries / _entries
obj.entries
Returns an array with the following structure: [prop, value]. Created at the specified deepness.
RETURNS: array
param | type | default | required |
---|---|---|---|
path | string | '' | no |
clear / _clear
obj.clear
If invoked with no params => initialize store to empty object. If invoked with params => clear queue.
RETURNS: undefined
License
MIT
Author: Luca Gesmundo