(defn analyze-dot [env target field member+ form]
(let [v [target field member+]
{:keys [dot-action target method field args]} (build-dot-form v)
enve (assoc env :context :expr)
targetexpr (analyze enve target)
form-meta (meta form)
target-tag (:tag targetexpr)
prop (or field method)
tag (or (:tag form-meta)
(and (js-tag? target-tag)
(vary-meta (normalize-js-tag target-tag)
update-in [:prefix] (fnil conj '[Object]) prop))
nil)]
(when (not (string/starts-with? (str prop) "cljs$"))
;; Adding to Object
(when (= 'Object (first (-> tag meta :prefix)))
(warning :infer-warning env
{:warn-type :object :form form :property prop}))
(when (not= 'js target-tag)
;; Cannot determine type of the target
(when (or (nil? target-tag) ('#{any} target-tag))
(warning :infer-warning env
{:warn-type :target :form form}))
;; Unresolveable property on existing extern
(let [[pre' pre] ((juxt butlast identity) (-> tag meta :prefix))]
(when (and (has-extern? pre') (not (has-extern? pre)))
(warning :infer-warning env
{:warn-type :property :form form
:type (symbol "js"
(string/join "."
(cond-> pre' (= 'prototype (last pre')) butlast)))
:property prop})))))
(when (js-tag? tag)
(let [pre (-> tag meta :prefix)]
(when-not (has-extern? pre)
(swap! env/*compiler* update-in
(into [::namespaces (-> env :ns :name) :externs] pre) merge {}))))
(case dot-action
::access (let [children [targetexpr]]
{:op :dot
:env env
:form form
:target targetexpr
:field field
:children children
:tag (if (js-tag? tag)
(or (js-tag (-> tag meta :prefix) :tag) tag)
tag)})
::call (let [argexprs (map #(analyze enve %) args)
children (into [targetexpr] argexprs)]
{:op :dot
:env env
:form form
:target targetexpr
:method method
:args argexprs
:children children
:tag (if (js-tag? tag)
(or (js-tag (-> tag meta :prefix) :ret-tag) 'js)
tag)}))))