UNPKG

@inversifyjs/core

Version:

InversifyJs core package

99 lines 3.78 kB
import { stringifyServiceIdentifier, } from '@inversifyjs/common'; import { bindingTypeValues } from '../../binding/models/BindingType.js'; import { isStackOverflowError } from '../../error/calculations/isStackOverflowError.js'; import { InversifyCoreError } from '../../error/models/InversifyCoreError.js'; import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind.js'; import { isPlanServiceRedirectionBindingNode } from './isPlanServiceRedirectionBindingNode.js'; const INDEX_NOT_FOUND = -1; export function handleResolveError(params, error) { if (isStackOverflowError(error) || InversifyCoreError.isErrorOfKind(error, InversifyCoreErrorKind.planningMaxDepthExceeded)) { const stringifiedCircularDependencies = stringifyServiceIdentifierTrace(extractLikelyCircularDependency(params)); throw new InversifyCoreError(InversifyCoreErrorKind.planning, `Circular dependency found: ${stringifiedCircularDependencies}`, { cause: error }); } throw error; } function extractLikelyCircularDependency(params) { const root = params.planResult.tree.root; const stack = []; function depthFirstSearch(node) { const existingIndex = stack.indexOf(node); if (existingIndex !== INDEX_NOT_FOUND) { const cycleNodes = [ ...stack.slice(existingIndex), node, ]; return cycleNodes.map((n) => n.serviceIdentifier); } stack.push(node); try { for (const child of getChildServiceNodes(node)) { const result = depthFirstSearch(child); if (result !== undefined) { return result; } } } finally { stack.pop(); } return undefined; } const result = depthFirstSearch(root); return result ?? []; } function getChildServiceNodes(serviceNode) { const children = []; const bindings = serviceNode.bindings; if (bindings === undefined) { return children; } const processBindingNode = (bindingNode) => { if (isPlanServiceRedirectionBindingNode(bindingNode)) { for (const redirection of bindingNode.redirections) { processBindingNode(redirection); } return; } switch (bindingNode.binding.type) { case bindingTypeValues.Instance: { const instanceNode = bindingNode; for (const ctorParam of instanceNode.constructorParams) { if (ctorParam !== undefined) { children.push(ctorParam); } } for (const propParam of instanceNode.propertyParams.values()) { children.push(propParam); } break; } case bindingTypeValues.ResolvedValue: { const resolvedValueNode = bindingNode; for (const param of resolvedValueNode.params) { children.push(param); } break; } default: break; } }; if (Array.isArray(bindings)) { for (const bindingNode of bindings) { processBindingNode(bindingNode); } } else { processBindingNode(bindings); } return children; } function stringifyServiceIdentifierTrace(serviceIdentifiers) { const serviceIdentifiersArray = [...serviceIdentifiers]; if (serviceIdentifiersArray.length === 0) { return '(No dependency trace)'; } return serviceIdentifiersArray.map(stringifyServiceIdentifier).join(' -> '); } //# sourceMappingURL=handleResolveError.js.map