UNPKG

hakojs

Version:

A secure, embeddable JavaScript engine that runs untrusted code inside WebAssembly sandboxes with fine-grained permissions and resource limits

150 lines (144 loc) 3.23 kB
// src/mem/lifetime.ts function isDisposable(value) { return Boolean(value && typeof value === "object" && "dispose" in value && typeof value.dispose === "function" && "alive" in value && typeof value.alive === "boolean"); } function isAbstractDisposableResult(value) { return Boolean(value && typeof value === "object" && value instanceof AbstractDisposableResult); } class AbstractDisposableResult { static success(value) { return new DisposableSuccess(value); } static fail(error, onUnwrap) { return new DisposableFail(error, onUnwrap); } static is(result) { return result instanceof AbstractDisposableResult; } [Symbol.dispose]() { this.dispose(); } } class DisposableSuccess extends AbstractDisposableResult { value; constructor(value) { super(); this.value = value; } get alive() { return isDisposable(this.value) ? this.value.alive : true; } dispose() { if (isDisposable(this.value)) { this.value.dispose(); } } unwrap() { return this.value; } unwrapOr(_fallback) { return this.value; } } class DisposableFail extends AbstractDisposableResult { error; onUnwrap; constructor(error, onUnwrap) { super(); this.error = error; this.onUnwrap = onUnwrap; } get alive() { return isDisposable(this.error) ? this.error.alive : true; } dispose() { if (isDisposable(this.error)) { this.error.dispose(); } } unwrap() { this.onUnwrap(this); throw this.error; } unwrapOr(fallback) { return fallback; } } var DisposableResult = AbstractDisposableResult; function scopeFinally(scope, blockError) { let disposeError; try { scope.release(); } catch (error) { disposeError = error; } if (blockError && disposeError) { Object.assign(blockError, { message: `${blockError.message} Then, failed to dispose scope: ${disposeError.message}`, disposeError }); throw blockError; } if (blockError || disposeError) { throw blockError || disposeError; } } class Scope { cleanupFns = []; isDisposed = false; add(fn) { if (this.isDisposed) { throw new Error("Cannot add cleanup function to a disposed scope"); } this.cleanupFns.push(fn); } release() { if (this.isDisposed) { return; } for (let i = this.cleanupFns.length - 1;i >= 0; i--) { try { this.cleanupFns[i](); } catch (error) { console.error("Error during cleanup:", error); } } this.cleanupFns = []; this.isDisposed = true; } manage(value) { if (isDisposable(value)) { this.add(() => { if (value.alive) { value.dispose(); } }); } return value; } static withScope(block) { const scope = new Scope; let blockError; try { return block(scope); } catch (error) { blockError = error; throw error; } finally { scopeFinally(scope, blockError); } } [Symbol.dispose]() { this.release(); } } export { isAbstractDisposableResult, Scope, DisposableSuccess, DisposableResult, DisposableFail }; //# debugId=AE3DC613B1E704FA64756E2164756E21 //# sourceMappingURL=lifetime.js.map