@adonisjs/fold
- Version 10.1.2
- Published
- 173 kB
- 1 dependency
- MIT license
Install
npm i @adonisjs/fold
yarn add @adonisjs/fold
pnpm add @adonisjs/fold
Overview
A simple and straight forward implementation for IoC container in JavaScript
Index
Functions
Classes
Functions
function inject
inject: () => { <C extends Function>(target: C): void; (target: any, propertyKey: string | symbol): void;};
The "@inject" decorator uses Reflection to inspect the dependencies of a class or a method and defines them as metaData on the class for the container to discover them.
function moduleCaller
moduleCaller: ( target: Constructor<any>, method: string) => { toCallable< T extends ContainerResolver<any> | Container<any> = undefined, Args extends any[] = any[] >( container?: T ): ModuleCallable<T, Args>; toHandleMethod< T_1 extends ContainerResolver<any> | Container<any> = undefined, Args_1 extends any[] = any[] >( container?: T_1 ): ModuleHandler<T_1, Args_1>;};
The moduleCaller works around a very specific pattern we use with AdonisJS, ie to construct classes and call methods using the container.
For example: Controllers of AdonisJS allows defining a controller as follows
route.get('/', [HomeController, 'index'])Behind the scenes, we have to run following operations in order to call the handle method on the defined middleware.
- Create an instance of the controller class using the container. - Call the method using the container. Hence having the ability to use DI
function moduleExpression
moduleExpression: ( expression: string, parentURL: URL | string) => { parse(): [string, string]; toCallable< T extends ContainerResolver<any> | Container<any> = undefined, Args extends any[] = any[] >( container?: T ): ModuleCallable<T, Args>; toHandleMethod< T_1 extends ContainerResolver<any> | Container<any> = undefined, Args_1 extends any[] = any[] >( container?: T_1 ): ModuleHandler<T_1, Args_1>;};
The moduleExpression module works around a very specific pattern we use with AdonisJS, ie to bind modules as string.
For example: With the router of AdonisJS, we can bind a controller to a route as follows.
Route.get('users', '#controllers/users_controller.index')Behind the scenes, we have to run following operations in order to call a method on the users_controller class.
- Dynamic import
#controllers/users_controller
module - Check if the module has a default export. - Create an instance of the default export class using the container. - Call theindex
method on the controller class using the container.Router is just one example, we do this with event listeners, redis pub/sub and so on.
So, instead of writing all this parsing logic, we encapsulate it inside the "moduleExpression" module.
function moduleImporter
moduleImporter: ( importFn: () => Promise<{ default: Constructor<any> }>, method: string) => { toCallable< T extends ContainerResolver<any> | Container<any> = undefined, Args extends any[] = any[] >( container?: T ): ModuleCallable<T, Args>; toHandleMethod< T_1 extends ContainerResolver<any> | Container<any> = undefined, Args_1 extends any[] = any[] >( container?: T_1 ): ModuleHandler<T_1, Args_1>;};
The moduleImporter module works around a very specific pattern we use with AdonisJS, ie to lazy load modules by wrapping import calls inside a callback.
For example: Middleware of AdonisJS allows registering middleware as an array of import calls.
defineMiddleware([() => import('#middleware/silent_auth')])defineMiddleware({auth: () => import('#middleware/auth')})Behind the scenes, we have to run following operations in order to call the handle method on the defined middleware.
- Lazily call the registered callbacks to import the middleware. - Check if the module has a default export. - Create an instance of the default export class using the container. - Call the
handle
method on the middleware class using the container.
Classes
class Container
class Container<KnownBindings extends Record<any, any>> {}
The container class exposes the API to register bindings, values and resolve them.
Known bindings types can be defined at the time of the constructing the container.
new Container<{ 'route': Route, encryption: Encryption }>()You can resolve bindings and construct classes as follows
await container.make(BINDING_NAME)await container.make(CLASS_CONSTRUCTOR)
constructor
constructor(options?: ContainerOptions);
method alias
alias: <Alias extends keyof KnownBindings>( alias: Alias extends string | symbol ? Alias : never, value: | AbstractConstructor<KnownBindings[Alias]> | Exclude< { [K in keyof KnownBindings]: KnownBindings[K] extends KnownBindings[Alias] ? K : never; }[keyof KnownBindings], Alias >) => void;
Register an alias for a binding. The value can be a reference to an existing binding or to a class constructor that will instantiate to the same value as the alias.
method bind
bind: { <Binding extends keyof KnownBindings>( binding: Binding extends string | symbol ? Binding : never, resolver: BindingResolver<KnownBindings, KnownBindings[Binding]> ): void; <Binding extends AbstractConstructor<any>>( binding: Binding, resolver: BindingResolver<KnownBindings, InstanceType<Binding>> ): void;};
Register a binding inside the container. The method receives a key-value pair.
- Key can be a string, symbol or a constructor. - The value is always a factory function to construct the dependency.
container.bind('route', () => new Route())await container.make('route')container.bind(Route, () => new Route())await container.make(Route)const routeSymbol = Symbol('route')container.bind(routeSymbol, () => new Route())await container.make(routeSymbol)
method bindValue
bindValue: { <Binding extends keyof KnownBindings>( binding: Binding extends string | symbol ? Binding : never, value: KnownBindings[Binding] ): void; <Binding extends AbstractConstructor<any>>( binding: Binding, value: InstanceType<Binding> ): void;};
Register a binding as a value
container.bindValue(Route, new Route())
method call
call: <Value extends Record<any, any>, Method extends ExtractFunctions<Value>>( value: Value, method: Method, runtimeValues?: any[], createError?: ErrorCreator) => Promise<ReturnType<Value[Method]>>;
Call a method on an object by injecting its dependencies. The method dependencies are resolved in the same manner as a class constructor dependencies.
await container.call(await container.make(UsersController), 'index')
method contextualBinding
contextualBinding: <Binding extends AbstractConstructor<any>>( parent: Constructor<any>, binding: Binding, resolver: BindingResolver<KnownBindings, Make<Binding>>) => void;
Add a contextual binding for a given class constructor. A contextual takes a parent, parent's dependency and a callback to self resolve the dependency.
For example: - When "UsersController" - Asks for "Hash class" - Provide "Argon2" implementation
method createResolver
createResolver: () => ContainerResolver<KnownBindings>;
Create a container resolver to resolve bindings, or make classes.
const resolver = container.createResolver()await resolver.make(CLASS_CONSTRUCTOR)Bind values with the resolver. Resolver values are isolated from the container.
resolver.bindValue(HttpContext, new HttpContext())await resolver.make(UsersController)
method hasAllBindings
hasAllBindings: { <Binding extends keyof KnownBindings>(bindings: Binding[]): boolean; (binding: BindingKey[]): boolean;};
Find if the container has all the bindings registered using the "bind", the "singleton", or the "bindValue" methods.
method hasBinding
hasBinding: { <Binding extends keyof KnownBindings>(binding: Binding): boolean; (binding: BindingKey): boolean;};
Find if the container has a binding registered using the "bind", the "singleton", or the "bindValue" methods.
method make
make: { <Binding extends keyof KnownBindings>( binding: Binding, runtimeValues?: any[], createError?: ErrorCreator ): Promise< Binding extends string | symbol ? KnownBindings[Binding] : Make<Binding> >; <Binding>( binding: Binding, runtimeValues?: any[], createError?: ErrorCreator ): Promise<Make<Binding>>;};
Resolves the binding or constructor a class instance as follows.
- Resolve the binding from the values (if registered) - Resolve the binding from the bindings (if registered) - If binding is a class, then create a instance of it. The constructor dependencies are further resolved as well. - All other values are returned as it is.
await container.make('route')await container.make(Database)
method resolving
resolving: { <Binding extends keyof KnownBindings>( binding: Binding extends string | symbol ? Binding : never, callback: HookCallback<KnownBindings, KnownBindings[Binding]> ): void; <Binding extends AbstractConstructor<any>>( binding: Binding, callback: HookCallback<KnownBindings, InstanceType<Binding>> ): void;};
Define hooks to be executed after a binding has been resolved from the container.
The hooks are executed for
- Bindings - Only once for singletons - And class constructor
In other words, the hooks are not executed for direct values registered with the container
method restore
restore: (binding: AbstractConstructor<any>) => void;
Restore binding by removing its swap
method restoreAll
restoreAll: (bindings?: AbstractConstructor<any>[]) => void;
Restore mentioned or all bindings by removing their swaps
method singleton
singleton: { <Binding extends keyof KnownBindings>( binding: Binding extends string | symbol ? Binding : never, resolver: BindingResolver<KnownBindings, KnownBindings[Binding]> ): void; <Binding extends AbstractConstructor<any>>( binding: Binding, resolver: BindingResolver<KnownBindings, InstanceType<Binding>> ): void;};
Register a binding as a single. The singleton method is same as the bind method, but the factory function is invoked only once.
container.singleton('route', () => new Route())await container.make('route')container.singleton(Route, () => new Route())await container.make(Route)const routeSymbol = Symbol('route')container.singleton(routeSymbol, () => new Route())await container.make(routeSymbol)
method swap
swap: <Binding extends AbstractConstructor<any>>( binding: Binding, resolver: BindingResolver<KnownBindings, InstanceType<Binding>>) => void;
Define a fake implementation for a binding or a class constructor. Fakes have the highest priority when resolving dependencies from the container.
method useEmitter
useEmitter: (emitter: Exclude<ContainerOptions['emitter'], undefined>) => this;
Define an emitter instance to use
method when
when: ( parent: Constructor<any>) => ContextBindingsBuilder<KnownBindings, AbstractConstructor<any>>;
Create a contextual builder to define contextual bindings
class ContainerResolver
class ContainerResolver<KnownBindings extends Record<any, any>> {}
Container resolver exposes the APIs to resolve bindings. You can think of resolver as an isolated container instance, with only the APIs to resolve bindings.
const container = new Container()const resolver = container.createResolver()await resolver.make(BINDING_NAME)await resolver.make(CLASS_CONSTRUCTOR)
constructor
constructor( container: { bindings: Bindings; bindingValues: BindingValues; swaps: Swaps; hooks: Hooks; aliases: Map< Partial<keyof KnownBindings>, keyof KnownBindings | AbstractConstructor<any> >; contextualBindings: Map<Constructor<any>, ContextualBindings>; }, options: ContainerOptions);
method bindValue
bindValue: { <Binding extends keyof KnownBindings>( binding: Binding extends string | symbol ? Binding : never, value: KnownBindings[Binding] ): void; <Binding extends AbstractConstructor<any>>( binding: Binding, value: InstanceType<Binding> ): void;};
Register a binding as a value
container.bindValue(Route, new Route())
method call
call: <Value extends Record<any, any>, Method extends ExtractFunctions<Value>>( value: Value, method: Method, runtimeValues?: any[], createError?: ErrorCreator) => Promise<ReturnType<Value[Method]>>;
Call a method on an object by injecting its dependencies. The method dependencies are resolved in the same manner as a class constructor dependencies.
await resolver.call(await resolver.make(UsersController), 'index')
method hasAllBindings
hasAllBindings: { <Binding extends keyof KnownBindings>(bindings: Binding[]): boolean; (bindings: BindingKey[]): boolean;};
Find if the resolver has all the bindings registered using the "bind", the "singleton", or the "bindValue" methods.
method hasBinding
hasBinding: { <Binding extends keyof KnownBindings>(binding: Binding): boolean; (binding: BindingKey): boolean;};
Find if the resolver has a binding registered using the "bind", the "singleton", or the "bindValue" methods.
method make
make: { <Binding extends keyof KnownBindings>( binding: Binding, runtimeValues?: any[], createError?: ErrorCreator ): Promise< Binding extends string | symbol ? KnownBindings[Binding] : Make<Binding> >; <Binding>( binding: Binding, runtimeValues?: any[], createError?: ErrorCreator ): Promise<Make<Binding>>;};
Resolves the binding or constructor a class instance as follows.
- Resolve the binding from the values (if registered) - Resolve the binding from the bindings (if registered) - If binding is a class, then create a instance of it. The constructor dependencies are further resolved as well. - All other values are returned as it is.
await resolver.make('route')await resolver.make(Database)
method resolveFor
resolveFor: <Binding>( parent: unknown, binding: Binding, runtimeValues?: any[], createError?: ErrorCreator) => Promise<Make<Binding>>;
Resolves binding in context of a parent. The method is same as the "make" method, but instead takes a parent class constructor.
Package Files (7)
Dependencies (1)
Dev Dependencies (25)
- @adonisjs/eslint-config
- @adonisjs/prettier-config
- @adonisjs/tsconfig
- @commitlint/cli
- @commitlint/config-conventional
- @japa/assert
- @japa/file-system
- @japa/runner
- @swc/core
- @types/node
- benchmark
- c8
- cross-env
- del-cli
- eslint
- expect-type
- github-label-sync
- husky
- p-event
- prettier
- reflect-metadata
- release-it
- ts-node
- tsup
- typescript
Peer Dependencies (0)
No peer dependencies.
Badge
To add a badge like this oneto your package's README, use the codes available below.
You may also use Shields.io to create a custom badge linking to https://www.jsdocs.io/package/@adonisjs/fold
.
- Markdown[![jsDocs.io](https://img.shields.io/badge/jsDocs.io-reference-blue)](https://www.jsdocs.io/package/@adonisjs/fold)
- HTML<a href="https://www.jsdocs.io/package/@adonisjs/fold"><img src="https://img.shields.io/badge/jsDocs.io-reference-blue" alt="jsDocs.io"></a>
- Updated .
Package analyzed in 3557 ms. - Missing or incorrect documentation? Open an issue for this package.