From 7743276a30aef769b8056085b888f1b3b31f9466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Pintos=20L=C3=B3pez?= Date: Thu, 16 Jan 2025 19:59:09 +0100 Subject: [PATCH] feat(core): update plan related error messages Updated plan related error messages with binding metadata details --- .changeset/fair-flies-run.md | 5 + .../buildFilteredServiceBindings.spec.ts | 53 ++--- .../buildFilteredServiceBindings.ts | 11 +- ...BindingNodeSingleInjectionBindings.spec.ts | 37 +++ ...ctionBindingNodeSingleInjectionBindings.ts | 4 + ...ServiceNodeSingleInjectionBindings.spec.ts | 32 ++- ...checkServiceNodeSingleInjectionBindings.ts | 4 + .../planning/calculations/plan.int.spec.ts | 12 +- .../src/planning/calculations/plan.spec.ts | 218 ++---------------- .../core/src/planning/calculations/plan.ts | 26 ++- ...rWhenUnexpectedBindingsAmountFound.spec.ts | 110 ++++++++- ...wErrorWhenUnexpectedBindingsAmountFound.ts | 41 +++- 12 files changed, 301 insertions(+), 252 deletions(-) create mode 100644 .changeset/fair-flies-run.md diff --git a/.changeset/fair-flies-run.md b/.changeset/fair-flies-run.md new file mode 100644 index 00000000..1150e735 --- /dev/null +++ b/.changeset/fair-flies-run.md @@ -0,0 +1,5 @@ +--- +"@inversifyjs/core": minor +--- + +Updated plan related error messages with binding metadata details diff --git a/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.spec.ts b/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.spec.ts index eea906d6..43663cf0 100644 --- a/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.spec.ts +++ b/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.spec.ts @@ -1,10 +1,9 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; import { Binding } from '../../binding/models/Binding'; -import { InternalBindingMetadata } from '../../binding/models/BindingMetadataImplementation'; +import { BindingMetadata } from '../../binding/models/BindingMetadata'; import { bindingScopeValues } from '../../binding/models/BindingScope'; import { bindingTypeValues } from '../../binding/models/BindingType'; -import { SingleInmutableLinkedList } from '../../common/models/SingleInmutableLinkedList'; import { BasePlanParams } from '../models/BasePlanParams'; import { buildFilteredServiceBindings, @@ -14,24 +13,18 @@ import { describe(buildFilteredServiceBindings.name, () => { describe('having no options', () => { let paramsMock: jest.Mocked; - let bindingMetadataListFixture: SingleInmutableLinkedList; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { paramsMock = { getBindings: jest.fn(), } as Partial> as jest.Mocked; - bindingMetadataListFixture = { - last: { - elem: { - name: 'name', - serviceIdentifier: 'service-id', - tags: new Map(), - }, - previous: undefined, - }, - } as Partial< - SingleInmutableLinkedList - > as SingleInmutableLinkedList; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'name', + serviceIdentifier: 'service-id', + tags: new Map(), + }; }); describe('when called, and params.getBinding() returns undefined', () => { @@ -40,7 +33,7 @@ describe(buildFilteredServiceBindings.name, () => { beforeAll(() => { result = buildFilteredServiceBindings( paramsMock, - bindingMetadataListFixture, + bindingMetadataFixture, ); }); @@ -51,7 +44,7 @@ describe(buildFilteredServiceBindings.name, () => { it('should call params.getBinding()', () => { expect(paramsMock.getBindings).toHaveBeenCalledTimes(1); expect(paramsMock.getBindings).toHaveBeenCalledWith( - bindingMetadataListFixture.last.elem.serviceIdentifier, + bindingMetadataFixture.serviceIdentifier, ); }); @@ -86,7 +79,7 @@ describe(buildFilteredServiceBindings.name, () => { result = buildFilteredServiceBindings( paramsMock, - bindingMetadataListFixture, + bindingMetadataFixture, ); }); @@ -97,7 +90,7 @@ describe(buildFilteredServiceBindings.name, () => { it('should call params.getBinding()', () => { expect(paramsMock.getBindings).toHaveBeenCalledTimes(1); expect(paramsMock.getBindings).toHaveBeenCalledWith( - bindingMetadataListFixture.last.elem.serviceIdentifier, + bindingMetadataFixture.serviceIdentifier, ); }); @@ -109,25 +102,19 @@ describe(buildFilteredServiceBindings.name, () => { describe('having options with customServiceIdentifier', () => { let paramsMock: jest.Mocked; - let bindingMetadataListFixture: SingleInmutableLinkedList; + let bindingMetadataFixture: BindingMetadata; let optionsFixture: BuildFilteredServiceBindingsOptions; beforeAll(() => { paramsMock = { getBindings: jest.fn(), } as Partial> as jest.Mocked; - bindingMetadataListFixture = { - last: { - elem: { - name: 'name', - serviceIdentifier: 'service-id', - tags: new Map(), - }, - previous: undefined, - }, - } as Partial< - SingleInmutableLinkedList - > as SingleInmutableLinkedList; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'name', + serviceIdentifier: 'service-id', + tags: new Map(), + }; optionsFixture = { customServiceIdentifier: 'custom-service-id', }; @@ -139,7 +126,7 @@ describe(buildFilteredServiceBindings.name, () => { beforeAll(() => { result = buildFilteredServiceBindings( paramsMock, - bindingMetadataListFixture, + bindingMetadataFixture, optionsFixture, ); }); diff --git a/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.ts b/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.ts index c25ae244..517351e4 100644 --- a/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.ts +++ b/packages/container/libraries/core/src/planning/calculations/buildFilteredServiceBindings.ts @@ -1,11 +1,7 @@ import { ServiceIdentifier } from '@inversifyjs/common'; import { Binding } from '../../binding/models/Binding'; -import { - BindingMetadataImplementation, - InternalBindingMetadata, -} from '../../binding/models/BindingMetadataImplementation'; -import { SingleInmutableLinkedList } from '../../common/models/SingleInmutableLinkedList'; +import { BindingMetadata } from '../../binding/models/BindingMetadata'; import { BasePlanParams } from '../models/BasePlanParams'; export interface BuildFilteredServiceBindingsOptions { @@ -14,12 +10,9 @@ export interface BuildFilteredServiceBindingsOptions { export function buildFilteredServiceBindings( params: BasePlanParams, - bindingMetadataList: SingleInmutableLinkedList, + bindingMetadata: BindingMetadata, options?: BuildFilteredServiceBindingsOptions, ): Binding[] { - const bindingMetadata: BindingMetadataImplementation = - new BindingMetadataImplementation(bindingMetadataList.last); - const serviceIdentifier: ServiceIdentifier = options?.customServiceIdentifier ?? bindingMetadata.serviceIdentifier; diff --git a/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.spec.ts b/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.spec.ts index 74de1c8e..9db2f9e2 100644 --- a/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.spec.ts +++ b/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.spec.ts @@ -3,9 +3,11 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; jest.mock('./isPlanServiceRedirectionBindingNode'); jest.mock('./throwErrorWhenUnexpectedBindingsAmountFound'); +import { BindingMetadata } from '../../binding/models/BindingMetadata'; import { bindingScopeValues } from '../../binding/models/BindingScope'; import { bindingTypeValues } from '../../binding/models/BindingType'; import { ServiceRedirectionBinding } from '../../binding/models/ServiceRedirectionBinding'; +import { MetadataTag } from '../../metadata/models/MetadataTag'; import { BindingNodeParent } from '../models/BindingNodeParent'; import { PlanServiceRedirectionBindingNode } from '../models/PlanServiceRedirectionBindingNode'; import { checkPlanServiceRedirectionBindingNodeSingleInjectionBindings } from './checkPlanServiceRedirectionBindingNodeSingleInjectionBindings'; @@ -18,6 +20,7 @@ describe( describe('having a PlanServiceRedirectionBindingNode with no redirections', () => { let planServiceRedirectionBindingNodeFixture: PlanServiceRedirectionBindingNode; let isOptionalFixture: boolean; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { planServiceRedirectionBindingNodeFixture = { @@ -27,6 +30,15 @@ describe( redirections: [], }; isOptionalFixture = false; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called', () => { @@ -37,6 +49,7 @@ describe( checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( planServiceRedirectionBindingNodeFixture, isOptionalFixture, + bindingMetadataFixture, ); }); @@ -54,6 +67,7 @@ describe( planServiceRedirectionBindingNodeFixture.redirections, isOptionalFixture, planServiceRedirectionBindingNodeFixture, + bindingMetadataFixture, ); }); @@ -66,6 +80,7 @@ describe( describe('having a PlanServiceRedirectionBindingNode with a single redirection to a leaf node', () => { let planServiceRedirectionBindingNodeFixture: PlanServiceRedirectionBindingNode; let isOptionalFixture: boolean; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { planServiceRedirectionBindingNodeFixture = { @@ -94,6 +109,15 @@ describe( ], }; isOptionalFixture = false; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns false', () => { @@ -110,6 +134,7 @@ describe( checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( planServiceRedirectionBindingNodeFixture, isOptionalFixture, + bindingMetadataFixture, ); }); @@ -133,6 +158,7 @@ describe( let planServiceRedirectionBindingNodeRedirectionFixture: PlanServiceRedirectionBindingNode; let planServiceRedirectionBindingNodeFixture: PlanServiceRedirectionBindingNode; let isOptionalFixture: boolean; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { planServiceRedirectionBindingNodeRedirectionFixture = { @@ -148,6 +174,15 @@ describe( redirections: [planServiceRedirectionBindingNodeRedirectionFixture], }; isOptionalFixture = false; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns true', () => { @@ -164,6 +199,7 @@ describe( checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( planServiceRedirectionBindingNodeFixture, isOptionalFixture, + bindingMetadataFixture, ); }); @@ -181,6 +217,7 @@ describe( planServiceRedirectionBindingNodeRedirectionFixture.redirections, isOptionalFixture, planServiceRedirectionBindingNodeRedirectionFixture, + bindingMetadataFixture, ); }); diff --git a/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.ts b/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.ts index 863b1d2a..a44e524b 100644 --- a/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.ts +++ b/packages/container/libraries/core/src/planning/calculations/checkPlanServiceRedirectionBindingNodeSingleInjectionBindings.ts @@ -1,3 +1,4 @@ +import { BindingMetadata } from '../../binding/models/BindingMetadata'; import { PlanBindingNode } from '../models/PlanBindingNode'; import { PlanServiceRedirectionBindingNode } from '../models/PlanServiceRedirectionBindingNode'; import { isPlanServiceRedirectionBindingNode } from './isPlanServiceRedirectionBindingNode'; @@ -8,6 +9,7 @@ const SINGLE_INJECTION_BINDINGS: number = 1; export function checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( serviceRedirectionBindingNode: PlanServiceRedirectionBindingNode, isOptional: boolean, + bindingMetadata: BindingMetadata, ): void { if ( serviceRedirectionBindingNode.redirections.length === @@ -20,6 +22,7 @@ export function checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( planBindingNode, isOptional, + bindingMetadata, ); } @@ -30,5 +33,6 @@ export function checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( serviceRedirectionBindingNode.redirections, isOptional, serviceRedirectionBindingNode, + bindingMetadata, ); } diff --git a/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.spec.ts b/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.spec.ts index 6137c62b..f75df925 100644 --- a/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.spec.ts +++ b/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.spec.ts @@ -4,6 +4,8 @@ jest.mock('./checkPlanServiceRedirectionBindingNodeSingleInjectionBindings'); jest.mock('./isPlanServiceRedirectionBindingNode'); jest.mock('./throwErrorWhenUnexpectedBindingsAmountFound'); +import { BindingMetadata } from '../../binding/models/BindingMetadata'; +import { MetadataTag } from '../../metadata/models/MetadataTag'; import { PlanBindingNode } from '../models/PlanBindingNode'; import { PlanServiceNode } from '../models/PlanServiceNode'; import { PlanServiceNodeParent } from '../models/PlanServiceNodeParent'; @@ -16,6 +18,7 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { describe('having a PlanServiceNode with no bindings', () => { let nodeFixture: PlanServiceNode; let isOptionalFixture: boolean; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { nodeFixture = { @@ -24,6 +27,15 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { serviceIdentifier: 'service-id', }; isOptionalFixture = false; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called', () => { @@ -33,6 +45,7 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { result = checkServiceNodeSingleInjectionBindings( nodeFixture, isOptionalFixture, + bindingMetadataFixture, ); }); @@ -50,6 +63,7 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { nodeFixture.bindings, isOptionalFixture, nodeFixture, + bindingMetadataFixture, ); }); @@ -63,6 +77,7 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { let nodeFixtureBinding: PlanBindingNode; let nodeFixture: PlanServiceNode; let isOptionalFixture: boolean; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { nodeFixtureBinding = Symbol() as unknown as PlanBindingNode; @@ -72,6 +87,15 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { serviceIdentifier: 'service-id', }; isOptionalFixture = false; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns false', () => { @@ -87,6 +111,7 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { result = checkServiceNodeSingleInjectionBindings( nodeFixture, isOptionalFixture, + bindingMetadataFixture, ); }); @@ -118,6 +143,7 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { result = checkServiceNodeSingleInjectionBindings( nodeFixture, isOptionalFixture, + bindingMetadataFixture, ); }); @@ -131,7 +157,11 @@ describe(checkServiceNodeSingleInjectionBindings.name, () => { ).toHaveBeenCalledTimes(1); expect( checkPlanServiceRedirectionBindingNodeSingleInjectionBindings, - ).toHaveBeenCalledWith(nodeFixtureBinding, isOptionalFixture); + ).toHaveBeenCalledWith( + nodeFixtureBinding, + isOptionalFixture, + bindingMetadataFixture, + ); }); it('should not call throwErrorWhenUnexpectedBindingsAmountFound()', () => { diff --git a/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.ts b/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.ts index 941eb8cf..d903b5ed 100644 --- a/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.ts +++ b/packages/container/libraries/core/src/planning/calculations/checkServiceNodeSingleInjectionBindings.ts @@ -1,3 +1,4 @@ +import { BindingMetadata } from '../../binding/models/BindingMetadata'; import { PlanBindingNode } from '../models/PlanBindingNode'; import { PlanServiceNode } from '../models/PlanServiceNode'; import { checkPlanServiceRedirectionBindingNodeSingleInjectionBindings } from './checkPlanServiceRedirectionBindingNodeSingleInjectionBindings'; @@ -9,6 +10,7 @@ const SINGLE_INJECTION_BINDINGS: number = 1; export function checkServiceNodeSingleInjectionBindings( serviceNode: PlanServiceNode, isOptional: boolean, + bindingMetadata: BindingMetadata, ): void { if (Array.isArray(serviceNode.bindings)) { if (serviceNode.bindings.length === SINGLE_INJECTION_BINDINGS) { @@ -20,6 +22,7 @@ export function checkServiceNodeSingleInjectionBindings( checkPlanServiceRedirectionBindingNodeSingleInjectionBindings( planBindingNode, isOptional, + bindingMetadata, ); } @@ -31,5 +34,6 @@ export function checkServiceNodeSingleInjectionBindings( serviceNode.bindings, isOptional, serviceNode, + bindingMetadata, ); } diff --git a/packages/container/libraries/core/src/planning/calculations/plan.int.spec.ts b/packages/container/libraries/core/src/planning/calculations/plan.int.spec.ts index dd1de38c..c3092bea 100644 --- a/packages/container/libraries/core/src/planning/calculations/plan.int.spec.ts +++ b/packages/container/libraries/core/src/planning/calculations/plan.int.spec.ts @@ -414,7 +414,11 @@ describe(plan.name, () => { kind: InversifyCoreErrorKind.planning, message: `No bindings found for service: "${ServiceIds.nonExistent}". -Trying to resolve bindings for "${ServiceIds.nonExistent} (Root service)".`, +Trying to resolve bindings for "${ServiceIds.nonExistent} (Root service)". + +Binding metadata: +- service identifier: non-existent-service-id +- name: -`, }, ], [ @@ -427,7 +431,11 @@ Trying to resolve bindings for "${ServiceIds.nonExistent} (Root service)".`, kind: InversifyCoreErrorKind.planning, message: `No bindings found for service: "${ServiceIds.nonExistent}". -Trying to resolve bindings for "${ServiceIds.serviceRedirectionToNonExistent}".`, +Trying to resolve bindings for "${ServiceIds.serviceRedirectionToNonExistent}". + +Binding metadata: +- service identifier: service-redirection-to-non-existent-service-id +- name: -`, }, ], ])( diff --git a/packages/container/libraries/core/src/planning/calculations/plan.spec.ts b/packages/container/libraries/core/src/planning/calculations/plan.spec.ts index 027b65e4..55c3c34b 100644 --- a/packages/container/libraries/core/src/planning/calculations/plan.spec.ts +++ b/packages/container/libraries/core/src/planning/calculations/plan.spec.ts @@ -5,13 +5,12 @@ jest.mock('./checkServiceNodeSingleInjectionBindings'); import { LazyServiceIdentifier, ServiceIdentifier } from '@inversifyjs/common'; -import { InternalBindingMetadata } from '../../binding/models/BindingMetadataImplementation'; +import { BindingMetadataImplementation } from '../../binding/models/BindingMetadataImplementation'; import { bindingScopeValues } from '../../binding/models/BindingScope'; import { bindingTypeValues } from '../../binding/models/BindingType'; import { ConstantValueBinding } from '../../binding/models/ConstantValueBinding'; import { InstanceBinding } from '../../binding/models/InstanceBinding'; import { ServiceRedirectionBinding } from '../../binding/models/ServiceRedirectionBinding'; -import { SingleInmutableLinkedList } from '../../common/models/SingleInmutableLinkedList'; import { Writable } from '../../common/models/Writable'; import { ClassMetadataFixtures } from '../../metadata/fixtures/ClassMetadataFixtures'; import { ClassElementMetadataKind } from '../../metadata/models/ClassElementMetadataKind'; @@ -89,26 +88,10 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map([ - [ - planParamsMock.rootConstraints.tag?.key as string, - planParamsMock.rootConstraints.tag?.value as string, - ], - ]), - }, - previous: undefined, - }); - expect(buildFilteredServiceBindings).toHaveBeenCalledTimes(1); expect(buildFilteredServiceBindings).toHaveBeenCalledWith( planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -170,21 +153,10 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - expect(buildFilteredServiceBindings).toHaveBeenCalledTimes(1); expect(buildFilteredServiceBindings).toHaveBeenCalledWith( planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -239,21 +211,10 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - expect(buildFilteredServiceBindings).toHaveBeenCalledTimes(1); expect(buildFilteredServiceBindings).toHaveBeenCalledWith( planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -322,21 +283,10 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - expect(buildFilteredServiceBindings).toHaveBeenCalledTimes(1); expect(buildFilteredServiceBindings).toHaveBeenCalledWith( planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -455,32 +405,6 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedFirstBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - - const expectedSecondBindingMetadataList: SingleInmutableLinkedList = - expectedFirstBindingMetadataList.concat({ - name: constructorArgumentMetadata.name, - serviceIdentifier: - constructorArgumentMetadata.value as ServiceIdentifier, - tags: constructorArgumentMetadata.tags, - }); - - const expectedThirdBindingMetadataList: SingleInmutableLinkedList = - expectedFirstBindingMetadataList.concat({ - name: propertyMetadata.name, - serviceIdentifier: propertyMetadata.value as ServiceIdentifier, - tags: propertyMetadata.tags, - }); - const expectedSublan: jest.Mocked = { getBindings: planParamsMock.getBindings, getClassMetadata: planParamsMock.getClassMetadata, @@ -496,17 +420,17 @@ describe(plan.name, () => { expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 1, planParamsMock, - expectedFirstBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 2, expectedSublan, - expectedSecondBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 3, expectedSublan, - expectedThirdBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -663,35 +587,6 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedFirstBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - - const expectedSecondBindingMetadataList: SingleInmutableLinkedList = - expectedFirstBindingMetadataList.concat({ - name: constructorArgumentMetadata.name, - serviceIdentifier: ( - constructorArgumentMetadata.value as LazyServiceIdentifier - ).unwrap(), - tags: constructorArgumentMetadata.tags, - }); - - const expectedThirdBindingMetadataList: SingleInmutableLinkedList = - expectedFirstBindingMetadataList.concat({ - name: propertyMetadata.name, - serviceIdentifier: ( - propertyMetadata.value as LazyServiceIdentifier - ).unwrap(), - tags: propertyMetadata.tags, - }); - const expectedSublan: jest.Mocked = { getBindings: planParamsMock.getBindings, getClassMetadata: planParamsMock.getClassMetadata, @@ -707,17 +602,17 @@ describe(plan.name, () => { expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 1, planParamsMock, - expectedFirstBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 2, expectedSublan, - expectedSecondBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 3, expectedSublan, - expectedThirdBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -875,32 +770,6 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedFirstBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - - const expectedSecondBindingMetadataList: SingleInmutableLinkedList = - expectedFirstBindingMetadataList.concat({ - name: constructorArgumentMetadata.name, - serviceIdentifier: - constructorArgumentMetadata.value as ServiceIdentifier, - tags: constructorArgumentMetadata.tags, - }); - - const expectedThirdBindingMetadataList: SingleInmutableLinkedList = - expectedFirstBindingMetadataList.concat({ - name: propertyMetadata.name, - serviceIdentifier: propertyMetadata.value as ServiceIdentifier, - tags: propertyMetadata.tags, - }); - const expectedSublan: jest.Mocked = { getBindings: planParamsMock.getBindings, getClassMetadata: planParamsMock.getClassMetadata, @@ -916,17 +785,17 @@ describe(plan.name, () => { expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 1, planParamsMock, - expectedFirstBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 2, expectedSublan, - expectedSecondBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 3, expectedSublan, - expectedThirdBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -951,11 +820,13 @@ describe(plan.name, () => { 1, constructorParamsPlanServiceNode, constructorArgumentMetadata.optional, + expect.any(BindingMetadataImplementation), ); expect(checkServiceNodeSingleInjectionBindings).toHaveBeenNthCalledWith( 2, propertyParamsPlanServiceNode, propertyMetadata.optional, + expect.any(BindingMetadataImplementation), ); }); @@ -1082,21 +953,10 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - expect(buildFilteredServiceBindings).toHaveBeenCalledTimes(1); expect(buildFilteredServiceBindings).toHaveBeenCalledWith( planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -1159,17 +1019,6 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - const expectedOptions: BuildFilteredServiceBindingsOptions = { customServiceIdentifier: serviceRedirectionBinding.targetServiceIdentifier, @@ -1179,12 +1028,12 @@ describe(plan.name, () => { expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 1, planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 2, planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), expectedOptions, ); }); @@ -1266,17 +1115,6 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - const expectedOptions: BuildFilteredServiceBindingsOptions = { customServiceIdentifier: serviceRedirectionBinding.targetServiceIdentifier, @@ -1286,12 +1124,12 @@ describe(plan.name, () => { expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 1, planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); expect(buildFilteredServiceBindings).toHaveBeenNthCalledWith( 2, planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), expectedOptions, ); }); @@ -1363,21 +1201,10 @@ describe(plan.name, () => { }); it('should call buildFilteredServiceBindings()', () => { - const expectedBindingMetadataList: SingleInmutableLinkedList = - new SingleInmutableLinkedList({ - elem: { - name: planParamsMock.rootConstraints.name, - serviceIdentifier: - planParamsMock.rootConstraints.serviceIdentifier, - tags: new Map(), - }, - previous: undefined, - }); - expect(buildFilteredServiceBindings).toHaveBeenCalledTimes(1); expect(buildFilteredServiceBindings).toHaveBeenCalledWith( planParamsMock, - expectedBindingMetadataList, + expect.any(BindingMetadataImplementation), ); }); @@ -1394,6 +1221,7 @@ describe(plan.name, () => { expect(checkServiceNodeSingleInjectionBindings).toHaveBeenCalledWith( expectedServiceNode, false, + expect.any(BindingMetadataImplementation), ); }); diff --git a/packages/container/libraries/core/src/planning/calculations/plan.ts b/packages/container/libraries/core/src/planning/calculations/plan.ts index 1761e64b..cff9b6e9 100644 --- a/packages/container/libraries/core/src/planning/calculations/plan.ts +++ b/packages/container/libraries/core/src/planning/calculations/plan.ts @@ -1,7 +1,11 @@ import { LazyServiceIdentifier, ServiceIdentifier } from '@inversifyjs/common'; import { Binding } from '../../binding/models/Binding'; -import { InternalBindingMetadata } from '../../binding/models/BindingMetadataImplementation'; +import { BindingMetadata } from '../../binding/models/BindingMetadata'; +import { + BindingMetadataImplementation, + InternalBindingMetadata, +} from '../../binding/models/BindingMetadataImplementation'; import { bindingTypeValues } from '../../binding/models/BindingType'; import { InstanceBinding } from '../../binding/models/InstanceBinding'; import { ServiceRedirectionBinding } from '../../binding/models/ServiceRedirectionBinding'; @@ -42,8 +46,12 @@ export function plan(params: PlanParams): PlanResult { previous: undefined, }); + const bindingMetadata: BindingMetadata = new BindingMetadataImplementation( + bindingMetadataList.last, + ); + const filteredServiceBindings: Binding[] = - buildFilteredServiceBindings(params, bindingMetadataList); + buildFilteredServiceBindings(params, bindingMetadata); const serviceNodeBindings: PlanBindingNode[] = []; @@ -66,6 +74,7 @@ export function plan(params: PlanParams): PlanResult { checkServiceNodeSingleInjectionBindings( serviceNode, params.rootConstraints.isOptional ?? false, + bindingMetadata, ); const [planBindingNode]: PlanBindingNode[] = serviceNodeBindings; @@ -130,8 +139,12 @@ function buildPlanServiceNodeFromClassElementMetadata( tags: elementMetadata.tags, }); + const bindingMetadata: BindingMetadata = new BindingMetadataImplementation( + updatedBindingMetadataList.last, + ); + const filteredServiceBindings: Binding[] = - buildFilteredServiceBindings(params, updatedBindingMetadataList); + buildFilteredServiceBindings(params, bindingMetadata); const serviceNodeBindings: PlanBindingNode[] = []; @@ -154,6 +167,7 @@ function buildPlanServiceNodeFromClassElementMetadata( checkServiceNodeSingleInjectionBindings( serviceNode, elementMetadata.optional, + bindingMetadata, ); const [planBindingNode]: PlanBindingNode[] = serviceNodeBindings; @@ -230,8 +244,12 @@ function buildServiceRedirectionPlanBindingNode( redirections: [], }; + const bindingMetadata: BindingMetadata = new BindingMetadataImplementation( + bindingMetadataList.last, + ); + const filteredServiceBindings: Binding[] = - buildFilteredServiceBindings(params, bindingMetadataList, { + buildFilteredServiceBindings(params, bindingMetadata, { customServiceIdentifier: binding.targetServiceIdentifier, }); diff --git a/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.spec.ts b/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.spec.ts index 06133f70..5c7e2d82 100644 --- a/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.spec.ts +++ b/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.spec.ts @@ -8,10 +8,12 @@ jest.mock('../../binding/calculations/stringifyBinding'); jest.mock('./isPlanServiceRedirectionBindingNode'); import { stringifyBinding } from '../../binding/calculations/stringifyBinding'; +import { BindingMetadata } from '../../binding/models/BindingMetadata'; import { bindingScopeValues } from '../../binding/models/BindingScope'; import { bindingTypeValues } from '../../binding/models/BindingType'; import { InversifyCoreError } from '../../error/models/InversifyCoreError'; import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind'; +import { MetadataTag } from '../../metadata/models/MetadataTag'; import { PlanBindingNode } from '../models/PlanBindingNode'; import { PlanServiceNode } from '../models/PlanServiceNode'; import { PlanServiceRedirectionBindingNode } from '../models/PlanServiceRedirectionBindingNode'; @@ -23,6 +25,7 @@ describe(throwErrorWhenUnexpectedBindingsAmountFound.name, () => { let bindingsFixture: undefined; let isOptionalFixture: false; let nodeFixture: PlanServiceNode; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { bindingsFixture = undefined; @@ -32,6 +35,15 @@ describe(throwErrorWhenUnexpectedBindingsAmountFound.name, () => { parent: undefined, serviceIdentifier: 'service-identifier', }; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns true', () => { @@ -53,6 +65,7 @@ describe(throwErrorWhenUnexpectedBindingsAmountFound.name, () => { typeof stringifyServiceIdentifier > ) + .mockReturnValueOnce(stringifiedServiceIdentifier) .mockReturnValueOnce(stringifiedServiceIdentifier) .mockReturnValueOnce(stringifiedServiceIdentifier); @@ -61,6 +74,7 @@ describe(throwErrorWhenUnexpectedBindingsAmountFound.name, () => { bindingsFixture, isOptionalFixture, nodeFixture, + bindingMetadataFixture, ); } catch (error) { result = error; @@ -76,7 +90,14 @@ describe(throwErrorWhenUnexpectedBindingsAmountFound.name, () => { kind: InversifyCoreErrorKind.planning, message: `No bindings found for service: "${stringifiedServiceIdentifier}". -Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)".`, +Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". + +Binding metadata: +- service identifier: ${stringifiedServiceIdentifier} +- name: binding-name +- tags: + - tag1 + - tag2`, }; expect(result).toBeInstanceOf(InversifyCoreError); @@ -91,6 +112,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". let bindingsFixture: PlanBindingNode; let isOptionalFixture: false; let nodeFixture: PlanServiceNode; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { const parentNode: PlanServiceNode = { @@ -123,6 +145,16 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". parent: undefined, serviceIdentifier: 'service-identifier', }; + + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns false', () => { @@ -139,6 +171,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". bindingsFixture, isOptionalFixture, nodeFixture, + bindingMetadataFixture, ); }); @@ -156,6 +189,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". let bindingsFixture: []; let isOptionalFixture: false; let nodeFixture: PlanServiceRedirectionBindingNode; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { bindingsFixture = []; @@ -176,6 +210,15 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". }, redirections: [], }; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns true', () => { @@ -200,6 +243,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". > ) .mockReturnValueOnce(stringifiedTargetServiceIdentifier) + .mockReturnValueOnce(stringifiedServiceIdentifier) .mockReturnValueOnce(stringifiedServiceIdentifier); try { @@ -207,6 +251,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". bindingsFixture, isOptionalFixture, nodeFixture, + bindingMetadataFixture, ); } catch (error: unknown) { result = error; @@ -222,7 +267,14 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". kind: InversifyCoreErrorKind.planning, message: `No bindings found for service: "${stringifiedTargetServiceIdentifier}". -Trying to resolve bindings for "${stringifiedServiceIdentifier}".`, +Trying to resolve bindings for "${stringifiedServiceIdentifier}". + +Binding metadata: +- service identifier: stringified-service-id +- name: binding-name +- tags: + - tag1 + - tag2`, }; expect(result).toBeInstanceOf(InversifyCoreError); @@ -237,6 +289,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier}".`, let bindingsFixture: []; let isOptionalFixture: false; let nodeFixture: PlanServiceNode; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { bindingsFixture = []; @@ -246,6 +299,15 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier}".`, parent: undefined, serviceIdentifier: 'service-identifier', }; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns true', () => { @@ -267,6 +329,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier}".`, typeof stringifyServiceIdentifier > ) + .mockReturnValueOnce(stringifiedServiceIdentifier) .mockReturnValueOnce(stringifiedServiceIdentifier) .mockReturnValueOnce(stringifiedServiceIdentifier); @@ -275,6 +338,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier}".`, bindingsFixture, isOptionalFixture, nodeFixture, + bindingMetadataFixture, ); } catch (error) { result = error; @@ -290,7 +354,14 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier}".`, kind: InversifyCoreErrorKind.planning, message: `No bindings found for service: "${stringifiedServiceIdentifier}". -Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)".`, +Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". + +Binding metadata: +- service identifier: stringified-service-id +- name: binding-name +- tags: + - tag1 + - tag2`, }; expect(result).toBeInstanceOf(InversifyCoreError); @@ -305,6 +376,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". let bindingsFixture: []; let isOptionalFixture: true; let nodeFixture: PlanServiceNode; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { bindingsFixture = []; @@ -314,6 +386,15 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". parent: undefined, serviceIdentifier: 'service-identifier', }; + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns true', () => { @@ -330,6 +411,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". bindingsFixture, isOptionalFixture, nodeFixture, + bindingMetadataFixture, ); }); @@ -347,6 +429,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". let bindingsFixture: PlanBindingNode[]; let isOptionalFixture: boolean; let nodeFixture: PlanServiceRedirectionBindingNode; + let bindingMetadataFixture: BindingMetadata; beforeAll(() => { const parentNode: PlanServiceNode = { @@ -410,6 +493,16 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". }, redirections: [], }; + + bindingMetadataFixture = { + getAncestor: () => undefined, + name: 'binding-name', + serviceIdentifier: 'service-identifier', + tags: new Map([ + ['tag1', 'value1'], + ['tag2', 'value2'], + ]), + }; }); describe('when called, and isPlanServiceRedirectionBindingNode() returns true', () => { @@ -439,6 +532,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". > ) .mockReturnValueOnce(stringifiedTargetServiceIdentifierFixture) + .mockReturnValueOnce(stringifiedServiceIdentifierFixture) .mockReturnValueOnce(stringifiedServiceIdentifierFixture); (stringifyBinding as jest.Mock) @@ -450,6 +544,7 @@ Trying to resolve bindings for "${stringifiedServiceIdentifier} (Root service)". bindingsFixture, isOptionalFixture, nodeFixture, + bindingMetadataFixture, ); } catch (error: unknown) { result = error; @@ -470,7 +565,14 @@ Registered bindings: ${stringifiedBindingFixture} ${stringifiedBindingFixture} -Trying to resolve bindings for "${stringifiedServiceIdentifierFixture}".`, +Trying to resolve bindings for "${stringifiedServiceIdentifierFixture}". + +Binding metadata: +- service identifier: stringified-service-id +- name: binding-name +- tags: + - tag1 + - tag2`, }; expect(result).toBeInstanceOf(InversifyCoreError); diff --git a/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.ts b/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.ts index 433d8e9e..ae218af2 100644 --- a/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.ts +++ b/packages/container/libraries/core/src/planning/calculations/throwErrorWhenUnexpectedBindingsAmountFound.ts @@ -4,8 +4,10 @@ import { } from '@inversifyjs/common'; import { stringifyBinding } from '../../binding/calculations/stringifyBinding'; +import { BindingMetadata } from '../../binding/models/BindingMetadata'; import { InversifyCoreError } from '../../error/models/InversifyCoreError'; import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind'; +import { MetadataTag } from '../../metadata/models/MetadataTag'; import { BindingNodeParent } from '../models/BindingNodeParent'; import { PlanBindingNode } from '../models/PlanBindingNode'; import { isPlanServiceRedirectionBindingNode } from './isPlanServiceRedirectionBindingNode'; @@ -14,6 +16,7 @@ export function throwErrorWhenUnexpectedBindingsAmountFound( bindings: PlanBindingNode[] | PlanBindingNode | undefined, isOptional: boolean, node: BindingNodeParent, + bindingMetadata: BindingMetadata, ): void { let serviceIdentifier: ServiceIdentifier; let parentServiceIdentifier: ServiceIdentifier | undefined; @@ -32,6 +35,7 @@ export function throwErrorWhenUnexpectedBindingsAmountFound( isOptional, serviceIdentifier, parentServiceIdentifier, + bindingMetadata, ); } else { throwErrorWhenSingleUnexpectedBindingFound( @@ -39,6 +43,7 @@ export function throwErrorWhenUnexpectedBindingsAmountFound( isOptional, serviceIdentifier, parentServiceIdentifier, + bindingMetadata, ); } } @@ -46,10 +51,13 @@ export function throwErrorWhenUnexpectedBindingsAmountFound( function throwBindingNotFoundError( serviceIdentifier: ServiceIdentifier, parentServiceIdentifier: ServiceIdentifier | undefined, + bindingMetadata: BindingMetadata, ): never { const errorMessage: string = `No bindings found for service: "${stringifyServiceIdentifier(serviceIdentifier)}". -Trying to resolve bindings for "${stringifyParentServiceIdentifier(serviceIdentifier, parentServiceIdentifier)}".`; +Trying to resolve bindings for "${stringifyParentServiceIdentifier(serviceIdentifier, parentServiceIdentifier)}". + +${stringifyBindingMetadata(bindingMetadata)}`; throw new InversifyCoreError(InversifyCoreErrorKind.planning, errorMessage); } @@ -59,10 +67,15 @@ function throwErrorWhenMultipleUnexpectedBindingsAmountFound( isOptional: boolean, serviceIdentifier: ServiceIdentifier, parentServiceIdentifier: ServiceIdentifier | undefined, + bindingMetadata: BindingMetadata, ): void { if (bindings.length === 0) { if (!isOptional) { - throwBindingNotFoundError(serviceIdentifier, parentServiceIdentifier); + throwBindingNotFoundError( + serviceIdentifier, + parentServiceIdentifier, + bindingMetadata, + ); } } else { const errorMessage: string = `Ambiguous bindings found for service: "${stringifyServiceIdentifier(serviceIdentifier)}". @@ -71,7 +84,9 @@ Registered bindings: ${bindings.map((binding: PlanBindingNode): string => stringifyBinding(binding.binding)).join('\n')} -Trying to resolve bindings for "${stringifyParentServiceIdentifier(serviceIdentifier, parentServiceIdentifier)}".`; +Trying to resolve bindings for "${stringifyParentServiceIdentifier(serviceIdentifier, parentServiceIdentifier)}". + +${stringifyBindingMetadata(bindingMetadata)}`; throw new InversifyCoreError(InversifyCoreErrorKind.planning, errorMessage); } @@ -82,9 +97,14 @@ function throwErrorWhenSingleUnexpectedBindingFound( isOptional: boolean, serviceIdentifier: ServiceIdentifier, parentServiceIdentifier: ServiceIdentifier | undefined, + bindingMetadata: BindingMetadata, ): void { if (bindings === undefined && !isOptional) { - throwBindingNotFoundError(serviceIdentifier, parentServiceIdentifier); + throwBindingNotFoundError( + serviceIdentifier, + parentServiceIdentifier, + bindingMetadata, + ); } else { return; } @@ -98,3 +118,16 @@ function stringifyParentServiceIdentifier( ? `${stringifyServiceIdentifier(serviceIdentifier)} (Root service)` : stringifyServiceIdentifier(parentServiceIdentifier); } + +function stringifyBindingMetadata(bindingMetadata: BindingMetadata): string { + const stringifiedTags: string = + bindingMetadata.tags.size === 0 + ? '' + : ` +- tags: + - ${[...bindingMetadata.tags.keys()].map((key: MetadataTag) => key.toString()).join('\n - ')}`; + + return `Binding metadata: +- service identifier: ${stringifyServiceIdentifier(bindingMetadata.serviceIdentifier)} +- name: ${bindingMetadata.name?.toString() ?? '-'}${stringifiedTags}`; +}