Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
8adef7b6a2 Bump @stylistic/eslint-plugin from 2.6.2 to 2.10.1
Bumps [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin) from 2.6.2 to 2.10.1.
- [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases)
- [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.10.1/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@stylistic/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 12:32:35 +00:00
9 changed files with 280 additions and 306 deletions

View File

@@ -9,21 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- feat: Add new `IdentifierRequiredError` class for missing identifiers.
- feat: Add the option to use the decorators without passing the identifier: In this case, the identifier will be the class name (register) or the property name (inject).
- Add pre release building to release workflow on dev/* branches an version changes.
### Deprecated
### Removed
- feat!: Disable `experimentalDecorators` and `emitDecoratorMetadata` in the `tsconfig.json` file to reflect the change to the stable decorators api.
### Fixed
- feat!: Update `Register`, `RegisterInstance` and `Inject` decorators to reflect the change to the stable decorators api.
- feat!: Update `Inject` Decorator typing to reflect the correct property type.
### Security

292
package-lock.json generated
View File

@@ -1,19 +1,19 @@
{
"name": "ts-injex",
"version": "0.0.9",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ts-injex",
"version": "0.0.9",
"version": "0.1.0",
"license": "MIT",
"dependencies": {
"eslint-plugin-prettier": "^5.2.1",
"jest-environment-jsdom": "^29.7.0"
},
"devDependencies": {
"@stylistic/eslint-plugin": "^2.6.2",
"@stylistic/eslint-plugin": "^2.10.1",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.11",
"@typescript-eslint/eslint-plugin": "^8.1.0",
@@ -1218,79 +1218,14 @@
}
},
"node_modules/@stylistic/eslint-plugin": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.6.2.tgz",
"integrity": "sha512-Ic5oFNM/25iuagob6LiIBkSI/A2y45TsyKtDtODXHRZDy52WfPfeexI6r+OH5+aWN9QGob2Bw+4JRM9/4areWw==",
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.10.1.tgz",
"integrity": "sha512-U+4yzNXElTf9q0kEfnloI9XbOyD4cnEQCxjUI94q0+W++0GAEQvJ/slwEj9lwjDHfGADRSr+Tco/z0XJvmDfCQ==",
"dev": true,
"dependencies": {
"@stylistic/eslint-plugin-js": "2.6.2",
"@stylistic/eslint-plugin-jsx": "2.6.2",
"@stylistic/eslint-plugin-plus": "2.6.2",
"@stylistic/eslint-plugin-ts": "2.6.2",
"@types/eslint": "^9.6.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": ">=8.40.0"
}
},
"node_modules/@stylistic/eslint-plugin-js": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.6.2.tgz",
"integrity": "sha512-wCr/kVctAPayMU3pcOI1MKR7MoKIh6VKZU89lPklAqtJoxT+Em6RueiiARbpznUYG5eg3LymiU+aMD+aIZXdqA==",
"dev": true,
"dependencies": {
"@types/eslint": "^9.6.0",
"acorn": "^8.12.1",
"eslint-visitor-keys": "^4.0.0",
"espree": "^10.1.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": ">=8.40.0"
}
},
"node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@stylistic/eslint-plugin-js/node_modules/espree": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
"dev": true,
"dependencies": {
"acorn": "^8.12.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@stylistic/eslint-plugin-jsx": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.6.2.tgz",
"integrity": "sha512-dSXK/fSPA938J1fBi10QmhzLKtZ/2TuyVNHQMk8jUhWfKJDleAogaSqcWNAbN8fwcoe9UWmt/3StiIf2oYC1aQ==",
"dev": true,
"dependencies": {
"@stylistic/eslint-plugin-js": "^2.6.2",
"@types/eslint": "^9.6.0",
"@typescript-eslint/utils": "^8.12.2",
"eslint-visitor-keys": "^4.2.0",
"espree": "^10.3.0",
"estraverse": "^5.3.0",
"picomatch": "^4.0.2"
},
@@ -1301,7 +1236,169 @@
"eslint": ">=8.40.0"
}
},
"node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": {
"node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
"version": "8.12.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz",
"integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "8.12.2",
"@typescript-eslint/visitor-keys": "8.12.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/types": {
"version": "8.12.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz",
"integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": {
"version": "8.12.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz",
"integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "8.12.2",
"@typescript-eslint/visitor-keys": "8.12.2",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
"ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/utils": {
"version": "8.12.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz",
"integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.12.2",
"@typescript-eslint/types": "8.12.2",
"@typescript-eslint/typescript-estree": "8.12.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
"version": "8.12.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz",
"integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "8.12.2",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/espree": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
"dev": true,
"dependencies": {
"acorn": "^8.14.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
@@ -1313,36 +1410,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@stylistic/eslint-plugin-plus": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.6.2.tgz",
"integrity": "sha512-cANcPASfRvq3VTbbQCrSIXq+2AI0IW68PNYaZoXXS0ENlp7HDB8dmrsJnOgWCcoEvdCB8z/eWcG/eq/v5Qcl+Q==",
"dev": true,
"dependencies": {
"@types/eslint": "^9.6.0",
"@typescript-eslint/utils": "^8.0.0"
},
"peerDependencies": {
"eslint": "*"
}
},
"node_modules/@stylistic/eslint-plugin-ts": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.6.2.tgz",
"integrity": "sha512-6OEN3VtUNxjgOvWPavnC10MByr1H4zsgwNND3rQXr5lDFv93MLUnTsH+/SH15OkuqdyJgrQILI6b9lYecb1vIg==",
"dev": true,
"dependencies": {
"@stylistic/eslint-plugin-js": "2.6.2",
"@types/eslint": "^9.6.0",
"@typescript-eslint/utils": "^8.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": ">=8.40.0"
}
},
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -1396,7 +1463,8 @@
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz",
"integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==",
"devOptional": true,
"optional": true,
"peer": true,
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
@@ -1406,7 +1474,8 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"devOptional": true
"optional": true,
"peer": true
},
"node_modules/@types/graceful-fs": {
"version": "4.1.9",
@@ -1471,7 +1540,8 @@
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"devOptional": true
"optional": true,
"peer": true
},
"node_modules/@types/json5": {
"version": "0.0.29",
@@ -1735,9 +1805,9 @@
"deprecated": "Use your platform's native atob() and btoa() methods instead"
},
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"bin": {
"acorn": "bin/acorn"
},

View File

@@ -1,6 +1,6 @@
{
"name": "ts-injex",
"version": "0.1.0-.1",
"version": "0.1.0",
"description": "Simple boilerplate code free dependency injection system for TypeScript.",
"type": "module",
"main": "./dist/index.js",
@@ -36,7 +36,7 @@
"typescript": "^5.5.4",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.11",
"@stylistic/eslint-plugin": "^2.6.2",
"@stylistic/eslint-plugin": "^2.10.1",
"@typescript-eslint/eslint-plugin": "^8.1.0",
"@typescript-eslint/parser": "^8.1.0",
"eslint-plugin-deprecation": "^3.0.0",

View File

@@ -67,29 +67,6 @@ export function test_InjectDecorator(
expect(instance.getDependency().value).toBe('test-value-init');
});
it('should inject dependency and run initializer without identifier', () => {
container.register('MockDependencyIdentifier', {
value: 'test-value',
});
class TestClass {
@Inject(undefined, (x: string) => {
(x as unknown as { value: string }).value =
'test-value-init';
return x;
})
MockDependencyIdentifier!: any;
public getDependency() {
return this.MockDependencyIdentifier;
}
}
const instance = new TestClass();
expect(instance.getDependency().value).toBe('test-value-init');
});
it('should throw an error when necessary is true and the initializer throws an error', () => {
let _error: Error | undefined = undefined;
@@ -101,7 +78,7 @@ export function test_InjectDecorator(
class TestClass {
@Inject(
'InitThrowDependencie',
(): any => {
() => {
throw new Error('Initializer error');
},
true,
@@ -298,19 +275,6 @@ export function test_RegisterDecorator(
TestClass,
);
});
it('should register a dependency without an identifier', () => {
@register()
class TestClass {
private readonly _dependency!: any;
public getDependency() {
return this._dependency;
}
}
expect(container.resolve('TestClass')).toBe(TestClass);
});
});
}
@@ -347,23 +311,6 @@ export function test_RegisterInstanceDecorator(
).toBe('instance');
});
it('should register an instance of a dependency with an identifier', () => {
@registerInstance()
class TestClass {
private readonly _dependency!: any;
public getDependency() {
return this._dependency;
}
public mark: string = 'instance';
}
expect(container.resolve<TestClass>('TestClass').mark).toBe(
'instance',
);
});
it('should register an instance of a dependency an run the init function', () => {
@registerInstance(
'InstanceIdentifier',

View File

@@ -1,6 +1,5 @@
import {
DependencyResolutionError,
IdentifierRequiredError,
InitializationError,
InjectorError,
NoInstantiationMethodError,
@@ -11,17 +10,17 @@ import { InitDelegate } from '../types/InitDelegate';
/**
* A decorator to inject a dependency from a DI (Dependency Injection) container into a class property.
* @template TargetType The type of the class to inject the dependency into.
* @template DependencyType The type of the dependency to be injected.
* @template PropertyType The type of the property to be injected.
* @param identifier The {@link Identifier|identifier} used to resolve the dependencie in the DI container or the property name if not provided.
* @param init An optional initializer {@link InitDelegate|function} to transform the dependency before injection
* @template T The type of the dependency to be injected.
* @template U The type of the property to be injected.
* @param identifier The identifier used to resolve the class in the DI container.
* @see {@link Identifier} for more information on identifiers.
* @param init Optional an initializer function to transform the dependency before injection
* or true to instantiate the dependency if it has a constructor.
* @see {@link InitDelegate} for more information on initializer functions.
* @param necessary If true, throws an error if the dependency is not found.
* @returns The resolved dependency or undefined if the dependency is not necessary
* and not found, or throws an error if the dependency is necessary and not found.
* @throws **Only throws errors if the dependency is necessary.**
* @throws An {@link IdentifierRequiredError} if the identifier is not provided and the class name is not available.
* @throws A {@link DependencyResolutionError} if the dependency is not found.
* @throws A {@link InjectorError} if an error occurs during the injection process.
* @throws A {@link NoInstantiationMethodError} if the dependency does not have a constructor.
@@ -41,86 +40,70 @@ import { InitDelegate } from '../types/InitDelegate';
* }
* ```
*/
export function Inject<TargetType, DependencyType, PropertyType>(
identifier?: Identifier,
init?: InitDelegate<DependencyType, PropertyType> | true,
export function Inject<T, U>(
identifier: Identifier,
init?: InitDelegate<T, U> | true,
necessary = true,
) {
return function (
constructor: undefined,
context: ClassFieldDecoratorContext<TargetType> & {
name: PropertyType;
},
): void {
const _identifier = identifier ?? context.name;
if (_identifier == null && necessary === true)
throw new IdentifierRequiredError();
return function (target: unknown, propertyKey: string | symbol): void {
/**
* Function to evaluate the dependency lazily
* to avoid circular dependencies, not found dependencies, etc.
* @returns The resolved dependency or undefined if the dependency is not found.
*/
const resolve = (): DependencyType | undefined => {
return TSinjex.getInstance().resolve<DependencyType>(
_identifier,
necessary,
);
const resolve = (): T | undefined => {
return TSinjex.getInstance().resolve<T>(identifier, necessary);
};
context.addInitializer(function (this: TargetType) {
Object.defineProperty(this, context.name, {
get() {
let instance: DependencyType | PropertyType | undefined;
Object.defineProperty(target, propertyKey, {
get() {
let instance: T | U | undefined;
const dependency: DependencyType | undefined = tryAndCatch(
() => resolve(),
necessary,
_identifier,
DependencyResolutionError,
);
const dependency: T | undefined = tryAndCatch(
() => resolve(),
necessary,
identifier,
DependencyResolutionError,
);
if (dependency != null) {
const initFunction: (() => PropertyType) | undefined =
typeof init === 'function' && dependency != null
? (): PropertyType => init(dependency)
: init === true && hasConstructor(dependency)
? (): PropertyType =>
new dependency() as PropertyType
: undefined;
if (dependency != null) {
const initFunction: (() => U) | undefined =
typeof init === 'function' && dependency != null
? (): U => init(dependency)
: init === true && hasConstructor(dependency)
? (): U => new dependency() as U
: undefined;
if (init == null) instance = dependency;
else if (initFunction != null)
instance = tryAndCatch(
initFunction,
necessary,
_identifier,
InitializationError,
);
else if (necessary)
throw new NoInstantiationMethodError(_identifier);
} else if (necessary)
throw new DependencyResolutionError(_identifier);
if (init == null) instance = dependency;
else if (initFunction != null)
instance = tryAndCatch(
initFunction,
necessary,
identifier,
InitializationError,
);
else if (necessary)
throw new NoInstantiationMethodError(identifier);
} else if (necessary)
throw new DependencyResolutionError(identifier);
/**
* Replace itself with the resolved dependency
* for performance reasons.
*/
Object.defineProperty(this, context.name, {
value: instance,
writable: false,
enumerable: false,
configurable: false,
});
return instance;
},
/**
* Make the property configurable to allow replacing it
* Replace itself with the resolved dependency
* for performance reasons.
*/
configurable: true,
});
Object.defineProperty(this, propertyKey, {
value: instance,
writable: false,
enumerable: false,
configurable: false,
});
return instance;
},
/**
* Make the property configurable to allow replacing it
*/
configurable: true,
});
};
}

View File

@@ -1,14 +1,14 @@
import { IdentifierRequiredError } from 'src/interfaces/Exceptions';
import { TSinjex } from '../classes/TSinjex';
import { Identifier } from '../types/Identifier';
/**
* A decorator to register a class in the **TSinjex** DI (Dependency Injection) container.
* @template TargetType The type of the class to be registered.
* @param identifier The {@link Identifier|identifier} used to register the class in the DI container or the class name if not provided.
* @param deprecated If true, the dependency is deprecated and a warning is logged only once upon the first resolution of the dependency.
* @param identifier The identifier used to register the class in the DI container.
* @see {@link Identifier} for more information on identifiers.
* @param deprecated If true, the dependency is deprecated and a warning
* is logged only once upon the first resolution of the dependency.
* @returns The decorator function to be applied on the class.
* @throws An {@link IdentifierRequiredError} if the identifier is not provided and the class name is not available.
* @example
* ```ts
* \@Register('MyClassIdentifier')
@@ -19,16 +19,12 @@ import { Identifier } from '../types/Identifier';
*/
export function Register<
TargetType extends new (...args: unknown[]) => InstanceType<TargetType>,
>(identifier?: Identifier, deprecated?: boolean) {
return function (
constructor: TargetType,
context: ClassDecoratorContext<TargetType>,
) {
const _identifier = identifier ?? context.name;
if (_identifier == null) throw new IdentifierRequiredError();
>(identifier: Identifier, deprecated?: boolean) {
return function (constructor: TargetType, ...args: unknown[]): void {
// Get the instance of the DI container
const diContainer = TSinjex.getInstance();
diContainer.register(_identifier, constructor, deprecated);
// Register the class in the DI container
diContainer.register(identifier, constructor, deprecated);
};
}

View File

@@ -1,4 +1,3 @@
import { IdentifierRequiredError } from 'src/interfaces/Exceptions';
import { TSinjex } from '../classes/TSinjex';
import { Identifier } from '../types/Identifier';
import { InitDelegate } from '../types/InitDelegate';
@@ -6,11 +5,12 @@ import { InitDelegate } from '../types/InitDelegate';
/**
* A decorator to register an instance of a class in the DI (Dependency Injection) container.
* @template TargetType The type of the class whose instance is to be registered.
* @param identifier The {@link Identifier|identifier} used to register the class in the DI container or the class name if not provided.
* @param init An optional initializer {@link InitDelegate|function} which get the constructor of the class
* @param identifier The identifier used to register the instance in the DI container.
* @see {@link Identifier} for more information on identifiers.
* @param init An optional initializer function which get the constructor of the class
* as input and returns an instance of the class.
* @see {@link InitDelegate} for more information on initializer functions.
* @returns The decorator function to be applied on the class.
* @throws An {@link IdentifierRequiredError} if the identifier is not provided and the class name is not available.
* @example
* ```ts
* \@RegisterInstance('MyClassInstanceIdentifier', (constructor) => new constructor())
@@ -22,51 +22,43 @@ import { InitDelegate } from '../types/InitDelegate';
export function RegisterInstance<
TargetType extends new (..._args: unknown[]) => InstanceType<TargetType>,
>(
identifier?: Identifier,
identifier: Identifier,
init?: InitDelegate<
TargetType & { new (..._args: unknown[]): InstanceType<TargetType> },
InstanceType<TargetType>
>,
) {
return function (
constructor: TargetType,
context: ClassDecoratorContext<TargetType>,
): void {
const _identifier = identifier ?? context.name;
if (_identifier == null) throw new IdentifierRequiredError();
return function (constructor: TargetType, ...args: unknown[]): void {
// Get the instance of the DI container
const diContainer = TSinjex.getInstance();
let instance: InstanceType<TargetType>;
/**
* Get the instance of the class
* and replace the lazy proxy with the instance
* for performance optimization.
*/
const getAndRegisterInstance = (): void => {
if (instance == null) {
if (init) {
instance = init(constructor);
} else {
instance = new constructor();
}
}
diContainer.register(_identifier, instance);
};
// Create a proxy to instantiate the class when needed (Lazy Initialization)
const lazyProxy: unknown = new Proxy(
let lazyProxy: unknown = new Proxy(
{},
{
get(_target, prop, _receiver) {
getAndRegisterInstance();
get(target, prop, receiver) {
if (instance == null) {
if (init) {
instance = init(constructor);
} else {
instance = new constructor(...args);
}
}
lazyProxy = instance;
// Return the requested property of the instance
return instance[prop as keyof InstanceType<TargetType>];
},
set(_target, prop, value, _receiver) {
getAndRegisterInstance();
set(target, prop, value, receiver) {
if (instance == null) {
if (init) {
instance = init(constructor);
} else {
instance = new constructor(...args);
}
}
lazyProxy = instance;
// Set the requested property of the instance
return (instance[prop as keyof InstanceType<TargetType>] =
@@ -75,6 +67,7 @@ export function RegisterInstance<
},
);
diContainer.register(_identifier, lazyProxy);
// Register the lazy proxy in the DI container
diContainer.register(identifier, lazyProxy);
};
}

View File

@@ -15,19 +15,6 @@ export class TSinjexError extends Error {
}
}
/**
* Error class for missing identifiers in {@link ITSinjex} methods.
*/
export class IdentifierRequiredError extends TSinjexError {
/**
* Creates a new instance of {@link IdentifierRequiredError}
*/
constructor() {
super('Identifier is required.');
this.name = 'TSinjexIdentifierRequiredError';
}
}
/**
* Error class for dependency resolution errors in {@link ITSinjex}.
* @see {@link ITSinjex.resolve}

View File

@@ -18,6 +18,8 @@
"importHelpers": true,
"isolatedModules": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"lib": [