CRBT-Team/Purplet

View on GitHub
packages/rest/src/DiscordAPIError.ts

Summary

Maintainability
A
0 mins
Test Coverage
import type { RESTJSONErrorCodes } from 'discord-api-types/rest';

interface APIJSONError {
  code: RESTJSONErrorCodes;
  message: string;
  errors: APIErrorObject;
}

interface APIErrorWithKeypath extends APIErrorEntry {
  keypath: string;
}

type APIErrorObject = { _errors: APIErrorEntry[] } & { [key: string]: APIErrorObject };

interface APIErrorEntry {
  code: string;
  message: string;
}

function getErrorList(error: APIErrorObject, keypath = ''): APIErrorWithKeypath[] {
  const errors: APIErrorWithKeypath[] = [];
  for (const key in error) {
    errors.push(
      ...(key === '_errors'
        ? error[key].map(e => ({ ...e, keypath: `${keypath}` }))
        : getErrorList(error[key], `${keypath}${/^\d+$/.exec(key) ? `[${key}]` : `.${key}`}`))
    );
  }
  return errors;
}

export class DiscordAPIError extends Error {
  #errorList: APIErrorWithKeypath[];

  status: number;
  statusText: string;
  code: RESTJSONErrorCodes;
  url: string;

  constructor(rawError: APIJSONError, response: Response, options?: ErrorOptions) {
    const errors = getErrorList(rawError.errors);
    const formattedList = getErrorList(rawError.errors)
      .map(e => ` - ${e.keypath}: ${e.message}`)
      .join('\n');
    super(rawError.message + (formattedList ? `\n${formattedList}` : ''), options);
    this.status = response.status;
    this.statusText = response.statusText;
    this.code = rawError.code;
    this.url = response.url;
    this.#errorList = errors;
  }

  get errors() {
    return this.#errorList;
  }
}