figgy-pudding
is a small JavaScript
library for managing and composing cascading options objects -- hiding what
needs to be hidden from each layer, without having to do a lot of manual munging
and passing of options.
$ npm install figgy-pudding
// print-package.js
const fetch = require('./fetch.js')
const puddin = require('figgy-pudding')
const PrintOpts = puddin({
json: { default: false }
})
async function printPkg (name, opts) {
// Expected pattern is to call this in every interface function. If `opts` is
// not passed in, it will automatically create an (empty) object for it.
opts = PrintOpts(opts)
const uri = `https://registry.npmjs.com/${name}`
const res = await fetch(uri, opts.concat({
// Add or override any passed-in configs and pass them down.
log: customLogger
}))
// The following would throw an error, because it's not in PrintOpts:
// console.log(opts.log)
if (opts.json) {
return res.json()
} else {
return res.text()
}
}
console.log(await printPkg('figgy', {
// Pass in *all* configs at the toplevel, as a regular object.
json: true,
cache: './tmp-cache'
}))
// fetch.js
const puddin = require('figgy-pudding')
const FetchOpts = puddin({
log: { default: require('npmlog') },
cache: {}
})
module.exports = async function (..., opts) {
opts = FetchOpts(opts)
}
- hide options from layer that didn't ask for it
- shared multi-layer options
- make sure
opts
argument is available - transparent key access like normal keys, through a Proxy. No need for
.get()
! - default values
- key aliases
- arbitrary key filter functions
- key/value iteration
- serialization
- 100% test coverage using
tap --100
Defines an Options constructor that can be used to collect only the needed options.
An optional default
property for specs can be used to specify default values
if nothing was passed in.
If the value for a spec is a string, it will be treated as an alias to that other key.
const MyAppOpts = figgyPudding({
lg: 'log',
log: {
default: () => require('npmlog')
},
cache: {}
})
Instantiates an options object defined by figgyPudding()
, which uses
providers
, in order, to find requested properties.
Each provider can be either a plain object, a Map
-like object (that is, one
with a .get()
method) or another figgyPudding Opts
object.
When nesting Opts
objects, their properties will not become available to the
new object, but any further nested Opts
that reference that property will be
able to read from their grandparent, as long as they define that key. Default
values for nested Opts
parents will be used, if found.
const ReqOpts = figgyPudding({
follow: {}
})
const opts = ReqOpts({
follow: true,
log: require('npmlog')
})
opts.follow // => true
opts.log // => Error: ReqOpts does not define `log`
const MoreOpts = figgyPudding({
log: {}
})
MoreOpts(opts).log // => npmlog object (passed in from original plain obj)
MoreOpts(opts).follow // => Error: MoreOpts does not define `follow`
Gets a value from the options object.
const opts = MyOpts(config)
opts.get('foo') // value of `foo`
opts.foo // Proxy-based access through `.get()`
Creates a new opts object of the same type as opts
with additional providers.
Providers further to the right shadow providers to the left, with properties in
the original opts
being shadows by the new providers.
const opts = MyOpts({x: 1})
opts.get('x') // 1
opts.concat({x: 2}).get('x') // 2
opts.get('x') // 1 (original opts object left intact)
Converts opts
to a plain, JSON-stringifiable JavaScript value. Used internally
by JavaScript to get JSON.stringify()
working.
Only keys that are readable by the current pudding type will be serialized.
const opts = MyOpts({x: 1})
opts.toJSON() // {x: 1}
JSON.stringify(opts) // '{"x":1}'
Iterates over the values of opts
, limited to the keys readable by the current
pudding type. thisArg
will be used to set the this
argument when calling the
fn
.
const opts = MyOpts({x: 1, y: 2})
opts.forEach((value, key) => console.log(key, '=', value))
Returns an iterator that iterates over the keys and values in opts
, limited to
the keys readable by the current pudding type. Each iteration returns an array
of [key, value]
.
const opts = MyOpts({x: 1, y: 2})
[...opts({x: 1, y: 2}).entries()] // [['x', 1], ['y', 2]]
Returns an iterator that iterates over the keys and values in opts
, limited to
the keys readable by the current pudding type. Each iteration returns an array
of [key, value]
. Makes puddings work natively with JS iteration mechanisms.
const opts = MyOpts({x: 1, y: 2})
[...opts({x: 1, y: 2})] // [['x', 1], ['y', 2]]
for (let [key, value] of opts({x: 1, y: 2})) {
console.log(key, '=', value)
}
Returns an iterator that iterates over the keys in opts
, limited to the keys
readable by the current pudding type.
const opts = MyOpts({x: 1, y: 2})
[...opts({x: 1, y: 2}).keys()] // ['x', 'y']
Returns an iterator that iterates over the values in opts
, limited to the keys
readable by the current pudding type.
'
const opts = MyOpts({x: 1, y: 2})
[...opts({x: 1, y: 2}).values()] // [1, 2]