@furystack/inject
Advanced tools
Comparing version 6.0.3 to 7.0.0
@@ -6,3 +6,4 @@ "use strict"; | ||
tslib_1.__exportStar(require("./injector"), exports); | ||
tslib_1.__exportStar(require("./injected"), exports); | ||
tslib_1.__exportStar(require("./models"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -5,3 +5,2 @@ "use strict"; | ||
const injector_1 = require("./injector"); | ||
require("./reflect-metadata-polyfill"); | ||
/** | ||
@@ -21,12 +20,6 @@ * The default options for the injectable classes | ||
return (ctor) => { | ||
const meta = Reflect.getMetadata('design:paramtypes', ctor); | ||
const metaValue = { | ||
dependencies: (meta && | ||
meta.map((param) => { | ||
return param; | ||
})) || | ||
[], | ||
options: { ...exports.defaultInjectableOptions, ...options }, | ||
}; | ||
injector_1.Injector.meta.set(ctor, metaValue); | ||
injector_1.Injector.options.set(ctor, { | ||
...exports.defaultInjectableOptions, | ||
...options, | ||
}); | ||
}; | ||
@@ -33,0 +26,0 @@ }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Injector = void 0; | ||
const injectable_1 = require("./injectable"); | ||
class Injector { | ||
@@ -43,3 +42,6 @@ constructor() { | ||
} | ||
const meta = Injector.meta.get(ctor); | ||
if (this.cachedSingletons.has(ctor)) { | ||
return this.cachedSingletons.get(ctor); | ||
} | ||
const meta = Injector.options.get(ctor); | ||
if (!meta) { | ||
@@ -53,7 +55,9 @@ throw Error(`No metadata found for '${ctor.name}'. Dependencies: ${dependencies | ||
} | ||
if (meta.options.lifetime === 'singleton') { | ||
const invalidDeps = meta.dependencies | ||
.map((dep) => ({ meta: Injector.meta.get(dep), dep })) | ||
.filter((m) => m.meta && (m.meta.options.lifetime === 'scoped' || m.meta.options.lifetime === 'transient')) | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.options.lifetime}`); | ||
const { lifetime } = meta; | ||
const injectedFields = Object.entries(Injector.injectableFields.get(ctor) || {}); | ||
if (lifetime === 'singleton') { | ||
const invalidDeps = [...injectedFields] | ||
.map(([, dep]) => ({ meta: Injector.options.get(dep), dep })) | ||
.filter((m) => m.meta && (m.meta.lifetime === 'scoped' || m.meta.lifetime === 'transient')) | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.lifetime}`); | ||
if (invalidDeps.length) { | ||
@@ -63,7 +67,7 @@ throw Error(`Injector error: Singleton type '${ctor.name}' depends on non-singleton injectables: ${invalidDeps.join(',')}`); | ||
} | ||
else if (meta.options.lifetime === 'scoped') { | ||
const invalidDeps = meta.dependencies | ||
.map((dep) => ({ meta: Injector.meta.get(dep), dep })) | ||
.filter((m) => m.meta && m.meta.options.lifetime === 'transient') | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.options.lifetime}`); | ||
else if (lifetime === 'scoped') { | ||
const invalidDeps = [...injectedFields.values()] | ||
.map(([, dep]) => ({ meta: Injector.options.get(dep), dep })) | ||
.filter((m) => m.meta && m.meta.lifetime === 'transient') | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.lifetime}`); | ||
if (invalidDeps.length) { | ||
@@ -73,12 +77,12 @@ throw Error(`Injector error: Scoped type '${ctor.name}' depends on transient injectables: ${invalidDeps.join(',')}`); | ||
} | ||
if (this.cachedSingletons.has(ctor)) { | ||
return this.cachedSingletons.get(ctor); | ||
} | ||
const fromParent = meta.options.lifetime === 'singleton' && this.options.parent && this.options.parent.getInstance(ctor); | ||
const fromParent = lifetime === 'singleton' && this.options.parent && this.options.parent.getInstance(ctor); | ||
if (fromParent) { | ||
return fromParent; | ||
} | ||
const deps = meta.dependencies.map((dep) => this.getInstance(dep, [...dependencies, ctor])); | ||
const newInstance = new ctor(...deps); | ||
if (meta.options.lifetime !== 'transient') { | ||
const deps = injectedFields.map(([key, dep]) => [key, this.getInstance(dep, [...dependencies, ctor])]); | ||
const newInstance = new ctor(); | ||
deps.forEach(([key, value]) => { | ||
newInstance[key] = value; | ||
}); | ||
if (lifetime !== 'transient') { | ||
this.setExplicitInstance(newInstance); | ||
@@ -96,13 +100,2 @@ } | ||
const ctor = key || instance.constructor; | ||
if (!Injector.meta.has(ctor)) { | ||
const meta = Reflect.getMetadata('design:paramtypes', ctor); | ||
Injector.meta.set(ctor, { | ||
dependencies: (meta && | ||
meta.map((param) => { | ||
return param; | ||
})) || | ||
[], | ||
options: { ...injectable_1.defaultInjectableOptions, lifetime: 'explicit' }, | ||
}); | ||
} | ||
if (instance.constructor === this.constructor) { | ||
@@ -130,3 +123,4 @@ throw Error('Cannot set an injector instance as injectable'); | ||
*/ | ||
Injector.meta = new Map(); | ||
Injector.options = new Map(); | ||
Injector.injectableFields = new Map(); | ||
//# sourceMappingURL=injector.js.map |
@@ -6,2 +6,3 @@ "use strict"; | ||
const injectable_1 = require("./injectable"); | ||
const injected_1 = require("./injected"); | ||
const injector_1 = require("./injector"); | ||
@@ -13,3 +14,3 @@ describe('Injector', () => { | ||
}); | ||
it('Parent should be the default instance, if not specified', () => { | ||
it('Parent should be undefined by default', () => { | ||
const i = new injector_1.Injector(); | ||
@@ -19,14 +20,14 @@ expect(i.options.parent).toBeUndefined(); | ||
it('Should throw an error on circular dependencies', () => { | ||
var InstanceClass_1; | ||
const i = new injector_1.Injector(); | ||
let InstanceClass = class InstanceClass { | ||
constructor(ohgodno) { | ||
this.ohgodno = ohgodno; | ||
/** */ | ||
} | ||
let InstanceClass = InstanceClass_1 = class InstanceClass { | ||
}; | ||
InstanceClass = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)(), | ||
tslib_1.__metadata("design:paramtypes", [InstanceClass]) | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(InstanceClass_1), | ||
tslib_1.__metadata("design:type", InstanceClass) | ||
], InstanceClass.prototype, "ohgodno", void 0); | ||
InstanceClass = InstanceClass_1 = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)() | ||
], InstanceClass); | ||
expect(() => i.getInstance(InstanceClass)).toThrow(); | ||
expect(() => i.getInstance(InstanceClass)).toThrowError('Circular dependencies found.'); | ||
}); | ||
@@ -86,15 +87,18 @@ it('Should set and return instance from cache', () => { | ||
let InstanceClass = class InstanceClass { | ||
constructor(injected1, injected2) { | ||
this.injected1 = injected1; | ||
this.injected2 = injected2; | ||
/** */ | ||
} | ||
}; | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(Injected1), | ||
tslib_1.__metadata("design:type", Injected1) | ||
], InstanceClass.prototype, "injected1", void 0); | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(Injected2), | ||
tslib_1.__metadata("design:type", Injected2) | ||
], InstanceClass.prototype, "injected2", void 0); | ||
InstanceClass = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)(), | ||
tslib_1.__metadata("design:paramtypes", [Injected1, Injected2]) | ||
(0, injectable_1.Injectable)() | ||
], InstanceClass); | ||
expect(i.getInstance(InstanceClass)).toBeInstanceOf(InstanceClass); | ||
expect(i.getInstance(InstanceClass).injected1).toBeInstanceOf(Injected1); | ||
expect(i.getInstance(InstanceClass).injected2).toBeInstanceOf(Injected2); | ||
const instance = i.getInstance(InstanceClass); | ||
expect(instance).toBeInstanceOf(InstanceClass); | ||
expect(instance.injected1).toBeInstanceOf(Injected1); | ||
expect(instance.injected2).toBeInstanceOf(Injected2); | ||
}); | ||
@@ -109,19 +113,18 @@ it('Should resolve parameters recursively', () => { | ||
let Injected2 = class Injected2 { | ||
constructor(injected1) { | ||
this.injected1 = injected1; | ||
} | ||
}; | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(Injected1), | ||
tslib_1.__metadata("design:type", Injected1) | ||
], Injected2.prototype, "injected1", void 0); | ||
Injected2 = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)(), | ||
tslib_1.__metadata("design:paramtypes", [Injected1]) | ||
(0, injectable_1.Injectable)() | ||
], Injected2); | ||
let InstanceClass = class InstanceClass { | ||
constructor(injected2) { | ||
this.injected2 = injected2; | ||
/** */ | ||
} | ||
}; | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(Injected2), | ||
tslib_1.__metadata("design:type", Injected2) | ||
], InstanceClass.prototype, "injected2", void 0); | ||
InstanceClass = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)(), | ||
tslib_1.__metadata("design:paramtypes", [Injected2]) | ||
(0, injectable_1.Injectable)() | ||
], InstanceClass); | ||
@@ -194,9 +197,9 @@ expect(i.getInstance(InstanceClass)).toBeInstanceOf(InstanceClass); | ||
let St1 = class St1 { | ||
constructor(lt) { | ||
this.lt = lt; | ||
} | ||
}; | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(Trs1), | ||
tslib_1.__metadata("design:type", Trs1) | ||
], St1.prototype, "lt", void 0); | ||
St1 = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)({ lifetime: 'singleton' }), | ||
tslib_1.__metadata("design:paramtypes", [Trs1]) | ||
(0, injectable_1.Injectable)({ lifetime: 'singleton' }) | ||
], St1); | ||
@@ -214,9 +217,9 @@ (0, utils_1.using)(new injector_1.Injector(), (i) => { | ||
let St2 = class St2 { | ||
constructor(sc) { | ||
this.sc = sc; | ||
} | ||
}; | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(Sc1), | ||
tslib_1.__metadata("design:type", Sc1) | ||
], St2.prototype, "sc", void 0); | ||
St2 = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)({ lifetime: 'singleton' }), | ||
tslib_1.__metadata("design:paramtypes", [Sc1]) | ||
(0, injectable_1.Injectable)({ lifetime: 'singleton' }) | ||
], St2); | ||
@@ -234,9 +237,9 @@ (0, utils_1.using)(new injector_1.Injector(), (i) => { | ||
let Sc2 = class Sc2 { | ||
constructor(sc) { | ||
this.sc = sc; | ||
} | ||
}; | ||
tslib_1.__decorate([ | ||
(0, injected_1.Injected)(Tr2), | ||
tslib_1.__metadata("design:type", Tr2) | ||
], Sc2.prototype, "sc", void 0); | ||
Sc2 = tslib_1.__decorate([ | ||
(0, injectable_1.Injectable)({ lifetime: 'scoped' }), | ||
tslib_1.__metadata("design:paramtypes", [Tr2]) | ||
(0, injectable_1.Injectable)({ lifetime: 'scoped' }) | ||
], Sc2); | ||
@@ -243,0 +246,0 @@ (0, utils_1.using)(new injector_1.Injector(), (i) => { |
{ | ||
"name": "@furystack/inject", | ||
"version": "6.0.3", | ||
"version": "7.0.0", | ||
"description": "Core FuryStack package", | ||
@@ -32,7 +32,7 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@furystack/utils": "^3.0.3", | ||
"@furystack/utils": "^3.0.4", | ||
"tslib": "^2.4.0" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^27.5.0" | ||
"@types/jest": "^27.5.2" | ||
}, | ||
@@ -39,0 +39,0 @@ "typings": "./types/index.d.ts", |
export * from './injectable' | ||
export * from './injector' | ||
export * from './injected' | ||
export * from './models' |
import { Injector } from './injector' | ||
import { Constructable } from './models/constructable' | ||
import './reflect-metadata-polyfill' | ||
/** | ||
@@ -28,14 +26,7 @@ * Options for the injectable instance | ||
return <T extends Constructable<any>>(ctor: T) => { | ||
const meta = Reflect.getMetadata('design:paramtypes', ctor) | ||
const metaValue = { | ||
dependencies: | ||
(meta && | ||
(meta as any[]).map((param) => { | ||
return param | ||
})) || | ||
[], | ||
options: { ...defaultInjectableOptions, ...options }, | ||
} | ||
Injector.meta.set(ctor, metaValue) | ||
Injector.options.set(ctor, { | ||
...defaultInjectableOptions, | ||
...options, | ||
}) | ||
} | ||
} |
import { Disposable, using, usingAsync } from '@furystack/utils' | ||
import { Injectable } from './injectable' | ||
import { Injected } from './injected' | ||
import { Injector } from './injector' | ||
@@ -11,3 +12,3 @@ | ||
it('Parent should be the default instance, if not specified', () => { | ||
it('Parent should be undefined by default', () => { | ||
const i = new Injector() | ||
@@ -21,7 +22,6 @@ expect(i.options.parent).toBeUndefined() | ||
class InstanceClass { | ||
constructor(public ohgodno: InstanceClass) { | ||
/** */ | ||
} | ||
@Injected(InstanceClass) | ||
public ohgodno!: InstanceClass | ||
} | ||
expect(() => i.getInstance(InstanceClass)).toThrow() | ||
expect(() => i.getInstance(InstanceClass)).toThrowError('Circular dependencies found.') | ||
}) | ||
@@ -74,9 +74,14 @@ | ||
class InstanceClass { | ||
constructor(public injected1: Injected1, public injected2: Injected2) { | ||
/** */ | ||
} | ||
@Injected(Injected1) | ||
public injected1!: Injected1 | ||
@Injected(Injected2) | ||
public injected2!: Injected2 | ||
} | ||
expect(i.getInstance(InstanceClass)).toBeInstanceOf(InstanceClass) | ||
expect(i.getInstance(InstanceClass).injected1).toBeInstanceOf(Injected1) | ||
expect(i.getInstance(InstanceClass).injected2).toBeInstanceOf(Injected2) | ||
const instance = i.getInstance(InstanceClass) | ||
expect(instance).toBeInstanceOf(InstanceClass) | ||
expect(instance.injected1).toBeInstanceOf(Injected1) | ||
expect(instance.injected2).toBeInstanceOf(Injected2) | ||
}) | ||
@@ -91,3 +96,4 @@ | ||
class Injected2 { | ||
constructor(public injected1: Injected1) {} | ||
@Injected(Injected1) | ||
public injected1!: Injected1 | ||
} | ||
@@ -97,5 +103,4 @@ | ||
class InstanceClass { | ||
constructor(public injected2: Injected2) { | ||
/** */ | ||
} | ||
@Injected(Injected2) | ||
public injected2!: Injected2 | ||
} | ||
@@ -177,3 +182,4 @@ expect(i.getInstance(InstanceClass)).toBeInstanceOf(InstanceClass) | ||
class St1 { | ||
constructor(public lt: Trs1) {} | ||
@Injected(Trs1) | ||
lt!: Trs1 | ||
} | ||
@@ -194,3 +200,4 @@ | ||
class St2 { | ||
constructor(public sc: Sc1) {} | ||
@Injected(Sc1) | ||
public sc!: Sc1 | ||
} | ||
@@ -211,3 +218,4 @@ | ||
class Sc2 { | ||
constructor(public sc: Tr2) {} | ||
@Injected(Tr2) | ||
public sc!: Tr2 | ||
} | ||
@@ -214,0 +222,0 @@ |
import { Disposable } from '@furystack/utils' | ||
import { defaultInjectableOptions } from './injectable' | ||
import { InjectableOptions } from './injectable' | ||
import { Constructable } from './models/constructable' | ||
@@ -39,10 +39,6 @@ | ||
*/ | ||
public static meta: Map< | ||
Constructable<any>, | ||
{ | ||
dependencies: Array<Constructable<any>> | ||
options: import('./injectable').InjectableOptions | ||
} | ||
> = new Map() | ||
public static options: Map<Constructable<any>, InjectableOptions> = new Map() | ||
public static injectableFields: Map<Constructable<any>, { [K: string]: Constructable<any> }> = new Map() | ||
public readonly cachedSingletons: Map<Constructable<any>, any> = new Map() | ||
@@ -62,3 +58,8 @@ | ||
} | ||
const meta = Injector.meta.get(ctor) | ||
if (this.cachedSingletons.has(ctor)) { | ||
return this.cachedSingletons.get(ctor) as T | ||
} | ||
const meta = Injector.options.get(ctor) | ||
if (!meta) { | ||
@@ -75,7 +76,11 @@ throw Error( | ||
if (meta.options.lifetime === 'singleton') { | ||
const invalidDeps = meta.dependencies | ||
.map((dep) => ({ meta: Injector.meta.get(dep), dep })) | ||
.filter((m) => m.meta && (m.meta.options.lifetime === 'scoped' || m.meta.options.lifetime === 'transient')) | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.options.lifetime}`) | ||
const { lifetime } = meta | ||
const injectedFields = Object.entries(Injector.injectableFields.get(ctor) || {}) | ||
if (lifetime === 'singleton') { | ||
const invalidDeps = [...injectedFields] | ||
.map(([, dep]) => ({ meta: Injector.options.get(dep), dep })) | ||
.filter((m) => m.meta && (m.meta.lifetime === 'scoped' || m.meta.lifetime === 'transient')) | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.lifetime}`) | ||
if (invalidDeps.length) { | ||
@@ -88,7 +93,7 @@ throw Error( | ||
} | ||
} else if (meta.options.lifetime === 'scoped') { | ||
const invalidDeps = meta.dependencies | ||
.map((dep) => ({ meta: Injector.meta.get(dep), dep })) | ||
.filter((m) => m.meta && m.meta.options.lifetime === 'transient') | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.options.lifetime}`) | ||
} else if (lifetime === 'scoped') { | ||
const invalidDeps = [...injectedFields.values()] | ||
.map(([, dep]) => ({ meta: Injector.options.get(dep), dep })) | ||
.filter((m) => m.meta && m.meta.lifetime === 'transient') | ||
.map((i) => i.meta && `${i.dep.name}:${i.meta.lifetime}`) | ||
if (invalidDeps.length) { | ||
@@ -101,13 +106,12 @@ throw Error( | ||
if (this.cachedSingletons.has(ctor)) { | ||
return this.cachedSingletons.get(ctor) as T | ||
} | ||
const fromParent = | ||
meta.options.lifetime === 'singleton' && this.options.parent && this.options.parent.getInstance(ctor) | ||
const fromParent = lifetime === 'singleton' && this.options.parent && this.options.parent.getInstance(ctor) | ||
if (fromParent) { | ||
return fromParent | ||
} | ||
const deps = meta.dependencies.map((dep) => this.getInstance(dep, [...dependencies, ctor])) | ||
const newInstance = new ctor(...deps) | ||
if (meta.options.lifetime !== 'transient') { | ||
const deps = injectedFields.map(([key, dep]) => [key, this.getInstance(dep, [...dependencies, ctor])]) | ||
const newInstance = new ctor() | ||
deps.forEach(([key, value]) => { | ||
newInstance[key as keyof T] = value | ||
}) | ||
if (lifetime !== 'transient') { | ||
this.setExplicitInstance(newInstance) | ||
@@ -126,14 +130,3 @@ } | ||
const ctor = key || (instance.constructor as Constructable<T>) | ||
if (!Injector.meta.has(ctor)) { | ||
const meta = Reflect.getMetadata('design:paramtypes', ctor) | ||
Injector.meta.set(ctor, { | ||
dependencies: | ||
(meta && | ||
(meta as any[]).map((param) => { | ||
return param | ||
})) || | ||
[], | ||
options: { ...defaultInjectableOptions, lifetime: 'explicit' as any }, | ||
}) | ||
} | ||
if (instance.constructor === this.constructor) { | ||
@@ -140,0 +133,0 @@ throw Error('Cannot set an injector instance as injectable') |
export * from './injectable'; | ||
export * from './injector'; | ||
export * from './injected'; | ||
export * from './models'; | ||
//# sourceMappingURL=index.d.ts.map |
import { Constructable } from './models/constructable'; | ||
import './reflect-metadata-polyfill'; | ||
/** | ||
@@ -19,3 +18,3 @@ * Options for the injectable instance | ||
*/ | ||
export declare const Injectable: (options?: Partial<InjectableOptions> | undefined) => <T extends Constructable<any>>(ctor: T) => void; | ||
export declare const Injectable: (options?: Partial<InjectableOptions>) => <T extends Constructable<any>>(ctor: T) => void; | ||
//# sourceMappingURL=injectable.d.ts.map |
import { Disposable } from '@furystack/utils'; | ||
import { InjectableOptions } from './injectable'; | ||
import { Constructable } from './models/constructable'; | ||
@@ -18,5 +19,5 @@ export declare class Injector implements Disposable { | ||
*/ | ||
static meta: Map<Constructable<any>, { | ||
dependencies: Array<Constructable<any>>; | ||
options: import('./injectable').InjectableOptions; | ||
static options: Map<Constructable<any>, InjectableOptions>; | ||
static injectableFields: Map<Constructable<any>, { | ||
[K: string]: Constructable<any>; | ||
}>; | ||
@@ -23,0 +24,0 @@ readonly cachedSingletons: Map<Constructable<any>, any>; |
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
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
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
49
78180
952
Updated@furystack/utils@^3.0.4