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

elastic-object

v1.0.12

Published

Just like plain old objects, but with built-in array methods, get(), set() and other goodies

Downloads

188

Readme

Elastic Object

DeepScan grade

Plain Objects are great for handling data, but they can be a bit clunky. This is where Elastic Object comes in. On top of the regular object functionality, it features get() and set() with dotted.string.notation, as well as loops and all the other good stuff you already know from Arrays, Maps or Sets. It is easily extendable in case you want to add your own methods. And it's not huge either.

Installation

npm i elastic-object

Usage

Below is a simple example of how to create an Elastic Object. For the methods, please refer to the complete documentation.

import ElasticObject from 'elastic-object'; // note that ElasticObject is implemented as ESM and not in CJS

const eObj = new ElasticObject({
    path: {
        to: {
            string: "foo",
            integer: 42
        },
    },
    another: {
        path: {
            to: {
                float: 3.14
            }
        }
    }
});

console.log(eObj.get('path.to.string')); // "foo"
eObj.set('path.to.string', "bar");
console.log(eObj.get('path.to.string')); // "bar"
eObj.path.to.string = "quux";
console.log(eObj.get('path.to.string')); // "quux"

eObj.forEach((value, key) => {
    console.log(key, value); // "path", { to: { string: "bar", integer: 42 } } etc.
});

Features

Standard object methods

Elastic Objects are extensions of plain objects, so everything you can do with plain objects can be done with elastic objects, too. There are some differences, though:

  • Static methods, such as assign() or create(), which you would expect to return regular objects, will return elastic objects instead.
  • keys(), values(), entries(), assign(), create() and fromEntries() are also available as instance methods. From within the instance keys(), values(), entries() refer to this and take no arguments. assign() uses this as the target argument. create() and fromEntries() work exactly like their static counterparts.

Accessors

Accessing properties with set('path.to.property') is a common implementation pattern, but it's not native to JavaScript. With set(), get(), has() and unset() Elastic Object has built-in support for this pattern. To avoid confusion with JavaScript's native dot notation, this document uses the term dotted.string.notation instead. The feature is powered by Sindre Sorhus' dot-prop library.

Array methods

Not all array methods make sense on an object, but every(), filter(), find(), forEach(), includes(), length(), map(), reduce(), reduceRight(), some() and sort() certainly do; Elastic Object has them all. There is also findPath() as an equivalent of findIndex(). All methods work pretty much like their array counterparts, which means they generally refer to the top level of the object. findPath(), however, searches all levels as long as the values are either arrays or objects. Note that length() is, contrary to the array implementation, built out as a function.

Other methods

toJson(), clone() and cloneProperty() cover common tasks and it makes sense to have them available. The flatten() method finally returns a version of the object with all nested paths converted to strings in dotted.string.notation. The above example as a flat object looks like this:

{
    'path': {to: {…}}
    'path.to': {string: 'string', integer: 42, float: 3.14, boolean: true, null: null}
    'path.to.boolean': true
    'path.to.float': 3.14
    'path.to.integer': 42
    'path.to.null': null
    'path.to.string': "string"
}

Chainability

Whenever a method would normally return an object, an elastic object with the same plugins will be returned instead. This means that you can chain methods, like this:

eObj.set('path.to.string', "foo").set('path.to.integer', 42).set('another.path.to.float', 3.14);
eObj.get('path.to.a.plain.object').filter(value => value > 3).values();

Adding properties

You aren't limited to Elastic Object's native functionality. It has a plugin system that allows you to pass an object of new methods as an argument to the constructor. /plugins/array.js and /plugins/native.js are loaded by default and you can check out these modules if you wish to add your own set of methods. Methods are added to the prototype chain, which may make them available project-wide depending on your implementation . Make sure that they implement the chainability paradigm as mentioned above.

Below is a short example of how this works. Keep in mind to use regular function syntax to ensure access to this.

const myPlugins = {
    methodA: function() {        
        console.log(this);
    }
    // more methods
}

const data = { bar: 42 };

// standard Elastic Object
const eObj1 = new ElasticObject(data);
eObj1.methodA(); // TypeError: eObj1.methodA is not a function

// Elastic Object with custom methods
const eObj2 = new ElasticObject(data, myPlugins);
eObj2.methodA(); // ElasticObject { bar: 42 }

// Load plugins after creation
const eObj3 = ElasticObject.create(data);
eObj3.methodA(); // TypeError: eObj1.methodA is not a function
eObj3.loadPlugins(myPlugins); // now it works
eObj3.methodA(); // ElasticObject { bar: 42 }



// the magic formula for chainability:
import isPlainObject from "whats-the-type/isPlainObject.js";

const foo = function() {
    const value = {a: 1}; // or whereever your value comes from
    return isPlainObject(value) ? this.create(value) : value;
}

Method overview

The following table is an overview of the available methods. The links in the first column point to this documentation, the second column to the original documentation which you might also find helpful.

| Method | External reference | Notes | |:-------|:-------------------|:------| | eObj.assign() | Object.assign() | Instance flavor: eObj.assign(...sources), this is the target | | ElasticObject.assign() | Object.assign() | Static flavor: ElasticObject.assign(target, ...sources) | | eObj.create() | Object.create() | Instance flavor: eObj.create(anyObj) | | ElasticObject.create() | Object.create() | Static flavor: ElasticObject.create(anyObj) | | eObj.clone() | stucturedClone() | Clones the whole object | | eObj.cloneEntry() | stucturedClone() | Clones any property of the object | | eObj.entries() | Object.entries() | Instance flavor: eObj.entries(), uses this | | ElasticObject.entries() | Object.entries() | Static flavor: ElasticObject.entries(anyObj) | | eObj.every() | Array.every() | Same signature and usage | | eObj.filter() | Array.filter() | Returns an Elastic Object, chain .values() to get only the values | | eObj.find() | Array.find() | Same signature and usage | | eObj.findPath() | Array.findIndex() | Returns path in dotted.string.notation rather than an index | | eObj.flatten() | | Flattened version of the object | | eObj.forEach() | Array.forEach() | Same signature and usage | | eObj.fromEntries() | Object.fromEntries() | Instance flavor: eObj.fromEntries(iteratable) | | ElasticObject.fromEntries() | Object.fromEntries() | Static flavor: ElasticObject.fromEntries(iteratable) | | eObj.get() | getProperty() | Same signature, but without the first argument object | | eObj.has() | hasProperty() | Same signature, but without the first argument object | | eObj.includes() | Array.includes() | Same signature and usage | | eObj.keys() | Object.keys() | Instance flavor: eObj.keys(), uses this | | ElasticObject.keys() | Object.keys() | Static flavor: ElasticObject.keys(anyObj) | | eObj.length() | Array.length | In difference to Array.length, this is implemented as a function | | eObj.map() | Array.map() | Same signature and usage | | eObj.paths() | | Keys of the flattened object | | eObj.reduce() | Array.reduce() | Same signature and usage | | eObj.reduceRight() | Array.reduceRight() | Same signature and usage | | eObj.set() | setProperty() | Same signature, but without the first argument object | | eObj.some() | Array.some() | Same signature and usage | | eObj.sort() | Array.sort() | Same signature and usage | | eObj.toJson() | JSON.stringify() | With boolean pretty argument for pretty-print | | eObj.unset() | deleteProperty() | Same signature, but without the first argument object | | eObj.values() | Object.values() | Instance flavor: eObj.values(), uses this | | ElasticObject.values() | Object.values() | Static flavor: ElasticObject.values(anyObj) |

Resources