npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hobj

v0.2.0

Published

Handy object manipulation tools

Downloads

30

Readme

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:

<script src="https://unpkg.com/lucagez/hobj/dist/hobj.umd.js"></script>

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:

  1. BEFORE
  2. METHOD
  3. AFTER

Usage

Init Hobj

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',
});

Store

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',
};

Paths

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' } } }

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 = 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' }

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 = 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
// TRUE

Every 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' }

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(path)

Checks if a (nested) path exists in the object.

RETURNS: true/false

| param | type | default | required | |-------|--------|-----------|----------| | path | string | undefined | no |

get / _get

obj.get(path)

Returns object belonging to a (nested) path.

RETURNS:

  • object if a path is provided
  • undefined if the provided path does not exists

| param | type | default | required | |-------|--------|-----------|----------| | path | string | undefined | no |

set / _set

obj.set(path, value)

Set property at (nested) path.

RETURNS: store

| param | type | default | required | |-------|--------|-----------|----------| | path | string | undefined | no | | value | any | undefined | no |

delete / _delete

obj.delete(path)

Delete (nested) property.

RETURNS: true/false. Deletion is successful or not.

| param | type | default | required | |-------|--------|-----------|----------| | path | string | undefined | no |

sub / _sub

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:

  • object if a path is provided
  • undefined if the provided path does not exists
  • store (a cloned instance of) if no path is provided

| param | type | default | required | |-------|--------|-----------|----------| | path | string | '' | no |

for / _for

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, 0

forDeep / _forDeep

obj.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, 0

size / _size

obj.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 |

sizeDeep / _sizeDeep

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 |

merge / _merge

obj.merge(obj)

(Deeply) merge the provided object with the current store.

RETURNS: store

| param | type | default | required | |-------|---------|-----------|----------| | obj | object | {} | no |

keys / _keys

obj.keys([path])

Returns an array containing every top-level property at specified deepness.

RETURNS: array

| param | type | default | required | |-------|--------|-----------|----------| | path | string | '' | no |

entries / _entries

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 |

clear / _clear

obj.clear(when, method)

If invoked with no params => initialize store to empty object. If invoked with params => clear queue.

RETURNS: undefined

License

MIT

Author: Luca Gesmundo