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

@almela/obx

v0.0.6

Published

Fast & Lightweight Object Manipulation Library for Javascript

Downloads

18

Readme

Contributors Forks Stargazers Issues MIT License LinkedIn

About

obx is a super fast, tiny, well documented, and battle-tested object manipulation library for Javascript.

Getting Started

Installation

Install with npm

npm i @almela/obx

or with yarn

yarn add @almela/obx 

Usage

In your file, simply add

import * as obx from '@almela/obx'

or simply import select functions

import { eq, cp } from '@almela/obx'

Docs

For even more examples, see the tests.

Functions

eq

Assert that two objects are equal. Objects are equal if they have the same keys and values.

Params

  • a : Object - Object 1
  • b : Object - Object 2
  • params : Object - Parameters object
    • [.depth] : number - Depth of equality check. Defaults to infinity

Object order doesn't matter

obx.eq(
  { foo: "bar", bar: "baz" },
  { bar: "baz", foo: "bar" }
)
// -> true

With Arrays

obx.eq([1, 2, 3], [1, 2, 3])
// -> true

Array order does matter!

obx.eq([1, 2, 3], [3, 2, 1])
// -> false

Custom depth

obx.eq({ foo: "bar" }, { foo: "baz" }, { depth: 0 })
// -> true
obx.eq({ foo: { bar: "baz" } }, { foo: {} }, { depth: 1 })
// -> true
obx.eq({ foo: { bar: "baz" } }, { foo: {} }, { depth: 2 })
// -> false

Functions

// Unfortunately, functions are basically impossible to
// diff. `eq` assumes that all functions are the same.
obx.eq({ foo: (x) => x + 1 }, { foo: (x) => x + 2 })
// -> true

cp

Deep copy an object.

Params

  • o : Object - Object to copy
  • params : Object - Parameters object
    • [.depth] : number - Depth of copy. Defaults to infinity

Copy by value, not by reference

const a = {
   foo: {
     bar: 'baz'
   }
}
const b = obx.cp(a)

a.foo.bar = 'bar'
console.log(b)
// object remains the same
// -> {
//   foo: {
//     bar: 'baz'
//   }
// }

get

Get value from object.

Params

  • o : Object - The object
  • p : String - Value path

Get a deep key

obx.get("foo.bar", {
   foo: {
     bar: "baz"
   }
});
// -> "baz"

Also works with arrays

obx.get("foo.2.baz", {
   foo: [
     {
       foo: 'foo'
     },
     {
       bar: 'bar'
     },
     {
       baz: 'baz'
     }
   ]
});
// -> "baz"

No key? No problem.

obx.get("foo.2.baz", {
   foo: 'bar'
})
// -> null

set

Set value in object.

Params

  • o : Object - The object to be mutated
  • p : String - Value path
  • v : Object - Value to set
const o = {}
obx.set(o, "foo.bar.baz.haz", "hello")
// -> {
//   foo: {
//     bar: {
//       baz: {
//         haz: "hello"
//       }
//     }
//   }
// }
const o = {}
obx.set(o, "foo.2.foo", 'bar')
// o -> {
//    foo: [<2 empty slots>, {
//      foo: 'bar'
//    }]
// }

len

Recursively find the number of keys of an object. Note that this includes object-valued keys.

Params

  • o : Object - Object to find length of
  • params : Object - Parameters object
    • [.depth] : number - Depth of len check. Defaults to infinity

Simple object

obx.len({ foo: 'bar', bar: 'baz' }) // -> 2

Recursive object, depth 1

// Here depth is only computed at the top level
obx.len({ foo: 'bar', bar: { bar: 'baz', baz: [1, 2, 3] } }, { depth: 1 }) // -> 2

Recursive object, infinite depth

// Note: array keys are counted
obx.len({ foo: 'bar', bar: { bar: 'baz', baz: [1, 2, 3] } }) // -> 7

map

Recursively map though all entries of an object. Note that map will also iterate through object-valued keys.

Params

  • o : Object - Object to map through
  • fn : function - Callback function. Contains [k, v] pair, path, object
  • params : Object - Parameters object
    • [.depth] : number - Depth of map. Defaults to infinity

Basic Mapping

 const o = {
   foo: "bar",
   bar: "baz",
   baz: "foo",
 };

 // Note that map will callback on every value of the object, including sub objects!
 const emphasis = ([_, v]) => (v instanceof Object ? v : v + "!");

 // Note that depth could be anything here, since this is just a flat object.
 obx.map(o, emphasis, { depth: 1 });
 // -> {
 //      foo: "bar!",
 //      bar: "baz!",
 //      baz: "foo!",
 //    }

Recursive Mapping, low depth

 const o = {
   foo: "bar",
   bar: {
     baz: "foo",
   },
 };

 // Note that map will callback on every value of the object, including sub objects!
 const emphasis = ([_, v]) => (v instanceof Object ? v : v + "!");
 obx.map(o, emphasis, { depth: 1 });
 // -> {
 //      foo: "bar!",
 //      bar: {
 //        baz: "foo",
 //      }
 //    }
 //
 //    Note that the inner key is unchanged.

Recursive Mapping, high depth

const o = {
   foo: "bar",
   bar: [
     { foo: "bar", bar: "baz" },
     { foo: "bar", bar: "baz" },
     { foo: "bar", bar: "baz" },
   ],
   raz: "faz",
 };

 // Note that map will callback on every value of the object, including sub objects!
 const emphasis = ([_, v]) => (v instanceof Object ? v : v + "!");
 obx.map(o, emphasis);
 // -> {
 //       foo: "bar!",
 //       bar: [
 //         { foo: "bar!", bar: "baz!" },
 //         { foo: "bar!", bar: "baz!" },
 //         { foo: "bar!", bar: "baz!" },
 //       ],
 //       raz: "faz!",
 //    }

