UNPKG

inversify

Version:

A powerful and lightweight inversion of control container for JavaScript and Node.js apps powered by TypeScript.

148 lines (147 loc) 7.18 kB
import { BindingCount } from '../bindings/binding_count'; import * as ERROR_MSGS from '../constants/error_msgs'; import { BindingTypeEnum, TargetTypeEnum } from '../constants/literal_types'; import * as METADATA_KEY from '../constants/metadata_keys'; import { isStackOverflowExeption } from '../utils/exceptions'; import { circularDependencyToException, getServiceIdentifierAsString, listMetadataForTarget, listRegisteredBindingsForServiceIdentifier } from '../utils/serialization'; import { Context } from './context'; import { Metadata } from './metadata'; import { Plan } from './plan'; import { getBaseClassDependencyCount, getDependencies, getFunctionName } from './reflection_utils'; import { Request } from './request'; import { Target } from './target'; function getBindingDictionary(cntnr) { return cntnr._bindingDictionary; } function _createTarget(isMultiInject, targetType, serviceIdentifier, name, key, value) { var metadataKey = isMultiInject ? METADATA_KEY.MULTI_INJECT_TAG : METADATA_KEY.INJECT_TAG; var injectMetadata = new Metadata(metadataKey, serviceIdentifier); var target = new Target(targetType, name, serviceIdentifier, injectMetadata); if (key !== undefined) { var tagMetadata = new Metadata(key, value); target.metadata.push(tagMetadata); } return target; } function _getActiveBindings(metadataReader, avoidConstraints, context, parentRequest, target) { var bindings = getBindings(context.container, target.serviceIdentifier); var activeBindings = []; if (bindings.length === BindingCount.NoBindingsAvailable && context.container.options.autoBindInjectable && typeof target.serviceIdentifier === 'function' && metadataReader.getConstructorMetadata(target.serviceIdentifier).compilerGeneratedMetadata) { context.container.bind(target.serviceIdentifier).toSelf(); bindings = getBindings(context.container, target.serviceIdentifier); } if (!avoidConstraints) { activeBindings = bindings.filter(function (binding) { var request = new Request(binding.serviceIdentifier, context, parentRequest, binding, target); return binding.constraint(request); }); } else { activeBindings = bindings; } _validateActiveBindingCount(target.serviceIdentifier, activeBindings, target, context.container); return activeBindings; } function _validateActiveBindingCount(serviceIdentifier, bindings, target, container) { switch (bindings.length) { case BindingCount.NoBindingsAvailable: if (target.isOptional()) { return bindings; } else { var serviceIdentifierString = getServiceIdentifierAsString(serviceIdentifier); var msg = ERROR_MSGS.NOT_REGISTERED; msg += listMetadataForTarget(serviceIdentifierString, target); msg += listRegisteredBindingsForServiceIdentifier(container, serviceIdentifierString, getBindings); throw new Error(msg); } case BindingCount.OnlyOneBindingAvailable: return bindings; case BindingCount.MultipleBindingsAvailable: default: if (!target.isArray()) { var serviceIdentifierString = getServiceIdentifierAsString(serviceIdentifier); var msg = ERROR_MSGS.AMBIGUOUS_MATCH + " " + serviceIdentifierString; msg += listRegisteredBindingsForServiceIdentifier(container, serviceIdentifierString, getBindings); throw new Error(msg); } else { return bindings; } } } function _createSubRequests(metadataReader, avoidConstraints, serviceIdentifier, context, parentRequest, target) { var activeBindings; var childRequest; if (parentRequest === null) { activeBindings = _getActiveBindings(metadataReader, avoidConstraints, context, null, target); childRequest = new Request(serviceIdentifier, context, null, activeBindings, target); var thePlan = new Plan(context, childRequest); context.addPlan(thePlan); } else { activeBindings = _getActiveBindings(metadataReader, avoidConstraints, context, parentRequest, target); childRequest = parentRequest.addChildRequest(target.serviceIdentifier, activeBindings, target); } activeBindings.forEach(function (binding) { var subChildRequest = null; if (target.isArray()) { subChildRequest = childRequest.addChildRequest(binding.serviceIdentifier, binding, target); } else { if (binding.cache) { return; } subChildRequest = childRequest; } if (binding.type === BindingTypeEnum.Instance && binding.implementationType !== null) { var dependencies = getDependencies(metadataReader, binding.implementationType); if (!context.container.options.skipBaseClassChecks) { var baseClassDependencyCount = getBaseClassDependencyCount(metadataReader, binding.implementationType); if (dependencies.length < baseClassDependencyCount) { var error = ERROR_MSGS.ARGUMENTS_LENGTH_MISMATCH(getFunctionName(binding.implementationType)); throw new Error(error); } } dependencies.forEach(function (dependency) { _createSubRequests(metadataReader, false, dependency.serviceIdentifier, context, subChildRequest, dependency); }); } }); } function getBindings(container, serviceIdentifier) { var bindings = []; var bindingDictionary = getBindingDictionary(container); if (bindingDictionary.hasKey(serviceIdentifier)) { bindings = bindingDictionary.get(serviceIdentifier); } else if (container.parent !== null) { bindings = getBindings(container.parent, serviceIdentifier); } return bindings; } function plan(metadataReader, container, isMultiInject, targetType, serviceIdentifier, key, value, avoidConstraints) { if (avoidConstraints === void 0) { avoidConstraints = false; } var context = new Context(container); var target = _createTarget(isMultiInject, targetType, serviceIdentifier, '', key, value); try { _createSubRequests(metadataReader, avoidConstraints, serviceIdentifier, context, null, target); return context; } catch (error) { if (isStackOverflowExeption(error)) { circularDependencyToException(context.plan.rootRequest); } throw error; } } function createMockRequest(container, serviceIdentifier, key, value) { var target = new Target(TargetTypeEnum.Variable, '', serviceIdentifier, new Metadata(key, value)); var context = new Context(container); var request = new Request(serviceIdentifier, context, null, [], target); return request; } export { plan, createMockRequest, getBindingDictionary };