Skip to content

Commit 76ac6bf

Browse files
authored
CLJS-3322: Upgrade to latest Closure Library - handle non-legacy GCL goog.module namespaces (#105)
* bump gcl * add goog.module handling case to analyzer * add goog.module handling case to compiler * add missing case to browser REPL bootstrap for goog.module * generalize munge-goog-module-lib * add resolve-import helper * fixup emission test * resolve goog.module imports in resolve-var * check that emission doesn't shadow import usage * wrap goog.module.get in goog.scope to avoid silly Closure warnings * remove dependency on goog.object from cljs.core macros file * add comment about goog.scope workaround * add docstrings to extern parsing ns * add Token/FUNCTION case * Token/NAME should check for simple name * handle goog.module case in parse-externs * make parsed->defs a multimethod * add resource->source-file helper * ^Node type hints * in NAME case stop if parent is OBJECTLIT * STRING_KEY case does not need split on "." * when parsing goog.modules, only provide ClojureScript defs for exported defs * remove unneeded condition * add internal reference to goog.math.Long (to allow self-parity tests to pass) * test cases
1 parent 71c6f47 commit 76ac6bf

File tree

15 files changed

+269
-52
lines changed

15 files changed

+269
-52
lines changed

deps.edn

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
org.clojure/clojure {:mvn/version "1.10.0"}
66
org.clojure/core.specs.alpha {:mvn/version "0.1.24"}
77
org.clojure/data.json {:mvn/version "0.2.6"}
8-
org.clojure/google-closure-library {:mvn/version "0.0-20201211-3e6c510d"}
8+
org.clojure/google-closure-library {:mvn/version "0.0-20211011-0726fdeb"}
99
org.clojure/spec.alpha {:mvn/version "0.1.143"}
1010
org.clojure/tools.reader {:mvn/version "1.3.3"}
1111
org.clojure/test.check {:mvn/version "0.10.0-alpha3"}}

pom.template.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
<dependency>
3636
<groupId>org.clojure</groupId>
3737
<artifactId>google-closure-library</artifactId>
38-
<version>0.0-20201211-3e6c510d</version>
38+
<version>0.0-20210811-6da97fe1</version>
3939
</dependency>
4040
<dependency>
4141
<groupId>org.clojure</groupId>

project.clj

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
[org.clojure/tools.reader "1.3.3"]
1616
[org.clojure/test.check "0.10.0-alpha3" :scope "test"]
1717
[com.cognitect/transit-clj "0.8.309"]
18-
[org.clojure/google-closure-library "0.0-20201211-3e6c510d"]
18+
[org.clojure/google-closure-library "0.0-20210811-6da97fe1"]
1919
[com.google.javascript/closure-compiler-unshaded "v20210808"]]
2020
:profiles {:1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]}
2121
:uberjar {:aot :all :main cljs.main}

script/bootstrap

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CORE_SPECS_ALPHA_RELEASE="0.1.24"
88
CLOSURE_RELEASE="20210808"
99
DJSON_RELEASE="0.2.6"
1010
TRANSIT_RELEASE="0.8.309"
11-
GCLOSURE_LIB_RELEASE="0.0-20201211-3e6c510d"
11+
GCLOSURE_LIB_RELEASE="0.0-20210811-6da97fe1"
1212
TREADER_RELEASE="1.3.3"
1313
TEST_CHECK_RELEASE="0.10.0-alpha3"
1414

src/main/cljs/cljs/core.cljs

+4
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,10 @@ reduces them without incurring seq initialization"
22842284
(not (identical? n js/Infinity))
22852285
(== (js/parseFloat n) (js/parseInt n 10))))
22862286

2287+
(def
2288+
^{:doc "INTERNAL: do not use"}
2289+
LongImpl goog.math.Long)
2290+
22872291
(defn int?
22882292
"Return true if x satisfies integer? or is an instance of goog.math.Integer
22892293
or goog.math.Long."

src/main/cljs/cljs/loader.cljs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
(ns cljs.loader
1010
(:require [goog.object :as gobj]
1111
[goog.html.legacyconversions :as legacy])
12-
(:import [goog.module ModuleLoader]
13-
[goog.module ModuleManager]))
12+
(:import [goog.module ModuleManager]
13+
[goog.module ModuleLoader]))
1414

