ts.di
Version:
Typescript写的依赖注入库。An dependency-injection library for TypeScript.
169 lines • 6.8 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
require("reflect-metadata");
let Injector = Injector_1 = class Injector {
static get(ctor) {
return Injector_1.getWithFollower(ctor, undefined);
}
/* Set a class as @Singleton() and give it a custom \a value for future retrieving.
* If there exist an instance of target class, and \a overwrite haven't set,
* setting will be failed and function will return false. Otherwise, newIt singleton
* instance will be set and true will be returned.
*/
static setSingleton(ctor, val, overwrite) {
Injector_1.registerSingleton(ctor);
if (!overwrite && ctor[Injector_1.singletonInstance]) {
return false;
}
ctor[Injector_1.singletonInstance] = val;
return true;
}
static isSingletonExist(ctor) {
return !!ctor[Injector_1.singletonInstance];
}
static getWithFollower(ctor, fllower) {
// A class without @Injectable() decorated can be instantiate too
// **But that is not recommended**
if (Injector_1.strictDecorationCheck && !ctor[Injector_1.isInjectable]) {
throw new Error("To get a instance of " + ctor.name + ", you should decorate it with @Injectable().");
}
// There is a different instantiation for Singleton class.
if (ctor[Injector_1.isSingleton]) {
return ctor[Injector_1.singletonInstance] = ctor[Injector_1.singletonInstance] || Injector_1.create(ctor);
}
return Injector_1.create(ctor, fllower);
}
static create(ctor, follwer) {
// If there is a factory for it
if (ctor[Injector_1.factorSymbol])
return ctor[Injector_1.factorSymbol]();
let argtypes = Reflect.getMetadata("design:paramtypes", ctor) || [];
// If it depends on nothing, just newIt it.
if (argtypes.length === 0) {
return new ctor();
}
// If it depends on something else, check if there is a dependency loop
let newFollower;
if (Injector_1.checkDependencyLoop) {
if (follwer && follwer.indexOf(ctor) != -1) {
throw new Error("Found dependency loop while trying to instantiate " + ctor.name + ". Please check your code.");
}
// Prepare for next dependency loop check
newFollower = [ctor].concat(follwer);
}
// Instantiate the arguments it's constructor needs
let args = [];
for (let i = 0; i < argtypes.length; i++) {
args.push(Injector_1.getWithFollower(argtypes[i], newFollower));
}
// newIt it
return new ctor(...args);
}
static registerInjectable(ctor) {
ctor[Injector_1.isInjectable] = true;
return ctor;
}
static registerSingleton(ctor) {
ctor[Injector_1.isInjectable] = true;
ctor[Injector_1.isSingleton] = true;
return ctor;
}
static injectDecoratorFactor(undefOrTypeFunc) {
if (undefOrTypeFunc) {
return (target, propertyKey) => {
Object.defineProperty(target, propertyKey, {
get: () => {
let obj = Injector_1.get(undefOrTypeFunc());
Object.defineProperty(target, propertyKey, obj);
return obj;
}
});
};
}
return (target, propertyKey) => {
Object.defineProperty(target, propertyKey, {
get: () => {
let obj = Injector_1.get(Reflect.getMetadata("design:type", target, propertyKey));
Object.defineProperty(target, propertyKey, obj);
return obj;
}
});
};
}
static factorOfDecoratorFactor(ctor) {
return (target, propertyKey, descriptor) => {
ctor[Injector_1.factorSymbol] = target[propertyKey];
};
}
};
Injector.factorSymbol = Symbol('Injector.factorSymbol');
Injector.isInjectable = Symbol('Injector.isInjectable');
Injector.isSingleton = Symbol('Injector.isSingleton');
Injector.singletonInstance = Symbol('Injector.singletonInstance');
Injector.checkDependencyLoop = false; // for performance considering, disable it by default.
Injector.strictDecorationCheck = true;
Injector = Injector_1 = __decorate([
Injectable()
], Injector);
exports.Injector = Injector;
/* \brief @Injectable() marks a class injectable
*
* Use Injector.get() to get a instance of that class
* Calling Injector.get() multiple times on a @Injectable() decorated class
* will produce different instances.
*
*/
function Injectable() {
return Injector.registerInjectable;
}
exports.Injectable = Injectable;
/* @Singleton() marks a singleton class.
* Use Injector.get() to get the instance of singleton class
*/
function Singleton() {
return Injector.registerSingleton;
}
exports.Singleton = Singleton;
/* \brief @Inject() marks a property as injected property
*
* Unlike @Injectable() unable to instantiate class having dependency loop,
* @Inject(()=>Type) can instantiate dependencies like A->B->A as long as there is a
* @Singleton() class among them.
*
*/
function Inject(TypeFunc) {
return Injector.injectDecoratorFactor(TypeFunc);
}
exports.Inject = Inject;
/* \brief @FactorOf(Class) tell Injector to use it(this decorated function) to create instance of \a Class.
*
* Example :
* \code ts
* @Singleton()
* class A {
* // it's almost impossible to create A using our Injector.
* // Because param val should provided by ourselves but not Injector.
* // So a factor function to create it is necessary.
* constructor(private val:number){}
* }
* class FactorUtils {
* @FactorOf(A)
* someFunctionToCreateA(){
* return {val:1234}
* }
* }
*
* Injector.get(A).val === 1234;// this will be true
* \endcode
*/
function FactorOf(ctor) {
return Injector.factorOfDecoratorFactor(ctor);
}
exports.FactorOf = FactorOf;
var Injector_1;
//# sourceMappingURL=Injector.js.map