|
3 | 3 | objects and attach extra data to them."
|
4 | 4 | {:added "0.31"
|
5 | 5 | :author "Jeff Valk, Oleksandr Yakushev"}
|
| 6 | + (:refer-clojure :exclude [print-str]) |
6 | 7 | (:require
|
7 | 8 | [clojure.java.io :as io]
|
8 | 9 | [clojure.main]
|
9 |
| - [clojure.pprint :as pp] |
10 | 10 | [clojure.repl :as repl]
|
11 | 11 | [clojure.spec.alpha :as s]
|
12 | 12 | [clojure.string :as str]
|
13 | 13 | [orchard.info :as info]
|
14 | 14 | [orchard.java.resource :as resource]
|
15 |
| - [orchard.misc :as misc :refer [assoc-some]]) |
| 15 | + [orchard.misc :as misc :refer [assoc-some]] |
| 16 | + [orchard.print :as print]) |
16 | 17 | (:import
|
17 |
| - (java.io StringWriter) |
18 | 18 | (java.net URL)
|
19 | 19 | (java.nio.file Path)))
|
20 | 20 |
|
21 | 21 | (def ^:private ^Path cwd-path (.toAbsolutePath (.toPath (io/file ""))))
|
22 | 22 |
|
23 |
| -(defn- pprint-write |
24 |
| - "We don't use `clojure.pprint/pprint` directly because it appends a newline at |
25 |
| - the end which we don't want." |
26 |
| - [value writer] |
27 |
| - (pp/write value :stream writer)) |
| 23 | +(defn- print-str [value] |
| 24 | + ;; Limit printed collections to 5 items. |
| 25 | + (binding [*print-length* 5] |
| 26 | + (print/print-str value))) |
28 | 27 |
|
29 | 28 | ;;; ## Stacktraces
|
30 | 29 |
|
|
221 | 220 |
|
222 | 221 | (defn- prepare-spec-data
|
223 | 222 | "Prepare spec problems for display in user stacktraces. Take in a map `ed` as
|
224 |
| - returned by `clojure.spec.alpha/explain-data` and return a map of pretty |
225 |
| - printed problems. The content of the returned map is modeled after |
| 223 | + returned by `clojure.spec.alpha/explain-data` and return a map of printed |
| 224 | + problems. The content of the returned map is modeled after |
226 | 225 | `clojure.spec.alpha/explain-printer`."
|
227 |
| - [ed pprint-str] |
| 226 | + [ed] |
228 | 227 | (let [problems (sort-by #(count (:path %)) (::s/problems ed))]
|
229 | 228 | {:spec (pr-str (::s/spec ed))
|
230 |
| - :value (pprint-str (::s/value ed)) |
| 229 | + :value (print-str (::s/value ed)) |
231 | 230 | :problems
|
232 | 231 | (mapv
|
233 | 232 | (fn [{:keys [in val pred reason via path] :as prob}]
|
234 |
| - (->> {:in (some-> in not-empty pr-str) |
235 |
| - :val (pprint-str val) |
| 233 | + (->> {:in (some-> in not-empty print-str) |
| 234 | + :val (print-str val) |
236 | 235 | :predicate (pr-str (s/abbrev pred))
|
237 | 236 | :reason reason
|
238 | 237 | :spec (some-> via not-empty last pr-str)
|
|
243 | 242 | ::s/failure} (key %)))
|
244 | 243 | prob)]
|
245 | 244 | (when (seq extras)
|
246 |
| - (pprint-str extras)))} |
| 245 | + (print-str extras)))} |
247 | 246 | (filter clojure.core/val)
|
248 | 247 | (into {})))
|
249 | 248 | problems)}))
|
|
258 | 257 |
|
259 | 258 | (defn- analyze-cause
|
260 | 259 | "Analyze the `cause-data` of an exception, in `Throwable->map` format."
|
261 |
| - [cause-data print-fn] |
262 |
| - (let [pprint-str #(let [writer (StringWriter.)] |
263 |
| - (print-fn % writer) |
264 |
| - (str writer)) |
265 |
| - phase (-> cause-data :data :clojure.error/phase) |
| 260 | + [cause-data] |
| 261 | + (let [phase (-> cause-data :data :clojure.error/phase) |
266 | 262 | m (-> {:class (name (:type cause-data))
|
267 | 263 | :phase phase
|
268 | 264 | :message (:message cause-data)
|
|
274 | 270 | (if (::s/failure data)
|
275 | 271 | (assoc m
|
276 | 272 | :message "Spec assertion failed."
|
277 |
| - :spec (prepare-spec-data data pprint-str)) |
| 273 | + :spec (prepare-spec-data data)) |
278 | 274 | (assoc m
|
279 |
| - :data (pprint-str data) |
| 275 | + :data (print-str data) |
280 | 276 | :location (select-keys data [:clojure.error/line
|
281 | 277 | :clojure.error/column
|
282 | 278 | :clojure.error/phase
|
|
297 | 293 |
|
298 | 294 | (defn- analyze-causes
|
299 | 295 | "Analyze the cause chain of the `exception-data` in `Throwable->map` format."
|
300 |
| - [exception-data print-fn] |
| 296 | + [exception-data] |
301 | 297 | (let [triage-message (maybe-triage-message exception-data)
|
302 | 298 | causes (update (vec (:via exception-data)) 0
|
303 | 299 | #(cond-> %
|
|
306 | 302 | (nil? (:trace %)) (assoc :trace (:trace exception-data))
|
307 | 303 | ;; If non-nil, assoc triage-message to first cause.
|
308 | 304 | triage-message (assoc :triage triage-message)))]
|
309 |
| - (mapv #(extract-location (analyze-cause % print-fn)) causes))) |
| 305 | + (mapv #(extract-location (analyze-cause %)) causes))) |
310 | 306 |
|
311 | 307 | (defn analyze
|
312 |
| - "Return the analyzed cause chain for `exception` beginning with the |
313 |
| - thrown exception. `exception` can be an instance of `Throwable` or a |
314 |
| - map in the same format as `Throwable->map`. For `ex-info` |
315 |
| - exceptions, the response contains a `:data` slot with the pretty |
316 |
| - printed data. For clojure.spec asserts, the `:spec` slot contains a |
317 |
| - map of pretty printed components describing spec failures." |
318 |
| - ([exception] |
319 |
| - (analyze exception pprint-write)) |
320 |
| - ([exception print-fn] |
321 |
| - (cond (instance? Throwable exception) |
322 |
| - (analyze-causes (Throwable->map-with-traces exception) print-fn) |
323 |
| - (and (map? exception) (:trace exception)) |
324 |
| - (analyze-causes exception print-fn)))) |
| 308 | + "Return the analyzed cause chain for `exception` beginning with the thrown |
| 309 | + exception. `exception` can be an instance of `Throwable` or a map in the same |
| 310 | + format as `Throwable->map`. For `ex-info` exceptions, the response contains a |
| 311 | + `:data` slot with the printed data. For clojure.spec asserts, the `:spec` slot |
| 312 | + contains a map of printed components describing spec failures." |
| 313 | + [exception] |
| 314 | + (cond (instance? Throwable exception) |
| 315 | + (analyze-causes (Throwable->map-with-traces exception)) |
| 316 | + (and (map? exception) (:trace exception)) |
| 317 | + (analyze-causes exception))) |
0 commit comments