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] (defn parse [m]
(reader/parse {:capacities {:components html/components (reader/parse {:capacities {:components html/components
:queries #{:random-boolean} :queries {'random-boolean
{:value :random-boolean}}
:hooks {:main :hooks {:main
{:hook hook {:hook hook
:properties {:view :view}}} :properties {:view :view}}}
:events {:alert :events {'alert
{:permissions [:read] {:permissions [:read]
:value []}}}} :value :alert}}}}
m)) m))
(defn render-extension [m el el-errors] (defn render-extension [m el el-errors]

View File

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

View File

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

View File

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

View File

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

View File

@ -20,13 +20,14 @@
(when (reference? o) (when (reference? o)
(first 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 (defn- resolve-symbol
"Resolve a symbol first via the extension definition then via the host ctx." "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))) (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 (defn resolve
"Resolve a reference defined by a hook "Resolve a reference defined by a hook
@ -37,7 +38,7 @@
[ctx ext type value] [ctx ext type value]
(if-let [s (reference->symbol value)] (if-let [s (reference->symbol value)]
(if-let [ns (get type->ns type)] (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} {:data o}
{:errors [(errors/error ::errors/unknown-reference {:value s})]}) {:errors [(errors/error ::errors/unknown-reference {:value s})]})
{:errors [(errors/error ::errors/unknown-reference-type {:value type})]}) {:errors [(errors/error ::errors/unknown-reference-type {:value type})]})

View File

@ -2,10 +2,11 @@
"Resolve values based on provided types. "Resolve values based on provided types.
Handles primitives, references and composed values." Handles primitives, references and composed values."
(:refer-clojure :exclude [resolve]) (:refer-clojure :exclude [resolve])
(:require [clojure.string :as string] (:require [clojure.string :as string]
[clojure.set :as set] [clojure.set :as set]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[pluto.reader.errors :as errors])) [pluto.reader.errors :as errors]
[pluto.reader.reference :as reference]))
(defmulti resolve (defmulti resolve
"Resolve a value based on a type. "Resolve a value based on a type.
@ -72,12 +73,16 @@
{} type) {} type)
{:errors [(errors/error ::errors/invalid-assoc-type {:type type :value value})]})) {:errors [(errors/error ::errors/invalid-assoc-type {:type type :value value})]}))
(defmethod resolve :event [_ _ _ value] (defmethod resolve :event [ctx ext type [event-name event-properties :as value]]
{:data #(re-frame/dispatch 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] (defmethod resolve :query [ctx ext type [query-name query-properties :as value]]
{:data #(when-let [o (re-frame/subscribe value)] (if-let [data (:data (reference/resolve ctx ext type value))]
@o)}) {: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] (defmethod resolve :default [_ _ type value]
{:errors [(errors/error ::errors/invalid-type (merge {:type type} (when value {:value 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] (defn- resolve-component-properties [ctx ext component properties]
(reduce-kv (fn [acc k v] (reduce-kv (fn [acc k v]
(let [{:keys [data errors]} (resolve-property ctx ext component 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 {} {:data {}
:errors []} :errors []}
properties)) properties))
@ -100,7 +101,7 @@
(defn parse [ctx ext o] (defn parse [ctx ext o]
(cond (cond
(list? o) (list? o)
(let [{:keys [data errors]} (blocks/parse ctx o)] (let [{:keys [data errors]} (blocks/parse ctx ext o)]
(if errors (if errors
{:errors errors} {:errors errors}
(parse ctx ext data))) (parse ctx ext data)))

View File

@ -16,23 +16,23 @@
(deftest let-block (deftest let-block
(testing "parse" (testing "parse"
(is (= {:data [blocks/let-block {:env {'s "Hello"}} 's]} (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]} (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]} (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]} (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]]} (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} (is (= {:data [blocks/let-block {:env nil}
['test {} 's]] ['test {} 's]]
:errors [{::errors/type ::errors/invalid-destructuring-format ::errors/value ['s "Hello" 1]}]} :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]]} (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 (deftest let-block-resolution
(is (= ['test {} 1] (blocks/let-block {:env {'a 1}} ['test {} 'a]))) (is (= ['test {} 1] (blocks/let-block {:env {'a 1}} ['test {} 'a])))

View File

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