diff options
| author | Asko Nõmm <asko@nmm.ee> | 2025-09-26 19:22:23 +0300 |
|---|---|---|
| committer | Asko Nõmm <asko@nmm.ee> | 2025-09-26 19:22:23 +0300 |
| commit | af83d8c7cdf85b675016eeeecaa85bb547141f4b (patch) | |
| tree | ed3b2746f44bda0619a005beab3c4b22fe6914e7 | |
| parent | 537a14bd9e9146cd9f963520aea75778a32ebc42 (diff) | |
On second thought it's really not related to templating, just nodes, so moving to nodes ns.
| -rw-r--r-- | resources/clj-kondo/config.edn | 10 | ||||
| -rw-r--r-- | src/dompa/nodes.cljc | 52 | ||||
| -rw-r--r-- | src/dompa/templates.cljc | 37 | ||||
| -rw-r--r-- | test/dompa/nodes_test.cljc | 24 | ||||
| -rw-r--r-- | test/dompa/templates_test.cljc | 24 |
5 files changed, 79 insertions, 68 deletions
diff --git a/resources/clj-kondo/config.edn b/resources/clj-kondo/config.edn index 1a76557..1fc2855 100644 --- a/resources/clj-kondo/config.edn +++ b/resources/clj-kondo/config.edn @@ -1,5 +1,5 @@ -{:hooks {:analyze-call {dompa.templates/$ hooks.dompa/$ - dompa.templates/defhtml hooks.dompa/defhtml}} - :linters {:dompa.templates/$-arg-validation {:level :warning} - :dompa.templates/defhtml-arg-validation {:level :warning}} - :lint-as {dompa.templates/defhtml clojure.core/defn}}
\ No newline at end of file +{:hooks {:analyze-call {dompa.nodes/$ hooks.dompa/$ + dompa.nodes/defhtml hooks.dompa/defhtml}} + :linters {:dompa.nodes/$-arg-validation {:level :warning} + :dompa.nodes/defhtml-arg-validation {:level :warning}} + :lint-as {dompa.nodes/defhtml clojure.core/defn}}
\ No newline at end of file diff --git a/src/dompa/nodes.cljc b/src/dompa/nodes.cljc index d72aa75..24d446e 100644 --- a/src/dompa/nodes.cljc +++ b/src/dompa/nodes.cljc @@ -73,4 +73,54 @@ (->html nodes {:void-nodes default-void-nodes})) ([nodes {:keys [void-nodes]}] (-> (node->html-reducer-fn void-nodes ->html) - (reduce "" nodes))))
\ No newline at end of file + (reduce "" nodes)))) + +(defmacro defhtml + "Creates a new function with `name` that outputs HTML. + + Example usage: + + ```clojure + (defhtml about-page [who] + ($ :div + ($ \"hello \" who))) + + (about-page \"world\") + ``` + " + [name & args-and-elements] + (let [[args & elements] args-and-elements] + `(defn ~name ~args + (->html (vector ~@elements))))) + +(defn $->flat-xf [] + (fn [rf] + (letfn [(step [result input] + (if (sequential? input) + (reduce step result input) + (rf result input)))] + (fn + ([] (rf)) + ([result] (rf result)) + ([result input] (step result input)))))) + +(defn $->flat [children] + (into [] ($->flat-xf) children)) + +(defmacro $ + "A helper that simplifies node creation. Particularly useful + where you need compile-time composition over run-time, like when + combined with the `defhtml` macro." + [name & opts] + `(if (string? ~name) + {:node/name :dompa/text + :node/value (str ~name ~@opts)} + (let [opts# (list ~@opts) + first-opt# (first opts#) + attrs?# (and (map? first-opt#) + (not (contains? first-opt# :node/name))) + attrs# (if attrs?# first-opt# {}) + children# (if attrs?# (rest opts#) opts#)] + (cond-> {:node/name ~name} + attrs?# (assoc :node/attrs attrs#) + (seq children#) (assoc :node/children ($->flat children#)))))) diff --git a/src/dompa/templates.cljc b/src/dompa/templates.cljc deleted file mode 100644 index 2f79fd2..0000000 --- a/src/dompa/templates.cljc +++ /dev/null @@ -1,37 +0,0 @@ -(ns dompa.templates - (:require [dompa.nodes :as nodes])) - -(defmacro defhtml - [name & args-and-elements] - (let [[args & elements] args-and-elements] - `(defn ~name ~args - (nodes/->html (vector ~@elements))))) - -(defn ->flat-xf [] - (fn [rf] - (letfn [(step [result input] - (if (sequential? input) - (reduce step result input) - (rf result input)))] - (fn - ([] (rf)) - ([result] (rf result)) - ([result input] (step result input)))))) - -(defn ->flat [children] - (into [] (->flat-xf) children)) - -(defmacro $ - [name & opts] - `(if (string? ~name) - {:node/name :dompa/text - :node/value (str ~name ~@opts)} - (let [opts# (list ~@opts) - first-opt# (first opts#) - attrs?# (and (map? first-opt#) - (not (contains? first-opt# :node/name))) - attrs# (if attrs?# first-opt# {}) - children# (if attrs?# (rest opts#) opts#)] - (cond-> {:node/name ~name} - attrs?# (assoc :node/attrs attrs#) - (seq children#) (assoc :node/children (->flat children#)))))) diff --git a/test/dompa/nodes_test.cljc b/test/dompa/nodes_test.cljc index 55f9394..0e2b63f 100644 --- a/test/dompa/nodes_test.cljc +++ b/test/dompa/nodes_test.cljc @@ -1,2 +1,24 @@ (ns dompa.nodes-test - (:require [clojure.test :refer [deftest is testing]])) + (:require [clojure.test :refer [deftest is testing]] + [dompa.nodes :refer [$]])) + +(deftest node-composition-test + (testing "a simple node" + (is (= {:node/name :div + :node/children [{:node/name :dompa/text + :node/value "hello world"}]} + ($ :div ($ "hello world"))))) + + (testing "a fragment node" + (is (= {:node/name :<> + :node/children [{:node/name :span + :node/children [{:node/name :dompa/text + :node/value "hello"}]} + {:node/name :span + :node/children [{:node/name :dompa/text + :node/value "world"}]}]} + ($ :<> + ($ :span + ($ "hello")) + ($ :span + ($ "world"))))))) diff --git a/test/dompa/templates_test.cljc b/test/dompa/templates_test.cljc deleted file mode 100644 index 6bbaf2c..0000000 --- a/test/dompa/templates_test.cljc +++ /dev/null @@ -1,24 +0,0 @@ -(ns dompa.templates-test - (:require [clojure.test :refer [deftest is testing]] - [dompa.templates :refer [defhtml $]])) - -(deftest node-composition-test - (testing "a simple node" - (is (= {:node/name :div - :node/children [{:node/name :dompa/text - :node/value "hello world"}]} - ($ :div ($ "hello world"))))) - - (testing "a fragment node" - (is (= {:node/name :<> - :node/children [{:node/name :span - :node/children [{:node/name :dompa/text - :node/value "hello"}]} - {:node/name :span - :node/children [{:node/name :dompa/text - :node/value "world"}]}]} - ($ :<> - ($ :span - ($ "hello")) - ($ :span - ($ "world"))))))) |
