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] 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; +}