ts-ioc-container 51.0.0 → 52.0.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 (39) hide show
  1. package/README.md +31 -40
  2. package/cjm/container/Container.js +6 -6
  3. package/cjm/errors/CannonSingletonApplyError.js +12 -0
  4. package/cjm/hooks/HookContext.js +2 -2
  5. package/cjm/index.js +15 -20
  6. package/cjm/injector/MetadataInjector.js +21 -3
  7. package/cjm/provider/IProvider.js +0 -49
  8. package/cjm/provider/Provider.js +34 -20
  9. package/cjm/registration/IRegistration.js +23 -5
  10. package/cjm/registration/Registration.js +7 -11
  11. package/esm/container/Container.js +6 -6
  12. package/esm/errors/CannonSingletonApplyError.js +8 -0
  13. package/esm/hooks/HookContext.js +1 -1
  14. package/esm/index.js +3 -7
  15. package/esm/injector/MetadataInjector.js +15 -1
  16. package/esm/provider/IProvider.js +1 -43
  17. package/esm/provider/Provider.js +34 -20
  18. package/esm/registration/IRegistration.js +13 -3
  19. package/esm/registration/Registration.js +4 -8
  20. package/package.json +1 -1
  21. package/typings/errors/CannonSingletonApplyError.d.ts +5 -0
  22. package/typings/index.d.ts +4 -7
  23. package/typings/injector/MetadataInjector.d.ts +7 -0
  24. package/typings/provider/IProvider.d.ts +7 -24
  25. package/typings/provider/Provider.d.ts +11 -9
  26. package/typings/registration/IRegistration.d.ts +15 -4
  27. package/typings/registration/Registration.d.ts +1 -2
  28. package/cjm/injector/inject.js +0 -22
  29. package/cjm/provider/DecoratorProvider.js +0 -21
  30. package/cjm/provider/ProviderPipe.js +0 -10
  31. package/cjm/provider/SingletonProvider.js +0 -26
  32. package/esm/injector/inject.js +0 -15
  33. package/esm/provider/DecoratorProvider.js +0 -16
  34. package/esm/provider/ProviderPipe.js +0 -5
  35. package/esm/provider/SingletonProvider.js +0 -21
  36. package/typings/injector/inject.d.ts +0 -9
  37. package/typings/provider/DecoratorProvider.d.ts +0 -12
  38. package/typings/provider/ProviderPipe.d.ts +0 -8
  39. package/typings/provider/SingletonProvider.d.ts +0 -14
package/README.md CHANGED
@@ -681,7 +681,18 @@ The `lazy()` registerPipe can be used in two ways: with the `@register` decorato
681
681
 
682
682
  ```typescript
683
683
  import 'reflect-metadata';
684
- import { args, bindTo, Container, inject, lazy, Provider, register, Registration as R, singleton } from 'ts-ioc-container';
684
+ import {
685
+ appendArgs,
686
+ args,
687
+ bindTo,
688
+ Container,
689
+ inject,
690
+ lazy,
691
+ Provider,
692
+ register,
693
+ Registration as R,
694
+ singleton,
695
+ } from 'ts-ioc-container';
685
696
 
686
697
  /**
687
698
  * Lazy Loading with registerPipe
@@ -853,7 +864,7 @@ describe('lazy registerPipe', () => {
853
864
  it('should allow selective lazy loading - email lazy, SMS eager', () => {
854
865
  const container = new Container()
855
866
  // EmailService is lazy - won't connect to SMTP until used
856
- .addRegistration(R.fromClass(EmailService).pipe(singleton(), (p) => p.lazy()))
867
+ .addRegistration(R.fromClass(EmailService).pipe(singleton(), lazy()))
857
868
  // SmsService is eager - connects to gateway immediately
858
869
  .addRegistration(R.fromClass(SmsService).pipe(singleton()))
859
870
  .addRegistration(R.fromClass(NotificationService));
@@ -872,7 +883,7 @@ describe('lazy registerPipe', () => {
872
883
 
873
884
  it('should initialize lazy email service when first accessed', () => {
874
885
  const container = new Container()
875
- .addRegistration(R.fromClass(EmailService).pipe(singleton(), (p) => p.lazy()))
886
+ .addRegistration(R.fromClass(EmailService).pipe(singleton(), lazy()))
876
887
  .addRegistration(R.fromClass(SmsService).pipe(singleton()))
877
888
  .addRegistration(R.fromClass(NotificationService));
878
889
 
@@ -888,8 +899,8 @@ describe('lazy registerPipe', () => {
888
899
  it('should work with multiple lazy providers', () => {
889
900
  const container = new Container()
890
901
  // Both services are lazy
891
- .addRegistration(R.fromClass(EmailService).pipe(singleton(), (p) => p.lazy()))
892
- .addRegistration(R.fromClass(SmsService).pipe(singleton(), (p) => p.lazy()))
902
+ .addRegistration(R.fromClass(EmailService).pipe(singleton(), lazy()))
903
+ .addRegistration(R.fromClass(SmsService).pipe(singleton(), lazy()))
893
904
  .addRegistration(R.fromClass(NotificationService));
894
905
 
895
906
  const notifications = container.resolve<NotificationService>(NotificationService);
@@ -940,7 +951,7 @@ describe('lazy registerPipe', () => {
940
951
 
941
952
  it('should use Provider.fromClass with lazy() helper', () => {
942
953
  // Create pure provider with lazy loading
943
- const cacheProvider = Provider.fromClass(CacheService).pipe(lazy(), singleton());
954
+ const cacheProvider = Provider.fromClass(CacheService).lazy().singleton();
944
955
 
945
956
  const container = new Container();
946
957
  container.register('CacheService', cacheProvider);
@@ -958,7 +969,7 @@ describe('lazy registerPipe', () => {
958
969
 
959
970
  it('should allow importing lazy as named export', () => {
960
971
  // Demonstrate that lazy() is imported from the library
961
- const cacheProvider = Provider.fromClass(CacheService).pipe(lazy());
972
+ const cacheProvider = Provider.fromClass(CacheService).lazy();
962
973
 
963
974
  const container = new Container();
964
975
  container.register('CacheService', cacheProvider);
@@ -990,12 +1001,7 @@ describe('lazy registerPipe', () => {
990
1001
 
991
1002
  it('should combine lazy with args and singleton', () => {
992
1003
  const container = new Container().addRegistration(
993
- R.fromClass(ConfigService)
994
- .pipe(
995
- (p) => p.addArgs('https://api.example.com', 5000),
996
- (p) => p.lazy(),
997
- )
998
- .pipe(singleton()),
1004
+ R.fromClass(ConfigService).pipe(appendArgs('https://api.example.com', 5000), lazy()).pipe(singleton()),
999
1005
  );
1000
1006
 
1001
1007
  // Config not initialized yet
@@ -1288,20 +1294,7 @@ Provider is dependency factory which creates dependency.
1288
1294
  - `new Provider((container, options) => container.resolve(Logger, options))`
1289
1295
 
1290
1296
  ```typescript
