Last active
February 1, 2019 14:43
-
-
Save mhuebert/7be2abd9c188bd84c79c05596fd5dbbf to your computer and use it in GitHub Desktop.
js-interop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{:deps {chia {:git/url "https://github.com/mhuebert/chia" | |
:sha "885e84e84b39836a9cb12bc3b90880dc25a11482"}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns XYZ | |
(:require [chia.util.js-interop :as j]) | |
(def o | |
(-> #js {} | |
(j/assoc! :x 1) ;; gobj/set | |
(j/update :x inc) ;; gobj/get and gobj/set | |
(j/assoc-in! [:y :z] 0) ;; gobj/getValueByKeys and gobj/set | |
(j/update-in! [:y :z] inc))) ;; gobj/getValueByKeys and gobj/set | |
(j/get o :x) ;; gobj/get | |
(j/get o :x :not-found) | |
(j/get-in o [:y :z]) ;; gobj/getValueByKeys | |
(j/get-in o [:y :z] :not-found) | |
(j/select-keys o [:x :y]) ;; returns new object containing only the provided keys which are contained in `o` | |
(j/contains? o :x) ;; gobj/containsKey | |
(j/set! o :a 0) ;; set! uses `unchecked-set`, whereas `assoc!` uses gobj/set | |
(let [{:keys [x y]} (j/lookup o)] | |
;; j/lookup wraps `o` to support ILookup, & therefore destructuring | |
) | |
(j/push! a 0) ;; JS array push, returns array | |
(j/unshift! a 0) ;; JS array unshift (prepend), returns array | |
(j/call o :someFn arg1 arg2) ;; call a fn on `o` with `this` bound to `o`, like o.someFn(arg1, arg2) | |
;; this one maybe shouldn't stay, or should be renamed | |
(j/!get o :x) ;; unchecked-get, faster than gobj/get, compiles to javascript property array access | |
;; using a core function marked as INTERNAL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; macros namespace | |
(ns chia.util.js-interop | |
(:refer-clojure :exclude [get get-in assoc! contains? set!]) | |
(:require [clojure.core :as core])) | |
(defn wrap-key [k] | |
(cond | |
(string? k) k | |
(keyword? k) (name k) | |
(symbol? k) (if (= (:tag (meta k)) "String") | |
k | |
`(wrap-key ~k)) | |
:else `(wrap-key ~k))) | |
(defn wrap-path [p] | |
(if (vector? p) | |
(mapv wrap-key p) | |
`(mapv wrap-key ~p))) | |
(defn- get* | |
([o k] | |
(get* o k nil)) | |
([o k not-found] | |
`(~'goog.object/get ~o ~(wrap-key k) ~not-found))) | |
(defmacro get | |
[& args] | |
(apply get* args)) | |
(defmacro !get [o k] | |
`(core/unchecked-get ~o ~(wrap-key k))) | |
(defn- get-in* | |
([o path] | |
(get-in* o path nil)) | |
([o path not-found] | |
`(or ~(if (vector? path) | |
`(~'goog.object/getValueByKeys ~o ~@(mapv wrap-key path)) | |
`(.apply ~'goog.object/getValueByKeys | |
nil | |
(to-array (cons ~o (map wrap-key ~path))))) | |
~not-found))) | |
(defmacro get-in | |
[& args] | |
(apply get-in* args)) | |
(defn doto-pairs [o f pairs] | |
`(doto ~o | |
~@(loop [pairs (partition 2 pairs) | |
out []] | |
(if (empty? pairs) | |
out | |
(let [[k v] (first pairs)] | |
(recur (rest pairs) | |
(conj out (f (wrap-key k) v)))))))) | |
(defmacro assoc! [o & pairs] | |
(doto-pairs o (fn [k v] | |
`(~'goog.object/set ~k ~v)) pairs)) | |
(defmacro set! [o & pairs] | |
(doto-pairs o (fn [k v] | |
`(~'cljs.core/unchecked-set ~k ~v)) pairs)) | |
(defmacro push! [a v] | |
`(doto ~a | |
(~'.push ~v))) | |
(defmacro unshift! [arr v] | |
`(doto ~arr | |
(~'.unshift ~v))) | |
(defmacro then [promise arglist & body] | |
`(~'.then ~'^js ~promise | |
(fn ~arglist ~@body))) | |
(defn contains? [o k] | |
`(~'goog.object/containsKey o ~(wrap-key k))) | |
(defmacro call [o k & args] | |
`(let [^js f# (get ~o ~k)] | |
(~'.call f# ~o ~@args))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; functions namespace | |
(ns chia.util.js-interop | |
(:refer-clojure :exclude [get unchecked-get get-in assoc! assoc-in! update! update-in! select-keys contains?]) | |
(:require [goog.object :as gobj] | |
[cljs.core :as core]) | |
(:require-macros [chia.util.js-interop :as j])) | |
(defn wrap-key [k] | |
(cond-> k | |
(keyword? k) (name))) | |
(defn get | |
([o k] | |
(j/get o k)) | |
([o k not-found] | |
(j/get o k not-found))) | |
(defn get-in | |
([obj ks] | |
(.apply gobj/getValueByKeys nil (to-array (cons obj (map wrap-key ks))))) | |
([obj ks not-found] | |
(or (get-in obj ks) not-found))) | |
(defn assoc! | |
[obj & pairs] | |
(loop [[k v & more] pairs] | |
(gobj/set obj (wrap-key k) v) | |
(if (seq more) | |
(recur more) | |
obj))) | |
(defn assoc-in! [obj ks value] | |
(assert (> (count ks) 1)) | |
(let [ks (mapv wrap-key ks) | |
inner-obj (get-in obj (drop-last ks))] | |
(gobj/set inner-obj (last ks) value) | |
obj)) | |
(defn set! [obj k val] | |
(core/unchecked-set obj (wrap-key k) val) | |
obj) | |
(defn update! [obj k f & args] | |
(gobj/set obj (wrap-key k) | |
(apply f (cons (gobj/get obj (wrap-key k)) args))) | |
obj) | |
(defn update-in! [obj ks f & args] | |
(let [ks (mapv wrap-key ks) | |
val-at-path (.apply gobj/getValueByKeys nil (to-array (cons obj ks)))] | |
(assoc-in! obj ks (apply f (cons val-at-path args))))) | |
(deftype JSLookup [obj] | |
ILookup | |
(-lookup [_ k] | |
(gobj/get obj (wrap-key k))) | |
(-lookup [_ k not-found] | |
(gobj/get obj (wrap-key k) not-found)) | |
IDeref | |
(-deref [o] obj)) | |
(defn lookup | |
"Allows for single-level destructuring of JS keys | |
(let [{:keys [id]} (lookup some-obj)] | |
...)" | |
[obj] | |
(JSLookup. obj)) | |
(defn select-keys [o ks] | |
(reduce (fn [m k] | |
(let [k (wrap-key k)] | |
(cond-> m | |
(gobj/containsKey o k) | |
(doto | |
(unchecked-set k | |
(gobj/get o k nil)))))) #js {} ks)) | |
(defn push! [^js a v] | |
(doto a | |
(.push v))) | |
(defn contains? [o k] | |
(gobj/containsKey o (wrap-key k))) | |
(defn call [^js o k & args] | |
(.apply (j/get o k) o (to-array args))) | |
(defn !get [o k] | |
(core/unchecked-get o (wrap-key k))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment