parseProps = (props, i = 0) => {
  if (!props) return null;
  if (props.hasOwnProperty(window) || props.hasOwnProperty('prevObject') || props.hasOwnProperty(Window)) return null; // window was causing infinite loops
  if (typeof props !== 'object') return props;

  // check if current props has PROPS property..don't traverse further just grab name property
  if (Object.prototype.hasOwnProperty.call(props, 'props')) {
    if (!props.hasOwnProperty('type')) return undefined;
    else if (props.type.hasOwnProperty('name') && props.type.name.length) return props.type.name;
    else if (props.type.hasOwnProperty('displayName') && props.type.displayName.length) return props.type.displayName;
    else if (props.hasOwnProperty('type')) return `${props.type}`;
  }

  // otherwise parse the props
  else {
    const parsedProps = {};
    // TODO remove for in loop
    for (const key in props) {
      if (!props[key]) parsedProps[key] = null;

      // stringify methods
      else if (key === 'routes') return;
      else if (typeof props[key] === 'function') parsedProps[key] = parseFunction(props[key]);
      // array parse parseProps forEach element
      else if (Array.isArray(props[key]) && key === 'children') parsedProps[key] = parseArray(props[key]);

      // else if type is an object
      else if (typeof props[key] === 'object') {
        // handle custom objects and components with one child
        if (props[key] && Object.keys(props[key]).length) {
          if (i < 3) { // limit this func
            const iterator = i + 1;
            parsedProps[key] = parseProps(props[key], iterator);
          } else parsedProps[key] = 'obj*'; // end recursion so we dont get infinite loops
        }
      }
      // handle text nodes and other random values
      else parsedProps[key] = props[key];
    }
    return parsedProps;
  }
}
Parse Component's props. Handle nested objects and functions

@param {object} props - Object representing a component's props