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

@wessberg/di

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wessberg/di - npm Package Compare versions

Comparing version 2.0.3 to 2.1.0

129

dist/cjs/index.d.ts

@@ -1,7 +0,122 @@

export { ConstructorArgument } from "./constructor-arguments/constructor-argument";
export { IGetOptions } from "./get-options/i-get-options";
export { RegisterOptions } from "./register-options/i-register-options";
export { IHasOptions } from "./has-options/i-has-options";
export { DIContainer } from "./di-container/di-container";
export { IDIContainer } from "./di-container/i-di-container";
export { CONSTRUCTOR_ARGUMENTS_SYMBOL, CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER } from "./constructor-arguments/constructor-arguments-identifier";
declare const CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = "___CTOR_ARGS___";
declare const CONSTRUCTOR_ARGUMENTS_SYMBOL: unique symbol;
type ConstructorArgument = string | undefined;
interface IWithConstructorArgumentsSymbol {
[CONSTRUCTOR_ARGUMENTS_SYMBOL]?: ConstructorArgument[];
}
interface IContainerIdentifierable {
identifier: string;
}
interface IGetOptions extends IContainerIdentifierable {
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type NewableService<T> = new (...args: any[]) => T;
/* eslint-disable @typescript-eslint/no-explicit-any */
type CustomConstructableService<T> = (...args: any[]) => T;
type Implementation<T> = NewableService<T> & IWithConstructorArgumentsSymbol;
type ImplementationInstance<T> = CustomConstructableService<T> & IWithConstructorArgumentsSymbol;
interface IRegisterOptionsBase extends IContainerIdentifierable {
}
interface IRegisterOptionsWithImplementation<T> extends IRegisterOptionsBase {
implementation: Implementation<T> | null;
}
interface IRegisterOptionsWithoutImplementation extends IRegisterOptionsBase {
}
type RegisterOptions<T> = IRegisterOptionsWithImplementation<T> | IRegisterOptionsWithoutImplementation;
interface IHasOptions extends IContainerIdentifierable {
}
interface IDIContainer {
registerSingleton<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
registerSingleton<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerSingleton<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
registerTransient<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
registerTransient<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerTransient<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
get<T>(options?: IGetOptions): T;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
has<T>(options?: IHasOptions): boolean;
}
/**
* A Dependency-Injection container that holds services and can produce instances of them as required.
* It mimics reflection by parsing the app at compile-time and supporting the generic-reflection syntax.
* @author Frederik Wessberg
*/
declare class DIContainer implements IDIContainer {
/**
* A map between interface names and the services that should be dependency injected
*/
private readonly constructorArguments;
/**
* A Map between identifying names for services and their IRegistrationRecords.
*/
private readonly serviceRegistry;
/**
* A map between identifying names for services and concrete instances of their implementation.
*/
private readonly instances;
/**
* Registers a service that will be instantiated once in the application lifecycle. All requests
* for the service will retrieve the same instance of it.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
registerSingleton<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerSingleton<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
registerSingleton<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
/**
* Registers a service that will be instantiated every time it is requested throughout the application lifecycle.
* This means that every call to get() will return a unique instance of the service.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
registerTransient<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerTransient<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
registerTransient<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
/**
* Gets an instance of the service matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
get<T>(options?: IGetOptions): T;
/**
* Returns true if a service has been registered matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
has<T>(options?: IHasOptions): boolean;
/**
* Registers a service
*/
private register;
/**
* Returns true if an instance exists that matches the given identifier.
*/
private hasInstance;
/**
* Gets the cached instance, if any, associated with the given identifier.
*/
private getInstance;
/**
* Gets an IRegistrationRecord associated with the given identifier.
*/
private getRegistrationRecord;
/**
* Caches the given instance so that it can be retrieved in the future.
*/
private setInstance;
/**
* Gets a lazy reference to another service
*/
private getLazyIdentifier;
/**
* Constructs a new instance of the given identifier and returns it.
* It checks the constructor arguments and injects any services it might depend on recursively.
*/
private constructInstance;
}
export { ConstructorArgument, IGetOptions, RegisterOptions, IHasOptions, DIContainer, IDIContainer, CONSTRUCTOR_ARGUMENTS_SYMBOL, CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER };

@@ -1,8 +0,201 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var di_container_1 = require("./di-container/di-container");
exports.DIContainer = di_container_1.DIContainer;
var constructor_arguments_identifier_1 = require("./constructor-arguments/constructor-arguments-identifier");
exports.CONSTRUCTOR_ARGUMENTS_SYMBOL = constructor_arguments_identifier_1.CONSTRUCTOR_ARGUMENTS_SYMBOL;
exports.CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = constructor_arguments_identifier_1.CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER;
//# sourceMappingURL=index.js.map
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = `___CTOR_ARGS___`;
const CONSTRUCTOR_ARGUMENTS_SYMBOL = Symbol.for(CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER);
/**
* A Dependency-Injection container that holds services and can produce instances of them as required.
* It mimics reflection by parsing the app at compile-time and supporting the generic-reflection syntax.
* @author Frederik Wessberg
*/
class DIContainer {
/**
* A map between interface names and the services that should be dependency injected
*/
constructorArguments = new Map();
/**
* A Map between identifying names for services and their IRegistrationRecords.
*/
serviceRegistry = new Map();
/**
* A map between identifying names for services and concrete instances of their implementation.
*/
instances = new Map();
registerSingleton(newExpression, options) {
if (options == null) {
throw new ReferenceError(`2 arguments required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
if (newExpression == null) {
return this.register("SINGLETON", newExpression, options);
}
else {
return this.register("SINGLETON", newExpression, options);
}
}
registerTransient(newExpression, options) {
if (options == null) {
throw new ReferenceError(`2 arguments required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
if (newExpression == null) {
return this.register("TRANSIENT", newExpression, options);
}
else {
return this.register("TRANSIENT", newExpression, options);
}
}
/**
* Gets an instance of the service matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
get(options) {
if (options == null) {
throw new ReferenceError(`1 argument required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
return this.constructInstance(options);
}
/**
* Returns true if a service has been registered matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
has(options) {
if (options == null) {
throw new ReferenceError(`1 argument required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
return this.serviceRegistry.has(options.identifier);
}
register(kind, newExpression, options) {
// Take all of the constructor arguments for the implementation
const implementationArguments = "implementation" in options &&
options.implementation != null &&
options.implementation[CONSTRUCTOR_ARGUMENTS_SYMBOL] != null
? options.implementation[CONSTRUCTOR_ARGUMENTS_SYMBOL]
: [];
this.constructorArguments.set(options.identifier, implementationArguments);
this.serviceRegistry.set(options.identifier, "implementation" in options && options.implementation != null
? { ...options, kind }
: { ...options, kind, newExpression: newExpression });
}
/**
* Returns true if an instance exists that matches the given identifier.
*/
hasInstance(identifier) {
return this.getInstance(identifier) != null;
}
/**
* Gets the cached instance, if any, associated with the given identifier.
*/
getInstance(identifier) {
const instance = this.instances.get(identifier);
return instance == null ? null : instance;
}
/**
* Gets an IRegistrationRecord associated with the given identifier.
*/
getRegistrationRecord({ identifier, parentChain, }) {
const record = this.serviceRegistry.get(identifier);
if (record == null) {
throw new ReferenceError(`${this.constructor.name} could not find a service for identifier: "${identifier}". ${parentChain == null || parentChain.length < 1
? ""
: `It is required by the service: '${parentChain
.map((parent) => parent.identifier)
.join(" -> ")}'.`} Remember to register it as a service!`);
}
return record;
}
/**
* Caches the given instance so that it can be retrieved in the future.
*/
setInstance(identifier, instance) {
this.instances.set(identifier, instance);
return instance;
}
/**
* Gets a lazy reference to another service
*/
getLazyIdentifier(lazyPointer) {
return (new Proxy({}, { get: (_, key) => lazyPointer()[key] }));
}
/**
* Constructs a new instance of the given identifier and returns it.
* It checks the constructor arguments and injects any services it might depend on recursively.
*/
constructInstance({ identifier, parentChain = [], }) {
const registrationRecord = this.getRegistrationRecord({
identifier,
parentChain,
});
// If an instance already exists (and it is a singleton), return that one
if (this.hasInstance(identifier) &&
registrationRecord.kind === "SINGLETON") {
return this.getInstance(identifier);
}
// Otherwise, instantiate a new one
let instance;
const me = {
identifier,
ref: this.getLazyIdentifier(() => instance),
};
// If a user-provided new-expression has been provided, invoke that to get an instance.
if ("newExpression" in registrationRecord) {
if (typeof registrationRecord.newExpression !== "function") {
throw new TypeError(`Could not instantiate the service with the identifier: '${registrationRecord.identifier}': You provided a custom instantiation argument, but it wasn't of type function. It has to be a function that returns whatever should be used as an instance of the Service!`);
}
try {
instance = registrationRecord.newExpression();
}
catch (ex) {
throw new Error(`Could not instantiate the service with the identifier: '${registrationRecord.identifier}': When you registered the service, you provided a custom instantiation function, but it threw an exception when it was run!`);
}
}
else {
// Find the arguments for the identifier
const mappedArgs = this.constructorArguments.get(identifier);
if (mappedArgs == null) {
throw new ReferenceError(`${this.constructor.name} could not find constructor arguments for the service: '${identifier}'. Have you registered it as a service?`);
}
// Instantiate all of the argument services (or re-use them if they were registered as singletons)
const instanceArgs = mappedArgs.map((dep) => {
if (dep === undefined)
return undefined;
const matchedParent = parentChain.find((parent) => parent.identifier === dep);
if (matchedParent != null)
return matchedParent.ref;
return this.constructInstance({
identifier: dep,
parentChain: [...parentChain, me],
});
});
try {
// Try to construct an instance with 'new' and if it fails, call the implementation directly.
const newable = registrationRecord.implementation;
instance = new newable(...instanceArgs);
}
catch (ex) {
if (registrationRecord.implementation == null) {
throw new ReferenceError(`${this.constructor.name} could not construct a new service of kind: ${identifier}. Reason: No implementation was given!`);
}
const constructable = registrationRecord.implementation;
// Try without 'new' and call the implementation as a function.
instance = constructable(...instanceArgs);
}
}
return registrationRecord.kind === "SINGLETON"
? this.setInstance(identifier, instance)
: instance;
}
}
const DI_COMPILER_ERROR_HINT = `Note: You must use DI-Compiler (https://github.com/wessberg/di-compiler) for this library to work correctly. Please consult the readme for instructions on how to install and configure it for your project.`;
exports.CONSTRUCTOR_ARGUMENTS_SYMBOL = CONSTRUCTOR_ARGUMENTS_SYMBOL;
exports.CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER;
exports.DIContainer = DIContainer;
//# sourceMappingURL=index.js.map

@@ -1,7 +0,122 @@

export { ConstructorArgument } from "./constructor-arguments/constructor-argument";
export { IGetOptions } from "./get-options/i-get-options";
export { RegisterOptions } from "./register-options/i-register-options";
export { IHasOptions } from "./has-options/i-has-options";
export { DIContainer } from "./di-container/di-container";
export { IDIContainer } from "./di-container/i-di-container";
export { CONSTRUCTOR_ARGUMENTS_SYMBOL, CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER } from "./constructor-arguments/constructor-arguments-identifier";
declare const CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = "___CTOR_ARGS___";
declare const CONSTRUCTOR_ARGUMENTS_SYMBOL: unique symbol;
type ConstructorArgument = string | undefined;
interface IWithConstructorArgumentsSymbol {
[CONSTRUCTOR_ARGUMENTS_SYMBOL]?: ConstructorArgument[];
}
interface IContainerIdentifierable {
identifier: string;
}
interface IGetOptions extends IContainerIdentifierable {
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type NewableService<T> = new (...args: any[]) => T;
/* eslint-disable @typescript-eslint/no-explicit-any */
type CustomConstructableService<T> = (...args: any[]) => T;
type Implementation<T> = NewableService<T> & IWithConstructorArgumentsSymbol;
type ImplementationInstance<T> = CustomConstructableService<T> & IWithConstructorArgumentsSymbol;
interface IRegisterOptionsBase extends IContainerIdentifierable {
}
interface IRegisterOptionsWithImplementation<T> extends IRegisterOptionsBase {
implementation: Implementation<T> | null;
}
interface IRegisterOptionsWithoutImplementation extends IRegisterOptionsBase {
}
type RegisterOptions<T> = IRegisterOptionsWithImplementation<T> | IRegisterOptionsWithoutImplementation;
interface IHasOptions extends IContainerIdentifierable {
}
interface IDIContainer {
registerSingleton<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
registerSingleton<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerSingleton<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
registerTransient<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
registerTransient<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerTransient<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
get<T>(options?: IGetOptions): T;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
has<T>(options?: IHasOptions): boolean;
}
/**
* A Dependency-Injection container that holds services and can produce instances of them as required.
* It mimics reflection by parsing the app at compile-time and supporting the generic-reflection syntax.
* @author Frederik Wessberg
*/
declare class DIContainer implements IDIContainer {
/**
* A map between interface names and the services that should be dependency injected
*/
private readonly constructorArguments;
/**
* A Map between identifying names for services and their IRegistrationRecords.
*/
private readonly serviceRegistry;
/**
* A map between identifying names for services and concrete instances of their implementation.
*/
private readonly instances;
/**
* Registers a service that will be instantiated once in the application lifecycle. All requests
* for the service will retrieve the same instance of it.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
registerSingleton<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerSingleton<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
registerSingleton<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
/**
* Registers a service that will be instantiated every time it is requested throughout the application lifecycle.
* This means that every call to get() will return a unique instance of the service.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
registerTransient<T, U extends T = T>(newExpression: ImplementationInstance<U>, options: IRegisterOptionsWithoutImplementation): void;
registerTransient<T, U extends T = T>(newExpression: undefined, options: IRegisterOptionsWithImplementation<U>): void;
registerTransient<T, U extends T = T>(newExpression?: ImplementationInstance<U> | undefined, options?: RegisterOptions<U>): void;
/**
* Gets an instance of the service matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
get<T>(options?: IGetOptions): T;
/**
* Returns true if a service has been registered matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
has<T>(options?: IHasOptions): boolean;
/**
* Registers a service
*/
private register;
/**
* Returns true if an instance exists that matches the given identifier.
*/
private hasInstance;
/**
* Gets the cached instance, if any, associated with the given identifier.
*/
private getInstance;
/**
* Gets an IRegistrationRecord associated with the given identifier.
*/
private getRegistrationRecord;
/**
* Caches the given instance so that it can be retrieved in the future.
*/
private setInstance;
/**
* Gets a lazy reference to another service
*/
private getLazyIdentifier;
/**
* Constructs a new instance of the given identifier and returns it.
* It checks the constructor arguments and injects any services it might depend on recursively.
*/
private constructInstance;
}
export { ConstructorArgument, IGetOptions, RegisterOptions, IHasOptions, DIContainer, IDIContainer, CONSTRUCTOR_ARGUMENTS_SYMBOL, CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER };

@@ -1,3 +0,195 @@

export { DIContainer } from "./di-container/di-container";
export { CONSTRUCTOR_ARGUMENTS_SYMBOL, CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER } from "./constructor-arguments/constructor-arguments-identifier";
//# sourceMappingURL=index.js.map
const CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER = `___CTOR_ARGS___`;
const CONSTRUCTOR_ARGUMENTS_SYMBOL = Symbol.for(CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER);
/**
* A Dependency-Injection container that holds services and can produce instances of them as required.
* It mimics reflection by parsing the app at compile-time and supporting the generic-reflection syntax.
* @author Frederik Wessberg
*/
class DIContainer {
/**
* A map between interface names and the services that should be dependency injected
*/
constructorArguments = new Map();
/**
* A Map between identifying names for services and their IRegistrationRecords.
*/
serviceRegistry = new Map();
/**
* A map between identifying names for services and concrete instances of their implementation.
*/
instances = new Map();
registerSingleton(newExpression, options) {
if (options == null) {
throw new ReferenceError(`2 arguments required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
if (newExpression == null) {
return this.register("SINGLETON", newExpression, options);
}
else {
return this.register("SINGLETON", newExpression, options);
}
}
registerTransient(newExpression, options) {
if (options == null) {
throw new ReferenceError(`2 arguments required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
if (newExpression == null) {
return this.register("TRANSIENT", newExpression, options);
}
else {
return this.register("TRANSIENT", newExpression, options);
}
}
/**
* Gets an instance of the service matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
get(options) {
if (options == null) {
throw new ReferenceError(`1 argument required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
return this.constructInstance(options);
}
/**
* Returns true if a service has been registered matching the interface given as a generic type parameter.
* For example, 'container.get<IFoo>()' returns a concrete instance of the implementation associated with the
* generic interface name.
*
* You should not pass any options to the method if using the compiler. It will do that automatically.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
has(options) {
if (options == null) {
throw new ReferenceError(`1 argument required, but only 0 present. ${DI_COMPILER_ERROR_HINT}`);
}
return this.serviceRegistry.has(options.identifier);
}
register(kind, newExpression, options) {
// Take all of the constructor arguments for the implementation
const implementationArguments = "implementation" in options &&
options.implementation != null &&
options.implementation[CONSTRUCTOR_ARGUMENTS_SYMBOL] != null
? options.implementation[CONSTRUCTOR_ARGUMENTS_SYMBOL]
: [];
this.constructorArguments.set(options.identifier, implementationArguments);
this.serviceRegistry.set(options.identifier, "implementation" in options && options.implementation != null
? { ...options, kind }
: { ...options, kind, newExpression: newExpression });
}
/**
* Returns true if an instance exists that matches the given identifier.
*/
hasInstance(identifier) {
return this.getInstance(identifier) != null;
}
/**
* Gets the cached instance, if any, associated with the given identifier.
*/
getInstance(identifier) {
const instance = this.instances.get(identifier);
return instance == null ? null : instance;
}
/**
* Gets an IRegistrationRecord associated with the given identifier.
*/
getRegistrationRecord({ identifier, parentChain, }) {
const record = this.serviceRegistry.get(identifier);
if (record == null) {
throw new ReferenceError(`${this.constructor.name} could not find a service for identifier: "${identifier}". ${parentChain == null || parentChain.length < 1
? ""
: `It is required by the service: '${parentChain
.map((parent) => parent.identifier)
.join(" -> ")}'.`} Remember to register it as a service!`);
}
return record;
}
/**
* Caches the given instance so that it can be retrieved in the future.
*/
setInstance(identifier, instance) {
this.instances.set(identifier, instance);
return instance;
}
/**
* Gets a lazy reference to another service
*/
getLazyIdentifier(lazyPointer) {
return (new Proxy({}, { get: (_, key) => lazyPointer()[key] }));
}
/**
* Constructs a new instance of the given identifier and returns it.
* It checks the constructor arguments and injects any services it might depend on recursively.
*/
constructInstance({ identifier, parentChain = [], }) {
const registrationRecord = this.getRegistrationRecord({
identifier,
parentChain,
});
// If an instance already exists (and it is a singleton), return that one
if (this.hasInstance(identifier) &&
registrationRecord.kind === "SINGLETON") {
return this.getInstance(identifier);
}
// Otherwise, instantiate a new one
let instance;
const me = {
identifier,
ref: this.getLazyIdentifier(() => instance),
};
// If a user-provided new-expression has been provided, invoke that to get an instance.
if ("newExpression" in registrationRecord) {
if (typeof registrationRecord.newExpression !== "function") {
throw new TypeError(`Could not instantiate the service with the identifier: '${registrationRecord.identifier}': You provided a custom instantiation argument, but it wasn't of type function. It has to be a function that returns whatever should be used as an instance of the Service!`);
}
try {
instance = registrationRecord.newExpression();
}
catch (ex) {
throw new Error(`Could not instantiate the service with the identifier: '${registrationRecord.identifier}': When you registered the service, you provided a custom instantiation function, but it threw an exception when it was run!`);
}
}
else {
// Find the arguments for the identifier
const mappedArgs = this.constructorArguments.get(identifier);
if (mappedArgs == null) {
throw new ReferenceError(`${this.constructor.name} could not find constructor arguments for the service: '${identifier}'. Have you registered it as a service?`);
}
// Instantiate all of the argument services (or re-use them if they were registered as singletons)
const instanceArgs = mappedArgs.map((dep) => {
if (dep === undefined)
return undefined;
const matchedParent = parentChain.find((parent) => parent.identifier === dep);
if (matchedParent != null)
return matchedParent.ref;
return this.constructInstance({
identifier: dep,
parentChain: [...parentChain, me],
});
});
try {
// Try to construct an instance with 'new' and if it fails, call the implementation directly.
const newable = registrationRecord.implementation;
instance = new newable(...instanceArgs);
}
catch (ex) {
if (registrationRecord.implementation == null) {
throw new ReferenceError(`${this.constructor.name} could not construct a new service of kind: ${identifier}. Reason: No implementation was given!`);
}
const constructable = registrationRecord.implementation;
// Try without 'new' and call the implementation as a function.
instance = constructable(...instanceArgs);
}
}
return registrationRecord.kind === "SINGLETON"
? this.setInstance(identifier, instance)
: instance;
}
}
const DI_COMPILER_ERROR_HINT = `Note: You must use DI-Compiler (https://github.com/wessberg/di-compiler) for this library to work correctly. Please consult the readme for instructions on how to install and configure it for your project.`;
export { CONSTRUCTOR_ARGUMENTS_SYMBOL, CONSTRUCTOR_ARGUMENTS_SYMBOL_IDENTIFIER, DIContainer };
//# sourceMappingURL=index.js.map

4

LICENSE.md
The MIT License (MIT)
Copyright © 2018 Frederik Wessberg <frederikwessberg@hotmail.com>
Copyright © 2022 [Frederik Wessberg](mailto:frederikwessberg@hotmail.com) ([@FredWessberg](https://twitter.com/FredWessberg)) ([Website](https://github.com/wessberg))

@@ -21,2 +21,2 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
SOFTWARE
{
"name": "@wessberg/di",
"version": "2.0.3",
"description": "A compile-time powered Dependency-Injection container for Typescript that holds services and can produce instances of them as required.",
"scripts": {
"generate:readme": "scaffold readme",
"generate:license": "scaffold license",
"generate:contributing": "scaffold contributing",
"generate:coc": "scaffold coc",
"generate:all": "npm run generate:license & npm run generate:contributing & npm run generate:coc & npm run generate:readme",
"update": "ncu -ua && npm update && npm install",
"lint": "tsc --noEmit && tslint -c tslint.json --project tsconfig.json",
"clean:dist": "rm -rf dist",
"clean:compiled": "rm -rf compiled",
"clean": "npm run clean:dist && npm run clean:compiled",
"tsc:cjs": "tsc --module commonjs --outDir dist/cjs -p tsconfig.dist.json",
"tsc:esm": "tsc --module es2015 --outDir dist/esm -p tsconfig.dist.json",
"prebuild": "npm run clean:dist",
"build": "npm run tsc:cjs & npm run tsc:esm",
"validate": "npm run lint",
"prepare": "npm run build",
"beforepublish": "NODE_ENV=production npm run lint && NODE_ENV=production npm run prepare && npm run generate:all && git commit -am \"Bumped version\" || true",
"publish:patch": "npm run beforepublish && npm version patch && git push && npm publish",
"publish:minor": "npm run beforepublish && npm version minor && git push && npm publish",
"publish:major": "npm run beforepublish && npm version major && git push && npm publish"
},
"keywords": [
"DI",
"dependency injection",
"ioc",
"inversion",
"service",
"container",
"newable",
"reflection",
"singleton",
"transient"
],
"devDependencies": {
"@wessberg/ts-config": "^0.0.30",
"@wessberg/scaffold": "^1.0.4",
"tslint": "^5.11.0",
"typescript": "^3.1.6"
},
"dependencies": {
"tslib": "^1.9.3"
},
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"browser": "./dist/esm/index.js",
"types": "./dist/esm/index.d.ts",
"typings": "./dist/esm/index.d.ts",
"es2015": "./dist/esm/index.js",
"repository": {
"type": "git",
"url": "https://github.com/wessberg/di.git"
},
"bugs": {
"url": "https://github.com/wessberg/di/issues"
},
"author": {
"name": "Frederik Wessberg",
"email": "frederikwessberg@hotmail.com",
"url": "https://github.com/wessberg"
},
"engines": {
"node": ">=9.0.0"
},
"license": "MIT",
"files": [
"dist/**/*.*"
],
"scaffold": {
"patreonUserId": "11315442",
"logo": "https://raw.githubusercontent.com/wessberg/di/master/documentation/asset/di-logo.png",
"contributorMeta": {
"Frederik Wessberg": {
"imageUrl": "https://avatars2.githubusercontent.com/u/20454213?s=460&v=4",
"role": "Maintainer",
"twitterHandle": "FredWessberg",
"isCocEnforcer": true
}
},
"backers": []
}
"name": "@wessberg/di",
"version": "2.1.0",
"description": "A compile-time powered Dependency-Injection container for Typescript that holds services and can produce instances of them as required.",
"scripts": {
"generate:sandhog": "sandhog all --yes",
"generate:changelog": "standard-changelog --first-release",
"generate:all": "pnpm run generate:sandhog && pnpm run generate:changelog",
"clean": "rimraf dist",
"lint": "tsc --noEmit && eslint \"src/**/*.ts\" --color",
"prettier": "prettier --write \"{src,test,documentation}/**/*.{js,ts,json,html,xml,css,md}\"",
"prebuild": "pnpm run clean",
"build": "pnpm run prebuild && pnpm run rollup",
"prewatch": "pnpm run clean",
"watch": "pnpm run prewatch && pnpm run rollup -- --watch",
"rollup": "rollup -c rollup.config.js",
"preversion": "pnpm run lint && pnpm run build",
"version": "pnpm run preversion && pnpm run generate:all && git add .",
"release": "np --no-cleanup --no-yarn --no-tests",
"update:check": "pnpx npm-check-updates -x typescript-* --dep dev,prod",
"update:commit": "pnpx npm-check-updates -u -x typescript-* --dep dev,prod && pnpm update && pnpm install"
},
"keywords": [
"DI",
"dependency injection",
"ioc",
"inversion",
"service",
"container",
"newable",
"reflection",
"singleton",
"transient"
],
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"@wessberg/ts-config": "^2.0.0",
"rollup-plugin-ts": "^2.0.5",
"typescript": "4.6.3",
"tslib": "^2.3.1",
"npm-check-updates": "^12.5.8",
"sandhog": "^1.0.43",
"standard-changelog": "^2.0.27",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^38.1.6",
"husky": "^7.0.4",
"np": "^7.6.1",
"pnpm": "^6.32.4",
"prettier": "^2.6.2",
"pretty-quick": "^3.1.3",
"rimraf": "^3.0.2",
"rollup": "^2.70.1"
},
"dependencies": {},
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"browser": "./dist/esm/index.js",
"types": "./dist/esm/index.d.ts",
"typings": "./dist/esm/index.d.ts",
"es2015": "./dist/esm/index.js",
"repository": {
"type": "git",
"url": "https://github.com/wessberg/di.git"
},
"bugs": {
"url": "https://github.com/wessberg/di/issues"
},
"contributors": [
{
"name": "Frederik Wessberg",
"email": "frederikwessberg@hotmail.com",
"url": "https://github.com/wessberg",
"imageUrl": "https://avatars2.githubusercontent.com/u/20454213?s=460&v=4",
"role": "Lead Developer",
"twitter": "FredWessberg",
"github": "wessberg"
}
],
"engines": {
"node": ">=9.0.0"
},
"license": "MIT",
"files": [
"dist/**/*.*"
]
}

@@ -1,15 +0,30 @@

<img alt="Logo for @wessberg/di" src="https://raw.githubusercontent.com/wessberg/di/master/documentation/asset/di-logo.png" height="200"></img><br>
<a href="https://npmcharts.com/compare/@wessberg/di?minimal=true"><img alt="Downloads per month" src="https://img.shields.io/npm/dm/%40wessberg%2Fdi.svg" height="20"></img></a>
<a href="https://david-dm.org/wessberg/di"><img alt="Dependencies" src="https://img.shields.io/david/wessberg/di.svg" height="20"></img></a>
<a href="https://www.npmjs.com/package/@wessberg/di"><img alt="NPM Version" src="https://badge.fury.io/js/%40wessberg%2Fdi.svg" height="20"></img></a>
<a href="https://github.com/wessberg/di/graphs/contributors"><img alt="Contributors" src="https://img.shields.io/github/contributors/wessberg%2Fdi.svg" height="20"></img></a>
<a href="https://opensource.org/licenses/MIT"><img alt="MIT License" src="https://img.shields.io/badge/License-MIT-yellow.svg" height="20"></img></a>
<a href="https://www.patreon.com/bePatron?u=11315442"><img alt="Support on Patreon" src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" height="20"></img></a>
<!-- SHADOW_SECTION_LOGO_START -->
# `@wessberg/di`
<div><img alt="Logo" src="https://raw.githubusercontent.com/wessberg/di/master/documentation/asset/di-logo.png" height="150" /></div>
<!-- SHADOW_SECTION_LOGO_END -->
<!-- SHADOW_SECTION_DESCRIPTION_SHORT_START -->
> A compile-time powered Dependency-Injection container for Typescript that holds services and can produce instances of them as required.
<!-- SHADOW_SECTION_DESCRIPTION_SHORT_END -->
<!-- SHADOW_SECTION_BADGES_START -->
<a href="https://npmcharts.com/compare/%40wessberg%2Fdi?minimal=true"><img alt="Downloads per month" src="https://img.shields.io/npm/dm/%40wessberg%2Fdi.svg" /></a>
<a href="https://www.npmjs.com/package/%40wessberg%2Fdi"><img alt="NPM version" src="https://badge.fury.io/js/%40wessberg%2Fdi.svg" /></a>
<a href="https://david-dm.org/wessberg/di"><img alt="Dependencies" src="https://img.shields.io/david/wessberg%2Fdi.svg" /></a>
<a href="https://github.com/wessberg/di/graphs/contributors"><img alt="Contributors" src="https://img.shields.io/github/contributors/wessberg%2Fdi.svg" /></a>
<a href="https://opensource.org/licenses/MIT"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg" /></a>
<a href="https://www.patreon.com/bePatron?u=11315442"><img alt="Support on Patreon" src="https://img.shields.io/badge/patreon-donate-green.svg" /></a>
<!-- SHADOW_SECTION_BADGES_END -->
<!-- SHADOW_SECTION_DESCRIPTION_LONG_START -->
## Description
<!-- SHADOW_SECTION_DESCRIPTION_LONG_END -->
This is a tiny library that brings Dependency-Injection to Typescript. There are several competing libraries out there, but this one is unique in the sense

@@ -28,5 +43,47 @@ that:

<!-- SHADOW_SECTION_BACKERS_START -->
## Backers
| <a href="https://usebubbles.com"><img alt="Bubbles" src="https://uploads-ssl.webflow.com/5d682047c28b217055606673/5e5360be16879c1d0dca6514_icon-thin-128x128%402x.png" height="70" /></a> | <a href="https://github.com/cblanc"><img alt="Christopher Blanchard" src="https://avatars0.githubusercontent.com/u/2160685?s=400&v=4" height="70" /></a> | <a href="https://github.com/ideal-postcodes"><img alt="Ideal Postcodes" src="https://avatars.githubusercontent.com/u/4996310?s=200&v=4" height="70" /></a> | <a href="https://www.xerox.com"><img alt="Xerox" src="https://avatars.githubusercontent.com/u/9158512?s=200&v=4" height="70" /></a> | <a href="https://changelog.me"><img alt="Trent Raymond" src="https://avatars.githubusercontent.com/u/1509616?v=4" height="70" /></a> |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| [Bubbles](https://usebubbles.com)<br><strong>Twitter</strong>: [@usebubbles](https://twitter.com/usebubbles) | [Christopher Blanchard](https://github.com/cblanc) | [Ideal Postcodes](https://github.com/ideal-postcodes) | [Xerox](https://www.xerox.com) | [Trent Raymond](https://changelog.me) |
### Patreon
<a href="https://www.patreon.com/bePatron?u=11315442"><img alt="Patrons on Patreon" src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dwessberg%26type%3Dpatrons" width="200" /></a>
<!-- SHADOW_SECTION_BACKERS_END -->
<!-- SHADOW_SECTION_TOC_START -->
## Table of Contents
- [Description](#description)
- [Backers](#backers)
- [Patreon](#patreon)
- [Table of Contents](#table-of-contents)
- [Install](#install)
- [npm](#npm)
- [Yarn](#yarn)
- [pnpm](#pnpm)
- [Usage](#usage)
- [Registering services](#registering-services)
- [Retrieving instances of services](#retrieving-instances-of-services)
- [Injecting instances of services into classes](#injecting-instances-of-services-into-classes)
- [Getting instances directly from the `DIContainer`](#getting-instances-directly-from-the-dicontainer)
- [Contributing](#contributing)
- [Maintainers](#maintainers)
- [FAQ](#faq)
- [This is pure magic. How does it work?](#this-is-pure-magic-how-does-it-work)
- [Is it possible to have multiple, scoped containers?](#is-it-possible-to-have-multiple-scoped-containers)
- [License](#license)
<!-- SHADOW_SECTION_TOC_END -->
<!-- SHADOW_SECTION_INSTALL_START -->
## Install
### NPM
### npm

@@ -43,4 +100,16 @@ ```

### pnpm
```
$ pnpm add @wessberg/di
```
<!-- SHADOW_SECTION_INSTALL_END -->
<!-- SHADOW_SECTION_USAGE_START -->
## Usage
<!-- SHADOW_SECTION_USAGE_END -->
This library is meant to be super straightforward, super simple to use.

@@ -55,3 +124,3 @@ The following examples hopefully shows that:

```typescript
import {DIContainer} from "@wessberg/di";
import { DIContainer } from "@wessberg/di";

@@ -63,7 +132,7 @@ // Instantiate a new container for services

// the same instance of MyService will be injected
DIContainer.registerSingleton<IMyService, MyService>();
container.registerSingleton<IMyService, MyService>();
// Register the service as a Transient. Whenever the 'IMyService' service is requested,
// a new instance of MyService will be injected
DIContainer.registerTransient<IMyOtherService, MyOtherService>();
container.registerTransient<IMyOtherService, MyOtherService>();

@@ -73,6 +142,6 @@ // Rather than mapping a class to an interface,

// the required interface
DIContainer.registerSingleton<IAppConfig>(() => myAppConfig);
container.registerSingleton<IAppConfig>(() => myAppConfig);
// You don't have to map an interface to an implementation.
DIContainer.registerSingleton<MyAwesomeService>();
container.registerSingleton<MyAwesomeService>();
```

@@ -111,2 +180,4 @@

<!-- SHADOW_SECTION_CONTRIBUTING_START -->
## Contributing

@@ -116,8 +187,20 @@

<!-- SHADOW_SECTION_CONTRIBUTING_END -->
<!-- SHADOW_SECTION_MAINTAINERS_START -->
## Maintainers
- <a href="https://github.com/wessberg"><img alt="Frederik Wessberg" src="https://avatars2.githubusercontent.com/u/20454213?s=460&v=4" height="11"></img></a> [Frederik Wessberg](https://github.com/wessberg): _Maintainer_
| <a href="mailto:frederikwessberg@hotmail.com"><img alt="Frederik Wessberg" src="https://avatars2.githubusercontent.com/u/20454213?s=460&v=4" height="70" /></a> |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Frederik Wessberg](mailto:frederikwessberg@hotmail.com)<br><strong>Twitter</strong>: [@FredWessberg](https://twitter.com/FredWessberg)<br><strong>Github</strong>: [@wessberg](https://github.com/wessberg)<br>_Lead Developer_ |
<!-- SHADOW_SECTION_MAINTAINERS_END -->
<!-- SHADOW_SECTION_FAQ_START -->
## FAQ
<!-- SHADOW_SECTION_FAQ_END -->
#### This is pure magic. How does it work?

@@ -131,8 +214,8 @@

## Backers 🏅
<!-- SHADOW_SECTION_LICENSE_START -->
[Become a backer](https://www.patreon.com/bePatron?u=11315442) and get your name, logo, and link to your site listed here.
## License
## License 📄
MIT © [Frederik Wessberg](mailto:frederikwessberg@hotmail.com) ([@FredWessberg](https://twitter.com/FredWessberg)) ([Website](https://github.com/wessberg))
MIT © [Frederik Wessberg](https://github.com/wessberg)
<!-- SHADOW_SECTION_LICENSE_END -->

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