UNPKG

@inversifyjs/container

Version:

InversifyJs container

339 lines 14.7 kB
import { stringifyServiceIdentifier, } from '@inversifyjs/common'; import { bindingScopeValues, bindingTypeValues, getClassMetadata, ResolvedValueElementMetadataKind, } from '@inversifyjs/core'; import { getBindingId } from '@inversifyjs/core'; import { BindingConstraintUtils } from '../../container/binding/utils/BindingConstraintUtils.js'; import { InversifyContainerError } from '../../error/models/InversifyContainerError.js'; import { InversifyContainerErrorKind } from '../../error/models/InversifyContainerErrorKind.js'; import { buildBindingIdentifier } from '../calculations/buildBindingIdentifier.js'; import { isAnyAncestorBindingConstraints } from '../calculations/isAnyAncestorBindingConstraints.js'; import { isAnyAncestorBindingConstraintsWithName } from '../calculations/isAnyAncestorBindingConstraintsWithName.js'; import { isAnyAncestorBindingConstraintsWithServiceId } from '../calculations/isAnyAncestorBindingConstraintsWithServiceId.js'; import { isAnyAncestorBindingConstraintsWithTag } from '../calculations/isAnyAncestorBindingConstraintsWithTag.js'; import { isBindingConstraintsWithName } from '../calculations/isBindingConstraintsWithName.js'; import { isBindingConstraintsWithNoNameNorTags } from '../calculations/isBindingConstraintsWithNoNameNorTags.js'; import { isBindingConstraintsWithTag } from '../calculations/isBindingConstraintsWithTag.js'; import { isMultipleResolvedValueMetadataInjectOptions } from '../calculations/isMultipleResolvedValueMetadataInjectOptions.js'; import { isNoAncestorBindingConstraints } from '../calculations/isNoAncestorBindingConstraints.js'; import { isNoAncestorBindingConstraintsWithName } from '../calculations/isNoAncestorBindingConstraintsWithName.js'; import { isNoAncestorBindingConstraintsWithServiceId } from '../calculations/isNoAncestorBindingConstraintsWithServiceId.js'; import { isNoAncestorBindingConstraintsWithTag } from '../calculations/isNoAncestorBindingConstraintsWithTag.js'; import { isNotParentBindingConstraints } from '../calculations/isNotParentBindingConstraints.js'; import { isNotParentBindingConstraintsWithName } from '../calculations/isNotParentBindingConstraintsWithName.js'; import { isNotParentBindingConstraintsWithServiceId } from '../calculations/isNotParentBindingConstraintsWithServiceId.js'; import { isNotParentBindingConstraintsWithTag } from '../calculations/isNotParentBindingConstraintsWithTag.js'; import { isParentBindingConstraints } from '../calculations/isParentBindingConstraints.js'; import { isParentBindingConstraintsWithName } from '../calculations/isParentBindingConstraintsWithName.js'; import { isParentBindingConstraintsWithServiceId } from '../calculations/isParentBindingConstraintsWithServiceId.js'; import { isParentBindingConstraintsWithTag } from '../calculations/isParentBindingConstraintsWithTag.js'; import { isResolvedValueMetadataInjectOptions } from '../calculations/isResolvedValueMetadataInjectOptions.js'; export class BindInFluentSyntaxImplementation { #binding; constructor(binding) { this.#binding = binding; } getIdentifier() { return buildBindingIdentifier(this.#binding); } inRequestScope() { this.#binding.scope = bindingScopeValues.Request; return new BindWhenOnFluentSyntaxImplementation(this.#binding); } inSingletonScope() { this.#binding.scope = bindingScopeValues.Singleton; return new BindWhenOnFluentSyntaxImplementation(this.#binding); } inTransientScope() { this.#binding.scope = bindingScopeValues.Transient; return new BindWhenOnFluentSyntaxImplementation(this.#binding); } } export class BindToFluentSyntaxImplementation { #callback; #containerModuleId; #defaultScope; #serviceIdentifier; constructor(callback, containerModuleId, defaultScope, serviceIdentifier) { this.#callback = callback; this.#containerModuleId = containerModuleId; this.#defaultScope = defaultScope; this.#serviceIdentifier = serviceIdentifier; } to(type) { const classMetadata = getClassMetadata(type); const binding = { cache: { isRight: false, value: undefined, }, id: getBindingId(), implementationType: type, isSatisfiedBy: BindingConstraintUtils.always, moduleId: this.#containerModuleId, onActivation: undefined, onDeactivation: undefined, scope: classMetadata.scope ?? this.#defaultScope, serviceIdentifier: this.#serviceIdentifier, type: bindingTypeValues.Instance, }; this.#callback(binding); return new BindInWhenOnFluentSyntaxImplementation(binding); } toSelf() { if (typeof this.#serviceIdentifier !== 'function') { throw new Error('"toSelf" function can only be applied when a newable function is used as service identifier'); } return this.to(this.#serviceIdentifier); } toConstantValue(value) { const binding = { cache: { isRight: false, value: undefined, }, id: getBindingId(), isSatisfiedBy: BindingConstraintUtils.always, moduleId: this.#containerModuleId, onActivation: undefined, onDeactivation: undefined, scope: bindingScopeValues.Singleton, serviceIdentifier: this.#serviceIdentifier, type: bindingTypeValues.ConstantValue, value, }; this.#callback(binding); return new BindWhenOnFluentSyntaxImplementation(binding); } toDynamicValue(builder) { const binding = { cache: { isRight: false, value: undefined, }, id: getBindingId(), isSatisfiedBy: BindingConstraintUtils.always, moduleId: this.#containerModuleId, onActivation: undefined, onDeactivation: undefined, scope: this.#defaultScope, serviceIdentifier: this.#serviceIdentifier, type: bindingTypeValues.DynamicValue, value: builder, }; this.#callback(binding); return new BindInWhenOnFluentSyntaxImplementation(binding); } toResolvedValue(factory, injectOptions) { const binding = { cache: { isRight: false, value: undefined, }, factory, id: getBindingId(), isSatisfiedBy: BindingConstraintUtils.always, metadata: this.#buildResolvedValueMetadata(injectOptions), moduleId: this.#containerModuleId, onActivation: undefined, onDeactivation: undefined, scope: this.#defaultScope, serviceIdentifier: this.#serviceIdentifier, type: bindingTypeValues.ResolvedValue, }; this.#callback(binding); return new BindInWhenOnFluentSyntaxImplementation(binding); } // eslint-disable-next-line @typescript-eslint/no-explicit-any toFactory(builder) { const binding = { cache: { isRight: false, value: undefined, }, factory: builder, id: getBindingId(), isSatisfiedBy: BindingConstraintUtils.always, moduleId: this.#containerModuleId, onActivation: undefined, onDeactivation: undefined, scope: bindingScopeValues.Singleton, serviceIdentifier: this.#serviceIdentifier, type: bindingTypeValues.Factory, }; this.#callback(binding); return new BindWhenOnFluentSyntaxImplementation(binding); } toService(service) { const binding = { id: getBindingId(), isSatisfiedBy: BindingConstraintUtils.always, moduleId: this.#containerModuleId, serviceIdentifier: this.#serviceIdentifier, targetServiceIdentifier: service, type: bindingTypeValues.ServiceRedirection, }; this.#callback(binding); } #buildResolvedValueMetadata(options) { const resolvedValueMetadata = { arguments: (options ?? []).map((injectOption) => { if (isResolvedValueMetadataInjectOptions(injectOption)) { if (isMultipleResolvedValueMetadataInjectOptions(injectOption)) { return { chained: injectOption.chained ?? false, kind: ResolvedValueElementMetadataKind.multipleInjection, name: injectOption.name, optional: injectOption.optional ?? false, tags: new Map((injectOption.tags ?? []).map((tag) => [ tag.key, tag.value, ])), value: injectOption.serviceIdentifier, }; } else { return { kind: ResolvedValueElementMetadataKind.singleInjection, name: injectOption.name, optional: injectOption.optional ?? false, tags: new Map((injectOption.tags ?? []).map((tag) => [ tag.key, tag.value, ])), value: injectOption.serviceIdentifier, }; } } else { return { kind: ResolvedValueElementMetadataKind.singleInjection, name: undefined, optional: false, tags: new Map(), value: injectOption, }; } }), }; return resolvedValueMetadata; } } export class BindOnFluentSyntaxImplementation { #binding; constructor(binding) { this.#binding = binding; } getIdentifier() { return buildBindingIdentifier(this.#binding); } onActivation(activation) { this.#binding.onActivation = activation; return new BindWhenFluentSyntaxImplementation(this.#binding); } onDeactivation(deactivation) { this.#binding.onDeactivation = deactivation; if (this.#binding.scope !== bindingScopeValues.Singleton) { throw new InversifyContainerError(InversifyContainerErrorKind.invalidOperation, `Binding for service "${stringifyServiceIdentifier(this.#binding.serviceIdentifier)}" has a deactivation function, but its scope is not singleton. Deactivation functions can only be used with singleton bindings.`); } return new BindWhenFluentSyntaxImplementation(this.#binding); } } export class BindWhenFluentSyntaxImplementation { #binding; constructor(binding) { this.#binding = binding; } getIdentifier() { return buildBindingIdentifier(this.#binding); } when(constraint) { this.#binding.isSatisfiedBy = constraint; return new BindOnFluentSyntaxImplementation(this.#binding); } whenAnyAncestor(constraint) { return this.when(isAnyAncestorBindingConstraints(constraint)); } whenAnyAncestorIs(serviceIdentifier) { return this.when(isAnyAncestorBindingConstraintsWithServiceId(serviceIdentifier)); } whenAnyAncestorNamed(name) { return this.when(isAnyAncestorBindingConstraintsWithName(name)); } whenAnyAncestorTagged(tag, tagValue) { return this.when(isAnyAncestorBindingConstraintsWithTag(tag, tagValue)); } whenDefault() { return this.when(isBindingConstraintsWithNoNameNorTags); } whenNamed(name) { return this.when(isBindingConstraintsWithName(name)); } whenNoParent(constraint) { return this.when(isNotParentBindingConstraints(constraint)); } whenNoParentIs(serviceIdentifier) { return this.when(isNotParentBindingConstraintsWithServiceId(serviceIdentifier)); } whenNoParentNamed(name) { return this.when(isNotParentBindingConstraintsWithName(name)); } whenNoParentTagged(tag, tagValue) { return this.when(isNotParentBindingConstraintsWithTag(tag, tagValue)); } whenParent(constraint) { return this.when(isParentBindingConstraints(constraint)); } whenParentIs(serviceIdentifier) { return this.when(isParentBindingConstraintsWithServiceId(serviceIdentifier)); } whenParentNamed(name) { return this.when(isParentBindingConstraintsWithName(name)); } whenParentTagged(tag, tagValue) { return this.when(isParentBindingConstraintsWithTag(tag, tagValue)); } whenTagged(tag, tagValue) { return this.when(isBindingConstraintsWithTag(tag, tagValue)); } whenNoAncestor(constraint) { return this.when(isNoAncestorBindingConstraints(constraint)); } whenNoAncestorIs(serviceIdentifier) { return this.when(isNoAncestorBindingConstraintsWithServiceId(serviceIdentifier)); } whenNoAncestorNamed(name) { return this.when(isNoAncestorBindingConstraintsWithName(name)); } whenNoAncestorTagged(tag, tagValue) { return this.when(isNoAncestorBindingConstraintsWithTag(tag, tagValue)); } } export class BindWhenOnFluentSyntaxImplementation extends BindWhenFluentSyntaxImplementation { #bindOnFluentSyntax; constructor(binding) { super(binding); this.#bindOnFluentSyntax = new BindOnFluentSyntaxImplementation(binding); } onActivation(activation) { return this.#bindOnFluentSyntax.onActivation(activation); } onDeactivation(deactivation) { return this.#bindOnFluentSyntax.onDeactivation(deactivation); } } export class BindInWhenOnFluentSyntaxImplementation extends BindWhenOnFluentSyntaxImplementation { #bindInFluentSyntax; constructor(binding) { super(binding); this.#bindInFluentSyntax = new BindInFluentSyntaxImplementation(binding); } inRequestScope() { return this.#bindInFluentSyntax.inRequestScope(); } inSingletonScope() { return this.#bindInFluentSyntax.inSingletonScope(); } inTransientScope() { return this.#bindInFluentSyntax.inTransientScope(); } } //# sourceMappingURL=BindingFluentSyntaxImplementation.js.map