ts-ioc-container 32.19.2 → 33.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
@@ -151,6 +151,7 @@ import {
151
151
  by,
152
152
  scope,
153
153
  register,
154
+ Tag,
154
155
  } from 'ts-ioc-container';
155
156
 
156
157
  @register(key('ILogger'), scope((s) => s.hasTag('child')))
@@ -178,6 +179,23 @@ describe('Scopes', function () {
178
179
  expect(app.scope).not.toBe(root);
179
180
  expect(app.scope.hasTag('child')).toBe(true);
180
181
  });
182
+
183
+ it('should get path by reduceToRoot', () => {
184
+ const root = new Container(new MetadataInjector(), { tags: ['root'] });
185
+ const child = root.createScope('child');
186
+ const grandChild = child.createScope('grandChild');
187
+ const collectTags = (acc: Array<Tag[]>, c: IContainer) => [...acc, Array.from(c.tags)];
188
+
189
+ const tagsPath = grandChild.reduceToRoot(collectTags, []);
190
+ expect(tagsPath).toEqual([['root'], ['child'], ['grandChild']]);
191
+ const actual = root.findChild((s) => {
192
+ const current = tagsPath.shift() ?? [];
193
+ const a = current.every((t) => s.hasTag(t));
194
+ const b = tagsPath.length === 0;
195
+ return a && b;
196
+ });
197
+ expect(actual).toBe(grandChild);
198
+ });
181
199
  });
182
200
 
