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

objectbuilder

v3.0.0

Published

Combine and extend objects containing arrays and subobjects

Downloads

58

Readme

objectbuilder

objectbuilder provides a simple and flexible interface to create modified copies of nested javascript objects.

Use case

Configuration of npm modules is often done by creating fairly complicated nested JavaScript object literals:

const someconfig = {
   name: "sampleproject",
   compiler: {
      input: './source',
      output: './build'
   },
   plugins: ['errorlog']
};

It is useful to have a flexible way to create modified versions of such objects. For example we could create specialized configurations for production and debugging. This package provides a flexible way to do so:

import * as B from 'objectbuilder';

const debugconfig = B.build(someconfig, {
   // By default, new properties overwrite existing ones
   name: "sampleproject-debug",

   // If we want to extend an object instead of overwriting,
   // we can declare it with the `object()` function
   compiler: B.object({
      debugging: true
   }),

   // To append to arrays there is an equivalent `array()` function
   plugins: B.array(['linter'])
});

The resulting debugconfig looks like this:

{
   name: "sampleproject-debug",
   compiler: {
      input: './source',
      output: './build',
      debugging: true
   },
   plugins: ['errorlog', 'linter']
}

Installation

With npm:

npm install --save objectbuilder

Or yarn:

yarn add objectbuilder

Main API

Combining objects: build(obj1, obj2, ...)

build() is the main function, and it simply combines objects by copying all the properties to a new object:

const r = B.build(
   {a: 1},
   {b: 2},
   {c: 3}
);
assert.deepEqual(r,
   {a: 1, b: 2, c: 3}
);

build() always creates a new object and doesn't modify the input objects.

By default, build() does a simple "shallow" assignment, where property values on later objects overwrite those on earlier objects, even if they are themselves objects:

const r = B.build(
   {a: {x: 1}},
   {a: {y: 2}}
);
assert.deepEqual(r,
   {a: {y: 2}}
);

The result object contains the a property from the second parameter given to build(). The a property for the first parameter got copied to the result but then was overwritten by the a property of the second parameter.

Combining subobjects: object(props, ...)

If a subobject shouldn't overwrite existing properties, but instead extend them, this can be declared with the object() function. It tells build() to combine the new properties with existing ones (if any):

const r = B.build(
   {a: {x: 1}},
   {a: B.object({y: 2})}
);
assert.deepEqual(r,
   {a: {x: 1, y: 2}}
);

You can nest object() declarations and specify exactly which properties should overwrite or extend existing properties.

Removing properties

objectbuilder exports a special constant remove, which can be used to mark properties that should be removed from the combined result.

const r = B.build(
   {a: 1, b: 2},
   {b: B.remove}
);
assert.deepEqual(r,
   {a: 1}
);

object.extend(props, ...)

This is just a different name for the object() function that describes its functionality better.

Combining arrays: array(items, ...)

The same situation can also occur when properties are arrays. By default build() overwrites existing arrays, but you can mark a property with array() to declare that it should extend existing arrays instead of overwriting:

const r = B.build(
   {a: [1,2]},
   {a: B.array([3,4])}
);
assert.deepEqual(r,
   {a: [1,2,3,4]}
);

array_append(items, ...)

This is just a different name for the array() function that describes its functionality better.

array_prepend(items, ...)

Extends existing arrays like array() or array.append(), but inserts the new elements at the beginning instead of the end.

Customization

objectbuilder can easily be customized if you want to modify you objects in different ways.

Custom handling of properties: modify()

The modules exports a modify() function that can be used to adjust the handling of properties by build() to your liking. For example, lets say you want to have a string that gets appended to an existing string:

function string_append(tail) {
   return B.modify(function(orig) {
      if (orig === undefined)
         orig = "";
      return orig + tail;
   });
}

const someconfig = {name: "someproject"};
const debugconfig = B.build(
   someconfig,
   {name: string_append("-debug")}
);
assert.deepEqual(debugconfig, {name: "someproject-debug"});

The function given to modify() is called whenever build() needs to apply the new property to an object it is building. It gets the old value of the property as an parameter and is expected to return the new value.

Modifying existing properties

Instead of combining existing properties with new values, objectbuilder's customization can also be used create modifications of the existing values.

For example, you can create a modifier that converts existing property values to upper case:

function uppercase() {
   return B.modify(function(orig) {
      if (orig === undefined)
         return undefined;
      return orig.toUpperCase();
   });
}

const original = {name: "someproject"};
const modified = B.build(
   original,
   {name: uppercase()}
);
assert.deepEqual(modified, {name: "SOMEPROJECT"});