Skip to content

Commit

Permalink
Merge pull request #109 from inversify/refactor/add-tagged-decorator
Browse files Browse the repository at this point in the history
Add tagged decorator
  • Loading branch information
notaphplover authored Nov 17, 2024
2 parents 740056d + 0be9665 commit 4e6b574
Show file tree
Hide file tree
Showing 5 changed files with 619 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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 { updateMetadataTag } from './updateMetadataTag';

describe(updateMetadataTag.name, () => {
describe('having metadata with missing tag', () => {
let metadataFixture:
| ManagedClassElementMetadata
| MaybeManagedClassElementMetadata;
let keyFixture: MetadataTag;
let valueFixture: unknown;

beforeAll(() => {
metadataFixture = {
kind: ClassElementMetadataKind.singleInjection,
name: undefined,
optional: false,
tags: new Map(),
targetName: undefined,
value: 'service-id',
};
keyFixture = 'tag-fixture';
valueFixture = Symbol();
});

describe('when called', () => {
let result: unknown;

beforeAll(() => {
result = updateMetadataTag(keyFixture, valueFixture)(metadataFixture);
});

it('should return metadata', () => {
const expected:
| ManagedClassElementMetadata
| MaybeManagedClassElementMetadata = {
...metadataFixture,
tags: new Map([[keyFixture, valueFixture]]),
};

expect(result).toStrictEqual(expected);
});
});
});

describe('having metadata with existing tag', () => {
let metadataFixture:
| ManagedClassElementMetadata
| MaybeManagedClassElementMetadata;
let keyFixture: MetadataTag;
let valueFixture: unknown;

beforeAll(() => {
metadataFixture = {
kind: ClassElementMetadataKind.singleInjection,
name: undefined,
optional: false,
tags: new Map([['tag-fixture', Symbol()]]),
targetName: undefined,
value: 'service-id',
};
keyFixture = 'tag-fixture';
valueFixture = Symbol();
});

describe('when called', () => {
let result: unknown;

beforeAll(() => {
try {
updateMetadataTag(keyFixture, valueFixture)(metadataFixture);
} catch (error: unknown) {
result = error;
}
});

it('should throw InversifyCoreError', () => {
const expectedErrorProperties: Partial<InversifyCoreError> = {
kind: InversifyCoreErrorKind.injectionDecoratorConflict,
message: 'Unexpected duplicated tag decorator with existing tag',
};

expect(result).toBeInstanceOf(InversifyCoreError);
expect(result).toStrictEqual(
expect.objectContaining(expectedErrorProperties),
);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { InversifyCoreError } from '../../error/models/InversifyCoreError';
import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind';
import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetadata';
import { MaybeManagedClassElementMetadata } from '../models/MaybeManagedClassElementMetadata';
import { MetadataTag } from '../models/MetadataTag';

export function updateMetadataTag(
key: MetadataTag,
value: unknown,
): (
metadata: ManagedClassElementMetadata | MaybeManagedClassElementMetadata,
) => ManagedClassElementMetadata | MaybeManagedClassElementMetadata {
return (
metadata: ManagedClassElementMetadata | MaybeManagedClassElementMetadata,
): ManagedClassElementMetadata | MaybeManagedClassElementMetadata => {
if (metadata.tags.has(key)) {
throw new InversifyCoreError(
InversifyCoreErrorKind.injectionDecoratorConflict,
'Unexpected duplicated tag decorator with existing tag',
);
}

metadata.tags.set(key, value);

return metadata;
};
}
Original file line number Diff line number Diff line change
@@ -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 { tagged } from './tagged';

describe(tagged.name, () => {
describe('when called', () => {
let result: unknown;

beforeAll(() => {
class Foo {
@tagged('bar', 'bar-value')
public readonly bar!: string;

@tagged('baz', 'baz-value')
public readonly baz!: string;

constructor(
@tagged('firstParam', 'firstParam-value')
public firstParam: number,
@tagged('secondParam', 'secondParam-value')
public secondParam: number,
) {}
}

result = getReflectMetadata(Foo, classMetadataReflectKey);
});

it('should return expected metadata', () => {
const expected: MaybeClassMetadata = {
constructorArguments: [
{
kind: MaybeClassElementMetadataKind.unknown,
name: undefined,
optional: false,
tags: new Map([['firstParam', 'firstParam-value']]),
targetName: undefined,
},
{
kind: MaybeClassElementMetadataKind.unknown,
name: undefined,
optional: false,
tags: new Map([['secondParam', 'secondParam-value']]),
targetName: undefined,
},
],
lifecycle: {
postConstructMethodName: undefined,
preDestroyMethodName: undefined,
},
properties: new Map([
[
'bar',
{
kind: MaybeClassElementMetadataKind.unknown,
name: undefined,
optional: false,
tags: new Map([['bar', 'bar-value']]),
targetName: undefined,
},
],
[
'baz',
{
kind: MaybeClassElementMetadataKind.unknown,
name: undefined,
optional: false,
tags: new Map([['baz', 'baz-value']]),
targetName: undefined,
},
],
]),
};

expect(result).toStrictEqual(expected);
});
});
});
Loading

0 comments on commit 4e6b574

Please sign in to comment.