@wessberg/di
Advanced tools
Comparing version 2.0.3 to 2.1.0
@@ -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 |
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 |
171
package.json
{ | ||
"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/**/*.*" | ||
] | ||
} |
121
README.md
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
81889
0
214
20
9
634
- Removedtslib@^1.9.3
- Removedtslib@1.14.1(transitive)