UNPKG

@stone-js/pipeline

Version:

An implementation based on the Chain of Responsibility (aka CoR) design pattern.

405 lines (400 loc) 15.8 kB
/** * Represents a Promiseable type. */ type Promiseable<T> = T | Promise<T>; /** * A string type that represents a pipe alias. */ type PipeAlias = string; /** * A class type that represents a pipe. */ type PipeClass<T = unknown, R = T, Args extends any[] = any[]> = new (...args: Args) => PipeInstance<T, R>; /** * A function type that represents a pipe. */ type FunctionalPipe<T = unknown, R = T> = (passable: T, next: PipeExecutor<T, R>, ...params: any[]) => Promiseable<R>; /** * A factory function type that represents a pipe. */ type FactoryPipe<T = unknown, R = T, Args extends any[] = any[]> = (...args: Args) => FunctionalPipe<T, R>; /** * A type that can either be a function or a string, representing a pipeline step. * * A pipe can either be a function that performs an action or a string identifier to be resolved. */ type PipeType<T = unknown, R = T, Args extends any[] = any[]> = PipeAlias | PipeClass<T, R, Args> | FunctionalPipe<T, R> | FactoryPipe<T, R, Args>; /** * A mixed type that can be either a simple Pipe or a MetaPipe configuration. */ type MixedPipe<T = unknown, R = T, Args extends any[] = any[]> = PipeType<T, R, Args> | MetaPipe<T, R, Args>; /** * Pipe Executor function type. * * @param passable - The passable objects being sent through the pipeline. * @returns The result of the execution, which could be a synchronous or asynchronous response. * * @template T - The type of the passable object. * @template R - The type of the return value from the pipeline execution, defaulting to `T`. */ type PipeExecutor<T = unknown, R = T> = (passable: T) => Promiseable<R>; /** * Next Pipe Executor function type. * * @param passable - The passable objects being sent through the pipeline. * @returns The result of the execution, which could be a synchronous or asynchronous response. * * @template T - The type of the passable object. * @template R - The type of the return value from the pipeline execution, defaulting to `T`. */ type NextPipe<T = unknown, R = T> = PipeExecutor<T, R>; /** * Reducer callback function type used to build a sequence of pipe executions. * * @param previousPipeExecutor - The executor from the previous step in the pipeline. * @param currentPipe - The current pipe being added to the sequence. * @returns The combined executor function. * * @template T - The type of the passable object. * @template R - The type of the return value from the pipeline execution, defaulting to `T`. */ type ReducerCallback<T = unknown, R = T, Args extends any[] = any[]> = (previousPipeExecutor: PipeExecutor<T, R>, currentPipe: MetaPipe<T, R, Args>) => PipeExecutor<T, R>; /** * A function type that represents a resolver for a given pipe. * * @typeParam T - The type of the passable object in the pipeline. * @typeParam R - The type of the return value from the resolved pipe, which defaults to `T`. * @param pipe - The pipe that needs to be resolved, which can be either a simple pipe or a MetaPipe. * @returns The resolved pipe instance of type `PipeInstance<T, R> | undefined`. * * This type is used to provide a custom mechanism for resolving pipes before they are executed in the pipeline. */ type PipeResolver<T = unknown, R = T, Args extends any[] = any[]> = (pipe: MetaPipe<T, R, Args>) => PipeInstance<T, R> | undefined; /** * ConfigContextOptions. */ interface PipelineOptions<T = unknown, R = T, Args extends any[] = any[]> { hooks?: PipelineHook<T, R, Args>; resolver?: PipeResolver<T, R, Args>; } /** * Represents a pipe instance that contains different pipe functions. * * @template T - The type of the passable object. * @template R - The type of the return value from the pipeline execution, defaulting to `T`. * * An object representing a set of functions used as part of the pipeline. * The keys represent function names, and the values are functions that take specific arguments. */ type PipeInstance<T = unknown, R = T> = PipeDefaultInstance<T, R> | PipeCustomInstance<T, R> | object; /** * Represents a pipe instance that contains a default pipe function. * * @template T - The type of the passable object. * @template R - The type of the return value from the pipeline execution, defaulting to `T`. * * An object representing a default function used as part of the pipeline. * The key is the `handle` property, which is a function that takes specific arguments. */ interface PipeDefaultInstance<T = unknown, R = T> { handle: FunctionalPipe<T, R>; } /** * Represents a pipe instance that contains different pipe functions. * * @template T - The type of the passable object. * @template R - The type of the return value from the pipeline execution, defaulting to `T`. * * An object representing a set of functions used as part of the pipeline. * The keys represent function names, and the values are functions that take specific arguments. */ interface PipeCustomInstance<T = unknown, R = T> { [key: string]: FunctionalPipe<T, R>; } /** * Represents a MetaPipe configuration item, with a pipe, parameters, and priority level. * * A configuration object used for managing pipes in the pipeline. */ interface MetaPipe<T = unknown, R = T, Args extends any[] = any[]> { /** The pipe to execute, which can be a function or a string identifier. */ module: PipeType<T, R, Args>; /** An optional array of parameters to pass to the pipe. */ params?: any[]; /** An optional priority level of the pipe. */ priority?: number; /** An optional flag indicating whether the pipe is a class. */ isClass?: boolean; /** An optional flag indicating whether the pipe is a container alias. */ isAlias?: boolean; /** An optional flag indicating whether the pipe is a factory. */ isFactory?: boolean; } /** * HookName Type. */ type HookName = 'onProcessingPipe' | 'onPipeProcessed'; /** * Hook Type. * * Represents a hook that can either be synchronous or asynchronous. */ type PipelineHook<T = unknown, R = T, Args extends any[] = any[]> = Record<HookName, Array<PipelineHookListener<T, R, Args>>>; /** * PipelineHookContext Type. */ interface PipelineHookContext<T = unknown, R = T, Args extends any[] = any[]> { passable: T; pipe: MetaPipe<T, R, Args>; instance: PipeCustomInstance<T, R>; pipes: Array<MetaPipe<T, R, Args>>; } /** * PipelineHookListener Type. * * Represents a listener hook that can either be synchronous or asynchronous. */ type PipelineHookListener<T = unknown, R = T, Args extends any[] = any[]> = (context: PipelineHookContext<T, R, Args>) => Promiseable<void>; /** * Class representing a Pipeline. * * @template T - The type of the passable object in the pipeline. * @template R - The type of the return value from the pipeline execution. * * This class is responsible for managing and executing a series of operations * on a set of passable values through multiple configurable pipes. */ declare class Pipeline<T = unknown, R = T, Args extends any[] = any[]> { /** The passable objects sent through the pipeline */ private passable?; /** The method name to call on each pipe */ private method; /** Flag indicating whether the pipeline should run synchronously or asynchronously */ private isSync; /** The default priority for the pipes in the pipeline */ private _defaultPriority; /** The sorted metadata pipes that will be executed */ private sortedMetaPipes; /** The pipeline hooks */ private readonly hooks; /** The resolver function used to resolve pipes before they are executed in the pipeline. */ private readonly resolver?; /** * Create a pipeline instance. * * @param options - Optional Pipeline options. * @returns The pipeline instance. */ static create<T = unknown, R = T, Args extends any[] = any[]>(options?: PipelineOptions<T, R, Args>): Pipeline<T, R>; /** * Initialize a new Pipeline instance. * * @param options - Optional Pipeline options. */ protected constructor(options?: PipelineOptions<T, R, Args>); /** * Set the default priority for pipes in the pipeline. * * @param value - The priority value to set. * @returns The current Pipeline instance. */ defaultPriority(value: number): this; /** * Set the passable objects being sent through the pipeline. * * @param passable - The object to pass through the pipeline. * @returns The current Pipeline instance. */ send(passable: T): this; /** * Set the pipes for the pipeline. * * @param pipes - The pipes or MetaPipe instances. * @returns The current Pipeline instance. */ through(...pipes: Array<MixedPipe<T, R, Args>>): this; /** * Add additional pipes to the pipeline. * * @param {...MixedPipe} pipe - A single pipe or a list of pipes to add. * @returns The current Pipeline instance. */ pipe(...pipe: Array<MixedPipe<T, R, Args>>): this; /** * Set the method to call on each pipe. * * @param method - The method name to use on each pipe. * @returns The current Pipeline instance. */ via(method: string): this; /** * Configure the pipeline to run synchronously or asynchronously. * * @param value - Set true for sync, false for async (default is true). * @returns The current Pipeline instance. */ sync(value?: boolean): this; /** * Add a hook to the pipeline. * * @param name - The name of the hook. * @param listener - The hook listener function. * @returns The current Pipeline instance. */ on(name: HookName, listener: PipelineHookListener<T, R, Args> | Array<PipelineHookListener<T, R, Args>>): this; /** * Run the pipeline with a final destination callback. * * @param destination - The final function to execute. * @returns The result of the pipeline, either synchronously or as a Promise. */ then(destination: PipeExecutor<T, R>): Promiseable<R>; /** * Run the pipeline and return the result. * * @returns The result of the pipeline, either synchronously or as a Promise. */ thenReturn(): Promiseable<R>; /** * Get the asynchronous reducer to iterate over the pipes. * * @returns The asynchronous reducer callback. */ private asyncReducer; /** * Get the synchronous reducer to iterate over the pipes. * * @returns The synchronous reducer callback. */ private reducer; /** * Resolve and execute async pipe. * * @param currentPipe - The current pipe to execute (class or service alias string). * @param passable - The passable object to send through the pipe. * @param previousPipeExecutor - The previous pipe executor in the sequence. * @returns The result of the pipe execution. * @throws PipelineError If the pipe cannot be resolved or the method is missing. */ private executeAsyncPipe; /** * Resolve and execute a pipe. * * @param currentPipe - The current pipe to execute (class or service alias string). * @param passable - The passable object to send through the pipe. * @param previousPipeExecutor - The previous pipe executor in the sequence. * @returns The result of the pipe execution. * @throws PipelineError If the pipe cannot be resolved or the method is missing. */ private executePipe; /** * Resolve pipe. * * @param currentPipe - The current pipe to execute (class or service alias string). * @returns The resolved pipe instance. * @throws PipelineError If the pipe cannot be resolved or the method is missing. */ private resolvePipe; /** * Create an instance from the provided pipe. * * @param currentPipe - The pipe function to create an instance from. * @returns The created instance or an object with the method. */ private createInstanceFromPipe; /** * Validate that the required method exists on the instance. * * @param instance - The instance to validate. * @param currentPipe - The current pipe being executed. * @throws {PipelineError} If the method does not exist on the instance. */ private validatePipeMethod; /** * Execute lifecycle async hooks. * * @param name - The hook's name. * @param pipe - The current pipe instance. */ private executeAsyncHooks; /** * Execute lifecycle hooks. * * @param name - The hook's name. * @param pipe - The current pipe instance. */ private executeHooks; } /** * Custom error for pipeline operations. */ declare class PipelineError extends Error { constructor(message: string); } /** * Define a new middleware for the pipeline. * * @param module - The pipe module to add to the pipeline. * @param options - Additional options for the middleware. * @returns The metadata for the middleware. */ declare const defineMiddleware: <T = unknown, R = T, Args extends any[] = any[]>(module: PipeType<T, R, Args>, options?: Omit<MetaPipe<T, R, Args>, "module">) => MetaPipe<T, R, Args>; /** * Check if the value is a string. * * @param value - The value to check. * @returns `true` if the value is an string, otherwise `false`. */ declare const isString: (value: unknown) => value is string; /** * Check if the value is a function. * * @param value - The value to check. * @returns `true` if the value is a function, otherwise `false`. */ declare const isFunction: <ClassType = Function>(value: unknown) => value is ClassType; /** * Checks if the given value is a constructor function. * * @param value - The value to be checked. * @returns True if the value is a constructor function, false otherwise. */ declare const isConstructor: <ClassType = any>(value: unknown) => value is new (...args: any[]) => ClassType; /** * Check if the meta pipe is a function pipe. * * @param metaPipe - The meta pipe to check. * @returns `true` if the meta pipe is a function pipe, otherwise `false`. */ declare const isFunctionPipe: <T = unknown, R = T, Args extends any[] = any[]>(metaPipe: MetaPipe<T, R, Args>) => metaPipe is { module: FunctionalPipe<T, R>; }; /** * Check if the meta pipe is an alias pipe. * * @param metaPipe - The meta pipe to check. * @returns `true` if the meta pipe is an alias pipe, otherwise `false`. */ declare const isAliasPipe: <T = unknown, R = T, Args extends any[] = any[]>(metaPipe: MetaPipe<T, R, Args>) => metaPipe is { module: PipeAlias; }; /** * Check if the meta pipe is a class pipe. * * @param metaPipe - The meta pipe to check. * @returns `true` if the meta pipe is a class pipe, otherwise `false`. */ declare const isClassPipe: <T = unknown, R = T, Args extends any[] = any[]>(metaPipe: MetaPipe<T, R, Args>) => metaPipe is { module: PipeClass<T, R, Args>; }; /** * Check if the meta pipe is a factory pipe. * * @param metaPipe - The meta pipe to check. * @returns `true` if the meta pipe is a factory pipe, otherwise `false`. */ declare const isFactoryPipe: <T = unknown, R = T, Args extends any[] = any[]>(metaPipe: MetaPipe<T, R, Args>) => metaPipe is { module: FactoryPipe<T, R, Args>; }; export { Pipeline, PipelineError, defineMiddleware, isAliasPipe, isClassPipe, isConstructor, isFactoryPipe, isFunction, isFunctionPipe, isString }; export type { FactoryPipe, FunctionalPipe, HookName, MetaPipe, MixedPipe, NextPipe, PipeAlias, PipeClass, PipeCustomInstance, PipeDefaultInstance, PipeExecutor, PipeInstance, PipeResolver, PipeType, PipelineHook, PipelineHookContext, PipelineHookListener, PipelineOptions, Promiseable, ReducerCallback };