Published demo site

This commit is contained in:
Julien Eluard 2018-05-10 11:57:22 +02:00
parent a91faf961c
commit 5761bf27dc
No known key found for this signature in database
GPG Key ID: 6FD7DB5437FCBEF6
22 changed files with 2827 additions and 195 deletions

View File

@ -1,18 +1,8 @@
Launch figwheel with ./scripts/figwheel.sh then open index.html Launch figwheel with ./scripts/figwheel.sh then open http://127.0.0.1/index.html
### IPFS ### IPFS
You need to start a daemon locally, as the main gateway has CORS. The mobile app To upload a directory to IPFS:
does not have this limitation and can hit directly the gateway.
Before starting the dameon setup CORS:
```
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["GET", "POST"]'
```
and then
``` ```
ipfs daemon ipfs daemon

View File

@ -10,8 +10,8 @@
(def compiler-config {:main 'pluto.demo (def compiler-config {:main 'pluto.demo
:asset-path "js/out" :asset-path "js/out"
:output-to "resources/public/js/pluto.js" :output-to "resources/public/assets/pluto.js"
:output-dir "resources/public/js/out" :output-dir "resources/public/assets/pluto"
:optimizations :none :optimizations :none
:static-fns true :static-fns true
:elide-asserts false :elide-asserts false
@ -19,6 +19,12 @@
:preloads ['day8.re-frame-10x.preload] :preloads ['day8.re-frame-10x.preload]
:source-map true}) :source-map true})
(def compiler-release-config {:main 'pluto.demo
:output-to "resources/public/assets/pluto.js"
:optimizations :advanced
:static-fns true
:elide-asserts true})
(def test-config {:main 'pluto.runner (def test-config {:main 'pluto.runner
:output-to "target/test.js" :output-to "target/test.js"
:output-dir "target/test" :output-dir "target/test"
@ -65,7 +71,7 @@
;;; Compiling task. ;;; Compiling task.
(defn compile-once [] (defn compile-once []
(api/build source-dir compiler-config)) (api/build source-dir compiler-release-config))
(defn compile-refresh [] (defn compile-refresh []
(api/watch source-dir compiler-config)) (api/watch source-dir compiler-config))
@ -118,4 +124,4 @@
;;; Build script entrypoint. ;;; Build script entrypoint.
(task *command-line-args*) (task (map string/trim *command-line-args*))

44
demo/index.html Normal file
View File

@ -0,0 +1,44 @@
<html>
<script type="text/javascript" src="assets/instascan.min.js"></script>
<script type="text/javascript" src="assets/qrcode.min.js"></script>
<body>
<main>
<div id="selection">
<span>Scan this QR code to load from IPFS</span>
<div id="ipfs"></div>
<div>
Or load from HTTP <button onclick="pluto.demo.load_and_render('ipfs:QmSKP6f2uUsFq4mk1Afe4ZktxwQifrLb4xRQYNE1LxidKz')">Demo</button>
</div>
</div>
<div id="extension">
<iframe id="frame" srcdoc="<body><main></main></body>"></iframe>
<div id="errors"></div>
</div>
<video id="preview"></video>
</main>
</body>
</html>
<script src="assets/pluto.js"></script>
<script>
var qrcode = new QRCode("ethereum:status-extension:ipfs:QmSKP6f2uUsFq4mk1Afe4ZktxwQifrLb4xRQYNE1LxidKz");
var svg = qrcode.svg();
document.getElementById("ipfs").innerHTML = svg;
</script>
<script type="text/javascript">
let scanner = new Instascan.Scanner({ video: document.getElementById('preview') });
scanner.addListener('scan', function (content) {
console.log(content);
pluto.demo.load_and_render(content.replace("ethereum:status-extension:", ""));
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
scanner.start(cameras[0]);
} else {
console.error('No cameras found.');
}
}).catch(function (e) {
console.error(e);
});
</script>

1244
demo/pluto.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
resources/public/assets/qrcode.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,12 +0,0 @@
{:hooks/main
#view [:main]
:views/main
[view {}
[text "Hello"]]}
; (let [cond? #query [:random-boolean]]
; (when cond?
; [text {}]
; "World"))

View File

@ -0,0 +1,19 @@
{:extension/meta
{:name "Simple Demo"
:description "A simple demo of extension"
:documentation "Nothing. Just see a text with dynamic random color."}
:hooks/main
{:name ""
:description ""
:view #status/view [:main]}
:views/main
[view {}
[text {} "Hello"]
(let [cond? #status/query [:random-boolean]]
(if cond?
[text {:style {:color "green"}}
"World?"]
[text {:style {:color "red"}}
"World?"]))]}

View File

@ -7,18 +7,18 @@
{:on-activated #event [:fetch-all-posts]} {:on-activated #event [:fetch-all-posts]}
:events/fetch-all-posts :events/fetch-all-posts
[:ethereum/logs {:address "0xfa28ec7198028438514b49a3cf353bca5541ce1d" [:status/ethereum.logs {:address "0xfa28ec7198028438514b49a3cf353bca5541ce1d"
:topics ["PeepEth()"] :topics ["PeepEth()"]
:inputs [{:name :hash :type :string}] ;; Allows to decode transaction data :inputs [{:name :hash :type :string}] ;; Allows to decode transaction data
:on-log #event [:fetch-ipfs]}] ;; A map of decoded data will be injected :on-log #status/event [:fetch-ipfs]}] ;; A map of decoded data will be injected
:events/fetch-ipfs :events/fetch-ipfs
(let [{:keys [hash]} properties] (let [{:keys [hash]} properties]
[:ipfs/get {:hash hash [:status/ipfs.get {:hash hash
:on-success #event [:db/append {:path [:all-posts]}]}]) :on-success #status/event [:status/db.append {:path [:all-posts]}]}])
:queries/all-posts :queries/all-posts
[:db/get {:path [:all-posts] [:status/db.get {:path [:all-posts]
:limit 20}] :limit 20}]
:views/post :views/post
@ -43,10 +43,10 @@
{:en "Peepeth !!"} {:en "Peepeth !!"}
:hooks/main :hooks/main
[screen {:style #style [:screen]} [screen {:style #status/style [:screen]}
[toolbar {} [toolbar {}
[text {} [text {}
#i18n [:title]]] #i18n [:title]]]
(let {posts #query [:all-posts]} (let [posts #status/query [:all-posts]]
[list {:data posts [list {:data posts
:template #view [:post]}])]} :template #status/view [:post]}])]}

View File

@ -1,10 +1,44 @@
<html> <html>
<script type="text/javascript" src="assets/instascan.min.js"></script>
<script type="text/javascript" src="assets/qrcode.min.js"></script>
<body> <body>
<main>
<div id="selection">
<span>Scan this QR code to load from IPFS</span>
<div id="ipfs"></div>
<div>
Or load from HTTP <button onclick="pluto.demo.load_and_render('ipfs:QmSKP6f2uUsFq4mk1Afe4ZktxwQifrLb4xRQYNE1LxidKz')">Demo</button>
</div>
</div>
<div id="extension">
<iframe id="frame" srcdoc="<body><main></main></body>"></iframe> <iframe id="frame" srcdoc="<body><main></main></body>"></iframe>
<div id="errors"></div>
</div>
<video id="preview"></video>
</main>
</body> </body>
</html> </html>
<script src="js/pluto.js"></script> <script src="assets/pluto.js"></script>
<script> <script>
pluto.demo.run(); var qrcode = new QRCode("ethereum:status-extension:ipfs:QmSKP6f2uUsFq4mk1Afe4ZktxwQifrLb4xRQYNE1LxidKz");
var svg = qrcode.svg();
document.getElementById("ipfs").innerHTML = svg;
</script>
<script type="text/javascript">
let scanner = new Instascan.Scanner({ video: document.getElementById('preview') });
scanner.addListener('scan', function (content) {
console.log(content);
pluto.demo.load_and_render(content.replace("ethereum:status-extension:", ""));
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
scanner.start(cameras[0]);
} else {
console.error('No cameras found.');
}
}).catch(function (e) {
console.error(e);
});
</script> </script>

4
scripts/publish.sh Normal file
View File

@ -0,0 +1,4 @@
mkdir -p demo
clj -R:repl build.clj compile once
cp resources/public/assets/pluto.js demo/
cp resources/public/index.html demo/

View File

@ -3,11 +3,11 @@
(defn view [props & content] (defn view [props & content]
(into [:div props] content)) (into [:div props] content))
(defn button [props content] (defn button [props & content]
[:button props content]) (into [:button props] content))
(defn text [props content] (defn text [props & content]
[:span props content]) (into [:span props] content))
(def components {'view view (def components {'view view
'button button 'button button

View File

@ -1,5 +1,6 @@
(ns pluto.demo (ns pluto.demo
(:require [pluto.components.html :as html] (:require [clojure.string :as string]
[pluto.components.html :as html]
[pluto.reader :as reader] [pluto.reader :as reader]
[pluto.storage :as storage] [pluto.storage :as storage]
[pluto.storage.http :as http] [pluto.storage.http :as http]
@ -34,19 +35,18 @@
(let [frame (js/document.getElementById "frame")] (let [frame (js/document.getElementById "frame")]
(reagent/render (h) (.. (aget frame "contentWindow" "document") -body -firstChild)))) (reagent/render (h) (.. (aget frame "contentWindow" "document") -body -firstChild))))
(defn header [] (defn main-browser
[:div "A simple hook for :hooks/main"
"Random boolean: " [{:keys [data errors]}]
(let [b @(re-frame/subscribe [:random-boolean])]
[:span {:style {:color (if b :green :red)}}
(str b)])])
(defn wrap-with-cartouche [o]
(println ">>>>" o)
(fn [] (fn []
[:div [:div
^{:key 1} [header] (let [{:views/keys [main]} data]
^{:key 2} o])) main)
(when (seq errors)
(into [:ul]
(for [{:keys [type] :as m} errors]
[:li
[:span [:b (str type)] (pr-str (dissoc m :type))]])))]))
(defn wrap-extensions [os] (defn wrap-extensions [os]
(fn [] (fn []
@ -56,23 +56,28 @@
[:h2 (:name o)] [:h2 (:name o)]
[:p (:content o)]])])) [:p (:content o)]])]))
(defn ^:export run (defn storage-for [type]
[] (condp = type
"url" (http/HTTPStorage.)
"ipfs" (ipfs/IPFSStorage. "https://gateway.ipfs.io")))
(defn fetch [uri cb]
(let [[type id] (string/split uri ":")]
(storage/fetch
(storage-for type)
{:value id} cb)))
(defn ^:export load-and-render
[s]
(re-frame/clear-subscription-cache!) (re-frame/clear-subscription-cache!)
(fetch s
(storage/fetch (ipfs/IPFSStorage. "http://localhost:8080")
{:id "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG" :URL "/demo.edn"}
#(->> %
wrap-extensions
render))
(storage/fetch (http/HTTPStorage.)
{:URL "/demo.edn"}
#(-> % #(-> %
;; TODO merge all returned files in a map
:value
first
:content
reader/read reader/read
:data :data
((fn [m] (println "<<<" m) (reader/parse {:components html/components :valid-hooks #{:hooks/main}} m))) ((fn [m] (reader/parse {:components html/components :valid-extensions #{:extension/meta} :valid-hooks #{:hooks/main}} m)))
:data main-browser
:views/main
wrap-with-cartouche
render))) render)))

View File

@ -49,10 +49,10 @@
{:data {:data
(try (try
(edn/read-string {:default #(do (accumulate-reader-error! errors {:type :unknown-tag :tag %1 :value %2}) %2) (edn/read-string {:default #(do (accumulate-reader-error! errors {:type :unknown-tag :tag %1 :value %2}) %2)
:readers {'query #(mark-reference :query %) :readers {'status/query #(mark-reference :query %)
'event #(mark-reference :event %) 'status/event #(mark-reference :event %)
'view #(mark-reference :view %) 'status/view #(mark-reference :view %)
'style #(mark-reference :style %)}} 'status/style #(mark-reference :style %)}}
s) s)
(catch #?(:clj Exception :cljs :default) e (catch #?(:clj Exception :cljs :default) e
(accumulate-reader-error! errors (assoc (ex-data e) :message (ex-message e))) (accumulate-reader-error! errors (assoc (ex-data e) :message (ex-message e)))
@ -101,26 +101,25 @@
(reduce #(let [{:keys [data errors]} (parse-view opts %2)] (reduce #(let [{:keys [data errors]} (parse-view opts %2)]
(cond-> (update %1 :data conj data) (cond-> (update %1 :data conj data)
(seq errors) (accumulate-errors errors))) (seq errors) (accumulate-errors errors)))
{} children)) {:data []} children))
(defn parse-hiccup-element [{:keys [components] :as opts} o] (defn parse-hiccup-element [{:keys [components] :as opts} o]
;; TODO permissions ;; TODO permissions
;; TODO replace elements
(cond (cond
(primitive? o) {:data o} (or (symbol? o) (primitive? o)) {:data o}
(vector? o) (vector? o)
(let [[element properties & children] o (let [[element properties & children] o
component (element components)] component (if (fn? element) element (get components element))]
(cond-> (let [m (parse-hiccup-children opts children)] (cond-> (let [m (parse-hiccup-children opts children)]
;; Reduce parsed children to a single map and wrap them in a hiccup element ;; Reduce parsed children to a single map and wrap them in a hiccup element
;; whose component has been translated to the local platform ;; whose component has been translated to the local platform
(update m :data #(apply conj [(or component element) properties] %))) (update m :data #(apply conj [(or component element) properties] %)))
(nil? component) (accumulate-errors [{:type :unknown-component :element element}]))))) (nil? component) (accumulate-errors [{:type :unknown-component :element element}])))
:else 3))
(defn parse-view [opts o] (defn parse-view [opts o]
(cond (cond
(instance? Reference o) (resolve-reference (:tag o) (:value o)) (list? o) (parse-view opts (:data (blocks/parse opts o)))
(list? o) (blocks/parse opts o)
:else (parse-hiccup-element opts o))) :else (parse-hiccup-element opts o)))
(defmulti parse-value (defmulti parse-value
@ -131,9 +130,12 @@
* :errors a collection of errors" * :errors a collection of errors"
(fn [_ k _] (namespace k))) (fn [_ k _] (namespace k)))
(defmethod parse-value "extension" [opts _ v] v)
(defmethod parse-value "views" [opts _ v] (parse-view opts v)) (defmethod parse-value "views" [opts _ v] (parse-view opts v))
;; TODO extension, events, queries, i18n, styles ;; TODO extension, events, queries, i18n, styles
(defmethod parse-value :default [_ k _] {:errors [{:type :unkown-element-type :value k}]}) (defmethod parse-value :default [_ k _] {:errors [{:type :unknown-element-type :value k}]})
(defn merge-parsed-value (defn merge-parsed-value
"Merge result of parse-value into a map. "Merge result of parse-value into a map.
@ -157,10 +159,6 @@
* :permissions a vector of required permissions * :permissions a vector of required permissions
* :errors a vector of errors map triggered during parse" * :errors a vector of errors map triggered during parse"
[opts m] [opts m]
;; TODO
; Replace lookup refs with values
; Replace conditional blocks with reagent components
; Errors; Permissions; env cascade (:outer)
(let [errors (validate-keys opts (keys m))] (let [errors (validate-keys opts (keys m))]
(cond-> (reduce-kv #(merge-parsed-value opts %1 %2 %3) {} m) (cond-> (reduce-kv #(merge-parsed-value opts %1 %2 %3) {} m)
(seq errors) (accumulate-errors errors)))) (seq errors) (accumulate-errors (map (fn [error] {:type (key error) :value (val error)}) errors)))))

View File

@ -0,0 +1,56 @@
(ns pluto.reader.blocks
(:require [clojure.walk :as walk]
[re-frame.core :as re-frame]))
(defmulti parse
""
(fn [_ [type]] type))
(defn resolve-queries [env]
;; TODO only resolve encoded queries
(reduce-kv #(assoc %1 %2 (if (record? %3) @(re-frame/subscribe (:value %3))) %3)
{}
env))
(defn let-block [{:keys [env]} child]
(cond
(coll? child) (walk/prewalk-replace (resolve-queries env) child)))
(defn bindings->env [v]
;; TODO errors: pair number of arguments, keys are symbols, values are primitives or queries
;; TODO destructuring
(apply hash-map v))
(defmethod parse 'let [_ [_ bindings & body]]
{:data
;; TODO error if multiple body as let only considers last
(let [m (bindings->env bindings)
child (last body)]
[let-block {:env m} child])})
(defn when-block [{:keys [test]} body]
;; TODO warning if test is not of boolean type
(when test
body))
(defmethod parse 'when [_ [_ test & body]]
(cond
(symbol? test)
{:data (apply conj [when-block {:test test}] body)}
:else
{:errors [{:type :unsupported-type :value test}]}))
(defn if-block [{:keys [test]} & body]
;; TODO warning if test is not of boolean type
(if test
(first body)
(second body)))
(defmethod parse 'if [_ [_ test then else]]
(cond
(symbol? test)
{:data (apply conj [if-block {:test test}] (list then else))}
:else
{:errors [{:type :unsupported-type :value test}]}))
(defmethod parse :default [opts block] {:errors [{:type :unknown-block-type :opts opts :block block}]})

View File

@ -1,73 +0,0 @@
(ns pluto.reader.blocks
(:require [re-frame.core :as re-frame]))
(defmulti parse (fn [_ [type]] type))
(defn bindings->env [v]
(apply hash-map v))
(defn primitive? [o]
(or (boolean? o)
(int? o)
(float? o)
(string? o)))
(defmulti encode-value (fn [[f & _]] f))
(defmethod encode-value 'query [[_ & args]] (apply conj args))
(defn env-value [o]
;; TODO encode query as record. Validate query exists and potentially that data type matches
;; Ensure rest is pure data or arguments
(println "ENV" o (type o))
(cond
(list? o) (encode-value o)
(primitive? o) o
#_(and (instance? Reference o)
(= :query (:type o)))
;o
;; TODO accumulate errors
:else {:errors [{:type :incorrect-let-value :value o}]}))
(defn env [m]
(reduce-kv #(assoc %1 %2 (env-value %3))
{}
m))
(defn resolve-queries [env]
;; TODO only resolve encoded queries
(reduce-kv #(assoc %1 %2 @(re-frame/subscribe %3))
{}
env))
(defn let-block [{:keys [env]} [k p children]]
;; Propagate env as meta on children element
;; TODO support multiple children
;; TODO figure out envs as part of properties, with cascading scopes (delegate to :outer)
;; Disallow symbol shadowing
[k (assoc p :env (resolve-queries env)) (with-meta children {:env (resolve-queries env)})])
(defmethod parse 'let [_ [_ bindings & body]]
{:data
;; TODO validate pairs of data
;; keys -> symbols
;; values -> primitive types, query
;; TODO warning if multiple body as let only considers last
(let [m (bindings->env bindings)]
[let-block {:env (env m)} (last body)])})
(defn test? [{:keys [env test]}]
(cond
(boolean? test) test
(symbol? test) (test env)))
(defn when-block [props body]
(when (test? props)
body))
(defmethod parse 'when [[props test & body]]
;; TODO test can only be a symbol. This symbol must point to primitive type or query.
;; TODO If value known at read time, resolve statically
(apply conj [when-block {:test test :env (:env (meta body))}] body))
(defmethod parse :default [opts block] {:errors [{:type :unknown-block-type :opts opts :block block}]})

View File

@ -1,12 +1,18 @@
(ns pluto.storage.http (ns pluto.storage.http
(:require [pluto.storage :as storage])) (:require [pluto.storage :as storage]))
(defn result [xhr]
(let [status (.-status xhr)]
(if (= 404 status)
{:type :error :value status}
{:type :success :value (.-responseText xhr)})))
(deftype HTTPStorage [] (deftype HTTPStorage []
storage/Storage storage/Storage
(fetch [_ id callback] (fetch [_ {:keys [value]} callback]
(let [xhr (js/XMLHttpRequest.)] (let [xhr (js/XMLHttpRequest.)]
(.open xhr "GET" (:URL id) true) (.open xhr "GET" (str value "/extension.edn") true)
(.send xhr nil) (.send xhr nil)
(set! (.-onreadystatechange xhr) (set! (.-onreadystatechange xhr)
#(when (= (.-readyState xhr) 4) #(when (= (.-readyState xhr) 4)
(callback (.-response xhr))))))) (callback (result xhr)))))))

View File

@ -1,16 +1,18 @@
(ns pluto.storage.ipfs (ns pluto.storage.ipfs
(:require [pluto.storage :as storage])) (:require [clojure.string :as string]
[pluto.storage :as storage]))
(defn- ipfs->extension [ipfs-extension] (defn- ipfs->extension [ipfs-extension]
{:extension-id (:Hash ipfs-extension) {:extension-id (:Hash ipfs-extension)
:name (:Name ipfs-extension)}) :name (:Name ipfs-extension)})
(defn parse-directory [response] (defn parse-directory [response]
(when-not (string/blank? response)
(->> (js->clj (js/JSON.parse response) :keywordize-keys true) (->> (js->clj (js/JSON.parse response) :keywordize-keys true)
:Objects :Objects
first first
:Links :Links
(map ipfs->extension))) (map ipfs->extension))))
(defn fetch-promise [url] (defn fetch-promise [url]
(new js/Promise (fn [resolve reject] (new js/Promise (fn [resolve reject]
@ -19,7 +21,8 @@
(.send xhr nil) (.send xhr nil)
(set! (.-onreadystatechange xhr) (set! (.-onreadystatechange xhr)
#(when (= (.-readyState xhr) 4) #(when (= (.-readyState xhr) 4)
(resolve (.-response xhr)))))))) ;; TODO handle error codes
(resolve (.-responseText xhr))))))))
(defn list-all [gateway-url directory] (defn list-all [gateway-url directory]
(fetch-promise (str gateway-url "/api/v0/ls?arg=" directory))) (fetch-promise (str gateway-url "/api/v0/ls?arg=" directory)))
@ -41,7 +44,7 @@
storage/Storage storage/Storage
(fetch [this extension callback] (fetch [this extension callback]
(.. (..
(list-all gateway-url (:id extension)) (list-all gateway-url (:value extension))
(then parse-directory) (then parse-directory)
(then (partial fetch-all gateway-url)) (then (partial fetch-all gateway-url))
(then callback)))) (then #(callback {:type :success :value %})))))

View File

@ -0,0 +1,7 @@
(ns pluto.reader.blocks-test
(:require [cljs.test :refer-macros [is deftest async use-fixtures]]
[pluto.reader.blocks :as blocks]))
(deftest parse
(is (= nil (blocks/parse {} '(let [s "Hello"] s))))
(is (= nil (blocks/parse {} '(let [s "Hello"] ['test {} s])))))

View File

@ -1,6 +1,7 @@
(ns pluto.reader-test (ns pluto.reader-test
(:require [cljs.test :refer-macros [is deftest async use-fixtures]] (:require [cljs.test :refer-macros [is deftest async use-fixtures]]
[pluto.reader :as reader :refer [Reference]])) [pluto.reader :as reader :refer [Reference]]
[pluto.reader.blocks :as blocks]))
(deftest read (deftest read
(is (= {:data nil} (reader/read ""))) (is (= {:data nil} (reader/read "")))
@ -37,10 +38,11 @@
(is (= {:invalid-hooks #{:hooks/unknown}} (is (= {:invalid-hooks #{:hooks/unknown}}
(reader/validate-keys {:valid-hooks #{:hooks/main}} #{:hooks/main :hooks/unknown})))) (reader/validate-keys {:valid-hooks #{:hooks/main}} #{:hooks/main :hooks/unknown}))))
#_
(deftest parse-hiccup-children (deftest parse-hiccup-children
(is (= {:data (list [:text {} ""])} (reader/parse-hiccup-children {:components {'text :text}} (list ['text {} ""]))))) (is (= {:data (list [:text {} ""])} (reader/parse-hiccup-children {:components {'text :text}} (list ['text {} ""])))))
#_
(deftest parse (deftest parse
(is (= {} (reader/parse {} {}))) (is (= {} (reader/parse {} {})))
(is (= {:data {:views/main ['text {} "Hello"]} (is (= {:data {:views/main ['text {} "Hello"]}
@ -51,13 +53,16 @@
(is (= {:data {:views/main [:text {} "Hello"]}} (is (= {:data {:views/main [:text {} "Hello"]}}
(reader/parse {:components {'text :text}} {:views/main ['text {} "Hello"]})))) (reader/parse {:components {'text :text}} {:views/main ['text {} "Hello"]}))))
#_
(deftest parse-references (deftest parse-references
(is (= {:data {:views/main [:pluto.reader-test/main]}} (reader/parse {} {:views/main (Reference. :view [::main])})))) (is (= {:data {:views/main [:pluto.reader-test/main]}} (reader/parse {} {:views/main (Reference. :view [::main])}))))
(deftest parse-let-blocks
(is (= {:data {:views/main [blocks/let-block {:env {'s "Hello"}} [:text {} 's]]}}
(reader/parse {:components {'text :text}} {:views/main (list 'let ['s "Hello"] ['text {} 's])})))
#_ #_
(deftest parse-blocks (is (= nil (reader/parse {:components {'text :text}} {:views/main (list 'let ['cond? (Reference. :query [::query])] ['text])})))
(is (= nil (reader/parse {} {:views/main (list 'let ['cond? true] ['text])}))) #_
(is (= nil (reader/parse {} {:views/main (list 'let ['cond? (Reference. :query [::query])] ['text])}))) (is (= nil (reader/parse {:components {'text :text}} {:views/main (list 'let ['cond? (Reference. :query [::query])]
(is (= nil (reader/parse {} {:views/main (list 'let ['cond? (Reference. :query [::query])]
(list 'when 'cond? (list 'when 'cond?
['text {} "World"]))})))) ['text {} "World"]))}))))

View File

@ -1,5 +1,7 @@
(ns pluto.runner (ns pluto.runner
(:require [doo.runner :refer-macros [doo-tests]] (:require [doo.runner :refer-macros [doo-tests]]
[pluto.reader-test])) [pluto.reader-test]
[pluto.reader.blocks-test]))
(doo-tests 'pluto.reader-test) (doo-tests 'pluto.reader-test
'pluto.reader.blocks-test)