const isPlainObject = ( value: unknown, ): value is Record => { if (typeof value !== "object" || value === null) { return false; } const prototype = Object.getPrototypeOf(value); return ( (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value) ); }; type Replacer = (value: unknown) => unknown | Promise; type ReplaceLeavesReturnValue = // eslint-disable-next-line @typescript-eslint/no-explicit-any TInput extends any[] ? unknown[] : // eslint-disable-next-line @typescript-eslint/no-explicit-any TInput extends Record ? { [P in keyof TInput]: unknown } : unknown; export const replaceLeaves = async ( input: TInput, replacer: Replacer, ): Promise> => { if (Array.isArray(input)) { const preparedProcedureArgs: unknown[] = []; for (let i = 0; i < input.length; i++) { preparedProcedureArgs[i] = await replaceLeaves(input[i], replacer); } return preparedProcedureArgs as ReplaceLeavesReturnValue; } if (isPlainObject(input)) { const preparedProcedureArgs: Record = {}; for (const key in input) { preparedProcedureArgs[key] = await replaceLeaves( input[key as keyof typeof input], replacer, ); } return preparedProcedureArgs as ReplaceLeavesReturnValue; } return (await replacer(input)) as ReplaceLeavesReturnValue; };