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;