diff --git a/Makefile b/Makefile
index 10afe60..974101e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,11 @@
-.PHONY = tests
+.PHONY: dev
compile:
clojure -m cljs.main -O advanced -d target -o target/pluto.js -c pluto.js
+dev:
+ clojure -A:dev
+
install:
lein install
diff --git a/deps.edn b/deps.edn
index d916569..4837866 100644
--- a/deps.edn
+++ b/deps.edn
@@ -3,15 +3,12 @@
reagent {:mvn/version "0.8.1"}
re-frame {:mvn/version "0.10.6"}}
:paths ["src"]
- :aliases {:examples {:extra-paths ["pluto-web/src" "target" "test" "examples/src" "examples/resources"]
- :extra-deps {com.bhauman/figwheel-main {:mvn/version "0.2.0"}
- com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}
- binaryage/devtools {:mvn/version "0.9.10"}
- cljsjs/codemirror {:mvn/version "5.40.2-1"}
- cljsjs/parinfer {:mvn/version "3.11.0-0"}
- cljsjs/parinfer-codemirror {:mvn/version "1.4.1-2"}
- cljsjs/material-ui {:mvn/version "3.9.1-0"}}
- :main-opts ["-m" "figwheel.main" "-b" "examples/dev" "-r"]}
+ :aliases {:dev {:extra-paths ["dev/src" "dev/resources" "target"]
+ :extra-deps {status-im/pluto-web {:mvn/version "0.1.0"}
+ com.bhauman/figwheel-main {:mvn/version "0.2.0"}
+ com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}
+ binaryage/devtools {:mvn/version "0.9.10"}}
+ :main-opts ["-m" "figwheel.main" "-b" "dev/core" "-r"]}
:compile {:extra-paths ["test"]
:main-opts ["-e" "(require,'[eftest.runner,:refer,[find-tests,run-tests]]),(run-tests,(find-tests,\"test\"))"]}
:test-clj {:extra-paths ["test"]
diff --git a/dev/core.cljs.edn b/dev/core.cljs.edn
new file mode 100644
index 0000000..2e5d6a7
--- /dev/null
+++ b/dev/core.cljs.edn
@@ -0,0 +1,4 @@
+^{:watch-dirs ["src" "dev/src"]
+ :log-level :info}
+{:main pluto.dev}
+
diff --git a/dev/resources/public/assets/extensions/demo/extension.edn b/dev/resources/public/assets/extensions/demo/extension.edn
new file mode 100644
index 0000000..3b20e10
--- /dev/null
+++ b/dev/resources/public/assets/extensions/demo/extension.edn
@@ -0,0 +1,64 @@
+{meta
+ {:name "Simple Demo"
+ :description "A simple demo of extension"
+ :documentation "Nothing. Just see a text with dynamic random color."}
+
+ lifecycle
+ {:on-activation [alert {:value "Activation !!"}]}
+
+ hooks/main.demo
+ {:view [main]}
+
+ events/my-alert
+ (let [{you :arg [value :as all] :value} properties]
+ [alert {:value "Eh! ${you} ${value}"}])
+
+ events/cb
+ (let [{value :arg v :value} properties
+ {cond2? :cond?} [random-boolean]]
+ (if cond?
+ [alert {:value "Eh bis! ${cond2?}"}]
+ [alert {:value "Eh ter! ${cond2?}"}])
+ [identity {:cb [my-alert {:arg value :value ["%% ${v}"]}]}])
+
+ views/local-view
+ {:component-did-mount [alert {:value "Mount!!"}]
+ :view
+ (let [{name :name color :color level :level} properties]
+ (case level
+ :polite [text {:style {:color color}} "Hello!! ${name}"]
+ :neutral [text {:style {:color color}} "Hey!! ${name}"]
+ [text "?? ${name}"]))}
+
+ views/local-view2
+ (let [{name :name color :color level :level} properties]
+ (case level
+ :polite [text {:style {:color color}} "Hey!! ${name}"]
+ "Hello ${name}"))
+
+ views/main
+ (let [{name :name users :users} properties
+ {cond? :cond?} [random-boolean]]
+ [view
+ [text "1"]
+ [text "2"]
+ ;[local-view {:name "Hey!! ${name}" :color :red :level :polite}]
+ [button {:on-click [cb {:arg name :value "AA"}]}
+ "Click!"]
+ ;[button {:on-click [alert {}]}
+ ; "Click2 !"]
+
+ [button {:on-click [my-alert {:arg cond? :value ["%% ${name}"]}]}
+ "Click2 !"]
+ [button {:on-click [alert {:value "AA"}]}
+ "Click3 !"]
+ (if cond?
+ [text {:style {:color "green"}}
+ name]
+ [text {:style {:color "red"}}
+ name])
+ [view "Nested for block"]
+ (for [{nm :nm} users]
+ [view
+ (for [{nm2 :nm} users]
+ [text nm " and " nm2])])])}
diff --git a/dev/resources/public/index.html b/dev/resources/public/index.html
new file mode 100644
index 0000000..0a3ca4d
--- /dev/null
+++ b/dev/resources/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/src/pluto/dev.cljs b/dev/src/pluto/dev.cljs
new file mode 100644
index 0000000..8da896d
--- /dev/null
+++ b/dev/src/pluto/dev.cljs
@@ -0,0 +1,105 @@
+(ns ^:figwheel-hooks pluto.dev
+ (:require pluto.reader.events
+ pluto.reader.views
+ pluto.web.events
+ pluto.web.queries
+ [pluto.core :as pluto]
+ [pluto.log :as log]
+ [pluto.storages :as storages]
+ [pluto.web.components :as components]
+ [devtools.core :as devtools]
+ [reagent.core :as reagent]
+ [re-frame.core :as re-frame]
+ [re-frame.registrar :as registrar]
+ [re-frame.loggers :as re-frame.loggers]))
+
+(enable-console-print!)
+(devtools/install!)
+
+(defn ^:before-load before-reload []
+ (re-frame/clear-subscription-cache!)
+ (println "Reloading ..."))
+
+(defn ^:after-load after-reload []
+ (println "Reloading done."))
+
+(def warn (js/console.warn.bind js/console))
+(re-frame.loggers/set-loggers!
+ {:warn (fn [& args]
+ (cond
+ (= "re-frame: overwriting" (first args)) nil
+ :else (apply warn args)))})
+
+(defn- dispatch-events [ctx events]
+ (doseq [event events]
+ (if (vector? event)
+ (re-frame/dispatch event)
+ (log/fire! ctx ::log/error :event/dispatch event))))
+
+(defn- resolve-query [ctx [id :as data]]
+ (if (registrar/get-handler :sub id)
+ (re-frame/subscribe data)
+ (log/fire! ctx ::log/error :query/resolve data)))
+
+(def ctx
+ {:env {:id "Extension ID"}
+ :capacities {:components components/all
+ :queries {'random-boolean
+ {:data :random-boolean}
+ 'identity
+ {:data :extensions/identity
+ :arguments {:value :map}}}
+ :hooks {:main
+ {:properties {:view :view}}}
+ :events {'identity
+ {:permissions [:read]
+ :data :identity
+ :arguments {:cb :event}}
+ 'alert
+ {:permissions [:read]
+ :data :alert
+ :arguments {:value :string}}}}
+ :event-fn dispatch-events
+ :query-fn resolve-query})
+
+(def payload
+ {:name "Test Extension"
+ :users [{:nm "Jane"}
+ {:nm "Sue"}]})
+
+(defn render [h el]
+ (reagent/render (h {:name "Test Extension"
+ :users [{:nm "Jane"}
+ {:nm "Sue"}]}) el))
+
+(defn errors-list [v]
+ (fn []
+ [:div
+ [:div "Errors"]
+ (into [:ul]
+ (for [[_ {type :type :as m}] v]
+ [:li
+ [:span [:b (str type)] (pr-str (dissoc m :type))]]))]))
+
+(defn render-extension [m el el-errors]
+ (let [{:keys [data errors]} (pluto/parse ctx m)]
+ (when errors
+ (render (errors-list errors) el-errors))
+ (when-let [f (get-in data [:lifecycle :on-activation])]
+ (f))
+ (if-let [view (get-in data [:hooks :main.demo :view])]
+ (render view el)
+ (render (fn [] [:div "Oups"]) el))))
+
+(defn read-extension [o el el-errors]
+ (let [{:keys [data errors]} (pluto/read (:content o))]
+ (render-extension data el el-errors)))
+
+(defn render-result [{:keys [type value]} el el-errors]
+ (case type
+ :error (set! (.-innerHTML el-errors) value)
+ (read-extension value el el-errors)))
+
+(defn ^:export bootstrap
+ [s el el-errors]
+ (storages/fetch s #(render-result % el el-errors)))
diff --git a/scripts/merge-pr.sh b/scripts/merge-pr.sh
deleted file mode 100644
index f833407..0000000
--- a/scripts/merge-pr.sh
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/bin/bash
-
-set -eof pipefail
-
-trap cleanup EXIT
-
-fatal() {
- echo "FATAL: $@" >&2
- exit 1
-}
-
-warn() {
- echo "$@"
-}
-
-confirm() {
- read -p "$1 (type 'yes' to continue) " r
- if [[ $r != yes ]]; then
- exit 3
- fi
-}
-
-load_config() {
- [[ -f merge-pr.conf ]] && . merge-pr.conf
- : ${OWNER:=status-im}
- : ${REPO:=pluto}
- : ${REMOTE:=origin}
- : ${BRANCH:=master}
-}
-
-check_pr_prereq() {
- if ! command -v jq >/dev/null; then
- fatal "jq(1) is not found, PR cannot be queried."
- fi
- if ! command -v curl >/dev/null; then
- fatal "curl(1) is not found, PR cannot be queried."
- fi
-}
-
-GH_URL_BASE="https://api.github.com"
-
-get_pr_info() {
- echo '[ Reading PR info ]'
- local pr=$1
- local pr_info_url="$GH_URL_BASE/repos/${OWNER}/${REPO}/pulls/$pr"
- set +e
- local pr_info
- pr_info=$(curl -fsS "$pr_info_url")
- if [ $? -ne 0 ]; then
- fatal "Unable to get PR info from $pr_info_url"
- fi
- set -e
- if [[ $(echo "$pr_info" | jq -r .state) == closed ]]; then
- fatal "PR $pr is closed, will not merge"
- fi
- if [[ ($(echo "$pr_info" | jq -r .maintainer_can_modify) == true) ||\
- ($(echo "$pr_info" | jq -r .author_association) == MEMBER) ||\
- ($(echo "$pr_info" | jq -r .author_association) == OWNER)]]; then
- RW_PR_REPO=1
- else
- warn "PR does not allow 'edits from maintainers', so it will be kept open"
- fi
- PR_URL=$(echo "$pr_info" | jq -r .head.repo.ssh_url)
- PR_REMOTE_NAME=pr-$pr
- PR_BRANCH=$(echo "$pr_info" | jq -r .head.ref)
- PR_LOCAL_BRANCH=pr-$pr
-}
-
-fetch_pr() {
- echo '[ Fetching PR ]'
- git remote add $PR_REMOTE_NAME $PR_URL
- git fetch $PR_REMOTE_NAME $PR_BRANCH
-}
-
-refresh_base_branch() {
- git fetch $REMOTE $BRANCH
-}
-
-rebase_pr() {
- git checkout -B $PR_LOCAL_BRANCH $PR_REMOTE_NAME/$PR_BRANCH
- git rebase $BRANCH
-}
-
-check_is_pr_single_commit() {
- if [[ $(git rev-list $BRANCH..$PR_LOCAL_BRANCH | wc -l) -ne 1 ]] ;then
- confirm "PR has multiple commits, continue merging without squashing them?"
- fi
-}
-
-confirm_pr() {
- git log -p $BRANCH..$PR_LOCAL_BRANCH
- confirm "Do you like this PR?"
-}
-
-sign_pr() {
- git commit --amend --gpg-sign --signoff
-}
-
-verify_pr() {
- git show --show-signature $PR_LOCAL_BRANCH
- confirm "Is the signature on the commit correct?"
-}
-
-merge_pr() {
- # If PR is specified and can be pushed into, do it to mark PR as closed
- if [[ -n $RW_PR_REPO ]]; then
- git push -f $PR_REMOTE_NAME $PR_LOCAL_BRANCH:$PR_BRANCH
- fi
- git checkout $BRANCH
- git merge --ff-only $PR_LOCAL_BRANCH
- git push $REMOTE $BRANCH
-}
-
-cleanup() {
- if [[ -z $DEBUG ]]; then
- git checkout -q $BRANCH
- git branch -q -D $PR_LOCAL_BRANCH 2>/dev/null || :
- git remote remove $PR_REMOTE_NAME 2>/dev/null || :
- fi
-}
-
-run() {
- if [[ $# -ne 1 ]] ; then
- cat <&2
-Requirements:
- jq
- curl
-Usage:
- ./merge-pr.sh
-
-EOF
- exit 2
- fi
- load_config
- check_pr_prereq
- get_pr_info "$@"
- cleanup
- fetch_pr
- refresh_base_branch
- rebase_pr
- check_is_pr_single_commit
- confirm_pr
- sign_pr
- verify_pr
- merge_pr
-}
-
-run "$@"
diff --git a/scripts/publish.sh b/scripts/publish.sh
deleted file mode 100644
index 703585f..0000000
--- a/scripts/publish.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-clojure -m cljs.main -O advanced -d website/static/js -o website/static/js/pluto.js -c pluto.js
-cd website
-GIT_USER=jeluard\
-CURRENT_BRANCH=#2 \
- USE_SSH=true \
- yarn run publish-gh-pages
-cd ..
diff --git a/src/pluto/js.cljs b/src/pluto/js.cljs
deleted file mode 100644
index 2874272..0000000
--- a/src/pluto/js.cljs
+++ /dev/null
@@ -1,344 +0,0 @@
-(ns pluto.js
- "Exports reader function to JavaScript hosts.
- Type conversion is properly handled."
- (:require [pluto.core :as pluto]))
-
-(defn ^:export to-clj [o]
- (js->clj o))
-
-(defn ^:export from-clj [o]
- (clj->js o))
-
-(defn component [])
-
-;; TODO find a syntax so that :event can define associated types they will be injected
-
-(def ctx
- {:capacities {:components {'view {:data component}
- 'scroll-view {:data component :properties {:keyboard-should-persist-taps :keyword :content-container-style :map}}
- 'keyboard-avoiding-view {:data component}
- 'text {:data component}
- 'touchable-opacity {:data component :properties {:on-press :event}}
- 'icon {:data component :properties {:key :keyword :color :any}}
- 'image {:data component :properties {:uri :string :source :string}}
- 'input {:data component :properties {:on-change :event :placeholder :string :keyboard-type :keyword :change-delay? :number :placeholder-text-color :any :selection-color :any}}
- 'button {:data component :properties {:enabled :boolean :disabled :boolean :on-click :event}}
- 'link {:data component :properties {:uri :string}}
- 'list {:data component :properties {:data :vector :item-view :view :key? :keyword}}
- 'checkbox {:data component :properties {:on-change :event :checked :boolean}}
- 'activity-indicator {:data component :properties {:animating :boolean :color :string :size :keyword :hides-when-stopped :boolean}}
- 'picker {:data component :properties {:on-change :event :selected :string :enabled :boolean :data :vector}}
- 'nft-token-viewer {:data component :properties {:token :string}}
- 'transaction-status {:data component :properties {:outgoing :string :tx-hash :string}}
- 'map {:data component
- :properties {:marker {:lng :number
- :lat :number
- :boundingbox {:lng1 :number
- :lat1 :number
- :lng2 :number
- :lat2 :number}}
- :fly? :boolean
- :interactive? :boolean
- :on-change :event}}
- 'map-link {:data component :properties {:text :string :lng :any :lat :any}}}
- :queries {'identity {:data :extensions/identity :arguments {:value :map}}
- 'store/get {:data :store/get :arguments {:key :string}}
- 'contacts/all {:data :extensions.contacts/all}
- 'wallet/collectibles {:data :get-collectible-token :arguments {:token :string :symbol :string}}
- 'wallet/balance {:data :extensions.wallet/balance :arguments {:token :string}}
- 'wallet/token {:data :extensions.wallet/token :arguments {:token :string :amount? :number :amount-in-wei? :number}}
- 'wallet/tokens {:data :extensions.wallet/tokens :arguments {:filter? :vector :visible? :boolean}}}
- :events {'identity
- {:permissions [:read]
- :data :extensions/identity-event
- :arguments {:cb :event}}
- 'alert
- {:permissions [:read]
- :data :alert
- :arguments {:value :string}}
- 'selection-screen
- {:permissions [:read]
- :data :extensions/show-selection-screen
- :arguments {:items :vector :on-select :event :render :view :title :string :extractor-key :keyword}}
- 'chat.command/set-parameter
- {:permissions [:read]
- :data :extensions.chat.command/set-parameter
- :arguments {:value :any}}
- 'chat.command/set-custom-parameter
- {:permissions [:read]
- :data :extensions.chat.command/set-custom-parameter
- :arguments {:key :keyword :value :any}}
- 'chat.command/set-parameter-with-custom-params
- {:permissions [:read]
- :data :extensions.chat.command/set-parameter-with-custom-params
- :arguments {:value :string :params :map}}
- 'chat.command/send-plain-text-message
- {:permissions [:read]
- :data :extensions.chat.command/send-plain-text-message
- :arguments {:value :string}}
- 'chat.command/send-message
- {:permissions [:read]
- :data :extensions.chat.command/send-message
- :arguments {:params :map}}
- 'log
- {:permissions [:read]
- :data :log
- :arguments {:value :string}}
- 'arithmetic
- {:permissions [:read]
- :data :extensions/arithmetic
- :arguments {:values :vector
- :operation {:one-of #{:plus :minus :times :divide}}
- :on-result :event}}
- 'schedule/start
- {:permissions [:read]
- :data :extensions/schedule-start
- :arguments {:interval :number
- :on-created :event
- :on-result :event}}
- 'schedule/cancel
- {:permissions [:read]
- :data :extensions/schedule-cancel
- :arguments {:value :number}}
- 'json/parse
- {:permissions [:read]
- :data :extensions/json-parse
- :arguments {:value :string
- :on-result :event}}
- 'json/stringify
- {:permissions [:read]
- :data :extensions/json-stringify
- :arguments {:value :string
- :on-result :event}}
- 'store/put
- {:permissions [:read]
- :data :store/put
- :arguments {:key :string :value :any}}
- 'store/puts
- {:permissions [:read]
- :data :store/puts
- :arguments {:value :vector}}
- 'store/append
- {:permissions [:read]
- :data :store/append
- :arguments {:key :string :value :any}}
- 'store/clear
- {:permissions [:read]
- :data :store/clear
- :arguments {:key :string}}
- 'store/clear-all
- {:permissions [:read]
- :data :store/clear-all}
- 'http/get
- {:permissions [:read]
- :data :http/get
- :arguments {:url :string
- :timeout? :string
- :on-success :event
- :on-failure? :event}}
- 'http/post
- {:permissions [:read]
- :data :http/post
- :arguments {:url :string
- :body :string
- :timeout? :string
- :on-success :event
- :on-failure? :event}}
- 'ipfs/cat
- {:permissions [:read]
- :data :ipfs/cat
- :arguments {:hash :string
- :on-success :event
- :on-failure? :event}}
- 'ipfs/add
- {:permissions [:read]
- :data :ipfs/add
- :arguments {:value :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum/transaction-receipt
- {:permissions [:read]
- :data :extensions/ethereum-transaction-receipt
- :arguments {:value :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum/await-transaction-receipt
- {:permissions [:read]
- :data :extensions/ethereum-await-transaction-receipt
- :arguments {:value :string
- :interval :number
- :on-success :event
- :on-failure? :event}}
- 'ethereum/sign
- {:permissions [:read]
- :data :extensions/ethereum-sign
- :arguments {:message? :string
- :data? :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum/create-address
- {:permissions [:read]
- :data :extensions/ethereum-create-address
- :arguments {:on-result :event}}
- 'ethereum/send-transaction
- {:permissions [:read]
- :data :extensions/ethereum-send-transaction
- :arguments {:to :string
- :gas? :string
- :gas-price? :string
- :value? :string
- :method? :string
- :params? :vector
- :nonce? :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum/logs
- {:permissions [:read]
- :data :extensions/ethereum-logs
- :arguments {:from? :string
- :to? :string
- :address? :vector
- :topics? :vector
- :block-hash? :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum/create-filter
- {:permissions [:read]
- :data :extensions/ethereum-create-filter
- :arguments {:type {:one-of #{:filter :block :pending-transaction}}
- :from? :string
- :to? :string
- :address? :vector
- :topics? :vector
- :block-hash? :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum/logs-changes
- {:permissions [:read]
- :data :extensions/ethereum-logs-changes
- :arguments {:id :string}}
- 'ethereum/cancel-filter
- {:permissions [:read]
- :data :extensions/ethereum-cancel-filter
- :arguments {:id :string}}
- 'ethereum.ens/resolve
- {:permissions [:read]
- :data :extensions/ethereum-resolve-ens
- :arguments {:name :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc20/total-supply
- {:permissions [:read]
- :data :extensions/ethereum-erc20-total-supply
- :arguments {:contract :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc20/balance-of
- {:permissions [:read]
- :data :extensions/ethereum-erc20-balance-of
- :arguments {:contract :string
- :token-owner :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc20/transfer
- {:permissions [:read]
- :data :extensions/ethereum-erc20-transfer
- :arguments {:contract :string
- :to :string
- :value :number
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc20/transfer-from
- {:permissions [:read]
- :data :extensions/ethereum-erc20-transfer-from
- :arguments {:contract :string
- :from :string
- :to :string
- :value :number
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc20/approve
- {:permissions [:read]
- :data :extensions/ethereum-erc20-approve
- :arguments {:contract :string
- :spender :string
- :value :number
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc20/allowance
- {:permissions [:read]
- :data :extensions/ethereum-erc20-allowance
- :arguments {:contract :string
- :token-owner :string
- :spender :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc721/owner-of
- {:permissions [:read]
- :data :extensions/ethereum-erc721-owner-of
- :arguments {:contract :string
- :token-id :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc721/is-approved-for-all
- {:permissions [:read]
- :data :extensions/ethereum-erc721-is-approved-for-all
- :arguments {:contract :string
- :owner :string
- :operator :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc721/get-approved
- {:permissions [:read]
- :data :extensions/ethereum-erc721-get-approved
- :arguments {:contract :string
- :token-id :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc721/set-approval-for-all
- {:permissions [:read]
- :data :extensions/ethereum-erc721-set-approval-for-all
- :arguments {:contract :string
- :operator :string
- :approved :boolean
- :on-success :event
- :on-failure? :event}}
- 'ethereum.erc721/safe-transfer-from
- {:permissions [:read]
- :data :extensions/ethereum-erc721-safe-transfer-from
- :arguments {:contract :string
- :from :string
- :to :string
- :token-id :string
- :data? :string
- :on-success :event
- :on-failure? :event}}
- 'ethereum/call
- {:permissions [:read]
- :data :extensions/ethereum-call
- :arguments {:to :string
- :method :string
- :params? :vector
- :outputs? :vector
- :on-success :event
- :on-failure? :event}}}
- :hooks {:wallet.settings {:properties {:label :string
- :view :view
- :on-click? :event}}
- :chat.command {:properties {:description? :string
- :scope #{:personal-chats :public-chats :group-chats}
- :short-preview :view
- :preview :view
- :parameters? [{:id :keyword
- :type {:one-of #{:text :phone :password :number}}
- :placeholder :string
- :suggestions? :view}]
- :on-send? :event
- :on-send-sync? :event
- :on-receive? :event}}}}})
-
-(defn ^:export read [s]
- (pluto/read s))
-
-(defn ^:export parse [m]
- (pluto/parse ctx (:data m)))