UNPKG

@finos/legend-shared

Version:
142 lines 5.79 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { printObject, uuid, } from '../CommonUtils.js'; /** * A generic error that can be used for building other errors in the application * which does not require Javascript stack trace. * * If the Javascript stack trace is needed to trace back where the problem occurs, * `EnrichedError` is the more suitable candidate. * * This type of error is useful for wrapping the innermost error or errors coming * from the servers. Since we enforce in the app that errors thrown must be of type * `Error`, this acts as a good wrapper to manage errors better. * See https://github.com/microsoft/TypeScript/issues/13219 */ export class ApplicationError extends Error { uuid = uuid(); constructor(message) { super(); this.message = message === undefined || message === '' ? '(no error message)' : message; } /** * This provides more detail (better context) about the error, including the error message * stack trace, etc. */ get detail() { return this.message; } } // Since Javascript does not fully support rethrowing error, we need to customize and manipulate the stack trace // See https://stackoverflow.com/questions/42754270/re-throwing-exception-in-nodejs-and-not-losing-stack-trace export class EnrichedError extends Error { constructor(name, error, overideMessage) { super(overideMessage ? overideMessage : error instanceof Error ? error.message : error); this.name = name; // if the material used to make this error is also an error, we maintain the stack trace and // follow the `rethrown` error stack trace convention // See https://www.twilio.com/blog/how-to-read-and-understand-a-java-stacktrace if (error instanceof Error) { const messageLines = (this.message.match(/\n/g) ?? []).length + 1; this.stack = `${(this.stack ?? '') .split('\n') .slice(0, messageLines + 1) .join('\n')}\nCaused by: ${error.stack}`; } else { if (typeof Error.captureStackTrace === 'function') { // Maintains proper stack trace for where our error was thrown (only available on V8) // This only works in Chrome for now. Firefox (as of Feb 2020) will throw error // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error Error.captureStackTrace(this, this.constructor); } else { // otherwise, use the non-standard but defacto stack trace (available in most browser) this.stack = new Error(error).stack; } } } } /** * Signals that a method has been invoked at an illegal or * inappropriate point at runtime. In other words, the environment * or application is not in an appropriate state for the requested * operation. */ export class IllegalStateError extends EnrichedError { constructor(error) { super('Illegal State Error [PLEASE NOTIFY DEVELOPER]', error); } } export class UnsupportedOperationError extends EnrichedError { constructor(message, unsupportedObject) { super('Unsupported Operation Error', message || unsupportedObject ? `${message}${unsupportedObject ? `\n${printObject(unsupportedObject)}` : ''}` : undefined); } } /** * This is a relatively crude way to handle error of type unknown thrown for now. * We should revisit this when Typescript supports `throws` clause * See https://github.com/microsoft/TypeScript/issues/13219 * * NOTE: There's a problem with this check in JSDOM leading so we have to disable this in test environment * JSDOM uses their own isolated object rather than native object for performance purpose * See https://github.com/jsdom/jsdom/issues/3082 * For example, TypeErrors generated by `webidl2js` or `whatwg-url` used by `jsdom`, or manually-thrown ones inside impl classes, * are thrown using global.TypeError, not dom.window.TypeError. This change is hard to implement as of now * See https://github.com/jsdom/jsdom/issues/2727 * See https://github.com/facebook/jest/issues/2549 * * Read more related discussions at: * https://github.com/jsdom/jsdom/issues/1737 * https://github.com/webcomponents/polyfills/issues/105 * https://github.com/jsdom/jsdom/issues/1769 * https://github.com/jsdom/jsdom/issues/2555 */ export function assertErrorThrown(error) { // eslint-disable-next-line no-process-env if (process.env.NODE_ENV === 'test') { return; } if (!(error instanceof Error)) { throw new IllegalStateError('Expected error to be thrown'); } } export const returnUndefOnError = (fn) => { try { return fn(); } catch { return undefined; } }; export const decorateErrorMessageIfExists = (fn, errorMessageDecorator) => { try { return fn(); } catch (error) { assertErrorThrown(error); error.message = errorMessageDecorator(error.message); throw error; } }; //# sourceMappingURL=ErrorUtils.js.map