initial commit

This commit is contained in:
2026-06-25 21:30:32 +00:00
commit 328faf6251
220 changed files with 162103 additions and 0 deletions
+460
View File
@@ -0,0 +1,460 @@
(ns ajax.core
(:require goog.net.EventType
goog.net.ErrorCode
[goog.net.XhrIo :as xhr]
[goog.net.XhrManager :as xhrm]
[goog.Uri :as uri]
[goog.json :as goog-json]
[goog.Uri.QueryData :as query-data]
[goog.json.Serializer]
[goog.events :as events]
[goog.structs :as structs]
[cljs.reader :as reader]
[clojure.string :as str]
[cognitect.transit :as t])
(:require-macros [ajax.macros :as m]
[poppea :as p]))
(defprotocol AjaxImpl
"An abstraction for a javascript class that implements
Ajax calls."
(-js-ajax-request [this uri method body headers handler opts]
"Makes an actual ajax request. All parameters except opts
are in JS format. Should return an AjaxRequest."))
(defprotocol AjaxRequest
"An abstraction for a running ajax request."
(-abort [this]
"Aborts a running ajax request, if possible."))
(defprotocol DirectlySubmittable
"A marker interface for types that can be directly sent to XhrIo.")
(defprotocol AjaxResponse
"An abstraction for an ajax response."
(-status [this]
"Returns the HTTP Status of the response as an integer.")
(-status-text [this]
"Returns the HTTP Status Text of the response as a string.")
(-body [this]
"Returns the response body as a string or as type specified in response-format
such as a blob or arraybuffer.")
(-get-response-header [this header]
"Gets the specified response header (specified by a string) as a string.")
(-was-aborted [this]
"Was the response aborted."))
(m/register-directly-submittable js/FormData js/ArrayBufferView
js/Blob js/Document)
(defn submittable? [params]
(or (satisfies? DirectlySubmittable params)
(string? params)))
(extend-type goog.net.XhrIo
AjaxImpl
(-js-ajax-request
[this uri method body headers handler
{:keys [timeout with-credentials]
:or {with-credentials false
timeout 0}}]
(doto this
(events/listen goog.net.EventType/COMPLETE
#(handler (.-target %)))
(.setTimeoutInterval timeout)
(.setWithCredentials with-credentials)
(.send uri method body (clj->js headers))))
AjaxRequest
(-abort [this] (.abort this goog.net.ErrorCode/ABORT))
AjaxResponse
(-body [this] (.getResponseText this))
(-status [this] (.getStatus this))
(-status-text [this] (.getStatusText this))
(-get-response-header [this header]
(.getResponseHeader this header))
(-was-aborted [this]
(= (.getLastErrorCode this) goog.net.ErrorCode/ABORT)))
(defn ready-state
[e]
({0 :not-initialized
1 :connection-established
2 :request-received
3 :processing-request
4 :response-ready} (.-readyState (.-target e))))
(extend-type js/XMLHttpRequest
AjaxImpl
(-js-ajax-request
[this uri method body headers handler
{:keys [timeout with-credentials response-format]
:or {with-credentials false
timeout 0}}]
(set! (.-withCredentials this) with-credentials)
(set! (.-onreadystatechange this) #(when (= :response-ready (ready-state %)) (handler this)))
(.open this method uri true)
(set! (.-timeout this) timeout)
; IE8 needs timeout to be set between open and send
; https://msdn.microsoft.com/en-us/library/cc304105(v=vs.85).aspx
(when-let [response-type (:type response-format)]
(set! (.-responseType this) (name response-type)))
(doseq [[k v] headers]
(.setRequestHeader this k v))
(.send this (or body ""))
this)
AjaxRequest
(-abort [this] (.abort this))
AjaxResponse
(-body [this] (.-response this))
(-status [this] (.-status this))
(-status-text [this] (.-statusText this))
(-get-response-header [this header]
(.getResponseHeader this header))
(-was-aborted [this] (= 0 (.-readyState this))))
(extend-type goog.net.XhrManager
AjaxImpl
(-js-ajax-request
[this uri method body headers handler
{:keys [id timeout priority max-retries]}]
(.send this id uri method body (clj->js headers)
priority handler max-retries)))
(defn abort ([this] (-abort this)))
(defn success? [status]
(some #{status} [200 201 202 204 205 206]))
;;; Standard Formats
(defn read-edn [xhrio]
(reader/read-string (-body xhrio)))
(defn edn-response-format
([] {:read read-edn
:description "EDN"
:content-type "application/edn"})
([opts] (edn-response-format)))
(defn edn-request-format []
{:write pr-str
:content-type "application/edn"})
(p/defn-curried transit-write
[writer params]
(t/write writer params))
(defn transit-request-format
([] (transit-request-format {}))
([{:keys [type writer] :as opts}]
(let [writer (or writer (t/writer (or type :json) opts))]
{:write (transit-write writer)
:content-type "application/transit+json"})))
(p/defn-curried transit-read [reader raw xhrio]
(let [text (-body xhrio)
data (t/read reader text)]
(if raw data (js->clj data))))
(defn transit-response-format
([] (transit-response-format {}))
([{:keys [type reader raw] :as opts}]
(let [reader (or reader (t/reader (or type :json) opts))]
{:read (transit-read reader raw)
:description "Transit"
:content-type "application/transit+json"})))
(defn params-to-str [params]
(if params
(-> params
clj->js
structs/Map.
query-data/createFromMap
.toString)))
(defn url-request-format []
{:write params-to-str
:content-type "application/x-www-form-urlencoded"})
(defn raw-response-format
([] {:read -body :description "raw text" :content-type "*/*"})
([opts] (raw-response-format)))
(defn write-json [data]
(.serialize (goog.json.Serializer.) (clj->js data)))
(defn json-request-format []
{:write write-json
:content-type "application/json"})
(p/defn-curried json-read [prefix raw keywords? xhrio]
(let [text (-body xhrio)
text (if (and prefix (= 0 (.indexOf text prefix)))
(.substring text (.length prefix))
text)
json (goog-json/parse text)]
(if raw
json
(js->clj json :keywordize-keys keywords?))))
(defn json-response-format
"Returns a JSON response format. Options include
:keywords? Returns the keys as keywords
:prefix A prefix that needs to be stripped off. This is to
combat JSON hijacking. If you're using JSON with GET request,
you should think about using this.
http://stackoverflow.com/questions/2669690/why-does-google-prepend-while1-to-their-json-responses
http://haacked.com/archive/2009/06/24/json-hijacking.aspx"
([] (json-response-format {}))
([{:keys [prefix keywords? raw]}]
{:read (json-read prefix raw keywords?)
:description (str "JSON"
(if prefix (str " prefix '" prefix "'"))
(if keywords? " keywordize"))
:content-type "application/json"}))
;;; Detection and Accept Code
(def default-formats
[json-response-format
edn-response-format
transit-response-format
["text/plain" raw-response-format]
["text/html" raw-response-format]
raw-response-format])
(p/defn-curried get-format [opts format-entry]
(cond (vector? format-entry) (get-format opts
(second format-entry))
(map? format-entry) format-entry
; Must be a format generating function
:else (format-entry opts)))
(p/defn-curried accept-entry [opts format-entry]
(or (if (vector? format-entry)
(first format-entry)
(:content-type (get-format opts format-entry)))
"*/*"))
(p/defn-curried detect-content-type [content-type opts format-entry]
(let [accept (accept-entry opts format-entry)]
(or (= accept "*/*")
(>= (.indexOf content-type accept) 0))))
(defn get-default-format [xhrio {:keys [response-format] :as opts}]
(let [f (detect-content-type
(or (-get-response-header xhrio "Content-Type") "")
opts)]
(->> response-format
(filter f)
first
(get-format opts))))
(p/defn-curried detect-response-format-read
[opts xhrio]
((:read (get-default-format xhrio opts)) xhrio))
(defn accept-header [{:keys [response-format] :as opts}]
(if (vector? response-format)
(str/join ", " (map (accept-entry opts) response-format))
(accept-entry opts response-format)))
(defn detect-response-format
([] (detect-response-format {:response-format default-formats}))
([opts]
(let [accept (accept-header opts)]
{:read (detect-response-format-read opts)
:format (str "(from " accept ")")
:content-type accept})))
;;; AJAX calls
(defn get-response-format [{:keys [response-format] :as opts}]
(cond
(vector? response-format) (detect-response-format opts)
(map? response-format) response-format
(ifn? response-format) {:read response-format
:description "custom"
:content-type "*/*"}
:else (throw (js/Error. (str "unrecognized response format: " response-format)))))
(defn exception-response [e status {:keys [description]} xhrio]
(let [response {:status status
:failure :error
:response nil}
status-text (str (.-message e)
" Format should have been "
description)
parse-error (assoc response
:status-text status-text
:failure :parse
:original-text (-body xhrio))]
(if (success? status)
parse-error
(assoc response
:status-text (-status-text xhrio)
:parse-error parse-error))))
(defn fail [status status-text failure & params]
(let [response {:status status
:status-text status-text
:failure failure}]
[false (reduce conj
response
(map vec (partition 2 params)))]))
(defn interpret-response [{:keys [read] :as format} xhrio]
(try
(let [status (-status xhrio)
fail (partial fail status)]
(case status
-1 (if (-was-aborted xhrio)
(fail "Request aborted by client." :aborted)
(fail "Request timed out." :timeout))
204 [true nil] ; 204 and 205 should have empty responses
205 [true nil]
(try
(let [response (read xhrio)]
(if (success? status)
[true response]
(fail (-status-text xhrio) :error :response response)))
(catch js/Object e
[false (exception-response e status format xhrio)]))))
(catch js/Object e
; These errors should never happen
(fail 0 (.-message e) :exception :exception e))))
(defn no-format [xhrio]
(throw (js/Error. "No response format was supplied.")))
(defn uri-with-params [uri params]
(if params
(str uri
(if (re-find #"\?" uri) "&" "?") ; add & if uri contains ?
(params-to-str params))
uri))
(defn get-request-format [format]
(cond
(map? format) format
(ifn? format) {:write format :content-type "text/plain"}
:else nil))
(defn normalize-method [method]
(if (keyword? method)
(str/upper-case (name method))
method))
(defn process-inputs [{:keys [uri method format params headers]}
{:keys [content-type]}]
(let [headers (merge {"Accept" content-type}
(or headers {}))]
(if (= (normalize-method method) "GET")
[(uri-with-params uri params) nil headers]
(let [{:keys [write content-type]}
(get-request-format format)
body (cond
(not (nil? write)) (write params)
(submittable? params) params
:else (throw (js/Error. (str "unrecognized request format: " format))))
content-type (if content-type
{"Content-Type" (str content-type "; charset=utf-8")})
headers (merge headers content-type)]
[uri body headers]))))
(p/defn-curried js-handler [response-format handler xhrio]
(let [response
(interpret-response response-format xhrio)]
(handler response)))
(defn base-handler [response-format {:keys [handler]}]
(if handler
(js-handler response-format handler)
(throw (js/Error. "No ajax handler provided."))))
(defn ajax-request
[{:keys [method api] :as opts}]
(let [response-format (get-response-format opts)
method (normalize-method method)
[uri body headers] (process-inputs opts response-format)
handler (base-handler response-format opts)
api (or api (new goog.net.XhrIo))]
(-js-ajax-request api uri method body
headers handler opts)))
;;; "Easy" API beyond this point
(defn keyword-request-format [format format-params]
(cond
(map? format) format
(fn? format) {:write format}
(nil? format) (transit-request-format format-params)
:else (case format
:transit (transit-request-format format-params)
:json (json-request-format)
:edn (edn-request-format)
:raw (url-request-format)
:url (url-request-format)
nil)))
(defn keyword-response-format-2 [format format-params]
(cond
(vector? format) [(first format)
(keyword-response-format-2 (second format)
format-params)]
(map? format) format
(fn? format) {:read format :description "custom"}
(nil? format) (detect-response-format)
:else (case format
:transit (transit-response-format format-params)
:json (json-response-format format-params)
:edn (edn-response-format)
:raw (raw-response-format)
:detect (detect-response-format)
nil)))
(defn keyword-response-format [format format-params]
(if (vector? format)
(->> format
(map #(keyword-response-format-2 % format-params))
(apply vector))
(keyword-response-format-2 format format-params)))
(p/defn-curried transform-handler
[{:keys [handler error-handler finally]} [ok result]]
(if-let [h (if ok handler error-handler)]
(h result))
(when (fn? finally)
(finally)))
(defn transform-opts [{:keys [method format response-format params]
:as opts}]
"Note that if you call GET, POST et al, this function gets
called and will include JSON and EDN code in your JS.
If you don't want this to happen, use ajax-request directly
(and use advanced optimisation)."
(let [needs-format
(not (or (submittable? params)
(= method "GET")))
rf (if (or format needs-format)
(keyword-request-format format opts))]
(assoc opts
:handler (transform-handler opts)
:format rf
:response-format (keyword-response-format response-format opts))))
(defn easy-ajax-request [uri method opts]
(-> opts
(assoc :uri uri
:method method)
ajax.core/transform-opts
ajax.core/ajax-request))
(m/easy-api GET)
(m/easy-api HEAD)
(m/easy-api POST)
(m/easy-api PUT)
(m/easy-api DELETE)
(m/easy-api OPTIONS)
(m/easy-api TRACE)
(m/easy-api PATCH)
+1891
View File
File diff suppressed because it is too large Load Diff
Executable
+3110
View File
File diff suppressed because one or more lines are too long
Executable
+1
View File
File diff suppressed because one or more lines are too long
+12131
View File
File diff suppressed because it is too large Load Diff
+39030
View File
File diff suppressed because it is too large Load Diff
+886
View File
@@ -0,0 +1,886 @@
(ns cljs.core.async
(:refer-clojure :exclude [reduce into merge map take partition partition-by])
(:require [cljs.core.async.impl.protocols :as impl]
[cljs.core.async.impl.channels :as channels]
[cljs.core.async.impl.buffers :as buffers]
[cljs.core.async.impl.timers :as timers]
[cljs.core.async.impl.dispatch :as dispatch]
[cljs.core.async.impl.ioc-helpers :as helpers])
(:require-macros [cljs.core.async.impl.ioc-macros :as ioc]
[cljs.core.async.macros :refer [go go-loop]]))
(defn- fn-handler [f]
(reify
impl/Handler
(active? [_] true)
(commit [_] f)))
(defn buffer
"Returns a fixed buffer of size n. When full, puts will block/park."
[n]
(buffers/fixed-buffer n))
(defn dropping-buffer
"Returns a buffer of size n. When full, puts will complete but
val will be dropped (no transfer)."
[n]
(buffers/dropping-buffer n))
(defn sliding-buffer
"Returns a buffer of size n. When full, puts will complete, and be
buffered, but oldest elements in buffer will be dropped (not
transferred)."
[n]
(buffers/sliding-buffer n))
(defn unblocking-buffer?
"Returns true if a channel created with buff will never block. That is to say,
puts into this buffer will never cause the buffer to be full. "
[buff]
(satisfies? impl/UnblockingBuffer buff))
(defn chan
"Creates a channel with an optional buffer, an optional transducer (like (map f),
(filter p) etc or a composition thereof), and an optional exception handler.
If buf-or-n is a number, will create and use a fixed buffer of that size. If a
transducer is supplied a buffer must be specified. ex-handler must be a
fn of one argument - if an exception occurs during transformation it will be called
with the thrown value as an argument, and any non-nil return value will be placed
in the channel."
([] (chan nil))
([buf-or-n] (chan buf-or-n nil nil))
([buf-or-n xform] (chan buf-or-n xform nil))
([buf-or-n xform ex-handler]
(let [buf-or-n (if (= buf-or-n 0)
nil
buf-or-n)]
(when xform (assert buf-or-n "buffer must be supplied when transducer is"))
(channels/chan (if (number? buf-or-n)
(buffer buf-or-n)
buf-or-n)
xform
ex-handler))))
(defn timeout
"Returns a channel that will close after msecs"
[msecs]
(timers/timeout msecs))
(defn <!
"takes a val from port. Must be called inside a (go ...) block. Will
return nil if closed. Will park if nothing is available.
Returns true unless port is already closed"
[port]
(throw (js/Error. "<! used not in (go ...) block")))
(defn take!
"Asynchronously takes a val from port, passing to fn1. Will pass nil
if closed. If on-caller? (default true) is true, and value is
immediately available, will call fn1 on calling thread.
Returns nil."
([port fn1] (take! port fn1 true))
([port fn1 on-caller?]
(let [ret (impl/take! port (fn-handler fn1))]
(when ret
(let [val @ret]
(if on-caller?
(fn1 val)
(dispatch/run #(fn1 val)))))
nil)))
(defn- nop [_])
(def ^:private fhnop (fn-handler nop))
(defn >!
"puts a val into port. nil values are not allowed. Must be called
inside a (go ...) block. Will park if no buffer space is available.
Returns true unless port is already closed."
[port val]
(throw (js/Error. ">! used not in (go ...) block")))
(defn put!
"Asynchronously puts a val into port, calling fn0 (if supplied) when
complete. nil values are not allowed. Will throw if closed. If
on-caller? (default true) is true, and the put is immediately
accepted, will call fn0 on calling thread. Returns nil."
([port val]
(if-let [ret (impl/put! port val fhnop)]
@ret
true))
([port val fn1] (put! port val fn1 true))
([port val fn1 on-caller?]
(if-let [retb (impl/put! port val (fn-handler fn1))]
(let [ret @retb]
(if on-caller?
(fn1 ret)
(dispatch/run #(fn1 ret)))
ret)
true)))
(defn close!
([port]
(impl/close! port)))
(defn- random-array
[n]
(let [a (make-array n)]
(dotimes [x n]
(aset a x 0))
(loop [i 1]
(if (= i n)
a
(do
(let [j (rand-int i)]
(aset a i (aget a j))
(aset a j i)
(recur (inc i))))))))
(defn- alt-flag []
(let [flag (atom true)]
(reify
impl/Handler
(active? [_] @flag)
(commit [_]
(reset! flag nil)
true))))
(defn- alt-handler [flag cb]
(reify
impl/Handler
(active? [_] (impl/active? flag))
(commit [_]
(impl/commit flag)
cb)))
(defn do-alts
"returns derefable [val port] if immediate, nil if enqueued"
[fret ports opts]
(let [flag (alt-flag)
n (count ports)
idxs (random-array n)
priority (:priority opts)
ret
(loop [i 0]
(when (< i n)
(let [idx (if priority i (aget idxs i))
port (nth ports idx)
wport (when (vector? port) (port 0))
vbox (if wport
(let [val (port 1)]
(impl/put! wport val (alt-handler flag #(fret [% wport]))))
(impl/take! port (alt-handler flag #(fret [% port]))))]
(if vbox
(channels/box [@vbox (or wport port)])
(recur (inc i))))))]
(or
ret
(when (contains? opts :default)
(when-let [got (and (impl/active? flag) (impl/commit flag))]
(channels/box [(:default opts) :default]))))))
(defn alts!
"Completes at most one of several channel operations. Must be called
inside a (go ...) block. ports is a vector of channel endpoints,
which can be either a channel to take from or a vector of
[channel-to-put-to val-to-put], in any combination. Takes will be
made as if by <!, and puts will be made as if by >!. Unless
the :priority option is true, if more than one port operation is
ready a non-deterministic choice will be made. If no operation is
ready and a :default value is supplied, [default-val :default] will
be returned, otherwise alts! will park until the first operation to
become ready completes. Returns [val port] of the completed
operation, where val is the value taken for takes, and a
boolean (true unless already closed, as per put!) for puts.
opts are passed as :key val ... Supported options:
:default val - the value to use if none of the operations are immediately ready
:priority true - (default nil) when true, the operations will be tried in order.
Note: there is no guarantee that the port exps or val exprs will be
used, nor in what order should they be, so they should not be
depended upon for side effects."
[ports & {:as opts}]
(throw (js/Error. "alts! used not in (go ...) block")))
;;;;;;; channel ops
(defn pipe
"Takes elements from the from channel and supplies them to the to
channel. By default, the to channel will be closed when the from
channel closes, but can be determined by the close? parameter. Will
stop consuming the from channel if the to channel closes"
([from to] (pipe from to true))
([from to close?]
(go-loop []
(let [v (<! from)]
(if (nil? v)
(when close? (close! to))
(when (>! to v)
(recur)))))
to))
(defn- pipeline*
([n to xf from close? ex-handler type]
(assert (pos? n))
(let [jobs (chan n)
results (chan n)
process (fn [[v p :as job]]
(if (nil? job)
(do (close! results) nil)
(let [res (chan 1 xf ex-handler)]
(go
(>! res v)
(close! res))
(put! p res)
true)))
async (fn [[v p :as job]]
(if (nil? job)
(do (close! results) nil)
(let [res (chan 1)]
(xf v res)
(put! p res)
true)))]
(dotimes [_ n]
(case type
:compute (go-loop []
(let [job (<! jobs)]
(when (process job)
(recur))))
:async (go-loop []
(let [job (<! jobs)]
(when (async job)
(recur))))))
(go-loop []
(let [v (<! from)]
(if (nil? v)
(close! jobs)
(let [p (chan 1)]
(>! jobs [v p])
(>! results p)
(recur)))))
(go-loop []
(let [p (<! results)]
(if (nil? p)
(when close? (close! to))
(let [res (<! p)]
(loop []
(let [v (<! res)]
(when (and (not (nil? v)) (>! to v))
(recur))))
(recur))))))))
(defn pipeline-async
"Takes elements from the from channel and supplies them to the to
channel, subject to the async function af, with parallelism n. af
must be a function of two arguments, the first an input value and
the second a channel on which to place the result(s). af must close!
the channel before returning. The presumption is that af will
return immediately, having launched some asynchronous operation
whose completion/callback will manipulate the result channel. Outputs
will be returned in order relative to the inputs. By default, the to
channel will be closed when the from channel closes, but can be
determined by the close? parameter. Will stop consuming the from
channel if the to channel closes."
([n to af from] (pipeline-async n to af from true))
([n to af from close?] (pipeline* n to af from close? nil :async)))
(defn pipeline
"Takes elements from the from channel and supplies them to the to
channel, subject to the transducer xf, with parallelism n. Because
it is parallel, the transducer will be applied independently to each
element, not across elements, and may produce zero or more outputs
per input. Outputs will be returned in order relative to the
inputs. By default, the to channel will be closed when the from
channel closes, but can be determined by the close? parameter. Will
stop consuming the from channel if the to channel closes.
Note this is supplied for API compatibility with the Clojure version.
Values of N > 1 will not result in actual concurrency in a
single-threaded runtime."
([n to xf from] (pipeline n to xf from true))
([n to xf from close?] (pipeline n to xf from close? nil))
([n to xf from close? ex-handler] (pipeline* n to xf from close? ex-handler :compute)))
(defn split
"Takes a predicate and a source channel and returns a vector of two
channels, the first of which will contain the values for which the
predicate returned true, the second those for which it returned
false.
The out channels will be unbuffered by default, or two buf-or-ns can
be supplied. The channels will close after the source channel has
closed."
([p ch] (split p ch nil nil))
([p ch t-buf-or-n f-buf-or-n]
(let [tc (chan t-buf-or-n)
fc (chan f-buf-or-n)]
(go-loop []
(let [v (<! ch)]
(if (nil? v)
(do (close! tc) (close! fc))
(when (>! (if (p v) tc fc) v)
(recur)))))
[tc fc])))
(defn reduce
"f should be a function of 2 arguments. Returns a channel containing
the single result of applying f to init and the first item from the
channel, then applying f to that result and the 2nd item, etc. If
the channel closes without yielding items, returns init and f is not
called. ch must close before reduce produces a result."
[f init ch]
(go-loop [ret init]
(let [v (<! ch)]
(if (nil? v)
ret
(recur (f ret v))))))
(defn onto-chan
"Puts the contents of coll into the supplied channel.
By default the channel will be closed after the items are copied,
but can be determined by the close? parameter.
Returns a channel which will close after the items are copied."
([ch coll] (onto-chan ch coll true))
([ch coll close?]
(go-loop [vs (seq coll)]
(if (and vs (>! ch (first vs)))
(recur (next vs))
(when close?
(close! ch))))))
(defn to-chan
"Creates and returns a channel which contains the contents of coll,
closing when exhausted."
[coll]
(let [ch (chan (bounded-count 100 coll))]
(onto-chan ch coll)
ch))
(defprotocol Mux
(muxch* [_]))
(defprotocol Mult
(tap* [m ch close?])
(untap* [m ch])
(untap-all* [m]))
(defn mult
"Creates and returns a mult(iple) of the supplied channel. Channels
containing copies of the channel can be created with 'tap', and
detached with 'untap'.
Each item is distributed to all taps in parallel and synchronously,
i.e. each tap must accept before the next item is distributed. Use
buffering/windowing to prevent slow taps from holding up the mult.
Items received when there are no taps get dropped.
If a tap puts to a closed channel, it will be removed from the mult."
[ch]
(let [cs (atom {}) ;;ch->close?
m (reify
Mux
(muxch* [_] ch)
Mult
(tap* [_ ch close?] (swap! cs assoc ch close?) nil)
(untap* [_ ch] (swap! cs dissoc ch) nil)
(untap-all* [_] (reset! cs {}) nil))
dchan (chan 1)
dctr (atom nil)
done (fn [_] (when (zero? (swap! dctr dec))
(put! dchan true)))]
(go-loop []
(let [val (<! ch)]
(if (nil? val)
(doseq [[c close?] @cs]
(when close? (close! c)))
(let [chs (keys @cs)]
(reset! dctr (count chs))
(doseq [c chs]
(when-not (put! c val done)
(done nil)
(untap* m c)))
;;wait for all
(when (seq chs)
(<! dchan))
(recur)))))
m))
(defn tap
"Copies the mult source onto the supplied channel.
By default the channel will be closed when the source closes,
but can be determined by the close? parameter."
([mult ch] (tap mult ch true))
([mult ch close?] (tap* mult ch close?) ch))
(defn untap
"Disconnects a target channel from a mult"
[mult ch]
(untap* mult ch))
(defn untap-all
"Disconnects all target channels from a mult"
[mult] (untap-all* mult))
(defprotocol Mix
(admix* [m ch])
(unmix* [m ch])
(unmix-all* [m])
(toggle* [m state-map])
(solo-mode* [m mode]))
(defn ioc-alts! [state cont-block ports & {:as opts}]
(ioc/aset-all! state helpers/STATE-IDX cont-block)
(when-let [cb (cljs.core.async/do-alts
(fn [val]
(ioc/aset-all! state helpers/VALUE-IDX val)
(helpers/run-state-machine-wrapped state))
ports
opts)]
(ioc/aset-all! state helpers/VALUE-IDX @cb)
:recur))
(defn mix
"Creates and returns a mix of one or more input channels which will
be put on the supplied out channel. Input sources can be added to
the mix with 'admix', and removed with 'unmix'. A mix supports
soloing, muting and pausing multiple inputs atomically using
'toggle', and can solo using either muting or pausing as determined
by 'solo-mode'.
Each channel can have zero or more boolean modes set via 'toggle':
:solo - when true, only this (ond other soloed) channel(s) will appear
in the mix output channel. :mute and :pause states of soloed
channels are ignored. If solo-mode is :mute, non-soloed
channels are muted, if :pause, non-soloed channels are
paused.
:mute - muted channels will have their contents consumed but not included in the mix
:pause - paused channels will not have their contents consumed (and thus also not included in the mix)
"
[out]
(let [cs (atom {}) ;;ch->attrs-map
solo-modes #{:mute :pause}
attrs (conj solo-modes :solo)
solo-mode (atom :mute)
change (chan)
changed #(put! change true)
pick (fn [attr chs]
(reduce-kv
(fn [ret c v]
(if (attr v)
(conj ret c)
ret))
#{} chs))
calc-state (fn []
(let [chs @cs
mode @solo-mode
solos (pick :solo chs)
pauses (pick :pause chs)]
{:solos solos
:mutes (pick :mute chs)
:reads (conj
(if (and (= mode :pause) (not (empty? solos)))
(vec solos)
(vec (remove pauses (keys chs))))
change)}))
m (reify
Mux
(muxch* [_] out)
Mix
(admix* [_ ch] (swap! cs assoc ch {}) (changed))
(unmix* [_ ch] (swap! cs dissoc ch) (changed))
(unmix-all* [_] (reset! cs {}) (changed))
(toggle* [_ state-map] (swap! cs (partial merge-with cljs.core/merge) state-map) (changed))
(solo-mode* [_ mode]
(assert (solo-modes mode) (str "mode must be one of: " solo-modes))
(reset! solo-mode mode)
(changed)))]
(go-loop [{:keys [solos mutes reads] :as state} (calc-state)]
(let [[v c] (alts! reads)]
(if (or (nil? v) (= c change))
(do (when (nil? v)
(swap! cs dissoc c))
(recur (calc-state)))
(if (or (solos c)
(and (empty? solos) (not (mutes c))))
(when (>! out v)
(recur state))
(recur state)))))
m))
(defn admix
"Adds ch as an input to the mix"
[mix ch]
(admix* mix ch))
(defn unmix
"Removes ch as an input to the mix"
[mix ch]
(unmix* mix ch))
(defn unmix-all
"removes all inputs from the mix"
[mix]
(unmix-all* mix))
(defn toggle
"Atomically sets the state(s) of one or more channels in a mix. The
state map is a map of channels -> channel-state-map. A
channel-state-map is a map of attrs -> boolean, where attr is one or
more of :mute, :pause or :solo. Any states supplied are merged with
the current state.
Note that channels can be added to a mix via toggle, which can be
used to add channels in a particular (e.g. paused) state."
[mix state-map]
(toggle* mix state-map))
(defn solo-mode
"Sets the solo mode of the mix. mode must be one of :mute or :pause"
[mix mode]
(solo-mode* mix mode))
(defprotocol Pub
(sub* [p v ch close?])
(unsub* [p v ch])
(unsub-all* [p] [p v]))
(defn pub
"Creates and returns a pub(lication) of the supplied channel,
partitioned into topics by the topic-fn. topic-fn will be applied to
each value on the channel and the result will determine the 'topic'
on which that value will be put. Channels can be subscribed to
receive copies of topics using 'sub', and unsubscribed using
'unsub'. Each topic will be handled by an internal mult on a
dedicated channel. By default these internal channels are
unbuffered, but a buf-fn can be supplied which, given a topic,
creates a buffer with desired properties.
Each item is distributed to all subs in parallel and synchronously,
i.e. each sub must accept before the next item is distributed. Use
buffering/windowing to prevent slow subs from holding up the pub.
Items received when there are no matching subs get dropped.
Note that if buf-fns are used then each topic is handled
asynchronously, i.e. if a channel is subscribed to more than one
topic it should not expect them to be interleaved identically with
the source."
([ch topic-fn] (pub ch topic-fn (constantly nil)))
([ch topic-fn buf-fn]
(let [mults (atom {}) ;;topic->mult
ensure-mult (fn [topic]
(or (get @mults topic)
(get (swap! mults
#(if (% topic) % (assoc % topic (mult (chan (buf-fn topic))))))
topic)))
p (reify
Mux
(muxch* [_] ch)
Pub
(sub* [p topic ch close?]
(let [m (ensure-mult topic)]
(tap m ch close?)))
(unsub* [p topic ch]
(when-let [m (get @mults topic)]
(untap m ch)))
(unsub-all* [_] (reset! mults {}))
(unsub-all* [_ topic] (swap! mults dissoc topic)))]
(go-loop []
(let [val (<! ch)]
(if (nil? val)
(doseq [m (vals @mults)]
(close! (muxch* m)))
(let [topic (topic-fn val)
m (get @mults topic)]
(when m
(when-not (>! (muxch* m) val)
(swap! mults dissoc topic)))
(recur)))))
p)))
(defn sub
"Subscribes a channel to a topic of a pub.
By default the channel will be closed when the source closes,
but can be determined by the close? parameter."
([p topic ch] (sub p topic ch true))
([p topic ch close?] (sub* p topic ch close?)))
(defn unsub
"Unsubscribes a channel from a topic of a pub"
[p topic ch]
(unsub* p topic ch))
(defn unsub-all
"Unsubscribes all channels from a pub, or a topic of a pub"
([p] (unsub-all* p))
([p topic] (unsub-all* p topic)))
;;;;
(defn map
"Takes a function and a collection of source channels, and returns a
channel which contains the values produced by applying f to the set
of first items taken from each source channel, followed by applying
f to the set of second items from each channel, until any one of the
channels is closed, at which point the output channel will be
closed. The returned channel will be unbuffered by default, or a
buf-or-n can be supplied"
([f chs] (map f chs nil))
([f chs buf-or-n]
(let [chs (vec chs)
out (chan buf-or-n)
cnt (count chs)
rets (object-array cnt)
dchan (chan 1)
dctr (atom nil)
done (mapv (fn [i]
(fn [ret]
(aset rets i ret)
(when (zero? (swap! dctr dec))
(put! dchan (.slice rets 0)))))
(range cnt))]
(go-loop []
(reset! dctr cnt)
(dotimes [i cnt]
(try
(take! (chs i) (done i))
(catch js/Object e
(swap! dctr dec))))
(let [rets (<! dchan)]
(if (some nil? rets)
(close! out)
(do (>! out (apply f rets))
(recur)))))
out)))
(defn merge
"Takes a collection of source channels and returns a channel which
contains all values taken from them. The returned channel will be
unbuffered by default, or a buf-or-n can be supplied. The channel
will close after all the source channels have closed."
([chs] (merge chs nil))
([chs buf-or-n]
(let [out (chan buf-or-n)]
(go-loop [cs (vec chs)]
(if (pos? (count cs))
(let [[v c] (alts! cs)]
(if (nil? v)
(recur (filterv #(not= c %) cs))
(do (>! out v)
(recur cs))))
(close! out)))
out)))
(defn into
"Returns a channel containing the single (collection) result of the
items taken from the channel conjoined to the supplied
collection. ch must close before into produces a result."
[coll ch]
(reduce conj coll ch))
(defn take
"Returns a channel that will return, at most, n items from ch. After n items
have been returned, or ch has been closed, the return chanel will close.
The output channel is unbuffered by default, unless buf-or-n is given."
([n ch]
(take n ch nil))
([n ch buf-or-n]
(let [out (chan buf-or-n)]
(go (loop [x 0]
(when (< x n)
(let [v (<! ch)]
(when (not (nil? v))
(>! out v)
(recur (inc x))))))
(close! out))
out)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; deprecated - do not use ;;;;;;;;;;;;;;;;;;;;;;;;;
(defn map<
"Deprecated - this function will be removed. Use transducer instead"
[f ch]
(reify
impl/Channel
(close! [_] (impl/close! ch))
(closed? [_] (impl/closed? ch))
impl/ReadPort
(take! [_ fn1]
(let [ret
(impl/take! ch
(reify
impl/Handler
(active? [_] (impl/active? fn1))
#_(lock-id [_] (impl/lock-id fn1))
(commit [_]
(let [f1 (impl/commit fn1)]
#(f1 (if (nil? %) nil (f %)))))))]
(if (and ret (not (nil? @ret)))
(channels/box (f @ret))
ret)))
impl/WritePort
(put! [_ val fn1] (impl/put! ch val fn1))))
(defn map>
"Deprecated - this function will be removed. Use transducer instead"
[f ch]
(reify
impl/Channel
(close! [_] (impl/close! ch))
impl/ReadPort
(take! [_ fn1] (impl/take! ch fn1))
impl/WritePort
(put! [_ val fn1]
(impl/put! ch (f val) fn1))))
(defn filter>
"Deprecated - this function will be removed. Use transducer instead"
[p ch]
(reify
impl/Channel
(close! [_] (impl/close! ch))
(closed? [_] (impl/closed? ch))
impl/ReadPort
(take! [_ fn1] (impl/take! ch fn1))
impl/WritePort
(put! [_ val fn1]
(if (p val)
(impl/put! ch val fn1)
(channels/box (not (impl/closed? ch)))))))
(defn remove>
"Deprecated - this function will be removed. Use transducer instead"
[p ch]
(filter> (complement p) ch))
(defn filter<
"Deprecated - this function will be removed. Use transducer instead"
([p ch] (filter< p ch nil))
([p ch buf-or-n]
(let [out (chan buf-or-n)]
(go-loop []
(let [val (<! ch)]
(if (nil? val)
(close! out)
(do (when (p val)
(>! out val))
(recur)))))
out)))
(defn remove<
"Deprecated - this function will be removed. Use transducer instead"
([p ch] (remove< p ch nil))
([p ch buf-or-n] (filter< (complement p) ch buf-or-n)))
(defn- mapcat* [f in out]
(go-loop []
(let [val (<! in)]
(if (nil? val)
(close! out)
(do (doseq [v (f val)]
(>! out v))
(when-not (impl/closed? out)
(recur)))))))
(defn mapcat<
"Deprecated - this function will be removed. Use transducer instead"
([f in] (mapcat< f in nil))
([f in buf-or-n]
(let [out (chan buf-or-n)]
(mapcat* f in out)
out)))
(defn mapcat>
"Deprecated - this function will be removed. Use transducer instead"
([f out] (mapcat> f out nil))
([f out buf-or-n]
(let [in (chan buf-or-n)]
(mapcat* f in out)
in)))
(defn unique
"Deprecated - this function will be removed. Use transducer instead"
([ch]
(unique ch nil))
([ch buf-or-n]
(let [out (chan buf-or-n)]
(go (loop [last nil]
(let [v (<! ch)]
(when (not (nil? v))
(if (= v last)
(recur last)
(do (>! out v)
(recur v))))))
(close! out))
out)))
(defn partition
"Deprecated - this function will be removed. Use transducer instead"
([n ch]
(partition n ch nil))
([n ch buf-or-n]
(let [out (chan buf-or-n)]
(go (loop [arr (make-array n)
idx 0]
(let [v (<! ch)]
(if (not (nil? v))
(do (aset ^objects arr idx v)
(let [new-idx (inc idx)]
(if (< new-idx n)
(recur arr new-idx)
(do (>! out (vec arr))
(recur (make-array n) 0)))))
(do (when (> idx 0)
(>! out (vec arr)))
(close! out))))))
out)))
(defn partition-by
"Deprecated - this function will be removed. Use transducer instead"
([f ch]
(partition-by f ch nil))
([f ch buf-or-n]
(let [out (chan buf-or-n)]
(go (loop [lst (make-array 0)
last ::nothing]
(let [v (<! ch)]
(if (not (nil? v))
(let [new-itm (f v)]
(if (or (= new-itm last)
(keyword-identical? last ::nothing))
(do (.push lst v)
(recur lst new-itm))
(do (>! out (vec lst))
(let [new-lst (make-array 0)]
(.push new-lst v)
(recur new-lst new-itm)))))
(do (when (> (alength lst) 0)
(>! out (vec lst)))
(close! out))))))
out)))
+8486
View File
File diff suppressed because it is too large Load Diff
+131
View File
@@ -0,0 +1,131 @@
;; Copyright (c) Rich Hickey and contributors. All rights reserved.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.core.async.impl.buffers
(:require [cljs.core.async.impl.protocols :as impl]))
;; -----------------------------------------------------------------------------
;; DO NOT USE, this is internal buffer representation
(defn acopy [src src-start dest dest-start len]
(loop [cnt 0]
(when (< cnt len)
(aset dest
(+ dest-start cnt)
(aget src (+ src-start cnt)))
(recur (inc cnt)))))
(deftype RingBuffer [^:mutable head ^:mutable tail ^:mutable length ^:mutable arr]
Object
(pop [_]
(when-not (zero? length)
(let [x (aget arr tail)]
(aset arr tail nil)
(set! tail (js-mod (inc tail) (alength arr)))
(set! length (dec length))
x)))
(unshift [_ x]
(aset arr head x)
(set! head (js-mod (inc head) (alength arr)))
(set! length (inc length))
nil)
(unbounded-unshift [this x]
(if (== (inc length) (alength arr))
(.resize this))
(.unshift this x))
;; Doubles the size of the buffer while retaining all the existing values
(resize
[_]
(let [new-arr-size (* (alength arr) 2)
new-arr (make-array new-arr-size)]
(cond
(< tail head)
(do (acopy arr tail new-arr 0 length)
(set! tail 0)
(set! head length)
(set! arr new-arr))
(> tail head)
(do (acopy arr tail new-arr 0 (- (alength arr) tail))
(acopy arr 0 new-arr (- (alength arr) tail) head)
(set! tail 0)
(set! head length)
(set! arr new-arr))
(== tail head)
(do (set! tail 0)
(set! head 0)
(set! arr new-arr)))))
(cleanup [this keep?]
(dotimes [x length]
(let [v (.pop this)]
(when ^boolean (keep? v)
(.unshift this v))))))
(defn ring-buffer [n]
(assert (> n 0) "Can't create a ring buffer of size 0")
(RingBuffer. 0 0 0 (make-array n)))
;; -----------------------------------------------------------------------------
(deftype FixedBuffer [buf n]
impl/Buffer
(full? [this]
(== (.-length buf) n))
(remove! [this]
(.pop buf))
(add!* [this itm]
(.unbounded-unshift buf itm)
this)
cljs.core/ICounted
(-count [this]
(.-length buf)))
(defn fixed-buffer [n]
(FixedBuffer. (ring-buffer n) n))
(deftype DroppingBuffer [buf n]
impl/UnblockingBuffer
impl/Buffer
(full? [this]
false)
(remove! [this]
(.pop buf))
(add!* [this itm]
(when-not (== (.-length buf) n)
(.unshift buf itm))
this)
cljs.core/ICounted
(-count [this]
(.-length buf)))
(defn dropping-buffer [n]
(DroppingBuffer. (ring-buffer n) n))
(deftype SlidingBuffer [buf n]
impl/UnblockingBuffer
impl/Buffer
(full? [this]
false)
(remove! [this]
(.pop buf))
(add!* [this itm]
(when (== (.-length buf) n)
(impl/remove! this))
(.unshift buf itm)
this)
cljs.core/ICounted
(-count [this]
(.-length buf)))
(defn sliding-buffer [n]
(SlidingBuffer. (ring-buffer n) n))
+359
View File
@@ -0,0 +1,359 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.core.async.impl.buffers');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.core.async.impl.protocols');
cljs.core.async.impl.buffers.acopy = (function cljs$core$async$impl$buffers$acopy(src,src_start,dest,dest_start,len){
var cnt = (0);
while(true){
if((cnt < len)){
(dest[(dest_start + cnt)] = (src[(src_start + cnt)]));
var G__5703 = (cnt + (1));
cnt = G__5703;
continue;
} else {
return null;
}
break;
}
});
/**
* @constructor
* @implements {cljs.core.async.impl.buffers.Object}
*/
cljs.core.async.impl.buffers.RingBuffer = (function (head,tail,length,arr){
this.head = head;
this.tail = tail;
this.length = length;
this.arr = arr;
});
(cljs.core.async.impl.buffers.RingBuffer.prototype.pop = (function (){
var self__ = this;
var _ = this;
if((self__.length === (0))){
return null;
} else {
var x = (self__.arr[self__.tail]);
(self__.arr[self__.tail] = null);
(self__.tail = ((self__.tail + (1)) % self__.arr.length));
(self__.length = (self__.length - (1)));
return x;
}
}));
(cljs.core.async.impl.buffers.RingBuffer.prototype.unshift = (function (x){
var self__ = this;
var _ = this;
(self__.arr[self__.head] = x);
(self__.head = ((self__.head + (1)) % self__.arr.length));
(self__.length = (self__.length + (1)));
return null;
}));
(cljs.core.async.impl.buffers.RingBuffer.prototype.unbounded_unshift = (function (x){
var self__ = this;
var this$ = this;
if(((self__.length + (1)) === self__.arr.length)){
this$.resize();
} else {
}
return this$.unshift(x);
}));
(cljs.core.async.impl.buffers.RingBuffer.prototype.resize = (function (){
var self__ = this;
var _ = this;
var new_arr_size = (self__.arr.length * (2));
var new_arr = (new Array(new_arr_size));
if((self__.tail < self__.head)){
cljs.core.async.impl.buffers.acopy(self__.arr,self__.tail,new_arr,(0),self__.length);
(self__.tail = (0));
(self__.head = self__.length);
return (self__.arr = new_arr);
} else {
if((self__.tail > self__.head)){
cljs.core.async.impl.buffers.acopy(self__.arr,self__.tail,new_arr,(0),(self__.arr.length - self__.tail));
cljs.core.async.impl.buffers.acopy(self__.arr,(0),new_arr,(self__.arr.length - self__.tail),self__.head);
(self__.tail = (0));
(self__.head = self__.length);
return (self__.arr = new_arr);
} else {
if((self__.tail === self__.head)){
(self__.tail = (0));
(self__.head = (0));
return (self__.arr = new_arr);
} else {
return null;
}
}
}
}));
(cljs.core.async.impl.buffers.RingBuffer.prototype.cleanup = (function (keep_QMARK_){
var self__ = this;
var this$ = this;
var n__5636__auto__ = self__.length;
var x = (0);
while(true){
if((x < n__5636__auto__)){
var v_5704 = this$.pop();
if((keep_QMARK_.cljs$core$IFn$_invoke$arity$1 ? keep_QMARK_.cljs$core$IFn$_invoke$arity$1(v_5704) : keep_QMARK_.call(null,v_5704))){
this$.unshift(v_5704);
} else {
}
var G__5705 = (x + (1));
x = G__5705;
continue;
} else {
return null;
}
break;
}
}));
(cljs.core.async.impl.buffers.RingBuffer.getBasis = (function (){
return new cljs.core.PersistentVector(null, 4, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.with_meta(cljs.core.cst$sym$head,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$tail,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$length,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$arr,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null))], null);
}));
(cljs.core.async.impl.buffers.RingBuffer.cljs$lang$type = true);
(cljs.core.async.impl.buffers.RingBuffer.cljs$lang$ctorStr = "cljs.core.async.impl.buffers/RingBuffer");
(cljs.core.async.impl.buffers.RingBuffer.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.buffers/RingBuffer");
}));
/**
* Positional factory function for cljs.core.async.impl.buffers/RingBuffer.
*/
cljs.core.async.impl.buffers.__GT_RingBuffer = (function cljs$core$async$impl$buffers$__GT_RingBuffer(head,tail,length,arr){
return (new cljs.core.async.impl.buffers.RingBuffer(head,tail,length,arr));
});
cljs.core.async.impl.buffers.ring_buffer = (function cljs$core$async$impl$buffers$ring_buffer(n){
if((n > (0))){
} else {
throw (new Error(["Assert failed: ","Can't create a ring buffer of size 0","\n","(> n 0)"].join('')));
}
return (new cljs.core.async.impl.buffers.RingBuffer((0),(0),(0),(new Array(n))));
});
/**
* @constructor
* @implements {cljs.core.ICounted}
* @implements {cljs.core.async.impl.protocols.Buffer}
*/
cljs.core.async.impl.buffers.FixedBuffer = (function (buf,n){
this.buf = buf;
this.n = n;
this.cljs$lang$protocol_mask$partition0$ = 2;
this.cljs$lang$protocol_mask$partition1$ = 0;
});
(cljs.core.async.impl.buffers.FixedBuffer.prototype.cljs$core$async$impl$protocols$Buffer$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.buffers.FixedBuffer.prototype.cljs$core$async$impl$protocols$Buffer$full_QMARK_$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return (self__.buf.length === self__.n);
}));
(cljs.core.async.impl.buffers.FixedBuffer.prototype.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return self__.buf.pop();
}));
(cljs.core.async.impl.buffers.FixedBuffer.prototype.cljs$core$async$impl$protocols$Buffer$add_BANG__STAR_$arity$2 = (function (this$,itm){
var self__ = this;
var this$__$1 = this;
self__.buf.unbounded_unshift(itm);
return this$__$1;
}));
(cljs.core.async.impl.buffers.FixedBuffer.prototype.cljs$core$ICounted$_count$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return self__.buf.length;
}));
(cljs.core.async.impl.buffers.FixedBuffer.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$buf,cljs.core.cst$sym$n], null);
}));
(cljs.core.async.impl.buffers.FixedBuffer.cljs$lang$type = true);
(cljs.core.async.impl.buffers.FixedBuffer.cljs$lang$ctorStr = "cljs.core.async.impl.buffers/FixedBuffer");
(cljs.core.async.impl.buffers.FixedBuffer.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.buffers/FixedBuffer");
}));
/**
* Positional factory function for cljs.core.async.impl.buffers/FixedBuffer.
*/
cljs.core.async.impl.buffers.__GT_FixedBuffer = (function cljs$core$async$impl$buffers$__GT_FixedBuffer(buf,n){
return (new cljs.core.async.impl.buffers.FixedBuffer(buf,n));
});
cljs.core.async.impl.buffers.fixed_buffer = (function cljs$core$async$impl$buffers$fixed_buffer(n){
return (new cljs.core.async.impl.buffers.FixedBuffer(cljs.core.async.impl.buffers.ring_buffer(n),n));
});
/**
* @constructor
* @implements {cljs.core.ICounted}
* @implements {cljs.core.async.impl.protocols.UnblockingBuffer}
* @implements {cljs.core.async.impl.protocols.Buffer}
*/
cljs.core.async.impl.buffers.DroppingBuffer = (function (buf,n){
this.buf = buf;
this.n = n;
this.cljs$lang$protocol_mask$partition0$ = 2;
this.cljs$lang$protocol_mask$partition1$ = 0;
});
(cljs.core.async.impl.buffers.DroppingBuffer.prototype.cljs$core$async$impl$protocols$UnblockingBuffer$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.buffers.DroppingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.buffers.DroppingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$full_QMARK_$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return false;
}));
(cljs.core.async.impl.buffers.DroppingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return self__.buf.pop();
}));
(cljs.core.async.impl.buffers.DroppingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$add_BANG__STAR_$arity$2 = (function (this$,itm){
var self__ = this;
var this$__$1 = this;
if((self__.buf.length === self__.n)){
} else {
self__.buf.unshift(itm);
}
return this$__$1;
}));
(cljs.core.async.impl.buffers.DroppingBuffer.prototype.cljs$core$ICounted$_count$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return self__.buf.length;
}));
(cljs.core.async.impl.buffers.DroppingBuffer.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$buf,cljs.core.cst$sym$n], null);
}));
(cljs.core.async.impl.buffers.DroppingBuffer.cljs$lang$type = true);
(cljs.core.async.impl.buffers.DroppingBuffer.cljs$lang$ctorStr = "cljs.core.async.impl.buffers/DroppingBuffer");
(cljs.core.async.impl.buffers.DroppingBuffer.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.buffers/DroppingBuffer");
}));
/**
* Positional factory function for cljs.core.async.impl.buffers/DroppingBuffer.
*/
cljs.core.async.impl.buffers.__GT_DroppingBuffer = (function cljs$core$async$impl$buffers$__GT_DroppingBuffer(buf,n){
return (new cljs.core.async.impl.buffers.DroppingBuffer(buf,n));
});
cljs.core.async.impl.buffers.dropping_buffer = (function cljs$core$async$impl$buffers$dropping_buffer(n){
return (new cljs.core.async.impl.buffers.DroppingBuffer(cljs.core.async.impl.buffers.ring_buffer(n),n));
});
/**
* @constructor
* @implements {cljs.core.ICounted}
* @implements {cljs.core.async.impl.protocols.UnblockingBuffer}
* @implements {cljs.core.async.impl.protocols.Buffer}
*/
cljs.core.async.impl.buffers.SlidingBuffer = (function (buf,n){
this.buf = buf;
this.n = n;
this.cljs$lang$protocol_mask$partition0$ = 2;
this.cljs$lang$protocol_mask$partition1$ = 0;
});
(cljs.core.async.impl.buffers.SlidingBuffer.prototype.cljs$core$async$impl$protocols$UnblockingBuffer$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.buffers.SlidingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.buffers.SlidingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$full_QMARK_$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return false;
}));
(cljs.core.async.impl.buffers.SlidingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return self__.buf.pop();
}));
(cljs.core.async.impl.buffers.SlidingBuffer.prototype.cljs$core$async$impl$protocols$Buffer$add_BANG__STAR_$arity$2 = (function (this$,itm){
var self__ = this;
var this$__$1 = this;
if((self__.buf.length === self__.n)){
this$__$1.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1(null);
} else {
}
self__.buf.unshift(itm);
return this$__$1;
}));
(cljs.core.async.impl.buffers.SlidingBuffer.prototype.cljs$core$ICounted$_count$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
return self__.buf.length;
}));
(cljs.core.async.impl.buffers.SlidingBuffer.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$buf,cljs.core.cst$sym$n], null);
}));
(cljs.core.async.impl.buffers.SlidingBuffer.cljs$lang$type = true);
(cljs.core.async.impl.buffers.SlidingBuffer.cljs$lang$ctorStr = "cljs.core.async.impl.buffers/SlidingBuffer");
(cljs.core.async.impl.buffers.SlidingBuffer.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.buffers/SlidingBuffer");
}));
/**
* Positional factory function for cljs.core.async.impl.buffers/SlidingBuffer.
*/
cljs.core.async.impl.buffers.__GT_SlidingBuffer = (function cljs$core$async$impl$buffers$__GT_SlidingBuffer(buf,n){
return (new cljs.core.async.impl.buffers.SlidingBuffer(buf,n));
});
cljs.core.async.impl.buffers.sliding_buffer = (function cljs$core$async$impl$buffers$sliding_buffer(n){
return (new cljs.core.async.impl.buffers.SlidingBuffer(cljs.core.async.impl.buffers.ring_buffer(n),n));
});
+182
View File
@@ -0,0 +1,182 @@
;; Copyright (c) Rich Hickey and contributors. All rights reserved.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.core.async.impl.channels
(:require [cljs.core.async.impl.protocols :as impl]
[cljs.core.async.impl.dispatch :as dispatch]
[cljs.core.async.impl.buffers :as buffers]))
(defn box [val]
(reify cljs.core/IDeref
(-deref [_] val)))
(deftype PutBox [handler val])
(defn put-active? [box]
(impl/active? (.-handler box)))
(def ^:const MAX_DIRTY 64)
(defprotocol MMC
(abort [this]))
(deftype ManyToManyChannel [takes ^:mutable dirty-takes puts ^:mutable dirty-puts ^not-native buf ^:mutable closed add!]
MMC
(abort [this]
(loop []
(let [putter (.pop puts)]
(when-not (nil? putter)
(let [^not-native put-handler (.-handler putter)
val (.-val putter)]
(if ^boolean (impl/active? put-handler)
(let [put-cb (impl/commit put-handler)]
(dispatch/run #(put-cb true)))
(recur))))))
(.cleanup puts (constantly false))
(impl/close! this))
impl/WritePort
(put! [this val ^not-native handler]
(assert (not (nil? val)) "Can't put nil in on a channel")
;; bug in CLJS compiler boolean inference - David
(let [^boolean closed closed]
(if (or closed (not ^boolean (impl/active? handler)))
(box (not closed))
(if (and buf (not (impl/full? buf)))
(do
(impl/commit handler)
(let [done? (reduced? (add! buf val))]
(loop []
(when (and (pos? (.-length takes)) (pos? (count buf)))
(let [^not-native taker (.pop takes)]
(if ^boolean (impl/active? taker)
(let [take-cb (impl/commit taker)
val (impl/remove! buf)]
(dispatch/run (fn [] (take-cb val))))
(recur)))))
(when done? (abort this))
(box true)))
(let [taker (loop []
(let [^not-native taker (.pop takes)]
(when taker
(if (impl/active? taker)
taker
(recur)))))]
(if taker
(let [take-cb (impl/commit taker)]
(impl/commit handler)
(dispatch/run (fn [] (take-cb val)))
(box true))
(do
(if (> dirty-puts MAX_DIRTY)
(do (set! dirty-puts 0)
(.cleanup puts put-active?))
(set! dirty-puts (inc dirty-puts)))
(assert (< (.-length puts) impl/MAX-QUEUE-SIZE)
(str "No more than " impl/MAX-QUEUE-SIZE
" pending puts are allowed on a single channel."
" Consider using a windowed buffer."))
(.unbounded-unshift puts (PutBox. handler val))
nil)))))))
impl/ReadPort
(take! [this ^not-native handler]
(if (not ^boolean (impl/active? handler))
nil
(if (and (not (nil? buf)) (pos? (count buf)))
(let [_ (impl/commit handler)
retval (box (impl/remove! buf))]
(loop []
(when-not (impl/full? buf)
(let [putter (.pop puts)]
(when-not (nil? putter)
(let [^not-native put-handler (.-handler putter)
val (.-val putter)]
(when ^boolean (impl/active? put-handler)
(let [put-cb (impl/commit put-handler)]
(impl/commit handler)
(dispatch/run #(put-cb true))
(when (reduced? (add! buf val))
(abort this)))))
(recur)))))
retval)
(let [putter (loop []
(let [putter (.pop puts)]
(when putter
(if ^boolean (impl/active? (.-handler putter))
putter
(recur)))))]
(if putter
(let [put-cb (impl/commit (.-handler putter))]
(impl/commit handler)
(dispatch/run #(put-cb true))
(box (.-val putter)))
(if closed
(do
(when buf (add! buf))
(if (and (impl/active? handler) (impl/commit handler))
(let [has-val (and buf (pos? (count buf)))]
(let [val (when has-val (impl/remove! buf))]
(box val)))
nil))
(do
(if (> dirty-takes MAX_DIRTY)
(do (set! dirty-takes 0)
(.cleanup takes impl/active?))
(set! dirty-takes (inc dirty-takes)))
(assert (< (.-length takes) impl/MAX-QUEUE-SIZE)
(str "No more than " impl/MAX-QUEUE-SIZE
" pending takes are allowed on a single channel."))
(.unbounded-unshift takes handler)
nil)))))))
impl/Channel
(closed? [_] closed)
(close! [this]
(if ^boolean closed
nil
(do (set! closed true)
(when (and buf (zero? (.-length puts)))
(add! buf))
(loop []
(let [^not-native taker (.pop takes)]
(when-not (nil? taker)
(when ^boolean (impl/active? taker)
(let [take-cb (impl/commit taker)
val (when (and buf (pos? (count buf))) (impl/remove! buf))]
(dispatch/run (fn [] (take-cb val)))))
(recur))))
nil))))
(defn- ex-handler [ex]
(.log js/console ex)
nil)
(defn- handle [buf exh t]
(let [else ((or exh ex-handler) t)]
(if (nil? else)
buf
(impl/add! buf else))))
(defn chan
([buf] (chan buf nil))
([buf xform] (chan buf xform nil))
([buf xform exh]
(ManyToManyChannel. (buffers/ring-buffer 32) 0 (buffers/ring-buffer 32)
0 buf false
(let [add! (if xform (xform impl/add!) impl/add!)]
(fn
([buf]
(try
(add! buf)
(catch :default t
(handle buf exh t))))
([buf val]
(try
(add! buf val)
(catch :default t
(handle buf exh t)))))))))
+540
View File
@@ -0,0 +1,540 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.core.async.impl.channels');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.core.async.impl.protocols');
goog.require('cljs.core.async.impl.dispatch');
goog.require('cljs.core.async.impl.buffers');
cljs.core.async.impl.channels.box = (function cljs$core$async$impl$channels$box(val){
if((typeof cljs !== 'undefined') && (typeof cljs.core !== 'undefined') && (typeof cljs.core.async !== 'undefined') && (typeof cljs.core.async.impl !== 'undefined') && (typeof cljs.core.async.impl.channels !== 'undefined') && (typeof cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713 !== 'undefined')){
} else {
/**
* @constructor
* @implements {cljs.core.IMeta}
* @implements {cljs.core.IDeref}
* @implements {cljs.core.IWithMeta}
*/
cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713 = (function (val,meta5714){
this.val = val;
this.meta5714 = meta5714;
this.cljs$lang$protocol_mask$partition0$ = 425984;
this.cljs$lang$protocol_mask$partition1$ = 0;
});
(cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713.prototype.cljs$core$IWithMeta$_with_meta$arity$2 = (function (_5715,meta5714__$1){
var self__ = this;
var _5715__$1 = this;
return (new cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713(self__.val,meta5714__$1));
}));
(cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713.prototype.cljs$core$IMeta$_meta$arity$1 = (function (_5715){
var self__ = this;
var _5715__$1 = this;
return self__.meta5714;
}));
(cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713.prototype.cljs$core$IDeref$_deref$arity$1 = (function (_){
var self__ = this;
var ___$1 = this;
return self__.val;
}));
(cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$val,cljs.core.cst$sym$meta5714], null);
}));
(cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713.cljs$lang$type = true);
(cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713.cljs$lang$ctorStr = "cljs.core.async.impl.channels/t_cljs$core$async$impl$channels5713");
(cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.channels/t_cljs$core$async$impl$channels5713");
}));
/**
* Positional factory function for cljs.core.async.impl.channels/t_cljs$core$async$impl$channels5713.
*/
cljs.core.async.impl.channels.__GT_t_cljs$core$async$impl$channels5713 = (function cljs$core$async$impl$channels$box_$___GT_t_cljs$core$async$impl$channels5713(val__$1,meta5714){
return (new cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713(val__$1,meta5714));
});
}
return (new cljs.core.async.impl.channels.t_cljs$core$async$impl$channels5713(val,cljs.core.PersistentArrayMap.EMPTY));
});
/**
* @constructor
*/
cljs.core.async.impl.channels.PutBox = (function (handler,val){
this.handler = handler;
this.val = val;
});
(cljs.core.async.impl.channels.PutBox.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$handler,cljs.core.cst$sym$val], null);
}));
(cljs.core.async.impl.channels.PutBox.cljs$lang$type = true);
(cljs.core.async.impl.channels.PutBox.cljs$lang$ctorStr = "cljs.core.async.impl.channels/PutBox");
(cljs.core.async.impl.channels.PutBox.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.channels/PutBox");
}));
/**
* Positional factory function for cljs.core.async.impl.channels/PutBox.
*/
cljs.core.async.impl.channels.__GT_PutBox = (function cljs$core$async$impl$channels$__GT_PutBox(handler,val){
return (new cljs.core.async.impl.channels.PutBox(handler,val));
});
cljs.core.async.impl.channels.put_active_QMARK_ = (function cljs$core$async$impl$channels$put_active_QMARK_(box){
return cljs.core.async.impl.protocols.active_QMARK_(box.handler);
});
cljs.core.async.impl.channels.MAX_DIRTY = (64);
/**
* @interface
*/
cljs.core.async.impl.channels.MMC = function(){};
var cljs$core$async$impl$channels$MMC$abort$dyn_5716 = (function (this$){
var x__5393__auto__ = (((this$ == null))?null:this$);
var m__5394__auto__ = (cljs.core.async.impl.channels.abort[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(this$) : m__5394__auto__.call(null,this$));
} else {
var m__5392__auto__ = (cljs.core.async.impl.channels.abort["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(this$) : m__5392__auto__.call(null,this$));
} else {
throw cljs.core.missing_protocol("MMC.abort",this$);
}
}
});
cljs.core.async.impl.channels.abort = (function cljs$core$async$impl$channels$abort(this$){
if((((!((this$ == null)))) && ((!((this$.cljs$core$async$impl$channels$MMC$abort$arity$1 == null)))))){
return this$.cljs$core$async$impl$channels$MMC$abort$arity$1(this$);
} else {
return cljs$core$async$impl$channels$MMC$abort$dyn_5716(this$);
}
});
/**
* @constructor
* @implements {cljs.core.async.impl.channels.MMC}
* @implements {cljs.core.async.impl.protocols.Channel}
* @implements {cljs.core.async.impl.protocols.WritePort}
* @implements {cljs.core.async.impl.protocols.ReadPort}
*/
cljs.core.async.impl.channels.ManyToManyChannel = (function (takes,dirty_takes,puts,dirty_puts,buf,closed,add_BANG_){
this.takes = takes;
this.dirty_takes = dirty_takes;
this.puts = puts;
this.dirty_puts = dirty_puts;
this.buf = buf;
this.closed = closed;
this.add_BANG_ = add_BANG_;
});
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$channels$MMC$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$channels$MMC$abort$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
while(true){
var putter_5717 = self__.puts.pop();
if((putter_5717 == null)){
} else {
var put_handler_5718 = putter_5717.handler;
var val_5719 = putter_5717.val;
if(put_handler_5718.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null)){
var put_cb_5720 = put_handler_5718.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
cljs.core.async.impl.dispatch.run(((function (put_cb_5720,put_handler_5718,val_5719,putter_5717,this$__$1){
return (function (){
return (put_cb_5720.cljs$core$IFn$_invoke$arity$1 ? put_cb_5720.cljs$core$IFn$_invoke$arity$1(true) : put_cb_5720.call(null,true));
});})(put_cb_5720,put_handler_5718,val_5719,putter_5717,this$__$1))
);
} else {
continue;
}
}
break;
}
self__.puts.cleanup(cljs.core.constantly(false));
return this$__$1.cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1(null);
}));
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$protocols$WritePort$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$protocols$WritePort$put_BANG_$arity$3 = (function (this$,val,handler){
var self__ = this;
var this$__$1 = this;
if((!((val == null)))){
} else {
throw (new Error(["Assert failed: ","Can't put nil in on a channel","\n","(not (nil? val))"].join('')));
}
var closed__$1 = self__.closed;
if(((closed__$1) || ((!(handler.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null)))))){
return cljs.core.async.impl.channels.box((!(closed__$1)));
} else {
if(cljs.core.truth_((function (){var and__5043__auto__ = self__.buf;
if(cljs.core.truth_(and__5043__auto__)){
return cljs.core.not(self__.buf.cljs$core$async$impl$protocols$Buffer$full_QMARK_$arity$1(null));
} else {
return and__5043__auto__;
}
})())){
handler.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
var done_QMARK_ = cljs.core.reduced_QMARK_((self__.add_BANG_.cljs$core$IFn$_invoke$arity$2 ? self__.add_BANG_.cljs$core$IFn$_invoke$arity$2(self__.buf,val) : self__.add_BANG_.call(null,self__.buf,val)));
while(true){
if((((self__.takes.length > (0))) && ((cljs.core.count(self__.buf) > (0))))){
var taker_5721 = self__.takes.pop();
if(taker_5721.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null)){
var take_cb_5722 = taker_5721.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
var val_5723__$1 = self__.buf.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1(null);
cljs.core.async.impl.dispatch.run(((function (take_cb_5722,val_5723__$1,taker_5721,done_QMARK_,closed__$1,this$__$1){
return (function (){
return (take_cb_5722.cljs$core$IFn$_invoke$arity$1 ? take_cb_5722.cljs$core$IFn$_invoke$arity$1(val_5723__$1) : take_cb_5722.call(null,val_5723__$1));
});})(take_cb_5722,val_5723__$1,taker_5721,done_QMARK_,closed__$1,this$__$1))
);
} else {
continue;
}
} else {
}
break;
}
if(done_QMARK_){
this$__$1.cljs$core$async$impl$channels$MMC$abort$arity$1(null);
} else {
}
return cljs.core.async.impl.channels.box(true);
} else {
var taker = (function (){while(true){
var taker = self__.takes.pop();
if(cljs.core.truth_(taker)){
if(cljs.core.truth_(taker.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null))){
return taker;
} else {
continue;
}
} else {
return null;
}
break;
}
})();
if(cljs.core.truth_(taker)){
var take_cb = taker.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
handler.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
cljs.core.async.impl.dispatch.run((function (){
return (take_cb.cljs$core$IFn$_invoke$arity$1 ? take_cb.cljs$core$IFn$_invoke$arity$1(val) : take_cb.call(null,val));
}));
return cljs.core.async.impl.channels.box(true);
} else {
if((self__.dirty_puts > (64))){
(self__.dirty_puts = (0));
self__.puts.cleanup(cljs.core.async.impl.channels.put_active_QMARK_);
} else {
(self__.dirty_puts = (self__.dirty_puts + (1)));
}
if((self__.puts.length < (1024))){
} else {
throw (new Error(["Assert failed: ",["No more than ",cljs.core.str.cljs$core$IFn$_invoke$arity$1((1024))," pending puts are allowed on a single channel."," Consider using a windowed buffer."].join(''),"\n","(< (.-length puts) impl/MAX-QUEUE-SIZE)"].join('')));
}
self__.puts.unbounded_unshift((new cljs.core.async.impl.channels.PutBox(handler,val)));
return null;
}
}
}
}));
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$protocols$ReadPort$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$protocols$ReadPort$take_BANG_$arity$2 = (function (this$,handler){
var self__ = this;
var this$__$1 = this;
if((!(handler.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null)))){
return null;
} else {
if((((!((self__.buf == null)))) && ((cljs.core.count(self__.buf) > (0))))){
var _ = handler.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
var retval = cljs.core.async.impl.channels.box(self__.buf.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1(null));
while(true){
if(cljs.core.truth_(self__.buf.cljs$core$async$impl$protocols$Buffer$full_QMARK_$arity$1(null))){
} else {
var putter_5724 = self__.puts.pop();
if((putter_5724 == null)){
} else {
var put_handler_5725 = putter_5724.handler;
var val_5726 = putter_5724.val;
if(put_handler_5725.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null)){
var put_cb_5727 = put_handler_5725.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
handler.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
cljs.core.async.impl.dispatch.run(((function (put_cb_5727,put_handler_5725,val_5726,putter_5724,_,retval,this$__$1){
return (function (){
return (put_cb_5727.cljs$core$IFn$_invoke$arity$1 ? put_cb_5727.cljs$core$IFn$_invoke$arity$1(true) : put_cb_5727.call(null,true));
});})(put_cb_5727,put_handler_5725,val_5726,putter_5724,_,retval,this$__$1))
);
if(cljs.core.reduced_QMARK_((self__.add_BANG_.cljs$core$IFn$_invoke$arity$2 ? self__.add_BANG_.cljs$core$IFn$_invoke$arity$2(self__.buf,val_5726) : self__.add_BANG_.call(null,self__.buf,val_5726)))){
this$__$1.cljs$core$async$impl$channels$MMC$abort$arity$1(null);
} else {
}
} else {
}
continue;
}
}
break;
}
return retval;
} else {
var putter = (function (){while(true){
var putter = self__.puts.pop();
if(cljs.core.truth_(putter)){
if(cljs.core.async.impl.protocols.active_QMARK_(putter.handler)){
return putter;
} else {
continue;
}
} else {
return null;
}
break;
}
})();
if(cljs.core.truth_(putter)){
var put_cb = cljs.core.async.impl.protocols.commit(putter.handler);
handler.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
cljs.core.async.impl.dispatch.run((function (){
return (put_cb.cljs$core$IFn$_invoke$arity$1 ? put_cb.cljs$core$IFn$_invoke$arity$1(true) : put_cb.call(null,true));
}));
return cljs.core.async.impl.channels.box(putter.val);
} else {
if(cljs.core.truth_(self__.closed)){
if(cljs.core.truth_(self__.buf)){
(self__.add_BANG_.cljs$core$IFn$_invoke$arity$1 ? self__.add_BANG_.cljs$core$IFn$_invoke$arity$1(self__.buf) : self__.add_BANG_.call(null,self__.buf));
} else {
}
if(cljs.core.truth_((function (){var and__5043__auto__ = handler.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null);
if(cljs.core.truth_(and__5043__auto__)){
return handler.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
} else {
return and__5043__auto__;
}
})())){
var has_val = (function (){var and__5043__auto__ = self__.buf;
if(cljs.core.truth_(and__5043__auto__)){
return (cljs.core.count(self__.buf) > (0));
} else {
return and__5043__auto__;
}
})();
var val = (cljs.core.truth_(has_val)?self__.buf.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1(null):null);
return cljs.core.async.impl.channels.box(val);
} else {
return null;
}
} else {
if((self__.dirty_takes > (64))){
(self__.dirty_takes = (0));
self__.takes.cleanup(cljs.core.async.impl.protocols.active_QMARK_);
} else {
(self__.dirty_takes = (self__.dirty_takes + (1)));
}
if((self__.takes.length < (1024))){
} else {
throw (new Error(["Assert failed: ",["No more than ",cljs.core.str.cljs$core$IFn$_invoke$arity$1((1024))," pending takes are allowed on a single channel."].join(''),"\n","(< (.-length takes) impl/MAX-QUEUE-SIZE)"].join('')));
}
self__.takes.unbounded_unshift(handler);
return null;
}
}
}
}
}));
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$protocols$Channel$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$protocols$Channel$closed_QMARK_$arity$1 = (function (_){
var self__ = this;
var ___$1 = this;
return self__.closed;
}));
(cljs.core.async.impl.channels.ManyToManyChannel.prototype.cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1 = (function (this$){
var self__ = this;
var this$__$1 = this;
if(self__.closed){
return null;
} else {
(self__.closed = true);
if(cljs.core.truth_((function (){var and__5043__auto__ = self__.buf;
if(cljs.core.truth_(and__5043__auto__)){
return (self__.puts.length === (0));
} else {
return and__5043__auto__;
}
})())){
(self__.add_BANG_.cljs$core$IFn$_invoke$arity$1 ? self__.add_BANG_.cljs$core$IFn$_invoke$arity$1(self__.buf) : self__.add_BANG_.call(null,self__.buf));
} else {
}
while(true){
var taker_5728 = self__.takes.pop();
if((taker_5728 == null)){
} else {
if(taker_5728.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(null)){
var take_cb_5729 = taker_5728.cljs$core$async$impl$protocols$Handler$commit$arity$1(null);
var val_5730 = (cljs.core.truth_((function (){var and__5043__auto__ = self__.buf;
if(cljs.core.truth_(and__5043__auto__)){
return (cljs.core.count(self__.buf) > (0));
} else {
return and__5043__auto__;
}
})())?self__.buf.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1(null):null);
cljs.core.async.impl.dispatch.run(((function (take_cb_5729,val_5730,taker_5728,this$__$1){
return (function (){
return (take_cb_5729.cljs$core$IFn$_invoke$arity$1 ? take_cb_5729.cljs$core$IFn$_invoke$arity$1(val_5730) : take_cb_5729.call(null,val_5730));
});})(take_cb_5729,val_5730,taker_5728,this$__$1))
);
} else {
}
continue;
}
break;
}
return null;
}
}));
(cljs.core.async.impl.channels.ManyToManyChannel.getBasis = (function (){
return new cljs.core.PersistentVector(null, 7, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$takes,cljs.core.with_meta(cljs.core.cst$sym$dirty_DASH_takes,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.cst$sym$puts,cljs.core.with_meta(cljs.core.cst$sym$dirty_DASH_puts,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$buf,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$tag,cljs.core.cst$sym$not_DASH_native], null)),cljs.core.with_meta(cljs.core.cst$sym$closed,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.cst$sym$add_BANG_], null);
}));
(cljs.core.async.impl.channels.ManyToManyChannel.cljs$lang$type = true);
(cljs.core.async.impl.channels.ManyToManyChannel.cljs$lang$ctorStr = "cljs.core.async.impl.channels/ManyToManyChannel");
(cljs.core.async.impl.channels.ManyToManyChannel.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.channels/ManyToManyChannel");
}));
/**
* Positional factory function for cljs.core.async.impl.channels/ManyToManyChannel.
*/
cljs.core.async.impl.channels.__GT_ManyToManyChannel = (function cljs$core$async$impl$channels$__GT_ManyToManyChannel(takes,dirty_takes,puts,dirty_puts,buf,closed,add_BANG_){
return (new cljs.core.async.impl.channels.ManyToManyChannel(takes,dirty_takes,puts,dirty_puts,buf,closed,add_BANG_));
});
cljs.core.async.impl.channels.ex_handler = (function cljs$core$async$impl$channels$ex_handler(ex){
console.log(ex);
return null;
});
cljs.core.async.impl.channels.handle = (function cljs$core$async$impl$channels$handle(buf,exh,t){
var else$ = (function (){var fexpr__5731 = (function (){var or__5045__auto__ = exh;
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return cljs.core.async.impl.channels.ex_handler;
}
})();
return (fexpr__5731.cljs$core$IFn$_invoke$arity$1 ? fexpr__5731.cljs$core$IFn$_invoke$arity$1(t) : fexpr__5731.call(null,t));
})();
if((else$ == null)){
return buf;
} else {
return cljs.core.async.impl.protocols.add_BANG_.cljs$core$IFn$_invoke$arity$2(buf,else$);
}
});
cljs.core.async.impl.channels.chan = (function cljs$core$async$impl$channels$chan(var_args){
var G__5733 = arguments.length;
switch (G__5733) {
case 1:
return cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 3:
return cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$1 = (function (buf){
return cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$2(buf,null);
}));
(cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$2 = (function (buf,xform){
return cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$3(buf,xform,null);
}));
(cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$3 = (function (buf,xform,exh){
return (new cljs.core.async.impl.channels.ManyToManyChannel(cljs.core.async.impl.buffers.ring_buffer((32)),(0),cljs.core.async.impl.buffers.ring_buffer((32)),(0),buf,false,(function (){var add_BANG_ = (cljs.core.truth_(xform)?(xform.cljs$core$IFn$_invoke$arity$1 ? xform.cljs$core$IFn$_invoke$arity$1(cljs.core.async.impl.protocols.add_BANG_) : xform.call(null,cljs.core.async.impl.protocols.add_BANG_)):cljs.core.async.impl.protocols.add_BANG_);
return (function() {
var G__5737 = null;
var G__5737__1 = (function (buf__$1){
try{return (add_BANG_.cljs$core$IFn$_invoke$arity$1 ? add_BANG_.cljs$core$IFn$_invoke$arity$1(buf__$1) : add_BANG_.call(null,buf__$1));
}catch (e5734){var t = e5734;
return cljs.core.async.impl.channels.handle(buf__$1,exh,t);
}});
var G__5737__2 = (function (buf__$1,val){
try{return (add_BANG_.cljs$core$IFn$_invoke$arity$2 ? add_BANG_.cljs$core$IFn$_invoke$arity$2(buf__$1,val) : add_BANG_.call(null,buf__$1,val));
}catch (e5735){var t = e5735;
return cljs.core.async.impl.channels.handle(buf__$1,exh,t);
}});
G__5737 = function(buf__$1,val){
switch(arguments.length){
case 1:
return G__5737__1.call(this,buf__$1);
case 2:
return G__5737__2.call(this,buf__$1,val);
}
throw(new Error('Invalid arity: ' + arguments.length));
};
G__5737.cljs$core$IFn$_invoke$arity$1 = G__5737__1;
G__5737.cljs$core$IFn$_invoke$arity$2 = G__5737__2;
return G__5737;
})()
})()));
}));
(cljs.core.async.impl.channels.chan.cljs$lang$maxFixedArity = 3);
+37
View File
@@ -0,0 +1,37 @@
(ns cljs.core.async.impl.dispatch
(:require [cljs.core.async.impl.buffers :as buffers]
[goog.async.nextTick]))
(def tasks (buffers/ring-buffer 32))
(def running? false)
(def queued? false)
(def TASK_BATCH_SIZE 1024)
(declare queue-dispatcher)
(defn process-messages []
(set! running? true)
(set! queued? false)
(loop [count 0]
(let [m (.pop tasks)]
(when-not (nil? m)
(m)
(when (< count TASK_BATCH_SIZE)
(recur (inc count))))))
(set! running? false)
(when (> (.-length tasks) 0)
(queue-dispatcher)))
(defn queue-dispatcher []
(when-not (and queued? running?)
(set! queued? true)
(goog.async.nextTick process-messages)))
(defn run [f]
(.unbounded-unshift tasks f)
(queue-dispatcher))
(defn queue-delay [f delay]
(js/setTimeout f delay))
+57
View File
@@ -0,0 +1,57 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.core.async.impl.dispatch');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.core.async.impl.buffers');
goog.require('goog.async.nextTick');
cljs.core.async.impl.dispatch.tasks = cljs.core.async.impl.buffers.ring_buffer((32));
cljs.core.async.impl.dispatch.running_QMARK_ = false;
cljs.core.async.impl.dispatch.queued_QMARK_ = false;
cljs.core.async.impl.dispatch.TASK_BATCH_SIZE = (1024);
cljs.core.async.impl.dispatch.process_messages = (function cljs$core$async$impl$dispatch$process_messages(){
(cljs.core.async.impl.dispatch.running_QMARK_ = true);
(cljs.core.async.impl.dispatch.queued_QMARK_ = false);
var count_5708 = (0);
while(true){
var m_5709 = cljs.core.async.impl.dispatch.tasks.pop();
if((m_5709 == null)){
} else {
(m_5709.cljs$core$IFn$_invoke$arity$0 ? m_5709.cljs$core$IFn$_invoke$arity$0() : m_5709.call(null));
if((count_5708 < cljs.core.async.impl.dispatch.TASK_BATCH_SIZE)){
var G__5710 = (count_5708 + (1));
count_5708 = G__5710;
continue;
} else {
}
}
break;
}
(cljs.core.async.impl.dispatch.running_QMARK_ = false);
if((cljs.core.async.impl.dispatch.tasks.length > (0))){
return (cljs.core.async.impl.dispatch.queue_dispatcher.cljs$core$IFn$_invoke$arity$0 ? cljs.core.async.impl.dispatch.queue_dispatcher.cljs$core$IFn$_invoke$arity$0() : cljs.core.async.impl.dispatch.queue_dispatcher.call(null));
} else {
return null;
}
});
cljs.core.async.impl.dispatch.queue_dispatcher = (function cljs$core$async$impl$dispatch$queue_dispatcher(){
if(((cljs.core.async.impl.dispatch.queued_QMARK_) && (cljs.core.async.impl.dispatch.running_QMARK_))){
return null;
} else {
(cljs.core.async.impl.dispatch.queued_QMARK_ = true);
return goog.async.nextTick(cljs.core.async.impl.dispatch.process_messages);
}
});
cljs.core.async.impl.dispatch.run = (function cljs$core$async$impl$dispatch$run(f){
cljs.core.async.impl.dispatch.tasks.unbounded_unshift(f);
return cljs.core.async.impl.dispatch.queue_dispatcher();
});
cljs.core.async.impl.dispatch.queue_delay = (function cljs$core$async$impl$dispatch$queue_delay(f,delay){
return setTimeout(f,delay);
});
+144
View File
@@ -0,0 +1,144 @@
(ns cljs.core.async.impl.ioc-helpers
(:require [cljs.core.async.impl.protocols :as impl])
(:require-macros [cljs.core.async.impl.ioc-macros :as ioc]))
(def ^:const FN-IDX 0)
(def ^:const STATE-IDX 1)
(def ^:const VALUE-IDX 2)
(def ^:const BINDINGS-IDX 3)
(def ^:const EXCEPTION-FRAMES 4)
(def ^:const CURRENT-EXCEPTION 5)
(def ^:const USER-START-IDX 6)
(defn aset-object [arr idx o]
(aget arr idx o))
(defn aget-object [arr idx]
(aget arr idx))
(defn finished?
"Returns true if the machine is in a finished state"
[state-array]
(keyword-identical? (aget state-array STATE-IDX) :finished))
(defn- fn-handler
[f]
(reify
impl/Handler
(active? [_] true)
(commit [_] f)))
(defn run-state-machine [state]
((aget-object state FN-IDX) state))
(defn run-state-machine-wrapped [state]
(try
(run-state-machine state)
(catch js/Object ex
(impl/close! ^not-native (aget-object state USER-START-IDX))
(throw ex))))
(defn take! [state blk ^not-native c]
(if-let [cb (impl/take! c (fn-handler
(fn [x]
(ioc/aset-all! state VALUE-IDX x STATE-IDX blk)
(run-state-machine-wrapped state))))]
(do (ioc/aset-all! state VALUE-IDX @cb STATE-IDX blk)
:recur)
nil))
(defn put! [state blk ^not-native c val]
(if-let [cb (impl/put! c val (fn-handler (fn [ret-val]
(ioc/aset-all! state VALUE-IDX ret-val STATE-IDX blk)
(run-state-machine-wrapped state))))]
(do (ioc/aset-all! state VALUE-IDX @cb STATE-IDX blk)
:recur)
nil))
(defn return-chan [state value]
(let [^not-native c (aget state USER-START-IDX)]
(when-not (nil? value)
(impl/put! c value (fn-handler (fn [] nil))))
(impl/close! c)
c))
(defrecord ExceptionFrame [catch-block
^Class catch-exception
finally-block
continue-block
prev])
(defn add-exception-frame [state catch-block catch-exception finally-block continue-block]
(ioc/aset-all! state
EXCEPTION-FRAMES
(->ExceptionFrame catch-block
catch-exception
finally-block
continue-block
(aget-object state EXCEPTION-FRAMES))))
(defn process-exception [state]
(let [exception-frame (aget-object state EXCEPTION-FRAMES)
catch-block (:catch-block exception-frame)
catch-exception (:catch-exception exception-frame)
exception (aget-object state CURRENT-EXCEPTION)]
(cond
(and exception
(not exception-frame))
(throw exception)
(and exception
catch-block
(instance? catch-exception exception))
(ioc/aset-all! state
STATE-IDX
catch-block
VALUE-IDX
exception
CURRENT-EXCEPTION
nil
EXCEPTION-FRAMES
(assoc exception-frame
:catch-block nil
:catch-exception nil))
(and exception
(not catch-block)
(not (:finally-block exception-frame)))
(do (ioc/aset-all! state
EXCEPTION-FRAMES
(:prev exception-frame))
(recur state))
(and exception
(not catch-block)
(:finally-block exception-frame))
(ioc/aset-all! state
STATE-IDX
(:finally-block exception-frame)
EXCEPTION-FRAMES
(assoc exception-frame
:finally-block nil))
(and (not exception)
(:finally-block exception-frame))
(do (ioc/aset-all! state
STATE-IDX
(:finally-block exception-frame)
EXCEPTION-FRAMES
(assoc exception-frame
:finally-block nil)))
(and (not exception)
(not (:finally-block exception-frame)))
(do (ioc/aset-all! state
STATE-IDX
(:continue-block exception-frame)
EXCEPTION-FRAMES
(:prev exception-frame)))
:else (throw (js/Error. "No matching clause")))))
+542
View File
@@ -0,0 +1,542 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.core.async.impl.ioc_helpers');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.core.async.impl.protocols');
cljs.core.async.impl.ioc_helpers.FN_IDX = (0);
cljs.core.async.impl.ioc_helpers.STATE_IDX = (1);
cljs.core.async.impl.ioc_helpers.VALUE_IDX = (2);
cljs.core.async.impl.ioc_helpers.BINDINGS_IDX = (3);
cljs.core.async.impl.ioc_helpers.EXCEPTION_FRAMES = (4);
cljs.core.async.impl.ioc_helpers.CURRENT_EXCEPTION = (5);
cljs.core.async.impl.ioc_helpers.USER_START_IDX = (6);
cljs.core.async.impl.ioc_helpers.aset_object = (function cljs$core$async$impl$ioc_helpers$aset_object(arr,idx,o){
return (arr[idx][o]);
});
cljs.core.async.impl.ioc_helpers.aget_object = (function cljs$core$async$impl$ioc_helpers$aget_object(arr,idx){
return (arr[idx]);
});
/**
* Returns true if the machine is in a finished state
*/
cljs.core.async.impl.ioc_helpers.finished_QMARK_ = (function cljs$core$async$impl$ioc_helpers$finished_QMARK_(state_array){
return cljs.core.keyword_identical_QMARK_((state_array[(1)]),cljs.core.cst$kw$finished);
});
cljs.core.async.impl.ioc_helpers.fn_handler = (function cljs$core$async$impl$ioc_helpers$fn_handler(f){
if((typeof cljs !== 'undefined') && (typeof cljs.core !== 'undefined') && (typeof cljs.core.async !== 'undefined') && (typeof cljs.core.async.impl !== 'undefined') && (typeof cljs.core.async.impl.ioc_helpers !== 'undefined') && (typeof cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784 !== 'undefined')){
} else {
/**
* @constructor
* @implements {cljs.core.async.impl.protocols.Handler}
* @implements {cljs.core.IMeta}
* @implements {cljs.core.IWithMeta}
*/
cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784 = (function (f,meta8785){
this.f = f;
this.meta8785 = meta8785;
this.cljs$lang$protocol_mask$partition0$ = 393216;
this.cljs$lang$protocol_mask$partition1$ = 0;
});
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.prototype.cljs$core$IWithMeta$_with_meta$arity$2 = (function (_8786,meta8785__$1){
var self__ = this;
var _8786__$1 = this;
return (new cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784(self__.f,meta8785__$1));
}));
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.prototype.cljs$core$IMeta$_meta$arity$1 = (function (_8786){
var self__ = this;
var _8786__$1 = this;
return self__.meta8785;
}));
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.prototype.cljs$core$async$impl$protocols$Handler$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.prototype.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1 = (function (_){
var self__ = this;
var ___$1 = this;
return true;
}));
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.prototype.cljs$core$async$impl$protocols$Handler$commit$arity$1 = (function (_){
var self__ = this;
var ___$1 = this;
return self__.f;
}));
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$f,cljs.core.cst$sym$meta8785], null);
}));
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.cljs$lang$type = true);
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.cljs$lang$ctorStr = "cljs.core.async.impl.ioc-helpers/t_cljs$core$async$impl$ioc_helpers8784");
(cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.ioc-helpers/t_cljs$core$async$impl$ioc_helpers8784");
}));
/**
* Positional factory function for cljs.core.async.impl.ioc-helpers/t_cljs$core$async$impl$ioc_helpers8784.
*/
cljs.core.async.impl.ioc_helpers.__GT_t_cljs$core$async$impl$ioc_helpers8784 = (function cljs$core$async$impl$ioc_helpers$fn_handler_$___GT_t_cljs$core$async$impl$ioc_helpers8784(f__$1,meta8785){
return (new cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784(f__$1,meta8785));
});
}
return (new cljs.core.async.impl.ioc_helpers.t_cljs$core$async$impl$ioc_helpers8784(f,cljs.core.PersistentArrayMap.EMPTY));
});
cljs.core.async.impl.ioc_helpers.run_state_machine = (function cljs$core$async$impl$ioc_helpers$run_state_machine(state){
var fexpr__8787 = cljs.core.async.impl.ioc_helpers.aget_object(state,(0));
return (fexpr__8787.cljs$core$IFn$_invoke$arity$1 ? fexpr__8787.cljs$core$IFn$_invoke$arity$1(state) : fexpr__8787.call(null,state));
});
cljs.core.async.impl.ioc_helpers.run_state_machine_wrapped = (function cljs$core$async$impl$ioc_helpers$run_state_machine_wrapped(state){
try{return cljs.core.async.impl.ioc_helpers.run_state_machine(state);
}catch (e8788){if((e8788 instanceof Object)){
var ex = e8788;
cljs.core.async.impl.ioc_helpers.aget_object(state,(6)).cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1(null);
throw ex;
} else {
throw e8788;
}
}});
cljs.core.async.impl.ioc_helpers.take_BANG_ = (function cljs$core$async$impl$ioc_helpers$take_BANG_(state,blk,c){
var temp__4655__auto__ = c.cljs$core$async$impl$protocols$ReadPort$take_BANG_$arity$2(null,cljs.core.async.impl.ioc_helpers.fn_handler((function (x){
var statearr_8789_8791 = state;
(statearr_8789_8791[(2)] = x);
(statearr_8789_8791[(1)] = blk);
return cljs.core.async.impl.ioc_helpers.run_state_machine_wrapped(state);
})));
if(cljs.core.truth_(temp__4655__auto__)){
var cb = temp__4655__auto__;
var statearr_8790_8792 = state;
(statearr_8790_8792[(2)] = cljs.core.deref(cb));
(statearr_8790_8792[(1)] = blk);
return cljs.core.cst$kw$recur;
} else {
return null;
}
});
cljs.core.async.impl.ioc_helpers.put_BANG_ = (function cljs$core$async$impl$ioc_helpers$put_BANG_(state,blk,c,val){
var temp__4655__auto__ = c.cljs$core$async$impl$protocols$WritePort$put_BANG_$arity$3(null,val,cljs.core.async.impl.ioc_helpers.fn_handler((function (ret_val){
var statearr_8793_8795 = state;
(statearr_8793_8795[(2)] = ret_val);
(statearr_8793_8795[(1)] = blk);
return cljs.core.async.impl.ioc_helpers.run_state_machine_wrapped(state);
})));
if(cljs.core.truth_(temp__4655__auto__)){
var cb = temp__4655__auto__;
var statearr_8794_8796 = state;
(statearr_8794_8796[(2)] = cljs.core.deref(cb));
(statearr_8794_8796[(1)] = blk);
return cljs.core.cst$kw$recur;
} else {
return null;
}
});
cljs.core.async.impl.ioc_helpers.return_chan = (function cljs$core$async$impl$ioc_helpers$return_chan(state,value){
var c = (state[(6)]);
if((value == null)){
} else {
c.cljs$core$async$impl$protocols$WritePort$put_BANG_$arity$3(null,value,cljs.core.async.impl.ioc_helpers.fn_handler((function (){
return null;
})));
}
c.cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1(null);
return c;
});
/**
* @constructor
* @implements {cljs.core.IRecord}
* @implements {cljs.core.IKVReduce}
* @implements {cljs.core.IEquiv}
* @implements {cljs.core.IHash}
* @implements {cljs.core.ICollection}
* @implements {cljs.core.ICounted}
* @implements {cljs.core.ISeqable}
* @implements {cljs.core.IMeta}
* @implements {cljs.core.ICloneable}
* @implements {cljs.core.IPrintWithWriter}
* @implements {cljs.core.IIterable}
* @implements {cljs.core.IWithMeta}
* @implements {cljs.core.IAssociative}
* @implements {cljs.core.IMap}
* @implements {cljs.core.ILookup}
*/
cljs.core.async.impl.ioc_helpers.ExceptionFrame = (function (catch_block,catch_exception,finally_block,continue_block,prev,__meta,__extmap,__hash){
this.catch_block = catch_block;
this.catch_exception = catch_exception;
this.finally_block = finally_block;
this.continue_block = continue_block;
this.prev = prev;
this.__meta = __meta;
this.__extmap = __extmap;
this.__hash = __hash;
this.cljs$lang$protocol_mask$partition0$ = 2230716170;
this.cljs$lang$protocol_mask$partition1$ = 139264;
});
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$ILookup$_lookup$arity$2 = (function (this__5343__auto__,k__5344__auto__){
var self__ = this;
var this__5343__auto____$1 = this;
return this__5343__auto____$1.cljs$core$ILookup$_lookup$arity$3(null,k__5344__auto__,null);
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$ILookup$_lookup$arity$3 = (function (this__5345__auto__,k8798,else__5346__auto__){
var self__ = this;
var this__5345__auto____$1 = this;
var G__8802 = k8798;
var G__8802__$1 = (((G__8802 instanceof cljs.core.Keyword))?G__8802.fqn:null);
switch (G__8802__$1) {
case "catch-block":
return self__.catch_block;
break;
case "catch-exception":
return self__.catch_exception;
break;
case "finally-block":
return self__.finally_block;
break;
case "continue-block":
return self__.continue_block;
break;
case "prev":
return self__.prev;
break;
default:
return cljs.core.get.cljs$core$IFn$_invoke$arity$3(self__.__extmap,k8798,else__5346__auto__);
}
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IKVReduce$_kv_reduce$arity$3 = (function (this__5363__auto__,f__5364__auto__,init__5365__auto__){
var self__ = this;
var this__5363__auto____$1 = this;
return cljs.core.reduce.cljs$core$IFn$_invoke$arity$3((function (ret__5366__auto__,p__8803){
var vec__8804 = p__8803;
var k__5367__auto__ = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__8804,(0),null);
var v__5368__auto__ = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__8804,(1),null);
return (f__5364__auto__.cljs$core$IFn$_invoke$arity$3 ? f__5364__auto__.cljs$core$IFn$_invoke$arity$3(ret__5366__auto__,k__5367__auto__,v__5368__auto__) : f__5364__auto__.call(null,ret__5366__auto__,k__5367__auto__,v__5368__auto__));
}),init__5365__auto__,this__5363__auto____$1);
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IPrintWithWriter$_pr_writer$arity$3 = (function (this__5358__auto__,writer__5359__auto__,opts__5360__auto__){
var self__ = this;
var this__5358__auto____$1 = this;
var pr_pair__5361__auto__ = (function (keyval__5362__auto__){
return cljs.core.pr_sequential_writer(writer__5359__auto__,cljs.core.pr_writer,""," ","",opts__5360__auto__,keyval__5362__auto__);
});
return cljs.core.pr_sequential_writer(writer__5359__auto__,pr_pair__5361__auto__,"#cljs.core.async.impl.ioc-helpers.ExceptionFrame{",", ","}",opts__5360__auto__,cljs.core.concat.cljs$core$IFn$_invoke$arity$2(new cljs.core.PersistentVector(null, 5, 5, cljs.core.PersistentVector.EMPTY_NODE, [(new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,[cljs.core.cst$kw$catch_DASH_block,self__.catch_block],null)),(new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,[cljs.core.cst$kw$catch_DASH_exception,self__.catch_exception],null)),(new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,[cljs.core.cst$kw$finally_DASH_block,self__.finally_block],null)),(new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,[cljs.core.cst$kw$continue_DASH_block,self__.continue_block],null)),(new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,[cljs.core.cst$kw$prev,self__.prev],null))], null),self__.__extmap));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IIterable$_iterator$arity$1 = (function (G__8797){
var self__ = this;
var G__8797__$1 = this;
return (new cljs.core.RecordIter((0),G__8797__$1,5,new cljs.core.PersistentVector(null, 5, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$kw$catch_DASH_block,cljs.core.cst$kw$catch_DASH_exception,cljs.core.cst$kw$finally_DASH_block,cljs.core.cst$kw$continue_DASH_block,cljs.core.cst$kw$prev], null),(cljs.core.truth_(self__.__extmap)?cljs.core._iterator(self__.__extmap):cljs.core.nil_iter())));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IMeta$_meta$arity$1 = (function (this__5341__auto__){
var self__ = this;
var this__5341__auto____$1 = this;
return self__.__meta;
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$ICloneable$_clone$arity$1 = (function (this__5338__auto__){
var self__ = this;
var this__5338__auto____$1 = this;
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,self__.catch_exception,self__.finally_block,self__.continue_block,self__.prev,self__.__meta,self__.__extmap,self__.__hash));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$ICounted$_count$arity$1 = (function (this__5347__auto__){
var self__ = this;
var this__5347__auto____$1 = this;
return (5 + cljs.core.count(self__.__extmap));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IHash$_hash$arity$1 = (function (this__5339__auto__){
var self__ = this;
var this__5339__auto____$1 = this;
var h__5154__auto__ = self__.__hash;
if((!((h__5154__auto__ == null)))){
return h__5154__auto__;
} else {
var h__5154__auto____$1 = (function (){var fexpr__8807 = (function (coll__5340__auto__){
return (846900531 ^ cljs.core.hash_unordered_coll(coll__5340__auto__));
});
return fexpr__8807(this__5339__auto____$1);
})();
(self__.__hash = h__5154__auto____$1);
return h__5154__auto____$1;
}
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IEquiv$_equiv$arity$2 = (function (this8799,other8800){
var self__ = this;
var this8799__$1 = this;
return (((!((other8800 == null)))) && ((((this8799__$1.constructor === other8800.constructor)) && (((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this8799__$1.catch_block,other8800.catch_block)) && (((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this8799__$1.catch_exception,other8800.catch_exception)) && (((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this8799__$1.finally_block,other8800.finally_block)) && (((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this8799__$1.continue_block,other8800.continue_block)) && (((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this8799__$1.prev,other8800.prev)) && (cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this8799__$1.__extmap,other8800.__extmap)))))))))))))));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IMap$_dissoc$arity$2 = (function (this__5353__auto__,k__5354__auto__){
var self__ = this;
var this__5353__auto____$1 = this;
if(cljs.core.contains_QMARK_(new cljs.core.PersistentHashSet(null, new cljs.core.PersistentArrayMap(null, 5, [cljs.core.cst$kw$finally_DASH_block,null,cljs.core.cst$kw$catch_DASH_block,null,cljs.core.cst$kw$catch_DASH_exception,null,cljs.core.cst$kw$prev,null,cljs.core.cst$kw$continue_DASH_block,null], null), null),k__5354__auto__)){
return cljs.core.dissoc.cljs$core$IFn$_invoke$arity$2(cljs.core._with_meta(cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentArrayMap.EMPTY,this__5353__auto____$1),self__.__meta),k__5354__auto__);
} else {
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,self__.catch_exception,self__.finally_block,self__.continue_block,self__.prev,self__.__meta,cljs.core.not_empty(cljs.core.dissoc.cljs$core$IFn$_invoke$arity$2(self__.__extmap,k__5354__auto__)),null));
}
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IAssociative$_contains_key_QMARK_$arity$2 = (function (this__5350__auto__,k8798){
var self__ = this;
var this__5350__auto____$1 = this;
var G__8808 = k8798;
var G__8808__$1 = (((G__8808 instanceof cljs.core.Keyword))?G__8808.fqn:null);
switch (G__8808__$1) {
case "catch-block":
case "catch-exception":
case "finally-block":
case "continue-block":
case "prev":
return true;
break;
default:
return cljs.core.contains_QMARK_(self__.__extmap,k8798);
}
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IAssociative$_assoc$arity$3 = (function (this__5351__auto__,k__5352__auto__,G__8797){
var self__ = this;
var this__5351__auto____$1 = this;
var pred__8809 = cljs.core.keyword_identical_QMARK_;
var expr__8810 = k__5352__auto__;
if(cljs.core.truth_((function (){var G__8812 = cljs.core.cst$kw$catch_DASH_block;
var G__8813 = expr__8810;
return (pred__8809.cljs$core$IFn$_invoke$arity$2 ? pred__8809.cljs$core$IFn$_invoke$arity$2(G__8812,G__8813) : pred__8809.call(null,G__8812,G__8813));
})())){
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(G__8797,self__.catch_exception,self__.finally_block,self__.continue_block,self__.prev,self__.__meta,self__.__extmap,null));
} else {
if(cljs.core.truth_((function (){var G__8814 = cljs.core.cst$kw$catch_DASH_exception;
var G__8815 = expr__8810;
return (pred__8809.cljs$core$IFn$_invoke$arity$2 ? pred__8809.cljs$core$IFn$_invoke$arity$2(G__8814,G__8815) : pred__8809.call(null,G__8814,G__8815));
})())){
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,G__8797,self__.finally_block,self__.continue_block,self__.prev,self__.__meta,self__.__extmap,null));
} else {
if(cljs.core.truth_((function (){var G__8816 = cljs.core.cst$kw$finally_DASH_block;
var G__8817 = expr__8810;
return (pred__8809.cljs$core$IFn$_invoke$arity$2 ? pred__8809.cljs$core$IFn$_invoke$arity$2(G__8816,G__8817) : pred__8809.call(null,G__8816,G__8817));
})())){
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,self__.catch_exception,G__8797,self__.continue_block,self__.prev,self__.__meta,self__.__extmap,null));
} else {
if(cljs.core.truth_((function (){var G__8818 = cljs.core.cst$kw$continue_DASH_block;
var G__8819 = expr__8810;
return (pred__8809.cljs$core$IFn$_invoke$arity$2 ? pred__8809.cljs$core$IFn$_invoke$arity$2(G__8818,G__8819) : pred__8809.call(null,G__8818,G__8819));
})())){
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,self__.catch_exception,self__.finally_block,G__8797,self__.prev,self__.__meta,self__.__extmap,null));
} else {
if(cljs.core.truth_((function (){var G__8820 = cljs.core.cst$kw$prev;
var G__8821 = expr__8810;
return (pred__8809.cljs$core$IFn$_invoke$arity$2 ? pred__8809.cljs$core$IFn$_invoke$arity$2(G__8820,G__8821) : pred__8809.call(null,G__8820,G__8821));
})())){
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,self__.catch_exception,self__.finally_block,self__.continue_block,G__8797,self__.__meta,self__.__extmap,null));
} else {
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,self__.catch_exception,self__.finally_block,self__.continue_block,self__.prev,self__.__meta,cljs.core.assoc.cljs$core$IFn$_invoke$arity$3(self__.__extmap,k__5352__auto__,G__8797),null));
}
}
}
}
}
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$ISeqable$_seq$arity$1 = (function (this__5356__auto__){
var self__ = this;
var this__5356__auto____$1 = this;
return cljs.core.seq(cljs.core.concat.cljs$core$IFn$_invoke$arity$2(new cljs.core.PersistentVector(null, 5, 5, cljs.core.PersistentVector.EMPTY_NODE, [(new cljs.core.MapEntry(cljs.core.cst$kw$catch_DASH_block,self__.catch_block,null)),(new cljs.core.MapEntry(cljs.core.cst$kw$catch_DASH_exception,self__.catch_exception,null)),(new cljs.core.MapEntry(cljs.core.cst$kw$finally_DASH_block,self__.finally_block,null)),(new cljs.core.MapEntry(cljs.core.cst$kw$continue_DASH_block,self__.continue_block,null)),(new cljs.core.MapEntry(cljs.core.cst$kw$prev,self__.prev,null))], null),self__.__extmap));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$IWithMeta$_with_meta$arity$2 = (function (this__5342__auto__,G__8797){
var self__ = this;
var this__5342__auto____$1 = this;
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(self__.catch_block,self__.catch_exception,self__.finally_block,self__.continue_block,self__.prev,G__8797,self__.__extmap,self__.__hash));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.prototype.cljs$core$ICollection$_conj$arity$2 = (function (this__5348__auto__,entry__5349__auto__){
var self__ = this;
var this__5348__auto____$1 = this;
if(cljs.core.vector_QMARK_(entry__5349__auto__)){
return this__5348__auto____$1.cljs$core$IAssociative$_assoc$arity$3(null,cljs.core._nth.cljs$core$IFn$_invoke$arity$2(entry__5349__auto__,(0)),cljs.core._nth.cljs$core$IFn$_invoke$arity$2(entry__5349__auto__,(1)));
} else {
return cljs.core.reduce.cljs$core$IFn$_invoke$arity$3(cljs.core._conj,this__5348__auto____$1,entry__5349__auto__);
}
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.getBasis = (function (){
return new cljs.core.PersistentVector(null, 5, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$catch_DASH_block,cljs.core.with_meta(cljs.core.cst$sym$catch_DASH_exception,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$tag,cljs.core.cst$sym$Class], null)),cljs.core.cst$sym$finally_DASH_block,cljs.core.cst$sym$continue_DASH_block,cljs.core.cst$sym$prev], null);
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.cljs$lang$type = true);
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.cljs$lang$ctorPrSeq = (function (this__5389__auto__){
return (new cljs.core.List(null,"cljs.core.async.impl.ioc-helpers/ExceptionFrame",null,(1),null));
}));
(cljs.core.async.impl.ioc_helpers.ExceptionFrame.cljs$lang$ctorPrWriter = (function (this__5389__auto__,writer__5390__auto__){
return cljs.core._write(writer__5390__auto__,"cljs.core.async.impl.ioc-helpers/ExceptionFrame");
}));
/**
* Positional factory function for cljs.core.async.impl.ioc-helpers/ExceptionFrame.
*/
cljs.core.async.impl.ioc_helpers.__GT_ExceptionFrame = (function cljs$core$async$impl$ioc_helpers$__GT_ExceptionFrame(catch_block,catch_exception,finally_block,continue_block,prev){
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(catch_block,catch_exception,finally_block,continue_block,prev,null,null,null));
});
/**
* Factory function for cljs.core.async.impl.ioc-helpers/ExceptionFrame, taking a map of keywords to field values.
*/
cljs.core.async.impl.ioc_helpers.map__GT_ExceptionFrame = (function cljs$core$async$impl$ioc_helpers$map__GT_ExceptionFrame(G__8801){
var extmap__5385__auto__ = (function (){var G__8822 = cljs.core.dissoc.cljs$core$IFn$_invoke$arity$variadic(G__8801,cljs.core.cst$kw$catch_DASH_block,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.cst$kw$catch_DASH_exception,cljs.core.cst$kw$finally_DASH_block,cljs.core.cst$kw$continue_DASH_block,cljs.core.cst$kw$prev], 0));
if(cljs.core.record_QMARK_(G__8801)){
return cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentArrayMap.EMPTY,G__8822);
} else {
return G__8822;
}
})();
return (new cljs.core.async.impl.ioc_helpers.ExceptionFrame(cljs.core.cst$kw$catch_DASH_block.cljs$core$IFn$_invoke$arity$1(G__8801),cljs.core.cst$kw$catch_DASH_exception.cljs$core$IFn$_invoke$arity$1(G__8801),cljs.core.cst$kw$finally_DASH_block.cljs$core$IFn$_invoke$arity$1(G__8801),cljs.core.cst$kw$continue_DASH_block.cljs$core$IFn$_invoke$arity$1(G__8801),cljs.core.cst$kw$prev.cljs$core$IFn$_invoke$arity$1(G__8801),null,cljs.core.not_empty(extmap__5385__auto__),null));
});
cljs.core.async.impl.ioc_helpers.add_exception_frame = (function cljs$core$async$impl$ioc_helpers$add_exception_frame(state,catch_block,catch_exception,finally_block,continue_block){
var statearr_8825 = state;
(statearr_8825[(4)] = cljs.core.async.impl.ioc_helpers.__GT_ExceptionFrame(catch_block,catch_exception,finally_block,continue_block,cljs.core.async.impl.ioc_helpers.aget_object(state,(4))));
return statearr_8825;
});
cljs.core.async.impl.ioc_helpers.process_exception = (function cljs$core$async$impl$ioc_helpers$process_exception(state){
while(true){
var exception_frame = cljs.core.async.impl.ioc_helpers.aget_object(state,(4));
var catch_block = cljs.core.cst$kw$catch_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame);
var catch_exception = cljs.core.cst$kw$catch_DASH_exception.cljs$core$IFn$_invoke$arity$1(exception_frame);
var exception = cljs.core.async.impl.ioc_helpers.aget_object(state,(5));
if(cljs.core.truth_((function (){var and__5043__auto__ = exception;
if(cljs.core.truth_(and__5043__auto__)){
return cljs.core.not(exception_frame);
} else {
return and__5043__auto__;
}
})())){
throw exception;
} else {
if(cljs.core.truth_((function (){var and__5043__auto__ = exception;
if(cljs.core.truth_(and__5043__auto__)){
var and__5043__auto____$1 = catch_block;
if(cljs.core.truth_(and__5043__auto____$1)){
return (exception instanceof catch_exception);
} else {
return and__5043__auto____$1;
}
} else {
return and__5043__auto__;
}
})())){
var statearr_8826 = state;
(statearr_8826[(1)] = catch_block);
(statearr_8826[(2)] = exception);
(statearr_8826[(5)] = null);
(statearr_8826[(4)] = cljs.core.assoc.cljs$core$IFn$_invoke$arity$variadic(exception_frame,cljs.core.cst$kw$catch_DASH_block,null,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.cst$kw$catch_DASH_exception,null], 0)));
return statearr_8826;
} else {
if(cljs.core.truth_((function (){var and__5043__auto__ = exception;
if(cljs.core.truth_(and__5043__auto__)){
return ((cljs.core.not(catch_block)) && (cljs.core.not(cljs.core.cst$kw$finally_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame))));
} else {
return and__5043__auto__;
}
})())){
var statearr_8827_8831 = state;
(statearr_8827_8831[(4)] = cljs.core.cst$kw$prev.cljs$core$IFn$_invoke$arity$1(exception_frame));
var G__8832 = state;
state = G__8832;
continue;
} else {
if(cljs.core.truth_((function (){var and__5043__auto__ = exception;
if(cljs.core.truth_(and__5043__auto__)){
var and__5043__auto____$1 = cljs.core.not(catch_block);
if(and__5043__auto____$1){
return cljs.core.cst$kw$finally_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame);
} else {
return and__5043__auto____$1;
}
} else {
return and__5043__auto__;
}
})())){
var statearr_8828 = state;
(statearr_8828[(1)] = cljs.core.cst$kw$finally_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame));
(statearr_8828[(4)] = cljs.core.assoc.cljs$core$IFn$_invoke$arity$3(exception_frame,cljs.core.cst$kw$finally_DASH_block,null));
return statearr_8828;
} else {
if(cljs.core.truth_((function (){var and__5043__auto__ = cljs.core.not(exception);
if(and__5043__auto__){
return cljs.core.cst$kw$finally_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame);
} else {
return and__5043__auto__;
}
})())){
var statearr_8829 = state;
(statearr_8829[(1)] = cljs.core.cst$kw$finally_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame));
(statearr_8829[(4)] = cljs.core.assoc.cljs$core$IFn$_invoke$arity$3(exception_frame,cljs.core.cst$kw$finally_DASH_block,null));
return statearr_8829;
} else {
if(((cljs.core.not(exception)) && (cljs.core.not(cljs.core.cst$kw$finally_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame))))){
var statearr_8830 = state;
(statearr_8830[(1)] = cljs.core.cst$kw$continue_DASH_block.cljs$core$IFn$_invoke$arity$1(exception_frame));
(statearr_8830[(4)] = cljs.core.cst$kw$prev.cljs$core$IFn$_invoke$arity$1(exception_frame));
return statearr_8830;
} else {
throw (new Error("No matching clause"));
}
}
}
}
}
}
break;
}
});
+41
View File
@@ -0,0 +1,41 @@
;; Copyright (c) Rich Hickey and contributors. All rights reserved.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.core.async.impl.protocols)
(def ^:const MAX-QUEUE-SIZE 1024)
(defprotocol ReadPort
(take! [port fn1-handler] "derefable val if taken, nil if take was enqueued"))
(defprotocol WritePort
(put! [port val fn1-handler] "derefable boolean (false if already closed) if handled, nil if put was enqueued.
Must throw on nil val."))
(defprotocol Channel
(close! [chan])
(closed? [chan]))
(defprotocol Handler
(active? [h] "returns true if has callback. Must work w/o lock")
#_(lock-id [h] "a unique id for lock acquisition order, 0 if no lock")
(commit [h] "commit to fulfilling its end of the transfer, returns cb. Must be called within lock"))
(defprotocol Buffer
(full? [b])
(remove! [b])
(add!* [b itm]))
(defn add!
([b] b)
([b itm]
(assert (not (nil? itm)))
(add!* b itm)))
;; Defines a buffer that will never block (return true to full?)
(defprotocol UnblockingBuffer)
+284
View File
@@ -0,0 +1,284 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.core.async.impl.protocols');
goog.require('cljs.core');
goog.require('cljs.core.constants');
cljs.core.async.impl.protocols.MAX_QUEUE_SIZE = (1024);
/**
* @interface
*/
cljs.core.async.impl.protocols.ReadPort = function(){};
var cljs$core$async$impl$protocols$ReadPort$take_BANG_$dyn_5689 = (function (port,fn1_handler){
var x__5393__auto__ = (((port == null))?null:port);
var m__5394__auto__ = (cljs.core.async.impl.protocols.take_BANG_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$2 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$2(port,fn1_handler) : m__5394__auto__.call(null,port,fn1_handler));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.take_BANG_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$2 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$2(port,fn1_handler) : m__5392__auto__.call(null,port,fn1_handler));
} else {
throw cljs.core.missing_protocol("ReadPort.take!",port);
}
}
});
/**
* derefable val if taken, nil if take was enqueued
*/
cljs.core.async.impl.protocols.take_BANG_ = (function cljs$core$async$impl$protocols$take_BANG_(port,fn1_handler){
if((((!((port == null)))) && ((!((port.cljs$core$async$impl$protocols$ReadPort$take_BANG_$arity$2 == null)))))){
return port.cljs$core$async$impl$protocols$ReadPort$take_BANG_$arity$2(port,fn1_handler);
} else {
return cljs$core$async$impl$protocols$ReadPort$take_BANG_$dyn_5689(port,fn1_handler);
}
});
/**
* @interface
*/
cljs.core.async.impl.protocols.WritePort = function(){};
var cljs$core$async$impl$protocols$WritePort$put_BANG_$dyn_5690 = (function (port,val,fn1_handler){
var x__5393__auto__ = (((port == null))?null:port);
var m__5394__auto__ = (cljs.core.async.impl.protocols.put_BANG_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$3 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$3(port,val,fn1_handler) : m__5394__auto__.call(null,port,val,fn1_handler));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.put_BANG_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$3 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$3(port,val,fn1_handler) : m__5392__auto__.call(null,port,val,fn1_handler));
} else {
throw cljs.core.missing_protocol("WritePort.put!",port);
}
}
});
/**
* derefable boolean (false if already closed) if handled, nil if put was enqueued.
* Must throw on nil val.
*/
cljs.core.async.impl.protocols.put_BANG_ = (function cljs$core$async$impl$protocols$put_BANG_(port,val,fn1_handler){
if((((!((port == null)))) && ((!((port.cljs$core$async$impl$protocols$WritePort$put_BANG_$arity$3 == null)))))){
return port.cljs$core$async$impl$protocols$WritePort$put_BANG_$arity$3(port,val,fn1_handler);
} else {
return cljs$core$async$impl$protocols$WritePort$put_BANG_$dyn_5690(port,val,fn1_handler);
}
});
/**
* @interface
*/
cljs.core.async.impl.protocols.Channel = function(){};
var cljs$core$async$impl$protocols$Channel$close_BANG_$dyn_5691 = (function (chan){
var x__5393__auto__ = (((chan == null))?null:chan);
var m__5394__auto__ = (cljs.core.async.impl.protocols.close_BANG_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(chan) : m__5394__auto__.call(null,chan));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.close_BANG_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(chan) : m__5392__auto__.call(null,chan));
} else {
throw cljs.core.missing_protocol("Channel.close!",chan);
}
}
});
cljs.core.async.impl.protocols.close_BANG_ = (function cljs$core$async$impl$protocols$close_BANG_(chan){
if((((!((chan == null)))) && ((!((chan.cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1 == null)))))){
return chan.cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1(chan);
} else {
return cljs$core$async$impl$protocols$Channel$close_BANG_$dyn_5691(chan);
}
});
var cljs$core$async$impl$protocols$Channel$closed_QMARK_$dyn_5692 = (function (chan){
var x__5393__auto__ = (((chan == null))?null:chan);
var m__5394__auto__ = (cljs.core.async.impl.protocols.closed_QMARK_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(chan) : m__5394__auto__.call(null,chan));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.closed_QMARK_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(chan) : m__5392__auto__.call(null,chan));
} else {
throw cljs.core.missing_protocol("Channel.closed?",chan);
}
}
});
cljs.core.async.impl.protocols.closed_QMARK_ = (function cljs$core$async$impl$protocols$closed_QMARK_(chan){
if((((!((chan == null)))) && ((!((chan.cljs$core$async$impl$protocols$Channel$closed_QMARK_$arity$1 == null)))))){
return chan.cljs$core$async$impl$protocols$Channel$closed_QMARK_$arity$1(chan);
} else {
return cljs$core$async$impl$protocols$Channel$closed_QMARK_$dyn_5692(chan);
}
});
/**
* @interface
*/
cljs.core.async.impl.protocols.Handler = function(){};
var cljs$core$async$impl$protocols$Handler$active_QMARK_$dyn_5693 = (function (h){
var x__5393__auto__ = (((h == null))?null:h);
var m__5394__auto__ = (cljs.core.async.impl.protocols.active_QMARK_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(h) : m__5394__auto__.call(null,h));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.active_QMARK_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(h) : m__5392__auto__.call(null,h));
} else {
throw cljs.core.missing_protocol("Handler.active?",h);
}
}
});
/**
* returns true if has callback. Must work w/o lock
*/
cljs.core.async.impl.protocols.active_QMARK_ = (function cljs$core$async$impl$protocols$active_QMARK_(h){
if((((!((h == null)))) && ((!((h.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1 == null)))))){
return h.cljs$core$async$impl$protocols$Handler$active_QMARK_$arity$1(h);
} else {
return cljs$core$async$impl$protocols$Handler$active_QMARK_$dyn_5693(h);
}
});
var cljs$core$async$impl$protocols$Handler$commit$dyn_5694 = (function (h){
var x__5393__auto__ = (((h == null))?null:h);
var m__5394__auto__ = (cljs.core.async.impl.protocols.commit[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(h) : m__5394__auto__.call(null,h));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.commit["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(h) : m__5392__auto__.call(null,h));
} else {
throw cljs.core.missing_protocol("Handler.commit",h);
}
}
});
/**
* commit to fulfilling its end of the transfer, returns cb. Must be called within lock
*/
cljs.core.async.impl.protocols.commit = (function cljs$core$async$impl$protocols$commit(h){
if((((!((h == null)))) && ((!((h.cljs$core$async$impl$protocols$Handler$commit$arity$1 == null)))))){
return h.cljs$core$async$impl$protocols$Handler$commit$arity$1(h);
} else {
return cljs$core$async$impl$protocols$Handler$commit$dyn_5694(h);
}
});
/**
* @interface
*/
cljs.core.async.impl.protocols.Buffer = function(){};
var cljs$core$async$impl$protocols$Buffer$full_QMARK_$dyn_5695 = (function (b){
var x__5393__auto__ = (((b == null))?null:b);
var m__5394__auto__ = (cljs.core.async.impl.protocols.full_QMARK_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(b) : m__5394__auto__.call(null,b));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.full_QMARK_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(b) : m__5392__auto__.call(null,b));
} else {
throw cljs.core.missing_protocol("Buffer.full?",b);
}
}
});
cljs.core.async.impl.protocols.full_QMARK_ = (function cljs$core$async$impl$protocols$full_QMARK_(b){
if((((!((b == null)))) && ((!((b.cljs$core$async$impl$protocols$Buffer$full_QMARK_$arity$1 == null)))))){
return b.cljs$core$async$impl$protocols$Buffer$full_QMARK_$arity$1(b);
} else {
return cljs$core$async$impl$protocols$Buffer$full_QMARK_$dyn_5695(b);
}
});
var cljs$core$async$impl$protocols$Buffer$remove_BANG_$dyn_5696 = (function (b){
var x__5393__auto__ = (((b == null))?null:b);
var m__5394__auto__ = (cljs.core.async.impl.protocols.remove_BANG_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(b) : m__5394__auto__.call(null,b));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.remove_BANG_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(b) : m__5392__auto__.call(null,b));
} else {
throw cljs.core.missing_protocol("Buffer.remove!",b);
}
}
});
cljs.core.async.impl.protocols.remove_BANG_ = (function cljs$core$async$impl$protocols$remove_BANG_(b){
if((((!((b == null)))) && ((!((b.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1 == null)))))){
return b.cljs$core$async$impl$protocols$Buffer$remove_BANG_$arity$1(b);
} else {
return cljs$core$async$impl$protocols$Buffer$remove_BANG_$dyn_5696(b);
}
});
var cljs$core$async$impl$protocols$Buffer$add_BANG__STAR_$dyn_5697 = (function (b,itm){
var x__5393__auto__ = (((b == null))?null:b);
var m__5394__auto__ = (cljs.core.async.impl.protocols.add_BANG__STAR_[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$2 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$2(b,itm) : m__5394__auto__.call(null,b,itm));
} else {
var m__5392__auto__ = (cljs.core.async.impl.protocols.add_BANG__STAR_["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$2 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$2(b,itm) : m__5392__auto__.call(null,b,itm));
} else {
throw cljs.core.missing_protocol("Buffer.add!*",b);
}
}
});
cljs.core.async.impl.protocols.add_BANG__STAR_ = (function cljs$core$async$impl$protocols$add_BANG__STAR_(b,itm){
if((((!((b == null)))) && ((!((b.cljs$core$async$impl$protocols$Buffer$add_BANG__STAR_$arity$2 == null)))))){
return b.cljs$core$async$impl$protocols$Buffer$add_BANG__STAR_$arity$2(b,itm);
} else {
return cljs$core$async$impl$protocols$Buffer$add_BANG__STAR_$dyn_5697(b,itm);
}
});
cljs.core.async.impl.protocols.add_BANG_ = (function cljs$core$async$impl$protocols$add_BANG_(var_args){
var G__5699 = arguments.length;
switch (G__5699) {
case 1:
return cljs.core.async.impl.protocols.add_BANG_.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.core.async.impl.protocols.add_BANG_.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.core.async.impl.protocols.add_BANG_.cljs$core$IFn$_invoke$arity$1 = (function (b){
return b;
}));
(cljs.core.async.impl.protocols.add_BANG_.cljs$core$IFn$_invoke$arity$2 = (function (b,itm){
if((!((itm == null)))){
} else {
throw (new Error("Assert failed: (not (nil? itm))"));
}
return cljs.core.async.impl.protocols.add_BANG__STAR_(b,itm);
}));
(cljs.core.async.impl.protocols.add_BANG_.cljs$lang$maxFixedArity = 2);
/**
* @interface
*/
cljs.core.async.impl.protocols.UnblockingBuffer = function(){};
+167
View File
@@ -0,0 +1,167 @@
;; Copyright (c) Rich Hickey and contributors. All rights reserved.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.core.async.impl.timers
(:require [cljs.core.async.impl.protocols :as impl]
[cljs.core.async.impl.channels :as channels]
[cljs.core.async.impl.dispatch :as dispatch]))
(def MAX_LEVEL 15) ;; 16 levels
(def P (/ 1 2))
(defn random-level
([] (random-level 0))
([level]
(if (and (< (.random js/Math) P)
(< level MAX_LEVEL))
(recur (inc level))
level)))
(deftype SkipListNode [key ^:mutable val forward]
ISeqable
(-seq [coll]
(list key val))
IPrintWithWriter
(-pr-writer [coll writer opts]
(pr-sequential-writer writer pr-writer "[" " " "]" opts coll)))
(defn skip-list-node
([level] (skip-list-node nil nil level))
([k v level]
(let [arr (make-array (inc level))]
(loop [i 0]
(when (< i (alength arr))
(aset arr i nil)
(recur (inc i))))
(SkipListNode. k v arr))))
(defn least-greater-node
([x k level] (least-greater-node x k level nil))
([x k level update]
(if-not (neg? level)
(let [x (loop [x x]
(if-let [x' (aget (.-forward x) level)]
(if (< (.-key x') k)
(recur x')
x)
x))]
(when-not (nil? update)
(aset update level x))
(recur x k (dec level) update))
x)))
(deftype SkipList [header ^:mutable level]
Object
(put [coll k v]
(let [update (make-array MAX_LEVEL)
x (least-greater-node header k level update)
x (aget (.-forward x) 0)]
(if (and (not (nil? x)) (== (.-key x) k))
(set! (.-val x) v)
(let [new-level (random-level)]
(when (> new-level level)
(loop [i (inc level)]
(when (<= i (inc new-level))
(aset update i header)
(recur (inc i))))
(set! level new-level))
(let [x (skip-list-node k v (make-array new-level))]
(loop [i 0]
(when (<= i level)
(let [links (.-forward (aget update i))]
(aset (.-forward x) i (aget links i))
(aset links i x)))))))))
(remove [coll k]
(let [update (make-array MAX_LEVEL)
x (least-greater-node header k level update)
x (aget (.-forward x) 0)]
(when (and (not (nil? x)) (== (.-key x) k))
(loop [i 0]
(when (<= i level)
(let [links (.-forward (aget update i))]
(if (identical? (aget links i) x)
(do
(aset links i (aget (.-forward x) i))
(recur (inc i)))
(recur (inc i))))))
(while (and (> level 0)
(nil? (aget (.-forward header) level)))
(set! level (dec level))))))
(ceilingEntry [coll k]
(loop [x header level level]
(if-not (neg? level)
(let [nx (loop [x x]
(let [x' (aget (.-forward x) level)]
(when-not (nil? x')
(if (>= (.-key x') k)
x'
(recur x')))))]
(if-not (nil? nx)
(recur nx (dec level))
(recur x (dec level))))
(when-not (identical? x header)
x))))
(floorEntry [coll k]
(loop [x header level level]
(if-not (neg? level)
(let [nx (loop [x x]
(let [x' (aget (.-forward x) level)]
(if-not (nil? x')
(if (> (.-key x') k)
x
(recur x'))
(when (zero? level)
x))))]
(if nx
(recur nx (dec level))
(recur x (dec level))))
(when-not (identical? x header)
x))))
ISeqable
(-seq [coll]
(letfn [(iter [node]
(lazy-seq
(when-not (nil? node)
(cons [(.-key node) (.-val node)]
(iter (aget (.-forward node) 0))))))]
(iter (aget (.-forward header) 0))))
IPrintWithWriter
(-pr-writer [coll writer opts]
(let [pr-pair (fn [keyval]
(pr-sequential-writer writer pr-writer "" " " "" opts keyval))]
(pr-sequential-writer writer pr-pair "{" ", " "}" opts coll))))
(defn skip-list []
(SkipList. (skip-list-node 0) 0))
(def timeouts-map (skip-list))
(def TIMEOUT_RESOLUTION_MS 10)
(defn timeout
"returns a channel that will close after msecs"
[msecs]
(let [timeout (+ (.valueOf (js/Date.)) msecs)
me (.ceilingEntry timeouts-map timeout)]
(or (when (and me (< (.-key me) (+ timeout TIMEOUT_RESOLUTION_MS)))
(.-val me))
(let [timeout-channel (channels/chan nil)]
(.put timeouts-map timeout timeout-channel)
(dispatch/queue-delay
(fn []
(.remove timeouts-map timeout)
(impl/close! timeout-channel))
msecs)
timeout-channel))))
+470
View File
@@ -0,0 +1,470 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.core.async.impl.timers');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.core.async.impl.protocols');
goog.require('cljs.core.async.impl.channels');
goog.require('cljs.core.async.impl.dispatch');
cljs.core.async.impl.timers.MAX_LEVEL = (15);
cljs.core.async.impl.timers.P = ((1) / (2));
cljs.core.async.impl.timers.random_level = (function cljs$core$async$impl$timers$random_level(var_args){
var G__8836 = arguments.length;
switch (G__8836) {
case 0:
return cljs.core.async.impl.timers.random_level.cljs$core$IFn$_invoke$arity$0();
break;
case 1:
return cljs.core.async.impl.timers.random_level.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.core.async.impl.timers.random_level.cljs$core$IFn$_invoke$arity$0 = (function (){
return cljs.core.async.impl.timers.random_level.cljs$core$IFn$_invoke$arity$1((0));
}));
(cljs.core.async.impl.timers.random_level.cljs$core$IFn$_invoke$arity$1 = (function (level){
while(true){
if((((Math.random() < cljs.core.async.impl.timers.P)) && ((level < cljs.core.async.impl.timers.MAX_LEVEL)))){
var G__8838 = (level + (1));
level = G__8838;
continue;
} else {
return level;
}
break;
}
}));
(cljs.core.async.impl.timers.random_level.cljs$lang$maxFixedArity = 1);
/**
* @constructor
* @implements {cljs.core.ISeqable}
* @implements {cljs.core.IPrintWithWriter}
*/
cljs.core.async.impl.timers.SkipListNode = (function (key,val,forward){
this.key = key;
this.val = val;
this.forward = forward;
this.cljs$lang$protocol_mask$partition0$ = 2155872256;
this.cljs$lang$protocol_mask$partition1$ = 0;
});
(cljs.core.async.impl.timers.SkipListNode.prototype.cljs$core$ISeqable$_seq$arity$1 = (function (coll){
var self__ = this;
var coll__$1 = this;
return (new cljs.core.List(null,self__.key,(new cljs.core.List(null,self__.val,null,(1),null)),(2),null));
}));
(cljs.core.async.impl.timers.SkipListNode.prototype.cljs$core$IPrintWithWriter$_pr_writer$arity$3 = (function (coll,writer,opts){
var self__ = this;
var coll__$1 = this;
return cljs.core.pr_sequential_writer(writer,cljs.core.pr_writer,"["," ","]",opts,coll__$1);
}));
(cljs.core.async.impl.timers.SkipListNode.getBasis = (function (){
return new cljs.core.PersistentVector(null, 3, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$key,cljs.core.with_meta(cljs.core.cst$sym$val,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.cst$sym$forward], null);
}));
(cljs.core.async.impl.timers.SkipListNode.cljs$lang$type = true);
(cljs.core.async.impl.timers.SkipListNode.cljs$lang$ctorStr = "cljs.core.async.impl.timers/SkipListNode");
(cljs.core.async.impl.timers.SkipListNode.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.timers/SkipListNode");
}));
/**
* Positional factory function for cljs.core.async.impl.timers/SkipListNode.
*/
cljs.core.async.impl.timers.__GT_SkipListNode = (function cljs$core$async$impl$timers$__GT_SkipListNode(key,val,forward){
return (new cljs.core.async.impl.timers.SkipListNode(key,val,forward));
});
cljs.core.async.impl.timers.skip_list_node = (function cljs$core$async$impl$timers$skip_list_node(var_args){
var G__8840 = arguments.length;
switch (G__8840) {
case 1:
return cljs.core.async.impl.timers.skip_list_node.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 3:
return cljs.core.async.impl.timers.skip_list_node.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.core.async.impl.timers.skip_list_node.cljs$core$IFn$_invoke$arity$1 = (function (level){
return cljs.core.async.impl.timers.skip_list_node.cljs$core$IFn$_invoke$arity$3(null,null,level);
}));
(cljs.core.async.impl.timers.skip_list_node.cljs$core$IFn$_invoke$arity$3 = (function (k,v,level){
var arr = (new Array((level + (1))));
var i_8842 = (0);
while(true){
if((i_8842 < arr.length)){
(arr[i_8842] = null);
var G__8843 = (i_8842 + (1));
i_8842 = G__8843;
continue;
} else {
}
break;
}
return (new cljs.core.async.impl.timers.SkipListNode(k,v,arr));
}));
(cljs.core.async.impl.timers.skip_list_node.cljs$lang$maxFixedArity = 3);
cljs.core.async.impl.timers.least_greater_node = (function cljs$core$async$impl$timers$least_greater_node(var_args){
var G__8845 = arguments.length;
switch (G__8845) {
case 3:
return cljs.core.async.impl.timers.least_greater_node.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
case 4:
return cljs.core.async.impl.timers.least_greater_node.cljs$core$IFn$_invoke$arity$4((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.core.async.impl.timers.least_greater_node.cljs$core$IFn$_invoke$arity$3 = (function (x,k,level){
return cljs.core.async.impl.timers.least_greater_node.cljs$core$IFn$_invoke$arity$4(x,k,level,null);
}));
(cljs.core.async.impl.timers.least_greater_node.cljs$core$IFn$_invoke$arity$4 = (function (x,k,level,update){
while(true){
if((!((level < (0))))){
var x__$1 = (function (){var x__$1 = x;
while(true){
var temp__4655__auto__ = (x__$1.forward[level]);
if(cljs.core.truth_(temp__4655__auto__)){
var x_SINGLEQUOTE_ = temp__4655__auto__;
if((x_SINGLEQUOTE_.key < k)){
var G__8847 = x_SINGLEQUOTE_;
x__$1 = G__8847;
continue;
} else {
return x__$1;
}
} else {
return x__$1;
}
break;
}
})();
if((update == null)){
} else {
(update[level] = x__$1);
}
var G__8848 = x__$1;
var G__8849 = k;
var G__8850 = (level - (1));
var G__8851 = update;
x = G__8848;
k = G__8849;
level = G__8850;
update = G__8851;
continue;
} else {
return x;
}
break;
}
}));
(cljs.core.async.impl.timers.least_greater_node.cljs$lang$maxFixedArity = 4);
/**
* @constructor
* @implements {cljs.core.async.impl.timers.Object}
* @implements {cljs.core.ISeqable}
* @implements {cljs.core.IPrintWithWriter}
*/
cljs.core.async.impl.timers.SkipList = (function (header,level){
this.header = header;
this.level = level;
this.cljs$lang$protocol_mask$partition0$ = 2155872256;
this.cljs$lang$protocol_mask$partition1$ = 0;
});
(cljs.core.async.impl.timers.SkipList.prototype.put = (function (k,v){
var self__ = this;
var coll = this;
var update = (new Array(cljs.core.async.impl.timers.MAX_LEVEL));
var x = cljs.core.async.impl.timers.least_greater_node.cljs$core$IFn$_invoke$arity$4(self__.header,k,self__.level,update);
var x__$1 = (x.forward[(0)]);
if((((!((x__$1 == null)))) && ((x__$1.key === k)))){
return (x__$1.val = v);
} else {
var new_level = cljs.core.async.impl.timers.random_level.cljs$core$IFn$_invoke$arity$0();
if((new_level > self__.level)){
var i_8852 = (self__.level + (1));
while(true){
if((i_8852 <= (new_level + (1)))){
(update[i_8852] = self__.header);
var G__8853 = (i_8852 + (1));
i_8852 = G__8853;
continue;
} else {
}
break;
}
(self__.level = new_level);
} else {
}
var x__$2 = cljs.core.async.impl.timers.skip_list_node.cljs$core$IFn$_invoke$arity$3(k,v,(new Array(new_level)));
var i = (0);
while(true){
if((i <= self__.level)){
var links = (update[i]).forward;
(x__$2.forward[i] = (links[i]));
return (links[i] = x__$2);
} else {
return null;
}
break;
}
}
}));
(cljs.core.async.impl.timers.SkipList.prototype.remove = (function (k){
var self__ = this;
var coll = this;
var update = (new Array(cljs.core.async.impl.timers.MAX_LEVEL));
var x = cljs.core.async.impl.timers.least_greater_node.cljs$core$IFn$_invoke$arity$4(self__.header,k,self__.level,update);
var x__$1 = (x.forward[(0)]);
if((((!((x__$1 == null)))) && ((x__$1.key === k)))){
var i_8854 = (0);
while(true){
if((i_8854 <= self__.level)){
var links_8855 = (update[i_8854]).forward;
if(((links_8855[i_8854]) === x__$1)){
(links_8855[i_8854] = (x__$1.forward[i_8854]));
var G__8856 = (i_8854 + (1));
i_8854 = G__8856;
continue;
} else {
var G__8857 = (i_8854 + (1));
i_8854 = G__8857;
continue;
}
} else {
}
break;
}
while(true){
if((((self__.level > (0))) && (((self__.header.forward[self__.level]) == null)))){
(self__.level = (self__.level - (1)));
continue;
} else {
return null;
}
break;
}
} else {
return null;
}
}));
(cljs.core.async.impl.timers.SkipList.prototype.ceilingEntry = (function (k){
var self__ = this;
var coll = this;
var x = self__.header;
var level__$1 = self__.level;
while(true){
if((!((level__$1 < (0))))){
var nx = (function (){var x__$1 = x;
while(true){
var x_SINGLEQUOTE_ = (x__$1.forward[level__$1]);
if((x_SINGLEQUOTE_ == null)){
return null;
} else {
if((x_SINGLEQUOTE_.key >= k)){
return x_SINGLEQUOTE_;
} else {
var G__8858 = x_SINGLEQUOTE_;
x__$1 = G__8858;
continue;
}
}
break;
}
})();
if((!((nx == null)))){
var G__8859 = nx;
var G__8860 = (level__$1 - (1));
x = G__8859;
level__$1 = G__8860;
continue;
} else {
var G__8861 = x;
var G__8862 = (level__$1 - (1));
x = G__8861;
level__$1 = G__8862;
continue;
}
} else {
if((x === self__.header)){
return null;
} else {
return x;
}
}
break;
}
}));
(cljs.core.async.impl.timers.SkipList.prototype.floorEntry = (function (k){
var self__ = this;
var coll = this;
var x = self__.header;
var level__$1 = self__.level;
while(true){
if((!((level__$1 < (0))))){
var nx = (function (){var x__$1 = x;
while(true){
var x_SINGLEQUOTE_ = (x__$1.forward[level__$1]);
if((!((x_SINGLEQUOTE_ == null)))){
if((x_SINGLEQUOTE_.key > k)){
return x__$1;
} else {
var G__8863 = x_SINGLEQUOTE_;
x__$1 = G__8863;
continue;
}
} else {
if((level__$1 === (0))){
return x__$1;
} else {
return null;
}
}
break;
}
})();
if(cljs.core.truth_(nx)){
var G__8864 = nx;
var G__8865 = (level__$1 - (1));
x = G__8864;
level__$1 = G__8865;
continue;
} else {
var G__8866 = x;
var G__8867 = (level__$1 - (1));
x = G__8866;
level__$1 = G__8867;
continue;
}
} else {
if((x === self__.header)){
return null;
} else {
return x;
}
}
break;
}
}));
(cljs.core.async.impl.timers.SkipList.prototype.cljs$core$ISeqable$_seq$arity$1 = (function (coll){
var self__ = this;
var coll__$1 = this;
var iter = (function cljs$core$async$impl$timers$iter(node){
return (new cljs.core.LazySeq(null,(function (){
if((node == null)){
return null;
} else {
return cljs.core.cons(new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [node.key,node.val], null),cljs$core$async$impl$timers$iter((node.forward[(0)])));
}
}),null,null));
});
return iter((self__.header.forward[(0)]));
}));
(cljs.core.async.impl.timers.SkipList.prototype.cljs$core$IPrintWithWriter$_pr_writer$arity$3 = (function (coll,writer,opts){
var self__ = this;
var coll__$1 = this;
var pr_pair = (function (keyval){
return cljs.core.pr_sequential_writer(writer,cljs.core.pr_writer,""," ","",opts,keyval);
});
return cljs.core.pr_sequential_writer(writer,pr_pair,"{",", ","}",opts,coll__$1);
}));
(cljs.core.async.impl.timers.SkipList.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$header,cljs.core.with_meta(cljs.core.cst$sym$level,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null))], null);
}));
(cljs.core.async.impl.timers.SkipList.cljs$lang$type = true);
(cljs.core.async.impl.timers.SkipList.cljs$lang$ctorStr = "cljs.core.async.impl.timers/SkipList");
(cljs.core.async.impl.timers.SkipList.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.core.async.impl.timers/SkipList");
}));
/**
* Positional factory function for cljs.core.async.impl.timers/SkipList.
*/
cljs.core.async.impl.timers.__GT_SkipList = (function cljs$core$async$impl$timers$__GT_SkipList(header,level){
return (new cljs.core.async.impl.timers.SkipList(header,level));
});
cljs.core.async.impl.timers.skip_list = (function cljs$core$async$impl$timers$skip_list(){
return (new cljs.core.async.impl.timers.SkipList(cljs.core.async.impl.timers.skip_list_node.cljs$core$IFn$_invoke$arity$1((0)),(0)));
});
cljs.core.async.impl.timers.timeouts_map = cljs.core.async.impl.timers.skip_list();
cljs.core.async.impl.timers.TIMEOUT_RESOLUTION_MS = (10);
/**
* returns a channel that will close after msecs
*/
cljs.core.async.impl.timers.timeout = (function cljs$core$async$impl$timers$timeout(msecs){
var timeout = ((new Date()).valueOf() + msecs);
var me = cljs.core.async.impl.timers.timeouts_map.ceilingEntry(timeout);
var or__5045__auto__ = (cljs.core.truth_((function (){var and__5043__auto__ = me;
if(cljs.core.truth_(and__5043__auto__)){
return (me.key < (timeout + cljs.core.async.impl.timers.TIMEOUT_RESOLUTION_MS));
} else {
return and__5043__auto__;
}
})())?me.val:null);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
var timeout_channel = cljs.core.async.impl.channels.chan.cljs$core$IFn$_invoke$arity$1(null);
cljs.core.async.impl.timers.timeouts_map.put(timeout,timeout_channel);
cljs.core.async.impl.dispatch.queue_delay((function (){
cljs.core.async.impl.timers.timeouts_map.remove(timeout);
return cljs.core.async.impl.protocols.close_BANG_(timeout_channel);
}),msecs);
return timeout_channel;
}
});
+477
View File
@@ -0,0 +1,477 @@
goog.provide('cljs.core.constants');
goog.require('cljs.core');
cljs.core.cst$kw$response = new cljs.core.Keyword(null,"response","response",-1068424192);
cljs.core.cst$sym$form = new cljs.core.Symbol(null,"form","form",16469056,null);
cljs.core.cst$sym$tag = new cljs.core.Symbol(null,"tag","tag",350170304,null);
cljs.core.cst$kw$description = new cljs.core.Keyword(null,"description","description",-1428560544);
cljs.core.cst$sym$_AMPERSAND_ = new cljs.core.Symbol(null,"&","&",-2144855648,null);
cljs.core.cst$sym$uuid = new cljs.core.Symbol(null,"uuid","uuid",-504564192,null);
cljs.core.cst$kw$div$todo_DASH_page = new cljs.core.Keyword(null,"div.todo-page","div.todo-page",-241729984);
cljs.core.cst$kw$features = new cljs.core.Keyword(null,"features","features",-1146962336);
cljs.core.cst$sym$case_STAR_ = new cljs.core.Symbol(null,"case*","case*",-1938255072,null);
cljs.core.cst$sym$after_DASH_render = new cljs.core.Symbol(null,"after-render","after-render",-656902336,null);
cljs.core.cst$kw$ex_DASH_kind = new cljs.core.Keyword(null,"ex-kind","ex-kind",1581199296);
cljs.core.cst$sym$clauses = new cljs.core.Symbol(null,"clauses","clauses",-1199594528,null);
cljs.core.cst$kw$async = new cljs.core.Keyword(null,"async","async",1050769601);
cljs.core.cst$sym$end = new cljs.core.Symbol(null,"end","end",1372345569,null);
cljs.core.cst$sym$defrecord_STAR_ = new cljs.core.Symbol(null,"defrecord*","defrecord*",-1936366207,null);
cljs.core.cst$sym$meta8942 = new cljs.core.Symbol(null,"meta8942","meta8942",1074984321,null);
cljs.core.cst$sym$base = new cljs.core.Symbol(null,"base","base",1825810849,null);
cljs.core.cst$sym$obj = new cljs.core.Symbol(null,"obj","obj",-1672671807,null);
cljs.core.cst$kw$finally = new cljs.core.Keyword(null,"finally","finally",1589088705);
cljs.core.cst$kw$data_DASH_index = new cljs.core.Keyword(null,"data-index","data-index",1161508385);
cljs.core.cst$sym$fqn = new cljs.core.Symbol(null,"fqn","fqn",-1749334463,null);
cljs.core.cst$sym$Class = new cljs.core.Symbol(null,"Class","Class",2064526977,null);
cljs.core.cst$sym$first = new cljs.core.Symbol(null,"first","first",996428481,null);
cljs.core.cst$kw$reader_DASH_error = new cljs.core.Keyword(null,"reader-error","reader-error",1610253121);
cljs.core.cst$sym$try = new cljs.core.Symbol(null,"try","try",-1273693247,null);
cljs.core.cst$sym$change = new cljs.core.Symbol(null,"change","change",477485025,null);
cljs.core.cst$sym$has_DASH_nil_QMARK_ = new cljs.core.Symbol(null,"has-nil?","has-nil?",825886722,null);
cljs.core.cst$kw$on_DASH_set = new cljs.core.Keyword(null,"on-set","on-set",-140953470);
cljs.core.cst$kw$live_for = new cljs.core.Keyword(null,"live_for","live_for",663254210);
cljs.core.cst$kw$format = new cljs.core.Keyword(null,"format","format",-1306924766);
cljs.core.cst$sym$puts = new cljs.core.Symbol(null,"puts","puts",-1883877054,null);
cljs.core.cst$sym$meta10272 = new cljs.core.Symbol(null,"meta10272","meta10272",1295395426,null);
cljs.core.cst$sym$vf = new cljs.core.Symbol(null,"vf","vf",1319108258,null);
cljs.core.cst$sym$rear = new cljs.core.Symbol(null,"rear","rear",-900164830,null);
cljs.core.cst$sym$hierarchy = new cljs.core.Symbol(null,"hierarchy","hierarchy",587061186,null);
cljs.core.cst$sym$iter = new cljs.core.Symbol(null,"iter","iter",-1346195486,null);
cljs.core.cst$kw$_STAR_ = new cljs.core.Keyword(null,"*","*",-1294732318);
cljs.core.cst$sym$clojure$core_SLASH_list = new cljs.core.Symbol("clojure.core","list","clojure.core/list",-1119203325,null);
cljs.core.cst$kw$get = new cljs.core.Keyword(null,"get","get",1683182755);
cljs.core.cst$sym$watching = new cljs.core.Symbol(null,"watching","watching",1947648227,null);
cljs.core.cst$sym$handler = new cljs.core.Symbol(null,"handler","handler",1444934915,null);
cljs.core.cst$sym$step = new cljs.core.Symbol(null,"step","step",-1365547645,null);
cljs.core.cst$kw$fname = new cljs.core.Keyword(null,"fname","fname",1500291491);
cljs.core.cst$sym$boolean = new cljs.core.Symbol(null,"boolean","boolean",-278886877,null);
cljs.core.cst$sym$update_DASH_count = new cljs.core.Symbol(null,"update-count","update-count",-411982269,null);
cljs.core.cst$kw$somef = new cljs.core.Keyword(null,"somef","somef",-622590365);
cljs.core.cst$sym$reaction = new cljs.core.Symbol(null,"reaction","reaction",2131401315,null);
cljs.core.cst$sym$method_DASH_table = new cljs.core.Symbol(null,"method-table","method-table",-1878263165,null);
cljs.core.cst$kw$ready = new cljs.core.Keyword(null,"ready","ready",1086465795);
cljs.core.cst$sym$chunk = new cljs.core.Symbol(null,"chunk","chunk",449371907,null);
cljs.core.cst$sym$callback = new cljs.core.Symbol(null,"callback","callback",935395299,null);
cljs.core.cst$kw$matched = new cljs.core.Keyword(null,"matched","matched",-975207164);
cljs.core.cst$sym$i = new cljs.core.Symbol(null,"i","i",253690212,null);
cljs.core.cst$kw$api = new cljs.core.Keyword(null,"api","api",-899839580);
cljs.core.cst$sym$rest = new cljs.core.Symbol(null,"rest","rest",398835108,null);
cljs.core.cst$kw$original_DASH_text = new cljs.core.Keyword(null,"original-text","original-text",744448452);
cljs.core.cst$kw$namespaced_DASH_map = new cljs.core.Keyword(null,"namespaced-map","namespaced-map",1235665380);
cljs.core.cst$kw$meta = new cljs.core.Keyword(null,"meta","meta",1499536964);
cljs.core.cst$sym$p = new cljs.core.Symbol(null,"p","p",1791580836,null);
cljs.core.cst$sym$s_DASH_pos = new cljs.core.Symbol(null,"s-pos","s-pos",-540562492,null);
cljs.core.cst$kw$ul = new cljs.core.Keyword(null,"ul","ul",-1349521403);
cljs.core.cst$kw$kf = new cljs.core.Keyword(null,"kf","kf",1608087589);
cljs.core.cst$sym$rep_DASH_fn = new cljs.core.Symbol(null,"rep-fn","rep-fn",-1724891035,null);
cljs.core.cst$kw$mutes = new cljs.core.Keyword(null,"mutes","mutes",1068806309);
cljs.core.cst$kw$keywords_QMARK_ = new cljs.core.Keyword(null,"keywords?","keywords?",764949733);
cljs.core.cst$kw$dup = new cljs.core.Keyword(null,"dup","dup",556298533);
cljs.core.cst$sym$meta2240 = new cljs.core.Symbol(null,"meta2240","meta2240",-230975163,null);
cljs.core.cst$kw$solo = new cljs.core.Keyword(null,"solo","solo",-316350075);
cljs.core.cst$kw$li$message = new cljs.core.Keyword(null,"li.message","li.message",-992924155);
cljs.core.cst$kw$read = new cljs.core.Keyword(null,"read","read",1140058661);
cljs.core.cst$kw$key = new cljs.core.Keyword(null,"key","key",-1516042587);
cljs.core.cst$sym$comp = new cljs.core.Symbol(null,"comp","comp",-1462482139,null);
cljs.core.cst$sym$cljs$core_SLASH_array_DASH_map = new cljs.core.Symbol("cljs.core","array-map","cljs.core/array-map",-1519210683,null);
cljs.core.cst$sym$dispatch_DASH_fn = new cljs.core.Symbol(null,"dispatch-fn","dispatch-fn",-1401088155,null);
cljs.core.cst$kw$placeholder = new cljs.core.Keyword(null,"placeholder","placeholder",-104873083);
cljs.core.cst$sym$buffer = new cljs.core.Symbol(null,"buffer","buffer",-2037140571,null);
cljs.core.cst$kw$cljs$core$async_SLASH_nothing = new cljs.core.Keyword("cljs.core.async","nothing","cljs.core.async/nothing",-69252123);
cljs.core.cst$kw$index = new cljs.core.Keyword(null,"index","index",-1531685915);
cljs.core.cst$kw$i_SHARP_back$btn = new cljs.core.Keyword(null,"i#back.btn","i#back.btn",-1215314874);
cljs.core.cst$sym$prev_DASH_column = new cljs.core.Symbol(null,"prev-column","prev-column",324083974,null);
cljs.core.cst$kw$reader_DASH_exception = new cljs.core.Keyword(null,"reader-exception","reader-exception",-1938323098);
cljs.core.cst$kw$not_DASH_initialized = new cljs.core.Keyword(null,"not-initialized","not-initialized",-1937378906);
cljs.core.cst$kw$else = new cljs.core.Keyword(null,"else","else",-1508377146);
cljs.core.cst$sym$left = new cljs.core.Symbol(null,"left","left",1241415590,null);
cljs.core.cst$kw$li$todo_DASH_line = new cljs.core.Keyword(null,"li.todo-line","li.todo-line",-120685561);
cljs.core.cst$sym$ns_STAR_ = new cljs.core.Symbol(null,"ns*","ns*",1840949383,null);
cljs.core.cst$kw$failure = new cljs.core.Keyword(null,"failure","failure",720415879);
cljs.core.cst$kw$offset = new cljs.core.Keyword(null,"offset","offset",296498311);
cljs.core.cst$sym$path = new cljs.core.Symbol(null,"path","path",1452340359,null);
cljs.core.cst$kw$cljs$core_SLASH_none = new cljs.core.Keyword("cljs.core","none","cljs.core/none",926646439);
cljs.core.cst$sym$shift = new cljs.core.Symbol(null,"shift","shift",-1657295705,null);
cljs.core.cst$sym$cljs$core_SLASH_hash_DASH_map = new cljs.core.Symbol("cljs.core","hash-map","cljs.core/hash-map",303385767,null);
cljs.core.cst$sym$iters = new cljs.core.Symbol(null,"iters","iters",719353031,null);
cljs.core.cst$kw$derefed = new cljs.core.Keyword(null,"derefed","derefed",590684583);
cljs.core.cst$sym$meta10264 = new cljs.core.Symbol(null,"meta10264","meta10264",-212104601,null);
cljs.core.cst$sym$cljs$core_SLASH_apply = new cljs.core.Symbol("cljs.core","apply","cljs.core/apply",1757277831,null);
cljs.core.cst$kw$displayName = new cljs.core.Keyword(null,"displayName","displayName",-809144601);
cljs.core.cst$sym$args = new cljs.core.Symbol(null,"args","args",-1338879193,null);
cljs.core.cst$sym$active_QMARK_ = new cljs.core.Symbol(null,"active?","active?",2100031303,null);
cljs.core.cst$kw$span_SHARP_add_DASH_item$btn = new cljs.core.Keyword(null,"span#add-item.btn","span#add-item.btn",-776494201);
cljs.core.cst$sym$xform = new cljs.core.Symbol(null,"xform","xform",-85179481,null);
cljs.core.cst$kw$validator = new cljs.core.Keyword(null,"validator","validator",-1966190681);
cljs.core.cst$sym$finally = new cljs.core.Symbol(null,"finally","finally",-1065347064,null);
cljs.core.cst$kw$method = new cljs.core.Keyword(null,"method","method",55703592);
cljs.core.cst$sym$closed = new cljs.core.Symbol(null,"closed","closed",720856168,null);
cljs.core.cst$kw$content = new cljs.core.Keyword(null,"content","content",15833224);
cljs.core.cst$kw$raw = new cljs.core.Keyword(null,"raw","raw",1604651272);
cljs.core.cst$kw$default = new cljs.core.Keyword(null,"default","default",-1987822328);
cljs.core.cst$kw$cljsRender = new cljs.core.Keyword(null,"cljsRender","cljsRender",247449928);
cljs.core.cst$kw$finally_DASH_block = new cljs.core.Keyword(null,"finally-block","finally-block",832982472);
cljs.core.cst$sym$lists_DASH_page = new cljs.core.Symbol(null,"lists-page","lists-page",1789205992,null);
cljs.core.cst$sym$prefer_DASH_table = new cljs.core.Symbol(null,"prefer-table","prefer-table",462168584,null);
cljs.core.cst$sym$cb = new cljs.core.Symbol(null,"cb","cb",-2064487928,null);
cljs.core.cst$sym$cljs$core$async_SLASH_t_cljs$core$async10263 = new cljs.core.Symbol("cljs.core.async","t_cljs$core$async10263","cljs.core.async/t_cljs$core$async10263",-798337432,null);
cljs.core.cst$sym$loop_STAR_ = new cljs.core.Symbol(null,"loop*","loop*",615029416,null);
cljs.core.cst$sym$watches = new cljs.core.Symbol(null,"watches","watches",1367433992,null);
cljs.core.cst$kw$ns = new cljs.core.Keyword(null,"ns","ns",441598760);
cljs.core.cst$kw$symbol = new cljs.core.Keyword(null,"symbol","symbol",-1038572696);
cljs.core.cst$sym$buf_DASH_fn = new cljs.core.Symbol(null,"buf-fn","buf-fn",-1200281591,null);
cljs.core.cst$kw$name = new cljs.core.Keyword(null,"name","name",1843675177);
cljs.core.cst$sym$NaN = new cljs.core.Symbol(null,"NaN","NaN",666918153,null);
cljs.core.cst$kw$pending = new cljs.core.Keyword(null,"pending","pending",-220036727);
cljs.core.cst$sym$rdr = new cljs.core.Symbol(null,"rdr","rdr",190007785,null);
cljs.core.cst$sym$bitmap = new cljs.core.Symbol(null,"bitmap","bitmap",501334601,null);
cljs.core.cst$sym$_seq = new cljs.core.Symbol(null,"_seq","_seq",-449557847,null);
cljs.core.cst$sym$on_DASH_set = new cljs.core.Symbol(null,"on-set","on-set",1499578057,null);
cljs.core.cst$sym$nil_DASH_val = new cljs.core.Symbol(null,"nil-val","nil-val",-513933559,null);
cljs.core.cst$kw$value = new cljs.core.Keyword(null,"value","value",305978217);
cljs.core.cst$sym$solo_DASH_mode = new cljs.core.Symbol(null,"solo-mode","solo-mode",2031788074,null);
cljs.core.cst$sym$somef = new cljs.core.Symbol(null,"somef","somef",1017941162,null);
cljs.core.cst$sym$meta10267 = new cljs.core.Symbol(null,"meta10267","meta10267",90644714,null);
cljs.core.cst$kw$response_DASH_format = new cljs.core.Keyword(null,"response-format","response-format",1664465322);
cljs.core.cst$kw$status_DASH_text = new cljs.core.Keyword(null,"status-text","status-text",-1834235478);
cljs.core.cst$kw$component_DASH_did_DASH_mount = new cljs.core.Keyword(null,"component-did-mount","component-did-mount",-1126910518);
cljs.core.cst$kw$file = new cljs.core.Keyword(null,"file","file",-1269645878);
cljs.core.cst$kw$textarea$edit_DASH_item_DASH_text = new cljs.core.Keyword(null,"textarea.edit-item-text","textarea.edit-item-text",-615742998);
cljs.core.cst$kw$i_SHARP_add_DASH_item_DASH_done$btn = new cljs.core.Keyword(null,"i#add-item-done.btn","i#add-item-done.btn",-1088566806);
cljs.core.cst$sym$cljs$core_SLASH_concat = new cljs.core.Symbol("cljs.core","concat","cljs.core/concat",-1133584918,null);
cljs.core.cst$sym$v = new cljs.core.Symbol(null,"v","v",1661996586,null);
cljs.core.cst$kw$compute = new cljs.core.Keyword(null,"compute","compute",1555393130);
cljs.core.cst$sym$js = new cljs.core.Symbol(null,"js","js",-886355190,null);
cljs.core.cst$kw$readers = new cljs.core.Keyword(null,"readers","readers",-2118263030);
cljs.core.cst$kw$secretary$core_SLASH_map = new cljs.core.Keyword("secretary.core","map","secretary.core/map",-31086646);
cljs.core.cst$kw$end_DASH_column = new cljs.core.Keyword(null,"end-column","end-column",1425389514);
cljs.core.cst$sym$riter = new cljs.core.Symbol(null,"riter","riter",-237834262,null);
cljs.core.cst$sym$__hash = new cljs.core.Symbol(null,"__hash","__hash",-1328796629,null);
cljs.core.cst$sym$meta = new cljs.core.Symbol(null,"meta","meta",-1154898805,null);
cljs.core.cst$sym$_meta = new cljs.core.Symbol(null,"_meta","_meta",-1716892533,null);
cljs.core.cst$kw$aborted = new cljs.core.Keyword(null,"aborted","aborted",1775972619);
cljs.core.cst$kw$span$unchecked_DASH_count = new cljs.core.Keyword(null,"span.unchecked-count","span.unchecked-count",-408283861);
cljs.core.cst$sym$afn = new cljs.core.Symbol(null,"afn","afn",216963467,null);
cljs.core.cst$kw$processing_DASH_request = new cljs.core.Keyword(null,"processing-request","processing-request",-264947221);
cljs.core.cst$kw$params = new cljs.core.Keyword(null,"params","params",710516235);
cljs.core.cst$kw$p$warn = new cljs.core.Keyword(null,"p.warn","p.warn",-621694453);
cljs.core.cst$kw$on_DASH_blur = new cljs.core.Keyword(null,"on-blur","on-blur",814300747);
cljs.core.cst$sym$todos = new cljs.core.Symbol(null,"todos","todos",-2024126901,null);
cljs.core.cst$sym$tree = new cljs.core.Symbol(null,"tree","tree",1444219499,null);
cljs.core.cst$sym$fn = new cljs.core.Symbol(null,"fn","fn",465265323,null);
cljs.core.cst$kw$div_SHARP_loader = new cljs.core.Keyword(null,"div#loader","div#loader",418409131);
cljs.core.cst$sym$front = new cljs.core.Symbol(null,"front","front",117022539,null);
cljs.core.cst$sym$buf = new cljs.core.Symbol(null,"buf","buf",1426618187,null);
cljs.core.cst$sym$mults = new cljs.core.Symbol(null,"mults","mults",-461114485,null);
cljs.core.cst$kw$component_DASH_did_DASH_update = new cljs.core.Keyword(null,"component-did-update","component-did-update",-1468549173);
cljs.core.cst$sym$next_DASH_entry = new cljs.core.Symbol(null,"next-entry","next-entry",1091342476,null);
cljs.core.cst$kw$read_DASH_cond = new cljs.core.Keyword(null,"read-cond","read-cond",1056899244);
cljs.core.cst$kw$val = new cljs.core.Keyword(null,"val","val",128701612);
cljs.core.cst$sym$key = new cljs.core.Symbol(null,"key","key",124488940,null);
cljs.core.cst$sym$meta4886 = new cljs.core.Symbol(null,"meta4886","meta4886",-297171700,null);
cljs.core.cst$sym$_next = new cljs.core.Symbol(null,"_next","_next",101877036,null);
cljs.core.cst$sym$inst = new cljs.core.Symbol(null,"inst","inst",-2008473268,null);
cljs.core.cst$sym$fn1 = new cljs.core.Symbol(null,"fn1","fn1",895834444,null);
cljs.core.cst$kw$recur = new cljs.core.Keyword(null,"recur","recur",-437573268);
cljs.core.cst$kw$li$todo_DASH_link = new cljs.core.Keyword(null,"li.todo-link","li.todo-link",1015736716);
cljs.core.cst$kw$type = new cljs.core.Keyword(null,"type","type",1174270348);
cljs.core.cst$kw$request_DASH_received = new cljs.core.Keyword(null,"request-received","request-received",2110590540);
cljs.core.cst$sym$kf = new cljs.core.Symbol(null,"kf","kf",-1046348180,null);
cljs.core.cst$sym$omgnata$core_SLASH_lists_DASH_page = new cljs.core.Symbol("omgnata.core","lists-page","omgnata.core/lists-page",593904300,null);
cljs.core.cst$kw$catch_DASH_block = new cljs.core.Keyword(null,"catch-block","catch-block",1175212748);
cljs.core.cst$sym$root_DASH_iter = new cljs.core.Symbol(null,"root-iter","root-iter",1974672108,null);
cljs.core.cst$kw$delete = new cljs.core.Keyword(null,"delete","delete",-1768633620);
cljs.core.cst$kw$div_SHARP_list_DASH_edit_DASH_container = new cljs.core.Keyword(null,"div#list-edit-container","div#list-edit-container",500002636);
cljs.core.cst$sym$do = new cljs.core.Symbol(null,"do","do",1686842252,null);
cljs.core.cst$sym$vec = new cljs.core.Symbol(null,"vec","vec",982683596,null);
cljs.core.cst$sym$p__4883 = new cljs.core.Symbol(null,"p__4883","p__4883",2053661997,null);
cljs.core.cst$sym$add_BANG_ = new cljs.core.Symbol(null,"add!","add!",2046056845,null);
cljs.core.cst$kw$preserve = new cljs.core.Keyword(null,"preserve","preserve",1276846509);
cljs.core.cst$kw$fallback_DASH_impl = new cljs.core.Keyword(null,"fallback-impl","fallback-impl",-1501286995);
cljs.core.cst$kw$route = new cljs.core.Keyword(null,"route","route",329891309);
cljs.core.cst$kw$keyword_DASH_fn = new cljs.core.Keyword(null,"keyword-fn","keyword-fn",-64566675);
cljs.core.cst$sym$Inf = new cljs.core.Symbol(null,"Inf","Inf",647172781,null);
cljs.core.cst$kw$source = new cljs.core.Keyword(null,"source","source",-433931539);
cljs.core.cst$kw$handlers = new cljs.core.Keyword(null,"handlers","handlers",79528781);
cljs.core.cst$kw$flush_DASH_on_DASH_newline = new cljs.core.Keyword(null,"flush-on-newline","flush-on-newline",-151457939);
cljs.core.cst$kw$finished = new cljs.core.Keyword(null,"finished","finished",-1018867731);
cljs.core.cst$sym$default_DASH_dispatch_DASH_val = new cljs.core.Symbol(null,"default-dispatch-val","default-dispatch-val",-1231201266,null);
cljs.core.cst$kw$componentWillUnmount = new cljs.core.Keyword(null,"componentWillUnmount","componentWillUnmount",1573788814);
cljs.core.cst$kw$no_DASH_test = new cljs.core.Keyword(null,"no-test","no-test",-1679482642);
cljs.core.cst$kw$string = new cljs.core.Keyword(null,"string","string",-1989541586);
cljs.core.cst$sym$queue = new cljs.core.Symbol(null,"queue","queue",-1198599890,null);
cljs.core.cst$sym$_ = new cljs.core.Symbol(null,"_","_",-1201019570,null);
cljs.core.cst$kw$vector = new cljs.core.Keyword(null,"vector","vector",1902966158);
cljs.core.cst$sym$validator = new cljs.core.Symbol(null,"validator","validator",-325659154,null);
cljs.core.cst$kw$illegal_DASH_argument = new cljs.core.Keyword(null,"illegal-argument","illegal-argument",-1845493170);
cljs.core.cst$sym$letfn_STAR_ = new cljs.core.Symbol(null,"letfn*","letfn*",-110097810,null);
cljs.core.cst$kw$cljs$analyzer_SLASH_analyzed = new cljs.core.Keyword("cljs.analyzer","analyzed","cljs.analyzer/analyzed",-735094162);
cljs.core.cst$sym$meta8924 = new cljs.core.Symbol(null,"meta8924","meta8924",1531656878,null);
cljs.core.cst$sym$if = new cljs.core.Symbol(null,"if","if",1181717262,null);
cljs.core.cst$sym$readable = new cljs.core.Symbol(null,"readable","readable",2113054478,null);
cljs.core.cst$kw$parse_DASH_error = new cljs.core.Keyword(null,"parse-error","parse-error",255902478);
cljs.core.cst$sym$cljs$core_SLASH_with_DASH_meta = new cljs.core.Symbol("cljs.core","with-meta","cljs.core/with-meta",749126446,null);
cljs.core.cst$sym$finally_DASH_block = new cljs.core.Symbol(null,"finally-block","finally-block",-1821453297,null);
cljs.core.cst$sym$arr = new cljs.core.Symbol(null,"arr","arr",2115492975,null);
cljs.core.cst$sym$new = new cljs.core.Symbol(null,"new","new",-444906321,null);
cljs.core.cst$kw$on_DASH_click = new cljs.core.Keyword(null,"on-click","on-click",1632826543);
cljs.core.cst$kw$strable = new cljs.core.Keyword(null,"strable","strable",1877668047);
cljs.core.cst$kw$descendants = new cljs.core.Keyword(null,"descendants","descendants",1824886031);
cljs.core.cst$kw$allow = new cljs.core.Keyword(null,"allow","allow",-1857325745);
cljs.core.cst$sym$ns = new cljs.core.Symbol(null,"ns","ns",2082130287,null);
cljs.core.cst$kw$title = new cljs.core.Keyword(null,"title","title",636505583);
cljs.core.cst$kw$sym = new cljs.core.Keyword(null,"sym","sym",-1444860305);
cljs.core.cst$kw$prefix = new cljs.core.Keyword(null,"prefix","prefix",-265908465);
cljs.core.cst$kw$column = new cljs.core.Keyword(null,"column","column",2078222095);
cljs.core.cst$sym$pick = new cljs.core.Symbol(null,"pick","pick",1300068175,null);
cljs.core.cst$kw$headers = new cljs.core.Keyword(null,"headers","headers",-835030129);
cljs.core.cst$kw$i$checkbox$btn = new cljs.core.Keyword(null,"i.checkbox.btn","i.checkbox.btn",15892367);
cljs.core.cst$sym$completed = new cljs.core.Symbol(null,"completed","completed",1154475024,null);
cljs.core.cst$sym$forward = new cljs.core.Symbol(null,"forward","forward",1083186224,null);
cljs.core.cst$kw$div$message = new cljs.core.Keyword(null,"div.message","div.message",197515312);
cljs.core.cst$kw$shouldComponentUpdate = new cljs.core.Keyword(null,"shouldComponentUpdate","shouldComponentUpdate",1795750960);
cljs.core.cst$kw$error_DASH_handler = new cljs.core.Keyword(null,"error-handler","error-handler",-484945776);
cljs.core.cst$kw$ancestors = new cljs.core.Keyword(null,"ancestors","ancestors",-776045424);
cljs.core.cst$sym$flag = new cljs.core.Symbol(null,"flag","flag",-1565787888,null);
cljs.core.cst$kw$style = new cljs.core.Keyword(null,"style","style",-496642736);
cljs.core.cst$sym$ensure_DASH_mult = new cljs.core.Symbol(null,"ensure-mult","ensure-mult",1796584816,null);
cljs.core.cst$sym$value = new cljs.core.Symbol(null,"value","value",1946509744,null);
cljs.core.cst$kw$write = new cljs.core.Keyword(null,"write","write",-1857649168);
cljs.core.cst$sym$name = new cljs.core.Symbol(null,"name","name",-810760592,null);
cljs.core.cst$sym$meta9735 = new cljs.core.Symbol(null,"meta9735","meta9735",-1978445200,null);
cljs.core.cst$sym$map__4884 = new cljs.core.Symbol(null,"map__4884","map__4884",-1688549712,null);
cljs.core.cst$sym$n = new cljs.core.Symbol(null,"n","n",-2092305744,null);
cljs.core.cst$kw$div = new cljs.core.Keyword(null,"div","div",1057191632);
cljs.core.cst$sym$frames = new cljs.core.Symbol(null,"frames","frames",-888748272,null);
cljs.core.cst$kw$readably = new cljs.core.Keyword(null,"readably","readably",1129599760);
cljs.core.cst$kw$more_DASH_marker = new cljs.core.Keyword(null,"more-marker","more-marker",-14717935);
cljs.core.cst$kw$span$btn$handle$fa_DASH_stack = new cljs.core.Keyword(null,"span.btn.handle.fa-stack","span.btn.handle.fa-stack",-1487675343);
cljs.core.cst$sym$fields = new cljs.core.Symbol(null,"fields","fields",-291534703,null);
cljs.core.cst$sym$re = new cljs.core.Symbol(null,"re","re",1869207729,null);
cljs.core.cst$sym$scheduled_QMARK_ = new cljs.core.Symbol(null,"scheduled?","scheduled?",579986609,null);
cljs.core.cst$kw$i$btn$delete_DASH_item = new cljs.core.Keyword(null,"i.btn.delete-item","i.btn.delete-item",982327537);
cljs.core.cst$sym$method_DASH_cache = new cljs.core.Symbol(null,"method-cache","method-cache",1230193905,null);
cljs.core.cst$sym$cs = new cljs.core.Symbol(null,"cs","cs",-117024463,null);
cljs.core.cst$kw$div_SHARP_add_DASH_item_DASH_container = new cljs.core.Keyword(null,"div#add-item-container","div#add-item-container",1139529041);
cljs.core.cst$sym$dirty_QMARK_ = new cljs.core.Symbol(null,"dirty?","dirty?",-419314319,null);
cljs.core.cst$sym$orig_DASH_route = new cljs.core.Symbol(null,"orig-route","orig-route",899103121,null);
cljs.core.cst$kw$reagentRender = new cljs.core.Keyword(null,"reagentRender","reagentRender",-358306383);
cljs.core.cst$kw$filename = new cljs.core.Keyword(null,"filename","filename",-1428840783);
cljs.core.cst$sym$meta10275 = new cljs.core.Symbol(null,"meta10275","meta10275",1969594161,null);
cljs.core.cst$sym$edit = new cljs.core.Symbol(null,"edit","edit",-1302639,null);
cljs.core.cst$sym$meta3381 = new cljs.core.Symbol(null,"meta3381","meta3381",999308338,null);
cljs.core.cst$sym$params = new cljs.core.Symbol(null,"params","params",-1943919534,null);
cljs.core.cst$sym$editable_QMARK_ = new cljs.core.Symbol(null,"editable?","editable?",-164945806,null);
cljs.core.cst$sym$base_DASH_count = new cljs.core.Symbol(null,"base-count","base-count",-1180647182,null);
cljs.core.cst$sym$verbose_DASH_handler_DASH_fn = new cljs.core.Symbol(null,"verbose-handler-fn","verbose-handler-fn",547340594,null);
cljs.core.cst$kw$render = new cljs.core.Keyword(null,"render","render",-1408033454);
cljs.core.cst$kw$illegal_DASH_state = new cljs.core.Keyword(null,"illegal-state","illegal-state",-1519851182);
cljs.core.cst$sym$clojure$core_SLASH_unquote_DASH_splicing = new cljs.core.Symbol("clojure.core","unquote-splicing","clojure.core/unquote-splicing",-552003150,null);
cljs.core.cst$sym$collision_DASH_hash = new cljs.core.Symbol(null,"collision-hash","collision-hash",-35831342,null);
cljs.core.cst$sym$deftype_STAR_ = new cljs.core.Symbol(null,"deftype*","deftype*",962659890,null);
cljs.core.cst$sym$let_STAR_ = new cljs.core.Symbol(null,"let*","let*",1920721458,null);
cljs.core.cst$sym$meta8945 = new cljs.core.Symbol(null,"meta8945","meta8945",1831858866,null);
cljs.core.cst$sym$start = new cljs.core.Symbol(null,"start","start",1285322546,null);
cljs.core.cst$kw$splicing_QMARK_ = new cljs.core.Keyword(null,"splicing?","splicing?",-428596366);
cljs.core.cst$sym$sourceIter = new cljs.core.Symbol(null,"sourceIter","sourceIter",1068220306,null);
cljs.core.cst$sym$coll = new cljs.core.Symbol(null,"coll","coll",-1006698606,null);
cljs.core.cst$sym$not_DASH_native = new cljs.core.Symbol(null,"not-native","not-native",-236392494,null);
cljs.core.cst$sym$js_STAR_ = new cljs.core.Symbol(null,"js*","js*",-1134233646,null);
cljs.core.cst$kw$details = new cljs.core.Keyword(null,"details","details",1956795411);
cljs.core.cst$kw$reagent_DASH_render = new cljs.core.Keyword(null,"reagent-render","reagent-render",-985383853);
cljs.core.cst$sym$strobj = new cljs.core.Symbol(null,"strobj","strobj",1088091283,null);
cljs.core.cst$sym$todo_DASH_page = new cljs.core.Symbol(null,"todo-page","todo-page",1011891,null);
cljs.core.cst$sym$catch_DASH_block = new cljs.core.Symbol(null,"catch-block","catch-block",-1479223021,null);
cljs.core.cst$sym$omgnata$core = new cljs.core.Symbol(null,"omgnata.core","omgnata.core",-1309113965,null);
cljs.core.cst$kw$line = new cljs.core.Keyword(null,"line","line",212345235);
cljs.core.cst$kw$priority = new cljs.core.Keyword(null,"priority","priority",1431093715);
cljs.core.cst$kw$solos = new cljs.core.Keyword(null,"solos","solos",1441458643);
cljs.core.cst$sym$_rest = new cljs.core.Symbol(null,"_rest","_rest",-2100466189,null);
cljs.core.cst$sym$meta1395 = new cljs.core.Symbol(null,"meta1395","meta1395",-1131043213,null);
cljs.core.cst$kw$list = new cljs.core.Keyword(null,"list","list",765357683);
cljs.core.cst$sym$fn_STAR_ = new cljs.core.Symbol(null,"fn*","fn*",-752876845,null);
cljs.core.cst$sym$val = new cljs.core.Symbol(null,"val","val",1769233139,null);
cljs.core.cst$kw$keyword = new cljs.core.Keyword(null,"keyword","keyword",811389747);
cljs.core.cst$sym$ascending_QMARK_ = new cljs.core.Symbol(null,"ascending?","ascending?",-1938452653,null);
cljs.core.cst$sym$recur = new cljs.core.Symbol(null,"recur","recur",1202958259,null);
cljs.core.cst$sym$xf = new cljs.core.Symbol(null,"xf","xf",2042434515,null);
cljs.core.cst$sym$ci = new cljs.core.Symbol(null,"ci","ci",2049808339,null);
cljs.core.cst$kw$status = new cljs.core.Keyword(null,"status","status",-1997798413);
cljs.core.cst$kw$span_SHARP_add_DASH_list$btn = new cljs.core.Keyword(null,"span#add-list.btn","span#add-list.btn",-1477394412);
cljs.core.cst$kw$response_DASH_ready = new cljs.core.Keyword(null,"response-ready","response-ready",245208276);
cljs.core.cst$kw$print_DASH_length = new cljs.core.Keyword(null,"print-length","print-length",1931866356);
cljs.core.cst$kw$writer = new cljs.core.Keyword(null,"writer","writer",-277568236);
cljs.core.cst$kw$col = new cljs.core.Keyword(null,"col","col",-1959363084);
cljs.core.cst$kw$on_DASH_double_DASH_click = new cljs.core.Keyword(null,"on-double-click","on-double-click",1434856980);
cljs.core.cst$kw$id = new cljs.core.Keyword(null,"id","id",-1388402092);
cljs.core.cst$sym$ratom = new cljs.core.Symbol(null,"ratom","ratom",1514010260,null);
cljs.core.cst$kw$i$btn$update_DASH_item_DASH_done = new cljs.core.Keyword(null,"i.btn.update-item-done","i.btn.update-item-done",-366159180);
cljs.core.cst$kw$class = new cljs.core.Keyword(null,"class","class",-2030961996);
cljs.core.cst$sym$state = new cljs.core.Symbol(null,"state","state",-348086572,null);
cljs.core.cst$kw$ok = new cljs.core.Keyword(null,"ok","ok",967785236);
cljs.core.cst$sym$vals = new cljs.core.Symbol(null,"vals","vals",-1886377036,null);
cljs.core.cst$sym$all = new cljs.core.Symbol(null,"all","all",-1762306027,null);
cljs.core.cst$sym$clojure$core_SLASH_deref = new cljs.core.Symbol("clojure.core","deref","clojure.core/deref",188719157,null);
cljs.core.cst$kw$catch_DASH_exception = new cljs.core.Keyword(null,"catch-exception","catch-exception",-1997306795);
cljs.core.cst$kw$cljs$core_SLASH_halt = new cljs.core.Keyword("cljs.core","halt","cljs.core/halt",-1049036715);
cljs.core.cst$kw$nil = new cljs.core.Keyword(null,"nil","nil",99600501);
cljs.core.cst$sym$timestamps = new cljs.core.Symbol(null,"timestamps","timestamps",819472597,null);
cljs.core.cst$sym$cached_DASH_hierarchy = new cljs.core.Symbol(null,"cached-hierarchy","cached-hierarchy",-1085460203,null);
cljs.core.cst$sym$header = new cljs.core.Symbol(null,"header","header",1759972661,null);
cljs.core.cst$kw$auto_DASH_run = new cljs.core.Keyword(null,"auto-run","auto-run",1958400437);
cljs.core.cst$kw$reader = new cljs.core.Keyword(null,"reader","reader",169660853);
cljs.core.cst$kw$checked = new cljs.core.Keyword(null,"checked","checked",-50955819);
cljs.core.cst$sym$s = new cljs.core.Symbol(null,"s","s",-948495851,null);
cljs.core.cst$kw$cljsName = new cljs.core.Keyword(null,"cljsName","cljsName",999824949);
cljs.core.cst$kw$parents = new cljs.core.Keyword(null,"parents","parents",-2027538891);
cljs.core.cst$sym$cnt = new cljs.core.Symbol(null,"cnt","cnt",1924510325,null);
cljs.core.cst$kw$parse = new cljs.core.Keyword(null,"parse","parse",-1162164619);
cljs.core.cst$sym$_SLASH_ = new cljs.core.Symbol(null,"/","/",-1371932971,null);
cljs.core.cst$kw$initk = new cljs.core.Keyword(null,"initk","initk",-1693342987);
cljs.core.cst$sym$meta10820 = new cljs.core.Symbol(null,"meta10820","meta10820",179373909,null);
cljs.core.cst$sym$node = new cljs.core.Symbol(null,"node","node",-2073234571,null);
cljs.core.cst$kw$component_DASH_will_DASH_unmount = new cljs.core.Keyword(null,"component-will-unmount","component-will-unmount",-2058314698);
cljs.core.cst$kw$prev = new cljs.core.Keyword(null,"prev","prev",-1597069226);
cljs.core.cst$sym$sym = new cljs.core.Symbol(null,"sym","sym",195671222,null);
cljs.core.cst$sym$column = new cljs.core.Symbol(null,"column","column",-576213674,null);
cljs.core.cst$kw$url = new cljs.core.Keyword(null,"url","url",276297046);
cljs.core.cst$sym$sb = new cljs.core.Symbol(null,"sb","sb",-1249746442,null);
cljs.core.cst$kw$continue_DASH_block = new cljs.core.Keyword(null,"continue-block","continue-block",-1852047850);
cljs.core.cst$sym$clojure$core_SLASH_unquote = new cljs.core.Symbol("clojure.core","unquote","clojure.core/unquote",843087510,null);
cljs.core.cst$kw$query_DASH_params = new cljs.core.Keyword(null,"query-params","query-params",900640534);
cljs.core.cst$sym$seed = new cljs.core.Symbol(null,"seed","seed",1709144854,null);
cljs.core.cst$kw$content_DASH_type = new cljs.core.Keyword(null,"content-type","content-type",-508222634);
cljs.core.cst$sym$ch = new cljs.core.Symbol(null,"ch","ch",1085813622,null);
cljs.core.cst$sym$level = new cljs.core.Symbol(null,"level","level",-1363938217,null);
cljs.core.cst$kw$end_DASH_line = new cljs.core.Keyword(null,"end-line","end-line",1837326455);
cljs.core.cst$kw$auto_DASH_focus = new cljs.core.Keyword(null,"auto-focus","auto-focus",1250006231);
cljs.core.cst$sym$prev_DASH_seed = new cljs.core.Symbol(null,"prev-seed","prev-seed",2126381367,null);
cljs.core.cst$kw$_DASH_elem_DASH_count = new cljs.core.Keyword(null,"-elem-count","-elem-count",663797079);
cljs.core.cst$sym$buf_DASH_pos = new cljs.core.Symbol(null,"buf-pos","buf-pos",-807229033,null);
cljs.core.cst$kw$max_DASH_retries = new cljs.core.Keyword(null,"max-retries","max-retries",-1933762121);
cljs.core.cst$kw$display_DASH_name = new cljs.core.Keyword(null,"display-name","display-name",694513143);
cljs.core.cst$kw$h3$list_DASH_title = new cljs.core.Keyword(null,"h3.list-title","h3.list-title",345558615);
cljs.core.cst$sym$omgnata$core_SLASH_todo_DASH_page = new cljs.core.Symbol("omgnata.core","todo-page","omgnata.core/todo-page",-1085648265,null);
cljs.core.cst$sym$cljs$core_SLASH_vec = new cljs.core.Symbol("cljs.core","vec","cljs.core/vec",307622519,null);
cljs.core.cst$kw$post = new cljs.core.Keyword(null,"post","post",269697687);
cljs.core.cst$sym$_DASH_Inf = new cljs.core.Symbol(null,"-Inf","-Inf",-2123243689,null);
cljs.core.cst$kw$div$todo_DASH_text = new cljs.core.Keyword(null,"div.todo-text","div.todo-text",-1124244424);
cljs.core.cst$sym$str_DASH_rep_DASH_fn = new cljs.core.Symbol(null,"str-rep-fn","str-rep-fn",-1179615016,null);
cljs.core.cst$sym$_hash = new cljs.core.Symbol(null,"_hash","_hash",-2130838312,null);
cljs.core.cst$sym$filename = new cljs.core.Symbol(null,"filename","filename",211690744,null);
cljs.core.cst$kw$on_DASH_dispose = new cljs.core.Keyword(null,"on-dispose","on-dispose",2105306360);
cljs.core.cst$kw$action = new cljs.core.Keyword(null,"action","action",-811238024);
cljs.core.cst$sym$calc_DASH_state = new cljs.core.Symbol(null,"calc-state","calc-state",-349968968,null);
cljs.core.cst$sym$cljs$core_SLASH_sequence = new cljs.core.Symbol("cljs.core","sequence","cljs.core/sequence",1908459032,null);
cljs.core.cst$kw$pause = new cljs.core.Keyword(null,"pause","pause",-2095325672);
cljs.core.cst$kw$error = new cljs.core.Keyword(null,"error","error",-978969032);
cljs.core.cst$kw$regex = new cljs.core.Keyword(null,"regex","regex",939488856);
cljs.core.cst$kw$componentFunction = new cljs.core.Keyword(null,"componentFunction","componentFunction",825866104);
cljs.core.cst$sym$topic_DASH_fn = new cljs.core.Symbol(null,"topic-fn","topic-fn",-862449736,null);
cljs.core.cst$kw$i_SHARP_clear_DASH_completed$btn = new cljs.core.Keyword(null,"i#clear-completed.btn","i#clear-completed.btn",2100368344);
cljs.core.cst$sym$head = new cljs.core.Symbol(null,"head","head",869147608,null);
cljs.core.cst$kw$exception = new cljs.core.Keyword(null,"exception","exception",-335277064);
cljs.core.cst$sym$keys = new cljs.core.Symbol(null,"keys","keys",-1586012071,null);
cljs.core.cst$sym$meta5714 = new cljs.core.Symbol(null,"meta5714","meta5714",269087833,null);
cljs.core.cst$sym$vec__10816 = new cljs.core.Symbol(null,"vec__10816","vec__10816",-1184809767,null);
cljs.core.cst$sym$set_BANG_ = new cljs.core.Symbol(null,"set!","set!",250714521,null);
cljs.core.cst$kw$unsupported_DASH_operation = new cljs.core.Keyword(null,"unsupported-operation","unsupported-operation",1890540953);
cljs.core.cst$sym$splicing_QMARK_ = new cljs.core.Symbol(null,"splicing?","splicing?",1211935161,null);
cljs.core.cst$kw$uri = new cljs.core.Keyword(null,"uri","uri",-774711847);
cljs.core.cst$kw$form = new cljs.core.Keyword(null,"form","form",-1624062471);
cljs.core.cst$kw$tag = new cljs.core.Keyword(null,"tag","tag",-1290361223);
cljs.core.cst$sym$tree_DASH_map = new cljs.core.Symbol(null,"tree-map","tree-map",1373073049,null);
cljs.core.cst$sym$meta9433 = new cljs.core.Symbol(null,"meta9433","meta9433",-1569560807,null);
cljs.core.cst$kw$input = new cljs.core.Keyword(null,"input","input",556931961);
cljs.core.cst$kw$secretary$core_SLASH_sequential = new cljs.core.Keyword("secretary.core","sequential","secretary.core/sequential",-347187207);
cljs.core.cst$sym$_DOT_ = new cljs.core.Symbol(null,".",".",1975675962,null);
cljs.core.cst$sym$var = new cljs.core.Symbol(null,"var","var",870848730,null);
cljs.core.cst$kw$mutable = new cljs.core.Keyword(null,"mutable","mutable",875778266);
cljs.core.cst$kw$json = new cljs.core.Keyword(null,"json","json",1279968570);
cljs.core.cst$sym$tag_DASH_fn = new cljs.core.Symbol(null,"tag-fn","tag-fn",242055482,null);
cljs.core.cst$sym$quote = new cljs.core.Symbol(null,"quote","quote",1377916282,null);
cljs.core.cst$kw$set = new cljs.core.Keyword(null,"set","set",304602554);
cljs.core.cst$kw$timeout = new cljs.core.Keyword(null,"timeout","timeout",-318625318);
cljs.core.cst$sym$line_DASH_start_QMARK_ = new cljs.core.Symbol(null,"line-start?","line-start?",1357012474,null);
cljs.core.cst$sym$root = new cljs.core.Symbol(null,"root","root",1191874074,null);
cljs.core.cst$sym$dirty_DASH_takes = new cljs.core.Symbol(null,"dirty-takes","dirty-takes",575642138,null);
cljs.core.cst$sym$multi = new cljs.core.Symbol(null,"multi","multi",1450238522,null);
cljs.core.cst$sym$str = new cljs.core.Symbol(null,"str","str",-1564826950,null);
cljs.core.cst$sym$next = new cljs.core.Symbol(null,"next","next",1522830042,null);
cljs.core.cst$kw$i$delete_DASH_list$btn = new cljs.core.Keyword(null,"i.delete-list.btn","i.delete-list.btn",-1371286758);
cljs.core.cst$sym$nodes = new cljs.core.Symbol(null,"nodes","nodes",-459054278,null);
cljs.core.cst$sym$seen = new cljs.core.Symbol(null,"seen","seen",1121531738,null);
cljs.core.cst$sym$hash_DASH_map = new cljs.core.Symbol(null,"hash-map","hash-map",-439030950,null);
cljs.core.cst$kw$arglists = new cljs.core.Keyword(null,"arglists","arglists",1661989754);
cljs.core.cst$sym$line = new cljs.core.Symbol(null,"line","line",1852876762,null);
cljs.core.cst$sym$out = new cljs.core.Symbol(null,"out","out",729986010,null);
cljs.core.cst$kw$vf = new cljs.core.Keyword(null,"vf","vf",-321423269);
cljs.core.cst$kw$on_DASH_change = new cljs.core.Keyword(null,"on-change","on-change",-732046149);
cljs.core.cst$sym$p__2237 = new cljs.core.Symbol(null,"p__2237","p__2237",1307436219,null);
cljs.core.cst$kw$eof = new cljs.core.Keyword(null,"eof","eof",-489063237);
cljs.core.cst$kw$hierarchy = new cljs.core.Keyword(null,"hierarchy","hierarchy",-1053470341);
cljs.core.cst$sym$catch = new cljs.core.Symbol(null,"catch","catch",-1616370245,null);
cljs.core.cst$kw$timestamp = new cljs.core.Keyword(null,"timestamp","timestamp",579478971);
cljs.core.cst$kw$on_DASH_key_DASH_down = new cljs.core.Keyword(null,"on-key-down","on-key-down",-1374733765);
cljs.core.cst$kw$connection_DASH_established = new cljs.core.Keyword(null,"connection-established","connection-established",-1403749733);
cljs.core.cst$sym$s_DASH_len = new cljs.core.Symbol(null,"s-len","s-len",1869978331,null);
cljs.core.cst$kw$alt_DASH_impl = new cljs.core.Keyword(null,"alt-impl","alt-impl",670969595);
cljs.core.cst$sym$ext_DASH_map_DASH_iter = new cljs.core.Symbol(null,"ext-map-iter","ext-map-iter",-1215982757,null);
cljs.core.cst$sym$tail = new cljs.core.Symbol(null,"tail","tail",494507963,null);
cljs.core.cst$kw$doc = new cljs.core.Keyword(null,"doc","doc",1913296891);
cljs.core.cst$sym$file_DASH_name = new cljs.core.Symbol(null,"file-name","file-name",-13685732,null);
cljs.core.cst$sym$record = new cljs.core.Symbol(null,"record","record",861424668,null);
cljs.core.cst$sym$changed = new cljs.core.Symbol(null,"changed","changed",-2083710852,null);
cljs.core.cst$sym$mseq = new cljs.core.Symbol(null,"mseq","mseq",1602647196,null);
cljs.core.cst$sym$count = new cljs.core.Symbol(null,"count","count",-514511684,null);
cljs.core.cst$sym$dirty_DASH_puts = new cljs.core.Symbol(null,"dirty-puts","dirty-puts",57041148,null);
cljs.core.cst$sym$initk = new cljs.core.Symbol(null,"initk","initk",-52811460,null);
cljs.core.cst$sym$solo_DASH_modes = new cljs.core.Symbol(null,"solo-modes","solo-modes",882180540,null);
cljs.core.cst$sym$catch_DASH_exception = new cljs.core.Symbol(null,"catch-exception","catch-exception",-356775268,null);
cljs.core.cst$kw$handler = new cljs.core.Keyword(null,"handler","handler",-195596612);
cljs.core.cst$kw$keywordize_DASH_keys = new cljs.core.Keyword(null,"keywordize-keys","keywordize-keys",1310784252);
cljs.core.cst$sym$takes = new cljs.core.Symbol(null,"takes","takes",298247964,null);
cljs.core.cst$sym$current = new cljs.core.Symbol(null,"current","current",552492924,null);
cljs.core.cst$sym$off = new cljs.core.Symbol(null,"off","off",-2047994980,null);
cljs.core.cst$kw$current_DASH_page = new cljs.core.Keyword(null,"current-page","current-page",-101294180);
cljs.core.cst$kw$textarea$add_DASH_item_DASH_text = new cljs.core.Keyword(null,"textarea.add-item-text","textarea.add-item-text",1628747740);
cljs.core.cst$sym$auto_DASH_run = new cljs.core.Symbol(null,"auto-run","auto-run",-696035332,null);
cljs.core.cst$sym$length = new cljs.core.Symbol(null,"length","length",-2065447907,null);
cljs.core.cst$sym$continue_DASH_block = new cljs.core.Symbol(null,"continue-block","continue-block",-211516323,null);
cljs.core.cst$sym$stack = new cljs.core.Symbol(null,"stack","stack",847125597,null);
cljs.core.cst$kw$p = new cljs.core.Keyword(null,"p","p",151049309);
cljs.core.cst$sym$cljs$core_SLASH_hash_DASH_set = new cljs.core.Symbol("cljs.core","hash-set","cljs.core/hash-set",1130426749,null);
cljs.core.cst$sym$transient_DASH_map = new cljs.core.Symbol(null,"transient-map","transient-map",351764893,null);
cljs.core.cst$kw$character = new cljs.core.Keyword(null,"character","character",380652989);
cljs.core.cst$kw$map = new cljs.core.Keyword(null,"map","map",1371690461);
cljs.core.cst$sym$cljs$core_SLASH_list = new cljs.core.Symbol("cljs.core","list","cljs.core/list",-1331406371,null);
cljs.core.cst$kw$eofthrow = new cljs.core.Keyword(null,"eofthrow","eofthrow",-334166531);
cljs.core.cst$sym$map__2238 = new cljs.core.Symbol(null,"map__2238","map__2238",-1136596483,null);
cljs.core.cst$kw$with_DASH_credentials = new cljs.core.Keyword(null,"with-credentials","with-credentials",-1163127235);
cljs.core.cst$sym$prev = new cljs.core.Symbol(null,"prev","prev",43462301,null);
cljs.core.cst$sym$len = new cljs.core.Symbol(null,"len","len",-1230778691,null);
cljs.core.cst$sym$meta8785 = new cljs.core.Symbol(null,"meta8785","meta8785",1337781949,null);
cljs.core.cst$kw$componentWillMount = new cljs.core.Keyword(null,"componentWillMount","componentWillMount",-285327619);
cljs.core.cst$kw$i = new cljs.core.Keyword(null,"i","i",-1386841315);
cljs.core.cst$kw$test = new cljs.core.Keyword(null,"test","test",577538877);
cljs.core.cst$kw$span$edit_DASH_mode = new cljs.core.Keyword(null,"span.edit-mode","span.edit-mode",-1495820483);
cljs.core.cst$sym$right = new cljs.core.Symbol(null,"right","right",1187949694,null);
cljs.core.cst$sym$buf_DASH_len = new cljs.core.Symbol(null,"buf-len","buf-len",404510846,null);
cljs.core.cst$kw$runtime_DASH_exception = new cljs.core.Keyword(null,"runtime-exception","runtime-exception",-1495664514);
cljs.core.cst$sym$meta5887 = new cljs.core.Symbol(null,"meta5887","meta5887",314048670,null);
cljs.core.cst$sym$throw = new cljs.core.Symbol(null,"throw","throw",595905694,null);
cljs.core.cst$kw$none = new cljs.core.Keyword(null,"none","none",1333468478);
cljs.core.cst$kw$buffer = new cljs.core.Keyword(null,"buffer","buffer",617295198);
cljs.core.cst$kw$poller_DASH_time = new cljs.core.Keyword(null,"poller-time","poller-time",364073438);
cljs.core.cst$sym$fseq = new cljs.core.Symbol(null,"fseq","fseq",-1466412450,null);
cljs.core.cst$sym$meta9892 = new cljs.core.Symbol(null,"meta9892","meta9892",483024702,null);
cljs.core.cst$kw$mute = new cljs.core.Keyword(null,"mute","mute",1151223646);
cljs.core.cst$sym$chunk_DASH_next = new cljs.core.Symbol(null,"chunk-next","chunk-next",-547810434,null);
cljs.core.cst$sym$attrs = new cljs.core.Symbol(null,"attrs","attrs",-450137186,null);
cljs.core.cst$kw$cljs$core_SLASH_not_DASH_found = new cljs.core.Keyword("cljs.core","not-found","cljs.core/not-found",-1572889185);
cljs.core.cst$sym$more = new cljs.core.Symbol(null,"more","more",-418290273,null);
cljs.core.cst$sym$def = new cljs.core.Symbol(null,"def","def",597100991,null);
cljs.core.cst$kw$span = new cljs.core.Keyword(null,"span","span",1394872991);
cljs.core.cst$kw$reads = new cljs.core.Keyword(null,"reads","reads",-1215067361);
cljs.core.cst$sym$on_DASH_dispose = new cljs.core.Symbol(null,"on-dispose","on-dispose",-549129409,null);
cljs.core.cst$sym$f = new cljs.core.Symbol(null,"f","f",43394975,null);
cljs.core.cst$sym$next_DASH_iter = new cljs.core.Symbol(null,"next-iter","next-iter",1526626239,null);
+214
View File
@@ -0,0 +1,214 @@
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns cljs.reader
(:require-macros [cljs.reader :refer [add-data-readers]])
(:require [goog.object :as gobject]
[cljs.tools.reader :as treader]
[cljs.tools.reader.edn :as edn])
(:import [goog.string StringBuffer]))
(defn ^:private zero-fill-right-and-truncate [s width]
(cond
(= width (count s)) s
(< width (count s)) (subs s 0 width)
:else
(loop [b (StringBuffer. s)]
(if (< (.getLength b) width)
(recur (.append b "0"))
(.toString b)))))
(defn ^:private divisible?
[num div]
(zero? (mod num div)))
(defn ^:private indivisible?
[num div]
(not (divisible? num div)))
(defn ^:private leap-year?
[year]
(and (divisible? year 4)
(or (indivisible? year 100)
(divisible? year 400))))
(def ^:private days-in-month
(let [dim-norm [nil 31 28 31 30 31 30 31 31 30 31 30 31]
dim-leap [nil 31 29 31 30 31 30 31 31 30 31 30 31]]
(fn [month leap-year?]
(get (if leap-year? dim-leap dim-norm) month))))
(def ^:private timestamp-regex #"(\d\d\d\d)(?:-(\d\d)(?:-(\d\d)(?:[T](\d\d)(?::(\d\d)(?::(\d\d)(?:[.](\d+))?)?)?)?)?)?(?:[Z]|([-+])(\d\d):(\d\d))?")
(defn ^:private parse-int [s]
(let [n (js/parseInt s 10)]
(if-not (js/isNaN n)
n)))
(defn ^:private check [low n high msg]
(when-not (<= low n high)
(throw (js/Error. (str msg " Failed: " low "<=" n "<=" high))))
n)
(defn parse-and-validate-timestamp [s]
(let [[_ years months days hours minutes seconds fraction offset-sign offset-hours offset-minutes :as v]
(re-matches timestamp-regex s)]
(if-not v
(throw (js/Error. (str "Unrecognized date/time syntax: " s)))
(let [years (parse-int years)
months (or (parse-int months) 1)
days (or (parse-int days) 1)
hours (or (parse-int hours) 0)
minutes (or (parse-int minutes) 0)
seconds (or (parse-int seconds) 0)
fraction (or (parse-int (zero-fill-right-and-truncate fraction 3)) 0)
offset-sign (if (= offset-sign "-") -1 1)
offset-hours (or (parse-int offset-hours) 0)
offset-minutes (or (parse-int offset-minutes) 0)
offset (* offset-sign (+ (* offset-hours 60) offset-minutes))]
[years
(check 1 months 12 "timestamp month field must be in range 1..12")
(check 1 days (days-in-month months (leap-year? years)) "timestamp day field must be in range 1..last day in month")
(check 0 hours 23 "timestamp hour field must be in range 0..23")
(check 0 minutes 59 "timestamp minute field must be in range 0..59")
(check 0 seconds (if (= minutes 59) 60 59) "timestamp second field must be in range 0..60")
(check 0 fraction 999 "timestamp millisecond field must be in range 0..999")
offset]))))
(defn parse-timestamp
[ts]
(if-let [[years months days hours minutes seconds ms offset]
(parse-and-validate-timestamp ts)]
(js/Date.
(- (.UTC js/Date years (dec months) days hours minutes seconds ms)
(* offset 60 1000)))
(throw (js/Error. (str "Unrecognized date/time syntax: " ts)))))
(defn ^:private read-date
[s]
(if (string? s)
(parse-timestamp s)
(throw (js/Error. "Instance literal expects a string for its timestamp."))))
(defn ^:private read-queue
[elems]
(if (vector? elems)
(into cljs.core/PersistentQueue.EMPTY elems)
(throw (js/Error. "Queue literal expects a vector for its elements."))))
(defn ^:private read-js
[form]
(cond
(vector? form)
(let [arr (array)]
(doseq [x form]
(.push arr x))
arr)
(map? form)
(let [obj (js-obj)]
(doseq [[k v] form]
(gobject/set obj (name k) v))
obj)
:else
(throw
(js/Error.
(str "JS literal expects a vector or map containing "
"only string or unqualified keyword keys")))))
(defn ^:private read-uuid
[uuid]
(if (string? uuid)
(cljs.core/uuid uuid)
(throw (js/Error. "UUID literal expects a string as its representation."))))
(def ^:dynamic *default-data-reader-fn*
(atom nil))
(def ^:dynamic *tag-table*
(atom
(add-data-readers
{'inst read-date
'uuid read-uuid
'queue read-queue
'js read-js})))
(defn read
"Reads the first object from an cljs.tools.reader.reader-types/IPushbackReader.
Returns the object read. If EOF, throws if eof-error? is true otherwise returns eof.
If no reader is provided, *in* will be used.
Reads data in the edn format (subset of Clojure data):
http://edn-format.org
cljs.tools.reader.edn/read doesn't depend on dynamic Vars, all configuration
is done by passing an opt map.
opts is a map that can include the following keys:
:eof - value to return on end-of-file. When not supplied, eof throws an exception.
:readers - a map of tag symbols to data-reader functions to be considered before default-data-readers.
When not supplied, only the default-data-readers will be used.
:default - A function of two args, that will, if present and no reader is found for a tag,
be called with the tag and the value."
([reader]
(edn/read
{:readers @*tag-table*
:default @*default-data-reader-fn*
:eof nil}
reader))
([{:keys [eof] :as opts} reader]
(edn/read
(update (merge opts {:default @*default-data-reader-fn*})
:readers (fn [m] (merge @*tag-table* m))) reader))
([reader eof-error? eof opts]
(edn/read reader eof-error? eof
(update (merge opts {:default @*default-data-reader-fn*})
:readers (fn [m] (merge @*tag-table* m))))))
(defn read-string
"Reads one object from the string s.
Returns nil when s is nil or empty.
Reads data in the edn format (subset of Clojure data):
http://edn-format.org
opts is a map as per cljs.tools.reader.edn/read"
([s]
(edn/read-string
{:readers @*tag-table*
:default @*default-data-reader-fn*
:eof nil} s))
([opts s]
(edn/read-string
(update (merge {:default @*default-data-reader-fn*} opts)
:readers (fn [m] (merge @*tag-table* m))) s)))
(defn register-tag-parser!
[tag f]
(let [old-parser (get @*tag-table* tag)]
(swap! *tag-table* assoc tag f)
old-parser))
(defn deregister-tag-parser!
[tag]
(let [old-parser (get @*tag-table* tag)]
(swap! *tag-table* dissoc tag)
old-parser))
(defn register-default-tag-parser!
[f]
(let [old-parser @*default-data-reader-fn*]
(swap! *default-data-reader-fn* (fn [_] f))
old-parser))
(defn deregister-default-tag-parser!
[]
(let [old-parser @*default-data-reader-fn*]
(swap! *default-data-reader-fn* (fn [_] nil))
old-parser))
+448
View File
@@ -0,0 +1,448 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.reader');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.tools.reader');
goog.require('cljs.tools.reader.edn');
goog.require('goog.string.StringBuffer');
goog.require('goog.object');
goog.scope(function(){
cljs.reader.goog$module$goog$object = goog.module.get('goog.object');
});
cljs.reader.zero_fill_right_and_truncate = (function cljs$reader$zero_fill_right_and_truncate(s,width){
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(width,cljs.core.count(s))){
return s;
} else {
if((width < cljs.core.count(s))){
return cljs.core.subs.cljs$core$IFn$_invoke$arity$3(s,(0),width);
} else {
var b = (new goog.string.StringBuffer(s));
while(true){
if((b.getLength() < width)){
var G__5976 = b.append("0");
b = G__5976;
continue;
} else {
return b.toString();
}
break;
}
}
}
});
cljs.reader.divisible_QMARK_ = (function cljs$reader$divisible_QMARK_(num,div){
return (cljs.core.mod(num,div) === (0));
});
cljs.reader.indivisible_QMARK_ = (function cljs$reader$indivisible_QMARK_(num,div){
return (!(cljs.reader.divisible_QMARK_(num,div)));
});
cljs.reader.leap_year_QMARK_ = (function cljs$reader$leap_year_QMARK_(year){
return ((cljs.reader.divisible_QMARK_(year,(4))) && (((cljs.reader.indivisible_QMARK_(year,(100))) || (cljs.reader.divisible_QMARK_(year,(400))))));
});
cljs.reader.days_in_month = (function (){var dim_norm = new cljs.core.PersistentVector(null, 13, 5, cljs.core.PersistentVector.EMPTY_NODE, [null,(31),(28),(31),(30),(31),(30),(31),(31),(30),(31),(30),(31)], null);
var dim_leap = new cljs.core.PersistentVector(null, 13, 5, cljs.core.PersistentVector.EMPTY_NODE, [null,(31),(29),(31),(30),(31),(30),(31),(31),(30),(31),(30),(31)], null);
return (function (month,leap_year_QMARK_){
return cljs.core.get.cljs$core$IFn$_invoke$arity$2((cljs.core.truth_(leap_year_QMARK_)?dim_leap:dim_norm),month);
});
})();
cljs.reader.timestamp_regex = /(\d\d\d\d)(?:-(\d\d)(?:-(\d\d)(?:[T](\d\d)(?::(\d\d)(?::(\d\d)(?:[.](\d+))?)?)?)?)?)?(?:[Z]|([-+])(\d\d):(\d\d))?/;
cljs.reader.parse_int = (function cljs$reader$parse_int(s){
var n = parseInt(s,(10));
if(cljs.core.not(isNaN(n))){
return n;
} else {
return null;
}
});
cljs.reader.check = (function cljs$reader$check(low,n,high,msg){
if((((low <= n)) && ((n <= high)))){
} else {
throw (new Error([cljs.core.str.cljs$core$IFn$_invoke$arity$1(msg)," Failed: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(low),"<=",cljs.core.str.cljs$core$IFn$_invoke$arity$1(n),"<=",cljs.core.str.cljs$core$IFn$_invoke$arity$1(high)].join('')));
}
return n;
});
cljs.reader.parse_and_validate_timestamp = (function cljs$reader$parse_and_validate_timestamp(s){
var vec__5977 = cljs.core.re_matches(cljs.reader.timestamp_regex,s);
var _ = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(0),null);
var years = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(1),null);
var months = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(2),null);
var days = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(3),null);
var hours = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(4),null);
var minutes = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(5),null);
var seconds = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(6),null);
var fraction = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(7),null);
var offset_sign = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(8),null);
var offset_hours = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(9),null);
var offset_minutes = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5977,(10),null);
var v = vec__5977;
if(cljs.core.not(v)){
throw (new Error(["Unrecognized date/time syntax: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(s)].join('')));
} else {
var years__$1 = cljs.reader.parse_int(years);
var months__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(months);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (1);
}
})();
var days__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(days);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (1);
}
})();
var hours__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(hours);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (0);
}
})();
var minutes__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(minutes);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (0);
}
})();
var seconds__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(seconds);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (0);
}
})();
var fraction__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(cljs.reader.zero_fill_right_and_truncate(fraction,(3)));
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (0);
}
})();
var offset_sign__$1 = ((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(offset_sign,"-"))?(-1):(1));
var offset_hours__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(offset_hours);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (0);
}
})();
var offset_minutes__$1 = (function (){var or__5045__auto__ = cljs.reader.parse_int(offset_minutes);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (0);
}
})();
var offset = (offset_sign__$1 * ((offset_hours__$1 * (60)) + offset_minutes__$1));
return new cljs.core.PersistentVector(null, 8, 5, cljs.core.PersistentVector.EMPTY_NODE, [years__$1,cljs.reader.check((1),months__$1,(12),"timestamp month field must be in range 1..12"),cljs.reader.check((1),days__$1,(function (){var G__5980 = months__$1;
var G__5981 = cljs.reader.leap_year_QMARK_(years__$1);
return (cljs.reader.days_in_month.cljs$core$IFn$_invoke$arity$2 ? cljs.reader.days_in_month.cljs$core$IFn$_invoke$arity$2(G__5980,G__5981) : cljs.reader.days_in_month.call(null,G__5980,G__5981));
})(),"timestamp day field must be in range 1..last day in month"),cljs.reader.check((0),hours__$1,(23),"timestamp hour field must be in range 0..23"),cljs.reader.check((0),minutes__$1,(59),"timestamp minute field must be in range 0..59"),cljs.reader.check((0),seconds__$1,((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(minutes__$1,(59)))?(60):(59)),"timestamp second field must be in range 0..60"),cljs.reader.check((0),fraction__$1,(999),"timestamp millisecond field must be in range 0..999"),offset], null);
}
});
cljs.reader.parse_timestamp = (function cljs$reader$parse_timestamp(ts){
var temp__4655__auto__ = cljs.reader.parse_and_validate_timestamp(ts);
if(cljs.core.truth_(temp__4655__auto__)){
var vec__5982 = temp__4655__auto__;
var years = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(0),null);
var months = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(1),null);
var days = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(2),null);
var hours = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(3),null);
var minutes = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(4),null);
var seconds = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(5),null);
var ms = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(6),null);
var offset = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5982,(7),null);
return (new Date((Date.UTC(years,(months - (1)),days,hours,minutes,seconds,ms) - ((offset * (60)) * (1000)))));
} else {
throw (new Error(["Unrecognized date/time syntax: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(ts)].join('')));
}
});
cljs.reader.read_date = (function cljs$reader$read_date(s){
if(typeof s === 'string'){
return cljs.reader.parse_timestamp(s);
} else {
throw (new Error("Instance literal expects a string for its timestamp."));
}
});
cljs.reader.read_queue = (function cljs$reader$read_queue(elems){
if(cljs.core.vector_QMARK_(elems)){
return cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentQueue.EMPTY,elems);
} else {
throw (new Error("Queue literal expects a vector for its elements."));
}
});
cljs.reader.read_js = (function cljs$reader$read_js(form){
if(cljs.core.vector_QMARK_(form)){
var arr = [];
var seq__5985_6019 = cljs.core.seq(form);
var chunk__5986_6020 = null;
var count__5987_6021 = (0);
var i__5988_6022 = (0);
while(true){
if((i__5988_6022 < count__5987_6021)){
var x_6023 = chunk__5986_6020.cljs$core$IIndexed$_nth$arity$2(null,i__5988_6022);
arr.push(x_6023);
var G__6024 = seq__5985_6019;
var G__6025 = chunk__5986_6020;
var G__6026 = count__5987_6021;
var G__6027 = (i__5988_6022 + (1));
seq__5985_6019 = G__6024;
chunk__5986_6020 = G__6025;
count__5987_6021 = G__6026;
i__5988_6022 = G__6027;
continue;
} else {
var temp__4657__auto___6028 = cljs.core.seq(seq__5985_6019);
if(temp__4657__auto___6028){
var seq__5985_6029__$1 = temp__4657__auto___6028;
if(cljs.core.chunked_seq_QMARK_(seq__5985_6029__$1)){
var c__5568__auto___6030 = cljs.core.chunk_first(seq__5985_6029__$1);
var G__6031 = cljs.core.chunk_rest(seq__5985_6029__$1);
var G__6032 = c__5568__auto___6030;
var G__6033 = cljs.core.count(c__5568__auto___6030);
var G__6034 = (0);
seq__5985_6019 = G__6031;
chunk__5986_6020 = G__6032;
count__5987_6021 = G__6033;
i__5988_6022 = G__6034;
continue;
} else {
var x_6035 = cljs.core.first(seq__5985_6029__$1);
arr.push(x_6035);
var G__6036 = cljs.core.next(seq__5985_6029__$1);
var G__6037 = null;
var G__6038 = (0);
var G__6039 = (0);
seq__5985_6019 = G__6036;
chunk__5986_6020 = G__6037;
count__5987_6021 = G__6038;
i__5988_6022 = G__6039;
continue;
}
} else {
}
}
break;
}
return arr;
} else {
if(cljs.core.map_QMARK_(form)){
var obj = ({});
var seq__5991_6040 = cljs.core.seq(form);
var chunk__5992_6041 = null;
var count__5993_6042 = (0);
var i__5994_6043 = (0);
while(true){
if((i__5994_6043 < count__5993_6042)){
var vec__6007_6044 = chunk__5992_6041.cljs$core$IIndexed$_nth$arity$2(null,i__5994_6043);
var k_6045 = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__6007_6044,(0),null);
var v_6046 = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__6007_6044,(1),null);
var G__6010_6047 = obj;
var G__6011_6048 = cljs.core.name(k_6045);
var G__6012_6049 = v_6046;
cljs.reader.goog$module$goog$object.set.call(null,G__6010_6047,G__6011_6048,G__6012_6049);
var G__6050 = seq__5991_6040;
var G__6051 = chunk__5992_6041;
var G__6052 = count__5993_6042;
var G__6053 = (i__5994_6043 + (1));
seq__5991_6040 = G__6050;
chunk__5992_6041 = G__6051;
count__5993_6042 = G__6052;
i__5994_6043 = G__6053;
continue;
} else {
var temp__4657__auto___6054 = cljs.core.seq(seq__5991_6040);
if(temp__4657__auto___6054){
var seq__5991_6055__$1 = temp__4657__auto___6054;
if(cljs.core.chunked_seq_QMARK_(seq__5991_6055__$1)){
var c__5568__auto___6056 = cljs.core.chunk_first(seq__5991_6055__$1);
var G__6057 = cljs.core.chunk_rest(seq__5991_6055__$1);
var G__6058 = c__5568__auto___6056;
var G__6059 = cljs.core.count(c__5568__auto___6056);
var G__6060 = (0);
seq__5991_6040 = G__6057;
chunk__5992_6041 = G__6058;
count__5993_6042 = G__6059;
i__5994_6043 = G__6060;
continue;
} else {
var vec__6013_6061 = cljs.core.first(seq__5991_6055__$1);
var k_6062 = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__6013_6061,(0),null);
var v_6063 = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__6013_6061,(1),null);
var G__6016_6064 = obj;
var G__6017_6065 = cljs.core.name(k_6062);
var G__6018_6066 = v_6063;
cljs.reader.goog$module$goog$object.set.call(null,G__6016_6064,G__6017_6065,G__6018_6066);
var G__6067 = cljs.core.next(seq__5991_6055__$1);
var G__6068 = null;
var G__6069 = (0);
var G__6070 = (0);
seq__5991_6040 = G__6067;
chunk__5992_6041 = G__6068;
count__5993_6042 = G__6069;
i__5994_6043 = G__6070;
continue;
}
} else {
}
}
break;
}
return obj;
} else {
throw (new Error(["JS literal expects a vector or map containing ","only string or unqualified keyword keys"].join('')));
}
}
});
cljs.reader.read_uuid = (function cljs$reader$read_uuid(uuid){
if(typeof uuid === 'string'){
return cljs.core.uuid(uuid);
} else {
throw (new Error("UUID literal expects a string as its representation."));
}
});
cljs.reader._STAR_default_data_reader_fn_STAR_ = cljs.core.atom.cljs$core$IFn$_invoke$arity$1(null);
cljs.reader._STAR_tag_table_STAR_ = cljs.core.atom.cljs$core$IFn$_invoke$arity$1(cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([new cljs.core.PersistentArrayMap(null, 4, [cljs.core.cst$sym$inst,cljs.reader.read_date,cljs.core.cst$sym$uuid,cljs.reader.read_uuid,cljs.core.cst$sym$queue,cljs.reader.read_queue,cljs.core.cst$sym$js,cljs.reader.read_js], null),cljs.core.PersistentArrayMap.EMPTY], 0)));
/**
* Reads the first object from an cljs.tools.reader.reader-types/IPushbackReader.
* Returns the object read. If EOF, throws if eof-error? is true otherwise returns eof.
* If no reader is provided, *in* will be used.
*
* Reads data in the edn format (subset of Clojure data):
* http://edn-format.org
*
* cljs.tools.reader.edn/read doesn't depend on dynamic Vars, all configuration
* is done by passing an opt map.
*
* opts is a map that can include the following keys:
* :eof - value to return on end-of-file. When not supplied, eof throws an exception.
* :readers - a map of tag symbols to data-reader functions to be considered before default-data-readers.
* When not supplied, only the default-data-readers will be used.
* :default - A function of two args, that will, if present and no reader is found for a tag,
* be called with the tag and the value.
*/
cljs.reader.read = (function cljs$reader$read(var_args){
var G__6072 = arguments.length;
switch (G__6072) {
case 1:
return cljs.reader.read.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.reader.read.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 4:
return cljs.reader.read.cljs$core$IFn$_invoke$arity$4((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.reader.read.cljs$core$IFn$_invoke$arity$1 = (function (reader){
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$2(new cljs.core.PersistentArrayMap(null, 3, [cljs.core.cst$kw$readers,cljs.core.deref(cljs.reader._STAR_tag_table_STAR_),cljs.core.cst$kw$default,cljs.core.deref(cljs.reader._STAR_default_data_reader_fn_STAR_),cljs.core.cst$kw$eof,null], null),reader);
}));
(cljs.reader.read.cljs$core$IFn$_invoke$arity$2 = (function (p__6073,reader){
var map__6074 = p__6073;
var map__6074__$1 = cljs.core.__destructure_map(map__6074);
var opts = map__6074__$1;
var eof = cljs.core.get.cljs$core$IFn$_invoke$arity$2(map__6074__$1,cljs.core.cst$kw$eof);
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$2(cljs.core.update.cljs$core$IFn$_invoke$arity$3(cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([opts,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$default,cljs.core.deref(cljs.reader._STAR_default_data_reader_fn_STAR_)], null)], 0)),cljs.core.cst$kw$readers,(function (m){
return cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.deref(cljs.reader._STAR_tag_table_STAR_),m], 0));
})),reader);
}));
(cljs.reader.read.cljs$core$IFn$_invoke$arity$4 = (function (reader,eof_error_QMARK_,eof,opts){
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(reader,eof_error_QMARK_,eof,cljs.core.update.cljs$core$IFn$_invoke$arity$3(cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([opts,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$default,cljs.core.deref(cljs.reader._STAR_default_data_reader_fn_STAR_)], null)], 0)),cljs.core.cst$kw$readers,(function (m){
return cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.deref(cljs.reader._STAR_tag_table_STAR_),m], 0));
})));
}));
(cljs.reader.read.cljs$lang$maxFixedArity = 4);
/**
* Reads one object from the string s.
* Returns nil when s is nil or empty.
*
* Reads data in the edn format (subset of Clojure data):
* http://edn-format.org
*
* opts is a map as per cljs.tools.reader.edn/read
*/
cljs.reader.read_string = (function cljs$reader$read_string(var_args){
var G__6077 = arguments.length;
switch (G__6077) {
case 1:
return cljs.reader.read_string.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.reader.read_string.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.reader.read_string.cljs$core$IFn$_invoke$arity$1 = (function (s){
return cljs.tools.reader.edn.read_string.cljs$core$IFn$_invoke$arity$2(new cljs.core.PersistentArrayMap(null, 3, [cljs.core.cst$kw$readers,cljs.core.deref(cljs.reader._STAR_tag_table_STAR_),cljs.core.cst$kw$default,cljs.core.deref(cljs.reader._STAR_default_data_reader_fn_STAR_),cljs.core.cst$kw$eof,null], null),s);
}));
(cljs.reader.read_string.cljs$core$IFn$_invoke$arity$2 = (function (opts,s){
return cljs.tools.reader.edn.read_string.cljs$core$IFn$_invoke$arity$2(cljs.core.update.cljs$core$IFn$_invoke$arity$3(cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$default,cljs.core.deref(cljs.reader._STAR_default_data_reader_fn_STAR_)], null),opts], 0)),cljs.core.cst$kw$readers,(function (m){
return cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.deref(cljs.reader._STAR_tag_table_STAR_),m], 0));
})),s);
}));
(cljs.reader.read_string.cljs$lang$maxFixedArity = 2);
cljs.reader.register_tag_parser_BANG_ = (function cljs$reader$register_tag_parser_BANG_(tag,f){
var old_parser = cljs.core.get.cljs$core$IFn$_invoke$arity$2(cljs.core.deref(cljs.reader._STAR_tag_table_STAR_),tag);
cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$4(cljs.reader._STAR_tag_table_STAR_,cljs.core.assoc,tag,f);
return old_parser;
});
cljs.reader.deregister_tag_parser_BANG_ = (function cljs$reader$deregister_tag_parser_BANG_(tag){
var old_parser = cljs.core.get.cljs$core$IFn$_invoke$arity$2(cljs.core.deref(cljs.reader._STAR_tag_table_STAR_),tag);
cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$3(cljs.reader._STAR_tag_table_STAR_,cljs.core.dissoc,tag);
return old_parser;
});
cljs.reader.register_default_tag_parser_BANG_ = (function cljs$reader$register_default_tag_parser_BANG_(f){
var old_parser = cljs.core.deref(cljs.reader._STAR_default_data_reader_fn_STAR_);
cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$2(cljs.reader._STAR_default_data_reader_fn_STAR_,(function (_){
return f;
}));
return old_parser;
});
cljs.reader.deregister_default_tag_parser_BANG_ = (function cljs$reader$deregister_default_tag_parser_BANG_(){
var old_parser = cljs.core.deref(cljs.reader._STAR_default_data_reader_fn_STAR_);
cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$2(cljs.reader._STAR_default_data_reader_fn_STAR_,(function (_){
return null;
}));
return old_parser;
});
+965
View File
@@ -0,0 +1,965 @@
;; Copyright (c) Nicola Mometto, Rich Hickey & contributors.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns ^{:doc "A clojure reader in clojure"
:author "Bronsa"}
cljs.tools.reader
(:refer-clojure :exclude [read read-line read-string char read+string
default-data-readers *default-data-reader-fn*
*data-readers* *suppress-read*])
(:require-macros [cljs.tools.reader.reader-types :refer [log-source]])
(:require [cljs.tools.reader.reader-types :refer
[read-char unread peek-char indexing-reader?
get-line-number get-column-number get-file-name
string-push-back-reader]]
[cljs.tools.reader.impl.utils :refer
[char ex-info? whitespace? numeric? desugar-meta next-id namespace-keys second'
ReaderConditional reader-conditional reader-conditional? char-code]]
[cljs.tools.reader.impl.commons :refer
[number-literal? read-past match-number parse-symbol read-comment throwing-reader]]
[cljs.tools.reader.impl.errors :as err]
[goog.array :as garray]
[goog.string :as gstring])
(:import goog.string.StringBuffer))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(declare ^:private read*
macros dispatch-macros
^:dynamic *data-readers*
^:dynamic *default-data-reader-fn*
^:dynamic *suppress-read*
default-data-readers)
(defn- ^boolean macro-terminating? [ch]
(case ch
(\" \; \@ \^ \` \~ \( \) \[ \] \{ \} \\) true
false))
(def sb (StringBuffer.))
(defn- read-token
"Read in a single logical token from the reader"
[^not-native rdr kind initch]
(if (nil? initch)
(err/throw-eof-at-start rdr kind)
(do
(.clear sb)
(loop [ch initch]
(if (or (whitespace? ch)
(macro-terminating? ch)
(nil? ch))
(do
(when-not (nil? ch)
(unread rdr ch))
(.toString sb))
(do
(.append sb ch)
(recur (read-char rdr))))))))
(declare read-tagged)
(defn- read-dispatch
[^not-native rdr _ opts pending-forms]
(if-let [ch (read-char rdr)]
(if-let [dm (dispatch-macros ch)]
(dm rdr ch opts pending-forms)
(read-tagged (doto rdr (unread ch)) ch opts pending-forms)) ;; ctor reader is implemented as a tagged literal
(err/throw-eof-at-dispatch rdr)))
(defn- read-unmatched-delimiter
[rdr ch opts pending-forms]
(err/throw-unmatch-delimiter rdr ch))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; readers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn read-regex
[^not-native rdr ch opts pending-forms]
(let [sb (StringBuffer.)]
(loop [ch (read-char rdr)]
(if (identical? \" ch)
(re-pattern (str sb))
(if (nil? ch)
(err/throw-eof-reading rdr :regex sb)
(do
(.append sb ch )
(when (identical? \\ ch)
(let [ch (read-char rdr)]
(if (nil? ch)
(err/throw-eof-reading rdr :regex sb))
(.append sb ch)))
(recur (read-char rdr))))))))
(defn- read-unicode-char
([token offset length base]
(let [l (+ offset length)]
(when-not (== (count token) l)
(err/throw-invalid-unicode-literal nil token))
(loop [i offset uc 0]
(if (== i l)
(js/String.fromCharCode uc)
(let [d (char-code (nth token i) base)]
(if (== d -1)
(err/throw-invalid-unicode-digit-in-token nil (nth token i) token)
(recur (inc i) (+ d (* uc base)))))))))
([^not-native rdr initch base length exact?]
(loop [i 1 uc (char-code initch base)]
(if (== uc -1)
(err/throw-invalid-unicode-digit rdr initch)
(if-not (== i length)
(let [ch (peek-char rdr)]
(if (or (whitespace? ch)
(macros ch)
(nil? ch))
(if exact?
(err/throw-invalid-unicode-len rdr i length)
(js/String.fromCharCode uc))
(let [d (char-code ch base)]
(read-char rdr)
(if (== d -1)
(err/throw-invalid-unicode-digit rdr ch)
(recur (inc i) (+ d (* uc base)))))))
(js/String.fromCharCode uc))))))
(def ^:private ^:const upper-limit (.charCodeAt \uD7ff 0))
(def ^:private ^:const lower-limit (.charCodeAt \uE000 0))
(defn- valid-octal? [token base]
(<= (js/parseInt token base) 0377))
(defn- read-char*
"Read in a character literal"
[^not-native rdr backslash opts pending-forms]
(let [ch (read-char rdr)]
(if-not (nil? ch)
(let [token (if (or (macro-terminating? ch)
(whitespace? ch))
(str ch)
(read-token rdr :character ch))
token-len (. token -length)]
(cond
(== 1 token-len) (.charAt token 0) ;;; no char type - so can't ensure/cache char
(= token "newline") \newline
(= token "space") \space
(= token "tab") \tab
(= token "backspace") \backspace
(= token "formfeed") \formfeed
(= token "return") \return
(gstring/startsWith token "u")
(let [c (read-unicode-char token 1 4 16)
ic (.charCodeAt c 0)]
(if (and (> ic upper-limit)
(< ic lower-limit))
(err/throw-invalid-character-literal rdr (.toString ic 16))
c))
(gstring/startsWith token "o")
(let [len (dec token-len)]
(if (> len 3)
(err/throw-invalid-octal-len rdr token)
(let [offset 1
base 8
uc (read-unicode-char token offset len base)]
(if-not (valid-octal? (subs token offset) base)
(err/throw-bad-octal-number rdr)
uc))))
:else (err/throw-unsupported-character rdr token)))
(err/throw-eof-in-character rdr))))
(defn- starting-line-col-info [^not-native rdr]
(when (indexing-reader? rdr)
[(get-line-number rdr) (int (dec (get-column-number rdr)))]))
(defn- ending-line-col-info [^not-native rdr]
(when (indexing-reader? rdr)
[(get-line-number rdr) (get-column-number rdr)]))
(defonce ^:private READ_EOF (js/Object.))
(defonce ^:private READ_FINISHED (js/Object.))
(def ^:dynamic *read-delim* false)
(defn- read-delimited-internal [kind delim rdr opts pending-forms]
(let [[start-line start-column] (starting-line-col-info rdr)
delim (char delim)]
(loop [a (transient [])]
(let [form (read* rdr false READ_EOF delim opts pending-forms)]
(if (identical? form READ_FINISHED)
(persistent! a)
(if (identical? form READ_EOF)
(err/throw-eof-delimited rdr kind start-line start-column (count a))
(recur (conj! a form))))))))
(defn- read-delimited
"Reads and returns a collection ended with delim"
[kind delim rdr opts pending-forms]
(binding [*read-delim* true]
(read-delimited-internal kind delim rdr opts pending-forms)))
(defn- read-list
"Read in a list, including its location if the reader is an indexing reader"
[rdr _ opts pending-forms]
(let [[start-line start-column] (starting-line-col-info rdr)
the-list (read-delimited :list \) rdr opts pending-forms)
[end-line end-column] (ending-line-col-info rdr)]
(with-meta (if (empty? the-list)
'()
(apply list the-list))
(when start-line
(merge
(when-let [file (get-file-name rdr)]
{:file file})
{:line start-line
:column start-column
:end-line end-line
:end-column end-column})))))
(defn- read-vector
"Read in a vector, including its location if the reader is an indexing reader"
[rdr _ opts pending-forms]
(let [[start-line start-column] (starting-line-col-info rdr)
the-vector (read-delimited :vector \] rdr opts pending-forms)
[end-line end-column] (ending-line-col-info rdr)]
(with-meta the-vector
(when start-line
(merge
(when-let [file (get-file-name rdr)]
{:file file})
{:line start-line
:column start-column
:end-line end-line
:end-column end-column})))))
(defn- read-map
"Read in a map, including its location if the reader is an indexing reader"
[rdr _ opts pending-forms]
(let [[start-line start-column] (starting-line-col-info rdr)
the-map (read-delimited :map \} rdr opts pending-forms)
map-count (count the-map)
ks (take-nth 2 the-map)
key-set (set ks)
[end-line end-column] (ending-line-col-info rdr)]
(when (odd? map-count)
(err/throw-odd-map rdr start-line start-column the-map))
(when-not (= (count key-set) (count ks))
(err/throw-dup-keys rdr :map ks))
(with-meta
(if (<= map-count (* 2 (.-HASHMAP-THRESHOLD cljs.core/PersistentArrayMap)))
(.fromArray cljs.core/PersistentArrayMap (to-array the-map) true true)
(.fromArray cljs.core/PersistentHashMap (to-array the-map) true))
(when start-line
(merge
(when-let [file (get-file-name rdr)]
{:file file})
{:line start-line
:column start-column
:end-line end-line
:end-column end-column})))))
(defn- read-number
[^not-native rdr initch]
(loop [sb (doto (StringBuffer.) (.append initch))
ch (read-char rdr)]
(if (or (whitespace? ch) (macros ch) (nil? ch))
(let [s (str sb)]
(unread rdr ch)
(or (match-number s)
(err/throw-invalid-number rdr s)))
(recur (doto sb (.append ch)) (read-char rdr)))))
(defn- escape-char [sb ^not-native rdr]
(let [ch (read-char rdr)]
(case ch
\t "\t"
\r "\r"
\n "\n"
\\ "\\"
\" "\""
\b "\b"
\f "\f"
\u (let [ch (read-char rdr)]
(if (== -1 (js/parseInt (int ch) 16))
(err/throw-invalid-unicode-escape rdr ch)
(read-unicode-char rdr ch 16 4 true)))
(if (numeric? ch)
(let [ch (read-unicode-char rdr ch 8 3 false)]
(if (> (int ch) 0377)
(err/throw-bad-octal-number rdr)
ch))
(err/throw-bad-escape-char rdr ch)))))
(defn- read-string*
[^not-native reader _ opts pending-forms]
(loop [sb (StringBuffer.)
ch (read-char reader)]
(if (nil? ch)
(err/throw-eof-reading reader :string \" sb)
(case ch
\\ (recur (doto sb (.append (escape-char sb reader)))
(read-char reader))
\" (str sb)
(recur (doto sb (.append ch)) (read-char reader))))))
(defn- loc-info [rdr line column]
(when-not (nil? line)
(let [file (get-file-name rdr)
filem (when-not (nil? file) {:file file})
[end-line end-column] (ending-line-col-info rdr)
lcm {:line line
:column column
:end-line end-line
:end-column end-column}]
(merge filem lcm))))
(defn- read-symbol
[rdr initch]
(let [[line column] (starting-line-col-info rdr)
token (read-token rdr :symbol initch)]
(when-not (nil? token)
(case token
;; special symbols
"nil" nil
"true" true
"false" false
"/" '/
(let [^not-native p (parse-symbol token)]
(if-not (nil? p)
(let [^not-native sym (symbol (-nth p 0) (-nth p 1))]
(-with-meta sym (loc-info rdr line column)))
(err/throw-invalid rdr :symbol token)))))))
(def ^:dynamic *alias-map*
"Map from ns alias to ns, if non-nil, it will be used to resolve read-time
ns aliases.
Defaults to nil"
nil)
(defn- resolve-alias [sym]
(get *alias-map* sym))
(defn- resolve-ns [sym]
(or (resolve-alias sym)
(when-let [ns (find-ns sym)]
(symbol (ns-name ns)))))
(defn- read-keyword
[^not-native reader initch opts pending-forms]
(let [ch (read-char reader)]
(if-not (whitespace? ch)
(let [token (read-token reader :keyword ch)
^not-native s (parse-symbol token)]
(if-not (nil? s)
(let [ns (-nth s 0)
name (-nth s 1)]
(if (identical? \: (.charAt token 0))
(if-not (nil? ns)
(if-let [ns (resolve-alias (symbol (subs ns 1)))]
(keyword (str ns) name)
(err/throw-invalid reader :keyword (str \: token)))
(if-let [ns *ns*]
(keyword (str ns) (subs name 1))
(err/reader-error reader "Invalid token: :" token)))
(keyword ns name)))
(err/throw-invalid reader :keyword (str \: token))))
(err/throw-single-colon reader))))
(defn- wrapping-reader
"Returns a function which wraps a reader in a call to sym"
[sym]
(fn [rdr _ opts pending-forms]
(list sym (read* rdr true nil opts pending-forms))))
(defn- read-meta
"Read metadata and return the following object with the metadata applied"
[rdr _ opts pending-forms]
(log-source rdr
(let [[line column] (starting-line-col-info rdr)
m (desugar-meta (read* rdr true nil opts pending-forms))]
(when-not (map? m)
(err/throw-bad-metadata rdr m))
(let [o (read* rdr true nil opts pending-forms)]
(if (implements? IMeta o)
(let [m (if (and line (seq? o))
(assoc m :line line :column column)
m)]
(if (implements? IWithMeta o)
(with-meta o (merge (meta o) m))
(reset-meta! o m)))
(err/throw-bad-metadata-target rdr o))))))
(defn- read-set
[rdr _ opts pending-forms]
(let [[start-line start-column] (starting-line-col-info rdr)
;; subtract 1 from start-column so it includes the # in the leading #{
start-column (if start-column (int (dec start-column)))
coll (read-delimited :set \} rdr opts pending-forms)
the-set (set coll)
[end-line end-column] (ending-line-col-info rdr)]
(when-not (= (count coll) (count the-set))
(err/reader-error rdr (err/throw-dup-keys rdr :set coll)))
(with-meta the-set
(when start-line
(merge
(when-let [file (get-file-name rdr)]
{:file file})
{:line start-line
:column start-column
:end-line end-line
:end-column end-column})))))
(defn- read-discard
"Read and discard the first object from rdr"
[rdr _ opts pending-forms]
(doto rdr
(read* true nil opts pending-forms)))
(defn- read-symbolic-value
[rdr _ opts pending-forms]
(let [sym (read* rdr true nil opts pending-forms)]
(case sym
NaN js/Number.NaN
-Inf js/Number.NEGATIVE_INFINITY
Inf js/Number.POSITIVE_INFINITY
(err/reader-error rdr (str "Invalid token: ##" sym)))))
(def ^:private RESERVED_FEATURES #{:else :none})
(defn- has-feature?
[rdr feature opts]
(if (keyword? feature)
(or (= :default feature) (contains? (get opts :features) feature))
(err/reader-error rdr "Feature should be a keyword: " feature)))
(defn- check-eof-error
[form rdr first-line]
(when (identical? form READ_EOF)
(err/throw-eof-error rdr (and (< first-line 0) first-line))))
(defn- check-reserved-features
[rdr form]
(when (get RESERVED_FEATURES form)
(err/reader-error rdr "Feature name " form " is reserved")))
(defn- check-invalid-read-cond
[form rdr first-line]
(when (identical? form READ_FINISHED)
(if (< first-line 0)
(err/reader-error rdr "read-cond requires an even number of forms")
(err/reader-error rdr "read-cond starting on line " first-line " requires an even number of forms"))))
(defn- read-suppress
"Read next form and suppress. Return nil or READ_FINISHED."
[first-line rdr opts pending-forms]
(binding [*suppress-read* true]
(let [form (read* rdr false READ_EOF \) opts pending-forms)]
(check-eof-error form rdr first-line)
(when (identical? form READ_FINISHED)
READ_FINISHED))))
(defonce ^:private NO_MATCH (js/Object.))
(defn- match-feature
"Read next feature. If matched, read next form and return.
Otherwise, read and skip next form, returning READ_FINISHED or nil."
[first-line rdr opts pending-forms]
(let [feature (read* rdr false READ_EOF \) opts pending-forms)]
(check-eof-error feature rdr first-line)
(if (= feature READ_FINISHED)
READ_FINISHED
(do
(check-reserved-features rdr feature)
(if (has-feature? rdr feature opts)
;; feature matched, read selected form
(doto (read* rdr false READ_EOF \) opts pending-forms)
(check-eof-error rdr first-line)
(check-invalid-read-cond rdr first-line))
;; feature not matched, ignore next form
(or (read-suppress first-line rdr opts pending-forms)
NO_MATCH))))))
(defn- read-cond-delimited
[rdr splicing opts pending-forms]
(let [first-line (if (indexing-reader? rdr) (get-line-number rdr) -1)
result (loop [matched NO_MATCH
finished nil]
(cond
;; still looking for match, read feature+form
(identical? matched NO_MATCH)
(let [match (match-feature first-line rdr opts pending-forms)]
(if (identical? match READ_FINISHED)
READ_FINISHED
(recur match nil)))
;; found match, just read and ignore the rest
(not (identical? finished READ_FINISHED))
(recur matched (read-suppress first-line rdr opts pending-forms))
:else
matched))]
(if (identical? result READ_FINISHED)
rdr
(if splicing
(do
(if (implements? ISequential result)
(do
(garray/insertArrayAt pending-forms (to-array result) 0)
rdr)
(err/reader-error rdr "Spliced form list in read-cond-splicing must implement ISequential")))
result))))
(defn- read-cond
[^not-native rdr _ opts pending-forms]
(when (not (and opts (#{:allow :preserve} (:read-cond opts))))
(throw (ex-info "Conditional read not allowed"
{:type :runtime-exception})))
(if-let [ch (read-char rdr)]
(let [splicing (= ch \@)
ch (if splicing (read-char rdr) ch)]
(when splicing
(when-not *read-delim*
(err/reader-error rdr "cond-splice not in list")))
(if-let [ch (if (whitespace? ch) (read-past whitespace? rdr) ch)]
(if (not= ch \()
(throw (ex-info "read-cond body must be a list"
{:type :runtime-exception}))
(binding [*suppress-read* (or *suppress-read* (= :preserve (:read-cond opts)))]
(if *suppress-read*
(reader-conditional (read-list rdr ch opts pending-forms) splicing)
(read-cond-delimited rdr splicing opts pending-forms))))
(err/throw-eof-in-character rdr)))
(err/throw-eof-in-character rdr)))
(def ^:private ^:dynamic arg-env nil)
(defn- garg
"Get a symbol for an anonymous ?argument?"
[n]
(symbol (str (if (== -1 n) "rest" (str "p" n))
"__" (next-id) "#")))
(defn- read-fn
[rdr _ opts pending-forms]
(if arg-env
(throw (ex-info "Nested #()s are not allowed" {:type :illegal-state})))
(binding [arg-env (sorted-map)]
(let [form (read* (doto rdr (unread \()) true nil opts pending-forms) ;; this sets bindings
rargs (rseq arg-env)
args (if rargs
(let [higharg (key (first rargs))]
(let [args (loop [i 1 args (transient [])]
(if (> i higharg)
(persistent! args)
(recur (inc i) (conj! args (or (get arg-env i)
(garg i))))))
args (if (arg-env -1)
(conj args '& (arg-env -1))
args)]
args))
[])]
(list 'fn* args form))))
(defn- register-arg
"Registers an argument to the arg-env"
[n]
(if arg-env
(if-let [ret (arg-env n)]
ret
(let [g (garg n)]
(set! arg-env (assoc arg-env n g))
g))
(throw (ex-info "Arg literal not in #()"
{:type :illegal-state})))) ;; should never hit this
(declare read-symbol)
(defn- read-arg
[^not-native rdr pct opts pending-forms]
(if (nil? arg-env)
(read-symbol rdr pct)
(let [ch (peek-char rdr)]
(cond
(or (whitespace? ch)
(macro-terminating? ch)
(nil? ch))
(register-arg 1)
(= ch \&)
(do (read-char rdr)
(register-arg -1))
:else
(let [n (read* rdr true nil opts pending-forms)]
(if-not (integer? n)
(throw (ex-info "Arg literal must be %, %& or %integer"
{:type :illegal-state}))
(register-arg n)))))))
(def ^:private ^:dynamic gensym-env nil)
(defn- read-unquote
[^not-native rdr comma opts pending-forms]
(if-let [ch (peek-char rdr)]
(if (= \@ ch)
((wrapping-reader 'clojure.core/unquote-splicing) (doto rdr read-char) \@ opts pending-forms)
((wrapping-reader 'clojure.core/unquote) rdr \~ opts pending-forms))))
(declare syntax-quote*)
(defn- unquote-splicing? [form]
(and (seq? form)
(= (first form) 'clojure.core/unquote-splicing)))
(defn- unquote? [form]
(and (seq? form)
(= (first form) 'clojure.core/unquote)))
(defn- expand-list
"Expand a list by resolving its syntax quotes and unquotes"
[s]
(loop [s (seq s) r (transient [])]
(if s
(let [item (first s)
ret (conj! r
(cond
(unquote? item) (list 'clojure.core/list (second item))
(unquote-splicing? item) (second item)
:else (list 'clojure.core/list (syntax-quote* item))))]
(recur (next s) ret))
(seq (persistent! r)))))
(defn- flatten-map
"Flatten a map into a seq of alternate keys and values"
[form]
(loop [s (seq form) key-vals (transient [])]
(if s
(let [e (first s)]
(recur (next s) (-> key-vals
(conj! (key e))
(conj! (val e)))))
(seq (persistent! key-vals)))))
(defn- register-gensym [sym]
(if-not gensym-env
(throw (ex-info "Gensym literal not in syntax-quote"
{:type :illegal-state})))
(or (get gensym-env sym)
(let [gs (symbol (str (subs (name sym)
0 (dec (count (name sym))))
"__" (next-id) "__auto__"))]
(set! gensym-env (assoc gensym-env sym gs))
gs)))
(defn- add-meta [form ret]
(if (and (implements? IWithMeta form)
(seq (dissoc (meta form) :line :column :end-line :end-column :file :source)))
(list 'cljs.core/with-meta ret (syntax-quote* (meta form)))
ret))
(defn- syntax-quote-coll [type coll]
(let [res (list 'cljs.core/sequence
(cons 'cljs.core/concat
(expand-list coll)))]
(if type
(list 'cljs.core/apply type res)
res)))
(defn map-func
"Decide which map type to use, array-map if less than 16 elements"
[coll]
(if (>= (count coll) 16)
'cljs.core/hash-map
'cljs.core/array-map))
(defn bool? [x]
(or (instance? js/Boolean x)
(true? x)
(false? x)))
(defn ^:dynamic resolve-symbol
"Resolve a symbol s into its fully qualified namespace version"
[s]
(throw (ex-info "resolve-symbol is not implemented" {:sym s})))
(defn- syntax-quote* [form]
(->>
(cond
(special-symbol? form) (list 'quote form)
(symbol? form)
(list 'quote
(if (and (not (namespace form))
(gstring/endsWith (name form) "#"))
(register-gensym form)
(let [sym (str form)]
(if (gstring/endsWith sym ".")
(let [csym (symbol (subs sym 0 (dec (count sym))))]
(symbol (str (resolve-symbol csym) ".")))
(resolve-symbol form)))))
(unquote? form) (second form)
(unquote-splicing? form) (throw (ex-info "unquote-splice not in list"
{:type :illegal-state}))
(coll? form)
(cond
(implements? IRecord form) form
(map? form) (syntax-quote-coll (map-func form) (flatten-map form))
(vector? form) (list 'cljs.core/vec (syntax-quote-coll nil form))
(set? form) (syntax-quote-coll 'cljs.core/hash-set form)
(or (seq? form) (list? form))
(let [seq (seq form)]
(if seq
(syntax-quote-coll nil seq)
'(cljs.core/list)))
:else (throw (ex-info "Unknown Collection type"
{:type :unsupported-operation})))
(or (keyword? form)
(number? form)
(string? form)
(nil? form)
(bool? form)
(instance? js/RegExp form))
form
:else (list 'quote form))
(add-meta form)))
(defn- read-syntax-quote
[rdr backquote opts pending-forms]
(binding [gensym-env {}]
(-> (read* rdr true nil opts pending-forms)
syntax-quote*)))
(defn- read-namespaced-map
[rdr _ opts pending-forms]
(let [[start-line start-column] (starting-line-col-info rdr)
token (read-token rdr :namespaced-map (read-char rdr))]
(if-let [ns (cond
(= token ":")
(ns-name *ns*)
(= \: (first token))
(some-> token (subs 1) parse-symbol second' symbol resolve-ns)
:else
(some-> token parse-symbol second'))]
(let [ch (read-past whitespace? rdr)]
(if (identical? ch \{)
(let [items (read-delimited :namespaced-map \} rdr opts pending-forms)
[end-line end-column] (ending-line-col-info rdr)]
(when (odd? (count items))
(err/throw-odd-map rdr nil nil items))
(let [keys (namespace-keys (str ns) (take-nth 2 items))
vals (take-nth 2 (rest items))]
(when-not (= (count (set keys)) (count keys))
(err/throw-dup-keys rdr :namespaced-map keys))
(with-meta (zipmap keys vals)
(when start-line
(merge
(when-let [file (get-file-name rdr)]
{:file file})
{:line start-line
:column start-column
:end-line end-line
:end-column end-column})))))
(err/throw-ns-map-no-map rdr token)))
(err/throw-bad-ns rdr token))))
(defn- macros [ch]
(case ch
\" read-string*
\: read-keyword
\; read-comment
\' (wrapping-reader 'quote)
\@ (wrapping-reader 'clojure.core/deref)
\^ read-meta
\` read-syntax-quote
\~ read-unquote
\( read-list
\) read-unmatched-delimiter
\[ read-vector
\] read-unmatched-delimiter
\{ read-map
\} read-unmatched-delimiter
\\ read-char*
\% read-arg
\# read-dispatch
nil))
(defn- dispatch-macros [ch]
(case ch
\^ read-meta ;; deprecated
\' (wrapping-reader 'var)
\( read-fn
\{ read-set
\< (throwing-reader "Unreadable form")
\= (throwing-reader "read-eval not supported")
\" read-regex
\! read-comment
\_ read-discard
\? read-cond
\: read-namespaced-map
\# read-symbolic-value
nil))
(defn- read-tagged [^not-native rdr initch opts pending-forms]
(let [tag (read* rdr true nil opts pending-forms)]
(if-not (symbol? tag)
(err/throw-bad-reader-tag rdr tag))
(if *suppress-read*
(tagged-literal tag (read* rdr true nil opts pending-forms))
(if-let [f (or (*data-readers* tag)
(default-data-readers tag))]
(f (read* rdr true nil opts pending-forms))
(if-let [f *default-data-reader-fn*]
(f tag (read* rdr true nil opts pending-forms))
(err/throw-unknown-reader-tag rdr tag))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Public API
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:dynamic *data-readers*
"Map from reader tag symbols to data reader Vars.
Reader tags without namespace qualifiers are reserved for Clojure.
This light version of tools.reader has no implementation for default
reader tags such as #inst and #uuid."
{})
(def ^:dynamic *default-data-reader-fn*
"When no data reader is found for a tag and *default-data-reader-fn*
is non-nil, it will be called with two arguments, the tag and the value.
If *default-data-reader-fn* is nil (the default value), an exception
will be thrown for the unknown tag."
nil)
(def ^:dynamic *suppress-read* false)
(def default-data-readers
"Default map of data reader functions provided by Clojure.
May be overridden by binding *data-readers*"
{})
(defn- read*-internal
[^not-native reader ^boolean eof-error? sentinel return-on opts pending-forms]
(loop []
(log-source reader
(if-not ^boolean (garray/isEmpty pending-forms)
(let [form (aget pending-forms 0)]
(garray/removeAt pending-forms 0)
form)
(let [ch (read-char reader)]
(cond
(whitespace? ch) (recur)
(nil? ch) (if eof-error? (err/throw-eof-error reader nil) sentinel)
(identical? ch return-on) READ_FINISHED
(number-literal? reader ch) (read-number reader ch)
:else (let [f (macros ch)]
(if-not (nil? f)
(let [res (f reader ch opts pending-forms)]
(if (identical? res reader)
(recur)
res))
(read-symbol reader ch)))))))))
(defn- read*
([reader eof-error? sentinel opts pending-forms]
(read* reader eof-error? sentinel nil opts pending-forms))
([^not-native reader eof-error? sentinel return-on opts pending-forms]
(try
(read*-internal reader eof-error? sentinel return-on opts pending-forms)
(catch js/Error e
(if (ex-info? e)
(let [d (ex-data e)]
(if (= :reader-exception (:type d))
(throw e)
(throw (ex-info (.-message e)
(merge {:type :reader-exception}
d
(if (indexing-reader? reader)
{:line (get-line-number reader)
:column (get-column-number reader)
:file (get-file-name reader)}))
e))))
(throw (ex-info (.-message e)
(merge {:type :reader-exception}
(if (indexing-reader? reader)
{:line (get-line-number reader)
:column (get-column-number reader)
:file (get-file-name reader)}))
e)))))))
(defn read
"Reads the first object from an IPushbackReader.
Returns the object read. If EOF, throws if eof-error? is true.
Otherwise returns sentinel. If no stream is provided, *in* will be used.
Opts is a persistent map with valid keys:
:read-cond - :allow to process reader conditionals, or
:preserve to keep all branches
:features - persistent set of feature keywords for reader conditionals
:eof - on eof, return value unless :eofthrow, then throw.
if not specified, will throw
To read data structures only, use cljs.tools.reader.edn/read
Note that the function signature of cljs.tools.reader/read and
cljs.tools.reader.edn/read is not the same for eof-handling"
{:arglists '([reader] [opts reader] [reader eof-error? eof-value])}
([reader] (read reader true nil))
([{eof :eof :as opts :or {eof :eofthrow}} reader] (read* reader (= eof :eofthrow) eof nil opts (to-array [])))
([reader eof-error? sentinel] (read* reader eof-error? sentinel nil {} (to-array []))))
(defn read-string
"Reads one object from the string s.
Returns nil when s is nil or empty.
To read data structures only, use cljs.tools.reader.edn/read-string
Note that the function signature of cljs.tools.reader/read-string and
cljs.tools.reader.edn/read-string is not the same for eof-handling"
([s]
(read-string {} s))
([opts s]
(when (and s (not (identical? s "")))
(read opts (string-push-back-reader s)))))
(defn read+string
"Like read, and taking the same args. reader must be a SourceLoggingPushbackReader.
Returns a vector containing the object read and the (whitespace-trimmed) string read."
([stream] (read+string stream true nil))
([stream eof-error? eof-value]
(let [buf (fn [stream] (str (:buffer @(.-frames stream))))
offset (count (buf stream))
o (log-source stream (read stream eof-error? eof-value))
s (.trim (subs (buf stream) offset))]
[o s]))
([opts stream]
(let [buf (fn [stream] (str (:buffer @(.-frames stream))))
offset (count (buf stream))
o (log-source stream (read opts stream))
s (.trim (subs (buf stream) offset))]
[o s])))
+1816
View File
File diff suppressed because it is too large Load Diff
+446
View File
@@ -0,0 +1,446 @@
;; Copyright (c) Nicola Mometto, Rich Hickey & contributors.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns ^{:doc "An EDN reader in clojure"
:author "Bronsa"}
cljs.tools.reader.edn
(:refer-clojure :exclude [read read-string char default-data-readers])
(:require [cljs.tools.reader.impl.errors :as err]
[cljs.tools.reader.reader-types :refer
[read-char unread peek-char indexing-reader?
get-line-number get-column-number get-file-name string-push-back-reader]]
[cljs.tools.reader.impl.utils :refer
[char ex-info? whitespace? numeric? desugar-meta namespace-keys second' char-code]]
[cljs.tools.reader.impl.commons :refer
[number-literal? read-past match-number parse-symbol read-comment throwing-reader]]
[cljs.tools.reader :refer [default-data-readers]]
[goog.string :as gstring])
(:import goog.string.StringBuffer))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(declare read macros dispatch-macros)
(defn- ^boolean macro-terminating? [ch]
(and (not (identical? \# ch))
(not (identical? \' ch))
(not (identical? \: ch))
(macros ch)))
(defn- ^boolean not-constituent? [ch]
(or (identical? \@ ch)
(identical? \` ch)
(identical? \~ ch)))
(defn- read-token
([rdr kind initch]
(read-token rdr kind initch true))
([rdr kind initch validate-leading?]
(cond
(not initch)
(err/throw-eof-at-start rdr kind)
(and validate-leading?
(not-constituent? initch))
(err/throw-bad-char rdr kind initch)
:else
(loop [sb (StringBuffer.)
ch (do (unread rdr initch) initch)]
(if (or (whitespace? ch)
(macro-terminating? ch)
(nil? ch))
(str sb)
(if (not-constituent? ch)
(err/throw-bad-char rdr kind ch)
(recur (doto sb (.append (read-char rdr))) (peek-char rdr))))))))
(declare read-tagged)
(defn- read-dispatch
[rdr _ opts]
(if-let [ch (read-char rdr)]
(if-let [dm (dispatch-macros ch)]
(dm rdr ch opts)
(read-tagged (doto rdr (unread ch)) ch opts))
(err/throw-eof-at-dispatch rdr)))
(defn- read-unmatched-delimiter
[rdr ch opts]
(err/throw-unmatch-delimiter rdr ch))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; readers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- read-unicode-char
([token offset length base]
(let [l (+ offset length)]
(when-not (== (count token) l)
(err/throw-invalid-unicode-literal nil token))
(loop [i offset uc 0]
(if (== i l)
(js/String.fromCharCode uc)
(let [d (char-code (nth token i) base)]
(if (== d -1)
(err/throw-invalid-unicode-digit-in-token nil (nth token i) token)
(recur (inc i) (+ d (* uc base)))))))))
([rdr initch base length exact?]
(loop [i 1 uc (char-code initch base)]
(if (== uc -1)
(err/throw-invalid-unicode-digit rdr initch)
(if-not (== i length)
(let [ch (peek-char rdr)]
(if (or (whitespace? ch)
(macros ch)
(nil? ch))
(if exact?
(err/throw-invalid-unicode-len rdr i length)
(js/String.fromCharCode uc))
(let [d (char-code ch base)]
(read-char rdr)
(if (== d -1)
(err/throw-invalid-unicode-digit rdr ch)
(recur (inc i) (+ d (* uc base)))))))
(js/String.fromCharCode uc))))))
(def ^:private ^:const upper-limit (.charCodeAt \uD7ff 0))
(def ^:private ^:const lower-limit (.charCodeAt \uE000 0))
(defn- read-char*
[rdr backslash opts]
(let [ch (read-char rdr)]
(if-not (nil? ch)
(let [token (if (or (macro-terminating? ch)
(not-constituent? ch)
(whitespace? ch))
(str ch)
(read-token rdr :character ch false))
token-len (count token)]
(cond
(== 1 token-len) (nth token 0)
(identical? token "newline") \newline
(identical? token "space") \space
(identical? token "tab") \tab
(identical? token "backspace") \backspace
(identical? token "formfeed") \formfeed
(identical? token "return") \return
(gstring/startsWith token "u")
(let [c (read-unicode-char token 1 4 16)
ic (.charCodeAt c)]
(if (and (> ic upper-limit)
(< ic lower-limit))
(err/throw-invalid-character-literal rdr (.toString ic 16))
c))
(gstring/startsWith token "o")
(let [len (dec token-len)]
(if (> len 3)
(err/throw-invalid-octal-len rdr token)
(let [uc (read-unicode-char token 1 len 8)]
(if (> (int uc) 0377)
(err/throw-bad-octal-number rdr)
uc))))
:else (err/throw-unsupported-character rdr token)))
(err/throw-eof-in-character rdr))))
(defn ^:private starting-line-col-info [rdr]
(when (indexing-reader? rdr)
[(get-line-number rdr) (int (dec (int (get-column-number rdr))))]))
(defn- read-delimited
[kind delim rdr opts]
(let [[start-line start-column] (starting-line-col-info rdr)
delim (char delim)]
(loop [a (transient [])]
(let [ch (read-past whitespace? rdr)]
(when-not ch
(err/throw-eof-delimited rdr kind start-line start-column (count a)))
(if (= delim (char ch))
(persistent! a)
(if-let [macrofn (macros ch)]
(let [mret (macrofn rdr ch opts)]
(recur (if-not (identical? mret rdr) (conj! a mret) a)))
(let [o (read (doto rdr (unread ch)) true nil opts)]
(recur (if-not (identical? o rdr) (conj! a o) a)))))))))
(defn- read-list
[rdr _ opts]
(let [the-list (read-delimited :list \) rdr opts)]
(if (empty? the-list)
'()
(apply list the-list))))
(defn- read-vector
[rdr _ opts]
(read-delimited :vector \] rdr opts))
(defn- read-map
[rdr _ opts]
(let [[start-line start-column] (starting-line-col-info rdr)
the-map (read-delimited :map \} rdr opts)
map-count (count the-map)
ks (take-nth 2 the-map)
key-set (set ks)]
(when (odd? map-count)
(err/throw-odd-map rdr start-line start-column the-map))
(when-not (= (count key-set) (count ks))
(err/throw-dup-keys rdr :map ks))
(if (<= map-count (* 2 (.-HASHMAP-THRESHOLD cljs.core/PersistentArrayMap)))
(.fromArray cljs.core/PersistentArrayMap (to-array the-map) true true)
(.fromArray cljs.core/PersistentHashMap (to-array the-map) true))))
(defn- read-number
[rdr initch opts]
(loop [sb (doto (StringBuffer.) (.append initch))
ch (read-char rdr)]
(if (or (whitespace? ch) (macros ch) (nil? ch))
(let [s (str sb)]
(unread rdr ch)
(or (match-number s)
(err/throw-invalid-number rdr s)))
(recur (doto sb (.append ch)) (read-char rdr)))))
(defn- escape-char [sb rdr]
(let [ch (read-char rdr)]
(case ch
\t "\t"
\r "\r"
\n "\n"
\\ "\\"
\" "\""
\b "\b"
\f "\f"
\u (let [ch (read-char rdr)]
(if (== -1 (js/parseInt (int ch) 16))
(err/throw-invalid-unicode-escape rdr ch)
(read-unicode-char rdr ch 16 4 true)))
(if (numeric? ch)
(let [ch (read-unicode-char rdr ch 8 3 false)]
(if (> (int ch) 0377)
(err/throw-bad-octal-number rdr)
ch))
(err/throw-bad-escape-char rdr ch)))))
(defn- read-string*
[rdr _ opts]
(loop [sb (StringBuffer.)
ch (read-char rdr)]
(case ch
nil (err/throw-eof-reading rdr :string \" sb)
\\ (recur (doto sb (.append (escape-char sb rdr)))
(read-char rdr))
\" (str sb)
(recur (doto sb (.append ch)) (read-char rdr)))))
(defn- read-symbol
[rdr initch]
(when-let [token (read-token rdr :symbol initch)]
(case token
;; special symbols
"nil" nil
"true" true
"false" false
"/" '/
(or (when-let [p (parse-symbol token)]
(symbol (p 0) (p 1)))
(err/throw-invalid rdr :symbol token)))))
(defn- read-keyword
[reader initch opts]
(let [ch (read-char reader)]
(if-not (whitespace? ch)
(let [token (read-token reader :keyword ch)
s (parse-symbol token)]
(if (and s (== -1 (.indexOf token "::")))
(let [ns (s 0)
name (s 1)]
(if (identical? \: (nth token 0))
(err/throw-invalid reader :keyword (str \: token)) ;; no ::keyword in edn
(keyword ns name)))
(err/throw-invalid reader :keyword (str \: token))))
(err/throw-single-colon reader))))
(defn- wrapping-reader
[sym]
(fn [rdr _ opts]
(list sym (read rdr true nil opts))))
(defn- read-meta
[rdr _ opts]
(let [m (desugar-meta (read rdr true nil opts))]
(when-not (map? m)
(err/throw-bad-metadata rdr m))
(let [o (read rdr true nil opts)]
(if (implements? IMeta o)
(with-meta o (merge (meta o) m))
(err/throw-bad-metadata-target rdr o)))))
(defn- read-set
[rdr _ opts]
(let [coll (read-delimited :set \} rdr opts)
the-set (set coll)]
(when-not (= (count coll) (count the-set))
(err/throw-dup-keys rdr :set coll))
the-set))
(defn- read-discard
[rdr _ opts]
(doto rdr
(read true nil true)))
(defn- read-namespaced-map
[rdr _ opts]
(let [token (read-token rdr :namespaced-map (read-char rdr))]
(if-let [ns (some-> token parse-symbol second')]
(let [ch (read-past whitespace? rdr)]
(if (identical? ch \{)
(let [items (read-delimited :namespaced-map \} rdr opts)]
(when (odd? (count items))
(err/throw-odd-map rdr nil nil items))
(let [keys (namespace-keys (str ns) (take-nth 2 items))
vals (take-nth 2 (rest items))]
(when-not (= (count (set keys)) (count keys))
(err/throw-dup-keys rdr :namespaced-map keys))
(zipmap keys vals)))
(err/throw-ns-map-no-map rdr token)))
(err/throw-bad-ns rdr token))))
(defn- read-symbolic-value
[rdr _ opts]
(let [sym (read rdr true nil opts)]
(case sym
NaN js/Number.NaN
-Inf js/Number.NEGATIVE_INFINITY
Inf js/Number.POSITIVE_INFINITY
(err/reader-error rdr (str "Invalid token: ##" sym)))))
(defn- macros [ch]
(case ch
\" read-string*
\: read-keyword
\; read-comment
\^ read-meta
\( read-list
\) read-unmatched-delimiter
\[ read-vector
\] read-unmatched-delimiter
\{ read-map
\} read-unmatched-delimiter
\\ read-char*
\# read-dispatch
nil))
(defn- dispatch-macros [ch]
(case ch
\^ read-meta ;deprecated
\{ read-set
\< (throwing-reader "Unreadable form")
\! read-comment
\_ read-discard
\: read-namespaced-map
\# read-symbolic-value
nil))
(defn- read-tagged [rdr initch opts]
(let [tag (read rdr true nil opts)
object (read rdr true nil opts)]
(if-not (symbol? tag)
(err/throw-bad-reader-tag rdr "Reader tag must be a symbol"))
(if-let [f (or (get (:readers opts) tag)
(default-data-readers tag))]
(f object)
(if-let [d (:default opts)]
(d tag object)
(err/throw-unknown-reader-tag rdr tag)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Public API
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn read
"Reads the first object from an IPushbackReader.
Returns the object read. If EOF, throws if eof-error? is true otherwise returns eof.
If no reader is provided, *in* will be used.
Reads data in the edn format (subset of Clojure data):
http://edn-format.org
cljs.tools.reader.edn/read doesn't depend on dynamic Vars, all configuration
is done by passing an opt map.
opts is a map that can include the following keys:
:eof - value to return on end-of-file. When not supplied, eof throws an exception.
:readers - a map of tag symbols to data-reader functions to be considered before default-data-readers.
When not supplied, only the default-data-readers will be used.
:default - A function of two args, that will, if present and no reader is found for a tag,
be called with the tag and the value."
([reader] (read {} reader))
([{:keys [eof] :as opts} reader]
(let [eof-error? (not (contains? opts :eof))]
(read reader eof-error? eof opts)))
([reader eof-error? eof opts]
(try
(loop []
(let [ch (read-char reader)]
(cond
(whitespace? ch) (recur)
(nil? ch) (if eof-error? (err/throw-eof-error reader nil) eof)
(number-literal? reader ch) (read-number reader ch opts)
:else (let [f (macros ch)]
(if f
(let [res (f reader ch opts)]
(if (identical? res reader)
(recur)
res))
(read-symbol reader ch))))))
(catch js/Error e
(if (ex-info? e)
(let [d (ex-data e)]
(if (= :reader-exception (:type d))
(throw e)
(throw (ex-info (.-message e)
(merge {:type :reader-exception}
d
(if (indexing-reader? reader)
{:line (get-line-number reader)
:column (get-column-number reader)
:file (get-file-name reader)}))
e))))
(throw (ex-info (.-message e)
(merge {:type :reader-exception}
(if (indexing-reader? reader)
{:line (get-line-number reader)
:column (get-column-number reader)
:file (get-file-name reader)}))
e)))))))
(defn read-string
"Reads one object from the string s.
Returns nil when s is nil or empty.
Reads data in the edn format (subset of Clojure data):
http://edn-format.org
opts is a map as per cljs.tools.reader.edn/read"
([s] (read-string {:eof nil} s))
([opts s]
(when (and s (not= s ""))
(read opts (string-push-back-reader s)))))
+934
View File
@@ -0,0 +1,934 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.tools.reader.edn');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.tools.reader.impl.errors');
goog.require('cljs.tools.reader.reader_types');
goog.require('cljs.tools.reader.impl.utils');
goog.require('cljs.tools.reader.impl.commons');
goog.require('cljs.tools.reader');
goog.require('goog.string');
goog.require('goog.string.StringBuffer');
cljs.tools.reader.edn.macro_terminating_QMARK_ = (function cljs$tools$reader$edn$macro_terminating_QMARK_(ch){
var and__5043__auto__ = (!(("#" === ch)));
if(and__5043__auto__){
var and__5043__auto____$1 = (!(("'" === ch)));
if(and__5043__auto____$1){
var and__5043__auto____$2 = (!((":" === ch)));
if(and__5043__auto____$2){
return (cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1 ? cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1(ch) : cljs.tools.reader.edn.macros.call(null,ch));
} else {
return and__5043__auto____$2;
}
} else {
return and__5043__auto____$1;
}
} else {
return and__5043__auto__;
}
});
cljs.tools.reader.edn.not_constituent_QMARK_ = (function cljs$tools$reader$edn$not_constituent_QMARK_(ch){
return ((("@" === ch)) || (((("`" === ch)) || (("~" === ch)))));
});
cljs.tools.reader.edn.read_token = (function cljs$tools$reader$edn$read_token(var_args){
var G__5893 = arguments.length;
switch (G__5893) {
case 3:
return cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
case 4:
return cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$4((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$3 = (function (rdr,kind,initch){
return cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$4(rdr,kind,initch,true);
}));
(cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$4 = (function (rdr,kind,initch,validate_leading_QMARK_){
if(cljs.core.not(initch)){
return cljs.tools.reader.impl.errors.throw_eof_at_start(rdr,kind);
} else {
if(cljs.core.truth_((function (){var and__5043__auto__ = validate_leading_QMARK_;
if(cljs.core.truth_(and__5043__auto__)){
return cljs.tools.reader.edn.not_constituent_QMARK_(initch);
} else {
return and__5043__auto__;
}
})())){
return cljs.tools.reader.impl.errors.throw_bad_char(rdr,kind,initch);
} else {
var sb = (new goog.string.StringBuffer());
var ch = (function (){
cljs.tools.reader.reader_types.unread(rdr,initch);
return initch;
})()
;
while(true){
if(((cljs.tools.reader.impl.utils.whitespace_QMARK_(ch)) || (((cljs.tools.reader.edn.macro_terminating_QMARK_(ch)) || ((ch == null)))))){
return cljs.core.str.cljs$core$IFn$_invoke$arity$1(sb);
} else {
if(cljs.tools.reader.edn.not_constituent_QMARK_(ch)){
return cljs.tools.reader.impl.errors.throw_bad_char(rdr,kind,ch);
} else {
var G__5896 = (function (){var G__5894 = sb;
G__5894.append(cljs.tools.reader.reader_types.read_char(rdr));
return G__5894;
})();
var G__5897 = cljs.tools.reader.reader_types.peek_char(rdr);
sb = G__5896;
ch = G__5897;
continue;
}
}
break;
}
}
}
}));
(cljs.tools.reader.edn.read_token.cljs$lang$maxFixedArity = 4);
cljs.tools.reader.edn.read_dispatch = (function cljs$tools$reader$edn$read_dispatch(rdr,_,opts){
var temp__4655__auto__ = cljs.tools.reader.reader_types.read_char(rdr);
if(cljs.core.truth_(temp__4655__auto__)){
var ch = temp__4655__auto__;
var temp__4655__auto____$1 = (cljs.tools.reader.edn.dispatch_macros.cljs$core$IFn$_invoke$arity$1 ? cljs.tools.reader.edn.dispatch_macros.cljs$core$IFn$_invoke$arity$1(ch) : cljs.tools.reader.edn.dispatch_macros.call(null,ch));
if(cljs.core.truth_(temp__4655__auto____$1)){
var dm = temp__4655__auto____$1;
return (dm.cljs$core$IFn$_invoke$arity$3 ? dm.cljs$core$IFn$_invoke$arity$3(rdr,ch,opts) : dm.call(null,rdr,ch,opts));
} else {
var G__5898 = (function (){var G__5901 = rdr;
cljs.tools.reader.reader_types.unread(G__5901,ch);
return G__5901;
})();
var G__5899 = ch;
var G__5900 = opts;
return (cljs.tools.reader.edn.read_tagged.cljs$core$IFn$_invoke$arity$3 ? cljs.tools.reader.edn.read_tagged.cljs$core$IFn$_invoke$arity$3(G__5898,G__5899,G__5900) : cljs.tools.reader.edn.read_tagged.call(null,G__5898,G__5899,G__5900));
}
} else {
return cljs.tools.reader.impl.errors.throw_eof_at_dispatch(rdr);
}
});
cljs.tools.reader.edn.read_unmatched_delimiter = (function cljs$tools$reader$edn$read_unmatched_delimiter(rdr,ch,opts){
return cljs.tools.reader.impl.errors.throw_unmatch_delimiter(rdr,ch);
});
cljs.tools.reader.edn.read_unicode_char = (function cljs$tools$reader$edn$read_unicode_char(var_args){
var G__5903 = arguments.length;
switch (G__5903) {
case 4:
return cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$4((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]));
break;
case 5:
return cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$5((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]),(arguments[(4)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$4 = (function (token,offset,length,base){
var l = (offset + length);
if((cljs.core.count(token) === l)){
} else {
cljs.tools.reader.impl.errors.throw_invalid_unicode_literal(null,token);
}
var i = offset;
var uc = (0);
while(true){
if((i === l)){
return String.fromCharCode(uc);
} else {
var d = cljs.tools.reader.impl.utils.char_code(cljs.core.nth.cljs$core$IFn$_invoke$arity$2(token,i),base);
if((d === (-1))){
return cljs.tools.reader.impl.errors.throw_invalid_unicode_digit_in_token(null,cljs.core.nth.cljs$core$IFn$_invoke$arity$2(token,i),token);
} else {
var G__5905 = (i + (1));
var G__5906 = (d + (uc * base));
i = G__5905;
uc = G__5906;
continue;
}
}
break;
}
}));
(cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$5 = (function (rdr,initch,base,length,exact_QMARK_){
var i = (1);
var uc = cljs.tools.reader.impl.utils.char_code(initch,base);
while(true){
if((uc === (-1))){
return cljs.tools.reader.impl.errors.throw_invalid_unicode_digit(rdr,initch);
} else {
if((!((i === length)))){
var ch = cljs.tools.reader.reader_types.peek_char(rdr);
if(cljs.core.truth_((function (){var or__5045__auto__ = cljs.tools.reader.impl.utils.whitespace_QMARK_(ch);
if(or__5045__auto__){
return or__5045__auto__;
} else {
var or__5045__auto____$1 = (cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1 ? cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1(ch) : cljs.tools.reader.edn.macros.call(null,ch));
if(cljs.core.truth_(or__5045__auto____$1)){
return or__5045__auto____$1;
} else {
return (ch == null);
}
}
})())){
if(cljs.core.truth_(exact_QMARK_)){
return cljs.tools.reader.impl.errors.throw_invalid_unicode_len(rdr,i,length);
} else {
return String.fromCharCode(uc);
}
} else {
var d = cljs.tools.reader.impl.utils.char_code(ch,base);
cljs.tools.reader.reader_types.read_char(rdr);
if((d === (-1))){
return cljs.tools.reader.impl.errors.throw_invalid_unicode_digit(rdr,ch);
} else {
var G__5907 = (i + (1));
var G__5908 = (d + (uc * base));
i = G__5907;
uc = G__5908;
continue;
}
}
} else {
return String.fromCharCode(uc);
}
}
break;
}
}));
(cljs.tools.reader.edn.read_unicode_char.cljs$lang$maxFixedArity = 5);
cljs.tools.reader.edn.upper_limit = "\uD7FF".charCodeAt((0));
cljs.tools.reader.edn.lower_limit = "\uE000".charCodeAt((0));
cljs.tools.reader.edn.read_char_STAR_ = (function cljs$tools$reader$edn$read_char_STAR_(rdr,backslash,opts){
var ch = cljs.tools.reader.reader_types.read_char(rdr);
if((!((ch == null)))){
var token = ((((cljs.tools.reader.edn.macro_terminating_QMARK_(ch)) || (((cljs.tools.reader.edn.not_constituent_QMARK_(ch)) || (cljs.tools.reader.impl.utils.whitespace_QMARK_(ch))))))?cljs.core.str.cljs$core$IFn$_invoke$arity$1(ch):cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$4(rdr,cljs.core.cst$kw$character,ch,false));
var token_len = ((token).length);
if(((1) === token_len)){
return cljs.core.nth.cljs$core$IFn$_invoke$arity$2(token,(0));
} else {
if((token === "newline")){
return "\n";
} else {
if((token === "space")){
return " ";
} else {
if((token === "tab")){
return "\t";
} else {
if((token === "backspace")){
return "\b";
} else {
if((token === "formfeed")){
return "\f";
} else {
if((token === "return")){
return "\r";
} else {
if(goog.string.startsWith(token,"u")){
var c = cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$4(token,(1),(4),(16));
var ic = c.charCodeAt();
if((((ic > cljs.tools.reader.edn.upper_limit)) && ((ic < cljs.tools.reader.edn.lower_limit)))){
return cljs.tools.reader.impl.errors.throw_invalid_character_literal(rdr,ic.toString((16)));
} else {
return c;
}
} else {
if(goog.string.startsWith(token,"o")){
var len = (token_len - (1));
if((len > (3))){
return cljs.tools.reader.impl.errors.throw_invalid_octal_len(rdr,token);
} else {
var uc = cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$4(token,(1),len,(8));
if(((uc | (0)) > (255))){
return cljs.tools.reader.impl.errors.throw_bad_octal_number(rdr);
} else {
return uc;
}
}
} else {
return cljs.tools.reader.impl.errors.throw_unsupported_character(rdr,token);
}
}
}
}
}
}
}
}
}
} else {
return cljs.tools.reader.impl.errors.throw_eof_in_character(rdr);
}
});
cljs.tools.reader.edn.starting_line_col_info = (function cljs$tools$reader$edn$starting_line_col_info(rdr){
if(cljs.tools.reader.reader_types.indexing_reader_QMARK_(rdr)){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.tools.reader.reader_types.get_line_number(rdr),(((cljs.tools.reader.reader_types.get_column_number(rdr) | (0)) - (1)) | (0))], null);
} else {
return null;
}
});
cljs.tools.reader.edn.read_delimited = (function cljs$tools$reader$edn$read_delimited(kind,delim,rdr,opts){
var vec__5909 = cljs.tools.reader.edn.starting_line_col_info(rdr);
var start_line = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5909,(0),null);
var start_column = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5909,(1),null);
var delim__$1 = cljs.tools.reader.impl.utils.char$(delim);
var a = cljs.core.transient$(cljs.core.PersistentVector.EMPTY);
while(true){
var ch = cljs.tools.reader.impl.commons.read_past(cljs.tools.reader.impl.utils.whitespace_QMARK_,rdr);
if(cljs.core.truth_(ch)){
} else {
cljs.tools.reader.impl.errors.throw_eof_delimited.cljs$core$IFn$_invoke$arity$5(rdr,kind,start_line,start_column,cljs.core.count(a));
}
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(delim__$1,cljs.tools.reader.impl.utils.char$(ch))){
return cljs.core.persistent_BANG_(a);
} else {
var temp__4655__auto__ = (cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1 ? cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1(ch) : cljs.tools.reader.edn.macros.call(null,ch));
if(cljs.core.truth_(temp__4655__auto__)){
var macrofn = temp__4655__auto__;
var mret = (macrofn.cljs$core$IFn$_invoke$arity$3 ? macrofn.cljs$core$IFn$_invoke$arity$3(rdr,ch,opts) : macrofn.call(null,rdr,ch,opts));
var G__5917 = (((!((mret === rdr))))?cljs.core.conj_BANG_.cljs$core$IFn$_invoke$arity$2(a,mret):a);
a = G__5917;
continue;
} else {
var o = (function (){var G__5912 = (function (){var G__5916 = rdr;
cljs.tools.reader.reader_types.unread(G__5916,ch);
return G__5916;
})();
var G__5913 = true;
var G__5914 = null;
var G__5915 = opts;
return (cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(G__5912,G__5913,G__5914,G__5915) : cljs.tools.reader.edn.read.call(null,G__5912,G__5913,G__5914,G__5915));
})();
var G__5918 = (((!((o === rdr))))?cljs.core.conj_BANG_.cljs$core$IFn$_invoke$arity$2(a,o):a);
a = G__5918;
continue;
}
}
break;
}
});
cljs.tools.reader.edn.read_list = (function cljs$tools$reader$edn$read_list(rdr,_,opts){
var the_list = cljs.tools.reader.edn.read_delimited(cljs.core.cst$kw$list,")",rdr,opts);
if(cljs.core.empty_QMARK_(the_list)){
return cljs.core.List.EMPTY;
} else {
return cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.list,the_list);
}
});
cljs.tools.reader.edn.read_vector = (function cljs$tools$reader$edn$read_vector(rdr,_,opts){
return cljs.tools.reader.edn.read_delimited(cljs.core.cst$kw$vector,"]",rdr,opts);
});
cljs.tools.reader.edn.read_map = (function cljs$tools$reader$edn$read_map(rdr,_,opts){
var vec__5919 = cljs.tools.reader.edn.starting_line_col_info(rdr);
var start_line = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5919,(0),null);
var start_column = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5919,(1),null);
var the_map = cljs.tools.reader.edn.read_delimited(cljs.core.cst$kw$map,"}",rdr,opts);
var map_count = cljs.core.count(the_map);
var ks = cljs.core.take_nth.cljs$core$IFn$_invoke$arity$2((2),the_map);
var key_set = cljs.core.set(ks);
if(cljs.core.odd_QMARK_(map_count)){
cljs.tools.reader.impl.errors.throw_odd_map(rdr,start_line,start_column,the_map);
} else {
}
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.count(key_set),cljs.core.count(ks))){
} else {
cljs.tools.reader.impl.errors.throw_dup_keys(rdr,cljs.core.cst$kw$map,ks);
}
if((map_count <= ((2) * cljs.core.PersistentArrayMap.HASHMAP_THRESHOLD))){
return cljs.core.PersistentArrayMap.fromArray(cljs.core.to_array(the_map),true,true);
} else {
return cljs.core.PersistentHashMap.fromArray(cljs.core.to_array(the_map),true);
}
});
cljs.tools.reader.edn.read_number = (function cljs$tools$reader$edn$read_number(rdr,initch,opts){
var sb = (function (){var G__5922 = (new goog.string.StringBuffer());
G__5922.append(initch);
return G__5922;
})();
var ch = cljs.tools.reader.reader_types.read_char(rdr);
while(true){
if(cljs.core.truth_((function (){var or__5045__auto__ = cljs.tools.reader.impl.utils.whitespace_QMARK_(ch);
if(or__5045__auto__){
return or__5045__auto__;
} else {
var or__5045__auto____$1 = (cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1 ? cljs.tools.reader.edn.macros.cljs$core$IFn$_invoke$arity$1(ch) : cljs.tools.reader.edn.macros.call(null,ch));
if(cljs.core.truth_(or__5045__auto____$1)){
return or__5045__auto____$1;
} else {
return (ch == null);
}
}
})())){
var s = cljs.core.str.cljs$core$IFn$_invoke$arity$1(sb);
cljs.tools.reader.reader_types.unread(rdr,ch);
var or__5045__auto__ = cljs.tools.reader.impl.commons.match_number(s);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return cljs.tools.reader.impl.errors.throw_invalid_number(rdr,s);
}
} else {
var G__5924 = (function (){var G__5923 = sb;
G__5923.append(ch);
return G__5923;
})();
var G__5925 = cljs.tools.reader.reader_types.read_char(rdr);
sb = G__5924;
ch = G__5925;
continue;
}
break;
}
});
cljs.tools.reader.edn.escape_char = (function cljs$tools$reader$edn$escape_char(sb,rdr){
var ch = cljs.tools.reader.reader_types.read_char(rdr);
var G__5926 = ch;
switch (G__5926) {
case "t":
return "\t";
break;
case "r":
return "\r";
break;
case "n":
return "\n";
break;
case "\\":
return "\\";
break;
case "\"":
return "\"";
break;
case "b":
return "\b";
break;
case "f":
return "\f";
break;
case "u":
var ch__$1 = cljs.tools.reader.reader_types.read_char(rdr);
if(((-1) === parseInt((ch__$1 | (0)),(16)))){
return cljs.tools.reader.impl.errors.throw_invalid_unicode_escape(rdr,ch__$1);
} else {
return cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$5(rdr,ch__$1,(16),(4),true);
}
break;
default:
if(cljs.tools.reader.impl.utils.numeric_QMARK_(ch)){
var ch__$1 = cljs.tools.reader.edn.read_unicode_char.cljs$core$IFn$_invoke$arity$5(rdr,ch,(8),(3),false);
if(((ch__$1 | (0)) > (255))){
return cljs.tools.reader.impl.errors.throw_bad_octal_number(rdr);
} else {
return ch__$1;
}
} else {
return cljs.tools.reader.impl.errors.throw_bad_escape_char(rdr,ch);
}
}
});
cljs.tools.reader.edn.read_string_STAR_ = (function cljs$tools$reader$edn$read_string_STAR_(rdr,_,opts){
var sb = (new goog.string.StringBuffer());
var ch = cljs.tools.reader.reader_types.read_char(rdr);
while(true){
var G__5928 = ch;
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(null,G__5928)){
return cljs.tools.reader.impl.errors.throw_eof_reading.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.cst$kw$string,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["\"",sb], 0));
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2("\\",G__5928)){
var G__5931 = (function (){var G__5929 = sb;
G__5929.append(cljs.tools.reader.edn.escape_char(sb,rdr));
return G__5929;
})();
var G__5932 = cljs.tools.reader.reader_types.read_char(rdr);
sb = G__5931;
ch = G__5932;
continue;
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2("\"",G__5928)){
return cljs.core.str.cljs$core$IFn$_invoke$arity$1(sb);
} else {
var G__5933 = (function (){var G__5930 = sb;
G__5930.append(ch);
return G__5930;
})();
var G__5934 = cljs.tools.reader.reader_types.read_char(rdr);
sb = G__5933;
ch = G__5934;
continue;
}
}
}
break;
}
});
cljs.tools.reader.edn.read_symbol = (function cljs$tools$reader$edn$read_symbol(rdr,initch){
var temp__4657__auto__ = cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$3(rdr,cljs.core.cst$kw$symbol,initch);
if(cljs.core.truth_(temp__4657__auto__)){
var token = temp__4657__auto__;
var G__5935 = token;
switch (G__5935) {
case "nil":
return null;
break;
case "true":
return true;
break;
case "false":
return false;
break;
case "/":
return cljs.core.cst$sym$_SLASH_;
break;
default:
var or__5045__auto__ = (function (){var temp__4657__auto____$1 = cljs.tools.reader.impl.commons.parse_symbol(token);
if(cljs.core.truth_(temp__4657__auto____$1)){
var p = temp__4657__auto____$1;
return cljs.core.symbol.cljs$core$IFn$_invoke$arity$2((p.cljs$core$IFn$_invoke$arity$1 ? p.cljs$core$IFn$_invoke$arity$1((0)) : p.call(null,(0))),(p.cljs$core$IFn$_invoke$arity$1 ? p.cljs$core$IFn$_invoke$arity$1((1)) : p.call(null,(1))));
} else {
return null;
}
})();
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return cljs.tools.reader.impl.errors.throw_invalid(rdr,cljs.core.cst$kw$symbol,token);
}
}
} else {
return null;
}
});
cljs.tools.reader.edn.read_keyword = (function cljs$tools$reader$edn$read_keyword(reader,initch,opts){
var ch = cljs.tools.reader.reader_types.read_char(reader);
if((!(cljs.tools.reader.impl.utils.whitespace_QMARK_(ch)))){
var token = cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$3(reader,cljs.core.cst$kw$keyword,ch);
var s = cljs.tools.reader.impl.commons.parse_symbol(token);
if(cljs.core.truth_((function (){var and__5043__auto__ = s;
if(cljs.core.truth_(and__5043__auto__)){
return ((-1) === token.indexOf("::"));
} else {
return and__5043__auto__;
}
})())){
var ns = (s.cljs$core$IFn$_invoke$arity$1 ? s.cljs$core$IFn$_invoke$arity$1((0)) : s.call(null,(0)));
var name = (s.cljs$core$IFn$_invoke$arity$1 ? s.cljs$core$IFn$_invoke$arity$1((1)) : s.call(null,(1)));
if((":" === cljs.core.nth.cljs$core$IFn$_invoke$arity$2(token,(0)))){
return cljs.tools.reader.impl.errors.throw_invalid(reader,cljs.core.cst$kw$keyword,[":",cljs.core.str.cljs$core$IFn$_invoke$arity$1(token)].join(''));
} else {
return cljs.core.keyword.cljs$core$IFn$_invoke$arity$2(ns,name);
}
} else {
return cljs.tools.reader.impl.errors.throw_invalid(reader,cljs.core.cst$kw$keyword,[":",cljs.core.str.cljs$core$IFn$_invoke$arity$1(token)].join(''));
}
} else {
return cljs.tools.reader.impl.errors.throw_single_colon(reader);
}
});
cljs.tools.reader.edn.wrapping_reader = (function cljs$tools$reader$edn$wrapping_reader(sym){
return (function (rdr,_,opts){
return (new cljs.core.List(null,sym,(new cljs.core.List(null,(cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(rdr,true,null,opts) : cljs.tools.reader.edn.read.call(null,rdr,true,null,opts)),null,(1),null)),(2),null));
});
});
cljs.tools.reader.edn.read_meta = (function cljs$tools$reader$edn$read_meta(rdr,_,opts){
var m = cljs.tools.reader.impl.utils.desugar_meta((cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(rdr,true,null,opts) : cljs.tools.reader.edn.read.call(null,rdr,true,null,opts)));
if(cljs.core.map_QMARK_(m)){
} else {
cljs.tools.reader.impl.errors.throw_bad_metadata(rdr,m);
}
var o = (cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(rdr,true,null,opts) : cljs.tools.reader.edn.read.call(null,rdr,true,null,opts));
if((((!((o == null))))?(((((o.cljs$lang$protocol_mask$partition0$ & (131072))) || ((cljs.core.PROTOCOL_SENTINEL === o.cljs$core$IMeta$))))?true:false):false)){
return cljs.core.with_meta(o,cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.meta(o),m], 0)));
} else {
return cljs.tools.reader.impl.errors.throw_bad_metadata_target(rdr,o);
}
});
cljs.tools.reader.edn.read_set = (function cljs$tools$reader$edn$read_set(rdr,_,opts){
var coll = cljs.tools.reader.edn.read_delimited(cljs.core.cst$kw$set,"}",rdr,opts);
var the_set = cljs.core.set(coll);
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.count(coll),cljs.core.count(the_set))){
} else {
cljs.tools.reader.impl.errors.throw_dup_keys(rdr,cljs.core.cst$kw$set,coll);
}
return the_set;
});
cljs.tools.reader.edn.read_discard = (function cljs$tools$reader$edn$read_discard(rdr,_,opts){
var G__5938 = rdr;
(cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(G__5938,true,null,true) : cljs.tools.reader.edn.read.call(null,G__5938,true,null,true));
return G__5938;
});
cljs.tools.reader.edn.read_namespaced_map = (function cljs$tools$reader$edn$read_namespaced_map(rdr,_,opts){
var token = cljs.tools.reader.edn.read_token.cljs$core$IFn$_invoke$arity$3(rdr,cljs.core.cst$kw$namespaced_DASH_map,cljs.tools.reader.reader_types.read_char(rdr));
var temp__4655__auto__ = (function (){var G__5939 = token;
var G__5939__$1 = (((G__5939 == null))?null:cljs.tools.reader.impl.commons.parse_symbol(G__5939));
if((G__5939__$1 == null)){
return null;
} else {
return cljs.tools.reader.impl.utils.second_SINGLEQUOTE_(G__5939__$1);
}
})();
if(cljs.core.truth_(temp__4655__auto__)){
var ns = temp__4655__auto__;
var ch = cljs.tools.reader.impl.commons.read_past(cljs.tools.reader.impl.utils.whitespace_QMARK_,rdr);
if((ch === "{")){
var items = cljs.tools.reader.edn.read_delimited(cljs.core.cst$kw$namespaced_DASH_map,"}",rdr,opts);
if(cljs.core.odd_QMARK_(cljs.core.count(items))){
cljs.tools.reader.impl.errors.throw_odd_map(rdr,null,null,items);
} else {
}
var keys = cljs.tools.reader.impl.utils.namespace_keys(cljs.core.str.cljs$core$IFn$_invoke$arity$1(ns),cljs.core.take_nth.cljs$core$IFn$_invoke$arity$2((2),items));
var vals = cljs.core.take_nth.cljs$core$IFn$_invoke$arity$2((2),cljs.core.rest(items));
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.count(cljs.core.set(keys)),cljs.core.count(keys))){
} else {
cljs.tools.reader.impl.errors.throw_dup_keys(rdr,cljs.core.cst$kw$namespaced_DASH_map,keys);
}
return cljs.core.zipmap(keys,vals);
} else {
return cljs.tools.reader.impl.errors.throw_ns_map_no_map(rdr,token);
}
} else {
return cljs.tools.reader.impl.errors.throw_bad_ns(rdr,token);
}
});
cljs.tools.reader.edn.read_symbolic_value = (function cljs$tools$reader$edn$read_symbolic_value(rdr,_,opts){
var sym = (cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(rdr,true,null,opts) : cljs.tools.reader.edn.read.call(null,rdr,true,null,opts));
var G__5940 = sym;
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.cst$sym$NaN,G__5940)){
return Number.NaN;
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.cst$sym$_DASH_Inf,G__5940)){
return Number.NEGATIVE_INFINITY;
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.cst$sym$Inf,G__5940)){
return Number.POSITIVE_INFINITY;
} else {
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([["Invalid token: ##",cljs.core.str.cljs$core$IFn$_invoke$arity$1(sym)].join('')], 0));
}
}
}
});
cljs.tools.reader.edn.macros = (function cljs$tools$reader$edn$macros(ch){
var G__5941 = ch;
switch (G__5941) {
case "\"":
return cljs.tools.reader.edn.read_string_STAR_;
break;
case ":":
return cljs.tools.reader.edn.read_keyword;
break;
case ";":
return cljs.tools.reader.impl.commons.read_comment;
break;
case "^":
return cljs.tools.reader.edn.read_meta;
break;
case "(":
return cljs.tools.reader.edn.read_list;
break;
case ")":
return cljs.tools.reader.edn.read_unmatched_delimiter;
break;
case "[":
return cljs.tools.reader.edn.read_vector;
break;
case "]":
return cljs.tools.reader.edn.read_unmatched_delimiter;
break;
case "{":
return cljs.tools.reader.edn.read_map;
break;
case "}":
return cljs.tools.reader.edn.read_unmatched_delimiter;
break;
case "\\":
return cljs.tools.reader.edn.read_char_STAR_;
break;
case "#":
return cljs.tools.reader.edn.read_dispatch;
break;
default:
return null;
}
});
cljs.tools.reader.edn.dispatch_macros = (function cljs$tools$reader$edn$dispatch_macros(ch){
var G__5943 = ch;
switch (G__5943) {
case "^":
return cljs.tools.reader.edn.read_meta;
break;
case "{":
return cljs.tools.reader.edn.read_set;
break;
case "<":
return cljs.tools.reader.impl.commons.throwing_reader("Unreadable form");
break;
case "!":
return cljs.tools.reader.impl.commons.read_comment;
break;
case "_":
return cljs.tools.reader.edn.read_discard;
break;
case ":":
return cljs.tools.reader.edn.read_namespaced_map;
break;
case "#":
return cljs.tools.reader.edn.read_symbolic_value;
break;
default:
return null;
}
});
cljs.tools.reader.edn.read_tagged = (function cljs$tools$reader$edn$read_tagged(rdr,initch,opts){
var tag = (cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(rdr,true,null,opts) : cljs.tools.reader.edn.read.call(null,rdr,true,null,opts));
var object = (cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 ? cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(rdr,true,null,opts) : cljs.tools.reader.edn.read.call(null,rdr,true,null,opts));
if((!((tag instanceof cljs.core.Symbol)))){
cljs.tools.reader.impl.errors.throw_bad_reader_tag(rdr,"Reader tag must be a symbol");
} else {
}
var temp__4655__auto__ = (function (){var or__5045__auto__ = cljs.core.get.cljs$core$IFn$_invoke$arity$2(cljs.core.cst$kw$readers.cljs$core$IFn$_invoke$arity$1(opts),tag);
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return (cljs.tools.reader.default_data_readers.cljs$core$IFn$_invoke$arity$1 ? cljs.tools.reader.default_data_readers.cljs$core$IFn$_invoke$arity$1(tag) : cljs.tools.reader.default_data_readers.call(null,tag));
}
})();
if(cljs.core.truth_(temp__4655__auto__)){
var f = temp__4655__auto__;
return (f.cljs$core$IFn$_invoke$arity$1 ? f.cljs$core$IFn$_invoke$arity$1(object) : f.call(null,object));
} else {
var temp__4655__auto____$1 = cljs.core.cst$kw$default.cljs$core$IFn$_invoke$arity$1(opts);
if(cljs.core.truth_(temp__4655__auto____$1)){
var d = temp__4655__auto____$1;
return (d.cljs$core$IFn$_invoke$arity$2 ? d.cljs$core$IFn$_invoke$arity$2(tag,object) : d.call(null,tag,object));
} else {
return cljs.tools.reader.impl.errors.throw_unknown_reader_tag(rdr,tag);
}
}
});
/**
* Reads the first object from an IPushbackReader.
* Returns the object read. If EOF, throws if eof-error? is true otherwise returns eof.
* If no reader is provided, *in* will be used.
*
* Reads data in the edn format (subset of Clojure data):
* http://edn-format.org
*
* cljs.tools.reader.edn/read doesn't depend on dynamic Vars, all configuration
* is done by passing an opt map.
*
* opts is a map that can include the following keys:
* :eof - value to return on end-of-file. When not supplied, eof throws an exception.
* :readers - a map of tag symbols to data-reader functions to be considered before default-data-readers.
* When not supplied, only the default-data-readers will be used.
* :default - A function of two args, that will, if present and no reader is found for a tag,
* be called with the tag and the value.
*/
cljs.tools.reader.edn.read = (function cljs$tools$reader$edn$read(var_args){
var G__5946 = arguments.length;
switch (G__5946) {
case 1:
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 4:
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$1 = (function (reader){
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentArrayMap.EMPTY,reader);
}));
(cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$2 = (function (p__5947,reader){
var map__5948 = p__5947;
var map__5948__$1 = cljs.core.__destructure_map(map__5948);
var opts = map__5948__$1;
var eof = cljs.core.get.cljs$core$IFn$_invoke$arity$2(map__5948__$1,cljs.core.cst$kw$eof);
var eof_error_QMARK_ = (!(cljs.core.contains_QMARK_(opts,cljs.core.cst$kw$eof)));
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4(reader,eof_error_QMARK_,eof,opts);
}));
(cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$4 = (function (reader,eof_error_QMARK_,eof,opts){
try{while(true){
var ch = cljs.tools.reader.reader_types.read_char(reader);
if(cljs.tools.reader.impl.utils.whitespace_QMARK_(ch)){
continue;
} else {
if((ch == null)){
if(cljs.core.truth_(eof_error_QMARK_)){
return cljs.tools.reader.impl.errors.throw_eof_error(reader,null);
} else {
return eof;
}
} else {
if(cljs.tools.reader.impl.commons.number_literal_QMARK_(reader,ch)){
return cljs.tools.reader.edn.read_number(reader,ch,opts);
} else {
var f = cljs.tools.reader.edn.macros(ch);
if(cljs.core.truth_(f)){
var res = (f.cljs$core$IFn$_invoke$arity$3 ? f.cljs$core$IFn$_invoke$arity$3(reader,ch,opts) : f.call(null,reader,ch,opts));
if((res === reader)){
continue;
} else {
return res;
}
} else {
return cljs.tools.reader.edn.read_symbol(reader,ch);
}
}
}
}
break;
}
}catch (e5949){if((e5949 instanceof Error)){
var e = e5949;
if(cljs.tools.reader.impl.utils.ex_info_QMARK_(e)){
var d = cljs.core.ex_data(e);
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.cst$kw$reader_DASH_exception,cljs.core.cst$kw$type.cljs$core$IFn$_invoke$arity$1(d))){
throw e;
} else {
throw cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3(e.message,cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$type,cljs.core.cst$kw$reader_DASH_exception], null),d,((cljs.tools.reader.reader_types.indexing_reader_QMARK_(reader))?new cljs.core.PersistentArrayMap(null, 3, [cljs.core.cst$kw$line,cljs.tools.reader.reader_types.get_line_number(reader),cljs.core.cst$kw$column,cljs.tools.reader.reader_types.get_column_number(reader),cljs.core.cst$kw$file,cljs.tools.reader.reader_types.get_file_name(reader)], null):null)], 0)),e);
}
} else {
throw cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3(e.message,cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$type,cljs.core.cst$kw$reader_DASH_exception], null),((cljs.tools.reader.reader_types.indexing_reader_QMARK_(reader))?new cljs.core.PersistentArrayMap(null, 3, [cljs.core.cst$kw$line,cljs.tools.reader.reader_types.get_line_number(reader),cljs.core.cst$kw$column,cljs.tools.reader.reader_types.get_column_number(reader),cljs.core.cst$kw$file,cljs.tools.reader.reader_types.get_file_name(reader)], null):null)], 0)),e);
}
} else {
throw e5949;
}
}}));
(cljs.tools.reader.edn.read.cljs$lang$maxFixedArity = 4);
/**
* Reads one object from the string s.
* Returns nil when s is nil or empty.
*
* Reads data in the edn format (subset of Clojure data):
* http://edn-format.org
*
* opts is a map as per cljs.tools.reader.edn/read
*/
cljs.tools.reader.edn.read_string = (function cljs$tools$reader$edn$read_string(var_args){
var G__5952 = arguments.length;
switch (G__5952) {
case 1:
return cljs.tools.reader.edn.read_string.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.tools.reader.edn.read_string.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.edn.read_string.cljs$core$IFn$_invoke$arity$1 = (function (s){
return cljs.tools.reader.edn.read_string.cljs$core$IFn$_invoke$arity$2(new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$eof,null], null),s);
}));
(cljs.tools.reader.edn.read_string.cljs$core$IFn$_invoke$arity$2 = (function (opts,s){
if(cljs.core.truth_((function (){var and__5043__auto__ = s;
if(cljs.core.truth_(and__5043__auto__)){
return cljs.core.not_EQ_.cljs$core$IFn$_invoke$arity$2(s,"");
} else {
return and__5043__auto__;
}
})())){
return cljs.tools.reader.edn.read.cljs$core$IFn$_invoke$arity$2(opts,cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$1(s));
} else {
return null;
}
}));
(cljs.tools.reader.edn.read_string.cljs$lang$maxFixedArity = 2);
+131
View File
@@ -0,0 +1,131 @@
;; Copyright (c) Nicola Mometto, Rich Hickey & contributors.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.tools.reader.impl.commons
(:refer-clojure :exclude [char])
(:require
[cljs.tools.reader.impl.errors :refer [reader-error]]
[cljs.tools.reader.reader-types :refer [peek-char read-char]]
[cljs.tools.reader.impl.utils :refer [numeric? newline? char]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn ^boolean number-literal?
"Checks whether the reader is at the start of a number literal"
[^not-native reader initch]
(or (numeric? initch)
(and (or (identical? \+ initch) (identical? \- initch))
(numeric? (peek-char reader)))))
(defn read-past
"Read until first character that doesn't match pred, returning
char."
[pred ^not-native rdr]
(loop [ch (read-char rdr)]
(if ^boolean (pred ch)
(recur (read-char rdr))
ch)))
(defn skip-line
"Advances the reader to the end of a line. Returns the reader"
[^not-native reader]
(loop []
(when-not (newline? (read-char reader))
(recur)))
reader)
(def int-pattern #"^([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)(N)?$")
(def ratio-pattern #"([-+]?[0-9]+)/([0-9]+)")
(def float-pattern #"([-+]?[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?")
(defn- match-int
[s]
(let [m (vec (re-find int-pattern s))]
(if-not (nil? (m 2))
0
(let [^boolean negate? (identical? "-" (m 1))
a (cond
(not (nil? (m 3))) [(m 3) 10]
(not (nil? (m 4))) [(m 4) 16]
(not (nil? (m 5))) [(m 5) 8]
(not (nil? (m 7))) [(m 7) (js/parseInt (m 6))]
:else [nil nil])
n (a 0)]
(when-not (nil? n)
(let [bn (js/parseInt n (a 1))
bn (if negate? (* -1 bn) bn)]
(when-not (js/isNaN bn)
bn)))))))
(defn- match-ratio
[s]
(let [m (vec (re-find ratio-pattern s))
numerator (m 1)
denominator (m 2)
numerator (if (re-find #"^\+" numerator)
(subs numerator 1)
numerator)]
(/ (-> numerator js/parseInt) ;;; No ratio type in cljs
(-> denominator js/parseInt)))); So will convert to js/Number
(defn- match-float
[s]
(let [m (vec (re-find float-pattern s))]
(if-not (nil? (m 4)) ;; for BigDecimal "10.03M", as all parsed to js/Number
(js/parseFloat (m 1))
(js/parseFloat s))))
(defn ^boolean matches? [pattern s]
(let [[match] (re-find pattern s)]
(identical? match s)))
(defn match-number [s]
(if (matches? int-pattern s)
(match-int s)
(if (matches? float-pattern s)
(match-float s)
(when (matches? ratio-pattern s)
(match-ratio s)))))
(defn parse-symbol
"Parses a string into a vector of the namespace and symbol"
[token]
(when-not (or (identical? "" token)
(true? (.test #":$" token))
(true? (.test #"^::" token)))
(let [ns-idx (.indexOf token "/")
ns (when (pos? ns-idx)
(subs token 0 ns-idx))]
(if-not (nil? ns)
(let [ns-idx (inc ns-idx)]
(when-not (== ns-idx (count token))
(let [sym (subs token ns-idx)]
(when (and (not (numeric? (nth sym 0)))
(not (identical? "" sym))
(false? (.test #":$" ns))
(or (identical? sym "/")
(== -1 (.indexOf sym "/"))))
[ns sym]))))
(when (or (identical? token "/")
(== -1 (.indexOf token "/")))
[nil token])))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; readers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn read-comment
[rdr & _]
(skip-line rdr))
(defn throwing-reader
[msg]
(fn [rdr & _]
(reader-error rdr msg)))
+192
View File
@@ -0,0 +1,192 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.tools.reader.impl.commons');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.tools.reader.impl.errors');
goog.require('cljs.tools.reader.reader_types');
goog.require('cljs.tools.reader.impl.utils');
/**
* Checks whether the reader is at the start of a number literal
*/
cljs.tools.reader.impl.commons.number_literal_QMARK_ = (function cljs$tools$reader$impl$commons$number_literal_QMARK_(reader,initch){
return ((cljs.tools.reader.impl.utils.numeric_QMARK_(initch)) || (((((("+" === initch)) || (("-" === initch)))) && (cljs.tools.reader.impl.utils.numeric_QMARK_(reader.cljs$tools$reader$reader_types$Reader$peek_char$arity$1(null))))));
});
/**
* Read until first character that doesn't match pred, returning
* char.
*/
cljs.tools.reader.impl.commons.read_past = (function cljs$tools$reader$impl$commons$read_past(pred,rdr){
var ch = rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null);
while(true){
if((pred.cljs$core$IFn$_invoke$arity$1 ? pred.cljs$core$IFn$_invoke$arity$1(ch) : pred.call(null,ch))){
var G__5357 = rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null);
ch = G__5357;
continue;
} else {
return ch;
}
break;
}
});
/**
* Advances the reader to the end of a line. Returns the reader
*/
cljs.tools.reader.impl.commons.skip_line = (function cljs$tools$reader$impl$commons$skip_line(reader){
while(true){
if(cljs.tools.reader.impl.utils.newline_QMARK_(reader.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null))){
} else {
continue;
}
break;
}
return reader;
});
cljs.tools.reader.impl.commons.int_pattern = /^([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)(N)?$/;
cljs.tools.reader.impl.commons.ratio_pattern = /([-+]?[0-9]+)\/([0-9]+)/;
cljs.tools.reader.impl.commons.float_pattern = /([-+]?[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?/;
cljs.tools.reader.impl.commons.match_int = (function cljs$tools$reader$impl$commons$match_int(s){
var m = cljs.core.vec(cljs.core.re_find(cljs.tools.reader.impl.commons.int_pattern,s));
if((!(((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((2)) : m.call(null,(2))) == null)))){
return (0);
} else {
var negate_QMARK_ = ("-" === (m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((1)) : m.call(null,(1))));
var a = (((!(((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((3)) : m.call(null,(3))) == null))))?new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((3)) : m.call(null,(3))),(10)], null):(((!(((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((4)) : m.call(null,(4))) == null))))?new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((4)) : m.call(null,(4))),(16)], null):(((!(((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((5)) : m.call(null,(5))) == null))))?new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((5)) : m.call(null,(5))),(8)], null):(((!(((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((7)) : m.call(null,(7))) == null))))?new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((7)) : m.call(null,(7))),parseInt((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((6)) : m.call(null,(6))))], null):new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [null,null], null)
))));
var n = (a.cljs$core$IFn$_invoke$arity$1 ? a.cljs$core$IFn$_invoke$arity$1((0)) : a.call(null,(0)));
if((n == null)){
return null;
} else {
var bn = parseInt(n,(a.cljs$core$IFn$_invoke$arity$1 ? a.cljs$core$IFn$_invoke$arity$1((1)) : a.call(null,(1))));
var bn__$1 = ((negate_QMARK_)?((-1) * bn):bn);
if(cljs.core.truth_(isNaN(bn__$1))){
return null;
} else {
return bn__$1;
}
}
}
});
cljs.tools.reader.impl.commons.match_ratio = (function cljs$tools$reader$impl$commons$match_ratio(s){
var m = cljs.core.vec(cljs.core.re_find(cljs.tools.reader.impl.commons.ratio_pattern,s));
var numerator = (m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((1)) : m.call(null,(1)));
var denominator = (m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((2)) : m.call(null,(2)));
var numerator__$1 = (cljs.core.truth_(cljs.core.re_find(/^\+/,numerator))?cljs.core.subs.cljs$core$IFn$_invoke$arity$2(numerator,(1)):numerator);
return (parseInt(numerator__$1) / parseInt(denominator));
});
cljs.tools.reader.impl.commons.match_float = (function cljs$tools$reader$impl$commons$match_float(s){
var m = cljs.core.vec(cljs.core.re_find(cljs.tools.reader.impl.commons.float_pattern,s));
if((!(((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((4)) : m.call(null,(4))) == null)))){
return parseFloat((m.cljs$core$IFn$_invoke$arity$1 ? m.cljs$core$IFn$_invoke$arity$1((1)) : m.call(null,(1))));
} else {
return parseFloat(s);
}
});
cljs.tools.reader.impl.commons.matches_QMARK_ = (function cljs$tools$reader$impl$commons$matches_QMARK_(pattern,s){
var vec__5358 = cljs.core.re_find(pattern,s);
var match = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5358,(0),null);
return (match === s);
});
cljs.tools.reader.impl.commons.match_number = (function cljs$tools$reader$impl$commons$match_number(s){
if(cljs.tools.reader.impl.commons.matches_QMARK_(cljs.tools.reader.impl.commons.int_pattern,s)){
return cljs.tools.reader.impl.commons.match_int(s);
} else {
if(cljs.tools.reader.impl.commons.matches_QMARK_(cljs.tools.reader.impl.commons.float_pattern,s)){
return cljs.tools.reader.impl.commons.match_float(s);
} else {
if(cljs.tools.reader.impl.commons.matches_QMARK_(cljs.tools.reader.impl.commons.ratio_pattern,s)){
return cljs.tools.reader.impl.commons.match_ratio(s);
} else {
return null;
}
}
}
});
/**
* Parses a string into a vector of the namespace and symbol
*/
cljs.tools.reader.impl.commons.parse_symbol = (function cljs$tools$reader$impl$commons$parse_symbol(token){
if(((("" === token)) || (((/:$/.test(token) === true) || (/^::/.test(token) === true))))){
return null;
} else {
var ns_idx = token.indexOf("/");
var ns = (((ns_idx > (0)))?cljs.core.subs.cljs$core$IFn$_invoke$arity$3(token,(0),ns_idx):null);
if((!((ns == null)))){
var ns_idx__$1 = (ns_idx + (1));
if((ns_idx__$1 === cljs.core.count(token))){
return null;
} else {
var sym = cljs.core.subs.cljs$core$IFn$_invoke$arity$2(token,ns_idx__$1);
if((((!(cljs.tools.reader.impl.utils.numeric_QMARK_(cljs.core.nth.cljs$core$IFn$_invoke$arity$2(sym,(0)))))) && ((((!(("" === sym)))) && (((/:$/.test(ns) === false) && ((((sym === "/")) || (((-1) === sym.indexOf("/"))))))))))){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [ns,sym], null);
} else {
return null;
}
}
} else {
if((((token === "/")) || (((-1) === token.indexOf("/"))))){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [null,token], null);
} else {
return null;
}
}
}
});
cljs.tools.reader.impl.commons.read_comment = (function cljs$tools$reader$impl$commons$read_comment(var_args){
var args__5775__auto__ = [];
var len__5769__auto___5363 = arguments.length;
var i__5770__auto___5364 = (0);
while(true){
if((i__5770__auto___5364 < len__5769__auto___5363)){
args__5775__auto__.push((arguments[i__5770__auto___5364]));
var G__5365 = (i__5770__auto___5364 + (1));
i__5770__auto___5364 = G__5365;
continue;
} else {
}
break;
}
var argseq__5776__auto__ = ((((1) < args__5775__auto__.length))?(new cljs.core.IndexedSeq(args__5775__auto__.slice((1)),(0),null)):null);
return cljs.tools.reader.impl.commons.read_comment.cljs$core$IFn$_invoke$arity$variadic((arguments[(0)]),argseq__5776__auto__);
});
(cljs.tools.reader.impl.commons.read_comment.cljs$core$IFn$_invoke$arity$variadic = (function (rdr,_){
return cljs.tools.reader.impl.commons.skip_line(rdr);
}));
(cljs.tools.reader.impl.commons.read_comment.cljs$lang$maxFixedArity = (1));
/** @this {Function} */
(cljs.tools.reader.impl.commons.read_comment.cljs$lang$applyTo = (function (seq5361){
var G__5362 = cljs.core.first(seq5361);
var seq5361__$1 = cljs.core.next(seq5361);
var self__5754__auto__ = this;
return self__5754__auto__.cljs$core$IFn$_invoke$arity$variadic(G__5362,seq5361__$1);
}));
cljs.tools.reader.impl.commons.throwing_reader = (function cljs$tools$reader$impl$commons$throwing_reader(msg){
return (function() {
var G__5366__delegate = function (rdr,_){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([msg], 0));
};
var G__5366 = function (rdr,var_args){
var _ = null;
if (arguments.length > 1) {
var G__5367__i = 0, G__5367__a = new Array(arguments.length - 1);
while (G__5367__i < G__5367__a.length) {G__5367__a[G__5367__i] = arguments[G__5367__i + 1]; ++G__5367__i;}
_ = new cljs.core.IndexedSeq(G__5367__a,0,null);
}
return G__5366__delegate.call(this,rdr,_);};
G__5366.cljs$lang$maxFixedArity = 1;
G__5366.cljs$lang$applyTo = (function (arglist__5368){
var rdr = cljs.core.first(arglist__5368);
var _ = cljs.core.rest(arglist__5368);
return G__5366__delegate(rdr,_);
});
G__5366.cljs$core$IFn$_invoke$arity$variadic = G__5366__delegate;
return G__5366;
})()
;
});
+247
View File
@@ -0,0 +1,247 @@
;; Copyright (c) Russ Olsen, Nicola Mometto, Rich Hickey & contributors.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.tools.reader.impl.errors
(:require [cljs.tools.reader.reader-types :as types]
[clojure.string :as s]
[cljs.tools.reader.impl.inspect :as i]))
(defn- ex-details
[rdr ex-type]
(let [details {:type :reader-exception
:ex-kind ex-type}]
(if (types/indexing-reader? rdr)
(assoc
details
:file (types/get-file-name rdr)
:line (types/get-line-number rdr)
:col (types/get-column-number rdr))
details)))
(defn- throw-ex
"Throw an ex-info error."
[rdr ex-type & msg]
(let [details (ex-details rdr ex-type)
file (:file details)
line (:line details)
col (:col details)
msg1 (if file (str file " "))
msg2 (if line (str "[line " line ", col " col "]"))
msg3 (if (or msg1 msg2) " ")
full-msg (apply str msg1 msg2 msg3 msg)]
(throw (ex-info full-msg details))))
(defn reader-error
"Throws an ExceptionInfo with the given message.
If rdr is an IndexingReader, additional information about column and line number is provided"
[rdr & msgs]
(throw-ex rdr :reader-error (apply str msgs)))
(defn illegal-arg-error
"Throws an ExceptionInfo with the given message.
If rdr is an IndexingReader, additional information about column and line number is provided"
[rdr & msgs]
(throw-ex rdr :illegal-argument (apply str msgs)))
(defn eof-error
"Throws an ExceptionInfo with the given message.
If rdr is an IndexingReader, additional information about column and line number is provided"
[rdr & msgs]
(throw-ex rdr :eof (apply str msgs)))
(defn throw-eof-delimited
([rdr kind column line] (throw-eof-delimited rdr kind line column nil))
([rdr kind line column n]
(eof-error
rdr
"Unexpected EOF while reading "
(if n
(str "item " n " of "))
(name kind)
(if line
(str ", starting at line " line " and column " column))
".")))
(defn throw-odd-map [rdr line col elements]
(reader-error
rdr
"The map literal starting with "
(i/inspect (first elements))
(if line (str " on line " line " column " col))
" contains "
(count elements)
" form(s). Map literals must contain an even number of forms."))
(defn throw-invalid-number [rdr token]
(reader-error
rdr
"Invalid number: "
token
"."))
(defn throw-invalid-unicode-literal [rdr token]
(throw
(illegal-arg-error
rdr
"Invalid unicode literal: \\"
token
".")))
(defn throw-invalid-unicode-escape [rdr ch]
(reader-error
rdr
"Invalid unicode escape: \\u"
ch
"."))
(defn throw-invalid [rdr kind token]
(reader-error rdr "Invalid " (name kind) ": " token "."))
(defn throw-eof-at-start [rdr kind]
(eof-error rdr "Unexpected EOF while reading start of " (name kind) "."))
(defn throw-bad-char [rdr kind ch]
(reader-error rdr "Invalid character: " ch " found while reading " (name kind) "."))
(defn throw-eof-at-dispatch [rdr]
(eof-error rdr "Unexpected EOF while reading dispatch character."))
(defn throw-unmatch-delimiter [rdr ch]
(reader-error rdr "Unmatched delimiter " ch "."))
(defn throw-eof-reading [rdr kind & start]
(let [init (case kind :regex "#\"" :string \")]
(eof-error rdr "Unexpected EOF reading " (name kind) " starting " (apply str init start) ".")))
(defn throw-invalid-unicode-char[rdr token]
(reader-error
rdr
"Invalid unicode character \\"
token
"."))
(defn throw-invalid-unicode-digit-in-token[rdr ch token]
(illegal-arg-error
rdr
"Invalid digit "
ch
" in unicode character \\"
token
"."))
(defn throw-invalid-unicode-digit[rdr ch]
(illegal-arg-error
rdr
"Invalid digit "
ch
" in unicode character."))
(defn throw-invalid-unicode-len[rdr actual expected]
(illegal-arg-error
rdr
"Invalid unicode literal. Unicode literals should be "
expected
"characters long. "
"Value supplied is "
actual
" characters long."))
(defn throw-invalid-character-literal[rdr token]
(reader-error rdr "Invalid character literal \\u" token "."))
(defn throw-invalid-octal-len[rdr token]
(reader-error
rdr
"Invalid octal escape sequence in a character literal: "
token
". Octal escape sequences must be 3 or fewer digits."))
(defn throw-bad-octal-number [rdr]
(reader-error rdr "Octal escape sequence must be in range [0, 377]."))
(defn throw-unsupported-character[rdr token]
(reader-error
rdr
"Unsupported character: "
token
"."))
(defn throw-eof-in-character [rdr]
(eof-error
rdr
"Unexpected EOF while reading character."))
(defn throw-bad-escape-char [rdr ch]
(reader-error rdr "Unsupported escape character: \\" ch "."))
(defn throw-single-colon [rdr]
(reader-error rdr "A single colon is not a valid keyword."))
(defn throw-bad-metadata [rdr x]
(reader-error
rdr
"Metadata cannot be "
(i/inspect x)
". Metadata must be a Symbol, Keyword, String or Map."))
(defn throw-bad-metadata-target [rdr target]
(reader-error
rdr
"Metadata can not be applied to "
(i/inspect target)
". "
"Metadata can only be applied to IMetas."))
(defn throw-feature-not-keyword [rdr feature]
(reader-error
rdr
"Feature cannot be "
(i/inspect feature)
". Features must be keywords."))
(defn throw-ns-map-no-map [rdr ns-name]
(reader-error rdr "Namespaced map with namespace " ns-name " does not specify a map."))
(defn throw-bad-ns [rdr ns-name]
(reader-error rdr "Invalid value used as namespace in namespaced map: " ns-name "."))
(defn throw-bad-reader-tag [rdr tag]
(reader-error
rdr
"Invalid reader tag: "
(i/inspect tag)
". Reader tags must be symbols."))
(defn throw-unknown-reader-tag [rdr tag]
(reader-error
rdr
"No reader function for tag "
(i/inspect tag)
"."))
(defn- duplicate-keys-error [msg coll]
(letfn [(duplicates [seq]
(for [[id freq] (frequencies seq)
:when (> freq 1)]
id))]
(let [dups (duplicates coll)]
(apply str msg
(when (> (count dups) 1) "s")
": " (interpose ", " dups)))))
(defn throw-dup-keys [rdr kind ks]
(reader-error
rdr
(duplicate-keys-error
(str (s/capitalize (name kind)) " literal contains duplicate key")
ks)))
(defn throw-eof-error [rdr line]
(if line
(eof-error rdr "EOF while reading, starting at line " line ".")
(eof-error rdr "EOF while reading.")))
+416
View File
@@ -0,0 +1,416 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.tools.reader.impl.errors');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.tools.reader.reader_types');
goog.require('clojure.string');
goog.require('cljs.tools.reader.impl.inspect');
cljs.tools.reader.impl.errors.ex_details = (function cljs$tools$reader$impl$errors$ex_details(rdr,ex_type){
var details = new cljs.core.PersistentArrayMap(null, 2, [cljs.core.cst$kw$type,cljs.core.cst$kw$reader_DASH_exception,cljs.core.cst$kw$ex_DASH_kind,ex_type], null);
if(cljs.tools.reader.reader_types.indexing_reader_QMARK_(rdr)){
return cljs.core.assoc.cljs$core$IFn$_invoke$arity$variadic(details,cljs.core.cst$kw$file,cljs.tools.reader.reader_types.get_file_name(rdr),cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.cst$kw$line,cljs.tools.reader.reader_types.get_line_number(rdr),cljs.core.cst$kw$col,cljs.tools.reader.reader_types.get_column_number(rdr)], 0));
} else {
return details;
}
});
/**
* Throw an ex-info error.
*/
cljs.tools.reader.impl.errors.throw_ex = (function cljs$tools$reader$impl$errors$throw_ex(var_args){
var args__5775__auto__ = [];
var len__5769__auto___5303 = arguments.length;
var i__5770__auto___5304 = (0);
while(true){
if((i__5770__auto___5304 < len__5769__auto___5303)){
args__5775__auto__.push((arguments[i__5770__auto___5304]));
var G__5305 = (i__5770__auto___5304 + (1));
i__5770__auto___5304 = G__5305;
continue;
} else {
}
break;
}
var argseq__5776__auto__ = ((((2) < args__5775__auto__.length))?(new cljs.core.IndexedSeq(args__5775__auto__.slice((2)),(0),null)):null);
return cljs.tools.reader.impl.errors.throw_ex.cljs$core$IFn$_invoke$arity$variadic((arguments[(0)]),(arguments[(1)]),argseq__5776__auto__);
});
(cljs.tools.reader.impl.errors.throw_ex.cljs$core$IFn$_invoke$arity$variadic = (function (rdr,ex_type,msg){
var details = cljs.tools.reader.impl.errors.ex_details(rdr,ex_type);
var file = cljs.core.cst$kw$file.cljs$core$IFn$_invoke$arity$1(details);
var line = cljs.core.cst$kw$line.cljs$core$IFn$_invoke$arity$1(details);
var col = cljs.core.cst$kw$col.cljs$core$IFn$_invoke$arity$1(details);
var msg1 = (cljs.core.truth_(file)?[cljs.core.str.cljs$core$IFn$_invoke$arity$1(file)," "].join(''):null);
var msg2 = (cljs.core.truth_(line)?["[line ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(line),", col ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(col),"]"].join(''):null);
var msg3 = (cljs.core.truth_((function (){var or__5045__auto__ = msg1;
if(cljs.core.truth_(or__5045__auto__)){
return or__5045__auto__;
} else {
return msg2;
}
})())?" ":null);
var full_msg = cljs.core.apply.cljs$core$IFn$_invoke$arity$5(cljs.core.str,msg1,msg2,msg3,msg);
throw cljs.core.ex_info.cljs$core$IFn$_invoke$arity$2(full_msg,details);
}));
(cljs.tools.reader.impl.errors.throw_ex.cljs$lang$maxFixedArity = (2));
/** @this {Function} */
(cljs.tools.reader.impl.errors.throw_ex.cljs$lang$applyTo = (function (seq5300){
var G__5301 = cljs.core.first(seq5300);
var seq5300__$1 = cljs.core.next(seq5300);
var G__5302 = cljs.core.first(seq5300__$1);
var seq5300__$2 = cljs.core.next(seq5300__$1);
var self__5754__auto__ = this;
return self__5754__auto__.cljs$core$IFn$_invoke$arity$variadic(G__5301,G__5302,seq5300__$2);
}));
/**
* Throws an ExceptionInfo with the given message.
* If rdr is an IndexingReader, additional information about column and line number is provided
*/
cljs.tools.reader.impl.errors.reader_error = (function cljs$tools$reader$impl$errors$reader_error(var_args){
var args__5775__auto__ = [];
var len__5769__auto___5308 = arguments.length;
var i__5770__auto___5309 = (0);
while(true){
if((i__5770__auto___5309 < len__5769__auto___5308)){
args__5775__auto__.push((arguments[i__5770__auto___5309]));
var G__5310 = (i__5770__auto___5309 + (1));
i__5770__auto___5309 = G__5310;
continue;
} else {
}
break;
}
var argseq__5776__auto__ = ((((1) < args__5775__auto__.length))?(new cljs.core.IndexedSeq(args__5775__auto__.slice((1)),(0),null)):null);
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic((arguments[(0)]),argseq__5776__auto__);
});
(cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic = (function (rdr,msgs){
return cljs.tools.reader.impl.errors.throw_ex.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.cst$kw$reader_DASH_error,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.str,msgs)], 0));
}));
(cljs.tools.reader.impl.errors.reader_error.cljs$lang$maxFixedArity = (1));
/** @this {Function} */
(cljs.tools.reader.impl.errors.reader_error.cljs$lang$applyTo = (function (seq5306){
var G__5307 = cljs.core.first(seq5306);
var seq5306__$1 = cljs.core.next(seq5306);
var self__5754__auto__ = this;
return self__5754__auto__.cljs$core$IFn$_invoke$arity$variadic(G__5307,seq5306__$1);
}));
/**
* Throws an ExceptionInfo with the given message.
* If rdr is an IndexingReader, additional information about column and line number is provided
*/
cljs.tools.reader.impl.errors.illegal_arg_error = (function cljs$tools$reader$impl$errors$illegal_arg_error(var_args){
var args__5775__auto__ = [];
var len__5769__auto___5313 = arguments.length;
var i__5770__auto___5314 = (0);
while(true){
if((i__5770__auto___5314 < len__5769__auto___5313)){
args__5775__auto__.push((arguments[i__5770__auto___5314]));
var G__5315 = (i__5770__auto___5314 + (1));
i__5770__auto___5314 = G__5315;
continue;
} else {
}
break;
}
var argseq__5776__auto__ = ((((1) < args__5775__auto__.length))?(new cljs.core.IndexedSeq(args__5775__auto__.slice((1)),(0),null)):null);
return cljs.tools.reader.impl.errors.illegal_arg_error.cljs$core$IFn$_invoke$arity$variadic((arguments[(0)]),argseq__5776__auto__);
});
(cljs.tools.reader.impl.errors.illegal_arg_error.cljs$core$IFn$_invoke$arity$variadic = (function (rdr,msgs){
return cljs.tools.reader.impl.errors.throw_ex.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.cst$kw$illegal_DASH_argument,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.str,msgs)], 0));
}));
(cljs.tools.reader.impl.errors.illegal_arg_error.cljs$lang$maxFixedArity = (1));
/** @this {Function} */
(cljs.tools.reader.impl.errors.illegal_arg_error.cljs$lang$applyTo = (function (seq5311){
var G__5312 = cljs.core.first(seq5311);
var seq5311__$1 = cljs.core.next(seq5311);
var self__5754__auto__ = this;
return self__5754__auto__.cljs$core$IFn$_invoke$arity$variadic(G__5312,seq5311__$1);
}));
/**
* Throws an ExceptionInfo with the given message.
* If rdr is an IndexingReader, additional information about column and line number is provided
*/
cljs.tools.reader.impl.errors.eof_error = (function cljs$tools$reader$impl$errors$eof_error(var_args){
var args__5775__auto__ = [];
var len__5769__auto___5318 = arguments.length;
var i__5770__auto___5319 = (0);
while(true){
if((i__5770__auto___5319 < len__5769__auto___5318)){
args__5775__auto__.push((arguments[i__5770__auto___5319]));
var G__5320 = (i__5770__auto___5319 + (1));
i__5770__auto___5319 = G__5320;
continue;
} else {
}
break;
}
var argseq__5776__auto__ = ((((1) < args__5775__auto__.length))?(new cljs.core.IndexedSeq(args__5775__auto__.slice((1)),(0),null)):null);
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic((arguments[(0)]),argseq__5776__auto__);
});
(cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic = (function (rdr,msgs){
return cljs.tools.reader.impl.errors.throw_ex.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.cst$kw$eof,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.str,msgs)], 0));
}));
(cljs.tools.reader.impl.errors.eof_error.cljs$lang$maxFixedArity = (1));
/** @this {Function} */
(cljs.tools.reader.impl.errors.eof_error.cljs$lang$applyTo = (function (seq5316){
var G__5317 = cljs.core.first(seq5316);
var seq5316__$1 = cljs.core.next(seq5316);
var self__5754__auto__ = this;
return self__5754__auto__.cljs$core$IFn$_invoke$arity$variadic(G__5317,seq5316__$1);
}));
cljs.tools.reader.impl.errors.throw_eof_delimited = (function cljs$tools$reader$impl$errors$throw_eof_delimited(var_args){
var G__5322 = arguments.length;
switch (G__5322) {
case 4:
return cljs.tools.reader.impl.errors.throw_eof_delimited.cljs$core$IFn$_invoke$arity$4((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]));
break;
case 5:
return cljs.tools.reader.impl.errors.throw_eof_delimited.cljs$core$IFn$_invoke$arity$5((arguments[(0)]),(arguments[(1)]),(arguments[(2)]),(arguments[(3)]),(arguments[(4)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.impl.errors.throw_eof_delimited.cljs$core$IFn$_invoke$arity$4 = (function (rdr,kind,column,line){
return cljs.tools.reader.impl.errors.throw_eof_delimited.cljs$core$IFn$_invoke$arity$5(rdr,kind,line,column,null);
}));
(cljs.tools.reader.impl.errors.throw_eof_delimited.cljs$core$IFn$_invoke$arity$5 = (function (rdr,kind,line,column,n){
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unexpected EOF while reading ",(cljs.core.truth_(n)?["item ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(n)," of "].join(''):null),cljs.core.name(kind),(cljs.core.truth_(line)?[", starting at line ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(line)," and column ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(column)].join(''):null),"."], 0));
}));
(cljs.tools.reader.impl.errors.throw_eof_delimited.cljs$lang$maxFixedArity = 5);
cljs.tools.reader.impl.errors.throw_odd_map = (function cljs$tools$reader$impl$errors$throw_odd_map(rdr,line,col,elements){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["The map literal starting with ",cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1(cljs.core.first(elements)),(cljs.core.truth_(line)?[" on line ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(line)," column ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(col)].join(''):null)," contains ",cljs.core.count(elements)," form(s). Map literals must contain an even number of forms."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_number = (function cljs$tools$reader$impl$errors$throw_invalid_number(rdr,token){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid number: ",token,"."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_unicode_literal = (function cljs$tools$reader$impl$errors$throw_invalid_unicode_literal(rdr,token){
throw cljs.tools.reader.impl.errors.illegal_arg_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid unicode literal: \\",token,"."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_unicode_escape = (function cljs$tools$reader$impl$errors$throw_invalid_unicode_escape(rdr,ch){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid unicode escape: \\u",ch,"."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid = (function cljs$tools$reader$impl$errors$throw_invalid(rdr,kind,token){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid ",cljs.core.name(kind),": ",token,"."], 0));
});
cljs.tools.reader.impl.errors.throw_eof_at_start = (function cljs$tools$reader$impl$errors$throw_eof_at_start(rdr,kind){
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unexpected EOF while reading start of ",cljs.core.name(kind),"."], 0));
});
cljs.tools.reader.impl.errors.throw_bad_char = (function cljs$tools$reader$impl$errors$throw_bad_char(rdr,kind,ch){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid character: ",ch," found while reading ",cljs.core.name(kind),"."], 0));
});
cljs.tools.reader.impl.errors.throw_eof_at_dispatch = (function cljs$tools$reader$impl$errors$throw_eof_at_dispatch(rdr){
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unexpected EOF while reading dispatch character."], 0));
});
cljs.tools.reader.impl.errors.throw_unmatch_delimiter = (function cljs$tools$reader$impl$errors$throw_unmatch_delimiter(rdr,ch){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unmatched delimiter ",ch,"."], 0));
});
cljs.tools.reader.impl.errors.throw_eof_reading = (function cljs$tools$reader$impl$errors$throw_eof_reading(var_args){
var args__5775__auto__ = [];
var len__5769__auto___5328 = arguments.length;
var i__5770__auto___5329 = (0);
while(true){
if((i__5770__auto___5329 < len__5769__auto___5328)){
args__5775__auto__.push((arguments[i__5770__auto___5329]));
var G__5330 = (i__5770__auto___5329 + (1));
i__5770__auto___5329 = G__5330;
continue;
} else {
}
break;
}
var argseq__5776__auto__ = ((((2) < args__5775__auto__.length))?(new cljs.core.IndexedSeq(args__5775__auto__.slice((2)),(0),null)):null);
return cljs.tools.reader.impl.errors.throw_eof_reading.cljs$core$IFn$_invoke$arity$variadic((arguments[(0)]),(arguments[(1)]),argseq__5776__auto__);
});
(cljs.tools.reader.impl.errors.throw_eof_reading.cljs$core$IFn$_invoke$arity$variadic = (function (rdr,kind,start){
var init = (function (){var G__5327 = kind;
var G__5327__$1 = (((G__5327 instanceof cljs.core.Keyword))?G__5327.fqn:null);
switch (G__5327__$1) {
case "regex":
return "#\"";
break;
case "string":
return "\"";
break;
default:
throw (new Error(["No matching clause: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(G__5327__$1)].join('')));
}
})();
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unexpected EOF reading ",cljs.core.name(kind)," starting ",cljs.core.apply.cljs$core$IFn$_invoke$arity$3(cljs.core.str,init,start),"."], 0));
}));
(cljs.tools.reader.impl.errors.throw_eof_reading.cljs$lang$maxFixedArity = (2));
/** @this {Function} */
(cljs.tools.reader.impl.errors.throw_eof_reading.cljs$lang$applyTo = (function (seq5324){
var G__5325 = cljs.core.first(seq5324);
var seq5324__$1 = cljs.core.next(seq5324);
var G__5326 = cljs.core.first(seq5324__$1);
var seq5324__$2 = cljs.core.next(seq5324__$1);
var self__5754__auto__ = this;
return self__5754__auto__.cljs$core$IFn$_invoke$arity$variadic(G__5325,G__5326,seq5324__$2);
}));
cljs.tools.reader.impl.errors.throw_invalid_unicode_char = (function cljs$tools$reader$impl$errors$throw_invalid_unicode_char(rdr,token){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid unicode character \\",token,"."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_unicode_digit_in_token = (function cljs$tools$reader$impl$errors$throw_invalid_unicode_digit_in_token(rdr,ch,token){
return cljs.tools.reader.impl.errors.illegal_arg_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid digit ",ch," in unicode character \\",token,"."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_unicode_digit = (function cljs$tools$reader$impl$errors$throw_invalid_unicode_digit(rdr,ch){
return cljs.tools.reader.impl.errors.illegal_arg_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid digit ",ch," in unicode character."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_unicode_len = (function cljs$tools$reader$impl$errors$throw_invalid_unicode_len(rdr,actual,expected){
return cljs.tools.reader.impl.errors.illegal_arg_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid unicode literal. Unicode literals should be ",expected,"characters long. ","Value supplied is ",actual," characters long."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_character_literal = (function cljs$tools$reader$impl$errors$throw_invalid_character_literal(rdr,token){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid character literal \\u",token,"."], 0));
});
cljs.tools.reader.impl.errors.throw_invalid_octal_len = (function cljs$tools$reader$impl$errors$throw_invalid_octal_len(rdr,token){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid octal escape sequence in a character literal: ",token,". Octal escape sequences must be 3 or fewer digits."], 0));
});
cljs.tools.reader.impl.errors.throw_bad_octal_number = (function cljs$tools$reader$impl$errors$throw_bad_octal_number(rdr){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Octal escape sequence must be in range [0, 377]."], 0));
});
cljs.tools.reader.impl.errors.throw_unsupported_character = (function cljs$tools$reader$impl$errors$throw_unsupported_character(rdr,token){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unsupported character: ",token,"."], 0));
});
cljs.tools.reader.impl.errors.throw_eof_in_character = (function cljs$tools$reader$impl$errors$throw_eof_in_character(rdr){
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unexpected EOF while reading character."], 0));
});
cljs.tools.reader.impl.errors.throw_bad_escape_char = (function cljs$tools$reader$impl$errors$throw_bad_escape_char(rdr,ch){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Unsupported escape character: \\",ch,"."], 0));
});
cljs.tools.reader.impl.errors.throw_single_colon = (function cljs$tools$reader$impl$errors$throw_single_colon(rdr){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["A single colon is not a valid keyword."], 0));
});
cljs.tools.reader.impl.errors.throw_bad_metadata = (function cljs$tools$reader$impl$errors$throw_bad_metadata(rdr,x){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Metadata cannot be ",cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1(x),". Metadata must be a Symbol, Keyword, String or Map."], 0));
});
cljs.tools.reader.impl.errors.throw_bad_metadata_target = (function cljs$tools$reader$impl$errors$throw_bad_metadata_target(rdr,target){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Metadata can not be applied to ",cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1(target),". ","Metadata can only be applied to IMetas."], 0));
});
cljs.tools.reader.impl.errors.throw_feature_not_keyword = (function cljs$tools$reader$impl$errors$throw_feature_not_keyword(rdr,feature){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Feature cannot be ",cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1(feature),". Features must be keywords."], 0));
});
cljs.tools.reader.impl.errors.throw_ns_map_no_map = (function cljs$tools$reader$impl$errors$throw_ns_map_no_map(rdr,ns_name){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Namespaced map with namespace ",ns_name," does not specify a map."], 0));
});
cljs.tools.reader.impl.errors.throw_bad_ns = (function cljs$tools$reader$impl$errors$throw_bad_ns(rdr,ns_name){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid value used as namespace in namespaced map: ",ns_name,"."], 0));
});
cljs.tools.reader.impl.errors.throw_bad_reader_tag = (function cljs$tools$reader$impl$errors$throw_bad_reader_tag(rdr,tag){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["Invalid reader tag: ",cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1(tag),". Reader tags must be symbols."], 0));
});
cljs.tools.reader.impl.errors.throw_unknown_reader_tag = (function cljs$tools$reader$impl$errors$throw_unknown_reader_tag(rdr,tag){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["No reader function for tag ",cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1(tag),"."], 0));
});
cljs.tools.reader.impl.errors.duplicate_keys_error = (function cljs$tools$reader$impl$errors$duplicate_keys_error(msg,coll){
var duplicates = (function cljs$tools$reader$impl$errors$duplicate_keys_error_$_duplicates(seq){
var iter__5523__auto__ = (function cljs$tools$reader$impl$errors$duplicate_keys_error_$_duplicates_$_iter__5342(s__5343){
return (new cljs.core.LazySeq(null,(function (){
var s__5343__$1 = s__5343;
while(true){
var temp__4657__auto__ = cljs.core.seq(s__5343__$1);
if(temp__4657__auto__){
var s__5343__$2 = temp__4657__auto__;
if(cljs.core.chunked_seq_QMARK_(s__5343__$2)){
var c__5521__auto__ = cljs.core.chunk_first(s__5343__$2);
var size__5522__auto__ = cljs.core.count(c__5521__auto__);
var b__5345 = cljs.core.chunk_buffer(size__5522__auto__);
if((function (){var i__5344 = (0);
while(true){
if((i__5344 < size__5522__auto__)){
var vec__5346 = cljs.core._nth.cljs$core$IFn$_invoke$arity$2(c__5521__auto__,i__5344);
var id = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5346,(0),null);
var freq = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5346,(1),null);
if((freq > (1))){
cljs.core.chunk_append(b__5345,id);
var G__5352 = (i__5344 + (1));
i__5344 = G__5352;
continue;
} else {
var G__5353 = (i__5344 + (1));
i__5344 = G__5353;
continue;
}
} else {
return true;
}
break;
}
})()){
return cljs.core.chunk_cons(cljs.core.chunk(b__5345),cljs$tools$reader$impl$errors$duplicate_keys_error_$_duplicates_$_iter__5342(cljs.core.chunk_rest(s__5343__$2)));
} else {
return cljs.core.chunk_cons(cljs.core.chunk(b__5345),null);
}
} else {
var vec__5349 = cljs.core.first(s__5343__$2);
var id = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5349,(0),null);
var freq = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5349,(1),null);
if((freq > (1))){
return cljs.core.cons(id,cljs$tools$reader$impl$errors$duplicate_keys_error_$_duplicates_$_iter__5342(cljs.core.rest(s__5343__$2)));
} else {
var G__5354 = cljs.core.rest(s__5343__$2);
s__5343__$1 = G__5354;
continue;
}
}
} else {
return null;
}
break;
}
}),null,null));
});
return iter__5523__auto__(cljs.core.frequencies(seq));
});
var dups = duplicates(coll);
return cljs.core.apply.cljs$core$IFn$_invoke$arity$5(cljs.core.str,msg,(((cljs.core.count(dups) > (1)))?"s":null),": ",cljs.core.interpose.cljs$core$IFn$_invoke$arity$2(", ",dups));
});
cljs.tools.reader.impl.errors.throw_dup_keys = (function cljs$tools$reader$impl$errors$throw_dup_keys(rdr,kind,ks){
return cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.tools.reader.impl.errors.duplicate_keys_error([clojure.string.capitalize(cljs.core.name(kind))," literal contains duplicate key"].join(''),ks)], 0));
});
cljs.tools.reader.impl.errors.throw_eof_error = (function cljs$tools$reader$impl$errors$throw_eof_error(rdr,line){
if(cljs.core.truth_(line)){
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["EOF while reading, starting at line ",line,"."], 0));
} else {
return cljs.tools.reader.impl.errors.eof_error.cljs$core$IFn$_invoke$arity$variadic(rdr,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2(["EOF while reading."], 0));
}
});
+90
View File
@@ -0,0 +1,90 @@
;; Copyright (c) Russ Olsen, Nicola Mometto, Rich Hickey & contributors.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.tools.reader.impl.inspect)
(declare inspect*)
(defn- inspect*-col [truncate col start end]
(let [n (count col)
l (if truncate 0 (min 10 n))
elements (map (partial inspect* true) (take l col))
content (apply str (interpose " " elements))
suffix (if (< l n) "...")]
(str start content suffix end)))
(defn- dispatch-inspect
[_ x]
(cond
(nil? x) :nil
(string? x) :string
(keyword? x) :strable
(number? x) :strable
(symbol? x) :strable
(vector? x) :vector
(list? x) :list
(map? x) :map
(set? x) :set
(= x true) :strable
(= x false) :strable
:default (type x)))
(defmulti inspect* dispatch-inspect)
(defmethod inspect* :string [truncate ^String x]
(let [n (if truncate 5 20)
suffix (if (> (.-length x) n) "...\"" "\"")]
(str
\"
(.substring ^String x 0 (min n (.-length x)))
suffix)))
(defmethod inspect* :strable [truncate x] (str x))
(defmethod inspect* cljs.core/IndexedSeq [truncate x]
"<indexed seq>")
(defmethod inspect* cljs.core/PersistentArrayMapSeq [truncate x]
"<map seq>")
(defmethod inspect* cljs.core/NodeSeq [truncate x]
"<map seq>")
(defmethod inspect* cljs.core/Cons [truncate x] "<cons>")
(defmethod inspect* cljs.core/LazySeq [truncate x] "<lazy seq>")
(defmethod inspect* :nil [_ _] "nil")
(defmethod inspect* :list [truncate col]
(inspect*-col truncate col \( \)))
(defmethod inspect* :map [truncate m]
(let [len (count m)
n-shown (if truncate 0 len)
contents (apply concat (take n-shown m))
suffix (if (> len n-shown) "...}" \})]
(inspect*-col truncate contents \{ suffix)))
(defmethod inspect* :set [truncate col]
(inspect*-col truncate col "#{" \}))
(defmethod inspect* :vector [truncate col]
(inspect*-col truncate col \[ \]))
(defmethod inspect* :default [truncate x]
(pr-str (type x)))
(defn inspect
"Return a string description of the value supplied.
May be the a string version of the value itself (e.g. \"true\")
or it may be a description (e.g. \"an instance of Foo\").
If truncate is true then return a very terse version of
the inspection."
([x] (inspect* false x))
([truncate x] (inspect* truncate x)))
+157
View File
@@ -0,0 +1,157 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.tools.reader.impl.inspect');
goog.require('cljs.core');
goog.require('cljs.core.constants');
cljs.tools.reader.impl.inspect.inspect_STAR__col = (function cljs$tools$reader$impl$inspect$inspect_STAR__col(truncate,col,start,end){
var n = cljs.core.count(col);
var l = (cljs.core.truth_(truncate)?(0):(function (){var x__5133__auto__ = (10);
var y__5134__auto__ = n;
return ((x__5133__auto__ < y__5134__auto__) ? x__5133__auto__ : y__5134__auto__);
})());
var elements = cljs.core.map.cljs$core$IFn$_invoke$arity$2(cljs.core.partial.cljs$core$IFn$_invoke$arity$2(cljs.tools.reader.impl.inspect.inspect_STAR_,true),cljs.core.take.cljs$core$IFn$_invoke$arity$2(l,col));
var content = cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.str,cljs.core.interpose.cljs$core$IFn$_invoke$arity$2(" ",elements));
var suffix = (((l < n))?"...":null);
return [cljs.core.str.cljs$core$IFn$_invoke$arity$1(start),cljs.core.str.cljs$core$IFn$_invoke$arity$1(content),suffix,cljs.core.str.cljs$core$IFn$_invoke$arity$1(end)].join('');
});
cljs.tools.reader.impl.inspect.dispatch_inspect = (function cljs$tools$reader$impl$inspect$dispatch_inspect(_,x){
if((x == null)){
return cljs.core.cst$kw$nil;
} else {
if(typeof x === 'string'){
return cljs.core.cst$kw$string;
} else {
if((x instanceof cljs.core.Keyword)){
return cljs.core.cst$kw$strable;
} else {
if(typeof x === 'number'){
return cljs.core.cst$kw$strable;
} else {
if((x instanceof cljs.core.Symbol)){
return cljs.core.cst$kw$strable;
} else {
if(cljs.core.vector_QMARK_(x)){
return cljs.core.cst$kw$vector;
} else {
if(cljs.core.list_QMARK_(x)){
return cljs.core.cst$kw$list;
} else {
if(cljs.core.map_QMARK_(x)){
return cljs.core.cst$kw$map;
} else {
if(cljs.core.set_QMARK_(x)){
return cljs.core.cst$kw$set;
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(x,true)){
return cljs.core.cst$kw$strable;
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(x,false)){
return cljs.core.cst$kw$strable;
} else {
return cljs.core.type(x);
}
}
}
}
}
}
}
}
}
}
}
});
if((typeof cljs !== 'undefined') && (typeof cljs.tools !== 'undefined') && (typeof cljs.tools.reader !== 'undefined') && (typeof cljs.tools.reader.impl !== 'undefined') && (typeof cljs.tools.reader.impl.inspect !== 'undefined') && (typeof cljs.tools.reader.impl.inspect.inspect_STAR_ !== 'undefined')){
} else {
cljs.tools.reader.impl.inspect.inspect_STAR_ = (function (){var method_table__5642__auto__ = cljs.core.atom.cljs$core$IFn$_invoke$arity$1(cljs.core.PersistentArrayMap.EMPTY);
var prefer_table__5643__auto__ = cljs.core.atom.cljs$core$IFn$_invoke$arity$1(cljs.core.PersistentArrayMap.EMPTY);
var method_cache__5644__auto__ = cljs.core.atom.cljs$core$IFn$_invoke$arity$1(cljs.core.PersistentArrayMap.EMPTY);
var cached_hierarchy__5645__auto__ = cljs.core.atom.cljs$core$IFn$_invoke$arity$1(cljs.core.PersistentArrayMap.EMPTY);
var hierarchy__5646__auto__ = cljs.core.get.cljs$core$IFn$_invoke$arity$3(cljs.core.PersistentArrayMap.EMPTY,cljs.core.cst$kw$hierarchy,(function (){var fexpr__5294 = cljs.core.get_global_hierarchy;
return (fexpr__5294.cljs$core$IFn$_invoke$arity$0 ? fexpr__5294.cljs$core$IFn$_invoke$arity$0() : fexpr__5294.call(null));
})());
return (new cljs.core.MultiFn(cljs.core.symbol.cljs$core$IFn$_invoke$arity$2("cljs.tools.reader.impl.inspect","inspect*"),cljs.tools.reader.impl.inspect.dispatch_inspect,cljs.core.cst$kw$default,hierarchy__5646__auto__,method_table__5642__auto__,prefer_table__5643__auto__,method_cache__5644__auto__,cached_hierarchy__5645__auto__));
})();
}
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$string,(function (truncate,x){
var n = (cljs.core.truth_(truncate)?(5):(20));
var suffix = (((x.length > n))?"...\"":"\"");
return ["\"",cljs.core.str.cljs$core$IFn$_invoke$arity$1(x.substring((0),(function (){var x__5133__auto__ = n;
var y__5134__auto__ = x.length;
return ((x__5133__auto__ < y__5134__auto__) ? x__5133__auto__ : y__5134__auto__);
})())),suffix].join('');
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$strable,(function (truncate,x){
return cljs.core.str.cljs$core$IFn$_invoke$arity$1(x);
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.IndexedSeq,(function (truncate,x){
return "<indexed seq>";
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.PersistentArrayMapSeq,(function (truncate,x){
return "<map seq>";
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.NodeSeq,(function (truncate,x){
return "<map seq>";
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.Cons,(function (truncate,x){
return "<cons>";
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.LazySeq,(function (truncate,x){
return "<lazy seq>";
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$nil,(function (_,___$1){
return "nil";
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$list,(function (truncate,col){
return cljs.tools.reader.impl.inspect.inspect_STAR__col(truncate,col,"(",")");
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$map,(function (truncate,m){
var len = cljs.core.count(m);
var n_shown = (cljs.core.truth_(truncate)?(0):len);
var contents = cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.concat,cljs.core.take.cljs$core$IFn$_invoke$arity$2(n_shown,m));
var suffix = (((len > n_shown))?"...}":"}");
return cljs.tools.reader.impl.inspect.inspect_STAR__col(truncate,contents,"{",suffix);
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$set,(function (truncate,col){
return cljs.tools.reader.impl.inspect.inspect_STAR__col(truncate,col,"#{","}");
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$vector,(function (truncate,col){
return cljs.tools.reader.impl.inspect.inspect_STAR__col(truncate,col,"[","]");
}));
cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IMultiFn$_add_method$arity$3(null,cljs.core.cst$kw$default,(function (truncate,x){
return cljs.core.pr_str.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.type(x)], 0));
}));
/**
* Return a string description of the value supplied.
* May be the a string version of the value itself (e.g. "true")
* or it may be a description (e.g. "an instance of Foo").
* If truncate is true then return a very terse version of
* the inspection.
*/
cljs.tools.reader.impl.inspect.inspect = (function cljs$tools$reader$impl$inspect$inspect(var_args){
var G__5296 = arguments.length;
switch (G__5296) {
case 1:
return cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$1 = (function (x){
return (cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IFn$_invoke$arity$2 ? cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IFn$_invoke$arity$2(false,x) : cljs.tools.reader.impl.inspect.inspect_STAR_.call(null,false,x));
}));
(cljs.tools.reader.impl.inspect.inspect.cljs$core$IFn$_invoke$arity$2 = (function (truncate,x){
return (cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IFn$_invoke$arity$2 ? cljs.tools.reader.impl.inspect.inspect_STAR_.cljs$core$IFn$_invoke$arity$2(truncate,x) : cljs.tools.reader.impl.inspect.inspect_STAR_.call(null,truncate,x));
}));
(cljs.tools.reader.impl.inspect.inspect.cljs$lang$maxFixedArity = 2);
+103
View File
@@ -0,0 +1,103 @@
;; Copyright (c) Nicola Mometto, Rich Hickey & contributors.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns cljs.tools.reader.impl.utils
(:refer-clojure :exclude [char])
(:require
[clojure.string :as string]
[goog.string :as gstring]))
(defn char [x]
(when-not (nil? x)
(cljs.core/char x)))
(defn ^boolean ex-info? [ex]
(instance? cljs.core.ExceptionInfo ex))
(defrecord ReaderConditional [splicing? form])
(defn ^boolean reader-conditional?
"Return true if the value is the data representation of a reader conditional"
[value]
(instance? ReaderConditional value))
(defn reader-conditional
"Construct a data representation of a reader conditional.
If true, splicing? indicates read-cond-splicing."
[form splicing?]
(ReaderConditional. splicing? form))
(extend-protocol IPrintWithWriter
ReaderConditional
(-pr-writer [coll writer opts]
(-write writer (str "#?" (when (:splicing? coll) "@")))
(pr-writer (:form coll) writer opts)))
(def ws-rx #"[\s]")
(defn ^boolean whitespace?
"Checks whether a given character is whitespace"
[ch]
(when-not (nil? ch)
(if (identical? ch \,)
true
(.test ws-rx ch))))
(defn ^boolean numeric?
"Checks whether a given character is numeric"
[ch]
(when-not (nil? ch)
(gstring/isNumeric ch)))
(defn ^boolean newline?
"Checks whether the character is a newline"
[c]
(or (identical? \newline c)
(identical? "\n" c)
(nil? c)))
(defn desugar-meta
"Resolves syntactical sugar in metadata" ;; could be combined with some other desugar?
[f]
(cond
(keyword? f) {f true}
(symbol? f) {:tag f}
(string? f) {:tag f}
:else f))
(def last-id (atom 0))
(defn next-id
[]
(swap! last-id inc))
(defn namespace-keys [ns keys]
(for [key keys]
(if (or (symbol? key)
(keyword? key))
(let [[key-ns key-name] ((juxt namespace name) key)
->key (if (symbol? key) symbol keyword)]
(cond
(nil? key-ns)
(->key ns key-name)
(= "_" key-ns)
(->key key-name)
:else
key))
key)))
(defn second' [[a b]]
(when-not a b))
(defn char-code [ch base]
(let [code (js/parseInt ch base)]
(if (js/isNaN code)
-1
code)))
+413
View File
@@ -0,0 +1,413 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.tools.reader.impl.utils');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('clojure.string');
goog.require('goog.string');
cljs.tools.reader.impl.utils.char$ = (function cljs$tools$reader$impl$utils$char(x){
if((x == null)){
return null;
} else {
return cljs.core.char$(x);
}
});
cljs.tools.reader.impl.utils.ex_info_QMARK_ = (function cljs$tools$reader$impl$utils$ex_info_QMARK_(ex){
return (ex instanceof cljs.core.ExceptionInfo);
});
/**
* @constructor
* @implements {cljs.core.IRecord}
* @implements {cljs.core.IKVReduce}
* @implements {cljs.core.IEquiv}
* @implements {cljs.core.IHash}
* @implements {cljs.core.ICollection}
* @implements {cljs.core.ICounted}
* @implements {cljs.core.ISeqable}
* @implements {cljs.core.IMeta}
* @implements {cljs.core.ICloneable}
* @implements {cljs.core.IPrintWithWriter}
* @implements {cljs.core.IIterable}
* @implements {cljs.core.IWithMeta}
* @implements {cljs.core.IAssociative}
* @implements {cljs.core.IMap}
* @implements {cljs.core.ILookup}
*/
cljs.tools.reader.impl.utils.ReaderConditional = (function (splicing_QMARK_,form,__meta,__extmap,__hash){
this.splicing_QMARK_ = splicing_QMARK_;
this.form = form;
this.__meta = __meta;
this.__extmap = __extmap;
this.__hash = __hash;
this.cljs$lang$protocol_mask$partition0$ = 2230716170;
this.cljs$lang$protocol_mask$partition1$ = 139264;
});
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$ILookup$_lookup$arity$2 = (function (this__5343__auto__,k__5344__auto__){
var self__ = this;
var this__5343__auto____$1 = this;
return this__5343__auto____$1.cljs$core$ILookup$_lookup$arity$3(null,k__5344__auto__,null);
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$ILookup$_lookup$arity$3 = (function (this__5345__auto__,k5233,else__5346__auto__){
var self__ = this;
var this__5345__auto____$1 = this;
var G__5237 = k5233;
var G__5237__$1 = (((G__5237 instanceof cljs.core.Keyword))?G__5237.fqn:null);
switch (G__5237__$1) {
case "splicing?":
return self__.splicing_QMARK_;
break;
case "form":
return self__.form;
break;
default:
return cljs.core.get.cljs$core$IFn$_invoke$arity$3(self__.__extmap,k5233,else__5346__auto__);
}
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IKVReduce$_kv_reduce$arity$3 = (function (this__5363__auto__,f__5364__auto__,init__5365__auto__){
var self__ = this;
var this__5363__auto____$1 = this;
return cljs.core.reduce.cljs$core$IFn$_invoke$arity$3((function (ret__5366__auto__,p__5238){
var vec__5239 = p__5238;
var k__5367__auto__ = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5239,(0),null);
var v__5368__auto__ = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5239,(1),null);
return (f__5364__auto__.cljs$core$IFn$_invoke$arity$3 ? f__5364__auto__.cljs$core$IFn$_invoke$arity$3(ret__5366__auto__,k__5367__auto__,v__5368__auto__) : f__5364__auto__.call(null,ret__5366__auto__,k__5367__auto__,v__5368__auto__));
}),init__5365__auto__,this__5363__auto____$1);
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IPrintWithWriter$_pr_writer$arity$3 = (function (this__5358__auto__,writer__5359__auto__,opts__5360__auto__){
var self__ = this;
var this__5358__auto____$1 = this;
var pr_pair__5361__auto__ = (function (keyval__5362__auto__){
return cljs.core.pr_sequential_writer(writer__5359__auto__,cljs.core.pr_writer,""," ","",opts__5360__auto__,keyval__5362__auto__);
});
return cljs.core.pr_sequential_writer(writer__5359__auto__,pr_pair__5361__auto__,"#cljs.tools.reader.impl.utils.ReaderConditional{",", ","}",opts__5360__auto__,cljs.core.concat.cljs$core$IFn$_invoke$arity$2(new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,[cljs.core.cst$kw$splicing_QMARK_,self__.splicing_QMARK_],null)),(new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,[cljs.core.cst$kw$form,self__.form],null))], null),self__.__extmap));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IIterable$_iterator$arity$1 = (function (G__5232){
var self__ = this;
var G__5232__$1 = this;
return (new cljs.core.RecordIter((0),G__5232__$1,2,new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$kw$splicing_QMARK_,cljs.core.cst$kw$form], null),(cljs.core.truth_(self__.__extmap)?cljs.core._iterator(self__.__extmap):cljs.core.nil_iter())));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IMeta$_meta$arity$1 = (function (this__5341__auto__){
var self__ = this;
var this__5341__auto____$1 = this;
return self__.__meta;
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$ICloneable$_clone$arity$1 = (function (this__5338__auto__){
var self__ = this;
var this__5338__auto____$1 = this;
return (new cljs.tools.reader.impl.utils.ReaderConditional(self__.splicing_QMARK_,self__.form,self__.__meta,self__.__extmap,self__.__hash));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$ICounted$_count$arity$1 = (function (this__5347__auto__){
var self__ = this;
var this__5347__auto____$1 = this;
return (2 + cljs.core.count(self__.__extmap));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IHash$_hash$arity$1 = (function (this__5339__auto__){
var self__ = this;
var this__5339__auto____$1 = this;
var h__5154__auto__ = self__.__hash;
if((!((h__5154__auto__ == null)))){
return h__5154__auto__;
} else {
var h__5154__auto____$1 = (function (){var fexpr__5242 = (function (coll__5340__auto__){
return (-209062840 ^ cljs.core.hash_unordered_coll(coll__5340__auto__));
});
return fexpr__5242(this__5339__auto____$1);
})();
(self__.__hash = h__5154__auto____$1);
return h__5154__auto____$1;
}
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IEquiv$_equiv$arity$2 = (function (this5234,other5235){
var self__ = this;
var this5234__$1 = this;
return (((!((other5235 == null)))) && ((((this5234__$1.constructor === other5235.constructor)) && (((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this5234__$1.splicing_QMARK_,other5235.splicing_QMARK_)) && (((cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this5234__$1.form,other5235.form)) && (cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(this5234__$1.__extmap,other5235.__extmap)))))))));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IMap$_dissoc$arity$2 = (function (this__5353__auto__,k__5354__auto__){
var self__ = this;
var this__5353__auto____$1 = this;
if(cljs.core.contains_QMARK_(new cljs.core.PersistentHashSet(null, new cljs.core.PersistentArrayMap(null, 2, [cljs.core.cst$kw$splicing_QMARK_,null,cljs.core.cst$kw$form,null], null), null),k__5354__auto__)){
return cljs.core.dissoc.cljs$core$IFn$_invoke$arity$2(cljs.core._with_meta(cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentArrayMap.EMPTY,this__5353__auto____$1),self__.__meta),k__5354__auto__);
} else {
return (new cljs.tools.reader.impl.utils.ReaderConditional(self__.splicing_QMARK_,self__.form,self__.__meta,cljs.core.not_empty(cljs.core.dissoc.cljs$core$IFn$_invoke$arity$2(self__.__extmap,k__5354__auto__)),null));
}
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IAssociative$_contains_key_QMARK_$arity$2 = (function (this__5350__auto__,k5233){
var self__ = this;
var this__5350__auto____$1 = this;
var G__5243 = k5233;
var G__5243__$1 = (((G__5243 instanceof cljs.core.Keyword))?G__5243.fqn:null);
switch (G__5243__$1) {
case "splicing?":
case "form":
return true;
break;
default:
return cljs.core.contains_QMARK_(self__.__extmap,k5233);
}
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IAssociative$_assoc$arity$3 = (function (this__5351__auto__,k__5352__auto__,G__5232){
var self__ = this;
var this__5351__auto____$1 = this;
var pred__5244 = cljs.core.keyword_identical_QMARK_;
var expr__5245 = k__5352__auto__;
if(cljs.core.truth_((function (){var G__5247 = cljs.core.cst$kw$splicing_QMARK_;
var G__5248 = expr__5245;
return (pred__5244.cljs$core$IFn$_invoke$arity$2 ? pred__5244.cljs$core$IFn$_invoke$arity$2(G__5247,G__5248) : pred__5244.call(null,G__5247,G__5248));
})())){
return (new cljs.tools.reader.impl.utils.ReaderConditional(G__5232,self__.form,self__.__meta,self__.__extmap,null));
} else {
if(cljs.core.truth_((function (){var G__5249 = cljs.core.cst$kw$form;
var G__5250 = expr__5245;
return (pred__5244.cljs$core$IFn$_invoke$arity$2 ? pred__5244.cljs$core$IFn$_invoke$arity$2(G__5249,G__5250) : pred__5244.call(null,G__5249,G__5250));
})())){
return (new cljs.tools.reader.impl.utils.ReaderConditional(self__.splicing_QMARK_,G__5232,self__.__meta,self__.__extmap,null));
} else {
return (new cljs.tools.reader.impl.utils.ReaderConditional(self__.splicing_QMARK_,self__.form,self__.__meta,cljs.core.assoc.cljs$core$IFn$_invoke$arity$3(self__.__extmap,k__5352__auto__,G__5232),null));
}
}
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$ISeqable$_seq$arity$1 = (function (this__5356__auto__){
var self__ = this;
var this__5356__auto____$1 = this;
return cljs.core.seq(cljs.core.concat.cljs$core$IFn$_invoke$arity$2(new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(new cljs.core.MapEntry(cljs.core.cst$kw$splicing_QMARK_,self__.splicing_QMARK_,null)),(new cljs.core.MapEntry(cljs.core.cst$kw$form,self__.form,null))], null),self__.__extmap));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IWithMeta$_with_meta$arity$2 = (function (this__5342__auto__,G__5232){
var self__ = this;
var this__5342__auto____$1 = this;
return (new cljs.tools.reader.impl.utils.ReaderConditional(self__.splicing_QMARK_,self__.form,G__5232,self__.__extmap,self__.__hash));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$ICollection$_conj$arity$2 = (function (this__5348__auto__,entry__5349__auto__){
var self__ = this;
var this__5348__auto____$1 = this;
if(cljs.core.vector_QMARK_(entry__5349__auto__)){
return this__5348__auto____$1.cljs$core$IAssociative$_assoc$arity$3(null,cljs.core._nth.cljs$core$IFn$_invoke$arity$2(entry__5349__auto__,(0)),cljs.core._nth.cljs$core$IFn$_invoke$arity$2(entry__5349__auto__,(1)));
} else {
return cljs.core.reduce.cljs$core$IFn$_invoke$arity$3(cljs.core._conj,this__5348__auto____$1,entry__5349__auto__);
}
}));
(cljs.tools.reader.impl.utils.ReaderConditional.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$splicing_QMARK_,cljs.core.cst$sym$form], null);
}));
(cljs.tools.reader.impl.utils.ReaderConditional.cljs$lang$type = true);
(cljs.tools.reader.impl.utils.ReaderConditional.cljs$lang$ctorPrSeq = (function (this__5389__auto__){
return (new cljs.core.List(null,"cljs.tools.reader.impl.utils/ReaderConditional",null,(1),null));
}));
(cljs.tools.reader.impl.utils.ReaderConditional.cljs$lang$ctorPrWriter = (function (this__5389__auto__,writer__5390__auto__){
return cljs.core._write(writer__5390__auto__,"cljs.tools.reader.impl.utils/ReaderConditional");
}));
/**
* Positional factory function for cljs.tools.reader.impl.utils/ReaderConditional.
*/
cljs.tools.reader.impl.utils.__GT_ReaderConditional = (function cljs$tools$reader$impl$utils$__GT_ReaderConditional(splicing_QMARK_,form){
return (new cljs.tools.reader.impl.utils.ReaderConditional(splicing_QMARK_,form,null,null,null));
});
/**
* Factory function for cljs.tools.reader.impl.utils/ReaderConditional, taking a map of keywords to field values.
*/
cljs.tools.reader.impl.utils.map__GT_ReaderConditional = (function cljs$tools$reader$impl$utils$map__GT_ReaderConditional(G__5236){
var extmap__5385__auto__ = (function (){var G__5251 = cljs.core.dissoc.cljs$core$IFn$_invoke$arity$variadic(G__5236,cljs.core.cst$kw$splicing_QMARK_,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([cljs.core.cst$kw$form], 0));
if(cljs.core.record_QMARK_(G__5236)){
return cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentArrayMap.EMPTY,G__5251);
} else {
return G__5251;
}
})();
return (new cljs.tools.reader.impl.utils.ReaderConditional(cljs.core.cst$kw$splicing_QMARK_.cljs$core$IFn$_invoke$arity$1(G__5236),cljs.core.cst$kw$form.cljs$core$IFn$_invoke$arity$1(G__5236),null,cljs.core.not_empty(extmap__5385__auto__),null));
});
/**
* Return true if the value is the data representation of a reader conditional
*/
cljs.tools.reader.impl.utils.reader_conditional_QMARK_ = (function cljs$tools$reader$impl$utils$reader_conditional_QMARK_(value){
return (value instanceof cljs.tools.reader.impl.utils.ReaderConditional);
});
/**
* Construct a data representation of a reader conditional.
* If true, splicing? indicates read-cond-splicing.
*/
cljs.tools.reader.impl.utils.reader_conditional = (function cljs$tools$reader$impl$utils$reader_conditional(form,splicing_QMARK_){
return (new cljs.tools.reader.impl.utils.ReaderConditional(splicing_QMARK_,form,null,null,null));
});
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IPrintWithWriter$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.impl.utils.ReaderConditional.prototype.cljs$core$IPrintWithWriter$_pr_writer$arity$3 = (function (coll,writer,opts){
var coll__$1 = this;
cljs.core._write(writer,["#?",(cljs.core.truth_(coll__$1.splicing_QMARK_)?"@":null)].join(''));
return cljs.core.pr_writer(coll__$1.form,writer,opts);
}));
cljs.tools.reader.impl.utils.ws_rx = /[\s]/;
/**
* Checks whether a given character is whitespace
*/
cljs.tools.reader.impl.utils.whitespace_QMARK_ = (function cljs$tools$reader$impl$utils$whitespace_QMARK_(ch){
if((ch == null)){
return null;
} else {
if((ch === ",")){
return true;
} else {
return cljs.tools.reader.impl.utils.ws_rx.test(ch);
}
}
});
/**
* Checks whether a given character is numeric
*/
cljs.tools.reader.impl.utils.numeric_QMARK_ = (function cljs$tools$reader$impl$utils$numeric_QMARK_(ch){
if((ch == null)){
return null;
} else {
return goog.string.isNumeric(ch);
}
});
/**
* Checks whether the character is a newline
*/
cljs.tools.reader.impl.utils.newline_QMARK_ = (function cljs$tools$reader$impl$utils$newline_QMARK_(c){
return ((("\n" === c)) || (((("\n" === c)) || ((c == null)))));
});
/**
* Resolves syntactical sugar in metadata
*/
cljs.tools.reader.impl.utils.desugar_meta = (function cljs$tools$reader$impl$utils$desugar_meta(f){
if((f instanceof cljs.core.Keyword)){
return cljs.core.PersistentArrayMap.createAsIfByAssoc([f,true]);
} else {
if((f instanceof cljs.core.Symbol)){
return new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$tag,f], null);
} else {
if(typeof f === 'string'){
return new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$tag,f], null);
} else {
return f;
}
}
}
});
cljs.tools.reader.impl.utils.last_id = cljs.core.atom.cljs$core$IFn$_invoke$arity$1((0));
cljs.tools.reader.impl.utils.next_id = (function cljs$tools$reader$impl$utils$next_id(){
return cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$2(cljs.tools.reader.impl.utils.last_id,cljs.core.inc);
});
cljs.tools.reader.impl.utils.namespace_keys = (function cljs$tools$reader$impl$utils$namespace_keys(ns,keys){
var iter__5523__auto__ = (function cljs$tools$reader$impl$utils$namespace_keys_$_iter__5254(s__5255){
return (new cljs.core.LazySeq(null,(function (){
var s__5255__$1 = s__5255;
while(true){
var temp__4657__auto__ = cljs.core.seq(s__5255__$1);
if(temp__4657__auto__){
var s__5255__$2 = temp__4657__auto__;
if(cljs.core.chunked_seq_QMARK_(s__5255__$2)){
var c__5521__auto__ = cljs.core.chunk_first(s__5255__$2);
var size__5522__auto__ = cljs.core.count(c__5521__auto__);
var b__5257 = cljs.core.chunk_buffer(size__5522__auto__);
if((function (){var i__5256 = (0);
while(true){
if((i__5256 < size__5522__auto__)){
var key = cljs.core._nth.cljs$core$IFn$_invoke$arity$2(c__5521__auto__,i__5256);
cljs.core.chunk_append(b__5257,(((((key instanceof cljs.core.Symbol)) || ((key instanceof cljs.core.Keyword))))?(function (){var vec__5258 = (function (){var fexpr__5261 = cljs.core.juxt.cljs$core$IFn$_invoke$arity$2(cljs.core.namespace,cljs.core.name);
return (fexpr__5261.cljs$core$IFn$_invoke$arity$1 ? fexpr__5261.cljs$core$IFn$_invoke$arity$1(key) : fexpr__5261.call(null,key));
})();
var key_ns = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5258,(0),null);
var key_name = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5258,(1),null);
var __GT_key = (((key instanceof cljs.core.Symbol))?cljs.core.symbol:cljs.core.keyword);
if((key_ns == null)){
return (__GT_key.cljs$core$IFn$_invoke$arity$2 ? __GT_key.cljs$core$IFn$_invoke$arity$2(ns,key_name) : __GT_key.call(null,ns,key_name));
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2("_",key_ns)){
return (__GT_key.cljs$core$IFn$_invoke$arity$1 ? __GT_key.cljs$core$IFn$_invoke$arity$1(key_name) : __GT_key.call(null,key_name));
} else {
return key;
}
}
})():key));
var G__5266 = (i__5256 + (1));
i__5256 = G__5266;
continue;
} else {
return true;
}
break;
}
})()){
return cljs.core.chunk_cons(cljs.core.chunk(b__5257),cljs$tools$reader$impl$utils$namespace_keys_$_iter__5254(cljs.core.chunk_rest(s__5255__$2)));
} else {
return cljs.core.chunk_cons(cljs.core.chunk(b__5257),null);
}
} else {
var key = cljs.core.first(s__5255__$2);
return cljs.core.cons((((((key instanceof cljs.core.Symbol)) || ((key instanceof cljs.core.Keyword))))?(function (){var vec__5262 = (function (){var fexpr__5265 = cljs.core.juxt.cljs$core$IFn$_invoke$arity$2(cljs.core.namespace,cljs.core.name);
return (fexpr__5265.cljs$core$IFn$_invoke$arity$1 ? fexpr__5265.cljs$core$IFn$_invoke$arity$1(key) : fexpr__5265.call(null,key));
})();
var key_ns = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5262,(0),null);
var key_name = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5262,(1),null);
var __GT_key = (((key instanceof cljs.core.Symbol))?cljs.core.symbol:cljs.core.keyword);
if((key_ns == null)){
return (__GT_key.cljs$core$IFn$_invoke$arity$2 ? __GT_key.cljs$core$IFn$_invoke$arity$2(ns,key_name) : __GT_key.call(null,ns,key_name));
} else {
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2("_",key_ns)){
return (__GT_key.cljs$core$IFn$_invoke$arity$1 ? __GT_key.cljs$core$IFn$_invoke$arity$1(key_name) : __GT_key.call(null,key_name));
} else {
return key;
}
}
})():key),cljs$tools$reader$impl$utils$namespace_keys_$_iter__5254(cljs.core.rest(s__5255__$2)));
}
} else {
return null;
}
break;
}
}),null,null));
});
return iter__5523__auto__(keys);
});
cljs.tools.reader.impl.utils.second_SINGLEQUOTE_ = (function cljs$tools$reader$impl$utils$second_SINGLEQUOTE_(p__5267){
var vec__5268 = p__5267;
var a = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5268,(0),null);
var b = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__5268,(1),null);
if(cljs.core.truth_(a)){
return null;
} else {
return b;
}
});
cljs.tools.reader.impl.utils.char_code = (function cljs$tools$reader$impl$utils$char_code(ch,base){
var code = parseInt(ch,base);
if(cljs.core.truth_(isNaN(code))){
return (-1);
} else {
return code;
}
});
+283
View File
@@ -0,0 +1,283 @@
;; Copyright (c) Nicola Mometto, Rich Hickey & contributors.
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns ^{:doc "Protocols and default Reader types implementation"
:author "Bronsa"}
cljs.tools.reader.reader-types
(:refer-clojure :exclude [char read-line])
(:require [cljs.tools.reader.impl.utils :refer [char whitespace? newline?]]
[goog.string])
(:import goog.string.StringBuffer))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; reader protocols
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defprotocol Reader
(read-char [reader]
"Returns the next char from the Reader, nil if the end of stream has been reached")
(peek-char [reader]
"Returns the next char from the Reader without removing it from the reader stream"))
(defprotocol IPushbackReader
(unread [reader ch]
"Pushes back a single character on to the stream"))
(defprotocol IndexingReader
(get-line-number [reader]
"Returns the line number of the next character to be read from the stream")
(get-column-number [reader]
"Returns the column number of the next character to be read from the stream")
(get-file-name [reader]
"Returns the file name the reader is reading from, or nil"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; reader deftypes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftype StringReader
[s s-len ^:mutable s-pos]
Reader
(read-char [reader]
(when (> s-len s-pos)
(let [r (.charAt s s-pos)]
(set! s-pos (inc s-pos))
r)))
(peek-char [reader]
(when (> s-len s-pos)
(.charAt s s-pos))))
(deftype NodeReadableReader [readable ^:mutable buf]
Reader
(read-char [reader]
(if buf
(let [c (aget buf 0)]
(set! buf nil)
(char c))
(let [c (str (.read readable 1))]
(when c
(char c)))))
(peek-char [reader]
(when-not buf
(set! buf (str (.read readable 1))))
(when buf
(char (aget buf 0)))))
(deftype PushbackReader
[^not-native rdr buf buf-len ^:mutable buf-pos]
Reader
(read-char [reader]
(let [c (if (< buf-pos buf-len)
(aget buf buf-pos)
(read-char rdr))]
(when (< buf-pos buf-len)
(set! buf-pos (inc buf-pos)))
(char c)))
(peek-char [reader]
(let [c (if (< buf-pos buf-len)
(aget buf buf-pos)
(peek-char rdr))]
(char c)))
IPushbackReader
(unread [reader ch]
(when ch
(if (zero? buf-pos) (throw (js/Error. "Pushback buffer is full")))
(set! buf-pos (dec buf-pos))
(aset buf buf-pos ch))))
(defn- normalize-newline [^not-native rdr ch]
(if (identical? \return ch)
(let [c (peek-char rdr)]
(when (or (identical? \formfeed c)
(identical? \newline c))
(read-char rdr))
\newline)
ch))
(deftype IndexingPushbackReader
[^not-native rdr ^:mutable line ^:mutable column
^:mutable line-start? ^:mutable prev
^:mutable prev-column file-name]
Reader
(read-char [reader]
(when-let [ch (read-char rdr)]
(let [ch (normalize-newline rdr ch)]
(set! prev line-start?)
(set! line-start? (newline? ch))
(when line-start?
(set! prev-column column)
(set! column 0)
(set! line (inc line)))
(set! column (inc column))
ch)))
(peek-char [reader]
(peek-char rdr))
IPushbackReader
(unread [reader ch]
(if line-start?
(do (set! line (dec line))
(set! column prev-column))
(set! column (dec column)))
(set! line-start? prev)
(unread rdr ch))
IndexingReader
(get-line-number [reader] (int line))
(get-column-number [reader] (int column))
(get-file-name [reader] file-name))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Source Logging support
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn merge-meta
"Returns an object of the same type and value as `obj`, with its
metadata merged over `m`."
[obj m]
(let [orig-meta (meta obj)]
(with-meta obj (merge m (dissoc orig-meta :source)))))
(defn- peek-source-log
"Returns a string containing the contents of the top most source
logging frame."
[frames]
(subs (str (:buffer frames)) (first (:offset frames))))
(defn- log-source-char
"Logs `char` to all currently active source logging frames."
[frames char]
(when-let [buffer (:buffer frames)]
(.append buffer char)))
(defn- drop-last-logged-char
"Removes the last logged character from all currently active source
logging frames. Called when pushing a character back."
[frames]
(when-let [buffer (:buffer frames)]
(.set buffer (subs (str buffer) 0 (dec (.getLength buffer))))))
(deftype SourceLoggingPushbackReader
[^not-native rdr ^:mutable line ^:mutable column
^:mutable line-start? ^:mutable prev
^:mutable prev-column file-name frames]
Reader
(read-char [reader]
(when-let [ch (read-char rdr)]
(let [ch (normalize-newline rdr ch)]
(set! prev line-start?)
(set! line-start? (newline? ch))
(when line-start?
(set! prev-column column)
(set! column 0)
(set! line (inc line)))
(set! column (inc column))
(log-source-char @frames ch)
ch)))
(peek-char [reader]
(peek-char rdr))
IPushbackReader
(unread [reader ch]
(if line-start?
(do (set! line (dec line))
(set! column prev-column))
(set! column (dec column)))
(set! line-start? prev)
(when ch
(drop-last-logged-char @frames))
(unread rdr ch))
IndexingReader
(get-line-number [reader] (int line))
(get-column-number [reader] (int column))
(get-file-name [reader] file-name))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Public API
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; fast check for provided implementations
(defn indexing-reader?
"Returns true if the reader satisfies IndexingReader"
[rdr]
(implements? IndexingReader rdr))
(defn string-reader
"Creates a StringReader from a given string"
([s]
(StringReader. s (count s) 0)))
(defn string-push-back-reader
"Creates a PushbackReader from a given string"
([s]
(string-push-back-reader s 1))
([s buf-len]
(PushbackReader. (string-reader s) (object-array buf-len) buf-len buf-len)))
(defn node-readable-push-back-reader [readable]
(PushbackReader. (NodeReadableReader. readable nil) (object-array 1) 1 1))
(defn indexing-push-back-reader
"Creates an IndexingPushbackReader from a given string or PushbackReader"
([s-or-rdr]
(indexing-push-back-reader s-or-rdr 1))
([s-or-rdr buf-len]
(indexing-push-back-reader s-or-rdr buf-len nil))
([s-or-rdr buf-len file-name]
(IndexingPushbackReader.
(if (string? s-or-rdr) (string-push-back-reader s-or-rdr buf-len) s-or-rdr) 1 1 true nil 0 file-name)))
(defn source-logging-push-back-reader
"Creates a SourceLoggingPushbackReader from a given string or PushbackReader"
([s-or-rdr]
(source-logging-push-back-reader s-or-rdr 1))
([s-or-rdr buf-len]
(source-logging-push-back-reader s-or-rdr buf-len nil))
([s-or-rdr buf-len file-name]
(SourceLoggingPushbackReader.
(if (string? s-or-rdr) (string-push-back-reader s-or-rdr buf-len) s-or-rdr)
1
1
true
nil
0
file-name
(atom {:buffer (StringBuffer.) :offset '(0)}))))
(defn read-line
"Reads a line from the reader or from *in* if no reader is specified"
([^not-native rdr]
(loop [c (read-char rdr) s (StringBuffer.)]
(if (newline? c)
(str s)
(recur (read-char rdr) (.append s c))))))
(defn ^boolean source-logging-reader?
[rdr]
(instance? SourceLoggingPushbackReader rdr))
(defn ^boolean line-start?
"Returns true if rdr is an IndexingReader and the current char starts a new line"
[^not-native rdr]
(when (indexing-reader? rdr)
(== 1 (get-column-number rdr))))
(defn log-source*
[reader f]
(let [buffer (:buffer @(.-frames reader))]
(try
(swap! (.-frames reader) update-in [:offset] conj (.getLength buffer))
(let [ret (f)]
(if (implements? IMeta ret)
(merge-meta ret {:source (peek-source-log @ (.-frames reader))})
ret))
(finally
(swap! (.-frames reader) update-in [:offset] rest)))))
+815
View File
@@ -0,0 +1,815 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('cljs.tools.reader.reader_types');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('cljs.tools.reader.impl.utils');
goog.require('goog.string');
goog.require('goog.string.StringBuffer');
/**
* @interface
*/
cljs.tools.reader.reader_types.Reader = function(){};
var cljs$tools$reader$reader_types$Reader$read_char$dyn_5273 = (function (reader){
var x__5393__auto__ = (((reader == null))?null:reader);
var m__5394__auto__ = (cljs.tools.reader.reader_types.read_char[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5394__auto__.call(null,reader));
} else {
var m__5392__auto__ = (cljs.tools.reader.reader_types.read_char["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5392__auto__.call(null,reader));
} else {
throw cljs.core.missing_protocol("Reader.read-char",reader);
}
}
});
/**
* Returns the next char from the Reader, nil if the end of stream has been reached
*/
cljs.tools.reader.reader_types.read_char = (function cljs$tools$reader$reader_types$read_char(reader){
if((((!((reader == null)))) && ((!((reader.cljs$tools$reader$reader_types$Reader$read_char$arity$1 == null)))))){
return reader.cljs$tools$reader$reader_types$Reader$read_char$arity$1(reader);
} else {
return cljs$tools$reader$reader_types$Reader$read_char$dyn_5273(reader);
}
});
var cljs$tools$reader$reader_types$Reader$peek_char$dyn_5274 = (function (reader){
var x__5393__auto__ = (((reader == null))?null:reader);
var m__5394__auto__ = (cljs.tools.reader.reader_types.peek_char[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5394__auto__.call(null,reader));
} else {
var m__5392__auto__ = (cljs.tools.reader.reader_types.peek_char["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5392__auto__.call(null,reader));
} else {
throw cljs.core.missing_protocol("Reader.peek-char",reader);
}
}
});
/**
* Returns the next char from the Reader without removing it from the reader stream
*/
cljs.tools.reader.reader_types.peek_char = (function cljs$tools$reader$reader_types$peek_char(reader){
if((((!((reader == null)))) && ((!((reader.cljs$tools$reader$reader_types$Reader$peek_char$arity$1 == null)))))){
return reader.cljs$tools$reader$reader_types$Reader$peek_char$arity$1(reader);
} else {
return cljs$tools$reader$reader_types$Reader$peek_char$dyn_5274(reader);
}
});
/**
* @interface
*/
cljs.tools.reader.reader_types.IPushbackReader = function(){};
var cljs$tools$reader$reader_types$IPushbackReader$unread$dyn_5275 = (function (reader,ch){
var x__5393__auto__ = (((reader == null))?null:reader);
var m__5394__auto__ = (cljs.tools.reader.reader_types.unread[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$2 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$2(reader,ch) : m__5394__auto__.call(null,reader,ch));
} else {
var m__5392__auto__ = (cljs.tools.reader.reader_types.unread["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$2 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$2(reader,ch) : m__5392__auto__.call(null,reader,ch));
} else {
throw cljs.core.missing_protocol("IPushbackReader.unread",reader);
}
}
});
/**
* Pushes back a single character on to the stream
*/
cljs.tools.reader.reader_types.unread = (function cljs$tools$reader$reader_types$unread(reader,ch){
if((((!((reader == null)))) && ((!((reader.cljs$tools$reader$reader_types$IPushbackReader$unread$arity$2 == null)))))){
return reader.cljs$tools$reader$reader_types$IPushbackReader$unread$arity$2(reader,ch);
} else {
return cljs$tools$reader$reader_types$IPushbackReader$unread$dyn_5275(reader,ch);
}
});
/**
* @interface
*/
cljs.tools.reader.reader_types.IndexingReader = function(){};
var cljs$tools$reader$reader_types$IndexingReader$get_line_number$dyn_5276 = (function (reader){
var x__5393__auto__ = (((reader == null))?null:reader);
var m__5394__auto__ = (cljs.tools.reader.reader_types.get_line_number[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5394__auto__.call(null,reader));
} else {
var m__5392__auto__ = (cljs.tools.reader.reader_types.get_line_number["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5392__auto__.call(null,reader));
} else {
throw cljs.core.missing_protocol("IndexingReader.get-line-number",reader);
}
}
});
/**
* Returns the line number of the next character to be read from the stream
*/
cljs.tools.reader.reader_types.get_line_number = (function cljs$tools$reader$reader_types$get_line_number(reader){
if((((!((reader == null)))) && ((!((reader.cljs$tools$reader$reader_types$IndexingReader$get_line_number$arity$1 == null)))))){
return reader.cljs$tools$reader$reader_types$IndexingReader$get_line_number$arity$1(reader);
} else {
return cljs$tools$reader$reader_types$IndexingReader$get_line_number$dyn_5276(reader);
}
});
var cljs$tools$reader$reader_types$IndexingReader$get_column_number$dyn_5277 = (function (reader){
var x__5393__auto__ = (((reader == null))?null:reader);
var m__5394__auto__ = (cljs.tools.reader.reader_types.get_column_number[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5394__auto__.call(null,reader));
} else {
var m__5392__auto__ = (cljs.tools.reader.reader_types.get_column_number["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5392__auto__.call(null,reader));
} else {
throw cljs.core.missing_protocol("IndexingReader.get-column-number",reader);
}
}
});
/**
* Returns the column number of the next character to be read from the stream
*/
cljs.tools.reader.reader_types.get_column_number = (function cljs$tools$reader$reader_types$get_column_number(reader){
if((((!((reader == null)))) && ((!((reader.cljs$tools$reader$reader_types$IndexingReader$get_column_number$arity$1 == null)))))){
return reader.cljs$tools$reader$reader_types$IndexingReader$get_column_number$arity$1(reader);
} else {
return cljs$tools$reader$reader_types$IndexingReader$get_column_number$dyn_5277(reader);
}
});
var cljs$tools$reader$reader_types$IndexingReader$get_file_name$dyn_5278 = (function (reader){
var x__5393__auto__ = (((reader == null))?null:reader);
var m__5394__auto__ = (cljs.tools.reader.reader_types.get_file_name[goog.typeOf(x__5393__auto__)]);
if((!((m__5394__auto__ == null)))){
return (m__5394__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5394__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5394__auto__.call(null,reader));
} else {
var m__5392__auto__ = (cljs.tools.reader.reader_types.get_file_name["_"]);
if((!((m__5392__auto__ == null)))){
return (m__5392__auto__.cljs$core$IFn$_invoke$arity$1 ? m__5392__auto__.cljs$core$IFn$_invoke$arity$1(reader) : m__5392__auto__.call(null,reader));
} else {
throw cljs.core.missing_protocol("IndexingReader.get-file-name",reader);
}
}
});
/**
* Returns the file name the reader is reading from, or nil
*/
cljs.tools.reader.reader_types.get_file_name = (function cljs$tools$reader$reader_types$get_file_name(reader){
if((((!((reader == null)))) && ((!((reader.cljs$tools$reader$reader_types$IndexingReader$get_file_name$arity$1 == null)))))){
return reader.cljs$tools$reader$reader_types$IndexingReader$get_file_name$arity$1(reader);
} else {
return cljs$tools$reader$reader_types$IndexingReader$get_file_name$dyn_5278(reader);
}
});
/**
* @constructor
* @implements {cljs.tools.reader.reader_types.Reader}
*/
cljs.tools.reader.reader_types.StringReader = (function (s,s_len,s_pos){
this.s = s;
this.s_len = s_len;
this.s_pos = s_pos;
});
(cljs.tools.reader.reader_types.StringReader.prototype.cljs$tools$reader$reader_types$Reader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.StringReader.prototype.cljs$tools$reader$reader_types$Reader$read_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
if((self__.s_len > self__.s_pos)){
var r = self__.s.charAt(self__.s_pos);
(self__.s_pos = (self__.s_pos + (1)));
return r;
} else {
return null;
}
}));
(cljs.tools.reader.reader_types.StringReader.prototype.cljs$tools$reader$reader_types$Reader$peek_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
if((self__.s_len > self__.s_pos)){
return self__.s.charAt(self__.s_pos);
} else {
return null;
}
}));
(cljs.tools.reader.reader_types.StringReader.getBasis = (function (){
return new cljs.core.PersistentVector(null, 3, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$s,cljs.core.cst$sym$s_DASH_len,cljs.core.with_meta(cljs.core.cst$sym$s_DASH_pos,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null))], null);
}));
(cljs.tools.reader.reader_types.StringReader.cljs$lang$type = true);
(cljs.tools.reader.reader_types.StringReader.cljs$lang$ctorStr = "cljs.tools.reader.reader-types/StringReader");
(cljs.tools.reader.reader_types.StringReader.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.tools.reader.reader-types/StringReader");
}));
/**
* Positional factory function for cljs.tools.reader.reader-types/StringReader.
*/
cljs.tools.reader.reader_types.__GT_StringReader = (function cljs$tools$reader$reader_types$__GT_StringReader(s,s_len,s_pos){
return (new cljs.tools.reader.reader_types.StringReader(s,s_len,s_pos));
});
/**
* @constructor
* @implements {cljs.tools.reader.reader_types.Reader}
*/
cljs.tools.reader.reader_types.NodeReadableReader = (function (readable,buf){
this.readable = readable;
this.buf = buf;
});
(cljs.tools.reader.reader_types.NodeReadableReader.prototype.cljs$tools$reader$reader_types$Reader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.NodeReadableReader.prototype.cljs$tools$reader$reader_types$Reader$read_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
if(cljs.core.truth_(self__.buf)){
var c = (self__.buf[(0)]);
(self__.buf = null);
return cljs.tools.reader.impl.utils.char$(c);
} else {
var c = cljs.core.str.cljs$core$IFn$_invoke$arity$1(self__.readable.read((1)));
if(cljs.core.truth_(c)){
return cljs.tools.reader.impl.utils.char$(c);
} else {
return null;
}
}
}));
(cljs.tools.reader.reader_types.NodeReadableReader.prototype.cljs$tools$reader$reader_types$Reader$peek_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
if(cljs.core.truth_(self__.buf)){
} else {
(self__.buf = cljs.core.str.cljs$core$IFn$_invoke$arity$1(self__.readable.read((1))));
}
if(cljs.core.truth_(self__.buf)){
return cljs.tools.reader.impl.utils.char$((self__.buf[(0)]));
} else {
return null;
}
}));
(cljs.tools.reader.reader_types.NodeReadableReader.getBasis = (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$sym$readable,cljs.core.with_meta(cljs.core.cst$sym$buf,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null))], null);
}));
(cljs.tools.reader.reader_types.NodeReadableReader.cljs$lang$type = true);
(cljs.tools.reader.reader_types.NodeReadableReader.cljs$lang$ctorStr = "cljs.tools.reader.reader-types/NodeReadableReader");
(cljs.tools.reader.reader_types.NodeReadableReader.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.tools.reader.reader-types/NodeReadableReader");
}));
/**
* Positional factory function for cljs.tools.reader.reader-types/NodeReadableReader.
*/
cljs.tools.reader.reader_types.__GT_NodeReadableReader = (function cljs$tools$reader$reader_types$__GT_NodeReadableReader(readable,buf){
return (new cljs.tools.reader.reader_types.NodeReadableReader(readable,buf));
});
/**
* @constructor
* @implements {cljs.tools.reader.reader_types.Reader}
* @implements {cljs.tools.reader.reader_types.IPushbackReader}
*/
cljs.tools.reader.reader_types.PushbackReader = (function (rdr,buf,buf_len,buf_pos){
this.rdr = rdr;
this.buf = buf;
this.buf_len = buf_len;
this.buf_pos = buf_pos;
});
(cljs.tools.reader.reader_types.PushbackReader.prototype.cljs$tools$reader$reader_types$Reader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.PushbackReader.prototype.cljs$tools$reader$reader_types$Reader$read_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
var c = (((self__.buf_pos < self__.buf_len))?(self__.buf[self__.buf_pos]):self__.rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null));
if((self__.buf_pos < self__.buf_len)){
(self__.buf_pos = (self__.buf_pos + (1)));
} else {
}
return cljs.tools.reader.impl.utils.char$(c);
}));
(cljs.tools.reader.reader_types.PushbackReader.prototype.cljs$tools$reader$reader_types$Reader$peek_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
var c = (((self__.buf_pos < self__.buf_len))?(self__.buf[self__.buf_pos]):self__.rdr.cljs$tools$reader$reader_types$Reader$peek_char$arity$1(null));
return cljs.tools.reader.impl.utils.char$(c);
}));
(cljs.tools.reader.reader_types.PushbackReader.prototype.cljs$tools$reader$reader_types$IPushbackReader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.PushbackReader.prototype.cljs$tools$reader$reader_types$IPushbackReader$unread$arity$2 = (function (reader,ch){
var self__ = this;
var reader__$1 = this;
if(cljs.core.truth_(ch)){
if((self__.buf_pos === (0))){
throw (new Error("Pushback buffer is full"));
} else {
}
(self__.buf_pos = (self__.buf_pos - (1)));
return (self__.buf[self__.buf_pos] = ch);
} else {
return null;
}
}));
(cljs.tools.reader.reader_types.PushbackReader.getBasis = (function (){
return new cljs.core.PersistentVector(null, 4, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.with_meta(cljs.core.cst$sym$rdr,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$tag,cljs.core.cst$sym$not_DASH_native], null)),cljs.core.cst$sym$buf,cljs.core.cst$sym$buf_DASH_len,cljs.core.with_meta(cljs.core.cst$sym$buf_DASH_pos,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null))], null);
}));
(cljs.tools.reader.reader_types.PushbackReader.cljs$lang$type = true);
(cljs.tools.reader.reader_types.PushbackReader.cljs$lang$ctorStr = "cljs.tools.reader.reader-types/PushbackReader");
(cljs.tools.reader.reader_types.PushbackReader.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.tools.reader.reader-types/PushbackReader");
}));
/**
* Positional factory function for cljs.tools.reader.reader-types/PushbackReader.
*/
cljs.tools.reader.reader_types.__GT_PushbackReader = (function cljs$tools$reader$reader_types$__GT_PushbackReader(rdr,buf,buf_len,buf_pos){
return (new cljs.tools.reader.reader_types.PushbackReader(rdr,buf,buf_len,buf_pos));
});
cljs.tools.reader.reader_types.normalize_newline = (function cljs$tools$reader$reader_types$normalize_newline(rdr,ch){
if(("\r" === ch)){
var c = rdr.cljs$tools$reader$reader_types$Reader$peek_char$arity$1(null);
if(((("\f" === c)) || (("\n" === c)))){
rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null);
} else {
}
return "\n";
} else {
return ch;
}
});
/**
* @constructor
* @implements {cljs.tools.reader.reader_types.IndexingReader}
* @implements {cljs.tools.reader.reader_types.Reader}
* @implements {cljs.tools.reader.reader_types.IPushbackReader}
*/
cljs.tools.reader.reader_types.IndexingPushbackReader = (function (rdr,line,column,line_start_QMARK_,prev,prev_column,file_name){
this.rdr = rdr;
this.line = line;
this.column = column;
this.line_start_QMARK_ = line_start_QMARK_;
this.prev = prev;
this.prev_column = prev_column;
this.file_name = file_name;
});
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$Reader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$Reader$read_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
var temp__4657__auto__ = self__.rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null);
if(cljs.core.truth_(temp__4657__auto__)){
var ch = temp__4657__auto__;
var ch__$1 = cljs.tools.reader.reader_types.normalize_newline(self__.rdr,ch);
(self__.prev = self__.line_start_QMARK_);
(self__.line_start_QMARK_ = cljs.tools.reader.impl.utils.newline_QMARK_(ch__$1));
if(cljs.core.truth_(self__.line_start_QMARK_)){
(self__.prev_column = self__.column);
(self__.column = (0));
(self__.line = (self__.line + (1)));
} else {
}
(self__.column = (self__.column + (1)));
return ch__$1;
} else {
return null;
}
}));
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$Reader$peek_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return self__.rdr.cljs$tools$reader$reader_types$Reader$peek_char$arity$1(null);
}));
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$IPushbackReader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$IPushbackReader$unread$arity$2 = (function (reader,ch){
var self__ = this;
var reader__$1 = this;
if(cljs.core.truth_(self__.line_start_QMARK_)){
(self__.line = (self__.line - (1)));
(self__.column = self__.prev_column);
} else {
(self__.column = (self__.column - (1)));
}
(self__.line_start_QMARK_ = self__.prev);
return self__.rdr.cljs$tools$reader$reader_types$IPushbackReader$unread$arity$2(null,ch);
}));
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$get_line_number$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return (self__.line | (0));
}));
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$get_column_number$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return (self__.column | (0));
}));
(cljs.tools.reader.reader_types.IndexingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$get_file_name$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return self__.file_name;
}));
(cljs.tools.reader.reader_types.IndexingPushbackReader.getBasis = (function (){
return new cljs.core.PersistentVector(null, 7, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.with_meta(cljs.core.cst$sym$rdr,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$tag,cljs.core.cst$sym$not_DASH_native], null)),cljs.core.with_meta(cljs.core.cst$sym$line,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$column,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$line_DASH_start_QMARK_,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$prev,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$prev_DASH_column,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.cst$sym$file_DASH_name], null);
}));
(cljs.tools.reader.reader_types.IndexingPushbackReader.cljs$lang$type = true);
(cljs.tools.reader.reader_types.IndexingPushbackReader.cljs$lang$ctorStr = "cljs.tools.reader.reader-types/IndexingPushbackReader");
(cljs.tools.reader.reader_types.IndexingPushbackReader.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.tools.reader.reader-types/IndexingPushbackReader");
}));
/**
* Positional factory function for cljs.tools.reader.reader-types/IndexingPushbackReader.
*/
cljs.tools.reader.reader_types.__GT_IndexingPushbackReader = (function cljs$tools$reader$reader_types$__GT_IndexingPushbackReader(rdr,line,column,line_start_QMARK_,prev,prev_column,file_name){
return (new cljs.tools.reader.reader_types.IndexingPushbackReader(rdr,line,column,line_start_QMARK_,prev,prev_column,file_name));
});
/**
* Returns an object of the same type and value as `obj`, with its
* metadata merged over `m`.
*/
cljs.tools.reader.reader_types.merge_meta = (function cljs$tools$reader$reader_types$merge_meta(obj,m){
var orig_meta = cljs.core.meta(obj);
return cljs.core.with_meta(obj,cljs.core.merge.cljs$core$IFn$_invoke$arity$variadic(cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([m,cljs.core.dissoc.cljs$core$IFn$_invoke$arity$2(orig_meta,cljs.core.cst$kw$source)], 0)));
});
/**
* Returns a string containing the contents of the top most source
* logging frame.
*/
cljs.tools.reader.reader_types.peek_source_log = (function cljs$tools$reader$reader_types$peek_source_log(frames){
return cljs.core.subs.cljs$core$IFn$_invoke$arity$2(cljs.core.str.cljs$core$IFn$_invoke$arity$1(cljs.core.cst$kw$buffer.cljs$core$IFn$_invoke$arity$1(frames)),cljs.core.first(cljs.core.cst$kw$offset.cljs$core$IFn$_invoke$arity$1(frames)));
});
/**
* Logs `char` to all currently active source logging frames.
*/
cljs.tools.reader.reader_types.log_source_char = (function cljs$tools$reader$reader_types$log_source_char(frames,char$){
var temp__4657__auto__ = cljs.core.cst$kw$buffer.cljs$core$IFn$_invoke$arity$1(frames);
if(cljs.core.truth_(temp__4657__auto__)){
var buffer = temp__4657__auto__;
return buffer.append(char$);
} else {
return null;
}
});
/**
* Removes the last logged character from all currently active source
* logging frames. Called when pushing a character back.
*/
cljs.tools.reader.reader_types.drop_last_logged_char = (function cljs$tools$reader$reader_types$drop_last_logged_char(frames){
var temp__4657__auto__ = cljs.core.cst$kw$buffer.cljs$core$IFn$_invoke$arity$1(frames);
if(cljs.core.truth_(temp__4657__auto__)){
var buffer = temp__4657__auto__;
return buffer.set(cljs.core.subs.cljs$core$IFn$_invoke$arity$3(cljs.core.str.cljs$core$IFn$_invoke$arity$1(buffer),(0),(buffer.getLength() - (1))));
} else {
return null;
}
});
/**
* @constructor
* @implements {cljs.tools.reader.reader_types.IndexingReader}
* @implements {cljs.tools.reader.reader_types.Reader}
* @implements {cljs.tools.reader.reader_types.IPushbackReader}
*/
cljs.tools.reader.reader_types.SourceLoggingPushbackReader = (function (rdr,line,column,line_start_QMARK_,prev,prev_column,file_name,frames){
this.rdr = rdr;
this.line = line;
this.column = column;
this.line_start_QMARK_ = line_start_QMARK_;
this.prev = prev;
this.prev_column = prev_column;
this.file_name = file_name;
this.frames = frames;
});
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$Reader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$Reader$read_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
var temp__4657__auto__ = self__.rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null);
if(cljs.core.truth_(temp__4657__auto__)){
var ch = temp__4657__auto__;
var ch__$1 = cljs.tools.reader.reader_types.normalize_newline(self__.rdr,ch);
(self__.prev = self__.line_start_QMARK_);
(self__.line_start_QMARK_ = cljs.tools.reader.impl.utils.newline_QMARK_(ch__$1));
if(cljs.core.truth_(self__.line_start_QMARK_)){
(self__.prev_column = self__.column);
(self__.column = (0));
(self__.line = (self__.line + (1)));
} else {
}
(self__.column = (self__.column + (1)));
cljs.tools.reader.reader_types.log_source_char(cljs.core.deref(self__.frames),ch__$1);
return ch__$1;
} else {
return null;
}
}));
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$Reader$peek_char$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return self__.rdr.cljs$tools$reader$reader_types$Reader$peek_char$arity$1(null);
}));
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$IPushbackReader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$IPushbackReader$unread$arity$2 = (function (reader,ch){
var self__ = this;
var reader__$1 = this;
if(cljs.core.truth_(self__.line_start_QMARK_)){
(self__.line = (self__.line - (1)));
(self__.column = self__.prev_column);
} else {
(self__.column = (self__.column - (1)));
}
(self__.line_start_QMARK_ = self__.prev);
if(cljs.core.truth_(ch)){
cljs.tools.reader.reader_types.drop_last_logged_char(cljs.core.deref(self__.frames));
} else {
}
return self__.rdr.cljs$tools$reader$reader_types$IPushbackReader$unread$arity$2(null,ch);
}));
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$ = cljs.core.PROTOCOL_SENTINEL);
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$get_line_number$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return (self__.line | (0));
}));
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$get_column_number$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return (self__.column | (0));
}));
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.prototype.cljs$tools$reader$reader_types$IndexingReader$get_file_name$arity$1 = (function (reader){
var self__ = this;
var reader__$1 = this;
return self__.file_name;
}));
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.getBasis = (function (){
return new cljs.core.PersistentVector(null, 8, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.with_meta(cljs.core.cst$sym$rdr,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$tag,cljs.core.cst$sym$not_DASH_native], null)),cljs.core.with_meta(cljs.core.cst$sym$line,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$column,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$line_DASH_start_QMARK_,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$prev,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.with_meta(cljs.core.cst$sym$prev_DASH_column,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$mutable,true], null)),cljs.core.cst$sym$file_DASH_name,cljs.core.cst$sym$frames], null);
}));
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.cljs$lang$type = true);
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.cljs$lang$ctorStr = "cljs.tools.reader.reader-types/SourceLoggingPushbackReader");
(cljs.tools.reader.reader_types.SourceLoggingPushbackReader.cljs$lang$ctorPrWriter = (function (this__5330__auto__,writer__5331__auto__,opt__5332__auto__){
return cljs.core._write(writer__5331__auto__,"cljs.tools.reader.reader-types/SourceLoggingPushbackReader");
}));
/**
* Positional factory function for cljs.tools.reader.reader-types/SourceLoggingPushbackReader.
*/
cljs.tools.reader.reader_types.__GT_SourceLoggingPushbackReader = (function cljs$tools$reader$reader_types$__GT_SourceLoggingPushbackReader(rdr,line,column,line_start_QMARK_,prev,prev_column,file_name,frames){
return (new cljs.tools.reader.reader_types.SourceLoggingPushbackReader(rdr,line,column,line_start_QMARK_,prev,prev_column,file_name,frames));
});
/**
* Returns true if the reader satisfies IndexingReader
*/
cljs.tools.reader.reader_types.indexing_reader_QMARK_ = (function cljs$tools$reader$reader_types$indexing_reader_QMARK_(rdr){
if((!((rdr == null)))){
if(((false) || ((cljs.core.PROTOCOL_SENTINEL === rdr.cljs$tools$reader$reader_types$IndexingReader$)))){
return true;
} else {
return false;
}
} else {
return false;
}
});
/**
* Creates a StringReader from a given string
*/
cljs.tools.reader.reader_types.string_reader = (function cljs$tools$reader$reader_types$string_reader(s){
return (new cljs.tools.reader.reader_types.StringReader(s,cljs.core.count(s),(0)));
});
/**
* Creates a PushbackReader from a given string
*/
cljs.tools.reader.reader_types.string_push_back_reader = (function cljs$tools$reader$reader_types$string_push_back_reader(var_args){
var G__5281 = arguments.length;
switch (G__5281) {
case 1:
return cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$1 = (function (s){
return cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$2(s,(1));
}));
(cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$2 = (function (s,buf_len){
return (new cljs.tools.reader.reader_types.PushbackReader(cljs.tools.reader.reader_types.string_reader(s),cljs.core.object_array.cljs$core$IFn$_invoke$arity$1(buf_len),buf_len,buf_len));
}));
(cljs.tools.reader.reader_types.string_push_back_reader.cljs$lang$maxFixedArity = 2);
cljs.tools.reader.reader_types.node_readable_push_back_reader = (function cljs$tools$reader$reader_types$node_readable_push_back_reader(readable){
return (new cljs.tools.reader.reader_types.PushbackReader((new cljs.tools.reader.reader_types.NodeReadableReader(readable,null)),cljs.core.object_array.cljs$core$IFn$_invoke$arity$1((1)),(1),(1)));
});
/**
* Creates an IndexingPushbackReader from a given string or PushbackReader
*/
cljs.tools.reader.reader_types.indexing_push_back_reader = (function cljs$tools$reader$reader_types$indexing_push_back_reader(var_args){
var G__5284 = arguments.length;
switch (G__5284) {
case 1:
return cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 3:
return cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$1 = (function (s_or_rdr){
return cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$2(s_or_rdr,(1));
}));
(cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$2 = (function (s_or_rdr,buf_len){
return cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$3(s_or_rdr,buf_len,null);
}));
(cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$core$IFn$_invoke$arity$3 = (function (s_or_rdr,buf_len,file_name){
return (new cljs.tools.reader.reader_types.IndexingPushbackReader(((typeof s_or_rdr === 'string')?cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$2(s_or_rdr,buf_len):s_or_rdr),(1),(1),true,null,(0),file_name));
}));
(cljs.tools.reader.reader_types.indexing_push_back_reader.cljs$lang$maxFixedArity = 3);
/**
* Creates a SourceLoggingPushbackReader from a given string or PushbackReader
*/
cljs.tools.reader.reader_types.source_logging_push_back_reader = (function cljs$tools$reader$reader_types$source_logging_push_back_reader(var_args){
var G__5287 = arguments.length;
switch (G__5287) {
case 1:
return cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 3:
return cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$1 = (function (s_or_rdr){
return cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$2(s_or_rdr,(1));
}));
(cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$2 = (function (s_or_rdr,buf_len){
return cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$3(s_or_rdr,buf_len,null);
}));
(cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$core$IFn$_invoke$arity$3 = (function (s_or_rdr,buf_len,file_name){
return (new cljs.tools.reader.reader_types.SourceLoggingPushbackReader(((typeof s_or_rdr === 'string')?cljs.tools.reader.reader_types.string_push_back_reader.cljs$core$IFn$_invoke$arity$2(s_or_rdr,buf_len):s_or_rdr),(1),(1),true,null,(0),file_name,cljs.core.atom.cljs$core$IFn$_invoke$arity$1(new cljs.core.PersistentArrayMap(null, 2, [cljs.core.cst$kw$buffer,(new goog.string.StringBuffer()),cljs.core.cst$kw$offset,cljs.core.list((0))], null))));
}));
(cljs.tools.reader.reader_types.source_logging_push_back_reader.cljs$lang$maxFixedArity = 3);
/**
* Reads a line from the reader or from *in* if no reader is specified
*/
cljs.tools.reader.reader_types.read_line = (function cljs$tools$reader$reader_types$read_line(rdr){
var c = rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null);
var s = (new goog.string.StringBuffer());
while(true){
if(cljs.tools.reader.impl.utils.newline_QMARK_(c)){
return cljs.core.str.cljs$core$IFn$_invoke$arity$1(s);
} else {
var G__5289 = rdr.cljs$tools$reader$reader_types$Reader$read_char$arity$1(null);
var G__5290 = s.append(c);
c = G__5289;
s = G__5290;
continue;
}
break;
}
});
cljs.tools.reader.reader_types.source_logging_reader_QMARK_ = (function cljs$tools$reader$reader_types$source_logging_reader_QMARK_(rdr){
return (rdr instanceof cljs.tools.reader.reader_types.SourceLoggingPushbackReader);
});
/**
* Returns true if rdr is an IndexingReader and the current char starts a new line
*/
cljs.tools.reader.reader_types.line_start_QMARK_ = (function cljs$tools$reader$reader_types$line_start_QMARK_(rdr){
if(cljs.tools.reader.reader_types.indexing_reader_QMARK_(rdr)){
return ((1) === rdr.cljs$tools$reader$reader_types$IndexingReader$get_column_number$arity$1(null));
} else {
return null;
}
});
cljs.tools.reader.reader_types.log_source_STAR_ = (function cljs$tools$reader$reader_types$log_source_STAR_(reader,f){
var buffer = cljs.core.cst$kw$buffer.cljs$core$IFn$_invoke$arity$1(cljs.core.deref(reader.frames));
try{cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$variadic(reader.frames,cljs.core.update_in,new cljs.core.PersistentVector(null, 1, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$kw$offset], null),cljs.core.conj,cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([buffer.getLength()], 0));
var ret = (f.cljs$core$IFn$_invoke$arity$0 ? f.cljs$core$IFn$_invoke$arity$0() : f.call(null));
if((((!((ret == null))))?(((((ret.cljs$lang$protocol_mask$partition0$ & (131072))) || ((cljs.core.PROTOCOL_SENTINEL === ret.cljs$core$IMeta$))))?true:false):false)){
return cljs.tools.reader.reader_types.merge_meta(ret,new cljs.core.PersistentArrayMap(null, 1, [cljs.core.cst$kw$source,cljs.tools.reader.reader_types.peek_source_log(cljs.core.deref(reader.frames))], null));
} else {
return ret;
}
}finally {cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$4(reader.frames,cljs.core.update_in,new cljs.core.PersistentVector(null, 1, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.cst$kw$offset], null),cljs.core.rest);
}});
+1
View File
@@ -0,0 +1 @@
{:output-dir "build/js", :externs ["closure-js/externs"], :optimizations :advanced, :output-to "build/js/app.js", :output-wrapper true, :source-map "build/js/app.js.map", :libs ["closure-js/libs"], :pseudo-names true, :main "omgnata.prod", :pretty-print false}
File diff suppressed because it is too large Load Diff
+290
View File
@@ -0,0 +1,290 @@
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.string
(:refer-clojure :exclude [replace reverse])
(:require [goog.string :as gstring])
(:import [goog.string StringBuffer]))
(defn- seq-reverse
[coll]
(reduce conj () coll))
(def ^:private re-surrogate-pair
(js/RegExp. "([\\uD800-\\uDBFF])([\\uDC00-\\uDFFF])" "g"))
(defn ^string reverse
"Returns s with its characters reversed."
[s]
(-> (.replace s re-surrogate-pair "$2$1")
(.. (split "") (reverse) (join ""))))
(defn- replace-all
[s re replacement]
(let [r (js/RegExp. (.-source re)
(cond-> "g"
(.-ignoreCase re) (str "i")
(.-multiline re) (str "m")
(.-unicode re) (str "u")))]
(.replace s r replacement)))
(defn- replace-with
[f]
(fn [& args]
(let [matches (drop-last 2 args)]
(if (= (count matches) 1)
(f (first matches))
(f (vec matches))))))
(defn ^string replace
"Replaces all instance of match with replacement in s.
match/replacement can be:
string / string
pattern / (string or function of match).
See also replace-first.
The replacement is literal (i.e. none of its characters are treated
specially) for all cases above except pattern / string.
For pattern / string, $1, $2, etc. in the replacement string are
substituted with the string that matched the corresponding
parenthesized group in the pattern.
Example:
(clojure.string/replace \"Almost Pig Latin\" #\"\\b(\\w)(\\w+)\\b\" \"$2$1ay\")
-> \"lmostAay igPay atinLay\""
[s match replacement]
(cond
(string? match)
(.replace s (js/RegExp. (gstring/regExpEscape match) "g") replacement)
(instance? js/RegExp match)
(if (string? replacement)
(replace-all s match replacement)
(replace-all s match (replace-with replacement)))
:else (throw (str "Invalid match arg: " match))))
(defn ^string replace-first
"Replaces the first instance of match with replacement in s.
match/replacement can be:
string / string
pattern / (string or function of match).
See also replace.
The replacement is literal (i.e. none of its characters are treated
specially) for all cases above except pattern / string.
For pattern / string, $1, $2, etc. in the replacement string are
substituted with the string that matched the corresponding
parenthesized group in the pattern.
Example:
(clojure.string/replace-first \"swap first two words\"
#\"(\\w+)(\\s+)(\\w+)\" \"$3$2$1\")
-> \"first swap two words\""
[s match replacement]
(.replace s match replacement))
(defn join
"Returns a string of all elements in coll, as returned by (seq coll),
separated by an optional separator."
([coll]
(loop [sb (StringBuffer.) coll (seq coll)]
(if-not (nil? coll)
(recur (. sb (append (str (first coll)))) (next coll))
^string (.toString sb))))
([separator coll]
(loop [sb (StringBuffer.) coll (seq coll)]
(if-not (nil? coll)
(do
(. sb (append (str (first coll))))
(let [coll (next coll)]
(when-not (nil? coll)
(. sb (append separator)))
(recur sb coll)))
^string (.toString sb)))))
(defn ^string upper-case
"Converts string to all upper-case."
[s]
(.toUpperCase s))
(defn ^string lower-case
"Converts string to all lower-case."
[s]
(.toLowerCase s))
(defn ^string capitalize
"Converts first character of the string to upper-case, all other
characters to lower-case."
[s]
(gstring/capitalize s))
;; The JavaScript split function takes a limit argument but the return
;; value is not the same as the Java split function.
;;
;; Java: (.split "a-b-c" #"-" 2) => ["a" "b-c"]
;; JavaScript: (.split "a-b-c" #"-" 2) => ["a" "b"]
;;
;; For consistency, the three arg version has been implemented to
;; mimic Java's behavior.
(defn- pop-last-while-empty
[v]
(loop [v v]
(if (identical? "" (peek v))
(recur (pop v))
v)))
(defn- discard-trailing-if-needed
[limit v]
(if (and (== 0 limit) (< 1 (count v)))
(pop-last-while-empty v)
v))
(defn- split-with-empty-regex
[s limit]
(if (or (<= limit 0) (>= limit (+ 2 (count s))))
(conj (vec (cons "" (map str (seq s)))) "")
(condp == limit
1 (vector s)
2 (vector "" s)
(let [c (- limit 2)]
(conj (vec (cons "" (subvec (vec (map str (seq s))) 0 c))) (subs s c))))))
(defn split
"Splits string on a regular expression. Optional argument limit is
the maximum number of parts. Not lazy. Returns vector of the parts.
Trailing empty strings are not returned - pass limit of -1 to return all."
([s re]
(split s re 0))
([s re limit]
(discard-trailing-if-needed limit
(if (identical? "/(?:)/" (str re))
(split-with-empty-regex s limit)
(if (< limit 1)
(vec (.split (str s) re))
(loop [s s
limit limit
parts []]
(if (== 1 limit)
(conj parts s)
(let [m (re-find re s)]
(if-not (nil? m)
(let [index (.indexOf s m)]
(recur (.substring s (+ index (count m)))
(dec limit)
(conj parts (.substring s 0 index))))
(conj parts s))))))))))
(defn split-lines
"Splits s on \\n or \\r\\n. Trailing empty lines are not returned."
[s]
(split s #"\n|\r\n"))
(defn ^string trim
"Removes whitespace from both ends of string."
[s]
(gstring/trim s))
(defn ^string triml
"Removes whitespace from the left side of string."
[s]
(gstring/trimLeft s))
(defn ^string trimr
"Removes whitespace from the right side of string."
[s]
(gstring/trimRight s))
(defn ^string trim-newline
"Removes all trailing newline \\n or return \\r characters from
string. Similar to Perl's chomp."
[s]
(loop [index (.-length s)]
(if (zero? index)
""
(let [ch (get s (dec index))]
(if (or (identical? \newline ch)
(identical? \return ch))
(recur (dec index))
(.substring s 0 index))))))
(defn ^boolean blank?
"True is s is nil, empty, or contains only whitespace."
[s]
(gstring/isEmptyOrWhitespace (gstring/makeSafe s)))
(defn ^string escape
"Return a new string, using cmap to escape each character ch
from s as follows:
If (cmap ch) is nil, append ch to the new string.
If (cmap ch) is non-nil, append (str (cmap ch)) instead."
[s cmap]
(let [buffer (StringBuffer.)
length (.-length s)]
(loop [index 0]
(if (== length index)
(. buffer (toString))
(let [ch (.charAt s index)
replacement (get cmap ch)]
(if-not (nil? replacement)
(.append buffer (str replacement))
(.append buffer ch))
(recur (inc index)))))))
(defn index-of
"Return index of value (string or char) in s, optionally searching
forward from from-index or nil if not found."
([s value]
(let [result (.indexOf s value)]
(if (neg? result)
nil
result)))
([s value from-index]
(let [result (.indexOf s value from-index)]
(if (neg? result)
nil
result))))
(defn last-index-of
"Return last index of value (string or char) in s, optionally
searching backward from from-index or nil if not found."
([s value]
(let [result (.lastIndexOf s value)]
(if (neg? result)
nil
result)))
([s value from-index]
(let [result (.lastIndexOf s value from-index)]
(if (neg? result)
nil
result))))
(defn ^boolean starts-with?
"True if s starts with substr."
[s substr]
(gstring/startsWith s substr))
(defn ^boolean ends-with?
"True if s ends with substr."
[s substr]
(gstring/endsWith s substr))
(defn ^boolean includes?
"True if s includes substr."
[s substr]
(gstring/contains s substr))
+479
View File
@@ -0,0 +1,479 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('clojure.string');
goog.require('cljs.core');
goog.require('cljs.core.constants');
goog.require('goog.string');
goog.require('goog.string.StringBuffer');
clojure.string.seq_reverse = (function clojure$string$seq_reverse(coll){
return cljs.core.reduce.cljs$core$IFn$_invoke$arity$3(cljs.core.conj,cljs.core.List.EMPTY,coll);
});
clojure.string.re_surrogate_pair = (new RegExp("([\\uD800-\\uDBFF])([\\uDC00-\\uDFFF])","g"));
/**
* Returns s with its characters reversed.
*/
clojure.string.reverse = (function clojure$string$reverse(s){
return s.replace(clojure.string.re_surrogate_pair,"$2$1").split("").reverse().join("");
});
clojure.string.replace_all = (function clojure$string$replace_all(s,re,replacement){
var r = (new RegExp(re.source,(function (){var G__5199 = "g";
var G__5199__$1 = (cljs.core.truth_(re.ignoreCase)?[G__5199,"i"].join(''):G__5199);
var G__5199__$2 = (cljs.core.truth_(re.multiline)?[G__5199__$1,"m"].join(''):G__5199__$1);
if(cljs.core.truth_(re.unicode)){
return [G__5199__$2,"u"].join('');
} else {
return G__5199__$2;
}
})()));
return s.replace(r,replacement);
});
clojure.string.replace_with = (function clojure$string$replace_with(f){
return (function() {
var G__5202__delegate = function (args){
var matches = cljs.core.drop_last.cljs$core$IFn$_invoke$arity$2((2),args);
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(cljs.core.count(matches),(1))){
var G__5200 = cljs.core.first(matches);
return (f.cljs$core$IFn$_invoke$arity$1 ? f.cljs$core$IFn$_invoke$arity$1(G__5200) : f.call(null,G__5200));
} else {
var G__5201 = cljs.core.vec(matches);
return (f.cljs$core$IFn$_invoke$arity$1 ? f.cljs$core$IFn$_invoke$arity$1(G__5201) : f.call(null,G__5201));
}
};
var G__5202 = function (var_args){
var args = null;
if (arguments.length > 0) {
var G__5203__i = 0, G__5203__a = new Array(arguments.length - 0);
while (G__5203__i < G__5203__a.length) {G__5203__a[G__5203__i] = arguments[G__5203__i + 0]; ++G__5203__i;}
args = new cljs.core.IndexedSeq(G__5203__a,0,null);
}
return G__5202__delegate.call(this,args);};
G__5202.cljs$lang$maxFixedArity = 0;
G__5202.cljs$lang$applyTo = (function (arglist__5204){
var args = cljs.core.seq(arglist__5204);
return G__5202__delegate(args);
});
G__5202.cljs$core$IFn$_invoke$arity$variadic = G__5202__delegate;
return G__5202;
})()
;
});
/**
* Replaces all instance of match with replacement in s.
*
* match/replacement can be:
*
* string / string
* pattern / (string or function of match).
*
* See also replace-first.
*
* The replacement is literal (i.e. none of its characters are treated
* specially) for all cases above except pattern / string.
*
* For pattern / string, $1, $2, etc. in the replacement string are
* substituted with the string that matched the corresponding
* parenthesized group in the pattern.
*
* Example:
* (clojure.string/replace "Almost Pig Latin" #"\b(\w)(\w+)\b" "$2$1ay")
* -> "lmostAay igPay atinLay"
*/
clojure.string.replace = (function clojure$string$replace(s,match,replacement){
if(typeof match === 'string'){
return s.replace((new RegExp(goog.string.regExpEscape(match),"g")),replacement);
} else {
if((match instanceof RegExp)){
if(typeof replacement === 'string'){
return clojure.string.replace_all(s,match,replacement);
} else {
return clojure.string.replace_all(s,match,clojure.string.replace_with(replacement));
}
} else {
throw ["Invalid match arg: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(match)].join('');
}
}
});
/**
* Replaces the first instance of match with replacement in s.
*
* match/replacement can be:
*
* string / string
* pattern / (string or function of match).
*
* See also replace.
*
* The replacement is literal (i.e. none of its characters are treated
* specially) for all cases above except pattern / string.
*
* For pattern / string, $1, $2, etc. in the replacement string are
* substituted with the string that matched the corresponding
* parenthesized group in the pattern.
*
* Example:
* (clojure.string/replace-first "swap first two words"
* #"(\w+)(\s+)(\w+)" "$3$2$1")
* -> "first swap two words"
*/
clojure.string.replace_first = (function clojure$string$replace_first(s,match,replacement){
return s.replace(match,replacement);
});
/**
* Returns a string of all elements in coll, as returned by (seq coll),
* separated by an optional separator.
*/
clojure.string.join = (function clojure$string$join(var_args){
var G__5206 = arguments.length;
switch (G__5206) {
case 1:
return clojure.string.join.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
break;
case 2:
return clojure.string.join.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(clojure.string.join.cljs$core$IFn$_invoke$arity$1 = (function (coll){
var sb = (new goog.string.StringBuffer());
var coll__$1 = cljs.core.seq(coll);
while(true){
if((!((coll__$1 == null)))){
var G__5208 = sb.append(cljs.core.str.cljs$core$IFn$_invoke$arity$1(cljs.core.first(coll__$1)));
var G__5209 = cljs.core.next(coll__$1);
sb = G__5208;
coll__$1 = G__5209;
continue;
} else {
return sb.toString();
}
break;
}
}));
(clojure.string.join.cljs$core$IFn$_invoke$arity$2 = (function (separator,coll){
var sb = (new goog.string.StringBuffer());
var coll__$1 = cljs.core.seq(coll);
while(true){
if((!((coll__$1 == null)))){
sb.append(cljs.core.str.cljs$core$IFn$_invoke$arity$1(cljs.core.first(coll__$1)));
var coll__$2 = cljs.core.next(coll__$1);
if((coll__$2 == null)){
} else {
sb.append(separator);
}
var G__5210 = sb;
var G__5211 = coll__$2;
sb = G__5210;
coll__$1 = G__5211;
continue;
} else {
return sb.toString();
}
break;
}
}));
(clojure.string.join.cljs$lang$maxFixedArity = 2);
/**
* Converts string to all upper-case.
*/
clojure.string.upper_case = (function clojure$string$upper_case(s){
return s.toUpperCase();
});
/**
* Converts string to all lower-case.
*/
clojure.string.lower_case = (function clojure$string$lower_case(s){
return s.toLowerCase();
});
/**
* Converts first character of the string to upper-case, all other
* characters to lower-case.
*/
clojure.string.capitalize = (function clojure$string$capitalize(s){
return goog.string.capitalize(s);
});
clojure.string.pop_last_while_empty = (function clojure$string$pop_last_while_empty(v){
var v__$1 = v;
while(true){
if(("" === cljs.core.peek(v__$1))){
var G__5212 = cljs.core.pop(v__$1);
v__$1 = G__5212;
continue;
} else {
return v__$1;
}
break;
}
});
clojure.string.discard_trailing_if_needed = (function clojure$string$discard_trailing_if_needed(limit,v){
if(((((0) === limit)) && (((1) < cljs.core.count(v))))){
return clojure.string.pop_last_while_empty(v);
} else {
return v;
}
});
clojure.string.split_with_empty_regex = (function clojure$string$split_with_empty_regex(s,limit){
if((((limit <= (0))) || ((limit >= ((2) + cljs.core.count(s)))))){
return cljs.core.conj.cljs$core$IFn$_invoke$arity$2(cljs.core.vec(cljs.core.cons("",cljs.core.map.cljs$core$IFn$_invoke$arity$2(cljs.core.str,cljs.core.seq(s)))),"");
} else {
var pred__5213 = cljs.core._EQ__EQ_;
var expr__5214 = limit;
if(cljs.core.truth_((pred__5213.cljs$core$IFn$_invoke$arity$2 ? pred__5213.cljs$core$IFn$_invoke$arity$2((1),expr__5214) : pred__5213.call(null,(1),expr__5214)))){
return (new cljs.core.PersistentVector(null,1,(5),cljs.core.PersistentVector.EMPTY_NODE,[s],null));
} else {
if(cljs.core.truth_((pred__5213.cljs$core$IFn$_invoke$arity$2 ? pred__5213.cljs$core$IFn$_invoke$arity$2((2),expr__5214) : pred__5213.call(null,(2),expr__5214)))){
return (new cljs.core.PersistentVector(null,2,(5),cljs.core.PersistentVector.EMPTY_NODE,["",s],null));
} else {
var c = (limit - (2));
return cljs.core.conj.cljs$core$IFn$_invoke$arity$2(cljs.core.vec(cljs.core.cons("",cljs.core.subvec.cljs$core$IFn$_invoke$arity$3(cljs.core.vec(cljs.core.map.cljs$core$IFn$_invoke$arity$2(cljs.core.str,cljs.core.seq(s))),(0),c))),cljs.core.subs.cljs$core$IFn$_invoke$arity$2(s,c));
}
}
}
});
/**
* Splits string on a regular expression. Optional argument limit is
* the maximum number of parts. Not lazy. Returns vector of the parts.
* Trailing empty strings are not returned - pass limit of -1 to return all.
*/
clojure.string.split = (function clojure$string$split(var_args){
var G__5217 = arguments.length;
switch (G__5217) {
case 2:
return clojure.string.split.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 3:
return clojure.string.split.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(clojure.string.split.cljs$core$IFn$_invoke$arity$2 = (function (s,re){
return clojure.string.split.cljs$core$IFn$_invoke$arity$3(s,re,(0));
}));
(clojure.string.split.cljs$core$IFn$_invoke$arity$3 = (function (s,re,limit){
return clojure.string.discard_trailing_if_needed(limit,((("/(?:)/" === cljs.core.str.cljs$core$IFn$_invoke$arity$1(re)))?clojure.string.split_with_empty_regex(s,limit):(((limit < (1)))?cljs.core.vec(cljs.core.str.cljs$core$IFn$_invoke$arity$1(s).split(re)):(function (){var s__$1 = s;
var limit__$1 = limit;
var parts = cljs.core.PersistentVector.EMPTY;
while(true){
if(((1) === limit__$1)){
return cljs.core.conj.cljs$core$IFn$_invoke$arity$2(parts,s__$1);
} else {
var m = cljs.core.re_find(re,s__$1);
if((!((m == null)))){
var index = s__$1.indexOf(m);
var G__5219 = s__$1.substring((index + cljs.core.count(m)));
var G__5220 = (limit__$1 - (1));
var G__5221 = cljs.core.conj.cljs$core$IFn$_invoke$arity$2(parts,s__$1.substring((0),index));
s__$1 = G__5219;
limit__$1 = G__5220;
parts = G__5221;
continue;
} else {
return cljs.core.conj.cljs$core$IFn$_invoke$arity$2(parts,s__$1);
}
}
break;
}
})())));
}));
(clojure.string.split.cljs$lang$maxFixedArity = 3);
/**
* Splits s on \n or \r\n. Trailing empty lines are not returned.
*/
clojure.string.split_lines = (function clojure$string$split_lines(s){
return clojure.string.split.cljs$core$IFn$_invoke$arity$2(s,/\n|\r\n/);
});
/**
* Removes whitespace from both ends of string.
*/
clojure.string.trim = (function clojure$string$trim(s){
return goog.string.trim(s);
});
/**
* Removes whitespace from the left side of string.
*/
clojure.string.triml = (function clojure$string$triml(s){
return goog.string.trimLeft(s);
});
/**
* Removes whitespace from the right side of string.
*/
clojure.string.trimr = (function clojure$string$trimr(s){
return goog.string.trimRight(s);
});
/**
* Removes all trailing newline \n or return \r characters from
* string. Similar to Perl's chomp.
*/
clojure.string.trim_newline = (function clojure$string$trim_newline(s){
var index = s.length;
while(true){
if((index === (0))){
return "";
} else {
var ch = cljs.core.get.cljs$core$IFn$_invoke$arity$2(s,(index - (1)));
if(((("\n" === ch)) || (("\r" === ch)))){
var G__5222 = (index - (1));
index = G__5222;
continue;
} else {
return s.substring((0),index);
}
}
break;
}
});
/**
* True is s is nil, empty, or contains only whitespace.
*/
clojure.string.blank_QMARK_ = (function clojure$string$blank_QMARK_(s){
return goog.string.isEmptyOrWhitespace(goog.string.makeSafe(s));
});
/**
* Return a new string, using cmap to escape each character ch
* from s as follows:
*
* If (cmap ch) is nil, append ch to the new string.
* If (cmap ch) is non-nil, append (str (cmap ch)) instead.
*/
clojure.string.escape = (function clojure$string$escape(s,cmap){
var buffer = (new goog.string.StringBuffer());
var length = s.length;
var index = (0);
while(true){
if((length === index)){
return buffer.toString();
} else {
var ch = s.charAt(index);
var replacement = cljs.core.get.cljs$core$IFn$_invoke$arity$2(cmap,ch);
if((!((replacement == null)))){
buffer.append(cljs.core.str.cljs$core$IFn$_invoke$arity$1(replacement));
} else {
buffer.append(ch);
}
var G__5223 = (index + (1));
index = G__5223;
continue;
}
break;
}
});
/**
* Return index of value (string or char) in s, optionally searching
* forward from from-index or nil if not found.
*/
clojure.string.index_of = (function clojure$string$index_of(var_args){
var G__5225 = arguments.length;
switch (G__5225) {
case 2:
return clojure.string.index_of.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 3:
return clojure.string.index_of.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(clojure.string.index_of.cljs$core$IFn$_invoke$arity$2 = (function (s,value){
var result = s.indexOf(value);
if((result < (0))){
return null;
} else {
return result;
}
}));
(clojure.string.index_of.cljs$core$IFn$_invoke$arity$3 = (function (s,value,from_index){
var result = s.indexOf(value,from_index);
if((result < (0))){
return null;
} else {
return result;
}
}));
(clojure.string.index_of.cljs$lang$maxFixedArity = 3);
/**
* Return last index of value (string or char) in s, optionally
* searching backward from from-index or nil if not found.
*/
clojure.string.last_index_of = (function clojure$string$last_index_of(var_args){
var G__5228 = arguments.length;
switch (G__5228) {
case 2:
return clojure.string.last_index_of.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
break;
case 3:
return clojure.string.last_index_of.cljs$core$IFn$_invoke$arity$3((arguments[(0)]),(arguments[(1)]),(arguments[(2)]));
break;
default:
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
}
});
(clojure.string.last_index_of.cljs$core$IFn$_invoke$arity$2 = (function (s,value){
var result = s.lastIndexOf(value);
if((result < (0))){
return null;
} else {
return result;
}
}));
(clojure.string.last_index_of.cljs$core$IFn$_invoke$arity$3 = (function (s,value,from_index){
var result = s.lastIndexOf(value,from_index);
if((result < (0))){
return null;
} else {
return result;
}
}));
(clojure.string.last_index_of.cljs$lang$maxFixedArity = 3);
/**
* True if s starts with substr.
*/
clojure.string.starts_with_QMARK_ = (function clojure$string$starts_with_QMARK_(s,substr){
return goog.string.startsWith(s,substr);
});
/**
* True if s ends with substr.
*/
clojure.string.ends_with_QMARK_ = (function clojure$string$ends_with_QMARK_(s,substr){
return goog.string.endsWith(s,substr);
});
/**
* True if s includes substr.
*/
clojure.string.includes_QMARK_ = (function clojure$string$includes_QMARK_(s,substr){
return goog.string.contains(s,substr);
});
+98
View File
@@ -0,0 +1,98 @@
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
;;; walk.cljs - generic tree walker with replacement
;; by Stuart Sierra
;; Jul5 17, 2011
;; CHANGE LOG:
;;
;; * July 17, 2011: Port to ClojureScript
;;
;; * December 15, 2008: replaced 'walk' with 'prewalk' & 'postwalk'
;;
;; * December 9, 2008: first version
(ns
^{:author "Stuart Sierra",
:doc "This file defines a generic tree walker for Clojure data
structures. It takes any data structure (list, vector, map, set,
seq), calls a function on every element, and uses the return value
of the function in place of the original. This makes it fairly
easy to write recursive search-and-replace functions, as shown in
the examples.
Note: \"walk\" supports all Clojure data structures EXCEPT maps
created with sorted-map-by. There is no (obvious) way to retrieve
the sorting function."}
clojure.walk)
(defn walk
"Traverses form, an arbitrary data structure. inner and outer are
functions. Applies inner to each element of form, building up a
data structure of the same type, then applies outer to the result.
Recognizes all Clojure data structures. Consumes seqs as with doall."
{:added "1.1"}
[inner outer form]
(cond
(list? form) (outer (apply list (map inner form)))
(map-entry? form)
(outer (MapEntry. (inner (key form)) (inner (val form)) nil))
(seq? form) (outer (doall (map inner form)))
(record? form) (outer (reduce (fn [r x] (conj r (inner x))) form form))
(coll? form) (outer (into (empty form) (map inner form)))
:else (outer form)))
(defn postwalk
"Performs a depth-first, post-order traversal of form. Calls f on
each sub-form, uses f's return value in place of the original.
Recognizes all Clojure data structures. Consumes seqs as with doall."
{:added "1.1"}
[f form]
(walk (partial postwalk f) f form))
(defn prewalk
"Like postwalk, but does pre-order traversal."
{:added "1.1"}
[f form]
(walk (partial prewalk f) identity (f form)))
(defn keywordize-keys
"Recursively transforms all map keys from strings to keywords."
{:added "1.1"}
[m]
(let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))]
;; only apply to maps
(postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
(defn stringify-keys
"Recursively transforms all map keys from keywords to strings."
{:added "1.1"}
[m]
(let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))]
;; only apply to maps
(postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
(defn prewalk-replace
"Recursively transforms form by replacing keys in smap with their
values. Like clojure/replace but works on any data structure. Does
replacement at the root of the tree first."
{:added "1.1"}
[smap form]
(prewalk (fn [x] (if (contains? smap x) (smap x) x)) form))
(defn postwalk-replace
"Recursively transforms form by replacing keys in smap with their
values. Like clojure/replace but works on any data structure. Does
replacement at the leaves of the tree first."
{:added "1.1"}
[smap form]
(postwalk (fn [x] (if (contains? smap x) (smap x) x)) form))
+131
View File
@@ -0,0 +1,131 @@
// Compiled by ClojureScript 1.11.60 {:static-fns true, :optimize-constants true, :optimizations :advanced}
goog.provide('clojure.walk');
goog.require('cljs.core');
goog.require('cljs.core.constants');
/**
* Traverses form, an arbitrary data structure. inner and outer are
* functions. Applies inner to each element of form, building up a
* data structure of the same type, then applies outer to the result.
* Recognizes all Clojure data structures. Consumes seqs as with doall.
*/
clojure.walk.walk = (function clojure$walk$walk(inner,outer,form){
if(cljs.core.list_QMARK_(form)){
var G__10713 = cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.list,cljs.core.map.cljs$core$IFn$_invoke$arity$2(inner,form));
return (outer.cljs$core$IFn$_invoke$arity$1 ? outer.cljs$core$IFn$_invoke$arity$1(G__10713) : outer.call(null,G__10713));
} else {
if(cljs.core.map_entry_QMARK_(form)){
var G__10714 = (new cljs.core.MapEntry((function (){var G__10715 = cljs.core.key(form);
return (inner.cljs$core$IFn$_invoke$arity$1 ? inner.cljs$core$IFn$_invoke$arity$1(G__10715) : inner.call(null,G__10715));
})(),(function (){var G__10716 = cljs.core.val(form);
return (inner.cljs$core$IFn$_invoke$arity$1 ? inner.cljs$core$IFn$_invoke$arity$1(G__10716) : inner.call(null,G__10716));
})(),null));
return (outer.cljs$core$IFn$_invoke$arity$1 ? outer.cljs$core$IFn$_invoke$arity$1(G__10714) : outer.call(null,G__10714));
} else {
if(cljs.core.seq_QMARK_(form)){
var G__10717 = cljs.core.doall.cljs$core$IFn$_invoke$arity$1(cljs.core.map.cljs$core$IFn$_invoke$arity$2(inner,form));
return (outer.cljs$core$IFn$_invoke$arity$1 ? outer.cljs$core$IFn$_invoke$arity$1(G__10717) : outer.call(null,G__10717));
} else {
if(cljs.core.record_QMARK_(form)){
var G__10718 = cljs.core.reduce.cljs$core$IFn$_invoke$arity$3((function (r,x){
return cljs.core.conj.cljs$core$IFn$_invoke$arity$2(r,(inner.cljs$core$IFn$_invoke$arity$1 ? inner.cljs$core$IFn$_invoke$arity$1(x) : inner.call(null,x)));
}),form,form);
return (outer.cljs$core$IFn$_invoke$arity$1 ? outer.cljs$core$IFn$_invoke$arity$1(G__10718) : outer.call(null,G__10718));
} else {
if(cljs.core.coll_QMARK_(form)){
var G__10719 = cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.empty(form),cljs.core.map.cljs$core$IFn$_invoke$arity$2(inner,form));
return (outer.cljs$core$IFn$_invoke$arity$1 ? outer.cljs$core$IFn$_invoke$arity$1(G__10719) : outer.call(null,G__10719));
} else {
return (outer.cljs$core$IFn$_invoke$arity$1 ? outer.cljs$core$IFn$_invoke$arity$1(form) : outer.call(null,form));
}
}
}
}
}
});
/**
* Performs a depth-first, post-order traversal of form. Calls f on
* each sub-form, uses f's return value in place of the original.
* Recognizes all Clojure data structures. Consumes seqs as with doall.
*/
clojure.walk.postwalk = (function clojure$walk$postwalk(f,form){
return clojure.walk.walk(cljs.core.partial.cljs$core$IFn$_invoke$arity$2(clojure.walk.postwalk,f),f,form);
});
/**
* Like postwalk, but does pre-order traversal.
*/
clojure.walk.prewalk = (function clojure$walk$prewalk(f,form){
return clojure.walk.walk(cljs.core.partial.cljs$core$IFn$_invoke$arity$2(clojure.walk.prewalk,f),cljs.core.identity,(f.cljs$core$IFn$_invoke$arity$1 ? f.cljs$core$IFn$_invoke$arity$1(form) : f.call(null,form)));
});
/**
* Recursively transforms all map keys from strings to keywords.
*/
clojure.walk.keywordize_keys = (function clojure$walk$keywordize_keys(m){
var f = (function (p__10720){
var vec__10721 = p__10720;
var k = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__10721,(0),null);
var v = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__10721,(1),null);
if(typeof k === 'string'){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.keyword.cljs$core$IFn$_invoke$arity$1(k),v], null);
} else {
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [k,v], null);
}
});
return clojure.walk.postwalk((function (x){
if(cljs.core.map_QMARK_(x)){
return cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentArrayMap.EMPTY,cljs.core.map.cljs$core$IFn$_invoke$arity$2(f,x));
} else {
return x;
}
}),m);
});
/**
* Recursively transforms all map keys from keywords to strings.
*/
clojure.walk.stringify_keys = (function clojure$walk$stringify_keys(m){
var f = (function (p__10724){
var vec__10725 = p__10724;
var k = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__10725,(0),null);
var v = cljs.core.nth.cljs$core$IFn$_invoke$arity$3(vec__10725,(1),null);
if((k instanceof cljs.core.Keyword)){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [cljs.core.name(k),v], null);
} else {
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [k,v], null);
}
});
return clojure.walk.postwalk((function (x){
if(cljs.core.map_QMARK_(x)){
return cljs.core.into.cljs$core$IFn$_invoke$arity$2(cljs.core.PersistentArrayMap.EMPTY,cljs.core.map.cljs$core$IFn$_invoke$arity$2(f,x));
} else {
return x;
}
}),m);
});
/**
* Recursively transforms form by replacing keys in smap with their
* values. Like clojure/replace but works on any data structure. Does
* replacement at the root of the tree first.
*/
clojure.walk.prewalk_replace = (function clojure$walk$prewalk_replace(smap,form){
return clojure.walk.prewalk((function (x){
if(cljs.core.contains_QMARK_(smap,x)){
return (smap.cljs$core$IFn$_invoke$arity$1 ? smap.cljs$core$IFn$_invoke$arity$1(x) : smap.call(null,x));
} else {
return x;
}
}),form);
});
/**
* Recursively transforms form by replacing keys in smap with their
* values. Like clojure/replace but works on any data structure. Does
* replacement at the leaves of the tree first.
*/
clojure.walk.postwalk_replace = (function clojure$walk$postwalk_replace(smap,form){
return clojure.walk.postwalk((function (x){
if(cljs.core.contains_QMARK_(smap,x)){
return (smap.cljs$core$IFn$_invoke$arity$1 ? smap.cljs$core$IFn$_invoke$arity$1(x) : smap.call(null,x));
} else {
return x;
}
}),form);
});
+381
View File
@@ -0,0 +1,381 @@
;; Copyright 2014 Cognitect. All Rights Reserved.
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS-IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
(ns cognitect.transit
(:refer-clojure :exclude [integer? uuid])
(:require [com.cognitect.transit :as t]
[com.cognitect.transit.types :as ty]
[com.cognitect.transit.eq :as eq])
(:import [goog.math Long]))
;; patch cljs.core/UUID IEquiv
(extend-type UUID
IEquiv
(-equiv [this other]
(cond
(instance? UUID other)
(identical? (.-uuid this) (.-uuid other))
(instance? ty/UUID other)
(identical? (.-uuid this) (.toString other))
:else false)))
(extend-protocol IComparable
UUID
(-compare [this other]
(if (or (instance? UUID other)
(instance? ty/UUID other))
(compare (.toString this) (.toString other))
(throw (js/Error. (str "Cannot compare " this " to " other)))))
ty/UUID
(-compare [this other]
(if (or (instance? UUID other)
(instance? ty/UUID other))
(compare (.toString this) (.toString other))
(throw (js/Error. (str "Cannot compare " this " to " other))))))
(extend-protocol IEquiv
Long
(-equiv [this other]
(.equiv this other))
ty/UUID
(-equiv [this other]
(if (instance? UUID other)
(-equiv other this)
(.equiv this other)))
ty/TaggedValue
(-equiv [this other]
(.equiv this other)))
(extend-protocol IHash
Long
(-hash [this]
(eq/hashCode this))
ty/UUID
(-hash [this]
(eq/hashCode this))
ty/TaggedValue
(-hash [this]
(eq/hashCode this)))
(extend-type ty/UUID
IPrintWithWriter
(-pr-writer [uuid writer _]
(-write writer (str "#uuid \"" (.toString uuid) "\""))))
(defn ^:no-doc opts-merge [a b]
(doseq [k (js-keys b)]
(let [v (aget b k)]
(aset a k v)))
a)
(deftype ^:no-doc MapBuilder []
Object
(init [_ node] (transient {}))
(add [_ m k v node] (assoc! m k v))
(finalize [_ m node] (persistent! m))
(fromArray [_ arr node] (cljs.core/PersistentArrayMap.fromArray arr true true)))
(deftype ^:no-doc VectorBuilder []
Object
(init [_ node] (transient []))
(add [_ v x node] (conj! v x))
(finalize [_ v node] (persistent! v))
(fromArray [_ arr node] (cljs.core/PersistentVector.fromArray arr true)))
(defn reader
"Return a transit reader. type may be either :json or :json-verbose.
opts may be a map optionally containing a :handlers entry. The value
of :handlers should be map from tag to a decoder function which returns
then in-memory representation of the semantic transit value."
([type] (reader type nil))
([type opts]
(t/reader (name type)
(opts-merge
#js {:handlers
(clj->js
(merge
{"$" (fn [v] (symbol v))
":" (fn [v] (keyword v))
"set" (fn [v] (into #{} v))
"list" (fn [v] (into () (.reverse v)))
"cmap" (fn [v]
(loop [i 0 ret (transient {})]
(if (< i (alength v))
(recur (+ i 2)
(assoc! ret (aget v i) (aget v (inc i))))
(persistent! ret))))}
(:handlers opts)))
:mapBuilder (MapBuilder.)
:arrayBuilder (VectorBuilder.)
:prefersStrings false}
(clj->js (dissoc opts :handlers))))))
(defn read
"Read a transit encoded string into ClojureScript values given a
transit reader."
[r str]
(.read r str))
(deftype ^:no-doc KeywordHandler []
Object
(tag [_ v] ":")
(rep [_ v] (.-fqn v))
(stringRep [_ v] (.-fqn v)))
(deftype ^:no-doc SymbolHandler []
Object
(tag [_ v] "$")
(rep [_ v] (.-str v))
(stringRep [_ v] (.-str v)))
(deftype ^:no-doc ListHandler []
Object
(tag [_ v] "list")
(rep [_ v]
(let [ret #js []]
(doseq [x v] (.push ret x))
(t/tagged "array" ret)))
(stringRep [_ v] nil))
(deftype ^:no-doc MapHandler []
Object
(tag [_ v] "map")
(rep [_ v] v)
(stringRep [_ v] nil))
(deftype ^:no-doc SetHandler []
Object
(tag [_ v] "set")
(rep [_ v]
(let [ret #js []]
(doseq [x v] (.push ret x))
(t/tagged "array" ret)))
(stringRep [v] nil))
(deftype ^:no-doc VectorHandler []
Object
(tag [_ v] "array")
(rep [_ v]
(let [ret #js []]
(doseq [x v] (.push ret x))
ret))
(stringRep [_ v] nil))
(deftype ^:no-doc UUIDHandler []
Object
(tag [_ v] "u")
(rep [_ v] (.-uuid v))
(stringRep [this v] (.rep this v)))
(defn writer
"Return a transit writer. type maybe either :json or :json-verbose.
opts is a map containing a :handlers entry. :handlers is a map of
type constructors to handler instances."
([type] (writer type nil))
([type opts]
(let [keyword-handler (KeywordHandler.)
symbol-handler (SymbolHandler.)
list-handler (ListHandler.)
map-handler (MapHandler.)
set-handler (SetHandler.)
vector-handler (VectorHandler.)
uuid-handler (UUIDHandler.)
handlers
(merge
{cljs.core/Keyword keyword-handler
cljs.core/Symbol symbol-handler
cljs.core/Range list-handler
cljs.core/List list-handler
cljs.core/Cons list-handler
cljs.core/EmptyList list-handler
cljs.core/LazySeq list-handler
cljs.core/RSeq list-handler
cljs.core/IndexedSeq list-handler
cljs.core/ChunkedCons list-handler
cljs.core/ChunkedSeq list-handler
cljs.core/PersistentQueueSeq list-handler
cljs.core/PersistentQueue list-handler
cljs.core/PersistentArrayMapSeq list-handler
cljs.core/PersistentTreeMapSeq list-handler
cljs.core/NodeSeq list-handler
cljs.core/ArrayNodeSeq list-handler
cljs.core/KeySeq list-handler
cljs.core/ValSeq list-handler
cljs.core/PersistentArrayMap map-handler
cljs.core/PersistentHashMap map-handler
cljs.core/PersistentTreeMap map-handler
cljs.core/PersistentHashSet set-handler
cljs.core/PersistentTreeSet set-handler
cljs.core/PersistentVector vector-handler
cljs.core/Subvec vector-handler
cljs.core/UUID uuid-handler}
(:handlers opts))]
(t/writer (name type)
(opts-merge
#js {:objectBuilder
(fn [m kfn vfn]
(reduce-kv
(fn [obj k v]
(doto obj (.push (kfn k) (vfn v))))
#js ["^ "] m))
:handlers
(specify handlers
Object
(forEach
([coll f]
(doseq [[k v] coll]
(f v k)))))
:unpack
(fn [x]
(if (instance? cljs.core/PersistentArrayMap x)
(.-arr x)
false))}
(clj->js (dissoc opts :handlers)))))))
(defn write
"Encode an object into a transit string given a transit writer."
[w o]
(.write w o))
(defn read-handler
"Construct a read handler. Implemented as identity, exists primarily
for API compatiblity with transit-clj"
[from-rep]
from-rep)
(defn write-handler
"Creates a transit write handler whose tag, rep,
stringRep, and verboseWriteHandler methods
invoke the provided fns."
([tag-fn rep-fn]
(write-handler tag-fn rep-fn nil nil))
([tag-fn rep-fn str-rep-fn]
(write-handler tag-fn rep-fn str-rep-fn nil))
([tag-fn rep-fn str-rep-fn verbose-handler-fn]
(reify
Object
(tag [_ o] (tag-fn o))
(rep [_ o] (rep-fn o))
(stringRep [_ o] (when str-rep-fn (str-rep-fn o)))
(getVerboseHandler [_] (when verbose-handler-fn (verbose-handler-fn))))))
;; =============================================================================
;; Constructors & Predicates
(defn tagged-value
"Construct a tagged value. tag must be a string and rep can
be any transit encodeable value."
[tag rep]
(ty/taggedValue tag rep))
(defn tagged-value?
"Returns true if x is a transit tagged value, false otherwise."
[x]
(ty/isTaggedValue x))
(defn integer
"Construct a transit integer value. Returns JavaScript number if
in the 53bit integer range, a goog.math.Long instance if above. s
may be a string or a JavaScript number."
[s]
(ty/intValue s))
(defn integer?
"Returns true if x is an integer value between the 53bit and 64bit
range, false otherwise."
[x]
(ty/isInteger x))
(defn bigint
"Construct a big integer from a string."
[s]
(ty/bigInteger s))
(defn bigint?
"Returns true if x is a transit big integer value, false otherwise."
[x]
(ty/isBigInteger x))
(defn bigdec
"Construct a big decimal from a string."
[s]
(ty/bigDecimalValue s))
(defn bigdec?
"Returns true if x is a transit big decimal value, false otherwise."
[x]
(ty/isBigDecimal x))
(defn uri
"Construct a URI from a string."
[s]
(ty/uri s))
(defn uri?
"Returns true if x is a transit URI value, false otherwise."
[x]
(ty/isURI x))
(defn uuid
"Construct a UUID from a string."
[s]
(ty/uuid s))
(defn uuid?
"Returns true if x is a transit UUID value, false otherwise."
[x]
(ty/isUUID x))
(defn binary
"Construct a transit binary value. s should be base64 encoded
string."
[s]
(ty/binary s))
(defn binary?
"Returns true if x is a transit binary value, false otherwise."
[x]
(ty/isBinary x))
(defn quoted
"Construct a quoted transit value. x should be a transit
encodeable value."
[x]
(ty/quoted x))
(defn quoted?
"Returns true if x is a transit quoted value, false otherwise."
[x]
(ty/isQuoted x))
(defn link
"Construct a transit link value. x should be an IMap instance
containing at a minimum the following keys: :href, :rel. It
may optionall include :name, :render, and :prompt. :href must
be a transit URI, all other values are strings, and :render must
be either :image or :link."
[x]
(ty/link x))
(defn link?
"Returns true if x a transit link value, false if otherwise."
[x]
(ty/isLink x))
+1172
View File
File diff suppressed because it is too large Load Diff
+626
View File
@@ -0,0 +1,626 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
"use strict";
goog.provide("com.cognitect.transit");
goog.require("com.cognitect.transit.impl.reader");
goog.require("com.cognitect.transit.impl.writer");
goog.require("com.cognitect.transit.types");
goog.require("com.cognitect.transit.eq");
goog.require("com.cognitect.transit.impl.decoder");
goog.require("com.cognitect.transit.caching");
/** @define {boolean} */
var TRANSIT_DEV = true;
/** @define {boolean} */
var TRANSIT_NODE_TARGET = false;
/** @define {boolean} */
var TRANSIT_BROWSER_TARGET = false;
/** @define {boolean} */
var TRANSIT_BROWSER_AMD_TARGET = false;
goog.scope(function() {
/**
* @class transit
*/
var transit = com.cognitect.transit;
var reader = com.cognitect.transit.impl.reader,
writer = com.cognitect.transit.impl.writer,
decoder = com.cognitect.transit.impl.decoder,
types = com.cognitect.transit.types,
eq = com.cognitect.transit.eq,
caching = com.cognitect.transit.caching;
/**
* Create a transit reader instance.
* @method transit.reader
* @param {string|null} type type of reader to construct.
* Default to "json". For verbose mode supply "json-verbose".
* @param {Object|null} opts reader options. A JavaScript object to
* customize the writer Valid entries include "defaultHandler",
* and "handler". "defaultHandler" should be JavaScript function
* taking two arguments, the first is the tag, the second the
* value. "handlers" should be an object of tags to handle. The
* values are functions that will receive the value of matched
* tag. "preferBuffers" may be supplied to customize binary
* decoding. If available binary data will read as Node.js Buffers,
* If Buffer is not available or "prefersBuffers" is set to false
* data will be read as Uint8Array. If neither Buffer nor Uint8Array is
* available - defaults to tagged value that simply wraps the
* base64 encoded string.
* @return {transit.reader} A transit reader.
* @example
* var r = transit.reader("json", {
* handlers: {
* "point": function(v) { return new Point(v[0], v[1]); }
* }
* });
*/
transit.reader = function(type, opts) {
if(type === "json" || type === "json-verbose" || type == null) {
type = "json";
var unmarshaller = new reader.JSONUnmarshaller(opts);
return new reader.Reader(unmarshaller, opts);
} else {
throw new Error("Cannot create reader of type " + type);
}
};
/**
* Create a transit writer instance.
* @method transit.writer
* @param {String|null} type type of writer to construct.
* Defaults to "json". For verbose mode supply "json-verbose".
* @param {Object|null} opts writer options. A JavaScript object to
* customize the writer. "handlers" options, a transit.map of
* JavaScript constructor and transit writer handler instance
* entries. "handlerForForeign" option, for dealing with values
* from other JavaScript contexts. This function will be passed
* the unmatchable value and the installed handlers. The function
* should return the correct handler. Note if this function is
* provided, special handling for Objects will also be
* auto-installed to catch plain Objects from the foreign context.
* @return {transit.writer} A transit writer.
* @example
* var r = transit.writer("json", {
* handlers: transit.map([
* Point, PointHandler
* ])
* });
*/
transit.writer = function(type, opts) {
if(type === "json" || type === "json-verbose" || type == null) {
if(type === "json-verbose") {
if(opts == null) opts = {};
opts["verbose"] = true;
}
type = "json";
var marshaller = new writer.JSONMarshaller(opts);
return new writer.Writer(marshaller, opts);
} else {
var err = new Error("Type must be \"json\"");
err.data = {type: type};
throw err;
}
};
/**
* Create a transit writer handler.
* @method transit.makeWriteHandler
* @param {Object} obj An object containing 3 functions, tag, rep and stringRep.
* "tag" should return a string representing the tag to be written on the wire.
* "rep" should return the representation on the wire. "stringRep" is should return
* the string representation of the value. Optional "getVerboseHandler" should return a
* handler for writing verbose output.
* @return {transit.handler} A transit write handler.
* @example
* var PointHandler = transit.makeWriteHandler({
* tag: "point",
* rep: function(p) { return [p.x, p.y]; },
* stringRep: function(p) { return null; }
* });
*/
transit.makeWriteHandler = function(obj) {
var Handler = function(){};
Handler.prototype.tag = obj["tag"];
Handler.prototype.rep = obj["rep"];
Handler.prototype.stringRep = obj["stringRep"];
Handler.prototype.getVerboseHandler = obj["getVerboseHandler"];
return new Handler();
};
transit.makeBuilder = function(obj) {
var Builder = function(){};
Builder.prototype.init = obj["init"];
Builder.prototype.add = obj["add"];
Builder.prototype.finalize = obj["finalize"];
Builder.prototype.fromArray = obj["fromArray"];
return new Builder();
};
/**
* Create a transit date.
* @method transit.date
* @param {Number|String} A number or string representing milliseconds since epoch.
* @return {Date} A JavaScript Date.
*/
transit.date = types.date;
/**
* Create an integer. If given a transit integer or a JavaScript
* number will simply return that value. Given a string will
* return a JavaScript number if the string represents an integer
* value in the 53bit range and a transit integer otherwise.
* @method transit.integer
* @param {Number|String|integer} s A value representing an integer.
* @return {transit.integer} A JavaScript number or transit integer.
*/
transit.integer = types.intValue;
/**
* Test if an object is a transit integer. Will return true if argument
* is a 64 bit integer or a JavaScript number that has an interpretation as
* an integer value, i.e. parseFloat(n) === parseInt(n)
* @method transit.isInteger
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if the value is a transit integer, false otherwise.
*/
transit.isInteger = types.isInteger;
/**
* Create transit UUID from high and low 64 bits. These integer values
* can be constructed with transit.integer.
* @method transit.uuid
* @param {transit.integer} high The high 64 bits.
* @param {transit.integer} low The low 64 bits.
* @return {transit.uuid} A transit UUID.
*/
transit.uuid = types.uuid;
/**
* Test if an object is a transit UUID.
* @method transit.isUUID
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if the vlaue is a transit UUID instance, false otherwise.
*/
transit.isUUID = types.isUUID;
/**
* Create a transit big integer.
* @method transit.bigInt
* @param {String} s A string representing an arbitrary size integer value.
* @return {transit.bigdec} A transit big integer.
*/
transit.bigInt = types.bigInteger;
/**
* Test if an object is a transit big integer.
* @method transit.isBigInt
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit big integer, false otherwise.
*/
transit.isBigInt = types.isBigInteger;
/**
* Create a transit big decimal.
* @method transit.bigDec
* @param {String} s A string representing an arbitrary precisions decimal value.
* @return {transit.bigdec} A transit big decimal.
*/
transit.bigDec = types.bigDecimalValue;
/**
* Test if an object is a transit big decimal.
* @method transit.isBigDec
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit big decimal, false otherwise.
*/
transit.isBigDec = types.isBigDecimal;
/**
* Create transit keyword.
* @method transit.keyword
* @param {String} name A string.
* @return {transit.keyword} A transit keyword.
* @example
* transit.keyword("foo");
*/
transit.keyword = types.keyword;
/**
* Test if an object is a transit keyword.
* @method transit.isKeyword
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit keyword, false otherwise.
*/
transit.isKeyword = types.isKeyword;
/**
* Create a transit symbol.
* @method transit.symbol
* @param {s} name A string.
* @return {transit.symbol} A transit symbol instance.
* @example
* transit.symbol("foo");
*/
transit.symbol = types.symbol;
/**
* Test if an object is a transit symbol
* @method transit.isSymbol
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit symbol, false otherwise.
*/
transit.isSymbol = types.isSymbol;
/**
* Create transit binary blob.
* @method transit.binary
* @param {String} s A base64 encoded string.
* @return {transit.binary} A transit binary blob instance.
*/
transit.binary = types.binary;
/**
* Test if an object is a transit binary blob.
* @method transit.isBinary
* @param {Object} x Any JavaScript value.
*/
transit.isBinary = types.isBinary;
/**
* Create a transit URI.
* @method transit.uri
* @param {String} A string representing a valid URI.
* @return {transit.uri} A transit URI.
*/
transit.uri = types.uri;
/**
* Test if an object is a transit URI.
* @method transit.isURI
* @param {Object} Any JavaScript value.
* @return {Boolean} true if x is a transit symbol, false otherwise.
*/
transit.isURI = types.isURI;
/**
* Create a transit hash map. Transit maps satisfy the current version
* of the ECMAScript 6 Map specification.
* @method transit.map
* @param {Array} xs A JavaScript array of alternating key value pairs.
* @return {transit.map} A transit map.
* @example
* transit.map([new Date(), "foo", [1,2], 3]);
*/
transit.map = types.map;
/**
* Test if an object is a transit map.
* @method transit.isMap
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit map, false otherwise.
*/
transit.isMap = types.isMap;
/**
* Create a transit set. Transit sets satisfy the current version of the
* of the ECMAScript 6 Set specification.
* @method transit.set
* @param {Array} xs A JavaScript array of values.
* @return {transit.set} A transit set.
* @example
* transit.set(["foo", [1,2], 3, {bar: "baz"}]);
*/
transit.set = types.set;
/**
* Test if an object is a transit set.
* @method transit.isSet
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit set, false otherwise.
*/
transit.isSet = types.isSet;
/**
* Create a transit list.
* @method transit.list
* @param {Array} A JavaScript array.
* @return {transit.list} A transit list.
*/
transit.list = types.list;
/**
* Test if an object is a transit list.
* @method transit.isList
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit list, false otherwise.
*/
transit.isList = types.isList;
/**
* Create a transit quoted value.
* @method transit.quoted
* @param {Object} x Any JavaScript value.
* @return {transit.quoted} A transit quoted value.
*/
transit.quoted = types.quoted;
/**
* Test if an object is a transit quoted value.
* @method transit.isQuoted
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit value, false otherwise.
*/
transit.isQuoted = types.isQuoted;
/**
* Create a transit tagged value.
* @method transit.tagged
* @param {String} tag A tag.
* @param {Object} value A JavaScrpt array, object, or string.
* @return {transit.tagged} A transit tagged value.
* @example
* transit.tagged("point", new Point(1,2));
*/
transit.tagged = types.taggedValue;
/**
* Test if an object is a transit tagged value.
* @method transit.isTaggedValue
* @param {Object} x Any JavaScript value.
* @return {Boolean} true if x is a transit value, false otherwise.
*/
transit.isTaggedValue = types.isTaggedValue;
/**
* Create a transit link.
* @method transit.link
* @param {transit.map} A transit map which must contain at a
* minimum the following keys: href, rel. It may optionally include
* name, render, and prompt. href must be a transit.uri, all other
* values are strings, and render must be either "image" or "link".
* @return {Object} A transit link.
*/
transit.link = types.link;
/**
* Test if an object is a transit link.
* @method transit.isLink
* @param {Object} x Any JavaScript object.
* @return {Boolean} true if x is a transit link, false otherwise.
*/
transit.isLink = types.isLink;
/**
* Compute the hashCode for any JavaScript object that has been
* extend to transit's equality and hashing protocol. JavaScript
* primitives and transit value are already extended to this protocol.
* Custom types may be extended to the protocol via transit.extenToEQ.
* @method transit.hash
* @param {Object} x Any JavaScript object that has been extended to
* transit's equality and hashing protocol.
* @return {Number} Returns JavaScript number - semantically a 32bit integer.
*/
transit.hash = eq.hashCode;
/**
* Compute the hashCode for JavaScript map-like types - either a JavaScript
* object or a JavaScript object that implements ES6 Map forEach.
* @method transit.hashMapLike
* @param {Object} x A plain JavaScript Object or Object that implements
* ES6 Map forEach.
* @return {Number} Returns JavaScript number - semantically a 32bit integer.
*/
transit.hashMapLike = eq.hashMapLike;
/**
* Compute the hashCode for JavaScript array-like types - either a JavaScript
* array or a JavaScript object that implements Array forEach.
* @method transit.hashArrayLike
* @param {Object} x A JavaScript Array or Object that implements
* Array forEach.
* @return {Number} Returns JavaScript number - semantically a 32bit integer.
*/
transit.hashMapLike = eq.hashArrayLike;
/**
* Test whether two JavaScript objects represent equal values. The
* objects to be tested should be extended to transit's equality
* and hasing protocol. JavaScript natives and transit value have
* already been extended to the protocol, including objects and
* arrays. Also transit maps and JavaScript objects may be
* compared for equality. Custom types may be extended via
* transit.extendToEQ.
* @param {Object} x A JavaScript object
* @param {Object} y A JavaScript object
* @return {Boolean} true if the x and y are equal, false otherwise.
*/
transit.equals = eq.equals;
/**
* Extend an object to hashing and equality required by
* transit maps and sets. Only required for custom
* types, JavaScript primitive types and transit
* types are handled.
* @method transit.extendToEQ
* @param {Object} x A JavaScript object, will be mutated.
* @return {Object} x
* @example
* transit.extendToEq(Point.protototype, {
* hashCode: function() {
* var bits = (this.x | 0) ^ ((this.y | 0) * 31);
* return bits ^ (bits >>> 32);
* },
* equals: function(other) {
* return this.x == other.x && this.y == other.y;
* }
* });
*/
transit.extendToEQ = eq.extendToEQ;
/**
* Convert a transit map instance into a JavaScript Object.
* Throws if the map has keys which have no string representation.
* @method transit.mapToObject
* @param {transit.map} m a transit map
* @return {Object} a JavaScript Object
*/
transit.mapToObject = function(m) {
var ret = {};
m.forEach(function(v, k) {
if(typeof k !== "string") {
throw Error("Cannot convert map with non-string keys");
} else {
ret[k] = v;
}
})
return ret;
};
/**
* Construct a Transit JSON decoder.
* @method transit.decoder
* @param {Object} options to the decoder. Can include map of
* handlers.
* @return {transit.decoder} a Transit JSON decoder
* @example
* var decoder = transit.decoder();
* var x = decoder.decode(json, transit.readCache());
*/
transit.decoder = decoder.decoder;
/**
* Construct a Transit read cache
* @method transit.readCache
* @return {transit.readCAche} a Transit read cache
*/
transit.readCache = caching.readCache;
/**
* Construct a Transit write cache
* @method transit.writeCache
* @return {transit.writeCache} a Transit write cache
*/
transit.writeCache = caching.writeCache;
transit.UUIDfromString = types.UUIDfromString;
transit.randomUUID = types.randomUUID;
transit.stringableKeys = writer.stringableKeys;
if(TRANSIT_BROWSER_TARGET) {
goog.exportSymbol("transit.reader", transit.reader);
goog.exportSymbol("transit.writer", transit.writer);
goog.exportSymbol("transit.makeBuilder", transit.makeBuilder);
goog.exportSymbol("transit.makeWriteHandler", transit.makeWriteHandler);
goog.exportSymbol("transit.date", types.date);
goog.exportSymbol("transit.integer", types.intValue);
goog.exportSymbol("transit.isInteger", types.isInteger);
goog.exportSymbol("transit.uuid", types.uuid);
goog.exportSymbol("transit.isUUID", types.isUUID);
goog.exportSymbol("transit.bigInt", types.bigInteger);
goog.exportSymbol("transit.isBigInt", types.isBigInteger);
goog.exportSymbol("transit.bigDec", types.bigDecimalValue);
goog.exportSymbol("transit.isBigDec", types.isBigDecimal);
goog.exportSymbol("transit.keyword", types.keyword);
goog.exportSymbol("transit.isKeyword", types.isKeyword);
goog.exportSymbol("transit.symbol", types.symbol);
goog.exportSymbol("transit.isSymbol", types.isSymbol);
goog.exportSymbol("transit.binary", types.binary);
goog.exportSymbol("transit.isBinary", types.isBinary);
goog.exportSymbol("transit.uri", types.uri);
goog.exportSymbol("transit.isURI", types.isURI);
goog.exportSymbol("transit.map", types.map);
goog.exportSymbol("transit.isMap", types.isMap);
goog.exportSymbol("transit.set", types.set);
goog.exportSymbol("transit.isSet", types.isSet);
goog.exportSymbol("transit.list", types.list);
goog.exportSymbol("transit.isList", types.isList);
goog.exportSymbol("transit.quoted", types.quoted);
goog.exportSymbol("transit.isQuoted", types.isQuoted);
goog.exportSymbol("transit.tagged", types.taggedValue);
goog.exportSymbol("transit.isTaggedValue", types.isTaggedValue);
goog.exportSymbol("transit.link", types.link);
goog.exportSymbol("transit.isLink", types.isLink);
goog.exportSymbol("transit.hash", eq.hashCode);
goog.exportSymbol("transit.hashMapLike", eq.hashMapLike);
goog.exportSymbol("transit.hashArrayLike", eq.hashArrayLike);
goog.exportSymbol("transit.equals", eq.equals);
goog.exportSymbol("transit.extendToEQ", eq.extendToEQ);
goog.exportSymbol("transit.mapToObject", transit.mapToObject);
goog.exportSymbol("transit.decoder", decoder.decoder);
goog.exportSymbol("transit.UUIDfromString", types.UUIDfromString);
goog.exportSymbol("transit.randomUUID", types.randomUUID);
goog.exportSymbol("transit.stringableKeys", writer.stringableKeys);
goog.exportSymbol("transit.readCache", caching.readCache);
goog.exportSymbol("transit.writeCache", caching.writeCache);
}
if(TRANSIT_NODE_TARGET) {
module.exports = {
reader: transit.reader,
writer: transit.writer,
makeBuilder: transit.makeBuilder,
makeWriteHandler: transit.makeWriteHandler,
date: types.date,
integer: types.intValue,
isInteger: types.isInteger,
uuid: types.uuid,
isUUID: types.isUUID,
bigInt: types.bigInteger,
isBigInt: types.isBigInteger,
bigDec: types.bigDecimalValue,
isBigDec: types.isBigDecimal,
keyword: types.keyword,
isKeyword: types.isKeyword,
symbol: types.symbol,
isSymbol: types.isSymbol,
binary: types.binary,
isBinary: types.isBinary,
uri: types.uri,
isURI: types.isURI,
map: types.map,
isMap: types.isMap,
set: types.set,
isSet: types.isSet,
list: types.list,
isList: types.isList,
quoted: types.quoted,
isQuoted: types.isQuoted,
tagged: types.taggedValue,
isTaggedValue: types.isTaggedValue,
link: types.link,
isLink: types.isLink,
hash: eq.hashCode,
hashArrayLike: eq.hashArrayLike,
hashMapLike: eq.hashMapLike,
equals: eq.equals,
extendToEQ: eq.extendToEQ,
mapToObject: transit.mapToObject,
decoder: decoder.decoder,
UUIDfromString: types.UUIDfromString,
randomUUID: types.randomUUID,
stringableKeys: writer.stringableKeys,
readCache: caching.readCache,
writeCache: caching.writeCache
};
}
});
+177
View File
@@ -0,0 +1,177 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.caching");
goog.require("com.cognitect.transit.delimiters");
goog.scope(function() {
var caching = com.cognitect.transit.caching,
d = com.cognitect.transit.delimiters;
/**
* @const
* @type {number}
*/
caching.MIN_SIZE_CACHEABLE = 3;
/**
* @const
* @type {number}
*/
caching.BASE_CHAR_IDX = 48;
/**
* @const
* @type {number}
*/
caching.CACHE_CODE_DIGITS = 44;
/**
* @const
* @type {number}
*/
caching.MAX_CACHE_ENTRIES = caching.CACHE_CODE_DIGITS*caching.CACHE_CODE_DIGITS;
/**
* @const
* @type {number}
*/
caching.MAX_CACHE_SIZE = 4096;
caching.isCacheable = function(string, asMapKey) {
if(string.length > caching.MIN_SIZE_CACHEABLE) {
if(asMapKey) {
return true;
} else {
var c0 = string.charAt(0),
c1 = string.charAt(1);
if(c0 === d.ESC) {
return c1 === ":" || c1 === "$" || c1 === "#";
} else {
return false;
}
}
} else {
return false;
}
};
// =============================================================================
// WriteCache
caching.idxToCode = function(idx) {
var hi = Math.floor(idx / caching.CACHE_CODE_DIGITS),
lo = idx % caching.CACHE_CODE_DIGITS,
loc = String.fromCharCode(lo + caching.BASE_CHAR_IDX)
if(hi === 0) {
return d.SUB + loc;
} else {
return d.SUB + String.fromCharCode(hi + caching.BASE_CHAR_IDX) + loc;
}
};
/**
* @constructor
*/
caching.WriteCache = function() {
this.idx = 0;
this.gen = 0;
this.cacheSize = 0;
this.cache = {};
};
caching.WriteCache.prototype.write = function(string, asMapKey) {
if(caching.isCacheable(string, asMapKey)) {
if(this.cacheSize === caching.MAX_CACHE_SIZE) {
this.clear();
this.gen = 0;
this.cache = {};
} else if(this.idx === caching.MAX_CACHE_ENTRIES) {
this.clear();
}
var entry = this.cache[string];
if(entry == null) {
this.cache[string] = [caching.idxToCode(this.idx), this.gen];
this.idx++;
return string;
} else if(entry[1] != this.gen) {
entry[1] = this.gen;
entry[0] = caching.idxToCode(this.idx);
this.idx++;
return string;
} else {
return entry[0];
}
} else {
return string;
}
};
caching.WriteCache.prototype.clear = function() {
this.idx = 0;
this.gen++;
};
caching.writeCache = function() {
return new caching.WriteCache();
};
// =============================================================================
// ReadCache
caching.isCacheCode = function(string) {
return (string.charAt(0) === d.SUB) && (string.charAt(1) !== " ");
};
caching.codeToIdx = function(code) {
if(code.length === 2) {
return code.charCodeAt(1) - caching.BASE_CHAR_IDX;
} else {
var hi = (code.charCodeAt(1) - caching.BASE_CHAR_IDX) * caching.CACHE_CODE_DIGITS,
lo = (code.charCodeAt(2) - caching.BASE_CHAR_IDX);
return hi + lo;
}
};
/**
* @constructor
*/
caching.ReadCache = function() {
this.idx = 0;
this.cache = [];
};
caching.ReadCache.prototype.write = function(obj, asMapKey) {
if(this.idx == caching.MAX_CACHE_ENTRIES) {
this.idx = 0;
}
this.cache[this.idx] = obj;
this.idx++;
return obj;
};
caching.ReadCache.prototype.read = function(string, asMapKey) {
return this.cache[caching.codeToIdx(string)];
};
caching.ReadCache.prototype.clear = function() {
this.idx = 0;
};
caching.readCache = function() {
return new caching.ReadCache();
};
});
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.delimiters");
goog.scope(function() {
var delimiters = com.cognitect.transit.delimiters;
/**
* @const
* @type {string}
*/
delimiters.ESC = "~";
/**
* @const
* @type {string}
*/
delimiters.TAG = "#";
/**
* @const
* @type {string}
*/
delimiters.SUB = "^";
/**
* @const
* @type {string}
*/
delimiters.RES = "`";
/**
* @const
* @type {string}
*/
delimiters.ESC_TAG = "~#";
});
+204
View File
@@ -0,0 +1,204 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.eq");
goog.require("com.cognitect.transit.util");
goog.scope(function() {
var eq = com.cognitect.transit.eq,
util = com.cognitect.transit.util;
/**
* @const
* @type {string}
*/
eq.hashCodeProperty = "transit$hashCode$";
/**
* @type {number}
*/
eq.hashCodeCounter = 1;
eq.equals = function (x, y) {
if(x == null) {
return y == null;
} else if(x === y) {
return true;
} else if(typeof x === "object") {
if(util.isArray(x)) {
if(util.isArray(y)) {
if(x.length === y.length) {
for(var i = 0; i < x.length; i++) {
if(!eq.equals(x[i], y[i])) {
return false;
}
}
return true;
} else {
return false;
}
} else {
return false;
}
} else if(x.com$cognitect$transit$equals) {
return x.com$cognitect$transit$equals(y);
} else if((y != null) && (typeof y === "object")) {
if(y.com$cognitect$transit$equals) {
return y.com$cognitect$transit$equals(x);
} else {
var xklen = 0,
yklen = util.objectKeys(y).length;
for(var p in x) {
if(!x.hasOwnProperty(p)) continue;
xklen++;
if(!y.hasOwnProperty(p)) {
return false;
} else {
if(!eq.equals(x[p], y[p])) {
return false;
}
}
}
return xklen === yklen;
}
} else {
return false;
}
} else {
return false
}
};
eq.hashCombine = function(seed, hash) {
return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2));
};
eq.stringCodeCache = {};
eq.stringCodeCacheSize = 0;
/**
* @const
* @type {number}
*/
eq.STR_CACHE_MAX = 256;
eq.hashString = function(str) {
// a la goog.string.HashCode
// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1206
var cached = eq.stringCodeCache[str];
if(cached != null) {
return cached;
}
var code = 0;
for (var i = 0; i < str.length; ++i) {
code = 31 * code + str.charCodeAt(i);
code %= 0x100000000;
}
eq.stringCodeCacheSize++;
if(eq.stringCodeCacheSize >= eq.STR_CACHE_MAX) {
eq.stringCodeCache = {};
eq.stringCodeCacheSize = 1;
}
eq.stringCodeCache[str] = code;
return code;
};
eq.hashMapLike = function(m) {
var code = 0;
// ES6 Map-like case
if(m.forEach != null) {
m.forEach(function(val, key, m) {
code = (code + (eq.hashCode(key) ^ eq.hashCode(val))) % 4503599627370496;
});
} else {
// JS Object case
var keys = util.objectKeys(m);
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
var val = m[key];
code = (code + (eq.hashCode(key) ^ eq.hashCode(val))) % 4503599627370496;
}
}
return code;
};
eq.hashArrayLike = function(arr) {
var code = 0;
if(util.isArray(arr)) {
for(var i = 0; i < arr.length; i++) {
code = eq.hashCombine(code, eq.hashCode(arr[i]));
}
} else if(arr.forEach) {
arr.forEach(function(x, i) {
code = eq.hashCombine(code, eq.hashCode(x));
});
}
return code;
};
eq.hashCode = function(x) {
if(x == null) {
return 0;
} else {
switch(typeof x) {
case 'number':
return x;
break;
case 'boolean':
return x === true ? 1 : 0;
break;
case 'string':
return eq.hashString(x);
break;
case 'function':
var code = x[eq.hashCodeProperty];
if(code) {
return code;
} else {
code = eq.hashCodeCounter;
if(typeof Object.defineProperty != "undefined") {
Object.defineProperty(x, eq.hashCodeProperty, {
value: code,
enumerable: false
});
} else {
x[eq.hashCodeProperty] = code;
}
eq.hashCodeCounter++;
return code;
}
break;
default:
if(x instanceof Date) {
return x.valueOf();
} else if(util.isArray(x)) {
return eq.hashArrayLike(x);
} if(x.com$cognitect$transit$hashCode) {
return x.com$cognitect$transit$hashCode();
} else {
return eq.hashMapLike(x);
}
break;
}
}
}
eq.extendToEQ = function(obj, opts) {
obj.com$cognitect$transit$hashCode = opts["hashCode"];
obj.com$cognitect$transit$equals = opts["equals"];
return obj;
}
});
+324
View File
@@ -0,0 +1,324 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.handlers");
goog.require("com.cognitect.transit.util");
goog.require("com.cognitect.transit.types");
goog.require("goog.math.Long");
goog.scope(function() {
var handlers = com.cognitect.transit.handlers,
util = com.cognitect.transit.util,
types = com.cognitect.transit.types,
Long = goog.math.Long;
handlers.ctorGuid = 0;
/**
* @const
* @type {string}
*/
handlers.ctorGuidProperty = "transit$guid$" + util.randomUUID();
handlers.typeTag = function(ctor) {
if(ctor == null) {
return "null";
} else if(ctor === String) {
return "string";
} else if(ctor === Boolean) {
return "boolean";
} else if(ctor === Number) {
return "number";
} else if(ctor === Array) {
return "array";
} else if(ctor === Object) {
return "map";
} else {
var tag = ctor[handlers.ctorGuidProperty];
if(tag == null) {
if(typeof Object.defineProperty != "undefined") {
tag = ++handlers.ctorGuid;
Object.defineProperty(ctor, handlers.ctorGuidProperty, {
value: tag,
enumerable: false
});
} else {
ctor[handlers.ctorGuidProperty] = tag = ++handlers.ctorGuid;
}
}
return tag;
}
};
handlers.constructor = function(x) {
if(x == null) {
return null;
} else {
return x.constructor;
}
};
handlers.padZeros = function(n,m) {
var s = n.toString();
for(var i = s.length; i < m; i++) {
s = "0"+s;
}
return s;
};
handlers.stringableKeys = function(m) {
var stringable = false,
ks = util.objectKeys(m);
for(var i = 0; i < ks.length; i++) {
}
return true;
};
/**
* @constructor
*/
handlers.NilHandler = function(){};
handlers.NilHandler.prototype.tag = function(v) { return "_"; };
handlers.NilHandler.prototype.rep = function(v) { return null; };
handlers.NilHandler.prototype.stringRep = function(v) { return "null"; };
/**
* @constructor
*/
handlers.StringHandler = function(){};
handlers.StringHandler.prototype.tag = function(v) { return "s"; };
handlers.StringHandler.prototype.rep = function(v) { return v; };
handlers.StringHandler.prototype.stringRep = function(v) { return v; };
/**
* @constructor
*/
handlers.NumberHandler = function(){};
handlers.NumberHandler.prototype.tag = function(v) { return "i"; };
handlers.NumberHandler.prototype.rep = function(v) { return v; };
handlers.NumberHandler.prototype.stringRep = function(v) { return v.toString(); };
/**
* @constructor
*/
handlers.IntegerHandler = function(){};
handlers.IntegerHandler.prototype.tag = function(v) { return "i"; };
handlers.IntegerHandler.prototype.rep = function(v) { return v.toString(); };
handlers.IntegerHandler.prototype.stringRep = function(v) { return v.toString(); };
/**
* @constructor
*/
handlers.BooleanHandler = function(){};
handlers.BooleanHandler.prototype.tag = function(v) { return "?"; };
handlers.BooleanHandler.prototype.rep = function(v) { return v; };
handlers.BooleanHandler.prototype.stringRep = function(v) { return v.toString(); };
/**
* @constructor
*/
handlers.ArrayHandler = function(){};
handlers.ArrayHandler.prototype.tag = function(v) { return "array"; };
handlers.ArrayHandler.prototype.rep = function(v) { return v; };
handlers.ArrayHandler.prototype.stringRep = function(v) { return null; };
/**
* @constructor
*/
handlers.MapHandler = function(){};
handlers.MapHandler.prototype.tag = function(v) { return "map"; };
handlers.MapHandler.prototype.rep = function(v) { return v; };
handlers.MapHandler.prototype.stringRep = function(v) { return null; };
/**
* @constructor
*/
handlers.VerboseDateHandler = function(){};
handlers.VerboseDateHandler.prototype.tag = function(v) { return "t"; };
handlers.VerboseDateHandler.prototype.rep = function(v) {
return v.getUTCFullYear()+"-"+handlers.padZeros(v.getUTCMonth()+1,2)+"-"+
handlers.padZeros(v.getUTCDate(),2)+"T"+handlers.padZeros(v.getUTCHours(),2)+":"+
handlers.padZeros(v.getUTCMinutes(),2)+":"+handlers.padZeros(v.getUTCSeconds(),2)+"."+
handlers.padZeros(v.getUTCMilliseconds(),3)+"Z";
};
handlers.VerboseDateHandler.prototype.stringRep = function(v, h) {
return h.rep(v);
};
/**
* @constructor
*/
handlers.DateHandler = function(){};
handlers.DateHandler.prototype.tag = function(v) { return "m"; };
handlers.DateHandler.prototype.rep = function(v) { return v.valueOf(); };
handlers.DateHandler.prototype.stringRep = function(v) { return v.valueOf().toString(); };
handlers.DateHandler.prototype.getVerboseHandler = function(v) {
return new handlers.VerboseDateHandler();
};
/**
* @constructor
*/
handlers.UUIDHandler = function(){};
handlers.UUIDHandler.prototype.tag = function(v) { return "u"; };
handlers.UUIDHandler.prototype.rep = function(v) { return v.toString(); };
handlers.UUIDHandler.prototype.stringRep = function(v) { return v.toString(); };
/**
* @constructor
*/
handlers.KeywordHandler = function(){};
handlers.KeywordHandler.prototype.tag = function(v) { return ":"; };
handlers.KeywordHandler.prototype.rep = function(v) { return v.name; }; // NOTE: should be fqn
handlers.KeywordHandler.prototype.stringRep = function(v, h) { return h.rep(v); };
/**
* @constructor
*/
handlers.SymbolHandler = function(){};
handlers.SymbolHandler.prototype.tag = function(v) { return "$"; };
handlers.SymbolHandler.prototype.rep = function(v) { return v.name; }; // NOTE: should be str
handlers.SymbolHandler.prototype.stringRep = function(v, h) { return h.rep(v); };
/**
* @constructor
*/
handlers.TaggedHandler = function(){};
handlers.TaggedHandler.prototype.tag = function(v) { return v.tag; };
handlers.TaggedHandler.prototype.rep = function(v) { return v.rep; };
handlers.TaggedHandler.prototype.stringRep = function(v, h) { return null; };
/**
* @constructor
*/
handlers.TransitSetHandler = function(){};
handlers.TransitSetHandler.prototype.tag = function(v) { return "set"; };
handlers.TransitSetHandler.prototype.rep = function(v) {
var arr = [];
v.forEach(function(key, set) {
arr.push(key);
});
return types.taggedValue("array", arr);
};
handlers.TransitSetHandler.prototype.stringRep = function(v, h) { return null; };
/**
* @constructor
*/
handlers.TransitArrayMapHandler = function(){};
handlers.TransitArrayMapHandler.prototype.tag = function(v) { return "map"; };
handlers.TransitArrayMapHandler.prototype.rep = function(v) { return v; };
handlers.TransitArrayMapHandler.prototype.stringRep = function(v, h) { return null; };
/**
* @constructor
*/
handlers.TransitMapHandler = function(){};
handlers.TransitMapHandler.prototype.tag = function(v) { return "map"; };
handlers.TransitMapHandler.prototype.rep = function(v) { return v; };
handlers.TransitMapHandler.prototype.stringRep = function(v, h) { return null; };
/**
* @constructor
*/
handlers.BufferHandler = function() {};
handlers.BufferHandler.prototype.tag = function(v) { return "b"; };
handlers.BufferHandler.prototype.rep = function(v) { return v.toString("base64"); };
handlers.BufferHandler.prototype.stringRep = function(v, h) { return null; };
/**
* @constructor
*/
handlers.Uint8ArrayHandler = function() {};
handlers.Uint8ArrayHandler.prototype.tag = function(v) { return "b"; };
handlers.Uint8ArrayHandler.prototype.rep = function(v) { return util.Uint8ToBase64(v); };
handlers.Uint8ArrayHandler.prototype.stringRep = function(v, h) { return null; };
handlers.defaultHandlers = function(hs) {
hs.set(null, new handlers.NilHandler());
hs.set(String, new handlers.StringHandler());
hs.set(Number, new handlers.NumberHandler());
hs.set(Long, new handlers.IntegerHandler());
hs.set(Boolean, new handlers.BooleanHandler());
hs.set(Array, new handlers.ArrayHandler());
hs.set(Object, new handlers.MapHandler());
hs.set(Date, new handlers.DateHandler());
hs.set(types.UUID, new handlers.UUIDHandler());
hs.set(types.Keyword, new handlers.KeywordHandler());
hs.set(types.Symbol, new handlers.SymbolHandler());
hs.set(types.TaggedValue, new handlers.TaggedHandler());
hs.set(types.TransitSet, new handlers.TransitSetHandler());
hs.set(types.TransitArrayMap, new handlers.TransitArrayMapHandler());
hs.set(types.TransitMap, new handlers.TransitMapHandler());
if(typeof Buffer != "undefined") {
hs.set(Buffer, new handlers.BufferHandler());
}
if(typeof Uint8Array != "undefined") {
hs.set(Uint8Array, new handlers.Uint8ArrayHandler());
}
return hs;
};
/**
* @constructor
*/
handlers.Handlers = function() {
this.handlers = {};
handlers.defaultHandlers(this);
};
handlers.Handlers.prototype.get = function(ctor) {
var h = null;
if(typeof ctor === "string") {
h = this.handlers[ctor];
} else {
h = this.handlers[handlers.typeTag(ctor)];
}
if(h != null) {
return h;
} else {
return this.handlers["default"];
}
};
handlers.Handlers.prototype["get"] = handlers.Handlers.prototype.get;
handlers.validTag = function(tag) {
switch(tag) {
case "null":
case "string":
case "boolean":
case "number":
case "array":
case "map":
return false;
break;
}
return true;
};
handlers.Handlers.prototype.set = function(ctor, handler) {
if(typeof ctor === "string" && handlers.validTag(ctor)) {
this.handlers[ctor] = handler;
} else {
this.handlers[handlers.typeTag(ctor)] = handler;
}
};
});
+317
View File
@@ -0,0 +1,317 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.impl.decoder");
goog.require("com.cognitect.transit.util");
goog.require("com.cognitect.transit.delimiters");
goog.require("com.cognitect.transit.caching");
goog.require("com.cognitect.transit.types");
goog.scope(function() {
var decoder = com.cognitect.transit.impl.decoder,
util = com.cognitect.transit.util,
d = com.cognitect.transit.delimiters,
caching = com.cognitect.transit.caching,
types = com.cognitect.transit.types;
// =============================================================================
// Decoder
/**
* @constructor
*/
decoder.Tag = function(s) {
this.str = s;
};
decoder.tag = function(s) {
return new decoder.Tag(s);
};
decoder.isTag = function(x) {
return x && (x instanceof decoder.Tag);
};
decoder.isGroundHandler = function(handler) {
switch(handler) {
case "_":
case "s":
case "?":
case "i":
case "d":
case "b":
case "'":
case "array":
case "map":
return true;
}
return false;
};
/**
* A transit decoder
* @constructor
*/
decoder.Decoder = function(options) {
this.options = options || {};
this.handlers = {};
for(var h in this.defaults.handlers) {
this.handlers[h] = this.defaults.handlers[h];
}
for(var h in this.options["handlers"]) {
if(decoder.isGroundHandler(h)) {
throw new Error("Cannot override handler for ground type \""+h+"\"");
}
this.handlers[h] = this.options["handlers"][h];
}
this.preferStrings = this.options["preferStrings"] != null ? this.options["preferStrings"] : this.defaults.preferStrings;
this.preferBuffers = this.options["preferBuffers"] != null ? this.options["preferBuffers"] : this.defaults.preferBuffers;
this.defaultHandler = this.options["defaultHandler"] || this.defaults.defaultHandler;
/* NOT PUBLIC */
this.mapBuilder = this.options["mapBuilder"];
this.arrayBuilder = this.options["arrayBuilder"];
};
decoder.Decoder.prototype.defaults = {
handlers: {
"_": function(v, d) { return types.nullValue(); },
"?": function(v, d) { return types.boolValue(v); },
"b": function(v, d) { return types.binary(v, d); },
"i": function(v, d) { return types.intValue(v); },
"n": function(v, d) { return types.bigInteger(v); },
"d": function(v, d) { return types.floatValue(v); },
"f": function(v, d) { return types.bigDecimalValue(v); },
"c": function(v, d) { return types.charValue(v); },
":": function(v, d) { return types.keyword(v); },
"$": function(v, d) { return types.symbol(v); },
"r": function(v, d) { return types.uri(v); },
"z": function(v, d) { return types.specialDouble(v); },
// tagged
"'": function(v, d) { return v; },
"m": function(v, d) { return types.date(v); },
"t": function(v, d) { return types.verboseDate(v); },
"u": function(v, d) { return types.uuid(v); },
"set": function(v, d) { return types.set(v); },
"list": function(v, d) { return types.list(v); },
"link": function(v, d) { return types.link(v); },
"cmap": function(v, d) { return types.map(v, false); }
},
defaultHandler: function(c, val) {
return types.taggedValue(c, val);
},
preferStrings: true,
preferBuffers: true
};
decoder.Decoder.prototype.decode = function(node, cache, asMapKey, tagValue) {
if(node == null) return null;
var t = typeof node;
switch(t) {
case "string":
return this.decodeString(node, cache, asMapKey, tagValue);
break;
case "object":
if(util.isArray(node)) {
if(node[0] === "^ ") {
return this.decodeArrayHash(node, cache, asMapKey, tagValue);
} else {
return this.decodeArray(node, cache, asMapKey, tagValue);
}
} else {
return this.decodeHash(node, cache, asMapKey, tagValue);
}
break;
}
return node;
};
decoder.Decoder.prototype["decode"] = decoder.Decoder.prototype.decode;
decoder.Decoder.prototype.decodeString = function(string, cache, asMapKey, tagValue) {
if(caching.isCacheable(string, asMapKey)) {
var val = this.parseString(string, cache, false);
if(cache) {
cache.write(val, asMapKey);
}
return val;
} else if(caching.isCacheCode(string)) {
return cache.read(string, asMapKey);
} else {
return this.parseString(string, cache, asMapKey);
}
};
decoder.Decoder.prototype.decodeHash = function(hash, cache, asMapKey, tagValue) {
var ks = util.objectKeys(hash),
key = ks[0],
tag = ks.length == 1 ? this.decode(key, cache, false, false) : null;
if(decoder.isTag(tag)) {
var val = hash[key],
handler = this.handlers[tag.str];
if(handler != null) {
return handler(this.decode(val, cache, false, true), this);
} else {
return types.taggedValue(tag.str, this.decode(val, cache, false, false));
}
} else if(this.mapBuilder) {
if((ks.length < (types.SMALL_ARRAY_MAP_THRESHOLD*2)) && this.mapBuilder.fromArray) {
var nodep = [];
for(var i = 0; i < ks.length; i++) {
var strKey = ks[i];
nodep.push(this.decode(strKey, cache, true, false));
nodep.push(this.decode(hash[strKey], cache, false, false));
}
return this.mapBuilder.fromArray(nodep, hash);
} else {
var ret = this.mapBuilder.init(hash);
for(var i = 0; i < ks.length; i++) {
var strKey = ks[i];
ret = this.mapBuilder.add(ret,
this.decode(strKey, cache, true, false),
this.decode(hash[strKey], cache, false, false),
hash);
}
return this.mapBuilder.finalize(ret, hash);
}
} else {
var nodep = [];
for(var i = 0; i < ks.length; i++) {
var strKey = ks[i];
nodep.push(this.decode(strKey, cache, true, false));
nodep.push(this.decode(hash[strKey], cache, false, false));
}
return types.map(nodep, false);
}
};
decoder.Decoder.prototype.decodeArrayHash = function(node, cache, asMapKey, tagValue) {
if(this.mapBuilder) {
if((node.length < ((types.SMALL_ARRAY_MAP_THRESHOLD*2)+1)) && this.mapBuilder.fromArray) {
var nodep = [];
for(var i = 1; i < node.length; i+=2) {
nodep.push(this.decode(node[i], cache, true, false));
nodep.push(this.decode(node[i+1], cache, false, false));
}
return this.mapBuilder.fromArray(nodep, node);
} else {
var ret = this.mapBuilder.init(node);
for(var i = 1; i < node.length; i+=2) {
ret = this.mapBuilder.add(ret,
this.decode(node[i], cache, true, false),
this.decode(node[i+1], cache, false, false),
node)
}
return this.mapBuilder.finalize(ret, node);
}
} else {
var nodep = [];
// collect keys
for(var i = 1; i < node.length; i +=2) {
nodep.push(this.decode(node[i], cache, true, false));
nodep.push(this.decode(node[i+1], cache, false, false));
}
return types.map(nodep, false);
}
};
decoder.Decoder.prototype.decodeArray = function(node, cache, asMapKey, tagValue) {
if(tagValue) {
var ret = [];
for(var i = 0; i < node.length; i++) {
ret.push(this.decode(node[i], cache, asMapKey, false));
}
return ret;
} else {
var cacheIdx = cache && cache.idx;
// tagged value as 2-array case
if((node.length === 2) &&
(typeof node[0] === "string")) {
var tag = this.decode(node[0], cache, false, false);
if(decoder.isTag(tag)) {
var val = node[1],
handler = this.handlers[tag.str];
if(handler != null) {
var ret = handler(this.decode(val, cache, asMapKey, true), this);
return ret;
} else {
return types.taggedValue(tag.str, this.decode(val, cache, asMapKey, false))
}
}
}
// rewind cache
if(cache && (cacheIdx != cache.idx)) {
cache.idx = cacheIdx;
}
if(this.arrayBuilder) {
// NOTE: hard coded for ClojureScript for now - David
if(node.length <= 32 && this.arrayBuilder.fromArray) {
var arr = [];
for(var i = 0; i < node.length; i++) {
arr.push(this.decode(node[i], cache, asMapKey, false));
}
return this.arrayBuilder.fromArray(arr, node);
} else {
var ret = this.arrayBuilder.init();
for(var i = 0; i < node.length; i++) {
ret = this.arrayBuilder.add(ret, this.decode(node[i], cache, asMapKey, false), node);
}
return this.arrayBuilder.finalize(ret, node);
}
} else {
var ret = [];
for(var i = 0; i < node.length; i++) {
ret.push(this.decode(node[i], cache, asMapKey, false));
}
return ret;
}
}
};
decoder.Decoder.prototype.parseString = function(string, cache, asMapKey) {
if(string.charAt(0) === d.ESC) {
var c = string.charAt(1);
if(c === d.ESC || c === d.SUB || c === d.RES) {
return string.substring(1);
} else if (c === d.TAG) {
return decoder.tag(string.substring(2));
} else {
var handler = this.handlers[c];
if(handler == null) {
return this.defaultHandler(c, string.substring(2));
} else {
return handler(string.substring(2), this);
}
}
} else {
return string;
}
};
decoder.decoder = function(options) {
return new decoder.Decoder(options);
};
});
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.impl.reader");
goog.require("com.cognitect.transit.impl.decoder");
goog.require("com.cognitect.transit.caching");
goog.scope(function() {
var reader = com.cognitect.transit.impl.reader,
decoder = com.cognitect.transit.impl.decoder,
caching = com.cognitect.transit.caching;
/**
* A JSON unmarshaller
* @constructor
*/
reader.JSONUnmarshaller = function(opts) {
this.decoder = new decoder.Decoder(opts);
};
/**
* @param {string} str a JSON string
* @param {caching.ReadCache} cache a read cache
* @returns {Object}
*/
reader.JSONUnmarshaller.prototype.unmarshal = function(str, cache) {
return this.decoder.decode(JSON.parse(str), cache);
};
/**
* A transit reader
* @constructor
* @param {reader.JSONUnmarshaller} unmarshaller
* @param {Object} options
*/
reader.Reader = function(unmarshaller, options) {
this.unmarshaller = unmarshaller;
this.options = options || {};
this.cache = this.options["cache"] ? this.options["cache"] : new caching.ReadCache();
};
/**
* @param {string} str a string to be read
* @returns {Object}
*/
reader.Reader.prototype.read = function(str) {
var ret = this.unmarshaller.unmarshal(str, this.cache)
this.cache.clear();
return ret;
};
reader.Reader.prototype["read"] = reader.Reader.prototype.read;
});
+491
View File
@@ -0,0 +1,491 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.impl.writer");
goog.require("com.cognitect.transit.util");
goog.require("com.cognitect.transit.caching");
goog.require("com.cognitect.transit.handlers");
goog.require("com.cognitect.transit.types");
goog.require("com.cognitect.transit.delimiters");
goog.require("goog.math.Long");
goog.scope(function() {
var writer = com.cognitect.transit.impl.writer,
util = com.cognitect.transit.util,
caching = com.cognitect.transit.caching,
handlers = com.cognitect.transit.handlers,
types = com.cognitect.transit.types,
d = com.cognitect.transit.delimiters,
Long = goog.math.Long;
writer.escape = function(string) {
if(string.length > 0) {
var c = string.charAt(0);
if(c === d.ESC || c === d.SUB || c === d.RES) {
return d.ESC+string;
} else {
return string;
}
} else {
return string;
}
};
/**
* @constructor
*/
writer.JSONMarshaller = function(opts) {
this.opts = opts || {};
this.preferStrings = this.opts["preferStrings"] != null ? this.opts["preferStrings"] : true;
this.objectBuilder = this.opts["objectBuilder"] || null;
this.handlers = new handlers.Handlers();
var optsHandlers = this.opts["handlers"];
if(optsHandlers) {
if(util.isArray(optsHandlers) || !optsHandlers.forEach) {
throw new Error("transit writer \"handlers\" option must be a map");
}
var self = this;
optsHandlers.forEach(function(v, k) {
self.handlers.set(k, v);
});
}
// Multiple JS context helper
this.handlerForForeign = this.opts["handlerForForeign"];
this.unpack = this.opts["unpack"] || function(x) {
if(types.isArrayMap(x) && x.backingMap === null) {
return x._entries;
} else {
return false;
}
};
this.verbose = (this.opts && this.opts["verbose"]) || false;
};
writer.JSONMarshaller.prototype.handler = function(obj) {
var h = this.handlers.get(handlers.constructor(obj));
if(h != null) {
return h;
} else {
var tag = obj && obj["transitTag"];
if(tag) {
return this.handlers.get(tag)
} else {
return null;
}
}
};
writer.JSONMarshaller.prototype.registerHandler = function(ctor, handler) {
this.handlers.set(ctor, handler);
};
writer.JSONMarshaller.prototype.emitNil = function(asMapKey, cache) {
if(asMapKey) {
return this.emitString(d.ESC, "_", "", asMapKey, cache);
} else {
return null;
}
};
writer.JSONMarshaller.prototype.emitString = function(prefix, tag, s, asMapKey, cache) {
var string = prefix+tag+s;
if(cache) {
return cache.write(string, asMapKey);
} else {
return string;
}
};
writer.JSONMarshaller.prototype.emitBoolean = function(b, asMapKey, cache) {
if(asMapKey) {
var s = b.toString();
return this.emitString(d.ESC, "?", s[0], asMapKey, cache);
} else {
return b;
}
};
writer.JSONMarshaller.prototype.emitInteger = function(i, asMapKey, cache) {
if(i === Infinity) {
return this.emitString(d.ESC, "z", "INF", asMapKey, cache);
} else if(i === -Infinity) {
return this.emitString(d.ESC, "z", "-INF", asMapKey, cache);
} else if(isNaN(i)) {
return this.emitString(d.ESC, "z", "NaN", asMapKey, cache);
} else if(asMapKey || (typeof i === "string") || (i instanceof Long)) {
return this.emitString(d.ESC, "i", i.toString(), asMapKey, cache);
} else {
return i;
}
};
writer.JSONMarshaller.prototype.emitDouble = function(d, asMapKey, cache) {
if(asMapKey) {
return this.emitString(d.ESC, "d", d, asMapKey, cache);
} else {
return d;
}
};
writer.JSONMarshaller.prototype.emitBinary = function(b, asMapKey, cache) {
return this.emitString(d.ESC, "b", b, asMapKey, cache);
};
writer.JSONMarshaller.prototype.emitQuoted = function(em, obj, cache) {
if(em.verbose) {
var ret = {},
k = this.emitString(d.ESC_TAG, "'", "", true, cache);
ret[k] = writer.marshal(this, obj, false, cache);
return ret;
} else {
return [this.emitString(d.ESC_TAG, "'", "", true, cache), writer.marshal(this, obj, false, cache)];
}
};
writer.emitObjects = function(em, iterable, cache) {
var ret = [];
if(util.isArray(iterable)) {
for(var i = 0; i < iterable.length; i++) {
ret.push(writer.marshal(em, iterable[i], false, cache));
}
} else {
iterable.forEach(function(v, i) {
ret.push(writer.marshal(em, v, false, cache));
});
}
return ret;
};
writer.emitArray = function(em, iterable, skip, cache) {
return writer.emitObjects(em, iterable, cache);
};
writer.isStringableKey = function(em, k) {
if(typeof k !== "string") {
var h = em.handler(k);
return h && h.tag(k).length === 1;
} else {
return true;
}
};
writer.stringableKeys = function(em, obj) {
var arr = em.unpack(obj),
stringableKeys = true;
if(arr) {
for(var i = 0; i < arr.length; i+=2) {
stringableKeys = writer.isStringableKey(em, arr[i]);
if(!stringableKeys) {
break;
}
}
return stringableKeys;
} else if(obj.keys) {
var iter = obj.keys(),
step = null;
if(iter.next) {
step = iter.next();
while(!step.done) {
stringableKeys = writer.isStringableKey(em, step.value);
if(!stringableKeys) {
break;
}
step = iter.next();
}
return stringableKeys;
}
}
if(obj.forEach) {
obj.forEach(function(v, k) {
stringableKeys = stringableKeys && writer.isStringableKey(em, k);
});
return stringableKeys;
} else {
throw new Error("Cannot walk keys of object type " + handlers.constructor(obj).name);
}
};
writer.isForeignObject = function(x) {
if(x.constructor["transit$isObject"]) {
return true;
}
var ret = x.constructor.toString(),
ret = ret.substr('function '.length),
ret = ret.substr(0, ret.indexOf('(')),
isObject = ret == "Object";
if(typeof Object.defineProperty != "undefined") {
Object.defineProperty(x.constructor, "transit$isObject", {
value: isObject,
enumerable: false
});
} else {
x.constructor["transit$isObject"] = isObject;
}
return isObject;
};
writer.emitMap = function(em, obj, skip, cache) {
if((obj.constructor === Object) ||
(obj.forEach != null) ||
(em.handlerForForeign && writer.isForeignObject(obj))) {
if(em.verbose) {
if(obj.forEach != null) {
if(writer.stringableKeys(em, obj)) {
var ret = {};
obj.forEach(function(v, k) {
ret[writer.marshal(em, k, true, false)] = writer.marshal(em, v, false, cache);
});
return ret;
} else {
var arr = em.unpack(obj),
rep = [],
tag = em.emitString(d.ESC_TAG, "cmap", "", true, cache);
if(arr) {
for(var i = 0; i < arr.length; i+=2) {
rep.push(writer.marshal(em, arr[i], true, false));
rep.push(writer.marshal(em, arr[i+1], false, cache));
}
} else {
obj.forEach(function(v, k) {
rep.push(writer.marshal(em, k, true, false));
rep.push(writer.marshal(em, v, false, cache));
});
}
var ret = {};
ret[tag] = rep;
return ret;
}
} else {
var ret = {},
ks = util.objectKeys(obj);
for(var i = 0; i < ks.length; i++) {
ret[writer.marshal(em, ks[i], true, false)] = writer.marshal(em, obj[ks[i]], false, cache);
}
return ret;
}
} else {
if(obj.forEach != null) {
if(writer.stringableKeys(em, obj)) {
var arr = em.unpack(obj),
ret = ["^ "];
if(arr) {
for(var i = 0; i < arr.length; i+=2) {
ret.push(writer.marshal(em, arr[i], true, cache));
ret.push(writer.marshal(em, arr[i+1], false, cache));
}
} else {
obj.forEach(function(v, k) {
ret.push(writer.marshal(em, k, true, cache));
ret.push(writer.marshal(em, v, false, cache));
});
}
return ret;
} else {
var arr = em.unpack(obj),
rep = [],
tag = em.emitString(d.ESC_TAG, "cmap", "", true, cache);
if(arr) {
for(var i = 0; i < arr.length; i+=2) {
rep.push(writer.marshal(em, arr[i], true, cache));
rep.push(writer.marshal(em, arr[i+1], false, cache));
}
} else {
obj.forEach(function(v, k) {
rep.push(writer.marshal(em, k, true, cache));
rep.push(writer.marshal(em, v, false, cache));
});
}
return [tag, rep];
}
} else {
var ret = ["^ "],
ks = util.objectKeys(obj);
for(var i = 0; i < ks.length; i++) {
ret.push(writer.marshal(em, ks[i], true, cache));
ret.push(writer.marshal(em, obj[ks[i]], false, cache));
}
return ret;
}
}
} else if(em.objectBuilder != null) {
return em.objectBuilder(obj, function(k) { return writer.marshal(em, k, true, cache); },
function(v) { return writer.marshal(em, v, false, cache); });
} else {
var name = handlers.constructor(obj).name,
err = new Error("Cannot write " + name);
err.data = {obj: obj, type: name};
throw err;
}
};
writer.emitTaggedMap = function(em, tag, rep, skip, cache) {
if(em.verbose) {
var ret = {};
ret[em.emitString(d.ESC_TAG, tag, "", true, cache)] = writer.marshal(em, rep, false, cache);
return ret;
} else {
return [em.emitString(d.ESC_TAG, tag, "", true, cache), writer.marshal(em, rep, false, cache)];
}
};
writer.emitEncoded = function(em, h, tag, rep, obj, asMapKey, cache) {
if(tag.length === 1) {
if(typeof rep === "string") {
return em.emitString(d.ESC, tag, rep, asMapKey, cache);
} else if(asMapKey || em.preferStrings) {
var vh = em.verbose && h.getVerboseHandler();
if(vh) {
tag = vh.tag(obj);
rep = vh.stringRep(obj, vh);
} else {
rep = h.stringRep(obj, h);
}
if(rep !== null) {
return em.emitString(d.ESC, tag, rep, asMapKey, cache);
} else {
var err = new Error("Tag \""+tag+"\" cannot be encoded as string");
err.data = {tag: tag, rep: rep, obj: obj};
throw err;
}
} else {
return writer.emitTaggedMap(em, tag, rep, asMapKey, cache);
}
} else {
return writer.emitTaggedMap(em, tag, rep, asMapKey, cache);
}
}
writer.marshal = function(em, obj, asMapKey, cache) {
var h = em.handler(obj) || (em.handlerForForeign ? em.handlerForForeign(obj, em.handlers) : null),
tag = h ? h.tag(obj) : null,
rep = h ? h.rep(obj) : null;
if(h != null && tag != null) {
switch(tag) {
case "_":
return em.emitNil(asMapKey, cache);
break;
case "s":
return em.emitString("", "", writer.escape(rep), asMapKey, cache);
break;
case "?":
return em.emitBoolean(rep, asMapKey, cache);
break;
case "i":
return em.emitInteger(rep, asMapKey, cache);
break;
case "d":
return em.emitDouble(rep, asMapKey, cache);
break;
case "b":
return em.emitBinary(rep, asMapKey, cache);
break;
case "'":
return em.emitQuoted(em, rep, cache);
break;
case "array":
return writer.emitArray(em, rep, asMapKey, cache);
break;
case "map":
return writer.emitMap(em, rep, asMapKey, cache);
break;
default:
return writer.emitEncoded(em, h, tag, rep, obj, asMapKey, cache);
break;
}
} else {
var name = handlers.constructor(obj).name,
err = new Error("Cannot write " + name);
err.data = {obj: obj, type: name};
throw err;
}
};
writer.maybeQuoted = function(em, obj) {
var h = em.handler(obj) || (em.handlerForForeign ? em.handlerForForeign(obj, em.handlers) : null);
if(h != null) {
if(h.tag(obj).length === 1) {
return types.quoted(obj);
} else {
return obj;
}
} else {
var name = handlers.constructor(obj).name,
err = new Error("Cannot write " + name);
err.data = {obj: obj, type: name};
throw err;
}
};
writer.marshalTop = function(em, obj, asMapKey, cache) {
return JSON.stringify(writer.marshal(em, writer.maybeQuoted(em, obj), asMapKey, cache));
};
/**
* @constructor
*/
writer.Writer = function(marshaller, options) {
this._marshaller = marshaller;
this.options = options || {};
if(this.options["cache"] === false) {
this.cache = null;
} else {
this.cache = this.options["cache"] ? this.options["cache"] : new caching.WriteCache();
}
};
writer.Writer.prototype.marshaller = function() {
return this._marshaller;
};
writer.Writer.prototype["marshaller"] = writer.Writer.prototype.marshaller;
writer.Writer.prototype.write = function(obj, opts) {
var ret = null,
ropts = opts || {},
asMapKey = ropts["asMapKey"] || false,
cache = this._marshaller.verbose ? false : this.cache;
if(ropts["marshalTop"] === false) {
ret = writer.marshal(this._marshaller, obj, asMapKey, cache)
} else {
ret = writer.marshalTop(this._marshaller, obj, asMapKey, cache)
}
if(this.cache != null) {
this.cache.clear();
}
return ret;
};
writer.Writer.prototype["write"] = writer.Writer.prototype.write;
writer.Writer.prototype.register = function(type, handler) {
this._marshaller.registerHandler(type, handler);
};
writer.Writer.prototype["register"] = writer.Writer.prototype.register;
});
+1089
View File
File diff suppressed because it is too large Load Diff
+144
View File
@@ -0,0 +1,144 @@
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide("com.cognitect.transit.util");
goog.require("goog.object");
goog.scope(function() {
var util = com.cognitect.transit.util,
gobject = goog.object;
if(typeof Object.keys != "undefined") {
util.objectKeys = function(obj) {
return Object.keys(obj);
};
} else {
util.objectKeys = function(obj) {
return gobject.getKeys(obj);
};
}
if(typeof Array.isArray != "undefined") {
util.isArray = function(obj) {
return Array.isArray(obj);
};
} else {
util.isArray = function(obj) {
return goog.typeOf(obj) === "array";
};
}
/**
* @const
* @type {string}
*/
util.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
util.randInt = function(ub) {
return Math.round(Math.random()*ub);
};
util.randHex = function() {
return util.randInt(15).toString(16);
};
util.randomUUID = function() {
var rhex = (0x8 | (0x3 & util.randInt(14))).toString(16),
ret = util.randHex() + util.randHex() + util.randHex() + util.randHex() +
util.randHex() + util.randHex() + util.randHex() + util.randHex() + "-" +
util.randHex() + util.randHex() + util.randHex() + util.randHex() + "-" +
"4" + util.randHex() + util.randHex() + util.randHex() + "-" +
rhex + util.randHex() + util.randHex() + util.randHex() + "-" +
util.randHex() + util.randHex() + util.randHex() + util.randHex() +
util.randHex() + util.randHex() + util.randHex() + util.randHex() +
util.randHex() + util.randHex() + util.randHex() + util.randHex();
return ret;
};
// https://github.com/davidchambers/Base64.js
util.btoa = function(input) {
if(typeof btoa != "undefined") {
return btoa(input);
} else {
var str = String(input);
for (
var block, charCode, idx = 0, map = util.chars, output = '';
str.charAt(idx | 0) || (map = '=', idx % 1);
output += map.charAt(63 & block >> 8 - idx % 1 * 8)
) {
charCode = str.charCodeAt(idx += 3/4);
if (charCode > 0xFF) {
throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
}
block = block << 8 | charCode;
}
return output;
}
};
/**
* @suppress {uselessCode}
*/
util.atob = function(input) {
if(typeof atob != "undefined") {
return atob(input);
} else {
var str = String(input).replace(/=+$/, '');
if (str.length % 4 == 1) {
throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
}
for (
var bc = 0, bs, buffer, idx = 0, output = '';
buffer = str.charAt(idx++);
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
) {
buffer = util.chars.indexOf(buffer);
}
return output;
}
};
util.Uint8ToBase64 = function(u8Arr) {
var CHUNK_SIZE = 0x8000,
index = 0,
length = u8Arr.length,
result = '',
slice = null;
while (index < length) {
slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
result += String.fromCharCode.apply(null, slice);
index += CHUNK_SIZE;
}
return util.btoa(result);
};
util.Base64ToUint8 = function(base64) {
var binary_string = util.atob(base64),
len = binary_string.length,
bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
var ascii = binary_string.charCodeAt(i);
bytes[i] = ascii;
}
return bytes;
};
});
+1793
View File
File diff suppressed because it is too large Load Diff
+471
View File
@@ -0,0 +1,471 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Utilities to check the preconditions, postconditions and
* invariants runtime.
*
* Methods in this package are given special treatment by the compiler
* for type-inference. For example, <code>goog.asserts.assert(foo)</code>
* will make the compiler treat <code>foo</code> as non-nullable. Similarly,
* <code>goog.asserts.assertNumber(foo)</code> informs the compiler about the
* type of <code>foo</code>. Where applicable, such assertions are preferable to
* casts by jsdoc with <code>@type</code>.
*
* The compiler has an option to disable asserts. So code like:
* <code>
* var x = goog.asserts.assert(foo());
* goog.asserts.assert(bar());
* </code>
* will be transformed into:
* <code>
* var x = foo();
* </code>
* The compiler will leave in foo() (because its return value is used),
* but it will remove bar() because it assumes it does not have side-effects.
*
* Additionally, note the compiler will consider the type to be "tightened" for
* all statements <em>after</em> the assertion. For example:
* <code>
* const /** ?Object &#ast;/ value = foo();
* goog.asserts.assert(value);
* // "value" is of type {!Object} at this point.
* </code>
*/
goog.provide('goog.asserts');
goog.provide('goog.asserts.AssertionError');
goog.require('goog.debug.Error');
goog.require('goog.dom.NodeType');
/**
* @define {boolean} Whether to strip out asserts or to leave them in.
*/
goog.asserts.ENABLE_ASSERTS =
goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG);
/**
* Error object for failed assertions.
* @param {string} messagePattern The pattern that was used to form message.
* @param {!Array<*>} messageArgs The items to substitute into the pattern.
* @constructor
* @extends {goog.debug.Error}
* @final
*/
goog.asserts.AssertionError = function(messagePattern, messageArgs) {
'use strict';
goog.debug.Error.call(this, goog.asserts.subs_(messagePattern, messageArgs));
/**
* The message pattern used to format the error message. Error handlers can
* use this to uniquely identify the assertion.
* @type {string}
*/
this.messagePattern = messagePattern;
};
goog.inherits(goog.asserts.AssertionError, goog.debug.Error);
/** @override @type {string} */
goog.asserts.AssertionError.prototype.name = 'AssertionError';
/**
* The default error handler.
* @param {!goog.asserts.AssertionError} e The exception to be handled.
* @return {void}
*/
goog.asserts.DEFAULT_ERROR_HANDLER = function(e) {
'use strict';
throw e;
};
/**
* The handler responsible for throwing or logging assertion errors.
* @private {function(!goog.asserts.AssertionError)}
*/
goog.asserts.errorHandler_ = goog.asserts.DEFAULT_ERROR_HANDLER;
/**
* Does simple python-style string substitution.
* subs("foo%s hot%s", "bar", "dog") becomes "foobar hotdog".
* @param {string} pattern The string containing the pattern.
* @param {!Array<*>} subs The items to substitute into the pattern.
* @return {string} A copy of `str` in which each occurrence of
* {@code %s} has been replaced an argument from `var_args`.
* @private
*/
goog.asserts.subs_ = function(pattern, subs) {
'use strict';
var splitParts = pattern.split('%s');
var returnString = '';
// Replace up to the last split part. We are inserting in the
// positions between split parts.
var subLast = splitParts.length - 1;
for (var i = 0; i < subLast; i++) {
// keep unsupplied as '%s'
var sub = (i < subs.length) ? subs[i] : '%s';
returnString += splitParts[i] + sub;
}
return returnString + splitParts[subLast];
};
/**
* Throws an exception with the given message and "Assertion failed" prefixed
* onto it.
* @param {string} defaultMessage The message to use if givenMessage is empty.
* @param {Array<*>} defaultArgs The substitution arguments for defaultMessage.
* @param {string|undefined} givenMessage Message supplied by the caller.
* @param {Array<*>} givenArgs The substitution arguments for givenMessage.
* @throws {goog.asserts.AssertionError} When the value is not a number.
* @private
*/
goog.asserts.doAssertFailure_ = function(
defaultMessage, defaultArgs, givenMessage, givenArgs) {
'use strict';
var message = 'Assertion failed';
if (givenMessage) {
message += ': ' + givenMessage;
var args = givenArgs;
} else if (defaultMessage) {
message += ': ' + defaultMessage;
args = defaultArgs;
}
// The '' + works around an Opera 10 bug in the unit tests. Without it,
// a stack trace is added to var message above. With this, a stack trace is
// not added until this line (it causes the extra garbage to be added after
// the assertion message instead of in the middle of it).
var e = new goog.asserts.AssertionError('' + message, args || []);
goog.asserts.errorHandler_(e);
};
/**
* Sets a custom error handler that can be used to customize the behavior of
* assertion failures, for example by turning all assertion failures into log
* messages.
* @param {function(!goog.asserts.AssertionError)} errorHandler
* @return {void}
*/
goog.asserts.setErrorHandler = function(errorHandler) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS) {
goog.asserts.errorHandler_ = errorHandler;
}
};
/**
* Checks if the condition evaluates to true if goog.asserts.ENABLE_ASSERTS is
* true.
* @template T
* @param {T} condition The condition to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {T} The value of the condition.
* @throws {goog.asserts.AssertionError} When the condition evaluates to false.
* @closurePrimitive {asserts.truthy}
*/
goog.asserts.assert = function(condition, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && !condition) {
goog.asserts.doAssertFailure_(
'', null, opt_message, Array.prototype.slice.call(arguments, 2));
}
return condition;
};
/**
* Checks if `value` is `null` or `undefined` if goog.asserts.ENABLE_ASSERTS is
* true.
*
* @param {T} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {R} `value` with its type narrowed to exclude `null` and `undefined`.
*
* @template T
* @template R :=
* mapunion(T, (V) =>
* cond(eq(V, 'null'),
* none(),
* cond(eq(V, 'undefined'),
* none(),
* V)))
* =:
*
* @throws {!goog.asserts.AssertionError} When `value` is `null` or `undefined`.
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertExists = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && value == null) {
goog.asserts.doAssertFailure_(
'Expected to exist: %s.', [value], opt_message,
Array.prototype.slice.call(arguments, 2));
}
return value;
};
/**
* Fails if goog.asserts.ENABLE_ASSERTS is true. This function is useful in case
* when we want to add a check in the unreachable area like switch-case
* statement:
*
* <pre>
* switch(type) {
* case FOO: doSomething(); break;
* case BAR: doSomethingElse(); break;
* default: goog.asserts.fail('Unrecognized type: ' + type);
* // We have only 2 types - "default:" section is unreachable code.
* }
* </pre>
*
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {void}
* @throws {goog.asserts.AssertionError} Failure.
* @closurePrimitive {asserts.fail}
*/
goog.asserts.fail = function(opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS) {
goog.asserts.errorHandler_(new goog.asserts.AssertionError(
'Failure' + (opt_message ? ': ' + opt_message : ''),
Array.prototype.slice.call(arguments, 1)));
}
};
/**
* Checks if the value is a number if goog.asserts.ENABLE_ASSERTS is true.
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {number} The value, guaranteed to be a number when asserts enabled.
* @throws {goog.asserts.AssertionError} When the value is not a number.
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertNumber = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && typeof value !== 'number') {
goog.asserts.doAssertFailure_(
'Expected number but got %s: %s.', [goog.typeOf(value), value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {number} */ (value);
};
/**
* Checks if the value is a string if goog.asserts.ENABLE_ASSERTS is true.
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {string} The value, guaranteed to be a string when asserts enabled.
* @throws {goog.asserts.AssertionError} When the value is not a string.
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertString = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && typeof value !== 'string') {
goog.asserts.doAssertFailure_(
'Expected string but got %s: %s.', [goog.typeOf(value), value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {string} */ (value);
};
/**
* Checks if the value is a function if goog.asserts.ENABLE_ASSERTS is true.
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {!Function} The value, guaranteed to be a function when asserts
* enabled.
* @throws {goog.asserts.AssertionError} When the value is not a function.
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertFunction = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && typeof value !== 'function') {
goog.asserts.doAssertFailure_(
'Expected function but got %s: %s.', [goog.typeOf(value), value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {!Function} */ (value);
};
/**
* Checks if the value is an Object if goog.asserts.ENABLE_ASSERTS is true.
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {!Object} The value, guaranteed to be a non-null object.
* @throws {goog.asserts.AssertionError} When the value is not an object.
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertObject = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && !goog.isObject(value)) {
goog.asserts.doAssertFailure_(
'Expected object but got %s: %s.', [goog.typeOf(value), value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {!Object} */ (value);
};
/**
* Checks if the value is an Array if goog.asserts.ENABLE_ASSERTS is true.
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {!Array<?>} The value, guaranteed to be a non-null array.
* @throws {goog.asserts.AssertionError} When the value is not an array.
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertArray = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && !Array.isArray(value)) {
goog.asserts.doAssertFailure_(
'Expected array but got %s: %s.', [goog.typeOf(value), value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {!Array<?>} */ (value);
};
/**
* Checks if the value is a boolean if goog.asserts.ENABLE_ASSERTS is true.
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {boolean} The value, guaranteed to be a boolean when asserts are
* enabled.
* @throws {goog.asserts.AssertionError} When the value is not a boolean.
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertBoolean = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && typeof value !== 'boolean') {
goog.asserts.doAssertFailure_(
'Expected boolean but got %s: %s.', [goog.typeOf(value), value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {boolean} */ (value);
};
/**
* Checks if the value is a DOM Element if goog.asserts.ENABLE_ASSERTS is true.
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @return {!Element} The value, likely to be a DOM Element when asserts are
* enabled.
* @throws {goog.asserts.AssertionError} When the value is not an Element.
* @closurePrimitive {asserts.matchesReturn}
* @deprecated Use goog.asserts.dom.assertIsElement instead.
*/
goog.asserts.assertElement = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS &&
(!goog.isObject(value) ||
/** @type {!Node} */ (value).nodeType != goog.dom.NodeType.ELEMENT)) {
goog.asserts.doAssertFailure_(
'Expected Element but got %s: %s.', [goog.typeOf(value), value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {!Element} */ (value);
};
/**
* Checks if the value is an instance of the user-defined type if
* goog.asserts.ENABLE_ASSERTS is true.
*
* The compiler may tighten the type returned by this function.
*
* Do not use this to ensure a value is an HTMLElement or a subclass! Cross-
* document DOM inherits from separate - though identical - browser classes, and
* such a check will unexpectedly fail. Please use the methods in
* goog.asserts.dom for these purposes.
*
* @param {?} value The value to check.
* @param {function(new: T, ...)} type A user-defined constructor.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @throws {goog.asserts.AssertionError} When the value is not an instance of
* type.
* @return {T}
* @template T
* @closurePrimitive {asserts.matchesReturn}
*/
goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && !(value instanceof type)) {
goog.asserts.doAssertFailure_(
'Expected instanceof %s but got %s.',
[goog.asserts.getType_(type), goog.asserts.getType_(value)],
opt_message, Array.prototype.slice.call(arguments, 3));
}
return value;
};
/**
* Checks whether the value is a finite number, if goog.asserts.ENABLE_ASSERTS
* is true.
*
* @param {*} value The value to check.
* @param {string=} opt_message Error message in case of failure.
* @param {...*} var_args The items to substitute into the failure message.
* @throws {goog.asserts.AssertionError} When the value is not a number, or is
* a non-finite number such as NaN, Infinity or -Infinity.
* @return {number} The value initially passed in.
*/
goog.asserts.assertFinite = function(value, opt_message, var_args) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS &&
(typeof value != 'number' || !isFinite(value))) {
goog.asserts.doAssertFailure_(
'Expected %s to be a finite number but it is not.', [value],
opt_message, Array.prototype.slice.call(arguments, 2));
}
return /** @type {number} */ (value);
};
/**
* Returns the type of a value. If a constructor is passed, and a suitable
* string cannot be found, 'unknown type name' will be returned.
* @param {*} value A constructor, object, or primitive.
* @return {string} The best display name for the value, or 'unknown type name'.
* @private
*/
goog.asserts.getType_ = function(value) {
'use strict';
if (value instanceof Function) {
return value.displayName || value.name || 'unknown type name';
} else if (value instanceof Object) {
return /** @type {string} */ (value.constructor.displayName) ||
value.constructor.name || Object.prototype.toString.call(value);
} else {
return value === null ? 'null' : typeof value;
}
};
+77
View File
@@ -0,0 +1,77 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Simple freelist.
*
* An anterative to goog.structs.SimplePool, it imposes the requirement that the
* objects in the list contain a "next" property that can be used to maintain
* the pool.
*/
goog.provide('goog.async.FreeList');
/**
* @template ITEM
*/
goog.async.FreeList = class {
/**
* @param {function():ITEM} create
* @param {function(ITEM):void} reset
* @param {number} limit
*/
constructor(create, reset, limit) {
/** @private @const {number} */
this.limit_ = limit;
/** @private @const {function()} */
this.create_ = create;
/** @private @const {function(ITEM):void} */
this.reset_ = reset;
/** @private {number} */
this.occupants_ = 0;
/** @private {ITEM} */
this.head_ = null;
}
/**
* @return {ITEM}
*/
get() {
let item;
if (this.occupants_ > 0) {
this.occupants_--;
item = this.head_;
this.head_ = item.next;
item.next = null;
} else {
item = this.create_();
}
return item;
}
/**
* @param {ITEM} item An item available for possible future reuse.
*/
put(item) {
this.reset_(item);
if (this.occupants_ < this.limit_) {
this.occupants_++;
item.next = this.head_;
this.head_ = item;
}
}
/**
* Visible for testing.
* @package
* @return {number}
*/
occupants() {
return this.occupants_;
}
};
+237
View File
@@ -0,0 +1,237 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Provides a function to schedule running a function as soon
* as possible after the current JS execution stops and yields to the event
* loop.
*/
goog.provide('goog.async.nextTick');
goog.require('goog.debug.entryPointRegistry');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.functions');
goog.require('goog.labs.userAgent.browser');
goog.require('goog.labs.userAgent.engine');
/**
* Fires the provided callbacks as soon as possible after the current JS
* execution context. setTimeout(…, 0) takes at least 4ms when called from
* within another setTimeout(…, 0) for legacy reasons.
*
* This will not schedule the callback as a microtask (i.e. a task that can
* preempt user input or networking callbacks). It is meant to emulate what
* setTimeout(_, 0) would do if it were not throttled. If you desire microtask
* behavior, use {@see goog.Promise} instead.
*
* @param {function(this:SCOPE)} callback Callback function to fire as soon as
* possible.
* @param {SCOPE=} opt_context Object in whose scope to call the listener.
* @param {boolean=} opt_useSetImmediate Avoid the IE workaround that
* ensures correctness at the cost of speed. See comments for details.
* @template SCOPE
*/
goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) {
'use strict';
var cb = callback;
if (opt_context) {
cb = goog.bind(callback, opt_context);
}
cb = goog.async.nextTick.wrapCallback_(cb);
// Note we do allow callers to also request setImmediate if they are willing
// to accept the possible tradeoffs of incorrectness in exchange for speed.
// The IE fallback of readystate change is much slower. See useSetImmediate_
// for details.
if (typeof goog.global.setImmediate === 'function' &&
(opt_useSetImmediate || goog.async.nextTick.useSetImmediate_())) {
goog.global.setImmediate(cb);
return;
}
// Look for and cache the custom fallback version of setImmediate.
if (!goog.async.nextTick.setImmediate_) {
goog.async.nextTick.setImmediate_ =
goog.async.nextTick.getSetImmediateEmulator_();
}
goog.async.nextTick.setImmediate_(cb);
};
/**
* Returns whether should use setImmediate implementation currently on window.
*
* window.setImmediate was introduced and currently only supported by IE10+,
* but due to a bug in the implementation it is not guaranteed that
* setImmediate is faster than setTimeout nor that setImmediate N is before
* setImmediate N+1. That is why we do not use the native version if
* available. We do, however, call setImmediate if it is a non-native function
* because that indicates that it has been replaced by goog.testing.MockClock
* which we do want to support.
* See
* http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10
*
* @return {boolean} Whether to use the implementation of setImmediate defined
* on Window.
* @private
* @suppress {missingProperties} For "Window.prototype.setImmediate"
*/
goog.async.nextTick.useSetImmediate_ = function() {
'use strict';
// Not a browser environment.
if (!goog.global.Window || !goog.global.Window.prototype) {
return true;
}
// MS Edge has window.setImmediate natively, but it's not on Window.prototype.
// Also, there's no clean way to detect if the goog.global.setImmediate has
// been replaced by mockClock as its replacement also shows up as "[native
// code]" when using toString. Therefore, just always use
// goog.global.setImmediate for Edge. It's unclear if it suffers the same
// issues as IE10/11, but based on
// https://dev.modern.ie/testdrive/demos/setimmediatesorting/
// it seems they've been working to ensure it's WAI.
if (goog.labs.userAgent.browser.isEdge() ||
goog.global.Window.prototype.setImmediate != goog.global.setImmediate) {
// Something redefined setImmediate in which case we decide to use it (This
// is so that we use the mockClock setImmediate).
return true;
}
return false;
};
/**
* Cache for the setImmediate implementation.
* @type {function(function())}
* @private
*/
goog.async.nextTick.setImmediate_;
/**
* Determines the best possible implementation to run a function as soon as
* the JS event loop is idle.
* @return {function(function())} The "setImmediate" implementation.
* @private
*/
goog.async.nextTick.getSetImmediateEmulator_ = function() {
'use strict';
// Create a private message channel and use it to postMessage empty messages
// to ourselves.
/** @type {!Function|undefined} */
var Channel = goog.global['MessageChannel'];
// If MessageChannel is not available and we are in a browser, implement
// an iframe based polyfill in browsers that have postMessage and
// document.addEventListener. The latter excludes IE8 because it has a
// synchronous postMessage implementation.
if (typeof Channel === 'undefined' && typeof window !== 'undefined' &&
window.postMessage && window.addEventListener &&
// Presto (The old pre-blink Opera engine) has problems with iframes
// and contentWindow.
!goog.labs.userAgent.engine.isPresto()) {
/** @constructor */
Channel = function() {
'use strict';
// Make an empty, invisible iframe.
var iframe = goog.dom.createElement(goog.dom.TagName.IFRAME);
iframe.style.display = 'none';
document.documentElement.appendChild(iframe);
var win = iframe.contentWindow;
var doc = win.document;
doc.open();
doc.close();
// Do not post anything sensitive over this channel, as the workaround for
// pages with file: origin could allow that information to be modified or
// intercepted.
var message = 'callImmediate' + Math.random();
// The same origin policy rejects attempts to postMessage from file: urls
// unless the origin is '*'.
var origin = win.location.protocol == 'file:' ?
'*' :
win.location.protocol + '//' + win.location.host;
var onmessage = goog.bind(function(e) {
'use strict';
// Validate origin and message to make sure that this message was
// intended for us. If the origin is set to '*' (see above) only the
// message needs to match since, for example, '*' != 'file://'. Allowing
// the wildcard is ok, as we are not concerned with security here.
if ((origin != '*' && e.origin != origin) || e.data != message) {
return;
}
this['port1'].onmessage();
}, this);
win.addEventListener('message', onmessage, false);
this['port1'] = {};
this['port2'] = {
postMessage: function() {
'use strict';
win.postMessage(message, origin);
}
};
};
}
if (typeof Channel !== 'undefined' && !goog.labs.userAgent.browser.isIE()) {
// Exclude all of IE due to
// http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/
// which allows starving postMessage with a busy setTimeout loop.
// This currently affects IE10 and IE11 which would otherwise be able
// to use the postMessage based fallbacks.
var channel = new Channel();
// Use a fifo linked list to call callbacks in the right order.
var head = {};
var tail = head;
channel['port1'].onmessage = function() {
'use strict';
if (head.next !== undefined) {
head = head.next;
var cb = head.cb;
head.cb = null;
cb();
}
};
return function(cb) {
'use strict';
tail.next = {cb: cb};
tail = tail.next;
channel['port2'].postMessage(0);
};
}
// Fall back to setTimeout with 0. In browsers this creates a delay of 5ms
// or more.
// NOTE(user): This fallback is used for IE.
return function(cb) {
'use strict';
goog.global.setTimeout(/** @type {function()} */ (cb), 0);
};
};
/**
* Helper function that is overrided to protect callbacks with entry point
* monitor if the application monitors entry points.
* @param {function()} callback Callback function to fire as soon as possible.
* @return {function()} The wrapped callback.
* @private
*/
goog.async.nextTick.wrapCallback_ = goog.functions.identity;
// Register the callback function as an entry point, so that it can be
// monitored for exception handling, etc. This has to be done in this file
// since it requires special code to handle all browsers.
goog.debug.entryPointRegistry.register(
/**
* @param {function(!Function): !Function} transformer The transforming
* function.
*/
function(transformer) {
'use strict';
goog.async.nextTick.wrapCallback_ = transformer;
});
+149
View File
@@ -0,0 +1,149 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('goog.async.run');
goog.require('goog.async.WorkQueue');
goog.require('goog.async.nextTick');
goog.require('goog.async.throwException');
/**
* @define {boolean} If true, use the global Promise to implement goog.async.run
* assuming either the native, or polyfill version will be used. Does still
* permit tests to use forceNextTick.
*/
goog.ASSUME_NATIVE_PROMISE = goog.define('goog.ASSUME_NATIVE_PROMISE', false);
/**
* Fires the provided callback just before the current callstack unwinds, or as
* soon as possible after the current JS execution context.
* @param {function(this:THIS)} callback
* @param {THIS=} opt_context Object to use as the "this value" when calling
* the provided function.
* @template THIS
*/
goog.async.run = function(callback, opt_context) {
'use strict';
if (!goog.async.run.schedule_) {
goog.async.run.initializeRunner_();
}
if (!goog.async.run.workQueueScheduled_) {
// Nothing is currently scheduled, schedule it now.
goog.async.run.schedule_();
goog.async.run.workQueueScheduled_ = true;
}
goog.async.run.workQueue_.add(callback, opt_context);
};
/**
* Initializes the function to use to process the work queue.
* @private
*/
goog.async.run.initializeRunner_ = function() {
'use strict';
if (goog.ASSUME_NATIVE_PROMISE ||
(goog.global.Promise && goog.global.Promise.resolve)) {
// Use goog.global.Promise instead of just Promise because the relevant
// externs may be missing, and don't alias it because this could confuse the
// compiler into thinking the polyfill is required when it should be treated
// as optional.
var promise = goog.global.Promise.resolve(undefined);
goog.async.run.schedule_ = function() {
'use strict';
promise.then(goog.async.run.processWorkQueue);
};
} else {
goog.async.run.schedule_ = function() {
'use strict';
goog.async.nextTick(goog.async.run.processWorkQueue);
};
}
};
/**
* Forces goog.async.run to use nextTick instead of Promise.
*
* This should only be done in unit tests. It's useful because MockClock
* replaces nextTick, but not the browser Promise implementation, so it allows
* Promise-based code to be tested with MockClock.
*
* However, we also want to run promises if the MockClock is no longer in
* control so we schedule a backup "setTimeout" to the unmocked timeout if
* provided.
*
* @param {function(function())=} opt_realSetTimeout
*/
goog.async.run.forceNextTick = function(opt_realSetTimeout) {
'use strict';
goog.async.run.schedule_ = function() {
'use strict';
goog.async.nextTick(goog.async.run.processWorkQueue);
if (opt_realSetTimeout) {
opt_realSetTimeout(goog.async.run.processWorkQueue);
}
};
};
/**
* The function used to schedule work asynchronousely.
* @private {function()}
*/
goog.async.run.schedule_;
/** @private {boolean} */
goog.async.run.workQueueScheduled_ = false;
/** @private {!goog.async.WorkQueue} */
goog.async.run.workQueue_ = new goog.async.WorkQueue();
if (goog.DEBUG) {
/**
* Reset the work queue. Only available for tests in debug mode.
*/
goog.async.run.resetQueue = function() {
'use strict';
goog.async.run.workQueueScheduled_ = false;
goog.async.run.workQueue_ = new goog.async.WorkQueue();
};
/**
* Resets the scheduler. Only available for tests in debug mode.
*/
goog.async.run.resetSchedulerForTest = function() {
goog.async.run.initializeRunner_();
};
}
/**
* Run any pending goog.async.run work items. This function is not intended
* for general use, but for use by entry point handlers to run items ahead of
* goog.async.nextTick.
*/
goog.async.run.processWorkQueue = function() {
'use strict';
// NOTE: additional work queue items may be added while processing.
var item = null;
while (item = goog.async.run.workQueue_.remove()) {
try {
item.fn.call(item.scope);
} catch (e) {
goog.async.throwException(e);
}
goog.async.run.workQueue_.returnUnused(item);
}
// There are no more work items, allow processing to be scheduled again.
goog.async.run.workQueueScheduled_ = false;
};
+28
View File
@@ -0,0 +1,28 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Provides a function to throw an error without interrupting
* the current execution context.
*/
goog.module('goog.async.throwException');
goog.module.declareLegacyNamespace();
/**
* Throw an item without interrupting the current execution context. For
* example, if processing a group of items in a loop, sometimes it is useful
* to report an error while still allowing the rest of the batch to be
* processed.
* @param {*} exception
*/
function throwException(exception) {
// Each throw needs to be in its own context.
goog.global.setTimeout(() => {
throw exception;
}, 0);
}
exports = throwException;
+123
View File
@@ -0,0 +1,123 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
goog.module('goog.async.WorkQueue');
goog.module.declareLegacyNamespace();
const FreeList = goog.require('goog.async.FreeList');
const {assert} = goog.require('goog.asserts');
// TODO(johnlenz): generalize the WorkQueue if this is used by more
// than goog.async.run.
/**
* A low GC workqueue. The key elements of this design:
* - avoids the need for goog.bind or equivalent by carrying scope
* - avoids the need for array reallocation by using a linked list
* - minimizes work entry objects allocation by recycling objects
* @final
* @struct
*/
class WorkQueue {
constructor() {
this.workHead_ = null;
this.workTail_ = null;
}
/**
* @param {function()} fn
* @param {Object|null|undefined} scope
*/
add(fn, scope) {
const item = this.getUnusedItem_();
item.set(fn, scope);
if (this.workTail_) {
this.workTail_.next = item;
this.workTail_ = item;
} else {
assert(!this.workHead_);
this.workHead_ = item;
this.workTail_ = item;
}
}
/**
* @return {?WorkItem}
*/
remove() {
let item = null;
if (this.workHead_) {
item = this.workHead_;
this.workHead_ = this.workHead_.next;
if (!this.workHead_) {
this.workTail_ = null;
}
item.next = null;
}
return item;
}
/**
* @param {!WorkItem} item
*/
returnUnused(item) {
WorkQueue.freelist_.put(item);
}
/**
* @return {!WorkItem}
* @private
*/
getUnusedItem_() {
return WorkQueue.freelist_.get();
}
}
/** @define {number} The maximum number of entries to keep for recycling. */
WorkQueue.DEFAULT_MAX_UNUSED =
goog.define('goog.async.WorkQueue.DEFAULT_MAX_UNUSED', 100);
/** @const @private {!FreeList<!WorkItem>} */
WorkQueue.freelist_ = new FreeList(
() => new WorkItem(), item => item.reset(), WorkQueue.DEFAULT_MAX_UNUSED);
/**
* @final
* @struct
*/
class WorkItem {
constructor() {
/** @type {?function()} */
this.fn = null;
/** @type {?Object|null|undefined} */
this.scope = null;
/** @type {?WorkItem} */
this.next = null;
}
/**
* @param {function()} fn
* @param {Object|null|undefined} scope
*/
set(fn, scope) {
'use strict';
this.fn = fn;
this.scope = scope;
this.next = null;
}
/** Reset the work item so they don't prevent GC before reuse */
reset() {
this.fn = null;
this.scope = null;
this.next = null;
}
}
exports = WorkQueue;
+3889
View File
File diff suppressed because it is too large Load Diff
+222
View File
@@ -0,0 +1,222 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Utilities for working with ES6 iterables.
*
* The goal is that this should be a replacement for goog.iter which uses
* a now non-standard approach to iterables.
*
* @see https://goo.gl/Rok5YQ
*/
goog.module('goog.collections.iters');
goog.module.declareLegacyNamespace();
/**
* Get the iterator for an iterable.
* @param {!Iterable<VALUE>} iterable
* @return {!Iterator<VALUE>}
* @template VALUE
*/
function getIterator(iterable) {
return iterable[goog.global.Symbol.iterator]();
}
exports.getIterator = getIterator;
/**
* Call a function with every value of an iterable.
*
* Warning: this function will never halt if given an iterable that
* is never exhausted.
*
* @param {!Iterable<VALUE>} iterable
* @param {function(VALUE) : *} f
* @template VALUE
*/
exports.forEach = function(iterable, f) {
for (const elem of iterable) {
f(elem);
}
};
/**
* An Iterable that wraps a child iterable, and maps every element of the child
* iterator to a new value, using a mapping function. Similar to Array.map, but
* for Iterable.
* @template TO,FROM
* @implements {IteratorIterable<TO>}
*/
class MapIterator {
/**
* @param {!Iterable<FROM>} childIter
* @param {function(FROM, number): TO} mapFn
*/
constructor(childIter, mapFn) {
/** @private @const {!Iterator<FROM>} */
this.childIterator_ = getIterator(childIter);
/** @private @const {function(FROM, number): TO} */
this.mapFn_ = mapFn;
/** @private {number} */
this.nextIndex_ = 0;
}
[Symbol.iterator]() {
return this;
}
/** @override */
next() {
const childResult = this.childIterator_.next();
// Always return a new object, even when childResult.done == true. This is
// so that we don't accidentally preserve generator return values, which
// are unlikely to be meaningful in the context of this MapIterator.
return {
value: childResult.done ?
undefined :
this.mapFn_.call(undefined, childResult.value, this.nextIndex_++),
done: childResult.done,
};
}
}
/**
* Maps the values of one iterable to create another iterable.
*
* When next() is called on the returned iterable, it will call the given
* function `f` with the next value of the given iterable
* `iterable` until the given iterable is exhausted.
*
* @param {!Iterable<VALUE>} iterable
* @param {function(VALUE, number): RESULT} f
* @return {!IteratorIterable<RESULT>} The created iterable that gives the
* mapped values.
* @template VALUE, RESULT
*/
exports.map = function(iterable, f) {
return new MapIterator(iterable, f);
};
/**
* An Iterable that wraps a child Iterable and returns a subset of the child's
* items, based on a filter function. Similar to Array.filter, but for
* Iterable.
* @template T
* @implements {IteratorIterable<T>}
*/
class FilterIterator {
/**
* @param {!Iterable<T>} childIter
* @param {function(T, number): boolean} filterFn
*/
constructor(childIter, filterFn) {
/** @private @const {!Iterator<T>} */
this.childIter_ = getIterator(childIter);
/** @private @const {function(T, number): boolean} */
this.filterFn_ = filterFn;
/** @private {number} */
this.nextIndex_ = 0;
}
[Symbol.iterator]() {
return this;
}
/** @override */
next() {
while (true) {
const childResult = this.childIter_.next();
if (childResult.done) {
// Don't return childResult directly, because that would preserve
// generator return values, and we want to ignore them.
return {done: true, value: undefined};
}
const passesFilter =
this.filterFn_.call(undefined, childResult.value, this.nextIndex_++);
if (passesFilter) {
return childResult;
}
}
}
}
/**
* Filter elements from one iterator to create another iterable.
*
* When next() is called on the returned iterator, it will call next() on the
* given iterator and call the given function `f` with that value until `true`
* is returned or the given iterator is exhausted.
*
* @param {!Iterable<VALUE>} iterable
* @param {function(VALUE, number): boolean} f
* @return {!IteratorIterable<VALUE>} The created iterable that gives the mapped
* values.
* @template VALUE
*/
exports.filter = function(iterable, f) {
return new FilterIterator(iterable, f);
};
/**
* @template T
* @implements {IteratorIterable<T>}
*/
class ConcatIterator {
/** @param {!Array<!Iterator<T>>} iterators */
constructor(iterators) {
/** @private @const {!Array<!Iterator<T>>} */
this.iterators_ = iterators;
/** @private {number} */
this.iterIndex_ = 0;
}
[Symbol.iterator]() {
return this;
}
/** @override */
next() {
while (this.iterIndex_ < this.iterators_.length) {
const result = this.iterators_[this.iterIndex_].next();
if (!result.done) {
return result;
}
this.iterIndex_++;
}
return /** @type {!IIterableResult<T>} */ ({done: true});
}
}
/**
* Concatenates multiple iterators to create a new iterable.
*
* When next() is called on the return iterator, it will call next() on the
* current passed iterator. When the current passed iterator is exhausted, it
* will move on to the next iterator until there are no more left.
*
* All generator return values will be ignored (i.e. when childIter.next()
* returns {done: true, value: notUndefined} it will be treated as just
* {done: true}).
*
* @param {...!Iterable<VALUE>} iterables
* @return {!IteratorIterable<VALUE>}
* @template VALUE
*/
exports.concat = function(...iterables) {
return new ConcatIterator(iterables.map(getIterator));
};
+159
View File
@@ -0,0 +1,159 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Helper methods that operate on Map-like objects (e.g. ES6
* Maps).
*/
goog.module('goog.collections.maps');
goog.module.declareLegacyNamespace();
/**
* A MapLike implements the same public interface as an ES6 Map, without tying
* the underlying code directly to the implementation. Any additions to this
* type should also be present on ES6 Maps.
* @template K,V
* @record
*/
class MapLike {
constructor() {
/** @const {number} The number of items in this map. */
this.size;
}
/**
* @param {K} key The key to set in the map.
* @param {V} val The value to set for the given key in the map.
*/
set(key, val) {};
/**
* @param {K} key The key to retrieve from the map.
* @return {V|undefined} The value for this key, or undefined if the key is
* not present in the map.
*/
get(key) {};
/**
* @return {!IteratorIterable<K>} An ES6 Iterator that iterates over the keys
* in the map.
*/
keys() {};
/**
* @return {!IteratorIterable<V>} An ES6 Iterator that iterates over the
* values in the map.
*/
values() {};
/**
* @param {K} key The key to check.
* @return {boolean} True iff this key is present in the map.
*/
has(key) {};
}
exports.MapLike = MapLike;
/**
* Iterates over each entry in the given entries and sets the entry in
* the map, overwriting any existing entries for the key.
* @param {!MapLike<K,V>} map The map to set entries on.
* @param {?Iterable<!Array<K|V>>} entries The iterable of entries. This
* iterable should really be of type Iterable<Array<[K,V]>>, but the tuple
* type is not representable in the Closure Type System.
* @template K,V
*/
function setAll(map, entries) {
if (!entries) return;
for (const [k, v] of entries) {
map.set(k, v);
}
}
exports.setAll = setAll;
/**
* Determines if a given map contains the given value, optionally using
* a custom comparison function.
* @param {!MapLike<?,V1>} map The map whose values to check.
* @param {V2} val The value to check for.
* @param {(function(V1,V2): boolean)=} valueEqualityFn The comparison function
* used to determine if the given value is equivalent to any of the values
* in the map. If no function is provided, defaults to strict equality
* (===).
* @return {boolean} True iff the given map contains the given value according
* to the comparison function.
* @template V1,V2
*/
function hasValue(map, val, valueEqualityFn = defaultEqualityFn) {
for (const v of map.values()) {
if (valueEqualityFn(v, val)) return true;
}
return false;
}
exports.hasValue = hasValue;
/** @const {function(?,?): boolean} */
const defaultEqualityFn = (a, b) => a === b;
/**
* Compares two maps using their public APIs to determine if they have
* equal contents, optionally using a custom comparison function when comaring
* values.
* @param {!MapLike<K,V1>} map The first map
* @param {!MapLike<K,V2>} otherMap The other map
* @param {(function(V1,V2): boolean)=} valueEqualityFn The comparison function
* used to determine if the values obtained from each map are equivalent. If
* no function is provided, defaults to strict equality (===).
* @return {boolean}
* @template K,V1,V2
*/
function equals(map, otherMap, valueEqualityFn = defaultEqualityFn) {
if (map === otherMap) return true;
if (map.size !== otherMap.size) return false;
for (const key of map.keys()) {
if (!otherMap.has(key)) return false;
if (!valueEqualityFn(map.get(key), otherMap.get(key))) return false;
}
return true;
}
exports.equals = equals;
/**
* Returns a new ES6 Map in which all the keys and values from the
* given map are interchanged (keys become values and values become keys). If
* multiple keys in the given map to the same value, the resulting value in the
* transposed map is implementation-dependent.
*
* It acts very similarly to {goog.object.transpose(Object)}.
* @param {!MapLike<K,V>} map The map to transpose.
* @return {!Map<V,K>} A transposed version of the given map.
* @template K,V
*/
function transpose(map) {
const /** !Map<V,K> */ transposed = new Map();
for (const key of map.keys()) {
const val = map.get(key);
transposed.set(val, key);
}
return transposed;
}
exports.transpose = transpose;
/**
* ToObject returns a new object whose properties are the keys from the Map.
* @param {!MapLike<K,V>} map The map to convert into an object.
* @return {!Object<K,V>} An object representation of the Map.
* @template K,V
*/
function toObject(map) {
const /** !Object<K,V> */ obj = {};
for (const key of map.keys()) {
obj[key] = map.get(key);
}
return obj;
}
exports.toObject = toObject;
+747
View File
@@ -0,0 +1,747 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Logging and debugging utilities.
*
* @see ../demos/debug.html
*/
goog.provide('goog.debug');
goog.require('goog.array');
goog.require('goog.debug.errorcontext');
/** @define {boolean} Whether logging should be enabled. */
goog.debug.LOGGING_ENABLED =
goog.define('goog.debug.LOGGING_ENABLED', goog.DEBUG);
/** @define {boolean} Whether to force "sloppy" stack building. */
goog.debug.FORCE_SLOPPY_STACKS =
goog.define('goog.debug.FORCE_SLOPPY_STACKS', false);
/**
* @define {boolean} TODO(user): Remove this hack once bug is resolved.
*/
goog.debug.CHECK_FOR_THROWN_EVENT =
goog.define('goog.debug.CHECK_FOR_THROWN_EVENT', false);
/**
* Catches onerror events fired by windows and similar objects.
* @param {function(Object)} logFunc The function to call with the error
* information.
* @param {boolean=} opt_cancel Whether to stop the error from reaching the
* browser.
* @param {Object=} opt_target Object that fires onerror events.
* @suppress {strictMissingProperties} onerror is not defined as a property
* on Object.
*/
goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) {
'use strict';
var target = opt_target || goog.global;
var oldErrorHandler = target.onerror;
var retVal = !!opt_cancel;
/**
* New onerror handler for this target. This onerror handler follows the spec
* according to
* http://www.whatwg.org/specs/web-apps/current-work/#runtime-script-errors
* The spec was changed in August 2013 to support receiving column information
* and an error object for all scripts on the same origin or cross origin
* scripts with the proper headers. See
* https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
*
* @param {string} message The error message. For cross-origin errors, this
* will be scrubbed to just "Script error.". For new browsers that have
* updated to follow the latest spec, errors that come from origins that
* have proper cross origin headers will not be scrubbed.
* @param {string} url The URL of the script that caused the error. The URL
* will be scrubbed to "" for cross origin scripts unless the script has
* proper cross origin headers and the browser has updated to the latest
* spec.
* @param {number} line The line number in the script that the error
* occurred on.
* @param {number=} opt_col The optional column number that the error
* occurred on. Only browsers that have updated to the latest spec will
* include this.
* @param {Error=} opt_error The optional actual error object for this
* error that should include the stack. Only browsers that have updated
* to the latest spec will inlude this parameter.
* @return {boolean} Whether to prevent the error from reaching the browser.
*/
target.onerror = function(message, url, line, opt_col, opt_error) {
'use strict';
if (oldErrorHandler) {
oldErrorHandler(message, url, line, opt_col, opt_error);
}
logFunc({
message: message,
fileName: url,
line: line,
lineNumber: line,
col: opt_col,
error: opt_error
});
return retVal;
};
};
/**
* Creates a string representing an object and all its properties.
* @param {Object|null|undefined} obj Object to expose.
* @param {boolean=} opt_showFn Show the functions as well as the properties,
* default is false.
* @return {string} The string representation of `obj`.
*/
goog.debug.expose = function(obj, opt_showFn) {
'use strict';
if (typeof obj == 'undefined') {
return 'undefined';
}
if (obj == null) {
return 'NULL';
}
var str = [];
for (var x in obj) {
if (!opt_showFn && typeof obj[x] === 'function') {
continue;
}
var s = x + ' = ';
try {
s += obj[x];
} catch (e) {
s += '*** ' + e + ' ***';
}
str.push(s);
}
return str.join('\n');
};
/**
* Creates a string representing a given primitive or object, and for an
* object, all its properties and nested objects. NOTE: The output will include
* Uids on all objects that were exposed. Any added Uids will be removed before
* returning.
* @param {*} obj Object to expose.
* @param {boolean=} opt_showFn Also show properties that are functions (by
* default, functions are omitted).
* @return {string} A string representation of `obj`.
*/
goog.debug.deepExpose = function(obj, opt_showFn) {
'use strict';
var str = [];
// Track any objects where deepExpose added a Uid, so they can be cleaned up
// before return. We do this globally, rather than only on ancestors so that
// if the same object appears in the output, you can see it.
var uidsToCleanup = [];
var ancestorUids = {};
var helper = function(obj, space) {
'use strict';
var nestspace = space + ' ';
var indentMultiline = function(str) {
'use strict';
return str.replace(/\n/g, '\n' + space);
};
try {
if (obj === undefined) {
str.push('undefined');
} else if (obj === null) {
str.push('NULL');
} else if (typeof obj === 'string') {
str.push('"' + indentMultiline(obj) + '"');
} else if (typeof obj === 'function') {
str.push(indentMultiline(String(obj)));
} else if (goog.isObject(obj)) {
// Add a Uid if needed. The struct calls implicitly adds them.
if (!goog.hasUid(obj)) {
uidsToCleanup.push(obj);
}
var uid = goog.getUid(obj);
if (ancestorUids[uid]) {
str.push('*** reference loop detected (id=' + uid + ') ***');
} else {
ancestorUids[uid] = true;
str.push('{');
for (var x in obj) {
if (!opt_showFn && typeof obj[x] === 'function') {
continue;
}
str.push('\n');
str.push(nestspace);
str.push(x + ' = ');
helper(obj[x], nestspace);
}
str.push('\n' + space + '}');
delete ancestorUids[uid];
}
} else {
str.push(obj);
}
} catch (e) {
str.push('*** ' + e + ' ***');
}
};
helper(obj, '');
// Cleanup any Uids that were added by the deepExpose.
for (var i = 0; i < uidsToCleanup.length; i++) {
goog.removeUid(uidsToCleanup[i]);
}
return str.join('');
};
/**
* Recursively outputs a nested array as a string.
* @param {Array<?>} arr The array.
* @return {string} String representing nested array.
*/
goog.debug.exposeArray = function(arr) {
'use strict';
var str = [];
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
str.push(goog.debug.exposeArray(arr[i]));
} else {
str.push(arr[i]);
}
}
return '[ ' + str.join(', ') + ' ]';
};
/**
* Normalizes the error/exception object between browsers.
* @param {*} err Raw error object.
* @return {{
* message: (?|undefined),
* name: (?|undefined),
* lineNumber: (?|undefined),
* fileName: (?|undefined),
* stack: (?|undefined)
* }} Representation of err as an Object. It will never return err.
* @suppress {strictMissingProperties} properties not defined on err
*/
goog.debug.normalizeErrorObject = function(err) {
'use strict';
var href = goog.getObjectByName('window.location.href');
if (err == null) {
err = 'Unknown Error of type "null/undefined"';
}
if (typeof err === 'string') {
return {
'message': err,
'name': 'Unknown error',
'lineNumber': 'Not available',
'fileName': href,
'stack': 'Not available'
};
}
var lineNumber, fileName;
var threwError = false;
try {
lineNumber = err.lineNumber || err.line || 'Not available';
} catch (e) {
// Firefox 2 sometimes throws an error when accessing 'lineNumber':
// Message: Permission denied to get property UnnamedClass.lineNumber
lineNumber = 'Not available';
threwError = true;
}
try {
fileName = err.fileName || err.filename || err.sourceURL ||
// $googDebugFname may be set before a call to eval to set the filename
// that the eval is supposed to present.
goog.global['$googDebugFname'] || href;
} catch (e) {
// Firefox 2 may also throw an error when accessing 'filename'.
fileName = 'Not available';
threwError = true;
}
var stack = goog.debug.serializeErrorStack_(err);
// The IE Error object contains only the name and the message.
// The Safari Error object uses the line and sourceURL fields.
if (threwError || !err.lineNumber || !err.fileName || !err.stack ||
!err.message || !err.name) {
var message = err.message;
if (message == null) {
if (err.constructor && err.constructor instanceof Function) {
var ctorName = err.constructor.name ?
err.constructor.name :
goog.debug.getFunctionName(err.constructor);
message = 'Unknown Error of type "' + ctorName + '"';
// TODO(user): Remove this hack once bug is resolved.
if (goog.debug.CHECK_FOR_THROWN_EVENT && ctorName == 'Event') {
try {
message = message + ' with Event.type "' + (err.type || '') + '"';
} catch (e) {
// Just give up on getting more information out of the error object.
}
}
} else {
message = 'Unknown Error of unknown type';
}
// Avoid TypeError since toString could be missing from the instance
// (e.g. if created Object.create(null)).
if (typeof err.toString === 'function' &&
Object.prototype.toString !== err.toString) {
message += ': ' + err.toString();
}
}
return {
'message': message,
'name': err.name || 'UnknownError',
'lineNumber': lineNumber,
'fileName': fileName,
'stack': stack || 'Not available'
};
}
// Standards error object
// Typed !Object. Should be a subtype of the return type, but it's not.
err.stack = stack;
// Return non-standard error to allow for consistent result (eg. enumerable).
return {
'message': err.message,
'name': err.name,
'lineNumber': err.lineNumber,
'fileName': err.fileName,
'stack': err.stack
};
};
/**
* Serialize stack by including the cause chain of the exception if it exists.
*
*
* @param {*} e an exception that may have a cause
* @param {!Object=} seen set of cause that have already been serialized
* @return {string}
* @private
* @suppress {missingProperties} properties not defined on cause and e
*/
goog.debug.serializeErrorStack_ = function(e, seen) {
'use strict';
if (!seen) {
seen = {};
}
seen[goog.debug.serializeErrorAsKey_(e)] = true;
var stack = e['stack'] || '';
// Add cause if exists.
var cause = e.cause;
if (cause && !seen[goog.debug.serializeErrorAsKey_(cause)]) {
stack += '\nCaused by: ';
// Some browsers like Chrome add the error message as the first frame of the
// stack, In this case we don't need to add it. Note: we don't use
// String.startsWith method because it might have to be polyfilled.
if (!cause.stack || cause.stack.indexOf(cause.toString()) != 0) {
stack += (typeof cause === 'string') ? cause : cause.message + '\n';
}
stack += goog.debug.serializeErrorStack_(cause, seen);
}
return stack;
};
/**
* Serialize an error to a string key.
* @param {*} e an exception
* @return {string}
* @private
*/
goog.debug.serializeErrorAsKey_ = function(e) {
'use strict';
var keyPrefix = '';
if (typeof e.toString === 'function') {
keyPrefix = '' + e;
}
return keyPrefix + e['stack'];
};
/**
* Converts an object to an Error using the object's toString if it's not
* already an Error, adds a stacktrace if there isn't one, and optionally adds
* an extra message.
* @param {*} err The original thrown error, object, or string.
* @param {string=} opt_message optional additional message to add to the
* error.
* @return {!Error} If err is an Error, it is enhanced and returned. Otherwise,
* it is converted to an Error which is enhanced and returned.
*/
goog.debug.enhanceError = function(err, opt_message) {
'use strict';
var error;
if (!(err instanceof Error)) {
error = Error(err);
if (Error.captureStackTrace) {
// Trim this function off the call stack, if we can.
Error.captureStackTrace(error, goog.debug.enhanceError);
}
} else {
error = err;
}
if (!error.stack) {
error.stack = goog.debug.getStacktrace(goog.debug.enhanceError);
}
if (opt_message) {
// find the first unoccupied 'messageX' property
var x = 0;
while (error['message' + x]) {
++x;
}
error['message' + x] = String(opt_message);
}
return error;
};
/**
* Converts an object to an Error using the object's toString if it's not
* already an Error, adds a stacktrace if there isn't one, and optionally adds
* context to the Error, which is reported by the closure error reporter.
* @param {*} err The original thrown error, object, or string.
* @param {!Object<string, string>=} opt_context Key-value context to add to the
* Error.
* @return {!Error} If err is an Error, it is enhanced and returned. Otherwise,
* it is converted to an Error which is enhanced and returned.
*/
goog.debug.enhanceErrorWithContext = function(err, opt_context) {
'use strict';
var error = goog.debug.enhanceError(err);
if (opt_context) {
for (var key in opt_context) {
goog.debug.errorcontext.addErrorContext(error, key, opt_context[key]);
}
}
return error;
};
/**
* Gets the current stack trace. Simple and iterative - doesn't worry about
* catching circular references or getting the args.
* @param {number=} opt_depth Optional maximum depth to trace back to.
* @return {string} A string with the function names of all functions in the
* stack, separated by \n.
* @suppress {es5Strict}
*/
goog.debug.getStacktraceSimple = function(opt_depth) {
'use strict';
if (!goog.debug.FORCE_SLOPPY_STACKS) {
var stack = goog.debug.getNativeStackTrace_(goog.debug.getStacktraceSimple);
if (stack) {
return stack;
}
// NOTE: browsers that have strict mode support also have native "stack"
// properties. Fall-through for legacy browser support.
}
var sb = [];
var fn = arguments.callee.caller;
var depth = 0;
while (fn && (!opt_depth || depth < opt_depth)) {
sb.push(goog.debug.getFunctionName(fn));
sb.push('()\n');
try {
fn = fn.caller;
} catch (e) {
sb.push('[exception trying to get caller]\n');
break;
}
depth++;
if (depth >= goog.debug.MAX_STACK_DEPTH) {
sb.push('[...long stack...]');
break;
}
}
if (opt_depth && depth >= opt_depth) {
sb.push('[...reached max depth limit...]');
} else {
sb.push('[end]');
}
return sb.join('');
};
/**
* Max length of stack to try and output
* @type {number}
*/
goog.debug.MAX_STACK_DEPTH = 50;
/**
* @param {Function} fn The function to start getting the trace from.
* @return {?string}
* @private
*/
goog.debug.getNativeStackTrace_ = function(fn) {
'use strict';
var tempErr = new Error();
if (Error.captureStackTrace) {
Error.captureStackTrace(tempErr, fn);
return String(tempErr.stack);
} else {
// IE10, only adds stack traces when an exception is thrown.
try {
throw tempErr;
} catch (e) {
tempErr = e;
}
var stack = tempErr.stack;
if (stack) {
return String(stack);
}
}
return null;
};
/**
* Gets the current stack trace, either starting from the caller or starting
* from a specified function that's currently on the call stack.
* @param {?Function=} fn If provided, when collecting the stack trace all
* frames above the topmost call to this function, including that call,
* will be left out of the stack trace.
* @return {string} Stack trace.
* @suppress {es5Strict}
*/
goog.debug.getStacktrace = function(fn) {
'use strict';
var stack;
if (!goog.debug.FORCE_SLOPPY_STACKS) {
// Try to get the stack trace from the environment if it is available.
var contextFn = fn || goog.debug.getStacktrace;
stack = goog.debug.getNativeStackTrace_(contextFn);
}
if (!stack) {
// NOTE: browsers that have strict mode support also have native "stack"
// properties. This function will throw in strict mode.
stack = goog.debug.getStacktraceHelper_(fn || arguments.callee.caller, []);
}
return stack;
};
/**
* Private helper for getStacktrace().
* @param {?Function} fn If provided, when collecting the stack trace all
* frames above the topmost call to this function, including that call,
* will be left out of the stack trace.
* @param {Array<!Function>} visited List of functions visited so far.
* @return {string} Stack trace starting from function fn.
* @suppress {es5Strict}
* @private
*/
goog.debug.getStacktraceHelper_ = function(fn, visited) {
'use strict';
var sb = [];
// Circular reference, certain functions like bind seem to cause a recursive
// loop so we need to catch circular references
if (goog.array.contains(visited, fn)) {
sb.push('[...circular reference...]');
// Traverse the call stack until function not found or max depth is reached
} else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) {
sb.push(goog.debug.getFunctionName(fn) + '(');
var args = fn.arguments;
// Args may be null for some special functions such as host objects or eval.
for (var i = 0; args && i < args.length; i++) {
if (i > 0) {
sb.push(', ');
}
var argDesc;
var arg = args[i];
switch (typeof arg) {
case 'object':
argDesc = arg ? 'object' : 'null';
break;
case 'string':
argDesc = arg;
break;
case 'number':
argDesc = String(arg);
break;
case 'boolean':
argDesc = arg ? 'true' : 'false';
break;
case 'function':
argDesc = goog.debug.getFunctionName(arg);
argDesc = argDesc ? argDesc : '[fn]';
break;
case 'undefined':
default:
argDesc = typeof arg;
break;
}
if (argDesc.length > 40) {
argDesc = argDesc.substr(0, 40) + '...';
}
sb.push(argDesc);
}
visited.push(fn);
sb.push(')\n');
try {
sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited));
} catch (e) {
sb.push('[exception trying to get caller]\n');
}
} else if (fn) {
sb.push('[...long stack...]');
} else {
sb.push('[end]');
}
return sb.join('');
};
/**
* Gets a function name
* @param {Function} fn Function to get name of.
* @return {string} Function's name.
*/
goog.debug.getFunctionName = function(fn) {
'use strict';
if (goog.debug.fnNameCache_[fn]) {
return goog.debug.fnNameCache_[fn];
}
// Heuristically determine function name based on code.
var functionSource = String(fn);
if (!goog.debug.fnNameCache_[functionSource]) {
var matches = /function\s+([^\(]+)/m.exec(functionSource);
if (matches) {
var method = matches[1];
goog.debug.fnNameCache_[functionSource] = method;
} else {
goog.debug.fnNameCache_[functionSource] = '[Anonymous]';
}
}
return goog.debug.fnNameCache_[functionSource];
};
/**
* Makes whitespace visible by replacing it with printable characters.
* This is useful in finding diffrences between the expected and the actual
* output strings of a testcase.
* @param {string} string whose whitespace needs to be made visible.
* @return {string} string whose whitespace is made visible.
*/
goog.debug.makeWhitespaceVisible = function(string) {
'use strict';
return string.replace(/ /g, '[_]')
.replace(/\f/g, '[f]')
.replace(/\n/g, '[n]\n')
.replace(/\r/g, '[r]')
.replace(/\t/g, '[t]');
};
/**
* Returns the type of a value. If a constructor is passed, and a suitable
* string cannot be found, 'unknown type name' will be returned.
*
* <p>Forked rather than moved from {@link goog.asserts.getType_}
* to avoid adding a dependency to goog.asserts.
* @param {*} value A constructor, object, or primitive.
* @return {string} The best display name for the value, or 'unknown type name'.
*/
goog.debug.runtimeType = function(value) {
'use strict';
if (value instanceof Function) {
return value.displayName || value.name || 'unknown type name';
} else if (value instanceof Object) {
return /** @type {string} */ (value.constructor.displayName) ||
value.constructor.name || Object.prototype.toString.call(value);
} else {
return value === null ? 'null' : typeof value;
}
};
/**
* Hash map for storing function names that have already been looked up.
* @type {Object}
* @private
*/
goog.debug.fnNameCache_ = {};
/**
* Private internal function to support goog.debug.freeze.
* @param {T} arg
* @return {T}
* @template T
* @private
*/
goog.debug.freezeInternal_ = goog.DEBUG && Object.freeze || function(arg) {
'use strict';
return arg;
};
/**
* Freezes the given object, but only in debug mode (and in browsers that
* support it). Note that this is a shallow freeze, so for deeply nested
* objects it must be called at every level to ensure deep immutability.
* @param {T} arg
* @return {T}
* @template T
*/
goog.debug.freeze = function(arg) {
'use strict';
// NOTE: this compiles to nothing, but hides the possible side effect of
// freezeInternal_ from the compiler so that the entire call can be
// removed if the result is not used.
return {
valueOf: function() {
'use strict';
return goog.debug.freezeInternal_(arg);
}
}.valueOf();
};
+158
View File
@@ -0,0 +1,158 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview A global registry for entry points into a program,
* so that they can be instrumented. Each module should register their
* entry points with this registry. Designed to be compiled out
* if no instrumentation is requested.
*
* Entry points may be registered before or after a call to
* goog.debug.entryPointRegistry.monitorAll. If an entry point is registered
* later, the existing monitor will instrument the new entry point.
*/
goog.provide('goog.debug.EntryPointMonitor');
goog.provide('goog.debug.entryPointRegistry');
goog.require('goog.asserts');
/**
* @interface
*/
goog.debug.entryPointRegistry.EntryPointMonitor = function() {};
/**
* Instruments a function.
*
* @param {!Function} fn A function to instrument.
* @return {!Function} The instrumented function.
*/
goog.debug.entryPointRegistry.EntryPointMonitor.prototype.wrap;
/**
* Try to remove an instrumentation wrapper created by this monitor.
* If the function passed to unwrap is not a wrapper created by this
* monitor, then we will do nothing.
*
* Notice that some wrappers may not be unwrappable. For example, if other
* monitors have applied their own wrappers, then it will be impossible to
* unwrap them because their wrappers will have captured our wrapper.
*
* So it is important that entry points are unwrapped in the reverse
* order that they were wrapped.
*
* @param {!Function} fn A function to unwrap.
* @return {!Function} The unwrapped function, or `fn` if it was not
* a wrapped function created by this monitor.
*/
goog.debug.entryPointRegistry.EntryPointMonitor.prototype.unwrap;
/**
* Alias for goog.debug.entryPointRegistry.EntryPointMonitor, for compatibility
* purposes.
* @const
*/
goog.debug.EntryPointMonitor = goog.debug.entryPointRegistry.EntryPointMonitor;
/**
* An array of entry point callbacks.
* @type {!Array<function(!Function)>}
* @private
*/
goog.debug.entryPointRegistry.refList_ = [];
/**
* Monitors that should wrap all the entry points.
* @type {!Array<!goog.debug.EntryPointMonitor>}
* @private
*/
goog.debug.entryPointRegistry.monitors_ = [];
/**
* Whether goog.debug.entryPointRegistry.monitorAll has ever been called.
* Checking this allows the compiler to optimize out the registrations.
* @type {boolean}
* @private
*/
goog.debug.entryPointRegistry.monitorsMayExist_ = false;
/**
* Register an entry point with this module.
*
* The entry point will be instrumented when a monitor is passed to
* goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the
* entry point is instrumented immediately.
*
* @param {function(!Function)} callback A callback function which is called
* with a transforming function to instrument the entry point. The callback
* is responsible for wrapping the relevant entry point with the
* transforming function.
*/
goog.debug.entryPointRegistry.register = function(callback) {
'use strict';
// Don't use push(), so that this can be compiled out.
goog.debug.entryPointRegistry
.refList_[goog.debug.entryPointRegistry.refList_.length] = callback;
// If no one calls monitorAll, this can be compiled out.
if (goog.debug.entryPointRegistry.monitorsMayExist_) {
var monitors = goog.debug.entryPointRegistry.monitors_;
for (var i = 0; i < monitors.length; i++) {
callback(goog.bind(monitors[i].wrap, monitors[i]));
}
}
};
/**
* Configures a monitor to wrap all entry points.
*
* Entry points that have already been registered are immediately wrapped by
* the monitor. When an entry point is registered in the future, it will also
* be wrapped by the monitor when it is registered.
*
* @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor.
*/
goog.debug.entryPointRegistry.monitorAll = function(monitor) {
'use strict';
goog.debug.entryPointRegistry.monitorsMayExist_ = true;
var transformer = goog.bind(monitor.wrap, monitor);
for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
goog.debug.entryPointRegistry.refList_[i](transformer);
}
goog.debug.entryPointRegistry.monitors_.push(monitor);
};
/**
* Try to unmonitor all the entry points that have already been registered. If
* an entry point is registered in the future, it will not be wrapped by the
* monitor when it is registered. Note that this may fail if the entry points
* have additional wrapping.
*
* @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap
* the entry points.
* @throws {Error} If the monitor is not the most recently configured monitor.
*/
goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) {
'use strict';
var monitors = goog.debug.entryPointRegistry.monitors_;
goog.asserts.assert(
monitor == monitors[monitors.length - 1],
'Only the most recent monitor can be unwrapped.');
var transformer = goog.bind(monitor.unwrap, monitor);
for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
goog.debug.entryPointRegistry.refList_[i](transformer);
}
monitors.length--;
};
+72
View File
@@ -0,0 +1,72 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Provides a base class for custom Error objects such that the
* stack is correctly maintained.
*
* You should never need to throw DebugError(msg) directly, Error(msg) is
* sufficient.
*/
goog.module('goog.debug.Error');
goog.module.declareLegacyNamespace();
/**
* Base class for custom error objects.
* @param {*=} msg The message associated with the error.
* @param {{
* message: (?|undefined),
* name: (?|undefined),
* lineNumber: (?|undefined),
* fileName: (?|undefined),
* stack: (?|undefined),
* cause: (?|undefined),
* }=} cause The original error object to chain with.
* @constructor
* @extends {Error}
*/
function DebugError(msg = undefined, cause = undefined) {
// Attempt to ensure there is a stack trace.
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DebugError);
} else {
const stack = new Error().stack;
if (stack) {
/** @override */
this.stack = stack;
}
}
if (msg) {
/** @override */
this.message = String(msg);
}
if (cause !== undefined) {
/** @type {?} */
this.cause = cause;
}
/**
* Whether to report this error to the server. Setting this to false will
* cause the error reporter to not report the error back to the server,
* which can be useful if the client knows that the error has already been
* logged on the server.
* @type {boolean}
*/
this.reportErrorToServer = true;
}
goog.inherits(DebugError, Error);
/** @override @type {string} */
DebugError.prototype.name = 'CustomError';
exports = DebugError;
+43
View File
@@ -0,0 +1,43 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Provides methods dealing with context on error objects.
*/
goog.provide('goog.debug.errorcontext');
/**
* Adds key-value context to the error.
* @param {!Error} err The error to add context to.
* @param {string} contextKey Key for the context to be added.
* @param {string} contextValue Value for the context to be added.
*/
goog.debug.errorcontext.addErrorContext = function(
err, contextKey, contextValue) {
'use strict';
if (!err[goog.debug.errorcontext.CONTEXT_KEY_]) {
err[goog.debug.errorcontext.CONTEXT_KEY_] = {};
}
err[goog.debug.errorcontext.CONTEXT_KEY_][contextKey] = contextValue;
};
/**
* @param {!Error} err The error to get context from.
* @return {!Object<string, string>} The context of the provided error.
*/
goog.debug.errorcontext.getErrorContext = function(err) {
'use strict';
return err[goog.debug.errorcontext.CONTEXT_KEY_] || {};
};
// TODO(user): convert this to a Symbol once goog.debug.ErrorReporter is
// able to use ES6.
/** @private @const {string} */
goog.debug.errorcontext.CONTEXT_KEY_ = '__closure__error__context__984382';
+364
View File
@@ -0,0 +1,364 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Error handling utilities.
*/
goog.provide('goog.debug.ErrorHandler');
goog.provide('goog.debug.ErrorHandler.ProtectedFunctionError');
goog.require('goog.Disposable');
goog.require('goog.asserts');
goog.require('goog.debug.EntryPointMonitor');
goog.require('goog.debug.Error');
/**
* The ErrorHandler can be used to to wrap functions with a try/catch
* statement. If an exception is thrown, the given error handler function will
* be called.
*
* When this object is disposed, it will stop handling exceptions and tracing.
* It will also try to restore window.setTimeout and window.setInterval
* if it wrapped them. Notice that in the general case, it is not technically
* possible to remove the wrapper, because functions have no knowledge of
* what they have been assigned to. So the app is responsible for other
* forms of unwrapping.
*
* @param {Function} handler Handler for exceptions.
* @constructor
* @extends {goog.Disposable}
* @implements {goog.debug.EntryPointMonitor}
*/
goog.debug.ErrorHandler = function(handler) {
'use strict';
goog.debug.ErrorHandler.base(this, 'constructor');
/**
* Handler for exceptions, which can do logging, reporting, etc.
* @type {Function}
* @private
*/
this.errorHandlerFn_ = handler;
/**
* Whether errors should be wrapped in
* goog.debug.ErrorHandler.ProtectedFunctionError before rethrowing.
* @type {boolean}
* @private
*/
this.wrapErrors_ = true; // TODO(malteubl) Change default.
/**
* Whether to add a prefix to all error messages. The prefix is
* goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX. This option
* only has an effect if this.wrapErrors_ is set to false.
* @type {boolean}
* @private
*/
this.prefixErrorMessages_ = false;
};
goog.inherits(goog.debug.ErrorHandler, goog.Disposable);
/** @override */
goog.debug.ErrorHandler.prototype.wrap = function(fn) {
'use strict';
return this.protectEntryPoint(goog.asserts.assertFunction(fn));
};
/** @override */
goog.debug.ErrorHandler.prototype.unwrap = function(fn) {
'use strict';
goog.asserts.assertFunction(fn);
return fn[this.getFunctionIndex_(false)] || fn;
};
/**
* Get the index for a function. Used for internal indexing.
* @param {boolean} wrapper True for the wrapper; false for the wrapped.
* @return {string} The index where we should store the function in its
* wrapper/wrapped function.
* @private
*/
goog.debug.ErrorHandler.prototype.getFunctionIndex_ = function(wrapper) {
'use strict';
return (wrapper ? '__wrapper_' : '__protected_') + goog.getUid(this) + '__';
};
/**
* Installs exception protection for an entry point function. When an exception
* is thrown from a protected function, a handler will be invoked to handle it.
*
* @param {Function} fn An entry point function to be protected.
* @return {!Function} A protected wrapper function that calls the entry point
* function.
*/
goog.debug.ErrorHandler.prototype.protectEntryPoint = function(fn) {
'use strict';
var protectedFnName = this.getFunctionIndex_(true);
if (!fn[protectedFnName]) {
var wrapper = fn[protectedFnName] = this.getProtectedFunction(fn);
wrapper[this.getFunctionIndex_(false)] = fn;
}
return fn[protectedFnName];
};
/**
* Helps {@link #protectEntryPoint} by actually creating the protected
* wrapper function, after {@link #protectEntryPoint} determines that one does
* not already exist for the given function. Can be overridden by subclasses
* that may want to implement different error handling, or add additional
* entry point hooks.
* @param {!Function} fn An entry point function to be protected.
* @return {!Function} protected wrapper function.
* @protected
*/
goog.debug.ErrorHandler.prototype.getProtectedFunction = function(fn) {
'use strict';
var that = this;
var googDebugErrorHandlerProtectedFunction = function() {
'use strict';
var self = /** @type {?} */ (this);
if (that.isDisposed()) {
return fn.apply(self, arguments);
}
try {
return fn.apply(self, arguments);
} catch (e) {
that.handleError_(e);
}
};
googDebugErrorHandlerProtectedFunction[this.getFunctionIndex_(false)] = fn;
return googDebugErrorHandlerProtectedFunction;
};
/**
* Internal error handler.
* @param {?} e The error string or an Error-like object.
* @private
*/
goog.debug.ErrorHandler.prototype.handleError_ = function(e) {
'use strict';
// Don't re-report errors that have already been handled by this code.
var MESSAGE_PREFIX =
goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX;
if ((e && typeof e === 'object' && typeof e.message === 'string' &&
e.message.indexOf(MESSAGE_PREFIX) == 0) ||
(typeof e === 'string' && e.indexOf(MESSAGE_PREFIX) == 0)) {
return;
}
this.errorHandlerFn_(e);
if (!this.wrapErrors_) {
// Add the prefix to the existing message.
if (this.prefixErrorMessages_) {
if (typeof e === 'object' && e && typeof e.message === 'string') {
/** @type {{message}} */ (e).message = MESSAGE_PREFIX + e.message;
} else {
e = MESSAGE_PREFIX + e;
}
}
if (goog.DEBUG) {
// Work around for https://code.google.com/p/v8/issues/detail?id=2625
// and https://code.google.com/p/chromium/issues/detail?id=237059
// Custom errors and errors with custom stack traces show the wrong
// stack trace
// If it has a stack and Error.captureStackTrace is supported (only
// supported in V8 as of May 2013) log the stack to the console.
if (e && typeof e.stack === 'string' && Error.captureStackTrace &&
goog.global['console']) {
goog.global['console']['error'](e.message, e.stack);
}
}
// Re-throw original error. This is great for debugging as it makes
// browser JS dev consoles show the correct error and stack trace.
throw e;
}
// Re-throw it since this may be expected by the caller.
throw new goog.debug.ErrorHandler.ProtectedFunctionError(e);
};
// TODO(mknichel): Allow these functions to take in the window to protect.
/**
* Installs exception protection for window.setTimeout to handle exceptions.
*/
goog.debug.ErrorHandler.prototype.protectWindowSetTimeout = function() {
'use strict';
this.protectWindowFunctionsHelper_('setTimeout');
};
/**
* Install exception protection for window.setInterval to handle exceptions.
*/
goog.debug.ErrorHandler.prototype.protectWindowSetInterval = function() {
'use strict';
this.protectWindowFunctionsHelper_('setInterval');
};
/**
* Install an unhandledrejection event listener that reports rejected promises.
* Note: this will only work with Chrome 49+ and friends, but so far is the only
* way to report uncaught errors in aysnc/await functions.
* @param {!Window=} win the window to instrument, defaults to current window
*/
goog.debug.ErrorHandler.prototype.catchUnhandledRejections = function(win) {
'use strict';
win = win || goog.global['window'];
if ('onunhandledrejection' in win) {
win.onunhandledrejection = (event) => {
// event.reason contains the rejection reason. When an Error is
// thrown, this is the Error object. If it is undefined, create a new
// error object.
const e =
event && event.reason ? event.reason : new Error('uncaught error');
this.handleError_(e);
};
}
};
/**
* Install exception protection for window.requestAnimationFrame to handle
* exceptions.
*/
goog.debug.ErrorHandler.prototype.protectWindowRequestAnimationFrame =
function() {
'use strict';
var win = goog.global['window'];
var fnNames = [
'requestAnimationFrame', 'mozRequestAnimationFrame', 'webkitAnimationFrame',
'msRequestAnimationFrame'
];
for (var i = 0; i < fnNames.length; i++) {
var fnName = fnNames[i];
if (fnNames[i] in win) {
this.protectWindowFunctionsHelper_(fnName);
}
}
};
/**
* Helper function for protecting a function that causes a function to be
* asynchronously called, for example setTimeout or requestAnimationFrame.
* @param {string} fnName The name of the function to protect.
* @private
*/
goog.debug.ErrorHandler.prototype.protectWindowFunctionsHelper_ = function(
fnName) {
'use strict';
var win = goog.global['window'];
var originalFn = win[fnName];
var that = this;
win[fnName] = function(fn, time) {
'use strict';
// Don't try to protect strings. In theory, we could try to globalEval
// the string, but this seems to lead to permission errors on IE6.
if (typeof fn === 'string') {
fn = goog.partial(goog.globalEval, fn);
}
arguments[0] = fn = that.protectEntryPoint(fn);
// IE doesn't support .call for setInterval/setTimeout, but it
// also doesn't care what "this" is, so we can just call the
// original function directly
if (originalFn.apply) {
return originalFn.apply(/** @type {?} */ (this), arguments);
} else {
var callback = fn;
if (arguments.length > 2) {
var args = Array.prototype.slice.call(arguments, 2);
callback = function() {
'use strict';
fn.apply(/** @type {?} */ (this), args);
};
}
return originalFn(callback, time);
}
};
win[fnName][this.getFunctionIndex_(false)] = originalFn;
};
/**
* Set whether to wrap errors that occur in protected functions in a
* goog.debug.ErrorHandler.ProtectedFunctionError.
* @param {boolean} wrapErrors Whether to wrap errors.
*/
goog.debug.ErrorHandler.prototype.setWrapErrors = function(wrapErrors) {
'use strict';
this.wrapErrors_ = wrapErrors;
};
/**
* Set whether to add a prefix to all error messages that occur in protected
* functions.
* @param {boolean} prefixErrorMessages Whether to add a prefix to error
* messages.
*/
goog.debug.ErrorHandler.prototype.setPrefixErrorMessages = function(
prefixErrorMessages) {
'use strict';
this.prefixErrorMessages_ = prefixErrorMessages;
};
/** @override */
goog.debug.ErrorHandler.prototype.disposeInternal = function() {
'use strict';
// Try to unwrap window.setTimeout and window.setInterval.
var win = goog.global['window'];
win.setTimeout = this.unwrap(win.setTimeout);
win.setInterval = this.unwrap(win.setInterval);
goog.debug.ErrorHandler.base(this, 'disposeInternal');
};
/**
* Error thrown to the caller of a protected entry point if the entry point
* throws an error.
* @param {*} cause The error thrown by the entry point.
* @constructor
* @extends {goog.debug.Error}
* @final
*/
goog.debug.ErrorHandler.ProtectedFunctionError = function(cause) {
'use strict';
/** @suppress {missingProperties} message may not be defined. */
var message = goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX +
(cause && cause.message ? String(cause.message) : String(cause));
goog.debug.ErrorHandler.ProtectedFunctionError.base(
this, 'constructor', message, /** @type {?} */ (cause));
/** @suppress {missingProperties} stack may not be defined. */
var stack = cause && cause.stack;
if (stack && typeof stack === 'string') {
this.stack = /** @type {string} */ (stack);
}
};
goog.inherits(goog.debug.ErrorHandler.ProtectedFunctionError, goog.debug.Error);
/**
* Text to prefix the message with.
* @type {string}
*/
goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX =
'Error in protected function: ';
+285
View File
@@ -0,0 +1,285 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Implements the disposable interface.
*/
goog.provide('goog.Disposable');
goog.require('goog.disposable.IDisposable');
goog.require('goog.dispose');
/**
* TODO(user): Remove this require.
* @suppress {extraRequire}
*/
goog.require('goog.disposeAll');
/**
* Class that provides the basic implementation for disposable objects. If your
* class holds references or resources that can't be collected by standard GC,
* it should extend this class or implement the disposable interface (defined
* in goog.disposable.IDisposable). See description of
* goog.disposable.IDisposable for examples of cleanup.
* @constructor
* @implements {goog.disposable.IDisposable}
*/
goog.Disposable = function() {
'use strict';
/**
* If monitoring the goog.Disposable instances is enabled, stores the creation
* stack trace of the Disposable instance.
* @type {string|undefined}
*/
this.creationStack;
if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
if (goog.Disposable.INCLUDE_STACK_ON_CREATION) {
this.creationStack = new Error().stack;
}
goog.Disposable.instances_[goog.getUid(this)] = this;
}
// Support sealing
this.disposed_ = this.disposed_;
this.onDisposeCallbacks_ = this.onDisposeCallbacks_;
};
/**
* @enum {number} Different monitoring modes for Disposable.
*/
goog.Disposable.MonitoringMode = {
/**
* No monitoring.
*/
OFF: 0,
/**
* Creating and disposing the goog.Disposable instances is monitored. All
* disposable objects need to call the `goog.Disposable` base
* constructor. The PERMANENT mode must be switched on before creating any
* goog.Disposable instances.
*/
PERMANENT: 1,
/**
* INTERACTIVE mode can be switched on and off on the fly without producing
* errors. It also doesn't warn if the disposable objects don't call the
* `goog.Disposable` base constructor.
*/
INTERACTIVE: 2
};
/**
* @define {number} The monitoring mode of the goog.Disposable
* instances. Default is OFF. Switching on the monitoring is only
* recommended for debugging because it has a significant impact on
* performance and memory usage. If switched off, the monitoring code
* compiles down to 0 bytes.
*/
goog.Disposable.MONITORING_MODE =
goog.define('goog.Disposable.MONITORING_MODE', 0);
/**
* @define {boolean} Whether to attach creation stack to each created disposable
* instance; This is only relevant for when MonitoringMode != OFF.
*/
goog.Disposable.INCLUDE_STACK_ON_CREATION =
goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true);
/**
* Maps the unique ID of every undisposed `goog.Disposable` object to
* the object itself.
* @type {!Object<number, !goog.Disposable>}
* @private
*/
goog.Disposable.instances_ = {};
/**
* @return {!Array<!goog.Disposable>} All `goog.Disposable` objects that
* haven't been disposed of.
*/
goog.Disposable.getUndisposedObjects = function() {
'use strict';
var ret = [];
for (var id in goog.Disposable.instances_) {
if (goog.Disposable.instances_.hasOwnProperty(id)) {
ret.push(goog.Disposable.instances_[Number(id)]);
}
}
return ret;
};
/**
* Clears the registry of undisposed objects but doesn't dispose of them.
*/
goog.Disposable.clearUndisposedObjects = function() {
'use strict';
goog.Disposable.instances_ = {};
};
/**
* Whether the object has been disposed of.
* @type {boolean}
* @private
*/
goog.Disposable.prototype.disposed_ = false;
/**
* Callbacks to invoke when this object is disposed.
* @type {Array<!Function>}
* @private
*/
goog.Disposable.prototype.onDisposeCallbacks_;
/**
* @return {boolean} Whether the object has been disposed of.
* @override
*/
goog.Disposable.prototype.isDisposed = function() {
'use strict';
return this.disposed_;
};
/**
* @return {boolean} Whether the object has been disposed of.
* @deprecated Use {@link #isDisposed} instead.
*/
goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed;
/**
* Disposes of the object. If the object hasn't already been disposed of, calls
* {@link #disposeInternal}. Classes that extend `goog.Disposable` should
* override {@link #disposeInternal} in order to cleanup references, resources
* and other disposable objects. Reentrant.
*
* @return {void} Nothing.
* @override
*/
goog.Disposable.prototype.dispose = function() {
'use strict';
if (!this.disposed_) {
// Set disposed_ to true first, in case during the chain of disposal this
// gets disposed recursively.
this.disposed_ = true;
this.disposeInternal();
if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
var uid = goog.getUid(this);
if (goog.Disposable.MONITORING_MODE ==
goog.Disposable.MonitoringMode.PERMANENT &&
!goog.Disposable.instances_.hasOwnProperty(uid)) {
throw new Error(
this + ' did not call the goog.Disposable base ' +
'constructor or was disposed of after a clearUndisposedObjects ' +
'call');
}
if (goog.Disposable.MONITORING_MODE !=
goog.Disposable.MonitoringMode.OFF &&
this.onDisposeCallbacks_ && this.onDisposeCallbacks_.length > 0) {
throw new Error(
this + ' did not empty its onDisposeCallbacks queue. This ' +
'probably means it overrode dispose() or disposeInternal() ' +
'without calling the superclass\' method.');
}
delete goog.Disposable.instances_[uid];
}
}
};
/**
* Associates a disposable object with this object so that they will be disposed
* together.
* @param {goog.disposable.IDisposable} disposable that will be disposed when
* this object is disposed.
*/
goog.Disposable.prototype.registerDisposable = function(disposable) {
'use strict';
this.addOnDisposeCallback(goog.partial(goog.dispose, disposable));
};
/**
* Invokes a callback function when this object is disposed. Callbacks are
* invoked in the order in which they were added. If a callback is added to
* an already disposed Disposable, it will be called immediately.
* @param {function(this:T):?} callback The callback function.
* @param {T=} opt_scope An optional scope to call the callback in.
* @template T
*/
goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) {
'use strict';
if (this.disposed_) {
opt_scope !== undefined ? callback.call(opt_scope) : callback();
return;
}
if (!this.onDisposeCallbacks_) {
this.onDisposeCallbacks_ = [];
}
this.onDisposeCallbacks_.push(
opt_scope !== undefined ? goog.bind(callback, opt_scope) : callback);
};
/**
* Performs appropriate cleanup. See description of goog.disposable.IDisposable
* for examples. Classes that extend `goog.Disposable` should override this
* method. Not reentrant. To avoid calling it twice, it must only be called from
* the subclass' `disposeInternal` method. Everywhere else the public `dispose`
* method must be used. For example:
*
* <pre>
* mypackage.MyClass = function() {
* mypackage.MyClass.base(this, 'constructor');
* // Constructor logic specific to MyClass.
* ...
* };
* goog.inherits(mypackage.MyClass, goog.Disposable);
*
* mypackage.MyClass.prototype.disposeInternal = function() {
* // Dispose logic specific to MyClass.
* ...
* // Call superclass's disposeInternal at the end of the subclass's, like
* // in C++, to avoid hard-to-catch issues.
* mypackage.MyClass.base(this, 'disposeInternal');
* };
* </pre>
*
* @protected
*/
goog.Disposable.prototype.disposeInternal = function() {
'use strict';
if (this.onDisposeCallbacks_) {
while (this.onDisposeCallbacks_.length) {
this.onDisposeCallbacks_.shift()();
}
}
};
/**
* Returns True if we can verify the object is disposed.
* Calls `isDisposed` on the argument if it supports it. If obj
* is not an object with an isDisposed() method, return false.
* @param {*} obj The object to investigate.
* @return {boolean} True if we can verify the object is disposed.
*/
goog.Disposable.isDisposed = function(obj) {
'use strict';
if (obj && typeof obj.isDisposed == 'function') {
return obj.isDisposed();
}
return false;
};
+25
View File
@@ -0,0 +1,25 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview The dispose method is used to clean up references and
* resources.
*/
goog.module('goog.dispose');
goog.module.declareLegacyNamespace();
/**
* Calls `dispose` on the argument if it supports it. If obj is not an
* object with a dispose() method, this is a no-op.
* @param {*} obj The object to dispose of.
*/
function dispose(obj) {
if (obj && typeof obj.dispose == 'function') {
obj.dispose();
}
}
exports = dispose;
+34
View File
@@ -0,0 +1,34 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview The disposeAll method is used to clean up references and
* resources.
*/
goog.module('goog.disposeAll');
goog.module.declareLegacyNamespace();
const dispose = goog.require('goog.dispose');
/**
* Calls `dispose` on each member of the list that supports it. (If the
* member is an ArrayLike, then `goog.disposeAll()` will be called
* recursively on each of its members.) If the member is not an object with a
* `dispose()` method, then it is ignored.
* @param {...*} var_args The list.
*/
function disposeAll(var_args) {
for (let i = 0, len = arguments.length; i < len; ++i) {
const disposable = arguments[i];
if (goog.isArrayLike(disposable)) {
disposeAll.apply(null, disposable);
} else {
dispose(disposable);
}
}
}
exports = disposeAll;
+48
View File
@@ -0,0 +1,48 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Definition of the disposable interface. A disposable object
* has a dispose method to to clean up references and resources.
*/
goog.provide('goog.disposable.IDisposable');
/**
* Interface for a disposable object. If a instance requires cleanup, it should
* implement this interface (it may subclass goog.Disposable).
*
* Examples of cleanup that can be done in `dispose` method:
* 1. Remove event listeners.
* 2. Cancel timers (setTimeout, setInterval, goog.Timer).
* 3. Call `dispose` on other disposable objects hold by current object.
* 4. Close connections (e.g. WebSockets).
*
* Note that it's not required to delete properties (e.g. DOM nodes) or set them
* to null as garbage collector will collect them assuming that references to
* current object will be lost after it is disposed.
*
* See also http://go/mdn/JavaScript/Memory_Management.
*
* @record
*/
goog.disposable.IDisposable = function() {};
/**
* Disposes of the object and its resources.
* @return {void} Nothing.
*/
goog.disposable.IDisposable.prototype.dispose = goog.abstractMethod;
/**
* @return {boolean} Whether the object has been disposed of.
*/
goog.disposable.IDisposable.prototype.isDisposed = goog.abstractMethod;
+398
View File
@@ -0,0 +1,398 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('goog.dom.asserts');
goog.require('goog.asserts');
/**
* @fileoverview Custom assertions to ensure that an element has the appropriate
* type.
*
* Using a goog.dom.safe wrapper on an object on the incorrect type (via an
* incorrect static type cast) can result in security bugs: For instance,
* g.d.s.setAnchorHref ensures that the URL assigned to the .href attribute
* satisfies the SafeUrl contract, i.e., is safe to dereference as a hyperlink.
* However, the value assigned to a HTMLLinkElement's .href property requires
* the stronger TrustedResourceUrl contract, since it can refer to a stylesheet.
* Thus, using g.d.s.setAnchorHref on an (incorrectly statically typed) object
* of type HTMLLinkElement can result in a security vulnerability.
* Assertions of the correct run-time type help prevent such incorrect use.
*
* In some cases, code using the DOM API is tested using mock objects (e.g., a
* plain object such as {'href': url} instead of an actual Location object).
* To allow such mocking, the assertions permit objects of types that are not
* relevant DOM API objects at all (for instance, not Element or Location).
*
* Note that instanceof checks don't work straightforwardly in older versions of
* IE, or across frames (see,
* http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object,
* http://stackoverflow.com/questions/26248599/instanceof-htmlelement-in-iframe-is-not-element-or-object).
*
* Hence, these assertions may pass vacuously in such scenarios. The resulting
* risk of security bugs is limited by the following factors:
* - A bug can only arise in scenarios involving incorrect static typing (the
* wrapper methods are statically typed to demand objects of the appropriate,
* precise type).
* - Typically, code is tested and exercised in multiple browsers.
*/
/**
* Asserts that a given object is a Location.
*
* To permit this assertion to pass in the context of tests where DOM APIs might
* be mocked, also accepts any other type except for subtypes of {!Element}.
* This is to ensure that, for instance, HTMLLinkElement is not being used in
* place of a Location, since this could result in security bugs due to stronger
* contracts required for assignments to the href property of the latter.
*
* @param {?Object} o The object whose type to assert.
* @return {!Location}
*/
goog.dom.asserts.assertIsLocation = function(o) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS) {
var win = goog.dom.asserts.getWindow_(o);
if (win) {
if (!o || (!(o instanceof win.Location) && o instanceof win.Element)) {
goog.asserts.fail(
'Argument is not a Location (or a non-Element mock); got: %s',
goog.dom.asserts.debugStringForType_(o));
}
}
}
return /** @type {!Location} */ (o);
};
/**
* Asserts that a given object is either the given subtype of Element
* or a non-Element, non-Location Mock.
*
* To permit this assertion to pass in the context of tests where DOM
* APIs might be mocked, also accepts any other type except for
* subtypes of {!Element}. This is to ensure that, for instance,
* HTMLScriptElement is not being used in place of a HTMLImageElement,
* since this could result in security bugs due to stronger contracts
* required for assignments to the src property of the latter.
*
* The DOM type is looked up in the window the object belongs to. In
* some contexts, this might not be possible (e.g. when running tests
* outside a browser, cross-domain lookup). In this case, the
* assertions are skipped.
*
* @param {?Object} o The object whose type to assert.
* @param {string} typename The name of the DOM type.
* @return {!Element} The object.
* @private
*/
// TODO(bangert): Make an analog of goog.dom.TagName to correctly handle casts?
goog.dom.asserts.assertIsElementType_ = function(o, typename) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS) {
var win = goog.dom.asserts.getWindow_(o);
if (win && typeof win[typename] != 'undefined') {
if (!o ||
(!(o instanceof win[typename]) &&
(o instanceof win.Location || o instanceof win.Element))) {
goog.asserts.fail(
'Argument is not a %s (or a non-Element, non-Location mock); ' +
'got: %s',
typename, goog.dom.asserts.debugStringForType_(o));
}
}
}
return /** @type {!Element} */ (o);
};
/**
* Asserts that a given object is a HTMLAnchorElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not of type Location nor a subtype
* of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLAnchorElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlAnchorElement instead.
*/
goog.dom.asserts.assertIsHTMLAnchorElement = function(o) {
'use strict';
return /** @type {!HTMLAnchorElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLAnchorElement'));
};
/**
* Asserts that a given object is a HTMLButtonElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLButtonElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlButtonElement instead.
*/
goog.dom.asserts.assertIsHTMLButtonElement = function(o) {
'use strict';
return /** @type {!HTMLButtonElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLButtonElement'));
};
/**
* Asserts that a given object is a HTMLLinkElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLLinkElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlLinkElement instead.
*/
goog.dom.asserts.assertIsHTMLLinkElement = function(o) {
'use strict';
return /** @type {!HTMLLinkElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLLinkElement'));
};
/**
* Asserts that a given object is a HTMLImageElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLImageElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlImageElement instead.
*/
goog.dom.asserts.assertIsHTMLImageElement = function(o) {
'use strict';
return /** @type {!HTMLImageElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLImageElement'));
};
/**
* Asserts that a given object is a HTMLAudioElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLAudioElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlAudioElement instead.
*/
goog.dom.asserts.assertIsHTMLAudioElement = function(o) {
'use strict';
return /** @type {!HTMLAudioElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLAudioElement'));
};
/**
* Asserts that a given object is a HTMLVideoElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLVideoElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlVideoElement instead.
*/
goog.dom.asserts.assertIsHTMLVideoElement = function(o) {
'use strict';
return /** @type {!HTMLVideoElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLVideoElement'));
};
/**
* Asserts that a given object is a HTMLInputElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLInputElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlInputElement instead.
*/
goog.dom.asserts.assertIsHTMLInputElement = function(o) {
'use strict';
return /** @type {!HTMLInputElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLInputElement'));
};
/**
* Asserts that a given object is a HTMLTextAreaElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLTextAreaElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlTextAreaElement instead.
*/
goog.dom.asserts.assertIsHTMLTextAreaElement = function(o) {
'use strict';
return /** @type {!HTMLTextAreaElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLTextAreaElement'));
};
/**
* Asserts that a given object is a HTMLCanvasElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLCanvasElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlCanvasElement instead.
*/
goog.dom.asserts.assertIsHTMLCanvasElement = function(o) {
'use strict';
return /** @type {!HTMLCanvasElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLCanvasElement'));
};
/**
* Asserts that a given object is a HTMLEmbedElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLEmbedElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlEmbedElement instead.
*/
goog.dom.asserts.assertIsHTMLEmbedElement = function(o) {
'use strict';
return /** @type {!HTMLEmbedElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLEmbedElement'));
};
/**
* Asserts that a given object is a HTMLFormElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLFormElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlFormElement instead.
*/
goog.dom.asserts.assertIsHTMLFormElement = function(o) {
'use strict';
return /** @type {!HTMLFormElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLFormElement'));
};
/**
* Asserts that a given object is a HTMLFrameElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLFrameElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlFrameElement instead.
*/
goog.dom.asserts.assertIsHTMLFrameElement = function(o) {
'use strict';
return /** @type {!HTMLFrameElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLFrameElement'));
};
/**
* Asserts that a given object is a HTMLIFrameElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLIFrameElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlIFrameElement instead.
*/
goog.dom.asserts.assertIsHTMLIFrameElement = function(o) {
'use strict';
return /** @type {!HTMLIFrameElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLIFrameElement'));
};
/**
* Asserts that a given object is a HTMLObjectElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLObjectElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlObjectElement instead.
*/
goog.dom.asserts.assertIsHTMLObjectElement = function(o) {
'use strict';
return /** @type {!HTMLObjectElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLObjectElement'));
};
/**
* Asserts that a given object is a HTMLScriptElement.
*
* To permit this assertion to pass in the context of tests where elements might
* be mocked, also accepts objects that are not a subtype of Element.
*
* @param {?Object} o The object whose type to assert.
* @return {!HTMLScriptElement}
* @deprecated Use goog.asserts.dom.assertIsHtmlScriptElement instead.
*/
goog.dom.asserts.assertIsHTMLScriptElement = function(o) {
'use strict';
return /** @type {!HTMLScriptElement} */ (
goog.dom.asserts.assertIsElementType_(o, 'HTMLScriptElement'));
};
/**
* Returns a string representation of a value's type.
*
* @param {*} value An object, or primitive.
* @return {string} The best display name for the value.
* @private
*/
goog.dom.asserts.debugStringForType_ = function(value) {
'use strict';
if (goog.isObject(value)) {
try {
return /** @type {string|undefined} */ (value.constructor.displayName) ||
value.constructor.name || Object.prototype.toString.call(value);
} catch (e) {
return '<object could not be stringified>';
}
} else {
return value === undefined ? 'undefined' :
value === null ? 'null' : typeof value;
}
};
/**
* Gets window of element.
* @param {?Object} o
* @return {?Window}
* @private
* @suppress {strictMissingProperties} ownerDocument not defined on Object
*/
goog.dom.asserts.getWindow_ = function(o) {
'use strict';
try {
var doc = o && o.ownerDocument;
// This can throw “Blocked a frame with origin "chrome-extension://..." from
// accessing a cross-origin frame” in Chrome extension.
var win =
doc && /** @type {?Window} */ (doc.defaultView || doc.parentWindow);
win = win || /** @type {!Window} */ (goog.global);
// This can throw “Permission denied to access property "Element" on
// cross-origin object”.
if (win.Element && win.Location) {
return win;
}
} catch (ex) {
}
return null;
};
+94
View File
@@ -0,0 +1,94 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Browser capability checks for the dom package.
*/
goog.provide('goog.dom.BrowserFeature');
goog.require('goog.userAgent');
/**
* @define {boolean} Whether we know at compile time that the browser doesn't
* support OffscreenCanvas.
*/
goog.dom.BrowserFeature.ASSUME_NO_OFFSCREEN_CANVAS =
goog.define('goog.dom.ASSUME_NO_OFFSCREEN_CANVAS', false);
/**
* @define {boolean} Whether we know at compile time that the browser supports
* all OffscreenCanvas contexts.
*/
// TODO(user): Eventually this should default to "FEATURESET_YEAR >= 202X".
goog.dom.BrowserFeature.ASSUME_OFFSCREEN_CANVAS =
goog.define('goog.dom.ASSUME_OFFSCREEN_CANVAS', false);
/**
* Detects if a particular OffscreenCanvas context is supported.
* @param {string} contextName name of the context to test.
* @return {boolean} Whether the browser supports this OffscreenCanvas context.
* @private
*/
goog.dom.BrowserFeature.detectOffscreenCanvas_ = function(contextName) {
'use strict';
// This code only gets removed because we forced @nosideeffects on
// the functions. See: b/138802376
try {
return Boolean(new self.OffscreenCanvas(0, 0).getContext(contextName));
} catch (ex) {
}
return false;
};
/**
* Whether the browser supports OffscreenCanvas 2D context.
* @const {boolean}
*/
goog.dom.BrowserFeature.OFFSCREEN_CANVAS_2D =
!goog.dom.BrowserFeature.ASSUME_NO_OFFSCREEN_CANVAS &&
(goog.dom.BrowserFeature.ASSUME_OFFSCREEN_CANVAS ||
goog.dom.BrowserFeature.detectOffscreenCanvas_('2d'));
/**
* Whether attributes 'name' and 'type' can be added to an element after it's
* created. False in Internet Explorer prior to version 9.
* @const {boolean}
*/
goog.dom.BrowserFeature.CAN_ADD_NAME_OR_TYPE_ATTRIBUTES = true;
/**
* Whether we can use element.children to access an element's Element
* children. Available since Gecko 1.9.1, IE 9. (IE<9 also includes comment
* nodes in the collection.)
* @const {boolean}
*/
goog.dom.BrowserFeature.CAN_USE_CHILDREN_ATTRIBUTE = true;
/**
* Opera, Safari 3, and Internet Explorer 9 all support innerText but they
* include text nodes in script and style tags. Not document-mode-dependent.
* @const {boolean}
*/
goog.dom.BrowserFeature.CAN_USE_INNER_TEXT = false;
/**
* MSIE, Opera, and Safari>=4 support element.parentElement to access an
* element's parent if it is an Element.
* @const {boolean}
*/
goog.dom.BrowserFeature.CAN_USE_PARENT_ELEMENT_PROPERTY =
goog.userAgent.IE || goog.userAgent.WEBKIT;
/**
* Whether NoScope elements need a scoped element written before them in
* innerHTML.
* MSDN: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx#1
* @const {boolean}
*/
goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT = goog.userAgent.IE;
+3499
View File
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('goog.dom.HtmlElement');
/**
* This subclass of HTMLElement is used when only a HTMLElement is possible and
* not any of its subclasses. Normally, a type can refer to an instance of
* itself or an instance of any subtype. More concretely, if HTMLElement is used
* then the compiler must assume that it might still be e.g. HTMLScriptElement.
* With this, the type check knows that it couldn't be any special element.
*
* @constructor
* @extends {HTMLElement}
*/
goog.dom.HtmlElement = function() {};
+56
View File
@@ -0,0 +1,56 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Defines the goog.dom.InputType enum. This enumerates all
* input element types (for INPUT, BUTTON, SELECT and TEXTAREA elements) in
* either the W3C HTML 4.01 index of elements or the HTML5 draft specification.
*
* References:
* http://www.w3.org/TR/html401/sgml/dtd.html#InputType
* http://www.w3.org/TR/html-markup/input.html#input
* https://html.spec.whatwg.org/multipage/forms.html#dom-input-type
* https://html.spec.whatwg.org/multipage/forms.html#dom-button-type
* https://html.spec.whatwg.org/multipage/forms.html#dom-select-type
* https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-type
*/
goog.provide('goog.dom.InputType');
/**
* Enum of all input types (for INPUT, BUTTON, SELECT and TEXTAREA elements)
* specified by the W3C HTML4.01 and HTML5 specifications.
* @enum {string}
*/
goog.dom.InputType = {
BUTTON: 'button',
CHECKBOX: 'checkbox',
COLOR: 'color',
DATE: 'date',
DATETIME: 'datetime',
DATETIME_LOCAL: 'datetime-local',
EMAIL: 'email',
FILE: 'file',
HIDDEN: 'hidden',
IMAGE: 'image',
MENU: 'menu',
MONTH: 'month',
NUMBER: 'number',
PASSWORD: 'password',
RADIO: 'radio',
RANGE: 'range',
RESET: 'reset',
SEARCH: 'search',
SELECT_MULTIPLE: 'select-multiple',
SELECT_ONE: 'select-one',
SUBMIT: 'submit',
TEL: 'tel',
TEXT: 'text',
TEXTAREA: 'textarea',
TIME: 'time',
URL: 'url',
WEEK: 'week'
};
+40
View File
@@ -0,0 +1,40 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Definition of goog.dom.NodeType.
*/
goog.provide('goog.dom.NodeType');
/**
* Constants for the nodeType attribute in the Node interface.
*
* These constants match those specified in the Node interface. These are
* usually present on the Node object in recent browsers, but not in older
* browsers (specifically, early IEs) and thus are given here.
*
* In some browsers (early IEs), these are not defined on the Node object,
* so they are provided here.
*
* See http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247
* @enum {number}
*/
goog.dom.NodeType = {
ELEMENT: 1,
ATTRIBUTE: 2,
TEXT: 3,
CDATA_SECTION: 4,
ENTITY_REFERENCE: 5,
ENTITY: 6,
PROCESSING_INSTRUCTION: 7,
COMMENT: 8,
DOCUMENT: 9,
DOCUMENT_TYPE: 10,
DOCUMENT_FRAGMENT: 11,
NOTATION: 12
};
+941
View File
@@ -0,0 +1,941 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Type-safe wrappers for unsafe DOM APIs.
*
* This file provides type-safe wrappers for DOM APIs that can result in
* cross-site scripting (XSS) vulnerabilities, if the API is supplied with
* untrusted (attacker-controlled) input. Instead of plain strings, the type
* safe wrappers consume values of types from the goog.html package whose
* contract promises that values are safe to use in the corresponding context.
*
* Hence, a program that exclusively uses the wrappers in this file (i.e., whose
* only reference to security-sensitive raw DOM APIs are in this file) is
* guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo
* correctness of code that produces values of the respective goog.html types,
* and absent code that violates type safety).
*
* For example, assigning to an element's .innerHTML property a string that is
* derived (even partially) from untrusted input typically results in an XSS
* vulnerability. The type-safe wrapper goog.dom.safe.setInnerHtml consumes a
* value of type goog.html.SafeHtml, whose contract states that using its values
* in a HTML context will not result in XSS. Hence a program that is free of
* direct assignments to any element's innerHTML property (with the exception of
* the assignment to .innerHTML in this file) is guaranteed to be free of XSS
* due to assignment of untrusted strings to the innerHTML property.
*/
goog.provide('goog.dom.safe');
goog.provide('goog.dom.safe.InsertAdjacentHtmlPosition');
goog.require('goog.asserts');
goog.require('goog.dom.asserts');
goog.require('goog.functions');
goog.require('goog.html.SafeHtml');
goog.require('goog.html.SafeScript');
goog.require('goog.html.SafeStyle');
goog.require('goog.html.SafeUrl');
goog.require('goog.html.TrustedResourceUrl');
goog.require('goog.html.uncheckedconversions');
goog.require('goog.string.Const');
goog.require('goog.string.internal');
/** @enum {string} */
goog.dom.safe.InsertAdjacentHtmlPosition = {
AFTERBEGIN: 'afterbegin',
AFTEREND: 'afterend',
BEFOREBEGIN: 'beforebegin',
BEFOREEND: 'beforeend'
};
/**
* Inserts known-safe HTML into a Node, at the specified position.
* @param {!Node} node The node on which to call insertAdjacentHTML.
* @param {!goog.dom.safe.InsertAdjacentHtmlPosition} position Position where
* to insert the HTML.
* @param {!goog.html.SafeHtml} html The known-safe HTML to insert.
*/
goog.dom.safe.insertAdjacentHtml = function(node, position, html) {
'use strict';
node.insertAdjacentHTML(position, goog.html.SafeHtml.unwrapTrustedHTML(html));
};
/**
* Tags not allowed in goog.dom.safe.setInnerHtml.
* @private @const {!Object<string, boolean>}
*/
goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_ = {
'MATH': true,
'SCRIPT': true,
'STYLE': true,
'SVG': true,
'TEMPLATE': true
};
/**
* Whether assigning to innerHTML results in a non-spec-compliant clean-up. Used
* to define goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse.
*
* <p>As mentioned in https://stackoverflow.com/questions/28741528, re-rendering
* an element in IE by setting innerHTML causes IE to recursively disconnect all
* parent/children connections that were in the previous contents of the
* element. Unfortunately, this can unexpectedly result in confusing cases where
* a function is run (typically asynchronously) on element that has since
* disconnected from the DOM but assumes the presence of its children. A simple
* workaround is to remove all children first. Testing on IE11 via
* https://jsperf.com/innerhtml-vs-removechild/239, removeChild seems to be
* ~10x faster than innerHTML='' for a large number of children (perhaps due
* to the latter's recursive behavior), implying that this workaround would
* not hurt performance and might actually improve it.
* @return {boolean}
* @private
*/
goog.dom.safe.isInnerHtmlCleanupRecursive_ =
goog.functions.cacheReturnValue(function() {
'use strict';
// `document` missing in some test frameworks.
if (goog.DEBUG && typeof document === 'undefined') {
return false;
}
// Create 3 nested <div>s without using innerHTML.
// We're not chaining the appendChilds in one call, as this breaks
// in a DocumentFragment.
var div = document.createElement('div');
var childDiv = document.createElement('div');
childDiv.appendChild(document.createElement('div'));
div.appendChild(childDiv);
// `firstChild` is null in Google Js Test.
if (goog.DEBUG && !div.firstChild) {
return false;
}
var innerChild = div.firstChild.firstChild;
div.innerHTML =
goog.html.SafeHtml.unwrapTrustedHTML(goog.html.SafeHtml.EMPTY);
return !innerChild.parentElement;
});
/**
* Assigns HTML to an element's innerHTML property. Helper to use only here and
* in soy.js.
* @param {?Element|?ShadowRoot} elem The element whose innerHTML is to be
* assigned to.
* @param {!goog.html.SafeHtml} html
*/
goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse = function(elem, html) {
'use strict';
// See comment above goog.dom.safe.isInnerHtmlCleanupRecursive_.
if (goog.dom.safe.isInnerHtmlCleanupRecursive_()) {
while (elem.lastChild) {
elem.removeChild(elem.lastChild);
}
}
elem.innerHTML = goog.html.SafeHtml.unwrapTrustedHTML(html);
};
/**
* Assigns known-safe HTML to an element's innerHTML property.
* @param {!Element|!ShadowRoot} elem The element whose innerHTML is to be
* assigned to.
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
* @throws {Error} If called with one of these tags: math, script, style, svg,
* template.
*/
goog.dom.safe.setInnerHtml = function(elem, html) {
'use strict';
if (goog.asserts.ENABLE_ASSERTS && elem.tagName) {
var tagName = elem.tagName.toUpperCase();
if (goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_[tagName]) {
throw new Error(
'goog.dom.safe.setInnerHtml cannot be used to set content of ' +
elem.tagName + '.');
}
}
goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse(elem, html);
};
/**
* Assigns constant HTML to an element's innerHTML property.
* @param {!Element} element The element whose innerHTML is to be assigned to.
* @param {!goog.string.Const} constHtml The known-safe HTML to assign.
* @throws {!Error} If called with one of these tags: math, script, style, svg,
* template.
*/
goog.dom.safe.setInnerHtmlFromConstant = function(element, constHtml) {
'use strict';
goog.dom.safe.setInnerHtml(
element,
goog.html.uncheckedconversions
.safeHtmlFromStringKnownToSatisfyTypeContract(
goog.string.Const.from('Constant HTML to be immediatelly used.'),
goog.string.Const.unwrap(constHtml)));
};
/**
* Assigns known-safe HTML to an element's outerHTML property.
* @param {!Element} elem The element whose outerHTML is to be assigned to.
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
*/
goog.dom.safe.setOuterHtml = function(elem, html) {
'use strict';
elem.outerHTML = goog.html.SafeHtml.unwrapTrustedHTML(html);
};
/**
* Safely assigns a URL a form element's action property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* form's action property. If url is of type string however, it is first
* sanitized using goog.html.SafeUrl.sanitize.
*
* Example usage:
* goog.dom.safe.setFormElementAction(formEl, url);
* which is a safe alternative to
* formEl.action = url;
* The latter can result in XSS vulnerabilities if url is a
* user-/attacker-controlled value.
*
* @param {!Element} form The form element whose action property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setFormElementAction = function(form, url) {
'use strict';
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
goog.dom.asserts.assertIsHTMLFormElement(form).action =
goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Safely assigns a URL to a button element's formaction property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* button's formaction property. If url is of type string however, it is first
* sanitized using goog.html.SafeUrl.sanitize.
*
* Example usage:
* goog.dom.safe.setButtonFormAction(buttonEl, url);
* which is a safe alternative to
* buttonEl.action = url;
* The latter can result in XSS vulnerabilities if url is a
* user-/attacker-controlled value.
*
* @param {!Element} button The button element whose action property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setButtonFormAction = function(button, url) {
'use strict';
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
goog.dom.asserts.assertIsHTMLButtonElement(button).formAction =
goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Safely assigns a URL to an input element's formaction property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* input's formaction property. If url is of type string however, it is first
* sanitized using goog.html.SafeUrl.sanitize.
*
* Example usage:
* goog.dom.safe.setInputFormAction(inputEl, url);
* which is a safe alternative to
* inputEl.action = url;
* The latter can result in XSS vulnerabilities if url is a
* user-/attacker-controlled value.
*
* @param {!Element} input The input element whose action property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setInputFormAction = function(input, url) {
'use strict';
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
goog.dom.asserts.assertIsHTMLInputElement(input).formAction =
goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Sets the given element's style property to the contents of the provided
* SafeStyle object.
* @param {!Element} elem
* @param {!goog.html.SafeStyle} style
* @return {void}
*/
goog.dom.safe.setStyle = function(elem, style) {
'use strict';
elem.style.cssText = goog.html.SafeStyle.unwrap(style);
};
/**
* Writes known-safe HTML to a document.
* @param {!Document} doc The document to be written to.
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
* @return {void}
*/
goog.dom.safe.documentWrite = function(doc, html) {
'use strict';
doc.write(goog.html.SafeHtml.unwrapTrustedHTML(html));
};
/**
* Safely assigns a URL to an anchor element's href property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* anchor's href property. If url is of type string however, it is first
* sanitized using goog.html.SafeUrl.sanitize.
*
* Example usage:
* goog.dom.safe.setAnchorHref(anchorEl, url);
* which is a safe alternative to
* anchorEl.href = url;
* The latter can result in XSS vulnerabilities if url is a
* user-/attacker-controlled value.
*
* @param {!HTMLAnchorElement} anchor The anchor element whose href property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setAnchorHref = function(anchor, url) {
'use strict';
goog.dom.asserts.assertIsHTMLAnchorElement(anchor);
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
anchor.href = goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Safely assigns a URL to an image element's src property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* image's src property. If url is of type string however, it is first
* sanitized using goog.html.SafeUrl.sanitize.
*
* @param {!HTMLImageElement} imageElement The image element whose src property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setImageSrc = function(imageElement, url) {
'use strict';
goog.dom.asserts.assertIsHTMLImageElement(imageElement);
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
var allowDataUrl = /^data:image\//i.test(url);
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url, allowDataUrl);
}
imageElement.src = goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Safely assigns a URL to a audio element's src property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* audio's src property. If url is of type string however, it is first
* sanitized using goog.html.SafeUrl.sanitize.
*
* @param {!HTMLAudioElement} audioElement The audio element whose src property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setAudioSrc = function(audioElement, url) {
'use strict';
goog.dom.asserts.assertIsHTMLAudioElement(audioElement);
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
var allowDataUrl = /^data:audio\//i.test(url);
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url, allowDataUrl);
}
audioElement.src = goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Safely assigns a URL to a video element's src property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* video's src property. If url is of type string however, it is first
* sanitized using goog.html.SafeUrl.sanitize.
*
* @param {!HTMLVideoElement} videoElement The video element whose src property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setVideoSrc = function(videoElement, url) {
'use strict';
goog.dom.asserts.assertIsHTMLVideoElement(videoElement);
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
var allowDataUrl = /^data:video\//i.test(url);
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url, allowDataUrl);
}
videoElement.src = goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Safely assigns a URL to an embed element's src property.
*
* Example usage:
* goog.dom.safe.setEmbedSrc(embedEl, url);
* which is a safe alternative to
* embedEl.src = url;
* The latter can result in loading untrusted code unless it is ensured that
* the URL refers to a trustworthy resource.
*
* @param {!HTMLEmbedElement} embed The embed element whose src property
* is to be assigned to.
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
*/
goog.dom.safe.setEmbedSrc = function(embed, url) {
'use strict';
goog.dom.asserts.assertIsHTMLEmbedElement(embed);
embed.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);
};
/**
* Safely assigns a URL to a frame element's src property.
*
* Example usage:
* goog.dom.safe.setFrameSrc(frameEl, url);
* which is a safe alternative to
* frameEl.src = url;
* The latter can result in loading untrusted code unless it is ensured that
* the URL refers to a trustworthy resource.
*
* @param {!HTMLFrameElement} frame The frame element whose src property
* is to be assigned to.
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
* @return {void}
*/
goog.dom.safe.setFrameSrc = function(frame, url) {
'use strict';
goog.dom.asserts.assertIsHTMLFrameElement(frame);
frame.src = goog.html.TrustedResourceUrl.unwrap(url);
};
/**
* Safely assigns a URL to an iframe element's src property.
*
* Example usage:
* goog.dom.safe.setIframeSrc(iframeEl, url);
* which is a safe alternative to
* iframeEl.src = url;
* The latter can result in loading untrusted code unless it is ensured that
* the URL refers to a trustworthy resource.
*
* @param {!HTMLIFrameElement} iframe The iframe element whose src property
* is to be assigned to.
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
* @return {void}
*/
goog.dom.safe.setIframeSrc = function(iframe, url) {
'use strict';
goog.dom.asserts.assertIsHTMLIFrameElement(iframe);
iframe.src = goog.html.TrustedResourceUrl.unwrap(url);
};
/**
* Safely assigns HTML to an iframe element's srcdoc property.
*
* Example usage:
* goog.dom.safe.setIframeSrcdoc(iframeEl, safeHtml);
* which is a safe alternative to
* iframeEl.srcdoc = html;
* The latter can result in loading untrusted code.
*
* @param {!HTMLIFrameElement} iframe The iframe element whose srcdoc property
* is to be assigned to.
* @param {!goog.html.SafeHtml} html The HTML to assign.
* @return {void}
*/
goog.dom.safe.setIframeSrcdoc = function(iframe, html) {
'use strict';
goog.dom.asserts.assertIsHTMLIFrameElement(iframe);
iframe.srcdoc = goog.html.SafeHtml.unwrapTrustedHTML(html);
};
/**
* Safely sets a link element's href and rel properties. Whether or not
* the URL assigned to href has to be a goog.html.TrustedResourceUrl
* depends on the value of the rel property. If rel contains "stylesheet"
* then a TrustedResourceUrl is required.
*
* Example usage:
* goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet');
* which is a safe alternative to
* linkEl.rel = 'stylesheet';
* linkEl.href = url;
* The latter can result in loading untrusted code unless it is ensured that
* the URL refers to a trustworthy resource.
*
* @param {!HTMLLinkElement} link The link element whose href property
* is to be assigned to.
* @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL
* to assign to the href property. Must be a TrustedResourceUrl if the
* value assigned to rel contains "stylesheet". A string value is
* sanitized with goog.html.SafeUrl.sanitize.
* @param {string} rel The value to assign to the rel property.
* @return {void}
* @throws {Error} if rel contains "stylesheet" and url is not a
* TrustedResourceUrl
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) {
'use strict';
goog.dom.asserts.assertIsHTMLLinkElement(link);
link.rel = rel;
if (goog.string.internal.caseInsensitiveContains(rel, 'stylesheet')) {
goog.asserts.assert(
url instanceof goog.html.TrustedResourceUrl,
'URL must be TrustedResourceUrl because "rel" contains "stylesheet"');
link.href = goog.html.TrustedResourceUrl.unwrap(url);
const win = link.ownerDocument && link.ownerDocument.defaultView;
const nonce = goog.dom.safe.getStyleNonce(win);
if (nonce) {
link.setAttribute('nonce', nonce);
}
} else if (url instanceof goog.html.TrustedResourceUrl) {
link.href = goog.html.TrustedResourceUrl.unwrap(url);
} else if (url instanceof goog.html.SafeUrl) {
link.href = goog.html.SafeUrl.unwrap(url);
} else { // string
// SafeUrl.sanitize must return legitimate SafeUrl when passed a string.
link.href = goog.html.SafeUrl.unwrap(
goog.html.SafeUrl.sanitizeAssertUnchanged(url));
}
};
/**
* Safely assigns a URL to an object element's data property.
*
* Example usage:
* goog.dom.safe.setObjectData(objectEl, url);
* which is a safe alternative to
* objectEl.data = url;
* The latter can result in loading untrusted code unless setit is ensured that
* the URL refers to a trustworthy resource.
*
* @param {!HTMLObjectElement} object The object element whose data property
* is to be assigned to.
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
* @return {void}
*/
goog.dom.safe.setObjectData = function(object, url) {
'use strict';
goog.dom.asserts.assertIsHTMLObjectElement(object);
object.data = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);
};
/**
* Safely assigns a URL to a script element's src property.
*
* Example usage:
* goog.dom.safe.setScriptSrc(scriptEl, url);
* which is a safe alternative to
* scriptEl.src = url;
* The latter can result in loading untrusted code unless it is ensured that
* the URL refers to a trustworthy resource.
*
* @param {!HTMLScriptElement} script The script element whose src property
* is to be assigned to.
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
* @return {void}
*/
goog.dom.safe.setScriptSrc = function(script, url) {
'use strict';
goog.dom.asserts.assertIsHTMLScriptElement(script);
script.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(url);
goog.dom.safe.setNonceForScriptElement_(script);
};
/**
* Safely assigns a value to a script element's content.
*
* Example usage:
* goog.dom.safe.setScriptContent(scriptEl, content);
* which is a safe alternative to
* scriptEl.text = content;
* The latter can result in executing untrusted code unless it is ensured that
* the code is loaded from a trustworthy resource.
*
* @param {!HTMLScriptElement} script The script element whose content is being
* set.
* @param {!goog.html.SafeScript} content The content to assign.
* @return {void}
*/
goog.dom.safe.setScriptContent = function(script, content) {
'use strict';
goog.dom.asserts.assertIsHTMLScriptElement(script);
script.textContent = goog.html.SafeScript.unwrapTrustedScript(content);
goog.dom.safe.setNonceForScriptElement_(script);
};
/**
* Set nonce-based CSPs to dynamically created scripts.
* @param {!HTMLScriptElement} script The script element whose nonce value
* is to be calculated
* @private
*/
goog.dom.safe.setNonceForScriptElement_ = function(script) {
'use strict';
var win = script.ownerDocument && script.ownerDocument.defaultView;
const nonce = goog.dom.safe.getScriptNonce(win);
if (nonce) {
script.setAttribute('nonce', nonce);
}
};
/**
* Safely assigns a URL to a Location object's href property.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
* loc's href property. If url is of type string however, it is first sanitized
* using goog.html.SafeUrl.sanitize.
*
* Example usage:
* goog.dom.safe.setLocationHref(document.location, redirectUrl);
* which is a safe alternative to
* document.location.href = redirectUrl;
* The latter can result in XSS vulnerabilities if redirectUrl is a
* user-/attacker-controlled value.
*
* @param {!Location} loc The Location object whose href property is to be
* assigned to.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.setLocationHref = function(loc, url) {
'use strict';
goog.dom.asserts.assertIsLocation(loc);
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
loc.href = goog.html.SafeUrl.unwrap(safeUrl);
};
/**
* Safely assigns the URL of a Location object.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and
* passed to Location#assign. If url is of type string however, it is
* first sanitized using goog.html.SafeUrl.sanitize.
*
* Example usage:
* goog.dom.safe.assignLocation(document.location, newUrl);
* which is a safe alternative to
* document.location.assign(newUrl);
* The latter can result in XSS vulnerabilities if newUrl is a
* user-/attacker-controlled value.
*
* This has the same behaviour as setLocationHref, however some test
* mock Location.assign instead of a property assignment.
*
* @param {!Location} loc The Location object which is to be assigned.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.assignLocation = function(loc, url) {
'use strict';
goog.dom.asserts.assertIsLocation(loc);
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
loc.assign(goog.html.SafeUrl.unwrap(safeUrl));
};
/**
* Safely replaces the URL of a Location object.
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and
* passed to Location#replace. If url is of type string however, it is
* first sanitized using goog.html.SafeUrl.sanitize.
*
* Example usage:
* goog.dom.safe.replaceLocation(document.location, newUrl);
* which is a safe alternative to
* document.location.replace(newUrl);
* The latter can result in XSS vulnerabilities if newUrl is a
* user-/attacker-controlled value.
*
* @param {!Location} loc The Location object which is to be replaced.
* @param {string|!goog.html.SafeUrl} url The URL to assign.
* @return {void}
* @see goog.html.SafeUrl#sanitize
*/
goog.dom.safe.replaceLocation = function(loc, url) {
'use strict';
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
loc.replace(goog.html.SafeUrl.unwrap(safeUrl));
};
/**
* Safely opens a URL in a new window (via window.open).
*
* If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to
* window.open. If url is of type string however, it is first sanitized
* using goog.html.SafeUrl.sanitize.
*
* Note that this function does not prevent leakages via the referer that is
* sent by window.open. It is advised to only use this to open 1st party URLs.
*
* Example usage:
* goog.dom.safe.openInWindow(url);
* which is a safe alternative to
* window.open(url);
* The latter can result in XSS vulnerabilities if url is a
* user-/attacker-controlled value.
*
* @param {string|!goog.html.SafeUrl} url The URL to open.
* @param {Window=} opt_openerWin Window of which to call the .open() method.
* Defaults to the global window.
* @param {!goog.string.Const|string=} opt_name Name of the window to open in.
* Can be _top, etc as allowed by window.open(). This accepts string for
* legacy reasons. Pass goog.string.Const if possible.
* @param {string=} opt_specs Comma-separated list of specifications, same as
* in window.open().
* @return {Window} Window the url was opened in.
*/
goog.dom.safe.openInWindow = function(url, opt_openerWin, opt_name, opt_specs) {
'use strict';
/** @type {!goog.html.SafeUrl} */
var safeUrl;
if (url instanceof goog.html.SafeUrl) {
safeUrl = url;
} else {
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
}
var win = opt_openerWin || goog.global;
// If opt_name is undefined, simply passing that in to open() causes IE to
// reuse the current window instead of opening a new one. Thus we pass '' in
// instead, which according to spec opens a new window. See
// https://html.spec.whatwg.org/multipage/browsers.html#dom-open .
var name = opt_name instanceof goog.string.Const ?
goog.string.Const.unwrap(opt_name) :
opt_name || '';
// Do not pass opt_specs to window.open unless it was provided by the caller.
// IE11 will use it as a signal to open a new window rather than a new tab
// (even if it is undefined).
if (opt_specs !== undefined) {
return win.open(goog.html.SafeUrl.unwrap(safeUrl), name, opt_specs);
} else {
return win.open(goog.html.SafeUrl.unwrap(safeUrl), name);
}
};
/**
* Parses the HTML as 'text/html'.
* @param {!DOMParser} parser
* @param {!goog.html.SafeHtml} html The HTML to be parsed.
* @return {!Document}
*/
goog.dom.safe.parseFromStringHtml = function(parser, html) {
'use strict';
return goog.dom.safe.parseFromString(parser, html, 'text/html');
};
/**
* Parses the string.
* @param {!DOMParser} parser
* @param {!goog.html.SafeHtml} content Note: We don't have a special type for
* XML or SVG supported by this function so we use SafeHtml.
* @param {string} type
* @return {!Document}
*/
goog.dom.safe.parseFromString = function(parser, content, type) {
'use strict';
return parser.parseFromString(
goog.html.SafeHtml.unwrapTrustedHTML(content), type);
};
/**
* Safely creates an HTMLImageElement from a Blob.
*
* Example usage:
* goog.dom.safe.createImageFromBlob(blob);
* which is a safe alternative to
* image.src = createObjectUrl(blob)
* The latter can result in executing malicious same-origin scripts from a bad
* Blob.
* @param {!Blob} blob The blob to create the image from.
* @return {!HTMLImageElement} The image element created from the blob.
* @throws {!Error} If called with a Blob with a MIME type other than image/.*.
*/
goog.dom.safe.createImageFromBlob = function(blob) {
'use strict';
// Any image/* MIME type is accepted as safe.
if (!/^image\/.*/g.test(blob.type)) {
throw new Error(
'goog.dom.safe.createImageFromBlob only accepts MIME type image/.*.');
}
var objectUrl = goog.global.URL.createObjectURL(blob);
var image = new goog.global.Image();
image.onload = function() {
'use strict';
goog.global.URL.revokeObjectURL(objectUrl);
};
goog.dom.safe.setImageSrc(
image,
goog.html.uncheckedconversions
.safeUrlFromStringKnownToSatisfyTypeContract(
goog.string.Const.from('Image blob URL.'), objectUrl));
return image;
};
/**
* Creates a DocumentFragment by parsing html in the context of a Range.
* @param {!Range} range The Range object starting from the context node to
* create a fragment in.
* @param {!goog.html.SafeHtml} html HTML to create a fragment from.
* @return {?DocumentFragment}
*/
goog.dom.safe.createContextualFragment = function(range, html) {
'use strict';
return range.createContextualFragment(
goog.html.SafeHtml.unwrapTrustedHTML(html));
};
/**
* Returns CSP script nonce, if set for any <script> tag.
* @param {?Window=} opt_window The window context used to retrieve the nonce.
* Defaults to global context.
* @return {string} CSP nonce or empty string if no nonce is present.
*/
goog.dom.safe.getScriptNonce = function(opt_window) {
return goog.dom.safe.getNonce_('script[nonce]', opt_window);
};
/**
* Returns CSP style nonce, if set for any <style> or <link rel="stylesheet">
* tag.
* @param {?Window=} opt_window The window context used to retrieve the nonce.
* Defaults to global context.
* @return {string} CSP nonce or empty string if no nonce is present.
*/
goog.dom.safe.getStyleNonce = function(opt_window) {
return goog.dom.safe.getNonce_(
'style[nonce],link[rel="stylesheet"][nonce]', opt_window);
};
/**
* According to the CSP3 spec a nonce must be a valid base64 string.
* @see https://www.w3.org/TR/CSP3/#grammardef-base64-value
* @private @const
*/
goog.dom.safe.NONCE_PATTERN_ = /^[\w+/_-]+[=]{0,2}$/;
/**
* Returns CSP nonce, if set for any tag of given type.
* @param {string} selector Selector for locating the element with nonce.
* @param {?Window=} win The window context used to retrieve the nonce.
* @return {string} CSP nonce or empty string if no nonce is present.
* @private
*/
goog.dom.safe.getNonce_ = function(selector, win) {
const doc = (win || goog.global).document;
if (!doc.querySelector) {
return '';
}
let el = doc.querySelector(selector);
if (el) {
// Try to get the nonce from the IDL property first, because browsers that
// implement additional nonce protection features (currently only Chrome) to
// prevent nonce stealing via CSS do not expose the nonce via attributes.
// See https://github.com/whatwg/html/issues/2369
const nonce = el['nonce'] || el.getAttribute('nonce');
if (nonce && goog.dom.safe.NONCE_PATTERN_.test(nonce)) {
return nonce;
}
}
return '';
};
+457
View File
@@ -0,0 +1,457 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Defines the goog.dom.TagName class. Its constants enumerate
* all HTML tag names specified in either the W3C HTML 4.01 index of elements
* or the HTML5.1 specification.
*
* References:
* https://www.w3.org/TR/html401/index/elements.html
* https://www.w3.org/TR/html51/dom.html#elements
*/
goog.provide('goog.dom.TagName');
goog.require('goog.dom.HtmlElement');
/**
* A tag name for an HTML element.
*
* This type is a lie. All instances are actually strings. Do not implement it.
*
* It exists because we need an object type to host the template type parameter,
* and that's not possible with literal or enum types. It is a record type so
* that runtime type checks don't try to validate the lie.
*
* @template T
* @record
*/
goog.dom.TagName = class {
/**
* Cast a string into the tagname for the associated constructor.
*
* @template T
* @param {string} name
* @param {function(new:T, ...?)} type
* @return {!goog.dom.TagName<T>}
*/
static cast(name, type) {
return /** @type {?} */ (name);
}
/** @suppress {unusedPrivateMembers} */
constructor() {
/** @private {null} */
this.googDomTagName_doNotImplementThisTypeOrElse_;
/** @private {T} */
this.ensureTypeScriptRemembersTypeT_;
}
/**
* Appease the compiler that instances are stringafiable for the
* purpose of being a dictionary key.
*
* Never implemented; always backed by `String::toString`.
*
* @override
* @return {string}
*/
toString() {}
};
/** @const {!goog.dom.TagName<!HTMLAnchorElement>} */
goog.dom.TagName.A = /** @type {?} */ ('A');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.ABBR = /** @type {?} */ ('ABBR');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.ACRONYM = /** @type {?} */ ('ACRONYM');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.ADDRESS = /** @type {?} */ ('ADDRESS');
/** @const {!goog.dom.TagName<!HTMLAppletElement>} */
goog.dom.TagName.APPLET = /** @type {?} */ ('APPLET');
/** @const {!goog.dom.TagName<!HTMLAreaElement>} */
goog.dom.TagName.AREA = /** @type {?} */ ('AREA');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.ARTICLE = /** @type {?} */ ('ARTICLE');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.ASIDE = /** @type {?} */ ('ASIDE');
/** @const {!goog.dom.TagName<!HTMLAudioElement>} */
goog.dom.TagName.AUDIO = /** @type {?} */ ('AUDIO');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.B = /** @type {?} */ ('B');
/** @const {!goog.dom.TagName<!HTMLBaseElement>} */
goog.dom.TagName.BASE = /** @type {?} */ ('BASE');
/** @const {!goog.dom.TagName<!HTMLBaseFontElement>} */
goog.dom.TagName.BASEFONT = /** @type {?} */ ('BASEFONT');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.BDI = /** @type {?} */ ('BDI');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.BDO = /** @type {?} */ ('BDO');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.BIG = /** @type {?} */ ('BIG');
/** @const {!goog.dom.TagName<!HTMLQuoteElement>} */
goog.dom.TagName.BLOCKQUOTE = /** @type {?} */ ('BLOCKQUOTE');
/** @const {!goog.dom.TagName<!HTMLBodyElement>} */
goog.dom.TagName.BODY = /** @type {?} */ ('BODY');
/** @const {!goog.dom.TagName<!HTMLBRElement>} */
goog.dom.TagName.BR = /** @type {?} */ ('BR');
/** @const {!goog.dom.TagName<!HTMLButtonElement>} */
goog.dom.TagName.BUTTON = /** @type {?} */ ('BUTTON');
/** @const {!goog.dom.TagName<!HTMLCanvasElement>} */
goog.dom.TagName.CANVAS = /** @type {?} */ ('CANVAS');
/** @const {!goog.dom.TagName<!HTMLTableCaptionElement>} */
goog.dom.TagName.CAPTION = /** @type {?} */ ('CAPTION');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.CENTER = /** @type {?} */ ('CENTER');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.CITE = /** @type {?} */ ('CITE');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.CODE = /** @type {?} */ ('CODE');
/** @const {!goog.dom.TagName<!HTMLTableColElement>} */
goog.dom.TagName.COL = /** @type {?} */ ('COL');
/** @const {!goog.dom.TagName<!HTMLTableColElement>} */
goog.dom.TagName.COLGROUP = /** @type {?} */ ('COLGROUP');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.COMMAND = /** @type {?} */ ('COMMAND');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.DATA = /** @type {?} */ ('DATA');
/** @const {!goog.dom.TagName<!HTMLDataListElement>} */
goog.dom.TagName.DATALIST = /** @type {?} */ ('DATALIST');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.DD = /** @type {?} */ ('DD');
/** @const {!goog.dom.TagName<!HTMLModElement>} */
goog.dom.TagName.DEL = /** @type {?} */ ('DEL');
/** @const {!goog.dom.TagName<!HTMLDetailsElement>} */
goog.dom.TagName.DETAILS = /** @type {?} */ ('DETAILS');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.DFN = /** @type {?} */ ('DFN');
/** @const {!goog.dom.TagName<!HTMLDialogElement>} */
goog.dom.TagName.DIALOG = /** @type {?} */ ('DIALOG');
/** @const {!goog.dom.TagName<!HTMLDirectoryElement>} */
goog.dom.TagName.DIR = /** @type {?} */ ('DIR');
/** @const {!goog.dom.TagName<!HTMLDivElement>} */
goog.dom.TagName.DIV = /** @type {?} */ ('DIV');
/** @const {!goog.dom.TagName<!HTMLDListElement>} */
goog.dom.TagName.DL = /** @type {?} */ ('DL');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.DT = /** @type {?} */ ('DT');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.EM = /** @type {?} */ ('EM');
/** @const {!goog.dom.TagName<!HTMLEmbedElement>} */
goog.dom.TagName.EMBED = /** @type {?} */ ('EMBED');
/** @const {!goog.dom.TagName<!HTMLFieldSetElement>} */
goog.dom.TagName.FIELDSET = /** @type {?} */ ('FIELDSET');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.FIGCAPTION = /** @type {?} */ ('FIGCAPTION');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.FIGURE = /** @type {?} */ ('FIGURE');
/** @const {!goog.dom.TagName<!HTMLFontElement>} */
goog.dom.TagName.FONT = /** @type {?} */ ('FONT');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.FOOTER = /** @type {?} */ ('FOOTER');
/** @const {!goog.dom.TagName<!HTMLFormElement>} */
goog.dom.TagName.FORM = /** @type {?} */ ('FORM');
/** @const {!goog.dom.TagName<!HTMLFrameElement>} */
goog.dom.TagName.FRAME = /** @type {?} */ ('FRAME');
/** @const {!goog.dom.TagName<!HTMLFrameSetElement>} */
goog.dom.TagName.FRAMESET = /** @type {?} */ ('FRAMESET');
/** @const {!goog.dom.TagName<!HTMLHeadingElement>} */
goog.dom.TagName.H1 = /** @type {?} */ ('H1');
/** @const {!goog.dom.TagName<!HTMLHeadingElement>} */
goog.dom.TagName.H2 = /** @type {?} */ ('H2');
/** @const {!goog.dom.TagName<!HTMLHeadingElement>} */
goog.dom.TagName.H3 = /** @type {?} */ ('H3');
/** @const {!goog.dom.TagName<!HTMLHeadingElement>} */
goog.dom.TagName.H4 = /** @type {?} */ ('H4');
/** @const {!goog.dom.TagName<!HTMLHeadingElement>} */
goog.dom.TagName.H5 = /** @type {?} */ ('H5');
/** @const {!goog.dom.TagName<!HTMLHeadingElement>} */
goog.dom.TagName.H6 = /** @type {?} */ ('H6');
/** @const {!goog.dom.TagName<!HTMLHeadElement>} */
goog.dom.TagName.HEAD = /** @type {?} */ ('HEAD');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.HEADER = /** @type {?} */ ('HEADER');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.HGROUP = /** @type {?} */ ('HGROUP');
/** @const {!goog.dom.TagName<!HTMLHRElement>} */
goog.dom.TagName.HR = /** @type {?} */ ('HR');
/** @const {!goog.dom.TagName<!HTMLHtmlElement>} */
goog.dom.TagName.HTML = /** @type {?} */ ('HTML');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.I = /** @type {?} */ ('I');
/** @const {!goog.dom.TagName<!HTMLIFrameElement>} */
goog.dom.TagName.IFRAME = /** @type {?} */ ('IFRAME');
/** @const {!goog.dom.TagName<!HTMLImageElement>} */
goog.dom.TagName.IMG = /** @type {?} */ ('IMG');
/** @const {!goog.dom.TagName<!HTMLInputElement>} */
goog.dom.TagName.INPUT = /** @type {?} */ ('INPUT');
/** @const {!goog.dom.TagName<!HTMLModElement>} */
goog.dom.TagName.INS = /** @type {?} */ ('INS');
/** @const {!goog.dom.TagName<!HTMLIsIndexElement>} */
goog.dom.TagName.ISINDEX = /** @type {?} */ ('ISINDEX');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.KBD = /** @type {?} */ ('KBD');
// HTMLKeygenElement is deprecated.
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.KEYGEN = /** @type {?} */ ('KEYGEN');
/** @const {!goog.dom.TagName<!HTMLLabelElement>} */
goog.dom.TagName.LABEL = /** @type {?} */ ('LABEL');
/** @const {!goog.dom.TagName<!HTMLLegendElement>} */
goog.dom.TagName.LEGEND = /** @type {?} */ ('LEGEND');
/** @const {!goog.dom.TagName<!HTMLLIElement>} */
goog.dom.TagName.LI = /** @type {?} */ ('LI');
/** @const {!goog.dom.TagName<!HTMLLinkElement>} */
goog.dom.TagName.LINK = /** @type {?} */ ('LINK');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.MAIN = /** @type {?} */ ('MAIN');
/** @const {!goog.dom.TagName<!HTMLMapElement>} */
goog.dom.TagName.MAP = /** @type {?} */ ('MAP');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.MARK = /** @type {?} */ ('MARK');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.MATH = /** @type {?} */ ('MATH');
/** @const {!goog.dom.TagName<!HTMLMenuElement>} */
goog.dom.TagName.MENU = /** @type {?} */ ('MENU');
/** @const {!goog.dom.TagName<!HTMLMenuItemElement>} */
goog.dom.TagName.MENUITEM = /** @type {?} */ ('MENUITEM');
/** @const {!goog.dom.TagName<!HTMLMetaElement>} */
goog.dom.TagName.META = /** @type {?} */ ('META');
/** @const {!goog.dom.TagName<!HTMLMeterElement>} */
goog.dom.TagName.METER = /** @type {?} */ ('METER');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.NAV = /** @type {?} */ ('NAV');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.NOFRAMES = /** @type {?} */ ('NOFRAMES');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.NOSCRIPT = /** @type {?} */ ('NOSCRIPT');
/** @const {!goog.dom.TagName<!HTMLObjectElement>} */
goog.dom.TagName.OBJECT = /** @type {?} */ ('OBJECT');
/** @const {!goog.dom.TagName<!HTMLOListElement>} */
goog.dom.TagName.OL = /** @type {?} */ ('OL');
/** @const {!goog.dom.TagName<!HTMLOptGroupElement>} */
goog.dom.TagName.OPTGROUP = /** @type {?} */ ('OPTGROUP');
/** @const {!goog.dom.TagName<!HTMLOptionElement>} */
goog.dom.TagName.OPTION = /** @type {?} */ ('OPTION');
/** @const {!goog.dom.TagName<!HTMLOutputElement>} */
goog.dom.TagName.OUTPUT = /** @type {?} */ ('OUTPUT');
/** @const {!goog.dom.TagName<!HTMLParagraphElement>} */
goog.dom.TagName.P = /** @type {?} */ ('P');
/** @const {!goog.dom.TagName<!HTMLParamElement>} */
goog.dom.TagName.PARAM = /** @type {?} */ ('PARAM');
/** @const {!goog.dom.TagName<!HTMLPictureElement>} */
goog.dom.TagName.PICTURE = /** @type {?} */ ('PICTURE');
/** @const {!goog.dom.TagName<!HTMLPreElement>} */
goog.dom.TagName.PRE = /** @type {?} */ ('PRE');
/** @const {!goog.dom.TagName<!HTMLProgressElement>} */
goog.dom.TagName.PROGRESS = /** @type {?} */ ('PROGRESS');
/** @const {!goog.dom.TagName<!HTMLQuoteElement>} */
goog.dom.TagName.Q = /** @type {?} */ ('Q');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.RP = /** @type {?} */ ('RP');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.RT = /** @type {?} */ ('RT');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.RTC = /** @type {?} */ ('RTC');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.RUBY = /** @type {?} */ ('RUBY');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.S = /** @type {?} */ ('S');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.SAMP = /** @type {?} */ ('SAMP');
/** @const {!goog.dom.TagName<!HTMLScriptElement>} */
goog.dom.TagName.SCRIPT = /** @type {?} */ ('SCRIPT');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.SECTION = /** @type {?} */ ('SECTION');
/** @const {!goog.dom.TagName<!HTMLSelectElement>} */
goog.dom.TagName.SELECT = /** @type {?} */ ('SELECT');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.SMALL = /** @type {?} */ ('SMALL');
/** @const {!goog.dom.TagName<!HTMLSourceElement>} */
goog.dom.TagName.SOURCE = /** @type {?} */ ('SOURCE');
/** @const {!goog.dom.TagName<!HTMLSpanElement>} */
goog.dom.TagName.SPAN = /** @type {?} */ ('SPAN');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.STRIKE = /** @type {?} */ ('STRIKE');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.STRONG = /** @type {?} */ ('STRONG');
/** @const {!goog.dom.TagName<!HTMLStyleElement>} */
goog.dom.TagName.STYLE = /** @type {?} */ ('STYLE');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.SUB = /** @type {?} */ ('SUB');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.SUMMARY = /** @type {?} */ ('SUMMARY');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.SUP = /** @type {?} */ ('SUP');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.SVG = /** @type {?} */ ('SVG');
/** @const {!goog.dom.TagName<!HTMLTableElement>} */
goog.dom.TagName.TABLE = /** @type {?} */ ('TABLE');
/** @const {!goog.dom.TagName<!HTMLTableSectionElement>} */
goog.dom.TagName.TBODY = /** @type {?} */ ('TBODY');
/** @const {!goog.dom.TagName<!HTMLTableCellElement>} */
goog.dom.TagName.TD = /** @type {?} */ ('TD');
/** @const {!goog.dom.TagName<!HTMLTemplateElement>} */
goog.dom.TagName.TEMPLATE = /** @type {?} */ ('TEMPLATE');
/** @const {!goog.dom.TagName<!HTMLTextAreaElement>} */
goog.dom.TagName.TEXTAREA = /** @type {?} */ ('TEXTAREA');
/** @const {!goog.dom.TagName<!HTMLTableSectionElement>} */
goog.dom.TagName.TFOOT = /** @type {?} */ ('TFOOT');
/** @const {!goog.dom.TagName<!HTMLTableCellElement>} */
goog.dom.TagName.TH = /** @type {?} */ ('TH');
/** @const {!goog.dom.TagName<!HTMLTableSectionElement>} */
goog.dom.TagName.THEAD = /** @type {?} */ ('THEAD');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.TIME = /** @type {?} */ ('TIME');
/** @const {!goog.dom.TagName<!HTMLTitleElement>} */
goog.dom.TagName.TITLE = /** @type {?} */ ('TITLE');
/** @const {!goog.dom.TagName<!HTMLTableRowElement>} */
goog.dom.TagName.TR = /** @type {?} */ ('TR');
/** @const {!goog.dom.TagName<!HTMLTrackElement>} */
goog.dom.TagName.TRACK = /** @type {?} */ ('TRACK');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.TT = /** @type {?} */ ('TT');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.U = /** @type {?} */ ('U');
/** @const {!goog.dom.TagName<!HTMLUListElement>} */
goog.dom.TagName.UL = /** @type {?} */ ('UL');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.VAR = /** @type {?} */ ('VAR');
/** @const {!goog.dom.TagName<!HTMLVideoElement>} */
goog.dom.TagName.VIDEO = /** @type {?} */ ('VIDEO');
/** @const {!goog.dom.TagName<!goog.dom.HtmlElement>} */
goog.dom.TagName.WBR = /** @type {?} */ ('WBR');
+34
View File
@@ -0,0 +1,34 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Utilities for HTML element tag names.
*/
goog.provide('goog.dom.tags');
goog.require('goog.object');
/**
* The void elements specified by
* http://www.w3.org/TR/html-markup/syntax.html#void-elements.
* @const @private {!Object<string, boolean>}
*/
goog.dom.tags.VOID_TAGS_ = goog.object.createSet(
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr');
/**
* Checks whether the tag is void (with no contents allowed and no legal end
* tag), for example 'br'.
* @param {string} tagName The tag name in lower case.
* @return {boolean}
*/
goog.dom.tags.isVoidTag = function(tagName) {
'use strict';
return goog.dom.tags.VOID_TAGS_[tagName] === true;
};
+447
View File
@@ -0,0 +1,447 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview A patched, standardized event object for browser events.
*
* <pre>
* The patched event object contains the following members:
* - type {string} Event type, e.g. 'click'
* - target {Object} The element that actually triggered the event
* - currentTarget {Object} The element the listener is attached to
* - relatedTarget {Object} For mouseover and mouseout, the previous object
* - offsetX {number} X-coordinate relative to target
* - offsetY {number} Y-coordinate relative to target
* - clientX {number} X-coordinate relative to viewport
* - clientY {number} Y-coordinate relative to viewport
* - screenX {number} X-coordinate relative to the edge of the screen
* - screenY {number} Y-coordinate relative to the edge of the screen
* - button {number} Mouse button. Use isButton() to test.
* - keyCode {number} Key-code
* - ctrlKey {boolean} Was ctrl key depressed
* - altKey {boolean} Was alt key depressed
* - shiftKey {boolean} Was shift key depressed
* - metaKey {boolean} Was meta key depressed
* - pointerId {number} Pointer ID
* - pointerType {string} Pointer type, e.g. 'mouse', 'pen', or 'touch'
* - defaultPrevented {boolean} Whether the default action has been prevented
* - state {Object} History state object
*
* NOTE: The keyCode member contains the raw browser keyCode. For normalized
* key and character code use {@link goog.events.KeyHandler}.
* </pre>
*/
goog.provide('goog.events.BrowserEvent');
goog.provide('goog.events.BrowserEvent.MouseButton');
goog.provide('goog.events.BrowserEvent.PointerType');
goog.require('goog.debug');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.reflect');
goog.require('goog.userAgent');
/**
* @define {boolean} If true, use the layerX and layerY properties of a native
* browser event over the offsetX and offsetY properties, which cause expensive
* reflow. If layerX or layerY is not defined, offsetX and offsetY will be used
* as usual.
*/
goog.events.USE_LAYER_XY_AS_OFFSET_XY =
goog.define('goog.events.USE_LAYER_XY_AS_OFFSET_XY', false);
/**
* Accepts a browser event object and creates a patched, cross browser event
* object.
* The content of this object will not be initialized if no event object is
* provided. If this is the case, init() needs to be invoked separately.
* @param {Event=} opt_e Browser event object.
* @param {EventTarget=} opt_currentTarget Current target for event.
* @constructor
* @extends {goog.events.Event}
*/
goog.events.BrowserEvent = function(opt_e, opt_currentTarget) {
'use strict';
goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : '');
/**
* Target that fired the event.
* @override
* @type {?Node}
*/
this.target = null;
/**
* Node that had the listener attached.
* @override
* @type {?Node|undefined}
*/
this.currentTarget = null;
/**
* For mouseover and mouseout events, the related object for the event.
* @type {?Node}
*/
this.relatedTarget = null;
/**
* X-coordinate relative to target.
* @type {number}
*/
this.offsetX = 0;
/**
* Y-coordinate relative to target.
* @type {number}
*/
this.offsetY = 0;
/**
* X-coordinate relative to the window.
* @type {number}
*/
this.clientX = 0;
/**
* Y-coordinate relative to the window.
* @type {number}
*/
this.clientY = 0;
/**
* X-coordinate relative to the monitor.
* @type {number}
*/
this.screenX = 0;
/**
* Y-coordinate relative to the monitor.
* @type {number}
*/
this.screenY = 0;
/**
* Which mouse button was pressed.
* @type {number}
*/
this.button = 0;
/**
* Key of key press.
* @type {string}
*/
this.key = '';
/**
* Keycode of key press.
* @type {number}
*/
this.keyCode = 0;
/**
* Keycode of key press.
* @type {number}
*/
this.charCode = 0;
/**
* Whether control was pressed at time of event.
* @type {boolean}
*/
this.ctrlKey = false;
/**
* Whether alt was pressed at time of event.
* @type {boolean}
*/
this.altKey = false;
/**
* Whether shift was pressed at time of event.
* @type {boolean}
*/
this.shiftKey = false;
/**
* Whether the meta key was pressed at time of event.
* @type {boolean}
*/
this.metaKey = false;
/**
* History state object, only set for PopState events where it's a copy of the
* state object provided to pushState or replaceState.
* @type {?Object}
*/
this.state = null;
/**
* Whether the default platform modifier key was pressed at time of event.
* (This is control for all platforms except Mac, where it's Meta.)
* @type {boolean}
*/
this.platformModifierKey = false;
/**
* @type {number}
*/
this.pointerId = 0;
/**
* @type {string}
*/
this.pointerType = '';
/**
* The browser event object.
* @private {?Event}
*/
this.event_ = null;
if (opt_e) {
this.init(opt_e, opt_currentTarget);
}
};
goog.inherits(goog.events.BrowserEvent, goog.events.Event);
/**
* Normalized button constants for the mouse.
* @enum {number}
*/
goog.events.BrowserEvent.MouseButton = {
LEFT: 0,
MIDDLE: 1,
RIGHT: 2
};
/**
* Normalized pointer type constants for pointer events.
* @enum {string}
*/
goog.events.BrowserEvent.PointerType = {
MOUSE: 'mouse',
PEN: 'pen',
TOUCH: 'touch'
};
/**
* Static data for mapping mouse buttons.
* @type {!Array<number>}
* @deprecated Use `goog.events.BrowserEvent.IE_BUTTON_MAP` instead.
*/
goog.events.BrowserEvent.IEButtonMap = goog.debug.freeze([
1, // LEFT
4, // MIDDLE
2 // RIGHT
]);
/**
* Static data for mapping mouse buttons.
* @const {!Array<number>}
*/
goog.events.BrowserEvent.IE_BUTTON_MAP = goog.events.BrowserEvent.IEButtonMap;
/**
* Static data for mapping MSPointerEvent types to PointerEvent types.
* @const {!Object<number, goog.events.BrowserEvent.PointerType>}
*/
goog.events.BrowserEvent.IE_POINTER_TYPE_MAP = goog.debug.freeze({
2: goog.events.BrowserEvent.PointerType.TOUCH,
3: goog.events.BrowserEvent.PointerType.PEN,
4: goog.events.BrowserEvent.PointerType.MOUSE
});
/**
* Accepts a browser event object and creates a patched, cross browser event
* object.
* @param {Event} e Browser event object.
* @param {EventTarget=} opt_currentTarget Current target for event.
*/
goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {
'use strict';
var type = this.type = e.type;
/**
* On touch devices use the first "changed touch" as the relevant touch.
* @type {?Touch}
*/
var relevantTouch =
e.changedTouches && e.changedTouches.length ? e.changedTouches[0] : null;
// TODO(nicksantos): Change this.target to type EventTarget.
this.target = /** @type {Node} */ (e.target) || e.srcElement;
// TODO(nicksantos): Change this.currentTarget to type EventTarget.
this.currentTarget = /** @type {Node} */ (opt_currentTarget);
var relatedTarget = /** @type {Node} */ (e.relatedTarget);
if (relatedTarget) {
// There's a bug in FireFox where sometimes, relatedTarget will be a
// chrome element, and accessing any property of it will get a permission
// denied exception. See:
// https://bugzilla.mozilla.org/show_bug.cgi?id=497780
if (goog.userAgent.GECKO) {
if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) {
relatedTarget = null;
}
}
} else if (type == goog.events.EventType.MOUSEOVER) {
relatedTarget = e.fromElement;
} else if (type == goog.events.EventType.MOUSEOUT) {
relatedTarget = e.toElement;
}
this.relatedTarget = relatedTarget;
if (relevantTouch) {
this.clientX = relevantTouch.clientX !== undefined ? relevantTouch.clientX :
relevantTouch.pageX;
this.clientY = relevantTouch.clientY !== undefined ? relevantTouch.clientY :
relevantTouch.pageY;
this.screenX = relevantTouch.screenX || 0;
this.screenY = relevantTouch.screenY || 0;
} else {
if (goog.events.USE_LAYER_XY_AS_OFFSET_XY) {
this.offsetX = (e.layerX !== undefined) ? e.layerX : e.offsetX;
this.offsetY = (e.layerY !== undefined) ? e.layerY : e.offsetY;
} else {
// Webkit emits a lame warning whenever layerX/layerY is accessed.
// http://code.google.com/p/chromium/issues/detail?id=101733
this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ?
e.offsetX :
e.layerX;
this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ?
e.offsetY :
e.layerY;
}
this.clientX = e.clientX !== undefined ? e.clientX : e.pageX;
this.clientY = e.clientY !== undefined ? e.clientY : e.pageY;
this.screenX = e.screenX || 0;
this.screenY = e.screenY || 0;
}
this.button = e.button;
this.keyCode = e.keyCode || 0;
this.key = e.key || '';
this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0);
this.ctrlKey = e.ctrlKey;
this.altKey = e.altKey;
this.shiftKey = e.shiftKey;
this.metaKey = e.metaKey;
this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey;
this.pointerId = e.pointerId || 0;
this.pointerType = goog.events.BrowserEvent.getPointerType_(e);
this.state = e.state;
this.event_ = e;
if (e.defaultPrevented) {
// Sync native event state to internal state via super class, where default
// prevention is implemented and managed.
goog.events.BrowserEvent.superClass_.preventDefault.call(this);
}
};
/**
* Tests to see which button was pressed during the event. This is really only
* useful in IE and Gecko browsers. And in IE, it's only useful for
* mousedown/mouseup events, because click only fires for the left mouse button.
*
* Safari 2 only reports the left button being clicked, and uses the value '1'
* instead of 0. Opera only reports a mousedown event for the middle button, and
* no mouse events for the right button. Opera has default behavior for left and
* middle click that can only be overridden via a configuration setting.
*
* There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html.
*
* @param {goog.events.BrowserEvent.MouseButton} button The button
* to test for.
* @return {boolean} True if button was pressed.
*/
goog.events.BrowserEvent.prototype.isButton = function(button) {
'use strict';
return this.event_.button == button;
};
/**
* Whether this has an "action"-producing mouse button.
*
* By definition, this includes left-click on windows/linux, and left-click
* without the ctrl key on Macs.
*
* @return {boolean} The result.
*/
goog.events.BrowserEvent.prototype.isMouseActionButton = function() {
'use strict';
// Ctrl+click should never behave like a left-click on mac, regardless of
// whether or not the browser will actually ever emit such an event. If
// we see it, treat it like right-click always.
return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) &&
!(goog.userAgent.MAC && this.ctrlKey);
};
/**
* @override
*/
goog.events.BrowserEvent.prototype.stopPropagation = function() {
'use strict';
goog.events.BrowserEvent.superClass_.stopPropagation.call(this);
if (this.event_.stopPropagation) {
this.event_.stopPropagation();
} else {
this.event_.cancelBubble = true;
}
};
/**
* @override
*/
goog.events.BrowserEvent.prototype.preventDefault = function() {
'use strict';
goog.events.BrowserEvent.superClass_.preventDefault.call(this);
var be = this.event_;
if (!be.preventDefault) {
be.returnValue = false;
} else {
be.preventDefault();
}
};
/**
* @return {Event} The underlying browser event object.
*/
goog.events.BrowserEvent.prototype.getBrowserEvent = function() {
'use strict';
return this.event_;
};
/**
* Extracts the pointer type from the given event.
* @param {!Event} e
* @return {string} The pointer type, e.g. 'mouse', 'pen', or 'touch'.
* @private
*/
goog.events.BrowserEvent.getPointerType_ = function(e) {
'use strict';
if (typeof (e.pointerType) === 'string') {
return e.pointerType;
}
// IE10 uses integer codes for pointer type.
// https://msdn.microsoft.com/en-us/library/hh772359(v=vs.85).aspx
return goog.events.BrowserEvent.IE_POINTER_TYPE_MAP[e.pointerType] || '';
};
+118
View File
@@ -0,0 +1,118 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Browser capability checks for the events package.
*/
goog.module('goog.events.BrowserFeature');
goog.module.declareLegacyNamespace();
/**
* Tricks Closure Compiler into believing that a function is pure. The compiler
* assumes that any `valueOf` function is pure, without analyzing its contents.
*
* @param {function(): T} fn
* @return {T}
* @template T
*/
const purify = (fn) => {
return ({valueOf: fn}).valueOf();
};
/**
* Enum of browser capabilities.
* @enum {boolean}
*/
exports = {
/**
* Whether the button attribute of the event is W3C compliant. False in
* Internet Explorer prior to version 9; document-version dependent.
*/
HAS_W3C_BUTTON: true,
/**
* Whether the browser supports full W3C event model.
*/
HAS_W3C_EVENT_SUPPORT: true,
/**
* To prevent default in IE7-8 for certain keydown events we need set the
* keyCode to -1.
*/
SET_KEY_CODE_TO_PREVENT_DEFAULT: false,
/**
* Whether the `navigator.onLine` property is supported.
*/
HAS_NAVIGATOR_ONLINE_PROPERTY: true,
/**
* Whether HTML5 network online/offline events are supported.
*/
HAS_HTML5_NETWORK_EVENT_SUPPORT: true,
/**
* Whether HTML5 network events fire on document.body, or otherwise the
* window.
*/
HTML5_NETWORK_EVENTS_FIRE_ON_BODY: false,
/**
* Whether touch is enabled in the browser.
*/
TOUCH_ENABLED:
('ontouchstart' in goog.global ||
!!(goog.global['document'] && document.documentElement &&
'ontouchstart' in document.documentElement) ||
// IE10 uses non-standard touch events, so it has a different check.
!!(goog.global['navigator'] &&
(goog.global['navigator']['maxTouchPoints'] ||
goog.global['navigator']['msMaxTouchPoints']))),
/**
* Whether addEventListener supports W3C standard pointer events.
* http://www.w3.org/TR/pointerevents/
*/
POINTER_EVENTS: ('PointerEvent' in goog.global),
/**
* Whether addEventListener supports MSPointer events (only used in IE10).
* http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx
* http://msdn.microsoft.com/library/hh673557(v=vs.85).aspx
*/
MSPOINTER_EVENTS:
('MSPointerEvent' in goog.global &&
!!(goog.global['navigator'] &&
goog.global['navigator']['msPointerEnabled'])),
/**
* Whether addEventListener supports {passive: true}.
* https://developers.google.com/web/updates/2016/06/passive-event-listeners
*/
PASSIVE_EVENTS: purify(function() {
// If we're in a web worker or other custom environment, we can't tell.
if (!goog.global.addEventListener || !Object.defineProperty) { // IE 8
return false;
}
var passive = false;
var options = Object.defineProperty({}, 'passive', {
get: function() {
passive = true;
}
});
try {
goog.global.addEventListener('test', goog.nullFunction, options);
goog.global.removeEventListener('test', goog.nullFunction, options);
} catch (e) {
}
return passive;
})
};
+125
View File
@@ -0,0 +1,125 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview A base class for event objects.
*/
goog.provide('goog.events.Event');
/**
* goog.events.Event no longer depends on goog.Disposable. Keep requiring
* goog.Disposable here to not break projects which assume this dependency.
* @suppress {extraRequire}
*/
goog.require('goog.Disposable');
goog.require('goog.events.EventId');
/**
* A base class for event objects, so that they can support preventDefault and
* stopPropagation.
*
* @param {string|!goog.events.EventId} type Event Type.
* @param {Object=} opt_target Reference to the object that is the target of
* this event. It has to implement the `EventTarget` interface
* declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}.
* @constructor
*/
goog.events.Event = function(type, opt_target) {
'use strict';
/**
* Event type.
* @type {string}
*/
this.type = type instanceof goog.events.EventId ? String(type) : type;
/**
* TODO(tbreisacher): The type should probably be
* EventTarget|goog.events.EventTarget.
*
* Target of the event.
* @type {Object|undefined}
*/
this.target = opt_target;
/**
* Object that had the listener attached.
* @type {Object|undefined}
*/
this.currentTarget = this.target;
/**
* Whether to cancel the event in internal capture/bubble processing for IE.
* @type {boolean}
* @private
*/
this.propagationStopped_ = false;
/**
* Whether the default action has been prevented.
* This is a property to match the W3C specification at
* {@link http://www.w3.org/TR/DOM-Level-3-Events/
* #events-event-type-defaultPrevented}.
* Must be treated as read-only outside the class.
* @type {boolean}
*/
this.defaultPrevented = false;
};
/**
* @return {boolean} true iff internal propagation has been stopped.
*/
goog.events.Event.prototype.hasPropagationStopped = function() {
'use strict';
return this.propagationStopped_;
};
/**
* Stops event propagation.
* @return {void}
*/
goog.events.Event.prototype.stopPropagation = function() {
'use strict';
this.propagationStopped_ = true;
};
/**
* Prevents the default action, for example a link redirecting to a url.
* @return {void}
*/
goog.events.Event.prototype.preventDefault = function() {
'use strict';
this.defaultPrevented = true;
};
/**
* Stops the propagation of the event. It is equivalent to
* `e.stopPropagation()`, but can be used as the callback argument of
* {@link goog.events.listen} without declaring another function.
* @param {!goog.events.Event} e An event.
* @return {void}
*/
goog.events.Event.stopPropagation = function(e) {
'use strict';
e.stopPropagation();
};
/**
* Prevents the default action. It is equivalent to
* `e.preventDefault()`, but can be used as the callback argument of
* {@link goog.events.listen} without declaring another function.
* @param {!goog.events.Event} e An event.
* @return {void}
*/
goog.events.Event.preventDefault = function(e) {
'use strict';
e.preventDefault();
};
+488
View File
@@ -0,0 +1,488 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Class to create objects which want to handle multiple events
* and have their listeners easily cleaned up via a dispose method.
*
* Example:
* <pre>
* function Something() {
* Something.base(this);
*
* ... set up object ...
*
* // Add event listeners
* this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar);
* this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand);
* this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse);
* this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover);
* this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover);
* }
* goog.inherits(Something, goog.events.EventHandler);
*
* Something.prototype.disposeInternal = function() {
* Something.base(this, 'disposeInternal');
* goog.dom.removeNode(this.container);
* };
*
*
* // Then elsewhere:
*
* var activeSomething = null;
* function openSomething() {
* activeSomething = new Something();
* }
*
* function closeSomething() {
* if (activeSomething) {
* activeSomething.dispose(); // Remove event listeners
* activeSomething = null;
* }
* }
* </pre>
*/
goog.provide('goog.events.EventHandler');
goog.require('goog.Disposable');
goog.require('goog.events');
goog.require('goog.object');
goog.requireType('goog.events.Event');
goog.requireType('goog.events.EventId');
goog.requireType('goog.events.EventTarget');
goog.requireType('goog.events.EventWrapper');
/**
* Super class for objects that want to easily manage a number of event
* listeners. It allows a short cut to listen and also provides a quick way
* to remove all events listeners belonging to this object.
* @param {SCOPE=} opt_scope Object in whose scope to call the listeners.
* @constructor
* @extends {goog.Disposable}
* @template SCOPE
*/
goog.events.EventHandler = function(opt_scope) {
'use strict';
goog.Disposable.call(this);
// TODO(mknichel): Rename this to this.scope_ and fix the classes in google3
// that access this private variable. :(
this.handler_ = opt_scope;
/**
* Keys for events that are being listened to.
* @type {!Object<!goog.events.Key>}
* @private
*/
this.keys_ = {};
};
goog.inherits(goog.events.EventHandler, goog.Disposable);
/**
* Utility array used to unify the cases of listening for an array of types
* and listening for a single event, without using recursion or allocating
* an array each time.
* @type {!Array<string>}
* @const
* @private
*/
goog.events.EventHandler.typeArray_ = [];
/**
* Listen to an event on a Listenable. If the function is omitted then the
* EventHandler's handleEvent method will be used.
* @param {goog.events.ListenableType} src Event source.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type to listen for or array of event types.
* @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
* opt_fn Optional callback function to be used as the listener or an object
* with handleEvent function.
* @param {(boolean|!AddEventListenerOptions)=} opt_options
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template EVENTOBJ, THIS
*/
goog.events.EventHandler.prototype.listen = function(
src, type, opt_fn, opt_options) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
return self.listen_(src, type, opt_fn, opt_options);
};
/**
* Listen to an event on a Listenable. If the function is omitted then the
* EventHandler's handleEvent method will be used.
* @param {goog.events.ListenableType} src Event source.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type to listen for or array of event types.
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
* null|undefined} fn Optional callback function to be used as the
* listener or an object with handleEvent function.
* @param {boolean|!AddEventListenerOptions|undefined} options
* @param {T} scope Object in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template T, EVENTOBJ, THIS
*/
goog.events.EventHandler.prototype.listenWithScope = function(
src, type, fn, options, scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
// TODO(mknichel): Deprecate this function.
return self.listen_(src, type, fn, options, scope);
};
/**
* Listen to an event on a Listenable. If the function is omitted then the
* EventHandler's handleEvent method will be used.
* @param {goog.events.ListenableType} src Event source.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type to listen for or array of event types.
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
* Optional callback function to be used as the listener or an object with
* handleEvent function.
* @param {(boolean|!AddEventListenerOptions)=} opt_options
* @param {Object=} opt_scope Object in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template EVENTOBJ, THIS
* @private
*/
goog.events.EventHandler.prototype.listen_ = function(
src, type, opt_fn, opt_options, opt_scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
if (!Array.isArray(type)) {
if (type) {
goog.events.EventHandler.typeArray_[0] = type.toString();
}
type = goog.events.EventHandler.typeArray_;
}
for (var i = 0; i < type.length; i++) {
var listenerObj = goog.events.listen(
src, type[i], opt_fn || self.handleEvent, opt_options || false,
opt_scope || self.handler_ || self);
if (!listenerObj) {
// When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
// (goog.events.CaptureSimulationMode) in IE8-, it will return null
// value.
return self;
}
var key = listenerObj.key;
self.keys_[key] = listenerObj;
}
return self;
};
/**
* Listen to an event on a Listenable. If the function is omitted, then the
* EventHandler's handleEvent method will be used. After the event has fired the
* event listener is removed from the target. If an array of event types is
* provided, each event type will be listened to once.
* @param {goog.events.ListenableType} src Event source.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type to listen for or array of event types.
* @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
* opt_fn
* Optional callback function to be used as the listener or an object with
* handleEvent function.
* @param {(boolean|!AddEventListenerOptions)=} opt_options
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template EVENTOBJ, THIS
*/
goog.events.EventHandler.prototype.listenOnce = function(
src, type, opt_fn, opt_options) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
return self.listenOnce_(src, type, opt_fn, opt_options);
};
/**
* Listen to an event on a Listenable. If the function is omitted, then the
* EventHandler's handleEvent method will be used. After the event has fired the
* event listener is removed from the target. If an array of event types is
* provided, each event type will be listened to once.
* @param {goog.events.ListenableType} src Event source.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type to listen for or array of event types.
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
* null|undefined} fn Optional callback function to be used as the
* listener or an object with handleEvent function.
* @param {boolean|undefined} capture Optional whether to use capture phase.
* @param {T} scope Object in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template T, EVENTOBJ, THIS
*/
goog.events.EventHandler.prototype.listenOnceWithScope = function(
src, type, fn, capture, scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
// TODO(mknichel): Deprecate this function.
return self.listenOnce_(src, type, fn, capture, scope);
};
/**
* Listen to an event on a Listenable. If the function is omitted, then the
* EventHandler's handleEvent method will be used. After the event has fired
* the event listener is removed from the target. If an array of event types is
* provided, each event type will be listened to once.
* @param {goog.events.ListenableType} src Event source.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type to listen for or array of event types.
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
* Optional callback function to be used as the listener or an object with
* handleEvent function.
* @param {(boolean|!AddEventListenerOptions)=} opt_options
* @param {Object=} opt_scope Object in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template EVENTOBJ, THIS
* @private
*/
goog.events.EventHandler.prototype.listenOnce_ = function(
src, type, opt_fn, opt_options, opt_scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
if (Array.isArray(type)) {
for (var i = 0; i < type.length; i++) {
self.listenOnce_(src, type[i], opt_fn, opt_options, opt_scope);
}
} else {
var listenerObj = goog.events.listenOnce(
src, type, opt_fn || self.handleEvent, opt_options,
opt_scope || self.handler_ || self);
if (!listenerObj) {
// When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
// (goog.events.CaptureSimulationMode) in IE8-, it will return null
// value.
return self;
}
var key = listenerObj.key;
self.keys_[key] = listenerObj;
}
return self;
};
/**
* Adds an event listener with a specific event wrapper on a DOM Node or an
* object that has implemented {@link goog.events.EventTarget}. A listener can
* only be added once to an object.
*
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
* events on.
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
* @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener
* Callback method, or an object with a handleEvent function.
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
* false).
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template THIS
*/
goog.events.EventHandler.prototype.listenWithWrapper = function(
src, wrapper, listener, opt_capt) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
// TODO(mknichel): Remove the opt_scope from this function and then
// templatize it.
return self.listenWithWrapper_(src, wrapper, listener, opt_capt);
};
/**
* Adds an event listener with a specific event wrapper on a DOM Node or an
* object that has implemented {@link goog.events.EventTarget}. A listener can
* only be added once to an object.
*
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
* events on.
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
* @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null}
* listener Optional callback function to be used as the
* listener or an object with handleEvent function.
* @param {boolean|undefined} capture Optional whether to use capture phase.
* @param {T} scope Object in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template T, THIS
*/
goog.events.EventHandler.prototype.listenWithWrapperAndScope = function(
src, wrapper, listener, capture, scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
// TODO(mknichel): Deprecate this function.
return self.listenWithWrapper_(src, wrapper, listener, capture, scope);
};
/**
* Adds an event listener with a specific event wrapper on a DOM Node or an
* object that has implemented {@link goog.events.EventTarget}. A listener can
* only be added once to an object.
*
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
* events on.
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
* @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
* method, or an object with a handleEvent function.
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
* false).
* @param {Object=} opt_scope Element in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template THIS
* @private
*/
goog.events.EventHandler.prototype.listenWithWrapper_ = function(
src, wrapper, listener, opt_capt, opt_scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
wrapper.listen(
src, listener, opt_capt, opt_scope || self.handler_ || self, self);
return self;
};
/**
* @return {number} Number of listeners registered by this handler.
*/
goog.events.EventHandler.prototype.getListenerCount = function() {
'use strict';
var count = 0;
for (var key in this.keys_) {
if (Object.prototype.hasOwnProperty.call(this.keys_, key)) {
count++;
}
}
return count;
};
/**
* Unlistens on an event.
* @param {goog.events.ListenableType} src Event source.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type or array of event types to unlisten to.
* @param {function(this:?, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
* opt_fn Optional callback function to be used as the listener or an object
* with handleEvent function.
* @param {(boolean|!EventListenerOptions)=} opt_options
* @param {Object=} opt_scope Object in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template EVENTOBJ, THIS
*/
goog.events.EventHandler.prototype.unlisten = function(
src, type, opt_fn, opt_options, opt_scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
if (Array.isArray(type)) {
for (var i = 0; i < type.length; i++) {
self.unlisten(src, type[i], opt_fn, opt_options, opt_scope);
}
} else {
var capture =
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
var listener = goog.events.getListener(
src, type, opt_fn || self.handleEvent, capture,
opt_scope || self.handler_ || self);
if (listener) {
goog.events.unlistenByKey(listener);
delete self.keys_[listener.key];
}
}
return self;
};
/**
* Removes an event listener which was added with listenWithWrapper().
*
* @param {EventTarget|goog.events.EventTarget} src The target to stop
* listening to events on.
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
* @param {function(?):?|{handleEvent:function(?):?}|null} listener The
* listener function to remove.
* @param {boolean=} opt_capt In DOM-compliant browsers, this determines
* whether the listener is fired during the capture or bubble phase of the
* event.
* @param {Object=} opt_scope Element in whose scope to call the listener.
* @return {THIS} This object, allowing for chaining of calls.
* @this {THIS}
* @template THIS
*/
goog.events.EventHandler.prototype.unlistenWithWrapper = function(
src, wrapper, listener, opt_capt, opt_scope) {
'use strict';
var self = /** @type {!goog.events.EventHandler} */ (this);
wrapper.unlisten(
src, listener, opt_capt, opt_scope || self.handler_ || self, self);
return self;
};
/**
* Unlistens to all events.
*/
goog.events.EventHandler.prototype.removeAll = function() {
'use strict';
goog.object.forEach(this.keys_, function(listenerObj, key) {
'use strict';
if (this.keys_.hasOwnProperty(key)) {
goog.events.unlistenByKey(listenerObj);
}
}, this);
this.keys_ = {};
};
/**
* Disposes of this EventHandler and removes all listeners that it registered.
* @override
* @protected
*/
goog.events.EventHandler.prototype.disposeInternal = function() {
'use strict';
goog.events.EventHandler.superClass_.disposeInternal.call(this);
this.removeAll();
};
/**
* Default event handler
* @param {goog.events.Event} e Event object.
*/
goog.events.EventHandler.prototype.handleEvent = function(e) {
'use strict';
throw new Error('EventHandler.handleEvent not implemented');
};
+41
View File
@@ -0,0 +1,41 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('goog.events.EventId');
/**
* A templated class that is used when registering for events. Typical usage:
*
* /** @type {goog.events.EventId<MyEventObj>} *\
* var myEventId = new goog.events.EventId(
* goog.events.getUniqueId(('someEvent'));
*
* // No need to cast or declare here since the compiler knows the
* // correct type of 'evt' (MyEventObj).
* something.listen(myEventId, function(evt) {});
*
* @param {string} eventId
* @template T
* @constructor
* @struct
* @final
*/
goog.events.EventId = function(eventId) {
'use strict';
/** @const */ this.id = eventId;
};
/**
* @override
* @return {string}
*/
goog.events.EventId.prototype.toString = function() {
'use strict';
return this.id;
};
+24
View File
@@ -0,0 +1,24 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview A typedef for event like objects that are dispatchable via the
* goog.events.dispatchEvent function.
*/
goog.provide('goog.events.EventLike');
goog.requireType('goog.events.Event');
goog.requireType('goog.events.EventId');
/**
* A typedef for event like objects that are dispatchable via the
* goog.events.dispatchEvent function. strings are treated as the type for a
* goog.events.Event. Objects are treated as an extension of a new
* goog.events.Event with the type property of the object being used as the type
* of the Event.
* @typedef {string|Object|goog.events.Event|goog.events.EventId}
*/
goog.events.EventLike;
+960
View File
@@ -0,0 +1,960 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview An event manager for both native browser event
* targets and custom JavaScript event targets
* (`goog.events.Listenable`). This provides an abstraction
* over browsers' event systems.
*
* It also provides a simulation of W3C event model's capture phase in
* Internet Explorer (IE 8 and below). Caveat: the simulation does not
* interact well with listeners registered directly on the elements
* (bypassing goog.events) or even with listeners registered via
* goog.events in a separate JS binary. In these cases, we provide
* no ordering guarantees.
*
* The listeners will receive a "patched" event object. Such event object
* contains normalized values for certain event properties that differs in
* different browsers.
*
* Example usage:
* <pre>
* goog.events.listen(myNode, 'click', function(e) { alert('woo') });
* goog.events.listen(myNode, 'mouseover', mouseHandler, true);
* goog.events.unlisten(myNode, 'mouseover', mouseHandler, true);
* goog.events.removeAll(myNode);
* </pre>
*
* in IE and event object patching]
*
* @see ../demos/events.html
* @see ../demos/event-propagation.html
* @see ../demos/stopevent.html
*/
// IMPLEMENTATION NOTES:
// goog.events stores an auxiliary data structure on each EventTarget
// source being listened on. This allows us to take advantage of GC,
// having the data structure GC'd when the EventTarget is GC'd. This
// GC behavior is equivalent to using W3C DOM Events directly.
goog.provide('goog.events');
goog.provide('goog.events.CaptureSimulationMode');
goog.provide('goog.events.Key');
goog.provide('goog.events.ListenableType');
goog.require('goog.asserts');
goog.require('goog.debug.entryPointRegistry');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.BrowserFeature');
goog.require('goog.events.Listenable');
goog.require('goog.events.ListenerMap');
goog.requireType('goog.debug.ErrorHandler');
goog.requireType('goog.events.EventId');
goog.requireType('goog.events.EventLike');
goog.requireType('goog.events.EventWrapper');
goog.requireType('goog.events.ListenableKey');
goog.requireType('goog.events.Listener');
/**
* @typedef {number|goog.events.ListenableKey}
*/
goog.events.Key;
/**
* @typedef {EventTarget|goog.events.Listenable}
*/
goog.events.ListenableType;
/**
* Property name on a native event target for the listener map
* associated with the event target.
* @private @const {string}
*/
goog.events.LISTENER_MAP_PROP_ = 'closure_lm_' + ((Math.random() * 1e6) | 0);
/**
* String used to prepend to IE event types.
* @const
* @private
*/
goog.events.onString_ = 'on';
/**
* Map of computed "on<eventname>" strings for IE event types. Caching
* this removes an extra object allocation in goog.events.listen which
* improves IE6 performance.
* @const
* @dict
* @private
*/
goog.events.onStringMap_ = {};
/**
* @enum {number} Different capture simulation mode for IE8-.
*/
goog.events.CaptureSimulationMode = {
/**
* Does not perform capture simulation. Will asserts in IE8- when you
* add capture listeners.
*/
OFF_AND_FAIL: 0,
/**
* Does not perform capture simulation, silently ignore capture
* listeners.
*/
OFF_AND_SILENT: 1,
/**
* Performs capture simulation.
*/
ON: 2
};
/**
* @define {number} The capture simulation mode for IE8-. By default,
* this is ON.
*/
goog.events.CAPTURE_SIMULATION_MODE =
goog.define('goog.events.CAPTURE_SIMULATION_MODE', 2);
/**
* Estimated count of total native listeners.
* @private {number}
*/
goog.events.listenerCountEstimate_ = 0;
/**
* Adds an event listener for a specific event on a native event
* target (such as a DOM element) or an object that has implemented
* {@link goog.events.Listenable}. A listener can only be added once
* to an object and if it is added again the key for the listener is
* returned. Note that if the existing listener is a one-off listener
* (registered via listenOnce), it will no longer be a one-off
* listener after a call to listen().
*
* @param {EventTarget|goog.events.Listenable} src The node to listen
* to events on.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type or array of event types.
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null}
* listener Callback method, or an object with a handleEvent function.
* WARNING: passing an Object is now softly deprecated.
* @param {(boolean|!AddEventListenerOptions)=} opt_options
* @param {T=} opt_handler Element in whose scope to call the listener.
* @return {goog.events.Key} Unique key for the listener.
* @template T,EVENTOBJ
*/
goog.events.listen = function(src, type, listener, opt_options, opt_handler) {
'use strict';
if (opt_options && opt_options.once) {
return goog.events.listenOnce(
src, type, listener, opt_options, opt_handler);
}
if (Array.isArray(type)) {
for (var i = 0; i < type.length; i++) {
goog.events.listen(src, type[i], listener, opt_options, opt_handler);
}
return null;
}
listener = goog.events.wrapListener(listener);
if (goog.events.Listenable.isImplementedBy(src)) {
var capture =
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
return src.listen(
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
opt_handler);
} else {
return goog.events.listen_(
/** @type {!EventTarget} */ (src), type, listener,
/* callOnce */ false, opt_options, opt_handler);
}
};
/**
* Adds an event listener for a specific event on a native event
* target. A listener can only be added once to an object and if it
* is added again the key for the listener is returned.
*
* Note that a one-off listener will not change an existing listener,
* if any. On the other hand a normal listener will change existing
* one-off listener to become a normal listener.
*
* @param {EventTarget} src The node to listen to events on.
* @param {string|?goog.events.EventId<EVENTOBJ>} type Event type.
* @param {!Function} listener Callback function.
* @param {boolean} callOnce Whether the listener is a one-off
* listener or otherwise.
* @param {(boolean|!AddEventListenerOptions)=} opt_options
* @param {Object=} opt_handler Element in whose scope to call the listener.
* @return {goog.events.ListenableKey} Unique key for the listener.
* @template EVENTOBJ
* @private
*/
goog.events.listen_ = function(
src, type, listener, callOnce, opt_options, opt_handler) {
'use strict';
if (!type) {
throw new Error('Invalid event type');
}
var capture =
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
var listenerMap = goog.events.getListenerMap_(src);
if (!listenerMap) {
src[goog.events.LISTENER_MAP_PROP_] = listenerMap =
new goog.events.ListenerMap(src);
}
var listenerObj = /** @type {goog.events.Listener} */ (
listenerMap.add(type, listener, callOnce, capture, opt_handler));
// If the listenerObj already has a proxy, it has been set up
// previously. We simply return.
if (listenerObj.proxy) {
return listenerObj;
}
var proxy = goog.events.getProxy();
listenerObj.proxy = proxy;
proxy.src = src;
proxy.listener = listenerObj;
// Attach the proxy through the browser's API
if (src.addEventListener) {
// Don't pass an object as `capture` if the browser doesn't support that.
if (!goog.events.BrowserFeature.PASSIVE_EVENTS) {
opt_options = capture;
}
// Don't break tests that expect a boolean.
if (opt_options === undefined) opt_options = false;
src.addEventListener(type.toString(), proxy, opt_options);
} else if (src.attachEvent) {
// The else if above used to be an unconditional else. It would call
// attachEvent come gws or high water. This would sometimes throw an
// exception on IE11, spoiling the day of some callers. The previous
// incarnation of this code, from 2007, indicates that it replaced an
// earlier still version that caused excess allocations on IE6.
src.attachEvent(goog.events.getOnString_(type.toString()), proxy);
} else if (src.addListener && src.removeListener) {
// In IE, MediaQueryList uses addListener() insteadd of addEventListener. In
// Safari, there is no global for the MediaQueryList constructor, so we just
// check whether the object "looks like" MediaQueryList.
goog.asserts.assert(
type === 'change', 'MediaQueryList only has a change event');
src.addListener(proxy);
} else {
throw new Error('addEventListener and attachEvent are unavailable.');
}
goog.events.listenerCountEstimate_++;
return listenerObj;
};
/**
* Helper function for returning a proxy function.
* @return {!Function} A new or reused function object.
*/
goog.events.getProxy = function() {
'use strict';
const proxyCallbackFunction = goog.events.handleBrowserEvent_;
const f = function(eventObject) {
return proxyCallbackFunction.call(f.src, f.listener, eventObject);
};
return f;
};
/**
* Adds an event listener for a specific event on a native event
* target (such as a DOM element) or an object that has implemented
* {@link goog.events.Listenable}. After the event has fired the event
* listener is removed from the target.
*
* If an existing listener already exists, listenOnce will do
* nothing. In particular, if the listener was previously registered
* via listen(), listenOnce() will not turn the listener into a
* one-off listener. Similarly, if there is already an existing
* one-off listener, listenOnce does not modify the listeners (it is
* still a once listener).
*
* @param {EventTarget|goog.events.Listenable} src The node to listen
* to events on.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type or array of event types.
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null}
* listener Callback method.
* @param {(boolean|!AddEventListenerOptions)=} opt_options
* @param {T=} opt_handler Element in whose scope to call the listener.
* @return {goog.events.Key} Unique key for the listener.
* @template T,EVENTOBJ
*/
goog.events.listenOnce = function(
src, type, listener, opt_options, opt_handler) {
'use strict';
if (Array.isArray(type)) {
for (var i = 0; i < type.length; i++) {
goog.events.listenOnce(src, type[i], listener, opt_options, opt_handler);
}
return null;
}
listener = goog.events.wrapListener(listener);
if (goog.events.Listenable.isImplementedBy(src)) {
var capture =
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
return src.listenOnce(
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
opt_handler);
} else {
return goog.events.listen_(
/** @type {!EventTarget} */ (src), type, listener,
/* callOnce */ true, opt_options, opt_handler);
}
};
/**
* Adds an event listener with a specific event wrapper on a DOM Node or an
* object that has implemented {@link goog.events.Listenable}. A listener can
* only be added once to an object.
*
* @param {EventTarget|goog.events.Listenable} src The target to
* listen to events on.
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
* @param {function(this:T, ?):?|{handleEvent:function(?):?}|null} listener
* Callback method, or an object with a handleEvent function.
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
* false).
* @param {T=} opt_handler Element in whose scope to call the listener.
* @template T
*/
goog.events.listenWithWrapper = function(
src, wrapper, listener, opt_capt, opt_handler) {
'use strict';
wrapper.listen(src, listener, opt_capt, opt_handler);
};
/**
* Removes an event listener which was added with listen().
*
* @param {EventTarget|goog.events.Listenable} src The target to stop
* listening to events on.
* @param {string|Array<string>|
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
* type Event type or array of event types to unlisten to.
* @param {function(?):?|{handleEvent:function(?):?}|null} listener The
* listener function to remove.
* @param {(boolean|!EventListenerOptions)=} opt_options
* whether the listener is fired during the capture or bubble phase of the
* event.
* @param {Object=} opt_handler Element in whose scope to call the listener.
* @return {?boolean} indicating whether the listener was there to remove.
* @template EVENTOBJ
*/
goog.events.unlisten = function(src, type, listener, opt_options, opt_handler) {
'use strict';
if (Array.isArray(type)) {
for (var i = 0; i < type.length; i++) {
goog.events.unlisten(src, type[i], listener, opt_options, opt_handler);
}
return null;
}
var capture =
goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
listener = goog.events.wrapListener(listener);
if (goog.events.Listenable.isImplementedBy(src)) {
return src.unlisten(
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
opt_handler);
}
if (!src) {
// TODO(chrishenry): We should tighten the API to only accept
// non-null objects, or add an assertion here.
return false;
}
var listenerMap = goog.events.getListenerMap_(
/** @type {!EventTarget} */ (src));
if (listenerMap) {
var listenerObj = listenerMap.getListener(
/** @type {string|!goog.events.EventId} */ (type), listener, capture,
opt_handler);
if (listenerObj) {
return goog.events.unlistenByKey(listenerObj);
}
}
return false;
};
/**
* Removes an event listener which was added with listen() by the key
* returned by listen().
*
* @param {goog.events.Key} key The key returned by listen() for this
* event listener.
* @return {boolean} indicating whether the listener was there to remove.
*/
goog.events.unlistenByKey = function(key) {
'use strict';
// TODO(chrishenry): Remove this check when tests that rely on this
// are fixed.
if (typeof key === 'number') {
return false;
}
var listener = key;
if (!listener || listener.removed) {
return false;
}
var src = listener.src;
if (goog.events.Listenable.isImplementedBy(src)) {
return /** @type {!goog.events.Listenable} */ (src).unlistenByKey(listener);
}
var type = listener.type;
var proxy = listener.proxy;
if (src.removeEventListener) {
src.removeEventListener(type, proxy, listener.capture);
} else if (src.detachEvent) {
src.detachEvent(goog.events.getOnString_(type), proxy);
} else if (src.addListener && src.removeListener) {
src.removeListener(proxy);
}
goog.events.listenerCountEstimate_--;
var listenerMap = goog.events.getListenerMap_(
/** @type {!EventTarget} */ (src));
// TODO(chrishenry): Try to remove this conditional and execute the
// first branch always. This should be safe.
if (listenerMap) {
listenerMap.removeByKey(listener);
if (listenerMap.getTypeCount() == 0) {
// Null the src, just because this is simple to do (and useful
// for IE <= 7).
listenerMap.src = null;
// We don't use delete here because IE does not allow delete
// on a window object.
src[goog.events.LISTENER_MAP_PROP_] = null;
}
} else {
/** @type {!goog.events.Listener} */ (listener).markAsRemoved();
}
return true;
};
/**
* Removes an event listener which was added with listenWithWrapper().
*
* @param {EventTarget|goog.events.Listenable} src The target to stop
* listening to events on.
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
* @param {function(?):?|{handleEvent:function(?):?}|null} listener The
* listener function to remove.
* @param {boolean=} opt_capt In DOM-compliant browsers, this determines
* whether the listener is fired during the capture or bubble phase of the
* event.
* @param {Object=} opt_handler Element in whose scope to call the listener.
*/
goog.events.unlistenWithWrapper = function(
src, wrapper, listener, opt_capt, opt_handler) {
'use strict';
wrapper.unlisten(src, listener, opt_capt, opt_handler);
};
/**
* Removes all listeners from an object. You can also optionally
* remove listeners of a particular type.
*
* @param {Object|undefined} obj Object to remove listeners from. Must be an
* EventTarget or a goog.events.Listenable.
* @param {string|!goog.events.EventId=} opt_type Type of event to remove.
* Default is all types.
* @return {number} Number of listeners removed.
*/
goog.events.removeAll = function(obj, opt_type) {
'use strict';
// TODO(chrishenry): Change the type of obj to
// (!EventTarget|!goog.events.Listenable).
if (!obj) {
return 0;
}
if (goog.events.Listenable.isImplementedBy(obj)) {
return /** @type {?} */ (obj).removeAllListeners(opt_type);
}
var listenerMap = goog.events.getListenerMap_(
/** @type {!EventTarget} */ (obj));
if (!listenerMap) {
return 0;
}
var count = 0;
var typeStr = opt_type && opt_type.toString();
for (var type in listenerMap.listeners) {
if (!typeStr || type == typeStr) {
// Clone so that we don't need to worry about unlistenByKey
// changing the content of the ListenerMap.
var listeners = listenerMap.listeners[type].concat();
for (var i = 0; i < listeners.length; ++i) {
if (goog.events.unlistenByKey(listeners[i])) {
++count;
}
}
}
}
return count;
};
/**
* Gets the listeners for a given object, type and capture phase.
*
* @param {Object} obj Object to get listeners for.
* @param {string|!goog.events.EventId} type Event type.
* @param {boolean} capture Capture phase?.
* @return {!Array<!goog.events.Listener>} Array of listener objects.
*/
goog.events.getListeners = function(obj, type, capture) {
'use strict';
if (goog.events.Listenable.isImplementedBy(obj)) {
return /** @type {!goog.events.Listenable} */ (obj).getListeners(
type, capture);
} else {
if (!obj) {
// TODO(chrishenry): We should tighten the API to accept
// !EventTarget|goog.events.Listenable, and add an assertion here.
return [];
}
var listenerMap = goog.events.getListenerMap_(
/** @type {!EventTarget} */ (obj));
return listenerMap ? listenerMap.getListeners(type, capture) : [];
}
};
/**
* Gets the goog.events.Listener for the event or null if no such listener is
* in use.
*
* @param {EventTarget|goog.events.Listenable} src The target from
* which to get listeners.
* @param {?string|!goog.events.EventId<EVENTOBJ>} type The type of the event.
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null} listener The
* listener function to get.
* @param {boolean=} opt_capt In DOM-compliant browsers, this determines
* whether the listener is fired during the
* capture or bubble phase of the event.
* @param {Object=} opt_handler Element in whose scope to call the listener.
* @return {goog.events.ListenableKey} the found listener or null if not found.
* @template EVENTOBJ
*/
goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) {
'use strict';
// TODO(chrishenry): Change type from ?string to string, or add assertion.
type = /** @type {string} */ (type);
listener = goog.events.wrapListener(listener);
var capture = !!opt_capt;
if (goog.events.Listenable.isImplementedBy(src)) {
return src.getListener(type, listener, capture, opt_handler);
}
if (!src) {
// TODO(chrishenry): We should tighten the API to only accept
// non-null objects, or add an assertion here.
return null;
}
var listenerMap = goog.events.getListenerMap_(
/** @type {!EventTarget} */ (src));
if (listenerMap) {
return listenerMap.getListener(type, listener, capture, opt_handler);
}
return null;
};
/**
* Returns whether an event target has any active listeners matching the
* specified signature. If either the type or capture parameters are
* unspecified, the function will match on the remaining criteria.
*
* @param {EventTarget|goog.events.Listenable} obj Target to get
* listeners for.
* @param {string|!goog.events.EventId=} opt_type Event type.
* @param {boolean=} opt_capture Whether to check for capture or bubble-phase
* listeners.
* @return {boolean} Whether an event target has one or more listeners matching
* the requested type and/or capture phase.
*/
goog.events.hasListener = function(obj, opt_type, opt_capture) {
'use strict';
if (goog.events.Listenable.isImplementedBy(obj)) {
return obj.hasListener(opt_type, opt_capture);
}
var listenerMap = goog.events.getListenerMap_(
/** @type {!EventTarget} */ (obj));
return !!listenerMap && listenerMap.hasListener(opt_type, opt_capture);
};
/**
* Provides a nice string showing the normalized event objects public members
* @param {Object} e Event Object.
* @return {string} String of the public members of the normalized event object.
*/
goog.events.expose = function(e) {
'use strict';
var str = [];
for (var key in e) {
if (e[key] && e[key].id) {
str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')');
} else {
str.push(key + ' = ' + e[key]);
}
}
return str.join('\n');
};
/**
* Returns a string with on prepended to the specified type. This is used for IE
* which expects "on" to be prepended. This function caches the string in order
* to avoid extra allocations in steady state.
* @param {string} type Event type.
* @return {string} The type string with 'on' prepended.
* @private
*/
goog.events.getOnString_ = function(type) {
'use strict';
if (type in goog.events.onStringMap_) {
return goog.events.onStringMap_[type];
}
return goog.events.onStringMap_[type] = goog.events.onString_ + type;
};
/**
* Fires an object's listeners of a particular type and phase
*
* @param {Object} obj Object whose listeners to call.
* @param {string|!goog.events.EventId} type Event type.
* @param {boolean} capture Which event phase.
* @param {Object} eventObject Event object to be passed to listener.
* @return {boolean} True if all listeners returned true else false.
*/
goog.events.fireListeners = function(obj, type, capture, eventObject) {
'use strict';
if (goog.events.Listenable.isImplementedBy(obj)) {
return /** @type {!goog.events.Listenable} */ (obj).fireListeners(
type, capture, eventObject);
}
return goog.events.fireListeners_(obj, type, capture, eventObject);
};
/**
* Fires an object's listeners of a particular type and phase.
* @param {Object} obj Object whose listeners to call.
* @param {string|!goog.events.EventId} type Event type.
* @param {boolean} capture Which event phase.
* @param {Object} eventObject Event object to be passed to listener.
* @return {boolean} True if all listeners returned true else false.
* @private
*/
goog.events.fireListeners_ = function(obj, type, capture, eventObject) {
'use strict';
/** @type {boolean} */
var retval = true;
var listenerMap = goog.events.getListenerMap_(
/** @type {EventTarget} */ (obj));
if (listenerMap) {
// TODO(chrishenry): Original code avoids array creation when there
// is no listener, so we do the same. If this optimization turns
// out to be not required, we can replace this with
// listenerMap.getListeners(type, capture) instead, which is simpler.
var listenerArray = listenerMap.listeners[type.toString()];
if (listenerArray) {
listenerArray = listenerArray.concat();
for (var i = 0; i < listenerArray.length; i++) {
var listener = listenerArray[i];
// We might not have a listener if the listener was removed.
if (listener && listener.capture == capture && !listener.removed) {
var result = goog.events.fireListener(listener, eventObject);
retval = retval && (result !== false);
}
}
}
}
return retval;
};
/**
* Fires a listener with a set of arguments
*
* @param {goog.events.Listener} listener The listener object to call.
* @param {Object} eventObject The event object to pass to the listener.
* @return {*} Result of listener.
*/
goog.events.fireListener = function(listener, eventObject) {
'use strict';
var listenerFn = listener.listener;
var listenerHandler = listener.handler || listener.src;
if (listener.callOnce) {
goog.events.unlistenByKey(listener);
}
return listenerFn.call(listenerHandler, eventObject);
};
/**
* Gets the total number of listeners currently in the system.
* @return {number} Number of listeners.
* @deprecated This returns estimated count, now that Closure no longer
* stores a central listener registry. We still return an estimation
* to keep existing listener-related tests passing. In the near future,
* this function will be removed.
*/
goog.events.getTotalListenerCount = function() {
'use strict';
return goog.events.listenerCountEstimate_;
};
/**
* Dispatches an event (or event like object) and calls all listeners
* listening for events of this type. The type of the event is decided by the
* type property on the event object.
*
* If any of the listeners returns false OR calls preventDefault then this
* function will return false. If one of the capture listeners calls
* stopPropagation, then the bubble listeners won't fire.
*
* @param {goog.events.Listenable} src The event target.
* @param {goog.events.EventLike} e Event object.
* @return {boolean} If anyone called preventDefault on the event object (or
* if any of the handlers returns false) this will also return false.
* If there are no handlers, or if all handlers return true, this returns
* true.
*/
goog.events.dispatchEvent = function(src, e) {
'use strict';
goog.asserts.assert(
goog.events.Listenable.isImplementedBy(src),
'Can not use goog.events.dispatchEvent with ' +
'non-goog.events.Listenable instance.');
return src.dispatchEvent(e);
};
/**
* Installs exception protection for the browser event entry point using the
* given error handler.
*
* @param {goog.debug.ErrorHandler} errorHandler Error handler with which to
* protect the entry point.
*/
goog.events.protectBrowserEventEntryPoint = function(errorHandler) {
'use strict';
goog.events.handleBrowserEvent_ =
errorHandler.protectEntryPoint(goog.events.handleBrowserEvent_);
};
/**
* Handles an event and dispatches it to the correct listeners. This
* function is a proxy for the real listener the user specified.
*
* @param {goog.events.Listener} listener The listener object.
* @param {Event=} opt_evt Optional event object that gets passed in via the
* native event handlers.
* @return {*} Result of the event handler.
* @this {EventTarget} The object or Element that fired the event.
* @private
*/
goog.events.handleBrowserEvent_ = function(listener, opt_evt) {
'use strict';
if (listener.removed) {
return true;
}
// Otherwise, simply fire the listener.
return goog.events.fireListener(
listener, new goog.events.BrowserEvent(opt_evt, this));
};
/**
* This is used to mark the IE event object so we do not do the Closure pass
* twice for a bubbling event.
* @param {Event} e The IE browser event.
* @private
*/
goog.events.markIeEvent_ = function(e) {
'use strict';
// Only the keyCode and the returnValue can be changed. We use keyCode for
// non keyboard events.
// event.returnValue is a bit more tricky. It is undefined by default. A
// boolean false prevents the default action. In a window.onbeforeunload and
// the returnValue is non undefined it will be alerted. However, we will only
// modify the returnValue for keyboard events. We can get a problem if non
// closure events sets the keyCode or the returnValue
var useReturnValue = false;
if (e.keyCode == 0) {
// We cannot change the keyCode in case that srcElement is input[type=file].
// We could test that that is the case but that would allocate 3 objects.
// If we use try/catch we will only allocate extra objects in the case of a
// failure.
try {
e.keyCode = -1;
return;
} catch (ex) {
useReturnValue = true;
}
}
if (useReturnValue ||
/** @type {boolean|undefined} */ (e.returnValue) == undefined) {
e.returnValue = true;
}
};
/**
* This is used to check if an IE event has already been handled by the Closure
* system so we do not do the Closure pass twice for a bubbling event.
* @param {Event} e The IE browser event.
* @return {boolean} True if the event object has been marked.
* @private
*/
goog.events.isMarkedIeEvent_ = function(e) {
'use strict';
return e.keyCode < 0 || e.returnValue != undefined;
};
/**
* Counter to create unique event ids.
* @private {number}
*/
goog.events.uniqueIdCounter_ = 0;
/**
* Creates a unique event id.
*
* @param {string} identifier The identifier.
* @return {string} A unique identifier.
* @idGenerator {unique}
*/
goog.events.getUniqueId = function(identifier) {
'use strict';
return identifier + '_' + goog.events.uniqueIdCounter_++;
};
/**
* @param {EventTarget} src The source object.
* @return {goog.events.ListenerMap} A listener map for the given
* source object, or null if none exists.
* @private
*/
goog.events.getListenerMap_ = function(src) {
'use strict';
var listenerMap = src[goog.events.LISTENER_MAP_PROP_];
// IE serializes the property as well (e.g. when serializing outer
// HTML). So we must check that the value is of the correct type.
return listenerMap instanceof goog.events.ListenerMap ? listenerMap : null;
};
/**
* Expando property for listener function wrapper for Object with
* handleEvent.
* @private @const {string}
*/
goog.events.LISTENER_WRAPPER_PROP_ =
'__closure_events_fn_' + ((Math.random() * 1e9) >>> 0);
/**
* @param {Object|Function} listener The listener function or an
* object that contains handleEvent method.
* @return {!Function} Either the original function or a function that
* calls obj.handleEvent. If the same listener is passed to this
* function more than once, the same function is guaranteed to be
* returned.
*/
goog.events.wrapListener = function(listener) {
'use strict';
goog.asserts.assert(listener, 'Listener can not be null.');
if (typeof listener === 'function') {
return listener;
}
goog.asserts.assert(
listener.handleEvent, 'An object listener must have handleEvent method.');
if (!listener[goog.events.LISTENER_WRAPPER_PROP_]) {
listener[goog.events.LISTENER_WRAPPER_PROP_] = function(e) {
'use strict';
return /** @type {?} */ (listener).handleEvent(e);
};
}
return listener[goog.events.LISTENER_WRAPPER_PROP_];
};
// Register the browser event handler as an entry point, so that
// it can be monitored for exception handling, etc.
goog.debug.entryPointRegistry.register(
/**
* @param {function(!Function): !Function} transformer The transforming
* function.
*/
function(transformer) {
'use strict';
goog.events.handleBrowserEvent_ =
transformer(goog.events.handleBrowserEvent_);
});
+495
View File
@@ -0,0 +1,495 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview A disposable implementation of a custom
* listenable/event target. See also: documentation for
* `goog.events.Listenable`.
*
* @see ../demos/eventtarget.html
* @see goog.events.Listenable
*/
goog.provide('goog.events.EventTarget');
goog.require('goog.Disposable');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.Listenable');
goog.require('goog.events.ListenerMap');
goog.require('goog.object');
goog.requireType('goog.events.EventId');
goog.requireType('goog.events.EventLike');
goog.requireType('goog.events.ListenableKey');
/**
* An implementation of `goog.events.Listenable` with full W3C
* EventTarget-like support (capture/bubble mechanism, stopping event
* propagation, preventing default actions).
*
* You may subclass this class to turn your class into a Listenable.
*
* Unless propagation is stopped, an event dispatched by an
* EventTarget will bubble to the parent returned by
* `getParentEventTarget`. To set the parent, call
* `setParentEventTarget`. Subclasses that don't support
* changing the parent can override the setter to throw an error.
*
* Example usage:
* <pre>
* var source = new goog.events.EventTarget();
* function handleEvent(e) {
* alert('Type: ' + e.type + '; Target: ' + e.target);
* }
* source.listen('foo', handleEvent);
* // Or: goog.events.listen(source, 'foo', handleEvent);
* ...
* source.dispatchEvent('foo'); // will call handleEvent
* ...
* source.unlisten('foo', handleEvent);
* // Or: goog.events.unlisten(source, 'foo', handleEvent);
* </pre>
*
* @constructor
* @extends {goog.Disposable}
* @implements {goog.events.Listenable}
*/
goog.events.EventTarget = function() {
'use strict';
goog.Disposable.call(this);
/**
* Maps of event type to an array of listeners.
* @private {!goog.events.ListenerMap}
*/
this.eventTargetListeners_ = new goog.events.ListenerMap(this);
/**
* The object to use for event.target. Useful when mixing in an
* EventTarget to another object.
* @private {!Object}
*/
this.actualEventTarget_ = this;
/**
* Parent event target, used during event bubbling.
*
* TODO(chrishenry): Change this to goog.events.Listenable. This
* currently breaks people who expect getParentEventTarget to return
* goog.events.EventTarget.
*
* @private {?goog.events.EventTarget}
*/
this.parentEventTarget_ = null;
};
goog.inherits(goog.events.EventTarget, goog.Disposable);
goog.events.Listenable.addImplementation(goog.events.EventTarget);
/**
* An artificial cap on the number of ancestors you can have. This is mainly
* for loop detection.
* @const {number}
* @private
*/
goog.events.EventTarget.MAX_ANCESTORS_ = 1000;
/**
* Returns the parent of this event target to use for bubbling.
*
* @return {goog.events.EventTarget} The parent EventTarget or null if
* there is no parent.
* @override
*/
goog.events.EventTarget.prototype.getParentEventTarget = function() {
'use strict';
return this.parentEventTarget_;
};
/**
* Sets the parent of this event target to use for capture/bubble
* mechanism.
* @param {goog.events.EventTarget} parent Parent listenable (null if none).
*/
goog.events.EventTarget.prototype.setParentEventTarget = function(parent) {
'use strict';
this.parentEventTarget_ = parent;
};
/**
* Adds an event listener to the event target. The same handler can only be
* added once per the type. Even if you add the same handler multiple times
* using the same type then it will only be called once when the event is
* dispatched.
*
* @param {string|!goog.events.EventId} type The type of the event to listen for
* @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
* to handle the event. The handler can also be an object that implements
* the handleEvent method which takes the event object as argument.
* @param {boolean=} opt_capture In DOM-compliant browsers, this determines
* whether the listener is fired during the capture or bubble phase
* of the event.
* @param {Object=} opt_handlerScope Object in whose scope to call
* the listener.
* @deprecated Use `#listen` instead, when possible. Otherwise, use
* `goog.events.listen` if you are passing Object
* (instead of Function) as handler.
*/
goog.events.EventTarget.prototype.addEventListener = function(
type, handler, opt_capture, opt_handlerScope) {
'use strict';
goog.events.listen(this, type, handler, opt_capture, opt_handlerScope);
};
/**
* Removes an event listener from the event target. The handler must be the
* same object as the one added. If the handler has not been added then
* nothing is done.
*
* @param {string|!goog.events.EventId} type The type of the event to listen for
* @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
* to handle the event. The handler can also be an object that implements
* the handleEvent method which takes the event object as argument.
* @param {boolean=} opt_capture In DOM-compliant browsers, this determines
* whether the listener is fired during the capture or bubble phase
* of the event.
* @param {Object=} opt_handlerScope Object in whose scope to call
* the listener.
* @deprecated Use `#unlisten` instead, when possible. Otherwise, use
* `goog.events.unlisten` if you are passing Object
* (instead of Function) as handler.
*/
goog.events.EventTarget.prototype.removeEventListener = function(
type, handler, opt_capture, opt_handlerScope) {
'use strict';
goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope);
};
/**
* @param {?goog.events.EventLike} e Event object.
* @return {boolean} If anyone called preventDefault on the event object (or
* if any of the listeners returns false) this will also return false.
* @override
*/
goog.events.EventTarget.prototype.dispatchEvent = function(e) {
'use strict';
this.assertInitialized_();
var ancestorsTree, ancestor = this.getParentEventTarget();
if (ancestor) {
ancestorsTree = [];
var ancestorCount = 1;
for (; ancestor; ancestor = ancestor.getParentEventTarget()) {
ancestorsTree.push(ancestor);
goog.asserts.assert(
(++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_),
'infinite loop');
}
}
return goog.events.EventTarget.dispatchEventInternal_(
this.actualEventTarget_, e, ancestorsTree);
};
/**
* Removes listeners from this object. Classes that extend EventTarget may
* need to override this method in order to remove references to DOM Elements
* and additional listeners.
* @override
* @protected
*/
goog.events.EventTarget.prototype.disposeInternal = function() {
'use strict';
goog.events.EventTarget.superClass_.disposeInternal.call(this);
this.removeAllListeners();
this.parentEventTarget_ = null;
};
/**
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
* method.
* @param {boolean=} opt_useCapture Whether to fire in capture phase
* (defaults to false).
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {!goog.events.ListenableKey} Unique key for the listener.
* @template SCOPE,EVENTOBJ
* @override
*/
goog.events.EventTarget.prototype.listen = function(
type, listener, opt_useCapture, opt_listenerScope) {
'use strict';
this.assertInitialized_();
return this.eventTargetListeners_.add(
String(type), listener, false /* callOnce */, opt_useCapture,
opt_listenerScope);
};
/**
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
* method.
* @param {boolean=} opt_useCapture Whether to fire in capture phase
* (defaults to false).
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {!goog.events.ListenableKey} Unique key for the listener.
* @template SCOPE,EVENTOBJ
* @override
*/
goog.events.EventTarget.prototype.listenOnce = function(
type, listener, opt_useCapture, opt_listenerScope) {
'use strict';
return this.eventTargetListeners_.add(
String(type), listener, true /* callOnce */, opt_useCapture,
opt_listenerScope);
};
/**
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
* method.
* @param {boolean=} opt_useCapture Whether to fire in capture phase
* (defaults to false).
* @param {SCOPE=} opt_listenerScope Object in whose scope to call
* the listener.
* @return {boolean} Whether any listener was removed.
* @template SCOPE,EVENTOBJ
* @override
*/
goog.events.EventTarget.prototype.unlisten = function(
type, listener, opt_useCapture, opt_listenerScope) {
'use strict';
return this.eventTargetListeners_.remove(
String(type), listener, opt_useCapture, opt_listenerScope);
};
/**
* @param {!goog.events.ListenableKey} key The key returned by
* listen() or listenOnce().
* @return {boolean} Whether any listener was removed.
* @override
*/
goog.events.EventTarget.prototype.unlistenByKey = function(key) {
'use strict';
return this.eventTargetListeners_.removeByKey(key);
};
/**
* @param {string|!goog.events.EventId=} opt_type Type of event to remove,
* default is to remove all types.
* @return {number} Number of listeners removed.
* @override
*/
goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) {
'use strict';
// TODO(chrishenry): Previously, removeAllListeners can be called on
// uninitialized EventTarget, so we preserve that behavior. We
// should remove this when usages that rely on that fact are purged.
if (!this.eventTargetListeners_) {
return 0;
}
return this.eventTargetListeners_.removeAll(opt_type);
};
/**
* @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the
* listeners to fire.
* @param {boolean} capture The capture mode of the listeners to fire.
* @param {EVENTOBJ} eventObject The event object to fire.
* @return {boolean} Whether all listeners succeeded without
* attempting to prevent default behavior. If any listener returns
* false or called goog.events.Event#preventDefault, this returns
* false.
* @template EVENTOBJ
* @override
*/
goog.events.EventTarget.prototype.fireListeners = function(
type, capture, eventObject) {
'use strict';
// TODO(chrishenry): Original code avoids array creation when there
// is no listener, so we do the same. If this optimization turns
// out to be not required, we can replace this with
// getListeners(type, capture) instead, which is simpler.
var listenerArray = this.eventTargetListeners_.listeners[String(type)];
if (!listenerArray) {
return true;
}
listenerArray = listenerArray.concat();
var rv = true;
for (var i = 0; i < listenerArray.length; ++i) {
var listener = listenerArray[i];
// We might not have a listener if the listener was removed.
if (listener && !listener.removed && listener.capture == capture) {
var listenerFn = listener.listener;
var listenerHandler = listener.handler || listener.src;
if (listener.callOnce) {
this.unlistenByKey(listener);
}
rv = listenerFn.call(listenerHandler, eventObject) !== false && rv;
}
}
return rv && !eventObject.defaultPrevented;
};
/**
* @param {string|!goog.events.EventId} type The type of the listeners to fire.
* @param {boolean} capture The capture mode of the listeners to fire.
* @return {!Array<!goog.events.ListenableKey>} An array of registered
* listeners.
* @template EVENTOBJ
* @override
*/
goog.events.EventTarget.prototype.getListeners = function(type, capture) {
'use strict';
return this.eventTargetListeners_.getListeners(String(type), capture);
};
/**
* @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event
* without the 'on' prefix.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The
* listener function to get.
* @param {boolean} capture Whether the listener is a capturing listener.
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {?goog.events.ListenableKey} the found listener or null if not found.
* @template SCOPE,EVENTOBJ
* @override
*/
goog.events.EventTarget.prototype.getListener = function(
type, listener, capture, opt_listenerScope) {
'use strict';
return this.eventTargetListeners_.getListener(
String(type), listener, capture, opt_listenerScope);
};
/**
* @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type.
* @param {boolean=} opt_capture Whether to check for capture or bubble
* listeners.
* @return {boolean} Whether there is any active listeners matching
* the requested type and/or capture phase.
* @template EVENTOBJ
* @override
*/
goog.events.EventTarget.prototype.hasListener = function(
opt_type, opt_capture) {
'use strict';
var id = (opt_type !== undefined) ? String(opt_type) : undefined;
return this.eventTargetListeners_.hasListener(id, opt_capture);
};
/**
* Sets the target to be used for `event.target` when firing
* event. Mainly used for testing. For example, see
* `goog.testing.events.mixinListenable`.
* @param {!Object} target The target.
*/
goog.events.EventTarget.prototype.setTargetForTesting = function(target) {
'use strict';
this.actualEventTarget_ = target;
};
/**
* Asserts that the event target instance is initialized properly.
* @private
*/
goog.events.EventTarget.prototype.assertInitialized_ = function() {
'use strict';
goog.asserts.assert(
this.eventTargetListeners_,
'Event target is not initialized. Did you call the superclass ' +
'(goog.events.EventTarget) constructor?');
};
/**
* Dispatches the given event on the ancestorsTree.
*
* @param {!Object} target The target to dispatch on.
* @param {goog.events.Event|Object|string} e The event object.
* @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors
* tree of the target, in reverse order from the closest ancestor
* to the root event target. May be null if the target has no ancestor.
* @return {boolean} If anyone called preventDefault on the event object (or
* if any of the listeners returns false) this will also return false.
* @private
*/
goog.events.EventTarget.dispatchEventInternal_ = function(
target, e, opt_ancestorsTree) {
'use strict';
/** @suppress {missingProperties} */
var type = e.type || /** @type {string} */ (e);
// If accepting a string or object, create a custom event object so that
// preventDefault and stopPropagation work with the event.
if (typeof e === 'string') {
e = new goog.events.Event(e, target);
} else if (!(e instanceof goog.events.Event)) {
var oldEvent = e;
e = new goog.events.Event(type, target);
goog.object.extend(e, oldEvent);
} else {
e.target = e.target || target;
}
var rv = true, currentTarget;
// Executes all capture listeners on the ancestors, if any.
if (opt_ancestorsTree) {
for (var i = opt_ancestorsTree.length - 1;
!e.hasPropagationStopped() && i >= 0; i--) {
currentTarget = e.currentTarget = opt_ancestorsTree[i];
rv = currentTarget.fireListeners(type, true, e) && rv;
}
}
// Executes capture and bubble listeners on the target.
if (!e.hasPropagationStopped()) {
currentTarget = /** @type {?} */ (e.currentTarget = target);
rv = currentTarget.fireListeners(type, true, e) && rv;
if (!e.hasPropagationStopped()) {
rv = currentTarget.fireListeners(type, false, e) && rv;
}
}
// Executes all bubble listeners on the ancestors, if any.
if (opt_ancestorsTree) {
for (i = 0; !e.hasPropagationStopped() && i < opt_ancestorsTree.length;
i++) {
currentTarget = e.currentTarget = opt_ancestorsTree[i];
rv = currentTarget.fireListeners(type, false, e) && rv;
}
}
return rv;
};
+437
View File
@@ -0,0 +1,437 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Event Types.
*/
goog.provide('goog.events.EventType');
goog.provide('goog.events.MouseAsMouseEventType');
goog.provide('goog.events.MouseEvents');
goog.provide('goog.events.PointerAsMouseEventType');
goog.provide('goog.events.PointerAsTouchEventType');
goog.provide('goog.events.PointerFallbackEventType');
goog.provide('goog.events.PointerTouchFallbackEventType');
goog.require('goog.events.BrowserFeature');
goog.require('goog.userAgent');
/**
* Returns a prefixed event name for the current browser.
* @param {string} eventName The name of the event.
* @return {string} The prefixed event name.
* @private
*/
goog.events.getVendorPrefixedName_ = function(eventName) {
'use strict';
return goog.userAgent.WEBKIT ? 'webkit' + eventName : eventName.toLowerCase();
};
/**
* Constants for event names.
* @enum {string}
*/
goog.events.EventType = {
// Mouse events
CLICK: 'click',
RIGHTCLICK: 'rightclick',
DBLCLICK: 'dblclick',
AUXCLICK: 'auxclick',
MOUSEDOWN: 'mousedown',
MOUSEUP: 'mouseup',
MOUSEOVER: 'mouseover',
MOUSEOUT: 'mouseout',
MOUSEMOVE: 'mousemove',
MOUSEENTER: 'mouseenter',
MOUSELEAVE: 'mouseleave',
// Non-existent event; will never fire. This exists as a mouse counterpart to
// POINTERCANCEL.
MOUSECANCEL: 'mousecancel',
// Selection events.
// https://www.w3.org/TR/selection-api/
SELECTIONCHANGE: 'selectionchange',
SELECTSTART: 'selectstart', // IE, Safari, Chrome
// Wheel events
// http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
WHEEL: 'wheel',
// Key events
KEYPRESS: 'keypress',
KEYDOWN: 'keydown',
KEYUP: 'keyup',
// Focus
BLUR: 'blur',
FOCUS: 'focus',
DEACTIVATE: 'deactivate', // IE only
FOCUSIN: 'focusin',
FOCUSOUT: 'focusout',
// Forms
CHANGE: 'change',
RESET: 'reset',
SELECT: 'select',
SUBMIT: 'submit',
INPUT: 'input',
PROPERTYCHANGE: 'propertychange', // IE only
// Drag and drop
DRAGSTART: 'dragstart',
DRAG: 'drag',
DRAGENTER: 'dragenter',
DRAGOVER: 'dragover',
DRAGLEAVE: 'dragleave',
DROP: 'drop',
DRAGEND: 'dragend',
// Touch events
// Note that other touch events exist, but we should follow the W3C list here.
// http://www.w3.org/TR/touch-events/#list-of-touchevent-types
TOUCHSTART: 'touchstart',
TOUCHMOVE: 'touchmove',
TOUCHEND: 'touchend',
TOUCHCANCEL: 'touchcancel',
// Misc
BEFOREUNLOAD: 'beforeunload',
CONSOLEMESSAGE: 'consolemessage',
CONTEXTMENU: 'contextmenu',
DEVICECHANGE: 'devicechange',
DEVICEMOTION: 'devicemotion',
DEVICEORIENTATION: 'deviceorientation',
DOMCONTENTLOADED: 'DOMContentLoaded',
ERROR: 'error',
HELP: 'help',
LOAD: 'load',
LOSECAPTURE: 'losecapture',
ORIENTATIONCHANGE: 'orientationchange',
READYSTATECHANGE: 'readystatechange',
RESIZE: 'resize',
SCROLL: 'scroll',
UNLOAD: 'unload',
// Media events
CANPLAY: 'canplay',
CANPLAYTHROUGH: 'canplaythrough',
DURATIONCHANGE: 'durationchange',
EMPTIED: 'emptied',
ENDED: 'ended',
LOADEDDATA: 'loadeddata',
LOADEDMETADATA: 'loadedmetadata',
PAUSE: 'pause',
PLAY: 'play',
PLAYING: 'playing',
PROGRESS: 'progress',
RATECHANGE: 'ratechange',
SEEKED: 'seeked',
SEEKING: 'seeking',
STALLED: 'stalled',
SUSPEND: 'suspend',
TIMEUPDATE: 'timeupdate',
VOLUMECHANGE: 'volumechange',
WAITING: 'waiting',
// Media Source Extensions events
// https://www.w3.org/TR/media-source/#mediasource-events
SOURCEOPEN: 'sourceopen',
SOURCEENDED: 'sourceended',
SOURCECLOSED: 'sourceclosed',
// https://www.w3.org/TR/media-source/#sourcebuffer-events
ABORT: 'abort',
UPDATE: 'update',
UPDATESTART: 'updatestart',
UPDATEEND: 'updateend',
// HTML 5 History events
// See http://www.w3.org/TR/html5/browsers.html#event-definitions-0
HASHCHANGE: 'hashchange',
PAGEHIDE: 'pagehide',
PAGESHOW: 'pageshow',
POPSTATE: 'popstate',
// Copy and Paste
// Support is limited. Make sure it works on your favorite browser
// before using.
// http://www.quirksmode.org/dom/events/cutcopypaste.html
COPY: 'copy',
PASTE: 'paste',
CUT: 'cut',
BEFORECOPY: 'beforecopy',
BEFORECUT: 'beforecut',
BEFOREPASTE: 'beforepaste',
// HTML5 online/offline events.
// http://www.w3.org/TR/offline-webapps/#related
ONLINE: 'online',
OFFLINE: 'offline',
// HTML 5 worker events
MESSAGE: 'message',
CONNECT: 'connect',
// Service Worker Events - ServiceWorkerGlobalScope context
// See https://w3c.github.io/ServiceWorker/#execution-context-events
// Note: message event defined in worker events section
INSTALL: 'install',
ACTIVATE: 'activate',
FETCH: 'fetch',
FOREIGNFETCH: 'foreignfetch',
MESSAGEERROR: 'messageerror',
// Service Worker Events - Document context
// See https://w3c.github.io/ServiceWorker/#document-context-events
STATECHANGE: 'statechange',
UPDATEFOUND: 'updatefound',
CONTROLLERCHANGE: 'controllerchange',
// CSS animation events.
ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'),
ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'),
ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'),
// CSS transition events. Based on the browser support described at:
// https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'),
// W3C Pointer Events
// http://www.w3.org/TR/pointerevents/
POINTERDOWN: 'pointerdown',
POINTERUP: 'pointerup',
POINTERCANCEL: 'pointercancel',
POINTERMOVE: 'pointermove',
POINTEROVER: 'pointerover',
POINTEROUT: 'pointerout',
POINTERENTER: 'pointerenter',
POINTERLEAVE: 'pointerleave',
GOTPOINTERCAPTURE: 'gotpointercapture',
LOSTPOINTERCAPTURE: 'lostpointercapture',
// IE specific events.
// See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx
// Note: these events will be supplanted in IE11.
MSGESTURECHANGE: 'MSGestureChange',
MSGESTUREEND: 'MSGestureEnd',
MSGESTUREHOLD: 'MSGestureHold',
MSGESTURESTART: 'MSGestureStart',
MSGESTURETAP: 'MSGestureTap',
MSGOTPOINTERCAPTURE: 'MSGotPointerCapture',
MSINERTIASTART: 'MSInertiaStart',
MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture',
MSPOINTERCANCEL: 'MSPointerCancel',
MSPOINTERDOWN: 'MSPointerDown',
MSPOINTERENTER: 'MSPointerEnter',
MSPOINTERHOVER: 'MSPointerHover',
MSPOINTERLEAVE: 'MSPointerLeave',
MSPOINTERMOVE: 'MSPointerMove',
MSPOINTEROUT: 'MSPointerOut',
MSPOINTEROVER: 'MSPointerOver',
MSPOINTERUP: 'MSPointerUp',
// Native IMEs/input tools events.
TEXT: 'text',
// The textInput event is supported in IE9+, but only in lower case. All other
// browsers use the camel-case event name.
TEXTINPUT: goog.userAgent.IE ? 'textinput' : 'textInput',
COMPOSITIONSTART: 'compositionstart',
COMPOSITIONUPDATE: 'compositionupdate',
COMPOSITIONEND: 'compositionend',
// The beforeinput event is initially only supported in Safari. See
// https://bugs.chromium.org/p/chromium/issues/detail?id=342670 for Chrome
// implementation tracking.
BEFOREINPUT: 'beforeinput',
// Webview tag events
// See https://developer.chrome.com/apps/tags/webview
EXIT: 'exit',
LOADABORT: 'loadabort',
LOADCOMMIT: 'loadcommit',
LOADREDIRECT: 'loadredirect',
LOADSTART: 'loadstart',
LOADSTOP: 'loadstop',
RESPONSIVE: 'responsive',
SIZECHANGED: 'sizechanged',
UNRESPONSIVE: 'unresponsive',
// HTML5 Page Visibility API. See details at
// `goog.labs.dom.PageVisibilityMonitor`.
VISIBILITYCHANGE: 'visibilitychange',
// LocalStorage event.
STORAGE: 'storage',
// DOM Level 2 mutation events (deprecated).
DOMSUBTREEMODIFIED: 'DOMSubtreeModified',
DOMNODEINSERTED: 'DOMNodeInserted',
DOMNODEREMOVED: 'DOMNodeRemoved',
DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument',
DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument',
DOMATTRMODIFIED: 'DOMAttrModified',
DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified',
// Print events.
BEFOREPRINT: 'beforeprint',
AFTERPRINT: 'afterprint',
// Web app manifest events.
BEFOREINSTALLPROMPT: 'beforeinstallprompt',
APPINSTALLED: 'appinstalled'
};
/**
* Returns one of the given pointer fallback event names in order of preference:
* 1. pointerEventName
* 2. msPointerEventName
* 3. fallbackEventName
* @param {string} pointerEventName
* @param {string} msPointerEventName
* @param {string} fallbackEventName
* @return {string} The supported pointer or fallback (mouse or touch) event
* name.
* @private
*/
goog.events.getPointerFallbackEventName_ = function(
pointerEventName, msPointerEventName, fallbackEventName) {
'use strict';
if (goog.events.BrowserFeature.POINTER_EVENTS) {
return pointerEventName;
}
if (goog.events.BrowserFeature.MSPOINTER_EVENTS) {
return msPointerEventName;
}
return fallbackEventName;
};
/**
* Constants for pointer event names that fall back to corresponding mouse event
* names on unsupported platforms. These are intended to be drop-in replacements
* for corresponding values in `goog.events.EventType`.
* @enum {string}
*/
goog.events.PointerFallbackEventType = {
POINTERDOWN: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERDOWN, goog.events.EventType.MSPOINTERDOWN,
goog.events.EventType.MOUSEDOWN),
POINTERUP: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERUP, goog.events.EventType.MSPOINTERUP,
goog.events.EventType.MOUSEUP),
POINTERCANCEL: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERCANCEL,
goog.events.EventType.MSPOINTERCANCEL,
// When falling back to mouse events, there is no MOUSECANCEL equivalent
// of POINTERCANCEL. In this case POINTERUP already falls back to MOUSEUP
// which represents both UP and CANCEL. POINTERCANCEL does not fall back
// to MOUSEUP to prevent listening twice on the same event.
goog.events.EventType.MOUSECANCEL),
POINTERMOVE: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERMOVE, goog.events.EventType.MSPOINTERMOVE,
goog.events.EventType.MOUSEMOVE),
POINTEROVER: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTEROVER, goog.events.EventType.MSPOINTEROVER,
goog.events.EventType.MOUSEOVER),
POINTEROUT: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTEROUT, goog.events.EventType.MSPOINTEROUT,
goog.events.EventType.MOUSEOUT),
POINTERENTER: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERENTER, goog.events.EventType.MSPOINTERENTER,
goog.events.EventType.MOUSEENTER),
POINTERLEAVE: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERLEAVE, goog.events.EventType.MSPOINTERLEAVE,
goog.events.EventType.MOUSELEAVE)
};
/**
* Constants for pointer event names that fall back to corresponding touch event
* names on unsupported platforms. These are intended to be drop-in replacements
* for corresponding values in `goog.events.EventType`.
* @enum {string}
*/
goog.events.PointerTouchFallbackEventType = {
POINTERDOWN: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERDOWN, goog.events.EventType.MSPOINTERDOWN,
goog.events.EventType.TOUCHSTART),
POINTERUP: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERUP, goog.events.EventType.MSPOINTERUP,
goog.events.EventType.TOUCHEND),
POINTERCANCEL: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERCANCEL,
goog.events.EventType.MSPOINTERCANCEL, goog.events.EventType.TOUCHCANCEL),
POINTERMOVE: goog.events.getPointerFallbackEventName_(
goog.events.EventType.POINTERMOVE, goog.events.EventType.MSPOINTERMOVE,
goog.events.EventType.TOUCHMOVE)
};
/**
* Mapping of mouse event names to underlying browser event names.
* @typedef {{
* MOUSEDOWN: string,
* MOUSEUP: string,
* MOUSECANCEL:string,
* MOUSEMOVE:string,
* MOUSEOVER:string,
* MOUSEOUT:string,
* MOUSEENTER:string,
* MOUSELEAVE: string,
* }}
*/
goog.events.MouseEvents;
/**
* An alias for `goog.events.EventType.MOUSE*` event types that is overridden by
* corresponding `POINTER*` event types.
* @const {!goog.events.MouseEvents}
*/
goog.events.PointerAsMouseEventType = {
MOUSEDOWN: goog.events.PointerFallbackEventType.POINTERDOWN,
MOUSEUP: goog.events.PointerFallbackEventType.POINTERUP,
MOUSECANCEL: goog.events.PointerFallbackEventType.POINTERCANCEL,
MOUSEMOVE: goog.events.PointerFallbackEventType.POINTERMOVE,
MOUSEOVER: goog.events.PointerFallbackEventType.POINTEROVER,
MOUSEOUT: goog.events.PointerFallbackEventType.POINTEROUT,
MOUSEENTER: goog.events.PointerFallbackEventType.POINTERENTER,
MOUSELEAVE: goog.events.PointerFallbackEventType.POINTERLEAVE
};
/**
* An alias for `goog.events.EventType.MOUSE*` event types that continue to use
* mouse events.
* @const {!goog.events.MouseEvents}
*/
goog.events.MouseAsMouseEventType = {
MOUSEDOWN: goog.events.EventType.MOUSEDOWN,
MOUSEUP: goog.events.EventType.MOUSEUP,
MOUSECANCEL: goog.events.EventType.MOUSECANCEL,
MOUSEMOVE: goog.events.EventType.MOUSEMOVE,
MOUSEOVER: goog.events.EventType.MOUSEOVER,
MOUSEOUT: goog.events.EventType.MOUSEOUT,
MOUSEENTER: goog.events.EventType.MOUSEENTER,
MOUSELEAVE: goog.events.EventType.MOUSELEAVE
};
/**
* An alias for `goog.events.EventType.TOUCH*` event types that is overridden by
* corresponding `POINTER*` event types.
* @enum {string}
*/
goog.events.PointerAsTouchEventType = {
TOUCHCANCEL: goog.events.PointerTouchFallbackEventType.POINTERCANCEL,
TOUCHEND: goog.events.PointerTouchFallbackEventType.POINTERUP,
TOUCHMOVE: goog.events.PointerTouchFallbackEventType.POINTERMOVE,
TOUCHSTART: goog.events.PointerTouchFallbackEventType.POINTERDOWN
};
+56
View File
@@ -0,0 +1,56 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Definition of the goog.events.EventWrapper interface.
*/
goog.provide('goog.events.EventWrapper');
goog.requireType('goog.events.EventHandler');
goog.requireType('goog.events.ListenableType');
/**
* Interface for event wrappers.
* @interface
*/
goog.events.EventWrapper = function() {};
/**
* Adds an event listener using the wrapper on a DOM Node or an object that has
* implemented {@link goog.events.EventTarget}. A listener can only be added
* once to an object.
*
* @param {goog.events.ListenableType} src The node to listen to events on.
* @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
* method, or an object with a handleEvent function.
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
* false).
* @param {Object=} opt_scope Element in whose scope to call the listener.
* @param {goog.events.EventHandler=} opt_eventHandler Event handler to add
* listener to.
*/
goog.events.EventWrapper.prototype.listen = function(
src, listener, opt_capt, opt_scope, opt_eventHandler) {};
/**
* Removes an event listener added using goog.events.EventWrapper.listen.
*
* @param {goog.events.ListenableType} src The node to remove listener from.
* @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
* method, or an object with a handleEvent function.
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
* false).
* @param {Object=} opt_scope Element in whose scope to call the listener.
* @param {goog.events.EventHandler=} opt_eventHandler Event handler to remove
* listener from.
*/
goog.events.EventWrapper.prototype.unlisten = function(
src, listener, opt_capt, opt_scope, opt_eventHandler) {};
+265
View File
@@ -0,0 +1,265 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview An interface for a listenable JavaScript object.
*/
goog.provide('goog.events.Listenable');
goog.requireType('goog.events.EventId');
goog.requireType('goog.events.EventLike');
goog.requireType('goog.events.ListenableKey');
/**
* A listenable interface. A listenable is an object with the ability
* to dispatch/broadcast events to "event listeners" registered via
* listen/listenOnce.
*
* The interface allows for an event propagation mechanism similar
* to one offered by native browser event targets, such as
* capture/bubble mechanism, stopping propagation, and preventing
* default actions. Capture/bubble mechanism depends on the ancestor
* tree constructed via `#getParentEventTarget`; this tree
* must be directed acyclic graph. The meaning of default action(s)
* in preventDefault is specific to a particular use case.
*
* Implementations that do not support capture/bubble or can not have
* a parent listenable can simply not implement any ability to set the
* parent listenable (and have `#getParentEventTarget` return
* null).
*
* Implementation of this class can be used with or independently from
* goog.events.
*
* Implementation must call `#addImplementation(implClass)`.
*
* @interface
* @see goog.events
* @see http://www.w3.org/TR/DOM-Level-2-Events/events.html
*/
goog.events.Listenable = function() {};
/**
* An expando property to indicate that an object implements
* goog.events.Listenable.
*
* See addImplementation/isImplementedBy.
*
* @type {string}
* @const
*/
goog.events.Listenable.IMPLEMENTED_BY_PROP =
'closure_listenable_' + ((Math.random() * 1e6) | 0);
/**
* Marks a given class (constructor) as an implementation of
* Listenable, so that we can query that fact at runtime. The class
* must have already implemented the interface.
* @param {function(new:goog.events.Listenable,...)} cls The class constructor.
* The corresponding class must have already implemented the interface.
*/
goog.events.Listenable.addImplementation = function(cls) {
'use strict';
cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true;
};
/**
* @param {?Object} obj The object to check.
* @return {boolean} Whether a given instance implements Listenable. The
* class/superclass of the instance must call addImplementation.
*/
goog.events.Listenable.isImplementedBy = function(obj) {
'use strict';
return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]);
};
/**
* Adds an event listener. A listener can only be added once to an
* object and if it is added again the key for the listener is
* returned. Note that if the existing listener is a one-off listener
* (registered via listenOnce), it will no longer be a one-off
* listener after a call to listen().
*
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
* method.
* @param {boolean=} opt_useCapture Whether to fire in capture phase
* (defaults to false).
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {!goog.events.ListenableKey} Unique key for the listener.
* @template SCOPE,EVENTOBJ
*/
goog.events.Listenable.prototype.listen = function(
type, listener, opt_useCapture, opt_listenerScope) {};
/**
* Adds an event listener that is removed automatically after the
* listener fired once.
*
* If an existing listener already exists, listenOnce will do
* nothing. In particular, if the listener was previously registered
* via listen(), listenOnce() will not turn the listener into a
* one-off listener. Similarly, if there is already an existing
* one-off listener, listenOnce does not modify the listeners (it is
* still a once listener).
*
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
* method.
* @param {boolean=} opt_useCapture Whether to fire in capture phase
* (defaults to false).
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {!goog.events.ListenableKey} Unique key for the listener.
* @template SCOPE,EVENTOBJ
*/
goog.events.Listenable.prototype.listenOnce = function(
type, listener, opt_useCapture, opt_listenerScope) {};
/**
* Removes an event listener which was added with listen() or listenOnce().
*
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
* method.
* @param {boolean=} opt_useCapture Whether to fire in capture phase
* (defaults to false).
* @param {SCOPE=} opt_listenerScope Object in whose scope to call
* the listener.
* @return {boolean} Whether any listener was removed.
* @template SCOPE,EVENTOBJ
*/
goog.events.Listenable.prototype.unlisten = function(
type, listener, opt_useCapture, opt_listenerScope) {};
/**
* Removes an event listener which was added with listen() by the key
* returned by listen().
*
* @param {!goog.events.ListenableKey} key The key returned by
* listen() or listenOnce().
* @return {boolean} Whether any listener was removed.
*/
goog.events.Listenable.prototype.unlistenByKey = function(key) {};
/**
* Dispatches an event (or event like object) and calls all listeners
* listening for events of this type. The type of the event is decided by the
* type property on the event object.
*
* If any of the listeners returns false OR calls preventDefault then this
* function will return false. If one of the capture listeners calls
* stopPropagation, then the bubble listeners won't fire.
*
* @param {?goog.events.EventLike} e Event object.
* @return {boolean} If anyone called preventDefault on the event object (or
* if any of the listeners returns false) this will also return false.
*/
goog.events.Listenable.prototype.dispatchEvent = function(e) {};
/**
* Removes all listeners from this listenable. If type is specified,
* it will only remove listeners of the particular type. otherwise all
* registered listeners will be removed.
*
* @param {string|!goog.events.EventId=} opt_type Type of event to remove,
* default is to remove all types.
* @return {number} Number of listeners removed.
*/
goog.events.Listenable.prototype.removeAllListeners = function(opt_type) {};
/**
* Returns the parent of this event target to use for capture/bubble
* mechanism.
*
* NOTE(chrishenry): The name reflects the original implementation of
* custom event target (`goog.events.EventTarget`). We decided
* that changing the name is not worth it.
*
* @return {?goog.events.Listenable} The parent EventTarget or null if
* there is no parent.
*/
goog.events.Listenable.prototype.getParentEventTarget = function() {};
/**
* Fires all registered listeners in this listenable for the given
* type and capture mode, passing them the given eventObject. This
* does not perform actual capture/bubble. Only implementors of the
* interface should be using this.
*
* @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the
* listeners to fire.
* @param {boolean} capture The capture mode of the listeners to fire.
* @param {EVENTOBJ} eventObject The event object to fire.
* @return {boolean} Whether all listeners succeeded without
* attempting to prevent default behavior. If any listener returns
* false or called goog.events.Event#preventDefault, this returns
* false.
* @template EVENTOBJ
*/
goog.events.Listenable.prototype.fireListeners = function(
type, capture, eventObject) {};
/**
* Gets all listeners in this listenable for the given type and
* capture mode.
*
* @param {string|!goog.events.EventId} type The type of the listeners to fire.
* @param {boolean} capture The capture mode of the listeners to fire.
* @return {!Array<!goog.events.ListenableKey>} An array of registered
* listeners.
* @template EVENTOBJ
*/
goog.events.Listenable.prototype.getListeners = function(type, capture) {};
/**
* Gets the goog.events.ListenableKey for the event or null if no such
* listener is in use.
*
* @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event
* without the 'on' prefix.
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The
* listener function to get.
* @param {boolean} capture Whether the listener is a capturing listener.
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {?goog.events.ListenableKey} the found listener or null if not found.
* @template SCOPE,EVENTOBJ
*/
goog.events.Listenable.prototype.getListener = function(
type, listener, capture, opt_listenerScope) {};
/**
* Whether there is any active listeners matching the specified
* signature. If either the type or capture parameters are
* unspecified, the function will match on the remaining criteria.
*
* @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type.
* @param {boolean=} opt_capture Whether to check for capture or bubble
* listeners.
* @return {boolean} Whether there is any active listeners matching
* the requested type and/or capture phase.
* @template EVENTOBJ
*/
goog.events.Listenable.prototype.hasListener = function(
opt_type, opt_capture) {};
+80
View File
@@ -0,0 +1,80 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview An interface that describes a single registered listener.
*/
goog.provide('goog.events.ListenableKey');
goog.requireType('goog.events.Listenable');
/**
* An interface that describes a single registered listener.
* @interface
*/
goog.events.ListenableKey = function() {};
/**
* Counter used to create a unique key
* @type {number}
* @private
*/
goog.events.ListenableKey.counter_ = 0;
/**
* Reserves a key to be used for ListenableKey#key field.
* @return {number} A number to be used to fill ListenableKey#key
* field.
*/
goog.events.ListenableKey.reserveKey = function() {
'use strict';
return ++goog.events.ListenableKey.counter_;
};
/**
* The source event target.
* @type {?Object|?goog.events.Listenable}
*/
goog.events.ListenableKey.prototype.src;
/**
* The event type the listener is listening to.
* @type {string}
*/
goog.events.ListenableKey.prototype.type;
/**
* The listener function.
* @type {function(?):?|{handleEvent:function(?):?}|null}
*/
goog.events.ListenableKey.prototype.listener;
/**
* Whether the listener works on capture phase.
* @type {boolean}
*/
goog.events.ListenableKey.prototype.capture;
/**
* The 'this' object for the listener function's scope.
* @type {?Object|undefined}
*/
goog.events.ListenableKey.prototype.handler;
/**
* A globally unique number to identify the key.
* @type {number}
*/
goog.events.ListenableKey.prototype.key;
+124
View File
@@ -0,0 +1,124 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Listener object.
* @see ../demos/events.html
*/
goog.provide('goog.events.Listener');
goog.require('goog.events.ListenableKey');
goog.requireType('goog.events.Listenable');
/**
* Simple class that stores information about a listener
* @param {function(?):?} listener Callback function.
* @param {Function} proxy Wrapper for the listener that patches the event.
* @param {EventTarget|goog.events.Listenable} src Source object for
* the event.
* @param {string} type Event type.
* @param {boolean} capture Whether in capture or bubble phase.
* @param {Object=} opt_handler Object in whose context to execute the callback.
* @implements {goog.events.ListenableKey}
* @constructor
*/
goog.events.Listener = function(
listener, proxy, src, type, capture, opt_handler) {
'use strict';
if (goog.events.Listener.ENABLE_MONITORING) {
this.creationStack = new Error().stack;
}
/** @override */
this.listener = listener;
/**
* A wrapper over the original listener. This is used solely to
* handle native browser events (it is used to simulate the capture
* phase and to patch the event object).
* @type {Function}
*/
this.proxy = proxy;
/**
* Object or node that callback is listening to
* @type {EventTarget|goog.events.Listenable}
*/
this.src = src;
/**
* The event type.
* @const {string}
*/
this.type = type;
/**
* Whether the listener is being called in the capture or bubble phase
* @const {boolean}
*/
this.capture = !!capture;
/**
* Optional object whose context to execute the listener in
* @type {Object|undefined}
*/
this.handler = opt_handler;
/**
* The key of the listener.
* @const {number}
* @override
*/
this.key = goog.events.ListenableKey.reserveKey();
/**
* Whether to remove the listener after it has been called.
* @type {boolean}
*/
this.callOnce = false;
/**
* Whether the listener has been removed.
* @type {boolean}
*/
this.removed = false;
};
/**
* @define {boolean} Whether to enable the monitoring of the
* goog.events.Listener instances. Switching on the monitoring is only
* recommended for debugging because it has a significant impact on
* performance and memory usage. If switched off, the monitoring code
* compiles down to 0 bytes.
*/
goog.events.Listener.ENABLE_MONITORING =
goog.define('goog.events.Listener.ENABLE_MONITORING', false);
/**
* If monitoring the goog.events.Listener instances is enabled, stores the
* creation stack trace of the Disposable instance.
* @type {string}
*/
goog.events.Listener.prototype.creationStack;
/**
* Marks this listener as removed. This also remove references held by
* this listener object (such as listener and event source).
*/
goog.events.Listener.prototype.markAsRemoved = function() {
'use strict';
this.removed = true;
this.listener = null;
this.proxy = null;
this.src = null;
this.handler = null;
};
+310
View File
@@ -0,0 +1,310 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview A map of listeners that provides utility functions to
* deal with listeners on an event target. Used by
* `goog.events.EventTarget`.
*
* WARNING: Do not use this class from outside goog.events package.
*
*/
goog.provide('goog.events.ListenerMap');
goog.require('goog.array');
goog.require('goog.events.Listener');
goog.require('goog.object');
goog.requireType('goog.events.EventId');
goog.requireType('goog.events.Listenable');
goog.requireType('goog.events.ListenableKey');
/**
* Creates a new listener map.
* @param {EventTarget|goog.events.Listenable} src The src object.
* @constructor
* @final
*/
goog.events.ListenerMap = function(src) {
'use strict';
/** @type {EventTarget|goog.events.Listenable} */
this.src = src;
/**
* Maps of event type to an array of listeners.
* @type {!Object<string, !Array<!goog.events.Listener>>}
*/
this.listeners = {};
/**
* The count of types in this map that have registered listeners.
* @private {number}
*/
this.typeCount_ = 0;
};
/**
* @return {number} The count of event types in this map that actually
* have registered listeners.
*/
goog.events.ListenerMap.prototype.getTypeCount = function() {
'use strict';
return this.typeCount_;
};
/**
* @return {number} Total number of registered listeners.
*/
goog.events.ListenerMap.prototype.getListenerCount = function() {
'use strict';
var count = 0;
for (var type in this.listeners) {
count += this.listeners[type].length;
}
return count;
};
/**
* Adds an event listener. A listener can only be added once to an
* object and if it is added again the key for the listener is
* returned.
*
* Note that a one-off listener will not change an existing listener,
* if any. On the other hand a normal listener will change existing
* one-off listener to become a normal listener.
*
* @param {string|!goog.events.EventId} type The listener event type.
* @param {!Function} listener This listener callback method.
* @param {boolean} callOnce Whether the listener is a one-off
* listener.
* @param {boolean=} opt_useCapture The capture mode of the listener.
* @param {Object=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {!goog.events.ListenableKey} Unique key for the listener.
*/
goog.events.ListenerMap.prototype.add = function(
type, listener, callOnce, opt_useCapture, opt_listenerScope) {
'use strict';
var typeStr = type.toString();
var listenerArray = this.listeners[typeStr];
if (!listenerArray) {
listenerArray = this.listeners[typeStr] = [];
this.typeCount_++;
}
var listenerObj;
var index = goog.events.ListenerMap.findListenerIndex_(
listenerArray, listener, opt_useCapture, opt_listenerScope);
if (index > -1) {
listenerObj = listenerArray[index];
if (!callOnce) {
// Ensure that, if there is an existing callOnce listener, it is no
// longer a callOnce listener.
listenerObj.callOnce = false;
}
} else {
listenerObj = new goog.events.Listener(
listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope);
listenerObj.callOnce = callOnce;
listenerArray.push(listenerObj);
}
return listenerObj;
};
/**
* Removes a matching listener.
* @param {string|!goog.events.EventId} type The listener event type.
* @param {!Function} listener This listener callback method.
* @param {boolean=} opt_useCapture The capture mode of the listener.
* @param {Object=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {boolean} Whether any listener was removed.
*/
goog.events.ListenerMap.prototype.remove = function(
type, listener, opt_useCapture, opt_listenerScope) {
'use strict';
var typeStr = type.toString();
if (!(typeStr in this.listeners)) {
return false;
}
var listenerArray = this.listeners[typeStr];
var index = goog.events.ListenerMap.findListenerIndex_(
listenerArray, listener, opt_useCapture, opt_listenerScope);
if (index > -1) {
var listenerObj = listenerArray[index];
listenerObj.markAsRemoved();
goog.array.removeAt(listenerArray, index);
if (listenerArray.length == 0) {
delete this.listeners[typeStr];
this.typeCount_--;
}
return true;
}
return false;
};
/**
* Removes the given listener object.
* @param {!goog.events.ListenableKey} listener The listener to remove.
* @return {boolean} Whether the listener is removed.
*/
goog.events.ListenerMap.prototype.removeByKey = function(listener) {
'use strict';
var type = listener.type;
if (!(type in this.listeners)) {
return false;
}
var removed = goog.array.remove(this.listeners[type], listener);
if (removed) {
/** @type {!goog.events.Listener} */ (listener).markAsRemoved();
if (this.listeners[type].length == 0) {
delete this.listeners[type];
this.typeCount_--;
}
}
return removed;
};
/**
* Removes all listeners from this map. If opt_type is provided, only
* listeners that match the given type are removed.
* @param {string|!goog.events.EventId=} opt_type Type of event to remove.
* @return {number} Number of listeners removed.
*/
goog.events.ListenerMap.prototype.removeAll = function(opt_type) {
'use strict';
var typeStr = opt_type && opt_type.toString();
var count = 0;
for (var type in this.listeners) {
if (!typeStr || type == typeStr) {
var listenerArray = this.listeners[type];
for (var i = 0; i < listenerArray.length; i++) {
++count;
listenerArray[i].markAsRemoved();
}
delete this.listeners[type];
this.typeCount_--;
}
}
return count;
};
/**
* Gets all listeners that match the given type and capture mode. The
* returned array is a copy (but the listener objects are not).
* @param {string|!goog.events.EventId} type The type of the listeners
* to retrieve.
* @param {boolean} capture The capture mode of the listeners to retrieve.
* @return {!Array<!goog.events.ListenableKey>} An array of matching
* listeners.
*/
goog.events.ListenerMap.prototype.getListeners = function(type, capture) {
'use strict';
var listenerArray = this.listeners[type.toString()];
var rv = [];
if (listenerArray) {
for (var i = 0; i < listenerArray.length; ++i) {
var listenerObj = listenerArray[i];
if (listenerObj.capture == capture) {
rv.push(listenerObj);
}
}
}
return rv;
};
/**
* Gets the goog.events.ListenableKey for the event or null if no such
* listener is in use.
*
* @param {string|!goog.events.EventId} type The type of the listener
* to retrieve.
* @param {!Function} listener The listener function to get.
* @param {boolean} capture Whether the listener is a capturing listener.
* @param {Object=} opt_listenerScope Object in whose scope to call the
* listener.
* @return {goog.events.ListenableKey} the found listener or null if not found.
*/
goog.events.ListenerMap.prototype.getListener = function(
type, listener, capture, opt_listenerScope) {
'use strict';
var listenerArray = this.listeners[type.toString()];
var i = -1;
if (listenerArray) {
i = goog.events.ListenerMap.findListenerIndex_(
listenerArray, listener, capture, opt_listenerScope);
}
return i > -1 ? listenerArray[i] : null;
};
/**
* Whether there is a matching listener. If either the type or capture
* parameters are unspecified, the function will match on the
* remaining criteria.
*
* @param {string|!goog.events.EventId=} opt_type The type of the listener.
* @param {boolean=} opt_capture The capture mode of the listener.
* @return {boolean} Whether there is an active listener matching
* the requested type and/or capture phase.
*/
goog.events.ListenerMap.prototype.hasListener = function(
opt_type, opt_capture) {
'use strict';
var hasType = (opt_type !== undefined);
var typeStr = hasType ? opt_type.toString() : '';
var hasCapture = (opt_capture !== undefined);
return goog.object.some(this.listeners, function(listenerArray, type) {
'use strict';
for (var i = 0; i < listenerArray.length; ++i) {
if ((!hasType || listenerArray[i].type == typeStr) &&
(!hasCapture || listenerArray[i].capture == opt_capture)) {
return true;
}
}
return false;
});
};
/**
* Finds the index of a matching goog.events.Listener in the given
* listenerArray.
* @param {!Array<!goog.events.Listener>} listenerArray Array of listener.
* @param {!Function} listener The listener function.
* @param {boolean=} opt_useCapture The capture flag for the listener.
* @param {Object=} opt_listenerScope The listener scope.
* @return {number} The index of the matching listener within the
* listenerArray.
* @private
*/
goog.events.ListenerMap.findListenerIndex_ = function(
listenerArray, listener, opt_useCapture, opt_listenerScope) {
'use strict';
for (var i = 0; i < listenerArray.length; ++i) {
var listenerObj = listenerArray[i];
if (!listenerObj.removed && listenerObj.listener == listener &&
listenerObj.capture == !!opt_useCapture &&
listenerObj.handler == opt_listenerScope) {
return i;
}
}
return -1;
};
+79
View File
@@ -0,0 +1,79 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Wrappers for the HTML5 File API. These wrappers closely mirror
* the underlying APIs, but use Closure-style events and Deferred return values.
* Their existence also makes it possible to mock the FileSystem API for testing
* in browsers that don't support it natively.
*
* When adding public functions to anything under this namespace, be sure to add
* its mock counterpart to goog.testing.fs.
*/
goog.provide('goog.fs.blob');
/**
* Concatenates one or more values together and converts them to a Blob.
*
* @param {...(string|!Blob|!ArrayBuffer)} var_args The values that will make up
* the resulting blob.
* @return {!Blob} The blob.
*/
goog.fs.blob.getBlob = function(var_args) {
'use strict';
const BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
if (BlobBuilder !== undefined) {
const bb = new BlobBuilder();
for (let i = 0; i < arguments.length; i++) {
bb.append(arguments[i]);
}
return bb.getBlob();
} else {
return goog.fs.blob.getBlobWithProperties(
Array.prototype.slice.call(arguments));
}
};
/**
* Creates a blob with the given properties.
* See https://developer.mozilla.org/en-US/docs/Web/API/Blob for more details.
*
* @param {!Array<string|!Blob|!ArrayBuffer>} parts The values that will make up
* the resulting blob (subset supported by both BlobBuilder.append() and
* Blob constructor).
* @param {string=} opt_type The MIME type of the Blob.
* @param {string=} opt_endings Specifies how strings containing newlines are to
* be written out.
* @return {!Blob} The blob.
*/
goog.fs.blob.getBlobWithProperties = function(parts, opt_type, opt_endings) {
'use strict';
const BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
if (BlobBuilder !== undefined) {
const bb = new BlobBuilder();
for (let i = 0; i < parts.length; i++) {
bb.append(parts[i], opt_endings);
}
return bb.getBlob(opt_type);
} else if (goog.global.Blob !== undefined) {
const properties = {};
if (opt_type) {
properties['type'] = opt_type;
}
if (opt_endings) {
properties['endings'] = opt_endings;
}
return new Blob(parts, properties);
} else {
throw new Error('This browser doesn\'t seem to support creating Blobs');
}
};
+112
View File
@@ -0,0 +1,112 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Wrapper for URL and its createObjectUrl and revokeObjectUrl
* methods that are part of the HTML5 File API.
*/
goog.provide('goog.fs.url');
/**
* Creates a blob URL for a blob object.
* Throws an error if the browser does not support Object Urls.
*
* @param {!File|!Blob|!MediaSource|!MediaStream} obj The object for which
* to create the URL.
* @return {string} The URL for the object.
*/
goog.fs.url.createObjectUrl = function(obj) {
'use strict';
return goog.fs.url.getUrlObject_().createObjectURL(obj);
};
/**
* Revokes a URL created by {@link goog.fs.url.createObjectUrl}.
* Throws an error if the browser does not support Object Urls.
*
* @param {string} url The URL to revoke.
* @return {void}
*/
goog.fs.url.revokeObjectUrl = function(url) {
'use strict';
goog.fs.url.getUrlObject_().revokeObjectURL(url);
};
/**
* @record
* @private
*/
goog.fs.url.UrlObject_ = function() {};
/**
* @param {!File|!Blob|!MediaSource|!MediaStream} arg
* @return {string}
*/
goog.fs.url.UrlObject_.prototype.createObjectURL = function(arg) {};
/**
* @param {string} s
* @return {void}
*/
goog.fs.url.UrlObject_.prototype.revokeObjectURL = function(s) {};
/**
* Get the object that has the createObjectURL and revokeObjectURL functions for
* this browser.
*
* @return {!goog.fs.url.UrlObject_} The object for this browser.
* @private
*/
goog.fs.url.getUrlObject_ = function() {
'use strict';
const urlObject = goog.fs.url.findUrlObject_();
if (urlObject != null) {
return urlObject;
} else {
throw new Error('This browser doesn\'t seem to support blob URLs');
}
};
/**
* Finds the object that has the createObjectURL and revokeObjectURL functions
* for this browser.
*
* @return {?goog.fs.url.UrlObject_} The object for this browser or null if the
* browser does not support Object Urls.
* @private
*/
goog.fs.url.findUrlObject_ = function() {
'use strict';
// This is what the spec says to do
// http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL
if (goog.global.URL !== undefined &&
goog.global.URL.createObjectURL !== undefined) {
return /** @type {!goog.fs.url.UrlObject_} */ (goog.global.URL);
// This is what the spec used to say to do
} else if (goog.global.createObjectURL !== undefined) {
return /** @type {!goog.fs.url.UrlObject_} */ (goog.global);
} else {
return null;
}
};
/**
* Checks whether this browser supports Object Urls. If not, calls to
* createObjectUrl and revokeObjectUrl will result in an error.
*
* @return {boolean} True if this browser supports Object Urls.
*/
goog.fs.url.browserSupportsObjectUrls = function() {
'use strict';
return goog.fs.url.findUrlObject_() != null;
};
+584
View File
@@ -0,0 +1,584 @@
/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Utilities for creating functions. Loosely inspired by these
* java classes from the Guava library:
* com.google.common.base.Functions
* https://google.github.io/guava/releases/snapshot-jre/api/docs/index.html?com/google/common/base/Functions.html
*
* com.google.common.base.Predicates
* https://google.github.io/guava/releases/snapshot-jre/api/docs/index.html?com/google/common/base/Predicates.html
*
* More about these can be found at
* https://github.com/google/guava/wiki/FunctionalExplained
*/
goog.provide('goog.functions');
/**
* Creates a function that always returns the same value.
* @param {T} retValue The value to return.
* @return {function():T} The new function.
* @template T
*/
goog.functions.constant = function(retValue) {
'use strict';
return function() {
'use strict';
return retValue;
};
};
/**
* Always returns false.
* @type {function(...): boolean}
*/
goog.functions.FALSE = function() {
'use strict';
return false;
};
/**
* Always returns true.
* @type {function(...): boolean}
*/
goog.functions.TRUE = function() {
'use strict';
return true;
};
/**
* Always returns `null`.
* @type {function(...): null}
*/
goog.functions.NULL = function() {
'use strict';
return null;
};
/**
* Always returns `undefined`.
* @type {function(...): undefined}
*/
goog.functions.UNDEFINED = function() {
return undefined;
};
/**
* Always returns `undefined` (loosely-typed version).
* @type {!Function}
*/
goog.functions.EMPTY = /** @type {?} */ (goog.functions.UNDEFINED);
/**
* A simple function that returns the first argument of whatever is passed
* into it.
* @param {T=} opt_returnValue The single value that will be returned.
* @param {...*} var_args Optional trailing arguments. These are ignored.
* @return {T} The first argument passed in, or undefined if nothing was passed.
* @template T
*/
goog.functions.identity = function(opt_returnValue, var_args) {
'use strict';
return opt_returnValue;
};
/**
* Creates a function that always throws an error with the given message.
* @param {string} message The error message.
* @return {!Function} The error-throwing function.
*/
goog.functions.error = function(message) {
'use strict';
return function() {
'use strict';
throw new Error(message);
};
};
/**
* Creates a function that throws the given object.
* @param {*} err An object to be thrown.
* @return {!Function} The error-throwing function.
*/
goog.functions.fail = function(err) {
'use strict';
return function() {
'use strict';
throw err;
};
};
/**
* Given a function, create a function that keeps opt_numArgs arguments and
* silently discards all additional arguments.
* @param {Function} f The original function.
* @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
* @return {!Function} A version of f that only keeps the first opt_numArgs
* arguments.
*/
goog.functions.lock = function(f, opt_numArgs) {
'use strict';
opt_numArgs = opt_numArgs || 0;
return function() {
'use strict';
const self = /** @type {*} */ (this);
return f.apply(self, Array.prototype.slice.call(arguments, 0, opt_numArgs));
};
};
/**
* Creates a function that returns its nth argument.
* @param {number} n The position of the return argument.
* @return {!Function} A new function.
*/
goog.functions.nth = function(n) {
'use strict';
return function() {
'use strict';
return arguments[n];
};
};
/**
* Like goog.partial(), except that arguments are added after arguments to the
* returned function.
*
* Usage:
* function f(arg1, arg2, arg3, arg4) { ... }
* var g = goog.functions.partialRight(f, arg3, arg4);
* g(arg1, arg2);
*
* @param {!Function} fn A function to partially apply.
* @param {...*} var_args Additional arguments that are partially applied to fn
* at the end.
* @return {!Function} A partially-applied form of the function goog.partial()
* was invoked as a method of.
*/
goog.functions.partialRight = function(fn, var_args) {
'use strict';
const rightArgs = Array.prototype.slice.call(arguments, 1);
return function() {
'use strict';
// Even in strict mode, IE10/11 and Edge (non-Chromium) use global context
// when free-calling functions. To catch cases where people were using this
// erroneously, we explicitly change the context to undefined to match
// strict mode specifications.
let self = /** @type {*} */ (this);
if (self === goog.global) {
self = undefined;
}
const newArgs = Array.prototype.slice.call(arguments);
newArgs.push.apply(newArgs, rightArgs);
return fn.apply(self, newArgs);
};
};
/**
* Given a function, create a new function that swallows its return value
* and replaces it with a new one.
* @param {Function} f A function.
* @param {T} retValue A new return value.
* @return {function(...?):T} A new function.
* @template T
*/
goog.functions.withReturnValue = function(f, retValue) {
'use strict';
return goog.functions.sequence(f, goog.functions.constant(retValue));
};
/**
* Creates a function that returns whether its argument equals the given value.
*
* Example:
* var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
*
* @param {*} value The value to compare to.
* @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
* comparison rather than a strict (===) one. Defaults to false.
* @return {function(*):boolean} The new function.
*/
goog.functions.equalTo = function(value, opt_useLooseComparison) {
'use strict';
return function(other) {
'use strict';
return opt_useLooseComparison ? (value == other) : (value === other);
};
};
/**
* Creates the composition of the functions passed in.
* For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
* @param {function(...?):T} fn The final function.
* @param {...Function} var_args A list of functions.
* @return {function(...?):T} The composition of all inputs.
* @template T
*/
goog.functions.compose = function(fn, var_args) {
'use strict';
const functions = arguments;
const length = functions.length;
return function() {
'use strict';
const self = /** @type {*} */ (this);
let result;
if (length) {
result = functions[length - 1].apply(self, arguments);
}
for (let i = length - 2; i >= 0; i--) {
result = functions[i].call(self, result);
}
return result;
};
};
/**
* Creates a function that calls the functions passed in in sequence, and
* returns the value of the last function. For example,
* (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
* @param {...Function} var_args A list of functions.
* @return {!Function} A function that calls all inputs in sequence.
*/
goog.functions.sequence = function(var_args) {
'use strict';
const functions = arguments;
const length = functions.length;
return function() {
'use strict';
const self = /** @type {*} */ (this);
let result;
for (let i = 0; i < length; i++) {
result = functions[i].apply(self, arguments);
}
return result;
};
};
/**
* Creates a function that returns true if each of its components evaluates
* to true. The components are evaluated in order, and the evaluation will be
* short-circuited as soon as a function returns false.
* For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
* @param {...Function} var_args A list of functions.
* @return {function(...?):boolean} A function that ANDs its component
* functions.
*/
goog.functions.and = function(var_args) {
'use strict';
const functions = arguments;
const length = functions.length;
return function() {
'use strict';
const self = /** @type {*} */ (this);
for (let i = 0; i < length; i++) {
if (!functions[i].apply(self, arguments)) {
return false;
}
}
return true;
};
};
/**
* Creates a function that returns true if any of its components evaluates
* to true. The components are evaluated in order, and the evaluation will be
* short-circuited as soon as a function returns true.
* For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
* @param {...Function} var_args A list of functions.
* @return {function(...?):boolean} A function that ORs its component
* functions.
*/
goog.functions.or = function(var_args) {
'use strict';
const functions = arguments;
const length = functions.length;
return function() {
'use strict';
const self = /** @type {*} */ (this);
for (let i = 0; i < length; i++) {
if (functions[i].apply(self, arguments)) {
return true;
}
}
return false;
};
};
/**
* Creates a function that returns the Boolean opposite of a provided function.
* For example, (goog.functions.not(f))(x) is equivalent to !f(x).
* @param {!Function} f The original function.
* @return {function(...?):boolean} A function that delegates to f and returns
* opposite.
*/
goog.functions.not = function(f) {
'use strict';
return function() {
'use strict';
const self = /** @type {*} */ (this);
return !f.apply(self, arguments);
};
};
/**
* Generic factory function to construct an object given the constructor
* and the arguments. Intended to be bound to create object factories.
*
* Example:
*
* var factory = goog.partial(goog.functions.create, Class);
*
* @param {function(new:T, ...)} constructor The constructor for the Object.
* @param {...*} var_args The arguments to be passed to the constructor.
* @return {T} A new instance of the class given in `constructor`.
* @template T
* @deprecated This function does not work with ES6 class constructors. Use
* arrow functions + spread args instead.
*/
goog.functions.create = function(constructor, var_args) {
'use strict';
/**
* @constructor
* @final
*/
const temp = function() {};
temp.prototype = constructor.prototype;
// obj will have constructor's prototype in its chain and
// 'obj instanceof constructor' will be true.
const obj = new temp();
// obj is initialized by constructor.
// arguments is only array-like so lacks shift(), but can be used with
// the Array prototype function.
constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
return obj;
};
/**
* @define {boolean} Whether the return value cache should be used.
* This should only be used to disable caches when testing.
*/
goog.functions.CACHE_RETURN_VALUE =
goog.define('goog.functions.CACHE_RETURN_VALUE', true);
/**
* Gives a wrapper function that caches the return value of a parameterless
* function when first called.
*
* When called for the first time, the given function is called and its
* return value is cached (thus this is only appropriate for idempotent
* functions). Subsequent calls will return the cached return value. This
* allows the evaluation of expensive functions to be delayed until first used.
*
* To cache the return values of functions with parameters, see goog.memoize.
*
* @param {function():T} fn A function to lazily evaluate.
* @return {function():T} A wrapped version the function.
* @template T
*/
goog.functions.cacheReturnValue = function(fn) {
'use strict';
let called = false;
let value;
return function() {
'use strict';
if (!goog.functions.CACHE_RETURN_VALUE) {
return fn();
}
if (!called) {
value = fn();
called = true;
}
return value;
};
};
/**
* Wraps a function to allow it to be called, at most, once. All
* additional calls are no-ops.
*
* This is particularly useful for initialization functions
* that should be called, at most, once.
*
* @param {function():*} f Function to call.
* @return {function():undefined} Wrapped function.
*/
goog.functions.once = function(f) {
'use strict';
// Keep a reference to the function that we null out when we're done with
// it -- that way, the function can be GC'd when we're done with it.
let inner = f;
return function() {
'use strict';
if (inner) {
const tmp = inner;
inner = null;
tmp();
}
};
};
/**
* Wraps a function to allow it to be called, at most, once per interval
* (specified in milliseconds). If the wrapper function is called N times within
* that interval, only the Nth call will go through.
*
* This is particularly useful for batching up repeated actions where the
* last action should win. This can be used, for example, for refreshing an
* autocomplete pop-up every so often rather than updating with every keystroke,
* since the final text typed by the user is the one that should produce the
* final autocomplete results. For more stateful debouncing with support for
* pausing, resuming, and canceling debounced actions, use
* `goog.async.Debouncer`.
*
* @param {function(this:SCOPE, ...?)} f Function to call.
* @param {number} interval Interval over which to debounce. The function will
* only be called after the full interval has elapsed since the last call.
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
* @return {function(...?): undefined} Wrapped function.
* @template SCOPE
*/
goog.functions.debounce = function(f, interval, opt_scope) {
'use strict';
let timeout = 0;
return /** @type {function(...?)} */ (function(var_args) {
'use strict';
goog.global.clearTimeout(timeout);
const args = arguments;
timeout = goog.global.setTimeout(function() {
'use strict';
f.apply(opt_scope, args);
}, interval);
});
};
/**
* Wraps a function to allow it to be called, at most, once per interval
* (specified in milliseconds). If the wrapper function is called N times in
* that interval, both the 1st and the Nth calls will go through.
*
* This is particularly useful for limiting repeated user requests where the
* the last action should win, but you also don't want to wait until the end of
* the interval before sending a request out, as it leads to a perception of
* slowness for the user.
*
* @param {function(this:SCOPE, ...?)} f Function to call.
* @param {number} interval Interval over which to throttle. The function can
* only be called once per interval.
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
* @return {function(...?): undefined} Wrapped function.
* @template SCOPE
*/
goog.functions.throttle = function(f, interval, opt_scope) {
'use strict';
let timeout = 0;
let shouldFire = false;
let storedArgs = [];
const handleTimeout = function() {
'use strict';
timeout = 0;
if (shouldFire) {
shouldFire = false;
fire();
}
};
const fire = function() {
'use strict';
timeout = goog.global.setTimeout(handleTimeout, interval);
let args = storedArgs;
storedArgs = []; // Avoid a space leak by clearing stored arguments.
f.apply(opt_scope, args);
};
return /** @type {function(...?)} */ (function(var_args) {
'use strict';
storedArgs = arguments;
if (!timeout) {
fire();
} else {
shouldFire = true;
}
});
};
/**
* Wraps a function to allow it to be called, at most, once per interval
* (specified in milliseconds). If the wrapper function is called N times within
* that interval, only the 1st call will go through.
*
* This is particularly useful for limiting repeated user requests where the
* first request is guaranteed to have all the data required to perform the
* final action, so there's no need to wait until the end of the interval before
* sending the request out.
*
* @param {function(this:SCOPE, ...?)} f Function to call.
* @param {number} interval Interval over which to rate-limit. The function will
* only be called once per interval, and ignored for the remainer of the
* interval.
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
* @return {function(...?): undefined} Wrapped function.
* @template SCOPE
*/
goog.functions.rateLimit = function(f, interval, opt_scope) {
'use strict';
let timeout = 0;
const handleTimeout = function() {
'use strict';
timeout = 0;
};
return /** @type {function(...?)} */ (function(var_args) {
'use strict';
if (!timeout) {
timeout = goog.global.setTimeout(handleTimeout, interval);
f.apply(opt_scope, arguments);
}
});
};
/**
* Returns true if the specified value is a function.
* @param {*} val Variable to test.
* @return {boolean} Whether variable is a function.
*/
goog.functions.isFunction = (val) => {
return typeof val === 'function';
};

Some files were not shown because too many files have changed in this diff Show More