Skip to content

Commit 715cdc0

Browse files
committed
Bump Google Closure Compiler & Library
Google Closure Compiler is now latest. GCL snapshot is from December. Address various minor breaking changes in GCC & GCL. GCL removed some long outstanding type detection helpers - goog/isFunction, goog/isString, goog/isArray. For isFunction add a new js-fn? macro which uses `typeOf` operator. For isString rely on string? now. for isArray, isNumber use goog/typeOf Throwable from goog common Java lib is now gone. Just print the Throwable for now. More GCL libs are now written in ES6. This broke self-parity because cljs.closure/transpile did not respect `:language-out`. Port GCC Transpiler implementation so we have more control. Self-parity build now uses :language-out :es6 and passes. Add tests for new transpile helpers. GCL now has a new import mechanism only for types `goog.requireType`. This signals to GCC that the file is required but only for type checking. Update cljs.js-deps so that `:require-type` is included when parsing JS files. Update cljs.closure/js-dependencies so that `:require-types` deps are inputs to the build so that GCC can type check. Add JS file parsing tests that check for `:require-types` in both the JS index and for individual file parsing. Update the CI script to adopt -M over -A.
1 parent 496cbc2 commit 715cdc0

File tree

19 files changed

+150
-79
lines changed

19 files changed

+150
-79
lines changed

.github/workflows/test.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
${{ runner.os }}-jsc
4545
4646
- name: Build tests
47-
run: clojure -A:runtime.test.build
47+
run: clojure -M:runtime.test.build
4848

4949
- name: Install JSC
5050
run: ./ci/install_jsc.sh
@@ -86,7 +86,7 @@ jobs:
8686
${{ runner.os }}-${{ env.cache-name }}-
8787
8888
- name: Build tests
89-
run: clojure -A:selfhost.test.build
89+
run: clojure -M:selfhost.test.build
9090

9191
- name: Run tests
9292
run: |
@@ -125,7 +125,7 @@ jobs:
125125
${{ runner.os }}-${{ env.cache-name }}-
126126
127127
- name: Build tests
128-
run: clojure -A:selfparity.test.build
128+
run: clojure -M:selfparity.test.build
129129

130130
- name: Run tests
131131
run: |
@@ -164,7 +164,7 @@ jobs:
164164
${{ runner.os }}-${{ env.cache-name }}-
165165
166166
- name: Run tests
167-
run: clojure -A:compiler.test:compiler.test.run
167+
run: clojure -M:compiler.test:compiler.test.run
168168

169169
# CLI Tests
170170
cli-test:
@@ -205,5 +205,5 @@ jobs:
205205
- name: Run tests
206206
run: |
207207
unset JAVA_TOOL_OPTIONS
208-
clojure -A:cli.test.run | tee test-out.txt
208+
clojure -M:cli.test.run | tee test-out.txt
209209
grep -qxF '0 failures, 0 errors.' test-out.txt

bin/cljsc

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ if ! test "$(ls -A "$CLOJURESCRIPT_HOME/lib" 2>/dev/null)"; then
1313
fi
1414

1515
CLJSC_CP=''
16-
for next in lib/*: src/main/clojure: src/main/cljs: src/test/cljs; do
16+
for next in lib/*: src/main/clojure: src/main/cljs: src/test/cljs: src/test/self; do
1717
CLJSC_CP="${CLJSC_CP}${CLOJURESCRIPT_HOME}/${next}"
1818
done
1919

deps.edn

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{:paths ["src/main/clojure" "src/main/cljs" "resources"]
22
:deps
3-
{com.google.javascript/closure-compiler-unshaded {:mvn/version "v20200315"}
3+
{com.google.javascript/closure-compiler-unshaded {:mvn/version "v20210202"}
44
com.cognitect/transit-clj {:mvn/version "0.8.309"}
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-20191016-6ae1f72f"}
8+
org.clojure/google-closure-library {:mvn/version "0.0-20201211-3e6c510d"}
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

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
<dependency>
3131
<groupId>com.google.javascript</groupId>
3232
<artifactId>closure-compiler-unshaded</artifactId>
33-
<version>v20200315</version>
33+
<version>v20210202</version>
3434
</dependency>
3535
<dependency>
3636
<groupId>org.clojure</groupId>
3737
<artifactId>google-closure-library</artifactId>
38-
<version>0.0-20191016-6ae1f72f</version>
38+
<version>0.0-20201211-3e6c510d</version>
3939
</dependency>
4040
<dependency>
4141
<groupId>org.clojure</groupId>

project.clj

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
:source-paths ["src/main/clojure" "src/main/cljs"]
99
:resource-paths ["src/main/cljs" "resources"]
1010
:test-paths ["src/test/clojure" "src/test/cljs" "src/test/self" "src/test/cljs_build" "src/test/cljs_cp"]
11-
:dependencies [[org.clojure/clojure "1.10.0-alpha4"]
11+
:dependencies [[org.clojure/clojure "1.10.0"]
1212
[org.clojure/spec.alpha "0.1.143"]
1313
[org.clojure/core.specs.alpha "0.1.24"]
1414
[org.clojure/data.json "0.2.6"]
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-20191016-6ae1f72f"]
19-
[com.google.javascript/closure-compiler-unshaded "v20200315"]]
18+
[org.clojure/google-closure-library "0.0-20201211-3e6c510d"]
19+
[com.google.javascript/closure-compiler-unshaded "v20210202"]]
2020
:profiles {:1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]}
2121
:uberjar {:aot :all :main cljs.main}
2222
:closure-snapshot {:dependencies [[com.google.javascript/closure-compiler-unshaded "1.0-SNAPSHOT"]]}}

resources/self_parity_test.edn

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
{:optimizations :none
22
:main self-parity.test
3+
:language-in :es6
4+
:language-out :es6
5+
:verbose true
36
:output-to "builds/out-self-parity/main.js"
47
:output-dir "builds/out-self-parity"
58
:cache-analysis-format :edn

script/bootstrap

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ set -e
55
CLOJURE_RELEASE="1.9.0"
66
SPEC_ALPHA_RELEASE="0.1.143"
77
CORE_SPECS_ALPHA_RELEASE="0.1.24"
8-
CLOSURE_RELEASE="20200315"
8+
CLOSURE_RELEASE="20210202"
99
DJSON_RELEASE="0.2.6"
1010
TRANSIT_RELEASE="0.8.309"
11-
GCLOSURE_LIB_RELEASE="0.0-20191016-6ae1f72f"
11+
GCLOSURE_LIB_RELEASE="0.0-20201211-3e6c510d"
1212
TREADER_RELEASE="1.3.3"
1313
TEST_CHECK_RELEASE="0.10.0-alpha3"
1414

script/test-self-parity

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mkdir -p builds/out-self-parity/clojure/test
1515
mv clojure/template.clj builds/out-self-parity/clojure
1616
mv clojure/test builds/out-self-parity/clojure
1717

18-
if ! bin/cljsc src/test/self/self_parity "{:optimizations :none :output-to \"builds/out-self-parity/main.js\" :output-dir \"builds/out-self-parity\" :main self-parity.test :target :nodejs}"; then
18+
if ! bin/cljsc src/test/self/self_parity "{:optimizations :simple :language-in :es6 :language-out :es5 :output-to \"builds/out-self-parity/main.js\" :output-dir \"builds/out-self-parity\" :main self-parity.test :target :nodejs}"; then
1919
>&2 echo ClojureScript compilation failed
2020
exit 1
2121
fi;

src/main/cljs/cljs/core.cljs

+11-11
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@
273273
(defn ^boolean string?
274274
"Returns true if x is a JavaScript string."
275275
[x]
276-
(goog/isString x))
276+
(identical? "string" (goog/typeOf x)))
277277

278278
(defn char?
279279
"Returns true if x is a JavaScript string of length one."
@@ -2026,7 +2026,7 @@ reduces them without incurring seq initialization"
20262026
(defn fn?
20272027
"Return true if f is a JavaScript function or satisfies the Fn protocol."
20282028
[f]
2029-
(or ^boolean (goog/isFunction f) (satisfies? Fn f)))
2029+
(or (js-fn? f) (satisfies? Fn f)))
20302030

20312031
(deftype MetaFn [afn meta]
20322032
IMeta
@@ -2085,7 +2085,7 @@ reduces them without incurring seq initialization"
20852085
"Returns an object of the same type and value as obj, with
20862086
map m as its metadata."
20872087
[o meta]
2088-
(if ^boolean (goog/isFunction o)
2088+
(if (js-fn? o)
20892089
(MetaFn. o meta)
20902090
(when-not (nil? o)
20912091
(-with-meta o meta))))
@@ -6461,14 +6461,14 @@ reduces them without incurring seq initialization"
64616461
ILookup
64626462
(-lookup [coll k] (-lookup coll k nil))
64636463
(-lookup [coll k not-found]
6464-
(if (and ^boolean (goog/isString k)
6464+
(if (and (string? k)
64656465
(not (nil? (scan-array 1 k keys))))
64666466
(unchecked-get strobj k)
64676467
not-found))
64686468

64696469
IAssociative
64706470
(-assoc [coll k v]
6471-
(if ^boolean (goog/isString k)
6471+
(if (string? k)
64726472
(if (or (> update-count (.-HASHMAP_THRESHOLD ObjMap))
64736473
(>= (alength keys) (.-HASHMAP_THRESHOLD ObjMap)))
64746474
(obj-map->hash-map coll k v)
@@ -6484,14 +6484,14 @@ reduces them without incurring seq initialization"
64846484
;; non-string key. game over.
64856485
(obj-map->hash-map coll k v)))
64866486
(-contains-key? [coll k]
6487-
(if (and ^boolean (goog/isString k)
6487+
(if (and (string? k)
64886488
(not (nil? (scan-array 1 k keys))))
64896489
true
64906490
false))
64916491

64926492
IFind
64936493
(-find [coll k]
6494-
(when (and ^boolean (goog/isString k)
6494+
(when (and (string? k)
64956495
(not (nil? (scan-array 1 k keys))))
64966496
(MapEntry. k (unchecked-get strobj k) nil)))
64976497

@@ -6510,7 +6510,7 @@ reduces them without incurring seq initialization"
65106510

65116511
IMap
65126512
(-dissoc [coll k]
6513-
(if (and ^boolean (goog/isString k)
6513+
(if (and (string? k)
65146514
(not (nil? (scan-array 1 k keys))))
65156515
(let [new-keys (aclone keys)
65166516
new-strobj (obj-clone strobj keys)]
@@ -6624,7 +6624,7 @@ reduces them without incurring seq initialization"
66246624
(cond
66256625
(keyword? k) (array-index-of-keyword? arr k)
66266626

6627-
(or ^boolean (goog/isString k) (number? k))
6627+
(or (string? k) (number? k))
66286628
(array-index-of-identical? arr k)
66296629

66306630
(symbol? k) (array-index-of-symbol? arr k)
@@ -10264,12 +10264,12 @@ reduces them without incurring seq initialization"
1026410264
(array? obj)
1026510265
(pr-sequential-writer writer pr-writer "#js [" " " "]" opts obj)
1026610266

10267-
^boolean (goog/isString obj)
10267+
(string? obj)
1026810268
(if (:readably opts)
1026910269
(-write writer (quote-string obj))
1027010270
(-write writer obj))
1027110271

10272-
^boolean (goog/isFunction obj)
10272+
(js-fn? obj)
1027310273
(let [name (.-name obj)
1027410274
name (if (or (nil? name) (gstring/isEmpty name))
1027510275
"Function"

src/main/clojure/cljs/closure.clj

+41-24
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@
3737
CompilerInput CompilerInput$ModuleType DependencyOptions
3838
CompilerOptions$LanguageMode SourceMap$Format
3939
SourceMap$DetailLevel ClosureCodingConvention SourceFile
40-
Result JSError CheckLevel DiagnosticGroups
41-
CommandLineRunner AnonymousFunctionNamingPolicy
42-
JSModule SourceMap VariableMap PrintStreamErrorManager]
40+
Result JSError CheckLevel DiagnosticGroup DiagnosticGroups
41+
CommandLineRunner
42+
JSModule SourceMap VariableMap PrintStreamErrorManager DiagnosticType
43+
VariableRenamingPolicy PropertyRenamingPolicy]
4344
[com.google.javascript.jscomp.bundle Transpiler]
4445
[com.google.javascript.jscomp.deps ClosureBundler ModuleLoader$ResolutionMode ModuleNames
4546
SimpleDependencyInfo]
4647
[com.google.javascript.rhino Node]
4748
[java.nio.file Path Paths Files StandardWatchEventKinds WatchKey
4849
WatchEvent FileVisitor FileVisitResult FileSystems]
4950
[java.nio.charset Charset StandardCharsets]
50-
[com.sun.nio.file SensitivityWatchEventModifier]
51-
[com.google.common.base Throwables]))
51+
[com.sun.nio.file SensitivityWatchEventModifier]))
5252

5353
;; Copied from clojure.tools.gitlibs
5454

@@ -162,7 +162,6 @@
162162
:message-descriptions DiagnosticGroups/MESSAGE_DESCRIPTIONS
163163
:misplaced-msg-annotation DiagnosticGroups/MISPLACED_MSG_ANNOTATION
164164
:misplaced-type-annotation DiagnosticGroups/MISPLACED_TYPE_ANNOTATION
165-
:missing-getcssname DiagnosticGroups/MISSING_GETCSSNAME
166165
:missing-override DiagnosticGroups/MISSING_OVERRIDE
167166
:missing-polyfill DiagnosticGroups/MISSING_POLYFILL
168167
:missing-properties DiagnosticGroups/MISSING_PROPERTIES
@@ -175,7 +174,6 @@
175174
:non-standard-jsdoc DiagnosticGroups/NON_STANDARD_JSDOC
176175
:report-unknown-types DiagnosticGroups/REPORT_UNKNOWN_TYPES
177176
:strict-missing-properties DiagnosticGroups/STRICT_MISSING_PROPERTIES
178-
:strict-missing-require DiagnosticGroups/STRICT_MISSING_REQUIRE
179177
:strict-module-dep-check DiagnosticGroups/STRICT_MODULE_DEP_CHECK
180178
:strict-requires DiagnosticGroups/STRICT_REQUIRES
181179
:suspicious-code DiagnosticGroups/SUSPICIOUS_CODE
@@ -262,15 +260,6 @@
262260
(when (contains? opts :pseudo-names)
263261
(set! (.generatePseudoNames compiler-options) (:pseudo-names opts)))
264262

265-
(when (contains? opts :anon-fn-naming-policy)
266-
(let [policy (:anon-fn-naming-policy opts)]
267-
(set! (.anonymousFunctionNaming compiler-options)
268-
(case policy
269-
:off AnonymousFunctionNamingPolicy/OFF
270-
:unmapped AnonymousFunctionNamingPolicy/UNMAPPED
271-
:mapped AnonymousFunctionNamingPolicy/MAPPED
272-
(throw (util/compilation-error (IllegalArgumentException. (str "Invalid :anon-fn-naming-policy value " policy " - only :off, :unmapped, :mapped permitted"))))))))
273-
274263
(when-let [lang-key (:language-in opts :ecmascript5)]
275264
(.setLanguageIn compiler-options (lang-key->lang-mode lang-key)))
276265

@@ -816,7 +805,8 @@
816805
(if (seq requires)
817806
(let [node (or (get (@env/*compiler* :js-dependency-index) (first requires))
818807
(deps/find-classpath-lib (first requires)))
819-
new-req (remove #(contains? visited %) (:requires node))]
808+
new-req (remove #(contains? visited %)
809+
(into (:requires node) (:require-types node)))]
820810
(recur (into (rest requires) new-req)
821811
(into visited new-req)
822812
(conj deps node)))
@@ -2052,18 +2042,45 @@
20522042
(.appendTo bundler sb module source)
20532043
(.toString sb)))
20542044

2045+
(defn ^DiagnosticGroup es5-warnings []
2046+
(DiagnosticGroup.
2047+
(into-array DiagnosticType
2048+
[(DiagnosticType/error "JSC_CANNOT_CONVERT" "")])))
2049+
2050+
(defn ^CompilerOptions transpile-options []
2051+
(doto (CompilerOptions.)
2052+
(.setQuoteKeywordProperties true)
2053+
(.setSkipNonTranspilationPasses true)
2054+
(.setVariableRenaming VariableRenamingPolicy/OFF)
2055+
(.setPropertyRenaming PropertyRenamingPolicy/OFF)
2056+
(.setWrapGoogModulesForWhitespaceOnly false)
2057+
(.setPrettyPrint true)
2058+
(.setSourceMapOutputPath "/dev/null")
2059+
(.setSourceMapIncludeSourcesContent true)
2060+
(.setWarningLevel (es5-warnings) CheckLevel/OFF)))
2061+
2062+
(defn closure-transpile
2063+
"Transpile a single JavaScript file to JavaScript. Used to lower Closure
2064+
Library files written in more recent versions of the JavaScript standard."
2065+
([rsc opts]
2066+
(closure-transpile (util/path rsc) (slurp rsc) opts))
2067+
([path source opts]
2068+
(let [cc (make-closure-compiler)
2069+
cc-opts (set-options opts (transpile-options))
2070+
externs (SourceFile/fromCode "externs.js" "function Symbol() {}")
2071+
source (SourceFile/fromCode path source)
2072+
result (.compile cc externs source cc-opts)]
2073+
;; TODO: error handling
2074+
(.toSource cc))))
2075+
20552076
;; TODO: better error handling
2056-
;; TODO: actually respect the target :language-out level
2057-
;; currently just using default options for Transpiler
20582077
(defn transpile
2059-
[{:keys [language-out] :or {language-out :es3}} rsc {:keys [module lang] :as js}]
2078+
[{:keys [language-out] :or {language-out :es3} :as opts} rsc {:keys [module lang] :as js}]
20602079
(let [source (slurp rsc)
20612080
source' (if (and lang
20622081
(< (.indexOf lang-level (expand-lang-key language-out))
20632082
(.indexOf lang-level (expand-lang-key lang))))
2064-
(let [cc (Transpiler/compilerSupplier)
2065-
result (.compile cc (url->nio-path rsc) source)]
2066-
(.source result))
2083+
(closure-transpile (util/path rsc) source opts)
20672084
source)]
20682085
(str "/*TRANSPILED*/"
20692086
(cond-> source'
@@ -3286,7 +3303,7 @@
32863303
(if-let [f (opts-fn :watch-error-fn opts)]
32873304
(f e)
32883305
(binding [*out* *err*]
3289-
(println (Throwables/getStackTraceAsString e)))))))
3306+
(println e))))))
32903307
(watch-all [^Path root]
32913308
(Files/walkFileTree root
32923309
(reify

src/main/clojure/cljs/compiler.cljc

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@
210210
(nil? a) nil
211211
#?(:clj (map? a) :cljs (ana.impl/cljs-map? a)) (emit a)
212212
#?(:clj (seq? a) :cljs (ana.impl/cljs-seq? a)) (apply emits a)
213-
#?(:clj (fn? a) :cljs ^boolean (goog/isFunction a)) (a)
213+
#?(:clj (fn? a) :cljs (js-fn? a)) (a)
214214
:else (let [^String s (cond-> a (not (string? a)) .toString)]
215215
#?(:clj (when-some [^AtomicLong gen-col *source-map-data-gen-col*]
216216
(.addAndGet gen-col (.length s)))

src/main/clojure/cljs/core.cljc

+4-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
#?@(:cljs [alias coercive-not coercive-not= coercive-= coercive-boolean
4343
truth_ js-arguments js-delete js-in js-debugger exists? divide js-mod
4444
unsafe-bit-and bit-shift-right-zero-fill mask bitpos caching-hash
45-
defcurried rfn specify! js-this this-as implements? array js-obj
45+
defcurried rfn specify! js-this this-as implements? array js-obj js-fn?
4646
simple-benchmark gen-apply-to js-str es6-iterable load-file* undefined?
4747
specify copy-arguments goog-define js-comment js-inline-comment
4848
unsafe-cast require-macros use-macros gen-apply-to-simple unchecked-get unchecked-set])])
@@ -982,6 +982,9 @@
982982
(core/defmacro string? [x]
983983
(bool-expr (core/list 'js* "typeof ~{} === 'string'" x)))
984984

985+
(core/defmacro js-fn? [x]
986+
(bool-expr (core/list 'js* "typeof ~{} === 'function'" x)))
987+
985988
(core/defmacro exists?
986989
"Return true if argument exists, analogous to usage of typeof operator
987990
in JavaScript."

0 commit comments

Comments
 (0)