ts-ioc-container 56.0.0 → 56.1.1

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
@@ -5,7 +5,6 @@
5
5
  ![npm package minimized gzipped size (select exports)](https://img.shields.io/bundlejs/size/ts-ioc-container)
6
6
  [![Coverage Status](https://coveralls.io/repos/github/IgorBabkin/ts-ioc-container/badge.svg?branch=master)](https://coveralls.io/github/IgorBabkin/ts-ioc-container?branch=master)
7
7
  ![License](https://img.shields.io/npm/l/ts-ioc-container)
8
- [![semantic-release](https://img.shields.io/badge/%20%20%20FLO%20-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
9
8
 
10
9
  `ts-ioc-container` is a fast, lightweight TypeScript dependency injection
11
10
  container for applications that need more than basic constructor injection:
@@ -2167,6 +2166,8 @@ Registration is provider factory which registers provider in container.
2167
2166
 
2168
2167
  Use `bindTo(key)` to register a provider under a specific key. By default the key is the class name. Multiple registrations can share the same key.
2169
2168
 
2169
+ A plain `DependencyKey` (`string` / `symbol`) or an `InjectionToken` that implements `BindToken` (`SingleToken`, `SingleAliasToken`, `GroupAliasToken`) can also be passed directly to `@register(...)` — it binds under the hood exactly like `bindTo(...)`, so `@register('ILogger')` / `@register(LoggerToken)` and `@register(bindTo('ILogger'))` / `@register(bindTo(LoggerToken))` are equivalent.
2170
+
2170
2171
  > [!TIP]
2171
2172
  > Prefer `SingleToken<T>` over plain string literals as registration keys. Tokens are type-safe, rename-friendly, and prevent typos that only surface at runtime.
2172
2173
 
@@ -2179,6 +2180,7 @@ import {
2179
2180
  Registration as R,
2180
2181
  scope,
2181
2182
  select as s,
2183
+ SingleToken,
2182
2184
  singleton,
2183
2185
  } from 'ts-ioc-container';
2184
2186
 
@@ -2240,6 +2242,28 @@ describe('Registration module', function () {
2240
2242
  expect(appContainer.resolve('FileLogger')).toBeInstanceOf(FileLogger);
2241
2243
  });
2242
2244
 
2245
+ it('should register directly from a token passed to @register, without wrapping it in bindTo()', function () {
2246
+ // Passing an InjectionToken straight to @register binds to it under the hood
2247
+ const LoggerToken = new SingleToken<FileLogger>('ILogger');
2248
+
2249
+ @register(LoggerToken, singleton())
2250
+ class FileLogger {}
2251
+
2252
+ const appContainer = createAppContainer().addRegistration(R.fromClass(FileLogger));
2253
+
2254
+ expect(LoggerToken.resolve(appContainer)).toBeInstanceOf(FileLogger);
2255
+ });
2256
+
2257
+ it('should register directly from a plain key passed to @register, without wrapping it in bindTo()', function () {
2258
+ // A plain DependencyKey straight in @register binds to it under the hood
2259
+ @register('PlainLogger')
2260
+ class Logger {}
2261
+
2262
+ const appContainer = createAppContainer().addRegistration(R.fromClass(Logger));
2263
+
2264
+ expect(appContainer.resolve('PlainLogger')).toBeInstanceOf(Logger);
2265
+ });
2266
+
2243
2267
  it('should register with multiple keys using aliases', function () {
2244
2268
  // Same service accessible via direct key and alias
2245
2269
  @register(bindTo('ILogger'), bindTo(s.alias('Logger')), singleton())
package/cjm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AddOnDisposeHookModule = exports.onContainerDisposed = exports.onContainerDisposedHooksRunner = exports.AddOnConstructAsyncHookModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.prepend = exports.append = exports.prependHooks = exports.appendHooks = exports.hasHooks = exports.hook = exports.getHooks = exports.CannonSingletonApplyTwiceError = exports.UnexpectedHookResultError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.Registration = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.inject = exports.MetadataInjector = exports.Injector = 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.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.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.InjectionToken = exports.HooksRunner = void 0;
3
+ exports.onContainerDisposedHooksRunner = exports.AddOnConstructAsyncHookModule = exports.onConstructAsync = exports.onConstructAsyncHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.prepend = exports.append = exports.prependHooks = exports.appendHooks = exports.hasHooks = exports.hook = exports.getHooks = exports.UnsupportedTokenTypeError = exports.CannonSingletonApplyTwiceError = exports.UnexpectedHookResultError = exports.ProviderDisposedError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.ContainerNotFoundError = exports.DependencyNotFoundError = exports.ContainerError = exports.Registration = exports.appendArgsFn = exports.appendArgs = exports.decorate = exports.singleton = exports.lazy = exports.scopeAccess = exports.scope = exports.bindTo = exports.register = exports.Provider = exports.ProxyInjector = exports.SimpleInjector = exports.resolveArgs = exports.argsFn = exports.args = exports.inject = exports.MetadataInjector = exports.Injector = 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.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.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.InjectionToken = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onContainerDisposed = void 0;
5
5
  var IContainer_1 = require("./container/IContainer");
6
6
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
7
7
  var Container_1 = require("./container/Container");
@@ -34,6 +34,8 @@ Object.defineProperty(exports, "appendArgs", { enumerable: true, get: function (
34
34
  Object.defineProperty(exports, "appendArgsFn", { enumerable: true, get: function () { return IRegistration_1.appendArgsFn; } });
35
35
  var Registration_1 = require("./registration/Registration");
36
36
  Object.defineProperty(exports, "Registration", { enumerable: true, get: function () { return Registration_1.Registration; } });
37
+ var ContainerError_1 = require("./errors/ContainerError");
38
+ Object.defineProperty(exports, "ContainerError", { enumerable: true, get: function () { return ContainerError_1.ContainerError; } });
37
39
  var DependencyNotFoundError_1 = require("./errors/DependencyNotFoundError");
38
40
  Object.defineProperty(exports, "DependencyNotFoundError", { enumerable: true, get: function () { return DependencyNotFoundError_1.DependencyNotFoundError; } });
39
41
  var ContainerNotFoundError_1 = require("./errors/ContainerNotFoundError");
@@ -50,6 +52,8 @@ var UnexpectedHookResultError_1 = require("./errors/UnexpectedHookResultError");
50
52
  Object.defineProperty(exports, "UnexpectedHookResultError", { enumerable: true, get: function () { return UnexpectedHookResultError_1.UnexpectedHookResultError; } });
51
53
  var CannonSingletonApplyTwiceError_1 = require("./errors/CannonSingletonApplyTwiceError");
52
54
  Object.defineProperty(exports, "CannonSingletonApplyTwiceError", { enumerable: true, get: function () { return CannonSingletonApplyTwiceError_1.CannonSingletonApplyTwiceError; } });
55
+ var UnsupportedTokenTypeError_1 = require("./errors/UnsupportedTokenTypeError");
56
+ Object.defineProperty(exports, "UnsupportedTokenTypeError", { enumerable: true, get: function () { return UnsupportedTokenTypeError_1.UnsupportedTokenTypeError; } });
53
57
  var hook_1 = require("./hooks/hook");
54
58
  Object.defineProperty(exports, "getHooks", { enumerable: true, get: function () { return hook_1.getHooks; } });
55
59
  Object.defineProperty(exports, "hook", { enumerable: true, get: function () { return hook_1.hook; } });
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.singleton = exports.decorate = exports.lazy = exports.scopeAccess = exports.appendArgsFn = exports.appendArgs = exports.scope = exports.bindTo = exports.register = exports.getTransformers = exports.registerPipe = exports.isProviderPipe = void 0;
4
+ const IContainer_1 = require("../container/IContainer");
4
5
  const SingleToken_1 = require("../token/SingleToken");
5
6
  const BindToken_1 = require("../token/BindToken");
6
7
  const class_1 = require("../metadata/class");
@@ -15,7 +16,13 @@ const METADATA_KEY = 'registration';
15
16
  const getTransformers = (Target) => (0, class_1.getClassMeta)(Target, METADATA_KEY) ?? [];
16
17
  exports.getTransformers = getTransformers;
17
18
  const register = (...mappers) => (0, class_1.addClassMeta)(METADATA_KEY, (acc) => {
18
- const result = mappers.map((m) => (0, exports.isProviderPipe)(m) ? (r) => m.mapRegistration(r) : m);
19
+ const result = mappers.map((m) => {
20
+ if ((0, exports.isProviderPipe)(m))
21
+ return (r) => m.mapRegistration(r);
22
+ if ((0, BindToken_1.isBindToken)(m) || (0, IContainer_1.isDependencyKey)(m))
23
+ return (0, exports.bindTo)(m);
24
+ return m;
25
+ });
19
26
  return acc ? [...result, ...acc] : result;
20
27
  });
21
28
  exports.register = register;
package/esm/index.js CHANGED
@@ -8,6 +8,7 @@ export { ProxyInjector } from './injector/ProxyInjector.js';
8
8
  export { Provider } from './provider/Provider.js';
9
9
  export { register, bindTo, scope, scopeAccess, lazy, singleton, decorate, appendArgs, appendArgsFn, } from './registration/IRegistration.js';
10
10
  export { Registration } from './registration/Registration.js';
11
+ export { ContainerError } from './errors/ContainerError.js';
11
12
  export { DependencyNotFoundError } from './errors/DependencyNotFoundError.js';
12
13
  export { ContainerNotFoundError } from './errors/ContainerNotFoundError.js';
13
14
  export { DependencyMissingKeyError } from './errors/DependencyMissingKeyError.js';
@@ -16,6 +17,7 @@ export { ContainerDisposedError } from './errors/ContainerDisposedError.js';
16
17
  export { ProviderDisposedError } from './errors/ProviderDisposedError.js';
17
18
  export { UnexpectedHookResultError } from './errors/UnexpectedHookResultError.js';
18
19
  export { CannonSingletonApplyTwiceError } from './errors/CannonSingletonApplyTwiceError.js';
20
+ export { UnsupportedTokenTypeError } from './errors/UnsupportedTokenTypeError.js';
19
21
  export { getHooks, hook, hasHooks, appendHooks, prependHooks, append, prepend, } from './hooks/hook.js';
20
22
  export { HookContext, createHookContextFactory, createHookContext } from './hooks/HookContext.js';
21
23
  export { injectProp } from './hooks/injectProp.js';
@@ -1,3 +1,4 @@
1
+ import { isDependencyKey } from '../container/IContainer.js';
1
2
  import { SingleToken } from '../token/SingleToken.js';
2
3
  import { isBindToken } from '../token/BindToken.js';
3
4
  import { addClassMeta, getClassMeta } from '../metadata/class.js';
@@ -9,7 +10,13 @@ export const registerPipe = (mapProvider) => ({
9
10
  const METADATA_KEY = 'registration';
10
11
  export const getTransformers = (Target) => getClassMeta(Target, METADATA_KEY) ?? [];
11
12
  export const register = (...mappers) => addClassMeta(METADATA_KEY, (acc) => {
12
- const result = mappers.map((m) => isProviderPipe(m) ? (r) => m.mapRegistration(r) : m);
13
+ const result = mappers.map((m) => {
14
+ if (isProviderPipe(m))
15
+ return (r) => m.mapRegistration(r);
16
+ if (isBindToken(m) || isDependencyKey(m))
17
+ return bindTo(m);
18
+ return m;
19
+ });
13
20
  return acc ? [...result, ...acc] : result;
14
21
  });
15
22
  export const bindTo = (...tokens) => (r) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "56.0.0",
3
+ "version": "56.1.1",
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",
@@ -58,31 +58,8 @@
58
58
  ],
59
59
  "repository": {
60
60
  "type": "git",
61
- "url": "git+https://github.com/IgorBabkin/ts-ioc-container"
62
- },
63
- "scripts": {
64
- "build:cjm": "rimraf cjm && tsc -p tsconfig.production.json --outDir cjm --module CommonJS",
65
- "build:esm": "rimraf esm && tsc -p tsconfig.production.json --outDir esm && node scripts/postbuild-extensions.mjs esm --esm",
66
- "build:types": "rimraf typings && tsc -p tsconfig.production.json --outDir typings --emitDeclarationOnly --declaration && node scripts/postbuild-extensions.mjs typings",
67
- "generate:docs": "scripts/generate-readme/generate-readme.ts && git add README.md",
68
- "build": "npm run build:cjm && npm run build:esm && npm run build:types",
69
- "test": "vitest run",
70
- "test:spec": "vitest run __tests__/specs",
71
- "bench:spec": "vitest bench __benchmarks__/specs/*.bench.ts",
72
- "test:coverage": "vitest run --coverage --coverage.reporter=lcov",
73
- "type-check": "tsc --noEmit",
74
- "type-check:watch": "tsc --noEmit --watch",
75
- "commit": "cz",
76
- "format": "prettier --write \"**/*.ts\"",
77
- "lint": "eslint lib/**/*.ts __tests__/**/*.ts __benchmarks__/**/*.ts scripts/**/*.ts",
78
- "lint:fix": "npm run lint --fix",
79
- "audit": "npm audit",
80
- "prepare": "husky",
81
- "release": "npm run build && npm test && npm publish",
82
- "docs:dev": "pnpm --filter ts-ioc-container-docs run dev",
83
- "docs:serve": "pnpm --filter ts-ioc-container-docs run dev",
84
- "docs:build": "pnpm --filter ts-ioc-container-docs run build",
85
- "docs:preview": "pnpm --filter ts-ioc-container-docs run preview"
61
+ "url": "git+https://github.com/IgorBabkin/ts-ioc-container",
62
+ "directory": "packages/ts-ioc-container"
86
63
  },
87
64
  "peerDependencies": {
88
65
  "reflect-metadata": "^0.2.0"
@@ -93,59 +70,35 @@
93
70
  }
94
71
  },
95
72
  "devDependencies": {
96
- "@commitlint/cli": "^20.2.0",
97
- "@commitlint/config-conventional": "^20.2.0",
98
- "@eslint/eslintrc": "^3.3.5",
99
- "@eslint/js": "^9.24.0",
100
- "@semantic-release/changelog": "^6.0.3",
101
- "@semantic-release/git": "^10.0.1",
102
- "@semantic-release/github": "^12.0.2",
103
- "@semantic-release/npm": "^13.1.2",
104
73
  "@swc/core": "^1.15.24",
105
74
  "@types/node": "^25.5.2",
106
- "@typescript-eslint/eslint-plugin": "8.32.1",
107
- "@typescript-eslint/parser": "8.59.1",
108
75
  "@vitest/coverage-v8": "^4.1.2",
109
- "cz-conventional-changelog": "^3.3.0",
110
- "eslint": "9.24.0",
111
- "eslint-config-prettier": "10.1.8",
112
- "eslint-plugin-prettier": "5.2.6",
113
- "handlebars": "^4.7.8",
114
- "husky": "^9.1.7",
115
- "lint-staged": "^16.4.0",
116
76
  "moq.ts": "^10.0.8",
117
- "prettier": "3.5.3",
118
- "prettier-plugin-astro": "^0.14.1",
119
77
  "reflect-metadata": "^0.2.2",
120
- "rimraf": "6.1.3",
121
- "semantic-release": "^25.0.2",
122
- "tsx": "^4.21.0",
123
78
  "tsyringe": "^4.10.0",
124
79
  "typescript": "5.8.3",
125
80
  "unplugin-swc": "^1.5.9",
126
81
  "vite": "^6.4.1",
127
82
  "vitest": "^4.1.2"
128
83
  },
129
- "lint-staged": {
130
- "*.{js,ts,tsx}": [
131
- "eslint --fix",
132
- "prettier --write"
133
- ],
134
- "docs/**/*.{js,ts,tsx,mjs,astro}": [
135
- "prettier --write"
136
- ],
137
- "docs/**/*.astro": [
138
- "eslint --fix"
139
- ]
140
- },
141
- "gitHead": "ae10f302c7e0f55196b42669040735112479a854",
142
- "config": {
143
- "commitizen": {
144
- "path": "./node_modules/cz-conventional-changelog"
145
- }
146
- },
147
- "packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd",
148
84
  "engines": {
149
85
  "node": ">= 18"
86
+ },
87
+ "scripts": {
88
+ "build:cjm": "node ../scripts/build.mjs cjm",
89
+ "build:esm": "node ../scripts/build.mjs esm",
90
+ "build:types": "node ../scripts/build.mjs types",
91
+ "generate:docs": "../scripts/generate-readme/generate-readme.ts && git add README.md",
92
+ "build": "pnpm run build:cjm && pnpm run build:esm && pnpm run build:types",
93
+ "test": "vitest run",
94
+ "test:spec": "vitest run __tests__/specs",
95
+ "bench:spec": "vitest bench __benchmarks__/specs/*.bench.ts",
96
+ "test:coverage": "vitest run --coverage --coverage.reporter=lcov --maxWorkers=2",
97
+ "type-check": "tsc --noEmit",
98
+ "type-check:watch": "tsc --noEmit --watch",
99
+ "format": "prettier --write \"**/*.ts\"",
100
+ "format:check": "prettier --check \"lib/**/*.ts\" \"__tests__/**/*.ts\" \"__benchmarks__/**/*.ts\"",
101
+ "lint": "eslint lib/**/*.ts __tests__/**/*.ts __benchmarks__/**/*.ts",
102
+ "lint:fix": "pnpm run lint --fix"
150
103
  }
151
- }
104
+ }
@@ -9,6 +9,7 @@ export { type ResolveDependency, type IProvider, type DecorateFn, type ArgsFn, t
9
9
  export { Provider } from './provider/Provider.js';
10
10
  export { type IRegistration, type ReturnTypeOfRegistration, type ScopeMatchRule, type ProviderPipe, register, bindTo, scope, scopeAccess, lazy, singleton, decorate, appendArgs, appendArgsFn, } from './registration/IRegistration.js';
11
11
  export { Registration } from './registration/Registration.js';
12
+ export { ContainerError } from './errors/ContainerError.js';
12
13
  export { DependencyNotFoundError } from './errors/DependencyNotFoundError.js';
13
14
  export { ContainerNotFoundError } from './errors/ContainerNotFoundError.js';
14
15
  export { DependencyMissingKeyError } from './errors/DependencyMissingKeyError.js';
@@ -17,6 +18,7 @@ export { ContainerDisposedError } from './errors/ContainerDisposedError.js';
17
18
  export { ProviderDisposedError } from './errors/ProviderDisposedError.js';
18
19
  export { UnexpectedHookResultError } from './errors/UnexpectedHookResultError.js';
19
20
  export { CannonSingletonApplyTwiceError } from './errors/CannonSingletonApplyTwiceError.js';
21
+ export { UnsupportedTokenTypeError } from './errors/UnsupportedTokenTypeError.js';
20
22
  export { getHooks, hook, hasHooks, appendHooks, prependHooks, append, prepend, type HookFn, type HookClass, type HookType, type MapHooksFn, type InjectFn, type HooksOfClass, } from './hooks/hook.js';
21
23
  export { HookContext, createHookContextFactory, createHookContext, type IHookContext } from './hooks/HookContext.js';
22
24
  export { injectProp } from './hooks/injectProp.js';
@@ -1,4 +1,4 @@
1
- import type { DependencyKey, IContainer, IContainerModule } from '../container/IContainer.js';
1
+ import { type DependencyKey, type IContainer, type IContainerModule } from '../container/IContainer.js';
2
2
  import type { ArgsFn, DecorateFn, GetCacheKey, IProvider, ScopeAccessRule } from '../provider/IProvider.js';
3
3
  import { BindToken } from '../token/BindToken.js';
4
4
  import { MapFn } from '../utils/fp.js';
@@ -20,7 +20,7 @@ export interface IRegistration<T = any> extends IContainerModule {
20
20
  }
21
21
  export type ReturnTypeOfRegistration<T> = T extends IRegistration<infer R> ? R : never;
22
22
  export declare const getTransformers: (Target: constructor<unknown>) => MapFn<IRegistration<any>>[];
23
- export declare const register: (...mappers: Array<MapFn<IRegistration> | ProviderPipe>) => ClassDecorator;
23
+ export declare const register: (...mappers: Array<MapFn<IRegistration> | ProviderPipe | BindToken | DependencyKey>) => ClassDecorator;
24
24
  export declare const bindTo: (...tokens: (DependencyKey | BindToken)[]) => MapFn<IRegistration>;
25
25
  export declare const scope: (...rules: ScopeMatchRule[]) => MapFn<IRegistration>;
26
26
  export declare const appendArgs: <T>(...extraArgs: unknown[]) => ProviderPipe<T>;