~benaiah/fennel-openresty

4905ad145c06c03c10f43a87fb906e8d53cebdc3 — Benaiah Mischenko 5 years ago a0aacdc
Import react-macros.fnl from fennel-online
1 files changed, 61 insertions(+), 0 deletions(-)

A app/src/react-macros.fnl
A app/src/react-macros.fnl => app/src/react-macros.fnl +61 -0
@@ 0,0 1,61 @@
(local unpack (or unpack table.unpack))
(fn push [tab v]
  (let [len (# tab)
        i (+ len 1)]
    (tset tab i v)))

(fn js! [val]
  (if (table? val)
    (let [RETURN (gensym)
          dolist `(do)]
      (if (sequence? val)
          (do
            (push dolist `(local @RETURN (js.new js.global.Array)))
            (each [i v (ipairs val)]
              (push dolist `(tset @RETURN @(- i 1) @(js! v))))
            (push dolist RETURN)
            dolist)

          (do (push dolist `(local @RETURN (js.new js.global.Object)))
              (each [k v (pairs val)]
                (push dolist `(tset @RETURN @(tostring k) @(js! v))))
              (push dolist RETURN)
              dolist)))
    val))

(fn create-component [el attrs ...]
  (let [ATTRS (gensym)
        CHILDREN (gensym)
        children [...]
        child-list []]
    (each [i v (ipairs children)]
      (push child-list `@(js! v)))
    `(do (local @ATTRS @(js! (or attrs {})))
         (: React :createElement @el @ATTRS
            @(unpack child-list)))))

(fn c! [arg1 ...]
  (if (sequence? arg1)
      (let [[name attrs] arg1
            child-forms []
            evaluated-child-forms []]
        (for [i 3 (# arg1)] ;; skip name and attrs
          (push child-forms (. arg1 i)))
        (each [_ child-form (ipairs child-forms)]
          ;; FIXME: this will eventually blow the stack
          (push evaluated-child-forms
                (if (sequence? child-form) (c! child-form)
                    child-form)))
        (create-component name attrs (unpack evaluated-child-forms)))

      ;; else
      (create-component arg1 ...)))

(fn component! [name args ...]
  (let [padded-args `[_ @(unpack args)]]
    `(fn @name @padded-args @...)))


{:js! js!
 :c! c!
 :component! component!}