sg0
v1.0.59
Published
All the little functions that make functional Node.JS easier.
Downloads
41
Readme
sg0
All the little functions that make functional Node.JS easier.
- Adds a number of 'fixes' to well-known and used functional-programming staples.
- Consistent and thorough understanding and tolerance for
undefined
andnull
as function inputs. - Adds
reduceObj(collection, initial, function callback(m,k,v) {...})
to make creation of an object with reduce much easier.- You do not have to continually manage
m
, just return the additions.
- You do not have to continually manage
undefined
and null
as Function Inputs
In many situations, it leads to less complex code when functions are tolerant of 'required' inputs
being undefined
or null
. It is sometimes better to return the undefined
or null
than to
truly require it. Consider sg.setOn(obj, keys, value)
, which allows null-ish anywhere in the keys.
const x = {a:42};
const b = sg.deref(x, 'b'); // => b === undefined
const bb = sg.deref(x, ['b', b]); // => bb === undefined
const foo = sg.setOn(x, 'b', 'foo'); // => foo === 'foo'; x === {a:42,b:'foo'}
const fo2 = sg.setOn(x, ['b', bb], 'foo'); // => fo2 === 'foo'; x === {a:42,b:'foo'} /* NO HARM */
reduceObj()
Assumes you are building up an object, so you can just return the new keys/values. You do not need to keep track of the current state of the being-built object.
Consider how AWS uses an Array for the Tags on objects: {..., Tags:[{Name:'a', Value:'b'}]}. Javascript works much better if it were {..., tags:{a:'b'}}
- By returning a 2-item Array, you are adding to the object being built.
- Adding the 'tags' key, and the result of (2).
- By returning a 2-item Array, you are adding to the
tags
object, withTag.Name
as the key, andTag.Value
as the value. - By returning
undefined
, we are keeping all k/vs that aren'tTags
.- Could return
null
which would ignore current k/v, resulting in an object of only {tags:{...}}.
- Could return
- Could also include the original
Tags:[{Name:'a', Value:'b'}]
by making (2) a many-item Array, and adding the original k/v.- Would be better in this case to use ['Tags', v], which is more clear, but [k,v] is the general form.
const awsInstance = await aws.ec2.describeInstances({}).Promise();
const instance = sg.reduceObj(awsInstance, {}, (m,v,k) => {
if (k === 'Tags') {
return ['tags', sg.reduceObj(v, {}, (m_tags,Tag) => { /* 1 */
return [Tag.Name, Tag.Value]; /* 2 */
})];
}
/* 3 */
});
// instance === {
// InstanceId: 'abc...',
// ...
// tags: {
// a: 'b'
// }
// }
// To preserve Tags:
const instance = sg.reduceObj(awsInstance, {}, (m,v,k) => {
if (k === 'Tags') {
return [['tags', sg.reduceObj(v, {}, (m_tags,Tag) => {
return [Tag.Name, Tag.Value];
})], [k,v]]; /* 4 */
}
});
Quick Fixes
Fixes a couple of function signatures, putting the callback as the final parameter, where it belongs. These functions simply call into the expected function, rearranging the parameters.
sg.setTimeout(ms, callback);
sg.reduce(collection, initial, callback);
sg.setTimeout(ms, callback)
return setTimeout(callback, ms);
sg.reduce(collection, initial, callback)
Calls _.reduce(collection, callback, initial)
, not the Javascript-provided Array reduce.
Fix Fixes
I don't know why lodash renamed some of the underscore functions, or removed things,
but sg
restored these.
sg.min();
sg.max();
sg.rest();
sg.pluck();
sg.head();
sg.last();
sg.initial();
sg.any();
sg.all();
sg.compose();
sg.contains();
sg.findWhere();
sg.indexBy();
sg.invoke();
sg.mapObject();
sg.pairs();
sg.where();
Ease Usage
Similar to the quick fixes, these functions make it easier to call another common function, or create a new function to do something common.
sg.inspect(x, colors [= false]);
sg.firstKey(x);
sg.numKeys(x);
sg.isObject(x); // x isn't an Array, RegExp, etc.
sg.isPod(x); // x is a type that doesn't have properties (`.` will not work)
sg.isnt(x); // x is `null` or `undefined`
sg.trueOrFalse(x); // sg.tf() is alias
sg.inspect(x, colors [= false])
Calls util.inspect()
, but provides the options to do max-depth, and colorize. Returns
the decorated message, to pass to console.log()
or similar.
sg.firstKey(x) /* nullish ok */
[[x
can be nullish
; if so, returns x
.]]
Returns the first key of the object.
- Use this function to mean "Does the object have any content?"
- Many times, an object is supposed to have only one key, for example as a name.
if (!sg.firstKey(obj)) {
// obj has no content, it is just `{}`
}
const name = sg.firstKey(obj);
const value = obj[name];
sg.numKeys(x) /* nullish ok */
Returns the number of keys.
sg.isObject(x)
The normal _.isObject()
returns true
for lots of things that are (technically
speaking) Objects, but your code does not want to treat them that way. This function
returns true
if it is a 'real' object.
Returns true
if x is an object, and isn't one of the Object-like things like Array,
RegExp, Date, etc. Returns false
otherwise.
Notes:
- Returns
false
forError
objects. - Returns
false
fornullish
objects. (So this function is NOTnullish-input
aware.)
sg.isPod(x)
One of the great weaknesses in Javascript is that while (1) if (x) { x.y = 42; /*safe*/}
works great to
protect against dereferencing x
, if x
might be null
or undefined
, (2) if x
were the Number 1,
x.y = 42
would be unsafe.
This function can be used to make sure x
can be dereferenced.
if (!sg.isPod(x) && x) {
x.y = 42; /* safe */
}
Notes:
- Returns
false
fornull
andundefined
.- This makes sense,
null
andundefined
are not PODs. But is counter to the idea thatisPod()
is used to imply 'is dereferencable'.
- This makes sense,
- "POD" means "Plain Old Data".
sg.isnt(x)
x is null
or undefined
sg.trueOrFalse(x) [aka sg.tf()]
Returns true
or false
, following Javascript truthy-ness, but works right for edge cases:
- The strings 'true' and 'false' are
true
andfalse
, respectively. - Zero (the Number 0) is
false
. - All other Numbers are
true
. - Any string that could be parsed as a Number is treated as such (see above.)
- The empty string is parsed as 0 (zero).
- Otherwise:
- Truthy is
true
- Falsy is
false
- Truthy is
Synergize and Power Up
sg.kv(obj, key, value);
sg.ap(arr, value);
sg.kkvv(obj, kkey, vvalue, valueName [= 'value']);
sg.dottedKv(obj, key, value);
sg.push(arr, value);
sg.deref(obj, keys);
sg.setOn(obj, keys, value);
sg.setOnn(obj, keys, value);
sg.kv(obj, key, value)
sg.kv(obj, key, value)
Adds value
to obj
at key
. I.e. { ...obj, [key]: value}.
This function was created to make reduce
much easier to use and more clear, since augmenting
an object with a property is one of the most common uses of reduce
.
sg.reduce(data, {}, function(acc, value, key) {
return sg.kv(acc, key.toLowerCase(), value.toLowerCase());
});
sg.ap(arr, value)
Just like sg.kv
, but for pushing a value to the end of an Array
.
sg.reduce(data, [], function(acc, value) {
return sg.ap(acc, value * 2);
});
sg.dottedKv(obj, key, value)
Just like sg.kv
, when the key has dots (like would be used with MongoDB's
find()
to find based on a deep key.)
key
can be an array of strings, in which case the strings are .joined('.')
.
sg.push(arr, value)
Pushes value
into arr
, and returns the index by which value
can be accessed
in arr
.
var arr = ['I said'];
const index = sg.push(arr, 'booya');
arr[index] += ', baby!';
console.log(arr.join(' ')); // I said booya, baby!