ts-ioc-container 27.4.1 → 27.4.2

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
@@ -30,21 +30,20 @@
30
30
  - [Simple injector](#simple-injector)
31
31
  - [Proxy injector](#proxy-injector)
32
32
  - [Providers](#providers)
33
+ - [Registration module (Provider + DependencyKey)](#registration-and-providers) `@key`
33
34
  - [Provider](#provider) `@provider`
34
35
  - [Singleton provider](#singleton-provider)
35
36
  - [Tagged provider](#tagged-provider)
36
37
  - [Args provider](#args-provider)
37
38
  - [Aliases](#aliases) `alias`
38
39
  - [Container modules](#container-modules)
39
- - [Basic usage](#basic-usage-1)
40
- - [Registration module (Provider + DependencyKey)](#registration-module-provider--dependencykey) `@key`
41
40
  - [Hooks](#hooks) `@hook`
42
41
  - [OnConstruct](#onconstruct) `@onConstruct`
43
42
  - [OnDispose](#ondispose) `@onDispose`
44
43
  - [Tests and Mocks](#tests-and-mocks)
45
44
  - [Errors](#errors)
46
45
 
47
- ## Setup
46
+ ## Setu
48
47
 
49
48
  ```shell script
50
49
  npm install ts-ioc-container reflect-metadata
@@ -382,7 +381,7 @@ describe('ProxyInjector', function () {
382
381
 
383
382
  ```
384
383
 
385
- ## Providers
384
+ ## Registration and Providers
386
385
  `IProvider<T>` is used to describe how instances should be created. It has next basic methods:
387
386
  - `resolve` - creates instance with passed arguments
388
387
  - `clone` - we invoke it when we create a scope. It clones provider to new scope.
@@ -394,6 +393,58 @@ There are next types of providers:
394
393
  - `TaggedProvider` - provider that can be resolved only from container with certain tags and their sub scopes
395
394
  - `ArgsProvider` - provider that encapsulates arguments to pass it to constructor.
396
395
 
396
+ `Registration` - just a helper to register provider with certain key. `(preferrably to use)`
397
+
398
+ ### Registration (Provider + DependencyKey)
399
+ Sometimes you need to keep dependency key with class together. For example, you want to register class with key 'ILogger' and you want to keep this key with class. This is what `Registration` is for.
400
+
401
+ ```typescript
402
+ import 'reflect-metadata';
403
+ import { singleton, Container, tags, provider, ReflectionInjector, Registration as R, key } from 'ts-ioc-container';
404
+ import { DependencyMissingKeyError } from '../../lib/errors/DependencyMissingKeyError';
405
+
406
+ describe('Registration module', function () {
407
+ const createContainer = () => new Container(new ReflectionInjector(), { tags: ['root'] });
408
+
409
+ it('should register class', function () {
410
+ @key('ILogger')
411
+ @provider(singleton(), tags('root'))
412
+ class Logger {}
413
+
414
+ const root = createContainer().use(R.fromClass(Logger));
415
+
416
+ expect(root.resolve('ILogger')).toBeInstanceOf(Logger);
417
+ });
418
+
419
+ it('should register value', function () {
420
+ const root = createContainer().use(R.fromValue('smth').to('ISmth'));
421
+
422
+ expect(root.resolve('ISmth')).toBe('smth');
423
+ });
424
+
425
+ it('should register fn', function () {
426
+ const root = createContainer().use(R.fromFn(() => 'smth').to('ISmth'));
427
+
428
+ expect(root.resolve('ISmth')).toBe('smth');
429
+ });
430
+
431
+ it('should raise an error if key is not provider', () => {
432
+ expect(() => {
433
+ createContainer().use(R.fromValue('smth'));
434
+ }).toThrowError(DependencyMissingKeyError);
435
+ });
436
+
437
+ it('should register dependency by class name if @key is not provided', function () {
438
+ class FileLogger {}
439
+
440
+ const root = createContainer().use(R.fromClass(FileLogger));
441
+
442
+ expect(root.resolve('FileLogger')).toBeInstanceOf(FileLogger);
443
+ });
444
+ });
445
+
446
+ ```
447
+
397
448
  ### Provider
398
449
 
399
450
  ```typescript
@@ -618,8 +669,6 @@ describe('alias', () => {
618
669
  ## Container modules
619
670
  Sometimes you want to encapsulate registration logic in separate module. This is what `IContainerModule` is for.
620
671
 
621
- ### Basic usage
622
-
623
672
  ```typescript
624
673
  import 'reflect-metadata';
625
674
  import { IContainerModule, Registration as R, IContainer, key, Container, ReflectionInjector } from 'ts-ioc-container';
@@ -662,37 +711,6 @@ describe('Container Modules', function () {
662
711
 
663
712
  ```
664
713
 
665
- ### Registration module (Provider + DependencyKey)
666
- Sometimes you need to keep dependency key with class together. For example, you want to register class with key 'ILogger' and you want to keep this key with class. This is what `Registration` is for.
667
-
668
- ```typescript
669
- import 'reflect-metadata';
670
- import { singleton, Container, tags, provider, ReflectionInjector, Registration as R, key } from 'ts-ioc-container';
671
-
672
- describe('Registration module', function () {
673
- const createContainer = () => new Container(new ReflectionInjector(), { tags: ['root'] });
674
-
675
- it('should register dependency by @key', function () {
676
- @key('ILogger')
677
- @provider(singleton(), tags('root'))
678
- class Logger {}
679
-
680
- const root = createContainer().use(R.fromClass(Logger));
681
-
682
- expect(root.resolve('ILogger')).toBeInstanceOf(Logger);
683
- });
684
-
685
- it('should register dependency by class name if @key is not provided', function () {
686
- class FileLogger {}
687
-
688
- const root = createContainer().use(R.fromClass(FileLogger));
689
-
690
- expect(root.resolve('FileLogger')).toBeInstanceOf(FileLogger);
691
- });
692
- });
693
-
694
- ```
695
-
696
714
  ## Hooks
697
715
  Sometimes you need to invoke methods after construct or dispose of class. This is what hooks are for.
698
716
 
@@ -67,8 +67,10 @@ class Container {
67
67
  hasTag(tag) {
68
68
  return this.tags.includes(tag);
69
69
  }
70
- use(module) {
71
- module.applyTo(this);
70
+ use(...modules) {
71
+ for (const module of modules) {
72
+ module.applyTo(this);
73
+ }
72
74
  return this;
73
75
  }
74
76
  hasDependency(key) {
package/cjm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMetadata = exports.setMetadata = exports.by = exports.hook = exports.getHooks = exports.ProxyInjector = exports.SimpleInjector = exports.inject = exports.ReflectionInjector = exports.Registration = exports.key = exports.AutoMockedContainer = exports.TaggedProvider = exports.tags = exports.SingletonProvider = exports.singleton = exports.ArgsProvider = exports.args = exports.argsFn = exports.provider = exports.Provider = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.alias = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
3
+ exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = exports.by = exports.hook = exports.getHooks = exports.ProxyInjector = exports.SimpleInjector = exports.inject = exports.ReflectionInjector = exports.Registration = exports.key = exports.AutoMockedContainer = exports.TaggedProvider = exports.tags = exports.SingletonProvider = exports.singleton = exports.ArgsProvider = exports.args = exports.argsFn = exports.provider = exports.Provider = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyNotFoundError = exports.alias = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
4
4
  var IContainer_1 = require("./container/IContainer");
5
5
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
6
6
  var Container_1 = require("./container/Container");
@@ -48,3 +48,4 @@ Object.defineProperty(exports, "by", { enumerable: true, get: function () { retu
48
48
  var metadata_1 = require("./metadata");
49
49
  Object.defineProperty(exports, "setMetadata", { enumerable: true, get: function () { return metadata_1.setMetadata; } });
50
50
  Object.defineProperty(exports, "getMetadata", { enumerable: true, get: function () { return metadata_1.getMetadata; } });
51
+ Object.defineProperty(exports, "setParameterMetadata", { enumerable: true, get: function () { return metadata_1.setParameterMetadata; } });
@@ -2,19 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ReflectionInjector = exports.inject = void 0;
4
4
  const utils_1 = require("../utils");
5
+ const metadata_1 = require("../metadata");
5
6
  const INJECT_KEY = 'INJECT_FN_LIST';
6
- const inject = (value) => (target, propertyKey, parameterIndex) => {
7
- var _a;
8
- const metadata = (_a = Reflect.getOwnMetadata(INJECT_KEY, target)) !== null && _a !== void 0 ? _a : [];
9
- metadata[parameterIndex] = value;
10
- Reflect.defineMetadata(INJECT_KEY, metadata, target);
11
- };
7
+ const inject = (value) => (0, metadata_1.setParameterMetadata)(INJECT_KEY, value);
12
8
  exports.inject = inject;
13
9
  class ReflectionInjector {
14
10
  resolve(container, Target, ...deps) {
15
11
  var _a;
16
12
  const injectionFns = (_a = Reflect.getOwnMetadata(INJECT_KEY, Target)) !== null && _a !== void 0 ? _a : [];
17
- const args = (0, utils_1.merge)(injectionFns, deps.map(utils_1.constant)).map((fn) => fn(container));
13
+ const args = (0, utils_1.fillEmptyIndexes)(injectionFns, deps.map(utils_1.constant)).map((fn) => fn(container));
18
14
  return new Target(...args);
19
15
  }
20
16
  }
package/cjm/metadata.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMetadata = exports.setMetadata = void 0;
3
+ exports.setParameterMetadata = exports.getMetadata = exports.setMetadata = void 0;
4
4
  const setMetadata = (key, value) => (target) => {
5
5
  Reflect.defineMetadata(key, value, target);
6
6
  };
@@ -10,3 +10,10 @@ function getMetadata(target, key) {
10
10
  return Reflect.getOwnMetadata(key, target);
11
11
  }
12
12
  exports.getMetadata = getMetadata;
13
+ const setParameterMetadata = (key, value) => (target, propertyKey, parameterIndex) => {
14
+ var _a;
15
+ const metadata = (_a = Reflect.getOwnMetadata(key, target)) !== null && _a !== void 0 ? _a : [];
16
+ metadata[parameterIndex] = value;
17
+ Reflect.defineMetadata(key, metadata, target);
18
+ };
19
+ exports.setParameterMetadata = setParameterMetadata;
package/cjm/utils.js CHANGED
@@ -1,23 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.constant = exports.merge = exports.pipe = void 0;
3
+ exports.constant = exports.fillEmptyIndexes = exports.pipe = void 0;
4
4
  function pipe(...mappers) {
5
5
  return (value) => mappers.reduce((acc, current) => current(acc), value);
6
6
  }
7
7
  exports.pipe = pipe;
8
- function merge(baseArr, insertArr) {
9
- if (baseArr.length === 0) {
10
- return insertArr;
8
+ function fillEmptyIndexes(baseArr, insertArr) {
9
+ const a = [...baseArr];
10
+ const b = [...insertArr];
11
+ for (let i = 0; i < a.length; i++) {
12
+ if (a[i] === undefined) {
13
+ a[i] = b.shift();
14
+ }
11
15
  }
12
- if (insertArr.length === 0) {
13
- return baseArr;
14
- }
15
- const [b1, ...restBaseArr] = baseArr;
16
- const [i1, ...restInsertArr] = insertArr;
17
- return b1 === undefined
18
- ? [i1].concat(merge(restBaseArr, restInsertArr))
19
- : [b1].concat(merge(restBaseArr, insertArr));
16
+ return a.concat(b);
20
17
  }
21
- exports.merge = merge;
18
+ exports.fillEmptyIndexes = fillEmptyIndexes;
22
19
  const constant = (value) => () => value;
23
20
  exports.constant = constant;
@@ -64,8 +64,10 @@ export class Container {
64
64
  hasTag(tag) {
65
65
  return this.tags.includes(tag);
66
66
  }
67
- use(module) {
68
- module.applyTo(this);
67
+ use(...modules) {
68
+ for (const module of modules) {
69
+ module.applyTo(this);
70
+ }
69
71
  return this;
70
72
  }
71
73
  hasDependency(key) {
package/esm/index.js CHANGED
@@ -16,4 +16,4 @@ export { SimpleInjector } from './injector/SimpleInjector';
16
16
  export { ProxyInjector } from './injector/ProxyInjector';
17
17
  export { getHooks, hook } from './hook';
18
18
  export { by } from './by';
19
- export { setMetadata, getMetadata } from './metadata';
19
+ export { setMetadata, getMetadata, setParameterMetadata } from './metadata';
@@ -1,16 +1,12 @@
1
- import { constant, merge } from '../utils';
1
+ import { constant, fillEmptyIndexes } from '../utils';
2
+ import { setParameterMetadata } from '../metadata';
2
3
  const INJECT_KEY = 'INJECT_FN_LIST';
3
- export const inject = (value) => (target, propertyKey, parameterIndex) => {
4
- var _a;
5
- const metadata = (_a = Reflect.getOwnMetadata(INJECT_KEY, target)) !== null && _a !== void 0 ? _a : [];
6
- metadata[parameterIndex] = value;
7
- Reflect.defineMetadata(INJECT_KEY, metadata, target);
8
- };
4
+ export const inject = (value) => setParameterMetadata(INJECT_KEY, value);
9
5
  export class ReflectionInjector {
10
6
  resolve(container, Target, ...deps) {
11
7
  var _a;
12
8
  const injectionFns = (_a = Reflect.getOwnMetadata(INJECT_KEY, Target)) !== null && _a !== void 0 ? _a : [];
13
- const args = merge(injectionFns, deps.map(constant)).map((fn) => fn(container));
9
+ const args = fillEmptyIndexes(injectionFns, deps.map(constant)).map((fn) => fn(container));
14
10
  return new Target(...args);
15
11
  }
16
12
  }
package/esm/metadata.js CHANGED
@@ -5,3 +5,9 @@ export const setMetadata = (key, value) => (target) => {
5
5
  export function getMetadata(target, key) {
6
6
  return Reflect.getOwnMetadata(key, target);
7
7
  }
8
+ export const setParameterMetadata = (key, value) => (target, propertyKey, parameterIndex) => {
9
+ var _a;
10
+ const metadata = (_a = Reflect.getOwnMetadata(key, target)) !== null && _a !== void 0 ? _a : [];
11
+ metadata[parameterIndex] = value;
12
+ Reflect.defineMetadata(key, metadata, target);
13
+ };
package/esm/utils.js CHANGED
@@ -1,17 +1,14 @@
1
1
  export function pipe(...mappers) {
2
2
  return (value) => mappers.reduce((acc, current) => current(acc), value);
3
3
  }
4
- export function merge(baseArr, insertArr) {
5
- if (baseArr.length === 0) {
6
- return insertArr;
4
+ export function fillEmptyIndexes(baseArr, insertArr) {
5
+ const a = [...baseArr];
6
+ const b = [...insertArr];
7
+ for (let i = 0; i < a.length; i++) {
8
+ if (a[i] === undefined) {
9
+ a[i] = b.shift();
10
+ }
7
11
  }
8
- if (insertArr.length === 0) {
9
- return baseArr;
10
- }
11
- const [b1, ...restBaseArr] = baseArr;
12
- const [i1, ...restInsertArr] = insertArr;
13
- return b1 === undefined
14
- ? [i1].concat(merge(restBaseArr, restInsertArr))
15
- : [b1].concat(merge(restBaseArr, insertArr));
12
+ return a.concat(b);
16
13
  }
17
14
  export const constant = (value) => () => value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "27.4.1",
3
+ "version": "27.4.2",
4
4
  "description": "Typescript IoC container",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -41,8 +41,8 @@
41
41
  "build:cjm": "rimraf cjm && tsc -p tsconfig.production.json --outDir cjm --module CommonJS",
42
42
  "build:esm": "rimraf esm && tsc -p tsconfig.production.json --outDir esm",
43
43
  "build:types": "rimraf typings && tsc -p tsconfig.production.json --outDir typings --emitDeclarationOnly --declaration",
44
- "build:readme": "ts-node scripts/generateReadme/generateReadme.ts",
45
- "build": "npm run build:cjm && npm run build:esm && npm run build:types && npm run build:readme",
44
+ "generate:docs": "ts-node scripts/generateReadme/generateReadme.ts && git add README.md",
45
+ "build": "npm run build:cjm && npm run build:esm && npm run build:types",
46
46
  "coverage": "coveralls",
47
47
  "watch": "nodemon --watch ./lib --exec npm run build",
48
48
  "test": "jest --coverage"
@@ -60,5 +60,5 @@
60
60
  "ts-node": "^10.9.1",
61
61
  "typescript": "4.4.3"
62
62
  },
63
- "gitHead": "8e2634055ea996588cdf1a3c8aa76b83c489ab39"
63
+ "gitHead": "f3cf3333af2a2182dcce507a564d30c9cbee2ace"
64
64
  }
@@ -20,7 +20,7 @@ export declare class Container implements IContainer, Tagged {
20
20
  dispose(): void;
21
21
  getInstances(): unknown[];
22
22
  hasTag(tag: Tag): boolean;
23
- use(module: IContainerModule): this;
23
+ use(...modules: IContainerModule[]): this;
24
24
  hasDependency(key: DependencyKey): boolean;
25
25
  /**
26
26
  * @private
@@ -23,7 +23,7 @@ export interface IContainer extends Resolvable {
23
23
  removeScope(child: IContainer): void;
24
24
  getInstances(): unknown[];
25
25
  dispose(): void;
26
- use(module: IContainerModule): this;
26
+ use(...modules: IContainerModule[]): this;
27
27
  hasTag(tag: Tag): boolean;
28
28
  getAllProviders(): Map<DependencyKey, IProvider>;
29
29
  getTokensByProvider(predicate: (provider: IProvider) => boolean): DependencyKey[];
@@ -18,4 +18,4 @@ export { SimpleInjector } from './injector/SimpleInjector';
18
18
  export { ProxyInjector } from './injector/ProxyInjector';
19
19
  export { getHooks, hook } from './hook';
20
20
  export { by, InstancePredicate } from './by';
21
- export { setMetadata, getMetadata } from './metadata';
21
+ export { setMetadata, getMetadata, setParameterMetadata } from './metadata';
@@ -1,2 +1,3 @@
1
1
  export declare const setMetadata: <T>(key: string | symbol, value: T) => ClassDecorator;
2
2
  export declare function getMetadata<T>(target: Object, key: string | symbol): T | undefined;
3
+ export declare const setParameterMetadata: <T>(key: string | symbol, value: T) => ParameterDecorator;
@@ -1,5 +1,5 @@
1
1
  export declare type constructor<T> = new (...args: any[]) => T;
2
2
  export declare type MapFn<T> = (value: T) => T;
3
3
  export declare function pipe<T>(...mappers: MapFn<T>[]): MapFn<T>;
4
- export declare function merge<T>(baseArr: (T | undefined)[], insertArr: T[]): T[];
4
+ export declare function fillEmptyIndexes<T>(baseArr: (T | undefined)[], insertArr: T[]): T[];
5
5
  export declare const constant: <T>(value: T) => () => T;