You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
7.4 KiB

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