import { Token } from './token.class'; import { ServiceIdentifier } from './types/service-identifier.type'; import { ServiceMetadata } from './interfaces/service-metadata.interface'; import { ServiceOptions, ServiceOptionsWithDependencies } from './interfaces/service-options.interface'; import { ContainerIdentifier } from './types/container-identifier.type'; import { Disposable } from './types/disposable.type'; import { Resolvable } from './interfaces/resolvable.interface'; import { ContainerResetOptions } from './interfaces/container-reset-options.interface'; import { ContainerTreeVisitor } from './interfaces/tree-visitor.interface'; import { CreateContainerOptions } from './interfaces/create-container-options.interface'; import { CreateContainerResult } from './types/create-container-result.type'; export declare const enum ServiceIdentifierLocation { Local = "local", Parent = "parent", None = "none" } /** * An instance of a TypeDI container. * * A container allows you to get, set, and modify dependencies in-place. * You can also attach individual services to a container, using them * to store services for later execution. * * @example * ```ts * const container = defaultContainer.ofChild('my-new-container'); * * @Service({ container }) * class MyService { } * ``` */ export declare class ContainerInstance implements Disposable { readonly parent?: ContainerInstance | undefined; /** The ID of this container. This will always be unique. */ readonly id: ContainerIdentifier; /** Metadata for all registered services in this container. */ private readonly metadataMap; /** * Services registered with 'multiple: true' are saved as simple services * with a generated token and the mapping between the original ID and the * generated one is stored here. This is handled like this to allow simplifying * the inner workings of the service instance. */ private readonly multiServiceIds; /** * Indicates if the container has been disposed or not. * Any function call should fail when called after being disposed. */ readonly disposed: boolean; /** * The default global container. By default services are registered into this * container when registered via `Container.set()` or `@Service` decorator. */ static readonly defaultContainer: ContainerInstance; /** * The currently-present visitors attached to the container. * These are conjoined into a container of individual visitors, * which implements the standard ContainerTreeVisitor interface, * and individual listeners can be added and removed at will. * * @see {@link ContainerTreeVisitor} * @see {@link VisitorCollection} */ private visitor; /** * Whether the container is currently retrieving an identifier * which visitors should not be notified of. * * This is used to prevent {@link ContainerInstance.getManyOrNull} * from notifying visitors that it is retrieving a masked token, * which is used to store services of `{ multiple: true }`. */ private isRetrievingPrivateToken; /** * Create a ContainerInstance. * * @param id The ID of the container to create. * @param parent The parent of the container to create. * The parent is used for resolving identifiers which are * not present in this container. */ protected constructor(id: ContainerIdentifier, parent?: ContainerInstance | undefined); /** * Checks if the service with given name or type is registered service container. * Optionally, parameters can be passed in case if instance is initialized in the container for the first time. * * If recursive mode is enabled, the symbol is not available locally, and we have a parent, * we tell the parent to search its tree recursively too. * If the container tree is substantial, this operation may affect performance. * * @param identifier The identifier of the service to look up. * * @returns Whether the identifier is present in the current container, or its parent. * * @throws Error * This exception is thrown if the container has been disposed. */ has(identifier: ServiceIdentifier, recursive?: boolean): boolean; /** * Return the location of the given identifier. * If recursive mode is enabled, the symbol is not available locally, and we have a parent, * we tell the parent to search its tree recursively too. * If the container tree is substantial, this operation may affect performance. * * @param identifier The identifier of the service to look up. * * @returns A {@link ServiceIdentifierLocation}. * - If the identifier cannot be found, {@link ServiceIdentifierLocation.None | None}. * - If the identifier is found locally, {@link ServiceIdentifierLocation.Local | Local}. * - If the identifier is found upstream, {@link ServiceIdentifierLocation.Parent | Parent}. * * @throws Error * This exception is thrown if the container has been disposed. */ protected getIdentifierLocation(identifier: ServiceIdentifier): ServiceIdentifierLocation; /** * Get the value for the identifier in the current container. * If the identifier cannot be resolved locally, the parent tree * (if present) is recursively searched until a match is found * (or the tree is exhausted). * * @param identifier The identifier to get the value of. * * @returns The value of the identifier in the current scope. * * @throws ServiceNotFoundError * This exception is thrown if the identifier cannot be found in the tree. * * @throws Error * This exception is thrown if the container has been disposed. */ get(identifier: ServiceIdentifier, recursive?: boolean): T; /** * Resolve the metadata for the given identifier. Returns null if no metadata could be found. * * @param identifier The identifier to resolve metadata for. * @param recursive Whether the lookup operation is recursive. * * @returns * If the identifier is found, a tuple is returned consisting of the following: * 1. The metadata for the given identifier, if found. * 2. The location from where the metadata was returned. * {@link ServiceIdentifierLocation.Parent} is returned if the identifier was found upstream. * * If an identifier cannot be found, `null` is returned. * * @throws Error * This exception is thrown if the container has been disposed. */ protected resolveMetadata(identifier: ServiceIdentifier, recursive: boolean): readonly [ServiceMetadata, ServiceIdentifierLocation] | null; /** * Retrieves the service with given name or type from the service container. * Optionally, parameters can be passed in case if instance is initialized in the container for the first time. * * @param identifier The identifier to get the value of. * * @returns The resolved value for the given metadata, or `null` if it could not be found. * * @throws Error * This exception is thrown if the container has been disposed. */ getOrNull(identifier: ServiceIdentifier, recursive?: boolean): T | null; /** * Gets all instances registered in the container of the given service identifier. * Used when service are defined with the `{ multiple: true }` option. * * @example * ```ts * Container.set({ id: 'key', value: 1, dependencies: [ ], multiple: true }); * Container.set({ id: 'key', value: 2, dependencies: [ ], multiple: true }); * Container.set({ id: 'key', value: 3, dependencies: [ ], multiple: true }); * * const [one, two, three] = Container.getMany('key'); * ``` * * @param identifier The identifier to resolve. * * @returns An array containing the service instances for the given * identifier. * * @throws ServiceNotFoundError * This exception is thrown if a value could not be found for the given identifier. * * @throws Error * This exception is thrown if the container has been disposed. */ getMany(identifier: ServiceIdentifier, recursive?: boolean): T[]; /** * Gets all instances registered in the container of the given service identifier. * Used when service are defined with the `{ multiple: true }` option. * * @example * Here's an example: * ```ts * assert(container.getManyOrNull(UNKNOWN_TOKEN) === null); * assert(Array.isArray(container.getManyOrNull(KNOWN_TOKEN))); * ``` * * @param identifier The identifier to resolve. * * @see {@link ContainerInstance.getMany} * * @returns An array containing the service instances for the given identifier. * If none can be found, `null` is returned. * * @throws Error * This exception is thrown if the container has been disposed. */ getManyOrNull(identifier: ServiceIdentifier, recursive?: boolean): T[] | null; /** * Add a service to the container using the provided options, along with * a pre-wrapped list of dependencies. * * _This is mainly for internal use._ * * @param serviceOptions The options for the service to add to the container. * @param precompiledDependencies A precompiled list of dependencies in {@link TypeWrapper} form for the given service. * * @returns The identifier of the given service in the container. * This can then be passed to {@link ContainerInstance.get | .get} to resolve the identifier. * * @throws Error * This exception is thrown if the container has been disposed. */ set(serviceOptions: Omit, 'dependencies'>, precompiledDependencies: Resolvable[]): ServiceIdentifier; /** * Add a service to the container using the provided options, containing * all information about the new service including its dependencies. * * @param serviceOptions The options for the service to add to the container. * * @returns The identifier of the given service in the container. * This can then be passed to {@link ContainerInstance.get | .get} to resolve the identifier. * * @throws Error * This exception is thrown if the container has been disposed. */ set(serviceOptions: ServiceOptionsWithDependencies): ServiceIdentifier; /** * Add a value to the container. * * @example * ```ts * // We can simplify this: * Container.set({ id: 'key', value: 'test', dependencies: [ ] }); * // To this: * Container.setValue('key', 'test'); * ``` * * @param id The ID of the new value to set inside the container. * Must be either a string or a Token. * * @param value The value to set the ID to. * * @returns The identifier of the given service in the container. * This can then be passed to {@link ContainerInstance.get | .get} to resolve the identifier. */ setValue, TValue extends TServiceID extends Token ? U : unknown>(id: TServiceID, value: TValue): ServiceIdentifier; /** * Removes services with the given list of service identifiers. * * @param identifierOrIdentifierArray The list of service identifiers to remove from the container. * * @example * Here's an example: * ```ts * const NAME = new Token(); * * // Set a new identifier in the container: * defaultContainer.setValue(NAME, 'Joanna'); * assert(defaultContainer.get(NAME) === 'Joanna'); * * // Now remove it, making the container forget it ever existed: * defaultContainer.remove(NAME); * assert(defaultContainer.getOrNull(NAME) === null); * ``` * * @returns The current {@link ContainerInstance} instance. * * @throws Error * This exception is thrown if the container has been disposed. */ remove(identifierOrIdentifierArray: ServiceIdentifier | ServiceIdentifier[]): this; /** * Gets a separate container instance for the given instance id. * Optionally, a parent can be passed, which will act as an upstream resolver for the container. * * @remarks This is functionally equivalent to {@link ContainerInstance.of}. * However, it allows container creation from a static interface. * * @example * ```ts * // Create a container which has the default container as its parent: * ContainerInstance.of('my-new-container'); * * // Create a container without a parent: * ContainerInstance.of('my-new-container-without-a-parent', null); * * // Create a container with a separate container: * ContainerInstance.of('my-new-special-container', myOtherContainer); * ``` * * @param containerId The ID of the container to resolve or create. Defaults to "default". * @param parent The parent of the container, or null to explicitly signal that one should not be provided. * Defaults to the default container. * @param options The options to supplement how the container is created. * * @see {@link CreateContainerOptions} * * @returns The newly-created {@link ContainerInstance}, or the pre-existing container with the same name * if one already exists. */ static of(containerId?: ContainerIdentifier, parent?: ContainerInstance | null, options?: TOptions): CreateContainerResult; /** * Gets a separate container instance for the given instance id. * * @param containerId The ID of the container to resolve or create. Defaults to "default". * * @example * ``` * const newContainer = Container.of('foo'); * * @Service({ container: newContainer }, []) * class MyService {} * ``` * * @returns The newly-created {@link ContainerInstance}, or the pre-existing container * with the same name if one already exists. */ of(containerId?: ContainerIdentifier, options?: TOptions): CreateContainerResult; /** * Create a registry with the specified ID, with this instance as its parent. * * @param containerId The ID of the container to resolve or create. Defaults to "default". * * @returns The newly-created {@link ContainerInstance}, or the pre-existing container * with the same name if one already exists. * * @throws Error * This exception is thrown if the container has been disposed. */ ofChild(containerId?: ContainerIdentifier, options?: TOptions): CreateContainerResult; /** * Completely resets the container by removing all previously registered services from it. * * @throws Error * This exception is thrown if the container has been disposed. */ reset(options?: ContainerResetOptions): this; /** * Dispose the container, rendering it unable to perform any further injection or storage. * * @remarks * It is currently not advised to dispose of the default container. * This would result in resolution issues in your application. * * @example * ```ts * const appContainer = Container.of('app'); * * appContainer.dispose().then( * () => console.log('The container has been disposed.') * ); * * appContainer.disposed === true; * * // This will throw an error: * appContainer.get( * new Token('test') * ); * ``` * * @returns A promise that resolves when the disposal process is complete. * * @throws Error * This exception is thrown if the container has been disposed. */ dispose(): Promise; private throwIfDisposed; /** * Gets the value belonging to passed in {@link ServiceMetadata} instance. * * @remarks * - If {@link ServiceMetadata.value | serviceMetadata.value} is present, it is immediately returned. * - Alternatively, the requested type is resolved to the appropriate value, * which is then saved to {@link ServiceMetadata.value | serviceMetadata.value} and returned. */ private getServiceValue; private getConstructorParameters; /** * Resolve a {@link Resolvable} object in the current container. * * @param resolvable The {@link Resolvable} to resolve. * * @returns The resolved value of the item. */ private resolveResolvable; private resolveTypeWrapper; /** * Check if the given service is able to be destroyed and, if so, destroys it in-place. * @deprecated * * @remarks * If the service contains a method named `destroy`, it is called. * However, the value it returns is ignored. * * @param serviceMetadata the service metadata containing the instance to destroy * @param force when true the service will be always destroyed even if it's cannot be re-created */ private disposeServiceInstance; /** * Add a visitor to the container. * @experimental * * @param visitor The visitor to add to this container. * * @see {@link ContainerTreeVisitor} * * @returns Whether the operation was successful. */ acceptTreeVisitor(visitor: ContainerTreeVisitor): boolean; /** * Remove a visitor from the container. * No-op if the visitor was never attached to the container. * @experimental * * @param visitor The visitor to remove from the container. * * @see {@link ContainerTreeVisitor} * * @returns Whether the operation was successful. */ detachTreeVisitor(visitor: ContainerTreeVisitor): boolean; /** Iterate over each service in the container. */ [Symbol.iterator](): IterableIterator<[ServiceIdentifier, ServiceMetadata]>; } export declare const defaultContainer: ContainerInstance;