Repository: juxt/aero (clojure)

Issue:
#or and #ref tags don't combine as expected in "large" maps
On aero 1.1.4 the #or and #ref tags do not combined as expected when the maps contain enough data.

The following config map
```clojure
 {:x "foo"
  :y #or [#ref [:x] "bar"]}
```
will properly evaluate to
```clojure
 {:x "foo"
  :y "foo"}
```

However the config map
```clojure
 {:x "foo"
  :y #or [#ref [:x] "bar"]
  :junk0 "0"
  :junk1 "1"
  :junk2 "2"
  :junk3 "3"
  :junk4 "4"
  :junk5 "5"
  :junk6 "6"
  :junk7 "7"
  :junk8 "8"}
```
improperly evaluates to
```clojure
 {:x "foo"
  :y nil
  :junk0 "0"
  :junk1 "1"
  :junk2 "2"
  :junk3 "3"
  :junk4 "4"
  :junk5 "5"
  :junk6 "6"
  :junk7 "7"
  :junk8 "8"}
```

Pull request:
If one of the children of 'or are incomplete, we need to mark the return
of 'or as incomplete also.

Fix #82

cc/ @mchughs

Patch:
diff --git a/src/aero/alpha/core.cljc b/src/aero/alpha/core.cljc
index 16b3852..1067c3b 100644
--- a/src/aero/alpha/core.cljc
+++ b/src/aero/alpha/core.cljc
@@ -34,7 +34,7 @@
                {`reassemble (fn [_ queue]
                               (mapv second (sort-by first queue)))})
 
-    (list? x)
+    (seq? x)
     (with-meta (map-indexed (fn [idx v] [idx v]) x)
                {`reassemble (fn [_ queue]
                               (apply list (map second (sort-by first queue))))})
@@ -128,7 +128,7 @@
   "Expand value x.  Dispatches on whether it's a scalar or collection.  If it's
   a collection it will expand the elements of the collection."
   [x opts env ks]
-  (if (or (and (map? x) (not (record? x))) (set? x) (list? x) (vector? x))
+  (if (or (and (map? x) (not (record? x))) (set? x) (seq? x) (vector? x))
     (expand-coll x opts env ks)
     (expand-scalar x opts env ks)))
 
diff --git a/src/aero/core.cljc b/src/aero/core.cljc
index c7b45a2..696c31d 100644
--- a/src/aero/core.cljc
+++ b/src/aero/core.cljc
@@ -261,14 +261,17 @@
         (expand-scalar-repeatedly (:form tl) opts env ks)]
     (if incomplete?
       (update expansion ::value rewrap)
-      (loop [[x & xs] value]
+      (loop [[x & xs] value
+             idx 0]
         (let [{:keys [:aero.core/incomplete? :aero.core/value]
                :as expansion}
-              (expand x opts env ks)]
+              (expand x opts env (conj ks idx))]
           (cond
             ;; We skipped a value, we cannot be sure whether it will be true in the future, so return with the remainder to check (including the skipped)
             incomplete?
-            (tagged-literal (:tag tl) (cons value xs))
+            {::value (tagged-literal (:tag tl) (cons value xs))
+             ::incomplete? true
+             ::incomplete (::incomplete expansion)}
 
             ;; We found a value, and it's truthy, and we aren't skipped (because order), we successfully got one!
             value
@@ -280,7 +283,7 @@
 
             :else
             ;; Falsey value, but not skipped, recur with the rest to try
-            (recur xs)))))))
+            (recur xs (inc idx))))))))
 
 (defn- assoc-in-kv-seq
   [x ks v]


Test patch:
diff --git a/test/aero/core_test.cljc b/test/aero/core_test.cljc
index 3812a8b..b896abe 100644
--- a/test/aero/core_test.cljc
+++ b/test/aero/core_test.cljc
@@ -11,7 +11,9 @@
                      [cljs.test :refer [deftest is testing]]
                      [goog.object :as gobj]
                      [goog.string :as gstring]
-                     goog.string.format)))
+                     goog.string.format
+                     [cljs.tools.reader.reader-types
+                      :refer [source-logging-push-back-reader]])))
 
 (defn env [s]
   #?(:clj (System/getenv (str s)))
@@ -207,3 +209,25 @@
      (is (= #{10} (:bar
                     (read-config (java.io.StringReader.
                                    "{:foo 10 :bar #{#ref [:foo]}}")))))))
+
+(deftest or-incomplete-child
+  (let [config-str "{:x \"foo\"
+                   :y #or [#ref [:x] \"bar\"]
+                   :junk0 \"0\"
+                   :junk1 \"1\"
+                   :junk2 \"2\"
+                   :junk3 \"3\"
+                   :junk4 \"4\"
+                   :junk5 \"5\"
+                   :junk6 \"6\"
+                   :junk7 \"7\"
+                   :junk8 \"8\"}"
+        config (#?(:cljs source-logging-push-back-reader
+                   :clj java.io.StringReader.) config-str)]
+    (is (= "foo" (:x (read-config config))))))
+
+(deftest or-dangling-ref
+  (let [config-str "{:y #or [#ref [:x] \"bar\"]}"
+        config (#?(:cljs source-logging-push-back-reader
+                   :clj java.io.StringReader.) config-str)]
+    (is (= "bar" (:y (read-config config))))))