183
201
  ```
@@ -10,10 +10,10 @@ class AutoMockedContainer {
10
10
  this.level = 0;
11
11
  this.isDisposed = false;
12
12
  }
13
- getPath() {
14
- return [];
13
+ findChild(matchFn) {
14
+ return undefined;
15
15
  }
16
- findScopeByPath(path, matchTags) {
16
+ findParent(matchFn) {
17
17
  return undefined;
18
18
  }
19
19
  hasDependency(key) {
@@ -29,6 +29,9 @@ class AutoMockedContainer {
29
29
  getInstances() {
30
30
  return [];
31
31
  }
32
+ reduceToRoot(fn, initial) {
33
+ return initial;
34
+ }
32
35
  removeScope() { }
33
36
  use() {
34
37
  return this;
@@ -61,18 +61,14 @@ class Container {
61
61
  this.registrations.splice(0, this.registrations.length);
62
62
  }
63
63
  getInstances(direction = 'child') {
64
- switch (direction) {
65
- case 'parent': {
66
- return [...this.instances.values(), ...this.parent.getInstances('parent')];
67
- }
68
- case 'child': {
69
- const instances = [...this.instances.values()];
70
- for (const scope of this.scopes) {
71
- instances.push(...scope.getInstances('child'));
72
- }
73
- return instances;
74
- }
64
+ if (direction === 'parent') {
65
+ return this.parent.getInstances('parent').concat([...this.instances.values()]);
66
+ }
67
+ const instances = [...this.instances.values()];
68
+ for (const scope of this.scopes) {
69
+ instances.push(...scope.getInstances('child'));
75
70
  }
71
+ return instances;
76
72
  }
77
73
  hasTag(tag) {
78
74
  return this.tags.has(tag);
@@ -100,25 +96,24 @@ class Container {
100
96
  }
101
97
  return this.parent.resolveOneByAlias(predicate, { args, child, lazy });
102
98
  }
103
- getPath() {
104
- return [...this.parent.getPath(), Array.from(this.tags)];
99
+ reduceToRoot(fn, initial) {
100
+ return fn(this.parent.reduceToRoot(fn, initial), this);
105
101
  }
106
- findScopeByPath(tags, matchTags) {
107
- const [currentTags, ...rest] = tags;
108
- if (!matchTags(this, currentTags)) {
109
- return undefined;
102
+ findChild(matchFn) {
103
+ if (matchFn(this)) {
104
+ return this;
110
105
  }
111
106
  for (const scope of this.scopes) {
112
- const found = scope.findScopeByPath(rest, matchTags);
113
- if (found) {
114
- return found;
107
+ const child = scope.findChild(matchFn);
108
+ if (child) {
109
+ return child;
115
110
  }
116
111
  }
117
- if (rest.length === 0) {
118
- return this;
119
- }
120
112
  return undefined;
121
113
  }
114
+ findParent(matchFn) {
115
+ return matchFn(this) ? this : this.parent.findParent(matchFn);
116
+ }
122
117
  /**
123
118
  * @private
124
119
  */
@@ -16,10 +16,13 @@ class EmptyContainer {
16
16
  hasOwnInstance(value) {
17
17
  throw new Error('Method not implemented.');
18
18
  }
19
- getPath() {
20
- return [];
19
+ reduceToRoot(fn, initial) {
20
+ return initial;
21
+ }
22
+ findChild(matchFn) {
23
+ return undefined;
21
24
  }
22
- findScopeByPath(path, matchTags) {
25
+ findParent(matchFn) {
23
26
  return undefined;
24
27
  }
25
28
  hasDependency(key) {
@@ -7,10 +7,10 @@ export class AutoMockedContainer {
7
7
  this.level = 0;
8
8
  this.isDisposed = false;
9
9
  }
10
- getPath() {
11
- return [];
10
+ findChild(matchFn) {
11
+ return undefined;
12
12
  }
13
- findScopeByPath(path, matchTags) {
13
+ findParent(matchFn) {
14
14
  return undefined;
15
15
  }
16
16
  hasDependency(key) {
@@ -26,6 +26,9 @@ export class AutoMockedContainer {
26
26
  getInstances() {
27
27
  return [];
28
28
  }
29
+ reduceToRoot(fn, initial) {
30
+ return initial;
31
+ }
29
32
  removeScope() { }
30
33
  use() {
31
34
  return this;
@@ -58,18 +58,14 @@ export class Container {
58
58
  this.registrations.splice(0, this.registrations.length);
59
59
  }
60
60
  getInstances(direction = 'child') {
61
- switch (direction) {
62
- case 'parent': {
63
- return [...this.instances.values(), ...this.parent.getInstances('parent')];
64
- }
65
- case 'child': {
66
- const instances = [...this.instances.values()];
67
- for (const scope of this.scopes) {
68
- instances.push(...scope.getInstances('child'));
69
- }
70
- return instances;
71
- }
61
+ if (direction === 'parent') {
62
+ return this.parent.getInstances('parent').concat([...this.instances.values()]);
63
+ }
64
+ const instances = [...this.instances.values()];
65
+ for (const scope of this.scopes) {
66
+ instances.push(...scope.getInstances('child'));
72
67
  }
68
+ return instances;
73
69
  }
74
70
  hasTag(tag) {
75
71
  return this.tags.has(tag);
@@ -97,25 +93,24 @@ export class Container {
97
93
  }
98
94
  return this.parent.resolveOneByAlias(predicate, { args, child, lazy });
99
95
  }
100
- getPath() {
101
- return [...this.parent.getPath(), Array.from(this.tags)];
96
+ reduceToRoot(fn, initial) {
97
+ return fn(this.parent.reduceToRoot(fn, initial), this);
102
98
  }
103
- findScopeByPath(tags, matchTags) {
104
- const [currentTags, ...rest] = tags;
105
- if (!matchTags(this, currentTags)) {
106
- return undefined;
99
+ findChild(matchFn) {
100
+ if (matchFn(this)) {
101
+ return this;
107
102
  }
108
103
  for (const scope of this.scopes) {
109
- const found = scope.findScopeByPath(rest, matchTags);
110
- if (found) {
111
- return found;
104
+ const child = scope.findChild(matchFn);
105
+ if (child) {
106
+ return child;
112
107
  }
113
108
  }
114
- if (rest.length === 0) {
115
- return this;
116
- }
117
109
  return undefined;
118
110
  }
111
+ findParent(matchFn) {
112
+ return matchFn(this) ? this : this.parent.findParent(matchFn);
113
+ }
119
114
  /**
120
115
  * @private
121
116
  */
@@ -13,10 +13,13 @@ export class EmptyContainer {
13
13
  hasOwnInstance(value) {
14
14
  throw new Error('Method not implemented.');
15
15
  }
16
- getPath() {
17
- return [];
16
+ reduceToRoot(fn, initial) {
17
+ return initial;
18
+ }
19
+ findChild(matchFn) {
20
+ return undefined;
18
21
  }
19
- findScopeByPath(path, matchTags) {
22
+ findParent(matchFn) {
20
23
  return undefined;
21
24
  }
22
25
  hasDependency(key) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "32.19.2",
3
+ "version": "33.0.0",
4
4
  "description": "Typescript IoC container",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -59,5 +59,5 @@
59
59
  "ts-node": "^10.9.1",
60
60
  "typescript": "5.4.3"
61
61
  },
62
- "gitHead": "6079839647755cc6b4797f3abff6932de4a23d92"
62
+ "gitHead": "9fa774ef445611ecf1b7c08c450c3d251e2e2171"
63
63
  }
@@ -1,18 +1,19 @@
1
- import { AliasPredicate, DependencyKey, IContainer, InjectionToken, MatchTags, ResolveOptions, TagPath } from './IContainer';
1
+ import { AliasPredicate, DependencyKey, IContainer, InjectionToken, ReduceFn, ResolveOptions } from './IContainer';
2
2
  import { IRegistration } from '../registration/IRegistration';
3
3
  export declare abstract class AutoMockedContainer implements IContainer {
4
4
  tags: Set<string>;
5
5
  id: string;
6
6
  level: number;
7
7
  isDisposed: boolean;
8
- getPath(): TagPath;
9
- findScopeByPath(path: TagPath, matchTags: MatchTags): IContainer | undefined;
8
+ findChild(matchFn: (s: IContainer) => boolean): IContainer | undefined;
9
+ findParent(matchFn: (s: IContainer) => boolean): IContainer | undefined;
10
10
  hasDependency(key: string): boolean;
11
11
  createScope(): IContainer;
12
12
  abstract resolve<T>(key: InjectionToken<T>, options?: ResolveOptions): T;
13
13
  dispose(): void;
14
14
  register(): this;
15
15
  getInstances(): object[];
16
+ reduceToRoot<TResult>(fn: ReduceFn<TResult>, initial: TResult): TResult;
16
17
  removeScope(): void;
17
18
  use(): this;
18
19
  getRegistrations(): never[];
@@ -1,4 +1,4 @@
1
- import { AliasPredicate, DependencyKey, IContainer, IContainerModule, InjectionToken, MatchTags, ResolveOptions, Tag, TagPath } from './IContainer';
1
+ import { AliasPredicate, DependencyKey, IContainer, IContainerModule, InjectionToken, ReduceFn, ResolveOptions, Tag } from './IContainer';
2
2
  import { IInjector } from '../injector/IInjector';
3
3
  import { IProvider } from '../provider/IProvider';
4
4
  import { IRegistration } from '../registration/IRegistration';
@@ -31,8 +31,9 @@ export declare class Container implements IContainer {
31
31
  hasDependency(key: DependencyKey): boolean;
32
32
  resolveManyByAlias(predicate: AliasPredicate, { args, child, lazy }?: ResolveOptions, result?: Map<DependencyKey, unknown>): Map<DependencyKey, unknown>;
33
33
  resolveOneByAlias<T>(predicate: AliasPredicate, { args, child, lazy }?: ResolveOptions): [DependencyKey, T];
34
- getPath(): TagPath;
35
- findScopeByPath(tags: TagPath, matchTags: MatchTags): IContainer | undefined;
34
+ reduceToRoot<TResult>(fn: ReduceFn<TResult>, initial: TResult): TResult;
35
+ findChild(matchFn: (s: IContainer) => boolean): IContainer | undefined;
36
+ findParent(matchFn: (s: IContainer) => boolean): IContainer | undefined;
36
37
  /**
37
38
  * @private
38
39
  */
@@ -1,4 +1,4 @@
1
- import { AliasPredicate, DependencyKey, IContainer, IContainerModule, InjectionToken, MatchTags, ResolveOptions, TagPath } from './IContainer';
1
+ import { AliasPredicate, DependencyKey, IContainer, IContainerModule, InjectionToken, ReduceFn, ResolveOptions } from './IContainer';
2
2
  import { IProvider } from '../provider/IProvider';
3
3
  import { IRegistration } from '../registration/IRegistration';
4
4
  export declare class EmptyContainer implements IContainer {
@@ -8,8 +8,9 @@ export declare class EmptyContainer implements IContainer {
8
8
  level: number;
9
9
  id: string;
10
10
  tags: Set<string>;
11
- getPath(): TagPath;
12
- findScopeByPath(path: TagPath, matchTags: MatchTags): IContainer | undefined;
11
+ reduceToRoot<TResult>(fn: ReduceFn<TResult>, initial: TResult): TResult;
12
+ findChild(matchFn: (s: IContainer) => boolean): IContainer | undefined;
13
+ findParent(matchFn: (s: IContainer) => boolean): IContainer | undefined;
13
14
  hasDependency(key: string): boolean;
14
15
  hasTag(): boolean;
15
16
  createScope(): IContainer;
@@ -22,10 +22,9 @@ export interface Tagged {
22
22
  readonly level: number;
23
23
  hasTag(tag: Tag): boolean;
24
24
  }
25
- export type TagPath = Array<Tag[]>;
26
- export type MatchTags = (scope: IContainer, tags: Tag[]) => boolean;
27
25
  export type Alias = string;
28
26
  export type AliasPredicate = (aliases: Set<Alias>) => boolean;
27
+ export type ReduceFn<TResult> = (acc: TResult, container: IContainer) => TResult;
29
28
  export interface IContainer extends Resolvable, Tagged {
30
29
  readonly isDisposed: boolean;
31
30
  tags: Set<Tag>;
@@ -38,8 +37,9 @@ export interface IContainer extends Resolvable, Tagged {
38
37
  use(module: IContainerModule): this;
39
38
  getRegistrations(): IRegistration[];
40
39
  hasDependency(key: DependencyKey): boolean;
41
- getPath(): TagPath;
42
- findScopeByPath(path: TagPath, matchTags: MatchTags): IContainer | undefined;
40
+ reduceToRoot<TResult>(fn: ReduceFn<TResult>, initial: TResult): TResult;
41
+ findChild(matchFn: (s: IContainer) => boolean): IContainer | undefined;
42
+ findParent(matchFn: (s: IContainer) => boolean): IContainer | undefined;
43
43
  resolveManyByAlias(predicate: AliasPredicate, options?: ResolveOptions, result?: Map<DependencyKey, unknown>): Map<DependencyKey, unknown>;
44
44
  resolveOneByAlias<T>(predicate: AliasPredicate, options?: ResolveOptions): [DependencyKey, T];
45
45
  hasInstance(value: object): boolean;
@@ -1,4 +1,4 @@
1
- export { IContainer, Resolvable, IContainerModule, isDependencyKey, DependencyKey, InjectionToken, Tag, Tagged, TagPath, } from './container/IContainer';
1
+ export { IContainer, Resolvable, IContainerModule, isDependencyKey, DependencyKey, InjectionToken, Tag, Tagged, } from './container/IContainer';
2
2
  export { Container } from './container/Container';
3
3
  export { EmptyContainer } from './container/EmptyContainer';
4
4
  export { AutoMockedContainer } from './container/AutoMockedContainer';
@@ -12,7 +12,7 @@ export type ChildrenVisibilityPredicate = (options: {
12
12
  export type ArgsFn = (l: IContainer, ...args: unknown[]) => unknown[];
13
13
  export declare function args<T = unknown>(...extraArgs: unknown[]): MapFn<IProvider<T>>;
14
14
  export declare function argsFn<T = unknown>(fn: ArgsFn): MapFn<IProvider<T>>;
15
- export interface IProvider<T = unknown> {
15
+ export interface IProvider<T = any> {
16
16
  key?: DependencyKey;
17
17
  resolve(container: IContainer, options: ProviderResolveOptions): T;
18
18
  isVisible(parent: Tagged, child: Tagged): boolean;
@@ -1,7 +1,7 @@
1
1
  import { ArgsFn, ChildrenVisibilityPredicate, IProvider, ProviderResolveOptions, ResolveDependency } from './IProvider';
2
2
  import { Alias, AliasPredicate, DependencyKey, IContainer, Tagged } from '../container/IContainer';
3
3
  import { constructor, MapFn } from '../utils';
4
- export declare class Provider<T> implements IProvider<T> {
4
+ export declare class Provider<T = any> implements IProvider<T> {
5
5
  private readonly resolveDependency;
6
6
  static fromClass<T>(Target: constructor<T>): IProvider<T>;
7
7
  static fromValue<T>(value: T): IProvider<T>;
@@ -2,7 +2,7 @@ import { DependencyKey, IContainer, IContainerModule } from '../container/IConta
2
2
  import { constructor, MapFn } from '../utils';
3
3
  import { IProvider } from '../provider/IProvider';
4
4
  export type ScopePredicate = (s: IContainer) => boolean;
5
- export interface IRegistration<T = unknown> extends IContainerModule {
5
+ export interface IRegistration<T = any> extends IContainerModule {
6
6
  when(isValidWhen: ScopePredicate): this;
7
7
  to(key: DependencyKey): this;
8
8
  pipe(...mappers: MapFn<IProvider<T>>[]): this;
@@ -10,5 +10,5 @@ export interface IRegistration<T = unknown> extends IContainerModule {
10
10
  export type ReturnTypeOfRegistration<T> = T extends IRegistration<infer R> ? R : never;
11
11
  export declare const key: (key: DependencyKey) => MapFn<IRegistration>;
12
12
  export declare const scope: (predicate: ScopePredicate) => MapFn<IRegistration>;
13
- export declare const getTransformers: (Target: constructor<unknown>) => MapFn<IRegistration<unknown>>[];
13
+ export declare const getTransformers: (Target: constructor<unknown>) => MapFn<IRegistration<any>>[];
14
14
  export declare const register: (...mappers: MapFn<IRegistration>[]) => ClassDecorator;
@@ -2,12 +2,12 @@ import { DependencyKey, IContainer } from '../container/IContainer';
2
2
  import { constructor, MapFn } from '../utils';
3
3
  import { IProvider, ResolveDependency } from '../provider/IProvider';
4
4
  import { IRegistration, ScopePredicate } from './IRegistration';
5
- export declare class Registration<T = unknown> implements IRegistration<T> {
5
+ export declare class Registration<T = any> implements IRegistration<T> {
6
6
  private createProvider;
7
7
  private key?;
8
8
  private matchScope;
9
- static fromClass<T>(Target: constructor<T>): IRegistration<unknown>;
10
- static fromValue<T>(value: T): IRegistration<unknown>;
9
+ static fromClass<T>(Target: constructor<T>): IRegistration<any>;
10
+ static fromValue<T>(value: T): IRegistration<any>;
11
11
  static fromFn<T>(fn: ResolveDependency<T>): Registration<T>;
12
12
  private mappers;
13
13
  constructor(createProvider: (key: DependencyKey) => IProvider<T>, key?: DependencyKey | undefined, matchScope?: ScopePredicate);