{"id":19097187,"url":"https://github.com/atmajs/a-di","last_synced_at":"2026-03-10T12:33:22.926Z","repository":{"id":57171556,"uuid":"68247873","full_name":"atmajs/a-di","owner":"atmajs","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-22T22:43:39.000Z","size":483,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-08T23:15:26.430Z","etag":null,"topics":["di-framework","di-library","injection","ioc"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/atmajs.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2016-09-14T22:17:43.000Z","updated_at":"2024-10-22T22:43:43.000Z","dependencies_parsed_at":"2024-10-23T05:55:43.407Z","dependency_job_id":null,"html_url":"https://github.com/atmajs/a-di","commit_stats":null,"previous_names":["tenbits/di","tenbits/a-di"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/atmajs/a-di","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atmajs%2Fa-di","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atmajs%2Fa-di/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atmajs%2Fa-di/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atmajs%2Fa-di/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atmajs","download_url":"https://codeload.github.com/atmajs/a-di/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atmajs%2Fa-di/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30333514,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T05:25:20.737Z","status":"ssl_error","status_checked_at":"2026-03-10T05:25:17.430Z","response_time":106,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["di-framework","di-library","injection","ioc"],"created_at":"2024-11-09T03:39:21.162Z","updated_at":"2026-03-10T12:33:22.893Z","avatar_url":"https://github.com/atmajs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align='center'\u003e\n    \u003cimg src='assets/logo.png'/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href='https://travis-ci.org/tenbits/a-di' target='_blank'\u003e\n        \u003cimg src='https://travis-ci.org/tenbits/a-di.png?branch=master' /\u003e\n        \u003c/a\u003e\n    \u003ca href='http://badge.fury.io/js/a-di' target='_blank'\u003e\n        \u003cimg src='https://badge.fury.io/js/a-di.svg' /\u003e\n        \u003c/a\u003e\n    \u003ca href='http://badge.fury.io/bo/a-di' target='_blank'\u003e\n        \u003cimg src='https://badge.fury.io/bo/a-di.svg' /\u003e\n        \u003c/a\u003e\n\u003c/p\u003e\n\n# Yet another Dependency Injection Library for JavaScript\n\n_Highly inspired by [Autofac.NET](https://autofac.org/)_\n\n\u003e We have tried to accommodate all the best DI and IoC practices for JavaScript\n\n`const di = new Di;`\n\n##### \u0026#9776;\n\n- `1` [Registration](#1-registration)\n    - `1.1` [Type](#11-type)\n    - `1.2` [Instance](#12-instance)\n    - `1.3` [Factory](#12-factory)\n- `2` [Dependency definitions](#2-dependency-defintions)\n    - `2.1` [Constructor](#21-constructor)\n        - `2.1.1` [External definitions](#211-external-definitions)\n        - `2.1.2` [Decorators](#212-decorators)\n        - `2.1.3` [Default parameters](#213-default-parameters)\n        - `2.1.4` [In-place meta information](#214-inplace-meta-information)\n        - `2.1.5` [_Other ways_](#215-other-ways)\n    - `2.2` [Properties](#22-properties)\n    - `2.3` [Methods](#23-methods)\n- `3` [Consume](#3-Consume)\n    - `3.1` [Initialize registered components](#31-Initialize-registered-components)\n    - `3.2` [Create inherited classes](#32-create-inherited-classes)\n    - `3.3` [Create function delegates](#33-create-function-delegates)\n\n- `4` [Additional configuration](#4-additional-configuration)\n\n- `5` [How do we use the library?](#5-how-do-we-use-the-library)\n\n# `1` Registration\n\n\u003e The greatest challenge for DI frameworks in JavaScript is to get the list of dependencies for a constructor, method, etc. JavaScript is not statically typed, so here other ways should be found to declare the dependencies. And we also try to follow the _**1st rule**_ of any di framework - `\"Your classes should not be dependent on the DI itself\"`.\n\n\u003e Though you can use it as a **Service Locator**\n\nWhen registering the component, you specify identifiers, by which the dependency is resolved. It can be some another `Type`, string identifier. _But we do not encourage you to use string identifiers._\n\nIt is also possible to get the instance without having previously to register the Type\n\n```ts\nconst foo = di.resolve(Foo);\n```\n\n\u003e Later you can register another Type for this one.\n\n### `1.1` Type\n\n`Class` constructor;\n\n\n```ts\nclass Foo {\n    constructor (bar, qux) {}\n}\n```\n\n### `1.2` Instance\n\nPass already instantiated class to the container, and it will be used by all dependents\n```ts\ndi.registerInstance(new Foo(di.resolve(IBar), di.resolve(IQux))).as(IFoo);\n\n// or use Initializer wich will be called on first `IFoo` require.\ndi.registerInstance(IBar, IFoo, (bar, foo) =\u003e new Foo(bar, foo)).as(IFoo);\n\n// you can even suppress the lamda here\ndi.registerInstance(IBar, IFoo, Foo).as(IFoo);\n```\n\n### `1.3` Factory\n\nRegister a `function` which will create the instance on demand. Is similar to instance initializer, but the factory is called every time the dependency is required.\n\n```ts\ndi.registerFactory(IBar, (bar) =\u003e {}).as(IFoo);\n\n// No arguments are defined - we pass the di itself, for the case your factory method is out of the current di scope.\ndi.registerFactory(di =\u003e {}).as(IFoo);\n```\n\n---\n\n# `2` Dependency definitions\n\n### `2.1` Constructor\n\n\n#### `2.1.1` External definitions\n\nFrom the previous paragraph you have already seen `using` method, when registering the `Type`. Here we define what identifiers should be used to instantiate the instance.\n\n\u003e ✨ **Pros**: Your implementation is fully decoupled from the DI and the registration itself.\n\n```ts\nclass Foo {\n    constructor (logger) { logger.log() }\n}\n// ----\nclass Bar {\n    log (...args) { console.log(...args) }\n}\n// ---\nclass ILog { log () {} }\n// ---\ndi\n    .registerType(Bar)\n    .as(ILog);\ndi\n    .registerType(Foo)\n    .using(ILog)\n    .asSelf()\n    .onActivated(foo =\u003e console.log(foo));\n\n```\n\n#### `2.1.2` Decorators\n\n\u003e ✨ **Pros**:  In-place configuration, but has reference to the di instance\n\n```ts\nclass Foo {\n    constructor (@di.inject(ILog) logger) {\n        logger.log()\n    }\n}\n\n```\n\n#### `2.1.3` Default parameters\n\n\u003e ✨ **Pros**:  `new Foo()` also works\n\n```ts\nclass Foo {\n    constructor (logger = di.resolve(ILog)) {\n        logger.log()\n    }\n}\n\n```\n\n#### `2.1.4` In-place meta information\n\n**Maybe most irrelevant feature, but anyway**\n\n\u003e ✨ **Pros**: Your implementation is decoupled from the DI, but holds meta information for the DI library.\n\nPer default we read the static `$inject` property on the `Type`\n\n```ts\nclass Foo {\n    static $constructor = [ ILog ]\n\n    constructor (logger) { logger.log() }\n}\n```\n\nYou can override the reader and provide us with the Identifiers for injection.\n\n```ts\nconst CustomMetaReader = {\n    getConstructor (Type) {\n        return Type.$inject;\n    }\n};\ndi.defineMetaReader(CustomMetaReader);\n// ----\nclass Foo {\n    static $inject = [ILog]\n    constructor (logger) { logger.log() }\n\n}\n```\n\n#### `2.1.5` _Other ways_\n\n💬 Do you have any ideas? Please share them via issues.\n\n\u003e **TypeScript**: initially, this project targets plain JavaScript, but TypeScript is preferred.\n\n\n### `2.2` Properties\n\n\nProperty injections are supported by `Type`_s_ components.\n\n#### `2.2.1` External definitions\n\n```ts\nclass Foo {\n    constructor () {\n        this.logger = new DummyLogger();\n    }\n    doSmth () {\n        this.logger.log();\n    }\n}\n// ---\ndi\n    .registerType(Foo)\n    .properties({\n        // DummyLogger will be replaced with the registration for ILog\n        logger: ILog\n    })\n    .asSelf();\n```\n\n#### `2.2.2` In-place meta information\n\nPer default we read the static `$properties` to get the `key: Identifier` information.\n\n```ts\nclass Foo {\n    constructor () { }\n}\nFoo.$properties = {\n    logger: ILog\n};\n// ----\ndi\n    .registerType(Foo)\n    .asSelf();\n\n```\n\nYou can override the reader and provide us with the Identifiers for injection.\n\n```ts\nlet CustomMetaReader = {\n    getProperties (Type) {\n        // return hash with {key: Identifier}\n    }\n};\ndi.defineMetaReader(CustomMetaReader);\n```\n\n#### `2.2.3` _Other ways_\n\n💬 Ideas about better API - please share!\n\n\n----\n\n\n### `2.3` Methods\n\nInjections into `Type`_s_functions.\n\n#### `2.3.1` External definitions\n\n```ts\nclass Foo {\n    doSmth (logger) {\n        logger.log();\n    }\n}\n// ---\ndi\n    .registerType(Foo)\n    .methods({\n        // The method on an instance can be the called without any arguments\n        // Di will provide required dependencies to the inner function\n        doSmth: [ILog]\n    })\n    .asSelf();\n```\n\n#### `2.3.2` In-place meta information\n\nPer default we read the static `$methods` with `key:[Identifier, ...]` information.\n\n```ts\nclass Foo {\n    doSmth (logger) { logger.log() }\n\n    static $methods = {\n        doSmth: [ ILog ]\n    };\n}\n// ----\ndi\n    .registerType(Foo)\n    .asSelf();\n\n```\n\nYou can override the reader and provide us with the Identifiers for injection.\n\n```ts\nconst CustomMetaReader = {\n    getMethods (Type) {\n        // return hash with {key: [Identifier, ...]}\n    }\n};\ndi.defineMetaReader(CustomMetaReader);\n```\n\n#### `2.3.3` _Other ways_\n\n💬 Ideas about better API - please share!\n\n---\n\n# `3` Consume\n\n### `3.1` Initialize registered components\n\nWe inject all dependencies and return ready to use component.\n\n```ts\nlet x = di.resolve(IFoo);\n```\n\n### `3.2` Create inherited classes\n\nThe inherited class accepts empty constructor, in this case we will pass the resolved components to the base class.\n\n```ts\nlet FooWrapper = di.wrapType(IFoo);\nlet foo = new FooWrapper();\n```\n\n### `3.3` Create function delegates\n\nDefine function argument identifiers, and you can call the function without arguments.\n\n```ts\nlet myFunction = di.wrapFunction(IFoo, IBar, (foo, bar) =\u003e {});\nmyFunction();\n```\n\n---\n\n# `4` Additional configuration\n\n### `4.1` Predefine parameter values\n\nSometimes it is needed to set values for parameters, which will be directly passed inside the function.\n\n```ts\nclass Foo {\n    constructor (bar, shouldDoSmth)\n}\ndi\n    .registerType(Foo)\n    .using(Bar)\n    .withParams(null, true)\n```\n\n\u003e 1️⃣ Passing null values says the di library to resolve values from container by declared Type\n\n\u003e 2️⃣ Boolean `true` from sample just shows the idea of passing values. You may want to get the value from app configuration or some other source.\n\n### `4.2` Configurate arguments\n\nArguments _or values_ for a constructor/function are resolved from 3 sources:\n- Declared parameter values\n- Type definitions\n- Direct values from the current function call.\n\nWith options `\"ignore\" \"extend\" \"override\"` you can control how we handle the third source. Default is `\"override\"`\n\n\n\n# `5` How do we use the library?\n\nWe rarely use all of those registration and configuration features.\n\n1. All the `Services`, `Workers`, `Handlers`, `Factories` - actually everything except `Data Models` - we use mostly as singletons. Means any initialization of an Instance we do via `di.resolve`. Note, that no configuration or registration is required - when nothing specified di initializes the class as-is.\n\n\u003e We do this, while a class can `memoize` initialization, data, configuration, or method calls.\n\n```ts\nimport { UserService } from './UserService'\n// ....\nlet service = di.resolve(UserService);\n```\n\n2. To have more clear dependency tree structure, we define some dependencies via constructor as default parameters:\n\n```ts\nimport { UserService } from './UserService'\n// ....\nclass Foo {\n    constructor (\n        private service = di.resolve(UserService)\n    )\n}\n```\n\n\n2. For multiple implementations we use abstract classes.\n\n```ts\nabstract class AFoo {\n    abstract log ()\n    // ... some common logic\n}\n\n// Option 1. Register the implementation as a default for the base (AFoo)\n@di.for(AFoo)\nclass SomeFoo extends AFoo () {}\n\n// Option 2. Without the decorator, the type could be registered later somewhere in code:\ndi.registerType(AFoo).for(AFoo)\n\n\n//# Usage 1\nclass UserService {\n    constructor (\n        foo = di.resolve(AFoo)\n    ) {}\n}\n\n//# Usage 2\nclass UserService {\n    constructor (\n        @di.inject(AFoo) foo: AFoo\n    ){}\n}\n```\n\n\n🏁\n\n----\n©️ MIT — 2021 Atma.js Project\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatmajs%2Fa-di","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatmajs%2Fa-di","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatmajs%2Fa-di/lists"}