clojurific 0.12.1 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/cljf/launcher.js +15 -8
- package/package.json +2 -2
- package/compiler/deps.edn +0 -9
- package/compiler/src/main/cljs/cljs/analyzer/passes/and_or.cljc +0 -118
- package/compiler/src/main/cljs/cljs/analyzer/passes/lite.cljc +0 -32
- package/compiler/src/main/cljs/cljs/analyzer/passes.cljc +0 -32
- package/compiler/src/main/cljs/cljs/bootstrap_nodejs.js +0 -154
- package/compiler/src/main/cljs/cljs/core/specs/alpha.cljc +0 -272
- package/compiler/src/main/cljs/cljs/core/specs/alpha.cljs +0 -10
- package/compiler/src/main/cljs/cljs/core.cljs +0 -13194
- package/compiler/src/main/cljs/cljs/esm/goog/array.js +0 -61
- package/compiler/src/main/cljs/cljs/esm/goog/math.js +0 -1846
- package/compiler/src/main/cljs/cljs/esm/goog/object.js +0 -80
- package/compiler/src/main/cljs/cljs/esm/goog/string.js +0 -192
- package/compiler/src/main/cljs/cljs/esm/goog/userAgent/product.js +0 -10
- package/compiler/src/main/cljs/cljs/esm/goog.js +0 -90
- package/compiler/src/main/cljs/cljs/esm/karma.cljs +0 -103
- package/compiler/src/main/cljs/cljs/esm/lazy.clj +0 -51
- package/compiler/src/main/cljs/cljs/esm/lazy.cljs +0 -49
- package/compiler/src/main/cljs/cljs/esm/node_test.cljs +0 -21
- package/compiler/src/main/cljs/cljs/esm/repl_runtime.cljs +0 -353
- package/compiler/src/main/cljs/cljs/externs.js +0 -27
- package/compiler/src/main/cljs/cljs/imul.js +0 -11
- package/compiler/src/main/cljs/cljs/js.clj +0 -24
- package/compiler/src/main/cljs/cljs/js.cljs +0 -1432
- package/compiler/src/main/cljs/cljs/loader.cljs +0 -107
- package/compiler/src/main/cljs/cljs/main.clj +0 -67
- package/compiler/src/main/cljs/cljs/math.cljs +0 -869
- package/compiler/src/main/cljs/cljs/module_deps.js +0 -250
- package/compiler/src/main/cljs/cljs/nodejs.cljs +0 -27
- package/compiler/src/main/cljs/cljs/nodejs_externs.js +0 -3
- package/compiler/src/main/cljs/cljs/nodejscli.cljs +0 -22
- package/compiler/src/main/cljs/cljs/pprint.cljc +0 -167
- package/compiler/src/main/cljs/cljs/pprint.cljs +0 -3325
- package/compiler/src/main/cljs/cljs/proxy/impl.cljs +0 -32
- package/compiler/src/main/cljs/cljs/proxy.cljs +0 -184
- package/compiler/src/main/cljs/cljs/reader.clj +0 -18
- package/compiler/src/main/cljs/cljs/reader.cljs +0 -214
- package/compiler/src/main/cljs/cljs/repl.cljs +0 -206
- package/compiler/src/main/cljs/cljs/source_map/base64.cljs +0 -25
- package/compiler/src/main/cljs/cljs/source_map/base64_vlq.cljs +0 -102
- package/compiler/src/main/cljs/cljs/source_map.cljs +0 -305
- package/compiler/src/main/cljs/cljs/spec/alpha.cljc +0 -564
- package/compiler/src/main/cljs/cljs/spec/alpha.cljs +0 -1510
- package/compiler/src/main/cljs/cljs/spec/gen/alpha.cljc +0 -68
- package/compiler/src/main/cljs/cljs/spec/gen/alpha.cljs +0 -183
- package/compiler/src/main/cljs/cljs/spec/test/alpha.cljc +0 -329
- package/compiler/src/main/cljs/cljs/spec/test/alpha.cljs +0 -380
- package/compiler/src/main/cljs/cljs/stacktrace.cljc +0 -578
- package/compiler/src/main/cljs/cljs/test.cljc +0 -458
- package/compiler/src/main/cljs/cljs/test.cljs +0 -606
- package/compiler/src/main/cljs/clojure/browser/dom.cljs +0 -152
- package/compiler/src/main/cljs/clojure/browser/event.cljs +0 -101
- package/compiler/src/main/cljs/clojure/browser/net.cljs +0 -181
- package/compiler/src/main/cljs/clojure/browser/repl/preload.cljs +0 -13
- package/compiler/src/main/cljs/clojure/browser/repl.cljs +0 -283
- package/compiler/src/main/cljs/clojure/core/protocols.cljs +0 -29
- package/compiler/src/main/cljs/clojure/core/reducers.cljs +0 -312
- package/compiler/src/main/cljs/clojure/data.cljs +0 -162
- package/compiler/src/main/cljs/clojure/datafy.cljs +0 -63
- package/compiler/src/main/cljs/clojure/edn.cljs +0 -55
- package/compiler/src/main/cljs/clojure/reflect.cljs +0 -57
- package/compiler/src/main/cljs/clojure/set.cljs +0 -165
- package/compiler/src/main/cljs/clojure/string.cljs +0 -290
- package/compiler/src/main/cljs/clojure/walk.cljs +0 -98
- package/compiler/src/main/cljs/clojure/zip.cljs +0 -291
- package/compiler/src/main/cljs/process/env.cljs +0 -12
- package/compiler/src/main/cljs/shadow/resource.clj +0 -60
- package/compiler/src/main/cljs/shadow/resource.cljs +0 -10
- package/compiler/src/main/clojure/cljs/analyzer/api.cljc +0 -299
- package/compiler/src/main/clojure/cljs/analyzer/impl/namespaces.cljc +0 -68
- package/compiler/src/main/clojure/cljs/analyzer/impl.cljc +0 -59
- package/compiler/src/main/clojure/cljs/analyzer/macros.clj +0 -57
- package/compiler/src/main/clojure/cljs/analyzer/utils.clj +0 -36
- package/compiler/src/main/clojure/cljs/analyzer.cljc +0 -5292
- package/compiler/src/main/clojure/cljs/build/api.clj +0 -309
- package/compiler/src/main/clojure/cljs/cli.clj +0 -812
- package/compiler/src/main/clojure/cljs/closure.clj +0 -3440
- package/compiler/src/main/clojure/cljs/compiler/api.clj +0 -101
- package/compiler/src/main/clojure/cljs/compiler/macros.clj +0 -16
- package/compiler/src/main/clojure/cljs/compiler.cljc +0 -2748
- package/compiler/src/main/clojure/cljs/core/macros.clj +0 -43
- package/compiler/src/main/clojure/cljs/core/server.clj +0 -167
- package/compiler/src/main/clojure/cljs/core.cljc +0 -3719
- package/compiler/src/main/clojure/cljs/env/macros.clj +0 -37
- package/compiler/src/main/clojure/cljs/env.cljc +0 -102
- package/compiler/src/main/clojure/cljs/esm/repl/nrepl.clj +0 -151
- package/compiler/src/main/clojure/cljs/esm/repl.clj +0 -878
- package/compiler/src/main/clojure/cljs/esm.clj +0 -987
- package/compiler/src/main/clojure/cljs/externs/default.edn +0 -1549
- package/compiler/src/main/clojure/cljs/externs.clj +0 -479
- package/compiler/src/main/clojure/cljs/foreign/node.clj +0 -207
- package/compiler/src/main/clojure/cljs/instant.clj +0 -54
- package/compiler/src/main/clojure/cljs/js_deps.cljc +0 -412
- package/compiler/src/main/clojure/cljs/module_graph.cljc +0 -402
- package/compiler/src/main/clojure/cljs/repl/bootstrap.clj +0 -53
- package/compiler/src/main/clojure/cljs/repl/browser.clj +0 -540
- package/compiler/src/main/clojure/cljs/repl/node.clj +0 -253
- package/compiler/src/main/clojure/cljs/repl/node_repl.js +0 -114
- package/compiler/src/main/clojure/cljs/repl/reflect.clj +0 -85
- package/compiler/src/main/clojure/cljs/repl/server.clj +0 -236
- package/compiler/src/main/clojure/cljs/repl.cljc +0 -1615
- package/compiler/src/main/clojure/cljs/server/browser.clj +0 -54
- package/compiler/src/main/clojure/cljs/server/node.clj +0 -54
- package/compiler/src/main/clojure/cljs/source_map/base64.clj +0 -28
- package/compiler/src/main/clojure/cljs/source_map/base64_vlq.clj +0 -104
- package/compiler/src/main/clojure/cljs/source_map.clj +0 -369
- package/compiler/src/main/clojure/cljs/support.cljc +0 -18
- package/compiler/src/main/clojure/cljs/tagged_literals.cljc +0 -93
- package/compiler/src/main/clojure/cljs/util.cljc +0 -420
- package/compiler/src/main/clojure/cljs/vendor/bridge.clj +0 -42
- package/compiler/src/main/clojure/cljs/vendor/clojure/data/json.clj +0 -809
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader/default_data_readers.clj +0 -303
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader/edn.clj +0 -440
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader/impl/commons.clj +0 -131
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader/impl/errors.clj +0 -214
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader/impl/inspect.clj +0 -91
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader/impl/utils.clj +0 -127
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader/reader_types.clj +0 -431
- package/compiler/src/main/clojure/cljs/vendor/clojure/tools/reader.clj +0 -1035
- package/compiler/src/main/clojure/cljs/vendor/cognitect/transit.clj +0 -479
- /package/{compiler/no-clojurescript → no-clojurescript}/deps.edn +0 -0
|
@@ -1,2748 +0,0 @@
|
|
|
1
|
-
; Copyright (c) Rich Hickey. All rights reserved.
|
|
2
|
-
; The use and distribution terms for this software are covered by the
|
|
3
|
-
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
|
4
|
-
; which can be found in the file epl-v10.html at the root of this distribution.
|
|
5
|
-
; By using this software in any fashion, you are agreeing to be bound by
|
|
6
|
-
; the terms of this license.
|
|
7
|
-
; You must not remove this notice, or any other, from this software.
|
|
8
|
-
|
|
9
|
-
(ns cljs.compiler
|
|
10
|
-
#?(:clj (:refer-clojure :exclude [ensure macroexpand-1 munge])
|
|
11
|
-
:cljs (:refer-clojure :exclude [ensure js-reserved macroexpand-1 munge]))
|
|
12
|
-
#?(:cljs (:require-macros [cljs.compiler.macros :refer [emit-wrap]]
|
|
13
|
-
[cljs.env.macros :refer [ensure]]))
|
|
14
|
-
#?(:clj (:require [cljs.analyzer :as ana]
|
|
15
|
-
[cljs.env :as env :refer [ensure]]
|
|
16
|
-
[cljs.js-deps :as deps]
|
|
17
|
-
[cljs.source-map :as sm]
|
|
18
|
-
[cljs.tagged-literals :as tags]
|
|
19
|
-
[cljs.util :as util]
|
|
20
|
-
[cljs.vendor.clojure.data.json :as json]
|
|
21
|
-
[clojure.java.io :as io]
|
|
22
|
-
[clojure.set :as set]
|
|
23
|
-
[clojure.string :as string]
|
|
24
|
-
[cljs.vendor.clojure.tools.reader :as reader])
|
|
25
|
-
:cljs (:require [cljs.analyzer :as ana]
|
|
26
|
-
[cljs.analyzer.impl :as ana.impl]
|
|
27
|
-
[cljs.env :as env]
|
|
28
|
-
[cljs.source-map :as sm]
|
|
29
|
-
[cljs.tools.reader :as reader]
|
|
30
|
-
[clojure.set :as set]
|
|
31
|
-
[clojure.string :as string]
|
|
32
|
-
[goog.string :as gstring]))
|
|
33
|
-
#?(:clj (:import [cljs.tagged_literals JSValue]
|
|
34
|
-
java.lang.StringBuilder
|
|
35
|
-
[java.io File Writer]
|
|
36
|
-
[java.time Instant]
|
|
37
|
-
[java.util.concurrent Executors ExecutorService TimeUnit]
|
|
38
|
-
[java.util.concurrent.atomic AtomicLong])
|
|
39
|
-
:cljs (:import [goog.string StringBuffer])))
|
|
40
|
-
|
|
41
|
-
#?(:clj (set! *warn-on-reflection* true))
|
|
42
|
-
|
|
43
|
-
(def js-reserved ana/js-reserved)
|
|
44
|
-
|
|
45
|
-
(def ^:private es5>=
|
|
46
|
-
(into #{}
|
|
47
|
-
(comp
|
|
48
|
-
(mapcat (fn [lang]
|
|
49
|
-
[lang (keyword (string/replace (name lang) #"^ecmascript" "es"))])))
|
|
50
|
-
[:ecmascript5 :ecmascript5-strict :ecmascript6 :ecmascript6-strict
|
|
51
|
-
:ecmascript-2015 :ecmascript6-typed :ecmascript-2016 :ecmascript-2017
|
|
52
|
-
:ecmascript-2018 :ecmascript-2019 :ecmascript-2020 :ecmascript-2021
|
|
53
|
-
:ecmascript-next]))
|
|
54
|
-
|
|
55
|
-
(def ^:dynamic *recompiled* nil)
|
|
56
|
-
(def ^:dynamic *inputs* nil)
|
|
57
|
-
(def ^:dynamic *source-map-data* nil)
|
|
58
|
-
(def ^:dynamic *source-map-data-gen-col* nil)
|
|
59
|
-
(def ^:dynamic *lexical-renames* {})
|
|
60
|
-
|
|
61
|
-
;; ES module output (:module-format :esm)
|
|
62
|
-
;;
|
|
63
|
-
;; Every namespace becomes an ES module. Vars of the namespace being compiled
|
|
64
|
-
;; are module-local bindings named my$ns$var, exported as var. Vars of other
|
|
65
|
-
;; namespaces are referenced through namespace imports, i.e. my$ns.var, which
|
|
66
|
-
;; bundlers can statically resolve, tree-shake and rename.
|
|
67
|
-
|
|
68
|
-
(def ^:dynamic *esm*
|
|
69
|
-
"Per-file ESM emission state, a map of atoms. Bound by emit-source when
|
|
70
|
-
compiling with :module-format :esm."
|
|
71
|
-
nil)
|
|
72
|
-
|
|
73
|
-
(def ^:dynamic *esm-emitting*
|
|
74
|
-
"True while emitting (not analyzing) an ESM file. Var munging only switches
|
|
75
|
-
to ESM names during emission, analysis time munging is unaffected."
|
|
76
|
-
false)
|
|
77
|
-
|
|
78
|
-
(def ^:dynamic *esm-in-fn*
|
|
79
|
-
"True while emitting code nested in a JS function, where a top-level var
|
|
80
|
-
declaration can't be emitted."
|
|
81
|
-
false)
|
|
82
|
-
|
|
83
|
-
(def ^:dynamic *esm-repl*
|
|
84
|
-
"True while emitting a form evaluated at the REPL (cljs.esm.repl), the body
|
|
85
|
-
of a function the REPL runtime calls with the namespaces it references.
|
|
86
|
-
The namespace being compiled is one of them: its vars are module bindings
|
|
87
|
-
of a module already running, reached through the runtime's view of the
|
|
88
|
-
namespace, my$ns.var, and def assigns the view."
|
|
89
|
-
false)
|
|
90
|
-
|
|
91
|
-
(def esm-repl-runtime
|
|
92
|
-
"The namespace evaluating REPL forms in a running build, imported first by
|
|
93
|
-
the main namespaces under :esm-repl."
|
|
94
|
-
'cljs.esm.repl-runtime)
|
|
95
|
-
|
|
96
|
-
(defn esm-mode?
|
|
97
|
-
"Whether compiling to ES modules, :module-format :esm."
|
|
98
|
-
([] (esm-mode? (when env/*compiler* (:options @env/*compiler*))))
|
|
99
|
-
([opts] (= :esm (:module-format opts))))
|
|
100
|
-
|
|
101
|
-
(def cljs-reserved-file-names #{"deps.cljs"})
|
|
102
|
-
|
|
103
|
-
(defn get-first-ns-segment
|
|
104
|
-
"Gets the part up to the first `.` of a namespace.
|
|
105
|
-
Returns the empty string for nil.
|
|
106
|
-
Returns the entire string if no `.` in namespace"
|
|
107
|
-
[ns]
|
|
108
|
-
(let [ns (str ns)
|
|
109
|
-
idx (.indexOf ns ".")]
|
|
110
|
-
(if (== -1 idx)
|
|
111
|
-
ns
|
|
112
|
-
(subs ns 0 idx))))
|
|
113
|
-
|
|
114
|
-
(defn ^:dynamic find-ns-starts-with [needle]
|
|
115
|
-
(reduce-kv
|
|
116
|
-
(fn [xs ns _]
|
|
117
|
-
(when (= needle (get-first-ns-segment ns))
|
|
118
|
-
(reduced needle)))
|
|
119
|
-
nil
|
|
120
|
-
(::ana/namespaces @env/*compiler*)))
|
|
121
|
-
|
|
122
|
-
; Helper fn
|
|
123
|
-
(defn shadow-depth [s]
|
|
124
|
-
(let [{:keys [name info]} s]
|
|
125
|
-
(loop [d 0, {:keys [shadow]} info]
|
|
126
|
-
(cond
|
|
127
|
-
shadow (recur (inc d) shadow)
|
|
128
|
-
(find-ns-starts-with (str name)) (inc d)
|
|
129
|
-
:else d))))
|
|
130
|
-
|
|
131
|
-
(defn hash-scope [s]
|
|
132
|
-
(hash-combine #?(:clj (hash (:name s))
|
|
133
|
-
:cljs (-hash ^not-native (:name s)))
|
|
134
|
-
(shadow-depth s)))
|
|
135
|
-
|
|
136
|
-
(declare munge emits)
|
|
137
|
-
|
|
138
|
-
(defn esm-ns-alias
|
|
139
|
-
"Returns the identifier a namespace is imported as, i.e. my$ns."
|
|
140
|
-
[ns]
|
|
141
|
-
(if (= "goog" (str ns))
|
|
142
|
-
;; not goog, the Closure Library compatibility layer defines a global goog
|
|
143
|
-
"goog$"
|
|
144
|
-
(string/join "$" (map #(str (munge % #{})) (string/split (str ns) #"\.")))))
|
|
145
|
-
|
|
146
|
-
(defn esm-module-ns?
|
|
147
|
-
"Whether references into namespace ns (a string) should go through an ES
|
|
148
|
-
module import. Everything else, i.e. Math or unknown namespaces, keeps
|
|
149
|
-
being referenced as a global."
|
|
150
|
-
[ns]
|
|
151
|
-
(let [cenv @env/*compiler*]
|
|
152
|
-
(or (= ns (str ana/*cljs-ns*))
|
|
153
|
-
(= "goog" ns)
|
|
154
|
-
;; Closure Library namespaces, i.e. goog.string but not goog.DEBUG
|
|
155
|
-
(and (string/starts-with? ns "goog.")
|
|
156
|
-
(contains? (:js-dependency-index cenv) ns))
|
|
157
|
-
(contains? (::ana/namespaces cenv) (symbol ns))
|
|
158
|
-
;; namespaces of the build not analyzed yet, i.e. under :parallel-build
|
|
159
|
-
(contains? (:cljs.esm/namespaces cenv) (symbol ns)))))
|
|
160
|
-
|
|
161
|
-
(defn esm-var-name
|
|
162
|
-
"Munges the name of a var for ESM output, reserved words are munged like
|
|
163
|
-
they are for global namespace paths so that munging is idempotent."
|
|
164
|
-
[nm]
|
|
165
|
-
(str (munge nm js-reserved)))
|
|
166
|
-
|
|
167
|
-
(declare esm-goog-shim-exports)
|
|
168
|
-
|
|
169
|
-
(defn- munge-esm-var
|
|
170
|
-
([ns nm] (munge-esm-var ns nm js-reserved))
|
|
171
|
-
([ns nm reserved]
|
|
172
|
-
(let [local? (and (not *esm-repl*) (= ns (str ana/*cljs-ns*)))
|
|
173
|
-
idx (.indexOf ^String nm ".")
|
|
174
|
-
member (esm-var-name (if (neg? idx) nm (subs nm 0 idx)))
|
|
175
|
-
;; nm may be a property path, i.e. Foo.prototype.bar, reserved
|
|
176
|
-
;; words are valid property names, i.e. an npm module's default
|
|
177
|
-
nm' (if (neg? idx)
|
|
178
|
-
member
|
|
179
|
-
(str member "." (munge (subs nm (inc idx)) #{})))
|
|
180
|
-
;; Closure Library members are taken from ES module shims if they
|
|
181
|
-
;; provide them, otherwise from the Closure Library itself run by
|
|
182
|
-
;; the compatibility layer, see cljs.esm/install-goog-libs
|
|
183
|
-
lib? (and (or (= "goog" ns) (string/starts-with? ns "goog."))
|
|
184
|
-
(not (contains? #?(:clj (esm-goog-shim-exports ns ana/*cljs-ns*) :cljs #{}) member)))]
|
|
185
|
-
(cond
|
|
186
|
-
local? nil
|
|
187
|
-
lib? (swap! (:goog-lib-refs *esm*) conj ns)
|
|
188
|
-
:else (swap! (:refs *esm*) conj ns))
|
|
189
|
-
(str (esm-ns-alias ns) (when lib? "$") (if local? "$" ".") nm'))))
|
|
190
|
-
|
|
191
|
-
(defn- esm-split-dotted
|
|
192
|
-
"Fully qualified dotted references like cljs.core.PersistentVector.EMPTY
|
|
193
|
-
resolve to namespace cljs.core.PersistentVector, returns the longest
|
|
194
|
-
namespace prefix and the rest, if any."
|
|
195
|
-
[ns nm]
|
|
196
|
-
(let [segs (string/split ns #"\.")]
|
|
197
|
-
(loop [n (dec (count segs))]
|
|
198
|
-
(when (pos? n)
|
|
199
|
-
(let [prefix (string/join "." (take n segs))]
|
|
200
|
-
(if (esm-module-ns? prefix)
|
|
201
|
-
[prefix (string/join "." (concat (drop n segs) [nm]))]
|
|
202
|
-
(recur (dec n))))))))
|
|
203
|
-
|
|
204
|
-
(defn- esm-var-ref
|
|
205
|
-
"While emitting ES modules, returns [ns name] if symbol s references a var
|
|
206
|
-
of a namespace compiled to an ES module."
|
|
207
|
-
[s]
|
|
208
|
-
(when (and *esm-emitting* (symbol? s) (some? (namespace s)))
|
|
209
|
-
(if (esm-module-ns? (namespace s))
|
|
210
|
-
[(namespace s) (name s)]
|
|
211
|
-
(esm-split-dotted (namespace s) (name s)))))
|
|
212
|
-
|
|
213
|
-
(defn fn-self-name [{:keys [name info] :as name-var}]
|
|
214
|
-
(let [name (string/replace (str name) ".." "_DOT__DOT_")
|
|
215
|
-
{:keys [ns fn-scope]} info
|
|
216
|
-
scoped-name (apply str
|
|
217
|
-
(interpose "_$_"
|
|
218
|
-
(concat (map (comp str :name) fn-scope) [name])))]
|
|
219
|
-
(symbol
|
|
220
|
-
(munge
|
|
221
|
-
(str (string/replace (str ns) "." "$") "$" scoped-name)))))
|
|
222
|
-
|
|
223
|
-
(defn munge-reserved [reserved]
|
|
224
|
-
(fn [s]
|
|
225
|
-
(if-not (nil? (get reserved s))
|
|
226
|
-
(str s "$")
|
|
227
|
-
s)))
|
|
228
|
-
|
|
229
|
-
(defn munge
|
|
230
|
-
([s] (munge s js-reserved))
|
|
231
|
-
([s reserved]
|
|
232
|
-
(cond
|
|
233
|
-
#?(:clj (map? s)
|
|
234
|
-
:cljs (ana.impl/cljs-map? s))
|
|
235
|
-
(let [name-var s
|
|
236
|
-
name (:name name-var)
|
|
237
|
-
field (:field name-var)
|
|
238
|
-
info (:info name-var)]
|
|
239
|
-
(if-not (nil? (:fn-self-name info))
|
|
240
|
-
(fn-self-name s)
|
|
241
|
-
;; Unshadowing
|
|
242
|
-
(let [depth (shadow-depth s)
|
|
243
|
-
code (hash-scope s)
|
|
244
|
-
renamed (get *lexical-renames* code)
|
|
245
|
-
name (cond
|
|
246
|
-
(true? field) (str "self__." name)
|
|
247
|
-
(not (nil? renamed)) renamed
|
|
248
|
-
:else name)
|
|
249
|
-
munged-name (munge name reserved)]
|
|
250
|
-
(if (or (true? field) (zero? depth))
|
|
251
|
-
munged-name
|
|
252
|
-
(symbol (str munged-name "__$" depth))))))
|
|
253
|
-
;; vars of namespaces compiled to ES modules
|
|
254
|
-
(some? (esm-var-ref s))
|
|
255
|
-
(let [[ns nm] (esm-var-ref s)]
|
|
256
|
-
(symbol (munge-esm-var ns nm reserved)))
|
|
257
|
-
|
|
258
|
-
;; String munging
|
|
259
|
-
:else
|
|
260
|
-
(let [ss (string/replace (str s) ".." "_DOT__DOT_")
|
|
261
|
-
ss (string/replace ss
|
|
262
|
-
#?(:clj #"\/(.)" :cljs (js/RegExp. "\\/(.)")) ".$1") ; Division is special
|
|
263
|
-
rf (munge-reserved reserved)
|
|
264
|
-
ss (map rf (string/split ss #"\."))
|
|
265
|
-
ss (string/join "." ss)
|
|
266
|
-
ms #?(:clj (clojure.lang.Compiler/munge ss)
|
|
267
|
-
:cljs (munge-str ss))]
|
|
268
|
-
(if (symbol? s)
|
|
269
|
-
(symbol ms)
|
|
270
|
-
ms)))))
|
|
271
|
-
|
|
272
|
-
(defn esm-rewrite-core-refs
|
|
273
|
-
"Under ESM, rewrite cljs.core.foo references in emitted JS strings to
|
|
274
|
-
ESM references."
|
|
275
|
-
[s]
|
|
276
|
-
(if (and *esm-emitting* (string/includes? s "cljs.core."))
|
|
277
|
-
(string/replace s #"(?<![\w$.])cljs\.core\.([A-Za-z_$][\w$]*)"
|
|
278
|
-
(fn [[_ n]]
|
|
279
|
-
(munge-esm-var "cljs.core" n)))
|
|
280
|
-
s))
|
|
281
|
-
|
|
282
|
-
(defn- cc
|
|
283
|
-
"Emitted JS that references cljs.core vars as cljs.core.foo goes through
|
|
284
|
-
here to support ESM output."
|
|
285
|
-
[s]
|
|
286
|
-
(esm-rewrite-core-refs s))
|
|
287
|
-
|
|
288
|
-
(defn- esm-js-ns-ref
|
|
289
|
-
"Under ESM, returns the reference a js/my.ns or js/my.ns.foo global
|
|
290
|
-
reference of a namespace of the build is emitted as."
|
|
291
|
-
[js-name]
|
|
292
|
-
(when (string/includes? js-name ".")
|
|
293
|
-
(let [segs (string/split js-name #"\.")]
|
|
294
|
-
(loop [n (count segs)]
|
|
295
|
-
(when (pos? n)
|
|
296
|
-
(let [ns (string/join "." (take n segs))]
|
|
297
|
-
(if (esm-module-ns? ns)
|
|
298
|
-
(do (if (and (= ns (str ana/*cljs-ns*)) (not *esm-repl*))
|
|
299
|
-
;; the module's own namespace object
|
|
300
|
-
(reset! (:self-import *esm*) true)
|
|
301
|
-
(swap! (:refs *esm*) conj ns))
|
|
302
|
-
(string/join "." (cons (esm-ns-alias ns) (drop n segs))))
|
|
303
|
-
(recur (dec n)))))))))
|
|
304
|
-
|
|
305
|
-
(defn- esm-def!
|
|
306
|
-
"Records a var defined by the namespace being compiled as an export of the
|
|
307
|
-
ES module. Returns the module-local name of the var."
|
|
308
|
-
[sym]
|
|
309
|
-
(let [local (str (munge sym))
|
|
310
|
-
export (esm-var-name (name sym))]
|
|
311
|
-
(swap! (:exports *esm*) assoc export local)
|
|
312
|
-
(swap! (:export-syms *esm*) assoc export sym)
|
|
313
|
-
(when (get-in @env/*compiler*
|
|
314
|
-
[::ana/namespaces (symbol (namespace sym)) :defs (symbol (name sym)) :dynamic])
|
|
315
|
-
(swap! (:dynamic *esm*) conj export))
|
|
316
|
-
local))
|
|
317
|
-
|
|
318
|
-
(defn- emit-esm-type-binding
|
|
319
|
-
"Emits the binding a deftype / defrecord constructor is assigned to."
|
|
320
|
-
[t]
|
|
321
|
-
(if (and *esm-emitting* (not *esm-repl*))
|
|
322
|
-
(let [local (esm-def! t)]
|
|
323
|
-
(if *esm-in-fn*
|
|
324
|
-
(do (swap! (:hoist *esm*) conj local)
|
|
325
|
-
(emits local))
|
|
326
|
-
(emits "var " local)))
|
|
327
|
-
(emits (munge t))))
|
|
328
|
-
|
|
329
|
-
(defn- comma-sep [xs]
|
|
330
|
-
(interpose "," xs))
|
|
331
|
-
|
|
332
|
-
(defn- escape-char [^Character c]
|
|
333
|
-
(let [cp #?(:clj (.hashCode c)
|
|
334
|
-
:cljs (gstring/hashCode c))]
|
|
335
|
-
(case cp
|
|
336
|
-
; Handle printable escapes before ASCII
|
|
337
|
-
34 "\\\""
|
|
338
|
-
92 "\\\\"
|
|
339
|
-
; Handle non-printable escapes
|
|
340
|
-
8 "\\b"
|
|
341
|
-
12 "\\f"
|
|
342
|
-
10 "\\n"
|
|
343
|
-
13 "\\r"
|
|
344
|
-
9 "\\t"
|
|
345
|
-
(if (< 31 cp 127)
|
|
346
|
-
c ; Print simple ASCII characters
|
|
347
|
-
#?(:clj (format "\\u%04X" cp) ; Any other character is Unicode
|
|
348
|
-
:cljs (let [unpadded (.toString cp 16)
|
|
349
|
-
pad (subs "0000" (.-length unpadded))]
|
|
350
|
-
(str "\\u" pad unpadded)))))))
|
|
351
|
-
|
|
352
|
-
(defn- escape-string [^CharSequence s]
|
|
353
|
-
(let [sb #?(:clj (StringBuilder. (count s))
|
|
354
|
-
:cljs (StringBuffer.))]
|
|
355
|
-
(doseq [c s]
|
|
356
|
-
(.append sb (escape-char c)))
|
|
357
|
-
(.toString sb)))
|
|
358
|
-
|
|
359
|
-
(defn- wrap-in-double-quotes [x]
|
|
360
|
-
(str \" x \"))
|
|
361
|
-
|
|
362
|
-
(defmulti emit* :op)
|
|
363
|
-
|
|
364
|
-
(defn emit [ast]
|
|
365
|
-
(when *source-map-data*
|
|
366
|
-
(let [{:keys [env]} ast]
|
|
367
|
-
(when (:line env)
|
|
368
|
-
(let [{:keys [line column]} env]
|
|
369
|
-
(swap! *source-map-data*
|
|
370
|
-
(fn [m]
|
|
371
|
-
(let [minfo (cond-> {:gcol #?(:clj (.get ^AtomicLong *source-map-data-gen-col*)
|
|
372
|
-
:cljs (:gen-col m))
|
|
373
|
-
:gline (:gen-line m)}
|
|
374
|
-
(#{:var :local :js-var :binding} (:op ast))
|
|
375
|
-
(assoc :name (str (-> ast :info :name))))]
|
|
376
|
-
; Dec the line/column numbers for 0-indexing.
|
|
377
|
-
; tools.reader uses 1-indexed sources, chrome
|
|
378
|
-
; expects 0-indexed source maps.
|
|
379
|
-
(update-in m [:source-map (dec line)]
|
|
380
|
-
(fnil (fn [line]
|
|
381
|
-
(update-in line [(if column (dec column) 0)]
|
|
382
|
-
(fnil (fn [column] (conj column minfo)) [])))
|
|
383
|
-
(sorted-map))))))))))
|
|
384
|
-
(if (and *esm-emitting*
|
|
385
|
-
(not *esm-in-fn*)
|
|
386
|
-
(or (= :fn (:op ast))
|
|
387
|
-
;; these emit an IIFE in expression context
|
|
388
|
-
(and (= :expr (-> ast :env :context))
|
|
389
|
-
(contains? #{:case :throw :do :try :let :loop :letfn} (:op ast)))))
|
|
390
|
-
(binding [*esm-in-fn* true]
|
|
391
|
-
(emit* ast))
|
|
392
|
-
(emit* ast)))
|
|
393
|
-
|
|
394
|
-
(defn emits
|
|
395
|
-
([])
|
|
396
|
-
([^Object a]
|
|
397
|
-
(cond
|
|
398
|
-
(nil? a) nil
|
|
399
|
-
#?(:clj (map? a) :cljs (ana.impl/cljs-map? a)) (emit a)
|
|
400
|
-
#?(:clj (seq? a) :cljs (ana.impl/cljs-seq? a)) (apply emits a)
|
|
401
|
-
#?(:clj (fn? a) :cljs (js-fn? a)) (a)
|
|
402
|
-
:else (let [^String s (cond-> a (not (string? a)) .toString)]
|
|
403
|
-
#?(:clj (when-some [^AtomicLong gen-col *source-map-data-gen-col*]
|
|
404
|
-
(.addAndGet gen-col (.length s)))
|
|
405
|
-
:cljs (when-some [sm-data *source-map-data*]
|
|
406
|
-
(swap! sm-data update :gen-col #(+ % (.-length s)))))
|
|
407
|
-
#?(:clj (.write ^Writer *out* s)
|
|
408
|
-
:cljs (print s))))
|
|
409
|
-
nil)
|
|
410
|
-
([a b]
|
|
411
|
-
(emits a) (emits b))
|
|
412
|
-
([a b c]
|
|
413
|
-
(emits a) (emits b) (emits c))
|
|
414
|
-
([a b c d]
|
|
415
|
-
(emits a) (emits b) (emits c) (emits d))
|
|
416
|
-
([a b c d e]
|
|
417
|
-
(emits a) (emits b) (emits c) (emits d) (emits e))
|
|
418
|
-
([a b c d e & xs]
|
|
419
|
-
(emits a) (emits b) (emits c) (emits d) (emits e)
|
|
420
|
-
(doseq [x xs] (emits x))))
|
|
421
|
-
|
|
422
|
-
(defn ^:private _emitln []
|
|
423
|
-
(newline)
|
|
424
|
-
(when *source-map-data*
|
|
425
|
-
#?(:clj (.set ^AtomicLong *source-map-data-gen-col* 0))
|
|
426
|
-
(swap! *source-map-data*
|
|
427
|
-
(fn [{:keys [gen-line] :as m}]
|
|
428
|
-
(assoc m
|
|
429
|
-
:gen-line (inc gen-line)
|
|
430
|
-
#?@(:cljs [:gen-col 0])))))
|
|
431
|
-
nil)
|
|
432
|
-
|
|
433
|
-
(defn emitln
|
|
434
|
-
([] (_emitln))
|
|
435
|
-
([a]
|
|
436
|
-
(emits a) (_emitln))
|
|
437
|
-
([a b]
|
|
438
|
-
(emits a) (emits b) (_emitln))
|
|
439
|
-
([a b c]
|
|
440
|
-
(emits a) (emits b) (emits c) (_emitln))
|
|
441
|
-
([a b c d]
|
|
442
|
-
(emits a) (emits b) (emits c) (emits d) (_emitln))
|
|
443
|
-
([a b c d e]
|
|
444
|
-
(emits a) (emits b) (emits c) (emits d) (emits e) (_emitln))
|
|
445
|
-
([a b c d e & xs]
|
|
446
|
-
(emits a) (emits b) (emits c) (emits d) (emits e)
|
|
447
|
-
(doseq [x xs] (emits x))
|
|
448
|
-
(_emitln)))
|
|
449
|
-
|
|
450
|
-
(defn ^String emit-str [expr]
|
|
451
|
-
(with-out-str (emit expr)))
|
|
452
|
-
|
|
453
|
-
#?(:clj
|
|
454
|
-
(defmulti emit-constant* class)
|
|
455
|
-
:cljs
|
|
456
|
-
(defmulti emit-constant* type))
|
|
457
|
-
|
|
458
|
-
(declare emit-map emit-list emit-vector emit-set emit-js-object emit-js-array
|
|
459
|
-
emit-with-meta emit-constants-comma-sep emit-constant emit-record-value)
|
|
460
|
-
|
|
461
|
-
(defn all-distinct? [xs]
|
|
462
|
-
(apply distinct? xs))
|
|
463
|
-
|
|
464
|
-
#?(:clj
|
|
465
|
-
(defn emit-constant-no-meta [x]
|
|
466
|
-
(cond
|
|
467
|
-
(seq? x) (emit-list x emit-constants-comma-sep)
|
|
468
|
-
(record? x) (let [[ns name] (ana/record-ns+name x)]
|
|
469
|
-
(emit-record-value ns name #(emit-constant (into {} x))))
|
|
470
|
-
(map? x) (emit-map (keys x) (vals x) emit-constants-comma-sep all-distinct?)
|
|
471
|
-
(vector? x) (emit-vector x emit-constants-comma-sep)
|
|
472
|
-
(set? x) (emit-set x emit-constants-comma-sep all-distinct?)
|
|
473
|
-
:else (emit-constant* x)))
|
|
474
|
-
:cljs
|
|
475
|
-
(defn emit-constant-no-meta [x]
|
|
476
|
-
(cond
|
|
477
|
-
(ana.impl/cljs-seq? x) (emit-list x emit-constants-comma-sep)
|
|
478
|
-
(record? x) (let [[ns name] (ana/record-ns+name x)]
|
|
479
|
-
(emit-record-value ns name #(emit-constant (into {} x))))
|
|
480
|
-
(ana.impl/cljs-map? x) (emit-map (keys x) (vals x) emit-constants-comma-sep all-distinct?)
|
|
481
|
-
(ana.impl/cljs-vector? x) (emit-vector x emit-constants-comma-sep)
|
|
482
|
-
(ana.impl/cljs-set? x) (emit-set x emit-constants-comma-sep all-distinct?)
|
|
483
|
-
:else (emit-constant* x))))
|
|
484
|
-
|
|
485
|
-
(defn emit-constant [v]
|
|
486
|
-
(let [m (ana/elide-irrelevant-meta (meta v))]
|
|
487
|
-
(if (some? (seq m))
|
|
488
|
-
(emit-with-meta #(emit-constant-no-meta v) #(emit-constant-no-meta m))
|
|
489
|
-
(emit-constant-no-meta v))))
|
|
490
|
-
|
|
491
|
-
(defmethod emit-constant* :default
|
|
492
|
-
[x]
|
|
493
|
-
(throw
|
|
494
|
-
(ex-info (str "failed compiling constant: " x "; "
|
|
495
|
-
(pr-str (type x)) " is not a valid ClojureScript constant.")
|
|
496
|
-
{:constant x
|
|
497
|
-
:type (type x)
|
|
498
|
-
:clojure.error/phase :compilation})))
|
|
499
|
-
|
|
500
|
-
(defmethod emit-constant* nil [x] (emits "null"))
|
|
501
|
-
|
|
502
|
-
#?(:clj
|
|
503
|
-
(defmethod emit-constant* Long [x] (emits "(" x ")")))
|
|
504
|
-
|
|
505
|
-
#?(:clj
|
|
506
|
-
(defmethod emit-constant* Integer [x] (emits x))) ; reader puts Integers in metadata
|
|
507
|
-
|
|
508
|
-
#?(:clj
|
|
509
|
-
(defmethod emit-constant* Double [x]
|
|
510
|
-
(let [x (double x)]
|
|
511
|
-
(cond (Double/isNaN x)
|
|
512
|
-
(emits "NaN")
|
|
513
|
-
|
|
514
|
-
(Double/isInfinite x)
|
|
515
|
-
(emits (if (pos? x) "Infinity" "-Infinity"))
|
|
516
|
-
|
|
517
|
-
:else (emits x))))
|
|
518
|
-
:cljs
|
|
519
|
-
(defmethod emit-constant* js/Number [x]
|
|
520
|
-
(cond (js/isNaN x)
|
|
521
|
-
(emits "NaN")
|
|
522
|
-
|
|
523
|
-
(not (js/isFinite x))
|
|
524
|
-
(emits (if (pos? x) "Infinity" "-Infinity"))
|
|
525
|
-
|
|
526
|
-
(and (zero? x) (neg? (/ x)))
|
|
527
|
-
(emits "(-0)")
|
|
528
|
-
|
|
529
|
-
:else (emits "(" x ")"))))
|
|
530
|
-
|
|
531
|
-
#?(:clj
|
|
532
|
-
(defmethod emit-constant* BigDecimal [x] (emits (.doubleValue ^BigDecimal x))))
|
|
533
|
-
|
|
534
|
-
#?(:clj
|
|
535
|
-
(defmethod emit-constant* clojure.lang.BigInt [x] (emits (.doubleValue ^clojure.lang.BigInt x))))
|
|
536
|
-
|
|
537
|
-
(defmethod emit-constant* #?(:clj String :cljs js/String) [x]
|
|
538
|
-
(emits (wrap-in-double-quotes (escape-string x))))
|
|
539
|
-
|
|
540
|
-
(defmethod emit-constant* #?(:clj Boolean :cljs js/Boolean) [x] (emits (if x "true" "false")))
|
|
541
|
-
|
|
542
|
-
#?(:clj
|
|
543
|
-
(defmethod emit-constant* Character [x]
|
|
544
|
-
(emits (wrap-in-double-quotes (escape-char x)))))
|
|
545
|
-
|
|
546
|
-
(defmethod emit-constant* #?(:clj java.util.regex.Pattern :cljs js/RegExp) [x]
|
|
547
|
-
(if (= "" (str x))
|
|
548
|
-
(emits "(new RegExp(\"\"))")
|
|
549
|
-
(let [[_ flags pattern] (re-find #"^(?:\(\?([idmsux]*)\))?(.*)" (str x))]
|
|
550
|
-
#?(:clj (emits \/
|
|
551
|
-
(.replaceAll (re-matcher #"/" pattern) "\\\\/")
|
|
552
|
-
\/ flags)
|
|
553
|
-
:cljs (emits pattern)))))
|
|
554
|
-
|
|
555
|
-
(defn emits-keyword [kw]
|
|
556
|
-
(let [ns (namespace kw)
|
|
557
|
-
name (name kw)]
|
|
558
|
-
(emits (cc "new cljs.core.Keyword("))
|
|
559
|
-
(emit-constant ns)
|
|
560
|
-
(emits ",")
|
|
561
|
-
(emit-constant name)
|
|
562
|
-
(emits ",")
|
|
563
|
-
(emit-constant (if ns
|
|
564
|
-
(str ns "/" name)
|
|
565
|
-
name))
|
|
566
|
-
(emits ",")
|
|
567
|
-
(emit-constant (hash kw))
|
|
568
|
-
(emits ")")))
|
|
569
|
-
|
|
570
|
-
(defn emits-symbol [sym]
|
|
571
|
-
(let [ns (namespace sym)
|
|
572
|
-
name (name sym)
|
|
573
|
-
symstr (if-not (nil? ns)
|
|
574
|
-
(str ns "/" name)
|
|
575
|
-
name)]
|
|
576
|
-
(emits (cc "new cljs.core.Symbol("))
|
|
577
|
-
(emit-constant ns)
|
|
578
|
-
(emits ",")
|
|
579
|
-
(emit-constant name)
|
|
580
|
-
(emits ",")
|
|
581
|
-
(emit-constant symstr)
|
|
582
|
-
(emits ",")
|
|
583
|
-
(emit-constant (hash sym))
|
|
584
|
-
(emits ",")
|
|
585
|
-
(emit-constant nil)
|
|
586
|
-
(emits ")")))
|
|
587
|
-
|
|
588
|
-
(defn- esm-constants?
|
|
589
|
-
"Whether the module being emitted references keyword and symbol constants
|
|
590
|
-
of the constants module (:emit-constants). cljs.core, which the constants
|
|
591
|
-
module imports, keeps its own."
|
|
592
|
-
[]
|
|
593
|
-
(and *esm-emitting*
|
|
594
|
-
(-> @env/*compiler* :options :emit-constants)
|
|
595
|
-
(not= 'cljs.core ana/*cljs-ns*)
|
|
596
|
-
;; the constants module has the constants of the compiled namespaces
|
|
597
|
-
(not *esm-repl*)))
|
|
598
|
-
|
|
599
|
-
(defn- emit-constant-ref
|
|
600
|
-
"Emits the reference to constant x of the constants table, true if it has
|
|
601
|
-
one."
|
|
602
|
-
[x]
|
|
603
|
-
(when-let [value (and (-> @env/*compiler* :options :emit-constants)
|
|
604
|
-
(-> @env/*compiler* ::ana/constant-table x))]
|
|
605
|
-
(if *esm-emitting*
|
|
606
|
-
(when (esm-constants?)
|
|
607
|
-
(emits (esm-ns-alias ana/constants-ns-sym) "." value)
|
|
608
|
-
true)
|
|
609
|
-
(do (emits "cljs.core." value)
|
|
610
|
-
true))))
|
|
611
|
-
|
|
612
|
-
(defmethod emit-constant* #?(:clj clojure.lang.Keyword :cljs Keyword) [x]
|
|
613
|
-
(when-not (emit-constant-ref x)
|
|
614
|
-
(emits-keyword x)))
|
|
615
|
-
|
|
616
|
-
(defmethod emit-constant* #?(:clj clojure.lang.Symbol :cljs Symbol) [x]
|
|
617
|
-
(when-not (emit-constant-ref x)
|
|
618
|
-
(emits-symbol x)))
|
|
619
|
-
|
|
620
|
-
(defn emit-constants-comma-sep [cs]
|
|
621
|
-
(fn []
|
|
622
|
-
(doall
|
|
623
|
-
(map-indexed (fn [i m]
|
|
624
|
-
(if (even? i)
|
|
625
|
-
(emit-constant m)
|
|
626
|
-
(emits m)))
|
|
627
|
-
(comma-sep cs)))))
|
|
628
|
-
|
|
629
|
-
(def ^:private array-map-threshold 8)
|
|
630
|
-
|
|
631
|
-
;; tagged literal support
|
|
632
|
-
|
|
633
|
-
(defn- emit-inst [inst-ms]
|
|
634
|
-
(emits "new Date(" inst-ms ")"))
|
|
635
|
-
|
|
636
|
-
(defmethod emit-constant* #?(:clj java.util.Date :cljs js/Date) [^java.util.Date date]
|
|
637
|
-
(emit-inst (.getTime date)))
|
|
638
|
-
|
|
639
|
-
#?(:clj
|
|
640
|
-
(defmethod emit-constant* java.time.Instant [^java.time.Instant inst]
|
|
641
|
-
(emit-inst (.toEpochMilli inst))))
|
|
642
|
-
|
|
643
|
-
(defmethod emit-constant* #?(:clj java.util.UUID :cljs UUID) [^java.util.UUID uuid]
|
|
644
|
-
(let [uuid-str (.toString uuid)]
|
|
645
|
-
(emits (cc "new cljs.core.UUID(\"") uuid-str "\", " (hash uuid-str) ")")))
|
|
646
|
-
|
|
647
|
-
(defmethod emit-constant* #?(:clj JSValue :cljs cljs.tagged-literals/JSValue) [^JSValue v]
|
|
648
|
-
(let [items (.-val v)]
|
|
649
|
-
(if (map? items)
|
|
650
|
-
(emit-js-object items #(fn [] (emit-constant %)))
|
|
651
|
-
(emit-js-array items emit-constants-comma-sep))))
|
|
652
|
-
|
|
653
|
-
#?(:clj
|
|
654
|
-
(defmacro emit-wrap [env & body]
|
|
655
|
-
`(let [env# ~env]
|
|
656
|
-
(when (= :return (:context env#)) (emits "return "))
|
|
657
|
-
~@body
|
|
658
|
-
(when-not (= :expr (:context env#)) (emitln ";")))))
|
|
659
|
-
|
|
660
|
-
(defmethod emit* :no-op [m])
|
|
661
|
-
|
|
662
|
-
(defn emit-var
|
|
663
|
-
[{:keys [info env form] :as ast}]
|
|
664
|
-
(if-let [const-expr (:const-expr ast)]
|
|
665
|
-
(emit (assoc const-expr :env env))
|
|
666
|
-
(let [{:keys [options] :as cenv} @env/*compiler*
|
|
667
|
-
var-name (:name info)
|
|
668
|
-
info (if (= (namespace var-name) "js")
|
|
669
|
-
(let [js-module-name (get-in cenv [:js-module-index (name var-name) :name])]
|
|
670
|
-
(or js-module-name (name var-name)))
|
|
671
|
-
info)]
|
|
672
|
-
;; We need a way to write bindings out to source maps and javascript
|
|
673
|
-
;; without getting wrapped in an emit-wrap calls, otherwise we get
|
|
674
|
-
;; e.g. (function greet(return x, return y) {}).
|
|
675
|
-
(cond
|
|
676
|
-
(:binding-form? ast)
|
|
677
|
-
;; Emit the arg map so shadowing is properly handled when munging
|
|
678
|
-
;; (prevents duplicate fn-param-names)
|
|
679
|
-
(emits (munge ast))
|
|
680
|
-
|
|
681
|
-
;; ES modules are never loaded by the goog debug loader
|
|
682
|
-
(and *esm-emitting* (= 'js/COMPILED var-name))
|
|
683
|
-
(emit-wrap env (emits "true"))
|
|
684
|
-
|
|
685
|
-
;; a compile time constant, bundlers eliminate dead code depending on
|
|
686
|
-
;; it, set with :closure-defines {goog.DEBUG false}
|
|
687
|
-
(and *esm-emitting* (contains? '#{goog/DEBUG js/goog.DEBUG} var-name))
|
|
688
|
-
(when-not (= :statement (:context env))
|
|
689
|
-
(emit-wrap env
|
|
690
|
-
(emits (pr-str (get-in options [:closure-defines "goog.DEBUG"] true)))))
|
|
691
|
-
|
|
692
|
-
;; a direct eval in a module defeats tree shaking and renaming of all
|
|
693
|
-
;; of the module's bindings
|
|
694
|
-
(and *esm-emitting* (= 'js/eval var-name))
|
|
695
|
-
(when-not (= :statement (:context env))
|
|
696
|
-
(emit-wrap env (emits "(0,eval)")))
|
|
697
|
-
|
|
698
|
-
;; namespaces accessed as JavaScript globals, i.e. js/my.ns.foo
|
|
699
|
-
(and *esm-emitting* (= "js" (namespace var-name)) (esm-js-ns-ref (name var-name)))
|
|
700
|
-
(when-not (= :statement (:context env))
|
|
701
|
-
(emit-wrap env (emits (esm-js-ns-ref (name var-name)))))
|
|
702
|
-
|
|
703
|
-
:else
|
|
704
|
-
(when-not (= :statement (:context env))
|
|
705
|
-
(let [reserved (cond-> js-reserved
|
|
706
|
-
(and (es5>= (:language-out options))
|
|
707
|
-
;; we can skip munging things like `my.ns.default`
|
|
708
|
-
;; but not standalone `default` variable names
|
|
709
|
-
;; as they're not valid ES5 - Antonio
|
|
710
|
-
(some? (namespace var-name)))
|
|
711
|
-
(set/difference ana/es5-allowed))
|
|
712
|
-
js-module (get-in cenv [:js-namespaces (or (namespace var-name) (name var-name))])
|
|
713
|
-
info (cond-> info
|
|
714
|
-
(not= form 'js/-Infinity) (munge reserved))]
|
|
715
|
-
(emit-wrap env
|
|
716
|
-
(case (:module-type js-module)
|
|
717
|
-
;; Closure exports CJS exports through default property
|
|
718
|
-
:commonjs
|
|
719
|
-
(if (namespace var-name)
|
|
720
|
-
(emits (munge (namespace var-name) reserved) "[\"default\"]." (munge (name var-name) reserved))
|
|
721
|
-
(emits (munge (name var-name) reserved) "[\"default\"]"))
|
|
722
|
-
|
|
723
|
-
;; Emit bracket notation for default prop access instead of dot notation
|
|
724
|
-
:es6
|
|
725
|
-
(if (and (namespace var-name) (= "default" (name var-name)))
|
|
726
|
-
(emits (munge (namespace var-name) reserved) "[\"default\"]")
|
|
727
|
-
(emits info))
|
|
728
|
-
|
|
729
|
-
(emits info)))))))))
|
|
730
|
-
|
|
731
|
-
(defmethod emit* :var [expr] (emit-var expr))
|
|
732
|
-
(defmethod emit* :binding [expr] (emit-var expr))
|
|
733
|
-
(defmethod emit* :js-var [expr] (emit-var expr))
|
|
734
|
-
(defmethod emit* :local [expr] (emit-var expr))
|
|
735
|
-
|
|
736
|
-
(defmethod emit* :the-var
|
|
737
|
-
[{:keys [env var sym meta] :as arg}]
|
|
738
|
-
{:pre [(ana/ast? sym) (ana/ast? meta)]}
|
|
739
|
-
(let [{:keys [name]} (:info var)]
|
|
740
|
-
(emit-wrap env
|
|
741
|
-
(emits (cc "new cljs.core.Var(function(){return ") (munge name) ";},"
|
|
742
|
-
sym "," meta ")"))))
|
|
743
|
-
|
|
744
|
-
(defn emit-with-meta [expr meta]
|
|
745
|
-
(emits (cc "cljs.core.with_meta(") expr "," meta ")"))
|
|
746
|
-
|
|
747
|
-
(defmethod emit* :with-meta
|
|
748
|
-
[{:keys [expr meta env]}]
|
|
749
|
-
(emit-wrap env
|
|
750
|
-
(emit-with-meta expr meta)))
|
|
751
|
-
|
|
752
|
-
(defn distinct-keys? [keys]
|
|
753
|
-
(let [keys (map ana/unwrap-quote keys)]
|
|
754
|
-
(and (every? #(= (:op %) :const) keys)
|
|
755
|
-
(= (count (into #{} keys)) (count keys)))))
|
|
756
|
-
|
|
757
|
-
(defn obj-map-key [x]
|
|
758
|
-
(if (keyword? x)
|
|
759
|
-
(str \" "\\uFDD0" \'
|
|
760
|
-
(if (namespace x)
|
|
761
|
-
(str (namespace x) "/") "")
|
|
762
|
-
(name x)
|
|
763
|
-
\")
|
|
764
|
-
(str \" x \")))
|
|
765
|
-
|
|
766
|
-
(defn emit-obj-map [str-keys vals comma-sep distinct-keys?]
|
|
767
|
-
(if (zero? (count str-keys))
|
|
768
|
-
(emits (cc "cljs.core.ObjMap.EMPTY"))
|
|
769
|
-
(emits (cc "cljs.core.ObjMap.fromObject([") (comma-sep str-keys) "], {"
|
|
770
|
-
(comma-sep (map (fn [k v] (str k ":" (emit-str v))) str-keys vals))
|
|
771
|
-
"})")))
|
|
772
|
-
|
|
773
|
-
(defn emit-lite-map [keys vals comma-sep distinct-keys?]
|
|
774
|
-
(if (zero? (count keys))
|
|
775
|
-
(emits (cc "cljs.core.HashMapLite.EMPTY"))
|
|
776
|
-
(emits (cc "cljs.core.HashMapLite.fromArrays([") (comma-sep keys) "], [" (comma-sep vals) "])")))
|
|
777
|
-
|
|
778
|
-
(defn emit-map [keys vals comma-sep distinct-keys?]
|
|
779
|
-
(cond
|
|
780
|
-
(zero? (count keys))
|
|
781
|
-
(emits (cc "cljs.core.PersistentArrayMap.EMPTY"))
|
|
782
|
-
|
|
783
|
-
(<= (count keys) array-map-threshold)
|
|
784
|
-
(if (distinct-keys? keys)
|
|
785
|
-
(emits (cc "new cljs.core.PersistentArrayMap(null, ") (count keys) ", ["
|
|
786
|
-
(comma-sep (interleave keys vals))
|
|
787
|
-
"], null)")
|
|
788
|
-
(emits (cc "cljs.core.PersistentArrayMap.createAsIfByAssoc([")
|
|
789
|
-
(comma-sep (interleave keys vals))
|
|
790
|
-
"])"))
|
|
791
|
-
|
|
792
|
-
:else
|
|
793
|
-
(emits (cc "cljs.core.PersistentHashMap.fromArrays([")
|
|
794
|
-
(comma-sep keys)
|
|
795
|
-
"],["
|
|
796
|
-
(comma-sep vals)
|
|
797
|
-
"])")))
|
|
798
|
-
|
|
799
|
-
(defmethod emit* :map
|
|
800
|
-
[{:keys [env form keys vals]}]
|
|
801
|
-
(emit-wrap env
|
|
802
|
-
(if (ana/lite-mode?)
|
|
803
|
-
(let [form-keys (clojure.core/keys form)]
|
|
804
|
-
(if (every? #(or (string? %) (keyword? %)) form-keys)
|
|
805
|
-
(emit-obj-map (map obj-map-key form-keys) vals comma-sep distinct-keys?)
|
|
806
|
-
(emit-lite-map keys vals comma-sep distinct-keys?)))
|
|
807
|
-
(emit-map keys vals comma-sep distinct-keys?))))
|
|
808
|
-
|
|
809
|
-
(defn emit-list [items comma-sep]
|
|
810
|
-
(if (empty? items)
|
|
811
|
-
(emits (cc "cljs.core.List.EMPTY"))
|
|
812
|
-
(emits (cc "cljs.core.list(") (comma-sep items) ")")))
|
|
813
|
-
|
|
814
|
-
(defn emit-vector [items comma-sep]
|
|
815
|
-
(if (empty? items)
|
|
816
|
-
(emits (cc "cljs.core.PersistentVector.EMPTY"))
|
|
817
|
-
(let [cnt (count items)]
|
|
818
|
-
(if (< cnt 32)
|
|
819
|
-
(emits (cc "new cljs.core.PersistentVector(null, ") cnt
|
|
820
|
-
(cc ", 5, cljs.core.PersistentVector.EMPTY_NODE, [") (comma-sep items) "], null)")
|
|
821
|
-
(emits (cc "cljs.core.PersistentVector.fromArray([") (comma-sep items) "], true)")))))
|
|
822
|
-
|
|
823
|
-
(defn emit-lite-vector [items comma-sep]
|
|
824
|
-
(if (empty? items)
|
|
825
|
-
(emits (cc "cljs.core.VectorLite.EMPTY"))
|
|
826
|
-
(emits (cc "new cljs.core.VectorLite(null, [") (comma-sep items) "], null)")))
|
|
827
|
-
|
|
828
|
-
(defmethod emit* :vector
|
|
829
|
-
[{:keys [items env]}]
|
|
830
|
-
(emit-wrap env
|
|
831
|
-
(if (ana/lite-mode?)
|
|
832
|
-
(emit-lite-vector items comma-sep)
|
|
833
|
-
(emit-vector items comma-sep))))
|
|
834
|
-
|
|
835
|
-
(defn distinct-constants? [items]
|
|
836
|
-
(let [items (map ana/unwrap-quote items)]
|
|
837
|
-
(and (every? #(= (:op %) :const) items)
|
|
838
|
-
(= (count (into #{} items)) (count items)))))
|
|
839
|
-
|
|
840
|
-
(defn- checked-set-literals?
|
|
841
|
-
"Whether set literals of non-constant items throw on duplicates (CLJS-3415),
|
|
842
|
-
:checked-set-literals false keeps the earlier behavior: duplicates collapse."
|
|
843
|
-
[]
|
|
844
|
-
(not (false? (get-in @env/*compiler* [:options :checked-set-literals]))))
|
|
845
|
-
|
|
846
|
-
(defn emit-set [items comma-sep distinct-constants?]
|
|
847
|
-
(cond
|
|
848
|
-
(empty? items)
|
|
849
|
-
(emits (cc "cljs.core.PersistentHashSet.EMPTY"))
|
|
850
|
-
|
|
851
|
-
(distinct-constants? items)
|
|
852
|
-
(emits (cc "new cljs.core.PersistentHashSet(null, new cljs.core.PersistentArrayMap(null, ") (count items) ", ["
|
|
853
|
-
(comma-sep (interleave items (repeat "null"))) "], null), null)")
|
|
854
|
-
|
|
855
|
-
(checked-set-literals?)
|
|
856
|
-
(emits (cc "cljs.core.PersistentHashSet.createWithCheck([") (comma-sep items) "])")
|
|
857
|
-
|
|
858
|
-
:else (emits (cc "cljs.core.PersistentHashSet.createAsIfByAssoc([") (comma-sep items) "])")))
|
|
859
|
-
|
|
860
|
-
(defn emit-lite-set [items comma-sep distinct-constants?]
|
|
861
|
-
(cond
|
|
862
|
-
(empty? items)
|
|
863
|
-
(emits (cc "cljs.core.SetLite.EMPTY"))
|
|
864
|
-
|
|
865
|
-
(distinct-constants? items)
|
|
866
|
-
(emits (cc "cljs.core.set_lite([") (comma-sep items) "])")
|
|
867
|
-
|
|
868
|
-
(checked-set-literals?)
|
|
869
|
-
(emits (cc "cljs.core.set_lite_check([") (comma-sep items) "])")
|
|
870
|
-
|
|
871
|
-
:else (emits (cc "cljs.core.set_lite([") (comma-sep items) "])")))
|
|
872
|
-
|
|
873
|
-
(defmethod emit* :set
|
|
874
|
-
[{:keys [items env]}]
|
|
875
|
-
(emit-wrap env
|
|
876
|
-
(if (ana/lite-mode?)
|
|
877
|
-
(emit-lite-set items comma-sep distinct-constants?)
|
|
878
|
-
(emit-set items comma-sep distinct-constants?))))
|
|
879
|
-
|
|
880
|
-
(defn emit-js-object [items emit-js-object-val]
|
|
881
|
-
(emits "({")
|
|
882
|
-
(when-let [items (seq items)]
|
|
883
|
-
(let [[[k v] & r] items]
|
|
884
|
-
(emits "\"" (name k) "\": " (emit-js-object-val v))
|
|
885
|
-
(doseq [[k v] r]
|
|
886
|
-
(emits ", \"" (name k) "\": " (emit-js-object-val v)))))
|
|
887
|
-
(emits "})"))
|
|
888
|
-
|
|
889
|
-
(defn emit-js-array [items comma-sep]
|
|
890
|
-
(emits "[" (comma-sep items) "]"))
|
|
891
|
-
|
|
892
|
-
(defmethod emit* :js-object
|
|
893
|
-
[{:keys [keys vals env]}]
|
|
894
|
-
(emit-wrap env
|
|
895
|
-
(emit-js-object (map vector keys vals) identity)))
|
|
896
|
-
|
|
897
|
-
(defmethod emit* :js-array
|
|
898
|
-
[{:keys [items env]}]
|
|
899
|
-
(emit-wrap env
|
|
900
|
-
(emit-js-array items comma-sep)))
|
|
901
|
-
|
|
902
|
-
(defn emit-record-value
|
|
903
|
-
[ns name items]
|
|
904
|
-
(emits ns ".map__GT_" name "(" items ")"))
|
|
905
|
-
|
|
906
|
-
(defmethod emit* :quote
|
|
907
|
-
[{:keys [expr]}]
|
|
908
|
-
(emit expr))
|
|
909
|
-
|
|
910
|
-
(defmethod emit* :const
|
|
911
|
-
[{:keys [form env]}]
|
|
912
|
-
(when-not (= :statement (:context env))
|
|
913
|
-
(emit-wrap env (emit-constant form))))
|
|
914
|
-
|
|
915
|
-
(defn truthy-constant? [expr]
|
|
916
|
-
(let [{:keys [op form const-expr]} (ana/unwrap-quote expr)]
|
|
917
|
-
(or (and (= op :const)
|
|
918
|
-
form
|
|
919
|
-
(not (or (and (string? form) (= form ""))
|
|
920
|
-
(and (number? form) (zero? form)))))
|
|
921
|
-
(and (some? const-expr)
|
|
922
|
-
(truthy-constant? const-expr)))))
|
|
923
|
-
|
|
924
|
-
(defn falsey-constant? [expr]
|
|
925
|
-
(let [{:keys [op form const-expr]} (ana/unwrap-quote expr)]
|
|
926
|
-
(or (and (= op :const)
|
|
927
|
-
(or (false? form) (nil? form)))
|
|
928
|
-
(and (some? const-expr)
|
|
929
|
-
(falsey-constant? const-expr)))))
|
|
930
|
-
|
|
931
|
-
(defn safe-test? [env e]
|
|
932
|
-
(let [tag (ana/infer-tag env e)]
|
|
933
|
-
(or ('#{boolean seq} (ana/js-prim-ctor->tag tag tag))
|
|
934
|
-
(truthy-constant? e))))
|
|
935
|
-
|
|
936
|
-
(defmethod emit* :if
|
|
937
|
-
[{:keys [test then else env unchecked]}]
|
|
938
|
-
(let [context (:context env)
|
|
939
|
-
checked (not (or unchecked (safe-test? env test)))]
|
|
940
|
-
(cond
|
|
941
|
-
(truthy-constant? test) (emitln then)
|
|
942
|
-
(falsey-constant? test) (emitln else)
|
|
943
|
-
:else
|
|
944
|
-
(if (= :expr context)
|
|
945
|
-
(emits "(" (when checked (cc "cljs.core.truth_")) "(" test ")?" then ":" else ")")
|
|
946
|
-
(do
|
|
947
|
-
(if checked
|
|
948
|
-
(emitln (cc "if(cljs.core.truth_(") test ")){")
|
|
949
|
-
(emitln "if(" test "){"))
|
|
950
|
-
(emitln then "} else {")
|
|
951
|
-
(emitln else "}"))))))
|
|
952
|
-
|
|
953
|
-
(defn iife-open [{:keys [async]}]
|
|
954
|
-
(str (when async "(await ") "(" (when async "async ") "function (){"))
|
|
955
|
-
|
|
956
|
-
(defn iife-close [{:keys [async]}]
|
|
957
|
-
(str "})()" (when async ")")))
|
|
958
|
-
|
|
959
|
-
(defmethod emit* :case
|
|
960
|
-
[{v :test :keys [nodes default env]}]
|
|
961
|
-
(when (= (:context env) :expr)
|
|
962
|
-
(emitln (iife-open env)))
|
|
963
|
-
(let [gs (gensym "caseval__")]
|
|
964
|
-
(when (= :expr (:context env))
|
|
965
|
-
(emitln "var " gs ";"))
|
|
966
|
-
(emitln "switch (" v ") {")
|
|
967
|
-
(doseq [{ts :tests {:keys [then]} :then} nodes]
|
|
968
|
-
(doseq [test (map :test ts)]
|
|
969
|
-
(emitln "case " test ":"))
|
|
970
|
-
(if (= :expr (:context env))
|
|
971
|
-
(emitln gs "=" then)
|
|
972
|
-
(emitln then))
|
|
973
|
-
(emitln "break;"))
|
|
974
|
-
(when default
|
|
975
|
-
(emitln "default:")
|
|
976
|
-
(if (= :expr (:context env))
|
|
977
|
-
(emitln gs "=" default)
|
|
978
|
-
(emitln default)))
|
|
979
|
-
(emitln "}")
|
|
980
|
-
(when (= :expr (:context env))
|
|
981
|
-
(emitln "return " gs ";"
|
|
982
|
-
(iife-close env)))))
|
|
983
|
-
|
|
984
|
-
(defmethod emit* :throw
|
|
985
|
-
[{throw :exception :keys [env]}]
|
|
986
|
-
(if (= :expr (:context env))
|
|
987
|
-
(emits (iife-open env) "throw " throw (iife-close env))
|
|
988
|
-
(emitln "throw " throw ";")))
|
|
989
|
-
|
|
990
|
-
(def base-types
|
|
991
|
-
#{"null" "*" "...*"
|
|
992
|
-
"boolean" "Boolean"
|
|
993
|
-
"string" "String"
|
|
994
|
-
"number" "Number"
|
|
995
|
-
"array" "Array"
|
|
996
|
-
"object" "Object"
|
|
997
|
-
"RegExp"
|
|
998
|
-
"Date"})
|
|
999
|
-
|
|
1000
|
-
(def mapped-types
|
|
1001
|
-
{"nil" "null"})
|
|
1002
|
-
|
|
1003
|
-
(defn resolve-type [env ^String t]
|
|
1004
|
-
(cond
|
|
1005
|
-
(get base-types t) t
|
|
1006
|
-
|
|
1007
|
-
(get mapped-types t) (get mapped-types t)
|
|
1008
|
-
|
|
1009
|
-
#?(:clj (.startsWith t "!")
|
|
1010
|
-
:cljs (gstring/startsWith t "!"))
|
|
1011
|
-
(str "!" (resolve-type env (subs t 1)))
|
|
1012
|
-
|
|
1013
|
-
#?(:clj (.startsWith t "{")
|
|
1014
|
-
:cljs (gstring/startsWith t "{")) t
|
|
1015
|
-
|
|
1016
|
-
#?(:clj (.startsWith t "function")
|
|
1017
|
-
:cljs (gstring/startsWith t "function"))
|
|
1018
|
-
(let [idx (.lastIndexOf t ":")
|
|
1019
|
-
[fstr rstr] (if-not (== -1 idx)
|
|
1020
|
-
[(subs t 0 idx) (subs t (inc idx) (count t))]
|
|
1021
|
-
[t nil])
|
|
1022
|
-
ret-t (when rstr (resolve-type env rstr))
|
|
1023
|
-
axstr (subs fstr 9 (dec (count fstr)))
|
|
1024
|
-
args-ts (when-not (string/blank? axstr)
|
|
1025
|
-
(map (comp #(resolve-type env %) string/trim)
|
|
1026
|
-
(string/split axstr #",")))]
|
|
1027
|
-
(cond-> (str "function(" (string/join "," args-ts) ")")
|
|
1028
|
-
ret-t (str ":" ret-t)))
|
|
1029
|
-
|
|
1030
|
-
#?(:clj (.endsWith t "=")
|
|
1031
|
-
:cljs (gstring/endsWith t "="))
|
|
1032
|
-
(str (resolve-type env (subs t 0 (dec (count t)))) "=")
|
|
1033
|
-
|
|
1034
|
-
:else
|
|
1035
|
-
(munge (str (:name (ana/resolve-var env (symbol t)))))))
|
|
1036
|
-
|
|
1037
|
-
(defn resolve-types [env ts]
|
|
1038
|
-
(let [ts (-> ts string/trim (subs 1 (dec (count ts))))
|
|
1039
|
-
xs (string/split ts #"\|")]
|
|
1040
|
-
(str "{" (string/join "|" (map #(resolve-type env %) xs)) "}")))
|
|
1041
|
-
|
|
1042
|
-
(defn munge-param-return [env line]
|
|
1043
|
-
(cond
|
|
1044
|
-
(re-find #"@param" line)
|
|
1045
|
-
(let [[p ts n & xs] (map string/trim
|
|
1046
|
-
(string/split (string/trim line) #" "))]
|
|
1047
|
-
(if (and (= "@param" p)
|
|
1048
|
-
ts #?(:clj (.startsWith ^String ts "{")
|
|
1049
|
-
:cljs (gstring/startsWith ts "{")))
|
|
1050
|
-
(string/join " " (concat [p (resolve-types env ts) (munge n)] xs))
|
|
1051
|
-
line))
|
|
1052
|
-
|
|
1053
|
-
(re-find #"@return" line)
|
|
1054
|
-
(let [[p ts & xs] (map string/trim
|
|
1055
|
-
(string/split (string/trim line) #" "))]
|
|
1056
|
-
(if (and (= "@return" p)
|
|
1057
|
-
ts #?(:clj (.startsWith ^String ts "{")
|
|
1058
|
-
:cljs (gstring/startsWith ts "{")))
|
|
1059
|
-
(string/join " " (concat [p (resolve-types env ts)] xs))
|
|
1060
|
-
line))
|
|
1061
|
-
|
|
1062
|
-
:else line))
|
|
1063
|
-
|
|
1064
|
-
(defn checking-types? []
|
|
1065
|
-
(#{:error :warning}
|
|
1066
|
-
(get-in @env/*compiler*
|
|
1067
|
-
[:options :closure-warnings :check-types])))
|
|
1068
|
-
|
|
1069
|
-
(defn emit-comment
|
|
1070
|
-
"Emit a nicely formatted comment string."
|
|
1071
|
-
([doc jsdoc]
|
|
1072
|
-
(emit-comment nil doc jsdoc))
|
|
1073
|
-
([env doc jsdoc]
|
|
1074
|
-
(let [docs (when doc [doc])
|
|
1075
|
-
docs (if jsdoc (concat docs jsdoc) docs)
|
|
1076
|
-
docs (remove nil? docs)]
|
|
1077
|
-
(letfn [(print-comment-lines [e]
|
|
1078
|
-
(let [[x & ys]
|
|
1079
|
-
(map #(if (checking-types?) (munge-param-return env %) %)
|
|
1080
|
-
(string/split-lines e))]
|
|
1081
|
-
(emitln " * " (string/replace x "*/" "* /"))
|
|
1082
|
-
(doseq [next-line ys]
|
|
1083
|
-
(emitln " * "
|
|
1084
|
-
(-> next-line
|
|
1085
|
-
(string/replace #"^ " "")
|
|
1086
|
-
(string/replace "*/" "* /"))))))]
|
|
1087
|
-
(when (seq docs)
|
|
1088
|
-
(emitln "/**")
|
|
1089
|
-
(doseq [e docs]
|
|
1090
|
-
(when e
|
|
1091
|
-
(print-comment-lines e)))
|
|
1092
|
-
(emitln " */"))))))
|
|
1093
|
-
|
|
1094
|
-
(defn valid-define-value? [x]
|
|
1095
|
-
(or (string? x)
|
|
1096
|
-
(true? x)
|
|
1097
|
-
(false? x)
|
|
1098
|
-
(number? x)))
|
|
1099
|
-
|
|
1100
|
-
(defn get-define [mname jsdoc]
|
|
1101
|
-
(let [opts (get @env/*compiler* :options)]
|
|
1102
|
-
(and (some #?(:clj #(.startsWith ^String % "@define")
|
|
1103
|
-
:cljs #(gstring/startsWith % "@define"))
|
|
1104
|
-
jsdoc)
|
|
1105
|
-
opts
|
|
1106
|
-
(or (= (:optimizations opts) :none)
|
|
1107
|
-
(esm-mode? opts))
|
|
1108
|
-
(let [define (get-in opts [:closure-defines (str mname)])]
|
|
1109
|
-
(when (valid-define-value? define)
|
|
1110
|
-
(pr-str define))))))
|
|
1111
|
-
|
|
1112
|
-
(defmethod emit* :def
|
|
1113
|
-
[{:keys [name var init env doc goog-define jsdoc export test var-ast]}]
|
|
1114
|
-
;; Under ESM a var without init, i.e. (declare ^:dynamic *x*), still needs
|
|
1115
|
-
;; a binding other namespaces can import and set! with binding
|
|
1116
|
-
(when (and *esm-emitting* (not *esm-repl*) (nil? init) (not (:def-emits-var env)))
|
|
1117
|
-
(swap! (:hoist *esm*) conj (esm-def! name)))
|
|
1118
|
-
;; We only want to emit if an init is supplied, this is to avoid dead code
|
|
1119
|
-
;; elimination issues. The REPL is the exception to this rule.
|
|
1120
|
-
(when (or init (:def-emits-var env))
|
|
1121
|
-
(let [mname (binding [*esm-emitting* false] (munge name))
|
|
1122
|
-
;; at the REPL var is the namespace view's property, see *esm-repl*
|
|
1123
|
-
esm-local (when (and *esm-emitting* (not *esm-repl*)) (esm-def! name))
|
|
1124
|
-
esm-var-decl? (and esm-local
|
|
1125
|
-
(not *esm-in-fn*)
|
|
1126
|
-
(= :statement (:context env))
|
|
1127
|
-
(not (:def-emits-var env)))]
|
|
1128
|
-
(when (and esm-local (not esm-var-decl?))
|
|
1129
|
-
(swap! (:hoist *esm*) conj esm-local))
|
|
1130
|
-
(emit-comment env doc (concat
|
|
1131
|
-
(when goog-define
|
|
1132
|
-
[(str "@define {" goog-define "}")])
|
|
1133
|
-
jsdoc (:jsdoc init)))
|
|
1134
|
-
(when (= :return (:context env))
|
|
1135
|
-
(emitln "return ("))
|
|
1136
|
-
(when (:def-emits-var env)
|
|
1137
|
-
(emitln (iife-open env)))
|
|
1138
|
-
(when esm-var-decl?
|
|
1139
|
-
(emits "var "))
|
|
1140
|
-
(emits var)
|
|
1141
|
-
(when init
|
|
1142
|
-
(emits " = "
|
|
1143
|
-
(if-let [define (get-define mname jsdoc)]
|
|
1144
|
-
define
|
|
1145
|
-
(if (and goog-define *esm-emitting* (= :invoke (:op init)))
|
|
1146
|
-
;; no override, the default value of (goog/define name default)
|
|
1147
|
-
(second (:args init))
|
|
1148
|
-
init))))
|
|
1149
|
-
(when (:def-emits-var env)
|
|
1150
|
-
(emitln "; return (")
|
|
1151
|
-
(emits (merge
|
|
1152
|
-
{:op :the-var
|
|
1153
|
-
:env (assoc env :context :expr)}
|
|
1154
|
-
var-ast))
|
|
1155
|
-
(emitln ");"
|
|
1156
|
-
(iife-close env)))
|
|
1157
|
-
(when (= :return (:context env))
|
|
1158
|
-
(emitln ")"))
|
|
1159
|
-
;; NOTE: JavaScriptCore does not like this under advanced compilation
|
|
1160
|
-
;; this change was primarily for REPL interactions - David
|
|
1161
|
-
;(emits " = (typeof " mname " != 'undefined') ? " mname " : undefined")
|
|
1162
|
-
(when-not (= :expr (:context env)) (emitln ";"))
|
|
1163
|
-
(when export
|
|
1164
|
-
(if *esm-emitting*
|
|
1165
|
-
;; also a global for scripts calling into the build, i.e. my.app.init()
|
|
1166
|
-
(emitln (munge 'goog/exportSymbol) "('" (binding [*esm-emitting* false] (munge export)) "', " var ");")
|
|
1167
|
-
(emitln "goog.exportSymbol('" (munge export) "', " mname ");")))
|
|
1168
|
-
(when (and ana/*load-tests* test)
|
|
1169
|
-
(when (= :expr (:context env))
|
|
1170
|
-
(emitln ";"))
|
|
1171
|
-
(emitln var ".cljs$lang$test = " test ";")))))
|
|
1172
|
-
|
|
1173
|
-
(defn emit-apply-to
|
|
1174
|
-
[{:keys [name params env]}]
|
|
1175
|
-
(let [arglist (gensym "arglist__")
|
|
1176
|
-
delegate-name (str (munge name) "__delegate")]
|
|
1177
|
-
(emitln "(function (" arglist "){")
|
|
1178
|
-
(doseq [[i param] (map-indexed vector (drop-last 2 params))]
|
|
1179
|
-
(emits "var ")
|
|
1180
|
-
(emit param)
|
|
1181
|
-
(emits (cc " = cljs.core.first("))
|
|
1182
|
-
(emitln arglist ");")
|
|
1183
|
-
(emitln arglist (cc " = cljs.core.next(") arglist ");"))
|
|
1184
|
-
(if (< 1 (count params))
|
|
1185
|
-
(do
|
|
1186
|
-
(emits "var ")
|
|
1187
|
-
(emit (last (butlast params)))
|
|
1188
|
-
(emitln (cc " = cljs.core.first(") arglist ");")
|
|
1189
|
-
(emits "var ")
|
|
1190
|
-
(emit (last params))
|
|
1191
|
-
(emitln (cc " = cljs.core.rest(") arglist ");")
|
|
1192
|
-
(emits "return " delegate-name "(")
|
|
1193
|
-
(doseq [param params]
|
|
1194
|
-
(emit param)
|
|
1195
|
-
(when-not (= param (last params)) (emits ",")))
|
|
1196
|
-
(emitln ");"))
|
|
1197
|
-
(do
|
|
1198
|
-
(emits "var ")
|
|
1199
|
-
(emit (last params))
|
|
1200
|
-
(emitln (cc " = cljs.core.seq(") arglist ");")
|
|
1201
|
-
(emits "return " delegate-name "(")
|
|
1202
|
-
(doseq [param params]
|
|
1203
|
-
(emit param)
|
|
1204
|
-
(when-not (= param (last params)) (emits ",")))
|
|
1205
|
-
(emitln ");")))
|
|
1206
|
-
(emits "})")))
|
|
1207
|
-
|
|
1208
|
-
(defn emit-fn-params [params]
|
|
1209
|
-
(doseq [param params]
|
|
1210
|
-
(emit param)
|
|
1211
|
-
; Avoid extraneous comma (function greet(x, y, z,)
|
|
1212
|
-
(when-not (= param (last params))
|
|
1213
|
-
(emits ","))))
|
|
1214
|
-
|
|
1215
|
-
(defn emit-fn-method
|
|
1216
|
-
[{expr :body :keys [type name params env recurs]}]
|
|
1217
|
-
(let [async (:async env)]
|
|
1218
|
-
(emit-wrap env
|
|
1219
|
-
(emits "(" (when async "async ") "function " (munge name) "(")
|
|
1220
|
-
(emit-fn-params params)
|
|
1221
|
-
(emitln "){")
|
|
1222
|
-
(when type
|
|
1223
|
-
(emitln "var self__ = this;"))
|
|
1224
|
-
(when recurs (emitln "while(true){"))
|
|
1225
|
-
(emits expr)
|
|
1226
|
-
(when recurs
|
|
1227
|
-
(emitln "break;")
|
|
1228
|
-
(emitln "}"))
|
|
1229
|
-
(emits "})"))))
|
|
1230
|
-
|
|
1231
|
-
(defn emit-arguments-to-array
|
|
1232
|
-
"Emit code that copies function arguments into an array starting at an index.
|
|
1233
|
-
Returns name of var holding the array."
|
|
1234
|
-
[startslice]
|
|
1235
|
-
(assert (and (>= startslice 0) (integer? startslice)))
|
|
1236
|
-
(let [mname (munge (gensym))
|
|
1237
|
-
i (str mname "__i")
|
|
1238
|
-
a (str mname "__a")]
|
|
1239
|
-
(emitln "var " i " = 0, "
|
|
1240
|
-
a " = new Array(arguments.length - " startslice ");")
|
|
1241
|
-
(emitln "while (" i " < " a ".length) {"
|
|
1242
|
-
a "[" i "] = arguments[" i " + " startslice "]; ++" i ";}")
|
|
1243
|
-
a))
|
|
1244
|
-
|
|
1245
|
-
(defn emit-variadic-fn-method
|
|
1246
|
-
[{expr :body max-fixed-arity :fixed-arity variadic :variadic? :keys [type name params env recurs] :as f}]
|
|
1247
|
-
(emit-wrap env
|
|
1248
|
-
(let [name (or name (gensym))
|
|
1249
|
-
mname (munge name)
|
|
1250
|
-
delegate-name (str mname "__delegate")
|
|
1251
|
-
async (:async env)]
|
|
1252
|
-
(emitln (when *esm-emitting* "/*@__PURE__*/") "(function() { ")
|
|
1253
|
-
(emits "var " delegate-name " = " (when async "async ") "function (")
|
|
1254
|
-
(doseq [param params]
|
|
1255
|
-
(emit param)
|
|
1256
|
-
(when-not (= param (last params)) (emits ",")))
|
|
1257
|
-
(emitln "){")
|
|
1258
|
-
(when type
|
|
1259
|
-
(emitln "var self__ = this;"))
|
|
1260
|
-
(when recurs (emitln "while(true){"))
|
|
1261
|
-
(emits expr)
|
|
1262
|
-
(when recurs
|
|
1263
|
-
(emitln "break;")
|
|
1264
|
-
(emitln "}"))
|
|
1265
|
-
(emitln "};")
|
|
1266
|
-
|
|
1267
|
-
(emitln "var " mname " = " (when async "async ") "function ("
|
|
1268
|
-
(comma-sep
|
|
1269
|
-
(if variadic
|
|
1270
|
-
(concat (butlast params) ['var_args])
|
|
1271
|
-
params)) "){")
|
|
1272
|
-
(when type
|
|
1273
|
-
(emitln "var self__ = this;"))
|
|
1274
|
-
(when variadic
|
|
1275
|
-
(emits "var ")
|
|
1276
|
-
(emit (last params))
|
|
1277
|
-
(emitln " = null;")
|
|
1278
|
-
(emitln "if (arguments.length > " (dec (count params)) ") {")
|
|
1279
|
-
(let [a (emit-arguments-to-array (dec (count params)))]
|
|
1280
|
-
(emitln " " (last params) (cc " = new cljs.core.IndexedSeq(") a ",0,null);"))
|
|
1281
|
-
(emitln "} "))
|
|
1282
|
-
(emits "return " delegate-name ".call(this,")
|
|
1283
|
-
(doseq [param params]
|
|
1284
|
-
(emit param)
|
|
1285
|
-
(when-not (= param (last params)) (emits ",")))
|
|
1286
|
-
(emits ");")
|
|
1287
|
-
(emitln "};")
|
|
1288
|
-
|
|
1289
|
-
(emitln mname ".cljs$lang$maxFixedArity = " max-fixed-arity ";")
|
|
1290
|
-
(emits mname ".cljs$lang$applyTo = ")
|
|
1291
|
-
(emit-apply-to (assoc f :name name))
|
|
1292
|
-
(emitln ";")
|
|
1293
|
-
(emitln mname ".cljs$core$IFn$_invoke$arity$variadic = " delegate-name ";")
|
|
1294
|
-
(emitln "return " mname ";")
|
|
1295
|
-
(emitln "})()"))))
|
|
1296
|
-
|
|
1297
|
-
(defmethod emit* :fn
|
|
1298
|
-
[{variadic :variadic? :keys [name named? env methods max-fixed-arity recur-frames in-loop loop-lets]}]
|
|
1299
|
-
;;fn statements get erased, serve no purpose and can pollute scope if named
|
|
1300
|
-
(when-not (= :statement (:context env))
|
|
1301
|
-
(let [;; Under ESM the name def gives a fn is the module binding of its var:
|
|
1302
|
-
;; the function expression's name would shadow it in the fn's body,
|
|
1303
|
-
;; where calls (as the dispatcher of a variadic defn) must see the
|
|
1304
|
-
;; value set! (and with-redefs) assign. The engine names the fn
|
|
1305
|
-
;; after the binding it's assigned to.
|
|
1306
|
-
name (when-not (and *esm-emitting* (not named?)) name)
|
|
1307
|
-
recur-params (mapcat :params (filter #(and % @(:flag %)) recur-frames))
|
|
1308
|
-
loop-locals
|
|
1309
|
-
(->> (concat recur-params
|
|
1310
|
-
;; need to capture locals only if in recur fn or loop
|
|
1311
|
-
(when (or in-loop (seq recur-params))
|
|
1312
|
-
(mapcat :params loop-lets)))
|
|
1313
|
-
(map munge)
|
|
1314
|
-
seq)
|
|
1315
|
-
async (:async env)]
|
|
1316
|
-
(when loop-locals
|
|
1317
|
-
(when (= :return (:context env))
|
|
1318
|
-
(emits "return "))
|
|
1319
|
-
(emitln "((function (" (comma-sep (map munge loop-locals)) "){")
|
|
1320
|
-
(when-not (= :return (:context env))
|
|
1321
|
-
(emits "return ")))
|
|
1322
|
-
(if (= 1 (count methods))
|
|
1323
|
-
(if variadic
|
|
1324
|
-
(emit-variadic-fn-method (assoc (first methods) :name name))
|
|
1325
|
-
(emit-fn-method (assoc (first methods) :name name)))
|
|
1326
|
-
(let [name (or name (gensym))
|
|
1327
|
-
mname (munge name)
|
|
1328
|
-
maxparams (apply max-key count (map :params methods))
|
|
1329
|
-
mmap (into {}
|
|
1330
|
-
(map (fn [method]
|
|
1331
|
-
[(munge (symbol (str mname "__" (count (:params method)))))
|
|
1332
|
-
method])
|
|
1333
|
-
methods))
|
|
1334
|
-
ms (sort-by #(-> % second :params count) (seq mmap))]
|
|
1335
|
-
(when (= :return (:context env))
|
|
1336
|
-
(emits "return "))
|
|
1337
|
-
;; only defines and returns the fn, marked pure for bundlers
|
|
1338
|
-
(emitln (when *esm-emitting* "/*@__PURE__*/") "(function() {")
|
|
1339
|
-
(emitln "var " mname " = null;")
|
|
1340
|
-
(doseq [[n meth] ms]
|
|
1341
|
-
(emits "var " n " = ")
|
|
1342
|
-
(if (:variadic? meth)
|
|
1343
|
-
(emit-variadic-fn-method meth)
|
|
1344
|
-
(emit-fn-method meth))
|
|
1345
|
-
(emitln ";"))
|
|
1346
|
-
(emitln mname " = " (when async "async ") "function("
|
|
1347
|
-
(comma-sep (if variadic
|
|
1348
|
-
(concat (butlast maxparams) ['var_args])
|
|
1349
|
-
maxparams)) "){")
|
|
1350
|
-
(when variadic
|
|
1351
|
-
(emits "var ")
|
|
1352
|
-
(emit (last maxparams))
|
|
1353
|
-
(emitln " = var_args;"))
|
|
1354
|
-
(emitln "switch(arguments.length){")
|
|
1355
|
-
(doseq [[n meth] ms]
|
|
1356
|
-
(if (:variadic? meth)
|
|
1357
|
-
(do (emitln "default:")
|
|
1358
|
-
(let [restarg (munge (gensym))]
|
|
1359
|
-
(emitln "var " restarg " = null;")
|
|
1360
|
-
(emitln "if (arguments.length > " max-fixed-arity ") {")
|
|
1361
|
-
(let [a (emit-arguments-to-array max-fixed-arity)]
|
|
1362
|
-
(emitln restarg (cc " = new cljs.core.IndexedSeq(") a ",0,null);"))
|
|
1363
|
-
(emitln "}")
|
|
1364
|
-
(emitln "return " n ".cljs$core$IFn$_invoke$arity$variadic("
|
|
1365
|
-
(comma-sep (butlast maxparams))
|
|
1366
|
-
(when (> (count maxparams) 1) ", ")
|
|
1367
|
-
restarg ");")))
|
|
1368
|
-
(let [pcnt (count (:params meth))]
|
|
1369
|
-
(emitln "case " pcnt ":")
|
|
1370
|
-
(emitln "return " n ".call(this" (if (zero? pcnt) nil
|
|
1371
|
-
(list "," (comma-sep (take pcnt maxparams)))) ");"))))
|
|
1372
|
-
(emitln "}")
|
|
1373
|
-
(let [arg-count-js (if (= 'self__ (-> ms first val :params first :name))
|
|
1374
|
-
"(arguments.length - 1)"
|
|
1375
|
-
"arguments.length")]
|
|
1376
|
-
(emitln "throw(new Error('Invalid arity: ' + " arg-count-js "));"))
|
|
1377
|
-
(emitln "};")
|
|
1378
|
-
(when variadic
|
|
1379
|
-
(emitln mname ".cljs$lang$maxFixedArity = " max-fixed-arity ";")
|
|
1380
|
-
(emitln mname ".cljs$lang$applyTo = " (some #(let [[n m] %] (when (:variadic? m) n)) ms) ".cljs$lang$applyTo;"))
|
|
1381
|
-
(doseq [[n meth] ms]
|
|
1382
|
-
(let [c (count (:params meth))]
|
|
1383
|
-
(if (:variadic? meth)
|
|
1384
|
-
(emitln mname ".cljs$core$IFn$_invoke$arity$variadic = " n ".cljs$core$IFn$_invoke$arity$variadic;")
|
|
1385
|
-
(emitln mname ".cljs$core$IFn$_invoke$arity$" c " = " n ";"))))
|
|
1386
|
-
(emitln "return " mname ";")
|
|
1387
|
-
(emitln "})()")))
|
|
1388
|
-
(when loop-locals
|
|
1389
|
-
(emitln ";})(" (comma-sep loop-locals) "))")))))
|
|
1390
|
-
|
|
1391
|
-
(defmethod emit* :do
|
|
1392
|
-
[{:keys [statements ret env]}]
|
|
1393
|
-
(let [context (:context env)]
|
|
1394
|
-
(when (and (seq statements) (= :expr context)) (emitln (iife-open env)))
|
|
1395
|
-
(doseq [s statements] (emitln s))
|
|
1396
|
-
(emit ret)
|
|
1397
|
-
(when (and (seq statements) (= :expr context)) (emitln (iife-close env)))))
|
|
1398
|
-
|
|
1399
|
-
(defmethod emit* :try
|
|
1400
|
-
[{try :body :keys [env catch name finally]}]
|
|
1401
|
-
(let [context (:context env)]
|
|
1402
|
-
(if (or name finally)
|
|
1403
|
-
(do
|
|
1404
|
-
(when (= :expr context)
|
|
1405
|
-
(emits (iife-open env)))
|
|
1406
|
-
(emits "try{" try "}")
|
|
1407
|
-
(when name
|
|
1408
|
-
(emits "catch (" (munge name) "){" catch "}"))
|
|
1409
|
-
(when finally
|
|
1410
|
-
(assert (not= :const (:op (ana/unwrap-quote finally))) "finally block cannot contain constant")
|
|
1411
|
-
(emits "finally {" finally "}"))
|
|
1412
|
-
(when (= :expr context)
|
|
1413
|
-
(emits (iife-close env))))
|
|
1414
|
-
(emits try))))
|
|
1415
|
-
|
|
1416
|
-
(defn emit-let
|
|
1417
|
-
[{expr :body :keys [bindings env]} is-loop]
|
|
1418
|
-
(let [context (:context env)]
|
|
1419
|
-
(when (= :expr context)
|
|
1420
|
-
(emits (iife-open env)))
|
|
1421
|
-
(binding [*lexical-renames*
|
|
1422
|
-
(into *lexical-renames*
|
|
1423
|
-
(when (= :statement context)
|
|
1424
|
-
(map
|
|
1425
|
-
(fn [binding]
|
|
1426
|
-
(let [name (:name binding)]
|
|
1427
|
-
(vector (hash-scope binding)
|
|
1428
|
-
(gensym (str name "-")))))
|
|
1429
|
-
bindings)))]
|
|
1430
|
-
(doseq [{:keys [init] :as binding} bindings]
|
|
1431
|
-
(emits "var ")
|
|
1432
|
-
(emit binding) ; Binding will be treated as a var
|
|
1433
|
-
(emitln " = " init ";"))
|
|
1434
|
-
(when is-loop (emitln "while(true){"))
|
|
1435
|
-
(emits expr)
|
|
1436
|
-
(when is-loop
|
|
1437
|
-
(emitln "break;")
|
|
1438
|
-
(emitln "}")))
|
|
1439
|
-
(when (= :expr context) (emits (iife-close env)))))
|
|
1440
|
-
|
|
1441
|
-
(defmethod emit* :let [ast]
|
|
1442
|
-
(emit-let ast false))
|
|
1443
|
-
|
|
1444
|
-
(defmethod emit* :loop [ast]
|
|
1445
|
-
(emit-let ast true))
|
|
1446
|
-
|
|
1447
|
-
(defmethod emit* :recur
|
|
1448
|
-
[{:keys [frame exprs env]}]
|
|
1449
|
-
(let [temps (vec (take (count exprs) (repeatedly gensym)))
|
|
1450
|
-
params (:params frame)]
|
|
1451
|
-
(dotimes [i (count exprs)]
|
|
1452
|
-
(emitln "var " (temps i) " = " (exprs i) ";"))
|
|
1453
|
-
(dotimes [i (count exprs)]
|
|
1454
|
-
(emitln (munge (params i)) " = " (temps i) ";"))
|
|
1455
|
-
(emitln "continue;")))
|
|
1456
|
-
|
|
1457
|
-
(defmethod emit* :letfn
|
|
1458
|
-
[{expr :body :keys [bindings env]}]
|
|
1459
|
-
(let [context (:context env)]
|
|
1460
|
-
(when (= :expr context) (emits (iife-open env)))
|
|
1461
|
-
(doseq [{:keys [init] :as binding} bindings]
|
|
1462
|
-
(emitln "var " (munge binding) " = " init ";"))
|
|
1463
|
-
(emits expr)
|
|
1464
|
-
(when (= :expr context) (emits (iife-close env)))))
|
|
1465
|
-
|
|
1466
|
-
(defn protocol-prefix [psym]
|
|
1467
|
-
(symbol (str (-> (str psym)
|
|
1468
|
-
(.replace #?(:clj \. :cljs (js/RegExp. "\\." "g")) \$)
|
|
1469
|
-
(.replace \/ \$))
|
|
1470
|
-
"$")))
|
|
1471
|
-
|
|
1472
|
-
(defmethod emit* :invoke
|
|
1473
|
-
[{f :fn :keys [args env] :as expr}]
|
|
1474
|
-
(let [info (:info f)
|
|
1475
|
-
fn? (and ana/*cljs-static-fns*
|
|
1476
|
-
(not (:dynamic info))
|
|
1477
|
-
(:fn-var info))
|
|
1478
|
-
protocol (:protocol info)
|
|
1479
|
-
tag (ana/infer-tag env (first (:args expr)))
|
|
1480
|
-
proto? (and protocol tag
|
|
1481
|
-
(or (and ana/*cljs-static-fns* protocol (= tag 'not-native))
|
|
1482
|
-
(and
|
|
1483
|
-
(or ana/*cljs-static-fns*
|
|
1484
|
-
(:protocol-inline env))
|
|
1485
|
-
(or (= protocol tag)
|
|
1486
|
-
;; ignore new type hints for now - David
|
|
1487
|
-
(and (not (set? tag))
|
|
1488
|
-
(not ('#{any clj clj-or-nil clj-nil number string boolean function object array js} tag))
|
|
1489
|
-
(when-let [ps (:protocols
|
|
1490
|
-
(ana/resolve-existing-var env
|
|
1491
|
-
;; we're just checking for protocol methods,
|
|
1492
|
-
;; an internal optimization, don't emit warnings
|
|
1493
|
-
(vary-meta tag assoc ::ana/no-resolve true)))]
|
|
1494
|
-
(ps protocol)))))))
|
|
1495
|
-
first-arg-tag (ana/infer-tag env (first (:args expr)))
|
|
1496
|
-
opt-not? (and (= (:name info) 'cljs.core/not)
|
|
1497
|
-
(= first-arg-tag 'boolean))
|
|
1498
|
-
opt-count? (and (= (:name info) 'cljs.core/count)
|
|
1499
|
-
(boolean ('#{string array} first-arg-tag)))
|
|
1500
|
-
ns (:ns info)
|
|
1501
|
-
ftag (ana/infer-tag env f)
|
|
1502
|
-
js? (or (= ns 'js) (= ns 'Math) (:foreign info)) ;; foreign - i.e. global / Node.js library
|
|
1503
|
-
goog? (when ns
|
|
1504
|
-
(or (= ns 'goog)
|
|
1505
|
-
(when-let [ns-str (str ns)]
|
|
1506
|
-
(= (get (string/split ns-str #"\.") 0 nil) "goog"))
|
|
1507
|
-
(not (contains? (::ana/namespaces @env/*compiler*) ns))))
|
|
1508
|
-
|
|
1509
|
-
keyword? (or (= 'cljs.core/Keyword ftag)
|
|
1510
|
-
(let [f (ana/unwrap-quote f)]
|
|
1511
|
-
(and (= (-> f :op) :const)
|
|
1512
|
-
(keyword? (-> f :form)))))
|
|
1513
|
-
[f variadic-invoke]
|
|
1514
|
-
(if fn?
|
|
1515
|
-
(let [arity (count args)
|
|
1516
|
-
variadic? (:variadic? info)
|
|
1517
|
-
mps (:method-params info)
|
|
1518
|
-
mfa (:max-fixed-arity info)]
|
|
1519
|
-
(cond
|
|
1520
|
-
;; if only one method, no renaming needed
|
|
1521
|
-
(and (not variadic?)
|
|
1522
|
-
(= (count mps) 1))
|
|
1523
|
-
[f nil]
|
|
1524
|
-
|
|
1525
|
-
;; direct dispatch to variadic case
|
|
1526
|
-
(and variadic? (> arity mfa))
|
|
1527
|
-
[(update-in f [:info]
|
|
1528
|
-
(fn [info]
|
|
1529
|
-
(-> info
|
|
1530
|
-
(assoc :name (symbol (str (munge info) ".cljs$core$IFn$_invoke$arity$variadic")))
|
|
1531
|
-
;; bypass local fn-self-name munging, we're emitting direct
|
|
1532
|
-
;; shadowing already applied
|
|
1533
|
-
(update-in [:info]
|
|
1534
|
-
#(-> % (dissoc :shadow) (dissoc :fn-self-name))))))
|
|
1535
|
-
{:max-fixed-arity mfa}]
|
|
1536
|
-
|
|
1537
|
-
;; direct dispatch to specific arity case
|
|
1538
|
-
:else
|
|
1539
|
-
(let [arities (map count mps)]
|
|
1540
|
-
(if (some #{arity} arities)
|
|
1541
|
-
[(update-in f [:info]
|
|
1542
|
-
(fn [info]
|
|
1543
|
-
(-> info
|
|
1544
|
-
(assoc :name (symbol (str (munge info) ".cljs$core$IFn$_invoke$arity$" arity)))
|
|
1545
|
-
;; bypass local fn-self-name munging, we're emitting direct
|
|
1546
|
-
;; shadowing already applied
|
|
1547
|
-
(update-in [:info]
|
|
1548
|
-
#(-> % (dissoc :shadow) (dissoc :fn-self-name)))))) nil]
|
|
1549
|
-
[f nil]))))
|
|
1550
|
-
[f nil])]
|
|
1551
|
-
(emit-wrap env
|
|
1552
|
-
(cond
|
|
1553
|
-
opt-not?
|
|
1554
|
-
(emits "(!(" (first args) "))")
|
|
1555
|
-
|
|
1556
|
-
opt-count?
|
|
1557
|
-
(emits "((" (first args) ").length)")
|
|
1558
|
-
|
|
1559
|
-
proto?
|
|
1560
|
-
(let [pimpl (str (munge (protocol-prefix protocol))
|
|
1561
|
-
(munge (name (:name info))) "$arity$" (count args))]
|
|
1562
|
-
(emits (first args) "." pimpl "(" (comma-sep (cons "null" (rest args))) ")"))
|
|
1563
|
-
|
|
1564
|
-
keyword?
|
|
1565
|
-
(emits f ".cljs$core$IFn$_invoke$arity$" (count args) "(" (comma-sep args) ")")
|
|
1566
|
-
|
|
1567
|
-
variadic-invoke
|
|
1568
|
-
(let [mfa (:max-fixed-arity variadic-invoke)]
|
|
1569
|
-
(emits f "(" (comma-sep (take mfa args))
|
|
1570
|
-
(when-not (zero? mfa) ",")
|
|
1571
|
-
(cc "cljs.core.prim_seq.cljs$core$IFn$_invoke$arity$2([")
|
|
1572
|
-
(comma-sep (drop mfa args)) "], 0))"))
|
|
1573
|
-
|
|
1574
|
-
(or fn? js? goog?)
|
|
1575
|
-
(emits f "(" (comma-sep args) ")")
|
|
1576
|
-
|
|
1577
|
-
:else
|
|
1578
|
-
(if (and ana/*cljs-static-fns* (#{:var :local :js-var} (:op f)))
|
|
1579
|
-
;; higher order case, static information missing
|
|
1580
|
-
(let [fprop (str ".cljs$core$IFn$_invoke$arity$" (count args))]
|
|
1581
|
-
(if ana/*fn-invoke-direct*
|
|
1582
|
-
(emits "(" f fprop " ? " f fprop "(" (comma-sep args) ") : "
|
|
1583
|
-
f "(" (comma-sep args) "))")
|
|
1584
|
-
(emits "(" f fprop " ? " f fprop "(" (comma-sep args) ") : "
|
|
1585
|
-
f ".call(" (comma-sep (cons "null" args)) "))")))
|
|
1586
|
-
(emits f ".call(" (comma-sep (cons "null" args)) ")"))))))
|
|
1587
|
-
|
|
1588
|
-
(defmethod emit* :new
|
|
1589
|
-
[{ctor :class :keys [args env]}]
|
|
1590
|
-
(emit-wrap env
|
|
1591
|
-
(emits "(new " ctor "("
|
|
1592
|
-
(comma-sep args)
|
|
1593
|
-
"))")))
|
|
1594
|
-
|
|
1595
|
-
(defmethod emit* :qualified-method
|
|
1596
|
-
[{ctor :class :keys [args env kind name]}]
|
|
1597
|
-
(if (= :new kind)
|
|
1598
|
-
(emit-wrap env
|
|
1599
|
-
(emits "(function (...args) { return Reflect.construct(" ctor ", args) })"))
|
|
1600
|
-
(emit-wrap env
|
|
1601
|
-
(emits "(function (x, ...args) { return Reflect.apply(" ctor ".prototype." name ", x, args) })"))))
|
|
1602
|
-
|
|
1603
|
-
(defn- esm-foreign-var
|
|
1604
|
-
"If ast references a var of another namespace compiled to an ES module,
|
|
1605
|
-
returns [ns name]. Closure Library namespaces run by the compatibility
|
|
1606
|
-
layer are objects, set! assigns their properties; shims are modules."
|
|
1607
|
-
[{:keys [op info]}]
|
|
1608
|
-
(when (and *esm-emitting* (= :var op))
|
|
1609
|
-
(let [sym (:name info)
|
|
1610
|
-
ns (namespace sym)]
|
|
1611
|
-
(when (and ns
|
|
1612
|
-
(or *esm-repl* (not= ns (str ana/*cljs-ns*)))
|
|
1613
|
-
(not (string/includes? (name sym) "."))
|
|
1614
|
-
(or (not (or (= "goog" ns) (string/starts-with? ns "goog.")))
|
|
1615
|
-
#?(:clj (contains? (esm-goog-shim-exports ns ana/*cljs-ns*) (esm-var-name (name sym)))
|
|
1616
|
-
:cljs false))
|
|
1617
|
-
(esm-module-ns? ns))
|
|
1618
|
-
[ns (name sym)]))))
|
|
1619
|
-
|
|
1620
|
-
(defmethod emit* :set!
|
|
1621
|
-
[{:keys [target val env]}]
|
|
1622
|
-
;; Imported ES module bindings are read-only, set! goes through a setter
|
|
1623
|
-
;; exported by the module owning the var.
|
|
1624
|
-
(if-let [[ns nm] (esm-foreign-var target)]
|
|
1625
|
-
(let [export (esm-var-name nm)]
|
|
1626
|
-
(swap! (:refs *esm*) conj ns)
|
|
1627
|
-
(emit-wrap env
|
|
1628
|
-
(if (:dynamic (:info target))
|
|
1629
|
-
(emits (esm-ns-alias ns) ".$set$" export "(" val ")")
|
|
1630
|
-
(emits (esm-ns-alias ns) ".$$set(\"" export "\", " val ")"))))
|
|
1631
|
-
(emit-wrap env (emits "(" target " = " val ")"))))
|
|
1632
|
-
|
|
1633
|
-
(defn sublib-select
|
|
1634
|
-
[sublib]
|
|
1635
|
-
(when sublib
|
|
1636
|
-
(let [xs (string/split sublib #"\.")]
|
|
1637
|
-
(apply str
|
|
1638
|
-
(map #(str "['" % "']") xs)))))
|
|
1639
|
-
|
|
1640
|
-
(defn emit-global-export [ns-name global-exports lib opts]
|
|
1641
|
-
(let [[lib' sublib] (ana/lib&sublib lib)
|
|
1642
|
-
ref (str "goog.global"
|
|
1643
|
-
;; Convert object dot access to bracket access
|
|
1644
|
-
(->> (string/split (name (or (get global-exports (symbol lib'))
|
|
1645
|
-
(get global-exports (name lib'))))
|
|
1646
|
-
#"\.")
|
|
1647
|
-
(map (fn [prop] (str "[\"" prop "\"]")))
|
|
1648
|
-
(apply str)))]
|
|
1649
|
-
(when (and (ana/external-dep? lib')
|
|
1650
|
-
(= :none (:optimizations opts)))
|
|
1651
|
-
(emitln
|
|
1652
|
-
"if(!" ref ") throw new Error(\"External library, " lib' ", never provided\");"))
|
|
1653
|
-
(emitln
|
|
1654
|
-
(munge ns-name) "."
|
|
1655
|
-
(ana/munge-global-export lib)
|
|
1656
|
-
" = "
|
|
1657
|
-
ref
|
|
1658
|
-
(sublib-select sublib)
|
|
1659
|
-
";")))
|
|
1660
|
-
|
|
1661
|
-
(defn load-libs
|
|
1662
|
-
[libs seen reloads deps ns-name]
|
|
1663
|
-
(let [{:keys [options js-dependency-index]} @env/*compiler*
|
|
1664
|
-
{:keys [target nodejs-rt optimizations]} options
|
|
1665
|
-
loaded-libs (munge 'cljs.core.*loaded-libs*)
|
|
1666
|
-
loaded-libs-temp (munge (gensym 'cljs.core.*loaded-libs*))
|
|
1667
|
-
[node-libs libs-to-load] (let [libs (remove (set (vals seen)) (filter (set (vals libs)) deps))]
|
|
1668
|
-
(if (= :nodejs target)
|
|
1669
|
-
(let [{node-libs true libs-to-load false} (group-by ana/node-module-dep? libs)]
|
|
1670
|
-
[node-libs libs-to-load])
|
|
1671
|
-
[nil libs]))
|
|
1672
|
-
[goog-modules libs-to-load] (let [{goog-modules true libs-to-load false}
|
|
1673
|
-
(group-by ana/goog-module-dep? libs-to-load)]
|
|
1674
|
-
[goog-modules libs-to-load])
|
|
1675
|
-
global-exports-libs (filter ana/dep-has-global-exports? libs-to-load)]
|
|
1676
|
-
(when (-> libs meta :reload-all)
|
|
1677
|
-
(emitln "if(!COMPILED) " loaded-libs-temp " = " loaded-libs " || cljs.core.set([\"cljs.core\"]);")
|
|
1678
|
-
(emitln "if(!COMPILED) " loaded-libs " = cljs.core.set([\"cljs.core\"]);"))
|
|
1679
|
-
(doseq [lib libs-to-load]
|
|
1680
|
-
(cond
|
|
1681
|
-
#?@(:clj
|
|
1682
|
-
[(ana/foreign-dep? lib)
|
|
1683
|
-
;; we only load foreign libraries under optimizations :none
|
|
1684
|
-
;; under :modules we also elide loads, as the module loader will
|
|
1685
|
-
;; have handled it - David
|
|
1686
|
-
(when (and (= :none optimizations)
|
|
1687
|
-
(not (contains? options :modules)))
|
|
1688
|
-
(let [[lib _] (ana/lib&sublib lib)]
|
|
1689
|
-
(if nodejs-rt
|
|
1690
|
-
;; under node.js we load foreign libs globally
|
|
1691
|
-
(let [ijs (get js-dependency-index (name lib))]
|
|
1692
|
-
(emitln "cljs.core.load_file("
|
|
1693
|
-
(-> (io/file (util/output-directory options)
|
|
1694
|
-
(or (deps/-relative-path ijs)
|
|
1695
|
-
(util/relative-name (:url ijs))))
|
|
1696
|
-
str
|
|
1697
|
-
escape-string
|
|
1698
|
-
wrap-in-double-quotes)
|
|
1699
|
-
");"))
|
|
1700
|
-
(if-not (ana/external-dep? lib)
|
|
1701
|
-
(emitln "goog.require('" (munge lib) "');")
|
|
1702
|
-
;; TODO: validate the lib exists
|
|
1703
|
-
))))]
|
|
1704
|
-
:cljs
|
|
1705
|
-
[(and (ana/foreign-dep? lib)
|
|
1706
|
-
(not (keyword-identical? optimizations :none)))
|
|
1707
|
-
nil])
|
|
1708
|
-
|
|
1709
|
-
(or (-> libs meta :reload)
|
|
1710
|
-
(= (get reloads lib) :reload))
|
|
1711
|
-
(emitln "goog.require('" (munge lib) "', 'reload');")
|
|
1712
|
-
|
|
1713
|
-
(or (-> libs meta :reload-all)
|
|
1714
|
-
(= (get reloads lib) :reload-all))
|
|
1715
|
-
(emitln "goog.require('" (munge lib) "', 'reload-all');")
|
|
1716
|
-
|
|
1717
|
-
:else
|
|
1718
|
-
(when-not (= lib 'goog)
|
|
1719
|
-
(emitln "goog.require('" (munge lib) "');"))))
|
|
1720
|
-
;; Node Libraries
|
|
1721
|
-
(doseq [lib node-libs]
|
|
1722
|
-
(let [[lib' sublib] (ana/lib&sublib lib)]
|
|
1723
|
-
(emitln (munge ns-name) "."
|
|
1724
|
-
(ana/munge-node-lib lib)
|
|
1725
|
-
" = require('" lib' "')" (sublib-select sublib) ";")))
|
|
1726
|
-
;; Google Closure Library Modules (i.e. goog.module(...))
|
|
1727
|
-
;; these must be assigned to vars
|
|
1728
|
-
(doseq [lib goog-modules]
|
|
1729
|
-
(let [[lib' sublib] (ana/lib&sublib lib)]
|
|
1730
|
-
(emitln "goog.require('" lib' "');")
|
|
1731
|
-
;; we emit goog.scope here to suppress a Closure error about
|
|
1732
|
-
;; goog.module.get when compiling - meant to discourage incorrect
|
|
1733
|
-
;; usage by hand written code - not applicable here
|
|
1734
|
-
(emitln "goog.scope(function(){")
|
|
1735
|
-
(emitln (munge ns-name) "."
|
|
1736
|
-
(ana/munge-goog-module-lib lib)
|
|
1737
|
-
" = goog.module.get('" lib' "')" (sublib-select sublib) ";")
|
|
1738
|
-
(emitln "});")))
|
|
1739
|
-
;; Global Exports
|
|
1740
|
-
(doseq [lib global-exports-libs]
|
|
1741
|
-
(let [{:keys [global-exports]} (get js-dependency-index (name (-> lib ana/lib&sublib first)))]
|
|
1742
|
-
(emit-global-export ns-name global-exports lib options)))
|
|
1743
|
-
(when (-> libs meta :reload-all)
|
|
1744
|
-
(emitln "if(!COMPILED) " loaded-libs " = cljs.core.into(" loaded-libs-temp ", " loaded-libs ");"))))
|
|
1745
|
-
|
|
1746
|
-
#?(:clj
|
|
1747
|
-
(def esm-goog-shim-exports
|
|
1748
|
-
"The names exported by the hand written ES module shim of a Closure
|
|
1749
|
-
Library namespace, nil if there's none. Shims implement what cljs.core and
|
|
1750
|
-
the standard library use."
|
|
1751
|
-
(let [exports
|
|
1752
|
-
(memoize
|
|
1753
|
-
(fn [ns]
|
|
1754
|
-
(when-let [res (io/resource (str "cljs/esm/" (util/ns->relpath ns :js)))]
|
|
1755
|
-
(let [src (slurp res)
|
|
1756
|
-
decl #"export\s+(/\*\s*stub\s*\*/\s*)?(?:async\s+)?(?:function\*?|class|const|let|var)\s+([\w$]+)"]
|
|
1757
|
-
{:all (into #{}
|
|
1758
|
-
(concat
|
|
1759
|
-
(map #(nth % 2) (re-seq decl src))
|
|
1760
|
-
(mapcat (fn [[_ names]]
|
|
1761
|
-
(map #(string/trim (last (string/split % #"\s+as\s+")))
|
|
1762
|
-
(string/split names #",")))
|
|
1763
|
-
(re-seq #"export\s*\{([^}]*)\}" src))))
|
|
1764
|
-
;; export /* stub */ ..., only good enough for cljs.core
|
|
1765
|
-
:stubs (into #{} (keep (fn [[_ stub? name]] (when stub? name))) (re-seq decl src))}))))]
|
|
1766
|
-
(fn
|
|
1767
|
-
([ns] (:all (exports ns)))
|
|
1768
|
-
([ns from-ns]
|
|
1769
|
-
(when-let [{:keys [all stubs]} (exports ns)]
|
|
1770
|
-
(if (= 'cljs.core from-ns) all (reduce disj all stubs))))))))
|
|
1771
|
-
|
|
1772
|
-
#?(:clj
|
|
1773
|
-
(defn esm-goog-lib-path
|
|
1774
|
-
"The output path of the module exporting a Closure Library namespace run
|
|
1775
|
-
by the compatibility layer, see cljs.esm/install-goog-libs."
|
|
1776
|
-
[ns]
|
|
1777
|
-
(str "goog-lib/ns/" ns ".js")))
|
|
1778
|
-
|
|
1779
|
-
#?(:clj
|
|
1780
|
-
(defn- esm-path
|
|
1781
|
-
"Import path of path (relative to the output directory) from namespace
|
|
1782
|
-
from."
|
|
1783
|
-
[from path]
|
|
1784
|
-
(let [from-dir (.getParentFile (io/file (util/ns->relpath from :js)))
|
|
1785
|
-
rel (if from-dir
|
|
1786
|
-
(str (.relativize (.toPath from-dir) (.toPath (io/file path))))
|
|
1787
|
-
path)
|
|
1788
|
-
rel (string/replace rel File/separator "/")]
|
|
1789
|
-
(if (string/starts-with? rel ".")
|
|
1790
|
-
rel
|
|
1791
|
-
(str "./" rel)))))
|
|
1792
|
-
|
|
1793
|
-
#?(:clj
|
|
1794
|
-
(defn- esm-goog-lib!
|
|
1795
|
-
"Records a Closure Library namespace used without a shim, returns the
|
|
1796
|
-
import path of its module. Recorded in the analysis of namespace ns-name,
|
|
1797
|
-
which the analysis cache keeps: a build compiling none of its users still
|
|
1798
|
-
writes its module."
|
|
1799
|
-
[ns-name ns]
|
|
1800
|
-
(when-not (deps/closure-lib (:js-dependency-index @env/*compiler*) ns)
|
|
1801
|
-
(ana/warning :esm-unsupported-goog-ns (ana/empty-env) {:ns ns}))
|
|
1802
|
-
(swap! env/*compiler* update-in [::ana/namespaces ns-name :cljs.esm/goog-libs]
|
|
1803
|
-
(fnil conj #{}) (str ns))
|
|
1804
|
-
(esm-path ns-name (esm-goog-lib-path ns))))
|
|
1805
|
-
|
|
1806
|
-
#?(:clj
|
|
1807
|
-
(defn esm-ns-path
|
|
1808
|
-
"Returns the import path of namespace to relative to namespace from."
|
|
1809
|
-
[from to]
|
|
1810
|
-
(esm-path from (util/ns->relpath to :js))))
|
|
1811
|
-
|
|
1812
|
-
#?(:clj
|
|
1813
|
-
(defn- esm-import-specifier
|
|
1814
|
-
"Returns the import specifier of a JavaScript library. Package names are
|
|
1815
|
-
left as is for the bundler to resolve, paths relative to the source file
|
|
1816
|
-
are made relative to the output file."
|
|
1817
|
-
[lib]
|
|
1818
|
-
(let [lib (str lib)
|
|
1819
|
-
{:keys [^File src ^File dest]} *esm*
|
|
1820
|
-
;; canonical paths, the output or source directory may be a symlink
|
|
1821
|
-
canonical (fn ^java.nio.file.Path [^File f] (.toPath (.getCanonicalFile f)))
|
|
1822
|
-
relative (fn [^java.nio.file.Path target]
|
|
1823
|
-
(let [^java.nio.file.Path target (canonical (.toFile target))
|
|
1824
|
-
^java.nio.file.Path from (.getParent ^java.nio.file.Path (canonical dest))
|
|
1825
|
-
rel (str (.relativize from target))
|
|
1826
|
-
rel (string/replace rel File/separator "/")]
|
|
1827
|
-
(if (string/starts-with? rel ".")
|
|
1828
|
-
rel
|
|
1829
|
-
(str "./" rel))))]
|
|
1830
|
-
(cond
|
|
1831
|
-
(and (or (string/starts-with? lib "./") (string/starts-with? lib "../"))
|
|
1832
|
-
src dest)
|
|
1833
|
-
(relative (.normalize (.resolve (.getParent (.toAbsolutePath (.toPath src))) lib)))
|
|
1834
|
-
|
|
1835
|
-
;; classpath relative, i.e. "/my/lib.js"
|
|
1836
|
-
(and (string/starts-with? lib "/") dest)
|
|
1837
|
-
(let [path (subs lib 1)
|
|
1838
|
-
path (if (re-find #"\.[cm]?[jt]sx?$" path) path (str path ".js"))
|
|
1839
|
-
res (io/resource path)]
|
|
1840
|
-
(cond
|
|
1841
|
-
(nil? res)
|
|
1842
|
-
(throw (ex-info (str "Classpath JavaScript file " lib " not found")
|
|
1843
|
-
{:lib lib :clojure.error/phase :compilation}))
|
|
1844
|
-
|
|
1845
|
-
(= "file" (.getProtocol ^java.net.URL res))
|
|
1846
|
-
(relative (.toAbsolutePath (.toPath (io/file res))))
|
|
1847
|
-
|
|
1848
|
-
;; in a jar, copied to the output directory
|
|
1849
|
-
:else
|
|
1850
|
-
(let [out (io/file (util/output-directory (:options @env/*compiler*)) path)]
|
|
1851
|
-
(util/mkdirs out)
|
|
1852
|
-
(with-open [in (io/input-stream res)]
|
|
1853
|
-
(io/copy in out))
|
|
1854
|
-
(relative (.toAbsolutePath (.toPath out))))))
|
|
1855
|
-
|
|
1856
|
-
:else lib))))
|
|
1857
|
-
|
|
1858
|
-
#?(:clj
|
|
1859
|
-
(defn- emit-esm-import [ns-name dep]
|
|
1860
|
-
(let [dep-str (str dep)]
|
|
1861
|
-
(cond
|
|
1862
|
-
(ana/node-module-dep? dep)
|
|
1863
|
-
(let [[lib sublib] (ana/lib&sublib dep)
|
|
1864
|
-
alias (str (munge (symbol (str ns-name) (ana/munge-node-lib dep))))
|
|
1865
|
-
spec (esm-import-specifier lib)]
|
|
1866
|
-
;; REPL forms reach the binding through the namespace's
|
|
1867
|
-
;; registration, see emit-esm-repl-footer
|
|
1868
|
-
(some-> (:libs *esm*) (swap! assoc (esm-var-name (ana/munge-node-lib dep)) alias))
|
|
1869
|
-
(cond
|
|
1870
|
-
;; like shadow-cljs, :as binds CommonJS modules' module.exports and
|
|
1871
|
-
;; ES modules' namespace, decided by the bundler plugin
|
|
1872
|
-
(and (nil? sublib) (= :shadow (:npm-interop (:options @env/*compiler*))))
|
|
1873
|
-
(emitln "import " alias " from \"cljs-npm-as:" spec "\";")
|
|
1874
|
-
|
|
1875
|
-
(nil? sublib)
|
|
1876
|
-
(emitln "import * as " alias " from \"" spec "\";")
|
|
1877
|
-
|
|
1878
|
-
(= "default" sublib)
|
|
1879
|
-
(emitln "import " alias " from \"" spec "\";")
|
|
1880
|
-
|
|
1881
|
-
:else
|
|
1882
|
-
(do
|
|
1883
|
-
(emitln "import * as " alias "$module from \"" spec "\";")
|
|
1884
|
-
(emitln "const " alias " = " alias "$module" (sublib-select sublib) ";"))))
|
|
1885
|
-
|
|
1886
|
-
;; Closure Library shims are imported when referenced, Closure
|
|
1887
|
-
;; Library namespaces without one are loaded for their side effects
|
|
1888
|
-
(or (= "goog" dep-str) (string/starts-with? dep-str "goog."))
|
|
1889
|
-
(when-not (or (= "goog" dep-str) (esm-goog-shim-exports dep-str))
|
|
1890
|
-
(emitln "import \"" (esm-goog-lib! ns-name dep-str) "\";"))
|
|
1891
|
-
|
|
1892
|
-
;; Closure style libraries on the classpath, run by the Closure
|
|
1893
|
-
;; Library compatibility layer, i.e. transit-js
|
|
1894
|
-
(and (not (contains? (::ana/namespaces @env/*compiler*) (symbol dep-str)))
|
|
1895
|
-
(deps/closure-lib (:js-dependency-index @env/*compiler*) dep-str))
|
|
1896
|
-
(emitln "import \"" (esm-goog-lib! ns-name dep-str) "\";")
|
|
1897
|
-
|
|
1898
|
-
(contains? (::ana/namespaces @env/*compiler*) (symbol dep-str))
|
|
1899
|
-
(when-not (contains? @(:imported *esm*) dep-str)
|
|
1900
|
-
(swap! (:imported *esm*) conj dep-str)
|
|
1901
|
-
(emitln "import * as " (esm-ns-alias dep-str) " from \"" (esm-ns-path ns-name dep-str) "\";"))
|
|
1902
|
-
|
|
1903
|
-
:else
|
|
1904
|
-
(throw
|
|
1905
|
-
(ex-info (str "Unsupported dependency " dep-str " for ES module output")
|
|
1906
|
-
{:ns ns-name :dep dep :clojure.error/phase :compilation}))))))
|
|
1907
|
-
|
|
1908
|
-
#?(:clj
|
|
1909
|
-
(defn- emit-esm-preloads
|
|
1910
|
-
"Main namespaces import the :preloads first, ES modules evaluate their
|
|
1911
|
-
imports in order."
|
|
1912
|
-
[ns-name]
|
|
1913
|
-
(let [{:keys [main preloads esm-repl]} (:options @env/*compiler*)
|
|
1914
|
-
mains (set (map symbol (cond (coll? main) main main [main])))]
|
|
1915
|
-
(when (and (contains? mains ns-name)
|
|
1916
|
-
(not (some #{ns-name} (map symbol preloads))))
|
|
1917
|
-
(doseq [preload (cond->> preloads esm-repl (cons esm-repl-runtime))]
|
|
1918
|
-
(emitln "import \"" (esm-ns-path ns-name preload) "\";"))))))
|
|
1919
|
-
|
|
1920
|
-
#?(:clj (declare emit-esm-ns-import))
|
|
1921
|
-
|
|
1922
|
-
#?(:clj
|
|
1923
|
-
(defn- emit-esm-imports [ns-name deps]
|
|
1924
|
-
(emit-esm-preloads ns-name)
|
|
1925
|
-
(when-not (= 'cljs.core ns-name)
|
|
1926
|
-
(emit-esm-import ns-name 'cljs.core)
|
|
1927
|
-
(when (-> @env/*compiler* :options :emit-constants)
|
|
1928
|
-
(emit-esm-ns-import ns-name ana/constants-ns-sym)))
|
|
1929
|
-
(doseq [dep deps]
|
|
1930
|
-
(emit-esm-import ns-name dep))))
|
|
1931
|
-
|
|
1932
|
-
#?(:clj
|
|
1933
|
-
(defn- emit-esm-ns-import
|
|
1934
|
-
"Emits the import of a namespace referenced by ns-name."
|
|
1935
|
-
[ns-name ns]
|
|
1936
|
-
(emitln "import * as " (esm-ns-alias ns) " from \"" (esm-ns-path ns-name ns) "\";")))
|
|
1937
|
-
|
|
1938
|
-
#?(:clj
|
|
1939
|
-
(defn emit-esm-hmr-header
|
|
1940
|
-
"Under :esm-hmr, a reloaded module first restores the values of the
|
|
1941
|
-
instance it replaces, so that defonce keeps its value."
|
|
1942
|
-
[]
|
|
1943
|
-
(emitln "if (import.meta.hot && import.meta.hot.data.$$vals) { "
|
|
1944
|
-
"const vals = import.meta.hot.data.$$vals; "
|
|
1945
|
-
"for (const k in vals) { try { $$set(k, vals[k]); } catch (e) {} } }")))
|
|
1946
|
-
|
|
1947
|
-
#?(:clj
|
|
1948
|
-
(defn- emit-esm-hmr-footer
|
|
1949
|
-
"Under :esm-hmr modules accept their own updates. Importers keep the
|
|
1950
|
-
bindings of the module instance they imported, the new instance updates
|
|
1951
|
-
the bindings of all previous ones through their $$set. Runs
|
|
1952
|
-
^:dev/before-load and ^:dev/after-load hooks around updates."
|
|
1953
|
-
[ns-name exports]
|
|
1954
|
-
(let [opts (:options @env/*compiler*)
|
|
1955
|
-
;; ^:dev/before-load / ^:dev/after-load fns, and fns of this
|
|
1956
|
-
;; namespace given as :esm-before-load / :esm-after-load
|
|
1957
|
-
hooks (fn [k]
|
|
1958
|
-
(->> (concat
|
|
1959
|
-
(->> (get-in @env/*compiler* [::ana/namespaces ns-name :defs])
|
|
1960
|
-
(filter (fn [[_ v]] (get-in v [:meta k])))
|
|
1961
|
-
(map (fn [[sym _]] (symbol (str ns-name) (str sym)))))
|
|
1962
|
-
(->> (get opts ({:dev/before-load :esm-before-load
|
|
1963
|
-
:dev/after-load :esm-after-load} k))
|
|
1964
|
-
(filter #(= (str ns-name) (namespace %)))))
|
|
1965
|
-
distinct
|
|
1966
|
-
(map #(str (munge %)))
|
|
1967
|
-
sort))
|
|
1968
|
-
vals (str "{" (string/join ", " (map (fn [[export local]] (str "\"" export "\": " local)) exports)) "}")]
|
|
1969
|
-
(emitln "if (import.meta.hot) {")
|
|
1970
|
-
(emitln "const data = import.meta.hot.data;")
|
|
1971
|
-
(emitln "const vals = " vals ";")
|
|
1972
|
-
(emitln "for (const set of (data.$$sets || [])) for (const k in vals) { try { set(k, vals[k]); } catch (e) {} }")
|
|
1973
|
-
(emitln "(data.$$sets || (data.$$sets = [])).push($$set);")
|
|
1974
|
-
(emitln "import.meta.hot.dispose((data) => { data.$$vals = " vals "; });")
|
|
1975
|
-
(doseq [[k hook event] [[:dev/before-load "before_load" "vite:beforeUpdate"]
|
|
1976
|
-
[:dev/after-load "after_load" "vite:afterUpdate"]]]
|
|
1977
|
-
(when-let [fns (seq (hooks k))]
|
|
1978
|
-
(emitln "data.$$" hook " = () => { " (string/join " " (map #(str % "();") fns)) " };")
|
|
1979
|
-
(emitln "if (!data.$$" hook "_on) { data.$$" hook "_on = true; "
|
|
1980
|
-
"import.meta.hot.on(\"" event "\", () => data.$$" hook "()); }")))
|
|
1981
|
-
(if (= 'cljs.core ns-name)
|
|
1982
|
-
;; values of a previous cljs.core aren't compatible with a new one
|
|
1983
|
-
(emitln "import.meta.hot.accept(() => { if (typeof location !== \"undefined\") location.reload(); });")
|
|
1984
|
-
(emitln "import.meta.hot.accept();"))
|
|
1985
|
-
(emitln "}"))))
|
|
1986
|
-
|
|
1987
|
-
#?(:clj (def ^:private esm-repl-stamps (java.util.concurrent.atomic.AtomicLong.)))
|
|
1988
|
-
|
|
1989
|
-
#?(:clj
|
|
1990
|
-
(defn- emit-esm-repl-footer
|
|
1991
|
-
"Under :esm-repl modules register their namespace object, the setters
|
|
1992
|
-
of all their instances (see emit-esm-hmr-footer) and the npm modules
|
|
1993
|
-
they import, for the forms evaluated at the REPL, see
|
|
1994
|
-
cljs.esm.repl-runtime. gen counts the instances, it changes once a
|
|
1995
|
-
hot reload ran the module again. stamp identifies the compile, also
|
|
1996
|
-
recorded as :cljs.esm/repl-stamp of the namespace's analysis (which the
|
|
1997
|
-
analysis cache keeps): the REPL waits for a page to run the module of a
|
|
1998
|
-
compile."
|
|
1999
|
-
[ns-name libs]
|
|
2000
|
-
(let [ns (pr-str (str ns-name))
|
|
2001
|
-
stamp (str (System/currentTimeMillis) "-" (.incrementAndGet ^java.util.concurrent.atomic.AtomicLong esm-repl-stamps))]
|
|
2002
|
-
(swap! env/*compiler* assoc-in [::ana/namespaces ns-name :cljs.esm/repl-stamp] stamp)
|
|
2003
|
-
(emitln "{ const $$r = globalThis.$CLJS_ESM || (globalThis.$CLJS_ESM = { nses: new Map() }), $$e = $$r.nses.get(" ns ");")
|
|
2004
|
-
(emitln "$$r.nses.set(" ns ", { mod: " (esm-ns-alias ns-name) ", "
|
|
2005
|
-
"sets: import.meta.hot ? import.meta.hot.data.$$sets : [$$set], "
|
|
2006
|
-
"libs: {" (string/join ", " (map (fn [[k v]] (str "\"" k "\": " v)) (sort libs))) "}, "
|
|
2007
|
-
"gen: $$e ? $$e.gen + 1 : 1, stamp: \"" stamp "\" });")
|
|
2008
|
-
(emitln "if ($$r.registered) $$r.registered(" ns "); }"))))
|
|
2009
|
-
|
|
2010
|
-
#?(:clj
|
|
2011
|
-
(defn- dts-param
|
|
2012
|
-
"A TypeScript parameter name for a ClojureScript param, destructuring
|
|
2013
|
-
forms and gensyms become argN."
|
|
2014
|
-
[param i]
|
|
2015
|
-
(let [n (when (symbol? param) (str (munge param)))]
|
|
2016
|
-
(if (and n
|
|
2017
|
-
(re-matches #"[A-Za-z_][\w]*" n)
|
|
2018
|
-
(not (string/starts-with? n "p__"))
|
|
2019
|
-
(not= "_" n))
|
|
2020
|
-
n
|
|
2021
|
-
(str "arg" i)))))
|
|
2022
|
-
|
|
2023
|
-
#?(:clj
|
|
2024
|
-
(defn esm-dts
|
|
2025
|
-
"TypeScript declarations of the exports of namespace ns-name, so that
|
|
2026
|
-
TypeScript code can import ClojureScript modules."
|
|
2027
|
-
[ns-name export-syms]
|
|
2028
|
-
(let [defs (get-in @env/*compiler* [::ana/namespaces ns-name :defs])
|
|
2029
|
-
doc (fn [{:keys [doc]}]
|
|
2030
|
-
(when (and (string? doc) (not (string/blank? doc)))
|
|
2031
|
-
(str "/**\n"
|
|
2032
|
-
(apply str (map #(str " * " (string/replace % "*/" "* /") "\n")
|
|
2033
|
-
(string/split-lines doc)))
|
|
2034
|
-
" */\n")))]
|
|
2035
|
-
(apply str
|
|
2036
|
-
"// TypeScript declarations of ClojureScript namespace " ns-name "\n"
|
|
2037
|
-
(for [[export sym] (sort export-syms)
|
|
2038
|
-
:let [info (get defs (symbol (name sym)))]]
|
|
2039
|
-
(str (doc info)
|
|
2040
|
-
(if (and (:fn-var info) (seq (:method-params info)))
|
|
2041
|
-
(apply str
|
|
2042
|
-
(for [params (:method-params info)
|
|
2043
|
-
:let [variadic? (and (:variadic? info)
|
|
2044
|
-
(> (count params) (or (:max-fixed-arity info) 0)))
|
|
2045
|
-
fixed (if variadic? (butlast params) params)]]
|
|
2046
|
-
(str "export declare function " export "("
|
|
2047
|
-
(string/join ", "
|
|
2048
|
-
(concat
|
|
2049
|
-
(map-indexed (fn [i p] (str (dts-param p i) ": any")) fixed)
|
|
2050
|
-
(when variadic? ["...rest: any[]"])))
|
|
2051
|
-
"): any;\n")))
|
|
2052
|
-
(str "export declare const " export ": any;\n"))))))))
|
|
2053
|
-
|
|
2054
|
-
#?(:clj
|
|
2055
|
-
(defn emit-esm-footer
|
|
2056
|
-
"Emits the imports of namespaces only referenced by fully qualified
|
|
2057
|
-
names, the declarations of vars only defined in functions, setters and
|
|
2058
|
-
exports."
|
|
2059
|
-
[ns-name]
|
|
2060
|
-
(let [{:keys [refs imported hoist exports dynamic self-import goog-lib-refs libs]} *esm*
|
|
2061
|
-
exports (sort @exports)
|
|
2062
|
-
repl? (:esm-repl (:options @env/*compiler*))]
|
|
2063
|
-
(when repl?
|
|
2064
|
-
(reset! self-import true))
|
|
2065
|
-
(emitln)
|
|
2066
|
-
;; Closure Library namespaces run by the compatibility layer, default
|
|
2067
|
-
;; exports are the namespace objects
|
|
2068
|
-
(doseq [ns (sort @goog-lib-refs)]
|
|
2069
|
-
(emitln "import " (esm-ns-alias ns) "$ from \"" (esm-goog-lib! ns-name ns) "\";"))
|
|
2070
|
-
(when @self-import
|
|
2071
|
-
(emitln "import * as " (esm-ns-alias ns-name) " from \"./"
|
|
2072
|
-
(.getName (io/file (util/ns->relpath ns-name :js))) "\";"))
|
|
2073
|
-
(doseq [ns (sort (remove (conj @imported (str ns-name)) @refs))]
|
|
2074
|
-
(emit-esm-ns-import ns-name ns))
|
|
2075
|
-
(when (seq @hoist)
|
|
2076
|
-
(emitln "var " (string/join ", " (sort @hoist)) ";"))
|
|
2077
|
-
;; imported bindings can't be assigned, set! of another namespace's var
|
|
2078
|
-
;; is emitted as a call of one of these
|
|
2079
|
-
(doseq [export (sort @dynamic)]
|
|
2080
|
-
(emitln "export function $set$" export "(v) { return ("
|
|
2081
|
-
(get (into {} exports) export) " = v); }"))
|
|
2082
|
-
(emitln "export function $$set(name, v) {")
|
|
2083
|
-
(emitln "switch (name) {")
|
|
2084
|
-
(doseq [[export local] exports]
|
|
2085
|
-
(emitln "case \"" export "\": return (" local " = v);"))
|
|
2086
|
-
(emitln "}")
|
|
2087
|
-
(emitln "throw new Error(\"No var " ns-name "/\" + name);")
|
|
2088
|
-
(emitln "}")
|
|
2089
|
-
(emitln "export { "
|
|
2090
|
-
(string/join ", " (map (fn [[export local]] (str local " as " export)) exports))
|
|
2091
|
-
" };")
|
|
2092
|
-
(when (:esm-hmr (:options @env/*compiler*))
|
|
2093
|
-
(emit-esm-hmr-footer ns-name exports))
|
|
2094
|
-
(when repl?
|
|
2095
|
-
(emit-esm-repl-footer ns-name (some-> libs deref))))))
|
|
2096
|
-
|
|
2097
|
-
#?(:clj
|
|
2098
|
-
(defn emit-esm-repl
|
|
2099
|
-
"Emits ast, a form analyzed for the REPL in :return context, as the body
|
|
2100
|
-
of a function, see *esm-repl*. Returns {:js :refs :goog-lib-refs}, refs
|
|
2101
|
-
the namespaces it references as esm-ns-alias, goog-lib-refs the Closure
|
|
2102
|
-
Library namespaces run by the compatibility layer as esm-ns-alias plus
|
|
2103
|
-
$: the function's parameters."
|
|
2104
|
-
[ast]
|
|
2105
|
-
(let [state {:refs (atom #{})
|
|
2106
|
-
:imported (atom #{})
|
|
2107
|
-
:hoist (atom #{})
|
|
2108
|
-
:exports (atom {})
|
|
2109
|
-
:dynamic (atom #{})
|
|
2110
|
-
:self-import (atom false)
|
|
2111
|
-
:goog-lib-refs (atom #{})
|
|
2112
|
-
:libs (atom {})
|
|
2113
|
-
:export-syms (atom {})}
|
|
2114
|
-
js (binding [*esm* state
|
|
2115
|
-
*esm-emitting* true
|
|
2116
|
-
*esm-repl* true]
|
|
2117
|
-
(emit-str ast))]
|
|
2118
|
-
{:js js
|
|
2119
|
-
:refs @(:refs state)
|
|
2120
|
-
:goog-lib-refs @(:goog-lib-refs state)})))
|
|
2121
|
-
|
|
2122
|
-
(defmethod emit* :ns*
|
|
2123
|
-
[{:keys [name requires uses require-macros reloads env deps]}]
|
|
2124
|
-
(cond
|
|
2125
|
-
;; cljs.esm.repl loads the namespaces
|
|
2126
|
-
*esm-repl*
|
|
2127
|
-
(emit-wrap env (emits "null"))
|
|
2128
|
-
|
|
2129
|
-
*esm-emitting*
|
|
2130
|
-
#?(:clj (emit-esm-imports ana/*cljs-ns* deps)
|
|
2131
|
-
:cljs nil)
|
|
2132
|
-
|
|
2133
|
-
:else
|
|
2134
|
-
(do
|
|
2135
|
-
(load-libs requires nil (:require reloads) deps name)
|
|
2136
|
-
(load-libs uses requires (:use reloads) deps name)))
|
|
2137
|
-
(when (:repl-env env)
|
|
2138
|
-
(emitln "'nil';")))
|
|
2139
|
-
|
|
2140
|
-
(defmethod emit* :ns
|
|
2141
|
-
[{:keys [name requires uses require-macros reloads env deps]}]
|
|
2142
|
-
(cond
|
|
2143
|
-
*esm-repl*
|
|
2144
|
-
(emit-wrap env (emits "null"))
|
|
2145
|
-
|
|
2146
|
-
*esm-emitting*
|
|
2147
|
-
#?(:clj (emit-esm-imports name deps)
|
|
2148
|
-
:cljs nil)
|
|
2149
|
-
|
|
2150
|
-
:else
|
|
2151
|
-
(do
|
|
2152
|
-
(emitln "goog.provide('" (munge name) "');")
|
|
2153
|
-
(when-not (= name 'cljs.core)
|
|
2154
|
-
(emitln "goog.require('cljs.core');")
|
|
2155
|
-
(when (-> @env/*compiler* :options :emit-constants)
|
|
2156
|
-
(emitln "goog.require('" (munge ana/constants-ns-sym) "');")))
|
|
2157
|
-
(load-libs requires nil (:require reloads) deps name)
|
|
2158
|
-
(load-libs uses requires (:use reloads) deps name))))
|
|
2159
|
-
|
|
2160
|
-
(defmethod emit* :deftype
|
|
2161
|
-
[{:keys [t fields pmasks body protocols]}]
|
|
2162
|
-
(let [fields (map munge fields)]
|
|
2163
|
-
(emitln "")
|
|
2164
|
-
(emitln "/**")
|
|
2165
|
-
(emitln "* @constructor")
|
|
2166
|
-
(doseq [protocol protocols]
|
|
2167
|
-
(emitln " * @implements {" (munge (str protocol)) "}"))
|
|
2168
|
-
(emitln "*/")
|
|
2169
|
-
(emit-esm-type-binding t)
|
|
2170
|
-
(emitln " = (function (" (comma-sep fields) "){")
|
|
2171
|
-
(doseq [fld fields]
|
|
2172
|
-
(emitln "this." fld " = " fld ";"))
|
|
2173
|
-
(doseq [[pno pmask] pmasks]
|
|
2174
|
-
(emitln "this.cljs$lang$protocol_mask$partition" pno "$ = " pmask ";"))
|
|
2175
|
-
(emitln "});")
|
|
2176
|
-
(emit body)))
|
|
2177
|
-
|
|
2178
|
-
(defmethod emit* :class
|
|
2179
|
-
[{:keys [env name base params body]}]
|
|
2180
|
-
(emit-wrap env
|
|
2181
|
-
(emits "(class " (munge name))
|
|
2182
|
-
(when base
|
|
2183
|
-
(emits " extends " base))
|
|
2184
|
-
(emitln " {")
|
|
2185
|
-
(when body
|
|
2186
|
-
(emitln "constructor(" (comma-sep (map munge params)) ") {")
|
|
2187
|
-
;; this is accessible once the base class' constructor returned
|
|
2188
|
-
(emitln (if base "var self__;" "var self__ = this;"))
|
|
2189
|
-
(emit body)
|
|
2190
|
-
(emitln "}"))
|
|
2191
|
-
(emits "})")))
|
|
2192
|
-
|
|
2193
|
-
(defmethod emit* :super
|
|
2194
|
-
[{:keys [env args]}]
|
|
2195
|
-
;; super() evaluates to this
|
|
2196
|
-
(emit-wrap env
|
|
2197
|
-
(emits "(self__ = super(" (comma-sep args) "))")))
|
|
2198
|
-
|
|
2199
|
-
(defmethod emit* :defrecord
|
|
2200
|
-
[{:keys [t fields pmasks body protocols]}]
|
|
2201
|
-
(let [fields (concat (map munge fields) '[__meta __extmap __hash])]
|
|
2202
|
-
(emitln "")
|
|
2203
|
-
(emitln "/**")
|
|
2204
|
-
(emitln "* @constructor")
|
|
2205
|
-
(doseq [protocol protocols]
|
|
2206
|
-
(emitln " * @implements {" (munge (str protocol)) "}"))
|
|
2207
|
-
(emitln "*/")
|
|
2208
|
-
(emit-esm-type-binding t)
|
|
2209
|
-
(emitln " = (function (" (comma-sep fields) "){")
|
|
2210
|
-
(doseq [fld fields]
|
|
2211
|
-
(emitln "this." fld " = " fld ";"))
|
|
2212
|
-
(doseq [[pno pmask] pmasks]
|
|
2213
|
-
(emitln "this.cljs$lang$protocol_mask$partition" pno "$ = " pmask ";"))
|
|
2214
|
-
(emitln "});")
|
|
2215
|
-
(emit body)))
|
|
2216
|
-
|
|
2217
|
-
(defn emit-dot
|
|
2218
|
-
[{:keys [target field method args env]}]
|
|
2219
|
-
(emit-wrap env
|
|
2220
|
-
(if field
|
|
2221
|
-
(emits target "." (munge field #{}))
|
|
2222
|
-
(emits target "." (munge method #{}) "("
|
|
2223
|
-
(comma-sep args)
|
|
2224
|
-
")"))))
|
|
2225
|
-
|
|
2226
|
-
(defmethod emit* :host-field [ast] (emit-dot ast))
|
|
2227
|
-
(defmethod emit* :host-call [ast] (emit-dot ast))
|
|
2228
|
-
|
|
2229
|
-
(defmethod emit* :js
|
|
2230
|
-
[{:keys [op env code segs args]}]
|
|
2231
|
-
(if (and code #?(:clj (.startsWith ^String (string/trim code) "/*")
|
|
2232
|
-
:cljs (gstring/startsWith (string/trim code) "/*")))
|
|
2233
|
-
(emits code)
|
|
2234
|
-
(emit-wrap env
|
|
2235
|
-
(if code
|
|
2236
|
-
(emits (esm-rewrite-core-refs code))
|
|
2237
|
-
(emits (interleave (concat (map esm-rewrite-core-refs segs) (repeat nil))
|
|
2238
|
-
(concat args [nil])))))))
|
|
2239
|
-
|
|
2240
|
-
;; TODO: unify renaming helpers - this one was hard to find - David
|
|
2241
|
-
|
|
2242
|
-
#?(:clj
|
|
2243
|
-
(defn rename-to-js
|
|
2244
|
-
"Change the file extension from .cljs to .js. Takes a File or a
|
|
2245
|
-
String. Always returns a String."
|
|
2246
|
-
[^String file-str]
|
|
2247
|
-
(cond
|
|
2248
|
-
(.endsWith file-str ".cljs")
|
|
2249
|
-
(clojure.string/replace file-str #"\.cljs$" ".js")
|
|
2250
|
-
|
|
2251
|
-
(.endsWith file-str ".cljc")
|
|
2252
|
-
(if (= "cljs/core.cljc" file-str)
|
|
2253
|
-
"cljs/core$macros.js"
|
|
2254
|
-
(clojure.string/replace file-str #"\.cljc$" ".js"))
|
|
2255
|
-
|
|
2256
|
-
:else
|
|
2257
|
-
(throw (util/compilation-error (IllegalArgumentException.
|
|
2258
|
-
(str "Invalid source file extension " file-str)))))))
|
|
2259
|
-
|
|
2260
|
-
#?(:clj
|
|
2261
|
-
(defn with-core-cljs
|
|
2262
|
-
"Ensure that core.cljs has been loaded."
|
|
2263
|
-
([] (with-core-cljs
|
|
2264
|
-
(when env/*compiler*
|
|
2265
|
-
(:options @env/*compiler*))))
|
|
2266
|
-
([opts] (with-core-cljs opts (fn [])))
|
|
2267
|
-
([opts body]
|
|
2268
|
-
{:pre [(or (nil? opts) (map? opts))
|
|
2269
|
-
(fn? body)]}
|
|
2270
|
-
(when-not (get-in @env/*compiler* [::ana/namespaces 'cljs.core :defs])
|
|
2271
|
-
(ana/analyze-file "cljs/core.cljs" opts))
|
|
2272
|
-
(body))))
|
|
2273
|
-
|
|
2274
|
-
#?(:clj
|
|
2275
|
-
(defn url-path [^File f]
|
|
2276
|
-
(.getPath (.toURL (.toURI f)))))
|
|
2277
|
-
|
|
2278
|
-
#?(:clj
|
|
2279
|
-
(defn compiled-by-string
|
|
2280
|
-
([]
|
|
2281
|
-
(compiled-by-string
|
|
2282
|
-
(when env/*compiler*
|
|
2283
|
-
(:options @env/*compiler*))))
|
|
2284
|
-
([opts]
|
|
2285
|
-
(str "// Compiled by ClojureScript "
|
|
2286
|
-
(util/clojurescript-version)
|
|
2287
|
-
(when opts
|
|
2288
|
-
(str " " (pr-str (ana/build-affecting-options opts))))))))
|
|
2289
|
-
|
|
2290
|
-
#?(:clj
|
|
2291
|
-
(defn cached-core [ns ext opts]
|
|
2292
|
-
(and (= :none (:optimizations opts))
|
|
2293
|
-
(not (esm-mode? opts))
|
|
2294
|
-
(not= "cljc" ext)
|
|
2295
|
-
(= 'cljs.core ns)
|
|
2296
|
-
(io/resource "cljs/core.aot.js"))))
|
|
2297
|
-
|
|
2298
|
-
#?(:clj
|
|
2299
|
-
(defn macro-ns? [ns ext opts]
|
|
2300
|
-
(or (= "clj" ext)
|
|
2301
|
-
(= 'cljs.core$macros ns)
|
|
2302
|
-
(and (= ns 'cljs.core) (= "cljc" ext))
|
|
2303
|
-
(:macros-ns opts))))
|
|
2304
|
-
|
|
2305
|
-
#?(:clj
|
|
2306
|
-
(defn emit-cached-core [src dest cached opts]
|
|
2307
|
-
;; no need to bother with analysis cache reading, handled by
|
|
2308
|
-
;; with-core-cljs
|
|
2309
|
-
(when (or ana/*verbose* (:verbose opts))
|
|
2310
|
-
(util/debug-prn "Using cached cljs.core" (str src)))
|
|
2311
|
-
(spit dest (slurp cached))
|
|
2312
|
-
(.setLastModified ^File dest (util/last-modified src))
|
|
2313
|
-
(when (true? (:source-map opts))
|
|
2314
|
-
(spit (io/file (str dest ".map"))
|
|
2315
|
-
(json/write-str
|
|
2316
|
-
(assoc
|
|
2317
|
-
(json/read-str (slurp (io/resource "cljs/core.aot.js.map")))
|
|
2318
|
-
"file"
|
|
2319
|
-
(str (io/file (util/output-directory opts) "cljs" "core.js"))))))
|
|
2320
|
-
(merge
|
|
2321
|
-
(ana/parse-ns src dest nil)
|
|
2322
|
-
{:out-file dest})))
|
|
2323
|
-
|
|
2324
|
-
#?(:clj
|
|
2325
|
-
(defn emit-source-map [src dest sm-data opts]
|
|
2326
|
-
(let [sm-file (io/file (str (.getPath ^File dest) ".map"))]
|
|
2327
|
-
(if-let [smap (:source-map-asset-path opts)]
|
|
2328
|
-
(emitln "\n//# sourceMappingURL=" smap
|
|
2329
|
-
(string/replace (util/path sm-file)
|
|
2330
|
-
(str (util/path (io/file (:output-dir opts))))
|
|
2331
|
-
"")
|
|
2332
|
-
(if (true? (:source-map-timestamp opts))
|
|
2333
|
-
(str
|
|
2334
|
-
(if-not (string/index-of smap "?") "?" "&")
|
|
2335
|
-
"rel=" (System/currentTimeMillis))
|
|
2336
|
-
""))
|
|
2337
|
-
(emitln "\n//# sourceMappingURL="
|
|
2338
|
-
(or (:source-map-url opts) (.getName sm-file))
|
|
2339
|
-
(if (true? (:source-map-timestamp opts))
|
|
2340
|
-
(str "?rel=" (System/currentTimeMillis))
|
|
2341
|
-
"")))
|
|
2342
|
-
(spit sm-file
|
|
2343
|
-
(sm/encode {(url-path src) (:source-map sm-data)}
|
|
2344
|
-
{:lines (+ (:gen-line sm-data) 2)
|
|
2345
|
-
:file (url-path dest)
|
|
2346
|
-
:source-map-path (:source-map-path opts)
|
|
2347
|
-
:source-map-timestamp (:source-map-timestamp opts)
|
|
2348
|
-
:source-map-pretty-print (:source-map-pretty-print opts)
|
|
2349
|
-
;; ES modules are bundled from the output directory, which
|
|
2350
|
-
;; doesn't have the sources (jar ones aren't files)
|
|
2351
|
-
:sources-content (when (esm-mode? opts) [(slurp src)])
|
|
2352
|
-
:relpaths {(util/path src)
|
|
2353
|
-
(util/ns->relpath (first (:provides opts)) (:ext opts))}})))))
|
|
2354
|
-
|
|
2355
|
-
#?(:clj
|
|
2356
|
-
(defn- emit-source* [src dest out-file ext opts]
|
|
2357
|
-
(with-open [out ^java.io.Writer (io/make-writer out-file {})]
|
|
2358
|
-
(binding [*out* out
|
|
2359
|
-
ana/*cljs-ns* 'cljs.user
|
|
2360
|
-
ana/*cljs-file* (.getPath ^File src)
|
|
2361
|
-
reader/*alias-map* (or (ana/get-bridged-alias-map) reader/*alias-map* {})
|
|
2362
|
-
ana/*checked-arrays* (or ana/*checked-arrays* (:checked-arrays opts))
|
|
2363
|
-
ana/*cljs-static-fns* (or ana/*cljs-static-fns* (:static-fns opts))
|
|
2364
|
-
*source-map-data* (when (:source-map opts)
|
|
2365
|
-
(atom
|
|
2366
|
-
{:source-map (sorted-map)
|
|
2367
|
-
:gen-line 0}))
|
|
2368
|
-
*source-map-data-gen-col* (AtomicLong.)
|
|
2369
|
-
find-ns-starts-with (memoize find-ns-starts-with)
|
|
2370
|
-
*esm* (when (esm-mode? opts)
|
|
2371
|
-
{:src src
|
|
2372
|
-
:dest dest
|
|
2373
|
-
:refs (atom #{})
|
|
2374
|
-
:imported (atom #{})
|
|
2375
|
-
:hoist (atom #{})
|
|
2376
|
-
:exports (atom {})
|
|
2377
|
-
:dynamic (atom #{})
|
|
2378
|
-
:self-import (atom false)
|
|
2379
|
-
:goog-lib-refs (atom #{})
|
|
2380
|
-
:libs (atom {})
|
|
2381
|
-
:export-syms (atom {})})]
|
|
2382
|
-
(emitln (compiled-by-string opts))
|
|
2383
|
-
(when (and *esm* (:esm-hmr opts))
|
|
2384
|
-
(emit-esm-hmr-header))
|
|
2385
|
-
(with-open [rdr (io/reader src)]
|
|
2386
|
-
(let [env (ana/empty-env)
|
|
2387
|
-
emitter (when (:parallel-build opts)
|
|
2388
|
-
(Executors/newSingleThreadExecutor))
|
|
2389
|
-
emit (if *esm*
|
|
2390
|
-
#(binding [*esm-emitting* true] (emit %))
|
|
2391
|
-
emit)
|
|
2392
|
-
emit (if emitter
|
|
2393
|
-
#(.execute emitter ^Runnable (bound-fn [] (emit %)))
|
|
2394
|
-
emit)]
|
|
2395
|
-
(loop [forms (ana/forms-seq* rdr (util/path src))
|
|
2396
|
-
ns-name nil
|
|
2397
|
-
deps []]
|
|
2398
|
-
(if (seq forms)
|
|
2399
|
-
(let [env (assoc env :ns (ana/get-namespace ana/*cljs-ns*))
|
|
2400
|
-
{:keys [op] :as ast} (ana/analyze env (first forms) nil opts)]
|
|
2401
|
-
(cond
|
|
2402
|
-
(= op :ns)
|
|
2403
|
-
(let [ns-name (:name ast)
|
|
2404
|
-
ns-name (if (and (= 'cljs.core ns-name)
|
|
2405
|
-
(= "cljc" ext))
|
|
2406
|
-
'cljs.core$macros
|
|
2407
|
-
ns-name)]
|
|
2408
|
-
(emit ast)
|
|
2409
|
-
(recur (rest forms) ns-name (into deps (:deps ast))))
|
|
2410
|
-
|
|
2411
|
-
(= :ns* (:op ast))
|
|
2412
|
-
(let [ns-emitted? (some? ns-name)
|
|
2413
|
-
ns-name (if-not ns-emitted?
|
|
2414
|
-
(ana/gen-user-ns src)
|
|
2415
|
-
ns-name)]
|
|
2416
|
-
(if-not ns-emitted?
|
|
2417
|
-
(emit (assoc ast :name ns-name :op :ns))
|
|
2418
|
-
(emit ast))
|
|
2419
|
-
(recur (rest forms) ns-name (into deps (:deps ast))))
|
|
2420
|
-
|
|
2421
|
-
:else
|
|
2422
|
-
(let [ns-emitted? (some? ns-name)
|
|
2423
|
-
ns-name (if-not ns-emitted?
|
|
2424
|
-
(ana/gen-user-ns src)
|
|
2425
|
-
ns-name)]
|
|
2426
|
-
(when-not ns-emitted?
|
|
2427
|
-
(emit {:op :ns
|
|
2428
|
-
:name ns-name}))
|
|
2429
|
-
(emit ast)
|
|
2430
|
-
(recur (rest forms) ns-name deps))))
|
|
2431
|
-
(let [_ (when emitter
|
|
2432
|
-
(.shutdown emitter)
|
|
2433
|
-
(.awaitTermination emitter 1000 TimeUnit/HOURS))
|
|
2434
|
-
_ (when *esm*
|
|
2435
|
-
(binding [*esm-emitting* true]
|
|
2436
|
-
(emit-esm-footer (or ns-name 'cljs.user))))
|
|
2437
|
-
dts (when *esm*
|
|
2438
|
-
(esm-dts (or ns-name 'cljs.user) @(:export-syms *esm*)))
|
|
2439
|
-
sm-data (when *source-map-data* (assoc @*source-map-data*
|
|
2440
|
-
:gen-col (.get ^AtomicLong *source-map-data-gen-col*)))
|
|
2441
|
-
ret (merge
|
|
2442
|
-
{:ns (or ns-name 'cljs.user)
|
|
2443
|
-
:macros-ns (:macros-ns opts)
|
|
2444
|
-
:provides [ns-name]
|
|
2445
|
-
:requires (if (= ns-name 'cljs.core)
|
|
2446
|
-
(vec (distinct deps))
|
|
2447
|
-
(cond-> (conj (vec (distinct deps)) 'cljs.core)
|
|
2448
|
-
(get-in @env/*compiler* [:options :emit-constants])
|
|
2449
|
-
(conj ana/constants-ns-sym)))
|
|
2450
|
-
:file dest
|
|
2451
|
-
:out-file (.toString ^File dest)
|
|
2452
|
-
:source-file src}
|
|
2453
|
-
(when sm-data
|
|
2454
|
-
{:source-map (:source-map sm-data)})
|
|
2455
|
-
(when dts
|
|
2456
|
-
{:esm-dts dts}))]
|
|
2457
|
-
(when (and sm-data (= :none (:optimizations opts)))
|
|
2458
|
-
(emit-source-map src dest sm-data
|
|
2459
|
-
(merge opts {:ext ext :provides [ns-name]})))
|
|
2460
|
-
(let [path (.getPath (.toURL ^File dest))]
|
|
2461
|
-
(swap! env/*compiler* assoc-in [::compiled-cljs path] ret))
|
|
2462
|
-
(ana/ensure-defs ns-name)
|
|
2463
|
-
(let [{:keys [output-dir cache-analysis]} opts]
|
|
2464
|
-
(when (and (true? cache-analysis) output-dir)
|
|
2465
|
-
(ana/write-analysis-cache ns-name
|
|
2466
|
-
(ana/cache-file src (ana/parse-ns src) output-dir :write)
|
|
2467
|
-
src))
|
|
2468
|
-
ret))))))))))
|
|
2469
|
-
|
|
2470
|
-
#?(:clj
|
|
2471
|
-
(defn emit-source [src ^File dest ext opts]
|
|
2472
|
-
(if (esm-mode? opts)
|
|
2473
|
-
;; written to a temporary file first, dev servers watching the output
|
|
2474
|
-
;; directory never see a partially written module
|
|
2475
|
-
(let [tmp (io/file (str (.getPath dest) ".tmp"))
|
|
2476
|
-
ret (emit-source* src dest tmp ext opts)
|
|
2477
|
-
dts (io/file (string/replace (.getPath dest) #"\.js$" ".d.ts"))]
|
|
2478
|
-
(when-not (false? (:esm-dts opts))
|
|
2479
|
-
(spit dts (:esm-dts ret)))
|
|
2480
|
-
(java.nio.file.Files/move (.toPath tmp) (.toPath dest)
|
|
2481
|
-
(into-array java.nio.file.CopyOption
|
|
2482
|
-
[java.nio.file.StandardCopyOption/REPLACE_EXISTING
|
|
2483
|
-
java.nio.file.StandardCopyOption/ATOMIC_MOVE]))
|
|
2484
|
-
ret)
|
|
2485
|
-
(emit-source* src dest dest ext opts))))
|
|
2486
|
-
|
|
2487
|
-
#?(:clj
|
|
2488
|
-
(defn compile-file*
|
|
2489
|
-
([^File src ^File dest]
|
|
2490
|
-
(compile-file* src dest
|
|
2491
|
-
(when env/*compiler*
|
|
2492
|
-
(:options @env/*compiler*))))
|
|
2493
|
-
([^File src ^File dest opts]
|
|
2494
|
-
(ensure
|
|
2495
|
-
(with-core-cljs opts
|
|
2496
|
-
(fn []
|
|
2497
|
-
(when (and (or ana/*verbose* (:verbose opts))
|
|
2498
|
-
(not (:compiler-stats opts)))
|
|
2499
|
-
(util/debug-prn "Compiling" (str src) "to" (str dest)))
|
|
2500
|
-
(util/measure (and (or ana/*verbose* (:verbose opts))
|
|
2501
|
-
(:compiler-stats opts))
|
|
2502
|
-
(str "Compiling " (str src) " to " (str dest))
|
|
2503
|
-
(let [ext (util/ext src)
|
|
2504
|
-
{:keys [ns] :as ns-info} (ana/parse-ns src)]
|
|
2505
|
-
(if-let [cached (cached-core ns ext opts)]
|
|
2506
|
-
[(emit-cached-core src dest cached opts) false]
|
|
2507
|
-
(let [opts (if (macro-ns? ns ext opts)
|
|
2508
|
-
(assoc opts :macros-ns true)
|
|
2509
|
-
opts)
|
|
2510
|
-
dest-exists? (.exists dest)
|
|
2511
|
-
ret [(emit-source src dest ext opts) dest-exists?]]
|
|
2512
|
-
(.setLastModified ^File dest (util/last-modified src))
|
|
2513
|
-
ret))))))))))
|
|
2514
|
-
|
|
2515
|
-
#?(:clj
|
|
2516
|
-
(defn requires-compilation?
|
|
2517
|
-
"Return true if the src file requires compilation."
|
|
2518
|
-
([src dest]
|
|
2519
|
-
(requires-compilation? src dest
|
|
2520
|
-
(when env/*compiler*
|
|
2521
|
-
(:options @env/*compiler*))))
|
|
2522
|
-
([^File src ^File dest opts]
|
|
2523
|
-
(let [{:keys [ns requires]} (ana/parse-ns src)]
|
|
2524
|
-
(if (and (= 'cljs.loader ns) (not (contains? opts :cache-key)))
|
|
2525
|
-
false
|
|
2526
|
-
(ensure
|
|
2527
|
-
(or (not (.exists dest))
|
|
2528
|
-
(util/changed? src dest)
|
|
2529
|
-
(let [version' (util/compiled-by-version dest)
|
|
2530
|
-
version (util/clojurescript-version)]
|
|
2531
|
-
(and version (not= version version')))
|
|
2532
|
-
(and opts
|
|
2533
|
-
(not (and (io/resource "cljs/core.aot.js") (= 'cljs.core ns)))
|
|
2534
|
-
(not= (ana/build-affecting-options opts)
|
|
2535
|
-
(ana/build-affecting-options (util/build-options dest))))
|
|
2536
|
-
(and opts (:source-map opts)
|
|
2537
|
-
(if (= (:optimizations opts) :none)
|
|
2538
|
-
(not (.exists (io/file (str (.getPath dest) ".map"))))
|
|
2539
|
-
(not (get-in @env/*compiler* [::compiled-cljs (.getAbsolutePath dest)]))))
|
|
2540
|
-
(when-let [recompiled' (and *recompiled* @*recompiled*)]
|
|
2541
|
-
(some requires recompiled')))))))))
|
|
2542
|
-
|
|
2543
|
-
#?(:clj
|
|
2544
|
-
(defn compile-file
|
|
2545
|
-
"Compiles src to a file of the same name, but with a .js extension,
|
|
2546
|
-
in the src file's directory.
|
|
2547
|
-
|
|
2548
|
-
With dest argument, write file to provided location. If the dest
|
|
2549
|
-
argument is a file outside the source tree, missing parent
|
|
2550
|
-
directories will be created. The src file will only be compiled if
|
|
2551
|
-
the dest file has an older modification time.
|
|
2552
|
-
|
|
2553
|
-
Both src and dest may be either a String or a File.
|
|
2554
|
-
|
|
2555
|
-
Returns a map containing {:ns .. :provides .. :requires .. :file ..}.
|
|
2556
|
-
If the file was not compiled returns only {:file ...}"
|
|
2557
|
-
([src]
|
|
2558
|
-
(let [dest (rename-to-js src)]
|
|
2559
|
-
(compile-file src dest
|
|
2560
|
-
(when env/*compiler*
|
|
2561
|
-
(:options @env/*compiler*)))))
|
|
2562
|
-
([src dest]
|
|
2563
|
-
(compile-file src dest
|
|
2564
|
-
(when env/*compiler*
|
|
2565
|
-
(:options @env/*compiler*))))
|
|
2566
|
-
([src dest opts]
|
|
2567
|
-
{:post [map?]}
|
|
2568
|
-
(binding [ana/*file-defs* (atom #{})
|
|
2569
|
-
ana/*unchecked-if* false
|
|
2570
|
-
ana/*unchecked-arrays* false
|
|
2571
|
-
ana/*cljs-warnings* ana/*cljs-warnings*]
|
|
2572
|
-
(let [nses (get @env/*compiler* ::ana/namespaces)
|
|
2573
|
-
src-file (io/file src)
|
|
2574
|
-
dest-file (io/file dest)
|
|
2575
|
-
opts (merge {:optimizations :none} opts)]
|
|
2576
|
-
(if (.exists src-file)
|
|
2577
|
-
(try
|
|
2578
|
-
(let [{ns :ns :as ns-info} (ana/parse-ns src-file dest-file opts)
|
|
2579
|
-
opts (if (and (not= (util/ext src) "clj") ;; skip cljs.core macro-ns
|
|
2580
|
-
(= ns 'cljs.core))
|
|
2581
|
-
(cond-> opts
|
|
2582
|
-
(not (false? (:static-fns opts))) (assoc :static-fns true)
|
|
2583
|
-
true (dissoc :checked-arrays))
|
|
2584
|
-
opts)]
|
|
2585
|
-
(if (or (requires-compilation? src-file dest-file opts)
|
|
2586
|
-
(:force opts))
|
|
2587
|
-
(do
|
|
2588
|
-
(util/mkdirs dest-file)
|
|
2589
|
-
(when (and (get-in nses [ns :defs])
|
|
2590
|
-
(not= 'cljs.core ns)
|
|
2591
|
-
(not= :interactive (:mode opts)))
|
|
2592
|
-
(swap! env/*compiler* update-in [::ana/namespaces] dissoc ns))
|
|
2593
|
-
(let [[ret recompiled?] (compile-file* src-file dest-file opts)]
|
|
2594
|
-
(when (and *recompiled*
|
|
2595
|
-
recompiled?)
|
|
2596
|
-
(swap! *recompiled* conj ns))
|
|
2597
|
-
ret))
|
|
2598
|
-
(do
|
|
2599
|
-
;; populate compilation environment with analysis information
|
|
2600
|
-
;; when constants are optimized
|
|
2601
|
-
(when (or (and (= ns 'cljs.loader)
|
|
2602
|
-
(not (contains? opts :cache-key)))
|
|
2603
|
-
(and (true? (:optimize-constants opts))
|
|
2604
|
-
(nil? (get-in nses [ns :defs]))))
|
|
2605
|
-
(with-core-cljs opts (fn [] (ana/analyze-file src-file opts))))
|
|
2606
|
-
(assoc ns-info :out-file (.toString dest-file)))))
|
|
2607
|
-
(catch Exception e
|
|
2608
|
-
(throw (ex-info (str "failed compiling file:" src) {:file src :clojure.error/phase :compilation} e))))
|
|
2609
|
-
(throw (util/compilation-error (java.io.FileNotFoundException. (str "The file " src " does not exist."))))))))))
|
|
2610
|
-
|
|
2611
|
-
#?(:clj
|
|
2612
|
-
(defn cljs-files-in
|
|
2613
|
-
"Return a sequence of all .cljs and .cljc files in the given directory."
|
|
2614
|
-
[dir]
|
|
2615
|
-
(map io/file
|
|
2616
|
-
(reduce
|
|
2617
|
-
(fn [m x]
|
|
2618
|
-
(if (.endsWith ^String x ".cljs")
|
|
2619
|
-
(cond-> (conj m x)
|
|
2620
|
-
(contains? m (str (subs x 0 (dec (count x))) "c"))
|
|
2621
|
-
(set/difference #{(str (subs x 0 (dec (count x))) "c")}))
|
|
2622
|
-
;; ends with .cljc
|
|
2623
|
-
(cond-> m
|
|
2624
|
-
(not (contains? m (str (subs x 0 (dec (count x))) "s")))
|
|
2625
|
-
(conj x))))
|
|
2626
|
-
#{}
|
|
2627
|
-
(into []
|
|
2628
|
-
(comp
|
|
2629
|
-
(filter
|
|
2630
|
-
#(let [name (.getName ^File %)]
|
|
2631
|
-
(and (or (.endsWith name ".cljs")
|
|
2632
|
-
(.endsWith name ".cljc"))
|
|
2633
|
-
(not= \. (first name))
|
|
2634
|
-
(not (contains? cljs-reserved-file-names name)))))
|
|
2635
|
-
(map #(.getPath ^File %)))
|
|
2636
|
-
(file-seq dir))))))
|
|
2637
|
-
|
|
2638
|
-
#?(:clj
|
|
2639
|
-
(defn compile-root
|
|
2640
|
-
"Looks recursively in src-dir for .cljs files and compiles them to
|
|
2641
|
-
.js files. If target-dir is provided, output will go into this
|
|
2642
|
-
directory mirroring the source directory structure. Returns a list
|
|
2643
|
-
of maps containing information about each file which was compiled
|
|
2644
|
-
in dependency order."
|
|
2645
|
-
([src-dir]
|
|
2646
|
-
(compile-root src-dir "out"))
|
|
2647
|
-
([src-dir target-dir]
|
|
2648
|
-
(compile-root src-dir target-dir
|
|
2649
|
-
(when env/*compiler*
|
|
2650
|
-
(:options @env/*compiler*))))
|
|
2651
|
-
([src-dir target-dir opts]
|
|
2652
|
-
(swap! env/*compiler* assoc :root src-dir)
|
|
2653
|
-
(let [src-dir-file (io/file src-dir)
|
|
2654
|
-
inputs (deps/dependency-order
|
|
2655
|
-
(map #(ana/parse-ns %)
|
|
2656
|
-
(cljs-files-in src-dir-file)))]
|
|
2657
|
-
(binding [*inputs* (zipmap (map :ns inputs) inputs)]
|
|
2658
|
-
(loop [inputs (seq inputs) compiled []]
|
|
2659
|
-
(if inputs
|
|
2660
|
-
(let [{:keys [source-file] :as ns-info} (first inputs)
|
|
2661
|
-
output-file (util/to-target-file target-dir ns-info)
|
|
2662
|
-
ijs (compile-file source-file output-file opts)]
|
|
2663
|
-
(recur
|
|
2664
|
-
(next inputs)
|
|
2665
|
-
(conj compiled
|
|
2666
|
-
(assoc ijs :file-name (.getPath output-file)))))
|
|
2667
|
-
compiled)))))))
|
|
2668
|
-
|
|
2669
|
-
#?(:clj
|
|
2670
|
-
(defn find-source [file]
|
|
2671
|
-
(ana/parse-ns file)))
|
|
2672
|
-
|
|
2673
|
-
#?(:clj
|
|
2674
|
-
(defn find-root-sources
|
|
2675
|
-
[src-dir]
|
|
2676
|
-
(let [src-dir-file (io/file src-dir)]
|
|
2677
|
-
(map find-source (cljs-files-in src-dir-file)))))
|
|
2678
|
-
|
|
2679
|
-
;; TODO: needs fixing, table will include other things than keywords - David
|
|
2680
|
-
|
|
2681
|
-
(defn emit-constants-table [table]
|
|
2682
|
-
(emitln "goog.provide('" (munge ana/constants-ns-sym) "');")
|
|
2683
|
-
(emitln "goog.require('cljs.core');")
|
|
2684
|
-
(doseq [[sym value] table]
|
|
2685
|
-
(let [ns (namespace sym)
|
|
2686
|
-
name (name sym)]
|
|
2687
|
-
(emits "cljs.core." value " = ")
|
|
2688
|
-
(cond
|
|
2689
|
-
(keyword? sym) (emits-keyword sym)
|
|
2690
|
-
(symbol? sym) (emits-symbol sym)
|
|
2691
|
-
:else (throw
|
|
2692
|
-
(ex-info
|
|
2693
|
-
(str "Cannot emit constant for type " (type sym))
|
|
2694
|
-
{:error :invalid-constant-type
|
|
2695
|
-
:clojure.error/phase :compilation})))
|
|
2696
|
-
(emits ";\n"))))
|
|
2697
|
-
|
|
2698
|
-
#?(:clj
|
|
2699
|
-
(defn emit-esm-constants-table
|
|
2700
|
-
"The constants module of ES module output (:emit-constants): an export
|
|
2701
|
-
of each keyword and symbol constant in table."
|
|
2702
|
-
[table]
|
|
2703
|
-
(binding [*esm-emitting* true
|
|
2704
|
-
ana/*cljs-ns* ana/constants-ns-sym
|
|
2705
|
-
;; the namespaces cc references, cljs.core is imported below
|
|
2706
|
-
*esm* {:refs (atom #{}) :self-import (atom false)}]
|
|
2707
|
-
(emitln "import * as " (esm-ns-alias 'cljs.core) " from \""
|
|
2708
|
-
(esm-ns-path ana/constants-ns-sym 'cljs.core) "\";")
|
|
2709
|
-
(doseq [[x value] (sort-by (comp str val) table)]
|
|
2710
|
-
(emits "export const " value " = /*@__PURE__*/ ")
|
|
2711
|
-
(if (keyword? x) (emits-keyword x) (emits-symbol x))
|
|
2712
|
-
(emitln ";")))))
|
|
2713
|
-
|
|
2714
|
-
#?(:clj
|
|
2715
|
-
(defn emit-constants-table-to-file [table dest]
|
|
2716
|
-
(io/make-parents dest)
|
|
2717
|
-
(with-open [out ^java.io.Writer (io/make-writer dest {})]
|
|
2718
|
-
(binding [*out* out]
|
|
2719
|
-
(emit-constants-table table)))))
|
|
2720
|
-
|
|
2721
|
-
(defn emit-externs
|
|
2722
|
-
([externs]
|
|
2723
|
-
(emit-externs [] externs (atom #{})
|
|
2724
|
-
(when env/*compiler* (ana/get-externs))))
|
|
2725
|
-
([prefix externs top-level known-externs]
|
|
2726
|
-
(loop [ks (seq (keys externs))]
|
|
2727
|
-
(when ks
|
|
2728
|
-
(let [k (first ks)
|
|
2729
|
-
[top :as prefix'] (conj prefix k)]
|
|
2730
|
-
(when (and (not= 'prototype k)
|
|
2731
|
-
(nil? (get-in known-externs prefix')))
|
|
2732
|
-
(if-not (or (contains? @top-level top)
|
|
2733
|
-
(contains? known-externs top))
|
|
2734
|
-
(do
|
|
2735
|
-
(emitln "var " (string/join "." (map munge prefix')) ";")
|
|
2736
|
-
(swap! top-level conj top))
|
|
2737
|
-
(emitln (string/join "." (map munge prefix')) ";")))
|
|
2738
|
-
(let [m (get externs k)]
|
|
2739
|
-
(when-not (empty? m)
|
|
2740
|
-
(emit-externs prefix' m top-level known-externs))))
|
|
2741
|
-
(recur (next ks))))))
|
|
2742
|
-
|
|
2743
|
-
#?(:clj
|
|
2744
|
-
(defn emit-inferred-externs-to-file [externs dest]
|
|
2745
|
-
(io/make-parents dest)
|
|
2746
|
-
(with-open [out ^java.io.Writer (io/make-writer dest {})]
|
|
2747
|
-
(binding [*out* out]
|
|
2748
|
-
(emit-externs externs)))))
|