1291
- import {
1292
- args,
1293
- appendArgs,
1294
- appendArgsFn,
1295
- bindTo,
1296
- Container,
1297
- inject,
1298
- lazy,
1299
- Provider,
1300
- register,
1301
- Registration as R,
1302
- scopeAccess,
1303
- singleton,
1304
- } from 'ts-ioc-container';
1297
+ import { args, bindTo, Container, inject, lazy, Provider, register, Registration as R } from 'ts-ioc-container';
1305
1298
 
1306
1299
  /**
1307
1300
  * Data Processing Pipeline - Provider Patterns
@@ -1338,10 +1331,10 @@ describe('Provider', () => {
1338
1331
  });
1339
1332
 
1340
1333
  it('can be featured by fp method (Singleton Pattern)', () => {
1341
- // Pipe "singleton()" to cache the instance
1334
+ // Use ".singleton()" to cache the instance
1342
1335
  const appContainer = new Container({ tags: ['application'] }).register(
1343
1336
  'SharedLogger',
1344
- Provider.fromClass(Logger).pipe(singleton()),
1337
+ Provider.fromClass(Logger).singleton(),
1345
1338
  );
1346
1339
  expect(appContainer.resolve('SharedLogger')).toBe(appContainer.resolve('SharedLogger'));
1347
1340
  });
@@ -1373,7 +1366,7 @@ describe('Provider', () => {
1373
1366
 
1374
1367
  const container = new Container().register(
1375
1368
  'FileService',
1376
- Provider.fromClass(FileService).pipe(appendArgs('/var/data')),
1369
+ Provider.fromClass(FileService).addArgsFn((_, { args = [] } = {}) => [...args, '/var/data']),
1377
1370
  );
1378
1371
 
1379
1372
  const service = container.resolve<FileService>('FileService');
@@ -1387,10 +1380,8 @@ describe('Provider', () => {
1387
1380
 
1388
1381
  const container = new Container().register('DbPath', Provider.fromValue('localhost:5432')).register(
1389
1382
  'Database',
1390
- Provider.fromClass(Database).pipe(
1391
- // Dynamically resolve connection string at creation time
1392
- appendArgsFn((scope) => [`postgres://${scope.resolve('DbPath')}`]),
1393
- ),
1383
+ // Dynamically resolve connection string at creation time
1384
+ Provider.fromClass(Database).addArgsFn((scope) => [`postgres://${scope.resolve('DbPath')}`]),
1394
1385
  );
1395
1386
 
1396
1387
  const db = container.resolve<Database>('Database');
@@ -1403,7 +1394,7 @@ describe('Provider', () => {
1403
1394
 
1404
1395
  const appContainer = new Container({ tags: ['application'] }).register(
1405
1396
  'AdminService',
1406
- Provider.fromClass(AdminService).pipe(scopeAccess((_prev, { invocationScope }) => invocationScope.hasTag('admin'))),
1397
+ Provider.fromClass(AdminService).addAccessRule(({ invocationScope }) => invocationScope.hasTag('admin')),
1407
1398
  );
1408
1399
 
1409
1400
  const adminScope = appContainer.createScope({ tags: ['admin'] });
@@ -1778,8 +1769,8 @@ Sometimes you want to hide dependency if somebody wants to resolve it from certa
1778
1769
  > [!IMPORTANT]
1779
1770
  > Use `scope()` to decide where a provider is registered. Use `scopeAccess()` to decide which invocation scopes can see an already registered provider.
1780
1771
 
1781
- - `provider(scopeAccess((_prev, { invocationScope, providerScope }) => invocationScope === providerScope))` - dependency will be accessible only from the scope where it's registered
1782
- - `Provider.fromClass(Logger).pipe(scopeAccess((_prev, { invocationScope, providerScope }) => invocationScope === providerScope))`
1772
+ - `provider(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))` - dependency will be accessible only from the scope where it's registered
1773
+ - `Provider.fromClass(Logger).pipe(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))`
1783
1774
 
1784
1775
  Rules compose as a left-fold starting from `true` — each rule receives the accumulated result of all previous rules, enabling AND/OR logic across multiple `scopeAccess` calls.
1785
1776
 
@@ -1820,7 +1811,7 @@ describe('Visibility', function () {
1820
1811
  scope((s) => s.hasTag('application')), // Registered at app level
1821
1812
  singleton(),
1822
1813
  // Only accessible from admin scope, not regular request scope
1823
- scopeAccess((_prev, { invocationScope }) => invocationScope.hasTag('admin')),
1814
+ scopeAccess(({ invocationScope }) => invocationScope.hasTag('admin')),
1824
1815
  )
1825
1816
  class UserManagementService {
1826
1817
  deleteUser(userId: string): string {
@@ -1852,7 +1843,7 @@ describe('Visibility', function () {
1852
1843
  scope((s) => s.hasTag('application')),
1853
1844
  singleton(),
1854
1845
  // Only accessible from the scope where it was registered
1855
- scopeAccess((_prev, { invocationScope, providerScope }) => invocationScope === providerScope),
1846
+ scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope),
1856
1847
  )
1857
1848
  class AuditLogger {
1858
1849
  log(message: string): string {
@@ -2023,7 +2014,7 @@ describe('alias', () => {
2023
2014
 
2024
2015
  ### Decorator
2025
2016
 
2026
- Sometimes you want to decorate you class with some logic. This is what `DecoratorProvider` is for.
2017
+ Sometimes you want to decorate you class with some logic. Use the `decorate(...)` pipe — it appends a `DecorateFn` to the provider's mapper chain via `IProvider.map(...)`.
2027
2018
 
2028
2019
  - `provider(decorate((instance, container) => new LoggerDecorator(instance)))`
2029
2020
 
@@ -31,23 +31,23 @@ class Container {
31
31
  this.aliases.setAliasesByKey(key, aliases);
32
32
  return this;
33
33
  }
34
- resolve(target, { args, child = this, lazy } = {}) {
34
+ resolve(target, { args = [], child = this, lazy } = {}) {
35
35
  this.validateContainer();
36
36
  if (basic_1.Is.constructor(target)) {
37
37
  return this.injector.resolve(this, target, { args, lazy });
38
38
  }
39
39
  const provider = this.providers.get(target);
40
- return provider?.hasAccess({ invocationScope: child, providerScope: this })
40
+ return provider?.hasAccess({ invocationScope: child, providerScope: this, args })
41
41
  ? provider.resolve(this, { args, lazy })
42
42
  : this.parent.resolve(target, { args, child, lazy });
43
43
  }
44
- resolveByAlias(alias, { args, child = this, lazy, excludedKeys = [] } = {}) {
44
+ resolveByAlias(alias, { args = [], child = this, lazy, excludedKeys = [] } = {}) {
45
45
  this.validateContainer();
46
46
  const keys = [];
47
47
  const deps = [];
48
48
  for (const key of this.aliases.getKeysByAlias(alias).filter(array_1.Filter.exclude(excludedKeys))) {
49
49
  const provider = this.findProviderByKeyOrFail(key);
50
- if (!provider.hasAccess({ invocationScope: child, providerScope: this })) {
50
+ if (!provider.hasAccess({ invocationScope: child, providerScope: this, args })) {
51
51
  continue;
52
52
  }
53
53
  keys.push(key);
@@ -61,11 +61,11 @@ class Container {
61
61
  });
62
62
  return [...deps, ...parentDeps];
63
63
  }
64
- resolveOneByAlias(alias, { args, child = this, lazy } = {}) {
64
+ resolveOneByAlias(alias, { args = [], child = this, lazy } = {}) {
65
65
  this.validateContainer();
66
66
  const [key, ..._] = this.aliases.getKeysByAlias(alias);
67
67
  const provider = key ? this.findProviderByKeyOrFail(key) : undefined;
68
- return provider?.hasAccess({ invocationScope: child, providerScope: this })
68
+ return provider?.hasAccess({ invocationScope: child, providerScope: this, args })
69
69
  ? provider.resolve(this, { args, lazy })
70
70
  : this.parent.resolveOneByAlias(alias, { args, child, lazy });
71
71
  }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CannonSingletonApplyError = void 0;
4
+ const ContainerError_1 = require("./ContainerError");
5
+ class CannonSingletonApplyError extends ContainerError_1.ContainerError {
6
+ name = 'CannonSingletonApplyError';
7
+ constructor(message) {
8
+ super(message);
9
+ Object.setPrototypeOf(this, CannonSingletonApplyError.prototype);
10
+ }
11
+ }
12
+ exports.CannonSingletonApplyError = CannonSingletonApplyError;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createHookContextFactory = exports.createHookContext = exports.HookContext = void 0;
4
- const inject_1 = require("../injector/inject");
5
4
  const proxy_1 = require("../utils/proxy");
5
+ const MetadataInjector_1 = require("../injector/MetadataInjector");
6
6
  class HookContext {
7
7
  scope;
8
8
  methodName;
@@ -14,7 +14,7 @@ class HookContext {
14
14
  this.instance = (0, proxy_1.isProxy)(instance) ? (0, proxy_1.getProxyTarget)(instance) : instance;
15
15
  }
16
16
  resolveArgs(...args) {
17
- return (0, inject_1.resolveArgs)(this.instance.constructor, this.methodName)(this.scope, {
17
+ return (0, MetadataInjector_1.resolveArgs)(this.instance.constructor, this.methodName)(this.scope, {
18
18
  args: [...this.initialArgs, ...args],
19
19
  });
20
20
  }
package/cjm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.InjectionToken = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onDispose = exports.onDisposeHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.hasHooks = exports.hook = exports.getHooks = exports.UnexpectedHookResultError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.DependencyNotFoundError = exports.Registration = exports.bindTo = exports.register = exports.scope = exports.decorate = exports.SingletonProvider = exports.singleton = exports.Provider = exports.ProviderDecorator = exports.appendArgsFn = exports.appendArgs = exports.lazy = exports.scopeAccess = exports.ProxyInjector = exports.SimpleInjector = exports.MetadataInjector = exports.Injector = exports.argsFn = exports.args = exports.resolveArgs = exports.inject = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
4
- exports.resolveConstructor = exports.Is = exports.pipe = exports.select = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.methodTag = exports.getMethodLabels = exports.methodLabel = exports.getMethodMeta = exports.methodMeta = exports.getParamTags = exports.paramTag = exports.getParamLabels = exports.paramLabel = exports.getParamMeta = exports.paramMeta = exports.getClassTags = exports.classTag = exports.getClassLabels = exports.classLabel = exports.getClassMeta = exports.classMeta = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = void 0;
3
+ exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.InjectionToken = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onDispose = exports.onDisposeHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.hasHooks = exports.hook = exports.getHooks = exports.CannonSingletonApplyError = exports.UnexpectedHookResultError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.DependencyNotFoundError = exports.Registration = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
4
+ exports.resolveConstructor = exports.Is = exports.pipe = exports.select = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.methodTag = exports.getMethodLabels = exports.methodLabel = exports.getMethodMeta = exports.methodMeta = exports.getParamTags = exports.paramTag = exports.getParamLabels = exports.paramLabel = exports.getParamMeta = exports.paramMeta = exports.getClassTags = exports.classTag = exports.getClassLabels = exports.classLabel = exports.getClassMeta = exports.classMeta = exports.GroupInstanceToken = exports.ConstantToken = void 0;
5
5
  // Containers
6
6
  var IContainer_1 = require("./container/IContainer");
7
7
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
@@ -10,38 +10,31 @@ Object.defineProperty(exports, "Container", { enumerable: true, get: function ()
10
10
  var EmptyContainer_1 = require("./container/EmptyContainer");
11
11
  Object.defineProperty(exports, "EmptyContainer", { enumerable: true, get: function () { return EmptyContainer_1.EmptyContainer; } });
12
12
  // Injectors
13
- var inject_1 = require("./injector/inject");
14
- Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return inject_1.inject; } });
15
- Object.defineProperty(exports, "resolveArgs", { enumerable: true, get: function () { return inject_1.resolveArgs; } });
16
- Object.defineProperty(exports, "args", { enumerable: true, get: function () { return inject_1.args; } });
17
- Object.defineProperty(exports, "argsFn", { enumerable: true, get: function () { return inject_1.argsFn; } });
18
13
  var IInjector_1 = require("./injector/IInjector");
19
14
  Object.defineProperty(exports, "Injector", { enumerable: true, get: function () { return IInjector_1.Injector; } });
20
15
  var MetadataInjector_1 = require("./injector/MetadataInjector");
21
16
  Object.defineProperty(exports, "MetadataInjector", { enumerable: true, get: function () { return MetadataInjector_1.MetadataInjector; } });
17
+ Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return MetadataInjector_1.inject; } });
18
+ Object.defineProperty(exports, "args", { enumerable: true, get: function () { return MetadataInjector_1.args; } });
19
+ Object.defineProperty(exports, "argsFn", { enumerable: true, get: function () { return MetadataInjector_1.argsFn; } });
20
+ Object.defineProperty(exports, "resolveArgs", { enumerable: true, get: function () { return MetadataInjector_1.resolveArgs; } });
22
21
  var SimpleInjector_1 = require("./injector/SimpleInjector");
23
22
  Object.defineProperty(exports, "SimpleInjector", { enumerable: true, get: function () { return SimpleInjector_1.SimpleInjector; } });
24
23
  var ProxyInjector_1 = require("./injector/ProxyInjector");
25
24
  Object.defineProperty(exports, "ProxyInjector", { enumerable: true, get: function () { return ProxyInjector_1.ProxyInjector; } });
26
- // Providers
27
- var IProvider_1 = require("./provider/IProvider");
28
- Object.defineProperty(exports, "scopeAccess", { enumerable: true, get: function () { return IProvider_1.scopeAccess; } });
29
- Object.defineProperty(exports, "lazy", { enumerable: true, get: function () { return IProvider_1.lazy; } });
30
- Object.defineProperty(exports, "appendArgs", { enumerable: true, get: function () { return IProvider_1.appendArgs; } });
31
- Object.defineProperty(exports, "appendArgsFn", { enumerable: true, get: function () { return IProvider_1.appendArgsFn; } });
32
- Object.defineProperty(exports, "ProviderDecorator", { enumerable: true, get: function () { return IProvider_1.ProviderDecorator; } });
33
25
  var Provider_1 = require("./provider/Provider");
34
26
  Object.defineProperty(exports, "Provider", { enumerable: true, get: function () { return Provider_1.Provider; } });
35
- var SingletonProvider_1 = require("./provider/SingletonProvider");
36
- Object.defineProperty(exports, "singleton", { enumerable: true, get: function () { return SingletonProvider_1.singleton; } });
37
- Object.defineProperty(exports, "SingletonProvider", { enumerable: true, get: function () { return SingletonProvider_1.SingletonProvider; } });
38
- var DecoratorProvider_1 = require("./provider/DecoratorProvider");
39
- Object.defineProperty(exports, "decorate", { enumerable: true, get: function () { return DecoratorProvider_1.decorate; } });
40
27
  // Registrations
41
28
  var IRegistration_1 = require("./registration/IRegistration");
42
- Object.defineProperty(exports, "scope", { enumerable: true, get: function () { return IRegistration_1.scope; } });
43
29
  Object.defineProperty(exports, "register", { enumerable: true, get: function () { return IRegistration_1.register; } });
44
30
  Object.defineProperty(exports, "bindTo", { enumerable: true, get: function () { return IRegistration_1.bindTo; } });
31
+ Object.defineProperty(exports, "scope", { enumerable: true, get: function () { return IRegistration_1.scope; } });
32
+ Object.defineProperty(exports, "scopeAccess", { enumerable: true, get: function () { return IRegistration_1.scopeAccess; } });
33
+ Object.defineProperty(exports, "lazy", { enumerable: true, get: function () { return IRegistration_1.lazy; } });
34
+ Object.defineProperty(exports, "singleton", { enumerable: true, get: function () { return IRegistration_1.singleton; } });
35
+ Object.defineProperty(exports, "decorate", { enumerable: true, get: function () { return IRegistration_1.decorate; } });
36
+ Object.defineProperty(exports, "appendArgs", { enumerable: true, get: function () { return IRegistration_1.appendArgs; } });
37
+ Object.defineProperty(exports, "appendArgsFn", { enumerable: true, get: function () { return IRegistration_1.appendArgsFn; } });
45
38
  var Registration_1 = require("./registration/Registration");
46
39
  Object.defineProperty(exports, "Registration", { enumerable: true, get: function () { return Registration_1.Registration; } });
47
40
  // Errors
@@ -55,6 +48,8 @@ var ContainerDisposedError_1 = require("./errors/ContainerDisposedError");
55
48
  Object.defineProperty(exports, "ContainerDisposedError", { enumerable: true, get: function () { return ContainerDisposedError_1.ContainerDisposedError; } });
56
49
  var UnexpectedHookResultError_1 = require("./errors/UnexpectedHookResultError");
57
50
  Object.defineProperty(exports, "UnexpectedHookResultError", { enumerable: true, get: function () { return UnexpectedHookResultError_1.UnexpectedHookResultError; } });
51
+ var CannonSingletonApplyError_1 = require("./errors/CannonSingletonApplyError");
52
+ Object.defineProperty(exports, "CannonSingletonApplyError", { enumerable: true, get: function () { return CannonSingletonApplyError_1.CannonSingletonApplyError; } });
58
53
  // Hooks
59
54
  var hook_1 = require("./hooks/hook");
60
55
  Object.defineProperty(exports, "getHooks", { enumerable: true, get: function () { return hook_1.getHooks; } });
@@ -1,12 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MetadataInjector = void 0;
3
+ exports.resolveArgs = exports.argsFn = exports.args = exports.inject = exports.MetadataInjector = void 0;
4
4
  const IInjector_1 = require("./IInjector");
5
- const inject_1 = require("./inject");
5
+ const basic_1 = require("../utils/basic");
6
+ const parameter_1 = require("../metadata/parameter");
7
+ const toToken_1 = require("../token/toToken");
6
8
  class MetadataInjector extends IInjector_1.Injector {
7
9
  createInstance(scope, Target, { args: deps = [] } = {}) {
8
- const args = (0, inject_1.resolveArgs)(Target)(scope, { args: deps });
10
+ const args = (0, exports.resolveArgs)(Target)(scope, { args: deps });
9
11
  return new Target(...args);
10
12
  }
11
13
  }
12
14
  exports.MetadataInjector = MetadataInjector;
15
+ const hookMetaKey = (methodName = 'constructor') => `inject:${methodName}`;
16
+ const inject = (fn) => (target, propertyKey, parameterIndex) => {
17
+ (0, parameter_1.paramMeta)(hookMetaKey(propertyKey), () => (0, toToken_1.toToken)(fn))(basic_1.Is.instance(target) ? target.constructor : target, propertyKey, parameterIndex);
18
+ };
19
+ exports.inject = inject;
20
+ const args = (index) => (c, { args = [] }) => {
21
+ return args[index];
22
+ };
23
+ exports.args = args;
24
+ const argsFn = (fn) => (c, options) => fn(...(options.args ?? []));
25
+ exports.argsFn = argsFn;
26
+ const resolveArgs = (Target, methodName) => {
27
+ const tokens = (0, parameter_1.getParamMeta)(hookMetaKey(methodName), Target);
28
+ return (scope, { args = [], lazy }) => tokens.map((fn) => fn.resolve(scope, { args: args.map(toToken_1.argToToken).map((t) => t.resolve(scope)), lazy }));
29
+ };
30
+ exports.resolveArgs = resolveArgs;
@@ -1,51 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProviderDecorator = exports.lazy = exports.scopeAccess = exports.appendArgsFn = exports.appendArgs = void 0;
4
- const ProviderPipe_1 = require("./ProviderPipe");
5
- const appendArgs = (...extraArgs) => (0, ProviderPipe_1.registerPipe)((p) => p.addArgs(...extraArgs));
6
- exports.appendArgs = appendArgs;
7
- const appendArgsFn = (fn) => (0, ProviderPipe_1.registerPipe)((p) => p.addArgsFn(fn));
8
- exports.appendArgsFn = appendArgsFn;
9
- const scopeAccess = (rule) => (0, ProviderPipe_1.registerPipe)((p) => p.addAccessRule(rule));
10
- exports.scopeAccess = scopeAccess;
11
- const lazy = () => (0, ProviderPipe_1.registerPipe)((p) => p.lazy());
12
- exports.lazy = lazy;
13
- class ProviderDecorator {
14
- decorated;
15
- constructor(decorated) {
16
- this.decorated = decorated;
17
- }
18
- addAccessRule(rule) {
19
- this.decorated.addAccessRule(rule);
20
- return this;
21
- }
22
- hasAccess(options) {
23
- return this.decorated.hasAccess(options);
24
- }
25
- resolve(container, options) {
26
- return this.decorated.resolve(container, options);
27
- }
28
- pipe(...mappers) {
29
- const fns = mappers.map((m) => {
30
- if ((0, ProviderPipe_1.isProviderPipe)(m)) {
31
- return m.mapProvider.bind(m);
32
- }
33
- return m;
34
- });
35
- this.decorated = this.decorated.pipe(...fns);
36
- return this;
37
- }
38
- addArgs(...extraArgs) {
39
- this.decorated.addArgs(...extraArgs);
40
- return this;
41
- }
42
- addArgsFn(argsFn) {
43
- this.decorated.addArgsFn(argsFn);
44
- return this;
45
- }
46
- lazy() {
47
- this.decorated.lazy();
48
- return this;
49
- }
50
- }
51
- exports.ProviderDecorator = ProviderDecorator;
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Provider = void 0;
4
- const fp_1 = require("../utils/fp");
5
- const ProviderPipe_1 = require("./ProviderPipe");
4
+ const CannonSingletonApplyError_1 = require("../errors/CannonSingletonApplyError");
6
5
  class Provider {
7
6
  resolveDependency;
8
7
  static fromClass(Target) {
@@ -14,42 +13,57 @@ class Provider {
14
13
  static fromKey(key) {
15
14
  return new Provider((c) => c.resolve(key));
16
15
  }
17
- argsFn = (s, { args = [] } = {}) => args;
16
+ argsFnList = [];
18
17
  accessRules = [];
18
+ mappers = [];
19
19
  isLazy = false;
20
+ cache = new Map();
21
+ getKey;
20
22
  constructor(resolveDependency) {
21
23
  this.resolveDependency = resolveDependency;
22
24
  }
23
- pipe(...mappers) {
24
- const fns = mappers.map((m) => ((0, ProviderPipe_1.isProviderPipe)(m) ? m.mapProvider.bind(m) : m));
25
- return (0, fp_1.pipe)(...fns)(this);
25
+ resolve(scope, options) {
26
+ if (!this.getKey) {
27
+ return this.resolveDep(scope, options);
28
+ }
29
+ const key = this.getKey(...(options.args ?? []));
30
+ if (!this.cache.has(key)) {
31
+ this.cache.set(key, this.resolveDep(scope, options));
32
+ }
33
+ return this.cache.get(key);
26
34
  }
27
- resolve(container, { args = [], lazy } = {}) {
28
- return this.resolveDependency(container, {
29
- args: this.argsFn(container, { args }),
35
+ resolveDep(scope, { args = [], lazy } = {}) {
36
+ const dependency = this.resolveDependency(scope, {
37
+ args: this.argsFnList.reduce((acc, current) => current(scope, { args: acc }), args),
30
38
  lazy: lazy ?? this.isLazy,
31
39
  });
40
+ return this.mappers.reduce((acc, current) => current(acc, scope), dependency);
32
41
  }
33
- addAccessRule(rule) {
34
- this.accessRules.push(rule);
42
+ map(...mappers) {
43
+ this.mappers.push(...mappers);
35
44
  return this;
36
45
  }
37
- lazy() {
38
- this.isLazy = true;
46
+ addAccessRule(...rules) {
47
+ this.accessRules.push(...rules);
39
48
  return this;
40
49
  }
41
- addArgs(...extraArgs) {
42
- const parentFn = this.argsFn;
43
- this.argsFn = (container, options) => [...parentFn(container, options), ...extraArgs];
50
+ lazy() {
51
+ this.isLazy = true;
44
52
  return this;
45
53
  }
46
- addArgsFn(argsFn) {
47
- const parentFn = this.argsFn;
48
- this.argsFn = (container, options) => [...parentFn(container, options), ...argsFn(container, options)];
54
+ addArgsFn(...fns) {
55
+ this.argsFnList.push(...fns);
49
56
  return this;
50
57
  }
51
58
  hasAccess(options) {
52
- return this.accessRules.reduce((acc, rule) => rule(acc, options), true);
59
+ return this.accessRules.reduce((acc, rule) => rule(options, acc), true);
60
+ }
61
+ singleton(getCacheKey = () => '1') {
62
+ if (this.getKey) {
63
+ throw new CannonSingletonApplyError_1.CannonSingletonApplyError('Provider is already singleton');
64
+ }
65
+ this.getKey = getCacheKey;
66
+ return this;
53
67
  }
54
68
  }
55
69
  exports.Provider = Provider;
@@ -1,17 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.bindTo = exports.register = exports.getTransformers = exports.scope = void 0;
4
- const ProviderPipe_1 = require("../provider/ProviderPipe");
3
+ exports.singleton = exports.decorate = exports.lazy = exports.scopeAccess = exports.appendArgsFn = exports.appendArgs = exports.scope = exports.bindTo = exports.register = exports.getTransformers = exports.registerPipe = exports.isProviderPipe = void 0;
5
4
  const SingleToken_1 = require("../token/SingleToken");
6
5
  const BindToken_1 = require("../token/BindToken");
7
6
  const class_1 = require("../metadata/class");
8
- const scope = (...rules) => (r) => r.when(...rules);
9
- exports.scope = scope;
7
+ const isProviderPipe = (obj) => obj !== null && typeof obj === 'object' && 'mapProvider' in obj;
8
+ exports.isProviderPipe = isProviderPipe;
9
+ const registerPipe = (mapProvider) => ({
10
+ mapProvider,
11
+ mapRegistration: (r) => r.pipe(mapProvider),
12
+ });
13
+ exports.registerPipe = registerPipe;
10
14
  const METADATA_KEY = 'registration';
11
15
  const getTransformers = (Target) => (0, class_1.getClassMeta)(Target, METADATA_KEY) ?? [];
12
16
  exports.getTransformers = getTransformers;
13
17
  const register = (...mappers) => (0, class_1.classMeta)(METADATA_KEY, (acc) => {
14
- const result = mappers.map((m) => (0, ProviderPipe_1.isProviderPipe)(m) ? (r) => m.mapRegistration(r) : m);
18
+ const result = mappers.map((m) => (0, exports.isProviderPipe)(m) ? (r) => m.mapRegistration(r) : m);
15
19
  return acc ? [...result, ...acc] : result;
16
20
  });
17
21
  exports.register = register;
@@ -23,3 +27,17 @@ const bindTo = (...tokens) => (r) => {
23
27
  return r;
24
28
  };
25
29
  exports.bindTo = bindTo;
30
+ const scope = (...rules) => (r) => r.when(...rules);
31
+ exports.scope = scope;
32
+ const appendArgs = (...extraArgs) => (0, exports.registerPipe)((p) => p.addArgsFn((_, { args = [] } = {}) => [...args, ...extraArgs]));
33
+ exports.appendArgs = appendArgs;
34
+ const appendArgsFn = (fn) => (0, exports.registerPipe)((p) => p.addArgsFn((scope, options) => [...(options?.args ?? []), ...fn(scope, options)]));
35
+ exports.appendArgsFn = appendArgsFn;
36
+ const scopeAccess = (rule) => (0, exports.registerPipe)((p) => p.addAccessRule(rule));
37
+ exports.scopeAccess = scopeAccess;
38
+ const lazy = () => (0, exports.registerPipe)((p) => p.lazy());
39
+ exports.lazy = lazy;
40
+ const decorate = (...fns) => (0, exports.registerPipe)((p) => p.map(...fns));
41
+ exports.decorate = decorate;
42
+ const singleton = (getCacheKey) => (0, exports.registerPipe)((p) => p.singleton(getCacheKey));
43
+ exports.singleton = singleton;
@@ -5,7 +5,7 @@ const IContainer_1 = require("../container/IContainer");
5
5
  const Provider_1 = require("../provider/Provider");
6
6
  const DependencyMissingKeyError_1 = require("../errors/DependencyMissingKeyError");
7
7
  const IRegistration_1 = require("./IRegistration");
8
- const ProviderPipe_1 = require("../provider/ProviderPipe");
8
+ const IRegistration_2 = require("./IRegistration");
9
9
  const SingleToken_1 = require("../token/SingleToken");
10
10
  const fp_1 = require("../utils/fp");
11
11
  const basic_1 = require("../utils/basic");
@@ -14,12 +14,12 @@ class Registration {
14
14
  key;
15
15
  scopeRules;
16
16
  static fromClass(Target, { name } = {}) {
17
- const transform = (0, fp_1.pipe)(...(0, IRegistration_1.getTransformers)(Target));
17
+ const transform = (0, fp_1.pipe)(...(0, IRegistration_2.getTransformers)(Target));
18
18
  return transform(new Registration(() => Provider_1.Provider.fromClass(Target), name ?? Target.name));
19
19
  }
20
20
  static fromValue(value) {
21
21
  if (basic_1.Is.constructor(value)) {
22
- const transform = (0, fp_1.pipe)(...(0, IRegistration_1.getTransformers)(value));
22
+ const transform = (0, fp_1.pipe)(...(0, IRegistration_2.getTransformers)(value));
23
23
  return transform(new Registration(() => Provider_1.Provider.fromValue(value), value.name));
24
24
  }
25
25
  return new Registration(() => Provider_1.Provider.fromValue(value));
@@ -46,7 +46,7 @@ class Registration {
46
46
  return this;
47
47
  }
48
48
  pipe(...mappers) {
49
- const fns = mappers.map((m) => ((0, ProviderPipe_1.isProviderPipe)(m) ? m.mapProvider.bind(m) : m));
49
+ const fns = mappers.map((m) => ((0, IRegistration_1.isProviderPipe)(m) ? m.mapProvider.bind(m) : m));
50
50
  this.mappers.push(...fns);
51
51
  return this;
52
52
  }
@@ -63,11 +63,7 @@ class Registration {
63
63
  return this;
64
64
  }
65
65
  matchScope(container) {
66
- if (this.scopeRules.length === 0) {
67
- return true;
68
- }
69
- const [first, ...rest] = this.scopeRules;
70
- return rest.reduce((prev, curr) => curr(container, prev), first(container));
66
+ return this.scopeRules.reduce((prev, curr) => curr(container, prev), true);
71
67
  }
72
68
  applyTo(container) {
73
69
  if (!this.matchScope(container)) {
@@ -76,8 +72,8 @@ class Registration {
76
72
  if (!this.key) {
77
73
  throw new DependencyMissingKeyError_1.DependencyMissingKeyError('No key provided for registration');
78
74
  }
79
- const provider = this.createProvider();
80
- container.register(this.key, provider.pipe(...this.mappers), { aliases: [...this.aliases] });
75
+ const provider = this.mappers.reduce((p, m) => m(p), this.createProvider());
76
+ container.register(this.key, provider, { aliases: [...this.aliases] });
81
77
  }
82
78
  getKeyOrFail() {
83
79
  if (!this.key) {
@@ -28,23 +28,23 @@ export class Container {
28
28
  this.aliases.setAliasesByKey(key, aliases);
29
29
  return this;
30
30
  }
31
- resolve(target, { args, child = this, lazy } = {}) {
31
+ resolve(target, { args = [], child = this, lazy } = {}) {
32
32
  this.validateContainer();
33
33
  if (Is.constructor(target)) {
34
34
  return this.injector.resolve(this, target, { args, lazy });
35
35
  }
36
36
  const provider = this.providers.get(target);
37
- return provider?.hasAccess({ invocationScope: child, providerScope: this })
37
+ return provider?.hasAccess({ invocationScope: child, providerScope: this, args })
38
38
  ? provider.resolve(this, { args, lazy })
39
39
  : this.parent.resolve(target, { args, child, lazy });
40
40
  }
41
- resolveByAlias(alias, { args, child = this, lazy, excludedKeys = [] } = {}) {
41
+ resolveByAlias(alias, { args = [], child = this, lazy, excludedKeys = [] } = {}) {
42
42
  this.validateContainer();
43
43
  const keys = [];
44
44
  const deps = [];
45
45
  for (const key of this.aliases.getKeysByAlias(alias).filter(F.exclude(excludedKeys))) {
46
46
  const provider = this.findProviderByKeyOrFail(key);
47
- if (!provider.hasAccess({ invocationScope: child, providerScope: this })) {
47
+ if (!provider.hasAccess({ invocationScope: child, providerScope: this, args })) {
48
48
  continue;
49
49
  }
50
50
  keys.push(key);
@@ -58,11 +58,11 @@ export class Container {
58
58
  });
59
59
  return [...deps, ...parentDeps];
60
60
  }
61
- resolveOneByAlias(alias, { args, child = this, lazy } = {}) {
61
+ resolveOneByAlias(alias, { args = [], child = this, lazy } = {}) {
62
62
  this.validateContainer();
63
63
  const [key, ..._] = this.aliases.getKeysByAlias(alias);
64
64
  const provider = key ? this.findProviderByKeyOrFail(key) : undefined;
65
- return provider?.hasAccess({ invocationScope: child, providerScope: this })
65
+ return provider?.hasAccess({ invocationScope: child, providerScope: this, args })
66
66
  ? provider.resolve(this, { args, lazy })
67
67
  : this.parent.resolveOneByAlias(alias, { args, child, lazy });
68
68
  }