formatURL = (objURL) => {
  let protocol = objURL.protocol || "";

  if (protocol && protocol.substr(-1) !== ":") {
    protocol += ":";
  }

  let auth = objURL.auth || "";

  if (auth) {
    auth = encodeURIComponent(auth);
    auth = auth.replace(/%3A/i, ":");
    auth += "@";
  }

  let host = "";

  if (objURL.hostname) {
    host =
      auth +
      (objURL.hostname.indexOf(":") === -1
        ? objURL.hostname
        : `[${objURL.hostname}]`);

    if (objURL.port) {
      host += `:${objURL.port}`;
    }
  }

  let pathname = objURL.pathname || "";

  if (objURL.slashes) {
    host = `//${host || ""}`;

    if (pathname && pathname.charAt(0) !== "/") {
      pathname = `/${pathname}`;
    }
  } else if (!host) {
    host = "";
  }

  let search = objURL.search || "";

  if (search && search.charAt(0) !== "?") {
    search = `?${search}`;
  }

  let hash = objURL.hash || "";

  if (hash && hash.charAt(0) !== "#") {
    hash = `#${hash}`;
  }

  pathname = pathname.replace(
    /[?#]/g,
    /**
     * @param {string} match
     * @returns {string}
     */
    (match) => encodeURIComponent(match),
  );
  search = search.replace("#", "%23");

  return `${protocol}${host}${pathname}${search}${hash}`;
}
@param {{ protocol?: string, auth?: string, hostname?: string, port?: string, pathname?: string, search?: string, hash?: string, slashes?: boolean }} objURL
@returns {string}