Search code examples
clojureclojurescript

Clojurescript macros: Using the node api at compile time


I'm writing a cli script with lumo and I want the following macro, but using readFileSync from nodejs.

(defmacro compile-time-slurp [path]
  ;; slurp is not defined in self hosted cljs
  (slurp path))

Is this possible?

EDIT: To be more clear, this is in self-hosted clojurescript, where the slurp function is not available at macro-expansion-time.


Solution

  • ClojureScript macros are written in the Clojure language and have roughly this lifecycle:

    1. jvm loads Clojure runtime, gets ready and a bunch of other stuff.
    2. macro is compiled
    3. macro runs and produces a new ClojureScript expression
    4. if that expression is a macro loop again.

    This omits all the parts done in the rest of the ClojureScript compiler (which is most of it) so we can focus on the fact that ClojureScript macros only have access to the parts of Clojure that are available from the JVM and not node while they are running the form returned by that macro which will become part of the finished ClojureScript program has access to the node APIs such as readFileSync.

    In short, your macro should return a call to readFileSync rather than do the file reading while the macro is running. If your code really needs to read some files while evaluating the macro, because for instance they contain the code to output or something, then you would need to use the Clojure form to read those files such as the call to slurp you have above.