Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

rsdi

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rsdi - npm Package Compare versions

Comparing version 2.1.1 to 2.2.0

4

DefinitionName.d.ts

@@ -1,2 +0,2 @@

import { ResolverName } from "./types";
export declare function definitionNameToString(definitionName: ResolverName): string;
import { NamedResolvers, ResolverName } from "./types";
export declare function definitionNameToString<ContainerResolvers extends NamedResolvers = {}>(definitionName: ResolverName<ContainerResolvers>): string;

@@ -5,8 +5,9 @@ "use strict";

function definitionNameToString(definitionName) {
if (typeof definitionName === "string") {
return definitionName;
if (typeof definitionName === "object" ||
(typeof definitionName === "function" && definitionName.name)) {
return definitionName.name.toString();
}
return definitionName.name;
return definitionName.toString();
}
exports.definitionNameToString = definitionNameToString;
//# sourceMappingURL=DefinitionName.js.map

@@ -1,11 +0,9 @@

import { DependencyResolver, IDIContainer, ResolvedType, ResolverName } from "./types";
interface INamedResolvers {
[k: string]: DependencyResolver | any;
}
import { DependencyResolver, IDIContainer, NamedResolvers, ResolveDependencyType, ResolverName, ConvertToDefinedDependencies, NonStrictNamedResolvers } from "./types";
import ReferenceResolver from "./resolvers/ReferenceResolver";
/**
* Dependency injection container
*/
export default class DIContainer implements IDIContainer {
export default class DIContainer<ContainerResolvers extends NamedResolvers = {}> implements IDIContainer {
private resolvers;
private resolved;
private resolvedDependencies;
/**

@@ -16,3 +14,4 @@ * Resolves dependency by name

*/
get<Custom = void, Name extends ResolverName = string>(dependencyName: Name, parentDeps?: string[]): ResolvedType<Custom, Name>;
get<Name extends ResolverName<ContainerResolvers> = ResolverName<ContainerResolvers>>(dependencyName: Name, parentDeps?: string[]): ResolveDependencyType<ContainerResolvers, Name>;
use<Name extends ResolverName<ContainerResolvers> = ResolverName<ContainerResolvers>>(dependencyName: Name): ReferenceResolver<ContainerResolvers, Name>;
/**

@@ -22,3 +21,3 @@ * Adds multiple dependency resolvers to the container

*/
add(resolvers: INamedResolvers): void;
add<N extends NonStrictNamedResolvers>(this: DIContainer<ContainerResolvers>, resolvers: N): asserts this is DIContainer<ContainerResolvers & ConvertToDefinedDependencies<N>>;
/**

@@ -34,3 +33,2 @@ * Adds single dependency definition to the container

*/
export declare function resolveFunctionParameters(diContainer: IDIContainer, parameters?: Array<DependencyResolver<any> | any>, parentDeps?: string[]): any[];
export {};
export declare function resolveFunctionParameters(diContainer: DIContainer, parameters?: Array<DependencyResolver<any> | any>, parentDeps?: string[]): any[];

@@ -20,2 +20,3 @@ "use strict";

var DefinitionName_1 = require("./DefinitionName");
var ReferenceResolver_1 = __importDefault(require("./resolvers/ReferenceResolver"));
/**

@@ -27,3 +28,3 @@ * Dependency injection container

this.resolvers = {};
this.resolved = {};
this.resolvedDependencies = {};
}

@@ -35,3 +36,5 @@ /**

*/
DIContainer.prototype.get = function (dependencyName, parentDeps) {
DIContainer.prototype.get = function (dependencyName,
// @todo: move parent deps to separate method
parentDeps) {
if (parentDeps === void 0) { parentDeps = []; }

@@ -45,9 +48,13 @@ var name = (0, DefinitionName_1.definitionNameToString)(dependencyName);

}
if (this.resolved[name] !== undefined) {
return this.resolved[name];
if (this.resolvedDependencies[name] !== undefined) {
return this.resolvedDependencies[name];
}
var definition = this.resolvers[name];
this.resolved[name] = definition.resolve(this, __spreadArray(__spreadArray([], parentDeps, true), [name], false));
return this.resolved[name];
definition.setParentDependencies(__spreadArray(__spreadArray([], parentDeps, true), [name], false));
this.resolvedDependencies[name] = definition.resolve(this);
return this.resolvedDependencies[name];
};
DIContainer.prototype.use = function (dependencyName) {
return new ReferenceResolver_1.default(dependencyName);
};
/**

@@ -59,3 +66,3 @@ * Adds multiple dependency resolvers to the container

var _this = this;
Object.keys(resolvers).map(function (name) {
Object.keys(resolvers).forEach(function (name) {
_this.addResolver(name, resolvers[name]);

@@ -86,3 +93,4 @@ });

if (parameter instanceof AbstractResolver_1.default) {
return parameter.resolve(diContainer, parentDeps);
parameter.setParentDependencies(parentDeps);
return parameter.resolve(diContainer);
}

@@ -89,0 +97,0 @@ return parameter;

@@ -22,3 +22,3 @@ "use strict";

function CircularDependencyError(name, path) {
return _super.call(this, "Circular Dependency is detected. Dependency: \"" + name + "\", path: " +
return _super.call(this, "Circular Dependency is detected. Dependency: \"".concat(name, "\", path: ") +
path.join(" -> ") +

@@ -33,3 +33,3 @@ ".") || this;

function DependencyIsMissingError(name) {
return _super.call(this, "Dependency with name " + name + " is not defined") || this;
return _super.call(this, "Dependency with name ".concat(name, " is not defined")) || this;
}

@@ -50,3 +50,3 @@ return DependencyIsMissingError;

function MethodIsMissingError(objectName, methodName) {
return _super.call(this, methodName + " is not a member of " + objectName) || this;
return _super.call(this, "".concat(methodName, " is not a member of ").concat(objectName)) || this;
}

@@ -53,0 +53,0 @@ return MethodIsMissingError;

{
"name": "rsdi",
"version": "2.1.1",
"description": "Simple dependency injection container for JavaScript/TypeScript",
"scripts": {
"test": "jest",
"format": "prettier 'src/**/*.ts' --write",
"build": "tsc",
"build-prod": "rm -Rf ./dist/* && NODE_ENV=production tsc --build tsconfig.json && cp README.md package.json dist/",
"pre-commit": "lint-staged"
},
"keywords": [
"dependency injection",
"dependency",
"injection",
"ioc",
"container",
"javascript",
"typescript"
],
"homepage": "https://github.com/radzserg/rsdi",
"author": "Sergey Radzishevskii <radzserg@gmail.com>",
"license": "ISC",
"lint-staged": {
"src/**/*.ts": "prettier --write --ignore-unknown"
},
"devDependencies": {
"@types/jest": "^26.0.23",
"husky": "^7.0.2",
"jest": "^27.0.6",
"lint-staged": "^11.2.0",
"prettier": "^2.4.1",
"ts-jest": "^27.0.3",
"typescript": "^4.3.5"
}
"name": "rsdi",
"version": "2.2.0",
"description": "Simple dependency injection container for JavaScript/TypeScript",
"scripts": {
"test": "jest",
"test:types": "jest -c jest.config.tsd.js",
"format": "prettier 'src/**/*.ts' --write",
"build": "tsc",
"build-prod": "rm -Rf ./dist/* && NODE_ENV=production tsc --build tsconfig.json && cp README.md package.json dist/",
"pre-commit": "lint-staged",
"lint": "yarn eslint src/**/**.ts",
"prettify": "prettier --write --ignore-unknown"
},
"keywords": [
"dependency injection",
"dependency",
"injection",
"ioc",
"container",
"javascript",
"typescript"
],
"homepage": "https://github.com/radzserg/rsdi",
"author": "Sergey Radzishevskii <radzserg@gmail.com>",
"license": "ISC",
"lint-staged": {
"src/**/*.ts": [
"prettier --write --ignore-unknown",
"eslint"
]
},
"devDependencies": {
"@tsd/typescript": "^4.6.4",
"@types/jest": "^27.5.0",
"@typescript-eslint/eslint-plugin": "^5.27.1",
"eslint": "^8.17.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard-with-typescript": "^21.0.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"husky": "^7.0.2",
"jest": "^28.0.3",
"jest-runner-tsd": "^3.0.0",
"lint-staged": "^11.2.0",
"prettier": "^2.6.2",
"ts-jest": "^28.0.1",
"tsd": "^0.20.0",
"typescript": "^4.6.4"
},
"dependencies": {}
}
# RSDI - Dependency Injection Container
Simple and powerful dependency injection container for JavaScript/TypeScript.
Simple and powerful dependency injection container for with strong type checking system.
# Getting Started
- [Motivation](#motivation)
- [Features](#features)
- [When to use](#when-to-use)
- [Architecture](#architecture)
- [Usage](#usage)
- [Raw values](#raw-values)
- [Object resolver](#object-resolver)
- [Function resolver](#function-resolver)
- [Factory resolver](#factory-resolver)
- [Typescript type resolution](#typescript-type-resolution)
- [Dependency declaration](#dependency-declaration)
- Wiki
- [Async factory resolver](./docs/async_factory_resolver.md)
- [DI Container vs Context](./docs/context_vs_container.md)
Given that you have classes and factories in your application
## Motivation
Popular dependency injection libraries use `reflect-metadata` that allows to fetch argument types and based on
those types and do autowiring. Autowiring is a nice feature but the trade-off is decorators.
```typescript
class CookieStorage {}
class AuthStorage {
constructor(storage: CookieStorage) {}
@injectable()
class Foo {}
```
Why component Foo should know that it's injectable?
Your business logic depends on a specific framework that is not part of your domain model and can change.
More thoughts in a [dedicated article](https://radzserg.medium.com/https-medium-com-radzserg-dependency-injection-in-react-part-2-995e93b3327c)
## Features
- Simple but powerful
- Does not requires decorators
- Great types resolution
- Works great with both javascript and typescript
## When to use
`RSDI` is most effective in complex applications. When the complexity of your application is high, it becomes necessary to
break up huge components into smaller ones to control the complexity. You have components that use other components that
use other components. You have application layers and a layer hierarchy. There is a need to transfer dependencies from
the upper layers to the lower ones.
You like and respect and use Dependency Injection and TDD. You have to use Dependency Injection in order to have proper
unit tests. Tests that test only one module - class, component, function, but not integration with nested dependencies.
## Architecture
`RSDI` expects (but does not require) that you build all your dependencies into a dependency tree. Let's take a typical
web application as an example. Given that your application is quite large and has many layers:
- controllers (REST or graphql handlers)
- domain model handlers (your domain models, various managers, use-cases etc)
- DB repositories,
- Low level services
![architecture](https://github.com/radzserg/rsdi/raw/main/docs/RSDI_architecture.jpg "RSDI Architecture")
An application always has an entry point, whether it is a web application or a CLI application. This is the only place where you
should configure your dependency injection container. The top level components will then have the lower level components
injected.
# How to use
Let's take a simple web application as an example. We will cut into a small part of the application that registers a
new user. A real application will consist of dozens of components. The logic of the components will be much more
complicated. This is just a demo. It's up to you to use classes or factory functions for the demonstration, and we'll
use both.
```typescript
// sample web application components
export function UserController(
userRegistrator: UserRegistrator,
userRepository: UserRepository
) {
return {
async create(req: Request, res: Response) {
const user = await userRegistrator.register(req.body);
res.send(user);
},
async list(req: Request) {
const users = await userRepository.findAll(req.body);
res.send(users);
},
};
}
class Logger {}
class DummyLogger extends Logger {}
function loggerFactory(container: IDIContainer): Logger {
const env = container.get("ENV");
if (env === "test") {
return new DummyLogger();
}
return new Logger();
export class UserRegistrator {
public constructor(public readonly userRepository: UserRepository) {}
public async register(userData: SignupData) {
// validate
const user = this.userRepository.saveNewUser(userData);
// send sign up email
return user;
}
}
function UsersRepoFactory(knex: Knex): UsersRepo {
return {
async findById(id: number) {
await knex("users").where({ id });
},
};
export function MyDbProviderUserRepository(db: Knex): UserRepository {
return {
async saveNewUser(userAccountData: SignupData): Promise<void> {
await this.db("insert").insert(userAccountData);
},
};
}
export function buildDbConnection(): Knex {
return knex({
/* db credentials */
});
}
```
Your DI container initialisation will include
Now we need to configure the dependency injection container before use. Dependencies are declared and not really initiated
until the application really needs them. Your DI container initialization function - `configureDI` will include:

@@ -39,69 +128,64 @@ ```typescript

export default function configureDI() {
const container = new DIContainer();
container.add({
ENV: "test", // define raw value
Storage: object(CookieStorage), // constructor without arguments
AuthStorage: object(AuthStorage).construct(
use(Storage) // refer to another dependency
),
knex: knex(), // keeps raw value
Logger: factory(loggerFactory), // lazy function, will be resolved when it will be needed
UsersRepo: func(UsersRepoFactory, use("knex")),
});
return container;
const container = new DIContainer();
container.add({
buildDbConnection: factory(() => {
buildDbConnection();
}),
[MyDbProviderUserRepository.name]: func(
MyDbProviderUserRepository,
use(buildDbConnection)
),
[UserRegistrator.name]: object(UserRegistrator).contrstruct(
use(MyDbProviderUserRepository.name)
),
[UserController.name]: func(
UserController,
use(UserRegistrator.name),
use(MyDbProviderUserRepository.name)
),
});
return container;
}
```
The entry point of your application will include
**All resolvers are resolved only once and their result persists over the life of the container.**
Let's map our web application routes to configured controllers
```typescript
const container = configureDI();
const env: string = container.get("ENV"); // test
const authStorage: AuthStorage = container.get(AuthStorage); // object of AuthStorage
const logger: Logger = container.get(loggerFactory); // object of DummyLogger
// configure Express router
export default function configureRouter(
app: core.Express,
diContainer: IDIContainer
) {
const usersController = diContainer.get(UsersController);
app
.route("/users")
.get(usersController.list.bind(usersController))
.post(usersController.create.bind(usersController));
}
```
**All resolvers are resolved only once and their result persists over the life of the container.**
Add `configureDI` in the entry point of your application.
- [Features](#features)
- [Motivation](#motivation)
- [Usage](#usage)
- [Raw values](#raw-values)
- [Object resolver](#object-resolver)
- [Function resolver](#function-resolver)
- [Factory resolver](#factory-resolver)
- [Advanced Usage](#advanced-usage)
- [Typescript type resolution](#typescript-type-resolution)
- [Dependency declaration](#dependency-declaration)
- [Async factory resolver](#async-factory-resolver)
```typescript
// express.ts
const app = express();
## Features
const diContainer = configureDI();
configureRouter(app, diContainer);
- Simple but powerful
- Does not requires decorators
- Great types resolution
- Works great with both javascript and typescript
## Motivation
Popular dependency injection libraries use `reflect-metadata` that allows to fetch argument types and based on
those types and do autowiring. Autowiring is a nice feature but the trade-off is decorators.
```typescript
@injectable()
class Foo {}
app.listen(8000, () => {
console.log(`⚡️[server]: Server is running`);
});
```
Why component Foo should know that it's injectable?
The complete web application example can be found [here](https://radzserg.medium.com/dependency-injection-in-express-application-dd85295694ab)
Your business logic depends on a specific framework that is not part of your domain model and can change.
## Dependency Resolvers
More thoughts in a [dedicated article](https://radzserg.medium.com/https-medium-com-radzserg-dependency-injection-in-react-part-2-995e93b3327c)
### Raw values resolver
## Usage
Dependencies are set as raw values. Container keeps and return raw values.
### Raw values
Dependencies are set as raw values. No lazy initialisation happens. Container keeps and return raw values.
```typescript

@@ -112,5 +196,5 @@ import DIContainer from "rsdi";

container.add({
ENV: "PRODUCTION",
HTTP_PORT: 3000,
storage: new CookieStorage(),
ENV: "PRODUCTION",
HTTP_PORT: 3000,
storage: new CookieStorage(),
});

@@ -131,9 +215,8 @@ const env: string = container.get("ENV");

```typescript
// test class
class ControllerContainer {
constructor(authStorage: AuthStorage, logger: Logger) {}
constructor(authStorage: AuthStorage, logger: Logger) {}
add(controller: Controller) {
this.controllers.push(controller);
}
add(controller: Controller) {
this.controllers.push(controller);
}
}

@@ -144,12 +227,12 @@

container.add({
Storage: object(CookieStorage), // constructor without arguments
AuthStorage: object(AuthStorage).construct(
use(Storage) // refers to existing dependency
),
UsersController: object(UserController),
PostsController: object(PostsController),
ControllerContainer: object(MainCliCommand)
.construct(use(AuthStorage), new Logger()) // use existing dependency, or pass raw values
.method("add", use(UsersController)) // call class method after initialization
.method("add", use(PostsController)),
Storage: object(CookieStorage), // constructor without arguments
AuthStorage: object(AuthStorage).construct(
use(Storage) // refers to existing dependency
),
UsersController: object(UserController),
PostsController: object(PostsController),
ControllerContainer: object(MainCliCommand)
.construct(use(AuthStorage), new Logger()) // use existing dependency, or pass raw values
.method("add", use(UsersController)) // call class method after initialization
.method("add", use(PostsController)),
});

@@ -164,7 +247,7 @@ ```

function UsersRepoFactory(knex: Knex): UsersRepo {
return {
async findById(id: number) {
await knex("users").where({ id });
},
};
return {
async findById(id: number) {
await knex("users").where({ id });
},
};
}

@@ -174,4 +257,4 @@

container.add({
DBConnection: knex(/* ... */),
UsersRepoFactory: func(UsersRepoFactory, use("DBConnection")),
DBConnection: knex(/* ... */),
UsersRepoFactory: func(UsersRepoFactory, use("DBConnection")),
});

@@ -185,4 +268,4 @@

Factory resolver is similar to a Function resolver. You can use factory resolver when you need more flexibility
during initialization. `container: IDIContainer` will be passed in as an argument to the factory method. So you can
resolve other dependencies inside the factory function.
during initialization. `container: IDIContainer` will be passed in as an argument to the factory method. You can
resolve other dependencies inside the factory function and have conditions inside of it.

@@ -192,135 +275,135 @@ ```typescript

container.add({
BrowserHistory: factory(configureHistory),
BrowserHistory: factory(configureHistory),
});
function configureHistory(container: IDIContainer): History {
const history = createBrowserHistory();
const env = container.get("ENV");
if (env === "production") {
// do what you need
}
return history;
const history = createBrowserHistory();
const env = container.get("ENV");
if (env === "production") {
// do what you need
}
return history;
}
const history = container.get<History>("BrowserHistory");
const history = container.get("BrowserHistory");
```
## Advanced Usage
## Typescript type resolution
### Typescript type resolution
`container.get` - return type based on declaration.
`container.get` and `use` helper resolve type based on following convention:
- if given name is class - instance of a class
- if given name is function - return type of function
- if custom generic type is provided - custom type
- otherwise - any
```typescript
const container: DIContainer = new DIContainer();
container.add({
Bar: new Bar(),
Foo: new Bar(), // fake foo example
strVal: "raw string value",
numberVal: 123,
boolVal: true,
objectVal: object(Buzz), // resolvers to object of class Buzz
dateVal: func(function () {
return new Date(); // resolves to ReturnType of the function
}),
});
let bar: Bar = container.get(Bar); // types defined based on a given type Bar
let foo: Foo = container.get(Foo); // you can trick TS compiler (it's your responsibility)
let foo2: Foo = container.get<Foo>("Foo"); // custom generic type is provided
let foo3: Foo = container.get("Foo"); // any type
const strVal = container.get("strVal"); // strVal: string
const numberVal = container.get("numberVal"); // numberVal: number
const boolVal = container.get("boolVal"); // boolVal: boolean
const objectVal = container.get("objectVal"); // boolVal: Buzz
const dateVal = container.get("dateVal"); // dateVal: Date
```
Example: `use` defines type for a class constructor.
`contrainer.use` - allows to reference declared dependency with respect to types.
```typescript
class Foo {
constructor(private readonly bar: Bar) {}
export class Foo {
constructor(name: string, bar: Bar) {}
}
const container: DIContainer = new DIContainer();
container.add({
Bar: new Bar(),
Foo: object(Foo).construct(use(Bar)), // constuct method checks type and use return Bar type
bar: new ObjectResolver(Bar),
key1: new RawValueResolver("value1"),
// `bar` dependency cannot be referenced in the same `add` call
// Argument of type 'string' is not assignable to parameter of type... '
// foo: new ObjectResolver(Foo).construct("foo", container.use("bar")),
});
```
Example: `container.get` resolve type based on a given factory return type.
```typescript
function myFactory() {
return { a: 123 };
}
container.add({
myFactory: factory((container: IDIContainer) => {
return myFactory();
}),
foo: new ObjectResolver(Foo).construct("foo", container.use("bar")),
});
let { a } = container.get(myFactory);
```
### Dependency declaration
To support lazy loading `construct` method changes original Foo constructor to expect
`(string | ReferenceResolver<string>, Bar | ReferenceResolver<Bar>)`.
`container.use("bar")` - will return object `ReferenceResolver<Bar>` to respect safe types.
RSDI resolves dependencies on a given type. It can be string or function. In the simplest case, you can use strings.
`use` helper
```typescript
container.add({
Foo: new Foo(),
});
const foo = container.get<Foo>("Foo");
import { use } from "rsdi";
```
In order to avoid magic strings you can operate with types.
`use` helper is less strict version of `container.use`. It allows to reference dependencies that **will be defined** relying
on convention over configuration rule.
- if given name is a class - instance of the class
- if given name is a function - return type of the function
- if custom type is provided - return ReferenceResolver<Custom>
- otherwise - any
```typescript
const foo = container.get(Foo);
```
class Foo {
constructor(private readonly bar: Bar) {}
}
RSDI uses `Foo.name` behind the scene that equals to "Foo". Remember that this approach will not work for uglified code.
You can also rename the function Foo => Buzz, and forget to rename the declaration. From that perspective you can
declare dependencies this way.
function returnBoolean() {
return true;
}
```typescript
const container: DIContainer = new DIContainer();
container.add({
[Foo.name]: new Foo(),
[MyFactory.name]: MyFactory(),
Bar: new Bar(),
Foo: object(Foo).construct(use(Bar)), // resolves Bar
expectBoolFunc: func(function (a: boolean) {
return null;
}, use(returnBoolean)), // resolves to ReturnType of returnBoolean function
expectDateFunc: func(function (a: Date) {
return null;
}, use<Date>("date")), // resolves to Date
expectDateFunc2: func(function (a: Date) {
return null;
}, use("date")), // resolves to any
});
const foo = container.get(Foo);
const buzz = container.get(MyFactory);
```
### Async factory resolver
## Dependency declaration
RSDI intentionally does not provide the ability to resolve asynchronous dependencies. The container works with
resources. All resources will be used sooner or later. The lazy initialization feature won't be of much benefit
in this case. At the same time, mixing synchronous and asynchronous resolution will cause confusion primarily for
the consumers.
**Use string names**
The following approach will work in most scenarios.
```typescript
// UserRepository.ts
class UserRepository {
public constructor(private readonly dbConnection: any) {} // some ORM that requires opened connection
const container: DIContainer = new DIContainer();
async findUser() {
return await this.dbConnection.find(/*...params...*/);
}
}
container.add({
bar: new ObjectResolver(Bar),
key1: new RawValueResolver("value1"),
});
// configureDI.ts
import { createConnections } from "my-orm-library";
import DIContainer, { factory, use, IDIContainer } from "rsdi";
container.add({
foo: new ObjectResolver(Foo).construct("foo", container.use("bar")),
});
```
async function configureDI() {
// initialize async factories before DI container initialisation
const dbConnection = await createConnections();
Use function and class names by declaring them as `[MyClass.name]`. In this case, it is safe to rename functions and
classes in the IDE. IDE will identify all usages and rename them in the container as well. You can declare all dependencies
in a single `add` method and use `use` helper to reference other dependencies.
const container = new DIContainer();
container.addDefinitions({
DbConnection: dbConnection,
UserRepository: object(UserRepository).construct(use("DbConnection")),
});
return container;
}
// main.ts
const diContainer = await configureDI();
const userRepository = diContainer.get<UserRepository>("UserRepository");
```typescript
container.add({
[Foo.name]: new Foo(),
[MyFactory.name]: MyFactory(),
[Foo.name]: object(Foo).construct(use(Bar)),
});
const foo = container.get(Foo);
const buzz = container.get(MyFactory);
```

@@ -1,8 +0,11 @@

import { DependencyResolver, IDIContainer } from "../types";
import { DependencyResolver } from "../types";
import DIContainer from "../DIContainer";
/**
* Keep AbstractResolver so we can use `if (dep instanceof AbstractResolver) ` checks
* Keep AbstractResolver, so we can use `if (dep instanceof AbstractResolver) ` checks
*/
declare abstract class AbstractResolver<T = any> implements DependencyResolver<T> {
abstract resolve: (container: IDIContainer, parentDeps?: string[]) => T;
protected parentDeps: string[];
abstract resolve: (container: DIContainer) => T;
setParentDependencies(parentDeps: string[]): void;
}
export default AbstractResolver;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Keep AbstractResolver so we can use `if (dep instanceof AbstractResolver) ` checks
* Keep AbstractResolver, so we can use `if (dep instanceof AbstractResolver) ` checks
*/
var AbstractResolver = /** @class */ (function () {
function AbstractResolver() {
this.parentDeps = [];
}
AbstractResolver.prototype.setParentDependencies = function (parentDeps) {
this.parentDeps = parentDeps;
};
return AbstractResolver;

@@ -10,0 +14,0 @@ }());

import AbstractResolver from "./AbstractResolver";
import { IDIContainer } from "../types";
import DIContainer from "../DIContainer";
export declare type Factory = (container: IDIContainer) => any;

@@ -10,3 +11,3 @@ /**

constructor(factory: T);
resolve: (container: IDIContainer) => ReturnType<T>;
resolve: (container: DIContainer) => ReturnType<T>;
}
import AbstractResolver from "./AbstractResolver";
import { IDIContainer, WrapWithResolver } from "../types";
import { WrapWithResolver } from "../types";
import DIContainer from "../DIContainer";
/**

@@ -11,3 +12,3 @@ * FunctionResolver - allows to use custom function with specified parameters, where parameters are references to

constructor(func: T, ...parameters: T extends (...args: infer ArgTypes) => any ? WrapWithResolver<ArgTypes> : never);
resolve: (container: IDIContainer, parentDeps?: string[] | undefined) => ReturnType<T>;
resolve: (container: DIContainer) => ReturnType<T>;
}

@@ -37,4 +37,4 @@ "use strict";

_this.func = func;
_this.resolve = function (container, parentDeps) {
var parameters = (0, DIContainer_1.resolveFunctionParameters)(container, _this.parameters, parentDeps);
_this.resolve = function (container) {
var parameters = (0, DIContainer_1.resolveFunctionParameters)(container, _this.parameters, _this.parentDeps);
return _this.func.apply(_this, parameters);

@@ -41,0 +41,0 @@ };

import AbstractResolver from "./AbstractResolver";
import { ClassOf, DependencyResolver, IDIContainer, MethodArgs, WrapWithResolver } from "../types";
import { ClassOf, DependencyResolver, MethodArgs, WrapWithResolver } from "../types";
import DIContainer from "../DIContainer";
/**

@@ -27,3 +28,3 @@ * ObjectDefinition creates objects from the provided class.

method<MethodName extends keyof InstanceType<T>>(methodName: MethodName, ...args: MethodArgs<T, MethodName>): ObjectResolver<T>;
resolve: (diContainer: IDIContainer, parentDeps?: string[]) => InstanceType<T>;
resolve: (diContainer: DIContainer) => InstanceType<T>;
}

@@ -43,6 +43,5 @@ "use strict";

_this.methods = [];
_this.resolve = function (diContainer, parentDeps) {
_this.resolve = function (diContainer) {
var _a;
if (parentDeps === void 0) { parentDeps = []; }
var constructorParameters = (0, DIContainer_1.resolveFunctionParameters)(diContainer, _this.deps, parentDeps);
var constructorParameters = (0, DIContainer_1.resolveFunctionParameters)(diContainer, _this.deps, _this.parentDeps);
var object = new ((_a = _this.constructorFunction).bind.apply(_a, __spreadArray([void 0], constructorParameters, false)))();

@@ -54,3 +53,3 @@ _this.methods.forEach(function (method) {

}
var resolvedArgs = (0, DIContainer_1.resolveFunctionParameters)(diContainer, args, parentDeps);
var resolvedArgs = (0, DIContainer_1.resolveFunctionParameters)(diContainer, args, _this.parentDeps);
object[methodName].apply(object, resolvedArgs);

@@ -57,0 +56,0 @@ });

import AbstractResolver from "./AbstractResolver";
import { IDIContainer } from "../types";
import DIContainer from "../DIContainer";
import { AnyNamedResolvers, NamedResolvers, ResolveDependencyType, ResolverName } from "../types";
/**
* Refers to existing definition. i.e. definition with provided name must exists in DIContainer
*/
export default class ReferenceResolver<T = any> extends AbstractResolver<T> {
export default class ReferenceResolver<ExistingNamedResolvers extends NamedResolvers = AnyNamedResolvers, Name extends ResolverName<ExistingNamedResolvers> = ResolverName<ExistingNamedResolvers>> extends AbstractResolver<ResolveDependencyType<ExistingNamedResolvers, Name>> {
private readonly existingDefinitionName;
constructor(existingDefinitionName: string);
resolve: <Y extends T>(container: IDIContainer, parentDeps?: string[]) => Y;
constructor(existingDefinitionName: Name);
resolve: (container: DIContainer<ExistingNamedResolvers>) => ResolveDependencyType<ExistingNamedResolvers, Name>;
}

@@ -29,5 +29,4 @@ "use strict";

var _this = _super.call(this) || this;
_this.resolve = function (container, parentDeps) {
if (parentDeps === void 0) { parentDeps = []; }
return container.get(_this.existingDefinitionName, parentDeps);
_this.resolve = function (container) {
return container.get(_this.existingDefinitionName, _this.parentDeps);
};

@@ -34,0 +33,0 @@ _this.existingDefinitionName = existingDefinitionName;

import ObjectResolver from "./resolvers/ObjectResolver";
import RawValueResolver from "./resolvers/RawValueResolver";
import ReferenceResolver from "./resolvers/ReferenceResolver";
import FactoryResolver, { Factory } from "./resolvers/FactoryResolver";
import { ClassOf, ResolverName, WrapWithResolver } from "./types";
import { ClassOf, DependencyResolver, ResolverName, ResolveUsingSelfType, WrapWithResolver } from "./types";
import FunctionResolver from "./resolvers/FunctionResolver";

@@ -18,13 +17,9 @@ /**

/**
* Defines the type of resolved dependency
* - if Custom type is given - it will be returned
* - if name of Class is provided - instance type will be returned
* - if function is provided - function return type will be returned
*/
declare type ResolvedType<Custom, Name extends ResolverName> = Custom extends void ? Name extends string ? any : Name extends ClassOf<any> ? InstanceType<Name> : Name extends (...args: any) => infer FT ? FT : never : Custom;
/**
* Refers to existing definition. i.e. definition with provided name must exists in DIContainer
* Refers to existing definition. i.e. definition with provided name must exist in DIContainer.
* Fallback to self type
*
* @param definitionName
*
*/
export declare function diUse<Custom = void, Name extends ResolverName = ResolverName>(definitionName: Name): ReferenceResolver<ResolvedType<Custom, Name>>;
export declare function diUse<Custom = void, Name extends ResolverName = ResolverName>(definitionName: Name): Custom extends void ? DependencyResolver<ResolveUsingSelfType<Name>> : DependencyResolver<Custom>;
/**

@@ -42,2 +37,1 @@ * FactoryResolver - allows to use custom function to build dependency

export declare function diFunc<T extends (...args: any) => any>(func: T, ...parameters: T extends (...args: infer ArgTypes) => any ? WrapWithResolver<ArgTypes> : never): FunctionResolver<T>;
export {};

@@ -22,3 +22,2 @@ "use strict";

var FunctionResolver_1 = __importDefault(require("./resolvers/FunctionResolver"));
// shorthands for Definition classes
/**

@@ -41,7 +40,11 @@ * ObjectDefinition creates objects from the provided class.

/**
* Refers to existing definition. i.e. definition with provided name must exists in DIContainer
* Refers to existing definition. i.e. definition with provided name must exist in DIContainer.
* Fallback to self type
*
* @param definitionName
*
*/
function diUse(definitionName) {
return new ReferenceResolver_1.default((0, DefinitionName_1.definitionNameToString)(definitionName));
var dependencyName = (0, DefinitionName_1.definitionNameToString)(definitionName);
return new ReferenceResolver_1.default(dependencyName);
}

@@ -48,0 +51,0 @@ exports.diUse = diUse;

@@ -0,28 +1,87 @@

import ObjectResolver from "./resolvers/ObjectResolver";
import FunctionResolver from "./resolvers/FunctionResolver";
import DIContainer from "./DIContainer";
import FactoryResolver from "./resolvers/FactoryResolver";
export declare type DependencyResolver<T extends any = any> = {
setParentDependencies: (parentDeps: string[]) => void;
resolve: (container: DIContainer) => T;
};
export declare type AnyNamedResolvers = {
[k: string]: DependencyResolver;
};
/**
* Dependency injection container interface to expose
* Resolvers map
* {
* a: new FunctionResolver(() => 123),
* b: new RawValueResolver("stringValue"),
* // and also can contain raw value declarations
* c: "StringValue"
* }
*/
export interface IDIContainer {
get: <Custom, Name extends ResolverName = ResolverName>(dependencyName: Name) => ResolvedType<Custom, Name>;
}
export declare type DependencyResolver<T extends any = unknown> = {
resolve: (container: IDIContainer, parentDeps?: string[]) => T;
export declare type NonStrictNamedResolvers = {
[k: string]: DependencyResolver | any;
};
/**
* Resolvers map
* {
* a: new FunctionResolver(() => 123),
* b: new RawValueResolver("stringValue"),
* }
*/
export declare type NamedResolvers = {
[k: string]: DependencyResolver;
};
export declare type ConvertToDefinedDependencies<T = NonStrictNamedResolvers> = {
[K in keyof T]: T[K] extends DependencyResolver ? T[K] : DependencyResolver<T[K]>;
};
export declare type WrapWithResolver<T extends any[]> = {
[K in keyof T]: T[K] | DependencyResolver<T[K]>;
};
export declare type ResolverName = string | {
name: string;
};
export declare type ParametersWithResolver<T extends (...args: any) => any> = T extends (...args: infer P) => any ? WrapWithResolver<P> : never;
declare type Resolve<N extends DependencyResolver> = N extends {
resolve(...args: any[]): infer R;
} ? R : never;
export interface ClassOf<C extends Object> {
new (...args: any[]): C;
}
export declare type FetchClassesFromContainerResolvers<ContainerResolvers extends NamedResolvers = AnyNamedResolvers> = {
[P in keyof ContainerResolvers]: ContainerResolvers[P] extends ObjectResolver<ClassOf<any>> ? ContainerResolvers[P] extends ObjectResolver<infer X> ? X : never : never;
}[keyof ContainerResolvers];
export declare type FetchFunctionsFromContainerResolvers<ContainerResolvers extends NamedResolvers = AnyNamedResolvers> = {
[P in keyof ContainerResolvers]: ContainerResolvers[P] extends FunctionResolver<infer FT> ? FT : never;
}[keyof ContainerResolvers];
export declare type FetchFactoriesFromContainerResolvers<ContainerResolvers extends NamedResolvers = AnyNamedResolvers> = {
[P in keyof ContainerResolvers]: ContainerResolvers[P] extends FactoryResolver<infer FT> ? FT : never;
}[keyof ContainerResolvers];
export declare type ResolverName<ContainerResolvers extends NamedResolvers = AnyNamedResolvers> = keyof ContainerResolvers | {
name: keyof ContainerResolvers;
} | FetchClassesFromContainerResolvers<ContainerResolvers> | FetchFunctionsFromContainerResolvers<ContainerResolvers> | FetchFactoriesFromContainerResolvers<ContainerResolvers>;
export declare type ParametersWithResolver<T extends (...args: any) => any> = T extends (...args: infer P) => any ? WrapWithResolver<P> : never;
export declare type MethodArgs<T extends ClassOf<any>, K extends keyof InstanceType<T>> = ParametersWithResolver<InstanceType<T>[K]>;
/**
* Defines the type of resolved dependency
* - if name of Class is provided - instance type will be returned
* - if function is provided - function return type will be returned
* - if Custom type is provided - it will be returned
* Resolves types using self type
* - if T is a class - instance type will be returned
* - if T is a function - function return type will be returned
* - else any
*/
export declare type ResolvedType<Custom = void, Name extends ResolverName = ResolverName> = Name extends ClassOf<any> ? InstanceType<Name> : Name extends (...args: any) => infer FT ? FT : Custom extends void ? any : Custom;
export declare type ResolveUsingSelfType<T> = T extends ClassOf<any> ? InstanceType<T> : T extends (...args: any) => infer FT ? FT : never;
/**
* Tries to resolve type based on provided name and accumulated
* dependencies in the NamedResolvers
*/
export declare type TryResolveUsingExistingResolvers<Name, ExistingNamedResolvers extends NamedResolvers> = Name extends keyof NamedResolvers ? ExistingNamedResolvers[Name] extends DependencyResolver ? Resolve<ExistingNamedResolvers[Name]> : never : never;
/**
* Resolve dependency type
* - tries to resolve using already defined dependencies
* - reties to resolve using custom type,
* substituted by TS - const a: MyType = container.get("name")
* or explicitly provided const a = container.get<MyType>("name")
* - tries to resolve using self type. If a class or function is provided
* instance of a class or function return type will be returned
*/
export declare type ResolveDependencyType<ExistingNamedResolvers extends NamedResolvers = NamedResolvers, Name extends ResolverName<ExistingNamedResolvers> = ResolverName<ExistingNamedResolvers>> = TryResolveUsingExistingResolvers<Name, ExistingNamedResolvers> extends never ? ResolveUsingSelfType<Name> : TryResolveUsingExistingResolvers<Name, ExistingNamedResolvers>;
export interface IDIContainer {
get: (dependencyName: string | {
name: string;
}) => any;
}
export {};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc