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: if (!target.isArray()) { 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)) { if (context.plan) { 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 };