l3nz / cli-matic

Compact, hands-free [sub]command line parsing library for Clojure.
Eclipse Public License 2.0
365 stars 29 forks source link

try-catch-all macro does not work for cljs #133

Open mobileink opened 3 years ago

mobileink commented 3 years ago

version

Commit 3e072260e359be51bf6646e219042c319dd9f5f8

platform

I'm adapting cli-matic to work with nodejs using the Clojure CLI tools.

problem

When I pass an unknown subcommand I get a crash involving a Java Throwable

repro

I don't have an example yet, maybe later this week. I'm still testing the code.

expected behavior

Catch the error and emit a message as designed. With my fix I get a stacktrace with

message: 'Unknown subcommand: foobar - in path ["obazl" "foobar"]',
... some more stuff

actual behavior

/Users/gar/bazel/obazl/tool/out/cli_matic/utils_v2.js:116
}catch (e1580){if((e1580 instanceof java.lang.Throwable)){
                                    ^

ReferenceError: java is not defined
... stack trace ...

analysis

The current code won't work because (I think) it tries to use a reader conditional to deal with cljs macro definition. The code (in platform_macros.cljc) looks like this, schematically:

#?(:clj (defmacro foo ...definition using java stuff ...))
#?(:cljs (defmacro foo ...definition using only cljs-friendly stuff...))

and usage is:

  #?(:clj [cli-matic.platform-macros :refer [try-catch-all]]\n
     :cljs [cli-matic.platform-macros :refer-macros [try-catch-all]]\n               )

I believe the problem is that platform_macros.cljc will be processed in clj mode for the macros, so the :clj version ends up being used.

solution

Here's an alternative that seems to work:

macros_cljs.cljc: (defmacro foo ... definition, in clj, for cljs version ...) macros_clj.cljc: (defmacro foo ...definition, in clj, using java stuff ...)

Usage:

   #?(:clj  [cli-matic.macros-clj :refer [try-catch-all]]
      :cljs [cli-matic.macros-cljs :refer-macros [try-catch-all]])

So macros_cljs.cljc contains a clj definition for the macro that works for cljs. The file must be .cljc because it is processed twice, once as clj for the macro and once as cljs. At least I think that's how it works, based on trial and error. Note that there are no reader conditionals in the macro definition files - there would be no point, since such macros are always :clj.