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

@tsed/di

Package Overview
Dependencies
Maintainers
5
Versions
1032
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tsed/di - npm Package Compare versions

Comparing version 5.12.0 to 5.12.1

lib/decorators/intercept.d.ts

3

lib/index.d.ts

@@ -12,3 +12,6 @@ export * from "./class/Provider";

export * from "./decorators/value";
export * from "./decorators/intercept";
export * from "./decorators/interceptor";
export * from "./registries/ProviderRegistry";
export * from "./registries/GlobalProviders";
export * from "./services/InjectorService";

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

tslib_1.__exportStar(require("./decorators/value"), exports);
tslib_1.__exportStar(require("./decorators/intercept"), exports);
tslib_1.__exportStar(require("./decorators/interceptor"), exports);
tslib_1.__exportStar(require("./registries/ProviderRegistry"), exports);
tslib_1.__exportStar(require("./registries/GlobalProviders"), exports);
tslib_1.__exportStar(require("./services/InjectorService"), exports);
//# sourceMappingURL=index.js.map

19

lib/interfaces/IInjectableProperties.d.ts

@@ -1,4 +0,3 @@

/**
*
*/
import { InjectablePropertyType } from "./InjectablePropertyType";
import { TokenProvider } from "./TokenProvider";
export interface IInjectableProperty {

@@ -8,18 +7,14 @@ propertyKey: string;

export interface IInjectablePropertyService extends IInjectableProperty {
bindingType: "method" | "property";
bindingType: InjectablePropertyType.METHOD | InjectablePropertyType.PROPERTY | InjectablePropertyType.INTERCEPTOR;
propertyType: string;
useType: any;
useType: TokenProvider;
options?: any;
}
export interface IInjectablePropertyValue extends IInjectableProperty {
bindingType: "value" | "constant";
bindingType: InjectablePropertyType.CONSTANT | InjectablePropertyType.VALUE;
expression: string;
defaultValue?: any;
}
export interface IInjectablePropertyCustom extends IInjectableProperty {
bindingType: "custom";
onInvoke: (injector: any, instance: any, definition?: IInjectablePropertyCustom) => void;
[key: string]: any;
}
export interface IInjectableProperties {
[key: string]: IInjectablePropertyService | IInjectablePropertyValue | IInjectablePropertyCustom;
[key: string]: IInjectablePropertyService | IInjectablePropertyValue;
}
export * from "./IInjectableMethod";
export * from "./IInjectableProperties";
export * from "./IInterceptor";
export * from "./IInterceptorContext";
export * from "./IProvider";
export * from "./IDILogger";
export * from "./IDISettings";
export * from "./InjectablePropertyType";
export * from "./OnInit";

@@ -10,2 +13,4 @@ export * from "./OnDestroy";

export * from "./ProviderType";
export * from "./RegistrySettings";
export * from "./TokenProvider";
export * from "./TypedProvidersRegistry";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./InjectablePropertyType"), exports);
tslib_1.__exportStar(require("./ProviderScope"), exports);

@@ -5,0 +6,0 @@ tslib_1.__exportStar(require("./ProviderType"), exports);

import { Type } from "@tsed/core";
import { ProviderType } from "./ProviderType";
import { TokenProvider } from "./TokenProvider";
/**

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

*/
provide: any;
provide: TokenProvider;
/**

@@ -13,0 +14,0 @@ * Class to instantiate for the `token`.

@@ -1,13 +0,12 @@

import { Providers } from "../class/Providers";
import { IProvider, TypedProvidersRegistry } from "../interfaces";
/**
*
* @type {Providers}
* @type {GlobalProviderRegistry}
*/
export declare const GlobalProviders: Providers;
export declare const ProviderRegistry: TypedProvidersRegistry;
/**
*
* @type {Providers}
* Register a provider configuration.
* @param {IProvider<any>} provider
*/
export declare const ProviderRegistry: TypedProvidersRegistry;
export declare function registerProvider(provider: Partial<IProvider<any>>): void;
/**

@@ -107,5 +106,58 @@ * Add a new factory in the `ProviderRegistry`.

/**
* Register a provider configuration.
* @param {IProvider<any>} provider
* Add a new controller in the `ProviderRegistry`. This controller will be built when `InjectorService` will be loaded.
*
* #### Example
*
* ```typescript
* import {registerController, InjectorService} from "@tsed/common";
*
* export default class MyController {
* constructor(){}
* transform() {
* return "test";
* }
* }
*
* registerController({provide: MyController});
* // or
* registerController(MyController);
*
* const injector = new InjectorService();
* injector.load();
*
* const myController = injector.get<MyController>(MyController);
* myController.getFoo(); // test
* ```
*
* @param provider Provider configuration.
*/
export declare function registerProvider(provider: Partial<IProvider<any>>): void;
export declare const registerController: (provider: any, instance?: any) => void;
/**
* Add a new interceptor in the `ProviderRegistry`. This interceptor will be built when `InjectorService` will be loaded.
*
* #### Example
*
* ```typescript
* import {registerInterceptor, InjectorService} from "@tsed/common";
*
* export default class MyInterceptor {
* constructor(){}
* aroundInvoke() {
* return "test";
* }
* }
*
* registerInterceptor({provide: MyInterceptor});
* // or
* registerInterceptor(MyInterceptor);
*
* const injector = new InjectorService()
* injector.load();
*
* const myInterceptor = injector.get<MyInterceptor>(MyInterceptor);
* myInterceptor.aroundInvoke(); // test
* ```
*
* @param provider Provider configuration.
*/
export declare const registerInterceptor: (provider: any, instance?: any) => void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Provider_1 = require("../class/Provider");
const Providers_1 = require("../class/Providers");
const interfaces_1 = require("../interfaces");
const GlobalProviders_1 = require("./GlobalProviders");
/**
*
* @type {Providers}
* @type {GlobalProviderRegistry}
*/
// tslint:disable-next-line: variable-name
exports.GlobalProviders = new Providers_1.Providers();
exports.ProviderRegistry = GlobalProviders_1.GlobalProviders.getRegistry(interfaces_1.ProviderType.PROVIDER);
/**
*
* @type {Providers}
*/
// tslint:disable-next-line: variable-name
exports.ProviderRegistry = exports.GlobalProviders.getRegistry(interfaces_1.ProviderType.PROVIDER);
/**
*
* @type {Registry<Provider<any>, IProvider<any>>}
*/
exports.GlobalProviders.createRegistry(interfaces_1.ProviderType.SERVICE, Provider_1.Provider, {
GlobalProviders_1.GlobalProviders.createRegistry(interfaces_1.ProviderType.SERVICE, Provider_1.Provider, {
injectable: true,

@@ -30,3 +24,3 @@ buildable: true

*/
exports.GlobalProviders.createRegistry(interfaces_1.ProviderType.FACTORY, Provider_1.Provider, {
GlobalProviders_1.GlobalProviders.createRegistry(interfaces_1.ProviderType.FACTORY, Provider_1.Provider, {
injectable: true,

@@ -36,2 +30,28 @@ buildable: false

/**
*
* @type {Registry<Provider<any>, IProvider<any>>}
*/
GlobalProviders_1.GlobalProviders.createRegistry(interfaces_1.ProviderType.INTERCEPTOR, Provider_1.Provider, {
injectable: true,
buildable: true
});
/**
*
*/
GlobalProviders_1.GlobalProviders.createRegistry(interfaces_1.ProviderType.CONTROLLER, Provider_1.Provider, {
injectable: false,
buildable: true
});
/**
* Register a provider configuration.
* @param {IProvider<any>} provider
*/
function registerProvider(provider) {
if (!provider.provide) {
throw new Error("Provider.provide is required");
}
GlobalProviders_1.GlobalProviders.merge(provider.provide, provider);
}
exports.registerProvider = registerProvider;
/**
* Add a new factory in the `ProviderRegistry`.

@@ -99,3 +119,3 @@ *

*/
exports.registerFactory = exports.GlobalProviders.createRegisterFn(interfaces_1.ProviderType.FACTORY);
exports.registerFactory = GlobalProviders_1.GlobalProviders.createRegisterFn(interfaces_1.ProviderType.FACTORY);
/**

@@ -129,15 +149,62 @@ * Add a new service in the `ProviderRegistry`. This service will be built when `InjectorService` will be loaded.

*/
exports.registerService = exports.GlobalProviders.createRegisterFn(interfaces_1.ProviderType.SERVICE);
exports.registerService = GlobalProviders_1.GlobalProviders.createRegisterFn(interfaces_1.ProviderType.SERVICE);
/**
* Register a provider configuration.
* @param {IProvider<any>} provider
* Add a new controller in the `ProviderRegistry`. This controller will be built when `InjectorService` will be loaded.
*
* #### Example
*
* ```typescript
* import {registerController, InjectorService} from "@tsed/common";
*
* export default class MyController {
* constructor(){}
* transform() {
* return "test";
* }
* }
*
* registerController({provide: MyController});
* // or
* registerController(MyController);
*
* const injector = new InjectorService();
* injector.load();
*
* const myController = injector.get<MyController>(MyController);
* myController.getFoo(); // test
* ```
*
* @param provider Provider configuration.
*/
function registerProvider(provider) {
if (!provider.provide) {
throw new Error("Provider.provide is required");
}
exports.ProviderRegistry.merge(provider.provide, provider);
}
exports.registerProvider = registerProvider;
exports.registerController = GlobalProviders_1.GlobalProviders.createRegisterFn(interfaces_1.ProviderType.CONTROLLER);
/**
* Add a new interceptor in the `ProviderRegistry`. This interceptor will be built when `InjectorService` will be loaded.
*
* #### Example
*
* ```typescript
* import {registerInterceptor, InjectorService} from "@tsed/common";
*
* export default class MyInterceptor {
* constructor(){}
* aroundInvoke() {
* return "test";
* }
* }
*
* registerInterceptor({provide: MyInterceptor});
* // or
* registerInterceptor(MyInterceptor);
*
* const injector = new InjectorService()
* injector.load();
*
* const myInterceptor = injector.get<MyInterceptor>(MyInterceptor);
* myInterceptor.aroundInvoke(); // test
* ```
*
* @param provider Provider configuration.
*/
exports.registerInterceptor = GlobalProviders_1.GlobalProviders.createRegisterFn(interfaces_1.ProviderType.INTERCEPTOR);
//# sourceMappingURL=ProviderRegistry.js.map

@@ -1,4 +0,3 @@

import { RegistryKey, Type } from "@tsed/core";
import { Provider } from "../class/Provider";
import { IDILogger, IDISettings, IInjectableMethod, ProviderScope, ProviderType } from "../interfaces";
import { IDILogger, IDISettings, IInjectableMethod, IInjectablePropertyService, IInjectablePropertyValue, ProviderScope, ProviderType, TokenProvider } from "../interfaces";
/**

@@ -27,3 +26,3 @@ * This service contain all services collected by `@Service` or services declared manually with `InjectorService.factory()` or `InjectorService.service()`.

*/
export declare class InjectorService extends Map<RegistryKey, Provider<any>> {
export declare class InjectorService extends Map<TokenProvider, Provider<any>> {
settings: IDISettings;

@@ -55,3 +54,3 @@ logger: IDILogger;

*/
get<T>(target: Type<T> | symbol | any): T | undefined;
get<T>(token: TokenProvider): T | undefined;
/**

@@ -62,3 +61,3 @@ * The has() method returns a boolean indicating whether an element with the specified key exists or not.

*/
has(key: RegistryKey): boolean;
has(token: TokenProvider): boolean;
/**

@@ -69,3 +68,3 @@ * The getProvider() method returns a specified element from a Map object.

*/
getProvider(key: RegistryKey): Provider<any> | undefined;
getProvider(token: TokenProvider): Provider<any> | undefined;
/**

@@ -76,3 +75,3 @@ *

*/
forkProvider(key: RegistryKey, instance?: any): Provider<any>;
forkProvider(token: TokenProvider, instance?: any): Provider<any>;
/**

@@ -101,3 +100,3 @@ *

*
* @param target The injectable class to invoke. Class parameters are injected according constructor signature.
* @param token The injectable class to invoke. Class parameters are injected according constructor signature.
* @param locals Optional object. If preset then any argument Class are read from this object first, before the `InjectorService` is consulted.

@@ -108,3 +107,3 @@ * @param designParamTypes Optional object. List of injectable types.

*/
invoke<T>(target: any, locals?: Map<string | Function, any>, designParamTypes?: any[], requiredScope?: boolean): T;
invoke<T>(target: TokenProvider, locals?: Map<string | Function, any>, designParamTypes?: any[], requiredScope?: boolean): T;
/**

@@ -140,2 +139,3 @@ * Invoke a class method and inject service.

* @param options Object to configure the invocation.
* @deprecated
*/

@@ -156,15 +156,11 @@ invokeMethod(handler: any, options: IInjectableMethod<any>): any;

*
* @param instance
*/
private initInjector;
bindInjectableProperties(instance: any): void;
/**
*
* @returns {any}
* @param options
*/
private mapServices;
/**
*
* @param instance
* @param {string} propertyKey
*/
private bindInjectableProperties;
bindMethod(instance: any, { propertyKey }: IInjectablePropertyService): void;
/**

@@ -174,4 +170,5 @@ *

* @param {string} propertyKey
* @param {any} useType
*/
private bindMethod;
bindProperty(instance: any, { propertyKey, useType }: IInjectablePropertyService): void;
/**

@@ -183,3 +180,3 @@ *

*/
private bindProperty;
bindValue(instance: any, { propertyKey, expression, defaultValue }: IInjectablePropertyValue): void;
/**

@@ -191,18 +188,27 @@ *

*/
private bindValue;
bindConstant(instance: any, { propertyKey, expression, defaultValue }: IInjectablePropertyValue): {
get: () => any;
enumerable: boolean;
configurable: boolean;
};
/**
*
* @param instance
* @param {string} propertyKey
* @param {any} useType
* @param propertyKey
* @param useType
* @param options
*/
private bindConstant;
bindInterceptor(instance: any, { propertyKey, useType, options }: IInjectablePropertyService): void;
/**
*
* @param {string} eventName
* @param result
* @param {string} service
*/
private initInjector;
/**
*
* @returns {any}
* @param options
*/
private mapServices;
/**
*
* @returns {Map<Type<any>, any>}

@@ -209,0 +215,0 @@ */

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

const interfaces_1 = require("../interfaces");
const GlobalProviders_1 = require("../registries/GlobalProviders");
const ProviderRegistry_1 = require("../registries/ProviderRegistry");

@@ -63,4 +64,4 @@ /**

*/
get(target) {
return (super.has(target) && super.get(core_1.getClassOrSymbol(target)).instance) || undefined;
get(token) {
return (super.has(token) && super.get(core_1.getClassOrSymbol(token)).instance) || undefined;
}

@@ -72,4 +73,4 @@ /**

*/
has(key) {
return super.has(core_1.getClassOrSymbol(key)) && !!this.get(key);
has(token) {
return super.has(core_1.getClassOrSymbol(token)) && !!this.get(token);
}

@@ -81,4 +82,4 @@ /**

*/
getProvider(key) {
return super.get(core_1.getClassOrSymbol(key));
getProvider(token) {
return super.get(core_1.getClassOrSymbol(token));
}

@@ -90,5 +91,5 @@ /**

*/
forkProvider(key, instance) {
const provider = ProviderRegistry_1.GlobalProviders.get(key).clone();
this.set(key, provider);
forkProvider(token, instance) {
const provider = GlobalProviders_1.GlobalProviders.get(token).clone();
this.set(token, provider);
provider.instance = instance;

@@ -129,3 +130,3 @@ return provider;

*
* @param target The injectable class to invoke. Class parameters are injected according constructor signature.
* @param token The injectable class to invoke. Class parameters are injected according constructor signature.
* @param locals Optional object. If preset then any argument Class are read from this object first, before the `InjectorService` is consulted.

@@ -137,3 +138,3 @@ * @param designParamTypes Optional object. List of injectable types.

invoke(target, locals = new Map(), designParamTypes, requiredScope = false) {
const { onInvoke } = ProviderRegistry_1.GlobalProviders.getRegistrySettings(target);
const { onInvoke } = GlobalProviders_1.GlobalProviders.getRegistrySettings(target);
const provider = this.getProvider(target);

@@ -188,2 +189,3 @@ const parentScope = core_1.Store.from(target).get("scope");

* @param options Object to configure the invocation.
* @deprecated
*/

@@ -214,3 +216,3 @@ invokeMethod(handler, options) {

// TODO copy all provider from GlobalProvider registry. In future this action will be performed from Bootstrap class
ProviderRegistry_1.GlobalProviders.forEach((p, k) => {
GlobalProviders_1.GlobalProviders.forEach((p, k) => {
if (!this.has(k)) {

@@ -247,71 +249,30 @@ this.set(k, p.clone());

*
*/
initInjector() {
this.forkProvider(InjectorService, this);
}
/**
*
* @returns {any}
* @param options
*/
mapServices(options) {
const { serviceType, target, locals, parentScope, requiredScope } = options;
const serviceName = typeof serviceType === "function" ? core_1.nameOf(serviceType) : serviceType;
const localService = locals.get(serviceName) || locals.get(serviceType);
if (localService) {
return localService;
}
const provider = this.getProvider(serviceType);
if (!provider) {
throw new InjectionError_1.InjectionError(target, serviceName.toString());
}
const { buildable, injectable } = ProviderRegistry_1.GlobalProviders.getRegistrySettings(provider.type);
const scopeReq = provider.scope === interfaces_1.ProviderScope.REQUEST;
if (!injectable) {
throw new InjectionError_1.InjectionError(target, serviceName.toString(), "not injectable");
}
if (!buildable || (provider.instance && !scopeReq)) {
return provider.instance;
}
if (scopeReq && requiredScope && !parentScope) {
throw new InjectionScopeError_1.InjectionScopeError(provider.useClass, target);
}
try {
const instance = this.invoke(provider.useClass, locals, undefined, requiredScope);
locals.set(provider.provide, instance);
return instance;
}
catch (er) {
const error = new InjectionError_1.InjectionError(target, serviceName.toString(), "injection failed");
error.origin = er;
throw error;
}
}
/**
*
* @param instance
*/
bindInjectableProperties(instance) {
const properties = core_1.Store.from(core_1.getClass(instance)).get("injectableProperties") || [];
Object.keys(properties)
.map(key => properties[key])
.forEach(definition => {
switch (definition.bindingType) {
case "method":
this.bindMethod(instance, definition);
break;
case "property":
this.bindProperty(instance, definition);
break;
case "constant":
this.bindConstant(instance, definition);
break;
case "value":
this.bindValue(instance, definition);
break;
case "custom":
definition.onInvoke(this, instance, definition);
break;
}
});
const store = core_1.Store.from(core_1.getClass(instance));
if (store && store.has("injectableProperties")) {
const properties = store.get("injectableProperties") || [];
Object.keys(properties)
.map(key => properties[key])
.forEach(definition => {
switch (definition.bindingType) {
case interfaces_1.InjectablePropertyType.METHOD:
this.bindMethod(instance, definition);
break;
case interfaces_1.InjectablePropertyType.PROPERTY:
this.bindProperty(instance, definition);
break;
case interfaces_1.InjectablePropertyType.CONSTANT:
this.bindConstant(instance, definition);
break;
case interfaces_1.InjectablePropertyType.VALUE:
this.bindValue(instance, definition);
break;
case interfaces_1.InjectablePropertyType.INTERCEPTOR:
this.bindInterceptor(instance, definition);
break;
}
});
}
}

@@ -326,10 +287,7 @@ /**

const originalMethod = instance[propertyKey];
instance[propertyKey] = (locals = new Map()) => {
return this.invokeMethod(originalMethod.bind(instance), {
target,
methodName: propertyKey,
locals: locals instanceof Map ? locals : undefined
});
const deps = core_1.Metadata.getParamTypes(core_1.prototypeOf(target), propertyKey);
instance[propertyKey] = () => {
const services = deps.map((dependency) => this.get(dependency));
return originalMethod.call(instance, ...services);
};
instance[propertyKey].$injected = true;
}

@@ -387,8 +345,72 @@ /**

*
* @param {string} eventName
* @param result
* @param {string} service
* @param instance
* @param propertyKey
* @param useType
* @param options
*/
bindInterceptor(instance, { propertyKey, useType, options }) {
const target = core_1.getClass(instance);
const originalMethod = instance[propertyKey];
instance[propertyKey] = (...args) => {
const context = {
target,
method: propertyKey,
propertyKey,
args,
proceed(err) {
if (!err) {
return originalMethod.apply(instance, args);
}
throw err;
}
};
return this.get(useType).aroundInvoke(context, options);
};
}
/**
*
*/
initInjector() {
this.forkProvider(InjectorService, this);
}
/**
*
* @returns {any}
* @param options
*/
mapServices(options) {
const { serviceType, target, locals, parentScope, requiredScope } = options;
const serviceName = typeof serviceType === "function" ? core_1.nameOf(serviceType) : serviceType;
const localService = locals.get(serviceName) || locals.get(serviceType);
if (localService) {
return localService;
}
const provider = this.getProvider(serviceType);
if (!provider) {
throw new InjectionError_1.InjectionError(target, serviceName.toString());
}
const { buildable, injectable } = GlobalProviders_1.GlobalProviders.getRegistrySettings(provider.type);
const scopeReq = provider.scope === interfaces_1.ProviderScope.REQUEST;
if (!injectable) {
throw new InjectionError_1.InjectionError(target, serviceName.toString(), "not injectable");
}
if (!buildable || (provider.instance && !scopeReq)) {
return provider.instance;
}
if (scopeReq && requiredScope && !parentScope) {
throw new InjectionScopeError_1.InjectionScopeError(provider.useClass, target);
}
try {
const instance = this.invoke(provider.useClass, locals, undefined, requiredScope);
locals.set(provider.provide, instance);
return instance;
}
catch (er) {
const error = new InjectionError_1.InjectionError(target, serviceName.toString(), "injection failed");
error.origin = er;
throw error;
}
}
/**
*
* @returns {Map<Type<any>, any>}

@@ -400,3 +422,3 @@ */

const token = core_1.nameOf(provider.provide);
const settings = ProviderRegistry_1.GlobalProviders.getRegistrySettings(provider.type);
const settings = GlobalProviders_1.GlobalProviders.getRegistrySettings(provider.type);
const useClass = core_1.nameOf(provider.useClass);

@@ -403,0 +425,0 @@ if (settings.buildable) {

{
"name": "@tsed/di",
"version": "5.12.0",
"version": "5.12.1",
"description": "DI module for Ts.ED Framework",

@@ -11,3 +11,3 @@ "main": "lib/index.js",

"peerDependencies": {
"@tsed/core": "5.12.0"
"@tsed/core": "5.12.1"
},

@@ -28,3 +28,3 @@ "devDependencies": {},

"license": "MIT",
"gitHead": "03be1b6d53c66cdfe42a170047367975abd7947c"
"gitHead": "1ef77423e14ab625d3e28a645efed9866dd62a84"
}

@@ -7,2 +7,3 @@ # @tsed/di

You can get the latest release and the type definitions using npm:
```bash

@@ -12,2 +13,6 @@ npm install --save @tsed/di

> **Important!** TsExpressDecorators requires Node >= 6, Express >= 4, TypeScript >= 2.0 and
the `experimentalDecorators`, `emitDecoratorMetadata`, `types` and `lib` compilation
options in your `tsconfig.json` file.
## Contributors

@@ -14,0 +19,0 @@ Please read [contributing guidelines here](https://tsed.io/CONTRIBUTING.html)

@@ -12,3 +12,6 @@ export * from "./class/Provider";

export * from "./decorators/value";
export * from "./decorators/intercept";
export * from "./decorators/interceptor";
export * from "./registries/ProviderRegistry";
export * from "./registries/GlobalProviders";
export * from "./services/InjectorService";

@@ -1,4 +0,4 @@

/**
*
*/
import {InjectablePropertyType} from "./InjectablePropertyType";
import {TokenProvider} from "./TokenProvider";
export interface IInjectableProperty {

@@ -9,9 +9,10 @@ propertyKey: string;

export interface IInjectablePropertyService extends IInjectableProperty {
bindingType: "method" | "property";
bindingType: InjectablePropertyType.METHOD | InjectablePropertyType.PROPERTY | InjectablePropertyType.INTERCEPTOR;
propertyType: string;
useType: any;
useType: TokenProvider;
options?: any;
}
export interface IInjectablePropertyValue extends IInjectableProperty {
bindingType: "value" | "constant";
bindingType: InjectablePropertyType.CONSTANT | InjectablePropertyType.VALUE;
expression: string;

@@ -21,11 +22,4 @@ defaultValue?: any;

export interface IInjectablePropertyCustom extends IInjectableProperty {
bindingType: "custom";
onInvoke: (injector: any, instance: any, definition?: IInjectablePropertyCustom) => void;
[key: string]: any;
}
export interface IInjectableProperties {
[key: string]: IInjectablePropertyService | IInjectablePropertyValue | IInjectablePropertyCustom;
[key: string]: IInjectablePropertyService | IInjectablePropertyValue;
}
export * from "./IInjectableMethod";
export * from "./IInjectableProperties";
export * from "./IInterceptor";
export * from "./IInterceptorContext";
export * from "./IProvider";
export * from "./IDILogger";
export * from "./IDISettings";
export * from "./InjectablePropertyType";
export * from "./OnInit";

@@ -10,2 +13,4 @@ export * from "./OnDestroy";

export * from "./ProviderType";
export * from "./RegistrySettings";
export * from "./TokenProvider";
export * from "./TypedProvidersRegistry";
import {Type} from "@tsed/core";
import {ProviderType} from "./ProviderType";
import {TokenProvider} from "./TokenProvider";

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

*/
provide: any;
provide: TokenProvider;

@@ -14,0 +15,0 @@ /**

import {Provider} from "../class/Provider";
import {Providers} from "../class/Providers";
import {IProvider, ProviderType, TypedProvidersRegistry} from "../interfaces";
import {GlobalProviders} from "./GlobalProviders";
/**
*
* @type {Providers}
* @type {GlobalProviderRegistry}
*/
// tslint:disable-next-line: variable-name
export const GlobalProviders = new Providers();
/**
*
* @type {Providers}
*/
// tslint:disable-next-line: variable-name
export const ProviderRegistry: TypedProvidersRegistry = GlobalProviders.getRegistry(ProviderType.PROVIDER);
/**

@@ -33,4 +28,31 @@ *

});
/**
*
* @type {Registry<Provider<any>, IProvider<any>>}
*/
GlobalProviders.createRegistry(ProviderType.INTERCEPTOR, Provider, {
injectable: true,
buildable: true
});
/**
*
*/
GlobalProviders.createRegistry(ProviderType.CONTROLLER, Provider, {
injectable: false,
buildable: true
});
/**
* Register a provider configuration.
* @param {IProvider<any>} provider
*/
export function registerProvider(provider: Partial<IProvider<any>>): void {
if (!provider.provide) {
throw new Error("Provider.provide is required");
}
GlobalProviders.merge(provider.provide, provider);
}
/**
* Add a new factory in the `ProviderRegistry`.

@@ -128,13 +150,59 @@ *

export const registerService = GlobalProviders.createRegisterFn(ProviderType.SERVICE);
/**
* Register a provider configuration.
* @param {IProvider<any>} provider
* Add a new controller in the `ProviderRegistry`. This controller will be built when `InjectorService` will be loaded.
*
* #### Example
*
* ```typescript
* import {registerController, InjectorService} from "@tsed/common";
*
* export default class MyController {
* constructor(){}
* transform() {
* return "test";
* }
* }
*
* registerController({provide: MyController});
* // or
* registerController(MyController);
*
* const injector = new InjectorService();
* injector.load();
*
* const myController = injector.get<MyController>(MyController);
* myController.getFoo(); // test
* ```
*
* @param provider Provider configuration.
*/
export function registerProvider(provider: Partial<IProvider<any>>): void {
if (!provider.provide) {
throw new Error("Provider.provide is required");
}
ProviderRegistry.merge(provider.provide, provider);
}
export const registerController = GlobalProviders.createRegisterFn(ProviderType.CONTROLLER);
/**
* Add a new interceptor in the `ProviderRegistry`. This interceptor will be built when `InjectorService` will be loaded.
*
* #### Example
*
* ```typescript
* import {registerInterceptor, InjectorService} from "@tsed/common";
*
* export default class MyInterceptor {
* constructor(){}
* aroundInvoke() {
* return "test";
* }
* }
*
* registerInterceptor({provide: MyInterceptor});
* // or
* registerInterceptor(MyInterceptor);
*
* const injector = new InjectorService()
* injector.load();
*
* const myInterceptor = injector.get<MyInterceptor>(MyInterceptor);
* myInterceptor.aroundInvoke(); // test
* ```
*
* @param provider Provider configuration.
*/
export const registerInterceptor = GlobalProviders.createRegisterFn(ProviderType.INTERCEPTOR);

@@ -12,6 +12,11 @@ import {deepClone, getClass, getClassOrSymbol, Metadata, nameOf, prototypeOf, RegistryKey, Store, Type} from "@tsed/core";

IInjectablePropertyValue,
IInterceptor,
IInterceptorContext,
InjectablePropertyType,
ProviderScope,
ProviderType
ProviderType,
TokenProvider
} from "../interfaces";
import {GlobalProviders, registerFactory} from "../registries/ProviderRegistry";
import {GlobalProviders} from "../registries/GlobalProviders";
import {registerFactory} from "../registries/ProviderRegistry";

@@ -41,3 +46,3 @@ /**

*/
export class InjectorService extends Map<RegistryKey, Provider<any>> {
export class InjectorService extends Map<TokenProvider, Provider<any>> {
public settings: IDISettings = new Map();

@@ -75,4 +80,4 @@ public logger: IDILogger = console;

*/
get<T>(target: Type<T> | symbol | any): T | undefined {
return (super.has(target) && super.get(getClassOrSymbol(target))!.instance) || undefined;
get<T>(token: TokenProvider): T | undefined {
return (super.has(token) && super.get(getClassOrSymbol(token))!.instance) || undefined;
}

@@ -85,4 +90,4 @@

*/
has(key: RegistryKey): boolean {
return super.has(getClassOrSymbol(key)) && !!this.get(key);
has(token: TokenProvider): boolean {
return super.has(getClassOrSymbol(token)) && !!this.get(token);
}

@@ -95,4 +100,4 @@

*/
getProvider(key: RegistryKey): Provider<any> | undefined {
return super.get(getClassOrSymbol(key));
getProvider(token: TokenProvider): Provider<any> | undefined {
return super.get(getClassOrSymbol(token));
}

@@ -105,5 +110,5 @@

*/
forkProvider(key: RegistryKey, instance?: any): Provider<any> {
const provider = GlobalProviders.get(key)!.clone();
this.set(key, provider);
forkProvider(token: TokenProvider, instance?: any): Provider<any> {
const provider = GlobalProviders.get(token)!.clone();
this.set(token, provider);

@@ -147,3 +152,3 @@ provider.instance = instance;

*
* @param target The injectable class to invoke. Class parameters are injected according constructor signature.
* @param token The injectable class to invoke. Class parameters are injected according constructor signature.
* @param locals Optional object. If preset then any argument Class are read from this object first, before the `InjectorService` is consulted.

@@ -154,3 +159,8 @@ * @param designParamTypes Optional object. List of injectable types.

*/
invoke<T>(target: any, locals: Map<string | Function, any> = new Map(), designParamTypes?: any[], requiredScope: boolean = false): T {
invoke<T>(
target: TokenProvider,
locals: Map<string | Function, any> = new Map(),
designParamTypes?: any[],
requiredScope: boolean = false
): T {
const {onInvoke} = GlobalProviders.getRegistrySettings(target);

@@ -215,2 +225,3 @@ const provider = this.getProvider(target);

* @param options Object to configure the invocation.
* @deprecated
*/

@@ -285,52 +296,32 @@ public invokeMethod(handler: any, options: IInjectableMethod<any>): any {

*
* @param instance
*/
private initInjector() {
this.forkProvider(InjectorService, this);
}
public bindInjectableProperties(instance: any) {
const store = Store.from(getClass(instance));
/**
*
* @returns {any}
* @param options
*/
private mapServices(options: any) {
const {serviceType, target, locals, parentScope, requiredScope} = options;
const serviceName = typeof serviceType === "function" ? nameOf(serviceType) : serviceType;
const localService = locals.get(serviceName) || locals.get(serviceType);
if (store && store.has("injectableProperties")) {
const properties: IInjectableProperties = store.get("injectableProperties") || [];
if (localService) {
return localService;
Object.keys(properties)
.map(key => properties[key])
.forEach(definition => {
switch (definition.bindingType) {
case InjectablePropertyType.METHOD:
this.bindMethod(instance, definition);
break;
case InjectablePropertyType.PROPERTY:
this.bindProperty(instance, definition);
break;
case InjectablePropertyType.CONSTANT:
this.bindConstant(instance, definition);
break;
case InjectablePropertyType.VALUE:
this.bindValue(instance, definition);
break;
case InjectablePropertyType.INTERCEPTOR:
this.bindInterceptor(instance, definition);
break;
}
});
}
const provider = this.getProvider(serviceType);
if (!provider) {
throw new InjectionError(target, serviceName.toString());
}
const {buildable, injectable} = GlobalProviders.getRegistrySettings(provider.type);
const scopeReq = provider.scope === ProviderScope.REQUEST;
if (!injectable) {
throw new InjectionError(target, serviceName.toString(), "not injectable");
}
if (!buildable || (provider.instance && !scopeReq)) {
return provider.instance;
}
if (scopeReq && requiredScope && !parentScope) {
throw new InjectionScopeError(provider.useClass, target);
}
try {
const instance = this.invoke<any>(provider.useClass, locals, undefined, requiredScope);
locals.set(provider.provide, instance);
return instance;
} catch (er) {
const error = new InjectionError(target, serviceName.toString(), "injection failed");
(error as any).origin = er;
throw error;
}
}

@@ -341,47 +332,14 @@

* @param instance
*/
private bindInjectableProperties(instance: any) {
const properties: IInjectableProperties = Store.from(getClass(instance)).get("injectableProperties") || [];
Object.keys(properties)
.map(key => properties[key])
.forEach(definition => {
switch (definition.bindingType) {
case "method":
this.bindMethod(instance, definition);
break;
case "property":
this.bindProperty(instance, definition);
break;
case "constant":
this.bindConstant(instance, definition);
break;
case "value":
this.bindValue(instance, definition);
break;
case "custom":
definition.onInvoke(this, instance, definition);
break;
}
});
}
/**
*
* @param instance
* @param {string} propertyKey
*/
private bindMethod(instance: any, {propertyKey}: IInjectablePropertyService) {
public bindMethod(instance: any, {propertyKey}: IInjectablePropertyService) {
const target = getClass(instance);
const originalMethod = instance[propertyKey];
const deps = Metadata.getParamTypes(prototypeOf(target), propertyKey);
instance[propertyKey] = (locals: Map<Function, string> | any = new Map<Function, string>()) => {
return this.invokeMethod(originalMethod!.bind(instance), {
target,
methodName: propertyKey,
locals: locals instanceof Map ? locals : undefined
});
instance[propertyKey] = () => {
const services = deps.map((dependency: any) => this.get(dependency));
return originalMethod.call(instance, ...services);
};
instance[propertyKey].$injected = true;
}

@@ -395,3 +353,3 @@

*/
private bindProperty(instance: any, {propertyKey, useType}: IInjectablePropertyService) {
public bindProperty(instance: any, {propertyKey, useType}: IInjectablePropertyService) {
Object.defineProperty(instance, propertyKey, {

@@ -410,3 +368,3 @@ get: () => {

*/
private bindValue(instance: any, {propertyKey, expression, defaultValue}: IInjectablePropertyValue) {
public bindValue(instance: any, {propertyKey, expression, defaultValue}: IInjectablePropertyValue) {
const descriptor = {

@@ -427,3 +385,3 @@ get: () => this.settings.get(expression) || defaultValue,

*/
private bindConstant(instance: any, {propertyKey, expression, defaultValue}: IInjectablePropertyValue) {
public bindConstant(instance: any, {propertyKey, expression, defaultValue}: IInjectablePropertyValue) {
const clone = (o: any) => {

@@ -450,9 +408,86 @@ if (o) {

*
* @param {string} eventName
* @param result
* @param {string} service
* @param instance
* @param propertyKey
* @param useType
* @param options
*/
public bindInterceptor(instance: any, {propertyKey, useType, options}: IInjectablePropertyService) {
const target = getClass(instance);
const originalMethod = instance[propertyKey];
instance[propertyKey] = (...args: any[]) => {
const context: IInterceptorContext<any> = {
target,
method: propertyKey,
propertyKey,
args,
proceed(err?: Error) {
if (!err) {
return originalMethod.apply(instance, args);
}
throw err;
}
};
return this.get<IInterceptor>(useType)!.aroundInvoke(context, options);
};
}
/**
*
*/
private initInjector() {
this.forkProvider(InjectorService, this);
}
/**
*
* @returns {any}
* @param options
*/
private mapServices(options: any) {
const {serviceType, target, locals, parentScope, requiredScope} = options;
const serviceName = typeof serviceType === "function" ? nameOf(serviceType) : serviceType;
const localService = locals.get(serviceName) || locals.get(serviceType);
if (localService) {
return localService;
}
const provider = this.getProvider(serviceType);
if (!provider) {
throw new InjectionError(target, serviceName.toString());
}
const {buildable, injectable} = GlobalProviders.getRegistrySettings(provider.type);
const scopeReq = provider.scope === ProviderScope.REQUEST;
if (!injectable) {
throw new InjectionError(target, serviceName.toString(), "not injectable");
}
if (!buildable || (provider.instance && !scopeReq)) {
return provider.instance;
}
if (scopeReq && requiredScope && !parentScope) {
throw new InjectionScopeError(provider.useClass, target);
}
try {
const instance = this.invoke<any>(provider.useClass, locals, undefined, requiredScope);
locals.set(provider.provide, instance);
return instance;
} catch (er) {
const error = new InjectionError(target, serviceName.toString(), "injection failed");
(error as any).origin = er;
throw error;
}
}
/**
*
* @returns {Map<Type<any>, any>}

@@ -459,0 +494,0 @@ */

@@ -14,2 +14,5 @@ import {GlobalProviders, Inject, Provider, ProviderScope, ProviderType} from "@tsed/common";

value: any;
constant: any;
constructor() {

@@ -26,2 +29,6 @@ }

}
test3(o: any) {
return o + " called ";
}
}

@@ -1151,69 +1158,51 @@

describe("bindInjectableProperties()", () => {
const sandbox = Sinon.createSandbox();
class TestBind {
}
before(
inject([InjectorService], (injector: any) => {
this.injector = injector;
this.instance = new TestBind();
this.injectableProperties = {
testMethod: {
bindingType: "method"
},
testProp: {
bindingType: "property"
},
testConst: {
bindingType: "constant"
},
testValue: {
bindingType: "value"
},
testCustom: {
bindingType: "custom",
onInvoke: Sinon.stub()
}
};
Store.from(TestBind).set("injectableProperties", this.injectableProperties);
Sinon.stub(injector, "bindMethod");
Sinon.stub(injector, "bindProperty");
Sinon.stub(injector, "bindConstant");
Sinon.stub(injector, "bindValue");
injector.bindInjectableProperties(this.instance);
})
);
after(TestContext.reset);
after(() => {
this.injector.bindMethod.restore();
this.injector.bindProperty.restore();
this.injector.bindConstant.restore();
this.injector.bindValue.restore();
sandbox.restore();
});
it("should call bindMethod", () => {
this.injector.bindMethod.should.have.been.calledWithExactly(this.instance, this.injectableProperties.testMethod);
});
it("should bind all properties", () => {
// GIVEN
const injector = new InjectorService();
const instance = new TestBind();
it("should call bindProperty", () => {
this.injector.bindProperty.should.have.been.calledWithExactly(this.instance, this.injectableProperties.testProp);
});
sandbox.stub(injector as any, "bindMethod");
sandbox.stub(injector as any, "bindProperty");
sandbox.stub(injector as any, "bindConstant");
sandbox.stub(injector as any, "bindValue");
sandbox.stub(injector as any, "bindInterceptor");
it("shoul call bindConstant", () => {
this.injector.bindConstant.should.have.been.calledWithExactly(this.instance, this.injectableProperties.testConst);
});
const injectableProperties = {
testMethod: {
bindingType: "method"
},
testProp: {
bindingType: "property"
},
testConst: {
bindingType: "constant"
},
testValue: {
bindingType: "value"
},
testInterceptor: {
bindingType: "interceptor"
}
};
it("should call bindValue", () => {
this.injector.bindValue.should.have.been.calledWithExactly(this.instance, this.injectableProperties.testValue);
});
Store.from(TestBind).set("injectableProperties", injectableProperties);
it("should call onInvoke", () => {
this.injectableProperties.testCustom.onInvoke.should.have.been.calledWithExactly(
this.injector,
this.instance,
this.injectableProperties.testCustom
);
// WHEN
injector.bindInjectableProperties(instance);
// THEN
injector.bindMethod.should.have.been.calledWithExactly(instance, injectableProperties.testMethod);
injector.bindProperty.should.have.been.calledWithExactly(instance, injectableProperties.testProp);
injector.bindConstant.should.have.been.calledWithExactly(instance, injectableProperties.testConst);
injector.bindValue.should.have.been.calledWithExactly(instance, injectableProperties.testValue);
injector.bindInterceptor.should.have.been.calledWithExactly(instance, injectableProperties.testInterceptor);
});

@@ -1223,135 +1212,152 @@ });

describe("bindMethod()", () => {
class TestBind {
testMethod() {
}
}
const sandbox = Sinon.createSandbox();
before(
inject([InjectorService], (injector: any) => {
this.injector = injector;
this.instance = new TestBind();
after(() => sandbox.restore());
Sinon.stub(this.injector, "invokeMethod");
Sinon.stub(this.instance, "testMethod");
it("should bind the method", () => {
// GIVEN
const injector = new InjectorService();
const instance = new Test();
this.injector.bindMethod(this.instance, {propertyKey: "testMethod"});
const spyTest2 = sandbox.spy(instance, "test2");
sandbox.spy(injector, "get");
this.instance.testMethod();
})
);
// WHEN
injector.bindMethod(instance, {bindingType: "method", propertyKey: "test2"} as any);
const result = (instance as any).test2();
after(TestContext.reset);
after(() => {
this.injector.invokeMethod.restore();
// THEN
spyTest2.should.have.been.calledWithExactly(injector);
injector.get.should.have.been.calledWithExactly(InjectorService);
expect(result).to.eq(injector);
});
});
describe("bindProperty()", () => {
const sandbox = Sinon.createSandbox();
after(() => sandbox.restore());
it("should bind the method", () => {
expect(this.instance.testMethod.$injected).to.be.true;
});
// GIVEN
const injector = new InjectorService();
const instance = new Test();
it("should call bindMethod()", () => {
this.injector.invokeMethod.should.have.been.calledWithExactly(Sinon.match.func, {
target: TestBind,
methodName: "testMethod",
locals: Sinon.match.instanceOf(Map)
});
// WHEN
injector.bindProperty(instance, {bindingType: "property", propertyKey: "prop", useType: InjectorService} as any);
// THEN
expect(instance.prop).to.eq(injector);
});
});
describe("bindProperty()", () => {
class TestBind {
}
describe("bindValue()", () => {
it("should bind a property with a value", () => {
// GIVEN
const injector = new InjectorService();
const instance = new Test();
before(
inject([InjectorService], (injector: any) => {
this.injector = injector;
this.instance = new TestBind();
// WHEN
injector.bindValue(instance, {propertyKey: "value", expression: "expression"} as any);
Sinon.stub(this.injector, "get").returns(injector);
instance.value = "test";
// THEN
expect(instance.value).to.eq("test");
});
});
this.injector.bindProperty(this.instance, {propertyKey: "testProp", useType: InjectorService});
this.result = this.instance.testProp;
})
);
describe("bindConstant()", () => {
it("should bind a property with a value", () => {
// GIVEN
const injector = new InjectorService();
const instance = new Test();
after(TestContext.reset);
after(() => {
this.injector.get.restore();
});
injector.settings.set("expression", "constant");
it("should bind the method", () => {
expect(this.result).to.be.instanceOf(InjectorService);
});
// WHEN
injector.bindConstant(instance, {propertyKey: "constant", expression: "expression"} as any);
it("should call bindMethod()", () => {
this.injector.get.should.have.been.calledWithExactly(InjectorService);
// THEN
expect(instance.constant).to.eq("constant");
let actualError: any;
try {
instance.constant = "test";
} catch (er) {
actualError = er;
}
expect(!!actualError).to.eq(true);
});
});
describe("bindValue()", () => {
class TestBind {
}
describe("bindInterceptor()", () => {
const sandbox = Sinon.createSandbox();
before(
inject([InjectorService], (injector: any) => {
this.injector = injector;
this.instance = new TestBind();
after(() => sandbox.restore());
afterEach(() => sandbox.resetHistory());
Sinon.stub(this.injector.settings, "get").returns("value");
Sinon.stub(this.injector.settings, "set");
it("should bind the method and return result", async () => {
// GIVEN
class InterceptorTest {
aroundInvoke(ctx: any) {
return ctx.proceed() + " intercepted";
}
}
this.injector.bindValue(this.instance, {propertyKey: "testProp", expression: "expression"});
this.instance.testProp = "setValue";
this.result = this.instance.testProp;
})
);
const injector = new InjectorService();
const instance = new Test();
const originalMethod = instance["test3"];
after(TestContext.reset);
after(() => {
this.injector.settings.get.restore();
this.injector.settings.set.restore();
});
sandbox.stub(injector, "get").returns(new InterceptorTest());
it("should bind the method", () => {
expect(this.result).to.equal("value");
});
// WHEN
injector.bindInterceptor(instance, {
bindingType: "interceptor",
propertyKey: "test3",
useType: InterceptorTest
} as any);
it("should call get()", () => {
this.injector.settings.get.should.have.been.calledWithExactly("expression");
});
const result = (instance as any).test3("test");
it("should call set()", () => {
this.injector.settings.set.should.have.been.calledWithExactly("expression", "setValue");
// THEN
expect(originalMethod).should.not.eq(instance.test3);
injector.get.should.have.been.calledWithExactly(InterceptorTest);
expect(result).to.eq("test called intercepted");
});
});
it("should bind the method and throw error", async () => {
// GIVEN
class InterceptorTest {
aroundInvoke(ctx: any) {
return ctx.proceed(new Error());
}
}
describe("bindConstant()", () => {
class TestBind {
}
const injector = new InjectorService();
const instance = new Test();
const originalMethod = instance["test3"];
before(
inject([InjectorService], (injector: any) => {
this.injector = injector;
this.instance = new TestBind();
sandbox.stub(injector, "get").returns(new InterceptorTest());
Sinon.stub(this.injector.settings, "get").returns("value");
// WHEN
injector.bindInterceptor(instance, {
bindingType: "interceptor",
propertyKey: "test3",
useType: InterceptorTest
} as any);
this.injector.bindConstant(this.instance, {propertyKey: "testProp", expression: "expression"});
this.result = this.instance.testProp;
})
);
let actualError;
try {
(instance as any).test3("test");
} catch (er) {
actualError = er;
}
after(TestContext.reset);
after(() => {
this.injector.settings.get.restore();
});
// THEN
expect(originalMethod).should.not.eq(instance.test3);
injector.get.should.have.been.calledWithExactly(InterceptorTest);
it("should bind the method", () => {
expect(this.result).to.equal("value");
actualError.should.instanceOf(Error);
});
it("should call bindMethod()", () => {
this.injector.settings.get.should.have.been.calledWithExactly("expression");
});
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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