Lean JavaScript Utilities as Micro-libraries
npm install utilisejs
// clean all js files in current dir, except reserved, logging before deletion
fs.readdirSync(__dirname)
.filter(includes('js'))
.filter(not(is.in(core)))
.map(prepend(__dirname+'/'))
.map(log('deleting'))
.map(fs.unlinkSync)
`
`js
// from mutation observer, redraw all added nodes that are custom elements
mutations
.map(key('addedNodes'))
.map(to.arr)
.reduce(flatten)
.filter(by('nodeName', includes('-')))
.map(ripple.draw)
`
* Each function is in it's own repo. This library just has an automated link to all of them. This has a few benefits:
* You can npm i utilise and finally write imports like in each file.
* You don't have to make up esoteric names due to lack of in npm.
* You can use utilise.js to import everything (in your application).
* You can use { utility } = require('utilise/pure') to import what you need + tree shake.
* You don't have to load a 0.5MB utility library just to use one function.
* You can be a lot smarter with dead code elimination, even if you include the base file (but not use everything).
* There is no spraying your code with _. everywhere, since these functions are largely first-class additions to the grammar of the language that make your code a lot more fluent.
* These are mostly stable/fixed, a few new ones may still need experimenting with to get the API right.
* A smaller set of high power-to-weight ratio functions are preferred over many, many different functions that do similar things.
* Each micro-library is only just a few lines.
* Each micro-library has 100% coverage. See badges below.
* All browsers (IE >= 9) + node are supported. Tests are run on real browsers using popper.
* There is no polyfilling done here. Recommend using polyfill.io where needed. Some libraries will fail tests (like promise) which assume a native API like Promise, unless you shim first.
API Reference
Please also refer to the respective test.js for more cases and examples.
  all
Select all elements based on a CSS selector, piercing shadow boundaries if the browser supports it.
`js
all('li.class')
`
Narrow search space by also passing in a node
`js
all('li.class', ul)
`
  append
Append something to a string
`js
['lorem', 'ipsum']
.map(append('-foo')) // returns ['lorem-foo', 'ipsum-foo']
`
  args
Cherry-pick arguments to pass to function by index. This is useful when iterating a list, and invoking a function which may be confused if passed the index and array arguments.
`js
['lorem.txt', 'ipsum.txt']
.map(args(0)(fs.createWriteStream))
`
This would fail without args since the second argument (index) would try to be read as the encoding.
You can pick out more than one argument using an array instead of a number.
  attr
Get or set value of element attribute.
`js
attr('key')(el) // returns value for attribute key
attr('key', 'value')(el) // adds [key=value]
attr('key', false)(el) // removes attribute key
`
  az
Sorts array ascendingly based on the value of a key
`js
array.sort(az('value'))
`
Since it uses key internally, you can also sort on a deep key.
  body
Get the value of a resource from a ripple instance
`js
body(ripple)('users')
`
This is used internally to avoid any type-specific convienience defaults. Always returns undefined if the resource does not exist. You should probably use ripple('resource') to get the value of a resource in your application.
  by
Checks if a property matches a value
`js
users = [ { name: 'foo' }, { name: 'bar' } ]
users
.filter(by('name', 'foo'))
`
If the second value parameter is a function, you can run custom logic against each property (default is ==)
`js
nodes
.filter(by('nodeName', isCustomElement)) // checks if has '-' in tag
`
It is common to sometimes see filtering empty values via .filter(Boolean). If only one parameter is given, it filters out objects that do not have a value for the property.
`js
nodes
.filter(by('prop')) // removes object that do not have a value for prop
`
  chainable
Takes a function, and returns a new function that evaluates the original function and also returns it again ignoring what the evaluated function returns
`js
ripple('key', value) // this normally registers a resource, and returns the value
ripple.resource = chainable(ripple) // ripple.resource now registers a resource, but returns ripple again
ripple
.resource('foo', 'bar')
.resource('lorem', 'ipsum')
`
NB: I think this will be deprecated in favour of the more generic proxy function that is used to alter return values
  client
Simple variable: Am I on the server or browser?
`js
// browser
client == true
// server
client == false
`
Useful for isomorphic apps/libs, and also deadcode elimination.
  clone
Returns a new deep copy of an object
`js
copied = clone(original)
`
  colorfill
Adds color to strings, standardising behaviour across server/client
`js
require('colorfill')
'foo'.red // server, returns string in red
'foo'.red // client, returns string
`
  copy
Copies properties from one object to another
`js
keys(from)
.filter(not(is.in(private)))
.map(copy(from, to))
`
  datum
Returns the D3 datum for a node. Useful in lists as you cannot d3.select(node).datum()
`js
nodes
.map(datum)
`
  deb
Lightweight scoped version of console.log with a prefix, useful for per module identification
`js
deb = deb('[module/prefix]')
deb('something went wrong!') // [module/prefix] something went wrong
`
Returns the input, so it is useful with intermediary logging whilst iterating over a list
`js
list
.map(op1)
.map(deb)
.map(op2)
`
You can filter debug logs on server-side with DEBUG (module, or module/submodule) or using the debug querystring parameter on the client-side.
  debounce
Returns a debounced function. Specify time in ms, or defaults to 100ms.
`js
debounced = debounce(fn)
// or
debounced = debounce(200)(fn)
`
  def
Defines a property, if does not already exist, returning the value
`js
def(object, prop, value[, writable]) // returns value
`
  defaults
Sets default values for properties on an object if not already defined. Normally used at the beginning of components to default state values and expose API:
`js
var state = defaults(this.state, {
values: []
, focused: true
})
// state.focused == this.state.focused == true
// state.values == this.state.values == []
`
To idempotently define API on an element:
`js
defaults(this, { toggle, spin })
// this.spin()
// this.toggle()
`
In case you need to default and reference a property for another property, you can default them individually rather than via an object literal.
`js
defaults(state, 'numbers', [1,2,3,4,5])
defaults(state, 'odd', state.numbers.filter(d => d % 2))
// state.numbers == [1,2,3,4,5]
// state.odd == [1,3,5]
`
  delay
Creates a promise that eventually delays after the specified milliseconds. You can also set to resolve to a specific value.
`js
await delay(1000)
await delay(1000, 'some value')
`
  done
Given a versioned object, attaches a one-time callback for a response on the latest change. This is an alternative and more robust pattern than using random correlation ID's to link request-responses over a decoupled channel.
`js
done(push(newUser)(users))
(d => !d.invalid && showConfirmation())
`
  el
Creates a node from a CSS selector
`js
el(div.foo.bar[lorem=ipsum]) // returns
`
  emitterify
Enhance any object with .on, .once and .emit
`js
var o = emitterify({})
o.on('event') // get listeners for event
o.on('event', fn) // set listener on arbitrary event
o.once('event', fn) // set listener that is only called once
o.on('event.ns', fn) // set listener for event.namespace, unique listener per namespace
o.emit('event', payload) // emit event with optional payload
o.emit('event', [array]) // emit event with optional multiple arguments
`
  err
Lightweight scoped version of console.error with a prefix, useful for per module identification
`js
err = err('[module/prefix]')
err('something went wrong!') // [module/prefix] something went wrong
`
  escape
Escapes HTML
`js
escape = escape('') // '<div></div>'
`
  extend
Extends an object with properties from another, not overwriting properties by default. See also extend.
`js
to = { foo: 1 }
from = { foo: 2, bar: 3 }
extend(to)(from) // to == { foo: 1, bar: 3 }
`
  falsy
Function that returns false
`js
shouldIContinue = falsy // when executed, returns false
`
  file
Reads and returns a file. Server only.
`js
var template = file('template.html')
`
  filify
Browserify transform that resolves file('filename') to the actual file
`js
file('foo') // converted to a string containing the contents of the file foo
`
  filter
Filters an array
`js
once(tr, filter(isEven))
`
  first
Returns first element in array
`js
first(array) // returns array[0]
`
  flatten
Flattens a 2D array
`js
twoD = [[1], [2], [3]]
oneD = twoD.reduce(flatten) // [1, 2, 3]
`
  form
Converts a