clementine 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +4 -2
- data/LICENSE.txt +22 -0
- data/README.md +11 -6
- data/Rakefile +22 -0
- data/clementine.gemspec +2 -1
- data/ext/clojure-clojurescript-bef56a7/.gitignore +13 -0
- data/ext/clojure-clojurescript-bef56a7/Clojurescript.iml +12 -0
- data/ext/clojure-clojurescript-bef56a7/README.md +29 -0
- data/ext/clojure-clojurescript-bef56a7/benchmark/cljs/benchmark_runner.cljs +155 -0
- data/ext/clojure-clojurescript-bef56a7/bin/cljsc +21 -0
- data/ext/clojure-clojurescript-bef56a7/bin/cljsc.bat +18 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/bin/cljsc.clj +0 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/README.org +35 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/bcrepl.org +13 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/cljs.org +500 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/corelib.org +583 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/day1.org +203 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/day2.org +44 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/talk.org +126 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/testing +13 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/todo.org +121 -0
- data/ext/clojure-clojurescript-bef56a7/epl-v10.html +261 -0
- data/ext/clojure-clojurescript-bef56a7/pom.template.xml +88 -0
- data/ext/clojure-clojurescript-bef56a7/samples/dom/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/dom/src/dom/test.cljs +48 -0
- data/ext/clojure-clojurescript-bef56a7/samples/dom/test.html +30 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/README.md +53 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externed-lib.js +7 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externs.js +3 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-extern.html +14 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js-dev.html +18 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js.html +17 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/my-external-lib.js +3 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/core.cljs +9 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/extern-example.cljs +5 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/README.md +34 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/hello-dev.html +18 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/hello.html +13 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/core.cljs +8 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/foo/bar.cljs +4 -0
- data/ext/clojure-clojurescript-bef56a7/samples/nodehello.cljs +18 -0
- data/ext/clojure-clojurescript-bef56a7/samples/nodels.cljs +17 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/README.md +101 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/index.html +27 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/src/repl/test.cljs +73 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/README.md +42 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index-advanced.html +80 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index.html +88 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/reset.css +48 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/anneal.cljs +66 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/core.cljs +307 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/dom-helpers.cljs +95 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/layout.cljs +100 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/leaderboard.cljs +40 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/radial.cljs +91 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/showgraph.cljs +121 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/timeline.cljs +39 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/style.css +301 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/test_data.txt +1 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/tweet_maps.txt +1 -0
- data/ext/clojure-clojurescript-bef56a7/script/benchmark +30 -0
- data/ext/clojure-clojurescript-bef56a7/script/bootstrap +70 -0
- data/ext/clojure-clojurescript-bef56a7/script/browser-repl +16 -0
- data/ext/clojure-clojurescript-bef56a7/script/build +59 -0
- data/ext/clojure-clojurescript-bef56a7/script/clean +5 -0
- data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library-third-party.pom.template +59 -0
- data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library.pom.template +54 -0
- data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/make-closure-library-jars.sh +87 -0
- data/ext/clojure-clojurescript-bef56a7/script/compile +41 -0
- data/ext/clojure-clojurescript-bef56a7/script/repl +13 -0
- data/ext/clojure-clojurescript-bef56a7/script/repl.bat +13 -0
- data/ext/clojure-clojurescript-bef56a7/script/repljs +15 -0
- data/ext/clojure-clojurescript-bef56a7/script/repljs.bat +14 -0
- data/ext/clojure-clojurescript-bef56a7/script/test +38 -0
- data/ext/clojure-clojurescript-bef56a7/script/test-compile +30 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/analyzer.clj +975 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/closure.clj +173 -73
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/compiler.clj +1081 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/core.clj +1158 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl.clj +51 -25
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/browser.clj +258 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/reflect.clj +75 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl/rhino.clj +6 -5
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/server.clj +173 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/tagged_literals.clj +30 -0
- data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/core.cljs +7197 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs.cljs +1 -1
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs_externs.js +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejscli.cljs +1 -1
- data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/reader.cljs +551 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/dom.cljs +59 -13
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/event.cljs +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/net.cljs +8 -7
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/repl.cljs +2 -2
- data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/core/reducers.cljs +298 -0
- data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/data.cljs +162 -0
- data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/reflect.cljs +48 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/set.cljs +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/string.cljs +4 -10
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/walk.cljs +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/zip.cljs +0 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test.cljs +7 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test_other_ns.cljs +3 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/core_test.cljs +1678 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test.cljs +11 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test/foo.cljs +5 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/letfn_test.cljs +19 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test.cljs +6 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test/macros.clj +5 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test.cljs +14 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/bar.cljs +3 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/foo.cljs +7 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/reader_test.cljs +124 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/data_test.cljs +22 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/string_test.cljs +97 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/foo/ns_shadow_test.cljs +9 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/test_runner.cljs +26 -0
- data/lib/clementine.rb +3 -24
- data/lib/clementine/clojurescript_engine.rb +9 -48
- data/lib/clementine/clojurescript_engine/base.rb +15 -0
- data/lib/clementine/clojurescript_engine/jruby.rb +46 -0
- data/lib/clementine/{clojurescript_engine_mri.rb → clojurescript_engine/mri.rb} +17 -10
- data/lib/clementine/version.rb +1 -1
- data/test/clojurescript_engine_test.rb +36 -14
- metadata +177 -83
- data/vendor/assets/lib/clojure.jar +0 -0
- data/vendor/assets/lib/compiler.jar +0 -0
- data/vendor/assets/lib/goog.jar +0 -0
- data/vendor/assets/lib/js.jar +0 -0
- data/vendor/assets/src/clj/cljs/compiler.clj +0 -1341
- data/vendor/assets/src/clj/cljs/core.clj +0 -702
- data/vendor/assets/src/clj/cljs/repl/browser.clj +0 -341
- data/vendor/assets/src/cljs/cljs/core.cljs +0 -3330
- data/vendor/assets/src/cljs/cljs/reader.cljs +0 -360
@@ -8,9 +8,12 @@
|
|
8
8
|
|
9
9
|
(ns cljs.repl
|
10
10
|
(:refer-clojure :exclude [load-file])
|
11
|
+
(:import java.io.File)
|
11
12
|
(:require [clojure.string :as string]
|
12
13
|
[clojure.java.io :as io]
|
13
14
|
[cljs.compiler :as comp]
|
15
|
+
[cljs.analyzer :as ana]
|
16
|
+
[cljs.tagged-literals :as tags]
|
14
17
|
[cljs.closure :as cljsc]))
|
15
18
|
|
16
19
|
(def ^:dynamic *cljs-verbose* false)
|
@@ -61,11 +64,17 @@
|
|
61
64
|
(evaluate-form repl-env env filename form identity))
|
62
65
|
([repl-env env filename form wrap]
|
63
66
|
(try
|
64
|
-
(let [ast (
|
65
|
-
js (comp/
|
66
|
-
wrap-js (comp/
|
67
|
+
(let [ast (ana/analyze env form)
|
68
|
+
js (comp/emit-str ast)
|
69
|
+
wrap-js (comp/emit-str (binding [ana/*cljs-warn-on-undeclared* false
|
70
|
+
ana/*cljs-warn-on-redef* false
|
71
|
+
ana/*cljs-warn-on-dynamic* false
|
72
|
+
ana/*cljs-warn-on-fn-var* false
|
73
|
+
ana/*cljs-warn-fn-arity* false]
|
74
|
+
(ana/analyze env (wrap form))))]
|
67
75
|
(when (= (:op ast) :ns)
|
68
|
-
(load-dependencies repl-env (vals (:requires ast))
|
76
|
+
(load-dependencies repl-env (into (vals (:requires ast))
|
77
|
+
(distinct (vals (:uses ast))))))
|
69
78
|
(when *cljs-verbose*
|
70
79
|
(print js))
|
71
80
|
(let [ret (-evaluate repl-env filename (:line (meta form)) wrap-js)]
|
@@ -84,18 +93,18 @@
|
|
84
93
|
|
85
94
|
(defn load-stream [repl-env filename stream]
|
86
95
|
(with-open [r (io/reader stream)]
|
87
|
-
(let [env
|
96
|
+
(let [env (ana/empty-env)
|
88
97
|
pbr (clojure.lang.LineNumberingPushbackReader. r)
|
89
98
|
eof (Object.)]
|
90
99
|
(loop [r (read pbr false eof false)]
|
91
|
-
(let [env (assoc env :ns (
|
100
|
+
(let [env (assoc env :ns (ana/get-namespace ana/*cljs-ns*))]
|
92
101
|
(when-not (identical? eof r)
|
93
102
|
(evaluate-form repl-env env filename r)
|
94
103
|
(recur (read pbr false eof false))))))))
|
95
104
|
|
96
105
|
(defn load-file
|
97
106
|
[repl-env f]
|
98
|
-
(binding [
|
107
|
+
(binding [ana/*cljs-ns* 'cljs.user]
|
99
108
|
(let [res (if (= \/ (first f)) f (io/resource f))]
|
100
109
|
(assert res (str "Can't find " f " in classpath"))
|
101
110
|
(load-stream repl-env f res))))
|
@@ -112,7 +121,7 @@
|
|
112
121
|
|
113
122
|
(defn- eval-and-print [repl-env env form]
|
114
123
|
(let [ret (evaluate-form repl-env
|
115
|
-
(assoc env :ns (
|
124
|
+
(assoc env :ns (ana/get-namespace ana/*cljs-ns*))
|
116
125
|
"<cljs repl>"
|
117
126
|
form
|
118
127
|
(wrap-fn form))]
|
@@ -123,39 +132,56 @@
|
|
123
132
|
(prn nil))))))
|
124
133
|
|
125
134
|
(defn- read-next-form []
|
126
|
-
(try {:status :success :form (binding [*ns* (create-ns
|
135
|
+
(try {:status :success :form (binding [*ns* (create-ns ana/*cljs-ns*)
|
136
|
+
*data-readers* tags/*cljs-data-readers*]
|
127
137
|
(read))}
|
128
138
|
(catch Exception e
|
129
139
|
(println (.getMessage e))
|
130
140
|
{:status :error})))
|
131
141
|
|
142
|
+
(def default-special-fns
|
143
|
+
(let [load-file-fn (fn [repl-env file] (load-file repl-env file))]
|
144
|
+
{'in-ns (fn [_ quoted-ns]
|
145
|
+
(let [ns-name (second quoted-ns)]
|
146
|
+
(when-not (ana/get-namespace ns-name)
|
147
|
+
(ana/set-namespace ns-name {:name ns-name}))
|
148
|
+
(set! ana/*cljs-ns* ns-name)))
|
149
|
+
'load-file load-file-fn
|
150
|
+
'clojure.core/load-file load-file-fn
|
151
|
+
'load-namespace (fn [repl-env ns] (load-namespace repl-env ns))}))
|
152
|
+
|
153
|
+
(defn analyze-source
|
154
|
+
"Given a source directory, analyzes all .cljs files. Used to populate
|
155
|
+
cljs.analyzer/namespaces so as to support code reflection."
|
156
|
+
[src-dir]
|
157
|
+
(if-let [src-dir (and (not (empty? src-dir))
|
158
|
+
(File. src-dir))]
|
159
|
+
(doseq [file (comp/cljs-files-in src-dir)]
|
160
|
+
(ana/analyze-file (str "file://" (.getAbsolutePath file))))))
|
161
|
+
|
132
162
|
(defn repl
|
133
163
|
"Note - repl will reload core.cljs every time, even if supplied old repl-env"
|
134
|
-
[repl-env & {:keys [verbose warn-on-undeclared]}]
|
164
|
+
[repl-env & {:keys [verbose warn-on-undeclared special-fns]}]
|
135
165
|
(prn "Type: " :cljs/quit " to quit")
|
136
|
-
(binding [
|
166
|
+
(binding [ana/*cljs-ns* 'cljs.user
|
137
167
|
*cljs-verbose* verbose
|
138
|
-
|
139
|
-
(let [env {:context :statement :locals {}}
|
168
|
+
ana/*cljs-warn-on-undeclared* warn-on-undeclared]
|
169
|
+
(let [env {:context :statement :locals {}}
|
170
|
+
special-fns (merge default-special-fns special-fns)
|
171
|
+
is-special-fn? (set (keys special-fns))]
|
140
172
|
(-setup repl-env)
|
141
173
|
(loop []
|
142
|
-
(print (str "ClojureScript:"
|
174
|
+
(print (str "ClojureScript:" ana/*cljs-ns* "> "))
|
143
175
|
(flush)
|
144
176
|
(let [{:keys [status form]} (read-next-form)]
|
145
177
|
(cond
|
146
178
|
(= form :cljs/quit) :quit
|
147
|
-
|
179
|
+
|
148
180
|
(= status :error) (recur)
|
149
|
-
|
150
|
-
(and (seq? form) (
|
151
|
-
(do (
|
152
|
-
|
153
|
-
(and (seq? form) ('#{load-file clojure.core/load-file} (first form)))
|
154
|
-
(do (load-file repl-env (second form)) (newline) (recur))
|
155
|
-
|
156
|
-
(and (seq? form) ('#{load-namespace} (first form)))
|
157
|
-
(do (load-namespace repl-env (second form)) (newline) (recur))
|
158
|
-
|
181
|
+
|
182
|
+
(and (seq? form) (is-special-fn? (first form)))
|
183
|
+
(do (apply (get special-fns (first form)) repl-env (rest form)) (newline) (recur))
|
184
|
+
|
159
185
|
:else
|
160
186
|
(do (eval-and-print repl-env env form) (recur)))))
|
161
187
|
(-tear-down repl-env))))
|
@@ -0,0 +1,258 @@
|
|
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.repl.browser
|
10
|
+
(:refer-clojure :exclude [loaded-libs])
|
11
|
+
(:require [clojure.java.io :as io]
|
12
|
+
[cljs.compiler :as comp]
|
13
|
+
[cljs.closure :as cljsc]
|
14
|
+
[cljs.repl :as repl]
|
15
|
+
[cljs.repl.server :as server])
|
16
|
+
(:import cljs.repl.IJavaScriptEnv))
|
17
|
+
|
18
|
+
(defonce browser-state (atom {:return-value-fn nil
|
19
|
+
:client-js nil}))
|
20
|
+
|
21
|
+
(def loaded-libs (atom #{}))
|
22
|
+
(def preloaded-libs (atom #{}))
|
23
|
+
|
24
|
+
(defn- set-return-value-fn
|
25
|
+
"Save the return value function which will be called when the next
|
26
|
+
return value is received."
|
27
|
+
[f]
|
28
|
+
(swap! browser-state (fn [old] (assoc old :return-value-fn f))))
|
29
|
+
|
30
|
+
(defn send-for-eval
|
31
|
+
"Given a form and a return value function, send the form to the
|
32
|
+
browser for evaluation. The return value function will be called
|
33
|
+
when the return value is received."
|
34
|
+
([form return-value-fn]
|
35
|
+
(send-for-eval @(server/connection) form return-value-fn))
|
36
|
+
([conn form return-value-fn]
|
37
|
+
(do (set-return-value-fn return-value-fn)
|
38
|
+
(server/send-and-close conn 200 form "text/javascript"))))
|
39
|
+
|
40
|
+
(defn- return-value
|
41
|
+
"Called by the server when a return value is received."
|
42
|
+
[val]
|
43
|
+
(when-let [f (:return-value-fn @browser-state)]
|
44
|
+
(f val)))
|
45
|
+
|
46
|
+
(defn repl-client-js []
|
47
|
+
(slurp @(:client-js @browser-state)))
|
48
|
+
|
49
|
+
(defn send-repl-client-page
|
50
|
+
[request conn opts]
|
51
|
+
(server/send-and-close conn 200
|
52
|
+
(str "<html><head><meta charset=\"UTF-8\"></head><body>
|
53
|
+
<script type=\"text/javascript\">"
|
54
|
+
(repl-client-js)
|
55
|
+
"</script>"
|
56
|
+
"<script type=\"text/javascript\">
|
57
|
+
clojure.browser.repl.client.start(\"http://" (-> request :headers :host) "\");
|
58
|
+
</script>"
|
59
|
+
"</body></html>")
|
60
|
+
"text/html"))
|
61
|
+
|
62
|
+
(defn send-static [{path :path :as request} conn opts]
|
63
|
+
(if (and (:static-dir opts)
|
64
|
+
(not= "/favicon.ico" path))
|
65
|
+
(let [path (if (= "/" path) "/index.html" path)
|
66
|
+
st-dir (:static-dir opts)]
|
67
|
+
(if-let [local-path (seq (for [x (if (string? st-dir) [st-dir] st-dir)
|
68
|
+
:when (.exists (io/file (str x path)))]
|
69
|
+
(str x path)))]
|
70
|
+
(server/send-and-close conn 200 (slurp (first local-path))
|
71
|
+
(condp #(.endsWith %2 %1) path
|
72
|
+
".html" "text/html"
|
73
|
+
".css" "text/css"
|
74
|
+
".html" "text/html"
|
75
|
+
".jpg" "image/jpeg"
|
76
|
+
".js" "text/javascript"
|
77
|
+
".png" "image/png"
|
78
|
+
"text/plain"))
|
79
|
+
(server/send-404 conn path)))
|
80
|
+
(server/send-404 conn path)))
|
81
|
+
|
82
|
+
(server/dispatch-on :get
|
83
|
+
(fn [{:keys [path]} _ _] (.startsWith path "/repl"))
|
84
|
+
send-repl-client-page)
|
85
|
+
|
86
|
+
(server/dispatch-on :get
|
87
|
+
(fn [{:keys [path]} _ _] (or (= path "/")
|
88
|
+
(.endsWith path ".js")
|
89
|
+
(.endsWith path ".html")))
|
90
|
+
send-static)
|
91
|
+
|
92
|
+
(defmulti handle-post (fn [m _ _ ] (:type m)))
|
93
|
+
|
94
|
+
(server/dispatch-on :post (constantly true) handle-post)
|
95
|
+
|
96
|
+
(def ordering (agent {:expecting nil :fns {}}))
|
97
|
+
|
98
|
+
(defmethod handle-post :ready [_ conn _]
|
99
|
+
(do (reset! loaded-libs @preloaded-libs)
|
100
|
+
(send ordering (fn [_] {:expecting nil :fns {}}))
|
101
|
+
(send-for-eval conn
|
102
|
+
(cljsc/-compile
|
103
|
+
'[(ns cljs.user)
|
104
|
+
(set! *print-fn* clojure.browser.repl/repl-print)] {})
|
105
|
+
identity)))
|
106
|
+
|
107
|
+
(defn add-in-order [{:keys [expecting fns]} order f]
|
108
|
+
{:expecting (or expecting order) :fns (assoc fns order f)})
|
109
|
+
|
110
|
+
(defn run-in-order [{:keys [expecting fns]}]
|
111
|
+
(loop [order expecting
|
112
|
+
fns fns]
|
113
|
+
(if-let [f (get fns order)]
|
114
|
+
(do (f)
|
115
|
+
(recur (inc order) (dissoc fns order)))
|
116
|
+
{:expecting order :fns fns})))
|
117
|
+
|
118
|
+
(defn constrain-order
|
119
|
+
"Elements to be printed in the REPL will arrive out of order. Ensure
|
120
|
+
that they are printed in the correct order."
|
121
|
+
[order f]
|
122
|
+
(send-off ordering add-in-order order f)
|
123
|
+
(send-off ordering run-in-order))
|
124
|
+
|
125
|
+
(defmethod handle-post :print [{:keys [content order]} conn _ ]
|
126
|
+
(do (constrain-order order (fn [] (do (print (read-string content))
|
127
|
+
(.flush *out*))))
|
128
|
+
(server/send-and-close conn 200 "ignore__")))
|
129
|
+
|
130
|
+
(defmethod handle-post :result [{:keys [content order]} conn _ ]
|
131
|
+
(constrain-order order (fn [] (do (return-value content)
|
132
|
+
(server/set-connection conn)))))
|
133
|
+
|
134
|
+
(defn browser-eval
|
135
|
+
"Given a string of JavaScript, evaluate it in the browser and return a map representing the
|
136
|
+
result of the evaluation. The map will contain the keys :type and :value. :type can be
|
137
|
+
:success, :exception, or :error. :success means that the JavaScript was evaluated without
|
138
|
+
exception and :value will contain the return value of the evaluation. :exception means that
|
139
|
+
there was an exception in the browser while evaluating the JavaScript and :value will
|
140
|
+
contain the error message. :error means that some other error has occured."
|
141
|
+
[form]
|
142
|
+
(let [return-value (promise)]
|
143
|
+
(send-for-eval form
|
144
|
+
(fn [val] (deliver return-value val)))
|
145
|
+
(let [ret @return-value]
|
146
|
+
(try (read-string ret)
|
147
|
+
(catch Exception e
|
148
|
+
{:status :error
|
149
|
+
:value (str "Could not read return value: " ret)})))))
|
150
|
+
|
151
|
+
(defn load-javascript
|
152
|
+
"Accepts a REPL environment, a list of namespaces, and a URL for a
|
153
|
+
JavaScript file which contains the implementation for the list of
|
154
|
+
namespaces. Will load the JavaScript file into the REPL environment
|
155
|
+
if any of the namespaces have not already been loaded from the
|
156
|
+
ClojureScript REPL."
|
157
|
+
[repl-env ns-list url]
|
158
|
+
(let [missing (remove #(contains? @loaded-libs %) ns-list)]
|
159
|
+
(when (seq missing)
|
160
|
+
(browser-eval (slurp url))
|
161
|
+
(swap! loaded-libs (partial apply conj) missing))))
|
162
|
+
|
163
|
+
(defrecord BrowserEnv []
|
164
|
+
repl/IJavaScriptEnv
|
165
|
+
(-setup [this]
|
166
|
+
(do (require 'cljs.repl.reflect)
|
167
|
+
(repl/analyze-source (:src this))
|
168
|
+
(comp/with-core-cljs (server/start this))))
|
169
|
+
(-evaluate [_ _ _ js] (browser-eval js))
|
170
|
+
(-load [this ns url] (load-javascript this ns url))
|
171
|
+
(-tear-down [_]
|
172
|
+
(do (server/stop)
|
173
|
+
(reset! server/state {})
|
174
|
+
(reset! browser-state {}))))
|
175
|
+
|
176
|
+
(defn compile-client-js [opts]
|
177
|
+
(cljsc/build '[(ns clojure.browser.repl.client
|
178
|
+
(:require [goog.events :as event]
|
179
|
+
[clojure.browser.repl :as repl]))
|
180
|
+
(defn start [url]
|
181
|
+
(event/listen js/window
|
182
|
+
"load"
|
183
|
+
(fn []
|
184
|
+
(repl/start-evaluator url))))]
|
185
|
+
{:optimizations (:optimizations opts)
|
186
|
+
:output-dir (:working-dir opts)}))
|
187
|
+
|
188
|
+
(defn create-client-js-file [opts file-path]
|
189
|
+
(let [file (io/file file-path)]
|
190
|
+
(when (not (.exists file))
|
191
|
+
(spit file (compile-client-js opts)))
|
192
|
+
file))
|
193
|
+
|
194
|
+
(defn- provides-and-requires
|
195
|
+
"Return a flat list of all provided and required namespaces from a
|
196
|
+
sequence of IJavaScripts."
|
197
|
+
[deps]
|
198
|
+
(flatten (mapcat (juxt :provides :requires) deps)))
|
199
|
+
|
200
|
+
(defn- always-preload
|
201
|
+
"Return a list of all namespaces which are always loaded into the browser
|
202
|
+
when using a browser-connected REPL."
|
203
|
+
[]
|
204
|
+
(let [cljs (provides-and-requires (cljsc/cljs-dependencies {} ["clojure.browser.repl"]))
|
205
|
+
goog (provides-and-requires (cljsc/js-dependencies {} cljs))]
|
206
|
+
(disj (set (concat cljs goog)) nil)))
|
207
|
+
|
208
|
+
(defn repl-env
|
209
|
+
"Create a browser-connected REPL environment.
|
210
|
+
|
211
|
+
Options:
|
212
|
+
|
213
|
+
port: The port on which the REPL server will run. Defaults to 9000.
|
214
|
+
working-dir: The directory where the compiled REPL client JavaScript will
|
215
|
+
be stored. Defaults to \".repl\".
|
216
|
+
serve-static: Should the REPL server attempt to serve static content?
|
217
|
+
Defaults to true.
|
218
|
+
static-dir: List of directories to search for static content. Defaults to
|
219
|
+
[\".\" \"out/\"].
|
220
|
+
preloaded-libs: List of namespaces that should not be sent from the REPL server
|
221
|
+
to the browser. This may be required if the browser is already
|
222
|
+
loading code and reloading it would cause a problem.
|
223
|
+
optimizations: The level of optimization to use when compiling the client
|
224
|
+
end of the REPL. Defaults to :simple.
|
225
|
+
src: The source directory containing user-defined cljs files. Used to
|
226
|
+
support reflection. Defaults to \"src/\".
|
227
|
+
"
|
228
|
+
[& {:as opts}]
|
229
|
+
(let [opts (merge (BrowserEnv.)
|
230
|
+
{:port 9000
|
231
|
+
:optimizations :simple
|
232
|
+
:working-dir ".repl"
|
233
|
+
:serve-static true
|
234
|
+
:static-dir ["." "out/"]
|
235
|
+
:preloaded-libs []
|
236
|
+
:src "src/"}
|
237
|
+
opts)]
|
238
|
+
(do (reset! preloaded-libs (set (concat (always-preload) (map str (:preloaded-libs opts)))))
|
239
|
+
(reset! loaded-libs @preloaded-libs)
|
240
|
+
(swap! browser-state
|
241
|
+
(fn [old] (assoc old :client-js
|
242
|
+
(future (create-client-js-file
|
243
|
+
opts
|
244
|
+
(io/file (:working-dir opts) "client.js"))))))
|
245
|
+
opts)))
|
246
|
+
|
247
|
+
(comment
|
248
|
+
|
249
|
+
(require '[cljs.repl :as repl])
|
250
|
+
(require '[cljs.repl.browser :as browser])
|
251
|
+
(def env (browser/repl-env))
|
252
|
+
(repl/repl env)
|
253
|
+
;; simulate the browser with curl
|
254
|
+
;; curl -v -d "ready" http://127.0.0.1:9000
|
255
|
+
ClojureScript:> (+ 1 1)
|
256
|
+
;; curl -v -d "2" http://127.0.0.1:9000
|
257
|
+
|
258
|
+
)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
(ns cljs.repl.reflect
|
2
|
+
(:refer-clojure :exclude [macroexpand])
|
3
|
+
(:require [cljs.repl.server :as server]
|
4
|
+
[cljs.analyzer :as analyzer]
|
5
|
+
[cljs.compiler :as compiler]
|
6
|
+
[clojure.string :as str]
|
7
|
+
[clojure.pprint :as pprint]))
|
8
|
+
|
9
|
+
(defn- dissoc-unless
|
10
|
+
"Dissoc all keys from map that do not appear in key-set.
|
11
|
+
|
12
|
+
(dissoc-unless {:foo 1 :bar 2} #{:foo})
|
13
|
+
=> {:foo 1}"
|
14
|
+
[m key-set]
|
15
|
+
{:pre [(map? m)
|
16
|
+
(set? key-set)]}
|
17
|
+
(reduce (fn [coll key]
|
18
|
+
(if (contains? key-set key)
|
19
|
+
coll
|
20
|
+
(dissoc coll key)))
|
21
|
+
m (keys m)))
|
22
|
+
|
23
|
+
(defn- get-meta [sym]
|
24
|
+
(let [ns (symbol (namespace sym))
|
25
|
+
n (symbol (name sym))]
|
26
|
+
(if-let [sym-meta (get (:defs (get @analyzer/namespaces ns)) n)]
|
27
|
+
(-> (dissoc-unless sym-meta
|
28
|
+
#{:name :method-params :doc :line :file})
|
29
|
+
(update-in [:name] str)
|
30
|
+
(update-in [:method-params] #(str (vec %)))))))
|
31
|
+
|
32
|
+
(defn macroexpand [form]
|
33
|
+
"Fully expands a cljs macro form."
|
34
|
+
(let [mform (analyzer/macroexpand-1 {} form)]
|
35
|
+
(if (identical? form mform)
|
36
|
+
mform
|
37
|
+
(macroexpand mform))))
|
38
|
+
|
39
|
+
(defn- url-decode [encoded & [encoding]]
|
40
|
+
(java.net.URLDecoder/decode encoded (or encoding "UTF-8")))
|
41
|
+
|
42
|
+
(def read-url-string (comp read-string url-decode))
|
43
|
+
|
44
|
+
(defn parse-param
|
45
|
+
"Parses the query parameter of a path of the form \"/reflect?var=foo\"
|
46
|
+
into the vector [\"var\" \"foo\"]."
|
47
|
+
[path]
|
48
|
+
(-> (str/split path #"\?")
|
49
|
+
(last)
|
50
|
+
(str/split #"=")))
|
51
|
+
|
52
|
+
(defn- compile-and-return
|
53
|
+
"Compiles a form to javascript and returns it on conn."
|
54
|
+
[conn form]
|
55
|
+
(let [ast (analyzer/analyze {:ns {:name 'cljs.user}} form)
|
56
|
+
js (try (compiler/emit-str ast)
|
57
|
+
(catch Exception e (println e)))]
|
58
|
+
(server/send-and-close conn 200 js "text/javascript")))
|
59
|
+
|
60
|
+
(defmulti handle-reflect-query (fn [[param _] & _] param))
|
61
|
+
|
62
|
+
(defmethod handle-reflect-query "var"
|
63
|
+
[[_ sym] req conn opts]
|
64
|
+
(let [sym (read-url-string sym)]
|
65
|
+
(compile-and-return conn (get-meta sym))))
|
66
|
+
|
67
|
+
(defmethod handle-reflect-query "macroform"
|
68
|
+
[[_ mform] req conn opts]
|
69
|
+
(let [mform (-> mform read-url-string macroexpand)]
|
70
|
+
(server/send-and-close conn 200 (with-out-str (pprint/pprint mform)))))
|
71
|
+
|
72
|
+
(server/dispatch-on :get
|
73
|
+
(fn [{:keys [path]} _ _] (.startsWith path "/reflect"))
|
74
|
+
(fn [{:keys [path] :as req} conn opts]
|
75
|
+
(handle-reflect-query (parse-param path) req conn opts)))
|