1# figgy-pudding [](https://npm.im/figgy-pudding) [](https://npm.im/figgy-pudding) [](https://travis-ci.org/zkat/figgy-pudding) [](https://ci.appveyor.com/project/zkat/figgy-pudding) [](https://coveralls.io/github/zkat/figgy-pudding?branch=latest) 2 3[`figgy-pudding`](https://github.com/zkat/figgy-pudding) is a small JavaScript 4library for managing and composing cascading options objects -- hiding what 5needs to be hidden from each layer, without having to do a lot of manual munging 6and passing of options. 7 8### The God Object is Dead! 9### Now Bring Us Some Figgy Pudding! 10 11## Install 12 13`$ npm install figgy-pudding` 14 15## Table of Contents 16 17* [Example](#example) 18* [Features](#features) 19* [API](#api) 20 * [`figgyPudding(spec)`](#figgy-pudding) 21 * [`PuddingFactory(values)`](#pudding-factory) 22 * [`opts.get()`](#opts-get) 23 * [`opts.concat()`](#opts-concat) 24 * [`opts.toJSON()`](#opts-to-json) 25 * [`opts.forEach()`](#opts-for-each) 26 * [`opts[Symbol.iterator]()`](#opts-symbol-iterator) 27 * [`opts.entries()`](#opts-entries) 28 * [`opts.keys()`](#opts-keys) 29 * [`opts.value()`](#opts-values) 30 31### Example 32 33```javascript 34// print-package.js 35const fetch = require('./fetch.js') 36const puddin = require('figgy-pudding') 37 38const PrintOpts = puddin({ 39 json: { default: false } 40}) 41 42async function printPkg (name, opts) { 43 // Expected pattern is to call this in every interface function. If `opts` is 44 // not passed in, it will automatically create an (empty) object for it. 45 opts = PrintOpts(opts) 46 const uri = `https://registry.npmjs.com/${name}` 47 const res = await fetch(uri, opts.concat({ 48 // Add or override any passed-in configs and pass them down. 49 log: customLogger 50 })) 51 // The following would throw an error, because it's not in PrintOpts: 52 // console.log(opts.log) 53 if (opts.json) { 54 return res.json() 55 } else { 56 return res.text() 57 } 58} 59 60console.log(await printPkg('figgy', { 61 // Pass in *all* configs at the toplevel, as a regular object. 62 json: true, 63 cache: './tmp-cache' 64})) 65``` 66 67```javascript 68// fetch.js 69const puddin = require('figgy-pudding') 70 71const FetchOpts = puddin({ 72 log: { default: require('npmlog') }, 73 cache: {} 74}) 75 76module.exports = async function (..., opts) { 77 opts = FetchOpts(opts) 78} 79``` 80 81### Features 82 83* hide options from layer that didn't ask for it 84* shared multi-layer options 85* make sure `opts` argument is available 86* transparent key access like normal keys, through a Proxy. No need for`.get()`! 87* default values 88* key aliases 89* arbitrary key filter functions 90* key/value iteration 91* serialization 92* 100% test coverage using `tap --100` 93 94### API 95 96#### <a name="figgy-pudding"></a> `> figgyPudding({ key: { default: val } | String }, [opts]) -> PuddingFactory` 97 98Defines an Options constructor that can be used to collect only the needed 99options. 100 101An optional `default` property for specs can be used to specify default values 102if nothing was passed in. 103 104If the value for a spec is a string, it will be treated as an alias to that 105other key. 106 107##### Example 108 109```javascript 110const MyAppOpts = figgyPudding({ 111 lg: 'log', 112 log: { 113 default: () => require('npmlog') 114 }, 115 cache: {} 116}) 117``` 118 119#### <a name="pudding-factory"></a> `> PuddingFactory(...providers) -> FiggyPudding{}` 120 121Instantiates an options object defined by `figgyPudding()`, which uses 122`providers`, in order, to find requested properties. 123 124Each provider can be either a plain object, a `Map`-like object (that is, one 125with a `.get()` method) or another figgyPudding `Opts` object. 126 127When nesting `Opts` objects, their properties will not become available to the 128new object, but any further nested `Opts` that reference that property _will_ be 129able to read from their grandparent, as long as they define that key. Default 130values for nested `Opts` parents will be used, if found. 131 132##### Example 133 134```javascript 135const ReqOpts = figgyPudding({ 136 follow: {} 137}) 138 139const opts = ReqOpts({ 140 follow: true, 141 log: require('npmlog') 142}) 143 144opts.follow // => true 145opts.log // => Error: ReqOpts does not define `log` 146 147const MoreOpts = figgyPudding({ 148 log: {} 149}) 150MoreOpts(opts).log // => npmlog object (passed in from original plain obj) 151MoreOpts(opts).follow // => Error: MoreOpts does not define `follow` 152``` 153 154#### <a name="opts-get"></a> `> opts.get(key) -> Value` 155 156Gets a value from the options object. 157 158##### Example 159 160```js 161const opts = MyOpts(config) 162opts.get('foo') // value of `foo` 163opts.foo // Proxy-based access through `.get()` 164``` 165 166#### <a name="opts-concat"></a> `> opts.concat(...moreProviders) -> FiggyPudding{}` 167 168Creates a new opts object of the same type as `opts` with additional providers. 169Providers further to the right shadow providers to the left, with properties in 170the original `opts` being shadows by the new providers. 171 172##### Example 173 174```js 175const opts = MyOpts({x: 1}) 176opts.get('x') // 1 177opts.concat({x: 2}).get('x') // 2 178opts.get('x') // 1 (original opts object left intact) 179``` 180 181#### <a name="opts-to-json"></a> `> opts.toJSON() -> Value` 182 183Converts `opts` to a plain, JSON-stringifiable JavaScript value. Used internally 184by JavaScript to get `JSON.stringify()` working. 185 186Only keys that are readable by the current pudding type will be serialized. 187 188##### Example 189 190```js 191const opts = MyOpts({x: 1}) 192opts.toJSON() // {x: 1} 193JSON.stringify(opts) // '{"x":1}' 194``` 195 196#### <a name="opts-for-each"></a> `> opts.forEach((value, key, opts) => {}, thisArg) -> undefined` 197 198Iterates over the values of `opts`, limited to the keys readable by the current 199pudding type. `thisArg` will be used to set the `this` argument when calling the 200`fn`. 201 202##### Example 203 204```js 205const opts = MyOpts({x: 1, y: 2}) 206opts.forEach((value, key) => console.log(key, '=', value)) 207``` 208 209#### <a name="opts-entries"></a> `> opts.entries() -> Iterator<[[key, value], ...]>` 210 211Returns an iterator that iterates over the keys and values in `opts`, limited to 212the keys readable by the current pudding type. Each iteration returns an array 213of `[key, value]`. 214 215##### Example 216 217```js 218const opts = MyOpts({x: 1, y: 2}) 219[...opts({x: 1, y: 2}).entries()] // [['x', 1], ['y', 2]] 220``` 221 222#### <a name="opts-symbol-iterator"></a> `> opts[Symbol.iterator]() -> Iterator<[[key, value], ...]>` 223 224Returns an iterator that iterates over the keys and values in `opts`, limited to 225the keys readable by the current pudding type. Each iteration returns an array 226of `[key, value]`. Makes puddings work natively with JS iteration mechanisms. 227 228##### Example 229 230```js 231const opts = MyOpts({x: 1, y: 2}) 232[...opts({x: 1, y: 2})] // [['x', 1], ['y', 2]] 233for (let [key, value] of opts({x: 1, y: 2})) { 234 console.log(key, '=', value) 235} 236``` 237 238#### <a name="opts-keys"></a> `> opts.keys() -> Iterator<[key, ...]>` 239 240Returns an iterator that iterates over the keys in `opts`, limited to the keys 241readable by the current pudding type. 242 243##### Example 244 245```js 246const opts = MyOpts({x: 1, y: 2}) 247[...opts({x: 1, y: 2}).keys()] // ['x', 'y'] 248``` 249 250#### <a name="opts-values"></a> `> opts.values() -> Iterator<[value, ...]>` 251 252Returns an iterator that iterates over the values in `opts`, limited to the keys 253readable by the current pudding type. 254 255##### Example 256' 257```js 258const opts = MyOpts({x: 1, y: 2}) 259[...opts({x: 1, y: 2}).values()] // [1, 2] 260``` 261