Skip to content

Commit 35cfdc7

Browse files
authored
Merge pull request #65 from inversify/fix
Implements inversify/InversifyJS/issues/674#issuecomment-349302658
2 parents cafc953 + 41e3817 commit 35cfdc7

12 files changed

+146
-28
lines changed

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,55 @@ class Shuriken implements Weapon {
296296
}
297297
```
298298

299+
### Using @provideFluent multiple times
300+
301+
If you try to apply `@provideFluent` multiple times:
302+
303+
```ts
304+
let container = new Container();
305+
let provideFluent = fluentProvide(container);
306+
307+
const provideSingleton = (identifier: any) => {
308+
return provideFluent(identifier)
309+
.inSingletonScope()
310+
.done();
311+
};
312+
313+
function shouldThrow() {
314+
@provideSingleton("Ninja")
315+
@provideSingleton("SilentNinja")
316+
class Ninja {}
317+
return Ninja;
318+
}
319+
```
320+
321+
The library will throw an exception:
322+
323+
> Cannot apply @provideFluent decorator multiple times but is has been used multiple times in Ninja Please use @done(true) if you are trying to declare multiple bindings!
324+
325+
We throw an exception to ensure that you are are not trying to apply `@fluentProvide` multiple times by mistake.
326+
327+
You can overcome this by passing the `force` argument to `done()`:
328+
329+
```ts
330+
let container = new Container();
331+
let provideFluent = fluentProvide(container);
332+
333+
const provideSingleton = (identifier: any) => {
334+
return provideFluent(identifier)
335+
.inSingletonScope()
336+
.done(true); // IMPORTANT!
337+
};
338+
339+
function shouldThrow() {
340+
@provideSingleton("Ninja")
341+
@provideSingleton("SilentNinja")
342+
class Ninja {}
343+
return Ninja;
344+
}
345+
```
346+
347+
299348
## The auto provide utility
300349
This library includes a small utility apply to add the default `@provide` decorator to all
301350
the public properties of a module:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "inversify-binding-decorators",
3-
"version": "3.1.0",
3+
"version": "3.2.0",
44
"description": "An utility that allows developers to declare InversifyJS bindings using ES2016 decorators",
55
"main": "lib/index.js",
66
"jsnext:main": "es/index.js",

src/decorator/provide.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ function provide(container: interfaces.Container) {
2020
try {
2121
decorate(injectable(), target);
2222
} catch (e) {
23-
throw new Error(`${e.message} ` +
24-
"Please use @provide(ID, true) if you are trying to declare multiple bindings!");
23+
throw new Error(
24+
"Cannot apply @provide decorator multiple times but is has been used " +
25+
`multiple times in ${target.name} ` +
26+
"Please use @provide(ID, true) if you are trying to declare multiple bindings!"
27+
);
2528
}
2629
}
2730

src/interfaces/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { interfaces as inversifyInterfaces } from "inversify";
33
namespace interfaces {
44

55
export interface ProvideDoneSyntax {
6-
done(): (target: any) => any;
6+
done(force?: boolean): (target: any) => any;
77
}
88

99
export interface ProvideInSyntax<T> extends ProvideDoneSyntax {

src/syntax/provide_done_syntax.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import interfaces from "../interfaces/interfaces";
22
import { decorate, injectable } from "inversify";
3-
import { interfaces as inversifyInterfaces } from "inversify";
3+
import { interfaces as inversifyInterfaces, METADATA_KEY } from "inversify";
44

55
class ProvideDoneSyntax<T> implements interfaces.ProvideDoneSyntax {
66

@@ -10,10 +10,30 @@ class ProvideDoneSyntax<T> implements interfaces.ProvideDoneSyntax {
1010
this._binding = binding;
1111
}
1212

13-
public done() {
14-
return (target: any) => {
15-
decorate(injectable(), target);
16-
this._binding.implementationType = target;
13+
public done(force?: boolean) {
14+
const that = this;
15+
return function (target: any) {
16+
17+
const isAlreadyDecorated = Reflect.hasOwnMetadata(METADATA_KEY.PARAM_TYPES, target);
18+
const redecorateWithInject = force === true;
19+
20+
if (redecorateWithInject === true && isAlreadyDecorated === false) {
21+
decorate(injectable(), target);
22+
} else if (redecorateWithInject === true && isAlreadyDecorated === true) {
23+
// Do nothing
24+
} else {
25+
try {
26+
decorate(injectable(), target);
27+
} catch (e) {
28+
throw new Error(
29+
"Cannot apply @provideFluent decorator multiple times but is has been used " +
30+
`multiple times in ${target.name} ` +
31+
"Please use @done(true) if you are trying to declare multiple bindings!"
32+
);
33+
}
34+
}
35+
36+
that._binding.implementationType = target;
1737
return target;
1838
};
1939
}

src/syntax/provide_in_syntax.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ class ProvideInSyntax<T> implements interfaces.ProvideInSyntax<T> {
3232
return new ProvideWhenOnSyntax(provideWhenSyntax, provideOnSyntax);
3333
}
3434

35-
public done() {
35+
public done(force?: boolean) {
3636
let binding: inversifyInterfaces.Binding<T> = (<any>this._bindingInSyntax)._binding;
3737
let provideDoneSyntax = new ProvideDoneSyntax<T>(binding);
38-
return provideDoneSyntax.done();
38+
return provideDoneSyntax.done(force);
3939
}
4040

4141
}

src/syntax/provide_in_when_on_syntax.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ class ProvideInWhenOnSyntax<T> implements interfaces.ProvideInWhenOnSyntax<T> {
8585
return this._provideInSyntax.inTransientScope();
8686
}
8787

88-
public done() {
89-
return this._provideInSyntax.done();
88+
public done(force?: boolean) {
89+
return this._provideInSyntax.done(force);
9090
}
9191

9292
}

src/syntax/provide_on_syntax.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ class ProvideOnSyntax<T> implements interfaces.ProvideOnSyntax<T> {
2020
return new ProvideWhenSyntax(bindingWhenSyntax, this._provideDoneSyntax);
2121
}
2222

23-
public done() {
24-
return this._provideDoneSyntax.done();
23+
public done(force?: boolean) {
24+
return this._provideDoneSyntax.done(force);
2525
}
2626

2727
}

src/syntax/provide_when_on_syntax.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ class ProvideWhenOnSyntax<T> implements interfaces.ProvideWhenOnSyntax<T> {
7474
return this._provideOnSyntax.onActivation(fn);
7575
}
7676

77-
public done() {
78-
return this._provideWhenSyntax.done();
77+
public done(force?: boolean) {
78+
return this._provideWhenSyntax.done(force);
7979
}
8080

8181
}

src/syntax/provide_when_syntax.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ class ProvideWhenSyntax<T> implements interfaces.ProvideWhenSyntax<T> {
8585
return new ProvideOnSyntax<T>(bindingOnSyntax, this._provideDoneSyntax);
8686
}
8787

88-
public done() {
89-
return this._provideDoneSyntax.done();
88+
public done(force?: boolean) {
89+
return this._provideDoneSyntax.done(force);
9090
}
9191

9292
}

0 commit comments

Comments
 (0)