 (defn javascript-file [^URL url provides requires]
   (JavaScriptFile. url (map name provides) (map name requires)))
 
+(defn read-js
+  "Read a JavaScript file returning a map of file information."
+  [f]
+  (let [source (slurp f)
+        m (parse-js-ns (string/split-lines source))]
+    (assoc m :file f :source source)))
+
 (defprotocol Compilable
   (-compile [this opts] "Returns one or more IJavaScripts."))
-
-;; Compile
-;; =======
-
-(defmacro with-core
-  "Ensure that core.cljs has been loaded."
-  [& body]
-  `(do (when-not (:defs (get @comp/namespaces 'cljs.core))
-         (comp/analyze-file "cljs/core.cljs"))
-       ~@body))
-
-(defn empty-env []
-  {:ns (@comp/namespaces comp/*cljs-ns*) :context :statement :locals {}})
-
-(defn compile-form-seq
-  "Compile a sequence of forms to a JavaScript source string."
-  [forms]
-  (with-core
-    (with-out-str
-      (binding [comp/*cljs-ns* 'cljs.user]
-        (doseq [form forms]
-          (comp/emit (comp/analyze (empty-env) form)))))))
-
-(defn output-directory [opts]
-  (or (:output-dir opts) "out"))
-
-(defn compile-file
-  "Compile a single cljs file. If no output-file is specified, returns
-  a string of compiled JavaScript. With an output-file option, the
-  compiled JavaScript will written to this location and the function
-  returns a JavaScriptFile. In either case the return value satisfies
-  IJavaScript."
-  [^File file {:keys [output-file] :as opts}]
-  (if output-file
-    (let [out-file (io/file (output-directory opts) output-file)
-          ns-info (comp/compile-file file out-file)]
-      (javascript-file (to-url (:file ns-info))
-                       (:provides ns-info)
-                       (:requires ns-info)))
-    (compile-form-seq (comp/forms-seq file))))
-
-(defn compile-dir
-  "Recursively compile all cljs files under the given source
-  directory. Return a list of JavaScriptFiles in dependency order."
-  [^File src-dir opts]
-  (let [out-dir (output-directory opts)
-        compiled-info (comp/compile-root src-dir out-dir)]
-    (map (fn [{:keys [file ns requires]}]
-           (javascript-file (to-url file) [ns] requires))
-         compiled-info)))
-
-(defn mkdirs
-  "Create all parent directories the the passed file."
-  [f]
-  (.mkdirs (.getParentFile (.getCanonicalFile f))))
-
-(defn path-from-jarfile
-  "Given the URL of a file within a jar, return the path of the file
-  from the root of the jar."
-  [^URL url]
-  (last (string/split (.getFile url) #"\.jar!/")))
-
-(defn jar-file-to-disk
-  "Copy a file contained within a jar to disk. Return the created file."
-  [url out-dir]
-  (let [out-file (io/file out-dir (path-from-jarfile url)) 
-        content (slurp (io/reader url))]
-    (do (mkdirs out-file)
-        (spit out-file content)
-        out-file)))
-
-(extend-protocol Compilable
-
-  File
-  (-compile [this opts]
-    (if (.isDirectory this)
-      (compile-dir this opts)
-      (compile-file this opts)))
-
-  URL
-  (-compile [this opts]
-    (case (.getProtocol this)
-      "file" (-compile (io/file this) opts)
-      "jar" (let [out-file (jar-file-to-disk this (output-directory opts))]
-              (-compile out-file opts))))
-  
-  clojure.lang.PersistentList
-  (-compile [this opts]
-    (compile-form-seq [this]))
-  
-  String
-  (-compile [this opts] (-compile (io/file this) opts))
-  
-  clojure.lang.PersistentVector
-  (-compile [this opts] (compile-form-seq this))
-  )
-
-(comment
-  ;; compile a file in memory
-  (-compile "samples/hello/src/hello/core.cljs" {})
-  ;; compile a file to disk - see file @ 'out/clojure/set.js'
-  (-compile (io/resource "clojure/set.cljs") {:output-file "clojure/set.js"})
-  ;; compile a project
-  (-compile (io/file "samples/hello/src") {})
-  ;; compile a project with a custom output directory
-  (-compile (io/file "samples/hello/src") {:output-dir "my-output"})
-  ;; compile a form
-  (-compile '(defn plus-one [x] (inc x)) {})
-  ;; compile a vector of forms
-  (-compile '[(ns test.app (:require [goog.array :as array]))
-              (defn plus-one [x] (inc x))]
-            {})
-  )
-
-;; Dependencies
-;; ============
-;;
-;; Find all dependencies from files on the classpath. Eliminates the
-;; need for closurebuilder. cljs dependencies will be compiled as
-;; needed.
 
 (defn build-index
   "Index a list of dependencies by namespace and file name. There can

        out-name (output-path js)
        out-file (io/file out-dir out-name)]
    (do (when-not (.exists out-file)
          (do (mkdirs out-file)
              (spit out-file (-source js))))
        {:url (to-url out-file) :requires (-requires js) :provides (-provides js) :group (:group js)})))


  [opts requires]
  (let [index (js-dependency-index opts)]
    (loop [requires requires
           visited requires
           deps #{}]
      (if (seq requires)
        (let [node (get index (first requires))
              new-req (remove #(contains? visited %) (:requires node))]
          (recur (into (rest requires) new-req)
                 (into visited new-req)
                 (conj deps node)))
        (cons (get index "goog/base.js") (dependency-order deps))))))

(comment
