From 1434fb00b8923c6b3f9cb6e12a15a354029b341b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Pintos=20L=C3=B3pez?= Date: Sat, 16 Nov 2024 17:54:01 +0100 Subject: [PATCH 1/3] refactor(core): add buildDefaultMaybeClassElementMetadata --- ...ldDefaultMaybeClassElementMetadata.spec.ts | 27 +++++++++++++++++++ .../buildDefaultMaybeClassElementMetadata.ts | 12 +++++++++ 2 files changed, 39 insertions(+) create mode 100644 packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.spec.ts create mode 100644 packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.ts diff --git a/packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.spec.ts b/packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.spec.ts new file mode 100644 index 00000000..9a4ac70d --- /dev/null +++ b/packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.spec.ts @@ -0,0 +1,27 @@ +import { beforeAll, describe, expect, it } from '@jest/globals'; + +import { MaybeClassElementMetadataKind } from '../models/MaybeClassElementMetadataKind'; +import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; +import { buildDefaultMaybeClassElementMetadata } from './buildDefaultMaybeClassElementMetadata'; + +describe(buildDefaultMaybeClassElementMetadata.name, () => { + describe('when called', () => { + let result: unknown; + + beforeAll(() => { + result = buildDefaultMaybeClassElementMetadata(); + }); + + it('should return MaybeManagedClassElementMetadata', () => { + const expected: MaybeManagedClassElementMetadata = { + kind: MaybeClassElementMetadataKind.unknown, + name: undefined, + optional: false, + tags: new Map(), + targetName: undefined, + }; + + expect(result).toStrictEqual(expected); + }); + }); +}); diff --git a/packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.ts b/packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.ts new file mode 100644 index 00000000..345c7c9e --- /dev/null +++ b/packages/container/libraries/core/src/metadata/calculations/buildDefaultMaybeClassElementMetadata.ts @@ -0,0 +1,12 @@ +import { MaybeClassElementMetadataKind } from '../models/MaybeClassElementMetadataKind'; +import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; + +export function buildDefaultMaybeClassElementMetadata(): MaybeManagedClassElementMetadata { + return { + kind: MaybeClassElementMetadataKind.unknown, + name: undefined, + optional: false, + tags: new Map(), + targetName: undefined, + }; +} From 4dfff5a75b85c2186fe4cbd3fdcaf0fc18906028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Pintos=20L=C3=B3pez?= Date: Sat, 16 Nov 2024 17:54:13 +0100 Subject: [PATCH 2/3] refactor(core): add buildMaybeClassElementMetadataFromMaybeClassElementMetadata --- ...adataFromMaybeClassElementMetadata.spec.ts | 143 ++++++++++++++++++ ...ntMetadataFromMaybeClassElementMetadata.ts | 48 ++++++ 2 files changed, 191 insertions(+) create mode 100644 packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.spec.ts create mode 100644 packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.ts diff --git a/packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.spec.ts b/packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.spec.ts new file mode 100644 index 00000000..d7850b80 --- /dev/null +++ b/packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.spec.ts @@ -0,0 +1,143 @@ +import { beforeAll, describe, expect, it } from '@jest/globals'; + +import { InversifyCoreError } from '../../error/models/InversifyCoreError'; +import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind'; +import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind'; +import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; +import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; +import { MetadataTag } from '../models/MetadataTag'; +import { UnmanagedClassElementMetadata } from '../models/UnmanagedClassElementMetadata'; +import { buildMaybeClassElementMetadataFromMaybeClassElementMetadata } from './buildMaybeClassElementMetadataFromMaybeClassElementMetadata'; + +describe( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata.name, + () => { + describe('having unmanaged metadata', () => { + let metadataPartialFixture: Partial; + let metadataFixture: UnmanagedClassElementMetadata; + + beforeAll(() => { + metadataPartialFixture = {}; + metadataFixture = { + kind: ClassElementMetadataKind.unmanaged, + }; + }); + + describe('when called', () => { + let result: unknown; + + beforeAll(() => { + try { + buildMaybeClassElementMetadataFromMaybeClassElementMetadata( + metadataPartialFixture, + )(metadataFixture); + } catch (error: unknown) { + result = error; + } + }); + + it('should throw an InversifyCoreError', () => { + const expectedErrorProperties: Partial = { + kind: InversifyCoreErrorKind.injectionDecoratorConflict, + message: + 'Unexpected injection found. Found @unmanaged injection with additional @named, @optional, @tagged or @targetName injections', + }; + + expect(result).toBeInstanceOf(InversifyCoreError); + expect(result).toStrictEqual( + expect.objectContaining(expectedErrorProperties), + ); + }); + }); + }); + + describe('having non unmanaged metadata', () => { + let metadataPartialFixture: Partial; + let metadataFixture: ManagedClassElementMetadata; + + beforeAll(() => { + metadataPartialFixture = { + name: 'name-fixture', + optional: true, + targetName: 'target-name-fixture', + }; + metadataFixture = { + kind: ClassElementMetadataKind.singleInjection, + name: undefined, + optional: false, + tags: new Map([['foo', 'bar']]), + targetName: undefined, + value: 'service-identifier', + }; + }); + + describe('when called', () => { + let result: unknown; + + beforeAll(() => { + result = buildMaybeClassElementMetadataFromMaybeClassElementMetadata( + metadataPartialFixture, + )(metadataFixture); + }); + + it('should return ManagedClassElementMetadata', () => { + const expected: + | ManagedClassElementMetadata + | MaybeManagedClassElementMetadata = { + ...metadataFixture, + ...metadataPartialFixture, + }; + + expect(result).toStrictEqual(expected); + }); + }); + }); + + describe('having non unmanaged metadata and partial metadata with tags', () => { + let metadataPartialFixture: Partial; + let metadataFixture: ManagedClassElementMetadata; + + beforeAll(() => { + metadataPartialFixture = { + name: 'name-fixture', + optional: true, + tags: new Map([['bar', 'baz']]), + targetName: 'target-name-fixture', + }; + metadataFixture = { + kind: ClassElementMetadataKind.singleInjection, + name: undefined, + optional: false, + tags: new Map([['foo', 'bar']]), + targetName: undefined, + value: 'service-identifier', + }; + }); + + describe('when called', () => { + let result: unknown; + + beforeAll(() => { + result = buildMaybeClassElementMetadataFromMaybeClassElementMetadata( + metadataPartialFixture, + )(metadataFixture); + }); + + it('should return ManagedClassElementMetadata', () => { + const expected: + | ManagedClassElementMetadata + | MaybeManagedClassElementMetadata = { + ...metadataFixture, + ...metadataPartialFixture, + tags: new Map([ + ...metadataFixture.tags, + ...(metadataPartialFixture.tags as Map), + ]), + }; + + expect(result).toStrictEqual(expected); + }); + }); + }); + }, +); diff --git a/packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.ts b/packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.ts new file mode 100644 index 00000000..51908fea --- /dev/null +++ b/packages/container/libraries/core/src/metadata/calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata.ts @@ -0,0 +1,48 @@ +import { InversifyCoreError } from '../../error/models/InversifyCoreError'; +import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind'; +import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind'; +import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata'; +import { MaybeClassElementMetadata } from '../models/MaybeClassElementMetadata'; +import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata'; +import { buildDefaultMaybeClassElementMetadata } from './buildDefaultMaybeClassElementMetadata'; + +export function buildMaybeClassElementMetadataFromMaybeClassElementMetadata( + metadataPartial: Partial, +): ( + metadata: MaybeClassElementMetadata | undefined, +) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata { + return ( + metadata: MaybeClassElementMetadata | undefined, + ): ManagedClassElementMetadata | MaybeManagedClassElementMetadata => { + const definedMetadata: MaybeClassElementMetadata = + metadata ?? buildDefaultMaybeClassElementMetadata(); + + switch (definedMetadata.kind) { + case ClassElementMetadataKind.unmanaged: + throw new InversifyCoreError( + InversifyCoreErrorKind.injectionDecoratorConflict, + 'Unexpected injection found. Found @unmanaged injection with additional @named, @optional, @tagged or @targetName injections', + ); + default: + return buildMergedMetadata(definedMetadata, metadataPartial); + } + }; +} + +function buildMergedMetadata( + metadata: ManagedClassElementMetadata | MaybeManagedClassElementMetadata, + metadataPartial: Partial, +): ManagedClassElementMetadata | MaybeManagedClassElementMetadata { + const mergedMetadata: + | ManagedClassElementMetadata + | MaybeManagedClassElementMetadata = { + ...metadata, + ...metadataPartial, + }; + + if (metadataPartial.tags !== undefined) { + mergedMetadata.tags = new Map([...metadata.tags, ...metadataPartial.tags]); + } + + return mergedMetadata; +} From 4e6978d1c943ebb3cc2e8b65a4fbe0717d566d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Pintos=20L=C3=B3pez?= Date: Sat, 16 Nov 2024 17:54:38 +0100 Subject: [PATCH 3/3] refactor(core): add named decorator --- .../src/metadata/decorators/named.int.spec.ts | 84 +++++ .../src/metadata/decorators/named.spec.ts | 344 ++++++++++++++++++ .../core/src/metadata/decorators/named.ts | 34 ++ 3 files changed, 462 insertions(+) create mode 100644 packages/container/libraries/core/src/metadata/decorators/named.int.spec.ts create mode 100644 packages/container/libraries/core/src/metadata/decorators/named.spec.ts create mode 100644 packages/container/libraries/core/src/metadata/decorators/named.ts 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 new file mode 100644 index 00000000..031f3dbc --- /dev/null +++ b/packages/container/libraries/core/src/metadata/decorators/named.int.spec.ts @@ -0,0 +1,84 @@ +import { beforeAll, describe, expect, it } from '@jest/globals'; + +import 'reflect-metadata'; + +import { getReflectMetadata } from '@inversifyjs/reflect-metadata-utils'; + +import { classMetadataReflectKey } from '../../reflectMetadata/data/classMetadataReflectKey'; +import { MaybeClassElementMetadataKind } from '../models/MaybeClassElementMetadataKind'; +import { MaybeClassMetadata } from '../models/MaybeClassMetadata'; +import { named } from './named'; + +describe(named.name, () => { + describe('when called', () => { + let result: unknown; + + beforeAll(() => { + class Foo { + @named('bar') + public readonly bar!: string; + + @named('baz') + public readonly baz!: string; + + constructor( + @named('firstParam') + public firstParam: number, + @named('secondParam') + public secondParam: number, + ) {} + } + + result = getReflectMetadata(Foo, classMetadataReflectKey); + }); + + it('should return expected metadata', () => { + const expected: MaybeClassMetadata = { + constructorArguments: [ + { + kind: MaybeClassElementMetadataKind.unknown, + name: 'firstParam', + optional: false, + tags: new Map(), + targetName: undefined, + }, + { + kind: MaybeClassElementMetadataKind.unknown, + name: 'secondParam', + optional: false, + tags: new Map(), + targetName: undefined, + }, + ], + lifecycle: { + postConstructMethodName: undefined, + preDestroyMethodName: undefined, + }, + properties: new Map([ + [ + 'bar', + { + kind: MaybeClassElementMetadataKind.unknown, + name: 'bar', + optional: false, + tags: new Map(), + targetName: undefined, + }, + ], + [ + 'baz', + { + kind: MaybeClassElementMetadataKind.unknown, + name: 'baz', + optional: false, + tags: new Map(), + targetName: undefined, + }, + ], + ]), + }; + + expect(result).toStrictEqual(expected); + }); + }); +}); diff --git a/packages/container/libraries/core/src/metadata/decorators/named.spec.ts b/packages/container/libraries/core/src/metadata/decorators/named.spec.ts new file mode 100644 index 00000000..b59ae056 --- /dev/null +++ b/packages/container/libraries/core/src/metadata/decorators/named.spec.ts @@ -0,0 +1,344 @@ +import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; + +jest.mock( + '../calculations/buildMaybeClassElementMetadataFromMaybeClassElementMetadata', +); +jest.mock('../calculations/handleInjectionError'); +jest.mock('./injectBase'); + +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'; +import { named } from './named'; + +describe(named.name, () => { + describe('having a non undefined propertyKey and an undefined parameterIndex', () => { + let targetFixture: object; + let propertyKeyFixture: string | symbol; + + beforeAll(() => { + targetFixture = class {}; + propertyKeyFixture = 'property-key'; + }); + + 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, propertyKeyFixture); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('should call buildMaybeClassElementMetadataFromMaybeClassElementMetadata()', () => { + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledTimes(1); + expect( + buildMaybeClassElementMetadataFromMaybeClassElementMetadata, + ).toHaveBeenCalledWith({ name: nameFixture }); + }); + + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith(updateMetadataMock); + }); + + 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 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: object, + _propertyKey: string | symbol | undefined, + _parameterIndex: number | undefined, + 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({ name: nameFixture }); + }); + + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith(updateMetadataMock); + }); + + it('should throw handleInjectionError()', () => { + expect(handleInjectionError).toHaveBeenCalledTimes(1); + expect(handleInjectionError).toHaveBeenCalledWith( + targetFixture, + propertyKeyFixture, + undefined, + errorFixture, + ); + }); + + it('should throw an Error', () => { + expect(result).toBe(errorFixture); + }); + }); + }); + + describe('having an undefined propertyKey and an non undefined parameterIndex', () => { + let targetFixture: object; + let paramIndexFixture: number; + + beforeAll(() => { + targetFixture = class {}; + paramIndexFixture = 0; + }); + + 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({ name: nameFixture }); + }); + + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith(updateMetadataMock); + }); + + it('should call injectBaseDecorator()', () => { + expect(injectBaseDecoratorMock).toHaveBeenCalledTimes(1); + expect(injectBaseDecoratorMock).toHaveBeenCalledWith( + targetFixture, + undefined, + paramIndexFixture, + ); + }); + + it('should return undefined', () => { + expect(result).toBeUndefined(); + }); + }); + + 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: object, + _propertyKey: string | symbol | undefined, + _parameterIndex: number | undefined, + 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({ name: nameFixture }); + }); + + it('should call injectBase()', () => { + expect(injectBase).toHaveBeenCalledTimes(1); + expect(injectBase).toHaveBeenCalledWith(updateMetadataMock); + }); + + it('should throw handleInjectionError()', () => { + expect(handleInjectionError).toHaveBeenCalledTimes(1); + expect(handleInjectionError).toHaveBeenCalledWith( + targetFixture, + undefined, + paramIndexFixture, + errorFixture, + ); + }); + + it('should throw an Error', () => { + expect(result).toBe(errorFixture); + }); + }); + }); +}); diff --git a/packages/container/libraries/core/src/metadata/decorators/named.ts b/packages/container/libraries/core/src/metadata/decorators/named.ts new file mode 100644 index 00000000..7980de2a --- /dev/null +++ b/packages/container/libraries/core/src/metadata/decorators/named.ts @@ -0,0 +1,34 @@ +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 { MetadataName } from '../models/MetadataName'; +import { injectBase } from './injectBase'; + +export function named( + name: MetadataName, +): ParameterDecorator & PropertyDecorator { + return ( + target: object, + propertyKey: string | symbol | undefined, + parameterIndex?: number, + ): void => { + const updateMetadata: ( + metadata: MaybeClassElementMetadata | undefined, + ) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata = + buildMaybeClassElementMetadataFromMaybeClassElementMetadata({ + name, + }); + + try { + if (parameterIndex === undefined) { + injectBase(updateMetadata)(target, propertyKey as string | symbol); + } else { + injectBase(updateMetadata)(target, propertyKey, parameterIndex); + } + } catch (error: unknown) { + handleInjectionError(target, propertyKey, parameterIndex, error); + } + }; +}