diff --git a/resources/clj-kondo.exports/tensegritics/clojuredart/hooks/flutter2.clj b/resources/clj-kondo.exports/tensegritics/clojuredart/hooks/flutter2.clj index 8afa2e5c..727842c6 100644 --- a/resources/clj-kondo.exports/tensegritics/clojuredart/hooks/flutter2.clj +++ b/resources/clj-kondo.exports/tensegritics/clojuredart/hooks/flutter2.clj @@ -1,7 +1,7 @@ (ns hooks.flutter2 "Hook to support cljd.flutter.alpha2 macro" (:require [clj-kondo.hooks-api :as api - :refer [sexpr token-node list-node map-node vector-node]] + :refer [sexpr token-node list-node vector-node]] [clojure.string :as str])) (defn- ^:macro-support camel-kebab [s] @@ -38,8 +38,127 @@ (apply concat (get-node->let-binding-nodes (api/parse-string "{{{style displayLarge} textTheme} m/Theme :value-of [:counters]}"))))))) ,) +(defn watch-vector-node->let-binding-nodes + "Example: + Args: ` ] ]`" + ([node] + (watch-vector-node->let-binding-nodes node :watch)) + ([node opt-name] + (loop [pairs (partition 2 (:children node)) + last-binding-pair nil + ;; {:name hoge + ;; :value (rd/subscribe ,,,) + ;; :as true + ;; :dispose true + ;; :dedup true + ;; :> true} + aggr []] + (let [[k v :as pair] (first pairs)] + (if pair + (if (api/keyword-node? k) + (let [kw (sexpr k)] + (when (kw last-binding-pair) + (api/reg-finding! + (assoc (meta k) + :message (str "duplicate " kw " option in " opt-name " for `" + (:name last-binding-pair) "`") + :type :flutter/widget))) + (case kw + :as + (recur + (rest pairs) + (assoc last-binding-pair :as true) + (conj aggr [v (:value last-binding-pair)])) + + (:dispose :>) + (recur + (rest pairs) + (assoc last-binding-pair kw true) + (conj aggr + [(api/token-node '_) + (api/list-node + (list (api/token-node '->) v))])) + + (:dedup :refresh-on) + (recur + (rest pairs) + (assoc last-binding-pair kw true) + (conj aggr [(api/token-node '_) v])) + + ;; else unknown kw + (do + (api/reg-finding! + (assoc (meta k) + :message (str "unknown keyword option to " opt-name " `" kw "`") + :type :flutter/widget)) + (recur + (rest pairs) + last-binding-pair + aggr)))) ;; to ignore unknown keywords + (recur + (rest pairs) + {:name k + :value v} + (conj aggr + [k (let [node (api/list-node + (list (api/token-node 'deref) v))] + (with-meta node (meta v)))]))) + aggr))))) + +(defn managed-vector-node->let-binding-nodes + [node] + (loop [pairs (partition 2 (:children node)) + last-binding-pair nil + ;; {:name hoge + ;; :value (rd/subscribe ,,,) + ;; :refresh-on true + ;; :dispose true} + aggr []] + (let [[k v :as pair] (first pairs)] + (if pair + (if (api/keyword-node? k) + (let [kw (sexpr k)] + (when (kw last-binding-pair) + (api/reg-finding! + (assoc (meta k) + :message (str "duplicate " kw " option in :managed for `" + (:name last-binding-pair) "`") + :type :flutter/widget))) + (case kw + :dispose + (recur + (rest pairs) + (assoc last-binding-pair kw true) + (conj aggr + [(api/token-node '_) + (api/list-node + (list (api/token-node '->) v))])) + + :refresh-on + (recur + (rest pairs) + (assoc last-binding-pair kw true) + (conj aggr [(api/token-node '_) v])) -(defn vector-node->let-binding-nodesr + ;; else unknown kw + (do + (api/reg-finding! + (assoc (meta k) + :message (str "unknown keyword option to :managed `" kw "`") + :type :flutter/widget)) + (recur + (rest pairs) + last-binding-pair + aggr)))) + (recur + (rest pairs) + {:name k + :value v} + (conj aggr pair))) + aggr)))) + +(defn vector-node->let-binding-nodes "Example: Args: ` ] ]`" @@ -50,6 +169,29 @@ node-pair)) (partition 2 (:children node)))) +(defn vector-node->bg-watcher-node + [node] + (update node :children + (fn [[watcher & body]] + (let [watch-args (watch-vector-node->let-binding-nodes watcher :bg-watcher)] + (list* + (api/token-node 'let) + (vector-node (apply concat watch-args)) + body))))) + +(defn bind-node->let-binding-nodes + [node] + (if (api/map-node? node) + (mapv (fn [[_ v]] + [(api/token-node '_) v]) + (partition 2 (:children node))) + (do + (api/reg-finding! + (assoc (meta node) + :message (str ":bind needs a map parameter") + :type :flutter/widget)) + []))) + (defn top-key-value->let-binding-nodes "Examples: Args: ``, `` @@ -57,13 +199,49 @@ [node-key node-val] (case (sexpr node-key) :get (get-node->let-binding-nodes node-val) + :bind (bind-node->let-binding-nodes node-val) + (:key :keep-alive :spy :padding :color :width :height) [[(token-node '_) node-val]] (:vsync :context) (vector [(with-meta (token-node (sexpr node-val)) (meta node-val)) (token-node 'identity)]) - (:let :managed :watch) (vector-node->let-binding-nodesr node-val) - :bg-watcher [] + :let (vector-node->let-binding-nodes node-val) + :managed (managed-vector-node->let-binding-nodes node-val) + :watch (watch-vector-node->let-binding-nodes node-val) + :bg-watcher [[(token-node '_) (vector-node->bg-watcher-node node-val)]] ;; unsupported keys ignored [])) +(defn nest-body + [[head & tail]] + (if (seq? tail) + (cond + (api/token-node? head) + (nest-body + (list* (api/list-node + (list head)) + tail)) + + (api/list-node? head) + (let [[maybe-prop & followup] tail + nested-body + (if (and (api/token-node? maybe-prop) + (simple-symbol? (sexpr maybe-prop)) + (.startsWith (name (sexpr maybe-prop)) ".")) + (list maybe-prop (nest-body followup)) + (list (api/token-node '.child) + (nest-body (list* maybe-prop followup))))] + (update + head :children + (fn [children] + (concat children nested-body)))) + + :else + (api/list-node + (list head (nest-body tail)))) + (if (api/token-node? head) + (api/list-node + (list head)) + head))) + (defn widget "The idea is to have all of the bindings in let form and everything else in the body. @@ -98,16 +276,17 @@ (remove (fn [[_ i]] (when (> i 0) (api/keyword-node? (nth children (dec i)))))) - (map first)) + (map first) + nest-body) let-node (list-node - (list* - (token-node 'let) - (vector-node - (apply concat let-bindings)) - body))] - ; (clojure.pprint/pprint (sexpr let-node)) + (list + (token-node 'let) + (vector-node + (apply concat let-bindings)) + body))] + ;; (clojure.pprint/pprint (sexpr let-node)) {:node let-node})) (comment