Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Deraen committed Oct 29, 2016
1 parent fc01245 commit 9e88e36
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 94 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"react": "^15.3.1",
"react-addons-create-fragment": "^15.3.1",
"react-addons-transition-group": "^15.3.1",
"react-dom": "^15.3.1",
"material-ui": "^0.15.4"
"react-dom": "^15.3.1"
}
}
16 changes: 8 additions & 8 deletions src/cljsjs/closure.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
CompilerOptions SourceFile NodeTraversal$Callback JSModule]
[com.google.javascript.rhino Node]))

(defn is-require? [n]
(and (= 2 (.getChildCount n))
(.. n getFirstChild (matchesQualifiedName "require"))
(.. n getSecondChild isString)))
(defn is-require? [node]
(and (= 2 (.getChildCount node))
(.. node getFirstChild (matchesQualifiedName "require"))
(.. node getSecondChild isString)))

(defn finder [requires]
(defn require-finder [requires]
(reify NodeTraversal$Callback
(shouldTraverse ^boolean [this t n parent]
true)
Expand All @@ -18,17 +18,17 @@
(swap! requires conj (.. n getSecondChild getString)))
nil)))

(defn process-pass [compiler requires]
(defn find-require-pass [compiler requires]
(reify CompilerPass
(process [this _ root]
(NodeTraversal/traverseEs6 compiler root (finder requires)))))
(NodeTraversal/traverseEs6 compiler root (require-finder requires)))))

(defn find-requires [f]
(let [requires (atom [])
module (doto (JSModule. "$singleton$")
(.add (SourceFile/fromFile f)))
closure-compiler (com.google.javascript.jscomp.Compiler.)
pass (process-pass closure-compiler requires)]
pass (find-require-pass closure-compiler requires)]
(doseq [input (.getInputs module)]
(.process pass nil (.getAstRoot input closure-compiler)))
@requires))
Expand Down
185 changes: 101 additions & 84 deletions src/cljsjs/npm/build.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,101 +2,51 @@
(:require [cheshire.core :as json]
[clojure.java.io :as io]
[clojure.string :as string]
[clojure.set :as set]
[cljsjs.closure :as closure]
[boot.util :as util]
[boot.util :refer [info]]
[boot.core :as boot]
[boot.task.built-in :as built-in]))
[boot.task.built-in :as built-in]
[cljsjs.npm.util :as util]))

(defn read-json [file]
(with-open [r (io/reader file)]
(json/parse-stream r true)))
(if (.exists file)
(with-open [r (io/reader file)]
(json/parse-stream r true))))

