sg0 v1.0.59
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
undefinedandnullas 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
tagsobject, withTag.Nameas the key, andTag.Valueas the value. - By returning
undefined, we are keeping all k/vs that aren'tTags.- Could return
nullwhich 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.
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 aliassg.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
falseforErrorobjects. - Returns
falsefornullishobjects. (So this function is NOTnullish-inputaware.)
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
falsefornullandundefined.- This makes sense,
nullandundefinedare 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
trueandfalse, 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!6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago