diff --git a/src/utils/ErrorBoundary.ts b/src/utils/ErrorBoundary.ts index e9f297c5..520d2a35 100644 --- a/src/utils/ErrorBoundary.ts +++ b/src/utils/ErrorBoundary.ts @@ -14,25 +14,69 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {ObservableValue, BaseObservableValue} from "../observable/ObservableValue"; +export const ErrorValue = Symbol("ErrorBoundary:Error"); export class ErrorBoundary { + private _error?: Error; + constructor(private readonly errorCallback: (Error) => void) {} - try(callback: () => T): T | undefined; - try(callback: () => Promise): Promise | undefined { + /** + * Executes callback() and then runs errorCallback() on error. + * This will never throw but instead return `errorValue` if an error occured. + */ + try(callback: () => T): T | typeof ErrorValue; + try(callback: () => Promise): Promise | typeof ErrorValue { try { - let result: T | Promise = callback(); + let result: T | Promise = callback(); if (result instanceof Promise) { result = result.catch(err => { + this._error = err; this.errorCallback(err); - return undefined; + return ErrorValue; }); } return result; } catch (err) { + this._error = err; this.errorCallback(err); - return undefined; + return ErrorValue; } } + + get error(): Error | undefined { + return this._error; + } } + +export function tests() { + return { + "catches sync error": assert => { + let emitted = false; + const boundary = new ErrorBoundary(() => emitted = true); + const result = boundary.try(() => { + throw new Error("fail!"); + }); + assert(emitted); + assert.strictEqual(result, ErrorValue); + }, + "return value of callback is forwarded": assert => { + let emitted = false; + const boundary = new ErrorBoundary(() => emitted = true); + const result = boundary.try(() => { + return "hello"; + }); + assert(!emitted); + assert.strictEqual(result, "hello"); + }, + "catches async error": async assert => { + let emitted = false; + const boundary = new ErrorBoundary(() => emitted = true); + const result = await boundary.try(async () => { + throw new Error("fail!"); + }); + assert(emitted); + assert.strictEqual(result, ErrorValue); + } + } +} \ No newline at end of file