Skip to content

Commit

Permalink
refactor: update planing modules
Browse files Browse the repository at this point in the history
update interfaces to delegate @inversifyjs/core LegacyTarget
update planner modules to rely on @inversifyjs/core
update refelction_utils modules to rely on @inversifyjs/core
  • Loading branch information
notaphplover committed Nov 7, 2024
1 parent 3761eb2 commit b1e796d
Show file tree
Hide file tree
Showing 26 changed files with 497 additions and 816 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
- Updated `ServiceIdentifier` to rely on `Function` instead of `Abstract<T>`.
- `injectable` decorator is no longer required.

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ export { TYPES };
> **Note**: It is recommended to use Symbols but InversifyJS also support the usage of Classes and string literals (please refer to the features section to learn more).
### Step 2: Declare dependencies using the `@injectable` & `@inject` decorators
Let's continue by declaring some classes (concretions). The classes are implementations of the interfaces that we just declared. All the classes must be annotated with the `@injectable` decorator.
Let's continue by declaring some classes (concretions). The classes are implementations of the interfaces that we just declared. We will annotate them with the `@injectable` decorator.

When a class has a dependency on an interface we also need to use the `@inject` decorator to define an identifier for the interface that will be available at runtime. In this case we will use the Symbols `Symbol.for("Weapon")` and `Symbol.for("ThrowableWeapon")` as runtime identifiers.
When a class has a dependency on an interface we also need to use the `@inject` decorator to define an identifier for the interface that will be available at runtime. In this case we will use the Symbols `Symbol.for("Weapon")` and `Symbol.for("ThrowableWeapon")` as runtime identifiers.

