<commit_before>(ns keechma.ui-component
  (:require [cljs.core.async :refer [put!]]
            [com.stuartsierra.dependency :as dep]
            [keechma.util :as util]
            [clojure.string :refer [join]]
            [clojure.set :as set]))

(declare component->renderer)

(defn component-dep-graph [components]
  (reduce-kv (fn [graph k v]
               (if-not (fn? v)
                 (let [component-deps (:component-deps v)]
                   (if (util/in? component-deps :main)
                     (throw (js/Error "Nothing can depend on the :main component!"))
                     (reduce #(dep/depend %1 k %2) graph component-deps)))
                 graph)) (dep/graph) components))

(defn missing-component-deps [components]
  (reduce-kv (fn [missing k v]
               (if (nil? v)
                 (conj missing k)
                 missing)) [] components))


(defn component-with-deps [component-key component system]
  (let [dep-keys (:component-deps component)]
    (if-not (empty? dep-keys)
      (let [components (select-keys system dep-keys)
            missing-deps (missing-component-deps components)]  
        (if-not (empty? missing-deps)
          (throw (js/Error (str "Missing dependencies " (join ", " missing-deps) " for component " component-key)))
          (-> component
              (assoc :components components)
              (assoc :component-deps []))))
      component)))

(defn resolve-dep [dep-kw coll-kw component key component-dep]
  (-> component
      (assoc-in [coll-kw key] component-dep)
      (assoc dep-kw (util/without (dep-kw component) key))))

(def resolve-subscription-dep (partial resolve-dep :subscription-deps :subscriptions))
(def resolve-component-dep (partial resolve-dep :component-deps :components))

(defn resolved-system [components sorted-keys]
  (reduce (fn [system key]
            (let [component (get system key)]
              (if (fn? component)
                (assoc system key component)
                (assoc system key (component-with-deps key component system))))) components sorted-keys))

(defn system [components]
  (if (nil? (:main components))
    (throw (js/Error "System must have a :main component!"))
    (let [graph (component-dep-graph components)
          sorted-keys (dep/topo-sort graph)]
      (:main (resolved-system components sorted-keys)))))

(defprotocol IUIComponent  
  (url [this params])
  (subscription [this name])
  (component [this name])
  (send-command [this command] [this command args])<commit_msg>Add subscription resolving to `ui-component/system`<commit_after>(ns keechma.ui-component
  (:require [cljs.core.async :refer [put!]]
            [com.stuartsierra.dependency :as dep]
            [keechma.util :as util]
            [clojure.string :refer [join]]
            [clojure.set :as set]))

(declare component->renderer)

(defn component-dep-graph [components]
  (reduce-kv (fn [graph k v]
               (if-not (fn? v)
                 (let [component-deps (:component-deps v)]
                   (if (util/in? component-deps :main)
                     (throw (js/Error "Nothing can depend on the :main component!"))
                     (reduce #(dep/depend %1 k %2) graph component-deps)))
                 graph)) (dep/graph) components))

(defn missing-component-deps [components]
  (reduce-kv (fn [missing k v]
               (if (nil? v)
                 (conj missing k)
                 missing)) [] components))


(defn component-with-deps [component-key component system]
  (let [dep-keys (:component-deps component)]
    (if-not (empty? dep-keys)
      (let [components (select-keys system dep-keys)
            missing-deps (missing-component-deps components)]  
        (if-not (empty? missing-deps)
          (throw (js/Error (str "Missing dependencies " (join ", " missing-deps) " for component " component-key)))
          (-> component
              (assoc :components components)
              (assoc :component-deps []))))
      component)))

(defn resolve-dep [dep-kw coll-kw component key component-dep]
  (-> component
      (assoc-in [coll-kw key] component-dep)
      (assoc dep-kw (util/without (dep-kw component) key))))

(def resolve-subscription-dep (partial resolve-dep :subscription-deps :subscriptions))
(def resolve-component-dep (partial resolve-dep :component-deps :components))

(defn resolved-system [components sorted-keys]
  (reduce (fn [system key]
            (let [component (get system key)]
              (if (fn? component)
                (assoc system key component)
                (assoc system key (component-with-deps key component system))))) components sorted-keys))

(defn resolve-component-subscriptions [component subscriptions]
  (reduce (fn [c dep]
            (let [sub (get subscriptions dep)]
              (if (nil? sub)
                (throw (js/Error (str "Missing subscription: " dep)))
                (resolve-subscription-dep c dep sub))))
          component (or (:subscription-deps component) [])))

(defn resolve-subscriptions [components subscriptions]
  (reduce-kv (fn [components k c]
               (assoc components k (resolve-component-subscriptions c subscriptions)))
             {} components))

(defn system
  ([components] (system components {}))
  ([components subscriptions]
   (if (nil? (:main components))
     (throw (js/Error "System must have a :main component!"))
     (let [graph (component-dep-graph components)
           sorted-keys (dep/topo-sort graph)
           components-with-resolved-deps (resolve-subscriptions components subscriptions)]
       (:main (resolved-system components-with-resolved-deps sorted-keys))))))
 
(defprotocol IUIComponent  
  (url [this params])
  (subscription [this name])
  (component [this name])
  (send-command [this command] [this command args])
{'fraction_non_alphanumeric': 0.13044226467045258, 'fraction_numerical': 0.0006883496816382723, 'mean_word_length': 2.5245603395997573, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6412666', 'n_tokens_mistral': 1680, 'n_tokens_neox': 1664, 'n_words': 489}