(defn parse-version [version-pattern]
(let [[_ version] (re-find #"[\^](.*)" version-pattern)]
version))

(defn copy-main [out {:keys [name main]}]
(io/copy (io/file "node_modules" name main)
(doto (io/file out "cljsjs.npm" name main)
(io/make-parents))))

(defn with-files
"Runs middleware with filtered fileset and merges the result back into complete fileset."
[p middleware]
(fn [next-handler]
(fn [fileset]
(let [merge-fileset-handler (fn [fileset']
(next-handler (boot/commit! (assoc fileset :tree (merge (:tree fileset) (:tree fileset'))))))
handler (middleware merge-fileset-handler)
fileset (assoc fileset :tree (reduce-kv
(fn [tree path x]
(if (p x)
(assoc tree path x)
tree))
(empty (:tree fileset))
(:tree fileset)))]
(handler fileset)))))

(defn strip-node-modules [path]
(string/replace path #"^node_modules/" ""))

(defn package-path [full-path]
(second (re-find #"^node_modules/[^/]*/(.*)" full-path)))

(defn aname [package-name main? package-path]
(-> (str package-name (if-not main?
(str "/" (string/replace package-path #"\.js$" ""))))
(string/replace #"/" "\\$")))
(if main?
package-name
(-> package-path
(string/replace #"\.js$" "")
(string/replace #"/" "\\$"))))

(defn normalize-url
"Simple URL normalization logic for import paths. Can normalize
relative paths."
[url-string]
(loop [result nil
parts (string/split url-string #"/")]
(if (seq parts)
(let [part (first parts)]
(case part
;; Skip empty
"" (recur result (rest parts))
;; Skip "."
"." (recur result (rest parts))
;; Remove previous part, if there are previous non ".." parts
".." (if (and (seq result) (not= ".." (first result)))
(recur (rest result) (rest parts))
(recur (conj result part) (rest parts)))
(recur (conj result part) (rest parts))))
(string/join "/" (reverse result)))))

(defn drop-last-url-part [path]
(string/join "/" (butlast (string/split path #"/"))))
(defn relative-require? [require-path]
(.startsWith require-path "."))

(defn package'
"A Task, but not."
[{:keys [package-name main]}]
[{:keys [package-name main files]}]
(let [out (boot/tmp-dir!)]
(fn middleware [next-handler]
(fn handler [fileset]
(util/info "Package %s\n" package-name)
(let [files (->> (file-seq (io/file "node_modules" package-name))
(remove #(re-find #"^node_modules/.*/node_modules" (.getPath %)))
(remove #(re-find #"^node_modules/.*/dist" (.getPath %)))
(filter #(.endsWith (.getName %) ".js"))
(map (fn [file]
(let [path (.getPath file)
module-path (package-path path)
module-name (aname package-name (= main module-path) module-path)
requires (mapv (fn [require]
(if (.startsWith require ".")
(aname package-name false (normalize-url (str (drop-last-url-part module-path) "/" require)))
(string/replace require #"/" "\\$")))
(closure/find-requires file))]
(io/copy file (doto (io/file out "cljsjs.npm" (strip-node-modules path))
(io/make-parents)))
{:file (str "cljsjs.npm/" (strip-node-modules path))
:provides [module-name]
:requires requires
:module-type :commonjs}))))]
(info "Package %s\n" package-name)
(let [files (->> files
(map (fn [{:keys [output input deps]}]
(io/copy (io/file input)
(doto (io/file out output)
(io/make-parents)))
deps)))]
(doto (io/file out "deps.cljs")
(io/make-parents)
(spit (pr-str {:foreign-libs (vec files)}))))
Expand All @@ -105,26 +55,93 @@
boot/commit!
next-handler)))))

(defn generate-stuff' [path]
(if-let [package-index (read-json (io/file path "package.json"))]
(let [packages (map name (keys (:dependencies package-index)))
packages (filter identity (mapcat (fn [package-name]
(when-let [package (some-> (read-json (io/file path "node_modules" package-name "package.json"))
(clojure.set/rename-keys {:name :package-name})
(select-keys [:package-name :version :main :files :dependencies])
(assoc :path path))]
(println "adding" package-name)
(concat [package]
(generate-stuff' (io/file path "node_modules" package-name)))))
packages))]
packages)))

(defn generate-stuff [path]
(let [packages (generate-stuff' path)
packages (group-by :package-name packages)
packages (map (fn [[package-name x]]
(let [versions (set (map :version x))]
(when (seq (rest versions))
(println "multiple versions" package-name versions))
[package-name (first x)]))
packages)]
(into {} packages)))

(defn read-files [packages]
(->> (vals packages)
(map (fn [{:keys [path files package-name main] :as package}]
(assoc package :files (->> (if files
(conj (mapcat #(file-seq (io/file path "node_modules" package-name %)) files)
(io/file path "node_modules" package-name "package.json"))
(->> (file-seq (io/file path "node_modules" package-name))
(remove #(re-find (re-pattern (str "^" (.getPath path) "/node_modules/" package-name "/node_modules")) (.getPath %)))))
(filter #(.exists %))
(filter #(or (.endsWith (.getName %) ".js")
(= (.getName %) "package.json")))
;; FIXME:
(remove #(.contains (.getName %) "$"))
(map (fn [file]
(let [x-path (.getPath file)
module-path (string/replace (.getPath file) #"^.*node_modules/" "")
module-name (aname package-name (= (util/normalize-url (str package-name "/" (or main "index.js"))) module-path) module-path)
requires (mapv (fn [require-path]
(if (relative-require? require-path)
(aname package-name false (util/normalize-url (str (util/drop-last-url-part module-path) "/" require-path)))
(string/replace require-path #"/" "\\$")))
(closure/find-requires file))]
{:input (.getPath file)
:output (util/normalize-url (str "cljsjs.npm/" (strip-node-modules module-path)))
:deps {:file (util/normalize-url (str "cljsjs.npm/" (strip-node-modules module-path)))
:provides [module-name]
:requires requires
:module-type :commonjs}})))))))
(map (juxt :package-name identity))
(into {})))

(defn check-requires [stuff]
(let [provides (set (mapcat (comp :provides :deps) stuff))
requires (set (mapcat (comp :requires :deps) stuff))]
; (println provides requires)
(when-let [missing (set/difference requires provides)]
(println "missing" missing))
stuff))

(boot/deftask package
[]
(let [package-index (read-json (io/file "./package.json"))
packages (map name (keys (:dependencies package-index)))]
(let [packages-map (read-files (generate-stuff (io/file ".")))
packages (vals packages-map)]
(fn middleware [next-handler]
(let [next-handler (reduce (fn [next-handler package-name]
(let [package-json (-> (read-json (io/file "node_modules" package-name "package.json"))
(clojure.set/rename-keys {:name :package-name}))
middleware (with-files (constantly false)
(comp (package' package-json)
(built-in/pom :project (symbol "cljsjs.npm" package-name)
:version (:version package-json))
(built-in/jar)
(built-in/show :fileset true)))]
(let [next-handler (reduce (fn [next-handler {:keys [package-name version path dependencies] :as m}]
(let [middleware (util/with-files (constantly false)
(comp (package' m)
(built-in/pom :project (symbol "cljsjs.npm" package-name)
:version version
:dependencies (map (fn [[k _]]
[(symbol "cljsjs.npm" (name k)) (:version (get packages-map (name k)))])
dependencies))
(built-in/jar)
(built-in/show :fileset true)))]
(middleware next-handler)))
next-handler
(reverse packages))]
(fn handler [fileset]
(next-handler fileset))))))

(comment
(check-requires (read-files (generate-stuff (io/file "."))))
(get (generate-stuff ".") "loose-envify")
(read-json (io/file "node_modules" "react" "package.json"))
(boot.core/boot (comp (package) (boot.task.built-in/target))))
(boot.core/boot (comp (package) (boot.task.built-in/target) (boot.task.built-in/install))))
44 changes: 44 additions & 0 deletions src/cljsjs/npm/util.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
(ns cljsjs.npm.util
(:require [boot.core :as boot]
[clojure.string :as string]))

(defn with-files
"Runs middleware with filtered fileset and merges the result back into complete fileset."
[p middleware]
(fn [next-handler]
(fn [fileset]
(let [merge-fileset-handler (fn [fileset']
(next-handler (boot/commit! (assoc fileset :tree (merge (:tree fileset) (:tree fileset'))))))
handler (middleware merge-fileset-handler)
fileset (assoc fileset :tree (reduce-kv
(fn [tree path x]
(if (p x)
(assoc tree path x)
tree))
(empty (:tree fileset))
(:tree fileset)))]
(handler fileset)))))


(defn normalize-url
"Simple URL normalization logic for import paths. Can normalize
relative paths."
[url-string]
(loop [result nil
parts (string/split url-string #"/")]
(if (seq parts)
(let [part (first parts)]
(case part
;; Skip empty
"" (recur result (rest parts))
;; Skip "."
"." (recur result (rest parts))
;; Remove previous part, if there are previous non ".." parts
".." (if (and (seq result) (not= ".." (first result)))
(recur (rest result) (rest parts))
(recur (conj result part) (rest parts)))
(recur (conj result part) (rest parts))))
(string/join "/" (reverse result)))))

(defn drop-last-url-part [path]
(string/join "/" (butlast (string/split path #"/"))))

0 comments on commit 9e88e36

Please sign in to comment.