diff --git a/.changeset/fuzzy-cycles-own.md b/.changeset/fuzzy-cycles-own.md new file mode 100644 index 00000000..e0a706eb --- /dev/null +++ b/.changeset/fuzzy-cycles-own.md @@ -0,0 +1,5 @@ +--- +"@inversifyjs/core": minor +--- + +Updated `unmanaged` to support method decoration diff --git a/.changeset/good-sheep-cheat.md b/.changeset/good-sheep-cheat.md new file mode 100644 index 00000000..e67d64e7 --- /dev/null +++ b/.changeset/good-sheep-cheat.md @@ -0,0 +1,5 @@ +--- +"@inversifyjs/core": minor +--- + +Updated `inject` to support method decoration diff --git a/.changeset/many-jobs-mate.md b/.changeset/many-jobs-mate.md new file mode 100644 index 00000000..da5aee01 --- /dev/null +++ b/.changeset/many-jobs-mate.md @@ -0,0 +1,5 @@ +--- +"@inversifyjs/core": minor +--- + +Updated `optional` to support method decoration diff --git a/.changeset/mighty-shrimps-speak.md b/.changeset/mighty-shrimps-speak.md new file mode 100644 index 00000000..4ee279ab --- /dev/null +++ b/.changeset/mighty-shrimps-speak.md @@ -0,0 +1,5 @@ +--- +"@inversifyjs/core": minor +--- + +Updated `named` to support method decoration diff --git a/.changeset/ninety-dodos-develop.md b/.changeset/ninety-dodos-develop.md new file mode 100644 index 00000000..3659b7ed --- /dev/null +++ b/.changeset/ninety-dodos-develop.md @@ -0,0 +1,5 @@ +--- +"@inversifyjs/core": minor +--- + +Updated `tagged` to support method decoration diff --git a/.changeset/swift-toes-matter.md b/.changeset/swift-toes-matter.md new file mode 100644 index 00000000..8a043f15 --- /dev/null +++ b/.changeset/swift-toes-matter.md @@ -0,0 +1,5 @@ +--- +"@inversifyjs/core": minor +--- + +Updated `multiInject` to support method decoration diff --git a/packages/container/libraries/core/src/metadata/decorators/inject.int.spec.ts b/packages/container/libraries/core/src/metadata/decorators/inject.int.spec.ts index 79b1b435..e39e0355 100644 --- a/packages/container/libraries/core/src/metadata/decorators/inject.int.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/inject.int.spec.ts @@ -21,12 +21,23 @@ describe(inject.name, () => { @inject('baz') public readonly baz!: string; + #someField!: string; + constructor( @inject('firstParam') public firstParam: number, @inject('secondParam') public secondParam: number, ) {} + + public get someField(): string { + return this.#someField; + } + + @inject('someField') + public set someField(value: string) { + this.#someField = value; + } } result = getOwnReflectMetadata(Foo, classMetadataReflectKey); @@ -75,6 +86,16 @@ describe(inject.name, () => { value: 'baz', }, ], + [ + 'someField', + { + kind: ClassElementMetadataKind.singleInjection, + name: undefined, + optional: false, + tags: new Map(), + value: 'someField', + }, + ], ]), scope: undefined, }; diff --git a/packages/container/libraries/core/src/metadata/decorators/inject.spec.ts b/packages/container/libraries/core/src/metadata/decorators/inject.spec.ts index baa26918..4a451fde 100644 --- a/packages/container/libraries/core/src/metadata/decorators/inject.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/inject.spec.ts @@ -3,12 +3,10 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; import { ServiceIdentifier } from '@inversifyjs/common'; jest.mock('../calculations/buildManagedMetadataFromMaybeClassElementMetadata'); -jest.mock('../calculations/handleInjectionError'); jest.mock('./injectBase'); import { decrementPendingClassMetadataCount } from '../actions/decrementPendingClassMetadataCount'; import { buildManagedMetadataFromMaybeClassElementMetadata } from '../calculations/buildManagedMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ClassElementMetadata } from '../models/ClassElementMetadata'; import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; @@ -16,357 +14,67 @@ import { inject } from './inject'; import { injectBase } from './injectBase'; describe(inject.name, () => { - describe('having a non undefined propertyKey and an undefined parameterIndex', () => { - let serviceIdentifierFixture: ServiceIdentifier; - let targetFixture: object; - let propertyKeyFixture: string | symbol; + let serviceIdentifierFixture: ServiceIdentifier; - beforeAll(() => { - serviceIdentifierFixture = 'service-id-fixture'; - targetFixture = class {}; - propertyKeyFixture = 'property-key'; - }); - - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = inject(serviceIdentifierFixture)( - targetFixture, - propertyKeyFixture, - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.singleInjection, - serviceIdentifierFixture, - ); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); - }); - - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - inject(serviceIdentifierFixture)(targetFixture, propertyKeyFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.singleInjection, - serviceIdentifierFixture, - ); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - undefined, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); - }); + beforeAll(() => { + serviceIdentifierFixture = 'service-id-fixture'; }); - describe('having a undefined propertyKey and an non undefined parameterIndex', () => { - let serviceIdentifierFixture: ServiceIdentifier; - let targetFixture: object; - let paramIndexFixture: number; + describe('when called', () => { + let decoratorFixture: MethodDecorator & + ParameterDecorator & + PropertyDecorator; + let updateMetadataMock: jest.Mock< + ( + classElementMetadata: MaybeClassElementMetadata | undefined, + ) => ClassElementMetadata + >; - beforeAll(() => { - serviceIdentifierFixture = 'service-id-fixture'; - targetFixture = class {}; - paramIndexFixture = 0; - }); + let result: unknown; - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & + beforeAll(() => { + decoratorFixture = Symbol() as unknown as MethodDecorator & ParameterDecorator & PropertyDecorator; + updateMetadataMock = jest.fn(); - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = inject(serviceIdentifierFixture)( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); + ( + buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< + typeof buildManagedMetadataFromMaybeClassElementMetadata + > + ).mockReturnValueOnce(updateMetadataMock); - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.singleInjection, - serviceIdentifierFixture, - ); - }); + (injectBase as jest.Mock).mockReturnValueOnce(decoratorFixture); - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + result = inject(serviceIdentifierFixture); }); - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - inject(serviceIdentifierFixture)( - targetFixture, - undefined, - paramIndexFixture, - ); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.singleInjection, - serviceIdentifierFixture, - ); - }); + afterAll(() => { + jest.clearAllMocks(); + }); - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); + it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { + expect( + buildManagedMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledTimes(1); + expect( + buildManagedMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledWith( + ClassElementMetadataKind.singleInjection, + serviceIdentifierFixture, + ); + }); - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - errorFixture, - ); - }); + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith( + updateMetadataMock, + decrementPendingClassMetadataCount, + ); + }); - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + it('should return expected result', () => { + expect(result).toBe(decoratorFixture); }); }); }); diff --git a/packages/container/libraries/core/src/metadata/decorators/inject.ts b/packages/container/libraries/core/src/metadata/decorators/inject.ts index d3cef763..fad32b71 100644 --- a/packages/container/libraries/core/src/metadata/decorators/inject.ts +++ b/packages/container/libraries/core/src/metadata/decorators/inject.ts @@ -2,7 +2,6 @@ import { LazyServiceIdentifier, ServiceIdentifier } from '@inversifyjs/common'; import { decrementPendingClassMetadataCount } from '../actions/decrementPendingClassMetadataCount'; import { buildManagedMetadataFromMaybeClassElementMetadata } from '../calculations/buildManagedMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ClassElementMetadata } from '../models/ClassElementMetadata'; import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; @@ -10,7 +9,7 @@ import { injectBase } from './injectBase'; export function inject( serviceIdentifier: ServiceIdentifier | LazyServiceIdentifier, -): ParameterDecorator & PropertyDecorator { +): MethodDecorator & ParameterDecorator & PropertyDecorator { const updateMetadata: ( classElementMetadata: MaybeClassElementMetadata | undefined, ) => ClassElementMetadata = buildManagedMetadataFromMaybeClassElementMetadata( @@ -18,26 +17,5 @@ export function inject( serviceIdentifier, ); - return ( - target: object, - propertyKey: string | symbol | undefined, - parameterIndex?: number, - ): void => { - try { - if (parameterIndex === undefined) { - injectBase(updateMetadata, decrementPendingClassMetadataCount)( - target, - propertyKey as string | symbol, - ); - } else { - injectBase(updateMetadata, decrementPendingClassMetadataCount)( - target, - propertyKey, - parameterIndex, - ); - } - } catch (error: unknown) { - handleInjectionError(target, propertyKey, parameterIndex, error); - } - }; + return injectBase(updateMetadata, decrementPendingClassMetadataCount); } diff --git a/packages/container/libraries/core/src/metadata/decorators/injectBase.spec.ts b/packages/container/libraries/core/src/metadata/decorators/injectBase.spec.ts index 564c6725..4d5f8e67 100644 --- a/packages/container/libraries/core/src/metadata/decorators/injectBase.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/injectBase.spec.ts @@ -12,13 +12,18 @@ jest.mock('../actions/updateMaybeClassMetadataProperty', () => ({ updateMaybeClassMetadataProperty: jest.fn(), })); +jest.mock('../calculations/handleInjectionError'); + import { Newable } from '@inversifyjs/common'; import { updateOwnReflectMetadata } from '@inversifyjs/reflect-metadata-utils'; +import { InversifyCoreError } from '../../error/models/InversifyCoreError'; +import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind'; import { classMetadataReflectKey } from '../../reflectMetadata/data/classMetadataReflectKey'; import { updateMaybeClassMetadataConstructorArgument } from '../actions/updateMaybeClassMetadataConstructorArgument'; import { updateMaybeClassMetadataProperty } from '../actions/updateMaybeClassMetadataProperty'; import { getDefaultClassMetadata } from '../calculations/getDefaultClassMetadata'; +import { handleInjectionError } from '../calculations/handleInjectionError'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { MaybeClassMetadata } from '../models/MaybeClassMetadata'; import { injectBase } from './injectBase'; @@ -36,6 +41,19 @@ describe(injectBase.name, () => { >; beforeAll(() => { + ( + handleInjectionError as jest.Mock + ).mockImplementation( + ( + _target: unknown, + _propertyKey: unknown, + _indexOrTypedDescriptor: unknown, + error: unknown, + ) => { + throw error; + }, + ); + updateMetadataMock = jest.fn< ( @@ -147,7 +165,8 @@ describe(injectBase.name, () => { }); it('should throw an error', () => { - const expectedPartialError: Partial = { + const expectedPartialError: Partial = { + kind: InversifyCoreErrorKind.injectionDecoratorConflict, message: `Found an @inject decorator in a non constructor parameter. Found @inject decorator at method "doSomethingWithFoo" at class "TargetFixture"`, }; @@ -158,4 +177,89 @@ Found @inject decorator at method "doSomethingWithFoo" at class "TargetFixture"` ); }); }); + + describe('when called, as method decorator', () => { + let targetFixture: Newable; + let updateMaybeClassMetadataPropertyResult: jest.Mock< + (classMetadata: MaybeClassMetadata) => MaybeClassMetadata + >; + + beforeAll(() => { + updateMaybeClassMetadataPropertyResult = jest.fn(); + + ( + updateMaybeClassMetadataProperty as jest.Mock< + typeof updateMaybeClassMetadataProperty + > + ).mockReturnValueOnce(updateMaybeClassMetadataPropertyResult); + + class TargetFixture { + @injectBase(updateMetadataMock, updatePendingClassMetadataCountMock) + public set foo(_value: string | undefined) { + // setter logic + } + } + + targetFixture = TargetFixture; + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('should call updateOwnReflectMetadata()', () => { + expect(updateOwnReflectMetadata).toHaveBeenCalledTimes(1); + expect(updateOwnReflectMetadata).toHaveBeenCalledWith( + targetFixture, + classMetadataReflectKey, + getDefaultClassMetadata, + updateMaybeClassMetadataPropertyResult, + ); + }); + }); + + describe('when called, as method decorator on non-setter method', () => { + let result: unknown; + + beforeAll(() => { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + class TargetFixture { + @injectBase(updateMetadataMock, updatePendingClassMetadataCountMock) + public foo(): void { + // method logic + } + } + } catch (error: unknown) { + result = error; + } + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('should throw an error', () => { + const expectedPartialError: Partial = { + kind: InversifyCoreErrorKind.injectionDecoratorConflict, + message: `Found an @inject decorator in a non setter property method. +Found @inject decorator at method "foo" at class "TargetFixture"`, + }; + + expect(result).toBeInstanceOf(Error); + expect(result).toStrictEqual( + expect.objectContaining(expectedPartialError), + ); + }); + + it('should call handleInjectionError()', () => { + expect(handleInjectionError).toHaveBeenCalledTimes(1); + expect(handleInjectionError).toHaveBeenCalledWith( + expect.any(Object), + 'foo', + expect.any(Object), + expect.any(Error), + ); + }); + }); }); diff --git a/packages/container/libraries/core/src/metadata/decorators/injectBase.ts b/packages/container/libraries/core/src/metadata/decorators/injectBase.ts index 3f53fcfb..a38f86b7 100644 --- a/packages/container/libraries/core/src/metadata/decorators/injectBase.ts +++ b/packages/container/libraries/core/src/metadata/decorators/injectBase.ts @@ -1,9 +1,12 @@ import { updateOwnReflectMetadata } from '@inversifyjs/reflect-metadata-utils'; +import { InversifyCoreError } from '../../error/models/InversifyCoreError'; +import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind'; import { classMetadataReflectKey } from '../../reflectMetadata/data/classMetadataReflectKey'; import { updateMaybeClassMetadataConstructorArgument } from '../actions/updateMaybeClassMetadataConstructorArgument'; import { updateMaybeClassMetadataProperty } from '../actions/updateMaybeClassMetadataProperty'; import { getDefaultClassMetadata } from '../calculations/getDefaultClassMetadata'; +import { handleInjectionError } from '../calculations/handleInjectionError'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; export function injectBase( @@ -13,22 +16,61 @@ export function injectBase( updatePendingClassMetadataCount: ( target: object, ) => (metadata: MaybeClassElementMetadata | undefined) => void, -): ParameterDecorator & PropertyDecorator { - const decorator: ParameterDecorator & PropertyDecorator = ( +): MethodDecorator & ParameterDecorator & PropertyDecorator; +export function injectBase( + updateMetadata: ( + metadata: MaybeClassElementMetadata | undefined, + ) => MaybeClassElementMetadata, + updatePendingClassMetadataCount: ( + target: object, + ) => (metadata: MaybeClassElementMetadata | undefined) => void, +): ( + target: object, + propertyKey: string | symbol | undefined, + parameterIndex?: number | TypedPropertyDescriptor, +) => void; +export function injectBase( + updateMetadata: ( + metadata: MaybeClassElementMetadata | undefined, + ) => MaybeClassElementMetadata, + updatePendingClassMetadataCount: ( + target: object, + ) => (metadata: MaybeClassElementMetadata | undefined) => void, +): MethodDecorator & ParameterDecorator & PropertyDecorator { + const decorator: MethodDecorator & ParameterDecorator & PropertyDecorator = < + T, + >( target: object, propertyKey: string | symbol | undefined, - parameterIndex?: number, + parameterIndexOrDescriptor?: number | TypedPropertyDescriptor, ): void => { - if (parameterIndex === undefined) { - injectProperty(updateMetadata, updatePendingClassMetadataCount)( - target, - propertyKey as string | symbol, - ); - } else { - injectParameter(updateMetadata, updatePendingClassMetadataCount)( + try { + if (parameterIndexOrDescriptor === undefined) { + injectProperty(updateMetadata, updatePendingClassMetadataCount)( + target, + propertyKey as string | symbol, + ); + } else { + if (typeof parameterIndexOrDescriptor === 'number') { + injectParameter(updateMetadata, updatePendingClassMetadataCount)( + target, + propertyKey, + parameterIndexOrDescriptor, + ); + } else { + injectMethod(updateMetadata, updatePendingClassMetadataCount)( + target, + propertyKey as string | symbol, + parameterIndexOrDescriptor, + ); + } + } + } catch (error: unknown) { + handleInjectionError( target, propertyKey, - parameterIndex, + parameterIndexOrDescriptor, + error, ); } }; @@ -67,6 +109,48 @@ function buildComposedUpdateMetadata( }; } +function injectMethod( + updateMetadata: ( + metadata: MaybeClassElementMetadata | undefined, + ) => MaybeClassElementMetadata, + updatePendingClassMetadataCount: ( + target: object, + ) => (metadata: MaybeClassElementMetadata | undefined) => void, +): MethodDecorator { + const buildComposedUpdateMetadataFromTarget: ( + target: object, + ) => ( + metadata: MaybeClassElementMetadata | undefined, + ) => MaybeClassElementMetadata = buildComposedUpdateMetadata( + updateMetadata, + updatePendingClassMetadataCount, + ); + + return ( + target: object, + propertyKey: string | symbol, + descriptor: TypedPropertyDescriptor, + ): void => { + if (isPropertySetter(descriptor)) { + updateOwnReflectMetadata( + target.constructor, + classMetadataReflectKey, + getDefaultClassMetadata, + updateMaybeClassMetadataProperty( + buildComposedUpdateMetadataFromTarget(target), + propertyKey, + ), + ); + } else { + throw new InversifyCoreError( + InversifyCoreErrorKind.injectionDecoratorConflict, + `Found an @inject decorator in a non setter property method. +Found @inject decorator at method "${propertyKey.toString()}" at class "${target.constructor.name}"`, + ); + } + }; +} + function injectParameter( updateMetadata: ( metadata: MaybeClassElementMetadata | undefined, @@ -100,7 +184,8 @@ function injectParameter( ), ); } else { - throw new Error( + throw new InversifyCoreError( + InversifyCoreErrorKind.injectionDecoratorConflict, `Found an @inject decorator in a non constructor parameter. Found @inject decorator at method "${ propertyKey?.toString() ?? '' @@ -146,3 +231,7 @@ function isConstructorParameter( ): boolean { return typeof target === 'function' && propertyKey === undefined; } + +function isPropertySetter(descriptor: TypedPropertyDescriptor): boolean { + return descriptor.set !== undefined; +} diff --git a/packages/container/libraries/core/src/metadata/decorators/multiInject.int.spec.ts b/packages/container/libraries/core/src/metadata/decorators/multiInject.int.spec.ts index 532fbcb2..4706497e 100644 --- a/packages/container/libraries/core/src/metadata/decorators/multiInject.int.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/multiInject.int.spec.ts @@ -21,12 +21,23 @@ describe(multiInject.name, () => { @multiInject('baz') public readonly baz!: string; + #someField!: string; + constructor( @multiInject('firstParam') public firstParam: number, @multiInject('secondParam') public secondParam: number, ) {} + + public get someField(): string { + return this.#someField; + } + + @multiInject('someField') + public set someField(value: string) { + this.#someField = value; + } } result = getOwnReflectMetadata(Foo, classMetadataReflectKey); @@ -75,6 +86,16 @@ describe(multiInject.name, () => { value: 'baz', }, ], + [ + 'someField', + { + kind: ClassElementMetadataKind.multipleInjection, + name: undefined, + optional: false, + tags: new Map(), + value: 'someField', + }, + ], ]), scope: undefined, }; diff --git a/packages/container/libraries/core/src/metadata/decorators/multiInject.spec.ts b/packages/container/libraries/core/src/metadata/decorators/multiInject.spec.ts index 94b9422a..6db20f4b 100644 --- a/packages/container/libraries/core/src/metadata/decorators/multiInject.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/multiInject.spec.ts @@ -3,12 +3,10 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; import { ServiceIdentifier } from '@inversifyjs/common'; jest.mock('../calculations/buildManagedMetadataFromMaybeClassElementMetadata'); -jest.mock('../calculations/handleInjectionError'); jest.mock('./injectBase'); import { decrementPendingClassMetadataCount } from '../actions/decrementPendingClassMetadataCount'; import { buildManagedMetadataFromMaybeClassElementMetadata } from '../calculations/buildManagedMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ClassElementMetadata } from '../models/ClassElementMetadata'; import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; @@ -16,360 +14,67 @@ import { injectBase } from './injectBase'; import { multiInject } from './multiInject'; describe(multiInject.name, () => { - describe('having a non undefined propertyKey and an undefined parameterIndex', () => { - let serviceIdentifierFixture: ServiceIdentifier; - let targetFixture: object; - let propertyKeyFixture: string | symbol; + let serviceIdentifierFixture: ServiceIdentifier; - beforeAll(() => { - serviceIdentifierFixture = 'service-id-fixture'; - targetFixture = class {}; - propertyKeyFixture = 'property-key'; - }); - - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = multiInject(serviceIdentifierFixture)( - targetFixture, - propertyKeyFixture, - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.multipleInjection, - serviceIdentifierFixture, - ); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); - }); - - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - multiInject(serviceIdentifierFixture)( - targetFixture, - propertyKeyFixture, - ); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.multipleInjection, - serviceIdentifierFixture, - ); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - undefined, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); - }); + beforeAll(() => { + serviceIdentifierFixture = 'service-id-fixture'; }); - describe('having a undefined propertyKey and an non undefined parameterIndex', () => { - let serviceIdentifierFixture: ServiceIdentifier; - let targetFixture: object; - let paramIndexFixture: number; + describe('when called', () => { + let decoratorFixture: MethodDecorator & + ParameterDecorator & + PropertyDecorator; + let updateMetadataMock: jest.Mock< + ( + classElementMetadata: MaybeClassElementMetadata | undefined, + ) => ClassElementMetadata + >; - beforeAll(() => { - serviceIdentifierFixture = 'service-id-fixture'; - targetFixture = class {}; - paramIndexFixture = 0; - }); + let result: unknown; - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & + beforeAll(() => { + decoratorFixture = Symbol() as unknown as MethodDecorator & ParameterDecorator & PropertyDecorator; + updateMetadataMock = jest.fn(); - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = multiInject(serviceIdentifierFixture)( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); + ( + buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< + typeof buildManagedMetadataFromMaybeClassElementMetadata + > + ).mockReturnValueOnce(updateMetadataMock); - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.multipleInjection, - serviceIdentifierFixture, - ); - }); + (injectBase as jest.Mock).mockReturnValueOnce(decoratorFixture); - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + result = multiInject(serviceIdentifierFixture); }); - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildManagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildManagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - multiInject(serviceIdentifierFixture)( - targetFixture, - undefined, - paramIndexFixture, - ); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildManagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith( - ClassElementMetadataKind.multipleInjection, - serviceIdentifierFixture, - ); - }); + afterAll(() => { + jest.clearAllMocks(); + }); - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); + it('should call buildManagedMetadataFromMaybeClassElementMetadata()', () => { + expect( + buildManagedMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledTimes(1); + expect( + buildManagedMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledWith( + ClassElementMetadataKind.multipleInjection, + serviceIdentifierFixture, + ); + }); - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - errorFixture, - ); - }); + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith( + updateMetadataMock, + decrementPendingClassMetadataCount, + ); + }); - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + it('should return expected result', () => { + expect(result).toBe(decoratorFixture); }); }); }); diff --git a/packages/container/libraries/core/src/metadata/decorators/multiInject.ts b/packages/container/libraries/core/src/metadata/decorators/multiInject.ts index 1828e521..b09c4a4d 100644 --- a/packages/container/libraries/core/src/metadata/decorators/multiInject.ts +++ b/packages/container/libraries/core/src/metadata/decorators/multiInject.ts @@ -2,7 +2,6 @@ import { LazyServiceIdentifier, ServiceIdentifier } from '@inversifyjs/common'; import { decrementPendingClassMetadataCount } from '../actions/decrementPendingClassMetadataCount'; import { buildManagedMetadataFromMaybeClassElementMetadata } from '../calculations/buildManagedMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ClassElementMetadata } from '../models/ClassElementMetadata'; import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; @@ -10,7 +9,7 @@ import { injectBase } from './injectBase'; export function multiInject( serviceIdentifier: ServiceIdentifier | LazyServiceIdentifier, -): ParameterDecorator & PropertyDecorator { +): MethodDecorator & ParameterDecorator & PropertyDecorator { const updateMetadata: ( classElementMetadata: MaybeClassElementMetadata | undefined, ) => ClassElementMetadata = buildManagedMetadataFromMaybeClassElementMetadata( @@ -18,26 +17,5 @@ export function multiInject( serviceIdentifier, ); - return ( - target: object, - propertyKey: string | symbol | undefined, - parameterIndex?: number, - ): void => { - try { - if (parameterIndex === undefined) { - injectBase(updateMetadata, decrementPendingClassMetadataCount)( - target, - propertyKey as string | symbol, - ); - } else { - injectBase(updateMetadata, decrementPendingClassMetadataCount)( - target, - propertyKey, - parameterIndex, - ); - } - } catch (error: unknown) { - handleInjectionError(target, propertyKey, parameterIndex, error); - } - }; + return injectBase(updateMetadata, decrementPendingClassMetadataCount); } diff --git a/packages/container/libraries/core/src/metadata/decorators/named.int.spec.ts b/packages/container/libraries/core/src/metadata/decorators/named.int.spec.ts index d50de105..9f1145a0 100644 --- a/packages/container/libraries/core/src/metadata/decorators/named.int.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/named.int.spec.ts @@ -21,12 +21,23 @@ describe(named.name, () => { @named('baz') public readonly baz!: string; + #someField!: string; + constructor( @named('firstParam') public firstParam: number, @named('secondParam') public secondParam: number, ) {} + + public get someField(): string { + return this.#someField; + } + + @named('someField') + public set someField(value: string) { + this.#someField = value; + } } result = getOwnReflectMetadata(Foo, classMetadataReflectKey); @@ -71,6 +82,15 @@ describe(named.name, () => { tags: new Map(), }, ], + [ + 'someField', + { + kind: MaybeClassElementMetadataKind.unknown, + name: 'someField', + optional: false, + tags: new Map(), + }, + ], ]), scope: undefined, }; diff --git a/packages/container/libraries/core/src/metadata/decorators/named.spec.ts b/packages/container/libraries/core/src/metadata/decorators/named.spec.ts index 350cee48..99cf452f 100644 --- a/packages/container/libraries/core/src/metadata/decorators/named.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/named.spec.ts @@ -1,16 +1,12 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; -jest.mock('../actions/updateMetadataName'); jest.mock( '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata', ); -jest.mock('../calculations/handleInjectionError'); jest.mock('./injectBase'); import { incrementPendingClassMetadataCount } from '../actions/incrementPendingClassMetadataCount'; -import { updateMetadataName } from '../actions/updateMetadataName'; import { buildMaybeClassElementMetadataFromMaybeClassElementMetadata } from '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; @@ -18,356 +14,64 @@ import { injectBase } from './injectBase'; import { named } from './named'; describe(named.name, () => { - let updateMetadataNameResultMock: jest.Mock< - ( - metadata: ManagedClassElementMetadata | MaybeManagedClassElementMetadata, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; + let nameFixture: string; beforeAll(() => { - updateMetadataNameResultMock = jest.fn(); - - ( - updateMetadataName as jest.Mock - ).mockReturnValue(updateMetadataNameResultMock); + nameFixture = 'name-fixture'; }); - describe('having a non undefined propertyKey and an undefined parameterIndex', () => { - let targetFixture: object; - let propertyKeyFixture: string | symbol; + describe('when called', () => { + let decoratorFixture: MethodDecorator & + ParameterDecorator & + PropertyDecorator; + let updateMetadataMock: jest.Mock< + ( + classElementMetadata: MaybeClassElementMetadata | undefined, + ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata + >; - beforeAll(() => { - targetFixture = class {}; - propertyKeyFixture = 'property-key'; - }); + let result: unknown; - describe('when called', () => { - let nameFixture: string; - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & + beforeAll(() => { + decoratorFixture = Symbol() as unknown as MethodDecorator & ParameterDecorator & PropertyDecorator; + updateMetadataMock = jest.fn(); - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - nameFixture = 'name-fixture'; - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = named(nameFixture)(targetFixture, propertyKeyFixture); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); + ( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< + typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata + > + ).mockReturnValueOnce(updateMetadataMock); - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - ); - }); + (injectBase as jest.Mock).mockReturnValueOnce(decoratorFixture); - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + result = named(nameFixture); }); - describe('when called, and injectBase throws an Error', () => { - let nameFixture: string; - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - nameFixture = 'name-fixture'; - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - named(nameFixture)(targetFixture, propertyKeyFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - undefined, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + afterAll(() => { + jest.clearAllMocks(); }); - }); - - describe('having an undefined propertyKey and an non undefined parameterIndex', () => { - let targetFixture: object; - let paramIndexFixture: number; - beforeAll(() => { - targetFixture = class {}; - paramIndexFixture = 0; + it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledTimes(1); + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledWith(expect.any(Function)); }); - describe('when called', () => { - let nameFixture: string; - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - nameFixture = 'name-fixture'; - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = named(nameFixture)( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith( + updateMetadataMock, + incrementPendingClassMetadataCount, + ); }); - describe('when called, and injectBase throws an Error', () => { - let nameFixture: string; - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - nameFixture = 'name-fixture'; - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - named(nameFixture)(targetFixture, undefined, paramIndexFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + it('should return expected result', () => { + expect(result).toBe(decoratorFixture); }); }); }); diff --git a/packages/container/libraries/core/src/metadata/decorators/named.ts b/packages/container/libraries/core/src/metadata/decorators/named.ts index f49eb546..e5d96049 100644 --- a/packages/container/libraries/core/src/metadata/decorators/named.ts +++ b/packages/container/libraries/core/src/metadata/decorators/named.ts @@ -1,7 +1,6 @@ import { incrementPendingClassMetadataCount } from '../actions/incrementPendingClassMetadataCount'; import { updateMetadataName } from '../actions/updateMetadataName'; import { buildMaybeClassElementMetadataFromMaybeClassElementMetadata } from '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; @@ -10,7 +9,7 @@ import { injectBase } from './injectBase'; export function named( name: MetadataName, -): ParameterDecorator & PropertyDecorator { +): MethodDecorator & ParameterDecorator & PropertyDecorator { const updateMetadata: ( metadata: MaybeClassElementMetadata | undefined, ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata = @@ -18,26 +17,5 @@ export function named( updateMetadataName(name), ); - return ( - target: object, - propertyKey: string | symbol | undefined, - parameterIndex?: number, - ): void => { - try { - if (parameterIndex === undefined) { - injectBase(updateMetadata, incrementPendingClassMetadataCount)( - target, - propertyKey as string | symbol, - ); - } else { - injectBase(updateMetadata, incrementPendingClassMetadataCount)( - target, - propertyKey, - parameterIndex, - ); - } - } catch (error: unknown) { - handleInjectionError(target, propertyKey, parameterIndex, error); - } - }; + return injectBase(updateMetadata, incrementPendingClassMetadataCount); } diff --git a/packages/container/libraries/core/src/metadata/decorators/optional.int.spec.ts b/packages/container/libraries/core/src/metadata/decorators/optional.int.spec.ts index 86d0a0f3..a4609c0d 100644 --- a/packages/container/libraries/core/src/metadata/decorators/optional.int.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/optional.int.spec.ts @@ -21,12 +21,23 @@ describe(optional.name, () => { @optional() public readonly baz!: string; + #someField!: string; + constructor( @optional() public firstParam: number, @optional() public secondParam: number, ) {} + + public get someField(): string { + return this.#someField; + } + + @optional() + public set someField(value: string) { + this.#someField = value; + } } result = getOwnReflectMetadata(Foo, classMetadataReflectKey); @@ -71,6 +82,15 @@ describe(optional.name, () => { tags: new Map(), }, ], + [ + 'someField', + { + kind: MaybeClassElementMetadataKind.unknown, + name: undefined, + optional: true, + tags: new Map(), + }, + ], ]), scope: undefined, }; diff --git a/packages/container/libraries/core/src/metadata/decorators/optional.spec.ts b/packages/container/libraries/core/src/metadata/decorators/optional.spec.ts index 9854837a..63363409 100644 --- a/packages/container/libraries/core/src/metadata/decorators/optional.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/optional.spec.ts @@ -1,16 +1,12 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; -jest.mock('../actions/updateMetadataOptional'); jest.mock( '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata', ); -jest.mock('../calculations/handleInjectionError'); jest.mock('./injectBase'); import { incrementPendingClassMetadataCount } from '../actions/incrementPendingClassMetadataCount'; -import { updateMetadataOptional } from '../actions/updateMetadataOptional'; import { buildMaybeClassElementMetadataFromMaybeClassElementMetadata } from '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; @@ -18,330 +14,58 @@ import { injectBase } from './injectBase'; import { optional } from './optional'; describe(optional.name, () => { - describe('having a non undefined propertyKey and an undefined parameterIndex', () => { - let targetFixture: object; - let propertyKeyFixture: string | symbol; + describe('when called', () => { + let decoratorFixture: MethodDecorator & + ParameterDecorator & + PropertyDecorator; + let updateMetadataMock: jest.Mock< + ( + classElementMetadata: MaybeClassElementMetadata | undefined, + ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata + >; + + let result: unknown; beforeAll(() => { - targetFixture = class {}; - propertyKeyFixture = 'property-key'; - }); - - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & + decoratorFixture = Symbol() as unknown as MethodDecorator & ParameterDecorator & PropertyDecorator; + updateMetadataMock = jest.fn(); - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); + ( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< + typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata + > + ).mockReturnValueOnce(updateMetadataMock); - result = optional()(targetFixture, propertyKeyFixture); - }); + (injectBase as jest.Mock).mockReturnValueOnce(decoratorFixture); - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(updateMetadataOptional); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + result = optional(); }); - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - optional()(targetFixture, propertyKeyFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(updateMetadataOptional); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - undefined, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + afterAll(() => { + jest.clearAllMocks(); }); - }); - - describe('having an undefined propertyKey and an non undefined parameterIndex', () => { - let targetFixture: object; - let paramIndexFixture: number; - beforeAll(() => { - targetFixture = class {}; - paramIndexFixture = 0; + it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledTimes(1); + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledWith(expect.any(Function)); }); - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = optional()(targetFixture, undefined, paramIndexFixture); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(updateMetadataOptional); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith( + updateMetadataMock, + incrementPendingClassMetadataCount, + ); }); - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - optional()(targetFixture, undefined, paramIndexFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(updateMetadataOptional); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + it('should return expected result', () => { + expect(result).toBe(decoratorFixture); }); }); }); diff --git a/packages/container/libraries/core/src/metadata/decorators/optional.ts b/packages/container/libraries/core/src/metadata/decorators/optional.ts index cdf5c2e2..bfaa99be 100644 --- a/packages/container/libraries/core/src/metadata/decorators/optional.ts +++ b/packages/container/libraries/core/src/metadata/decorators/optional.ts @@ -1,13 +1,14 @@ import { incrementPendingClassMetadataCount } from '../actions/incrementPendingClassMetadataCount'; import { updateMetadataOptional } from '../actions/updateMetadataOptional'; import { buildMaybeClassElementMetadataFromMaybeClassElementMetadata } from '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; import { injectBase } from './injectBase'; -export function optional(): ParameterDecorator & PropertyDecorator { +export function optional(): MethodDecorator & + ParameterDecorator & + PropertyDecorator { const updateMetadata: ( metadata: MaybeClassElementMetadata | undefined, ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata = @@ -15,26 +16,5 @@ export function optional(): ParameterDecorator & PropertyDecorator { updateMetadataOptional, ); - return ( - target: object, - propertyKey: string | symbol | undefined, - parameterIndex?: number, - ): void => { - try { - if (parameterIndex === undefined) { - injectBase(updateMetadata, incrementPendingClassMetadataCount)( - target, - propertyKey as string | symbol, - ); - } else { - injectBase(updateMetadata, incrementPendingClassMetadataCount)( - target, - propertyKey, - parameterIndex, - ); - } - } catch (error: unknown) { - handleInjectionError(target, propertyKey, parameterIndex, error); - } - }; + return injectBase(updateMetadata, incrementPendingClassMetadataCount); } diff --git a/packages/container/libraries/core/src/metadata/decorators/tagged.int.spec.ts b/packages/container/libraries/core/src/metadata/decorators/tagged.int.spec.ts index 7a3b68ff..703704ee 100644 --- a/packages/container/libraries/core/src/metadata/decorators/tagged.int.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/tagged.int.spec.ts @@ -21,12 +21,23 @@ describe(tagged.name, () => { @tagged('baz', 'baz-value') public readonly baz!: string; + #someField!: string; + constructor( @tagged('firstParam', 'firstParam-value') public firstParam: number, @tagged('secondParam', 'secondParam-value') public secondParam: number, ) {} + + public get someField(): string { + return this.#someField; + } + + @tagged('someField', 'some-field-value') + public set someField(value: string) { + this.#someField = value; + } } result = getOwnReflectMetadata(Foo, classMetadataReflectKey); @@ -71,6 +82,15 @@ describe(tagged.name, () => { tags: new Map([['baz', 'baz-value']]), }, ], + [ + 'someField', + { + kind: MaybeClassElementMetadataKind.unknown, + name: undefined, + optional: false, + tags: new Map([['someField', 'some-field-value']]), + }, + ], ]), scope: undefined, }; diff --git a/packages/container/libraries/core/src/metadata/decorators/tagged.spec.ts b/packages/container/libraries/core/src/metadata/decorators/tagged.spec.ts index 8f587cc4..74894fd8 100644 --- a/packages/container/libraries/core/src/metadata/decorators/tagged.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/tagged.spec.ts @@ -1,389 +1,79 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; -jest.mock('../actions/updateMetadataName'); jest.mock( '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata', ); -jest.mock('../calculations/handleInjectionError'); jest.mock('./injectBase'); import { incrementPendingClassMetadataCount } from '../actions/incrementPendingClassMetadataCount'; -import { updateMetadataName } from '../actions/updateMetadataName'; import { buildMaybeClassElementMetadataFromMaybeClassElementMetadata } from '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; -import { MetadataTag } from '../models/MetadataTag'; import { injectBase } from './injectBase'; import { tagged } from './tagged'; describe(tagged.name, () => { - let updateMetadataNameResultMock: jest.Mock< - ( - metadata: ManagedClassElementMetadata | MaybeManagedClassElementMetadata, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; + let keyFixture: string; + let valueFixture: unknown; beforeAll(() => { - updateMetadataNameResultMock = jest.fn(); - - ( - updateMetadataName as jest.Mock - ).mockReturnValue(updateMetadataNameResultMock); + keyFixture = 'key-fixture'; + valueFixture = 'value-fixture'; }); - describe('having a non undefined propertyKey and an undefined parameterIndex', () => { - let targetFixture: object; - let propertyKeyFixture: string | symbol; + describe('when called', () => { + let decoratorFixture: MethodDecorator & + ParameterDecorator & + PropertyDecorator; + let updateMetadataMock: jest.Mock< + ( + classElementMetadata: MaybeClassElementMetadata | undefined, + ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata + >; - beforeAll(() => { - targetFixture = class {}; - propertyKeyFixture = 'property-key'; - }); + let result: unknown; - describe('when called', () => { - let keyFixture: MetadataTag; - let valueFixture: unknown; - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & + beforeAll(() => { + decoratorFixture = Symbol() as unknown as MethodDecorator & ParameterDecorator & PropertyDecorator; + updateMetadataMock = jest.fn(); - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - keyFixture = 'tag-fixture'; - valueFixture = Symbol(); - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = tagged(keyFixture, valueFixture)( - targetFixture, - propertyKeyFixture, - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); + ( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< + typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata + > + ).mockReturnValueOnce(updateMetadataMock); - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - ); - }); + (injectBase as jest.Mock).mockReturnValueOnce(decoratorFixture); - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + result = tagged(keyFixture, valueFixture); }); - describe('when called, and injectBase throws an Error', () => { - let keyFixture: MetadataTag; - let valueFixture: unknown; - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - keyFixture = 'tag-fixture'; - valueFixture = Symbol(); - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - tagged(keyFixture, valueFixture)(targetFixture, propertyKeyFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - undefined, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + afterAll(() => { + jest.clearAllMocks(); }); - }); - - describe('having an undefined propertyKey and an non undefined parameterIndex', () => { - let targetFixture: object; - let paramIndexFixture: number; - beforeAll(() => { - targetFixture = class {}; - paramIndexFixture = 0; + it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledTimes(1); + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledWith(expect.any(Function)); }); - describe('when called', () => { - let keyFixture: MetadataTag; - let valueFixture: unknown; - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - keyFixture = 'name-fixture'; - valueFixture = Symbol(); - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = tagged(keyFixture, valueFixture)( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith( + updateMetadataMock, + incrementPendingClassMetadataCount, + ); }); - describe('when called, and injectBase throws an Error', () => { - let keyFixture: MetadataTag; - let valueFixture: unknown; - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - keyFixture = 'tag-fixture'; - valueFixture = Symbol(); - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildMaybeClassElementMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - tagged(keyFixture, valueFixture)( - targetFixture, - undefined, - paramIndexFixture, - ); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildMaybeClassElementMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(expect.any(Function)); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - incrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + it('should return expected result', () => { + expect(result).toBe(decoratorFixture); }); }); }); diff --git a/packages/container/libraries/core/src/metadata/decorators/tagged.ts b/packages/container/libraries/core/src/metadata/decorators/tagged.ts index 083969cf..217142c5 100644 --- a/packages/container/libraries/core/src/metadata/decorators/tagged.ts +++ b/packages/container/libraries/core/src/metadata/decorators/tagged.ts @@ -1,7 +1,6 @@ import { incrementPendingClassMetadataCount } from '../actions/incrementPendingClassMetadataCount'; import { updateMetadataTag } from '../actions/updateMetadataTag'; import { buildMaybeClassElementMetadataFromMaybeClassElementMetadata } from '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; @@ -11,7 +10,7 @@ import { injectBase } from './injectBase'; export function tagged( key: MetadataTag, value: unknown, -): ParameterDecorator & PropertyDecorator { +): MethodDecorator & ParameterDecorator & PropertyDecorator { const updateMetadata: ( metadata: MaybeClassElementMetadata | undefined, ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata = @@ -19,26 +18,5 @@ export function tagged( updateMetadataTag(key, value), ); - return ( - target: object, - propertyKey: string | symbol | undefined, - parameterIndex?: number, - ): void => { - try { - if (parameterIndex === undefined) { - injectBase(updateMetadata, incrementPendingClassMetadataCount)( - target, - propertyKey as string | symbol, - ); - } else { - injectBase(updateMetadata, incrementPendingClassMetadataCount)( - target, - propertyKey, - parameterIndex, - ); - } - } catch (error: unknown) { - handleInjectionError(target, propertyKey, parameterIndex, error); - } - }; + return injectBase(updateMetadata, incrementPendingClassMetadataCount); } diff --git a/packages/container/libraries/core/src/metadata/decorators/unmanaged.int.spec.ts b/packages/container/libraries/core/src/metadata/decorators/unmanaged.int.spec.ts index 2ad4c3a2..81e65929 100644 --- a/packages/container/libraries/core/src/metadata/decorators/unmanaged.int.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/unmanaged.int.spec.ts @@ -21,12 +21,23 @@ describe(unmanaged.name, () => { @unmanaged() public readonly baz!: string; + #someField!: string; + constructor( @unmanaged() public firstParam: number, @unmanaged() public secondParam: number, ) {} + + public get someField(): string { + return this.#someField; + } + + @unmanaged() + public set someField(value: string) { + this.#someField = value; + } } result = getOwnReflectMetadata(Foo, classMetadataReflectKey); @@ -59,6 +70,12 @@ describe(unmanaged.name, () => { kind: ClassElementMetadataKind.unmanaged, }, ], + [ + 'someField', + { + kind: ClassElementMetadataKind.unmanaged, + }, + ], ]), scope: undefined, }; diff --git a/packages/container/libraries/core/src/metadata/decorators/unmanaged.spec.ts b/packages/container/libraries/core/src/metadata/decorators/unmanaged.spec.ts index 576131a9..8c49617f 100644 --- a/packages/container/libraries/core/src/metadata/decorators/unmanaged.spec.ts +++ b/packages/container/libraries/core/src/metadata/decorators/unmanaged.spec.ts @@ -3,342 +3,68 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; jest.mock( '../calculations/buildUnmanagedMetadataFromMaybeClassElementMetadata', ); -jest.mock('../calculations/handleInjectionError'); jest.mock('./injectBase'); import { decrementPendingClassMetadataCount } from '../actions/decrementPendingClassMetadataCount'; import { buildUnmanagedMetadataFromMaybeClassElementMetadata } from '../calculations/buildUnmanagedMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ClassElementMetadata } from '../models/ClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { injectBase } from './injectBase'; import { unmanaged } from './unmanaged'; describe(unmanaged.name, () => { - describe('having a non undefined propertyKey and an undefined parameterIndex', () => { - let targetFixture: object; - let propertyKeyFixture: string | symbol; + describe('when called', () => { + let decoratorFixture: MethodDecorator & + ParameterDecorator & + PropertyDecorator; + let updateMetadataMock: jest.Mock< + ( + classElementMetadata: MaybeClassElementMetadata | undefined, + ) => ClassElementMetadata + >; + + let result: unknown; beforeAll(() => { - targetFixture = class {}; - propertyKeyFixture = 'property-key'; - }); - - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & + decoratorFixture = Symbol() as unknown as MethodDecorator & ParameterDecorator & PropertyDecorator; + updateMetadataMock = jest.fn(); - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildUnmanagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildUnmanagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); + ( + buildUnmanagedMetadataFromMaybeClassElementMetadata as jest.Mock< + typeof buildUnmanagedMetadataFromMaybeClassElementMetadata + > + ).mockReturnValueOnce(updateMetadataMock); - result = unmanaged()(targetFixture, propertyKeyFixture); - }); + (injectBase as jest.Mock).mockReturnValueOnce(decoratorFixture); - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildUnmanagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + result = unmanaged(); }); - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildUnmanagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildUnmanagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - unmanaged()(targetFixture, propertyKeyFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildUnmanagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - propertyKeyFixture, - undefined, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + afterAll(() => { + jest.clearAllMocks(); }); - }); - - describe('having an undefined propertyKey and an non undefined parameterIndex', () => { - let targetFixture: object; - let paramIndexFixture: number; - beforeAll(() => { - targetFixture = class {}; - paramIndexFixture = 0; + it('should call buildUnmanagedMetadataFromMaybeClassElementMetadata()', () => { + expect( + buildUnmanagedMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledTimes(1); + expect( + buildUnmanagedMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledWith(); }); - describe('when called', () => { - let injectBaseDecoratorMock: jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - injectBaseDecoratorMock = jest.fn() as jest.Mock< - ParameterDecorator & PropertyDecorator - > & - ParameterDecorator & - PropertyDecorator; - - updateMetadataMock = jest.fn(); - - ( - buildUnmanagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildUnmanagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockReturnValueOnce( - injectBaseDecoratorMock, - ); - - result = unmanaged()(targetFixture, undefined, paramIndexFixture); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildUnmanagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should call injectBaseDecorator()', () => { - expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); - expect(injectBaseDecoratorMock).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - ); - }); - - it('should return undefined', () => { - expect(result).toBeUndefined(); - }); + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith( + updateMetadataMock, + decrementPendingClassMetadataCount, + ); }); - describe('when called, and injectBase throws an Error', () => { - let errorFixture: Error; - let updateMetadataMock: jest.Mock< - ( - classElementMetadata: MaybeClassElementMetadata | undefined, - ) => ClassElementMetadata - >; - - let result: unknown; - - beforeAll(() => { - errorFixture = new Error('message-error-fixture'); - updateMetadataMock = jest.fn(); - - ( - buildUnmanagedMetadataFromMaybeClassElementMetadata as jest.Mock< - typeof buildUnmanagedMetadataFromMaybeClassElementMetadata - > - ).mockReturnValueOnce(updateMetadataMock); - - (injectBase as jest.Mock).mockImplementation( - (): never => { - throw errorFixture; - }, - ); - - ( - handleInjectionError as jest.Mock - ).mockImplementation( - ( - _target: unknown, - _propertyKey: unknown, - _parameterIndex: unknown, - error: unknown, - ): never => { - throw error; - }, - ); - - try { - unmanaged()(targetFixture, undefined, paramIndexFixture); - } catch (error: unknown) { - result = error; - } - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should call buildUnmanagedMetadataFromMaybeClassElementMetadata()', () => { - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledTimes(1); - expect( - buildUnmanagedMetadataFromMaybeClassElementMetadata, - ).toHaveBeenCalledWith(); - }); - - it('should call injectBase()', () => { - expect(injectBase).toHaveBeenCalledTimes(1); - expect(injectBase).toHaveBeenCalledWith( - updateMetadataMock, - decrementPendingClassMetadataCount, - ); - }); - - it('should throw handleInjectionError()', () => { - expect(handleInjectionError).toHaveBeenCalledTimes(1); - expect(handleInjectionError).toHaveBeenCalledWith( - targetFixture, - undefined, - paramIndexFixture, - errorFixture, - ); - }); - - it('should throw an Error', () => { - expect(result).toBe(errorFixture); - }); + it('should return expected result', () => { + expect(result).toBe(decoratorFixture); }); }); }); diff --git a/packages/container/libraries/core/src/metadata/decorators/unmanaged.ts b/packages/container/libraries/core/src/metadata/decorators/unmanaged.ts index ba2cf0c9..732a85ef 100644 --- a/packages/container/libraries/core/src/metadata/decorators/unmanaged.ts +++ b/packages/container/libraries/core/src/metadata/decorators/unmanaged.ts @@ -1,36 +1,16 @@ import { decrementPendingClassMetadataCount } from '../actions/decrementPendingClassMetadataCount'; import { buildUnmanagedMetadataFromMaybeClassElementMetadata } from '../calculations/buildUnmanagedMetadataFromMaybeClassElementMetadata'; -import { handleInjectionError } from '../calculations/handleInjectionError'; import { ClassElementMetadata } from '../models/ClassElementMetadata'; import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; import { injectBase } from './injectBase'; -export function unmanaged(): ParameterDecorator & PropertyDecorator { +export function unmanaged(): MethodDecorator & + ParameterDecorator & + PropertyDecorator { const updateMetadata: ( classElementMetadata: MaybeClassElementMetadata | undefined, ) => ClassElementMetadata = buildUnmanagedMetadataFromMaybeClassElementMetadata(); - return ( - target: object, - propertyKey: string | symbol | undefined, - parameterIndex?: number, - ): void => { - try { - if (parameterIndex === undefined) { - injectBase(updateMetadata, decrementPendingClassMetadataCount)( - target, - propertyKey as string | symbol, - ); - } else { - injectBase(updateMetadata, decrementPendingClassMetadataCount)( - target, - propertyKey, - parameterIndex, - ); - } - } catch (error: unknown) { - handleInjectionError(target, propertyKey, parameterIndex, error); - } - }; + return injectBase(updateMetadata, decrementPendingClassMetadataCount); }