|
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