Skip to content

Commit

Permalink
Allow deactivating undefined singleton constant value services (#1628)
Browse files Browse the repository at this point in the history
* test: remove unused tsconfig

* style: update test description

* fix: allow deactivating singleton undefined values

* docs: update changelog
  • Loading branch information
notaphplover authored Nov 13, 2024
1 parent d6f09a6 commit aec9df3
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated planner with better error description when a binding can not be properly resolved.

### Fixed
- Updated container to allow deactivating singleton undefined values.
- Updated planner to provide right circular dependent services when such dependencies are detected.

## [6.1.3]
Expand Down
39 changes: 25 additions & 14 deletions src/container/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,10 +530,13 @@ class Container implements interfaces.Container {
}

private _preDestroy(
constructor: NewableFunction,
constructor: NewableFunction | undefined,
instance: unknown,
): Promise<void> | void {
if (Reflect.hasMetadata(METADATA_KEY.PRE_DESTROY, constructor)) {
if (
constructor !== undefined &&
Reflect.hasMetadata(METADATA_KEY.PRE_DESTROY, constructor)
) {
const data: interfaces.Metadata = Reflect.getMetadata(
METADATA_KEY.PRE_DESTROY,
constructor,
Expand Down Expand Up @@ -569,9 +572,11 @@ class Container implements interfaces.Container {
instance: T,
): void | Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const constructor: NewableFunction =
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Object.getPrototypeOf(instance).constructor;
const constructor: NewableFunction | undefined =
instance == undefined
? undefined
: // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Object.getPrototypeOf(instance).constructor;

try {
if (this._deactivations.hasKey(binding.serviceIdentifier)) {
Expand All @@ -589,7 +594,7 @@ class Container implements interfaces.Container {
constructor,
),
),
constructor,
binding.serviceIdentifier,
);
}
}
Expand All @@ -604,28 +609,34 @@ class Container implements interfaces.Container {
if (isPromise(propagateDeactivationResult)) {
return this._handleDeactivationError(
propagateDeactivationResult,
constructor,
binding.serviceIdentifier,
);
}
} catch (ex) {
if (ex instanceof Error) {
throw new Error(
ERROR_MSGS.ON_DEACTIVATION_ERROR(constructor.name, ex.message),
ERROR_MSGS.ON_DEACTIVATION_ERROR(
getServiceIdentifierAsString(binding.serviceIdentifier),
ex.message,
),
);
}
}
}

private async _handleDeactivationError(
asyncResult: Promise<void>,
constructor: NewableFunction,
serviceIdentifier: interfaces.ServiceIdentifier,
): Promise<void> {
try {
await asyncResult;
} catch (ex) {
if (ex instanceof Error) {
throw new Error(
ERROR_MSGS.ON_DEACTIVATION_ERROR(constructor.name, ex.message),
ERROR_MSGS.ON_DEACTIVATION_ERROR(
getServiceIdentifierAsString(serviceIdentifier),
ex.message,
),
);
}
}
Expand Down Expand Up @@ -917,7 +928,7 @@ class Container implements interfaces.Container {
private _propagateContainerDeactivationThenBindingAndPreDestroy<T>(
binding: Binding<T>,
instance: T,
constructor: NewableFunction,
constructor: NewableFunction | undefined,
): void | Promise<void> {
if (this.parent) {
return this._deactivate.bind(this.parent)(binding, instance);
Expand All @@ -933,7 +944,7 @@ class Container implements interfaces.Container {
private async _propagateContainerDeactivationThenBindingAndPreDestroyAsync<T>(
binding: Binding<T>,
instance: T,
constructor: NewableFunction,
constructor: NewableFunction | undefined,
): Promise<void> {
if (this.parent) {
await this._deactivate.bind(this.parent)(binding, instance);
Expand Down Expand Up @@ -961,7 +972,7 @@ class Container implements interfaces.Container {
private _bindingDeactivationAndPreDestroy<T>(
binding: Binding<T>,
instance: T,
constructor: NewableFunction,
constructor: NewableFunction | undefined,
): void | Promise<void> {
if (typeof binding.onDeactivation === 'function') {
const result: void | Promise<void> = binding.onDeactivation(instance);
Expand All @@ -979,7 +990,7 @@ class Container implements interfaces.Container {
private async _bindingDeactivationAndPreDestroyAsync<T>(
binding: Binding<T>,
instance: T,
constructor: NewableFunction,
constructor: NewableFunction | undefined,
): Promise<void> {
if (typeof binding.onDeactivation === 'function') {
await binding.onDeactivation(instance);
Expand Down
2 changes: 1 addition & 1 deletion test/bugs/issue_1515.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '../../src/inversify';

describe('Issue 1515', () => {
it('should not throw on false circular dependency', () => {
it('should properly throw on circular dependency', () => {
@injectable()
class Circle1 {
constructor(@inject('circle-2') public readonly circle2: unknown) {}
Expand Down
17 changes: 17 additions & 0 deletions test/bugs/issue_1518.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { expect } from 'chai';

import { Container } from '../../src/inversify';

describe('Issue 1515', () => {
it('should not throw on deactivating undefined singleton values', () => {
const container: Container = new Container();
const symbol: symbol = Symbol.for('foo');
container.bind(symbol).toConstantValue(undefined);

console.log(container.get(symbol));

container.unbindAll();

expect(() => {}).not.to.throw();
});
});
14 changes: 0 additions & 14 deletions test/tsconfig.json

This file was deleted.

0 comments on commit aec9df3

Please sign in to comment.