Skip to content

Commit

Permalink
feat(core): update ClassMetadata with lifecycle
Browse files Browse the repository at this point in the history
  • Loading branch information
notaphplover committed Oct 29, 2024
1 parent 62ffcc1 commit d7494d9
Show file tree
Hide file tree
Showing 11 changed files with 887 additions and 10 deletions.
2 changes: 2 additions & 0 deletions packages/container/libraries/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getClassMetadata } from './metadata/calculations/getClassMetadata';
import { ClassElementMetadata } from './metadata/models/ClassElementMetadata';
import { ClassElementMetadataKind } from './metadata/models/ClassElementMetadataKind';
import { ClassMetadata } from './metadata/models/ClassMetadata';
import { ClassMetadataLifecycle } from './metadata/models/ClassMetadataLifecycle';
import { ManagedClassElementMetadata } from './metadata/models/ManagedClassElementMetadata';
import { MetadataName } from './metadata/models/MetadataName';
import { MetadataTag } from './metadata/models/MetadataTag';
Expand All @@ -11,6 +12,7 @@ import { UnmanagedClassElementMetadata } from './metadata/models/UnmanagedClassE
export type {
ClassElementMetadata,
ClassMetadata,
ClassMetadataLifecycle,
ManagedClassElementMetadata,
MetadataName,
MetadataTag,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
import { beforeAll, describe, expect, it } from '@jest/globals';

import { ServiceIdentifier } from '@inversifyjs/common';

import {
INJECT_TAG,
MULTI_INJECT_TAG,
NAME_TAG,
NAMED_TAG,
OPTIONAL_TAG,
UNMANAGED_TAG,
} from '../../reflectMetadata/data/keys';
import { ClassElementMetadata } from '../models/ClassElementMetadata';
import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind';
import { LegacyMetadata } from '../models/LegacyMetadata';
import { MetadataName } from '../models/MetadataName';
import { MetadataTag } from '../models/MetadataTag';
import { MetadataTargetName } from '../models/MetadataTargetName';
import { getClassElementMetadataFromLegacyMetadata } from './getClassElementMetadataFromLegacyMetadata';

describe(getClassElementMetadataFromLegacyMetadata.name, () => {
describe('having an empty metadata list', () => {
let metadataListFixture: LegacyMetadata[];

beforeAll(() => {
metadataListFixture = [];
});

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

beforeAll(() => {
try {
getClassElementMetadataFromLegacyMetadata(metadataListFixture);
} catch (error: unknown) {
result = error;
}
});

it('should throw an Error', () => {
const expectedErrorProperties: Partial<Error> = {
message: 'Expected @inject, @multiInject or @unmanaged metadata',
};

expect(result).toBeInstanceOf(Error);
expect(result).toStrictEqual(
expect.objectContaining(expectedErrorProperties),
);
});
});
});

describe('having a metadata list with unmanaged metadata', () => {
let metadataListFixture: LegacyMetadata[];

beforeAll(() => {
metadataListFixture = [
{
key: UNMANAGED_TAG,
value: true,
},
];
});

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

beforeAll(() => {
result = getClassElementMetadataFromLegacyMetadata(metadataListFixture);
});

it('should return ClassElementMetadata', () => {
const expectedClassElementMetadata: ClassElementMetadata = {
kind: ClassElementMetadataKind.unmanaged,
};

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

describe.each<[string, LegacyMetadata]>([
[
'inject',
{
key: INJECT_TAG,
value: Symbol(),
},
],
[
'multi inject',
{
key: MULTI_INJECT_TAG,
value: Symbol(),
},
],
])(
'having a metadata list with both unmanaged and %s metadata',
(_: string, metadata: LegacyMetadata) => {
let metadataListFixture: LegacyMetadata[];

beforeAll(() => {
metadataListFixture = [
{
key: UNMANAGED_TAG,
value: true,
},
metadata,
];
});

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

beforeAll(() => {
try {
getClassElementMetadataFromLegacyMetadata(metadataListFixture);
} catch (error: unknown) {
result = error;
}
});

it('should throw an Error', () => {
const expectedErrorProperties: Partial<Error> = {
message:
'Expected a single @inject, @multiInject or @unmanaged metadata',
};

expect(result).toBeInstanceOf(Error);
expect(result).toStrictEqual(
expect.objectContaining(expectedErrorProperties),
);
});
});
},
);

describe.each<[string, ClassElementMetadataKind, LegacyMetadata]>([
[
'inject',
ClassElementMetadataKind.singleInjection,
{
key: INJECT_TAG,
value: Symbol(),
},
],
[
'multi inject',
ClassElementMetadataKind.multipleInjection,
{
key: MULTI_INJECT_TAG,
value: Symbol(),
},
],
])(
'having a metadata list with % metadata',
(
_: string,
classElementMetadataKind: ClassElementMetadataKind,
metadata: LegacyMetadata,
) => {
let metadataListFixture: LegacyMetadata[];

beforeAll(() => {
metadataListFixture = [metadata];
});

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

beforeAll(() => {
result =
getClassElementMetadataFromLegacyMetadata(metadataListFixture);
});

it('should return ClassElementMetadata', () => {
const expectedClassElementMetadata: ClassElementMetadata = {
kind: classElementMetadataKind,
name: undefined,
optional: false,
tags: new Map(),
targetName: undefined,
value: metadata.value as ServiceIdentifier,
};

expect(result).toStrictEqual(expectedClassElementMetadata);
});
});
},
);

describe.each<[string, ClassElementMetadataKind, LegacyMetadata]>([
[
'inject',
ClassElementMetadataKind.singleInjection,
{
key: INJECT_TAG,
value: Symbol(),
},
],
[
'multi inject',
ClassElementMetadataKind.multipleInjection,
{
key: MULTI_INJECT_TAG,
value: Symbol(),
},
],
])(
'having a metadata list with % metadata',
(
_: string,
classElementMetadataKind: ClassElementMetadataKind,
metadata: LegacyMetadata,
) => {
let customTagMetadataFixture: LegacyMetadata;
let nameMetadataFixture: LegacyMetadata;
let optionalMetadataFixture: LegacyMetadata;
let targetNameMetadataFixture: LegacyMetadata;
let metadataListFixture: LegacyMetadata[];

beforeAll(() => {
customTagMetadataFixture = {
key: 'customTag',
value: 'customTagValue',
};
nameMetadataFixture = {
key: NAME_TAG,
value: 'name-fixture',
};
optionalMetadataFixture = {
key: OPTIONAL_TAG,
value: true,
};
targetNameMetadataFixture = {
key: NAMED_TAG,
value: 'target-name-fixture',
};
metadataListFixture = [
metadata,
customTagMetadataFixture,
nameMetadataFixture,
optionalMetadataFixture,
targetNameMetadataFixture,
];
});

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

beforeAll(() => {
result =
getClassElementMetadataFromLegacyMetadata(metadataListFixture);
});

it('should return ClassElementMetadata', () => {
const expectedClassElementMetadata: ClassElementMetadata = {
kind: classElementMetadataKind,
name: nameMetadataFixture.value as MetadataName,
optional: true,
tags: new Map<MetadataTag, unknown>([
[
customTagMetadataFixture.key as MetadataTag,
customTagMetadataFixture.value,
],
]),
targetName: targetNameMetadataFixture.value as MetadataTargetName,
value: metadata.value as ServiceIdentifier,
};

expect(result).toStrictEqual(expectedClassElementMetadata);
});
});
},
);
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ServiceIdentifier } from '@inversifyjs/common';
import { LazyServiceIdentifier, ServiceIdentifier } from '@inversifyjs/common';

