container-ioc
Advanced tools
Comparing version
## Contribution guidelines | ||
### System prerequisites | ||
``` | ||
gulp-cli >= 1.3.0 | ||
``` | ||
##### Fork the project, and then go: | ||
@@ -18,7 +13,7 @@ ``` | ||
``` | ||
##### Gulp tasks: | ||
##### Npm scripts: | ||
``` | ||
gulp compile // compiles src files | ||
gulp test // compiles src and runs unit tests | ||
gulp tslint // tslints :) | ||
npm start // lints, compiles and tests source code | ||
npm run dev // runs dev workflow, lints, compiles, tests source code and watches source files. | ||
npm run compile-dist // compiles src code and puts everything into dist folder | ||
``` | ||
@@ -25,0 +20,0 @@ |
@@ -7,7 +7,11 @@ import { IConstructor, IInjectionInstance, IProvider, ProviderToken } from './interfaces'; | ||
constructor(parent?: IContainer | undefined); | ||
register(provider: IProvider | IProvider[] | IConstructor): void; | ||
register(provider: IProvider | IProvider[] | IConstructor | IConstructor[]): void; | ||
resolve(token: ProviderToken): IInjectionInstance; | ||
createScope(): IContainer; | ||
private registerAll(providers); | ||
private createInstance(registryData); | ||
private registerOne(provider); | ||
private nornalizeProvider(provider); | ||
private normalizeOneProvider(provider); | ||
private getInjections(cls); | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var registry_data_1 = require("./registry-data"); | ||
var decorators_1 = require("./decorators"); | ||
var Container = (function () { | ||
function Container(parent) { | ||
const registry_data_1 = require("./registry-data"); | ||
const decorators_1 = require("./decorators"); | ||
class Container { | ||
constructor(parent) { | ||
this.parent = parent; | ||
this.registry = new Map(); | ||
} | ||
Container.prototype.register = function (provider) { | ||
var _this = this; | ||
if (provider instanceof Array) { | ||
provider.forEach(function (p) { return _this.registerOne(p); }); | ||
register(provider) { | ||
provider = this.nornalizeProvider(provider); | ||
if (Array.isArray(provider)) { | ||
this.registerAll(provider); | ||
} | ||
else { | ||
provider = this.nornalizeProvider(provider); | ||
this.registerOne(provider); | ||
} | ||
}; | ||
Container.prototype.resolve = function (token) { | ||
var _this = this; | ||
var registryData = this.registry.get(token); | ||
} | ||
resolve(token) { | ||
const registryData = this.registry.get(token); | ||
if (!registryData) { | ||
@@ -27,41 +27,73 @@ if (this.parent) { | ||
else { | ||
throw new Error("No provider for " + token); | ||
throw new Error(`No provider for ${token}`); | ||
} | ||
} | ||
if (registryData.value) { | ||
return registryData.value; | ||
} | ||
if (registryData.instance) { | ||
return registryData.instance; | ||
} | ||
var cls = registryData.cls; | ||
var injectionsMd = this.getInjections(cls); | ||
var resolvedInjections = injectionsMd.map(function (injectionMd) { return _this.resolve(injectionMd.token); }); | ||
var args = []; | ||
injectionsMd.forEach(function (injection, index) { | ||
if (registryData.factory) { | ||
let injections = []; | ||
if (registryData.injections) { | ||
injections = registryData.injections.map(i => this.resolve(i)); | ||
} | ||
return registryData.factory(...injections); | ||
} | ||
const instance = this.createInstance(registryData); | ||
registryData.instance = instance; | ||
this.registry.set(token, registryData); | ||
return instance; | ||
} | ||
createScope() { | ||
return new Container(this); | ||
} | ||
registerAll(providers) { | ||
providers.forEach((p) => this.registerOne(p)); | ||
} | ||
createInstance(registryData) { | ||
const cls = registryData.cls; | ||
const injectionsMd = this.getInjections(cls); | ||
const resolvedInjections = injectionsMd.map(injectionMd => this.resolve(injectionMd.token)); | ||
const args = []; | ||
injectionsMd.forEach((injection, index) => { | ||
args[injection.parameterIndex] = resolvedInjections[index]; | ||
}); | ||
registryData.instance = new (cls.bind.apply(cls, [void 0].concat(args)))(); | ||
this.registry.set(token, registryData); | ||
return registryData.instance; | ||
}; | ||
Container.prototype.createScope = function () { | ||
return new Container(this); | ||
}; | ||
Container.prototype.registerOne = function (provider) { | ||
var token; | ||
var cls; | ||
if (typeof provider === 'function') { | ||
token = provider; | ||
cls = provider; | ||
return new cls(...args); | ||
} | ||
registerOne(provider) { | ||
const registryData = new registry_data_1.RegistryData(); | ||
if (provider.useValue) { | ||
registryData.value = provider.useValue; | ||
} | ||
else if (provider.useClass) { | ||
registryData.cls = provider.useClass; | ||
} | ||
else if (provider.useFactory) { | ||
registryData.factory = provider.useFactory; | ||
registryData.injections = provider.inject; | ||
} | ||
this.registry.set(provider.token, registryData); | ||
} | ||
nornalizeProvider(provider) { | ||
let normalizedProvider; | ||
if (Array.isArray(provider)) { | ||
normalizedProvider = provider.map((p) => this.normalizeOneProvider(p)); | ||
} | ||
else { | ||
token = provider.token; | ||
cls = provider.useClass; | ||
normalizedProvider = this.normalizeOneProvider(provider); | ||
} | ||
var registryData = new registry_data_1.RegistryData(cls); | ||
this.registry.set(token, registryData); | ||
}; | ||
Container.prototype.getInjections = function (cls) { | ||
return normalizedProvider; | ||
} | ||
normalizeOneProvider(provider) { | ||
if (typeof provider === 'function') { | ||
provider = { token: provider, useClass: provider }; | ||
} | ||
return provider; | ||
} | ||
getInjections(cls) { | ||
return Reflect.getOwnMetadata(decorators_1.INJECTIONS_MD_KEY, cls) || []; | ||
}; | ||
return Container; | ||
}()); | ||
} | ||
} | ||
exports.Container = Container; |
@@ -6,7 +6,7 @@ "use strict"; | ||
function Inject(token) { | ||
return function (target, propertyKey, parameterIndex) { | ||
var injections = Reflect.getOwnMetadata(exports.INJECTIONS_MD_KEY, target) || []; | ||
return (target, propertyKey, parameterIndex) => { | ||
const injections = Reflect.getOwnMetadata(exports.INJECTIONS_MD_KEY, target) || []; | ||
injections.push({ | ||
token: token, | ||
parameterIndex: parameterIndex | ||
token, | ||
parameterIndex | ||
}); | ||
@@ -13,0 +13,0 @@ Reflect.defineMetadata(exports.INJECTIONS_MD_KEY, injections, target); |
import 'reflect-metadata/Reflect'; | ||
export { Container } from './container'; | ||
export { Inject } from './decorators'; | ||
export { InjectionToken } from './injection-token'; |
@@ -8,1 +8,3 @@ "use strict"; | ||
exports.Inject = decorators_1.Inject; | ||
var injection_token_1 = require("./injection-token"); | ||
exports.InjectionToken = injection_token_1.InjectionToken; |
export declare type ProviderToken = any; | ||
export interface IProvider { | ||
token: ProviderToken; | ||
useClass: any; | ||
useClass?: IConstructor; | ||
useValue?: any; | ||
useFactory?: any; | ||
inject?: ProviderToken[]; | ||
} | ||
@@ -6,0 +9,0 @@ export interface IInjectionMd { |
@@ -1,10 +0,15 @@ | ||
import { IConstructor, IInjectionInstance } from './interfaces'; | ||
import { IConstructor, IInjectionInstance, ProviderToken } from './interfaces'; | ||
export interface IRegistryData { | ||
instance: IInjectionInstance; | ||
cls: IConstructor; | ||
value: any; | ||
factory: (...args: any[]) => any; | ||
injections: ProviderToken[]; | ||
} | ||
export declare class RegistryData { | ||
cls: any; | ||
instance: any; | ||
constructor(cls: any); | ||
instance: IInjectionInstance; | ||
value: any; | ||
cls: IConstructor; | ||
factory: (...args: any[]) => any; | ||
injections: ProviderToken[]; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var RegistryData = (function () { | ||
function RegistryData(cls) { | ||
this.cls = cls; | ||
this.instance = null; | ||
} | ||
return RegistryData; | ||
}()); | ||
class RegistryData { | ||
} | ||
exports.RegistryData = RegistryData; |
{ | ||
"name": "container-ioc", | ||
"version": "1.1.2", | ||
"version": "1.3.0", | ||
"description": "IoC container", | ||
@@ -24,4 +24,7 @@ "author": "Alexander Kozlov", | ||
"scripts": { | ||
"build": "tsc -w", | ||
"test": "mocha --reporter dot -w 'dist/**/*.spec.js'" | ||
"start": "node ./node_modules/gulp/bin/gulp.js", | ||
"dev": "node ./node_modules/gulp/bin/gulp.js dev", | ||
"test": "node ./node_modules/gulp/bin/gulp.js test", | ||
"compile": "node ./node_modules/gulp/bin/gulp.js compile", | ||
"compile-dist": "node ./node_modules/gulp/bin/gulp.js compile-dist" | ||
}, | ||
@@ -33,14 +36,14 @@ "bugs": { | ||
"devDependencies": { | ||
"@types/chai": "^4.0.4", | ||
"@types/core-js": "^0.9.43", | ||
"@types/mocha": "^2.2.43", | ||
"chai": "^4.1.2", | ||
"gulp": "^3.9.1", | ||
"gulp-mocha": "^4.3.1", | ||
"gulp-tslint": "^8.1.2", | ||
"gulp-typescript": "^3.2.2", | ||
"mocha": "^3.5.2", | ||
"tslint": "^5.7.0", | ||
"tslint-microsoft-contrib": "^5.0.1", | ||
"typescript": "^2.5.2" | ||
"@types/chai": "4.0.4", | ||
"@types/core-js": "0.9.43", | ||
"@types/mocha": "2.2.43", | ||
"chai": "4.1.2", | ||
"gulp": "3.9.1", | ||
"gulp-mocha": "4.3.1", | ||
"gulp-tslint": "8.1.2", | ||
"gulp-typescript": "3.2.2", | ||
"mocha": "3.5.3", | ||
"tslint": "5.7.0", | ||
"tslint-microsoft-contrib": "5.0.1", | ||
"typescript": "2.5.3" | ||
}, | ||
@@ -47,0 +50,0 @@ "dependencies": { |
103
README.md
@@ -18,17 +18,10 @@ ## IoC Container written in Typescript | ||
// Register classes: | ||
class RandomClass1 {}; | ||
class RandomClass3 { | ||
doSomething(): void { | ||
console.log('hello world'); | ||
} | ||
}; | ||
class A {} | ||
class B {} | ||
// Use Injector decorater to inject dependencies: | ||
class RandomClass2 { | ||
constructor(@Inject(RandomClass3) public instance3: any) { | ||
class C { | ||
constructor(@Inject(B) public b: B) { // use @Inject() decorator to mark injections in a class | ||
} | ||
}; | ||
} | ||
@@ -40,5 +33,19 @@ | ||
let providers = [ | ||
RandomClass1, | ||
{ token: 'anystring', useClass: RandomClass2 }, | ||
{ token: RandomClass3, useClass: RandomClass3 } | ||
A, | ||
{ token: 'IB', useClass: B }, | ||
{ token: C, useClass: C }, | ||
{ token: 'UseValue', useValue: 'any-primitive-or-object'}, | ||
{ | ||
token: 'FromFactory', | ||
useFactory: () => { | ||
return 'something'; | ||
} | ||
}, | ||
{ | ||
token: 'FromFactoryWithInjections', | ||
useFactory: (value, b, c) => { | ||
return `${value + b.constructor.name + c.constructor.name}`; | ||
}, | ||
inject: ['UseValue', 'IB', C] | ||
} | ||
]; | ||
@@ -50,50 +57,32 @@ | ||
// Resolve instances | ||
let instance1: RandomClass1 = container.resolve(RandomClass1); | ||
let instance2: RandomClass2 = container.resolve('anystring'); | ||
instance2.instance3.doSomething(); // hello world | ||
let a: A = container.resolve(A); | ||
let b: B = container.resolve('IB'); | ||
let c: C = container.resolve(C); | ||
let value: string = container.resolve('UseValue'); | ||
let fromFactory: string = container.resolve('FromFactory'); | ||
let fromFactoryWithInjections: string = container.resolve('FromFactoryWithInjections'); | ||
``` | ||
##### in a ES6 project: | ||
```Javascript | ||
let Container = require('container-ioc').Container; | ||
### Injection Token | ||
> Using string literals for tokens can become a head ache, use Injection Token instread: | ||
```Typescript | ||
import { InjectionToken, Container } from 'container-ioc'; | ||
let container = new Container(); | ||
interface IFactory { | ||
create(): any; | ||
} | ||
// Register classes: | ||
class RandomClass1 {}; | ||
class RandomClass3 { | ||
doSomething() { | ||
console.log('hello world'); | ||
} | ||
}; | ||
const TFactory = new InjectionToken<IFactory>('IFactory'); // T in TFactory stands for token | ||
class ConcreteFactory implements IFactory {} | ||
// Use Injector decorater to inject dependencies: | ||
class RandomClass2 { | ||
instance3; | ||
constructor() { | ||
this.instance3 = container.resolve(RandomClass3); | ||
} | ||
}; | ||
container.register({ token: TFactory, useClass: ConcreteFactory }); | ||
let factory: IFactory = container.resolve(TFactory); | ||
// Register classes in the container: | ||
// You can pass just a Class literal alone or a provider literal -> | ||
// { token: 'string or class literal', useClass: 'class literal' } | ||
let providers = [ | ||
RandomClass1, | ||
{ token: 'anystring', useClass: RandomClass2 }, | ||
{ token: RandomClass3, useClass: RandomClass3 } | ||
]; | ||
``` | ||
container.register(providers); | ||
// Resolve instances | ||
let instance1 = container.resolve(RandomClass1); | ||
let instance2 = container.resolve('anystring'); | ||
instance2.instance3.doSomething(); // hello world | ||
``` | ||
### Scoped containers | ||
@@ -104,7 +93,3 @@ > if a provider wasn't found in a container it will look up in ascendant containers if there's any: | ||
class SomeClass { | ||
doStuff(): void { | ||
console.log('hello world'); | ||
} | ||
} | ||
class A {} | ||
@@ -114,6 +99,6 @@ let parentContainer = new Container(); | ||
parentContainer.register({ token: 'ISome', useClass: SomeClass }); | ||
parentContainer.register({ token: 'IA', useClass: A }); | ||
let instance = childContainer.resolve('ISome'); | ||
instance.doStuff(); // hello world | ||
let a = childContainer.resolve('IA'); | ||
a.doStuff(); // hello world | ||
@@ -120,0 +105,0 @@ ``` |
Sorry, the diff of this file is not supported yet
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
81401
38.56%27
12.5%209
38.41%111
-11.9%1
Infinity%