ts-ioc-container 68.0.0 → 69.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
@@ -1774,13 +1774,16 @@ Sometimes you want to bind some arguments to provider.
1774
1774
  - `provider(appendArgsFn((container) => [container.resolve(Logger), 'someValue']))`
1775
1775
  - `Provider.fromClass(Logger).pipe(appendArgs('someArgument'))`
1776
1776
 
1777
- ### Token as argument
1777
+ ### Dependencies as arguments
1778
1778
 
1779
- When you pass an `InjectionToken` via `token.args(...)`, the container resolves it before the value reaches the constructor. Bare constructors are **not** auto-resolved — wrap a class in `ClassToken` to opt into resolution.
1779
+ Args are passed to the constructor **as-is** — the library never resolves an `InjectionToken` (or a bare constructor) it finds in the args list. Resolve it at the call site with `argsFn`:
1780
1780
 
1781
- - `ServiceToken.args(ValueToken)` — `ValueToken` is resolved from the container, its value is passed as arg
1782
- - `ServiceToken.args(new ClassToken(SomeService))` — `SomeService` is constructed by the container
1781
+ - `ServiceToken.argsFn((scope) => [ValueToken.resolve(scope)])` — `ValueToken` is resolved from the container, its value is passed as arg
1782
+ - `ServiceToken.argsFn((scope) => [scope.resolve(SomeService)])` — `SomeService` is constructed by the container
1783
1783
  - `ServiceToken.args('literal')` — literal value passed directly
1784
+ - `ServiceToken.args(ValueToken)` — the token object itself is passed as arg
1785
+
1786
+ `argToToken(value)` is the helper for a call site that wants "resolve tokens, pass literals through": it returns an `InjectionToken` as-is and wraps anything else in a `ConstantToken`, so `@inject((scope, { args = [] }) => argToToken(args[0]).resolve(scope))` accepts either.
1784
1787
 
1785
1788
  ### Positional arg injection with `arg(index)`, `args`, and `argsFn`
1786
1789
 
@@ -1788,10 +1791,73 @@ Constructor parameters that should pick up positional args from `ProviderOptions
1788
1791
 
1789
1792
  - `@inject(arg(0))` — resolves the first element of the `args` array passed at resolution time
1790
1793
  - `@inject(args)` — resolves the whole runtime `args` array
1791
- - Works together with `token.args(...)` to pass typed dependencies through the args context
1794
+ - Works together with `token.args(...)` / `token.argsFn(...)` to pass typed dependencies through the args context
1792
1795
 
1793
1796
  `argsFn(predicate)` is the general form: it iterates the runtime `args` array and returns the **first argument matching** `predicate(value, index)` — think `args.find(predicate)`. `arg(index)` is just a shortcut for matching by position: `arg(0)` is `argsFn((value, index) => index === 0)`. `args` is `(scope, options) => options.args`, i.e. it returns the runtime args array as-is. Every `InjectFn` receives `(scope, options)`, where `options.args` is the runtime args array.
1794
1797
 
1798
+ `findOrFail(predicate)` is the strict, variadic counterpart for places that take the raw args list — `singleton(findOrFail(isUserId))` keys a per-argument singleton, for example. It returns the first argument matching `predicate(value)` and throws `ArgumentNotFoundError` when none does, instead of silently handing out `undefined`.
1799
+
1800
+ ### Runtime args flow through tokens
1801
+
1802
+ Every container-backed token (`SingleToken`, `ClassToken`, `SingleAliasToken`, `GroupAliasToken`, `FunctionToken`) forwards the `args` of its own `resolve` call to the provider, exactly like `container.resolve(key, { args })` does. `token.args(...)` and `token.argsFn(...)` **append after** the runtime args, so `token.args('x').resolve(container, { args: ['r'] })` hands the provider `['r', 'x']`.
1803
+
1804
+ Because `@inject(token)` parameters are resolved with the args of the class being constructed, those args **cascade** into every injected dependency: they reach the dependency's provider, its `@inject(arg(index))` parameters, its `scopeAccess` rule and its `singleton()` cache key. That is what lets a per-user `UserService` share a per-user `UserRepository` without passing the id along by hand:
1805
+
1806
+ ```typescript
1807
+ import {
1808
+ arg,
1809
+ bindTo,
1810
+ Container,
1811
+ findOrFail,
1812
+ inject,
1813
+ register,
1814
+ Registration as R,
1815
+ singleton,
1816
+ SingleToken,
1817
+ } from 'ts-ioc-container';
1818
+
1819
+ interface IUserRepository {
1820
+ userId: string;
1821
+ }
1822
+
1823
+ const IUserRepositoryKey = new SingleToken<IUserRepository>('IUserRepository');
1824
+ const isUserId = (value: unknown): value is string => typeof value === 'string';
1825
+
1826
+ // one repository per user id - the id is the singleton cache key
1827
+ @register(bindTo(IUserRepositoryKey), singleton(findOrFail<string>(isUserId)))
1828
+ class UserRepository implements IUserRepository {
1829
+ constructor(@inject(arg(0)) public userId: string) {}
1830
+ }
1831
+
1832
+ class UserService {
1833
+ constructor(@inject(IUserRepositoryKey) public repository: IUserRepository) {}
1834
+ }
1835
+
1836
+ describe('Token Runtime Arguments', function () {
1837
+ it('should forward runtime args to the provider behind the token', function () {
1838
+ const container = new Container().addRegistration(R.fromClass(UserRepository));
1839
+
1840
+ expect(IUserRepositoryKey.resolve(container, { args: ['user-1'] }).userId).toBe('user-1');
1841
+ });
1842
+
1843
+ it('should cascade the runtime args of a class into its injected dependencies', function () {
1844
+ const container = new Container().addRegistration(R.fromClass(UserRepository));
1845
+
1846
+ const service = container.resolve(UserService, { args: ['user-1'] });
1847
+ const sameUser = container.resolve(UserService, { args: ['user-1'] });
1848
+ const otherUser = container.resolve(UserService, { args: ['user-2'] });
1849
+
1850
+ expect(service.repository.userId).toBe('user-1');
1851
+ expect(sameUser.repository).toBe(service.repository);
1852
+ expect(otherUser.repository.userId).toBe('user-2');
1853
+ });
1854
+ });
1855
+
1856
+ ```
1857
+
1858
+ > [!IMPORTANT]
1859
+ > Runtime args come first. A dependency that reads `@inject(arg(0))` sees the *caller's* first runtime arg whenever the caller was resolved with args, even if its token was specialized with `token.args(...)`. Pick args by shape (`argsFn(predicate)`, `findOrFail(predicate)`) rather than by position when a class can be resolved with runtime args and its dependencies are specialized with `token.args(...)`.
1860
+
1795
1861
  ### Immutable token chaining
1796
1862
 
1797
1863
  `token.args(...)`, `token.argsFn(...)`, and `token.lazy()` all return **new token instances** — the parent token is never mutated. This allows the same token to be specialized in multiple independent ways (one-way linked list: parent → many children).
@@ -1949,14 +2015,16 @@ describe('IProvider', function () {
1949
2015
  }
1950
2016
 
1951
2017
  // EntityManager is generic - it works with ANY repository.
1952
- // The repository is the first arg passed via `EntityManagerToken.args(...)`.
1953
- // `@inject(arg(0))` reads it; the container auto-resolves InjectionToken args
1954
- // before they reach the constructor.
2018
+ // The repository is the first arg; `@inject(arg(0))` reads it. Args are
2019
+ // passed through as-is, so the call site resolves the repository token
2020
+ // itself with `argsFn` before it reaches the constructor.
1955
2021
  const EntityManagerToken = new SingleToken<EntityManager>('EntityManager');
2022
+ const withRepository = (token: SingleToken<IRepository>) =>
2023
+ EntityManagerToken.argsFn((scope) => [token.resolve(scope)]);
1956
2024
 
1957
2025
  @register(
1958
2026
  bindTo(EntityManagerToken),
1959
- singleton((arg1) => (arg1 as SingleToken).token), // Cache unique instance per repository type
2027
+ singleton((repository) => (repository as IRepository).name), // Cache unique instance per repository type
1960
2028
  )
1961
2029
  class EntityManager {
1962
2030
  constructor(@inject(arg(0)) public repository: IRepository) {}
@@ -1965,11 +2033,11 @@ describe('IProvider', function () {
1965
2033
  class App {
1966
2034
  constructor(
1967
2035
  // Inject EntityManager configured for Users
1968
- @inject(EntityManagerToken.args(UserRepositoryToken))
2036
+ @inject(withRepository(UserRepositoryToken))
1969
2037
  public userManager: EntityManager,
1970
2038
 
1971
2039
  // Inject EntityManager configured for Todos
1972
- @inject(EntityManagerToken.args(TodoRepositoryToken))
2040
+ @inject(withRepository(TodoRepositoryToken))
1973
2041
  public todoManager: EntityManager,
1974
2042
  ) {}
1975
2043
  }
@@ -1993,14 +2061,14 @@ describe('IProvider', function () {
1993
2061
  .addRegistration(R.fromClass(TodoRepository));
1994
2062
 
1995
2063
  // Resolve user manager twice
1996
- const userManager1 = EntityManagerToken.args(UserRepositoryToken).resolve(root);
1997
- const userManager2 = EntityManagerToken.args(UserRepositoryToken).resolve(root);
2064
+ const userManager1 = withRepository(UserRepositoryToken).resolve(root);
2065
+ const userManager2 = withRepository(UserRepositoryToken).resolve(root);
1998
2066
 
1999
2067
  // Should be same instance (cached)
2000
2068
  expect(userManager1).toBe(userManager2);
2001
2069
 
2002
2070
  // Resolve todo manager
2003
- const todoManager = EntityManagerToken.args(TodoRepositoryToken).resolve(root);
2071
+ const todoManager = withRepository(TodoRepositoryToken).resolve(root);
2004
2072
 
2005
2073
  // Should be different from user manager
2006
2074
  expect(todoManager).not.toBe(userManager1);
@@ -3398,3 +3466,4 @@ The product-facing error contract is described in
3398
3466
  - [MethodNotImplementedError.ts](..%2F..%2Flib%2Ferrors%2FMethodNotImplementedError.ts)
3399
3467
  - [DependencyMissingKeyError.ts](..%2F..%2Flib%2Ferrors%2FDependencyMissingKeyError.ts)
3400
3468
  - [ContainerDisposedError.ts](..%2F..%2Flib%2Ferrors%2FContainerDisposedError.ts)
3469
+ - [ArgumentNotFoundError.ts](..%2F..%2Flib%2Ferrors%2FArgumentNotFoundError.ts)
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ArgumentNotFoundError = void 0;
4
+ const ContainerError_1 = require("./ContainerError");
5
+ class ArgumentNotFoundError extends ContainerError_1.ContainerError {
6
+ name = 'ArgumentNotFoundError';
7
+ constructor(message = 'Argument not found') {
8
+ super(message);
9
+ Object.setPrototypeOf(this, ArgumentNotFoundError.prototype);
10
+ }
11
+ }
12
+ exports.ArgumentNotFoundError = ArgumentNotFoundError;
package/cjm/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sequential = exports.injectProp = exports.createHookExecutionContext = exports.createHookContextFactory = exports.HookContext = exports.toHookFn = exports.hasHooks = exports.hook = exports.getHooks = exports.TypedEventDisposedError = exports.UnsupportedTokenTypeError = exports.CannonSingletonApplyTwiceError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.ContainerError = exports.Registration = exports.onResolve = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.arg = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.AutoResolveModule = exports.Container = exports.isDependencyKey = void 0;
4
- exports.ProxyRegistry = exports.pipe = exports.select = exports.TypedEvent = exports.getConstructorChain = exports.memoize = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.runAtOnce = exports.runInOrder = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.resolveConstructor = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.argToToken = exports.toMappedToken = exports.toToken = exports.InjectionToken = exports.toTask = exports.HookCollector = exports.oncePerInstance = exports.parallel = void 0;
5
- exports.Is = exports.unwrapProxy = void 0;
3
+ exports.injectProp = exports.createHookExecutionContext = exports.createHookContextFactory = exports.HookContext = exports.toHookFn = exports.hasHooks = exports.hook = exports.getHooks = exports.ArgumentNotFoundError = exports.TypedEventDisposedError = exports.UnsupportedTokenTypeError = exports.CannonSingletonApplyTwiceError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.ContainerError = exports.Registration = exports.onResolve = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.autoResolve = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.toRegistrationFn = exports.toProviderFn = exports.toBindToken = exports.registerPipe = exports.isProviderPipe = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.arg = exports.inject = exports.MetadataInjector = exports.Injector = exports.EmptyContainer = exports.AutoResolveModule = exports.Container = exports.isDependencyKey = void 0;
4
+ exports.pipe = exports.select = exports.TypedEvent = exports.getConstructorChain = exports.memoize = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.runAtOnce = exports.runInOrder = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.addMethodTag = exports.getMethodLabels = exports.addMethodLabel = exports.getMethodMeta = exports.addMethodMeta = exports.getParamTags = exports.addParamTag = exports.getParamLabels = exports.addParamLabel = exports.getParamMeta = exports.addParamMeta = exports.getClassTags = exports.addClassTag = exports.getClassLabels = exports.addClassLabel = exports.getClassMeta = exports.addClassMeta = exports.resolveConstructor = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.argToToken = exports.toMappedToken = exports.toToken = exports.InjectionToken = exports.toTask = exports.HookCollector = exports.oncePerInstance = exports.parallel = exports.sequential = void 0;
5
+ exports.Is = exports.unwrapProxy = exports.ProxyRegistry = exports.findOrFail = void 0;
6
6
  var IContainer_1 = require("./container/IContainer");
7
7
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
8
8
  var Container_1 = require("./container/Container");
@@ -65,6 +65,8 @@ var UnsupportedTokenTypeError_1 = require("./errors/UnsupportedTokenTypeError");
65
65
  Object.defineProperty(exports, "UnsupportedTokenTypeError", { enumerable: true, get: function () { return UnsupportedTokenTypeError_1.UnsupportedTokenTypeError; } });
66
66
  var TypedEventDisposedError_1 = require("./errors/TypedEventDisposedError");
67
67
  Object.defineProperty(exports, "TypedEventDisposedError", { enumerable: true, get: function () { return TypedEventDisposedError_1.TypedEventDisposedError; } });
68
+ var ArgumentNotFoundError_1 = require("./errors/ArgumentNotFoundError");
69
+ Object.defineProperty(exports, "ArgumentNotFoundError", { enumerable: true, get: function () { return ArgumentNotFoundError_1.ArgumentNotFoundError; } });
68
70
  var hook_1 = require("./hooks/hook");
69
71
  Object.defineProperty(exports, "getHooks", { enumerable: true, get: function () { return hook_1.getHooks; } });
70
72
  Object.defineProperty(exports, "hook", { enumerable: true, get: function () { return hook_1.hook; } });
@@ -152,6 +154,8 @@ var select_1 = require("./select");
152
154
  Object.defineProperty(exports, "select", { enumerable: true, get: function () { return select_1.select; } });
153
155
  var fp_1 = require("./utils/fp");
154
156
  Object.defineProperty(exports, "pipe", { enumerable: true, get: function () { return fp_1.pipe; } });
157
+ var array_1 = require("./utils/array");
158
+ Object.defineProperty(exports, "findOrFail", { enumerable: true, get: function () { return array_1.findOrFail; } });
155
159
  var ProxyRegistry_1 = require("./utils/ProxyRegistry");
156
160
  Object.defineProperty(exports, "ProxyRegistry", { enumerable: true, get: function () { return ProxyRegistry_1.ProxyRegistry; } });
157
161
  Object.defineProperty(exports, "unwrapProxy", { enumerable: true, get: function () { return ProxyRegistry_1.unwrapProxy; } });
@@ -27,6 +27,6 @@ const args = (c, { args = [] }) => args;
27
27
  exports.args = args;
28
28
  const resolveArgs = (target, methodName) => {
29
29
  const tokens = (0, parameter_1.getParamMeta)(hookMetaKey(methodName), target);
30
- return (scope, { args = [], lazy }) => tokens.map((fn) => fn.resolve(scope, { args: args.map(toToken_1.argToToken).map((t) => t.resolve(scope)), lazy }));
30
+ return (scope, { args = [], lazy }) => tokens.map((fn) => fn.resolve(scope, { args, lazy }));
31
31
  };
32
32
  exports.resolveArgs = resolveArgs;
@@ -6,7 +6,7 @@ class ClassToken extends InjectionToken_1.InjectionToken {
6
6
  target;
7
7
  _getArgsFn;
8
8
  _isLazy;
9
- constructor(target, { getArgsFn = () => [], isLazy = false } = {}) {
9
+ constructor(target, { getArgsFn = InjectionToken_1.forwardArgs, isLazy = false } = {}) {
10
10
  super();
11
11
  this.target = target;
12
12
  this._getArgsFn = getArgsFn;
@@ -6,7 +6,7 @@ class FunctionToken extends InjectionToken_1.InjectionToken {
6
6
  fn;
7
7
  _getArgsFn;
8
8
  _isLazy;
9
- constructor(fn, { getArgsFn = (_, { args = [] } = {}) => args, isLazy = false } = {}) {
9
+ constructor(fn, { getArgsFn = InjectionToken_1.forwardArgs, isLazy = false } = {}) {
10
10
  super();
11
11
  this.fn = fn;
12
12
  this._getArgsFn = getArgsFn;
@@ -6,7 +6,7 @@ class GroupAliasToken extends InjectionToken_1.InjectionToken {
6
6
  token;
7
7
  _getArgsFn;
8
8
  _isLazy;
9
- constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
9
+ constructor(token, { getArgsFn = InjectionToken_1.forwardArgs, isLazy = false } = {}) {
10
10
  super();
11
11
  this.token = token;
12
12
  this._getArgsFn = getArgsFn;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InjectionToken = void 0;
3
+ exports.InjectionToken = exports.forwardArgs = void 0;
4
4
  exports.isInjectionToken = isInjectionToken;
5
5
  const basic_1 = require("../utils/basic");
6
+ const forwardArgs = (_, { args = [] } = {}) => args;
7
+ exports.forwardArgs = forwardArgs;
6
8
  class InjectionToken {
7
9
  }
8
10
  exports.InjectionToken = InjectionToken;
@@ -6,7 +6,7 @@ class SingleAliasToken extends InjectionToken_1.InjectionToken {
6
6
  token;
7
7
  _getArgsFn;
8
8
  _isLazy;
9
- constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
9
+ constructor(token, { getArgsFn = InjectionToken_1.forwardArgs, isLazy = false } = {}) {
10
10
  super();
11
11
  this.token = token;
12
12
  this._getArgsFn = getArgsFn;
@@ -6,7 +6,7 @@ class SingleToken extends InjectionToken_1.InjectionToken {
6
6
  token;
7
7
  _getArgsFn;
8
8
  _isLazy;
9
- constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
9
+ constructor(token, { getArgsFn = InjectionToken_1.forwardArgs, isLazy = false } = {}) {
10
10
  super();
11
11
  this.token = token;
12
12
  this._getArgsFn = getArgsFn;
@@ -1,9 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Filter = void 0;
3
+ exports.findOrFail = exports.Filter = void 0;
4
+ const ArgumentNotFoundError_1 = require("../errors/ArgumentNotFoundError");
4
5
  exports.Filter = {
5
6
  exclude: (arr) => {
6
7
  const excludeSet = arr instanceof Array ? new Set(arr) : arr;
7
8
  return (v) => !excludeSet.has(v);
8
9
  },
9
10
  };
11
+ const findOrFail = (predicate) => (...args) => {
12
+ const index = args.findIndex((arg) => predicate(arg));
13
+ if (index === -1) {
14
+ throw new ArgumentNotFoundError_1.ArgumentNotFoundError();
15
+ }
16
+ return args[index];
17
+ };
18
+ exports.findOrFail = findOrFail;
@@ -0,0 +1,8 @@
1
+ import { ContainerError } from './ContainerError.js';
2
+ export class ArgumentNotFoundError extends ContainerError {
3
+ name = 'ArgumentNotFoundError';
4
+ constructor(message = 'Argument not found') {
5
+ super(message);
6
+ Object.setPrototypeOf(this, ArgumentNotFoundError.prototype);
7
+ }
8
+ }
package/esm/index.js CHANGED
@@ -19,6 +19,7 @@ export { ProviderDisposedError } from './errors/ProviderDisposedError.js';
19
19
  export { CannonSingletonApplyTwiceError } from './errors/CannonSingletonApplyTwiceError.js';
20
20
  export { UnsupportedTokenTypeError } from './errors/UnsupportedTokenTypeError.js';
21
21
  export { TypedEventDisposedError } from './errors/TypedEventDisposedError.js';
22
+ export { ArgumentNotFoundError } from './errors/ArgumentNotFoundError.js';
22
23
  export { getHooks, hook, hasHooks, toHookFn, } from './hooks/hook.js';
23
24
  export { HookContext, createHookContextFactory, createHookExecutionContext, } from './hooks/HookContext.js';
24
25
  export { injectProp } from './hooks/injectProp.js';
@@ -48,5 +49,6 @@ export { getConstructorChain } from './utils/getConstructorChain.js';
48
49
  export { TypedEvent } from './utils/TypedEvent.js';
49
50
  export { select } from './select.js';
50
51
  export { pipe } from './utils/fp.js';
52
+ export { findOrFail } from './utils/array.js';
51
53
  export { ProxyRegistry, unwrapProxy } from './utils/ProxyRegistry.js';
52
54
  export { Is } from './utils/basic.js';
@@ -1,7 +1,7 @@
1
1
  import { Injector } from './IInjector.js';
2
2
  import { resolveConstructor } from '../metadata/target.js';
3
- import { getParamMeta, addParamMeta } from '../metadata/parameter.js';
4
- import { argToToken, toMappedToken } from '../token/toToken.js';
3
+ import { addParamMeta, getParamMeta } from '../metadata/parameter.js';
4
+ import { toMappedToken } from '../token/toToken.js';
5
5
  export class MetadataInjector extends Injector {
6
6
  createInstance(scope, Target, { args: deps = [] } = {}) {
7
7
  const args = resolveArgs(Target)(scope, { args: deps });
@@ -19,5 +19,5 @@ export const arg = (index) => argsFn((value, i) => i === index);
19
19
  export const args = (c, { args = [] }) => args;
20
20
  export const resolveArgs = (target, methodName) => {
21
21
  const tokens = getParamMeta(hookMetaKey(methodName), target);
22
- return (scope, { args = [], lazy }) => tokens.map((fn) => fn.resolve(scope, { args: args.map(argToToken).map((t) => t.resolve(scope)), lazy }));
22
+ return (scope, { args = [], lazy }) => tokens.map((fn) => fn.resolve(scope, { args, lazy }));
23
23
  };
@@ -1,9 +1,9 @@
1
- import { InjectionToken } from './InjectionToken.js';
1
+ import { forwardArgs, InjectionToken } from './InjectionToken.js';
2
2
  export class ClassToken extends InjectionToken {
3
3
  target;
4
4
  _getArgsFn;
5
5
  _isLazy;
6
- constructor(target, { getArgsFn = () => [], isLazy = false } = {}) {
6
+ constructor(target, { getArgsFn = forwardArgs, isLazy = false } = {}) {
7
7
  super();
8
8
  this.target = target;
9
9
  this._getArgsFn = getArgsFn;
@@ -1,9 +1,9 @@
1
- import { InjectionToken } from './InjectionToken.js';
1
+ import { forwardArgs, InjectionToken } from './InjectionToken.js';
2
2
  export class FunctionToken extends InjectionToken {
3
3
  fn;
4
4
  _getArgsFn;
5
5
  _isLazy;
6
- constructor(fn, { getArgsFn = (_, { args = [] } = {}) => args, isLazy = false } = {}) {
6
+ constructor(fn, { getArgsFn = forwardArgs, isLazy = false } = {}) {
7
7
  super();
8
8
  this.fn = fn;
9
9
  this._getArgsFn = getArgsFn;
@@ -1,9 +1,9 @@
1
- import { InjectionToken } from './InjectionToken.js';
1
+ import { forwardArgs, InjectionToken } from './InjectionToken.js';
2
2
  export class GroupAliasToken extends InjectionToken {
3
3
  token;
4
4
  _getArgsFn;
5
5
  _isLazy;
6
- constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
6
+ constructor(token, { getArgsFn = forwardArgs, isLazy = false } = {}) {
7
7
  super();
8
8
  this.token = token;
9
9
  this._getArgsFn = getArgsFn;
@@ -1,4 +1,5 @@
1
1
  import { Is } from '../utils/basic.js';
2
+ export const forwardArgs = (_, { args = [] } = {}) => args;
2
3
  export class InjectionToken {
3
4
  }
4
5
  export function isInjectionToken(target) {
@@ -1,9 +1,9 @@
1
- import { InjectionToken } from './InjectionToken.js';
1
+ import { forwardArgs, InjectionToken } from './InjectionToken.js';
2
2
  export class SingleAliasToken extends InjectionToken {
3
3
  token;
4
4
  _getArgsFn;
5
5
  _isLazy;
6
- constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
6
+ constructor(token, { getArgsFn = forwardArgs, isLazy = false } = {}) {
7
7
  super();
8
8
  this.token = token;
9
9
  this._getArgsFn = getArgsFn;
@@ -1,9 +1,9 @@
1
- import { InjectionToken } from './InjectionToken.js';
1
+ import { forwardArgs, InjectionToken } from './InjectionToken.js';
2
2
  export class SingleToken extends InjectionToken {
3
3
  token;
4
4
  _getArgsFn;
5
5
  _isLazy;
6
- constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
6
+ constructor(token, { getArgsFn = forwardArgs, isLazy = false } = {}) {
7
7
  super();
8
8
  this.token = token;
9
9
  this._getArgsFn = getArgsFn;
@@ -1,6 +1,14 @@
1
+ import { ArgumentNotFoundError } from '../errors/ArgumentNotFoundError.js';
1
2
  export const Filter = {
2
3
  exclude: (arr) => {
3
4
  const excludeSet = arr instanceof Array ? new Set(arr) : arr;
4
5
  return (v) => !excludeSet.has(v);
5
6
  },
6
7
  };
8
+ export const findOrFail = (predicate) => (...args) => {
9
+ const index = args.findIndex((arg) => predicate(arg));
10
+ if (index === -1) {
11
+ throw new ArgumentNotFoundError();
12
+ }
13
+ return args[index];
14
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "68.0.0",
3
+ "version": "69.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
  "publishConfig": {
6
6
  "access": "public",
@@ -0,0 +1,5 @@
1
+ import { ContainerError } from './ContainerError.js';
2
+ export declare class ArgumentNotFoundError extends ContainerError {
3
+ name: string;
4
+ constructor(message?: string);
5
+ }
@@ -20,6 +20,7 @@ export { ProviderDisposedError } from './errors/ProviderDisposedError.js';
20
20
  export { CannonSingletonApplyTwiceError } from './errors/CannonSingletonApplyTwiceError.js';
21
21
  export { UnsupportedTokenTypeError } from './errors/UnsupportedTokenTypeError.js';
22
22
  export { TypedEventDisposedError } from './errors/TypedEventDisposedError.js';
23
+ export { ArgumentNotFoundError } from './errors/ArgumentNotFoundError.js';
23
24
  export { getHooks, hook, hasHooks, toHookFn, type HookFn, type HookClass, type HookType, type InjectFn, type HooksOfClass, } from './hooks/hook.js';
24
25
  export { HookContext, createHookContextFactory, createHookExecutionContext, type CreateHookExecutionContext, type IHookContext, } from './hooks/HookContext.js';
25
26
  export { injectProp } from './hooks/injectProp.js';
@@ -50,5 +51,6 @@ export { TypedEvent, type ITypedEvent, type TypedEventListener, type Unsubscribe
50
51
  export { type ExecutionContext } from './ExecutionContext.js';
51
52
  export { select } from './select.js';
52
53
  export { pipe, type MapFn } from './utils/fp.js';
54
+ export { findOrFail, type Predicate } from './utils/array.js';
53
55
  export { ProxyRegistry, unwrapProxy, type IProxyRegistry } from './utils/ProxyRegistry.js';
54
56
  export { type Branded, type constructor, type Instance, Is } from './utils/basic.js';
@@ -1,5 +1,6 @@
1
1
  import { type IContainer } from '../container/IContainer.js';
2
- import { ProviderOptions } from '../provider/IProvider.js';
2
+ import { ArgsFn, ProviderOptions } from '../provider/IProvider.js';
3
+ export declare const forwardArgs: ArgsFn;
3
4
  export declare abstract class InjectionToken<T = any> {
4
5
  abstract resolve(s: IContainer, options?: ProviderOptions): T;
5
6
  abstract args(...deps: unknown[]): InjectionToken<T>;
@@ -1,3 +1,5 @@
1
+ export type Predicate<T> = (value: T) => boolean;
1
2
  export declare const Filter: {
2
3
  exclude: <T>(arr: Set<T> | T[]) => (v: T) => boolean;
3
4
  };
5
+ export declare const findOrFail: <T>(predicate: Predicate<T>) => (...args: unknown[]) => T;