All files / src/components/common/Error useErrorUtilities.tsx

17.5% Statements 7/40
0% Branches 0/10
14.28% Functions 1/7
18.91% Lines 7/37

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                                              309x                                                   309x 3199x       3199x         3199x                           3199x                                     3199x              
import { useCallback, useState } from "react";
import { ErrorEmitter, GiveErrorEmitter } from "./ErrorEmitter";
 
type AllFunctionsCallerType<T extends any[] = any[]> = (...args: T) => void;
 
export type CallAll = <T extends any[]>(
  ...fns: Array<AllFunctionsCallerType<Array<T>> | null | undefined>
) => void;
 
type ComponentsTree = {
  componentName: string;
  child?: ComponentsTree | null;
};
 
interface ErrorInfo {
  getComponentNameFromErrorStack: (
    stack: string | undefined | null,
  ) => string[];
  callAll: CallAll;
  logError: (error: Error, info: React.ErrorInfo) => void;
  ErrorEmitter: GiveErrorEmitter;
}
 
const parseErrorStack = (errorStack: string): ComponentsTree | null => {
  const stackLines = errorStack.split("\n");
 
  const componentRegex = /\sat\s(\S+)\s\((\S+\.js|\.tsx|\.ts):(\d+):(\d+)\)/;
 
  let currentComponent: ComponentsTree | null = null;
 
  for (const line of stackLines) {
    const match = componentRegex.exec(line);
 
    if (match) {
      if (match[1] === "RenderedRoute") break;
 
      const componentName = match[1];
      const componentNode: ComponentsTree = {
        componentName,
        child: currentComponent,
      };
 
      currentComponent = componentNode;
    }
  }
 
  return currentComponent;
};
 
export const useErrorUtilities = (): ErrorInfo => {
  const [componentStack, setComponentStack] = useState<
    string | null | undefined
  >();
 
  const callAll: CallAll = (...fns) =>
    ((...args) => {
      fns.forEach((fn) => fn && fn(...args));
    })();
 
  const logError = (error: Error, info: React.ErrorInfo): void => {
    setComponentStack(info.componentStack);
    console.error("Error occurred:", error);
 
    console.log("Error:", { err: info.componentStack });
 
    console.groupCollapsed("Error details:");
    console.log("Name:", error.name);
    console.log("Message:", error.message);
    getComponentNameFromErrorStack(info.componentStack);
 
    console.groupEnd();
  };
 
  const getComponentNameFromErrorStack = useCallback(
    (stack: string | undefined | null): string[] => {
      if (!stack) return [];
      const componentsTree = parseErrorStack(stack);
 
      if (componentsTree) {
        console.log("Feature Component:", componentsTree.componentName);
 
        let component = componentsTree.child;
        while (component?.child) {
          component = component.child;
        }
        console.log("Crashing Component", component?.componentName);
      }
      return [];
    },
    [componentStack],
  );
 
  return {
    getComponentNameFromErrorStack,
    callAll,
    logError,
    ErrorEmitter: ErrorEmitter,
  };
};