From 84123b6733f3eaaaa1ac3f065f9c824ec433bc53 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Marczyk?= <michal.marczyk@gmail.com>
Date: Mon, 26 Nov 2012 16:51:51 +0100
Subject: [PATCH] CLJS-429: Data Conveying Exception: ex-data and ex-info

Introduces ex-data, ex-info, ex-message and ex-cause as well as an
ExceptionInfo type; cljs.core.ExceptionInfo.prototype is made to be a
custom Error type by resetting ExceptionInfo's prototype and the
constructor property on the new prototype.

Basic tests are included.
---
 src/cljs/cljs/core.cljs       |   42 +++++++++++++++++++++++++++++++++++++++++
 test/cljs/cljs/core_test.cljs |    8 +++++++
 2 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/src/cljs/cljs/core.cljs b/src/cljs/cljs/core.cljs
index e3dcd44..3fc2455 100644
--- a/src/cljs/cljs/core.cljs
+++ b/src/cljs/cljs/core.cljs
@@ -7306,3 +7306,45 @@ Maps become Objects. Arbitrary keys are encoded to by key->js."
   IHash
   (-hash [this]
     (goog.string/hashCode (pr-str this))))
+
+;;; ExceptionInfo
+
+(deftype ExceptionInfo [message data cause])
+
+;;; ExceptionInfo is a special case, do not emulate this
+(set! cljs.core.ExceptionInfo/prototype (js/Error.))
+(set! (.-constructor cljs.core.ExceptionInfo/prototype) ExceptionInfo)
+
+(defn ex-info
+  "Alpha - subject to change.
+  Create an instance of ExceptionInfo, an Error type that carries a
+  map of additional data."
+  ([msg map]
+     (ExceptionInfo. msg map nil))
+  ([msg map cause]
+     (ExceptionInfo. msg map cause)))
+
+(defn ex-data
+  "Alpha - subject to change.
+  Returns exception data (a map) if ex is an ExceptionInfo.
+  Otherwise returns nil."
+  [ex]
+  (when (instance? ExceptionInfo ex)
+    (.-data ex)))
+
+(defn ex-message
+  "Alpha - subject to change.
+  Returns the message attached to the given Error / ExceptionInfo object.
+  For non-Errors returns nil."
+  [ex]
+  (when (instance? js/Error ex)
+    (.-message ex)))
+
+(defn ex-cause
+  "Alpha - subject to change.
+  Returns exception cause (an Error / ExceptionInfo) if ex is an
+  ExceptionInfo.
+  Otherwise returns nil."
+  [ex]
+  (when (instance? ExceptionInfo ex)
+    (.-cause ex)))
diff --git a/test/cljs/cljs/core_test.cljs b/test/cljs/cljs/core_test.cljs
index 02489e8..253e80e 100644
--- a/test/cljs/cljs/core_test.cljs
+++ b/test/cljs/cljs/core_test.cljs
@@ -1770,5 +1770,13 @@
     (kvr-test (array-map :k0 :v0 :k1 :v1) [:k0 :v0 :k1 :v1])
     (kvr-test [:v0 :v1] [0 :v0 1 :v1]))
 
+  ;; data conveying exception
+  (assert (= {:foo 1}
+             (try (throw (ex-info "asdf" {:foo 1}))
+                  (catch ExceptionInfo e
+                    (ex-data e)))))
+  (assert (instance? js/Error (ex-info "asdf" {:foo 1})))
+  (assert (not (instance? cljs.core.ExceptionInfo (js/Error.))))
+
   :ok
   )
-- 
1.7.1

