ts-ioc-container 50.2.5 → 51.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.
package/README.md CHANGED
@@ -47,7 +47,7 @@ provider pipelines, aliases, and custom injector strategies.
47
47
  - [Alias](#alias) `asAlias`
48
48
  - [Decorator](#decorator) `decorate`
49
49
  - [Registration](#registration) `@register`
50
- - [Key](#key) `bindTo`
50
+ - [Token](#token) `bindTo`
51
51
  - [Scope](#scope) `scope`
52
52
  - [Module](#module)
53
53
  - [Hook](#hook) `@hook`
@@ -992,7 +992,7 @@ describe('lazy registerPipe', () => {
992
992
  const container = new Container().addRegistration(
993
993
  R.fromClass(ConfigService)
994
994
  .pipe(
995
- (p) => p.appendArgs('https://api.example.com', 5000),
995
+ (p) => p.addArgs('https://api.example.com', 5000),
996
996
  (p) => p.lazy(),
997
997
  )
998
998
  .pipe(singleton()),
@@ -1403,7 +1403,7 @@ describe('Provider', () => {
1403
1403
 
1404
1404
  const appContainer = new Container({ tags: ['application'] }).register(
1405
1405
  'AdminService',
1406
- Provider.fromClass(AdminService).pipe(scopeAccess(({ invocationScope }) => invocationScope.hasTag('admin'))),
1406
+ Provider.fromClass(AdminService).pipe(scopeAccess((_prev, { invocationScope }) => invocationScope.hasTag('admin'))),
1407
1407
  );
1408
1408
 
1409
1409
  const adminScope = appContainer.createScope({ tags: ['admin'] });
@@ -1778,8 +1778,10 @@ Sometimes you want to hide dependency if somebody wants to resolve it from certa
1778
1778
  > [!IMPORTANT]
1779
1779
  > Use `scope()` to decide where a provider is registered. Use `scopeAccess()` to decide which invocation scopes can see an already registered provider.
1780
1780
 
1781
- - `provider(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))` - dependency will be accessible only from the scope where it's registered
1782
- - `Provider.fromClass(Logger).pipe(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))`
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))`
1783
+
1784
+ 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.
1783
1785
 
1784
1786
  ```typescript
1785
1787
  import 'reflect-metadata';
@@ -1818,7 +1820,7 @@ describe('Visibility', function () {
1818
1820
  scope((s) => s.hasTag('application')), // Registered at app level
1819
1821
  singleton(),
1820
1822
  // Only accessible from admin scope, not regular request scope
1821
- scopeAccess(({ invocationScope }) => invocationScope.hasTag('admin')),
1823
+ scopeAccess((_prev, { invocationScope }) => invocationScope.hasTag('admin')),
1822
1824
  )
1823
1825
  class UserManagementService {
1824
1826
  deleteUser(userId: string): string {
@@ -1850,7 +1852,7 @@ describe('Visibility', function () {
1850
1852
  scope((s) => s.hasTag('application')),
1851
1853
  singleton(),
1852
1854
  // Only accessible from the scope where it was registered
1853
- scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope),
1855
+ scopeAccess((_prev, { invocationScope, providerScope }) => invocationScope === providerScope),
1854
1856
  )
1855
1857
  class AuditLogger {
1856
1858
  log(message: string): string {
@@ -2146,12 +2148,9 @@ Registration is provider factory which registers provider in container.
2146
2148
  - `Registration.fromValue(Logger)`
2147
2149
  - `Registration.fromFn((container, options) => container.resolve(Logger, options))`
2148
2150
 
2149
- ### Key
2150
-
2151
- Sometimes you want to register provider with certain key. This is what `key` is for.
2151
+ ### Token
2152
2152
 
2153
- - by default, key is class name
2154
- - you can assign the same key to different registrations
2153
+ Use `bindTo(key)` to register a provider under a specific key. By default the key is the class name. Multiple registrations can share the same key.
2155
2154
 
2156
2155
  > [!TIP]
2157
2156
  > Prefer `SingleToken<T>` over plain string literals as registration keys. Tokens are type-safe, rename-friendly, and prevent typos that only surface at runtime.
@@ -2,11 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ProviderDecorator = exports.lazy = exports.scopeAccess = exports.appendArgsFn = exports.appendArgs = void 0;
4
4
  const ProviderPipe_1 = require("./ProviderPipe");
5
- const appendArgs = (...extraArgs) => (0, ProviderPipe_1.registerPipe)((p) => p.appendArgs(...extraArgs));
5
+ const appendArgs = (...extraArgs) => (0, ProviderPipe_1.registerPipe)((p) => p.addArgs(...extraArgs));
6
6
  exports.appendArgs = appendArgs;
7
- const appendArgsFn = (fn) => (0, ProviderPipe_1.registerPipe)((p) => p.appendArgsFn(fn));
7
+ const appendArgsFn = (fn) => (0, ProviderPipe_1.registerPipe)((p) => p.addArgsFn(fn));
8
8
  exports.appendArgsFn = appendArgsFn;
9
- const scopeAccess = (rule) => (0, ProviderPipe_1.registerPipe)((p) => p.setAccessRule(rule));
9
+ const scopeAccess = (rule) => (0, ProviderPipe_1.registerPipe)((p) => p.addAccessRule(rule));
10
10
  exports.scopeAccess = scopeAccess;
11
11
  const lazy = () => (0, ProviderPipe_1.registerPipe)((p) => p.lazy());
12
12
  exports.lazy = lazy;
@@ -15,8 +15,8 @@ class ProviderDecorator {
15
15
  constructor(decorated) {
16
16
  this.decorated = decorated;
17
17
  }
18
- setAccessRule(rule) {
19
- this.decorated.setAccessRule(rule);
18
+ addAccessRule(rule) {
19
+ this.decorated.addAccessRule(rule);
20
20
  return this;
21
21
  }
22
22
  hasAccess(options) {
@@ -35,12 +35,12 @@ class ProviderDecorator {
35
35
  this.decorated = this.decorated.pipe(...fns);
36
36
  return this;
37
37
  }
38
- appendArgs(...extraArgs) {
39
- this.decorated.appendArgs(...extraArgs);
38
+ addArgs(...extraArgs) {
39
+ this.decorated.addArgs(...extraArgs);
40
40
  return this;
41
41
  }
42
- appendArgsFn(argsFn) {
43
- this.decorated.appendArgsFn(argsFn);
42
+ addArgsFn(argsFn) {
43
+ this.decorated.addArgsFn(argsFn);
44
44
  return this;
45
45
  }
46
46
  lazy() {
@@ -15,7 +15,7 @@ class Provider {
15
15
  return new Provider((c) => c.resolve(key));
16
16
  }
17
17
  argsFn = (s, { args = [] } = {}) => args;
18
- checkAccess = () => true;
18
+ accessRules = [];
19
19
  isLazy = false;
20
20
  constructor(resolveDependency) {
21
21
  this.resolveDependency = resolveDependency;
@@ -30,26 +30,26 @@ class Provider {
30
30
  lazy: lazy ?? this.isLazy,
31
31
  });
32
32
  }
33
- setAccessRule(predicate) {
34
- this.checkAccess = predicate;
33
+ addAccessRule(rule) {
34
+ this.accessRules.push(rule);
35
35
  return this;
36
36
  }
37
37
  lazy() {
38
38
  this.isLazy = true;
39
39
  return this;
40
40
  }
41
- appendArgs(...extraArgs) {
41
+ addArgs(...extraArgs) {
42
42
  const parentFn = this.argsFn;
43
43
  this.argsFn = (container, options) => [...parentFn(container, options), ...extraArgs];
44
44
  return this;
45
45
  }
46
- appendArgsFn(argsFn) {
46
+ addArgsFn(argsFn) {
47
47
  const parentFn = this.argsFn;
48
48
  this.argsFn = (container, options) => [...parentFn(container, options), ...argsFn(container, options)];
49
49
  return this;
50
50
  }
51
51
  hasAccess(options) {
52
- return this.checkAccess(options);
52
+ return this.accessRules.reduce((acc, rule) => rule(acc, options), true);
53
53
  }
54
54
  }
55
55
  exports.Provider = Provider;
@@ -1,15 +1,15 @@
1
1
  import { isProviderPipe, registerPipe } from './ProviderPipe';
2
- export const appendArgs = (...extraArgs) => registerPipe((p) => p.appendArgs(...extraArgs));
3
- export const appendArgsFn = (fn) => registerPipe((p) => p.appendArgsFn(fn));
4
- export const scopeAccess = (rule) => registerPipe((p) => p.setAccessRule(rule));
2
+ export const appendArgs = (...extraArgs) => registerPipe((p) => p.addArgs(...extraArgs));
3
+ export const appendArgsFn = (fn) => registerPipe((p) => p.addArgsFn(fn));
4
+ export const scopeAccess = (rule) => registerPipe((p) => p.addAccessRule(rule));
5
5
  export const lazy = () => registerPipe((p) => p.lazy());
6
6
  export class ProviderDecorator {
7
7
  decorated;
8
8
  constructor(decorated) {
9
9
  this.decorated = decorated;
10
10
  }
11
- setAccessRule(rule) {
12
- this.decorated.setAccessRule(rule);
11
+ addAccessRule(rule) {
12
+ this.decorated.addAccessRule(rule);
13
13
  return this;
14
14
  }
15
15
  hasAccess(options) {
@@ -28,12 +28,12 @@ export class ProviderDecorator {
28
28
  this.decorated = this.decorated.pipe(...fns);
29
29
  return this;
30
30
  }
31
- appendArgs(...extraArgs) {
32
- this.decorated.appendArgs(...extraArgs);
31
+ addArgs(...extraArgs) {
32
+ this.decorated.addArgs(...extraArgs);
33
33
  return this;
34
34
  }
35
- appendArgsFn(argsFn) {
36
- this.decorated.appendArgsFn(argsFn);
35
+ addArgsFn(argsFn) {
36
+ this.decorated.addArgsFn(argsFn);
37
37
  return this;
38
38
  }
39
39
  lazy() {
@@ -12,7 +12,7 @@ export class Provider {
12
12
  return new Provider((c) => c.resolve(key));
13
13
  }
14
14
  argsFn = (s, { args = [] } = {}) => args;
15
- checkAccess = () => true;
15
+ accessRules = [];
16
16
  isLazy = false;
17
17
  constructor(resolveDependency) {
18
18
  this.resolveDependency = resolveDependency;
@@ -27,25 +27,25 @@ export class Provider {
27
27
  lazy: lazy ?? this.isLazy,
28
28
  });
29
29
  }
30
- setAccessRule(predicate) {
31
- this.checkAccess = predicate;
30
+ addAccessRule(rule) {
31
+ this.accessRules.push(rule);
32
32
  return this;
33
33
  }
34
34
  lazy() {
35
35
  this.isLazy = true;
36
36
  return this;
37
37
  }
38
- appendArgs(...extraArgs) {
38
+ addArgs(...extraArgs) {
39
39
  const parentFn = this.argsFn;
40
40
  this.argsFn = (container, options) => [...parentFn(container, options), ...extraArgs];
41
41
  return this;
42
42
  }
43
- appendArgsFn(argsFn) {
43
+ addArgsFn(argsFn) {
44
44
  const parentFn = this.argsFn;
45
45
  this.argsFn = (container, options) => [...parentFn(container, options), ...argsFn(container, options)];
46
46
  return this;
47
47
  }
48
48
  hasAccess(options) {
49
- return this.checkAccess(options);
49
+ return this.accessRules.reduce((acc, rule) => rule(acc, options), true);
50
50
  }
51
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "50.2.5",
3
+ "version": "51.0.0",
4
4
  "description": "Fast, lightweight TypeScript dependency injection container with a clean API, scoped lifecycles, decorators, tokens, hooks, lazy injection, customizable providers, and no global container objects.",
5
5
  "workspaces": [
6
6
  "docs"
@@ -11,7 +11,7 @@ export type ScopeAccessOptions = {
11
11
  invocationScope: Tagged;
12
12
  providerScope: Tagged;
13
13
  };
14
- export type ScopeAccessRule = (options: ScopeAccessOptions) => boolean;
14
+ export type ScopeAccessRule = (prev: boolean, options: ScopeAccessOptions) => boolean;
15
15
  export type ArgsFn = (l: IContainer, options?: InjectOptions) => unknown[];
16
16
  export interface IMapper {
17
17
  mapItem<T>(target: IProvider<T>): IProvider<T>;
@@ -20,9 +20,9 @@ export interface IProvider<T = any> {
20
20
  resolve(container: IContainer, options: ProviderOptions): T;
21
21
  hasAccess(options: ScopeAccessOptions): boolean;
22
22
  pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
23
- setAccessRule(hasAccessWhen: ScopeAccessRule): this;
24
- appendArgs(...extraArgs: unknown[]): this;
25
- appendArgsFn(argsFn: ArgsFn): this;
23
+ addAccessRule(rule: ScopeAccessRule): this;
24
+ addArgs(...extraArgs: unknown[]): this;
25
+ addArgsFn(argsFn: ArgsFn): this;
26
26
  lazy(): this;
27
27
  }
28
28
  export declare const appendArgs: <T>(...extraArgs: unknown[]) => ProviderPipe<T>;
@@ -32,11 +32,11 @@ export declare const lazy: <T>() => ProviderPipe<T>;
32
32
  export declare abstract class ProviderDecorator<T> implements IProvider<T> {
33
33
  private decorated;
34
34
  protected constructor(decorated: IProvider<T>);
35
- setAccessRule(rule: ScopeAccessRule): this;
35
+ addAccessRule(rule: ScopeAccessRule): this;
36
36
  hasAccess(options: ScopeAccessOptions): boolean;
37
37
  resolve(container: IContainer, options: ProviderOptions): T;
38
38
  pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
39
- appendArgs(...extraArgs: unknown[]): this;
40
- appendArgsFn(argsFn: ArgsFn): this;
39
+ addArgs(...extraArgs: unknown[]): this;
40
+ addArgsFn(argsFn: ArgsFn): this;
41
41
  lazy(): this;
42
42
  }
@@ -9,14 +9,14 @@ export declare class Provider<T = any> implements IProvider<T> {
9
9
  static fromValue<T>(value: T): IProvider<T>;
10
10
  static fromKey<T>(key: DependencyKey): Provider<T>;
11
11
  private argsFn;
12
- private checkAccess;
12
+ private readonly accessRules;
13
13
  private isLazy;
14
14
  constructor(resolveDependency: ResolveDependency<T>);
15
15
  pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
16
16
  resolve(container: IContainer, { args, lazy }?: ProviderOptions): T;
17
- setAccessRule(predicate: ScopeAccessRule): this;
17
+ addAccessRule(rule: ScopeAccessRule): this;
18
18
  lazy(): this;
19
- appendArgs(...extraArgs: unknown[]): this;
20
- appendArgsFn(argsFn: ArgsFn): this;
19
+ addArgs(...extraArgs: unknown[]): this;
20
+ addArgsFn(argsFn: ArgsFn): this;
21
21
  hasAccess(options: ScopeAccessOptions): boolean;
22
22
  }