{"id":31049243,"url":"https://github.com/captemulation/service-builder","last_synced_at":"2025-09-14T21:48:29.968Z","repository":{"id":9388084,"uuid":"60103874","full_name":"CaptEmulation/service-builder","owner":"CaptEmulation","description":"Javascript functional dependency injector","archived":false,"fork":false,"pushed_at":"2023-01-06T01:39:28.000Z","size":484,"stargazers_count":4,"open_issues_count":10,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-09T15:51:42.753Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CaptEmulation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-31T16:00:59.000Z","updated_at":"2020-11-29T15:56:00.000Z","dependencies_parsed_at":"2023-01-13T15:19:51.397Z","dependency_job_id":null,"html_url":"https://github.com/CaptEmulation/service-builder","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/CaptEmulation/service-builder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CaptEmulation%2Fservice-builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CaptEmulation%2Fservice-builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CaptEmulation%2Fservice-builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CaptEmulation%2Fservice-builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CaptEmulation","download_url":"https://codeload.github.com/CaptEmulation/service-builder/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CaptEmulation%2Fservice-builder/sbom","scorecard":{"id":27238,"data":{"date":"2025-08-11","repo":{"name":"github.com/CaptEmulation/service-builder","commit":"8f99efbdcc8037c5093a50467f66ed2ff5b63b18"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/23 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"24 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-qrpm-p2h7-hrv2","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-14T18:11:25.673Z","repository_id":9388084,"created_at":"2025-08-14T18:11:25.674Z","updated_at":"2025-08-14T18:11:25.674Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275174427,"owners_count":25418064,"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","status":"online","status_checked_at":"2025-09-14T02:00:10.474Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-09-14T21:48:27.947Z","updated_at":"2025-09-14T21:48:29.947Z","avatar_url":"https://github.com/CaptEmulation.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![npm version](https://badge.fury.io/js/shutterstock-mold.svg)](https://badge.fury.io/js/shutterstock-mold) [![Build Status](https://travis-ci.org/shutterstock/mold.svg?branch=master)](https://travis-ci.org/shutterstock/mold)\n\n![logo](./MOLD.png?raw=true)\n\n# Introduction\n\n`shutterstock-mold` is a dependency injection framework that helps developers write factories that satisfy the principle of least privilege for functional arguments. The target audience for this library are those that like having factories but not necessarily writing them. In addition, this library makes writing unit tests with mocked dependencies a breeze.  \n\n# Example\n\nLet's assume we are building a car module.  The initial approach might be to create an object that has implicit dependencies:\n\n```\nfunction createCar() {\n  const engine = createEngine();\n  const wheels = createWheels();\n  return {\n    start() {\n      engine.start();\n    },\n    drive() {\n      if (engine.isRunning) {\n        wheels.rotate();\n      }\n    }\n  }\n}\n```\n - [ ] Supports dependency injection\n - [x] Supports principle of least privilege\n\nThis initial version is great because calling `createCar` is all that is needed to make a car.  Nothing more is needed to be known about how a car works.  However, the car that is being create is not very flexible.  Only one type of car can exist.\n\nLater developers learn that engines can have a variable number of cylinders and wheels can have different friction coefficients.  To support these the `createCar` factory is modified:\n\n```\nfunction createCar(engineCylinders, wheelFriction) {\n  const engine = createEngine(engineCylinders);\n  const wheels = createWheels(wheelFriction);\n  return {\n    start() {\n      engine.start();\n    },\n    drive() {\n      if (engine.isRunning) {\n        wheels.rotate();\n      }\n    }\n  }\n}\n```\n\n- [ ] Supports dependency injection\n- [ ] Supports principle of least privilege\n\nUh-oh... Now the `createCar` class is becoming very tightly coupled to its dependencies.  Furthermore, any changes to `createEngine` or `createWheels` now requires changes to `createCar` *and any code that is dependent on Car*.  We still don't support dependency injection, but also now `createCar` needs to know more about `createEngine` and `createWheels`.\n\nFor reasons of dependency injection, passing in dependencies as arguments helps write code that supports dependency injection.\n\n```\nfunction createCar(engine, wheels) {\n  return {\n    start() {\n      engine.start();\n    },\n    drive() {\n      if (engine.isRunning) {\n        wheels.rotate();\n      }\n    }\n  }\n}\n```\n\n- [x] Supports dependency injection\n- [ ] Supports principle of least privilege\n\nGreat!  Now `createCar` doesn't care where `engine` and `wheels` came from.  However, the problem of least privilege has only been moved around.  Now, in order to make a car instance, clients need to also make an `engine` and `wheels`.  Our code for instantiating a car has gone from:\n\n```\nconst car = createCar();\n```\nto\n```\nconst car = createCar(6, 0.2);\n```\nto\n```\nconst car = createCar(createEngine(6), createWheels(0.2));\n```\n\nNow imagine that `createEngine` and `createWheels` end up needing additional dependencies.  Before long, in order to use `createCar`, the developer will need to first create the rubber, the metal, the wood panelling and then tighten every screw.\n\n`shutterstock-mold` can create a factory for building cars.\n\n```\nimport builder from 'shutterstock-mold';\n\nconst carBlueprint = builder({\n  car(engine, wheels) { /* returns a car */ },\n  engine(cylinders) { /* returns an engine */ },\n  wheels(friction) { /* returns wheels */ },\n});\n\nconst sportsCarFactory = carBlueprint.dsl({\n  cylinders: 8,\n  friction: 0.9,\n});\n\n// Now anyone can make a sports car:\nconst sportsCar = sportsCarFactory.getCar();\n```\n\n`shutterstock-mold` will automatically create, walk and fill the dependency tree in order to create a instances.  Users of the factory do not need to car how instances are built.\n\n\nNow that we have a blueprint, we can create new factories with different dependencies:\n\n```\nconst sedanFactory = blueprint.dsl({\n  cylinders: 4,\n  friction: 0.6,\n});\n\n// Make a sedan\nconst sedan = sedanFactory.getCar();\n```\n\nOr even with entirely new types:\n\n```\nconst rocketCarFactory = blueprint.dsl({\n  engine: createJetEngine,\n  wheels: createRetractableWheels,\n});\n\nconst rocketCar = rocketCarFactory.getCar();\n```\n\nWith the factory DSL, dependencies do not need to be provided initially.\n\n```\nconst enginelessCarFactory = builder({\n  car(engine, wheels)  { /* returns a car */ },\n  wheels(friction) { /* returns wheels */ },\n}).dsl({\n  friction: 0.9,\n});\n\nenginelessCarFactory.getCar(); // Error: Failed to resolve engine from wheels,friction at car\n\nenginelessCarFactory\n  .withEngine(engine)\n  .getCar(); // Success\n```\n\n# Functional Factories\n\nInstead of the DSL syntax, a functional factory can be created.\n\n```\nconst carBlueprint = builder({\n  car(engine, wheels) { /* returns a car */ },\n  engine(cylinders) { /* returns an engine */ },\n  wheels(friction) { /* returns wheels */ },\n});\n\nconst racingCarFactory = carBlueprint.factory({\n  cylinders: 12,\n  friction: 0.95,\n});\n\nracingCarFactory(car =\u003e {\n  // Do something with car\n});\n```\n\nThe function passed into the factory will have dependencies matching the name of the arguments injected into the function when it is called.\n\n# Dependency Injection\n\nCreating a factory is always a two-step process.  The examples here go from builder =\u003e blueprint =\u003e factory.  Blueprint dependencies can be replaced at any time or overloaded when creating the final factory.  This is most useful for test.\n\n```\nconst carBlueprint = builder({\n  car(engine, wheels) { /* returns a car */ },\n  engine(cylinders) { /* returns an engine */ },\n  wheels(friction) { /* returns wheels */ },\n});\n\n// Create factory with mock wheels\nconst mockWheels = { rotate: mockFunc };\nconst testCarFactory = carBlueprint.dsl({\n  cylinders: 0,\n  // Since we are injecting the wheels, friction is no longer required\n  wheels: mockWheels,\n});\n\nconst testCar = testCarFactory.getCar();\ntestCar.start();\ntestCar.drive();\nexpect(mockWheels.rotate).toHaveBeenCalled();\n```\n\n# Additional Usage\n\n```\nimport builder from 'shutterstock-mold'\n\nconst blueprint = builder({\n  breakfast: function (meat, eggs, drink) {\n    return `${meat} with ${eggs} and ${drink}`;\n  },\n  eggs: eggStyle =\u003e `${eggStyle} eggs`,\n  solids: (meat, eggs) =\u003e [meat, eggs].join(', ')\n});\n\nconst factory = blueprint.dsl();\n\nfactory\n  .withMeat('ham')\n  .withEggStyle('scrambled')\n  .withDrink('orange juice')\n  .getBreakfast();\n// =\u003e 'ham with scrambled eggs and orange juice'\n\nconst anotherFactory = blueprint.dsl({\n  meat: 'sausage'\n})\n  .withEggStyle('scrambled');\n\nanotherFactory.getSolids();\n// =\u003e 'ham, scrambled eggs'\n\nanotherFactory.getEggs();\n// =\u003e 'scrambled eggs'\n\nanotherFactory.getBreakfast();\n// =\u003e Error: Failed to resolve drink from meat,eggStyle,eggs at breakfast\n```\n# Lazy properties\nInstead of using the getter functions, there are also lazily evaluated properties on the factory\n\n```\nconst blueprint = builder({\n  eggs: eggStyle =\u003e `${eggStyle} eggs`,\n});\nconst factory = blueprint.dsl({\n  eggStyle: 'fried',\n});\nconsole.log(factory.eggs);\n// =\u003e 'fried eggs'\n```\n\n# Implicit properties\nIf a non-function non-array is passed in as a dependency, then it will be implicitly wrapped in a function.\n\n```\nconst blueprint = builder({\n  foo: bar =\u003e `foo${bar}`,\n  bar: 'bar',  \n});\nconst factory = blueprint.dsl();\nconsole.log(factory.foo);\n// =\u003e 'foobar'\n```\n\n# Resolver\n\n`$` is a resolver for dependencies\n\n```\nconst blueprint = builder({\n  eggs: eggStyle =\u003e `${eggStyle} eggs`,\n  meat: meatStyle =\u003e `${meatStyle} steak`,\n});\nconst factory = blueprint.dsl({\n  eggStyle: 'fried',\n  meatStyle: 'rare',\n});\nconsole.log(factory.$((meat, eggs) =\u003e `${eggs} and ${meat}`));\n// =\u003e 'fried eggs and rare steak'\n```\n\nAlternatively, you can forgo the DSL syntax in favor of a pure resolver.  A resolver will accept a function and will call the function with all dependencies resolved (or will throw an error):\n\n```\nconst blueprint = builder({\n  eggs: eggStyle =\u003e `${eggStyle} eggs`,\n  meat: meatStyle =\u003e `${meatStyle} steak`,\n});\nconst $ = blueprint.factory({\n  eggStyle: 'fried',\n  meatStyle: 'rare',\n});\nconsole.log($((meat, eggs) =\u003e `${eggs} and ${meat}`));\n// =\u003e 'fried eggs and rare steak'\n\n// DSLs will also include a factory resolver named $\n\nconst factory = blueprint.dsl({\n  eggStyle: 'fried',\n  meatStyle: 'rare',\n});\nconsole.log(factory.$((meat, eggs) =\u003e `${eggs} and ${meat}`));\n```\n\n# Promises\n\nIf any dependencies return a promise, then the promise will be resolved before being used as dependency.  A side effect of this behavior is that any service that depends on a promise will also return a promise.\n\n```\nimport builder from 'shutterstock-mold'\n\nconst blueprint = builder({\n  breakfast: function (meat, eggs, drink) {\n    return `${meat} with ${eggs} and ${drink}`;\n  },\n  // Get eggs async\n  eggs: eggStyle =\u003e Promise.resolve(`${eggStyle} eggs`),\n  solids: (meat, eggs) =\u003e [meat, eggs].join(', ')\n});\n\nconst factory = blueprint.dsl();\n\nfactory\n  .withMeat('ham')\n  .withEggStyle('scrambled')\n  .withDrink('orange juice')\n  .getBreakfast()\n  .then(console.log.bind(console));\n// =\u003e 'ham with scrambled eggs and orange juice'\n\nconst anotherFactory = blueprint.dsl()\n  .withMeat('ham')\n  .withEggStyle('scrambled');\n\nanotherFactory.getSolids()\n  .then(console.log.bind(console));\n// =\u003e 'ham, scrambled eggs'\n\nanotherFactory.getEggs()\n  .then(console.log.bind(console));\n// =\u003e 'scrambled eggs'\n\nanotherFactory.getBreakfast()\n  .then(console.log.bind(console), console.error.bind(console));\n// =\u003e Error: Failed to resolve drink from meat,eggStyle,eggs at breakfast\n\n```\n\n# Async\n\nPromise providers work well with async / await\n\n```\nimport builder from 'shutterstock-mold'\n\nconst blueprint = builder({\n  breakfast: function (meat, eggs, drink) {\n    return `${meat} with ${eggs} and ${drink}`;\n  },\n  // Get eggs async\n  eggs: async eggStyle =\u003e await asyncOperation(`${eggStyle} eggs`),\n  solids: (meat, eggs) =\u003e [meat, eggs].join(', ')\n});\n\nconst factory = blueprint.dsl();\n\nconsole.log(await factory\n  .withMeat('ham')\n  .withEggStyle('scrambled')\n  .withDrink('orange juice')\n  .getBreakfast());\n// =\u003e 'ham with scrambled eggs and orange juice'\n\nconst anotherFactory = blueprint.dsl()\n  .withMeat('ham')\n  .withEggStyle('scrambled');\n\nconsole.log(await anotherFactory.getSolids());\n// =\u003e 'ham, scrambled eggs'\n\nconsole.log(await anotherFactory.getEggs());\n// =\u003e 'scrambled eggs'\n\nconsole.log(await anotherFactory.getBreakfast());\n// =\u003e Error: Failed to resolve drink from meat,eggStyle,eggs at breakfast\n```\n\n# Surviving Uglification\n\nMinification / uglifying code mangles variable names which breaks being able to resolve dependencies from function names.  The fix is the same as Angular 1.x, to use array style dependencies.  shutterstock-mold also supports annotate-ng style tags and is compatible with `ng-annotate` and `babel-plugin-angularjs-annotate`\n\n```\nimport builder from 'shutterstock-mold'\n\nconst blueprint = builder({\n  // Array style\n  breakfast: ['meat', 'eggs', 'drink', function (meat, eggs, drink) {\n    return `${meat} with ${eggs} and ${drink}`;\n  }],\n  // Directive style\n  eggs: eggStyle =\u003e {\n    \"ngInject\";\n    return `${eggStyle} eggs`\n  },\n  // Wrapper function style\n  solids: ng((meat, eggs) =\u003e [meat, eggs].join(', ')),\n});\n\nconst factory = blueprint.dsl();\n\n// Everything continues to work as before, except you can now safely uglify code\nfactory\n  .withMeat('ham')\n  .withEggStyle('scrambled')\n  .withDrink('orange juice')\n  .getBreakfast();\n// =\u003e 'ham with scrambled eggs and orange juice'\n\nconst anotherFactory = blueprint.dsl()\n  .withMeat('steak')\n  .withEggStyle('pouched');\n\nanotherFactory.getSolids();\n// =\u003e 'steak, pouched eggs'\n\nanotherFactory.getEggs();\n// =\u003e 'puched eggs'\n\nanotherFactory.getBreakfast();\n// =\u003e Error: Failed to resolve drink from meat,eggStyle,eggs at breakfast\n```\n\n# License\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaptemulation%2Fservice-builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcaptemulation%2Fservice-builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaptemulation%2Fservice-builder/lists"}