Skip to content

Commit 1d6d4cd

Browse files
committed
CLJS-3123: analyze google closure namespaces
arity checking, formatted docstrings, and type inference appear to be working
1 parent 9f4390a commit 1d6d4cd

File tree

2 files changed

+56
-29
lines changed

2 files changed

+56
-29
lines changed

src/main/clojure/cljs/analyzer.cljc

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@
1414
:refer [no-warn wrapping-errors with-warning-handlers
1515
disallowing-recur allowing-redef disallowing-ns*]]
1616
[cljs.env.macros :refer [ensure]]))
17-
#?(:clj (:require [cljs.util :as util :refer [ns->relpath topo-sort]]
18-
[clojure.java.io :as io]
19-
[clojure.string :as string]
20-
[clojure.set :as set]
21-
[cljs.env :as env :refer [ensure]]
22-
[cljs.js-deps :as deps]
23-
[cljs.tagged-literals :as tags]
24-
[clojure.tools.reader :as reader]
25-
[clojure.tools.reader.reader-types :as readers]
26-
[clojure.edn :as edn])
17+
#?(:clj (:require [cljs.util :as util :refer [ns->relpath topo-sort]]
18+
[clojure.java.io :as io]
19+
[clojure.string :as string]
20+
[clojure.set :as set]
21+
[cljs.env :as env :refer [ensure]]
22+
[cljs.js-deps :as deps]
23+
[cljs.tagged-literals :as tags]
24+
[clojure.tools.reader :as reader]
25+
[clojure.tools.reader.reader-types :as readers]
26+
[clojure.edn :as edn]
27+
[cljs.externs :as externs])
2728
:cljs (:require [goog.string :as gstring]
2829
[clojure.string :as string]
2930
[clojure.set :as set]
@@ -2576,18 +2577,23 @@
25762577
(some *cljs-dep-set* deps))))))
25772578
(doseq [dep deps]
25782579
(when-not (or (some? (get-in compiler [::namespaces dep :defs]))
2579-
(contains? (:js-dependency-index compiler) (name dep))
25802580
(node-module-dep? dep)
25812581
(js-module-exists? (name dep))
25822582
#?(:clj (deps/find-classpath-lib dep)))
2583-
#?(:clj (if-some [src (locate-src dep)]
2584-
(analyze-file src opts)
2585-
(throw
2586-
(error env
2587-
(error-message :undeclared-ns {:ns-sym dep :js-provide (name dep)}))))
2588-
:cljs (throw
2589-
(error env
2590-
(error-message :undeclared-ns {:ns-sym dep :js-provide (name dep)}))))))))))
2583+
(if (contains? (:js-dependency-index compiler) (name dep))
2584+
(let [dep-name (name dep)]
2585+
(when (string/starts-with? dep-name "goog.")
2586+
(let [js-lib (get-in compiler [:js-dependency-index dep-name])
2587+
ns (externs/analyze-goog-file (:file js-lib))]
2588+
(swap! env/*compiler* update-in [::namespaces dep] merge ns))))
2589+
#?(:clj (if-some [src (locate-src dep)]
2590+
(analyze-file src opts)
2591+
(throw
2592+
(error env
2593+
(error-message :undeclared-ns {:ns-sym dep :js-provide (name dep)}))))
2594+
:cljs (throw
2595+
(error env
2596+
(error-message :undeclared-ns {:ns-sym dep :js-provide (name dep)})))))))))))
25912597

25922598
(defn missing-use? [lib sym cenv]
25932599
(let [js-lib (get-in cenv [:js-dependency-index (name lib)])]

src/main/clojure/cljs/externs.clj

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
(def ^:dynamic *ignore-var* false)
2222
(def ^:dynamic *source-file* nil)
23+
(def ^:dynamic *goog-ns* nil)
2324

2425
;; ------------------------------------------------------------------------------
2526
;; Externs Parsing
@@ -37,6 +38,16 @@
3738
(if (.isString child)
3839
(symbol (.. child getString)))))))
3940

41+
(defn params->method-params [xs]
42+
(letfn [(not-opt? [x]
43+
(not (string/starts-with? (name x) "opt_")))]
44+
(let [required (into [] (take-while not-opt? xs))
45+
opts (drop-while not-opt? xs)]
46+
(loop [ret [required] opts opts]
47+
(if-let [opt (first opts)]
48+
(recur (conj ret (conj (last ret) opt)) (drop 1 opts))
49+
(seq ret))))))
50+
4051
(defn get-var-info [^Node node]
4152
(when node
4253
(let [info (.getJSDocInfo node)]
@@ -50,9 +61,15 @@
5061
(.isConstructor info) (merge {:ctor qname})
5162
(.isInterface info) (merge {:iface qname})))
5263
(if (.hasReturnType info)
53-
{:tag 'Function
54-
:ret-tag (get-tag (.getReturnType info))
55-
:arglists (list (into [] (map symbol (.getParameterNames info))))})))
64+
(let [arglist (into [] (map symbol (.getParameterNames info)))
65+
arglists (params->method-params arglist)]
66+
{:tag 'Function
67+
:fn-var true
68+
:ret-tag (get-tag (.getReturnType info))
69+
:variadic? (boolean (some '#{var_args} arglist))
70+
:max-fixed-arity (count (take-while #(not= 'var_args %) arglist))
71+
:method-params arglists
72+
:arglists arglists}))))
5673
{:file *source-file*
5774
:line (.getLineno node)}
5875
(when-let [doc (.getOriginalCommentString info)]
@@ -177,21 +194,25 @@
177194
(fn [m xs]
178195
(let [sym (last xs)]
179196
(cond-> m
180-
(seq xs) (assoc sym (meta sym)))))
197+
(seq xs) (assoc sym (merge (meta sym) {:ns *goog-ns* :name sym})))))
181198
{} externs))
182199

183200
(defn analyze-goog-file [f]
184201
(let [rsrc (io/resource f)
185-
desc (js-deps/parse-js-ns (line-seq (io/reader rsrc)))]
202+
desc (js-deps/parse-js-ns (line-seq (io/reader rsrc)))
203+
ns (-> (:provides desc) first symbol)]
186204
;; TODO: figure out what to do about other provides
187-
{:name (first (:provides desc))
188-
:defs (parsed->defs
189-
(parse-externs
190-
(SourceFile/fromInputStream f (io/input-stream rsrc))))}))
205+
(binding [*goog-ns* ns]
206+
{:name ns
207+
:defs (parsed->defs
208+
(parse-externs
209+
(SourceFile/fromInputStream f (io/input-stream rsrc))))})))
191210

192211
(comment
193212

194-
(analyze-goog-file "goog/string/string.js")
213+
(pprint (analyze-goog-file "goog/object/object.js"))
214+
215+
(pprint (analyze-goog-file "goog/string/string.js"))
195216

196217
(require '[clojure.java.io :as io]
197218
'[cljs.closure :as closure]

0 commit comments

Comments
 (0)