1515
(def module-infos MODULE_INFOS) ;; set by compiler
1616
(def module-uris

src/main/cljs/clojure/browser/repl.cljs

+4-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,10 @@
227227
(let [ret (.require__ js/goog src)]
228228
(when (= reload "reload-all")
229229
(set! (.-cljsReloadAll_ js/goog) false))
230-
ret))))))
230+
;; handle requires from Closure Library goog.modules
231+
(if (js/goog.isInModuleLoader_)
232+
(js/goog.module.getInternal_ src)
233+
ret)))))))
231234

232235
(defn connect
233236
"Connects to a REPL server from an HTML document. After the

src/main/clojure/cljs/analyzer.cljc

+35-1
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,12 @@
812812
(or (contains? global-exports (symbol module))
813813
(contains? global-exports (name module)))))
814814

815+
(defn goog-module-dep?
816+
[module]
817+
(let [[module _] (lib&sublib module)
818+
module-type (get-in @env/*compiler* [:js-dependency-index (str module) :module])]
819+
(= :goog module-type)))
820+
815821
(defn confirm-var-exists
816822
([env prefix suffix]
817823
(let [warn (confirm-var-exist-warning env prefix suffix)]
@@ -1010,6 +1016,12 @@
10101016
(str "node$module$" (munge (string/replace (str name) #"[.\/]" #?(:clj "\\$"
10111017
:cljs "$$")))))
10121018

1019+
(defn munge-goog-module-lib
1020+
([name]
1021+
(str "goog$module$" (munge (string/replace (str name) #"[.\/]" #?(:clj "\\$" :cljs "$$")))))
1022+
([ns name]
1023+
(str (munge ns) "." (munge-goog-module-lib name))))
1024+
10131025
(defn munge-global-export [name]
10141026
(str "global$module$" (munge (string/replace (str name) #"[.\/]" #?(:clj "\\$"
10151027
:cljs "$$")))))
@@ -1031,6 +1043,7 @@
10311043

10321044
(defn ns->module-type [ns]
10331045
(cond
1046+
(goog-module-dep? ns) :goog-module
10341047
(js-module-exists? ns) :js
10351048
(node-module-dep? ns) :node
10361049
(dep-has-global-exports? ns) :global))
@@ -1072,6 +1085,12 @@
10721085
:op :js-var
10731086
:foreign true}))
10741087

1088+
(defmethod resolve* :goog-module
1089+
[env sym full-ns current-ns]
1090+
{:name (symbol (str current-ns) (str (munge-goog-module-lib full-ns) "." (name sym)))
1091+
:ns current-ns
1092+
:op :var})
1093+
10751094
(defmethod resolve* :global
10761095
[env sym full-ns current-ns]
10771096
(let [pre (extern-pre sym current-ns)]
@@ -1135,6 +1154,15 @@
11351154
:op :js-var
11361155
:ns current-ns})))
11371156

1157+
(defn resolve-import
1158+
"goog.modules are deterministically assigned to a property of the namespace,
1159+
we cannot expect the reference will be globally available, so we resolve to
1160+
namespace local reference."
1161+
[env import]
1162+
(if (goog-module-dep? import)
1163+
(symbol (munge-goog-module-lib (-> env :ns :name) import))
1164+
import))
1165+
11381166
;; core.async calls `macroexpand-1` manually with an ill-formed
11391167
;; :locals map. Normally :locals maps symbols maps, but
11401168
;; core.async adds entries mapping symbols to symbols. We work
@@ -1207,7 +1235,13 @@
12071235
;; check if prefix is some existing def
12081236
(if-let [resolved (resolve-var env prefix nil false)]
12091237
(update resolved :name #(symbol (str % "." suffix)))
1210-
(let [idx (.lastIndexOf s ".")
1238+
;; glib imports (i.e. (:import [goog.module ModuleLoader])
1239+
;; are always just dotted symbols after the recursion
1240+
(let [s (str
1241+
(cond->> s
1242+
(goog-module-dep? sym)
1243+
(resolve-import env)))
1244+
idx (.lastIndexOf (str s) ".")
12111245
pre (subs s 0 idx)
12121246
suf (subs s (inc idx))]
12131247
{:op :var

src/main/clojure/cljs/compiler.cljc

+18
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,9 @@
12941294
(let [{node-libs true libs-to-load false} (group-by ana/node-module-dep? libs)]
12951295
[node-libs libs-to-load])
12961296
[nil libs]))
1297+
[goog-modules libs-to-load] (let [{goog-modules true libs-to-load false}
1298+
(group-by ana/goog-module-dep? libs-to-load)]
1299+
[goog-modules libs-to-load])
12971300
global-exports-libs (filter ana/dep-has-global-exports? libs-to-load)]
12981301
(when (-> libs meta :reload-all)
12991302
(emitln "if(!COMPILED) " loaded-libs-temp " = " loaded-libs " || cljs.core.set([\"cljs.core\"]);")
@@ -1336,11 +1339,26 @@
13361339
:else
13371340
(when-not (= lib 'goog)
13381341
(emitln "goog.require('" (munge lib) "');"))))
1342+
;; Node Libraries
13391343
(doseq [lib node-libs]
13401344
(let [[lib' sublib] (ana/lib&sublib lib)]
13411345
(emitln (munge ns-name) "."
13421346
(ana/munge-node-lib lib)
13431347
" = require('" lib' "')" (sublib-select sublib) ";")))
1348+
;; Google Closure Library Modules (i.e. goog.module(...))
1349+
;; these must be assigned to vars
1350+
(doseq [lib goog-modules]
1351+
(let [[lib' sublib] (ana/lib&sublib lib)]
1352+
(emitln "goog.require('" lib' "');")
1353+
;; we emit goog.scope here to suppress a Closure error about
1354+
;; goog.module.get when compiling - meant to discourage incorrect
1355+
;; usage by hand written code - not applicable here
1356+
(emitln "goog.scope(function(){")
1357+
(emitln (munge ns-name) "."
1358+
(ana/munge-goog-module-lib lib)
1359+
" = goog.module.get('" lib' "')" (sublib-select sublib) ";")
1360+
(emitln "});")))
1361+
;; Global Exports
13441362
(doseq [lib global-exports-libs]
13451363
(let [{:keys [global-exports]} (get js-dependency-index (name (-> lib ana/lib&sublib first)))]
13461364
(emit-global-export ns-name global-exports lib)))

src/main/clojure/cljs/core.cljc

+5-5
Original file line numberDiff line numberDiff line change
@@ -1430,9 +1430,9 @@
14301430
(core/let [psym (resolve p)
14311431
pfn-prefix (subs (core/str psym) 0
14321432
(clojure.core/inc (.indexOf (core/str psym) "/")))]
1433-
(cons `(goog.object/set ~psym ~type true)
1433+
(cons `(unchecked-set ~psym ~type true)
14341434
(map (core/fn [[f & meths :as form]]
1435-
`(goog.object/set ~(symbol (core/str pfn-prefix f))
1435+
`(unchecked-set ~(symbol (core/str pfn-prefix f))
14361436
~type ~(with-meta `(fn ~@meths) (meta form))))
14371437
sigs))))
14381438

@@ -2672,8 +2672,8 @@
26722672
(js-obj* '())
26732673
`(let [~@(apply concat (clojure.set/map-invert expr->local))
26742674
~obj ~(js-obj* (filter-on-keys core/string? kvs))]
2675-
~@(map (core/fn [[k v]] `(goog.object/set ~obj ~k ~v)) sym-pairs)
2676-
~@(map (core/fn [[k v]] `(goog.object/set ~obj ~v ~(core/get kvs k))) expr->local)
2675+
~@(map (core/fn [[k v]] `(unchecked-set ~obj ~k ~v)) sym-pairs)
2676+
~@(map (core/fn [[k v]] `(unchecked-set ~obj ~v ~(core/get kvs k))) expr->local)
26772677
~obj))))
26782678

26792679
(core/defmacro alength [a]
@@ -2888,7 +2888,7 @@
28882888
(core/list 'js* "''+~{}" s))
28892889

28902890
(core/defmacro es6-iterable [ty]
2891-
`(goog.object/set (.-prototype ~ty) cljs.core/ITER_SYMBOL
2891+
`(unchecked-set (.-prototype ~ty) cljs.core/ITER_SYMBOL
28922892
(fn []
28932893
(this-as this#
28942894
(cljs.core/es6-iterator this#)))))

0 commit comments

Comments
 (0)