diff --git a/src/interfaces/interfaces.ts b/src/interfaces/interfaces.ts index 220eb4f..6e89d81 100644 --- a/src/interfaces/interfaces.ts +++ b/src/interfaces/interfaces.ts @@ -16,6 +16,7 @@ namespace interfaces { export interface ProvideInSyntax extends ProvideDoneSyntax { inSingletonScope(): ProvideWhenOnSyntax; inTransientScope(): ProvideWhenOnSyntax; + inRequestScope(): ProvideWhenOnSyntax; } export interface ProvideInWhenOnSyntax extends ProvideInSyntax, ProvideWhenSyntax, ProvideOnSyntax {} diff --git a/src/syntax/provide_in_syntax.ts b/src/syntax/provide_in_syntax.ts index 08b32ab..a54b8f7 100644 --- a/src/syntax/provide_in_syntax.ts +++ b/src/syntax/provide_in_syntax.ts @@ -36,6 +36,15 @@ class ProvideInSyntax implements interfaces.ProvideInSyntax { return new ProvideWhenOnSyntax(provideWhenSyntax, provideOnSyntax); } + public inRequestScope(): interfaces.ProvideWhenOnSyntax { + let bindingWhenOnSyntax = (bind: inversifyInterfaces.Bind, target: any) => this._bindingInSyntax(bind, target).inRequestScope(); + let inDoneSyntax = new ProvideDoneSyntax(bindingWhenOnSyntax); + + let provideWhenSyntax = new ProvideWhenSyntax(bindingWhenOnSyntax, inDoneSyntax); + let provideOnSyntax = new ProvideOnSyntax(bindingWhenOnSyntax, inDoneSyntax); + return new ProvideWhenOnSyntax(provideWhenSyntax, provideOnSyntax); + } + public done(force?: boolean) { return this._provideDoneSyntax.done(force); } diff --git a/src/syntax/provide_in_when_on_syntax.ts b/src/syntax/provide_in_when_on_syntax.ts index 84fd226..56e0d0f 100644 --- a/src/syntax/provide_in_when_on_syntax.ts +++ b/src/syntax/provide_in_when_on_syntax.ts @@ -85,6 +85,10 @@ class ProvideInWhenOnSyntax implements interfaces.ProvideInWhenOnSyntax { return this._provideInSyntax.inTransientScope(); } + public inRequestScope(): interfaces.ProvideWhenOnSyntax { + return this._provideInSyntax.inRequestScope(); + } + public done(force?: boolean) { return this._provideInSyntax.done(force); } diff --git a/test/index.test.ts b/test/index.test.ts index 97e7711..fb5849b 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -212,11 +212,17 @@ describe("inversify-binding-decorators", () => { return fluentProvide(identifier).inTransientScope().done(); }; + let provideRequest = function (identifier: string) { + return fluentProvide(identifier).inRequestScope().done(); + }; + interface Warrior { katana: Weapon; shuriken: ThrowableWeapon; + personalItem: PersonalItem; fight(): string; sneak(): string; + use(): string; } interface Weapon { @@ -227,7 +233,12 @@ describe("inversify-binding-decorators", () => { throw(): string; } + interface PersonalItem { + use(): string; + } + let TYPE = { + PersonalItem: "PersonalItem", ThrowableWeapon: "ThrowableWeapon", Warrior: "Warrior", Weapon: "Weapon" @@ -255,22 +266,37 @@ describe("inversify-binding-decorators", () => { } } + @provideRequest(TYPE.PersonalItem) + class FamilyCrest implements PersonalItem { + private _mark: any; + public constructor() { + this._mark = Math.random(); + } + public use() { + return "use! " + this._mark; + } + } + @provideTransient(TYPE.Warrior) class Ninja implements Warrior { public katana: Weapon; public shuriken: ThrowableWeapon; + public personalItem: PersonalItem; public constructor( @inject(TYPE.Weapon) katana: Weapon, - @inject(TYPE.ThrowableWeapon) shuriken: ThrowableWeapon + @inject(TYPE.ThrowableWeapon) shuriken: ThrowableWeapon, + @inject(TYPE.PersonalItem) personalItem: PersonalItem ) { this.katana = katana; this.shuriken = shuriken; + this.personalItem = personalItem; } public fight() { return this.katana.hit(); } public sneak() { return this.shuriken.throw(); } + public use() { return this.personalItem.use(); } } @@ -279,13 +305,16 @@ describe("inversify-binding-decorators", () => { expect(ninja instanceof Ninja).eql(true); expect(ninja.katana instanceof Katana).eql(true); expect(ninja.shuriken instanceof Shuriken).eql(true); + expect(ninja.personalItem instanceof FamilyCrest).eql(true); expect(ninja.fight().indexOf("cut!")).eql(0); expect(ninja.sneak().indexOf("hit!")).eql(0); + expect(ninja.use().indexOf("use!")).eql(0); let ninja2 = container.get(TYPE.Warrior); expect(ninja.fight()).eql(ninja2.fight()); expect(ninja.sneak()).not.to.eql(ninja2.sneak()); + expect(ninja.use()).not.to.eql(ninja2.use()); }); diff --git a/test/syntax/provide_in_syntax.test.ts b/test/syntax/provide_in_syntax.test.ts index ec66765..03c517f 100644 --- a/test/syntax/provide_in_syntax.test.ts +++ b/test/syntax/provide_in_syntax.test.ts @@ -65,4 +65,27 @@ describe("ProvideInSyntax", () => { expect(mockBind.calledWith("Ninja")).to.be.eql(true, "mock bind was not called"); }); + it("Should be able to declare a binding with request scope", () => { + + class Ninja { } + let inRequestScopeExpectation = sinon.expectation.create("inRequestScope"); + let mockBindingInSyntax = { inRequestScope: inRequestScopeExpectation } as any as inversifyInterfaces.BindingInSyntax; + let mockBind = sinon.expectation.create("bind"); + let bindingInSyntaxFunction = + (bind: inversifyInterfaces.Bind, target: any) => { + bind("Ninja"); + return mockBindingInSyntax; + }; + let binding: inversifyInterfaces.Binding = (bindingInSyntaxFunction)._binding; + let provideDoneSyntax = new ProvideDoneSyntax(binding as any); + + let provideInSyntax = new ProvideInSyntax(bindingInSyntaxFunction, provideDoneSyntax); + + provideInSyntax.inRequestScope().done()(Ninja); + let metadata = Reflect.getMetadata(METADATA_KEY.provide, Reflect)[0]; + metadata.constraint(mockBind); + expect(inRequestScopeExpectation.calledOnce).to.eql(true, "inRequestScope was not called exactly once"); + expect(mockBind.calledWith("Ninja")).to.be.eql(true, "mock bind was not called"); + + }); });