dependency-container.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. import { __awaiter, __generator, __read, __spread, __values } from "tslib";
  2. import { isClassProvider, isFactoryProvider, isNormalToken, isTokenProvider, isValueProvider } from "./providers";
  3. import { isProvider } from "./providers/provider";
  4. import { isConstructorToken, isTokenDescriptor, isTransformDescriptor } from "./providers/injection-token";
  5. import Registry from "./registry";
  6. import Lifecycle from "./types/lifecycle";
  7. import ResolutionContext from "./resolution-context";
  8. import { formatErrorCtor } from "./error-helpers";
  9. import { DelayedConstructor } from "./lazy-helpers";
  10. import { isDisposable } from "./types/disposable";
  11. import Interceptors from "./interceptors";
  12. export var typeInfo = new Map();
  13. var InternalDependencyContainer = (function () {
  14. function InternalDependencyContainer(parent) {
  15. this.parent = parent;
  16. this._registry = new Registry();
  17. this.interceptors = new Interceptors();
  18. this.disposed = false;
  19. this.disposables = new Set();
  20. }
  21. InternalDependencyContainer.prototype.register = function (token, providerOrConstructor, options) {
  22. if (options === void 0) { options = { lifecycle: Lifecycle.Transient }; }
  23. this.ensureNotDisposed();
  24. var provider;
  25. if (!isProvider(providerOrConstructor)) {
  26. provider = { useClass: providerOrConstructor };
  27. }
  28. else {
  29. provider = providerOrConstructor;
  30. }
  31. if (isTokenProvider(provider)) {
  32. var path = [token];
  33. var tokenProvider = provider;
  34. while (tokenProvider != null) {
  35. var currentToken = tokenProvider.useToken;
  36. if (path.includes(currentToken)) {
  37. throw new Error("Token registration cycle detected! " + __spread(path, [currentToken]).join(" -> "));
  38. }
  39. path.push(currentToken);
  40. var registration = this._registry.get(currentToken);
  41. if (registration && isTokenProvider(registration.provider)) {
  42. tokenProvider = registration.provider;
  43. }
  44. else {
  45. tokenProvider = null;
  46. }
  47. }
  48. }
  49. if (options.lifecycle === Lifecycle.Singleton ||
  50. options.lifecycle == Lifecycle.ContainerScoped ||
  51. options.lifecycle == Lifecycle.ResolutionScoped) {
  52. if (isValueProvider(provider) || isFactoryProvider(provider)) {
  53. throw new Error("Cannot use lifecycle \"" + Lifecycle[options.lifecycle] + "\" with ValueProviders or FactoryProviders");
  54. }
  55. }
  56. this._registry.set(token, { provider: provider, options: options });
  57. return this;
  58. };
  59. InternalDependencyContainer.prototype.registerType = function (from, to) {
  60. this.ensureNotDisposed();
  61. if (isNormalToken(to)) {
  62. return this.register(from, {
  63. useToken: to
  64. });
  65. }
  66. return this.register(from, {
  67. useClass: to
  68. });
  69. };
  70. InternalDependencyContainer.prototype.registerInstance = function (token, instance) {
  71. this.ensureNotDisposed();
  72. return this.register(token, {
  73. useValue: instance
  74. });
  75. };
  76. InternalDependencyContainer.prototype.registerSingleton = function (from, to) {
  77. this.ensureNotDisposed();
  78. if (isNormalToken(from)) {
  79. if (isNormalToken(to)) {
  80. return this.register(from, {
  81. useToken: to
  82. }, { lifecycle: Lifecycle.Singleton });
  83. }
  84. else if (to) {
  85. return this.register(from, {
  86. useClass: to
  87. }, { lifecycle: Lifecycle.Singleton });
  88. }
  89. throw new Error('Cannot register a type name as a singleton without a "to" token');
  90. }
  91. var useClass = from;
  92. if (to && !isNormalToken(to)) {
  93. useClass = to;
  94. }
  95. return this.register(from, {
  96. useClass: useClass
  97. }, { lifecycle: Lifecycle.Singleton });
  98. };
  99. InternalDependencyContainer.prototype.resolve = function (token, context, isOptional) {
  100. if (context === void 0) { context = new ResolutionContext(); }
  101. if (isOptional === void 0) { isOptional = false; }
  102. this.ensureNotDisposed();
  103. var registration = this.getRegistration(token);
  104. if (!registration && isNormalToken(token)) {
  105. if (isOptional) {
  106. return undefined;
  107. }
  108. throw new Error("Attempted to resolve unregistered dependency token: \"" + token.toString() + "\"");
  109. }
  110. this.executePreResolutionInterceptor(token, "Single");
  111. if (registration) {
  112. var result = this.resolveRegistration(registration, context);
  113. this.executePostResolutionInterceptor(token, result, "Single");
  114. return result;
  115. }
  116. if (isConstructorToken(token)) {
  117. var result = this.construct(token, context);
  118. this.executePostResolutionInterceptor(token, result, "Single");
  119. return result;
  120. }
  121. throw new Error("Attempted to construct an undefined constructor. Could mean a circular dependency problem. Try using `delay` function.");
  122. };
  123. InternalDependencyContainer.prototype.executePreResolutionInterceptor = function (token, resolutionType) {
  124. var e_1, _a;
  125. if (this.interceptors.preResolution.has(token)) {
  126. var remainingInterceptors = [];
  127. try {
  128. for (var _b = __values(this.interceptors.preResolution.getAll(token)), _c = _b.next(); !_c.done; _c = _b.next()) {
  129. var interceptor = _c.value;
  130. if (interceptor.options.frequency != "Once") {
  131. remainingInterceptors.push(interceptor);
  132. }
  133. interceptor.callback(token, resolutionType);
  134. }
  135. }
  136. catch (e_1_1) { e_1 = { error: e_1_1 }; }
  137. finally {
  138. try {
  139. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  140. }
  141. finally { if (e_1) throw e_1.error; }
  142. }
  143. this.interceptors.preResolution.setAll(token, remainingInterceptors);
  144. }
  145. };
  146. InternalDependencyContainer.prototype.executePostResolutionInterceptor = function (token, result, resolutionType) {
  147. var e_2, _a;
  148. if (this.interceptors.postResolution.has(token)) {
  149. var remainingInterceptors = [];
  150. try {
  151. for (var _b = __values(this.interceptors.postResolution.getAll(token)), _c = _b.next(); !_c.done; _c = _b.next()) {
  152. var interceptor = _c.value;
  153. if (interceptor.options.frequency != "Once") {
  154. remainingInterceptors.push(interceptor);
  155. }
  156. interceptor.callback(token, result, resolutionType);
  157. }
  158. }
  159. catch (e_2_1) { e_2 = { error: e_2_1 }; }
  160. finally {
  161. try {
  162. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  163. }
  164. finally { if (e_2) throw e_2.error; }
  165. }
  166. this.interceptors.postResolution.setAll(token, remainingInterceptors);
  167. }
  168. };
  169. InternalDependencyContainer.prototype.resolveRegistration = function (registration, context) {
  170. this.ensureNotDisposed();
  171. if (registration.options.lifecycle === Lifecycle.ResolutionScoped &&
  172. context.scopedResolutions.has(registration)) {
  173. return context.scopedResolutions.get(registration);
  174. }
  175. var isSingleton = registration.options.lifecycle === Lifecycle.Singleton;
  176. var isContainerScoped = registration.options.lifecycle === Lifecycle.ContainerScoped;
  177. var returnInstance = isSingleton || isContainerScoped;
  178. var resolved;
  179. if (isValueProvider(registration.provider)) {
  180. resolved = registration.provider.useValue;
  181. }
  182. else if (isTokenProvider(registration.provider)) {
  183. resolved = returnInstance
  184. ? registration.instance ||
  185. (registration.instance = this.resolve(registration.provider.useToken, context))
  186. : this.resolve(registration.provider.useToken, context);
  187. }
  188. else if (isClassProvider(registration.provider)) {
  189. resolved = returnInstance
  190. ? registration.instance ||
  191. (registration.instance = this.construct(registration.provider.useClass, context))
  192. : this.construct(registration.provider.useClass, context);
  193. }
  194. else if (isFactoryProvider(registration.provider)) {
  195. resolved = registration.provider.useFactory(this);
  196. }
  197. else {
  198. resolved = this.construct(registration.provider, context);
  199. }
  200. if (registration.options.lifecycle === Lifecycle.ResolutionScoped) {
  201. context.scopedResolutions.set(registration, resolved);
  202. }
  203. return resolved;
  204. };
  205. InternalDependencyContainer.prototype.resolveAll = function (token, context, isOptional) {
  206. var _this = this;
  207. if (context === void 0) { context = new ResolutionContext(); }
  208. if (isOptional === void 0) { isOptional = false; }
  209. this.ensureNotDisposed();
  210. var registrations = this.getAllRegistrations(token);
  211. if (!registrations && isNormalToken(token)) {
  212. if (isOptional) {
  213. return [];
  214. }
  215. throw new Error("Attempted to resolve unregistered dependency token: \"" + token.toString() + "\"");
  216. }
  217. this.executePreResolutionInterceptor(token, "All");
  218. if (registrations) {
  219. var result_1 = registrations.map(function (item) {
  220. return _this.resolveRegistration(item, context);
  221. });
  222. this.executePostResolutionInterceptor(token, result_1, "All");
  223. return result_1;
  224. }
  225. var result = [this.construct(token, context)];
  226. this.executePostResolutionInterceptor(token, result, "All");
  227. return result;
  228. };
  229. InternalDependencyContainer.prototype.isRegistered = function (token, recursive) {
  230. if (recursive === void 0) { recursive = false; }
  231. this.ensureNotDisposed();
  232. return (this._registry.has(token) ||
  233. (recursive &&
  234. (this.parent || false) &&
  235. this.parent.isRegistered(token, true)));
  236. };
  237. InternalDependencyContainer.prototype.reset = function () {
  238. this.ensureNotDisposed();
  239. this._registry.clear();
  240. this.interceptors.preResolution.clear();
  241. this.interceptors.postResolution.clear();
  242. };
  243. InternalDependencyContainer.prototype.clearInstances = function () {
  244. var e_3, _a;
  245. this.ensureNotDisposed();
  246. try {
  247. for (var _b = __values(this._registry.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
  248. var _d = __read(_c.value, 2), token = _d[0], registrations = _d[1];
  249. this._registry.setAll(token, registrations
  250. .filter(function (registration) { return !isValueProvider(registration.provider); })
  251. .map(function (registration) {
  252. registration.instance = undefined;
  253. return registration;
  254. }));
  255. }
  256. }
  257. catch (e_3_1) { e_3 = { error: e_3_1 }; }
  258. finally {
  259. try {
  260. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  261. }
  262. finally { if (e_3) throw e_3.error; }
  263. }
  264. };
  265. InternalDependencyContainer.prototype.createChildContainer = function () {
  266. var e_4, _a;
  267. this.ensureNotDisposed();
  268. var childContainer = new InternalDependencyContainer(this);
  269. try {
  270. for (var _b = __values(this._registry.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
  271. var _d = __read(_c.value, 2), token = _d[0], registrations = _d[1];
  272. if (registrations.some(function (_a) {
  273. var options = _a.options;
  274. return options.lifecycle === Lifecycle.ContainerScoped;
  275. })) {
  276. childContainer._registry.setAll(token, registrations.map(function (registration) {
  277. if (registration.options.lifecycle === Lifecycle.ContainerScoped) {
  278. return {
  279. provider: registration.provider,
  280. options: registration.options
  281. };
  282. }
  283. return registration;
  284. }));
  285. }
  286. }
  287. }
  288. catch (e_4_1) { e_4 = { error: e_4_1 }; }
  289. finally {
  290. try {
  291. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  292. }
  293. finally { if (e_4) throw e_4.error; }
  294. }
  295. return childContainer;
  296. };
  297. InternalDependencyContainer.prototype.beforeResolution = function (token, callback, options) {
  298. if (options === void 0) { options = { frequency: "Always" }; }
  299. this.interceptors.preResolution.set(token, {
  300. callback: callback,
  301. options: options
  302. });
  303. };
  304. InternalDependencyContainer.prototype.afterResolution = function (token, callback, options) {
  305. if (options === void 0) { options = { frequency: "Always" }; }
  306. this.interceptors.postResolution.set(token, {
  307. callback: callback,
  308. options: options
  309. });
  310. };
  311. InternalDependencyContainer.prototype.dispose = function () {
  312. return __awaiter(this, void 0, void 0, function () {
  313. var promises;
  314. return __generator(this, function (_a) {
  315. switch (_a.label) {
  316. case 0:
  317. this.disposed = true;
  318. promises = [];
  319. this.disposables.forEach(function (disposable) {
  320. var maybePromise = disposable.dispose();
  321. if (maybePromise) {
  322. promises.push(maybePromise);
  323. }
  324. });
  325. return [4, Promise.all(promises)];
  326. case 1:
  327. _a.sent();
  328. return [2];
  329. }
  330. });
  331. });
  332. };
  333. InternalDependencyContainer.prototype.getRegistration = function (token) {
  334. if (this.isRegistered(token)) {
  335. return this._registry.get(token);
  336. }
  337. if (this.parent) {
  338. return this.parent.getRegistration(token);
  339. }
  340. return null;
  341. };
  342. InternalDependencyContainer.prototype.getAllRegistrations = function (token) {
  343. if (this.isRegistered(token)) {
  344. return this._registry.getAll(token);
  345. }
  346. if (this.parent) {
  347. return this.parent.getAllRegistrations(token);
  348. }
  349. return null;
  350. };
  351. InternalDependencyContainer.prototype.construct = function (ctor, context) {
  352. var _this = this;
  353. if (ctor instanceof DelayedConstructor) {
  354. return ctor.createProxy(function (target) {
  355. return _this.resolve(target, context);
  356. });
  357. }
  358. var instance = (function () {
  359. var paramInfo = typeInfo.get(ctor);
  360. if (!paramInfo || paramInfo.length === 0) {
  361. if (ctor.length === 0) {
  362. return new ctor();
  363. }
  364. else {
  365. throw new Error("TypeInfo not known for \"" + ctor.name + "\"");
  366. }
  367. }
  368. var params = paramInfo.map(_this.resolveParams(context, ctor));
  369. return new (ctor.bind.apply(ctor, __spread([void 0], params)))();
  370. })();
  371. if (isDisposable(instance)) {
  372. this.disposables.add(instance);
  373. }
  374. return instance;
  375. };
  376. InternalDependencyContainer.prototype.resolveParams = function (context, ctor) {
  377. var _this = this;
  378. return function (param, idx) {
  379. var _a, _b, _c;
  380. try {
  381. if (isTokenDescriptor(param)) {
  382. if (isTransformDescriptor(param)) {
  383. return param.multiple
  384. ? (_a = _this.resolve(param.transform)).transform.apply(_a, __spread([_this.resolveAll(param.token, new ResolutionContext(), param.isOptional)], param.transformArgs)) : (_b = _this.resolve(param.transform)).transform.apply(_b, __spread([_this.resolve(param.token, context, param.isOptional)], param.transformArgs));
  385. }
  386. else {
  387. return param.multiple
  388. ? _this.resolveAll(param.token, new ResolutionContext(), param.isOptional)
  389. : _this.resolve(param.token, context, param.isOptional);
  390. }
  391. }
  392. else if (isTransformDescriptor(param)) {
  393. return (_c = _this.resolve(param.transform, context)).transform.apply(_c, __spread([_this.resolve(param.token, context)], param.transformArgs));
  394. }
  395. return _this.resolve(param, context);
  396. }
  397. catch (e) {
  398. throw new Error(formatErrorCtor(ctor, idx, e));
  399. }
  400. };
  401. };
  402. InternalDependencyContainer.prototype.ensureNotDisposed = function () {
  403. if (this.disposed) {
  404. throw new Error("This container has been disposed, you cannot interact with a disposed container");
  405. }
  406. };
  407. return InternalDependencyContainer;
  408. }());
  409. export var instance = new InternalDependencyContainer();
  410. export default instance;