Skip to content
/ obx Public

Fast & Lightweight Object Manipulation Library for Javascript

License

Notifications You must be signed in to change notification settings

llGaetanll/obx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Contributors Forks Stargazers Issues MIT License LinkedIn


Logo

@almela/obx

obx - objects extended
Explore the docs »

View on NPM · Report Bug · Request Feature

Table of Contents
  1. About
  2. Getting Started
  3. Docs
  4. Roadmap
  5. Contributing
  6. License
  7. Contact
  8. Acknowledgments

About

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

(back to top)

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'

(back to top)

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
Examples

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
Examples

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
Examples

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
Examples
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
Examples

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
Examples

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

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

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
Examples

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
Examples

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
Examples
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
Examples
obx.isEmptyArr([]) // -> true
obx.isEmptyArr([1, 2, 3]) // -> false

Only works for arrays

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

(back to top)

Roadmap

  • Write docs
  • Write eq in terms of a list of objects?
    • Rewrite eq using inorder iterator
  • 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
  • Add traversal options to
    • reduce
    • zip
  • Complete test coverage
    • Test add
  • Transition to TS

(back to top)

License

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

(back to top)

Contact

Twitter: @GaetanAlmela

Email: npm@almela.io

GitHub Repo: llGaetanll/obx

(back to top)

About

Fast & Lightweight Object Manipulation Library for Javascript

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published