async-injection 1.2.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/Changelog.md +43 -1
  2. package/ReadMe.md +6 -2
  3. package/lib/cjs/async-factory-provider.d.ts +10 -2
  4. package/lib/cjs/async-factory-provider.js +11 -1
  5. package/lib/cjs/async-factory-provider.js.map +1 -1
  6. package/lib/cjs/bindable-provider.d.ts +34 -2
  7. package/lib/cjs/bindable-provider.js +52 -22
  8. package/lib/cjs/bindable-provider.js.map +1 -1
  9. package/lib/cjs/binder.d.ts +85 -1
  10. package/lib/cjs/binder.js.map +1 -1
  11. package/lib/cjs/class-provider.d.ts +24 -2
  12. package/lib/cjs/class-provider.js +59 -13
  13. package/lib/cjs/class-provider.js.map +1 -1
  14. package/lib/cjs/constant-provider.d.ts +5 -1
  15. package/lib/cjs/constant-provider.js +5 -1
  16. package/lib/cjs/constant-provider.js.map +1 -1
  17. package/lib/cjs/constants.d.ts +1 -0
  18. package/lib/cjs/constants.js +2 -1
  19. package/lib/cjs/constants.js.map +1 -1
  20. package/lib/cjs/container.d.ts +54 -1
  21. package/lib/cjs/container.js +104 -22
  22. package/lib/cjs/container.js.map +1 -1
  23. package/lib/cjs/decorators.d.ts +53 -6
  24. package/lib/cjs/decorators.js +110 -14
  25. package/lib/cjs/decorators.js.map +1 -1
  26. package/lib/cjs/index.d.ts +2 -2
  27. package/lib/cjs/index.js +5 -5
  28. package/lib/cjs/index.js.map +1 -1
  29. package/lib/cjs/injector.d.ts +29 -3
  30. package/lib/cjs/injector.js.map +1 -1
  31. package/lib/cjs/provider.d.ts +30 -0
  32. package/lib/cjs/provider.js +38 -1
  33. package/lib/cjs/provider.js.map +1 -1
  34. package/lib/cjs/state.d.ts +7 -4
  35. package/lib/cjs/state.js +6 -2
  36. package/lib/cjs/state.js.map +1 -1
  37. package/lib/cjs/sync-factory-provider.d.ts +14 -2
  38. package/lib/cjs/sync-factory-provider.js +16 -1
  39. package/lib/cjs/sync-factory-provider.js.map +1 -1
  40. package/lib/cjs/utils.d.ts +14 -0
  41. package/lib/cjs/utils.js +48 -0
  42. package/lib/cjs/utils.js.map +1 -0
  43. package/lib/esm/async-factory-provider.d.ts +10 -2
  44. package/lib/esm/async-factory-provider.js +11 -1
  45. package/lib/esm/async-factory-provider.js.map +1 -1
  46. package/lib/esm/bindable-provider.d.ts +34 -2
  47. package/lib/esm/bindable-provider.js +50 -20
  48. package/lib/esm/bindable-provider.js.map +1 -1
  49. package/lib/esm/binder.d.ts +85 -1
  50. package/lib/esm/binder.js.map +1 -1
  51. package/lib/esm/class-provider.d.ts +24 -2
  52. package/lib/esm/class-provider.js +59 -13
  53. package/lib/esm/class-provider.js.map +1 -1
  54. package/lib/esm/constant-provider.d.ts +5 -1
  55. package/lib/esm/constant-provider.js +5 -1
  56. package/lib/esm/constant-provider.js.map +1 -1
  57. package/lib/esm/constants.d.ts +1 -0
  58. package/lib/esm/constants.js +1 -0
  59. package/lib/esm/constants.js.map +1 -1
  60. package/lib/esm/container.d.ts +54 -1
  61. package/lib/esm/container.js +104 -22
  62. package/lib/esm/container.js.map +1 -1
  63. package/lib/esm/decorators.d.ts +53 -6
  64. package/lib/esm/decorators.js +109 -14
  65. package/lib/esm/decorators.js.map +1 -1
  66. package/lib/esm/index.d.ts +2 -2
  67. package/lib/esm/index.js +1 -1
  68. package/lib/esm/index.js.map +1 -1
  69. package/lib/esm/injector.d.ts +29 -3
  70. package/lib/esm/injector.js.map +1 -1
  71. package/lib/esm/provider.d.ts +30 -0
  72. package/lib/esm/provider.js +38 -1
  73. package/lib/esm/provider.js.map +1 -1
  74. package/lib/esm/state.d.ts +7 -4
  75. package/lib/esm/state.js +6 -2
  76. package/lib/esm/state.js.map +1 -1
  77. package/lib/esm/sync-factory-provider.d.ts +14 -2
  78. package/lib/esm/sync-factory-provider.js +16 -1
  79. package/lib/esm/sync-factory-provider.js.map +1 -1
  80. package/lib/esm/utils.d.ts +14 -0
  81. package/lib/esm/utils.js +42 -0
  82. package/lib/esm/utils.js.map +1 -0
  83. package/package.json +17 -12
@@ -2,12 +2,34 @@ import { BindableProvider } from './bindable-provider';
2
2
  import { ClassConstructor, InjectableId, Injector } from './injector';
3
3
  import { State } from './state';
4
4
  export declare type ResolveStateCallback = (id: InjectableId<any>) => State;
5
+ /**
6
+ * @inheritDoc
7
+ * This specialization invokes it's configured class constructor synchronously and then scans for (and invokes) any @PostConstruct (which may be synchronous or asynchronous).
8
+ */
5
9
  export declare class ClassBasedProvider<T> extends BindableProvider<T, ClassConstructor<T>> {
6
10
  protected stateResolver: ResolveStateCallback;
7
11
  constructor(injector: Injector, id: InjectableId<T>, maker: ClassConstructor<T>, stateResolver: ResolveStateCallback);
12
+ /**
13
+ * @inheritDoc
14
+ * @see the class description for this Provider.
15
+ * This method is just a singleton guard, the real work is done by provideAsStateImpl.
16
+ */
8
17
  provideAsState(): State<T>;
18
+ /**
19
+ * @inheritDoc
20
+ * This specialization returns undefined if 'asyncOnly' is true and there is no asynchronous PostConstruct annotation (since class constructors can never by asynchronous).
21
+ */
9
22
  resolveIfSingleton(asyncOnly: boolean): Promise<T>;
10
- protected makePostConstructState(obj: any): State<T>;
11
- protected getConstructorParameterStates<T>(): State[];
23
+ /**
24
+ * Make a resolved or pending State that reflects any @PostConstruct annotations.
25
+ */
26
+ protected makePostConstructState(obj: T): State<T>;
27
+ /**
28
+ * This method collects the States of all the constructor parameters for our target class.
29
+ */
30
+ protected getConstructorParameterStates(): State[];
31
+ /**
32
+ * Gather the needed constructor parameters, invoke the constructor, and figure out what post construction needs done.
33
+ */
12
34
  private provideAsStateImpl;
13
35
  }
