Skip to content

Commit b87b922

Browse files
committed
Improve path generation
1 parent 638e029 commit b87b922

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

src/lib/devtools/formatters/markup.cljs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,15 @@
171171
(conj lines [more-markup])))))
172172

173173
(defn <details> [value starting-index]
174+
;; This is very important when the value is a map
175+
;; we need to push the object to history so that we can be able to get the paths (i.e keys)
176+
;; the other option to this is ignoring this and then when generating paths, assume that all
177+
;; vectors that have two children which are
178+
;; a keyword as the first item and
179+
;; a sequence or map as the second item when the path info is not nil.
180+
;; are all just seq'd maps and that the first item in the vector is a key in the map.
181+
;; The seq'd map is a result of `(seq value)` done in `body-lines` above
182+
(devtools.formatters.state/push-object-to-current-history! value)
174183
(let [has-continuation? (pos? starting-index)
175184
body-markup (<standard-body> (body-lines value starting-index) has-continuation?)]
176185
(if has-continuation?

src/lib/devtools/formatters/state.cljs

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,25 @@
4646
(defn get-last-object-from-current-history []
4747
(first (get-current-history))) ; note the list is reversed
4848

49+
(defn get-second-last-object-from-current-history []
50+
(second (get-current-history))) ; note the list is reversed
51+
4952
(defn present-path-segment [v]
5053
(cond
5154
(string? v) v
52-
(keyword? v) (str v)
55+
;; we'd like to preserve keywords for easy get
56+
(keyword? v) v
5357
(number? v) v
5458
:else "?"))
5559

5660
(defn seek-path-segment [coll val]
5761
(let [* (fn [[k v]]
58-
(if (identical? v val)
62+
(cond
63+
;; we need to know the paths for keywords, these are clickable
64+
(identical? k val)
65+
(present-path-segment k)
66+
67+
(identical? v val)
5968
(present-path-segment k)))]
6069
(some * coll)))
6170

@@ -64,11 +73,45 @@
6473
(map? parent-object) (seek-path-segment (seq parent-object) object)
6574
(sequential? parent-object) (seek-path-segment (map-indexed (fn [i x] [i x]) parent-object) object)))
6675

76+
;; This function checks a unique situation of looping an immediate child element `obj` of a parent element `history`
77+
;; say we have a general map {:a 2 :b {:gh 45} :c 4}
78+
;; and we call devtools.formatters.core/body-api-call with the map, the map ends up in
79+
;; devtools.formatters.markup/<details> which then calls devtools.formatters.markup/body-lines
80+
;; where the map will get seq'd resulting in ([:a 2] [:b {:gh 45}] [:c 4])
81+
;; these 3 vectors will then be pushed to history which will result in an issue when generating the path
82+
;; for example if we are looping over at `obj` as 2 and `history` as `[:a 2]` `build-path-segment` will return
83+
;; the path as 1 since the immediate history is a vector instead of a map.
84+
;; This function detects the condition that this is the case and then the next operation will be to
85+
;; get the first item in the vector which is the path.
86+
(defn mapping?
87+
[history obj]
88+
(let [obj-kw (when (and (vector? obj)
89+
(= (count obj) 2)
90+
;; the map keys must always be one of these
91+
(or
92+
(-> obj first keyword?)
93+
(-> obj first string?)
94+
(-> obj first number?)))
95+
(first obj))]
96+
(when (and (map? history) obj-kw)
97+
(contains? history obj-kw))))
98+
6799
(defn extend-path-info [path-info object]
68100
(let [parent-object (get-last-object-from-current-history)]
69-
(if-some [path-segment (build-path-segment parent-object object)]
70-
(conj (or path-info []) path-segment)
71-
path-info)))
101+
(cond
102+
;; if the current item we are looping at is an artificial vector (explained at `mapping` above),
103+
;; dont append to the path
104+
(and (map? parent-object) (mapping? parent-object object))
105+
path-info
106+
;; if the previous item is an artificial vector, lets append to the path info but take the first item
107+
;; in the vector as the path. (Explained in `mapping` above)
108+
(and (map? (get-second-last-object-from-current-history))
109+
(mapping? (get-second-last-object-from-current-history) parent-object))
110+
(conj (or path-info []) (first parent-object))
111+
;; the current object is an item within the parent object
112+
(some? (build-path-segment parent-object object))
113+
(conj (or path-info []) (build-path-segment parent-object object))
114+
:else path-info)))
72115

73116
(defn add-object-to-current-path-info! [object]
74117
(update-current-state! update :path-info extend-path-info object))

0 commit comments

Comments
 (0)