Succor—pure, fast, small utility library

npm install @antediluvian/succor

Looking for the API reference documentation?

Table of contents

There is not exactly a shortage of utility libraries for JavaScript, so what could possibly incite a perceived need to create another one? I don't have a great excuse beyond wanting both more and less than what I've found.

An ideal utility library SHOULD

An ideal utility library SHOULD NOT

Prior art

This section summarizes why I can't just use any of the existing popular utility libraries.

Why not lodash?

Who not lodash/fp?

Why not ramda?

API Reference

All of the functions exported by this library are of the shape:

(options) -> (...arguments) -> value?
That is, they are all called like this:
const fn = succor[function](options); // WILL throw on bad options.
const value = fn(...arguments); // Will NEVER throw on bad arguments.

get

Safely “gets” a property at an arbitrary path inside of nested objects. Returns “undefined” if the path doesn't lead to a value.

get: (path) => (arg) => ret
where
path: Array<Number | String | Symbol>
arg : Any
ret : Any
path

Must be an Array whose elements are each either Number, String, or Symbol. Throws an error otherwise as these are the only valid indexes for paths.

arg

Anything, but should be an object, array, or other indexable entity to return a value.

ret

Returns the result of safely indexing into the first index in path, then the second index in path, etc. until an index doesn't exist in the argument or all indexes in the path have been looked up.

Although it's not the actual implementation you can imagine it working like:

arg?.[path[0]]?.[path[1]]?.…?.path[n]

Examples:

const s = Symbol('some symbol');

get(['a', 0, s])({ a: [{ [s]: 5 }] });
// => 5

get(['a', 0, s])(undefined)
// => undefined

get({})
// throws Error

pick

Safely “picks” the given properties at arbitrary paths inside of a nested object, returning a new object with only those properties.

pick: (paths) => (arg) => ret
where
paths: Array<Array<Number | String | Symbol>>
val  : Any
arg  : Any
ret  : Any
paths

Think of it as an Array of the kind of path you'd give to “get”. Must be an Array of: Arrays whose elements are each either Number, String, or Symbol. Throws an error otherwise as these are the only valid indexes for paths.

arg

Anything, but should be an object, array, or other indexable entity to return a value.

ret

Returns a new object that picks out the properties at the given paths. For each path it will safely index into the first index in path, then the second index in path, etc. until an index doesn't exist in the argument or all indexes in the path have been looked up. It will then set this value, if it exists, in the resulting object.

Although it's not the actual implementation you can imagine it working like

arg?.[path[0]]?.[path[1]]?.…?.path[n]

for each path in paths.

Examples:

const s = Symbol('some symbol');

pick([['a', 0, s], ['b']])({ a: [{ [s]: 5 }, 5], b: 5, c: 5 });
=> { a: [{ [s]: 5 }], b: 5 }

pick([['a', 0, s], ['b']])(undefined)
=> {}

pick({})
=> Throws Error

set

Safely “sets” a property at an arbitrary path inside of a nested object. Will create any missing objects alongs the path to ensure an object is always returned with the given value at the given path. Never mutates its arguments.

set: (path, val) => (arg) => ret
where
path: Array<Number | String | Symbol>
val : Any
arg : Any
ret : Any
path

Must be an Array whose elements are each either Number, String, or Symbol. Throws an error otherwise as these are the only valid indexes for paths.

val

Anything.

arg

Anything, but should be an object, array, or other indexable entity to make much sense.

ret

Returns a new object that clones the necessary parts of arg to ensure that val is found at path, but without ever mutating arg. If it is not possible to set the path in arg (arg might be undefined, a number, etc.) a completely new object will be returned to keep the contract.

Examples:

const s = Symbol('some symbol');

set(['a', 0, s], 'value')({ a: [{ [s]: 5 }], b: 5 });
=> { a: [{ [s]: 'value' }], b: 5 }

set(['a', 0, s], 'value')(undefined)
=> { a: [{ [s]: 'value' }] }

set({})
=> Throws Error