Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
(def machine
  (fsm/machine
    {:id      ::traffic
     :initial :red
     :states  {:red    {:on {::tick :green}}
               :green  {:on {::tick :orange}}
               :orange {:on {::tick :red}}}}))

(defn statechart->interceptor
  [{:keys [id path machine]}]
  (rf/->interceptor
    :id id
    :before (fn [context]
              (let [eid (get-in context [:coeffects :event 0])
                    s0 (or (get-in context (into [:coeffects :db] path))
                           (fsm/initialize m))]
                (try (let [s1 (fsm/transition machine (assoc s0 :fx [] :context context) {:type eid})]
                       (assoc-in context [:coeffects id] (dissoc s1 :context)))
                     (catch js/Object err
                       (js/console.warn (ex-info ::fsm.error {:id id :s0 s0 :eid eid} err))
                       context))))
    :after (fn [context]
             (if-let [s1 (get-in context [:coeffects id])]
               (let [db (or (get-in context [:effects :db])
                            (get-in context [:coeffects :db]))
                     fx (get-in context [:effects :fx] [])]
                 (-> context
                     (update :coeffects dissoc id)
                     (assoc-in [:effects :db] (assoc-in db path (dissoc s1 :fx)))
                     (assoc-in [:effects :fx] (into fx (:fx s1)))))
               context))))

(rf/clear-global-interceptor ::fsm-id)
(rf/reg-global-interceptor (statechart->interceptor {:id ::fsm-id :machine machine :path [:fsm/state]}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment