import { FDisposable } from "./f_disposable.js"; import { FInitable, FInitableBase } from "./f_initable.js"; import { FExecutionContext } from "../execution_context/f_execution_context.js"; import { FExceptionArgument } from "../exception/index.js"; // TODO Add overloading // return FUsing( // executionContext, // () => this.create(executionContext), // <- ! initializer without executionContext // (db) => worker(db) // <- ! worker without executionContext // ); export namespace FUsing { export type ResourceInitializerWithExecutionContext = (executionContext: FExecutionContext) => T | Promise; export type ResourceInitializerWithoutExecutionContext = () => T | Promise; export type ResourceInitializer = ResourceInitializerWithExecutionContext | ResourceInitializerWithoutExecutionContext; export type WorkerWithExecutionContext = (executionContext: FExecutionContext, resource: TResource) => Result; export type WorkerWithoutExecutionContext = (resource: TResource) => Result; export type Worker = WorkerWithExecutionContext | WorkerWithoutExecutionContext; export type Result = T | Promise; } /** * @deprecated Use TypeScript 5.2 introduces a new keyword - 'using'. See https://github.com/tc39/proposal-explicit-resource-management */ export function FUsing( executionContext: FExecutionContext, resourceFactory: FUsing.ResourceInitializer, worker: FUsing.Worker ): Promise { if (!resourceFactory || typeof resourceFactory !== "function") { throw new Error("Wrong argument: resourceFactory"); } if (!worker) { throw new Error("Wrong argument: worker"); } async function workerExecutor(workerExecutorCancellationToken: FExecutionContext, disposableResource: TResource): Promise { if (disposableResource instanceof FInitableBase || "init" in disposableResource) { await (disposableResource as FInitable).init(executionContext); } try { let workerResult: FUsing.Result; if (worker.length === 1) { workerResult = (worker as FUsing.WorkerWithoutExecutionContext)(disposableResource); } else if (worker.length === 2) { workerResult = (worker as FUsing.WorkerWithExecutionContext)(workerExecutorCancellationToken, disposableResource); } else { throw new FExceptionArgument("Wrong worker function. Expect a function with 1 or 2 arguments.", "worker"); } if (workerResult instanceof Promise) { return await workerResult; } else { return workerResult; } } finally { await disposableResource.dispose(); } } const resource = resourceFactory(executionContext); if (resource instanceof Promise) { return (resource as Promise) .then(disposableInstance => workerExecutor(executionContext, disposableInstance)); } else { return workerExecutor(executionContext, resource); } }