reduce

Recursively reduce through all entries of an object. Note that reduce will also iterate through object-valued keys.

Params

  • o : Object - Object to map through
  • fn : function - Callback function
  • a : Object - Accumulator
  • params : Object - Parameters object
    • [.depth] : number - Depth of reduce. Defaults to infinity
    • [.iter] : function - Iterator used by reduce. Defaults to inorder traversal.

Flat object

const o = { foo: "bar", bar: "baz" };

const combineVals = (a, [k, v]) => [...a, v];
obx.reduce(o, combineVals, []).join(", ");
// -> "bar, baz"

Deeper object

const o = {
  foo: "bar",
  bar: {
    baz: "haz",
  },
};

const combineVals = (a, [k, v]) => (v instanceof Object ? a : [...a, v]);
obx.reduce(o, combineVals, []).join(", ");
// -> "bar, haz"

Custom depth

const o = {
  foo: "bar",
  bar: {
    baz: {
      haz: "wow",
    },
    foo: "bar",
  },
  raz: {
    faz: "maz",
    gaz: 'haz',
    haz: [
      { maz: 'waz' },
      { foo: 'moo' }
    ]
  },
}

const combineVals = (a, [k, v]) => (v instanceof Object ? a : [...a, v]);
obx.reduce(o, combineVals, [], { depth: 2 }).join(", ");
// -> "bar, bar, maz, haz"
// Only gets keys down to depth 2

zip

Group multiple objects into a single iterator. Note that zip will also iterate through object-valued keys.

Params

  • objs : Array - Array of objects to be zipped together.
  • params : Object - Parameters object
    • [.depth] : number - Depth of zip. Defaults to infinity
    • [.key] : Boolean - Whether zip should return object keys. Defaults to false
    • [.val] : Boolean - Whether zip should return object values. Defaults to true
    • [.last] : Boolean - Whether zip should stop iterating when the last object is done, as opposed to the first. Defaults to false
    • [.iter] : function - Iterator used by zip. Defaults to inorder traversal.

Stops at the first null value

const a = ["a", "b", "c"];
const b = [1];

// loop runs only once
for (const z of obx.zip([a, b]))
 console.log(z)
// -> ["a", 1]

Recursive

 const a = {
  foo: "bar",
  bar: {
    baz: "haz",
  },
};

const b = [4, 5];

for (const z of obx.zip([a, b]))
 console.log(z)
// -> ["bar", 4]
// -> ["haz", 5]

More than 2 Objects

const a = ["a", "b", "c"];
const b = [1, 2, 3];
const c = ["x", "y", "z"];
const d = [3, 2, 1];

for (const z of obx.zip([a, b, c, d]))
 console.log(z)
// -> ["a", 1, "x", 3]
// -> ["b", 2, "y", 2]
// -> ["c", 3, "z", 1]

sub

Recursive, in-place object subtraction.

Params

  • o : Object - The object to be subtracted from. This object is mutated.
  • s : Object - The object to subtract with
  • params : Object - Parameters object
    • [.depth] : number - Depth of subtraction. Defaults to infinity

Simple subtraction

const a = {
  foo: "bar",
  bar: "baz",
  list: [1, 2, 3],
};

const b = {
  foo: "bar",
  list: [1, 2, 3],
};

obx.sub(a, b);
console.log(a)
// -> { bar: "baz" }

With arrays

const a = [1, 2, 3];
const b = [1, 2, 3];

obx.sub(a, b);
console.log(a)
// -> []

add

Recursive, in-place object addition. If both objects contain the same key, defaults to o

Params

  • o : Object - The object to be added to. This object is mutated.
  • a : Object - The object to add with
  • params : Object - Parameters object
    • [.depth] : number - Depth of addition. Defaults to infinity

Simple addition

const a = {
  foo: "bar",
  bar: "baz",
  list: [1, 2, 3],
};

const b = {
  foo: "bar",
  haz: 5,
};

obx.add(a, b);
console.log(a)
// -> { foo: "bar", bar: "baz", list: [1, 2, 3], haz: 5 }

isEmptyObj

Assert that an object type is empty.

Params

  • o : Object - Object to assert is empty
obx.isEmptyObj({}) // -> true
obx.isEmptyObj({ foo: 'bar' }) // -> false

Only works for objects

obx.isEmptyObj([]) // -> false

isEmptyArr

Assert that an array type is empty.

Params

  • a : Array - The array to assert is empty
obx.isEmptyArr([]) // -> true
obx.isEmptyArr([1, 2, 3]) // -> false

Only works for arrays

obx.isEmptyArr({}) // -> false

Roadmap

  • [x] Write docs
  • [ ] Write eq in terms of a list of objects?
    • [ ] Rewrite eq using inorder iterator
  • [x] Implement zip
  • [ ] Create new file of opinionated functions with nicer signatures based on existing functions
    • Other helpful functions like isEmptyObj and isEmptyArr could go in there too
  • [x] Add traversal options to
    • [x] reduce
    • [x] zip
  • [x] Complete test coverage
    • [x] Test add
  • [ ] Transition to TS

License

Distributed under the MIT License. See LICENSE.txt for more information.

Contact

Twitter: @GaetanAlmela

Email: [email protected]

GitHub Repo: llGaetanll/obx