```ts
// file entities.ts
Expand Down
37 changes: 36 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
},
"description": "A powerful and lightweight inversion of control container for JavaScript and Node.js apps powered by TypeScript.",
"dependencies": {
"@inversifyjs/common": "1.3.0"
"@inversifyjs/common": "1.3.0",
"@inversifyjs/core": "1.3.0"
},
"devDependencies": {
"@eslint/js": "9.13.0",
Expand Down
4 changes: 0 additions & 4 deletions src/constants/error_msgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@ export const NOT_REGISTERED: string =
'No matching bindings found for serviceIdentifier:';
export const MISSING_INJECTABLE_ANNOTATION: string =
'Missing required @injectable annotation in:';
export const MISSING_INJECT_ANNOTATION: string =
'Missing required @inject or @multiInject annotation in:';
export const UNDEFINED_INJECT_ANNOTATION: (name: string) => string = (
name: string,
) =>
`@inject called with undefined this could mean that the class ${name} has ` +
'a circular dependency problem. You can use a LazyServiceIdentifer to ' +
'overcome this limitation.';
export const CIRCULAR_DEPENDENCY: string = 'Circular dependency found:';
export const NOT_IMPLEMENTED: string =
'Sorry, this feature is not fully implemented yet.';
export const INVALID_BINDING_TYPE: string = 'Invalid binding type:';
export const NO_MORE_SNAPSHOTS_AVAILABLE: string =
'No snapshot available to restore.';
Expand Down
20 changes: 2 additions & 18 deletions src/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Newable as CommonNewable,
ServiceIdentifier as CommonServiceIdentifier,
} from '@inversifyjs/common';
import { LegacyTarget } from '@inversifyjs/core';

import { FactoryType } from '../utils/factory_type';

Expand Down Expand Up @@ -206,24 +207,7 @@ namespace interfaces {
): Request;
}

export interface Target {
id: number;
serviceIdentifier: ServiceIdentifier;
type: TargetType;
name: QueryableString;
identifier: string | symbol;
metadata: Metadata[];
getNamedTag(): interfaces.Metadata<string> | null;
getCustomTags(): interfaces.Metadata[] | null;
hasTag(key: string | number | symbol): boolean;
isArray(): boolean;
matchesArray(name: interfaces.ServiceIdentifier): boolean;
isNamed(): boolean;
isTagged(): boolean;
isOptional(): boolean;
matchesNamedTag(name: string): boolean;
matchesTag(key: string | number | symbol): (value: unknown) => boolean;
}
export type Target = LegacyTarget;

export interface ContainerOptions {
autoBindInjectable?: boolean;
Expand Down
6 changes: 3 additions & 3 deletions src/planning/metadata_reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ class MetadataReader implements interfaces.MetadataReader {
constructorFunc: NewableFunction,
): interfaces.ConstructorMetadata {
// TypeScript compiler generated annotations
const compilerGeneratedMetadata: NewableFunction[] | undefined =
Reflect.getMetadata(METADATA_KEY.PARAM_TYPES, constructorFunc) as
const compilerGeneratedMetadata: NewableFunction[] =
(Reflect.getMetadata(METADATA_KEY.DESIGN_PARAM_TYPES, constructorFunc) as
| NewableFunction[]
| undefined;
| undefined) ?? [];

// User generated constructor annotations
const userGeneratedMetadata: interfaces.MetadataMap | undefined =
Expand Down
72 changes: 55 additions & 17 deletions src/planning/planner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import {
ClassElementMetadataKind,
getClassElementMetadataFromLegacyMetadata,
LegacyTarget as Target,
LegacyTargetImpl as TargetImpl,
} from '@inversifyjs/core';
import { ClassElementMetadata } from '@inversifyjs/core';

import { BindingCount } from '../bindings/binding_count';
import * as ERROR_MSGS from '../constants/error_msgs';
import { BindingTypeEnum, TargetTypeEnum } from '../constants/literal_types';
import { BindingTypeEnum } from '../constants/literal_types';
import * as METADATA_KEY from '../constants/metadata_keys';
import { interfaces } from '../interfaces/interfaces';
import { isStackOverflowException } from '../utils/exceptions';
Expand All @@ -19,7 +27,6 @@ import {
getFunctionName,
} from './reflection_utils';
import { Request } from './request';
import { Target } from './target';

function getBindingDictionary(
cntnr: interfaces.Container,
Expand All @@ -39,22 +46,22 @@ function _createTarget(
key?: string | number | symbol,
value?: unknown,
): interfaces.Target {
const metadataKey: string = isMultiInject
? METADATA_KEY.MULTI_INJECT_TAG
: METADATA_KEY.INJECT_TAG;
const injectMetadata: Metadata = new Metadata(metadataKey, serviceIdentifier);
const target: Target = new Target(
targetType,
name,
const metadataList: Metadata[] = _getTargetMetadata(
isMultiInject,
serviceIdentifier,
injectMetadata,
key,
value,
);

if (key !== undefined) {
const tagMetadata: Metadata = new Metadata(key, value);
target.metadata.push(tagMetadata);
const classElementMetadata: ClassElementMetadata =
getClassElementMetadataFromLegacyMetadata(metadataList);

if (classElementMetadata.kind === ClassElementMetadataKind.unmanaged) {
throw new Error('Unexpected metadata when creating target');
}

const target: Target = new TargetImpl(name, classElementMetadata, targetType);

return target;
}

Expand Down Expand Up @@ -113,6 +120,27 @@ function _getActiveBindings(
return activeBindings;
}

function _getTargetMetadata(
isMultiInject: boolean,
serviceIdentifier: interfaces.ServiceIdentifier,
key: string | number | symbol | undefined,
value: unknown,
): Metadata[] {
const metadataKey: string = isMultiInject
? METADATA_KEY.MULTI_INJECT_TAG
: METADATA_KEY.INJECT_TAG;

const metadataList: Metadata[] = [
new Metadata(metadataKey, serviceIdentifier),
];

if (key !== undefined) {
metadataList.push(new Metadata(key, value));
}

return metadataList;
}

function _validateActiveBindingCount(
serviceIdentifier: interfaces.ServiceIdentifier,
bindings: interfaces.Binding<unknown>[],
Expand Down Expand Up @@ -321,12 +349,22 @@ function createMockRequest(
key: string | number | symbol,
value: unknown,
): interfaces.Request {
const target: Target = new Target(
TargetTypeEnum.Variable,
'',
const metadataList: Metadata[] = _getTargetMetadata(
false,
serviceIdentifier,
new Metadata(key, value),
key,
value,
);

const classElementMetadata: ClassElementMetadata =
getClassElementMetadataFromLegacyMetadata(metadataList);

if (classElementMetadata.kind === ClassElementMetadataKind.unmanaged) {
throw new Error('Unexpected metadata when creating target');
}

const target: Target = new TargetImpl('', classElementMetadata, 'Variable');

const context: Context = new Context(container);
const request: Request = new Request(
serviceIdentifier,
Expand Down
4 changes: 1 addition & 3 deletions src/planning/queryable_string.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { interfaces } from '../interfaces/interfaces';

class QueryableString implements interfaces.QueryableString {
export class QueryableString implements interfaces.QueryableString {
private readonly str: string;

constructor(str: string) {
Expand Down Expand Up @@ -34,5 +34,3 @@ class QueryableString implements interfaces.QueryableString {
return this.str;
}
}

export { QueryableString };
Loading

0 comments on commit b1e796d

Please sign in to comment.