import {
INJECT_TAG,
Expand All @@ -16,6 +16,7 @@ import { ManagedClassElementMetadata } from '../models/ManagedClassElementMetada
import { MetadataName } from '../models/MetadataName';
import { MetadataTag } from '../models/MetadataTag';
import { MetadataTargetName } from '../models/MetadataTargetName';
import { UnmanagedClassElementMetadata } from '../models/UnmanagedClassElementMetadata';

export function getClassElementMetadataFromLegacyMetadata(
metadataList: LegacyMetadata[],
Expand All @@ -31,13 +32,14 @@ export function getClassElementMetadataFromLegacyMetadata(
);

if (unmanagedMetadata !== undefined) {
return {
kind: ClassElementMetadataKind.unmanaged,
};
return getUnmanagedClassElementMetadata(
injectMetadata,
multiInjectMetadata,
);
}

if (multiInjectMetadata === undefined && injectMetadata === undefined) {
throw new Error();
throw new Error('Expected @inject, @multiInject or @unmanaged metadata');
}

const nameMetadata: LegacyMetadata | undefined = metadataList.find(
Expand Down Expand Up @@ -74,9 +76,26 @@ export function getClassElementMetadataFromLegacyMetadata(
targetName: targetNameMetadata?.value as MetadataTargetName | undefined,
value:
injectMetadata === undefined
? (multiInjectMetadata?.value as ServiceIdentifier)
: (injectMetadata.value as ServiceIdentifier),
? (multiInjectMetadata?.value as
| ServiceIdentifier
| LazyServiceIdentifier)
: (injectMetadata.value as ServiceIdentifier | LazyServiceIdentifier),
};

return managedClassElementMetadata;
}

function getUnmanagedClassElementMetadata(
injectMetadata: LegacyMetadata | undefined,
multiInjectMetadata: LegacyMetadata | undefined,
): UnmanagedClassElementMetadata {
if (multiInjectMetadata !== undefined || injectMetadata !== undefined) {
throw new Error(
'Expected a single @inject, @multiInject or @unmanaged metadata',
);
}

return {
kind: ClassElementMetadataKind.unmanaged,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { beforeAll, describe, expect, it } from '@jest/globals';

import { Newable } from '@inversifyjs/common';

import { ClassElementMetadata } from '../models/ClassElementMetadata';
import { ClassElementMetadataKind } from '../models/ClassElementMetadataKind';
import { getClassElementMetadataFromNewable } from './getClassElementMetadataFromNewable';

describe(getClassElementMetadataFromNewable.name, () => {
describe('when called', () => {
let typeFixture: Newable;

let result: unknown;

beforeAll(() => {
typeFixture = class {};

result = getClassElementMetadataFromNewable(typeFixture);
});

it('should return ClassElementMetadata', () => {
const expected: ClassElementMetadata = {
kind: ClassElementMetadataKind.singleInjection,
name: undefined,
optional: false,
tags: new Map(),
targetName: undefined,
value: typeFixture,
};

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

0 comments on commit d7494d9

Please sign in to comment.