Validate events/queries

This commit is contained in:
Julien Eluard 2018-10-09 14:55:53 +02:00
parent acd444435b
commit 430eaea950
No known key found for this signature in database
GPG Key ID: 6FD7DB5437FCBEF6
10 changed files with 63 additions and 57 deletions

View File

@ -56,13 +56,14 @@
(defn parse [m]
(reader/parse {:capacities {:components html/components
:queries #{:random-boolean}
:queries {'random-boolean
{:value :random-boolean}}
:hooks {:main
{:hook hook
:properties {:view :view}}}
:events {:alert
:events {'alert
{:permissions [:read]
:value []}}}}
:value :alert}}}}
m))
(defn render-extension [m el el-errors]

View File

@ -4,14 +4,14 @@
:documentation "Nothing. Just see a text with dynamic random color."}
hooks/main.demo
{:view [views/main]}
{:view [main]}
views/main
(let [{name :name} properties]
[view {}
[button {:on-click [:alert {:value name}]}
[button {:on-click [alert {:value name}]}
"Hello"]
(let [{cond? :cond?} [:random-boolean]]
(let [{cond? :cond?} [random-boolean]]
(if cond?
[text {:style {:color "green"}}
name]

View File

@ -8,19 +8,20 @@
(defmulti parse
"Parse a block element. Return hiccup data."
(fn [_ [type]] type))
(fn [ctx ext [type]] type))
(defn resolve-query [query]
(let [{:keys [data]} (types/resolve {} {} :query query)]
(data)))
(defn resolve-query [ctx ext query]
(let [{:keys [data errors]} (types/resolve ctx ext :query query)]
;; TODO errors ??
(when data (data))))
(defn- query? [binding-value]
(vector? binding-value))
(defn resolve-binding-value [v]
(defn resolve-binding-value [ctx ext v]
;; TODO resolve query statically
(cond
(query? v) (resolve-query v)
(query? v) (resolve-query ctx ext v)
(not (list? v)) v))
(defn resolve-binding-key [k v]
@ -29,16 +30,16 @@
;; TODO handle errors
(:data (destructuring/destructure k v))))
(defn assoc-binding [m k v]
(let [resolved-value (resolve-binding-value v)]
(let [o (resolve-binding-key k resolved-value)]
(if (symbol? o)
(assoc m o resolved-value)
(merge m o)))))
(defn assoc-binding [ctx ext m k v]
(let [resolved-value (resolve-binding-value ctx ext v)
o (resolve-binding-key k resolved-value)]
(if (symbol? o)
(assoc m o resolved-value)
(merge m o))))
(defn let-block [{:keys [env]} child]
(defn let-block [{:keys [env ctx ext]} child]
(cond
(coll? child) (walk/prewalk-replace (reduce-kv assoc-binding {} env) child)))
(coll? child) (walk/prewalk-replace (reduce-kv #(assoc-binding ctx ext %1 %2 %3) {} env) child)))
(defn properties? [o]
(= 'properties o))
@ -64,14 +65,14 @@
{:errors [(errors/error ::errors/invalid-destructuring-format bindings)]}
(reduce-kv merge-bindings {} (apply hash-map bindings))))
(defmethod parse 'let [{:keys [capacities]} [_ bindings & body]]
(defmethod parse 'let [ctx ext [_ bindings & body]]
(let [{:keys [data errors]} (bindings->env bindings)]
;; TODO fail if some symbol are not defined in the env
;; TODO resolve query references only once, error if unknown
(merge
{:data
(let [child (last body)]
[let-block {:env data} child])}
[let-block {:env data :ctx ctx :ext ext} child])}
(when errors
{:errors errors}))))
@ -80,7 +81,7 @@
(when test
body))
(defmethod parse 'when [_ [_ test & body]]
(defmethod parse 'when [_ _ [_ test & body]]
(cond
(symbol? test)
{:data (apply conj [when-block {:test test}] body)}
@ -92,7 +93,7 @@
(first body)
(second body)))
(defmethod parse 'if [_ [_ test then else]]
(defmethod parse 'if [_ _ [_ test then else]]
(cond
(symbol? test)
{:data (apply conj [if-block {:test test}] (list then else))}

View File

@ -20,11 +20,11 @@
::unknown-reference-type
::unknown-component
::unknown-component-property
::unknown-query
::unknown-event
::invalid-view
::invalid-block
::unsupported-test-type
::forbidden-read-path
::query-not-exposed})
::unsupported-test-type})
(spec/def ::value any?)

View File

@ -20,15 +20,12 @@
(defn root-id [s]
(keyword (first (string/split (name s) #"\."))))
(defn parse-hook [ctx ext hook v]
(types/resolve ctx ext (:properties hook) v))
(defn parse [ctx ext]
(reduce-kv (fn [acc hook-key data]
(let [hook-id (local-id hook-key)
hook-root (root-id hook-key)
hook (get-in ctx [:capacities :hooks hook-root])
{:keys [data errors] :as m} (parse-hook ctx ext hook data)]
(let [hook-id (local-id hook-key)
hook-root (root-id hook-key)
{:keys [properties] :as hook} (get-in ctx [:capacities :hooks hook-root])
{:keys [data errors] :as m} (types/resolve ctx ext properties data)]
(errors/merge-errors
(-> acc
(assoc-in [:data :hooks hook-root hook-id :parsed] data)

View File

@ -20,13 +20,14 @@
(when (reference? o)
(first o)))
(def type->ns {:view "views" :query "queries" :event "events"})
(def type->ns {:view "views" :query "queries" :event "events"})
(def type->capacity {:view :components :query :queries :event :events})
(defn- resolve-symbol
"Resolve a symbol first via the extension definition then via the host ctx."
[ctx ext ns s]
[ctx ext type ns s]
(or (get ext (symbol ns (name s)))
(get-in ctx [:capacities :components s :value])))
(get-in ctx [:capacities (get type->capacity type) s :value])))
(defn resolve
"Resolve a reference defined by a hook
@ -37,7 +38,7 @@
[ctx ext type value]
(if-let [s (reference->symbol value)]
(if-let [ns (get type->ns type)]
(if-let [o (resolve-symbol ctx ext ns s)]
(if-let [o (resolve-symbol ctx ext type ns s)]
{:data o}
{:errors [(errors/error ::errors/unknown-reference {:value s})]})
{:errors [(errors/error ::errors/unknown-reference-type {:value type})]})

View File

@ -2,10 +2,11 @@
"Resolve values based on provided types.
Handles primitives, references and composed values."
(:refer-clojure :exclude [resolve])
(:require [clojure.string :as string]
[clojure.set :as set]
[re-frame.core :as re-frame]
[pluto.reader.errors :as errors]))
(:require [clojure.string :as string]
[clojure.set :as set]
[re-frame.core :as re-frame]
[pluto.reader.errors :as errors]
[pluto.reader.reference :as reference]))
(defmulti resolve
"Resolve a value based on a type.
@ -72,12 +73,16 @@
{} type)
{:errors [(errors/error ::errors/invalid-assoc-type {:type type :value value})]}))
(defmethod resolve :event [_ _ _ value]
{:data #(re-frame/dispatch value)})
(defmethod resolve :event [ctx ext type [event-name event-properties :as value]]
(if-let [data (:data (reference/resolve ctx ext type value))]
{:data #(re-frame/dispatch [data event-properties])}
{:errors [(errors/error ::errors/unknown-event {:type type :value event-name})]}))
(defmethod resolve :query [ctx _ _ value]
{:data #(when-let [o (re-frame/subscribe value)]
@o)})
(defmethod resolve :query [ctx ext type [query-name query-properties :as value]]
(if-let [data (:data (reference/resolve ctx ext type value))]
{:data #(when-let [o (re-frame/subscribe [data query-properties])]
@o)}
{:errors [(errors/error ::errors/unknown-query {:type type :value query-name})]}))
(defmethod resolve :default [_ _ type value]
{:errors [(errors/error ::errors/invalid-type (merge {:type type} (when value {:value value})))]})

View File

@ -62,7 +62,8 @@
(defn- resolve-component-properties [ctx ext component properties]
(reduce-kv (fn [acc k v]
(let [{:keys [data errors]} (resolve-property ctx ext component k v)]
(-> (update acc :data assoc k data))))
(errors/merge-errors (update acc :data assoc k data)
errors)))
{:data {}
:errors []}
properties))
@ -100,7 +101,7 @@
(defn parse [ctx ext o]
(cond
(list? o)
(let [{:keys [data errors]} (blocks/parse ctx o)]
(let [{:keys [data errors]} (blocks/parse ctx ext o)]
(if errors
{:errors errors}
(parse ctx ext data)))

View File

@ -16,23 +16,23 @@
(deftest let-block
(testing "parse"
(is (= {:data [blocks/let-block {:env {'s "Hello"}} 's]}
(blocks/parse {} '(let [s "Hello"] s))))
(blocks/parse {} {} '(let [s "Hello"] s))))
(is (= {:data [blocks/let-block {:env '{{a :a} [:aa]}} 'a]}
(blocks/parse {:capacities {:queries #{:aa}}} '(let [{a :a} [:aa]] a))))
(blocks/parse {:capacities {:queries #{:aa}}} {} '(let [{a :a} [:aa]] a))))
(is (= {:data [blocks/let-block {:env '{a {:b 1} b 1}} 'b]}
(blocks/parse {} '(let [{a :a} {:a {:b 1}} {b :b} a] b))))
(blocks/parse {} {} '(let [{a :a} {:a {:b 1}} {b :b} a] b))))
(is (= {:data [blocks/let-block {:env '{x 1 {a :a} [:aa {:x x}]}} 'a]}
(blocks/parse {:capacities {:queries #{:aa}}} '(let [x 1 {a :a} [:aa {:x x}]] a))))
(blocks/parse {:capacities {:queries #{:aa}}} {} '(let [x 1 {a :a} [:aa {:x x}]] a))))
(is (= {:data [blocks/let-block {:env {'s "Hello"}} ['test {} 's]]}
(blocks/parse {} (list 'let ['s "Hello"] ['test {} 's]))))
(blocks/parse {} {} (list 'let ['s "Hello"] ['test {} 's]))))
(is (= {:data [blocks/let-block {:env nil}
['test {} 's]]
:errors [{::errors/type ::errors/invalid-destructuring-format ::errors/value ['s "Hello" 1]}]}
(blocks/parse {} (list 'let ['s "Hello" 1] ['test {} 's]))))
(blocks/parse {} {} (list 'let ['s "Hello" 1] ['test {} 's]))))
(is (= {:data [blocks/let-block {:env {'a 1}} ['test {} 'a]]}
(blocks/parse {} (list 'let ['{a :a} {:a 1}] ['test {} 'a]))))))
(blocks/parse {} {} (list 'let ['{a :a} {:a 1}] ['test {} 'a]))))))
(deftest let-block-resolution
(is (= ['test {} 1] (blocks/let-block {:env {'a 1}} ['test {} 'a])))

View File

@ -17,7 +17,7 @@
const ipfs = new window.Ipfs();
async function load() {
const buffer = await loadIPFS(ipfs, "QmVkhWzxTM9kmZANcUnzrfrzN5qg3Qh7GqZDQtX1E1JPE4");
const buffer = await loadIPFS(ipfs, "QmY3i6hjSa4vJeLMvntVgvmTxrjLWwV3fZKC51CMA9cKVX");
return buffer.toString();
}