@@ -2,11 +2,21 @@ import { BindableProvider } from './bindable-provider';
2
2
  import { POSTCONSTRUCT_ASYNC_METADATA_KEY, POSTCONSTRUCT_SYNC_METADATA_KEY, REFLECT_PARAMS } from './constants';
3
3
  import { _getInjectedIdAt, _getOptionalDefaultAt } from './decorators';
4
4
  import { State } from './state';
5
+ import { isPromise } from './utils';
6
+ /**
7
+ * @inheritDoc
8
+ * This specialization invokes it's configured class constructor synchronously and then scans for (and invokes) any @PostConstruct (which may be synchronous or asynchronous).
9
+ */
5
10
  export class ClassBasedProvider extends BindableProvider {
6
11
  constructor(injector, id, maker, stateResolver) {
7
12
  super(injector, id, maker);
8
13
  this.stateResolver = stateResolver;
9
14
  }
15
+ /**
16
+ * @inheritDoc
17
+ * @see the class description for this Provider.
18
+ * This method is just a singleton guard, the real work is done by provideAsStateImpl.
19
+ */
10
20
  provideAsState() {
11
21
  let retVal = this.singleton;
12
22
  if (!retVal) {
@@ -16,12 +26,20 @@ export class ClassBasedProvider extends BindableProvider {
16
26
  this.singleton = retVal;
17
27
  return retVal;
18
28
  }
29
+ /**
30
+ * @inheritDoc
31
+ * This specialization returns undefined if 'asyncOnly' is true and there is no asynchronous PostConstruct annotation (since class constructors can never by asynchronous).
32
+ */
19
33
  resolveIfSingleton(asyncOnly) {
20
34
  if ((!asyncOnly) || Reflect.getMetadata(POSTCONSTRUCT_ASYNC_METADATA_KEY, this.maker))
21
35
  return super.resolveIfSingleton(false);
22
36
  return undefined;
23
37
  }
38
+ /**
39
+ * Make a resolved or pending State that reflects any @PostConstruct annotations.
40
+ */
24
41
  makePostConstructState(obj) {
42
+ var _a, _b;
25
43
  if (typeof obj === 'object' && (!Array.isArray(obj)) && obj.constructor) {
26
44
  let maybeAsync = false;
27
45
  let pcFn;
@@ -32,13 +50,16 @@ export class ClassBasedProvider extends BindableProvider {
32
50
  };
33
51
  }
34
52
  else {
53
+ /* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
54
+ // Check to see if there is a @PostConstruct annotation on a method of the class.
35
55
  let postConstruct = Reflect.getMetadata(POSTCONSTRUCT_SYNC_METADATA_KEY, obj.constructor);
36
56
  if (!postConstruct) {
37
57
  maybeAsync = true;
38
58
  postConstruct = Reflect.getMetadata(POSTCONSTRUCT_ASYNC_METADATA_KEY, obj.constructor);
39
59
  }
40
60
  if (postConstruct && obj.constructor.prototype[postConstruct] && typeof obj.constructor.prototype[postConstruct] === 'function')
41
- pcFn = obj[postConstruct].bind(obj);
61
+ pcFn = (_b = (_a = obj[postConstruct]).bind) === null || _b === void 0 ? void 0 : _b.call(_a, obj);
62
+ /* eslint-enable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
42
63
  }
43
64
  if (pcFn) {
44
65
  let result;
@@ -46,81 +67,106 @@ export class ClassBasedProvider extends BindableProvider {
46
67
  result = pcFn();
47
68
  }
48
69
  catch (err) {
70
+ // The post construction method threw while executing, give the errorHandler (if any) a crack at recovery.
49
71
  try {
50
- obj = this.queryErrorHandler(err, obj);
72
+ obj = this.queryErrorHandler(err, obj); // The returned obj is unlikely to be the original obj.
51
73
  return State.MakeState(null, undefined, obj);
52
74
  }
53
75
  catch (e) {
76
+ // could not recover, propagate the error.
54
77
  return State.MakeState(null, e, undefined);
55
78
  }
56
79
  }
57
- if (result && (result instanceof Promise || (maybeAsync && typeof result.then === 'function'))) {
80
+ // The post construction method says it will let us know when it's finished.
81
+ if (result && (result instanceof Promise || (maybeAsync && isPromise(result)))) {
82
+ // Return a State that is pending (the other return statements in this method return a State which is resolved or rejected).
58
83
  return State.MakeState(this.makePromiseForObj(result, () => obj));
59
84
  }
60
85
  }
61
86
  }
87
+ // No PostConstruct, just return a resolved State
62
88
  return State.MakeState(null, undefined, obj);
63
89
  }
90
+ /**
91
+ * This method collects the States of all the constructor parameters for our target class.
92
+ */
64
93
  getConstructorParameterStates() {
65
94
  const argTypes = Reflect.getMetadata(REFLECT_PARAMS, this.maker);
66
- if (argTypes === undefined) {
95
+ if (argTypes === undefined || !Array.isArray(argTypes)) {
67
96
  return [];
68
97
  }
69
98
  return argTypes.map((argType, index) => {
99
+ // The reflect-metadata API fails on circular dependencies, and will return undefined for the argument instead.
70
100
  if (argType === undefined) {
71
101
  throw new Error(`Injection error. Recursive dependency in constructor for ${this.maker.toString()} at index ${index}`);
72
102
  }
103
+ // Check if an Inject annotation precedes the parameter.
73
104
  const overrideToken = _getInjectedIdAt(this.maker, index);
74
105
  const actualToken = overrideToken === undefined ? argType : overrideToken;
106
+ // Ask our configured container to resolve the parameter.
75
107
  let param = this.stateResolver(actualToken);
108
+ // If the parameter could not be resolved, see if there is an @Optional annotation
76
109
  if ((!param.pending) && param.rejected) {
77
- let md = _getOptionalDefaultAt(this.maker, index);
110
+ const md = _getOptionalDefaultAt(this.maker, index);
78
111
  if (md)
79
112
  param = State.MakeState(null, undefined, md.value);
80
113
  }
81
114
  return param;
82
115
  });
83
116
  }
117
+ /**
118
+ * Gather the needed constructor parameters, invoke the constructor, and figure out what post construction needs done.
119
+ */
84
120
  provideAsStateImpl() {
85
- let params = this.getConstructorParameterStates();
86
- let paramRejection = params.find((p) => {
121
+ const params = this.getConstructorParameterStates();
122
+ // If any of the params are in a rejected state, we cannot construct.
123
+ const paramRejection = params.find((p) => {
87
124
  return (!p.pending) && p.rejected;
88
125
  });
89
126
  if (paramRejection) {
90
127
  return paramRejection;
91
128
  }
129
+ // If any of the params are in a pending state, we will have to wait for them to be resolved before we can construct.
92
130
  const pendingParams = params.filter((p) => {
93
131
  return p.pending;
94
132
  }).map((p) => {
95
133
  return p.promise;
96
134
  });
97
135
  if (pendingParams.length > 0) {
98
- let objPromise = this.makePromiseForObj(Promise.all(pendingParams), () => {
136
+ // Some of the parameters needed for construction are not yet available, wait for them and then attempt construction.
137
+ const objPromise = this.makePromiseForObj(Promise.all(pendingParams), () => {
138
+ // All the parameters are now available, instantiate the class.
139
+ // If this throws, it will be handled by our caller.
99
140
  return Reflect.construct(this.maker, params.map((p) => p.fulfilled));
100
141
  });
142
+ // Once the obj is resolved, then we need to check for PostConstruct and if it was async, wait for that too.
101
143
  return State.MakeState(objPromise.then((obj) => {
102
- let state = this.makePostConstructState(obj);
144
+ const state = this.makePostConstructState(obj);
103
145
  if (state.pending) {
104
- return state.promise;
146
+ return state.promise; // chain (aka wait some more).
105
147
  }
106
148
  else if (state.rejected) {
107
- return state.rejected;
149
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
150
+ return state.rejected; // error
108
151
  }
109
152
  else {
110
- return state.fulfilled;
153
+ return state.fulfilled; // value (aka obj).
111
154
  }
112
155
  }));
113
156
  }
114
157
  else {
158
+ // All parameters needed for construction are available, instantiate the object.
115
159
  try {
116
- let newObj = Reflect.construct(this.maker, params.map((p) => p.fulfilled));
160
+ const newObj = Reflect.construct(this.maker, params.map((p) => p.fulfilled));
117
161
  return this.makePostConstructState(newObj);
118
162
  }
119
163
  catch (err) {
164
+ // There was an error, give the errorHandler (if any) a crack at recovery.
120
165
  try {
121
166
  return State.MakeState(null, undefined, this.queryErrorHandler(err));
122
167
  }
123
168
  catch (e) {
169
+ // could not recover, propagate the error.
124
170
  return State.MakeState(null, e, undefined);
125
171
  }
126
172
  }
@@ -1 +1 @@
1
- {"version":3,"file":"class-provider.js","sourceRoot":"","sources":["../../src/class-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { BindableProvider } from './bindable-provider';\nimport { POSTCONSTRUCT_ASYNC_METADATA_KEY, POSTCONSTRUCT_SYNC_METADATA_KEY, REFLECT_PARAMS } from './constants';\nimport { _getInjectedIdAt, _getOptionalDefaultAt } from './decorators';\nimport { ClassConstructor, InjectableId, Injector } from './injector';\nimport { State } from './state';\n\nexport type ResolveStateCallback = (id: InjectableId<any>) => State;\n\n/**\n * @inheritDoc\n * This specialization invokes it's configured class constructor synchronously and then scans for (and invokes) any @PostConstruct (which may be synchronous or asynchronous).\n */\nexport class ClassBasedProvider<T> extends BindableProvider<T, ClassConstructor<T>> {\n\tconstructor(injector: Injector, id: InjectableId<T>, maker: ClassConstructor<T>, protected stateResolver: ResolveStateCallback) {\n\t\tsuper(injector, id, maker);\n\t}\n\n\t/**\n\t * @inheritDoc\n\t * @see the class description for this Provider.\n\t * This method is just a singleton guard, the real work is done by provideAsStateImpl.\n\t */\n\tprovideAsState(): State<T> {\n\t\tlet retVal = this.singleton;\n\t\tif (!retVal) {\n\t\t\tretVal = this.provideAsStateImpl();\n\t\t}\n\t\tif (this.singleton === null)\n\t\t\tthis.singleton = retVal;\n\t\treturn retVal;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t * This specialization returns undefined if 'asyncOnly' is true and there is no asynchronous PostConstruct annotation (since class constructors can never by asynchronous).\n\t */\n\tresolveIfSingleton(asyncOnly: boolean): Promise<T> {\n\t\t// @ts-ignore\n\t\tif ((!asyncOnly) || Reflect.getMetadata(POSTCONSTRUCT_ASYNC_METADATA_KEY, this.maker))\n\t\t\treturn super.resolveIfSingleton(false);\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Make a resolved or pending State that reflects any @PostConstruct annotations.\n\t */\n\tprotected makePostConstructState(obj: any) {\n\t\tif (typeof obj === 'object' && (!Array.isArray(obj)) && obj.constructor) {\n\t\t\tlet maybeAsync = false;\n\t\t\tlet pcFn: Function;\n\t\t\tif (typeof this.successHandler === 'function') {\n\t\t\t\tmaybeAsync = true;\n\t\t\t\tpcFn = () => {\n\t\t\t\t\treturn this.successHandler(obj, this.injector, this.id, this.maker);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\t// Check to see if there is a @PostConstruct annotation on a method of the class.\n\t\t\t\t// @ts-ignore\n\t\t\t\tlet postConstruct = Reflect.getMetadata(POSTCONSTRUCT_SYNC_METADATA_KEY, obj.constructor);\n\t\t\t\tif (!postConstruct) {\n\t\t\t\t\tmaybeAsync = true;\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\tpostConstruct = Reflect.getMetadata(POSTCONSTRUCT_ASYNC_METADATA_KEY, obj.constructor);\n\t\t\t\t}\n\t\t\t\tif (postConstruct && obj.constructor.prototype[postConstruct] && typeof obj.constructor.prototype[postConstruct] === 'function')\n\t\t\t\t\tpcFn = obj[postConstruct].bind(obj);\n\t\t\t}\n\t\t\tif (pcFn) {\n\t\t\t\tlet result;\n\t\t\t\ttry {\n\t\t\t\t\tresult = pcFn();\n\t\t\t\t}\n\t\t\t\tcatch (err) {\n\t\t\t\t\t// The post construction method threw while executing, give the errorHandler (if any) a crack at recovery.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tobj = this.queryErrorHandler(err, obj); // The returned obj is unlikely to be the original obj.\n\t\t\t\t\t\treturn State.MakeState<T>(null, undefined, obj);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (e) {\n\t\t\t\t\t\t// could not recover, propagate the error.\n\t\t\t\t\t\treturn State.MakeState<T>(null, e, undefined);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// The post construction method says it will let us know when it's finished.\n\t\t\t\tif (result && (result instanceof Promise || (maybeAsync && typeof result.then === 'function'))) {\n\t\t\t\t\t// Return a State that is pending (the other return statements in this method return a State which is resolved or rejected).\n\t\t\t\t\treturn State.MakeState<T>(this.makePromiseForObj<void>(result, () => obj));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// No PostConstruct, just return a resolved State\n\t\treturn State.MakeState<T>(null, undefined, obj);\n\t}\n\n\t/**\n\t * This method collects the States of all the constructor parameters for our target class.\n\t */\n\tprotected getConstructorParameterStates<T>(): State[] {\n\t\t// @ts-ignore\n\t\tconst argTypes = Reflect.getMetadata(REFLECT_PARAMS, this.maker);\n\t\tif (argTypes === undefined) {\n\t\t\treturn [];\n\t\t}\n\t\treturn argTypes.map((argType, index) => {\n\t\t\t// The reflect-metadata API fails on circular dependencies, and will return undefined for the argument instead.\n\t\t\tif (argType === undefined) {\n\t\t\t\tthrow new Error(`Injection error. Recursive dependency in constructor for ${this.maker.toString()} at index ${index}`);\n\t\t\t}\n\t\t\t// Check if an Inject annotation precedes the parameter.\n\t\t\tconst overrideToken = _getInjectedIdAt(this.maker, index);\n\t\t\tconst actualToken = overrideToken === undefined ? argType : overrideToken;\n\t\t\t// Ask our configured container to resolve the parameter.\n\t\t\tlet param = this.stateResolver(actualToken);\n\t\t\t// If the parameter could not be resolved, see if there is an @Optional annotation\n\t\t\tif ((!param.pending) && param.rejected) {\n\t\t\t\tlet md = _getOptionalDefaultAt(this.maker, index);\n\t\t\t\tif (md)\n\t\t\t\t\tparam = State.MakeState<any>(null, undefined, md.value);\n\t\t\t}\n\t\t\treturn param;\n\t\t});\n\t}\n\n\t/**\n\t * Gather the needed constructor parameters, invoke the constructor, and figure out what post construction needs done.\n\t */\n\tprivate provideAsStateImpl(): State<T> {\n\t\tlet params = this.getConstructorParameterStates();\n\n\t\t// If any of the params are in a rejected state, we cannot construct.\n\t\tlet paramRejection = params.find((p) => {\n\t\t\treturn (!p.pending) && p.rejected;\n\t\t});\n\t\tif (paramRejection) {\n\t\t\treturn paramRejection;\n\t\t}\n\t\t// If any of the params are in a pending state, we will have to wait for them to be resolved before we can construct.\n\t\tconst pendingParams = params.filter((p) => {\n\t\t\treturn p.pending;\n\t\t}).map((p) => {\n\t\t\treturn p.promise;\n\t\t});\n\t\tif (pendingParams.length > 0) {\n\t\t\t// Some of the parameters needed for construction are not yet available, wait for them and then attempt construction.\n\t\t\tlet objPromise = this.makePromiseForObj<any[]>(Promise.all(pendingParams), () => {\n\t\t\t\t// All the parameters are now available, instantiate the class.\n\t\t\t\t// If this throws, it will be handled by our caller.\n\t\t\t\treturn Reflect.construct(this.maker, params.map((p) => p.fulfilled));\n\t\t\t});\n\t\t\t// Once the obj is resolved, then we need to check for PostConstruct and if it was async, wait for that too.\n\t\t\treturn State.MakeState<T>(objPromise.then((obj) => {\n\t\t\t\tlet state = this.makePostConstructState(obj);\n\t\t\t\tif (state.pending) {\n\t\t\t\t\treturn state.promise; // chain (aka wait some more).\n\t\t\t\t}\n\t\t\t\telse if (state.rejected) {\n\t\t\t\t\treturn state.rejected; // error\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn state.fulfilled; // value (aka obj).\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\telse {\n\t\t\t// All parameters needed for construction are available, instantiate the object.\n\t\t\ttry {\n\t\t\t\tlet newObj = Reflect.construct(this.maker, params.map((p) => p.fulfilled));\n\t\t\t\treturn this.makePostConstructState(newObj);\n\t\t\t}\n\t\t\tcatch (err) {\n\t\t\t\t// There was an error, give the errorHandler (if any) a crack at recovery.\n\t\t\t\ttry {\n\t\t\t\t\treturn State.MakeState<T>(null, undefined, this.queryErrorHandler(err));\n\t\t\t\t}\n\t\t\t\tcatch (e) {\n\t\t\t\t\t// could not recover, propagate the error.\n\t\t\t\t\treturn State.MakeState<T>(null, e, undefined);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"class-provider.js","sourceRoot":"","sources":["../../src/class-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { BindableProvider } from './bindable-provider';\nimport { POSTCONSTRUCT_ASYNC_METADATA_KEY, POSTCONSTRUCT_SYNC_METADATA_KEY, REFLECT_PARAMS } from './constants';\nimport { _getInjectedIdAt, _getOptionalDefaultAt } from './decorators';\nimport { ClassConstructor, InjectableId, Injector } from './injector';\nimport { State } from './state';\nimport { isPromise } from './utils';\n\nexport type ResolveStateCallback = (id: InjectableId<any>) => State;\n\n/**\n * @inheritDoc\n * This specialization invokes it's configured class constructor synchronously and then scans for (and invokes) any @PostConstruct (which may be synchronous or asynchronous).\n */\nexport class ClassBasedProvider<T> extends BindableProvider<T, ClassConstructor<T>> {\n\tconstructor(injector: Injector, id: InjectableId<T>, maker: ClassConstructor<T>, protected stateResolver: ResolveStateCallback) {\n\t\tsuper(injector, id, maker);\n\t}\n\n\t/**\n\t * @inheritDoc\n\t * @see the class description for this Provider.\n\t * This method is just a singleton guard, the real work is done by provideAsStateImpl.\n\t */\n\tprovideAsState(): State<T> {\n\t\tlet retVal = this.singleton;\n\t\tif (!retVal) {\n\t\t\tretVal = this.provideAsStateImpl();\n\t\t}\n\t\tif (this.singleton === null)\n\t\t\tthis.singleton = retVal;\n\t\treturn retVal;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t * This specialization returns undefined if 'asyncOnly' is true and there is no asynchronous PostConstruct annotation (since class constructors can never by asynchronous).\n\t */\n\tresolveIfSingleton(asyncOnly: boolean): Promise<T> {\n\t\tif ((!asyncOnly) || Reflect.getMetadata(POSTCONSTRUCT_ASYNC_METADATA_KEY, this.maker))\n\t\t\treturn super.resolveIfSingleton(false);\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Make a resolved or pending State that reflects any @PostConstruct annotations.\n\t */\n\tprotected makePostConstructState(obj: T): State<T> {\n\t\tif (typeof obj === 'object' && (!Array.isArray(obj)) && obj.constructor) {\n\t\t\tlet maybeAsync = false;\n\t\t\tlet pcFn: () => void | Error | Promise<void | Error>;\n\t\t\tif (typeof this.successHandler === 'function') {\n\t\t\t\tmaybeAsync = true;\n\t\t\t\tpcFn = () => {\n\t\t\t\t\treturn this.successHandler(obj, this.injector, this.id, this.maker);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\t/* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */\n\t\t\t\t// Check to see if there is a @PostConstruct annotation on a method of the class.\n\t\t\t\tlet postConstruct: string = Reflect.getMetadata(POSTCONSTRUCT_SYNC_METADATA_KEY, obj.constructor);\n\t\t\t\tif (!postConstruct) {\n\t\t\t\t\tmaybeAsync = true;\n\t\t\t\t\tpostConstruct = Reflect.getMetadata(POSTCONSTRUCT_ASYNC_METADATA_KEY, obj.constructor);\n\t\t\t\t}\n\t\t\t\tif (postConstruct && obj.constructor.prototype[postConstruct] && typeof obj.constructor.prototype[postConstruct] === 'function')\n\t\t\t\t\tpcFn = obj[postConstruct].bind?.(obj);\n\n\t\t\t\t/* eslint-enable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */\n\t\t\t}\n\t\t\tif (pcFn) {\n\t\t\t\tlet result: any;\n\t\t\t\ttry {\n\t\t\t\t\tresult = pcFn();\n\t\t\t\t}\n\t\t\t\tcatch (err) {\n\t\t\t\t\t// The post construction method threw while executing, give the errorHandler (if any) a crack at recovery.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tobj = this.queryErrorHandler(err, obj); // The returned obj is unlikely to be the original obj.\n\t\t\t\t\t\treturn State.MakeState<T>(null, undefined, obj);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (e) {\n\t\t\t\t\t\t// could not recover, propagate the error.\n\t\t\t\t\t\treturn State.MakeState<T>(null, e, undefined);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// The post construction method says it will let us know when it's finished.\n\t\t\t\tif (result && (result instanceof Promise || (maybeAsync && isPromise<void>(result)))) {\n\t\t\t\t\t// Return a State that is pending (the other return statements in this method return a State which is resolved or rejected).\n\t\t\t\t\treturn State.MakeState<T>(this.makePromiseForObj<void>(result, () => obj));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// No PostConstruct, just return a resolved State\n\t\treturn State.MakeState<T>(null, undefined, obj);\n\t}\n\n\t/**\n\t * This method collects the States of all the constructor parameters for our target class.\n\t */\n\tprotected getConstructorParameterStates(): State[] {\n\t\tconst argTypes = Reflect.getMetadata(REFLECT_PARAMS, this.maker);\n\t\tif (argTypes === undefined || !Array.isArray(argTypes)) {\n\t\t\treturn [];\n\t\t}\n\t\treturn argTypes.map((argType, index) => {\n\t\t\t// The reflect-metadata API fails on circular dependencies, and will return undefined for the argument instead.\n\t\t\tif (argType === undefined) {\n\t\t\t\tthrow new Error(`Injection error. Recursive dependency in constructor for ${this.maker.toString()} at index ${index}`);\n\t\t\t}\n\t\t\t// Check if an Inject annotation precedes the parameter.\n\t\t\tconst overrideToken = _getInjectedIdAt(this.maker, index);\n\t\t\tconst actualToken = overrideToken === undefined ? argType : overrideToken;\n\t\t\t// Ask our configured container to resolve the parameter.\n\t\t\tlet param = this.stateResolver(actualToken);\n\t\t\t// If the parameter could not be resolved, see if there is an @Optional annotation\n\t\t\tif ((!param.pending) && param.rejected) {\n\t\t\t\tconst md = _getOptionalDefaultAt(this.maker, index);\n\t\t\t\tif (md)\n\t\t\t\t\tparam = State.MakeState<any>(null, undefined, md.value);\n\t\t\t}\n\t\t\treturn param;\n\t\t});\n\t}\n\n\t/**\n\t * Gather the needed constructor parameters, invoke the constructor, and figure out what post construction needs done.\n\t */\n\tprivate provideAsStateImpl(): State<T> {\n\t\tconst params = this.getConstructorParameterStates();\n\n\t\t// If any of the params are in a rejected state, we cannot construct.\n\t\tconst paramRejection = params.find((p) => {\n\t\t\treturn (!p.pending) && p.rejected;\n\t\t});\n\t\tif (paramRejection) {\n\t\t\treturn paramRejection as State<T>;\n\t\t}\n\t\t// If any of the params are in a pending state, we will have to wait for them to be resolved before we can construct.\n\t\tconst pendingParams = params.filter((p) => {\n\t\t\treturn p.pending;\n\t\t}).map((p) => {\n\t\t\treturn p.promise;\n\t\t});\n\t\tif (pendingParams.length > 0) {\n\t\t\t// Some of the parameters needed for construction are not yet available, wait for them and then attempt construction.\n\t\t\tconst objPromise = this.makePromiseForObj<any[]>(Promise.all(pendingParams), () => {\n\t\t\t\t// All the parameters are now available, instantiate the class.\n\t\t\t\t// If this throws, it will be handled by our caller.\n\t\t\t\treturn Reflect.construct(this.maker, params.map((p) => p.fulfilled as unknown)) as T;\n\t\t\t});\n\t\t\t// Once the obj is resolved, then we need to check for PostConstruct and if it was async, wait for that too.\n\t\t\treturn State.MakeState<T>(objPromise.then((obj) => {\n\t\t\t\tconst state = this.makePostConstructState(obj);\n\t\t\t\tif (state.pending) {\n\t\t\t\t\treturn state.promise; // chain (aka wait some more).\n\t\t\t\t}\n\t\t\t\telse if (state.rejected) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\t\t\treturn state.rejected as any; // error\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn state.fulfilled; // value (aka obj).\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\telse {\n\t\t\t// All parameters needed for construction are available, instantiate the object.\n\t\t\ttry {\n\t\t\t\tconst newObj = Reflect.construct(this.maker, params.map((p) => p.fulfilled as unknown));\n\t\t\t\treturn this.makePostConstructState(newObj);\n\t\t\t}\n\t\t\tcatch (err) {\n\t\t\t\t// There was an error, give the errorHandler (if any) a crack at recovery.\n\t\t\t\ttry {\n\t\t\t\t\treturn State.MakeState<T>(null, undefined, this.queryErrorHandler(err));\n\t\t\t\t}\n\t\t\t\tcatch (e) {\n\t\t\t\t\t// could not recover, propagate the error.\n\t\t\t\t\treturn State.MakeState<T>(null, e, undefined);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1,5 +1,9 @@
1
- import { State } from './state';
2
1
  import { Provider } from './provider';
2
+ import { State } from './state';
3
+ /**
4
+ * @inheritDoc
5
+ * This specialization is always a Singleton.
6
+ */
3
7
  export declare class ConstantProvider<T> extends Provider<T> {
4
8
  constructor(constant: T);
5
9
  provideAsState(): State<T>;
@@ -1,5 +1,9 @@
1
- import { State } from './state';
2
1
  import { Provider } from './provider';
2
+ import { State } from './state';
3
+ /**
4
+ * @inheritDoc
5
+ * This specialization is always a Singleton.
6
+ */
3
7
  export class ConstantProvider extends Provider {
4
8
  constructor(constant) {
5
9
  super();
@@ -1 +1 @@
1
- {"version":3,"file":"constant-provider.js","sourceRoot":"","sources":["../../src/constant-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AAMpC,MAAM,OAAO,gBAAoB,SAAQ,QAAW;IACnD,YAAY,QAAW;QACtB,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAI,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC;IAED,cAAc;QACb,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;CACD","sourcesContent":["import {State} from './state';\nimport {Provider} from './provider';\n\n/**\n * @inheritDoc\n * This specialization is always a Singleton.\n */\nexport class ConstantProvider<T> extends Provider<T> {\n\tconstructor(constant: T) {\n\t\tsuper();\n\t\tthis.singleton = State.MakeState<T>(null, undefined, constant);\n\t}\n\n\tprovideAsState(): State<T> {\n\t\treturn this.singleton;\n\t}\n}\n"]}
1
+ {"version":3,"file":"constant-provider.js","sourceRoot":"","sources":["../../src/constant-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;;GAGG;AACH,MAAM,OAAO,gBAAoB,SAAQ,QAAW;IACnD,YAAY,QAAW;QACtB,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAI,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC;IAED,cAAc;QACb,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;CACD","sourcesContent":["import { Provider } from './provider';\nimport { State } from './state';\n\n/**\n * @inheritDoc\n * This specialization is always a Singleton.\n */\nexport class ConstantProvider<T> extends Provider<T> {\n\tconstructor(constant: T) {\n\t\tsuper();\n\t\tthis.singleton = State.MakeState<T>(null, undefined, constant);\n\t}\n\n\tprovideAsState(): State<T> {\n\t\treturn this.singleton;\n\t}\n}\n"]}
@@ -2,6 +2,7 @@ export declare const INJECTABLE_METADATA_KEY: unique symbol;
2
2
  export declare const INJECT_METADATA_KEY: unique symbol;
3
3
  export declare const POSTCONSTRUCT_SYNC_METADATA_KEY: unique symbol;
4
4
  export declare const POSTCONSTRUCT_ASYNC_METADATA_KEY: unique symbol;
5
+ export declare const RELEASE_METADATA_KEY: unique symbol;
5
6
  export declare const OPTIONAL_METADATA_KEY: unique symbol;
6
7
  export declare const REFLECT_PARAMS = "design:paramtypes";
7
8
  export declare const REFLECT_RETURN = "design:returntype";
@@ -2,6 +2,7 @@ export const INJECTABLE_METADATA_KEY = Symbol('INJECTABLE_KEY');
2
2
  export const INJECT_METADATA_KEY = Symbol('INJECT_KEY');
3
3
  export const POSTCONSTRUCT_SYNC_METADATA_KEY = Symbol('POSTCONSTRUCT_SYNC_KEY');
4
4
  export const POSTCONSTRUCT_ASYNC_METADATA_KEY = Symbol('POSTCONSTRUCT_ASYNC_KEY');
5
+ export const RELEASE_METADATA_KEY = Symbol('RELEASE_KEY');
5
6
  export const OPTIONAL_METADATA_KEY = Symbol('OPTIONAL_KEY');
6
7
  export const REFLECT_PARAMS = 'design:paramtypes';
7
8
  export const REFLECT_RETURN = 'design:returntype';
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAChF,MAAM,CAAC,MAAM,gCAAgC,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAClD,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC","sourcesContent":["export const INJECTABLE_METADATA_KEY = Symbol('INJECTABLE_KEY');\nexport const INJECT_METADATA_KEY = Symbol('INJECT_KEY');\nexport const POSTCONSTRUCT_SYNC_METADATA_KEY = Symbol('POSTCONSTRUCT_SYNC_KEY');\nexport const POSTCONSTRUCT_ASYNC_METADATA_KEY = Symbol('POSTCONSTRUCT_ASYNC_KEY');\nexport const OPTIONAL_METADATA_KEY = Symbol('OPTIONAL_KEY');\n\nexport const REFLECT_PARAMS = 'design:paramtypes';\nexport const REFLECT_RETURN = 'design:returntype';\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAChF,MAAM,CAAC,MAAM,gCAAgC,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAClD,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC","sourcesContent":["export const INJECTABLE_METADATA_KEY = Symbol('INJECTABLE_KEY');\nexport const INJECT_METADATA_KEY = Symbol('INJECT_KEY');\nexport const POSTCONSTRUCT_SYNC_METADATA_KEY = Symbol('POSTCONSTRUCT_SYNC_KEY');\nexport const POSTCONSTRUCT_ASYNC_METADATA_KEY = Symbol('POSTCONSTRUCT_ASYNC_KEY');\nexport const RELEASE_METADATA_KEY = Symbol('RELEASE_KEY');\nexport const OPTIONAL_METADATA_KEY = Symbol('OPTIONAL_KEY');\n\nexport const REFLECT_PARAMS = 'design:paramtypes';\nexport const REFLECT_RETURN = 'design:returntype';\n"]}
@@ -2,19 +2,72 @@ import { AsyncFactory, BindAs, Binder, SyncFactory } from './binder';
2
2
  import { AbstractConstructor, ClassConstructor, InjectableId, Injector } from './injector';
3
3
  import { Provider } from './provider';
4
4
  import { State } from './state';
5
+ /**
6
+ * Binder and Injector (aka Container) to handle (a)synchronous dependency management.
7
+ */
5
8
  export declare class Container implements Binder {
6
9
  protected parent?: Injector;
10
+ /**
11
+ * Create a new Container, with an optional parent Injector which will be searched if any given InjectableId is not bound within this Container.
12
+ */
7
13
  constructor(parent?: Injector);
8
14
  protected providers: Map<InjectableId<any>, Provider<any>>;
15
+ /**
16
+ * @inheritDoc
17
+ */
9
18
  isIdKnown<T>(id: InjectableId<T>, ascending?: boolean): boolean;
19
+ /**
20
+ * @inheritDoc
21
+ */
10
22
  get<T>(id: InjectableId<T>): T;
23
+ /**
24
+ * @inheritDoc
25
+ */
11
26
  resolve<T>(id: InjectableId<T>): Promise<T>;
12
- removeBinding<T>(id: InjectableId<T>, ascending?: boolean): void;
27
+ /**
28
+ * This method is not part of the Binding interface, because it is highly unusual.
29
+ * But that doesn't mean we can't imagine scenarios where you might require it.
30
+ *
31
+ * @param id The id to be removed.
32
+ * @param ascending If true, this will remove all bindings of the specified id all the way up the parent container chain (if it exists).
33
+ * @param releaseIfSingleton If true, @Provider.releaseIfSingleton will be invoked before the binding is removed.
34
+ */
35
+ removeBinding<T>(id: InjectableId<T>, ascending?: boolean, releaseIfSingleton?: boolean): void;
36
+ /**
37
+ * @inheritDoc
38
+ */
13
39
  bindConstant<T>(id: InjectableId<T>, value: T): void;
40
+ /**
41
+ * @inheritDoc
42
+ */
14
43
  bindClass<T>(id: ClassConstructor<T>, constructor?: ClassConstructor<T>): BindAs<T, ClassConstructor<T>>;
15
44
  bindClass<T>(id: string | symbol | AbstractConstructor<T>, constructor: ClassConstructor<T>): BindAs<T, ClassConstructor<T>>;
45
+ /**
46
+ * @inheritDoc
47
+ */
16
48
  bindFactory<T>(id: InjectableId<T>, factory: SyncFactory<T>): BindAs<T, SyncFactory<T>>;
49
+ /**
50
+ * @inheritDoc
51
+ */
17
52
  bindAsyncFactory<T>(id: InjectableId<T>, factory: AsyncFactory<T>): BindAs<T, AsyncFactory<T>>;
53
+ /**
54
+ * @inheritDoc
55
+ */
18
56
  resolveSingletons(asyncOnly?: boolean, parentRecursion?: boolean): Promise<void>;
57
+ /**
58
+ * As implied by the name prefix, this is a factored out method invoked only by the 'resolve' method.
59
+ * It makes searching our parent (if it exists) easier (and quicker) IF our parent is a fellow instance of Container.
60
+ */
19
61
  protected resolveState<T>(id: InjectableId<T>): State<T>;
62
+ /**
63
+ * Convenience method to assist in releasing non-garbage-collectable resources that Singletons in this Container may have allocated.
64
+ * It will walk through all registered Providers (of this Container only), and invoke their @see Provider.releaseIfSingleton method.
65
+ * This method is not part of the Binding interface, because you normally only create (and release) Containers.
66
+ * NOTE:
67
+ * This *only* releases active/pending Singleton's that have already been created by this Container.
68
+ * The most likely use of this method would be when you have created a new child Container for a limited duration transaction, and you want to easily cleanup temporary resources.
69
+ * For example, your service object may need to know when it should unsubscribe from an RxJs stream (failure to do so can result in your Singleton not being garbage collected at the end of a transaction).
70
+ * In theory, you could handle all unsubscription and cleanup yourself, but the @Release decorator and this method are meant to simply make that easier.
71
+ */
72
+ releaseSingletons(): void;
20
73
  }
@@ -4,16 +4,31 @@ import { ConstantProvider } from './constant-provider';
4
4
  import { INJECTABLE_METADATA_KEY } from './constants';
5
5
  import { State } from './state';
6
6
  import { FactoryBasedProvider } from './sync-factory-provider';
7
+ import { isPromise } from './utils';
8
+ /**
9
+ * Helper class to ensure we can distinguish between Error instances legitimately returned from Providers, and Errors thrown by Providers.
10
+ *
11
+ * @see resolveSingletons.
12
+ */
7
13
  class ReasonWrapper {
8
14
  constructor(reason) {
9
15
  this.reason = reason;
10
16
  }
11
17
  }
18
+ /**
19
+ * Binder and Injector (aka Container) to handle (a)synchronous dependency management.
20
+ */
12
21
  export class Container {
22
+ /**
23
+ * Create a new Container, with an optional parent Injector which will be searched if any given InjectableId is not bound within this Container.
24
+ */
13
25
  constructor(parent) {
14
26
  this.parent = parent;
15
27
  this.providers = new Map();
16
28
  }
29
+ /**
30
+ * @inheritDoc
31
+ */
17
32
  isIdKnown(id, ascending) {
18
33
  if (!!this.providers.get(id))
19
34
  return true;
@@ -21,23 +36,29 @@ export class Container {
21
36
  return this.parent.isIdKnown(id, true);
22
37
  return false;
23
38
  }
39
+ /**
40
+ * @inheritDoc
41
+ */
24
42
  get(id) {
25
- let provider = this.providers.get(id);
43
+ const provider = this.providers.get(id);
26
44
  if (!provider) {
27
45
  if (this.parent)
28
46
  return this.parent.get(id);
29
47
  throw new Error('Symbol not bound: ' + id.toString());
30
48
  }
31
- let state = provider.provideAsState();
49
+ const state = provider.provideAsState();
32
50
  if (state.pending)
33
51
  throw new Error('Synchronous request on unresolved asynchronous dependency tree: ' + id.toString());
34
52
  if (state.rejected)
35
53
  throw state.rejected;
36
54
  return state.fulfilled;
37
55
  }
56
+ /**
57
+ * @inheritDoc
58
+ */
38
59
  resolve(id) {
39
- let state = this.resolveState(id);
40
- if (state.promise) {
60
+ const state = this.resolveState(id);
61
+ if (isPromise(state.promise)) {
41
62
  return state.promise;
42
63
  }
43
64
  if (state.rejected) {
@@ -45,11 +66,31 @@ export class Container {
45
66
  }
46
67
  return Promise.resolve(state.fulfilled);
47
68
  }
48
- removeBinding(id, ascending) {
69
+ // noinspection JSUnusedGlobalSymbols
70
+ /**
71
+ * This method is not part of the Binding interface, because it is highly unusual.
72
+ * But that doesn't mean we can't imagine scenarios where you might require it.
73
+ *
74
+ * @param id The id to be removed.
75
+ * @param ascending If true, this will remove all bindings of the specified id all the way up the parent container chain (if it exists).
76
+ * @param releaseIfSingleton If true, @Provider.releaseIfSingleton will be invoked before the binding is removed.
77
+ */
78
+ removeBinding(id, ascending, releaseIfSingleton) {
79
+ var _a;
80
+ if (releaseIfSingleton) {
81
+ const p = this.providers.get(id);
82
+ if (p)
83
+ p.releaseIfSingleton();
84
+ }
49
85
  this.providers.delete(id);
50
- if (ascending && this.parent && this.parent.removeBinding)
51
- this.parent.removeBinding(id, true);
86
+ if (ascending && this.parent) {
87
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
88
+ (_a = this.parent) === null || _a === void 0 ? void 0 : _a.removeBinding(id, true, releaseIfSingleton);
89
+ }
52
90
  }
91
+ /**
92
+ * @inheritDoc
93
+ */
53
94
  bindConstant(id, value) {
54
95
  this.providers.set(id, new ConstantProvider(value));
55
96
  }
@@ -60,62 +101,87 @@ export class Container {
60
101
  if (!Reflect.getMetadata(INJECTABLE_METADATA_KEY, constructor)) {
61
102
  throw new Error('Class not decorated with @Injectable [' + constructor.toString() + ']');
62
103
  }
63
- let provider = new ClassBasedProvider(this, id, constructor, (i) => {
104
+ const provider = new ClassBasedProvider(this, id, constructor, (i) => {
64
105
  return this.resolveState(i);
65
106
  });
66
107
  this.providers.set(id, provider);
67
108
  return provider.makeBindAs();
68
109
  }
110
+ /**
111
+ * @inheritDoc
112
+ */
69
113
  bindFactory(id, factory) {
70
- let provider = new FactoryBasedProvider(this, id, factory);
114
+ const provider = new FactoryBasedProvider(this, id, factory);
71
115
  this.providers.set(id, provider);
72
116
  return provider.makeBindAs();
73
117
  }
118
+ /**
119
+ * @inheritDoc
120
+ */
74
121
  bindAsyncFactory(id, factory) {
75
- let provider = new AsyncFactoryBasedProvider(this, id, factory);
122
+ const provider = new AsyncFactoryBasedProvider(this, id, factory);
76
123
  this.providers.set(id, provider);
77
124
  return provider.makeBindAs();
78
125
  }
126
+ /**
127
+ * @inheritDoc
128
+ */
79
129
  resolveSingletons(asyncOnly, parentRecursion) {
80
- let makePromiseToResolve = () => {
130
+ var _a;
131
+ const makePromiseToResolve = () => {
81
132
  return new Promise((resolve, reject) => {
82
- let pending = new Map();
133
+ const pending = new Map();
134
+ // Ask each provider to resolve itself *IF* it is a singleton.
83
135
  this.providers.forEach((value, key) => {
84
- let p = value.resolveIfSingleton(asyncOnly);
85
- if (p)
136
+ // If the provider is a singleton *and* if resolution is being handled asynchronously, the provider will return a completion promise.
137
+ const p = value.resolveIfSingleton(asyncOnly);
138
+ if (p !== null && typeof p !== 'undefined')
86
139
  pending.set(key, p);
87
140
  });
88
- let pp = Array.from(pending.values());
89
- let keys = Array.from(pending.keys());
90
- Promise.all(pp.map(p => p.catch(e => new ReasonWrapper(e)))).then((results) => {
91
- let rejects = new Map();
141
+ // The contract for this method is that it behaves somewhat like Promise.allSettled (e.g. won't complete until all pending Singletons have settled).
142
+ // Further the contract states that if any of the asynchronous Singletons rejected, that we will also return a rejected Promise, and that the rejection reason will be a Map of the InjectableId's that did not resolve, and the Error they emitted.
143
+ const pp = Array.from(pending.values());
144
+ const keys = Array.from(pending.keys());
145
+ // Mapping the catch is an alternate version of Promise.allSettled (e.g. keeps Promise.all from short-circuiting).
146
+ Promise.all(pp
147
+ .map(p => p.catch(e => new ReasonWrapper(e))))
148
+ .then((results) => {
149
+ const rejects = new Map();
150
+ // Check the results. Since we don't export ReasonWrapper, it is safe to assume that an instance of that was produced by our map => catch code above, so it's a rejected Singleton error.
92
151
  results.forEach((result, idx) => {
93
152
  if (result instanceof ReasonWrapper) {
94
153
  rejects.set(keys[idx], result.reason);
95
154
  }
96
155
  });
156
+ // If we had rejections, notify our caller what they were.
97
157
  if (rejects.size > 0)
98
158
  reject(rejects);
99
159
  else
100
- resolve();
160
+ resolve(); // All good.
101
161
  });
102
162
  });
103
163
  };
104
- if (parentRecursion && this.parent && this.parent.resolveSingletons) {
105
- let pb = this.parent;
164
+ if (parentRecursion && typeof ((_a = this.parent) === null || _a === void 0 ? void 0 : _a.resolveSingletons) === "function") {
165
+ const pb = this.parent;
106
166
  return pb.resolveSingletons(asyncOnly, parentRecursion).then(() => {
107
167
  return makePromiseToResolve();
108
168
  });
109
169
  }
110
170
  return makePromiseToResolve();
111
171
  }
172
+ /**
173
+ * As implied by the name prefix, this is a factored out method invoked only by the 'resolve' method.
174
+ * It makes searching our parent (if it exists) easier (and quicker) IF our parent is a fellow instance of Container.
175
+ */
112
176
  resolveState(id) {
113
- let provider = this.providers.get(id);
177
+ const provider = this.providers.get(id);
114
178
  if (!provider) {
115
179
  if (this.parent) {
116
180
  if (this.parent instanceof Container) {
117
181
  return this.parent.resolveState(id);
118
182
  }
183
+ // This code (below) will only ever execute if the creator of this container passes in their own implementation of an Injector.
184
+ /* istanbul ignore next */
119
185
  try {
120
186
  return State.MakeState(this.parent.resolve(id), undefined, undefined);
121
187
  }
@@ -127,5 +193,21 @@ export class Container {
127
193
  }
128
194
  return provider.provideAsState();
129
195
  }
196
+ // noinspection JSUnusedGlobalSymbols
197
+ /**
198
+ * Convenience method to assist in releasing non-garbage-collectable resources that Singletons in this Container may have allocated.
199
+ * It will walk through all registered Providers (of this Container only), and invoke their @see Provider.releaseIfSingleton method.
200
+ * This method is not part of the Binding interface, because you normally only create (and release) Containers.
201
+ * NOTE:
202
+ * This *only* releases active/pending Singleton's that have already been created by this Container.
203
+ * The most likely use of this method would be when you have created a new child Container for a limited duration transaction, and you want to easily cleanup temporary resources.
204
+ * For example, your service object may need to know when it should unsubscribe from an RxJs stream (failure to do so can result in your Singleton not being garbage collected at the end of a transaction).
205
+ * In theory, you could handle all unsubscription and cleanup yourself, but the @Release decorator and this method are meant to simply make that easier.
206
+ */
207
+ releaseSingletons() {
208
+ this.providers.forEach((value) => {
209
+ value.releaseIfSingleton();
210
+ });
211
+ }
130
212
  }
131
213
  //# sourceMappingURL=container.js.map