diff --git a/deps.edn b/deps.edn index 03fea05ea..82f1a4324 100644 --- a/deps.edn +++ b/deps.edn @@ -5,7 +5,7 @@ org.clojure/clojure {:mvn/version "1.10.0"} org.clojure/core.specs.alpha {:mvn/version "0.1.24"} org.clojure/data.json {:mvn/version "0.2.6"} - org.clojure/google-closure-library {:mvn/version "0.0-20201211-3e6c510d"} + org.clojure/google-closure-library {:mvn/version "0.0-20211011-0726fdeb"} org.clojure/spec.alpha {:mvn/version "0.1.143"} org.clojure/tools.reader {:mvn/version "1.3.3"} org.clojure/test.check {:mvn/version "0.10.0-alpha3"}} diff --git a/pom.template.xml b/pom.template.xml index 2161fff9d..77f35e8bd 100644 --- a/pom.template.xml +++ b/pom.template.xml @@ -35,7 +35,7 @@ org.clojure google-closure-library - 0.0-20201211-3e6c510d + 0.0-20210811-6da97fe1 org.clojure diff --git a/project.clj b/project.clj index 402b11d14..27d0ddd13 100644 --- a/project.clj +++ b/project.clj @@ -15,7 +15,7 @@ [org.clojure/tools.reader "1.3.3"] [org.clojure/test.check "0.10.0-alpha3" :scope "test"] [com.cognitect/transit-clj "0.8.309"] - [org.clojure/google-closure-library "0.0-20201211-3e6c510d"] + [org.clojure/google-closure-library "0.0-20210811-6da97fe1"] [com.google.javascript/closure-compiler-unshaded "v20210808"]] :profiles {:1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]} :uberjar {:aot :all :main cljs.main} diff --git a/script/bootstrap b/script/bootstrap index 8455dac4b..45e4838e0 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -8,7 +8,7 @@ CORE_SPECS_ALPHA_RELEASE="0.1.24" CLOSURE_RELEASE="20210808" DJSON_RELEASE="0.2.6" TRANSIT_RELEASE="0.8.309" -GCLOSURE_LIB_RELEASE="0.0-20201211-3e6c510d" +GCLOSURE_LIB_RELEASE="0.0-20210811-6da97fe1" TREADER_RELEASE="1.3.3" TEST_CHECK_RELEASE="0.10.0-alpha3" diff --git a/src/main/cljs/cljs/core.cljs b/src/main/cljs/cljs/core.cljs index d316c559f..aca00175d 100644 --- a/src/main/cljs/cljs/core.cljs +++ b/src/main/cljs/cljs/core.cljs @@ -2284,6 +2284,10 @@ reduces them without incurring seq initialization" (not (identical? n js/Infinity)) (== (js/parseFloat n) (js/parseInt n 10)))) +(def + ^{:doc "INTERNAL: do not use"} + LongImpl goog.math.Long) + (defn int? "Return true if x satisfies integer? or is an instance of goog.math.Integer or goog.math.Long." diff --git a/src/main/cljs/cljs/loader.cljs b/src/main/cljs/cljs/loader.cljs index 33405cd47..473d0e5b8 100644 --- a/src/main/cljs/cljs/loader.cljs +++ b/src/main/cljs/cljs/loader.cljs @@ -9,8 +9,8 @@ (ns cljs.loader (:require [goog.object :as gobj] [goog.html.legacyconversions :as legacy]) - (:import [goog.module ModuleLoader] - [goog.module ModuleManager])) + (:import [goog.module ModuleManager] + [goog.module ModuleLoader])) (def module-infos MODULE_INFOS) ;; set by compiler (def module-uris diff --git a/src/main/cljs/clojure/browser/repl.cljs b/src/main/cljs/clojure/browser/repl.cljs index 891f7a03b..2010f8c51 100644 --- a/src/main/cljs/clojure/browser/repl.cljs +++ b/src/main/cljs/clojure/browser/repl.cljs @@ -227,7 +227,10 @@ (let [ret (.require__ js/goog src)] (when (= reload "reload-all") (set! (.-cljsReloadAll_ js/goog) false)) - ret)))))) + ;; handle requires from Closure Library goog.modules + (if (js/goog.isInModuleLoader_) + (js/goog.module.getInternal_ src) + ret))))))) (defn connect "Connects to a REPL server from an HTML document. After the diff --git a/src/main/clojure/cljs/analyzer.cljc b/src/main/clojure/cljs/analyzer.cljc index c70eabc7e..12a6bab46 100644 --- a/src/main/clojure/cljs/analyzer.cljc +++ b/src/main/clojure/cljs/analyzer.cljc @@ -812,6 +812,12 @@ (or (contains? global-exports (symbol module)) (contains? global-exports (name module))))) +(defn goog-module-dep? + [module] + (let [[module _] (lib&sublib module) + module-type (get-in @env/*compiler* [:js-dependency-index (str module) :module])] + (= :goog module-type))) + (defn confirm-var-exists ([env prefix suffix] (let [warn (confirm-var-exist-warning env prefix suffix)] @@ -1010,6 +1016,12 @@ (str "node$module$" (munge (string/replace (str name) #"[.\/]" #?(:clj "\\$" :cljs "$$"))))) +(defn munge-goog-module-lib + ([name] + (str "goog$module$" (munge (string/replace (str name) #"[.\/]" #?(:clj "\\$" :cljs "$$"))))) + ([ns name] + (str (munge ns) "." (munge-goog-module-lib name)))) + (defn munge-global-export [name] (str "global$module$" (munge (string/replace (str name) #"[.\/]" #?(:clj "\\$" :cljs "$$"))))) @@ -1031,6 +1043,7 @@ (defn ns->module-type [ns] (cond + (goog-module-dep? ns) :goog-module (js-module-exists? ns) :js (node-module-dep? ns) :node (dep-has-global-exports? ns) :global)) @@ -1072,6 +1085,12 @@ :op :js-var :foreign true})) +(defmethod resolve* :goog-module + [env sym full-ns current-ns] + {:name (symbol (str current-ns) (str (munge-goog-module-lib full-ns) "." (name sym))) + :ns current-ns + :op :var}) + (defmethod resolve* :global [env sym full-ns current-ns] (let [pre (extern-pre sym current-ns)] @@ -1135,6 +1154,15 @@ :op :js-var :ns current-ns}))) +(defn resolve-import + "goog.modules are deterministically assigned to a property of the namespace, + we cannot expect the reference will be globally available, so we resolve to + namespace local reference." + [env import] + (if (goog-module-dep? import) + (symbol (munge-goog-module-lib (-> env :ns :name) import)) + import)) + ;; core.async calls `macroexpand-1` manually with an ill-formed ;; :locals map. Normally :locals maps symbols maps, but ;; core.async adds entries mapping symbols to symbols. We work @@ -1207,7 +1235,13 @@ ;; check if prefix is some existing def (if-let [resolved (resolve-var env prefix nil false)] (update resolved :name #(symbol (str % "." suffix))) - (let [idx (.lastIndexOf s ".") + ;; glib imports (i.e. (:import [goog.module ModuleLoader]) + ;; are always just dotted symbols after the recursion + (let [s (str + (cond->> s + (goog-module-dep? sym) + (resolve-import env))) + idx (.lastIndexOf (str s) ".") pre (subs s 0 idx) suf (subs s (inc idx))] {:op :var diff --git a/src/main/clojure/cljs/compiler.cljc b/src/main/clojure/cljs/compiler.cljc index 7415678f7..cc5675a32 100644 --- a/src/main/clojure/cljs/compiler.cljc +++ b/src/main/clojure/cljs/compiler.cljc @@ -1294,6 +1294,9 @@ (let [{node-libs true libs-to-load false} (group-by ana/node-module-dep? libs)] [node-libs libs-to-load]) [nil libs])) + [goog-modules libs-to-load] (let [{goog-modules true libs-to-load false} + (group-by ana/goog-module-dep? libs-to-load)] + [goog-modules libs-to-load]) global-exports-libs (filter ana/dep-has-global-exports? libs-to-load)] (when (-> libs meta :reload-all) (emitln "if(!COMPILED) " loaded-libs-temp " = " loaded-libs " || cljs.core.set([\"cljs.core\"]);") @@ -1336,11 +1339,26 @@ :else (when-not (= lib 'goog) (emitln "goog.require('" (munge lib) "');")))) + ;; Node Libraries (doseq [lib node-libs] (let [[lib' sublib] (ana/lib&sublib lib)] (emitln (munge ns-name) "." (ana/munge-node-lib lib) " = require('" lib' "')" (sublib-select sublib) ";"))) + ;; Google Closure Library Modules (i.e. goog.module(...)) + ;; these must be assigned to vars + (doseq [lib goog-modules] + (let [[lib' sublib] (ana/lib&sublib lib)] + (emitln "goog.require('" lib' "');") + ;; we emit goog.scope here to suppress a Closure error about + ;; goog.module.get when compiling - meant to discourage incorrect + ;; usage by hand written code - not applicable here + (emitln "goog.scope(function(){") + (emitln (munge ns-name) "." + (ana/munge-goog-module-lib lib) + " = goog.module.get('" lib' "')" (sublib-select sublib) ";") + (emitln "});"))) + ;; Global Exports (doseq [lib global-exports-libs] (let [{:keys [global-exports]} (get js-dependency-index (name (-> lib ana/lib&sublib first)))] (emit-global-export ns-name global-exports lib))) diff --git a/src/main/clojure/cljs/core.cljc b/src/main/clojure/cljs/core.cljc index ab3bc3bf9..63ad476e9 100644 --- a/src/main/clojure/cljs/core.cljc +++ b/src/main/clojure/cljs/core.cljc @@ -1430,9 +1430,9 @@ (core/let [psym (resolve p) pfn-prefix (subs (core/str psym) 0 (clojure.core/inc (.indexOf (core/str psym) "/")))] - (cons `(goog.object/set ~psym ~type true) + (cons `(unchecked-set ~psym ~type true) (map (core/fn [[f & meths :as form]] - `(goog.object/set ~(symbol (core/str pfn-prefix f)) + `(unchecked-set ~(symbol (core/str pfn-prefix f)) ~type ~(with-meta `(fn ~@meths) (meta form)))) sigs)))) @@ -2672,8 +2672,8 @@ (js-obj* '()) `(let [~@(apply concat (clojure.set/map-invert expr->local)) ~obj ~(js-obj* (filter-on-keys core/string? kvs))] - ~@(map (core/fn [[k v]] `(goog.object/set ~obj ~k ~v)) sym-pairs) - ~@(map (core/fn [[k v]] `(goog.object/set ~obj ~v ~(core/get kvs k))) expr->local) + ~@(map (core/fn [[k v]] `(unchecked-set ~obj ~k ~v)) sym-pairs) + ~@(map (core/fn [[k v]] `(unchecked-set ~obj ~v ~(core/get kvs k))) expr->local) ~obj)))) (core/defmacro alength [a] @@ -2888,7 +2888,7 @@ (core/list 'js* "''+~{}" s)) (core/defmacro es6-iterable [ty] - `(goog.object/set (.-prototype ~ty) cljs.core/ITER_SYMBOL + `(unchecked-set (.-prototype ~ty) cljs.core/ITER_SYMBOL (fn [] (this-as this# (cljs.core/es6-iterator this#))))) diff --git a/src/main/clojure/cljs/externs.clj b/src/main/clojure/cljs/externs.clj index 37008ad49..b7b42fa36 100644 --- a/src/main/clojure/cljs/externs.clj +++ b/src/main/clojure/cljs/externs.clj @@ -16,7 +16,6 @@ [com.google.javascript.jscomp.parsing Config$JsDocParsing] [com.google.javascript.rhino Node Token JSTypeExpression JSDocInfo$Visibility] - [java.nio.charset StandardCharsets] [java.util.logging Level])) (def ^:dynamic *ignore-var* false) @@ -26,7 +25,10 @@ ;; ------------------------------------------------------------------------------ ;; Externs Parsing -(defn annotate [props ty] +(defn annotate + "Given a sequential list of properties [foo core baz] representing segments + of the namespace, annotate the last symbol with the type information." + [props ty] (when (seq props) (conj (into [] (butlast props)) @@ -35,7 +37,8 @@ (defn get-tag [^JSTypeExpression texpr] (when-let [root (.getRoot texpr)] (if (.isString root) - (symbol (.getString root))(if-let [child (.. root getFirstChild)] + (symbol (.getString root)) + (if-let [child (.. root getFirstChild)] (if (.isString child) (symbol (.. child getString))))))) @@ -97,17 +100,26 @@ (fn [^Node node] (.getToken node))) -(defmethod parse-extern-node Token/VAR [node] +;; handle named function case (i.e. goog.modules) +;; function foo {}, the entire function is the node +(defmethod parse-extern-node Token/FUNCTION [^Node node] + (when (> (.getChildCount node) 0) + (let [ty (get-var-info node)] + (doto + (cond-> (parse-extern-node (.getFirstChild node)) + ty (-> first (annotate ty) vector)))))) + +(defmethod parse-extern-node Token/VAR [^Node node] (when (> (.getChildCount node) 0) (let [ty (get-var-info node)] (cond-> (parse-extern-node (.getFirstChild node)) ty (-> first (annotate ty) vector))))) -(defmethod parse-extern-node Token/EXPR_RESULT [node] +(defmethod parse-extern-node Token/EXPR_RESULT [^Node node] (when (> (.getChildCount node) 0) (parse-extern-node (.getFirstChild node)))) -(defmethod parse-extern-node Token/ASSIGN [node] +(defmethod parse-extern-node Token/ASSIGN [^Node node] (when (> (.getChildCount node) 0) (let [ty (get-var-info node) lhs (cond-> (first (parse-extern-node (.getFirstChild node))) @@ -120,13 +132,24 @@ lhs)) [lhs])))) -(defmethod parse-extern-node Token/NAME [node] - (let [lhs (map symbol (string/split (.getQualifiedName node) #"\."))] - (if (> (.getChildCount node) 0) - (let [externs (parse-extern-node (.getFirstChild node))] - (conj (map (fn [ext] (concat lhs ext)) externs) - lhs)) - [lhs]))) +;; JavaScript name +;; function foo {}, in this case the `foo` name node +;; {"foo": bar}, in this case the `bar` name node +(defmethod parse-extern-node Token/NAME [^Node node] + (if (= Token/STRING_KEY (-> node .getParent .getToken)) + ;; if we are inside an object literal we are done + [] + ;; also check .getString - goog.module defs won't have qualified names + (let [name (or (.getQualifiedName node) (.getString node)) + lhs (when-not (string/blank? name) + (map symbol (string/split name #"\.")))] + (if (seq lhs) + (if (> (.getChildCount node) 0) + (let [externs (parse-extern-node (.getFirstChild node))] + (conj (map (fn [ext] (concat lhs ext)) externs) + lhs)) + [lhs]) + [])))) (defmethod parse-extern-node Token/GETPROP [node] (when-not *ignore-var* @@ -135,6 +158,8 @@ (annotate props ty) props)]))) +;; JavaScript Object literal +;; { ... } (defmethod parse-extern-node Token/OBJECTLIT [node] (when (> (.getChildCount node) 0) (loop [nodes (.children node) @@ -144,8 +169,10 @@ (recur (rest nodes) (concat externs (parse-extern-node (first nodes)))))))) -(defmethod parse-extern-node Token/STRING_KEY [node] - (let [lhs (map symbol (string/split (.getString node) #"\."))] +;; Object literal string key node +;; {"foo": bar} - the key and value together +(defmethod parse-extern-node Token/STRING_KEY [^Node node] + (let [lhs [(-> node .getString symbol)]] (if (> (.getChildCount node) 0) (let [externs (parse-extern-node (.getFirstChild node))] (conj (map (fn [ext] (concat lhs ext)) externs) @@ -154,7 +181,17 @@ (defmethod parse-extern-node :default [node]) -(defn parse-externs [^SourceFile source-file] +(defn parse-externs + "Returns a sequential collection of the form: + + [[foo core first] + [foo core next] + [foo core baz last] ...] + + Where the last symbol is annotated with var info via metadata. This simple + structure captures the nested form of Closure namespaces and aids + direct indexing." + [^SourceFile source-file] (binding [*source-file* (.getName source-file)] (let [^CompilerOptions compiler-options (doto (CompilerOptions.) @@ -167,8 +204,13 @@ compiler) (.init (list source-file) '() compiler-options)) js-ast (JsAst. source-file) - ^Node root (.getAstRoot js-ast closure-compiler)] - (loop [nodes (.children root) + ^Node root (.getAstRoot js-ast closure-compiler) + nodes (.children root)] + (loop [nodes (cond-> nodes + ;; handle goog.modules which won't have top-levels + ;; need to look at internal children + (= Token/MODULE_BODY (some-> nodes first .getToken)) + (-> first .children)) externs []] (if (empty? nodes) externs @@ -215,17 +257,42 @@ (= (inc (count ns-segs)) (count var-segs)) (= ns-segs (take (count ns-segs) var-segs))))) -(defn parsed->defs [externs] - (let [ns-segs (into [] (map symbol (string/split (str *goog-ns*) #"\.")))] - (reduce - (fn [m xs] - ;; ignore definitions from other provided namespaces not under consideration - (if (ns-match? ns-segs xs) - (let [sym (last xs)] - (cond-> m - (seq xs) (assoc sym (merge (meta sym) {:ns *goog-ns* :name sym})))) - m)) - {} externs))) +(defmulti parsed->defs (fn [_ module-type] module-type)) + +(defmethod parsed->defs :goog + ([externs _] + (let [grouped (group-by #(= 'exports (first %)) externs) + exports (->> (get grouped true) + (map (comp vec rest)) + (remove empty?) + set) + exported (filter exports (get grouped false))] + (reduce + (fn [m xs] + (let [sym (last xs)] + (cond-> m + (seq xs) (assoc sym (merge (meta sym) {:ns *goog-ns* :name sym}))))) + {} exported)))) + +(defmethod parsed->defs :default + ([externs _] + (let [ns-segs (into [] (map symbol (string/split (str *goog-ns*) #"\.")))] + (reduce + (fn [m xs] + ;; ignore definitions from other provided namespaces not under consideration + (if (ns-match? ns-segs xs) + (let [sym (last xs)] + (cond-> m + (seq xs) (assoc sym (merge (meta sym) {:ns *goog-ns* :name sym})))) + m)) + {} externs)))) + +(defn resource->source-file + [resource] + (-> (SourceFile/builder) + (.withPath (.toPath (io/file (.getPath resource)))) + (.withContent (io/input-stream resource)) + (.build))) (defn analyze-goog-file ([f] @@ -237,11 +304,8 @@ (binding [*goog-ns* ns] {:name ns :defs (parsed->defs - (parse-externs - (-> (SourceFile/builder) - (.withPath (.toPath (io/file (.getPath rsrc)))) - (.withContent (io/input-stream rsrc)) - (.build))))})))) + (parse-externs (resource->source-file rsrc)) + (:module desc))})))) (comment (require '[clojure.java.io :as io] diff --git a/src/test/cljs/cljs/predicates_test.cljs b/src/test/cljs/cljs/predicates_test.cljs index 2e49406c5..acb50f4b0 100644 --- a/src/test/cljs/cljs/predicates_test.cljs +++ b/src/test/cljs/cljs/predicates_test.cljs @@ -8,7 +8,7 @@ (ns cljs.predicates-test (:require [cljs.test :as test :refer-macros [deftest is]]) - (:import [goog.math Long Integer])) + (:import [goog.math Integer])) (def pred-val-table (let [uuid (uuid "00000000-0000-0000-0000-000000000000")] @@ -41,9 +41,15 @@ (let [posint 10e10 negint -10e10 neg0 (/ ##-Inf) - natl (Long.getZero) - posl (Long.fromNumber posint) - negl (Long.fromNumber negint) + ;; NOTE: we must go through a var because in self-parity tests + ;; we cannot simply import goog.module namespaces if cljs.core + ;; depends on the type - that's because cljs.core was *separately + ;; compiled* already bundling goog.modules. In many cases this is + ;; not an issue, but it is an issue if internally we use the type + ;; to make instanceof assertions - which we do for Long + natl (.getZero LongImpl) + posl (.fromNumber LongImpl posint) + negl (.fromNumber LongImpl negint) nati Integer.ZERO posi (Integer.fromNumber posint) negi (Integer.fromNumber negint)] @@ -69,4 +75,4 @@ (let [v (first row)] (dotimes [i (count row)] (is (= ((nth preds i) v) (nth row i)) - (pr-str (list (nth preds i) v)))))))) \ No newline at end of file + (pr-str (list (nth preds i) v)))))))) diff --git a/src/test/clojure/cljs/analyzer/glib_module_test.clj b/src/test/clojure/cljs/analyzer/glib_module_test.clj new file mode 100644 index 000000000..ad4d126ea --- /dev/null +++ b/src/test/clojure/cljs/analyzer/glib_module_test.clj @@ -0,0 +1,62 @@ +(ns cljs.analyzer.glib-module-test + (:require [cljs.analyzer :as ana] + [cljs.analyzer-tests :as ana-tests] + [clojure.test :as test :refer [deftest is testing]] + [cljs.env :as env])) + +(deftest glib-module-detect-test + (testing "Basic glib module detection" + (is (= :goog (get-in @ana-tests/test-cenv [:js-dependency-index (munge "goog.module.ModuleLoader") :module]))))) + +(deftest glib-module-predicate-test + (testing "glib module detection predicate" + (env/with-compiler-env ana-tests/test-cenv + (is (ana/goog-module-dep? 'goog.module.ModuleLoader))))) + +(deftest glib-module-classification-test + (testing "glib module classification" + (env/with-compiler-env ana-tests/test-cenv + (is (= :goog-module (ana/ns->module-type 'goog.module.ModuleLoader)))))) + +(deftest glib-module-resolve-var-test + (testing "glib module var resolution" + (let [cenv (env/default-compiler-env) + ns-ast (ana-tests/analyze-forms cenv + '[(ns foo.core + (:require [goog.module.ModuleLoader :as module-loader]))]) + aenv (assoc (ana/empty-env) :ns (ana/get-namespace cenv 'foo.core))] + (is (= '{:name foo.core/goog$module$goog$module$ModuleLoader.EventType + :ns foo.core + :op :var} + (env/with-compiler-env cenv + (ana/resolve-var aenv 'module-loader/EventType))))))) + +(deftest glib-module-resolve-import-test + (testing "glib module resolve import helper test" + (let [cenv (env/default-compiler-env) + ns-ast (ana-tests/analyze-forms cenv + '[(ns foo.core + (:require [goog.module.ModuleLoader :as module-loader]))]) + aenv (assoc (ana/empty-env) :ns (ana/get-namespace cenv 'foo.core))] + (is (= 'foo.core.goog$module$goog$module$ModuleLoader + (env/with-compiler-env cenv + (ana/resolve-import aenv 'goog.module.ModuleLoader))))))) + +(deftest glib-module-resolve-import-var-test + (testing "glib module :import var resolution" + (let [cenv (env/default-compiler-env) + ns-ast (ana-tests/analyze-forms cenv + '[(ns foo.core + (:import [goog.module ModuleLoader]))]) + aenv (assoc (ana/empty-env) :ns (ana/get-namespace cenv 'foo.core))] + (is (= '{:name foo.core.goog$module$goog$module$ModuleLoader + :ns goog.module ;; a bit odd, but doesn't matter, for emission we just :name + :op :var} + (env/with-compiler-env cenv + (ana/resolve-var aenv 'ModuleLoader))))))) + +(comment + + (test/run-tests) + + ) diff --git a/src/test/clojure/cljs/compiler/glib_module_test.clj b/src/test/clojure/cljs/compiler/glib_module_test.clj new file mode 100644 index 000000000..c9813d209 --- /dev/null +++ b/src/test/clojure/cljs/compiler/glib_module_test.clj @@ -0,0 +1,21 @@ +(ns cljs.compiler.glib-module-test + (:require [cljs.compiler-tests :as comp-tests] + [cljs.env :as env] + [clojure.test :as test :refer [deftest is testing]])) + +(deftest test-glib-module-compile + (testing "glib modules compiled to Closure Compile expectations" + (let [src (env/with-compiler-env (env/default-compiler-env) + (comp-tests/compile-form-seq + '[(ns test.foo + (:import [goog.module ModuleLoader])) + (def module-loader (ModuleLoader.))]))] + (is (re-find #"goog\.require\('goog\.module\.ModuleLoader'\)" src)) + (is (re-find #"test\.foo\.goog\$module\$goog\$module\$ModuleLoader = goog\.module\.get\('goog.module.ModuleLoader'\)" src)) + (is (re-find #"test\.foo\.module_loader = \(new test\.foo\.goog\$module\$goog\$module\$ModuleLoader\(\)\)" src))))) + +(comment + + (test/run-tests) + + ) diff --git a/src/test/clojure/cljs/externs_parsing_tests.clj b/src/test/clojure/cljs/externs_parsing_tests.clj index cc6bd0136..7bcc44539 100644 --- a/src/test/clojure/cljs/externs_parsing_tests.clj +++ b/src/test/clojure/cljs/externs_parsing_tests.clj @@ -36,6 +36,11 @@ (comment + (externs/parse-externs + (externs/resource->source-file (io/resource "goog/object/object.js"))) + + (externs/analyze-goog-file "goog/object/object.js") + (test/run-tests) (externs/analyze-goog-file "goog/date/date.js" 'goog.date.month)