|
| 1 | +(ns hooks.ornament |
| 2 | + (:require [clj-kondo.hooks-api :as api])) |
| 3 | + |
| 4 | +(defonce styled-registry (atom #{})) |
| 5 | + |
| 6 | +(defn- symbol-node? [node] |
| 7 | + (and (api/token-node? node) |
| 8 | + (symbol? (api/sexpr node)))) |
| 9 | + |
| 10 | +(defn- styled-component? [node] |
| 11 | + (and (symbol-node? node) |
| 12 | + (contains? @styled-registry (api/sexpr node)))) |
| 13 | + |
| 14 | +(defn defstyled [{:keys [node]}] |
| 15 | + (let [[class-name html-tag & more] (rest (:children node)) |
| 16 | + _ (when-not (and (symbol-node? class-name) |
| 17 | + (simple-symbol? (api/sexpr class-name))) |
| 18 | + (api/reg-finding! {:row (:row (meta class-name)) |
| 19 | + :col (:col (meta class-name)) |
| 20 | + :message "Style name must be a simple symbol" |
| 21 | + :type :lambdaisland.ornament/invalid-syntax})) |
| 22 | + _ (when-not (or (api/keyword-node? html-tag) |
| 23 | + (styled-component? html-tag)) |
| 24 | + (api/reg-finding! {:row (:row (meta html-tag)) |
| 25 | + :col (:col (meta html-tag)) |
| 26 | + :message "Tag must be a keyword or an ornament-styled-component" |
| 27 | + :type :lambdaisland.ornament/invalid-syntax})) |
| 28 | + fn-tag (first (drop-while (fn [x] |
| 29 | + (or (api/string-node? x) |
| 30 | + (api/keyword-node? x) |
| 31 | + (api/map-node? x) |
| 32 | + (api/vector-node? x) |
| 33 | + (api/token-node? x))) |
| 34 | + more)) |
| 35 | + _ (when (and fn-tag |
| 36 | + (not (api/list-node? fn-tag))) |
| 37 | + (api/reg-finding! {:row (:row (meta fn-tag)) |
| 38 | + :col (:col (meta fn-tag)) |
| 39 | + :message "Function part (if present) must be a list" |
| 40 | + :type :lambdaisland.ornament/invalid-syntax})) |
| 41 | + symbol-tag? (symbol-node? html-tag)] |
| 42 | + ;; Register this component in the styled-registry |
| 43 | + (swap! styled-registry conj (api/sexpr class-name)) |
| 44 | + (if (api/list-node? fn-tag) |
| 45 | + (let [[binding-vec & body] (:children fn-tag) |
| 46 | + fn-node (api/list-node |
| 47 | + (list* |
| 48 | + (api/token-node 'fn) |
| 49 | + binding-vec |
| 50 | + body)) |
| 51 | + new-def-node (api/list-node |
| 52 | + (if symbol-tag? |
| 53 | + (list (api/token-node 'def) |
| 54 | + class-name |
| 55 | + (api/list-node |
| 56 | + (list (api/token-node 'do) |
| 57 | + html-tag |
| 58 | + fn-node))) |
| 59 | + (list (api/token-node 'def) |
| 60 | + class-name |
| 61 | + fn-node)))] |
| 62 | + {:node new-def-node}) |
| 63 | + (let [def-class-form (api/list-node |
| 64 | + (if symbol-tag? |
| 65 | + (list (api/token-node 'def) |
| 66 | + class-name |
| 67 | + html-tag) |
| 68 | + (list (api/token-node 'def) |
| 69 | + class-name |
| 70 | + (api/token-node 'nil))))] |
| 71 | + {:node def-class-form})))) |
0 commit comments