{"id":15413846,"url":"https://github.com/fjorgemota/jimple","last_synced_at":"2025-07-09T11:06:35.691Z","repository":{"id":57148591,"uuid":"42757072","full_name":"fjorgemota/jimple","owner":"fjorgemota","description":"Just a dependency injection container to NodeJS and to the browser using new ES6 features","archived":false,"fork":false,"pushed_at":"2020-05-29T20:29:41.000Z","size":1652,"stargazers_count":74,"open_issues_count":19,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-13T13:54:31.553Z","etag":null,"topics":["dependency-injection","inversion-of-control","nodejs","pimple"],"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/fjorgemota.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-09-19T02:55:30.000Z","updated_at":"2025-05-25T00:30:26.000Z","dependencies_parsed_at":"2022-08-31T09:42:11.628Z","dependency_job_id":null,"html_url":"https://github.com/fjorgemota/jimple","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/fjorgemota/jimple","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fjorgemota%2Fjimple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fjorgemota%2Fjimple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fjorgemota%2Fjimple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fjorgemota%2Fjimple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fjorgemota","download_url":"https://codeload.github.com/fjorgemota/jimple/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fjorgemota%2Fjimple/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264446715,"owners_count":23609632,"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":["dependency-injection","inversion-of-control","nodejs","pimple"],"created_at":"2024-10-01T16:58:58.229Z","updated_at":"2025-07-09T11:06:35.648Z","avatar_url":"https://github.com/fjorgemota.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jimple\n\n[![Greenkeeper badge](https://badges.greenkeeper.io/fjorgemota/jimple.svg)](https://greenkeeper.io/)\n[![Build Status](https://travis-ci.org/fjorgemota/jimple.svg)](https://travis-ci.org/fjorgemota/jimple)\n[![npm](https://img.shields.io/npm/v/jimple.svg)](http://npmjs.org/package/jimple/)\n[![npm](https://img.shields.io/npm/dt/jimple.svg)](http://npmjs.org/package/jimple/)\n[![node](https://img.shields.io/node/v/jimple.svg)](http://npmjs.org/package/jimple)\n[![Codacy Badge](https://api.codacy.com/project/badge/1f3ecae240a747d090bef0340251f57c)](https://www.codacy.com/app/fjorgemota/jimple)\n[![Code Climate](https://codeclimate.com/github/fjorgemota/jimple/badges/gpa.svg)](https://codeclimate.com/github/fjorgemota/jimple)\n[![Test Coverage](https://codeclimate.com/github/fjorgemota/jimple/badges/coverage.svg)](https://codeclimate.com/github/fjorgemota/jimple/coverage)\n[![Issue Count](https://codeclimate.com/github/fjorgemota/jimple/badges/issue_count.svg)](https://codeclimate.com/github/fjorgemota/jimple)\n[![](https://data.jsdelivr.com/v1/package/npm/jimple/badge)](https://www.jsdelivr.com/package/npm/jimple)\n\nThis project is a port of [Pimple Dependency Injection container](https://github.com/silexphp/Pimple/) for NodeJS and for browsers using features provided by ES6.\n\nAll the code is tested using Mocha and seems to be stable. Below is the documentation for the project:\n\n## Features\n\nGood projects have good features. And because this here's the list of features that Jimple supports:\n\n- Define services;\n- Define factories;\n- Define parameters easily;\n- Defining services/parameters/factories from another files - because you should be able to split your configuration easily;\n- Simple API;\n- Runs on NodeJS and on browser;\n- Allows extending services easily;\n- Allow to get the raw service creator easily;\n- Pure Javascript;\n- Stable API;\n- No dependencies (in nodejs, in browser we need a shim);\n- No module loader integrated - You can use **any** module loader you want;\n- [Fully tested](https://travis-ci.org/fjorgemota/jimple) on each commit;\n- [100% code coverage](https://codeclimate.com/github/fjorgemota/jimple/coverage);\n- Fully Documented;\n- Less than [300 SLOC](https://github.com/fjorgemota/jimple/blob/master/src/Jimple.js);\n- ~1KB minified and gzipped - **Tested** on CI using [size-limit](https://github.com/ai/size-limit);\n- I already said that it have a really Simple API? :)\n\n### Testing without installing anything\n\nIf you liked that features, feel free to test Jimple **free** on a NodeJS environment without installing anything on your machine by using [Runkit](https://npm.runkit.com/jimple). Give it a try. :)\n\n## Installation\n\nThe installation of this package is very simple: In fact, it can be installed by just running:\n\n```\n    npm install --save jimple\n```\n\nIf using NodeJS (this installs the package based purely on ES 6), or:\n\n```\n    bower install --save jimple\n```\n\nIf you want to use this package in the browser. You can also use the version provided by a CDN, like [JSDelivr](https://www.jsdelivr.com/package/npm/jimple). So you can paste the code below on a page and start using Jimple really fast:\n\n```html\n\u003cscript language=\"javascript\" type=\"text/javascript\" src=\"https://cdn.jsdelivr.net/npm/jimple@latest/src/Jimple.js\"\u003e\u003c/script\u003e\n```\n\n**WARNING**: Please note that the code above uses always the latest version of Jimple. In production, please replace *latest* with a [valid version number from the Releases page](https://github.com/fjorgemota/jimple/releases) or use Bower or NPM to install a fixed version for you. =)\n\nNote that the browser version of this library uses a version compiled by [Babel](http://babeljs.io). And because this, and because browsers does not have great support to `Map` and `Set` yet, you will need to load [`babel-polyfill`](https://babeljs.io/docs/usage/polyfill/) (or some other similar polyfill that implements `Map` and `Set` support) **before** loading this package on the browser.\n\n## Usage\n\nCreating a Jimple Container is just a matter of creating a Jimple instance:\n\n```js\nvar Jimple = require(\"jimple\");\n\nvar container = new Jimple();\n```\n\nIn the browser, you can load Jimple using various ways:\n\n- AMD\n\n```js\n    define([\"jimple\"], function(Jimple) {\n        // Code using Jimple here..\n    });\n```\n\n- CommonJS/Browserify:\n\n```js\n    var Jimple = require(\"jimple\");\n```\n\n- Script tag:\n\n```html\n    \u003cscript language=\"javascript\" src=\"path/to/Jimple.js\"\u003e\u003c/script\u003e\n```\n\nAgain, it's important to note that Jimple needs of a polyfill to Map and Set classes - which are not supported by all the latest browsers actually - to do so, you can choice between some options, like [`babel-polyfill`](https://babeljs.io/docs/usage/polyfill/) for example.\n\nJimple, as Pimple and many other dependency injections containers, manage two different kind of data: **services** and **parameters**.\n\n## Defining services\n\nAs Pimple describes, a service is an object that does something as part of a larger system. Examples of services: a database connection, a templating engine, or a mailer. Almost any global object can be a service.\n\nServices in Jimple (and in Pimple too!) are defined by anonymous functions that return an instance of an object. Note that, in Jimple, you cannot use a generator as a service, as they will be detected as parameters, so, just **pure** functions can be a service. Different from Pimple, however, here we need to call the method `set()` on Jimple container, as Proxies in NodeJS seems to not be stable:\n\n```js\n// define some services\ncontainer.set('session_storage', function (c) {\n    return new SessionStorage('SESSION_ID');\n});\n\ncontainer.set('session', function (c) {\n    return new Session(c.get('session_storage'));\n});\n```\n\nNotice that the anonymous function that define a service has access to the current container instance, allowing references to other services or parameters.\n\nThe objects are created on demand, just when you get them. The order of the definitions does not matter.\n\nUsing the defined services is very easy, too:\n\n```js\n// get the session object\nvar session = container.get('session');\n\n// the above call is roughly equivalent to the following code:\n// var storage = new SessionStorage('SESSION_ID');\n// var session = new Session(storage);\n```\n\n## Defining factory services\n\nBy default, when you get a service, Jimple automatically cache it's value, returning always the **same instance** of it. If you want a different instance to be returned for all calls, wrap your anonymous function with the `factory()` method:\n\n```js\ncontainer.set('session', container.factory(function (c) {\n    return new Session(c.get('session_storage'));\n}));\n```\n\nNow, each time you call `container.get('session')`, a new instance of `Session` is returned for you.\n\n## Defining parameters\n\nDefining a parameter allows to ease the configuration of your container from the outside and to store global values. In Jimple, parameters are defined as anything that it's not a function:\n\n```js\n// define a parameter called cookie_name\ncontainer.set('cookie_name', 'SESSION_ID');\n```\n\nIf you change the `session_storage` service definition like below:\n\n```js\ncontainer.set('session_storage', function (c) {\n    return new SessionStorage(c.get('cookie_name'));\n});\n```\n\nYou can now easily change the cookie name by overriding the `cookie_name` parameter instead of redefining the service definition.\n\n### Defining parameters based on environment variables (NodeJS only)\n\nDo you wanna do define parameters in the container based on environment variables? It's okay! You can define it easily like that:\n\n```js\n//define parameter based on environment variable\ncontainer.set('cookie_name', process.env.COOKIE_NAME);\n```\n\n## Optional/Default parameters/services\n\nNot all services need all the services or parameters always, and you may do well with a default value for an parameter or service. In this case, you can do something like that:\n\n```js\ncontainer.set('session_storage', function (c) {\n    return new SessionStorage(c.has('cookie_name') ? c.get('cookie_name') : 'COOKIE_ID');\n});\n```\n\nIn this example, if the parameter `cookie_name` does not exist, the SessionStorage will be instantiated with the default `'COOKIE_ID'`, and this works for services too. :)\n\n\n## Protecting parameters\n\nBecause Jimple see anything that is a function as a service, you need to wrap anonymous functions with the `protect()` method to store them as parameters:\n\n```js\ncontainer.set('random_func', container.protect(function () {\n    return Math.random();\n}));\n```\n\n## Modifying Services after Definition\n\nIn some cases you may want to modify a **service definition** (note that you cannot extend a parameter, including protected parameters) after it has been defined. You can use the `extend()` method to define additional code to be run on your service just after it is created:\n\n```js\ncontainer.set('session_storage', function (c) {\n    return new SessionStorage(c.get('cookie_name'));\n});\n\ncontainer.extend('session_storage', function (storage, c) {\n    storage.someMethod();\n\n    return storage;\n});\n```\n\nThe first argument is the name of the service to extend, the second a function that gets access to the object instance and the container.\n\n## Extending a Container\n\nIf you use the same libraries over and over, you might want to reuse some services from one project to the next one; package your services into a provider by implementing the following object structure by duck-typing:\n\n```js\nvar provider = {\n\t\"register\": function(c) {\n\t\t// Define your services and parameters here\n\t}\n}\n```\n\nBecause JS has no support to interfaces yet, we cannot validate too much the structure of the provider.\n\nAfter creating a object with that structure, you can register it in the container:\n\n```js\ncontainer.register(provider);\n```\n\n### Extending a container from a file (NodeJS/Browserify only)\n\nIf you want to split your container's configuration (so each file is more..simple and specific), you can create multiple files like that:\n\n**file1.js:**\n\n```js\nmodule.exports.register = function(container) {\n    // Define your services and parameters here\n}\n```\n\nTo load the package, you can do something like:\n\n```js\ncontainer.register(require(\"./file1\"))\n```\n\nYou can, inclusive, create **directories** with container's configuration, by doing something like that:\n\n**xpto/file1.js:**\n\n```js\nmodule.exports.register = function(container) {\n    // Define your services and parameters here\n}\n```\n\n**xpto/file2.js:**\n\n```js\nmodule.exports.register = function(container) {\n    // Define your services and parameters here\n}\n```\n\n**xpto/index.js:**\n\n```js\nmodule.exports.register = function(container) {\n    container.register(require(\"./file1\"));\n    container.register(require(\"./file2\"));   \n}\n```\n\nAnd, finally, in some file creating the container:\n\n```js\ncontainer.register(require(\"./xpto\"));\n```\n\nNote that the **index.js** file is loaded first on **xpto** directory, and that **index.js** file loads the files **file1.js** and **file2.js** present on that directory. You can do that for any number of directories. :)\n\n### Extending a container using the shorthand function\n\nYou can use the exported `provider` shorthand method to easily create your container's configuration with a simple callback:\n\n```js\nconst { provider } = require('jimple');\n\nmodule.exports = provider((container) =\u003e {\n    // Define your services and parameters here\n});\n```\n\nIt can be used exact same way as the previous method (from a file), but it also can be used to export multiple configurations at the same time:\n\n```js\nconst { provider } = require('jimple');\n\nmodule.exports = {\n    configurationA: provider((container) =\u003e { ... }),\n    configurationB: provider((container) =\u003e { ... }),\n};\n```\n\n## Fetching the Service Creation Function\n\nWhen you access an object, Jimple automatically calls the anonymous function that you defined, which creates the service object for you. If you want to get raw access to this function, but don't want to `protect()` that service, you can use the `raw()` method to access the function directly:\n\n```js\ncontainer.set('session', function (c) {\n    return new Session(c.get('session_storage'));\n});\n\nvar sessionFunction = container.raw('session');\n```\n\n## Proxy - ES6\n\nIn ES6, we can use a Proxy object to define custom behavior for some fundamental operations ([see more here clicking here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)). That allows us to customize Jimple to have a experience very near from that provided by Pimple, which can get services and parameters directly without calling `get()` or set services and parameters without calling `set()`.\n\nHowever, for access that mode you cannot use the *Jimple* constructor, but a static method called `proxy()`. So, the code below:\n\n```js\nconst container = Jimple.proxy();\n\ncontainer['session_storage'] = function (c) {\n    return new SessionStorage('SESSION_ID');\n};\n\ncontainer['session'] = function (c) {\n    return new Session(c['session_storage']);\n};\n```\n\nIs in fact equivalent to that:\n\n```js\nconst container = new Jimple();\n\ncontainer.set('session_storage', function (c) {\n    return new SessionStorage('SESSION_ID');\n});\n\ncontainer.set('session', function (c) {\n    return new Session(c.get('session_storage'));\n});\n```\n\nPlease note that the `proxy()` method can receive a parameter, like the `Jimple` constructor. So you can note that:\n\n```js\nconst container = Jimple.proxy({\"SESSION_ID\": \"test\"});\n```\n\nIs in fact equivalent for:\n\n```js\nconst container = new Jimple({\"SESSION_ID\": \"test\"});\n```\n\nBy the way, observe that *Proxy* is an API that's not really supported everywhere (it's supported in NodeJS \u003e= 6, for example). So we do not recommend it's use in browser environments, for example.\n\nOf course, this option has some limitations: basically, you **CANNOT** use certain names like the names of the methods available in the container as names of your services/parameters. So something like:\n\n```js\nconst container = Jimple.proxy();\ncontainer.set = 42;\n```\n\nIs forbidden and throws an exception automatically.\n\n## Last, but not least important: Customization\n\nDo you wanna to customize Jimple's functionally? You can! Just extend it using ES6's class syntax:\n\n```js\nvar Jimple = require(\"jimple\");\n\nclass ABigContainer extends Jimple {\n    // Overwrite any of Jimple's method here, or add new methods\n}\n\nvar container = new ABigContainer();\n```\n\nGood customization. :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffjorgemota%2Fjimple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffjorgemota%2Fjimple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffjorgemota%2Fjimple/lists"}