{"version":3,"file":"FunctionUtils.mjs","sources":["../src/FunctionUtils.ts"],"sourcesContent":["/**\n * Utility functions for function manipulation and optimization.\n *\n * This module provides a collection of utility functions for working with functions,\n * including composition, debouncing, throttling, and more.\n *\n * @module FunctionUtils\n * @example\n * ```typescript\n * // Compose multiple functions\n * const addOne = (x: number) => x + 1;\n * const double = (x: number) => x * 2;\n * const addOneAndDouble = FunctionUtils.compose(double, addOne);\n *\n * // Debounce a function\n * const debouncedSearch = FunctionUtils.debounce(searchFunction, 300);\n *\n * // Throttle a function\n * const throttledScroll = FunctionUtils.throttle(handleScroll, 100);\n * ```\n */\n\nexport const FunctionUtils = {\n  /**\n   * Composes multiple functions into a single function, where the output\n   * of each function is passed as input to the next function.\n   *\n   * @template T - The type of the input to the first function\n   * @template R - The type of the output of the last function\n   * @param funcs - The functions to compose\n   * @returns A function that is the composition of all provided functions\n   *\n   * @example\n   * ```typescript\n   * const addOne = (x: number) => x + 1;\n   * const double = (x: number) => x * 2;\n   * const addOneAndDouble = FunctionUtils.compose(double, addOne);\n   * addOneAndDouble(5); // Returns 12 (5 + 1 = 6, then 6 * 2 = 12)\n   * ```\n   */\n  compose<T, R>(...funcs: Array<(arg: any) => any>): (arg: T) => R {\n    return function (this: any, arg: T): R {\n      return funcs.reduceRight(\n        (result, func) => func(result),\n        arg as unknown\n      ) as R;\n    };\n  },\n\n  /**\n   * Creates a debounced function that delays invoking the provided function\n   * until after the specified wait time has elapsed since the last time it was invoked.\n   *\n   * @template T - The type of the function's arguments\n   * @template R - The return type of the function\n   * @param func - The function to debounce\n   * @param waitTime - The number of milliseconds to delay\n   * @param immediate - If true, the function will be called on the leading edge instead of the trailing edge\n   * @returns A debounced version of the provided function\n   *\n   * @example\n   * ```typescript\n   * const debouncedSearch = FunctionUtils.debounce((query: string) => {\n   *   // Perform search\n   * }, 300);\n   *\n   * // Will only execute after 300ms of no calls\n   * debouncedSearch(\"test\");\n   * ```\n   */\n  debounce<T extends any[], R>(\n    func: (...args: T) => R,\n    waitTime: number = 1000,\n    immediate: boolean = false\n  ): (...args: T) => R | undefined {\n    let debounceTimeout: ReturnType<typeof setTimeout> | null = null;\n\n    return function (this: any, ...args: T): R | undefined {\n      const context = this;\n\n      const later = function (): void {\n        debounceTimeout = null;\n        if (!immediate) {\n          func.apply(context, args);\n        }\n      };\n\n      const callNow = immediate && !debounceTimeout;\n\n      if (debounceTimeout) {\n        clearTimeout(debounceTimeout);\n      }\n\n      debounceTimeout = setTimeout(later, waitTime);\n\n      if (callNow) {\n        return func.apply(context, args);\n      }\n    };\n  },\n\n  /**\n   * Creates a function that delays invoking the provided function\n   * until the current call stack has cleared.\n   *\n   * @template T - The type of the function's arguments\n   * @template R - The return type of the function\n   * @param func - The function to defer\n   * @returns A deferred version of the provided function\n   *\n   * @example\n   * ```typescript\n   * const deferredLog = FunctionUtils.defer((message: string) => {\n   *   console.log(message);\n   * });\n   *\n   * // Will execute after current execution context\n   * deferredLog(\"Hello\");\n   * ```\n   */\n  defer<T extends any[], R>(func: (...args: T) => R): (...args: T) => void {\n    return function (this: any, ...args: T): void {\n      setTimeout(() => func.apply(this, args), 0);\n    };\n  },\n\n  /**\n   * Creates a function that can only be called once. Subsequent calls\n   * will return the result of the first call.\n   *\n   * @template T - The type of the function's arguments\n   * @template R - The return type of the function\n   * @param func - The function to make callable only once\n   * @returns A function that can only be called once\n   *\n   * @example\n   * ```typescript\n   * const initialize = FunctionUtils.once(() => {\n   *   // Expensive initialization\n   *   return \"initialized\";\n   * });\n   *\n   * initialize(); // Returns \"initialized\"\n   * initialize(); // Returns \"initialized\" without executing the function again\n   * ```\n   */\n  once<T extends any[], R>(func: (...args: T) => R): (...args: T) => R {\n    let called = false;\n    let result: R;\n\n    return function (this: any, ...args: T): R {\n      if (!called) {\n        called = true;\n        result = func.apply(this, args);\n      }\n      return result;\n    };\n  },\n\n  /**\n   * Creates a throttled function that only invokes the provided function\n   * at most once per every wait milliseconds.\n   *\n   * @template T - The type of the function's arguments\n   * @template R - The return type of the function\n   * @param func - The function to throttle\n   * @param waitTime - The number of milliseconds to throttle invocations to\n   * @returns A throttled version of the provided function\n   *\n   * @example\n   * ```typescript\n   * const throttledScroll = FunctionUtils.throttle(() => {\n   *   // Handle scroll event\n   * }, 100);\n   *\n   * // Will execute at most once every 100ms\n   * window.addEventListener('scroll', throttledScroll);\n   * ```\n   */\n  throttle<T extends any[], R>(\n    func: (...args: T) => R,\n    waitTime: number = 1000\n  ): (...args: T) => R | undefined {\n    let lastCall = 0;\n\n    return function (this: any, ...args: T): R | undefined {\n      const now = Date.now();\n      if (now - lastCall >= waitTime) {\n        lastCall = now;\n        return func.apply(this, args);\n      }\n    };\n  },\n};\n"],"names":[],"mappings":"AAsBO,MAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkB3B,WAAiB,OAAgD;AAC/D,WAAO,SAAqB,KAAW;AACrC,aAAO,MAAM;AAAA,QACX,CAAC,QAAQ,SAAS,KAAK,MAAM;AAAA,QAC7B;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,SACE,MACA,WAAmB,KACnB,YAAqB,OACU;AAC/B,QAAI,kBAAwD;AAE5D,WAAO,YAAwB,MAAwB;AACrD,YAAM,UAAU;AAEhB,YAAM,QAAQ,WAAkB;AAC9B,0BAAkB;AAClB,YAAI,CAAC,WAAW;AACd,eAAK,MAAM,SAAS,IAAI;AAAA,QAC1B;AAAA,MACF;AAEA,YAAM,UAAU,aAAa,CAAC;AAE9B,UAAI,iBAAiB;AACnB,qBAAa,eAAe;AAAA,MAC9B;AAEA,wBAAkB,WAAW,OAAO,QAAQ;AAE5C,UAAI,SAAS;AACX,eAAO,KAAK,MAAM,SAAS,IAAI;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,MAA0B,MAA+C;AACvE,WAAO,YAAwB,MAAe;AAC5C,iBAAW,MAAM,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,KAAyB,MAA4C;AACnE,QAAI,SAAS;AACb,QAAI;AAEJ,WAAO,YAAwB,MAAY;AACzC,UAAI,CAAC,QAAQ;AACX,iBAAS;AACT,iBAAS,KAAK,MAAM,MAAM,IAAI;AAAA,MAChC;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,SACE,MACA,WAAmB,KACY;AAC/B,QAAI,WAAW;AAEf,WAAO,YAAwB,MAAwB;AACrD,YAAM,MAAM,KAAK,IAAA;AACjB,UAAI,MAAM,YAAY,UAAU;AAC9B,mBAAW;AACX,eAAO,KAAK,MAAM,MAAM,IAAI;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;"}