Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | 1x 1x 35x 35x 35x 30x 11x 11x 11x 30x 35x 35x 27x 27x 27x 35x 35x | import type { Simplify, Writable } from 'type-fest'; import type { Closable } from '../../utils/common/closable.ts'; import { asClosable } from '../../utils/common/closable.ts'; /** * Base interface for objects that support resource cleanup operations. * * Defines optional `flush` and `close` methods that can be either synchronous or asynchronous, providing a foundation * for proper resource management. */ export type Finalizer = { readonly flush?: () => void | Promise<void>; readonly close?: () => void | Promise<void> }; /** * Transforms a Finalizer to have synchronous flush and close methods. * * Used for resources that don't require asynchronous cleanup operations, such as in-memory buffers or simple data * structures. * * @example * * ```ts * // Memory sink uses synchronous operations * export type MemorySink = SyncFinalizer<LogSink> & MemoryStore; * ``` */ export type SyncFinalizer<T extends Finalizer> = Omit<T, 'close'> & { readonly flush: () => void; readonly close: () => void; }; /** * Transforms a Finalizer to have asynchronous flush and close methods. * * Used for resources that require asynchronous cleanup operations, such as file operations, network connections, or * database transactions. * * @example * * ```ts * // File sink uses asynchronous operations * export type FileSink = AsyncFinalizer<LogSink> & { readonly filePath: string }; * ``` */ export type AsyncFinalizer<T extends Finalizer> = Simplify< MergeFinalizer<T, { readonly flush: () => Promise<void>; readonly close: () => Promise<void> }> >; /** * Merges two Finalizer types, combining their flush and close method signatures. * * This utility type is used internally to properly compose finalizer behaviors when combining different resource * management patterns. */ export type MergeFinalizer<TBase extends Finalizer, TFinalizer extends Finalizer> = Simplify< Omit<TBase, 'flush' | 'close'> & ForgeFinalizer<[TBase, TFinalizer]> >; /** * Combines multiple finalizers into a single finalizer that manages all of them. * * This function creates a unified finalizer that: * * - Calls `flush()` on all provided finalizers that have a flush method * - Calls `close()` on all provided finalizers that have a close method * - Automatically handles both synchronous and asynchronous operations * - Returns synchronous methods if all finalizers are synchronous, otherwise async * * @example Basic usage * * ```ts * import { asSingleFinalizer } from 'emitnlog/logger/implementation'; * * const fileSink = fileSink('app.log'); * const memorySink = memorySink(); * const combinedFinalizer = asSingleFinalizer(fileSink, memorySink); * * // Flushes both file and memory sinks * await combinedFinalizer.flush?.(); * * // Closes both sinks * await combinedFinalizer.close?.(); * ``` * * @example Used in tee logger * * ```ts * // The tee logger uses this to manage multiple underlying loggers * const finalizer = asSingleFinalizer(...loggers); * const teeLogger = { * // ... other logger methods * ...finalizer, // Adds combined flush/close methods * }; * ``` * * @param finalizers Array of finalizers to combine * @returns A single finalizer that manages all the provided finalizers */ export const asSingleFinalizer = <Fs extends readonly Finalizer[]>(...finalizers: Fs): Simplify<ForgeFinalizer<Fs>> => { const finalizer: Writable<Finalizer> = {}; const flushables = finalizers.filter((logSink) => logSink.flush); if (flushables.length) { finalizer.flush = () => { const promises = flushables.map((logSink) => logSink.flush?.()).filter((result) => result instanceof Promise); return promises.length ? Promise.all(promises).then(() => undefined) : undefined; }; } const closables: Closable[] = finalizers.filter((logSink): logSink is Closable => !!logSink.close); if (closables.length) { const combined = asClosable(...closables); finalizer.close = () => combined.close(); } return finalizer as ForgeFinalizer<Fs>; }; type FinalizerKey = 'flush' | 'close'; type _FnsOf<T, K extends FinalizerKey> = T extends { [P in K]?: infer V } ? Extract<V, () => void | Promise<void>> : never; type _MethodUnion<Fs extends readonly unknown[], K extends FinalizerKey> = _FnsOf<Fs[number], K>; type _MergeOne<Fs extends readonly unknown[], K extends FinalizerKey> = [_MethodUnion<Fs, K>] extends [never] ? { readonly [P in K]?: () => void } : // eslint-disable-next-line @typescript-eslint/no-explicit-any Extract<ReturnType<_MethodUnion<Fs, K>>, Promise<any>> extends never ? { readonly [P in K]: () => void } : { readonly [P in K]: () => Promise<void> }; /** * Creates a finalizer type by analyzing an array of objects and determining the appropriate flush and close method * signatures. * * This advanced TypeScript utility: * * - Examines all objects in the array for flush/close methods * - Returns sync methods if all methods are synchronous * - Returns async methods if any method is asynchronous * - Makes methods optional if not all objects have them * * Used internally by `asSingleFinalizer` and `MergeFinalizer` to ensure proper type safety when combining multiple * finalizers. * * @example Type behavior * * ```ts * // All sync -> sync finalizer * type SyncResult = ForgeFinalizer<[{ flush: () => void }, { close: () => void }]>; * // Result: { flush: () => void; close: () => void } * * // Mixed sync/async -> async finalizer * type AsyncResult = ForgeFinalizer<[{ flush: () => Promise<void> }, { close: () => void }]>; * // Result: { flush: () => Promise<void>; close: () => Promise<void> } * ``` */ export type ForgeFinalizer<Fs extends readonly unknown[]> = _MergeOne<Fs, 'flush'> & _MergeOne<Fs, 'close'>; |