cherry 2024-08-29

Does Cherry support the #html [:div "xxx"] syntax of squint? I'm getting Error: No reader function for tag html.

Can I use defclass from a macro?

(defmacro create-class [class-name] `(defclass ~class-name))                                            

(create-class MyTestClass)
This never creates a class, but rather produces this code:
var create_class = (function (_AMPERSAND_form, _AMPERSAND_env, class_name) {
return cherry_core.sequence.call(null, cherry_core.seq.call(null, cherry_core.concat.call(null, cherry_core.list.call(null, cherry_core.symbol.call(null, "defclass")), cherry_core.list.call(null, class_name))));
});
create_class.call(null, MyTestClass);
Beyond the minimalistic example provided above, my use-case are web components which always have the same definition, all that changes is the render fn, so I'd like to reduce the boilerplate.

No worries, take your time.

Thanks for the reminder. Other issues got in the way, sorry. Issue welcome.

I might have some time today, hopefully

I'm on it now

have it working, but need to improve/clean up a little

Thank you very much @borkdude 🙏 It's really appreciated.

released in 0.3.20

Thank you. I will check later today, I'm just waking up.

@borkdude oh this is the hiccup. Nice!!! Thank you 🙏

This thread was actually about the macros though. I haven't reported it as an issue (just made the repro you asked for, see above). Do you want me to create an issue with the repro link in it?

But I'm definitely going to use the #html literal, it was me who reported that as you know so I'm very happy about that.

I can confirm it works like a charm, yay!

Issue please

I'll check out the repro repository now, sorry I fixed the wrong issue :)

@jakub.stastny.pt_serv ok, now you should be able to write the macro as:

(ns macros)

(defmacro create-class [class-name & args]
  `(cherry.core/defclass ~class-name ~@args))

with 0.3.22

Thank you @borkdude, will check it out shortly.

Btw, I wonder if you could have also solved this without a macro using extends or so

It'd be slightly more verbose I think, it'd be class, extends and then WebComponents.define or what's the thing that registers it.

By the way the log message shows squint now rather than cherry:

$ npx cherry compile src/lib/macros.cljs
[squint] Compiling CLJS file: src/lib/macros.cljs

lol, let me fix that

fixed on cherry main

👍 1

@borkdude I'm having issues with this one actually. So I'm in the repro repository and I have this:

(ns my-footer
  (:require-macros [foo.macros :refer [create-class]]))
The file src/foo/macros.cljs is there with (ns foo.macros definition. Yet it doesn't work.

in the repro repository you only had [macros :refer ...] right?

or did you update the repro?

Let me check, I thought this is how it was but let me see.

You're right, but even there I'm getting the same issue.

npx cherry compile src/components/my-footer.cljs
[squint] Compiling CLJS file: src/components/my-footer.cljs

node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^
Error: The "path" argument must be of type string or an instance of Buffer or URL. Received null
This happens on the require-macros line.

Even if the macros file is empty (beyond ns declaration), it still fails. It looks like it cannot find the file at all.

lemme try again locally

you shouldn't add this to your macro namespace:

(:require [cherry.core :refer [defclass]])

instead, write this:

(ns macros)

(defmacro create-class [class-name]
  `(cherry.core/defclass ~class-name))

note that the output will still fail due to the absence of a constructor in the defclass

OK now it compiles, will try on the main project whether it works.

you can now also print from the cherry macros

which wasn't possible before

so if you want to inspect the macro expansion, you can print it before returning it

also js interop is possible, so js/console.log etc

@borkdude some of the serialisation in macros is broken, it gives me this$.attachShadow([object Object]):

class MyFooter extends HTMLElement {
  constructor() {
super();const self__ = this;
const this$ = this;
this$.attachShadow([object Object])  }
connectedCallback() {
const this$ = this;
const self__ = this;return render.call(null, this$.shadowRoot);
}};
customElements.define("my-footer", MyFooter);
The macro:
(defmacro component [class-name element-name render-fn]
  `(do
     (cherry.core/defclass ~class-name
       (~'extends js/HTMLElement)
       (~'constructor [~'this]
         (~'super)
         (.attachShadow ~'this #js {"mode" "open"}))
       ~'Object
       (~'connectedCallback [~'this]
         (~render-fn (.-shadowRoot ~'this))))
     (js/customElements.define ~element-name ~class-name)))
I will see if I can come up with a workaround and once I'm more familiar with the issue, I will report it to GH issues.

you need to quote this: js/HTMLElement

no sorry, it's already in syntax-quote

what does the macro-expansion look like. before posting an issue, let's just check first if there's nothing wrong here

This won't work: #js {"mode" "open"}

That's exactly the problematic line, yes.

you can't emit a JS object from a macro, probably best to write (js-obj "mode" "open")

👍 1

OK now it all works. Cool!

👍 1

got a little busy, won't be able to check this this weekend, hopefully next week

👍 1

@borkdude Sorry to bother you about this, but is there any update? If it's on the back-burner now, let me know and I will create an issue from the repro so it gets done eventually. In the end I could use Squint for now (although I have to say I very much prefer Cherry).

You can't define macros in the same file as cherry code, they have to live in a separate file. Also you need to fully qualify the defclass symbol yourself since it's not a normal symbol that is available in clojure

🙏 1

squint.edn doesn't exist for cherry though, but the src folder is used by default I believe

so just put a src/foo/macros.cljs file in your project

then (:require-macros [foo.macros :as m]) or so

@borkdude Also you need to fully qualify the defclass symbol yourself since it's not a normal symbol that is available in clojure This bit I'm not sure about. I had this:

;; src/macros.cljs
(ns macros (:require [cherry.core :refer [defclass]]))

(defmacro create-class [class-name]
  `(defclass ~class-name))
Upon reading about the fully qualified symbol, I changed it to this:
;; src/macros.cljs
(ns macros)

(defmacro create-class [class-name]
  `(cherry.core/defclass ~class-name))
But neither of these work (wouldn't compile with Error: Nothing specified to load).

is it possible to make a repro of this? I'll take a look tomorrow

Thanks. I'll do it later, will post an issue here.

cool, I'll check tomorrow