Skip to content

Commit

Permalink
Add datascript and datascript-transit features (babashka#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
logseq-cldwalker authored Apr 11, 2022
1 parent 3f4e801 commit c72d8fd
Show file tree
Hide file tree
Showing 20 changed files with 236 additions and 33 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

For a list of breaking changes, check [here](#breaking-changes).

## 0.3.x

- Add initial features support with datascript and datascript-transit
- Include `cognitect.transit` as built-in dependency
- Add `clojure.pprint/print-table`

## 0.3.4

- Don't load modules more than once
Expand Down
49 changes: 38 additions & 11 deletions bb.edn
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,47 @@
:tasks
{:requires ([babashka.fs :as fs]
[cheshire.core :as json]
[clojure.edn :as edn]
[clojure.pprint :as pp]
[clojure.string :as str])

:init (do (def ^:dynamic *test* (= "true" (System/getenv "NBB_TESTS")))
(def windows? (-> (System/getProperty "os.name")
str/lower-case
(str/starts-with? "win")))
(when *test* (println "Tests are enabled.."))
(defn wrap-cmd [cmd]
(let [cmd (if *test*
(str (str/replace cmd
"-M" "-M:test")
" --config-merge shadow-tests.edn")
cmd)]
:init (do
(def ^:dynamic *test* (= "true" (System/getenv "NBB_TESTS")))
(def windows? (-> (System/getProperty "os.name")
str/lower-case
(str/starts-with? "win")))
(def features (some-> (System/getenv "NBB_FEATURES")
(str/split (re-pattern ","))))
(when *test* (println "Tests are enabled.."))
(defn wrap-cmd [cmd]
(let [cmd (if features
(format "-Sdeps '%s' %s"
{:deps
(into {}
(map (fn [f]
[(symbol (str f "/deps"))
{:local/root (str "features/" f)}])
features))}
cmd)
cmd)
cmd (if *test*
(str (str/replace cmd
"-M" "-M:test")
" --config-merge shadow-tests.edn")
cmd)]
(if features
(apply str cmd
(map (fn [f] (format " --config-merge features/%s/shadow-cljs.edn" f))
features))
cmd)))
;; Build requires map for nbb to require feature namespaces
(when features
(let [m (->> (fs/glob "features" "**/nbb_features.edn")
(mapcat (comp edn/read-string slurp str) )
(mapcat (fn [{:keys [namespaces js]}]
(mapv (fn [n] [n js]) namespaces)))
(into {}))]
(spit "src/nbb/feature-requires.edn" (with-out-str (pp/pprint m))))))
clean (fs/delete-tree "lib")

compile (clojure (wrap-cmd "-M -m shadow.cljs.devtools.cli --force-spawn compile modules"))
Expand Down
3 changes: 2 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@
org.babashka/sci-configs
{:git/url "https://github.com/babashka/sci-configs"
:git/sha "d197da2413bd8e4e5c43159620ddfe4286c731ba"}
org.clojure/tools.cli {:mvn/version "1.0.206"}}}
org.clojure/tools.cli {:mvn/version "1.0.206"}
com.cognitect/transit-cljs {:mvn/version "0.8.269"}}}
6 changes: 6 additions & 0 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,9 @@ See [js-interop docs](https://github.com/applied-science/js-interop).
### clojure.tools.cli

- `format-lines`, `summarize`, `get-default-options`, `parse-opts`, `make-summary-part`

## transit-cljs

### cognitect.transit

- `write`, `writer`, `write-handler`, `write-meta`, `read`, `read`, `read-handler`, `tagged-value`
13 changes: 13 additions & 0 deletions doc/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,16 @@ Then run `node out/nbb_main.js <args>` to test the compiled nbb.
## Test

To run tests, run `bb run-tests` for unit tests and `bb run-integration-tests` for running integration tests.

## Features

`nbb` can optionally bundle additional Clojure(Script) libraries as features. These can be specified with `$NBB_FEATURES` to compilation tasks e.g. `NBB_FEATURES=datascript,datascript-transit bb release`. The following features are provided:

* [datascript](https://github.com/tonsky/datascript)
* [datascript-transit](https://github.com/tonsky/datascript-transit)

To add a new feature, add the following under `features/$LIBRARY/`:
- `deps.edn` - Dependencies for library
- `shadow-cljs.edn` - Compiler options to build library in advanced/release mode
- `src/nbb/impl/$LIBRARY.cljs` - Sci mappings
- `src/nbb_features.edn` - Configuration to map namespaces to js assets
2 changes: 2 additions & 0 deletions features/datascript-transit/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{:deps
{datascript-transit/datascript-transit {:mvn/version "0.3.0"}}}
3 changes: 3 additions & 0 deletions features/datascript-transit/shadow-cljs.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{:modules
{:nbb_datascript_transit {:init-fn nbb.impl.datascript-transit/init
:depends-on #{:nbb_core :nbb_datascript :nbb_transit}}}}
18 changes: 18 additions & 0 deletions features/datascript-transit/src/nbb/impl/datascript_transit.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
(ns nbb.impl.datascript-transit
{:no-doc true}
(:require [datascript.transit :as dt]
[nbb.core :as nbb]
[sci.core :as sci :refer [copy-var]]))

(def transit-ns (sci/create-ns 'datascript.transit nil))

(def transit-namespace
{'read-handlers (copy-var dt/read-handlers transit-ns)
'write-handlers (copy-var dt/write-handlers transit-ns)
'read-transit-str (copy-var dt/read-transit-str transit-ns)
'write-transit-str (copy-var dt/write-transit-str transit-ns)})

(defn init []
(nbb/register-plugin!
::datascript-transit
{:namespaces {'datascript.transit transit-namespace}}))
3 changes: 3 additions & 0 deletions features/datascript-transit/src/nbb_features.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[{:name logseq/datascript-transit
:namespaces [datascript.transit]
:js "./nbb_datascript_transit.js"}]
2 changes: 2 additions & 0 deletions features/datascript/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{:deps
{datascript/datascript {:mvn/version "1.3.12"}}}
6 changes: 6 additions & 0 deletions features/datascript/shadow-cljs.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{:compiler-options {:externs ["datascript/externs.js"]}
:modules
{:nbb_datascript {:init-fn nbb.impl.datascript/init
;; From https://github.com/tonsky/datascript/issues/298#issuecomment-813790783
:prepend "if (global) { global.datascript = datascript } else if (window) { window.datascript = datascript } else { var datascript = {}}"
:depends-on #{:nbb_core}}}}
49 changes: 49 additions & 0 deletions features/datascript/src/nbb/impl/datascript.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
(ns nbb.impl.datascript
{:no-doc true}
(:require [datascript.core :as d]
[datascript.db :as db]
[nbb.core :as nbb]
[sci.core :as sci :refer [copy-var]]))

(def core-ns (sci/create-ns 'datascript.core nil))
(def db-ns (sci/create-ns 'datascript.db nil))

(def core-namespace
{'q (copy-var d/q core-ns)
'empty-db (copy-var d/empty-db core-ns)
'db-with (copy-var d/db-with core-ns)
'filter (copy-var d/filter core-ns)
'init-db (copy-var d/init-db core-ns)
'datom (copy-var d/datom core-ns)
'datoms (copy-var d/datoms core-ns)
'pull (copy-var d/pull core-ns)
'pull-many (copy-var d/pull-many core-ns)
'entity (copy-var d/entity core-ns)
'tx0 (copy-var d/tx0 core-ns)
'db (copy-var d/db core-ns)
'with (copy-var d/with core-ns)
'touch (copy-var d/touch core-ns)
'index-range (copy-var d/index-range core-ns)
'listen! (copy-var d/listen! core-ns)
'conn-from-db (copy-var d/conn-from-db core-ns)
'conn-from-datoms (copy-var d/conn-from-datoms core-ns)
'transact! (copy-var d/transact! core-ns)
'create-conn (copy-var d/create-conn core-ns)
'reset-conn! (copy-var d/reset-conn! core-ns)
'from-serializable (copy-var d/from-serializable core-ns)
'serializable (copy-var d/serializable core-ns)})

(def db-namespace
{'db-from-reader (copy-var db/db-from-reader db-ns)
'datom-from-reader (copy-var db/datom-from-reader db-ns)
'datom-added (copy-var db/datom-added db-ns)
'datom-tx (copy-var db/datom-tx db-ns)
'datom (copy-var db/datom db-ns)
'DB (copy-var db/DB db-ns)
'Datom (copy-var db/Datom db-ns)})

(defn init []
(nbb/register-plugin!
::datascript
{:namespaces {'datascript.core core-namespace
'datascript.db db-namespace}}))
3 changes: 3 additions & 0 deletions features/datascript/src/nbb_features.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[{:name logseq/datascript
:namespaces [datascript.core datascript.db]
:js "./nbb_datascript.js"}]
14 changes: 11 additions & 3 deletions script/nbb_tests.clj
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,15 @@
"(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})")))))

(deftest pprint-test
(is (= (str "(0 1 2 3 4 5 6 7 8 9)\n")
(nbb "-e" "(require '[cljs.pprint :as pp]) (with-out-str (pp/pprint (range 10)))")))
(testing "pprint"
(is (= (str "(0 1 2 3 4 5 6 7 8 9)\n")
(nbb "-e" "(require '[cljs.pprint :as pp]) (with-out-str (pp/pprint (range 10)))"))))
(testing "cljs.pprint = clojure.pprint"
(is (= (str "(0 1 2 3 4 5 6 7 8 9)\n")
(nbb "-e" "(require '[clojure.pprint :as pp]) (with-out-str (pp/pprint (range 10)))")))))
(nbb "-e" "(require '[clojure.pprint :as pp]) (with-out-str (pp/pprint (range 10)))"))))
(testing "print-table"
(is (= "\n| :a |\n|----|\n| 1 |\n| 2 |\n"
(nbb* "-e" "(require '[clojure.pprint :as pp]) (do (pp/print-table [{:a 1} {:a 2}]))")))))

(deftest api-test
(tasks/shell {:dir "test-scripts/api-test"} (npm "install"))
Expand Down Expand Up @@ -161,6 +165,10 @@
(is (= expected-cljs-bean-output
(normalize-interop-output (nbb* "examples/cljs-bean/example.cljs")))))

(deftest transit-test
(is (= {:fruits [:apple :banana :pear]}
(nbb "test-scripts/transit.cljs" (pr-str {:fruits [:apple :banana :pear]})))))

(deftest error-test
(let [err (-> (process ["node" "lib/nbb_main.js" "test-scripts/error.cljs"]
{:out :string
Expand Down
2 changes: 2 additions & 0 deletions shadow-cljs.edn
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
:depends-on #{:nbb_core}}
:nbb_tools_cli {:init-fn nbb.impl.tools-cli/init
:depends-on #{:nbb_core :nbb_goog_string}}
:nbb_transit {:init-fn nbb.impl.transit/init
:depends-on #{:nbb_core}}
:nbb_nrepl_server {:init-fn nbb.impl.nrepl-server/init
:depends-on #{:nbb_core :nbb_api}}
:nbb_repl {:init-fn nbb.impl.repl/init
Expand Down
46 changes: 32 additions & 14 deletions src/nbb/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
["path" :as path]
["url" :as url]
[clojure.string :as str]
[clojure.edn :as edn]
[goog.object :as gobj]
[nbb.classpath :as cp]
[nbb.common :refer [core-ns]]
[sci.core :as sci]
[sci.impl.vars :as vars]
[shadow.resource :as resource]
[shadow.esm :as esm])
(:require-macros [nbb.macros
:as macros
Expand Down Expand Up @@ -105,6 +107,14 @@

(declare old-require)

(defn- get-feature-requires
[]
(edn/read-string (resource/inline "nbb/feature-requires.edn")))

;; Lazily build map once to not effect initial load time
(def feature-requires
(memoize get-feature-requires))

(defn ^:private handle-libspecs [libspecs]
(if (seq libspecs)
(let [fst (first libspecs)
Expand All @@ -120,7 +130,7 @@
current-ns (symbol current-ns-str)]
(if as-alias
(do (old-require fst)
(handle-libspecs (next libspecs)))
(handle-libspecs (next libspecs)))
(case libname
;; built-ins
(reagent.core)
Expand Down Expand Up @@ -159,7 +169,12 @@
(load-module "./nbb_tools_cli.js" libname as refer rename libspecs)
(goog.string goog.string.format)
(load-module "./nbb_goog_string.js" libname as refer rename libspecs)
(if (string? libname)
(cognitect.transit)
(load-module "./nbb_transit.js" libname as refer rename libspecs)
(cond
(get (feature-requires) libname)
(load-module (get (feature-requires) libname) libname as refer rename libspecs)
(string? libname)
;; TODO: parse properties
(let [[libname properties] (str/split libname #"\$" 2)
properties (when properties (.split properties "."))
Expand Down Expand Up @@ -199,11 +214,12 @@
mod))))))]
(-> mod
(.then after-load)))
:else
;; assume symbol
(if (sci/eval-form @sci-ctx (list 'clojure.core/find-ns (list 'quote libname)))
;; built-in namespace
(do (old-require fst)
(handle-libspecs (next libspecs)))
(handle-libspecs (next libspecs)))
(let [file (str/replace (str munged) #"\." "/")
files [(str file ".cljs") (str file ".cljc")]
dirs @cp/classpath-entries
Expand Down Expand Up @@ -234,16 +250,16 @@
(if-let [clazz (get-in @sci-ctx [:class->opts libname :class])]
(do (when as
(swap! (:env @sci-ctx) assoc-in [:namespaces current-ns :imports as] libname))
(doseq [field refer]
(let [mod-field (gobj/get clazz (str field))
internal-subname (str current-ns "$" munged "$" field)]
(swap! sci-ctx sci/merge-opts {:classes {internal-subname mod-field}})
;; Repeat hack from above
(let [field (get rename field field)]
(swap! (:env @sci-ctx)
assoc-in
[:namespaces current-ns :imports field] internal-subname))))
(handle-libspecs (next libspecs)))
(doseq [field refer]
(let [mod-field (gobj/get clazz (str field))
internal-subname (str current-ns "$" munged "$" field)]
(swap! sci-ctx sci/merge-opts {:classes {internal-subname mod-field}})
;; Repeat hack from above
(let [field (get rename field field)]
(swap! (:env @sci-ctx)
assoc-in
[:namespaces current-ns :imports field] internal-subname))))
(handle-libspecs (next libspecs)))
(js/Promise.reject (js/Error. (str "Could not find namespace: " libname)))))))))))
(js/Promise.resolve @sci/ns)))

Expand Down Expand Up @@ -399,7 +415,8 @@
'array (sci/copy-var array core-ns)
'tap> (sci/copy-var tap> core-ns)
'add-tap (sci/copy-var add-tap core-ns)
'remove-tap (sci/copy-var remove-tap core-ns)}
'remove-tap (sci/copy-var remove-tap core-ns)
'uuid (sci/copy-var uuid core-ns)}

'clojure.main {'repl-requires (sci/copy-var
repl-requires
Expand All @@ -421,6 +438,7 @@
:set gobj/set
:getKeys gobj/getKeys
:getValueByKeys gobj/getValueByKeys}
'ExceptionInfo js/Error
'Math js/Math}
:disable-arity-checks true}))

Expand Down
2 changes: 2 additions & 0 deletions src/nbb/feature-requires.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
;; This is a stub file which is only populated when nbb is built with features
{}
22 changes: 22 additions & 0 deletions src/nbb/impl/transit.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
(ns nbb.impl.transit
(:require [cognitect.transit :as transit]
[nbb.core :as nbb]
[sci.core :as sci :refer [copy-var]]))

(def transit-ns (sci/create-ns 'cognitect.transit nil))

(def transit-namespace
{'write (copy-var transit/write transit-ns)
'writer (copy-var transit/writer transit-ns)
'write-handler (copy-var transit/write-handler transit-ns)
'write-meta (copy-var transit/write-meta transit-ns)
'read (copy-var transit/read transit-ns)
'reader (copy-var transit/reader transit-ns)
'read-handler (copy-var transit/read-handler transit-ns)
'tagged-value (copy-var transit/tagged-value transit-ns)
'ListHandler (copy-var transit/ListHandler transit-ns)})

(defn init []
(nbb/register-plugin!
::transit
{:namespaces {'cognitect.transit transit-namespace}}))
10 changes: 6 additions & 4 deletions src/nbb/pprint.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
(binding [*print-fn* @sci/print-fn]
(apply pp/pprint args)))

(defn print-table [& args]
(binding [*print-fn* @sci/print-fn]
(apply pp/print-table args)))

(def pprint-namespace
{'pprint (sci/copy-var pprint pns)})
{'pprint (sci/copy-var pprint pns)
'print-table (sci/copy-var print-table pns)})

(defn init []
(nbb/register-plugin!
::pprint
{:namespaces {'cljs.pprint pprint-namespace}}))



Loading

0 comments on commit c72d8fd

Please sign in to comment.