{"id":13447208,"url":"https://github.com/zkat/figgy-pudding","last_synced_at":"2025-04-30T16:20:29.107Z","repository":{"id":63586557,"uuid":"81156658","full_name":"zkat/figgy-pudding","owner":"zkat","description":"Cascading, controlled-visibility options object management.","archived":false,"fork":false,"pushed_at":"2020-05-11T17:23:26.000Z","size":3014,"stargazers_count":40,"open_issues_count":4,"forks_count":7,"subscribers_count":2,"default_branch":"latest","last_synced_at":"2025-03-30T17:46:13.112Z","etag":null,"topics":["configuration","javascript","npm","options-resolver"],"latest_commit_sha":null,"homepage":"https://npm.im/figgy-pudding","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zkat.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["zkat"]}},"created_at":"2017-02-07T02:26:08.000Z","updated_at":"2024-11-30T05:16:58.000Z","dependencies_parsed_at":"2022-11-21T22:17:21.126Z","dependency_job_id":null,"html_url":"https://github.com/zkat/figgy-pudding","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkat%2Ffiggy-pudding","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkat%2Ffiggy-pudding/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkat%2Ffiggy-pudding/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkat%2Ffiggy-pudding/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zkat","download_url":"https://codeload.github.com/zkat/figgy-pudding/tar.gz/refs/heads/latest","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251739909,"owners_count":21635946,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration","javascript","npm","options-resolver"],"created_at":"2024-07-31T05:01:10.969Z","updated_at":"2025-04-30T16:20:29.081Z","avatar_url":"https://github.com/zkat.png","language":"JavaScript","funding_links":["https://github.com/sponsors/zkat"],"categories":["JavaScript"],"sub_categories":[],"readme":"# 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)\n\n[`figgy-pudding`](https://github.com/zkat/figgy-pudding) is a small JavaScript\nlibrary for managing and composing cascading options objects -- hiding what\nneeds to be hidden from each layer, without having to do a lot of manual munging\nand passing of options.\n\n### The God Object is Dead!\n### Now Bring Us Some Figgy Pudding!\n\n## Install\n\n`$ npm install figgy-pudding`\n\n## Table of Contents\n\n* [Example](#example)\n* [Features](#features)\n* [API](#api)\n  * [`figgyPudding(spec)`](#figgy-pudding)\n  * [`PuddingFactory(values)`](#pudding-factory)\n    * [`opts.get()`](#opts-get)\n    * [`opts.concat()`](#opts-concat)\n    * [`opts.toJSON()`](#opts-to-json)\n    * [`opts.forEach()`](#opts-for-each)\n    * [`opts[Symbol.iterator]()`](#opts-symbol-iterator)\n    * [`opts.entries()`](#opts-entries)\n    * [`opts.keys()`](#opts-keys)\n    * [`opts.value()`](#opts-values)\n\n### Example\n\n```javascript\n// print-package.js\nconst fetch = require('./fetch.js')\nconst puddin = require('figgy-pudding')\n\nconst PrintOpts = puddin({\n  json: { default: false }\n})\n\nasync function printPkg (name, opts) {\n  // Expected pattern is to call this in every interface function. If `opts` is\n  // not passed in, it will automatically create an (empty) object for it.\n  opts = PrintOpts(opts)\n  const uri = `https://registry.npmjs.com/${name}`\n  const res = await fetch(uri, opts.concat({\n    // Add or override any passed-in configs and pass them down.\n    log: customLogger\n  }))\n  // The following would throw an error, because it's not in PrintOpts:\n  // console.log(opts.log)\n  if (opts.json) {\n    return res.json()\n  } else {\n    return res.text()\n  }\n}\n\nconsole.log(await printPkg('figgy', {\n  // Pass in *all* configs at the toplevel, as a regular object.\n  json: true,\n  cache: './tmp-cache'\n}))\n```\n\n```javascript\n// fetch.js\nconst puddin = require('figgy-pudding')\n\nconst FetchOpts = puddin({\n  log: { default: require('npmlog') },\n  cache: {}\n})\n\nmodule.exports = async function (..., opts) {\n  opts = FetchOpts(opts)\n}\n```\n\n### Features\n\n* hide options from layer that didn't ask for it\n* shared multi-layer options\n* make sure `opts` argument is available\n* transparent key access like normal keys, through a Proxy. No need for`.get()`!\n* default values\n* key aliases\n* arbitrary key filter functions\n* key/value iteration\n* serialization\n* 100% test coverage using `tap --100`\n\n### API\n\n#### \u003ca name=\"figgy-pudding\"\u003e\u003c/a\u003e `\u003e figgyPudding({ key: { default: val } | String }, [opts]) -\u003e PuddingFactory`\n\nDefines an Options constructor that can be used to collect only the needed\noptions.\n\nAn optional `default` property for specs can be used to specify default values\nif nothing was passed in.\n\nIf the value for a spec is a string, it will be treated as an alias to that\nother key.\n\n##### Example\n\n```javascript\nconst MyAppOpts = figgyPudding({\n  lg: 'log',\n  log: {\n    default: () =\u003e require('npmlog')\n  },\n  cache: {}\n})\n```\n\n#### \u003ca name=\"pudding-factory\"\u003e\u003c/a\u003e `\u003e PuddingFactory(...providers) -\u003e FiggyPudding{}`\n\nInstantiates an options object defined by `figgyPudding()`, which uses\n`providers`, in order, to find requested properties.\n\nEach provider can be either a plain object, a `Map`-like object (that is, one\nwith a `.get()` method) or another figgyPudding `Opts` object.\n\nWhen nesting `Opts` objects, their properties will not become available to the\nnew object, but any further nested `Opts` that reference that property _will_ be\nable to read from their grandparent, as long as they define that key. Default\nvalues for nested `Opts` parents will be used, if found.\n\n##### Example\n\n```javascript\nconst ReqOpts = figgyPudding({\n  follow: {}\n})\n\nconst opts = ReqOpts({\n  follow: true,\n  log: require('npmlog')\n})\n\nopts.follow // =\u003e true\nopts.log // =\u003e Error: ReqOpts does not define `log`\n\nconst MoreOpts = figgyPudding({\n  log: {}\n})\nMoreOpts(opts).log // =\u003e npmlog object (passed in from original plain obj)\nMoreOpts(opts).follow // =\u003e Error: MoreOpts does not define `follow`\n```\n\n#### \u003ca name=\"opts-get\"\u003e\u003c/a\u003e `\u003e opts.get(key) -\u003e Value`\n\nGets a value from the options object.\n\n##### Example\n\n```js\nconst opts = MyOpts(config)\nopts.get('foo') // value of `foo`\nopts.foo // Proxy-based access through `.get()`\n```\n\n#### \u003ca name=\"opts-concat\"\u003e\u003c/a\u003e `\u003e opts.concat(...moreProviders) -\u003e FiggyPudding{}`\n\nCreates a new opts object of the same type as `opts` with additional providers.\nProviders further to the right shadow providers to the left, with properties in\nthe original `opts` being shadows by the new providers.\n\n##### Example\n\n```js\nconst opts = MyOpts({x: 1})\nopts.get('x') // 1\nopts.concat({x: 2}).get('x') // 2\nopts.get('x') // 1 (original opts object left intact)\n```\n\n#### \u003ca name=\"opts-to-json\"\u003e\u003c/a\u003e `\u003e opts.toJSON() -\u003e Value`\n\nConverts `opts` to a plain, JSON-stringifiable JavaScript value. Used internally\nby JavaScript to get `JSON.stringify()` working.\n\nOnly keys that are readable by the current pudding type will be serialized.\n\n##### Example\n\n```js\nconst opts = MyOpts({x: 1})\nopts.toJSON() // {x: 1}\nJSON.stringify(opts) // '{\"x\":1}'\n```\n\n#### \u003ca name=\"opts-for-each\"\u003e\u003c/a\u003e `\u003e opts.forEach((value, key, opts) =\u003e {}, thisArg) -\u003e undefined`\n\nIterates over the values of `opts`, limited to the keys readable by the current\npudding type. `thisArg` will be used to set the `this` argument when calling the\n`fn`.\n\n##### Example\n\n```js\nconst opts = MyOpts({x: 1, y: 2})\nopts.forEach((value, key) =\u003e console.log(key, '=', value))\n```\n\n#### \u003ca name=\"opts-entries\"\u003e\u003c/a\u003e `\u003e opts.entries() -\u003e Iterator\u003c[[key, value], ...]\u003e`\n\nReturns an iterator that iterates over the keys and values in `opts`, limited to\nthe keys readable by the current pudding type. Each iteration returns an array\nof `[key, value]`.\n\n##### Example\n\n```js\nconst opts = MyOpts({x: 1, y: 2})\n[...opts({x: 1, y: 2}).entries()] // [['x', 1], ['y', 2]]\n```\n\n#### \u003ca name=\"opts-symbol-iterator\"\u003e\u003c/a\u003e `\u003e opts[Symbol.iterator]() -\u003e Iterator\u003c[[key, value], ...]\u003e`\n\nReturns an iterator that iterates over the keys and values in `opts`, limited to\nthe keys readable by the current pudding type. Each iteration returns an array\nof `[key, value]`. Makes puddings work natively with JS iteration mechanisms.\n\n##### Example\n\n```js\nconst opts = MyOpts({x: 1, y: 2})\n[...opts({x: 1, y: 2})] // [['x', 1], ['y', 2]]\nfor (let [key, value] of opts({x: 1, y: 2})) {\n  console.log(key, '=', value)\n}\n```\n\n#### \u003ca name=\"opts-keys\"\u003e\u003c/a\u003e `\u003e opts.keys() -\u003e Iterator\u003c[key, ...]\u003e`\n\nReturns an iterator that iterates over the keys in `opts`, limited to the keys\nreadable by the current pudding type.\n\n##### Example\n\n```js\nconst opts = MyOpts({x: 1, y: 2})\n[...opts({x: 1, y: 2}).keys()] // ['x', 'y']\n```\n\n#### \u003ca name=\"opts-values\"\u003e\u003c/a\u003e `\u003e opts.values() -\u003e Iterator\u003c[value, ...]\u003e`\n\nReturns an iterator that iterates over the values in `opts`, limited to the keys\nreadable by the current pudding type.\n\n##### Example\n'\n```js\nconst opts = MyOpts({x: 1, y: 2})\n[...opts({x: 1, y: 2}).values()] // [1, 2]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzkat%2Ffiggy-pudding","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzkat%2Ffiggy-pudding","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzkat%2Ffiggy-pudding/lists"}