Manual Reference Source Test

src/utilities/Clinical6Error.js

import ExtendableError from 'es6-error';

/**
 * Determines if the string is a JSON object
 *
 * @param {String} str The string to test
 * @return {Boolean} Returns true or false
 */
function isJsonString(str) {
  try {
    JSON.parse(str);
  } catch (e) {
    return false;
  }
  return true;
}

/**
 * Capitalizes the first letter in a string
 *
 * @param {String} string The string to modify
 * @return {String} The modified string.
 */
function capitalizeFirstLetter(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
}

// Babel can't extend native classes - use es6-error npm to handle this
// class ExtendableError extends Error {
//   constructor(message) {
//     super();
//     this.message = message;
//     this.stack = (new Error()).stack;
//     this.name = this.constructor.name;
//   }
// }

/**
 * Clinical6Error is a class that extends Error so that it can easily
 * translate information from internal SDK errors and platform errors
 *
 * @class Clinical6Error
 * @extends {ExtendableError}
 */
class Clinical6Error extends ExtendableError {
  /**
   * Creates an instance of Clinical6Error.
   *
   * @param {String} message - The message
   * @param {String} [module=undefined] - The SDK Module
   */
  constructor(message, module = undefined, request = undefined) {
    super(message);
    /** @type {String} */
    this.module = module;
    /** @type {Object} */
    this._response = message;
    /** @type {Object} */
    this._request = request;
    /** @type {String} */
    this.message = this.extractMessage(message);
  }

  /**
   * Formats the message to HTML (replaces newline only)
   *
   * @readonly
   */
  get messageHTML() {
    return this.message.split('\n').join('<br />');
  }

  /**
   * Returns the friendly error if it exists
   *
   * @readonly
   */
  get friendly() {
    return (this.isResponseObject()) ? this.response.friendly_error : '';
  }

  /**
   * Formats the friendly error to HTML (replaces newline only)
   *
   * @readonly
   */
  get friendlyHTML() {
    return this.friendly.split('\n').join('<br />');
  }

  /**
   * Returns the internal_code from teh platform if it exists
   *
   * @readonly
   */
  get code() {
    return (this.isResponseObject()) ? this.response.internal_code : null;
  }

  /**
   * Splits up the information about the error details into human readable text
   *
   * @readonly
   */
  get details() {
    let _return = null;
    if (this.isResponseObject()) {
      const j = this.response;
      if (j.error_detail) {
        if (typeof j.error_detail === 'object') {
          Object.keys(j.error_detail).forEach((key) => {
            const _key = key.replace('_', ' ');
            const _value = JSON.stringify(j.error_detail[key])
              .replace(/["[\]\\]/g, '') // replace quotes and array elements
              .replace(/[_]/g, ' ') // replace underscore
              .replace(/[,]/g, '$& '); // add spaces to commas if exists
            _return = capitalizeFirstLetter(`${_key} ${_value}`);
          });
        } else {
          const _value = j.error_detail.replace(/[_]/g, ' '); // replace underscore
          _return = capitalizeFirstLetter(`${_value}`);
        }
      }
    }
    return _return;
  }

  /**
   * Returns the response as an object if it's a string object (or object) or simply returns the
   * value
   *
   * @readonly
   */
  get response() {
    return (isJsonString(this._response)) ? JSON.parse(this._response) : this._response;
  }

  /**
   * Returns the status if the response is an object
   *
   * @readonly
   */
  get status() {
    return (this.isResponseObject()) ? this.response.status : null;
  }

  /**
   * Determines if _response is an object
   *
   * @return {Boolean} Returns if _response is an object
   */
  isResponseObject() {
    return (isJsonString(this._response) || typeof this._response === 'object');
  }

  /**
   * Extracts information from json to create the error message.
   *
   * @return {String} an error message with the details and friendly error
   */
  extractMessage(message) {
    let _return = message;
    if (this.status) {
      _return = `Status is ${this.status}`;
    }
    if (this.friendly) {
      _return = this.friendly;
    }
    if (this.details) {
      _return = `${this.details}:\n${_return}`;
    }

    // v3 error
    if (message && message.errors && Array.isArray(message.errors)) {
      const messages = [];
      message.errors.forEach((e) => {
        if (e.title && e.detail) {
          messages.push(`${e.title}: ${e.detail}`);
        } else if (e.source && e.detail) {
          // const splitSource = e.source.pointer.split('/');
          // const title = splitSource[splitSource.length - 1];
          messages.push(`"${e.source.pointer}": ${e.detail}`);
        } else if (e.detail) {
          messages.push(`${e.detail}`);
        } else {
          // eslint-disable-next-line no-console
          console.log(e);
        }
        if (e.source) {
          /** @type {Any} */
          this.source = e.source;
        }
      });
      _return = messages.join(' and ');
    }
    return _return;
  }
}

export default Clinical6Error;