chore(repo): remove project configuration and source files
- Delete all project configuration files, including ESLint, Prettier, and TypeScript settings. - Remove GitHub workflows for CI/CD and documentation deployment. - Delete source files, tests, and scripts related to the project. - Clean up package.json and associated scripts. Signed-off-by: Max P. <Mail@MPassarello.de>
This commit is contained in:
@@ -1,394 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { Inject } from '../decorators/Inject.js';
|
||||
import { DependencyResolutionError } from '../interfaces/Exceptions.js';
|
||||
import { ITSinjex_, ITSinjex } from '../interfaces/ITSinjex.js';
|
||||
import { ForceConstructor } from '../types/GenericContructor.js';
|
||||
|
||||
/**
|
||||
* Test the Inject decorator.
|
||||
* @param Container The implementation to test.
|
||||
* @param inject The Inject decorator to test.
|
||||
*/
|
||||
export function test_InjectDecorator(
|
||||
Container: ITSinjex_,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
inject: Function,
|
||||
): void {
|
||||
describe('Inject Decorator Tests', () => {
|
||||
let container: ITSinjex;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_instance'] = undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_dependencies'] = undefined;
|
||||
container = Container.getInstance();
|
||||
});
|
||||
|
||||
it('should inject dependency when necessary is true', () => {
|
||||
container.register('MockDependencyIdentifier', {
|
||||
value: 'test-value',
|
||||
});
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier')
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new TestClass();
|
||||
expect(instance.getDependency().value).toBe('test-value');
|
||||
});
|
||||
|
||||
it('should inject dependency and run initializer', () => {
|
||||
container.register('MockDependencyIdentifier', {
|
||||
value: 'test-value',
|
||||
});
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier', (x: string) => {
|
||||
(x as unknown as { value: string }).value =
|
||||
'test-value-init';
|
||||
|
||||
return x;
|
||||
})
|
||||
dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this.dependency;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
container.register('InitThrowDependencie', {
|
||||
value: 'test-value',
|
||||
});
|
||||
|
||||
try {
|
||||
class TestClass {
|
||||
@Inject(
|
||||
'InitThrowDependencie',
|
||||
() => {
|
||||
throw new Error('Initializer error');
|
||||
},
|
||||
true,
|
||||
)
|
||||
dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this.dependency;
|
||||
}
|
||||
}
|
||||
|
||||
const _instance = new TestClass();
|
||||
console.log(_instance.getDependency());
|
||||
} catch (error) {
|
||||
_error = error;
|
||||
}
|
||||
expect(_error).toBeInstanceOf(Error);
|
||||
});
|
||||
|
||||
it('should throw an error when necessary is true and dependency is not found', () => {
|
||||
let _error: Error | undefined = undefined;
|
||||
|
||||
try {
|
||||
class TestClass {
|
||||
@Inject('NonExistentDependencyIdentifier')
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
const _instance = new TestClass();
|
||||
console.log(_instance.getDependency());
|
||||
} catch (error) {
|
||||
_error = error;
|
||||
}
|
||||
expect(_error).toBeInstanceOf(DependencyResolutionError);
|
||||
});
|
||||
|
||||
it('should replace the property with the resolved dependency', () => {
|
||||
container.register('MockDependencyIdentifier', {
|
||||
value: 'test-value',
|
||||
});
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier')
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
|
||||
public isDependencyTypeofFunction() {
|
||||
return typeof this._dependency === 'function';
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new TestClass();
|
||||
|
||||
expect(instance.getDependency().value).toBe('test-value');
|
||||
|
||||
expect(instance.isDependencyTypeofFunction()).toBe(false);
|
||||
expect(instance.getDependency().value).toBe('test-value');
|
||||
});
|
||||
|
||||
it('should use a empty initializer when none is provided but true', () => {
|
||||
container.register(
|
||||
'MockDependencyIdentifier',
|
||||
class X {
|
||||
public value: string = 'test-value';
|
||||
constructor() {}
|
||||
},
|
||||
);
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier', true)
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new TestClass();
|
||||
expect(instance.getDependency().value).toBe('test-value');
|
||||
});
|
||||
|
||||
it('should throw an error when the dependency has no instantiation method', () => {
|
||||
container.register('MockDependencyIdentifier', {
|
||||
value: 'test-value',
|
||||
});
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier', true)
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
const instance = new TestClass();
|
||||
instance.getDependency();
|
||||
}).toThrow(new RegExp('No instantiation method found for.*'));
|
||||
});
|
||||
|
||||
it('should not throw an error when the dependency has no instantiation method if not necessary', () => {
|
||||
container.register('MockDependencyIdentifier', {
|
||||
value: 'test-value',
|
||||
});
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier', true, false)
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
const instance = new TestClass();
|
||||
instance.getDependency();
|
||||
}).not.toThrow(new RegExp('No instantiation method found for.*'));
|
||||
});
|
||||
|
||||
it('should throw an error when the dependency cannot be resolved', () => {
|
||||
container.register('MockDependencyIdentifier', null);
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier', true)
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
const instance = new TestClass();
|
||||
instance.getDependency();
|
||||
}).toThrow(new RegExp('.*could not be resolved.*'));
|
||||
});
|
||||
|
||||
it('should not throw an error when the dependency cannot be resolved if not necessary', () => {
|
||||
container.register('MockDependencyIdentifier', null);
|
||||
|
||||
class TestClass {
|
||||
@Inject('MockDependencyIdentifier', true, false)
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
const instance = new TestClass();
|
||||
instance.getDependency();
|
||||
}).not.toThrow(new RegExp('.*could not be resolved.*'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function test_RegisterDecorator(
|
||||
Container: ITSinjex_,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
register: Function,
|
||||
): void {
|
||||
describe('Register Decorator Tests', () => {
|
||||
let container: ITSinjex;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_instance'] = undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_dependencies'] = undefined;
|
||||
container = Container.getInstance();
|
||||
});
|
||||
|
||||
it('should register a dependency', () => {
|
||||
@register('MockDependencyIdentifier')
|
||||
class TestClass {
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
expect(container.resolve('MockDependencyIdentifier')).toBe(
|
||||
TestClass,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function test_RegisterInstanceDecorator(
|
||||
Container: ITSinjex_,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
registerInstance: Function,
|
||||
mode: 'instance' | 'standalone' = 'standalone',
|
||||
): void {
|
||||
describe('RegisterInstance Decorator Tests', () => {
|
||||
let container: ITSinjex;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_instance'] = undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_dependencies'] = undefined;
|
||||
container = Container.getInstance();
|
||||
});
|
||||
|
||||
it('should register an instance of a dependency', () => {
|
||||
@registerInstance(
|
||||
'InstanceIdentifier',
|
||||
mode === 'instance' ? 'instance' : undefined,
|
||||
)
|
||||
class TestClass {
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
|
||||
public mark: string = 'instance';
|
||||
}
|
||||
|
||||
expect(
|
||||
container.resolve<TestClass>('InstanceIdentifier').mark,
|
||||
).toBe('instance');
|
||||
});
|
||||
|
||||
it('should register an instance of a dependency an run the init function', () => {
|
||||
@registerInstance(
|
||||
'InstanceIdentifier',
|
||||
(x: ForceConstructor<TestClass>) => {
|
||||
const instance = new x();
|
||||
instance.mark = 'init';
|
||||
|
||||
return instance;
|
||||
},
|
||||
)
|
||||
class TestClass {
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
|
||||
public mark: string = 'instance';
|
||||
}
|
||||
|
||||
expect(
|
||||
container.resolve<TestClass>('InstanceIdentifier').mark,
|
||||
).toBe('init');
|
||||
});
|
||||
|
||||
it('should register an instance of a dependency and get it on set', () => {
|
||||
@registerInstance(
|
||||
'InstanceIdentifier',
|
||||
mode === 'instance' ? 'instance' : undefined,
|
||||
)
|
||||
class TestClass {
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
|
||||
public mark: string = 'instance';
|
||||
public test: string = 'test';
|
||||
}
|
||||
|
||||
container.resolve<TestClass>('InstanceIdentifier').test = 'test2';
|
||||
|
||||
expect(
|
||||
container.resolve<TestClass>('InstanceIdentifier').test,
|
||||
).toBe('test2');
|
||||
});
|
||||
|
||||
it('should register an instance of a dependency an run the init function on set', () => {
|
||||
@registerInstance(
|
||||
'InstanceIdentifier',
|
||||
(x: ForceConstructor<TestClass>) => {
|
||||
const instance = new x();
|
||||
instance.mark = 'init';
|
||||
|
||||
return instance;
|
||||
},
|
||||
)
|
||||
class TestClass {
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
|
||||
public mark: string = 'instance';
|
||||
public test: string = 'test';
|
||||
}
|
||||
|
||||
container.resolve<TestClass>('InstanceIdentifier').test = 'test2';
|
||||
|
||||
expect(
|
||||
container.resolve<TestClass>('InstanceIdentifier').test,
|
||||
).toBe('test2');
|
||||
});
|
||||
});
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
/* eslint-disable deprecation/deprecation */
|
||||
import { TSinjex } from 'src/classes/TSinjex.js';
|
||||
import { Inject } from 'src/decorators/Inject.js';
|
||||
import { Register } from 'src/decorators/Register.js';
|
||||
import { RegisterInstance } from 'src/decorators/RegisterInstance.js';
|
||||
import {
|
||||
test_InjectDecorator,
|
||||
test_RegisterDecorator,
|
||||
test_RegisterInstanceDecorator,
|
||||
} from './Decorators.spec.js';
|
||||
|
||||
test_InjectDecorator(TSinjex, Inject);
|
||||
|
||||
test_RegisterDecorator(TSinjex, Register);
|
||||
|
||||
test_RegisterInstanceDecorator(TSinjex, RegisterInstance);
|
||||
|
||||
test_RegisterInstanceDecorator(TSinjex, Register, 'instance');
|
@@ -1,184 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import {
|
||||
DependencyResolutionError,
|
||||
InitializationError,
|
||||
NoInstantiationMethodError,
|
||||
} from '../interfaces/Exceptions.js';
|
||||
import { ITSinjex, ITSinjex_ } from '../interfaces/ITSinjex.js';
|
||||
|
||||
export function test_RegisterFunction(
|
||||
Container: ITSinjex_,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
register: Function,
|
||||
): void {
|
||||
describe('Register Function Tests', () => {
|
||||
let container: ITSinjex;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_instance'] = undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_dependencies'] = undefined;
|
||||
container = Container.getInstance();
|
||||
});
|
||||
|
||||
it('should register a dependency', () => {
|
||||
const identifier = 'MockDependencyIdentifier';
|
||||
class TestClass {
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
register(identifier, TestClass, false);
|
||||
|
||||
const resolvedDependency = container.resolve(identifier);
|
||||
expect(resolvedDependency).toBe(TestClass);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function test_ResolveFunction(
|
||||
Container: ITSinjex_,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
resolve: Function,
|
||||
): void {
|
||||
describe('Resolve Function Tests', () => {
|
||||
let container: ITSinjex;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_instance'] = undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_dependencies'] = undefined;
|
||||
container = Container.getInstance();
|
||||
});
|
||||
|
||||
it('should resolve a dependency', () => {
|
||||
const identifier = 'MockDependencyIdentifier';
|
||||
class TestClass {
|
||||
private readonly _dependency!: any;
|
||||
|
||||
public getDependency() {
|
||||
return this._dependency;
|
||||
}
|
||||
}
|
||||
|
||||
container.register(identifier, TestClass);
|
||||
|
||||
const resolvedDependency = resolve(identifier);
|
||||
expect(resolvedDependency).toBe(TestClass);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the inject function.
|
||||
* @param Container The DI container implementation to test against.
|
||||
* @param inject The inject function to test.
|
||||
*/
|
||||
export function test_injectFunction(
|
||||
Container: ITSinjex_,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
inject: Function,
|
||||
): void {
|
||||
describe('inject Function Tests', () => {
|
||||
let container: ITSinjex;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset singleton
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_instance'] = undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_dependencies'] = undefined;
|
||||
container = Container.getInstance();
|
||||
});
|
||||
|
||||
it('should resolve and return the dependency as is', () => {
|
||||
container.register('SimpleDep', { value: 'test' });
|
||||
|
||||
const resolved = inject('SimpleDep');
|
||||
expect(resolved.value).toBe('test');
|
||||
});
|
||||
|
||||
it('should resolve and run the initializer function', () => {
|
||||
container.register('DepWithInit', { value: 'before' });
|
||||
|
||||
const resolved = inject('DepWithInit', (dep: any) => {
|
||||
dep.value = 'after';
|
||||
|
||||
return dep;
|
||||
});
|
||||
|
||||
expect(resolved.value).toBe('after');
|
||||
});
|
||||
|
||||
it('should resolve and instantiate the dependency if init is true and constructor exists', () => {
|
||||
class WithConstructor {
|
||||
value = 'constructed';
|
||||
}
|
||||
|
||||
container.register('Constructable', WithConstructor);
|
||||
|
||||
const resolved = inject('Constructable', true);
|
||||
expect(resolved.value).toBe('constructed');
|
||||
});
|
||||
|
||||
it('should return undefined if dependency is not found and not necessary', () => {
|
||||
const resolved = inject('NonExistentDep', undefined, false);
|
||||
expect(resolved).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should throw DependencyResolutionError if dependency is not found and necessary', () => {
|
||||
expect(() => inject('MissingDep')).toThrow(
|
||||
DependencyResolutionError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw InitializationError if init function throws', () => {
|
||||
container.register('InitThrows', {});
|
||||
|
||||
expect(() =>
|
||||
inject('InitThrows', () => {
|
||||
throw new Error('fail');
|
||||
}),
|
||||
).toThrow(InitializationError);
|
||||
});
|
||||
|
||||
it('should throw NoInstantiationMethodError if init = true and no constructor exists', () => {
|
||||
container.register('NonConstructable', {});
|
||||
|
||||
expect(() => inject('NonConstructable', true)).toThrow(
|
||||
NoInstantiationMethodError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not throw if no constructor and necessary = false', () => {
|
||||
container.register('SafeSkip', {});
|
||||
expect(() => inject('SafeSkip', true, false)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should return undefined if initializer fails and not necessary', () => {
|
||||
container.register('InitErrorOptional', {});
|
||||
|
||||
const result = inject(
|
||||
'InitErrorOptional',
|
||||
() => {
|
||||
throw new Error('ignored');
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined if dependency is null and not necessary', () => {
|
||||
container.register('NullDep', null);
|
||||
const result = inject('NullDep', true, false);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
import {
|
||||
test_injectFunction,
|
||||
test_RegisterFunction,
|
||||
test_ResolveFunction,
|
||||
} from './Functions.spec.js';
|
||||
import { TSinjex } from '../classes/TSinjex.js';
|
||||
import { inject } from '../functions/inject.js';
|
||||
import { register } from '../functions/register.js';
|
||||
import { resolve } from '../functions/resolve.js';
|
||||
|
||||
test_RegisterFunction(TSinjex, register);
|
||||
test_ResolveFunction(TSinjex, resolve);
|
||||
test_injectFunction(TSinjex, inject);
|
@@ -1,79 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
import { ITSinjex_, ITSinjex } from '../interfaces/ITSinjex.js';
|
||||
|
||||
/**
|
||||
* Test the implementation of the `ITSinjex` interface.
|
||||
* @param Container The implementation to test.
|
||||
* Must implement {@link ITSinjex}, {@link ITSinjex_}
|
||||
*/
|
||||
export function test_ITSinjex(Container: ITSinjex_): void {
|
||||
describe('IDIContainer Implementation Tests', () => {
|
||||
let container: ITSinjex;
|
||||
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_instance'] = undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(Container as any)['_dependencies'] = undefined;
|
||||
container = Container.getInstance();
|
||||
});
|
||||
|
||||
it('should register and resolve a dependency', () => {
|
||||
const identifier = 'myDependency';
|
||||
const dependency = { value: 42 };
|
||||
|
||||
container.register(identifier, dependency);
|
||||
|
||||
const resolvedDependency =
|
||||
container.resolve<typeof dependency>(identifier);
|
||||
expect(resolvedDependency).toBe(dependency);
|
||||
});
|
||||
|
||||
it('should register and resolve a dependency static', () => {
|
||||
const identifier = 'myDependency';
|
||||
const dependency = { value: 42 };
|
||||
|
||||
Container.register(identifier, dependency);
|
||||
|
||||
const resolvedDependency =
|
||||
Container.resolve<typeof dependency>(identifier);
|
||||
expect(resolvedDependency).toBe(dependency);
|
||||
});
|
||||
|
||||
it('should throw an error when resolving a non-registered dependency static', () => {
|
||||
const identifier = 'nonExistentDependency';
|
||||
|
||||
expect(() => Container.resolve<unknown>(identifier)).toThrow();
|
||||
});
|
||||
|
||||
it('should return undefined when resolving a non-registered, non-necessary dependency', () => {
|
||||
const resolvedDependency = Container.resolve<unknown>(
|
||||
'nonExistentDependency',
|
||||
false,
|
||||
);
|
||||
expect(resolvedDependency).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should warn when resolving a deprecated dependency', () => {
|
||||
const identifier = 'deprecatedDependency';
|
||||
const dependency = { value: 42 };
|
||||
|
||||
// Spy on console.warn
|
||||
const warnSpy = jest
|
||||
.spyOn(console, 'warn')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
Container.register(identifier, dependency, true);
|
||||
|
||||
const resolvedDependency =
|
||||
Container.resolve<typeof dependency>(identifier);
|
||||
expect(resolvedDependency).toBe(dependency);
|
||||
|
||||
// Expect console.warn to be called
|
||||
expect(warnSpy).toHaveBeenCalled();
|
||||
|
||||
// Restore the original console.warn
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
import { test_ITSinjex } from './ITSinjex.spec.js';
|
||||
import { TSinjex } from '../classes/TSinjex.js';
|
||||
|
||||
test_ITSinjex(TSinjex);
|
@@ -1,39 +0,0 @@
|
||||
import { Register } from './Register.js';
|
||||
import { Identifier } from '../types/Identifier.js';
|
||||
import { InitDelegate } from '../types/InitDelegate.js';
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
* @param deprecated If true, the dependency is deprecated and a warning
|
||||
* is logged only once upon the first resolution of the dependency.
|
||||
* @see {@link InitDelegate} for more information on initializer functions.
|
||||
* @returns The decorator function to be applied on the class.
|
||||
* @example
|
||||
* ```ts
|
||||
* \@RegisterInstance('MyClassInstanceIdentifier', (constructor) => new constructor())
|
||||
* class MyClass {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
* @deprecated Use {@link Register} instead. This decorator already uses the {@link Register} decorator internally.
|
||||
*/
|
||||
export function RegisterInstance<
|
||||
TargetType extends new (..._args: unknown[]) => InstanceType<TargetType>,
|
||||
>(
|
||||
identifier: Identifier,
|
||||
init?: InitDelegate<
|
||||
TargetType & { new (..._args: unknown[]): InstanceType<TargetType> },
|
||||
InstanceType<TargetType>
|
||||
>,
|
||||
deprecated?: boolean,
|
||||
): (constructor: TargetType, ...args: unknown[]) => void {
|
||||
const initDelegate = typeof init === 'function' ? init : undefined;
|
||||
|
||||
if (initDelegate) return Register(identifier, initDelegate, deprecated);
|
||||
else return Register(identifier, 'instance', deprecated);
|
||||
}
|
@@ -1,220 +0,0 @@
|
||||
import { TSinjex } from '../classes/TSinjex.js';
|
||||
import {
|
||||
DependencyResolutionError,
|
||||
InitializationError,
|
||||
InjectorError,
|
||||
NoInstantiationMethodError,
|
||||
} from '../interfaces/Exceptions.js';
|
||||
import { Identifier } from '../types/Identifier.js';
|
||||
import { InitDelegate } from '../types/InitDelegate.js';
|
||||
|
||||
/**
|
||||
* Resolves a dependency by its identifier without initialization or instantiation.
|
||||
* @template T The expected type of the dependency.
|
||||
* @param identifier The identifier used to resolve the dependency from the container.
|
||||
* @returns The resolved dependency.
|
||||
* @throws A {@link DependencyResolutionError} if the dependency is not found.
|
||||
* @example
|
||||
* ```ts
|
||||
* const logger = inject<Logger>('Logger');
|
||||
* ```
|
||||
*/
|
||||
export function inject<T>(identifier: Identifier): T;
|
||||
|
||||
/**
|
||||
* Resolves and instantiates a dependency using its constructor.
|
||||
* @template T The expected class type of the dependency.
|
||||
* @param identifier The identifier used to resolve the dependency from the container.
|
||||
* @param shouldInit Set to `true` to instantiate the dependency after resolution.
|
||||
* @returns The resolved and instantiated dependency.
|
||||
* @throws A {@link DependencyResolutionError} if the dependency is not found.
|
||||
* @throws A {@link NoInstantiationMethodError} if the dependency has no constructor.
|
||||
* @throws An {@link InitializationError} if instantiation fails.
|
||||
* @example
|
||||
* ```ts
|
||||
* const instance = inject<Service>('Service', true);
|
||||
* ```
|
||||
*/
|
||||
export function inject<T>(identifier: Identifier, shouldInit: true): T;
|
||||
|
||||
/**
|
||||
* Resolves and instantiates a dependency using its constructor, optionally failing silently.
|
||||
* @template T The expected class type of the dependency.
|
||||
* @param identifier The identifier used to resolve the dependency from the container.
|
||||
* @param shouldInit Set to `true` to instantiate the dependency.
|
||||
* @param isNecessary If `false`, resolution or instantiation errors return `undefined` instead of throwing.
|
||||
* @returns The resolved and instantiated dependency, or `undefined` if resolution or instantiation fails.
|
||||
* @example
|
||||
* ```ts
|
||||
* const instance = inject<Service>('OptionalService', true, false);
|
||||
* if (instance) instance.doSomething();
|
||||
* ```
|
||||
*/
|
||||
export function inject<T>(
|
||||
identifier: Identifier,
|
||||
shouldInit: true,
|
||||
isNecessary: false,
|
||||
): T | undefined;
|
||||
|
||||
/**
|
||||
* Resolves a dependency without instantiating it, optionally failing silently.
|
||||
* @template T The expected type of the dependency.
|
||||
* @param identifier The identifier used to resolve the dependency from the container.
|
||||
* @param shouldInit Set to `false` to skip instantiation.
|
||||
* @param isNecessary If `false`, resolution errors return `undefined` instead of throwing.
|
||||
* @returns The resolved dependency, or `undefined` if not found.
|
||||
* @example
|
||||
* ```ts
|
||||
* const config = inject<Config>('Config', false, false) ?? getDefaultConfig();
|
||||
* ```
|
||||
*/
|
||||
export function inject<T>(
|
||||
identifier: Identifier,
|
||||
shouldInit: false,
|
||||
isNecessary: false,
|
||||
): T | undefined;
|
||||
|
||||
/**
|
||||
* Resolves a dependency and applies a custom initializer function to transform the result.
|
||||
* @template T The original dependency type.
|
||||
* @template U The final return type after initialization.
|
||||
* @param identifier The identifier used to resolve the dependency.
|
||||
* @param init A function to transform or initialize the dependency.
|
||||
* @returns The transformed dependency.
|
||||
* @throws A {@link DependencyResolutionError} if the dependency is not found.
|
||||
* @throws An {@link InitializationError} if the initializer throws.
|
||||
* @example
|
||||
* ```ts
|
||||
* const client = inject<Api>('Api', (api) => api.getClient());
|
||||
* ```
|
||||
*/
|
||||
export function inject<T, U>(
|
||||
identifier: Identifier,
|
||||
init: InitDelegate<T, U>,
|
||||
): U;
|
||||
|
||||
/**
|
||||
* Resolves a dependency and applies a custom initializer function, optionally failing silently.
|
||||
* @template T The original dependency type.
|
||||
* @template U The final return type after initialization.
|
||||
* @param identifier The identifier used to resolve the dependency.
|
||||
* @param init A function to transform or initialize the dependency.
|
||||
* @param isNecessary If `false`, resolution or initializer errors return `undefined` instead of throwing.
|
||||
* @returns The transformed dependency, or `undefined` if resolution or initialization fails.
|
||||
* @example
|
||||
* ```ts
|
||||
* const db = inject<Database, Pool>('Database', (d) => d.getPool(), false);
|
||||
* if (db) db.query('SELECT * FROM users');
|
||||
* ```
|
||||
*/
|
||||
export function inject<T, U>(
|
||||
identifier: Identifier,
|
||||
init: InitDelegate<T, U>,
|
||||
isNecessary: false,
|
||||
): U | undefined;
|
||||
|
||||
/**
|
||||
* A function to inject a dependency from a DI (Dependency Injection) container into a variable.
|
||||
* This is the actual implementation that handles all overload variants.
|
||||
* @template T The original dependency type.
|
||||
* @template U The final return type after optional initialization or transformation.
|
||||
* @param identifier The identifier used to resolve the dependency.
|
||||
* @see {@link Identifier} for more information on identifiers.
|
||||
* @param init Optional: either `true` to instantiate via constructor, `false` to skip, or a function to transform the dependency.
|
||||
* @see {@link InitDelegate} for more information on initializer functions.
|
||||
* @param isNecessary If `true`, throws on failure; if `false`, returns `undefined` on resolution or initialization errors.
|
||||
* @returns The resolved dependency or result of initialization, or `undefined` if not necessary and resolution fails.
|
||||
* @throws A {@link DependencyResolutionError} if the dependency is not found (and necessary).
|
||||
* @throws A {@link NoInstantiationMethodError} if instantiation is requested but no constructor exists.
|
||||
* @throws An {@link InitializationError} if the initializer throws an error.
|
||||
* @throws A {@link InjectorError} for unknown errors during resolution or transformation.
|
||||
* @example
|
||||
* ```ts
|
||||
* const service = inject<Service>('Service');
|
||||
* ```
|
||||
* @example
|
||||
* ```ts
|
||||
* const instance = inject<Service>('Service', true);
|
||||
* ```
|
||||
* @example
|
||||
* ```ts
|
||||
* const logger = inject<ILogger>('ILogger_', (x) => x.getLogger('Module'), false);
|
||||
* ```
|
||||
*/
|
||||
export function inject<T, U>(
|
||||
identifier: Identifier,
|
||||
init?: InitDelegate<T, U> | true | false,
|
||||
isNecessary = true,
|
||||
): T | U | undefined {
|
||||
let instance: T | U | undefined;
|
||||
|
||||
const dependency: T | undefined = tryAndCatch(
|
||||
() => TSinjex.getInstance().resolve<T>(identifier, isNecessary),
|
||||
isNecessary,
|
||||
identifier,
|
||||
DependencyResolutionError,
|
||||
);
|
||||
|
||||
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 || init === false) instance = dependency;
|
||||
else if (initFunction != null)
|
||||
instance = tryAndCatch(
|
||||
initFunction,
|
||||
isNecessary,
|
||||
identifier,
|
||||
InitializationError,
|
||||
);
|
||||
else if (isNecessary) throw new NoInstantiationMethodError(identifier);
|
||||
} else if (isNecessary) throw new DependencyResolutionError(identifier);
|
||||
|
||||
return instance as T | U;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to execute a function and catches any errors that occur.
|
||||
* If the function is necessary and an error occurs, it throws the error
|
||||
* with the specified error class and identifier.
|
||||
* @param fn The function to execute.
|
||||
* @param necessary If true, throws an error if an error occurs.
|
||||
* @param identifier The identifier of the dependency.
|
||||
* @param errorClass The error class to throw if an error occurs.
|
||||
* @returns The result of the function or undefined if an error occurs and the function is not necessary.
|
||||
*/
|
||||
function tryAndCatch<ReturnType, ErrorType>(
|
||||
fn: () => ReturnType,
|
||||
necessary: boolean,
|
||||
identifier?: Identifier,
|
||||
errorClass?: ErrorType,
|
||||
): ReturnType | undefined {
|
||||
try {
|
||||
return fn();
|
||||
} catch (error) {
|
||||
if (necessary)
|
||||
throw new (errorClass != null ? errorClass : error)(
|
||||
identifier ?? 'not specified',
|
||||
error,
|
||||
);
|
||||
else return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an object has a constructor.
|
||||
* @param obj The object to check.
|
||||
* @returns True if the object has a constructor, false otherwise.
|
||||
*/
|
||||
function hasConstructor<T>(obj: T): obj is T & { new (): unknown } {
|
||||
const _obj = obj as unknown as { prototype?: { constructor?: unknown } };
|
||||
|
||||
return (
|
||||
_obj?.prototype != null &&
|
||||
typeof _obj.prototype.constructor === 'function'
|
||||
);
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
import { TSinjex } from '../classes/TSinjex.js';
|
||||
import { Identifier } from '../types/Identifier.js';
|
||||
|
||||
/**
|
||||
* Register a dependency.
|
||||
* @param identifier The identifier used to register the class in the DI container.
|
||||
* @see {@link Identifier} for more information on identifiers..
|
||||
* @param dependency The dependency to register.
|
||||
*/
|
||||
export function register<T>(identifier: Identifier, dependency: T): void;
|
||||
|
||||
/**
|
||||
* Register a dependency.
|
||||
* @param identifier The identifier used to register the class in the DI container.
|
||||
* @see {@link Identifier} for more information on identifiers.
|
||||
* @param dependency The dependency to register.
|
||||
* @param deprecated A warning is logged when the dependency is resolved.
|
||||
*/
|
||||
export function register<T>(
|
||||
identifier: Identifier,
|
||||
dependency: T,
|
||||
deprecated?: true,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Register a dependency.
|
||||
* @param identifier The identifier used to register the class in the DI container.
|
||||
* @see {@link Identifier} for more information on identifiers.
|
||||
* @param dependency The dependency to register.
|
||||
* @param deprecated If true, the dependency is deprecated => a warning
|
||||
* is logged when the dependency is resolved.
|
||||
*/
|
||||
export function register<T>(
|
||||
identifier: Identifier,
|
||||
dependency: T,
|
||||
deprecated?: boolean,
|
||||
): void {
|
||||
TSinjex.getInstance().register(identifier, dependency, deprecated);
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
import { TSinjex } from '../classes/TSinjex.js';
|
||||
import { DependencyResolutionError } from '../interfaces/Exceptions.js';
|
||||
import { Identifier } from '../types/Identifier.js';
|
||||
|
||||
/**
|
||||
* Resolve a dependency.
|
||||
* @param identifier The identifier used to register the class in the DI container.
|
||||
* @see {@link Identifier} for more information on identifiers.
|
||||
* @returns The resolved dependency.
|
||||
* @throws A {@link DependencyResolutionError} if the dependency is not found.
|
||||
*/
|
||||
export function resolve<T>(identifier: Identifier): T;
|
||||
|
||||
/**
|
||||
* Resolve a dependency
|
||||
* @param identifier The identifier used to register the class in the DI container.
|
||||
* @see {@link Identifier} for more information on identifiers.
|
||||
* @param isNecessary The dependency is **not** necessary.
|
||||
* @returns The resolved dependency or undefined if the dependency is not found.
|
||||
*/
|
||||
export function resolve<T>(
|
||||
identifier: Identifier,
|
||||
isNecessary: false,
|
||||
): T | undefined;
|
||||
|
||||
/**
|
||||
* Resolve a dependency.
|
||||
* @param identifier The identifier used to register the class in the DI container.
|
||||
* @see {@link Identifier} for more information on identifiers.
|
||||
* @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 A {@link DependencyResolutionError} if the dependency is not found and necessary.
|
||||
*/
|
||||
export function resolve<T>(
|
||||
identifier: Identifier,
|
||||
necessary?: boolean,
|
||||
): T | undefined {
|
||||
return TSinjex.getInstance().resolve<T>(identifier, necessary);
|
||||
}
|
22
src/index.ts
22
src/index.ts
@@ -1,22 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
|
||||
// Main
|
||||
export * from './classes/TSinjex.js';
|
||||
|
||||
// Decorators
|
||||
export * from './decorators/Inject.js';
|
||||
export * from './decorators/Register.js';
|
||||
export * from './decorators/RegisterInstance.js';
|
||||
|
||||
// Helper
|
||||
export * from './helper/ImplementsStatic.js';
|
||||
|
||||
// Functions
|
||||
export * from './functions/resolve.js';
|
||||
export * from './functions/register.js';
|
||||
export * from './functions/inject.js';
|
||||
|
||||
// Interfaces & Types
|
||||
export type * from './interfaces/ITSinjex.js';
|
||||
export type * from './types/InitDelegate.js';
|
||||
export type * from './types/GenericContructor.js';
|
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Generic constructor type.
|
||||
* This type is used to define a constructor of a class.
|
||||
*/
|
||||
export type GenericConstructor<
|
||||
T extends abstract new (...args: unknown[]) => InstanceType<T>,
|
||||
> = new (...args: ConstructorParameters<T>) => T;
|
||||
|
||||
/**
|
||||
* Force generic constructor type.
|
||||
* This type is used to force a class to has a constructor.
|
||||
*/
|
||||
export type ForceConstructor<T> = new (...args: unknown[]) => T;
|
Reference in New Issue
Block a user