|
114 | 114 | (diff-meta exp act))) |
115 | 115 |
|
116 | 116 | (defn diff-map [exp act] |
117 | | - (with-meta |
118 | | - (let [exp-ks (set (keys exp)) |
119 | | - act-ks (set (keys act))] |
120 | | - (reduce |
121 | | - (fn [m k] |
122 | | - (case [(contains? exp-ks k) (contains? act-ks k)] |
123 | | - [true false] |
124 | | - (assoc m (->Deletion k) (get exp k)) |
125 | | - [false true] |
126 | | - (assoc m (->Insertion k) (get act k)) |
127 | | - [true true] |
128 | | - (assoc m k (diff (get exp k) (get act k))) |
129 | | - ; `[false false]` will never occur because `k` necessarily |
130 | | - ; originated from at least one of the two sets |
131 | | - )) |
132 | | - {} |
133 | | - (set/union exp-ks act-ks))) |
134 | | - (diff-meta exp act))) |
| 117 | + (if (not= (record? exp) (record? act)) |
| 118 | + ;; If one of them is a record, and the other one a plain map, that's a |
| 119 | + ;; mismatch. The case where both of them are records, but of different |
| 120 | + ;; types, is handled in [[diff]] |
| 121 | + (->Mismatch exp act) |
| 122 | + (with-meta |
| 123 | + (let [exp-ks (set (keys exp)) |
| 124 | + act-ks (set (keys act))] |
| 125 | + (reduce |
| 126 | + (fn [m k] |
| 127 | + (case [(contains? exp-ks k) (contains? act-ks k)] |
| 128 | + [true false] |
| 129 | + ;; The `dissoc` is only relevant for records, which at this point |
| 130 | + ;; we are certain are of the same type. If the key is present in |
| 131 | + ;; one and not in the other, we know it's an optional key (not part |
| 132 | + ;; of the record base), and we can safely `dissoc` it while |
| 133 | + ;; retaining the record type. |
| 134 | + (assoc (dissoc m k) (->Deletion k) (get exp k)) |
| 135 | + [false true] |
| 136 | + (assoc m (->Insertion k) (get act k)) |
| 137 | + [true true] |
| 138 | + (assoc m k (diff (get exp k) (get act k))) |
| 139 | + ;; `[false false]` will never occur because `k` necessarily |
| 140 | + ;; originated from at least one of the two sets |
| 141 | + )) |
| 142 | + ;; In case of a record, we want to preserve the type, and you can't |
| 143 | + ;; call `empty` on records, so we start from `exp` and assoc/dissoc. |
| 144 | + (if (record? exp) exp {}) |
| 145 | + (set/union exp-ks act-ks))) |
| 146 | + (diff-meta exp act)))) |
135 | 147 |
|
136 | 148 | (defn diff-meta [exp act] |
137 | 149 | (when (or (meta exp) (meta act)) |
|
160 | 172 |
|
161 | 173 | (defn diff [exp act] |
162 | 174 | (cond |
| 175 | + (= exp act) |
| 176 | + exp |
| 177 | + |
163 | 178 | (nil? exp) |
164 | 179 | (diff-atom exp act) |
165 | 180 |
|
| 181 | + (record? exp) |
| 182 | + (if (= (type exp) (type act)) |
| 183 | + (diff-map exp act) |
| 184 | + ;; Either act is not a record, or it's a record of a different type, so |
| 185 | + ;; that's a mismatch |
| 186 | + (->Mismatch exp act)) |
| 187 | + |
166 | 188 | (and (diffable? exp) |
167 | 189 | (= (data/equality-partition exp) (data/equality-partition act))) |
168 | 190 | (diff-similar exp act) |
169 | 191 |
|
170 | 192 | (array? exp) |
171 | 193 | (diff-seq exp act) |
172 | 194 |
|
173 | | - (record? exp) |
174 | | - (diff-map exp act) |
175 | | - |
176 | 195 | :else |
177 | 196 | (diff-atom exp act))) |
178 | 197 |
|
|
0 commit comments