summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md17
-rw-r--r--deps.edn1
-rw-r--r--src/dompa/nodes.cljc15
-rw-r--r--test/dompa/nodes_test.cljc29
4 files changed, 54 insertions, 8 deletions
diff --git a/README.md b/README.md
index 003cd07..d106d1b 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,23 @@ The function you provide to `traverse` dictates the outcome for each node:
* To **remove a node**, return `nil`.
* To **replace a node with many nodes on the same level**, return a [fragment node](#fragment-nodes), which will be replaced by its children during HTML transformation.
+#### Zipping
+
+You can also use the `dompa.nodes/zip` function to create a [zipper](https://clojuredocs.org/clojure.zip/zipper) of a node, i.e:
+
+```clojure
+(ns my.app
+ (:require [dompa.nodes :as nodes]
+ [clojure.zip :as zip])
+
+(->> (nodes/zip {..node})
+ zip/down
+ zip/node)
+```
+
+And of course you can use this in combination with the `traverse` method as well, since the `traverse` method always operates on a single node at a time,
+and the zipper always starts with a root node, the two complement each other well.
+
-----
### 🛠️ Building Nodes with the `$` Helper
diff --git a/deps.edn b/deps.edn
index ed48cd9..31d2d77 100644
--- a/deps.edn
+++ b/deps.edn
@@ -2,6 +2,7 @@
:paths ["src" "resources"]
:aliases {:dev {:extra-paths ["resources/clj-kondo"]
:extra-deps {clj-kondo/clj-kondo {:mvn/version "2025.09.22"}}}
+ :test {:extra-paths ["test"]}
:test-clj {:extra-paths ["test"]
:extra-deps {io.github.cognitect-labs/test-runner {:git/tag "v0.5.1"
:git/sha "dfb30dd6"}}
diff --git a/src/dompa/nodes.cljc b/src/dompa/nodes.cljc
index 9dbecd0..e99b364 100644
--- a/src/dompa/nodes.cljc
+++ b/src/dompa/nodes.cljc
@@ -1,4 +1,5 @@
-(ns dompa.nodes)
+(ns dompa.nodes
+ (:require [clojure.zip :as zip]))
(def ^:private default-void-nodes
#{:!doctype :!DOCTYPE :area :base :br :col :embed :hr :img :input
@@ -50,6 +51,18 @@
updated-nodes))
(reduce [] nodes)))
+(defn zip
+ "Creates a zipper for given a given `node`."
+ [node]
+ (zip/zipper
+ (fn branch? [node]
+ (boolean (seq (:node/children node))))
+ (fn children [node]
+ (:node/children node))
+ (fn make-node [node children]
+ (assoc node :node/children children))
+ node))
+
(defn ->html
"Transform a vector of `nodes` into an HTML string.
diff --git a/test/dompa/nodes_test.cljc b/test/dompa/nodes_test.cljc
index 2606be6..ca8d483 100644
--- a/test/dompa/nodes_test.cljc
+++ b/test/dompa/nodes_test.cljc
@@ -1,9 +1,12 @@
(ns dompa.nodes-test
- #?(:clj (:require [clojure.test :refer [deftest is testing]]
- [dompa.nodes :refer [$ defhtml traverse ->html]]
- [dompa.html :as html]))
+ #?(:clj (:require
+ [clojure.test :refer [deftest is testing]]
+ [clojure.zip :as zip]
+ [dompa.html :as html]
+ [dompa.nodes :as nodes :refer [$ defhtml]]))
#?(:cljs (:require [cljs.test :refer-macros [deftest testing is]]
- [dompa.nodes :refer [$ traverse ->html] :refer-macros [defhtml]]
+ [clojure.zip :as zip]
+ [dompa.nodes :as nodes :refer [$] :refer-macros [defhtml]]
[dompa.html :as html])))
(defhtml hello [who]
@@ -18,7 +21,7 @@
($ :ul
(->> items
(map (fn [item]
- ($ :li ($ item))))
+ ($ :li ($ item))))
(into []))))
(deftest list-items-test
@@ -53,5 +56,17 @@
node))]
(is (= "<div>world hello</div>"
(-> (html/->nodes "<div>hello world</div>")
- (traverse traverser-fn)
- ->html)))))
+ (nodes/traverse traverser-fn)
+ nodes/->html)))))
+
+(deftest zip-test
+ (let [nodes (html/->nodes "<div><p>hello</p><p>world</p></div>")
+ zipper (nodes/zip (first nodes))]
+ (is (= :div
+ (:node/name (zip/node zipper))))
+ (is (= "hello"
+ (-> zipper
+ zip/down
+ zip/down
+ zip/node
+ :node/value))))) \ No newline at end of file