1import chalk from 'chalk';
2
3/**
4 * Wrap a method and profile the time it takes to execute the method using `EXPO_PROFILE`.
5 * Works best with named functions (i.e. not arrow functions).
6 *
7 * @param fn function to profile.
8 * @param functionName optional name of the function to display in the profile output.
9 */
10export function profile<IArgs extends any[], T extends (...args: IArgs) => any>(
11  fn: T,
12  functionName: string = fn.name
13): T {
14  if (!process.env['DEBUG']) {
15    return fn;
16  }
17
18  const name = chalk.dim(`⏱  [profile] ${functionName ?? 'unknown'}`);
19
20  return ((...args: IArgs) => {
21    // Start the timer.
22    console.time(name);
23
24    // Invoke the method.
25    const results = fn(...args);
26
27    // If non-promise then return as-is.
28    if (!(results instanceof Promise)) {
29      console.timeEnd(name);
30      return results;
31    }
32
33    // Otherwise await to profile after the promise resolves.
34    return new Promise<Awaited<ReturnType<T>>>((resolve, reject) => {
35      results.then(
36        (results) => {
37          resolve(results);
38          console.timeEnd(name);
39        },
40        (reason) => {
41          reject(reason);
42          console.timeEnd(name);
43        }
44      );
45    });
46  }) as T;
47}
48