Miguel de Benito Delgado 09de51fe69 🚧 WIP 29.5, refactor error handling
AI-assisted-by: claude-haiku-5.5
2026-11-05 11:18:15 +01:00

75 lines
2.4 KiB
Clojure

;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS SUBSIDIARY SL
(ns benches.render-wasm.errors
"Failure values for the benchmark harness.
A step that can fail returns its value or an Error. `attempt` turns a thrown
value into that Error and `failure?` tells the two apart:
(let [page (attempt (await (open-page owner)))]
(if (failure? page)
(record-failure page)
(use page)))
A fatal failure marks a write to the caller's own record or log. It cannot
be recorded in that record, so `attempt` throws it again and only a boundary
that owns the record or reports to the user catches it with `:catch-fatal`.
This namespace has no Node or browser dependencies."
(:require-macros
[app.common.exceptions :as ex]))
(def ^:private max-cause-depth 8)
(defn failure?
"True when `x` is an Error."
[x]
(instance? js/Error x))
(defn message-of
"Returns the message of an Error or the string form of another value."
[cause]
(or (ex-message cause) (str cause)))
(defn fatal-error
"Returns an exception that `fatal?` recognizes. `data` is its ex-data map and
`cause` the original failure."
[message data cause]
(ex-info message (assoc data :fatal true) cause))
(defn fatal?
"True when `cause` or one of its causes has the ex-data `:fatal` marker."
[cause]
(loop [cause cause
depth 0]
(cond
(nil? cause) false
(:fatal (ex-data cause)) true
(>= depth max-cause-depth) false
:else (recur (ex-cause cause) (inc depth)))))
(defn as-failure
"Returns `thrown` when it is an Error. Otherwise returns an Error whose
message is the string `thrown` or the printed value, with the value in the
`:thrown` ex-data."
[thrown]
(if (failure? thrown)
thrown
(ex-info (if (string? thrown)
thrown
(str "non-error value thrown: " (or (ex/ignoring (pr-str thrown)) "unprintable value")))
{:thrown thrown})))
(defn with-data
"Returns `x` when it is not a failure. For a failure returns an exception
with the same message, `x` as its cause and `data` merged under the ex-data
of `x`, so keys already present on `x` win."
[x data]
(if (failure? x)
(ex-info (message-of x) (merge data (ex-data x)) x)
x))