0.0.6 • Published 1 month ago

@almela/obx v0.0.6

Weekly downloads
-
License
MIT
Repository
-
Last release
1 month ago

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

  • 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

License

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

Contact

Twitter: @GaetanAlmela

Email: npm@almela.io

GitHub Repo: llGaetanll/obx

0.0.5

1 month ago

0.0.4

1 month ago

0.0.6

1 month ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago