ts-ioc-container 47.4.0 → 47.5.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 +65 -47
- package/cjm/container/Container.js +1 -1
- package/cjm/index.js +3 -2
- package/cjm/injector/ProxyInjector.js +5 -12
- package/cjm/injector/inject.js +7 -2
- package/cjm/provider/IProvider.js +1 -1
- package/cjm/provider/Provider.js +2 -2
- package/cjm/registration/Registration.js +2 -2
- package/cjm/token/ClassToken.js +27 -17
- package/cjm/token/FunctionToken.js +25 -15
- package/cjm/token/GroupAliasToken.js +18 -17
- package/cjm/token/InjectionToken.js +5 -0
- package/cjm/token/SingleAliasToken.js +18 -17
- package/cjm/token/SingleToken.js +20 -16
- package/esm/container/Container.js +1 -1
- package/esm/index.js +1 -1
- package/esm/injector/ProxyInjector.js +5 -12
- package/esm/injector/inject.js +5 -1
- package/esm/provider/IProvider.js +1 -1
- package/esm/provider/Provider.js +2 -2
- package/esm/registration/Registration.js +2 -2
- package/esm/token/ClassToken.js +28 -18
- package/esm/token/FunctionToken.js +25 -15
- package/esm/token/GroupAliasToken.js +19 -18
- package/esm/token/InjectionToken.js +4 -0
- package/esm/token/SingleAliasToken.js +19 -18
- package/esm/token/SingleToken.js +21 -17
- package/package.json +1 -1
- package/typings/hooks/hook.d.ts +1 -1
- package/typings/index.d.ts +1 -1
- package/typings/injector/IInjector.d.ts +1 -2
- package/typings/injector/ProxyInjector.d.ts +1 -1
- package/typings/injector/inject.d.ts +2 -1
- package/typings/provider/IProvider.d.ts +2 -2
- package/typings/provider/Provider.d.ts +1 -1
- package/typings/registration/Registration.d.ts +3 -1
- package/typings/token/ClassToken.d.ts +13 -8
- package/typings/token/FunctionToken.d.ts +10 -7
- package/typings/token/GroupAliasToken.d.ts +13 -8
- package/typings/token/InjectionToken.d.ts +4 -8
- package/typings/token/SingleAliasToken.d.ts +13 -8
- package/typings/token/SingleToken.d.ts +14 -9
package/README.md
CHANGED
|
@@ -248,9 +248,14 @@ describe('Basic usage', function () {
|
|
|
248
248
|
### Scope
|
|
249
249
|
Sometimes you need to create a scope of container. For example, when you want to create a scope per request in web application. You can assign tags to scope and provider and resolve dependencies only from certain scope.
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
> [!IMPORTANT]
|
|
252
|
+
> Scope creation is snapshot-like. Existing parent registrations are applied to the child scope when `createScope()` is called, and when a scope doesn't have a dependency it resolves from the parent container.
|
|
253
|
+
|
|
254
|
+
> [!WARNING]
|
|
255
|
+
> Registrations added to a parent after a child scope has already been created are not automatically applied to that existing child. Create a new scope or add the registration to the child explicitly.
|
|
256
|
+
|
|
257
|
+
> [!WARNING]
|
|
258
|
+
> Scope matching happens when a registration is applied to a container. Only registrations whose scope rules match that container are registered there.
|
|
254
259
|
|
|
255
260
|
```typescript
|
|
256
261
|
import 'reflect-metadata';
|
|
@@ -347,10 +352,12 @@ describe('Scopes', function () {
|
|
|
347
352
|
You can dynamically add tags to a container after it's been created using the `addTags()` method. This is useful for environment-based configuration, feature flags, and progressive container setup.
|
|
348
353
|
|
|
349
354
|
- Tags can be added one at a time or multiple at once
|
|
350
|
-
- Tags must be added **before** registrations are applied - scope matching happens at registration time
|
|
351
355
|
- Useful for conditional configuration based on `NODE_ENV` or runtime flags
|
|
352
356
|
- Container can be configured incrementally as the application initializes
|
|
353
357
|
|
|
358
|
+
> [!WARNING]
|
|
359
|
+
> Tags must be added **before** registrations are applied. Scope matching happens at registration time, so adding tags later does not retroactively make providers available.
|
|
360
|
+
|
|
354
361
|
```typescript
|
|
355
362
|
import { bindTo, Container, register, Registration as R, scope } from 'ts-ioc-container';
|
|
356
363
|
|
|
@@ -636,11 +643,13 @@ describe('hasRegistration', function () {
|
|
|
636
643
|
```
|
|
637
644
|
|
|
638
645
|
### Dispose
|
|
639
|
-
Sometimes you want to dispose container
|
|
646
|
+
Sometimes you want to dispose a container or scope. For example, when a request, page, widget, or other local lifecycle ends.
|
|
640
647
|
|
|
641
648
|
- container can be disposed
|
|
642
|
-
- when container is disposed then
|
|
643
|
-
|
|
649
|
+
- when container is disposed then it runs its `onDispose` hooks, unregisters its providers, removes its local instances, and detaches from its parent
|
|
650
|
+
|
|
651
|
+
> [!IMPORTANT]
|
|
652
|
+
> Dispose is local to the container being disposed. Child scopes are not disposed automatically; dispose them explicitly when their own lifecycle ends.
|
|
644
653
|
|
|
645
654
|
```typescript
|
|
646
655
|
import 'reflect-metadata';
|
|
@@ -744,6 +753,14 @@ describe('Disposing', function () {
|
|
|
744
753
|
### Lazy
|
|
745
754
|
Sometimes you want to create dependency only when somebody want to invoke it's method or property. This is what `lazy` is for.
|
|
746
755
|
|
|
756
|
+
- Lazy class instances are wrapped in a JavaScript `Proxy`; the real class instance is created on first property or method access.
|
|
757
|
+
|
|
758
|
+
> [!IMPORTANT]
|
|
759
|
+
> `lazy` is designed only for class instances resolved from class providers.
|
|
760
|
+
|
|
761
|
+
> [!WARNING]
|
|
762
|
+
> Do not use `lazy` for primitive values, plain values, functions, or non-class provider results.
|
|
763
|
+
|
|
747
764
|
```typescript
|
|
748
765
|
import 'reflect-metadata';
|
|
749
766
|
import { Container, inject, register, Registration as R, select as s, singleton } from 'ts-ioc-container';
|
|
@@ -869,7 +886,7 @@ describe('lazy provider', () => {
|
|
|
869
886
|
```
|
|
870
887
|
|
|
871
888
|
### Lazy with registerPipe
|
|
872
|
-
The `lazy()` registerPipe can be used in two ways: with the `@register` decorator or directly on the `Provider` pipe. This allows you to defer expensive
|
|
889
|
+
The `lazy()` registerPipe can be used in two ways: with the `@register` decorator or directly on the `Provider` pipe. This allows you to defer expensive class instance initialization until first access.
|
|
873
890
|
|
|
874
891
|
**Use cases:**
|
|
875
892
|
- Defer expensive initialization (database connections, SMTP, external APIs)
|
|
@@ -1466,22 +1483,12 @@ describe('SimpleInjector', function () {
|
|
|
1466
1483
|
### Proxy
|
|
1467
1484
|
This type of injector injects dependencies as dictionary `Record<string, unknown>`.
|
|
1468
1485
|
|
|
1486
|
+
- **`args` reserved keyword**: accessing `deps.args` returns the raw `args[]` array passed at resolve time
|
|
1487
|
+
- **Alias convention**: any property name containing `"alias"` (case-insensitive) is resolved via `resolveByAlias` instead of `resolve`
|
|
1488
|
+
|
|
1469
1489
|
```typescript
|
|
1470
1490
|
import { Container, ProxyInjector, Registration as R } from 'ts-ioc-container';
|
|
1471
1491
|
|
|
1472
|
-
/**
|
|
1473
|
-
* Clean Architecture - Proxy Injector
|
|
1474
|
-
*
|
|
1475
|
-
* The ProxyInjector injects dependencies as a single object (props/options pattern).
|
|
1476
|
-
* This is popular in modern JavaScript/TypeScript (like React props or destructuring).
|
|
1477
|
-
*
|
|
1478
|
-
* Advantages:
|
|
1479
|
-
* - Named parameters are more readable than positional arguments
|
|
1480
|
-
* - Order of arguments doesn't matter
|
|
1481
|
-
* - Easy to add/remove dependencies without breaking inheritance chains
|
|
1482
|
-
* - Works well with "Clean Architecture" adapters
|
|
1483
|
-
*/
|
|
1484
|
-
|
|
1485
1492
|
describe('ProxyInjector', function () {
|
|
1486
1493
|
it('should inject dependencies as a props object', function () {
|
|
1487
1494
|
class Logger {
|
|
@@ -1490,13 +1497,11 @@ describe('ProxyInjector', function () {
|
|
|
1490
1497
|
}
|
|
1491
1498
|
}
|
|
1492
1499
|
|
|
1493
|
-
// Dependencies defined as an interface
|
|
1494
1500
|
interface UserControllerDeps {
|
|
1495
1501
|
logger: Logger;
|
|
1496
1502
|
prefix: string;
|
|
1497
1503
|
}
|
|
1498
1504
|
|
|
1499
|
-
// Controller receives all dependencies in a single object
|
|
1500
1505
|
class UserController {
|
|
1501
1506
|
private logger: Logger;
|
|
1502
1507
|
private prefix: string;
|
|
@@ -1521,19 +1526,20 @@ describe('ProxyInjector', function () {
|
|
|
1521
1526
|
expect(controller.createUser('bob')).toBe('Logged: USER: bob');
|
|
1522
1527
|
});
|
|
1523
1528
|
|
|
1524
|
-
it('should
|
|
1529
|
+
it('should expose runtime args through the reserved "args" property', function () {
|
|
1525
1530
|
class Database {}
|
|
1526
1531
|
|
|
1527
|
-
|
|
1532
|
+
class ReportGenerator {
|
|
1528
1533
|
database: Database;
|
|
1529
|
-
format: string;
|
|
1530
|
-
}
|
|
1534
|
+
format: string;
|
|
1531
1535
|
|
|
1532
|
-
|
|
1533
|
-
|
|
1536
|
+
constructor({ database, args }: { database: Database; args: string[] }) {
|
|
1537
|
+
this.database = database;
|
|
1538
|
+
this.format = args[0];
|
|
1539
|
+
}
|
|
1534
1540
|
|
|
1535
1541
|
generate(): string {
|
|
1536
|
-
return `Report in ${this.
|
|
1542
|
+
return `Report in ${this.format}`;
|
|
1537
1543
|
}
|
|
1538
1544
|
}
|
|
1539
1545
|
|
|
@@ -1541,24 +1547,20 @@ describe('ProxyInjector', function () {
|
|
|
1541
1547
|
.addRegistration(R.fromClass(Database).bindToKey('database'))
|
|
1542
1548
|
.addRegistration(R.fromClass(ReportGenerator).bindToKey('ReportGenerator'));
|
|
1543
1549
|
|
|
1544
|
-
// "format" is passed at resolution time
|
|
1545
1550
|
const generator = container.resolve<ReportGenerator>('ReportGenerator', {
|
|
1546
|
-
args: [
|
|
1551
|
+
args: ['PDF'],
|
|
1547
1552
|
});
|
|
1548
1553
|
|
|
1549
|
-
expect(generator.
|
|
1554
|
+
expect(generator.database).toBeInstanceOf(Database);
|
|
1550
1555
|
expect(generator.generate()).toBe('Report in PDF');
|
|
1551
1556
|
});
|
|
1552
1557
|
|
|
1553
|
-
it('should resolve
|
|
1554
|
-
// If a property is named "loggersArray", it looks for alias "loggersArray"
|
|
1555
|
-
// and resolves it as an array of all matches.
|
|
1556
|
-
|
|
1558
|
+
it('should resolve dependencies by alias when property name contains "alias"', function () {
|
|
1557
1559
|
class FileLogger {}
|
|
1558
1560
|
class ConsoleLogger {}
|
|
1559
1561
|
|
|
1560
1562
|
interface AppDeps {
|
|
1561
|
-
|
|
1563
|
+
loggersAlias: any[];
|
|
1562
1564
|
}
|
|
1563
1565
|
|
|
1564
1566
|
class App {
|
|
@@ -1567,17 +1569,13 @@ describe('ProxyInjector', function () {
|
|
|
1567
1569
|
|
|
1568
1570
|
const container = new Container({ injector: new ProxyInjector() });
|
|
1569
1571
|
|
|
1570
|
-
// Mocking the behavior for this specific test as ProxyInjector uses resolveByAlias
|
|
1571
|
-
// which delegates to the container.
|
|
1572
|
-
// In a real scenario, you'd register multiple loggers with the same alias.
|
|
1573
1572
|
const mockLoggers = [new FileLogger(), new ConsoleLogger()];
|
|
1574
|
-
|
|
1575
1573
|
container.resolveByAlias = vi.fn().mockReturnValue(mockLoggers);
|
|
1576
1574
|
|
|
1577
1575
|
const app = container.resolve(App);
|
|
1578
1576
|
|
|
1579
|
-
expect(app.deps.
|
|
1580
|
-
expect(container.resolveByAlias).toHaveBeenCalledWith('
|
|
1577
|
+
expect(app.deps.loggersAlias).toBe(mockLoggers);
|
|
1578
|
+
expect(container.resolveByAlias).toHaveBeenCalledWith('loggersAlias');
|
|
1581
1579
|
});
|
|
1582
1580
|
});
|
|
1583
1581
|
|
|
@@ -1740,7 +1738,9 @@ describe('Provider', () => {
|
|
|
1740
1738
|
Sometimes you need to create only one instance of dependency per scope. For example, you want to create only one logger per scope.
|
|
1741
1739
|
|
|
1742
1740
|
- Singleton provider creates only one instance in every scope where it's resolved.
|
|
1743
|
-
|
|
1741
|
+
|
|
1742
|
+
> [!IMPORTANT]
|
|
1743
|
+
> Singleton means one instance per scope. If you create a scope `A` of container `root`, then `Logger` of `A` !== `Logger` of `root`.
|
|
1744
1744
|
|
|
1745
1745
|
```typescript
|
|
1746
1746
|
import 'reflect-metadata';
|
|
@@ -1831,13 +1831,28 @@ Sometimes you want to bind some arguments to provider. This is what `ArgsProvide
|
|
|
1831
1831
|
- `provider(setArgs('someArgument'))`
|
|
1832
1832
|
- `provider(setArgsFn((container) => [container.resolve(Logger), 'someValue']))`
|
|
1833
1833
|
- `Provider.fromClass(Logger).pipe(setArgs('someArgument'))`
|
|
1834
|
-
-
|
|
1834
|
+
- Use `setArgsFn(resolveByArgs)` to resolve `InjectionToken` args at resolution time (tokens are resolved, primitives pass through)
|
|
1835
|
+
|
|
1836
|
+
### Token as argument
|
|
1837
|
+
When passing args via `token.args(...)`, if an argument is an `InjectionToken` and the provider uses `setArgsFn(resolveByArgs)`, the token is resolved to its value rather than wrapped as a constant.
|
|
1838
|
+
- `ServiceToken.args(ValueToken)` — `ValueToken` is resolved from the container, its value is passed as arg
|
|
1839
|
+
- `ServiceToken.args('literal')` — literal value passed directly
|
|
1835
1840
|
|
|
1836
1841
|
### Positional arg injection with `args(index)`
|
|
1837
1842
|
Use `@inject(args(index))` to explicitly bind a constructor parameter to a positional argument from `ProviderOptions`. This is useful when combining `setArgsFn(resolveByArgs)` with token-based arg passing.
|
|
1838
1843
|
- `@inject(args(0))` — resolves the first element of the `args` array passed at resolution time
|
|
1839
1844
|
- Works together with `token.args(...)` to pass typed dependencies through the args context
|
|
1840
1845
|
|
|
1846
|
+
### Immutable token chaining
|
|
1847
|
+
`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).
|
|
1848
|
+
|
|
1849
|
+
```typescript
|
|
1850
|
+
const ApiToken = new SingleToken<IApiClient>('IApiClient');
|
|
1851
|
+
// Independent children — ApiToken is unchanged
|
|
1852
|
+
const dataToken = ApiToken.args('https://data.api.com', 5000);
|
|
1853
|
+
const userToken = ApiToken.args('https://users.api.com', 1000);
|
|
1854
|
+
```
|
|
1855
|
+
|
|
1841
1856
|
```typescript
|
|
1842
1857
|
import {
|
|
1843
1858
|
setArgs,
|
|
@@ -2008,6 +2023,10 @@ describe('ArgsProvider', function () {
|
|
|
2008
2023
|
|
|
2009
2024
|
### Visibility
|
|
2010
2025
|
Sometimes you want to hide dependency if somebody wants to resolve it from certain scope. This uses `ScopeAccessRule` to control access.
|
|
2026
|
+
|
|
2027
|
+
> [!IMPORTANT]
|
|
2028
|
+
> Use `scope()` to decide where a provider is registered. Use `scopeAccess()` to decide which invocation scopes can see an already registered provider.
|
|
2029
|
+
|
|
2011
2030
|
- `provider(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))` - dependency will be accessible only from the scope where it's registered
|
|
2012
2031
|
- `Provider.fromClass(Logger).pipe(scopeAccess(({ invocationScope, providerScope }) => invocationScope === providerScope))`
|
|
2013
2032
|
|
|
@@ -2808,4 +2827,3 @@ describe('inject property', () => {
|
|
|
2808
2827
|
- [MethodNotImplementedError.ts](..%2F..%2Flib%2Ferrors%2FMethodNotImplementedError.ts)
|
|
2809
2828
|
- [DependencyMissingKeyError.ts](..%2F..%2Flib%2Ferrors%2FDependencyMissingKeyError.ts)
|
|
2810
2829
|
- [ContainerDisposedError.ts](..%2F..%2Flib%2Ferrors%2FContainerDisposedError.ts)
|
|
2811
|
-
|
|
@@ -67,7 +67,7 @@ class Container {
|
|
|
67
67
|
const provider = key ? this.findProviderByKeyOrFail(key) : undefined;
|
|
68
68
|
return provider?.hasAccess({ invocationScope: child, providerScope: this })
|
|
69
69
|
? provider.resolve(this, { args, lazy })
|
|
70
|
-
: this.parent.resolveOneByAlias(
|
|
70
|
+
: this.parent.resolveOneByAlias(alias, { args, child, lazy });
|
|
71
71
|
}
|
|
72
72
|
createScope({ tags } = {}) {
|
|
73
73
|
this.validateContainer();
|
package/cjm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
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 = exports.SingleToken = exports.ClassToken = void 0;
|
|
3
|
+
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.MultiCache = exports.multiCache = exports.SingletonProvider = exports.singleton = exports.Provider = exports.resolveByArgs = exports.ProviderDecorator = exports.setArgs = exports.setArgsFn = 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 = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = 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; } });
|
|
@@ -14,6 +14,7 @@ var inject_1 = require("./injector/inject");
|
|
|
14
14
|
Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return inject_1.inject; } });
|
|
15
15
|
Object.defineProperty(exports, "resolveArgs", { enumerable: true, get: function () { return inject_1.resolveArgs; } });
|
|
16
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; } });
|
|
17
18
|
var IInjector_1 = require("./injector/IInjector");
|
|
18
19
|
Object.defineProperty(exports, "Injector", { enumerable: true, get: function () { return IInjector_1.Injector; } });
|
|
19
20
|
var MetadataInjector_1 = require("./injector/MetadataInjector");
|
|
@@ -2,21 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ProxyInjector = void 0;
|
|
4
4
|
const IInjector_1 = require("./IInjector");
|
|
5
|
-
function getProp(target, key) {
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
return target[key];
|
|
8
|
-
}
|
|
9
5
|
class ProxyInjector extends IInjector_1.Injector {
|
|
10
|
-
createInstance(scope, Target, { args
|
|
11
|
-
const args = deps.reduce((acc, it) => ({ ...acc, ...it }), {});
|
|
6
|
+
createInstance(scope, Target, { args = [] } = {}) {
|
|
12
7
|
const proxy = new Proxy({}, {
|
|
13
8
|
get(target, prop) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
? scope.resolveByAlias(prop)
|
|
19
|
-
: scope.resolve(prop);
|
|
9
|
+
if (prop === 'args') {
|
|
10
|
+
return args;
|
|
11
|
+
}
|
|
12
|
+
return prop.toString().search(/alias/gi) >= 0 ? scope.resolveByAlias(prop) : scope.resolve(prop);
|
|
20
13
|
},
|
|
21
14
|
});
|
|
22
15
|
return new Target(proxy);
|
package/cjm/injector/inject.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveArgs = exports.args = exports.inject = void 0;
|
|
3
|
+
exports.resolveArgs = exports.argsFn = exports.args = exports.inject = void 0;
|
|
4
|
+
const InjectionToken_1 = require("../token/InjectionToken");
|
|
4
5
|
const ConstantToken_1 = require("../token/ConstantToken");
|
|
5
6
|
const toToken_1 = require("../token/toToken");
|
|
6
7
|
const array_1 = require("../utils/array");
|
|
@@ -15,10 +16,14 @@ const args = (index) => (c, { args = [] }) => {
|
|
|
15
16
|
return args[index];
|
|
16
17
|
};
|
|
17
18
|
exports.args = args;
|
|
19
|
+
const argsFn = (fn) => (c, options) => fn(options.args ?? []);
|
|
20
|
+
exports.argsFn = argsFn;
|
|
18
21
|
const resolveArgs = (Target, methodName) => {
|
|
19
22
|
const argsTokens = (0, parameter_1.getParamMeta)(hookMetaKey(methodName), Target);
|
|
20
23
|
return (scope, { args = [], lazy }) => {
|
|
21
|
-
const depsTokens = args.map((v) =>
|
|
24
|
+
const depsTokens = args.map((v) => {
|
|
25
|
+
return !(0, InjectionToken_1.isInjectionToken)(v) ? new ConstantToken_1.ConstantToken(v) : v;
|
|
26
|
+
});
|
|
22
27
|
const allTokens = (0, array_1.fillEmptyIndexes)(argsTokens, depsTokens);
|
|
23
28
|
return allTokens.map((fn) => fn.resolve(scope, { args, lazy }));
|
|
24
29
|
};
|
|
@@ -8,7 +8,7 @@ const setArgs = (...extraArgs) => (0, ProviderPipe_1.registerPipe)((p) => p.setA
|
|
|
8
8
|
exports.setArgs = setArgs;
|
|
9
9
|
const setArgsFn = (fn) => (0, ProviderPipe_1.registerPipe)((p) => p.setArgs(fn));
|
|
10
10
|
exports.setArgsFn = setArgsFn;
|
|
11
|
-
const resolveByArgs = (s,
|
|
11
|
+
const resolveByArgs = (s, { args = [] } = {}) => args.map((d) => {
|
|
12
12
|
if (d instanceof InjectionToken_1.InjectionToken) {
|
|
13
13
|
return d.resolve(s);
|
|
14
14
|
}
|
package/cjm/provider/Provider.js
CHANGED
|
@@ -14,7 +14,7 @@ class Provider {
|
|
|
14
14
|
static fromKey(key) {
|
|
15
15
|
return new Provider((c) => c.resolve(key));
|
|
16
16
|
}
|
|
17
|
-
argsFn = () =>
|
|
17
|
+
argsFn = (s, { args = [] } = {}) => args;
|
|
18
18
|
checkAccess = () => true;
|
|
19
19
|
isLazy = false;
|
|
20
20
|
constructor(resolveDependency) {
|
|
@@ -26,7 +26,7 @@ class Provider {
|
|
|
26
26
|
}
|
|
27
27
|
resolve(container, { args = [], lazy } = {}) {
|
|
28
28
|
return this.resolveDependency(container, {
|
|
29
|
-
args:
|
|
29
|
+
args: this.argsFn(container, { args }),
|
|
30
30
|
lazy: lazy ?? this.isLazy,
|
|
31
31
|
});
|
|
32
32
|
}
|
|
@@ -13,9 +13,9 @@ class Registration {
|
|
|
13
13
|
createProvider;
|
|
14
14
|
key;
|
|
15
15
|
scopeRules;
|
|
16
|
-
static fromClass(Target) {
|
|
16
|
+
static fromClass(Target, { name } = {}) {
|
|
17
17
|
const transform = (0, fp_1.pipe)(...(0, IRegistration_1.getTransformers)(Target));
|
|
18
|
-
return transform(new Registration(() => Provider_1.Provider.fromClass(Target), Target.name));
|
|
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)) {
|
package/cjm/token/ClassToken.js
CHANGED
|
@@ -3,33 +3,43 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ClassToken = void 0;
|
|
4
4
|
const InjectionToken_1 = require("./InjectionToken");
|
|
5
5
|
class ClassToken extends InjectionToken_1.InjectionToken {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
target;
|
|
7
|
+
_getArgsFn;
|
|
8
|
+
_isLazy;
|
|
9
|
+
constructor(target, { getArgsFn = () => [], isLazy = false } = {}) {
|
|
9
10
|
super();
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
11
|
+
this.target = target;
|
|
12
|
+
this._getArgsFn = getArgsFn;
|
|
13
|
+
this._isLazy = isLazy;
|
|
12
14
|
}
|
|
13
15
|
select(fn) {
|
|
14
16
|
return (s) => fn(this.resolve(s));
|
|
15
17
|
}
|
|
16
|
-
resolve(s) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
lazy: this.options.lazy,
|
|
18
|
+
resolve(s, { args = [], lazy } = {}) {
|
|
19
|
+
return s.resolve(this.target, {
|
|
20
|
+
args: this._getArgsFn(s, { args }),
|
|
21
|
+
lazy: this._isLazy || lazy,
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
|
-
args(...
|
|
24
|
-
const
|
|
25
|
-
return new ClassToken(this.
|
|
24
|
+
args(...newArgs) {
|
|
25
|
+
const parentFn = this._getArgsFn;
|
|
26
|
+
return new ClassToken(this.target, {
|
|
27
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...newArgs],
|
|
28
|
+
isLazy: this._isLazy,
|
|
29
|
+
});
|
|
26
30
|
}
|
|
27
|
-
argsFn(
|
|
28
|
-
const
|
|
29
|
-
return new ClassToken(this.
|
|
31
|
+
argsFn(fn) {
|
|
32
|
+
const parentFn = this._getArgsFn;
|
|
33
|
+
return new ClassToken(this.target, {
|
|
34
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...fn(s)],
|
|
35
|
+
isLazy: this._isLazy,
|
|
36
|
+
});
|
|
30
37
|
}
|
|
31
38
|
lazy() {
|
|
32
|
-
return new ClassToken(this.
|
|
39
|
+
return new ClassToken(this.target, {
|
|
40
|
+
getArgsFn: this._getArgsFn,
|
|
41
|
+
isLazy: true,
|
|
42
|
+
});
|
|
33
43
|
}
|
|
34
44
|
}
|
|
35
45
|
exports.ClassToken = ClassToken;
|
|
@@ -4,29 +4,39 @@ exports.FunctionToken = void 0;
|
|
|
4
4
|
const InjectionToken_1 = require("./InjectionToken");
|
|
5
5
|
class FunctionToken extends InjectionToken_1.InjectionToken {
|
|
6
6
|
fn;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
constructor(fn) {
|
|
7
|
+
_getArgsFn;
|
|
8
|
+
_isLazy;
|
|
9
|
+
constructor(fn, { getArgsFn = (_, { args = [] } = {}) => args, isLazy = false } = {}) {
|
|
10
10
|
super();
|
|
11
11
|
this.fn = fn;
|
|
12
|
+
this._getArgsFn = getArgsFn;
|
|
13
|
+
this._isLazy = isLazy;
|
|
12
14
|
}
|
|
13
|
-
resolve(s, { args = [], lazy
|
|
15
|
+
resolve(s, { args = [], lazy } = {}) {
|
|
14
16
|
return this.fn(s, {
|
|
15
|
-
args:
|
|
16
|
-
lazy: this.
|
|
17
|
+
args: this._getArgsFn(s, { args }),
|
|
18
|
+
lazy: this._isLazy || lazy,
|
|
17
19
|
});
|
|
18
20
|
}
|
|
19
|
-
args(...
|
|
20
|
-
|
|
21
|
-
return this
|
|
21
|
+
args(...newArgs) {
|
|
22
|
+
const parentFn = this._getArgsFn;
|
|
23
|
+
return new FunctionToken(this.fn, {
|
|
24
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...newArgs],
|
|
25
|
+
isLazy: this._isLazy,
|
|
26
|
+
});
|
|
22
27
|
}
|
|
23
|
-
argsFn(
|
|
24
|
-
|
|
25
|
-
return this
|
|
28
|
+
argsFn(fn) {
|
|
29
|
+
const parentFn = this._getArgsFn;
|
|
30
|
+
return new FunctionToken(this.fn, {
|
|
31
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...fn(s)],
|
|
32
|
+
isLazy: this._isLazy,
|
|
33
|
+
});
|
|
26
34
|
}
|
|
27
|
-
lazy(
|
|
28
|
-
this.
|
|
29
|
-
|
|
35
|
+
lazy() {
|
|
36
|
+
return new FunctionToken(this.fn, {
|
|
37
|
+
getArgsFn: this._getArgsFn,
|
|
38
|
+
isLazy: true,
|
|
39
|
+
});
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
42
|
exports.FunctionToken = FunctionToken;
|
|
@@ -4,43 +4,44 @@ exports.toGroupAlias = exports.GroupAliasToken = void 0;
|
|
|
4
4
|
const InjectionToken_1 = require("./InjectionToken");
|
|
5
5
|
class GroupAliasToken extends InjectionToken_1.InjectionToken {
|
|
6
6
|
token;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
_getArgsFn;
|
|
8
|
+
_isLazy;
|
|
9
|
+
constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
|
|
9
10
|
super();
|
|
10
11
|
this.token = token;
|
|
11
|
-
this.
|
|
12
|
+
this._getArgsFn = getArgsFn;
|
|
13
|
+
this._isLazy = isLazy;
|
|
12
14
|
}
|
|
13
15
|
select(fn) {
|
|
14
16
|
return (s) => fn(this.resolve(s));
|
|
15
17
|
}
|
|
16
|
-
resolve(s) {
|
|
17
|
-
const argsFn = this.options.argsFn ?? (0, InjectionToken_1.setArgs)();
|
|
18
|
+
resolve(s, { args = [], lazy } = {}) {
|
|
18
19
|
return s.resolveByAlias(this.token, {
|
|
19
|
-
args:
|
|
20
|
-
lazy: this.
|
|
20
|
+
args: this._getArgsFn(s, { args }),
|
|
21
|
+
lazy: this._isLazy || lazy,
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
24
|
bindTo(r) {
|
|
24
25
|
r.bindToAlias(this.token);
|
|
25
26
|
}
|
|
26
|
-
args(...
|
|
27
|
-
const
|
|
27
|
+
args(...newArgs) {
|
|
28
|
+
const parentFn = this._getArgsFn;
|
|
28
29
|
return new GroupAliasToken(this.token, {
|
|
29
|
-
...
|
|
30
|
-
|
|
30
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...newArgs],
|
|
31
|
+
isLazy: this._isLazy,
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
|
-
argsFn(
|
|
34
|
-
const
|
|
34
|
+
argsFn(fn) {
|
|
35
|
+
const parentFn = this._getArgsFn;
|
|
35
36
|
return new GroupAliasToken(this.token, {
|
|
36
|
-
...
|
|
37
|
-
|
|
37
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...fn(s)],
|
|
38
|
+
isLazy: this._isLazy,
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
lazy() {
|
|
41
42
|
return new GroupAliasToken(this.token, {
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
getArgsFn: this._getArgsFn,
|
|
44
|
+
isLazy: true,
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.setArgs = exports.InjectionToken = void 0;
|
|
4
|
+
exports.isInjectionToken = isInjectionToken;
|
|
5
|
+
const basic_1 = require("../utils/basic");
|
|
4
6
|
class InjectionToken {
|
|
5
7
|
}
|
|
6
8
|
exports.InjectionToken = InjectionToken;
|
|
7
9
|
const setArgs = (...args) => (s) => args;
|
|
8
10
|
exports.setArgs = setArgs;
|
|
11
|
+
function isInjectionToken(target) {
|
|
12
|
+
return basic_1.Is.object(target) && 'resolve' in target && 'args' in target && 'argsFn' in target && 'lazy' in target;
|
|
13
|
+
}
|
|
@@ -4,43 +4,44 @@ exports.toSingleAlias = exports.SingleAliasToken = void 0;
|
|
|
4
4
|
const InjectionToken_1 = require("./InjectionToken");
|
|
5
5
|
class SingleAliasToken extends InjectionToken_1.InjectionToken {
|
|
6
6
|
token;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
_getArgsFn;
|
|
8
|
+
_isLazy;
|
|
9
|
+
constructor(token, { getArgsFn = () => [], isLazy = false } = {}) {
|
|
9
10
|
super();
|
|
10
11
|
this.token = token;
|
|
11
|
-
this.
|
|
12
|
+
this._getArgsFn = getArgsFn;
|
|
13
|
+
this._isLazy = isLazy;
|
|
12
14
|
}
|
|
13
15
|
select(fn) {
|
|
14
16
|
return (s) => fn(this.resolve(s));
|
|
15
17
|
}
|
|
16
|
-
resolve(s) {
|
|
17
|
-
const argsFn = this.options.argsFn ?? (0, InjectionToken_1.setArgs)();
|
|
18
|
+
resolve(s, { args = [], lazy } = {}) {
|
|
18
19
|
return s.resolveOneByAlias(this.token, {
|
|
19
|
-
args:
|
|
20
|
-
lazy: this.
|
|
20
|
+
args: this._getArgsFn(s, { args }),
|
|
21
|
+
lazy: this._isLazy || lazy,
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
24
|
bindTo(r) {
|
|
24
25
|
r.bindToAlias(this.token);
|
|
25
26
|
}
|
|
26
|
-
args(...
|
|
27
|
-
const
|
|
27
|
+
args(...newArgs) {
|
|
28
|
+
const parentFn = this._getArgsFn;
|
|
28
29
|
return new SingleAliasToken(this.token, {
|
|
29
|
-
...
|
|
30
|
-
|
|
30
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...newArgs],
|
|
31
|
+
isLazy: this._isLazy,
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
|
-
argsFn(
|
|
34
|
-
const
|
|
34
|
+
argsFn(fn) {
|
|
35
|
+
const parentFn = this._getArgsFn;
|
|
35
36
|
return new SingleAliasToken(this.token, {
|
|
36
|
-
...
|
|
37
|
-
|
|
37
|
+
getArgsFn: (s, opts) => [...parentFn(s, opts), ...fn(s)],
|
|
38
|
+
isLazy: this._isLazy,
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
lazy() {
|
|
41
42
|
return new SingleAliasToken(this.token, {
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
getArgsFn: this._getArgsFn,
|
|
44
|
+
isLazy: true,
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
}
|