{"id":13526534,"url":"https://github.com/young-steveo/bottlejs","last_synced_at":"2025-05-14T16:13:07.835Z","repository":{"id":21136396,"uuid":"24437723","full_name":"young-steveo/bottlejs","owner":"young-steveo","description":"A powerful dependency injection micro container for JavaScript applications","archived":false,"fork":false,"pushed_at":"2024-02-20T23:54:45.000Z","size":1341,"stargazers_count":1295,"open_issues_count":4,"forks_count":64,"subscribers_count":28,"default_branch":"master","last_synced_at":"2025-04-12T01:55:35.013Z","etag":null,"topics":["container","decorators","dependency-injection","javascript","middleware","service-locator"],"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/young-steveo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-09-25T00:36:51.000Z","updated_at":"2025-04-02T08:37:49.000Z","dependencies_parsed_at":"2023-12-22T00:57:44.348Z","dependency_job_id":"59e7aa52-12a7-4682-94bc-42e066cfcde6","html_url":"https://github.com/young-steveo/bottlejs","commit_stats":{"total_commits":228,"total_committers":28,"mean_commits":8.142857142857142,"dds":"0.45175438596491224","last_synced_commit":"c11e08e2ce7331eccfb0953a73585bd93c396641"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/young-steveo%2Fbottlejs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/young-steveo%2Fbottlejs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/young-steveo%2Fbottlejs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/young-steveo%2Fbottlejs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/young-steveo","download_url":"https://codeload.github.com/young-steveo/bottlejs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248505867,"owners_count":21115354,"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":["container","decorators","dependency-injection","javascript","middleware","service-locator"],"created_at":"2024-08-01T06:01:31.121Z","updated_at":"2025-04-12T01:55:40.405Z","avatar_url":"https://github.com/young-steveo.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"\n![BottleJS](/bottle-logo.jpg)\n# BottleJS\n\n[![Build Status](https://travis-ci.org/young-steveo/bottlejs.svg?branch=master)](https://travis-ci.org/young-steveo/bottlejs)\n[![npm version](https://badge.fury.io/js/bottlejs.svg)](https://badge.fury.io/js/bottlejs)\n[![dependencies Status](https://david-dm.org/young-steveo/bottlejs/status.svg)](https://david-dm.org/young-steveo/bottlejs)\n[![Known Vulnerabilities](https://snyk.io/test/github/young-steveo/bottlejs/badge.svg)](https://snyk.io/test/github/young-steveo/bottlejs)\n\n[![NPM](https://nodei.co/npm/bottlejs.png?downloads=true\u0026downloadRank=true)](https://nodei.co/npm/bottlejs/)\n\n\u003e A powerful dependency injection micro container\n\n## Introduction\n\nBottleJS is a tiny, powerful dependency injection container.  It features lazy loading, middleware hooks, decorators and a clean api inspired by the [AngularJS Module API](https://docs.angularjs.org/api/ng/type/angular.Module) and the simple PHP library [Pimple](http://pimple.sensiolabs.org/).  You'll like BottleJS if you enjoy:\n\n* building a stack from components rather than a kitchen-sink framework.\n* uncoupled objects and dependency injection.\n* an API that makes sense.\n* lazily loaded objects.\n* trying cool stuff :smile:\n\n## Browser Support\n\nBottleJS supports IE9+ and other ECMAScript 5 compliant browsers.\n\n## Installation\n\nBottleJS can be used in a browser or in a nodejs app.  It can be installed via bower or npm:\n\n```bash\n$ bower install bottlejs\n```\n\n```bash\n$ npm install bottlejs\n```\n\nBottleJS is also available on cdnjs:\n\n```html\n\u003cscript src=\"https://cdnjs.cloudflare.com/ajax/libs/bottlejs/2.0.1/bottle.min.js\"\u003e\u003c/script\u003e\n```\n\n## Simple Example\n\nThe simplest recipe to get started with is `Bottle#service`.  Say you have a constructor for a service object:\n\n```js\nvar Beer = function() { /* A beer service, :yum: */ };\n```\n\nYou can register the constructor with `Bottle#service`:\n\n```js\nvar bottle = new Bottle();\nbottle.service('Beer', Beer);\n```\n\nLater, when you need the constructed service, you just access the `Beer` property like this:\n\n```js\nbottle.container.Beer;\n```\n\nA lot happened behind the scenes:\n\n1. Bottle created a provider containing a factory function when you registered the Beer service.\n2. When the `bottle.container.Beer` property was accessed, Bottle looked up the provider and executed the factory to build and return the Beer service.\n3. The provider and factory were deleted, and the `bottle.container.Beer` property was set to be the Beer service instance.  Accessing `bottle.container.Beer` in the future becomes a simple property lookup.\n\n## Injecting Dependencies\n\nThe above example is simple.  But, what if the Beer service had dependencies?  For example:\n\n```js\nvar Barley = function() {};\nvar Hops = function() {};\nvar Water = function() {};\nvar Beer = function(barley, hops, water) { /* A beer service, :yum: */ };\n```\n\nYou can register services with `Bottle#service` and include dependencies like this:\n\n```js\nvar bottle = new Bottle();\nbottle.service('Barley', Barley);\nbottle.service('Hops', Hops);\nbottle.service('Water', Water);\nbottle.service('Beer', Beer, 'Barley', 'Hops', 'Water');\n```\n\nNow, when you access `bottle.container.Beer`, Bottle will lazily load all of the dependencies and inject them into your Beer service before returning it.\n\n### Service Factory\n\nIf you need more complex logic when generating a service, you can register a factory instead.  A factory function receives the container as an argument, and should return your constructed service:\n\n```js\nvar bottle = new Bottle();\nbottle.service('Barley', Barley);\nbottle.service('Hops', Hops);\nbottle.service('Water', Water);\nbottle.factory('Beer', function(container) {\n    var barley = container.Barley;\n    var hops = container.Hops;\n    var water = container.Water;\n\n    barley.halved();\n    hops.doubled();\n    water.spring();\n    return new Beer(barley, hops, water);\n});\n```\n\n### Service Provider\n\nThis is the meat of the Bottle library.  The above methods `Bottle#service` and `Bottle#factory` are just shorthand for the provider function.  You usually can get by with the simple functions above, but if you really need more granular control of your services in different environments, register them as a provider.  To use it, pass a constructor for the provider that exposes a `$get` function.  The `$get` function is used as a factory to build your service.\n\n```js\nvar bottle = new Bottle();\nbottle.service('Barley', Barley);\nbottle.service('Hops', Hops);\nbottle.service('Water', Water);\nbottle.provider('Beer', function() {\n    // This environment may not support water.\n    // We should polyfill it.\n    if (waterNotSupported) {\n        Beer.polyfillWater();\n    }\n\n    // this is the service factory.\n    this.$get = function(container) {\n        var barley = container.Barley;\n        var hops = container.Hops;\n        var water = container.Water;\n\n        barley.halved();\n        hops.doubled();\n        water.spring();\n        return new Beer(barley, hops, water);\n    };\n});\n```\n\n## Decorators\n\nBottle supports injecting decorators into the provider pipeline with the `Bottle#decorator` method.  Bottle decorators are just simple functions that intercept a service in the provider phase after it has been created, but before it is accessed for the first time.  The function should return the service, or another object to be used as the service instead.\n\n```js\nvar bottle = new Bottle();\nbottle.service('Beer', Beer);\nbottle.service('Wine', Wine);\nbottle.decorator(function(service) {\n    // this decorator will be run for both Beer and Wine services.\n    service.stayCold();\n    return service;\n});\n\nbottle.decorator('Wine', function(wine) {\n    // this decorator will only affect the Wine service.\n    wine.unCork();\n    return wine;\n});\n```\n\n## Middleware\n\nBottle middleware are similar to decorators, but they are executed every time a service is accessed from the container.  They are passed the service instance and a `next` function:\n\n```js\nvar bottle = new Bottle();\nbottle.service('Beer', Beer);\nbottle.middleware(function(service, next) {\n    // this middleware will be executed for all services\n    console.log('A service was accessed!');\n    next();\n});\n\nbottle.middleware('Beer', function(beer, next) {\n    // this middleware will only affect the Beer service.\n    console.log('Beer?  Nice.  Tip your bartender...');\n    next();\n});\n```\n\nMiddleware can pass an error object to the `next` function, and bottle will throw the error:\n\n```js\nvar bottle = new Bottle();\nbottle.service('Beer', Beer);\nbottle.middleware('Beer', function(beer, next) {\n    if (beer.hasGoneBad()) {\n        return next(new Error('The Beer has gone bad!'));\n    }\n    next();\n});\n\n// results in Uncaught Error: The Beer has gone bad!(…)\n```\n\n## Nested Bottles\nBottle will generate nested containers if dot notation is used in the service name.  An isolated sub container will be created for you based on the name given:\n\n```js\nvar bottle = new Bottle();\nvar IPA = function() {};\nbottle.service('Beer.IPA', IPA);\nbottle.container.Beer; // this is a new Bottle.container object\nbottle.container.Beer.IPA; // the service\nbottle.factory('Beer.DoubleIPA', function (container) {\n    var IPA = container.IPA; // note the container in here is the nearest parent.\n})\n```\n\n### Nested Containers Are Isolated\nNested containers are designed to provide isolation between different packages.  This means that you cannot access a nested container from a different parent when you are writing a factory.\n\n```js\nvar bottle = new Bottle();\nvar IPA = function() {};\nvar Wort = function() {};\nbottle.service('Ingredients.Wort', Wort);\nbottle.factory('Beer.IPA', function(container) {\n    // container is `Beer`, not the root, so:\n    container.Wort; // undefined\n    container.Ingredients.Wort; // undefined\n});\n```\n\n## API\n\n### Bottle\n\n#### pop(name)\n\nUsed to get an instance of bottle.  If a name is passed, bottle will return the same instance.  Calling the Bottle constructor as a function will call and return `Bottle.pop`, so `Bottle.pop('Soda') === Bottle('Soda')`\n\nParam                      | Type       | Details\n:--------------------------|:-----------|:--------\n**name**\u003cbr /\u003e*(optional)* | *String*   | The name of the bottle. If passed, bottle will store the instance internally and return the same instance if `Bottle.pop` is subsequently called with the same name.\n\n#### clear(name)\n\nRemoves the named instance from bottle's internal store, if it exists. The immediately subsequent call to `Bottle.pop(name)` will return a new instance. If no name is given, all named instances will be cleared.\n\nIn general, this function should only be called in situations where you intend to reset the bottle instance with new providers, decorators, etc. such as test setup.\n\nParam                      | Type       | Details\n:--------------------------|:-----------|:--------\n**name**\u003cbr /\u003e*(optional)* | *String*   | The name of the bottle. If passed, bottle will remove the internal instance, if such a bottle was created using `Bottle.pop`. If not passed, all named internal instances will be cleared.\n\n#### list(container)\n#### prototype.list()\n#### prototype.container.$list()\n\nUsed to list the names of all registered constants, values, and services on the container.  Must pass a container to the global static version `Bottle.list(bottle.container)`.  The instance and container versions return the services that are registered within.\n\nReturns an array of strings.\n\nParam                           | Type       | Details\n:-------------------------------|:-----------|:--------\n**container**\u003cbr /\u003e*(optional)* | *Object*   | A `bottle.container`.  Only required when using the global, static `Bottle.list` method.  The prototype version uses that instance's container, and the container version uses itself.\n\n#### config\n\nA global configuration object.\n\nProperty   | Type      | Default | Details\n:----------|:----------|:--------|:--------\n**strict** | *Boolean* | `false` | Enables strict mode.  Currently only verifies that automatically injected dependencies are not undefined.\n\n### Bottle.prototype\n\n#### decorators\n\nA collection of decorators registered by the bottle instance.  See `decorator(name, func)` below\n\n#### middlewares\n\nA collection of middleware registered by the bottle instance.  See `middleware(name, func)` below.\n\n#### nested\n\nA collection of nested bottles registered by the parent bottle instance when dot notation is used to define a service.  See \"Nested Bottles\" section in the documentation above.\n\n#### providerMap\n\nA collection of registered provider names.  Bottle uses this internally to determine whether a provider has already instantiated it's instance.  See `provider(name, Provider)` below.\n\n#### deferred\n\nAn array of deferred functions registered for this bottle instance.  See `defer(func)` below.\n\n#### constant(name, value)\n\nUsed to add a read only value to the container.\n\nParam     | Type       | Details\n:---------|:-----------|:--------\n**name**  | *String*   | The name of the constant.  Must be unique to each Bottle instance.\n**value** | *Mixed*    | A value that will be defined as enumerable, but not writable.\n\n#### decorator(name, func)\n#### container.$decorator(name, func)\n\nUsed to register a decorator function that the provider will use to modify your services at creation time. `bottle.container.$decorator` is an alias of `bottle.decorator`; this allows you to only add a decorator to a nested bottle.\n\nParam                      | Type       | Details\n:--------------------------|:-----------|:--------\n**name**\u003cbr /\u003e*(optional)* | *String*   | The name of the service this decorator will affect. Will run for all services if not passed.\n**func**                   | *Function* | A function that will accept the service as the first parameter.  Should return the service, or a new object to be used as the service.\n\n#### defer(func)\n\nRegister a function to be executed when `Bottle#resolve` is called.\n\nParam    | Type       | Details\n:--------|:-----------|:--------\n**func** | *Function* | A function to be called later.  Will be passed a value given to `Bottle#resolve`.\n\n#### digest(services)\n\nImmediately instantiate an array of services and return their instances\nin the order of the array of instances.\n\nParam        | Type    | Details\n:------------|:--------|:--------\n**services** | *Array* | Array of services that should be instantiated.\n\n#### factory(name, Factory)\n\nUsed to register a service factory\n\nParam       | Type       | Details\n:-----------|:-----------|:--------\n**name**    | *String*   | The name of the service.  Must be unique to each Bottle instance.\n**Factory** | *Function* | A function that should return the service object.  Will only be called once; the Service will be a singleton.  Gets passed an instance of the container to allow dependency injection when creating the service.\n\n#### instanceFactory(name, Factory)\n\nUsed to register a service instance factory that will return an instance when called.\n\nParam       | Type       | Details\n:-----------|:-----------|:--------\n**name**    | *String*   | The name of the service.  Must be unique to each Bottle instance.\n**Factory** | *Function* | A function that should return a fully configured service object. This factory function will be executed when a new instance is created. Gets passed an instance of the container.\n\n```js\nvar bottle = new Bottle();\nvar Hefeweizen = function(container) { return { abv: Math.random() * (6 - 4) + 4 }};\nbottle.instanceFactory('Beer.Hefeweizen', Hefeweizen);\n\nvar hefeFactory = bottle.container.Beer.Hefeweizen; // This is an instance factory with a single `instance` method\n\nvar beer1 = hefeFactory.instance(); // Calls factory function to create a new instance\nvar beer2 = hefeFactory.instance(); // Calls factory function to create a second new instance\n\nbeer1 !== beer2 // true\n```\n\nThis pattern is especially useful for request based context objects that store state or things like database connections.  See the documentation for Google Guice's [InjectingProviders](https://github.com/google/guice/wiki/InjectingProviders) for more examples.\n\n#### middleware(name, func)\n\nUsed to register a middleware function.  This function will be executed every time the service is accessed.\n\nParam                      | Type       | Details\n:--------------------------|:-----------|:--------\n**name**\u003cbr /\u003e*(optional)* | *String*   | The name of the service for which this middleware will be called. Will run for all services if not passed.\n**func**                   | *Function* | A function that will accept the service as the first parameter, and a `next` function as the second parameter.  Should execute `next()` to allow other middleware in the stack to execute.  Bottle will throw anything passed to the `next` function, i.e. `next(new Error('error msg'))`.\n\n#### provider(name, Provider)\n\nUsed to register a service provider\n\nParam        | Type       | Details\n:------------|:-----------|:--------\n**name**     | *String*   | The name of the service.  Must be unique to each Bottle instance.\n**Provider** | *Function* | A constructor function that will be instantiated as a singleton.  Should expose a function called `$get` that will be used as a factory to instantiate the service.\n\n#### resetProviders(names)\nParam                          | Type       | Details\n:------------------------------|:-----------|:--------\n**names**\u003cbr /\u003e*(optional)*    | *Array*    | An array of strings which contains names of the providers to be reset.\n**propagate**\u003cbr /\u003e*(optional)*| *Boolean*  | Propagate the reset to all providers that depend on the previous list.\n\nUsed to reset providers for the next reference to re-instantiate the provider.\n\nIf `names` param is passed, will reset only the named providers. When reseting an specific list of providers, it is possible to also propagate the reset to providers that depend on those.\n\n#### register(Obj)\n#### container.$register(Obj)\n\nUsed to register a service, factory, provider, or value based on properties of the Obj.  `bottle.container.$register` is an alias of `bottle.register`; this allows factories and providers to register multiple services on the container without needing access to the bottle instance itself.\n\nIf `Bottle.config.strict` is set to `true`, this method will throw an error if an injected dependency is `undefined`.\n\nParam   | Type       | Details\n:-------|:-----------|:--------\n**Obj** | *Object*\\|*Function* | An object or constructor with one of several properties:\u003cbr /\u003e\u003cul\u003e\u003cli\u003e**Obj.$name** \u0026mdash; *required* \u0026mdash; the name used to register the object\u003c/li\u003e\u003cli\u003e**Obj.$type** \u0026mdash; *optional* \u0026mdash; the method used to register the object.  Defaults to `'service'` in which case the Obj will be treated as a constructor. Valid types are: `'service'`, `'factory'`, `'provider'`, `'value'`\u003c/li\u003e\u003cli\u003e**Obj.$inject** \u0026mdash; *optional* \u0026mdash; If `Obj.$type` is `'service'`, this property can be a string name or an array of names of dependencies to inject into the constructor.\u003cbr /\u003eE.g. `Obj.$inject = ['dep1', 'dep2'];`\u003c/li\u003e\u003cli\u003e**Obj.$value** \u0026mdash; *optional* \u0026mdash; Normally Obj is registered on the container.  However, if this property is included, it's value will be registered on the container instead of the object itself.  Useful for registering objects on the bottle container without modifying those objects with bottle specific keys.\u003c/li\u003e\u003c/ul\u003e\n\n#### resolve(data)\n\nExecute any deferred functions registered by `Bottle#defer`.\n\nParam                      | Type    | Details\n:--------------------------|:--------|:--------\n**data**\u003cbr /\u003e*(optional)* | *Mixed* | Value to be passed to each deferred function as the first parameter.\n\n#### service(name, Constructor [, dependency [, ...]])\n\nUsed to register a service constructor.  If `Bottle.config.strict` is set to `true`, this method will throw an error if an injected dependency is `undefined`.\n\nParam                            | Type       | Details\n:--------------------------------|:-----------|:--------\n**name**                         | *String*   | The name of the service.  Must be unique to each Bottle instance.\n**Constructor**                  | *Function* | A constructor function that will be instantiated as a singleton.\n**dependency**\u003cbr /\u003e*(optional)* | *String*   | An optional name for a dependency to be passed to the constructor.  A dependency will be passed to the constructor for each name passed to `Bottle#service` in the order they are listed.\n\n#### serviceFactory(name, factoryService [, dependency [, ...]])\n\nUsed to register a service factory function. Works exactly like `factory` except the factory arguments will be injected instead of receiving the `container`. This is useful when implementing the Module Pattern or adding dependencies to your Higher Order Functions.\n\n```js\nfunction packageKeg(Barrel, Beer, Love) {\n    Barrel.add(Beer, Love);\n    return {\n        tap : function() {\n            return Barrel.dispense();\n        }\n    };\n}\nbottle.serviceFactory('Keg', packageKeg, 'Barrel', 'Beer', 'Love');\n```\n\nIf `Bottle.config.strict` is set to `true`, this method will throw an error if an injected dependency is `undefined`.\n\nParam                            | Type       | Details\n:--------------------------------|:-----------|:--------\n**name**                         | *String*   | The name of the service.  Must be unique to each Bottle instance.\n**serviceFactory**               | *Function* | A function that will be invoked to create the service object/value.\n**dependency**\u003cbr /\u003e*(optional)* | *String*   | An optional name for a dependency to be passed to the service function.  A dependency will be passed to the service function for each name passed to `Bottle#serviceFactory` in the order they are listed.\n\n#### value(name, val)\n\nUsed to add an arbitrary value to the container.\n\nParam    | Type     | Details\n:--------|:---------|:--------\n**name** | *String* | The name of the value.  Must be unique to each Bottle instance.\n**val**  | *Mixed*  | A value that will be defined as enumerable, but not writable.\n\n## TypeScript\n\nA TypeScript declaration file is bundled with this package. To get TypeScript to resolve it automatically, you need to set `moduleResolution` to `node` in your `tsconfig.json`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoung-steveo%2Fbottlejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoung-steveo%2Fbottlejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoung-steveo%2Fbottlejs/lists"}