Fork me on GitHub
#clojurescript
<
2021-06-05
>
souenzzo03:06:48

Hello My team needs to deliver a nodejs library to another team The other team expect a typescript-like user experience: a beautiful docs website and maybe an autocomplete. Which tools I can use from cljs world to do that? Like, I can generate docs via JSDocs or some other tool that document the API for javascript users, not for clojure users.

dazld16:06:54

Did you figure this out? An option could be to emit JSDoc comments around your exported functions. Typescript will pick up those annotations.

dazld16:06:37

Probably your TS api docs would work then too.

dazld17:06:20

Pretty sure that would work.

dazld17:06:33

Little known fact about TS is that it falls back to jsdoc in some situations, and buried inside it is an implementation of supporting types via jsdoc comments.

dazld17:06:22

Guess this was on your radar already though

souenzzo18:06:23

very valuable all this information As a clj dev I doent even know how to start to search things like "how do typescript do autocomplete" thank you so much @U3ZUC5M0R, I will try to do some POC and maybe a blog post about it 🙂

👍 3
dazld18:06:26

I’m interested in this topic too - if you remember me when you have something concrete, please do ping

dazld18:06:12

It might even be that you can skip TS completely and just ship jsdoc comments.. perhaps.

dazld18:06:18

Some macro magic may be appropriate, translating specs into jsdoc..

dazld18:06:47

Interesting question, thanks for asking.

👍 3
chromalchemy14:06:34

What is the best practice to compile some EDN data in .clj file, for consumption in .cljs files? Considering .cljc file, but I only need the .clj code at compile time. I am trying to use a https://github.com/shegeley/airtable-clj to download my data, then use shadow-cljs to compile a web-site with live-reload. I am using https://github.com/OrgPad-com/volcano library, which runs the the web page templating code with shadow-cljs and Reagent cljs when in dev mode, then uses clj via Lein to compile static html for production. It uses .cljc files for this code. It is nice to have a responsive dev mode, but it feels confusing and limiting for me to constrain myself to only code that can be run in both runtimes? I don’t want to try to re-duplicate the AirTable download and parsing code, just to run it in cljs runtime. Maybe I’m over-thinking it. Seems like it should be possible to have some clj functions that return data, then depend upon them in proper shadow-cljs build. Hopefully without having to treat them both like alien runtimes: Lein compile the clj to edn, then pre-load that into shadow-cljs as an in-lined resource, or have the cljs use a fetch function to read it as an external resource. Any hints? Thanks

borkdude15:06:48

@chromalchemy you can do this using a macro

thheller15:06:03

depending on the total size I would recommend downloading it in CLJS. inlining is fine for really small files, eg via https://clojureverse.org/t/using-none-code-resources-in-cljs-builds/3745

chromalchemy15:06:02

Thanks guys. @thheller I have successfully inlined some data using that method on another project, it worked! And was crucial to that moment simple_smile. But wouldn’t I still need to run some process to download and save the data first, before shadow-cljs can inline it? How could this be worked into a repeatable shadow-cljs build? @borkdude I will try the macro solution too.

thheller15:06:55

if it can change over time I would manage that data on the server and have your frontend download it when needed

chromalchemy16:06:47

Ok, I will consider that. I wanted to keep production site relatively static and simple. It doesn’t have to change often. I will not be using cljs on the production site. The cljs is only running for live-reload (which is probably over-complicating this whole thing.

chromalchemy16:06:30

@thheller wrote in another post > macros rewrite Clojure code at compilation time. They just take the raw form that was passed into the call and rewrite it to something else. They never eval their arguments. > On top of that the macros for ClojureScript are expanded at compilation time which happens in Clojure on the JVM. So they don’t have access to any JS at all. So in my context, would putting the .clj based Airtable data request and parsing code into a macro “magically” make it run in .cljs also? Was just hoping it could eval the .clj code as part of the shadow-cljs compile phase, and .cljc files depend on that resulting data.

thheller16:06:35

it is not clear what you are trying to do here. would help to see some code. sounds like you are making the problem way more complicated that it needs to be.

thheller16:06:15

"eval the .clj code". using a macro does that, so sounds like you want to write a macro?

chromalchemy16:06:02

Hmm.. Ok I’ll try to sort it out. I wasn’t sure if the .clj macro from called from .cljs could eval and return the data. But it seems so. I appreciate your other suggestions though, and will them.

Takis_19:06:18

Hello I compiled this simple code

(ns tempproject.tempnamespace)(defn ^:export add_cj [n1 n2] (+ n1 n2))
And i got the js file , someone told me that i can access the add_cj by calling tempproject.tempnamespace.add_cj(1,2); for example and it works ,but i give this code to MongoDB and it says ReferenceError: tempproject is not defined

Takis_19:06:03

on the js that is generated i dont see a var temproject, but code works, i tested it

Takis_19:06:09

the way of accesing the function with tempproject.tempnamespace.add_cj(1,2); should be working in all js enviroments? can i use something else to access add_cj ?

thheller19:06:17

how did you compile it?

Takis_19:06:38

clojure -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version \"1.10.741\"}}}' -m cljs.main -O advanced -c 

thheller19:06:57

I don't know mongodb but I guess it probably expects some commonjs or ES module format

Takis_19:06:34

is there an alternative way to acces the exported function?

thheller19:06:02

do you have a JS example for the mongodb side? what it expects?

Takis_19:06:52

i use it with java , so i give the code as string

Takis_19:06:37

function add_cj(arg__0,arg__1) { if(typeof Math.imul == "undefined" || (Math.imul(0xffffffff,5) == 0)) {
    Math.imul = function (a, b) {
        var ah  = (a >>> 16) & 0xffff;
        var al = a & 0xffff;
        var bh  = (b >>> 16) & 0xffff;
        var bl = b & 0xffff;
        // the shift by 0 fixes the sign on the high part
        // the final |0 converts the unsigned value into a signed value
        return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
    }
}


            ;var c=this||self;function e(a){var b=a.length;if(0<b){for(var h=Array(b),d=0;d<b;d++)h[d]=a[d];return h}return[]};function f(){this.c=""}f.prototype.toString=function(){return"SafeScript{"+this.c+"}"};f.prototype.a=function(a){this.c=a};(new f).a("");function g(){this.g=""}g.prototype.toString=function(){return"SafeStyle{"+this.g+"}"};g.prototype.a=function(a){this.g=a};(new g).a("");function k(){this.f=""}k.prototype.toString=function(){return"SafeStyleSheet{"+this.f+"}"};k.prototype.a=function(a){this.f=a};(new k).a("");function l(){this.b=""}l.prototype.toString=function(){return"SafeHtml{"+this.b+"}"};l.prototype.a=function(a){this.b=a};(new l).a("\x3c!DOCTYPE html\x3e");(new l).a("");(new l).a("\x3cbr\x3e");var m={},n={};if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof p)var p={};if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof q)var q=null;if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof r)var r=null;if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof t)var t=null;if("undefined"!==typeof Symbol){var u=Symbol;"object"!=typeof u||!u||u instanceof Array||u instanceof Object||Object.prototype.toString.call(u)}
var v="undefined"!==typeof Math&&"undefined"!==typeof Math.imul&&0!==Math.imul(4294967295,5)?function(a,b){return Math.imul(a,b)}:function(a,b){var h=a&65535,d=b&65535;return h*d+((a>>>16&65535)*d+h*(b>>>16&65535)<<16>>>0)|0};function w(a){a=v(a|0,-862048943);a=0^(v(a<<15|a>>>-15,461845907)|0);a=(v(a<<13|a>>>-13,5)+-430675100|0)^0;a=v(a^a>>>16,-2048144789);v(a^a>>>13,-1028477387)}w(1);w(0);if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof x)var x=null;
"undefined"!==typeof console&&(q=function(){return console.log.apply(console,e(arguments))},r=function(){return console.error.apply(console,e(arguments))});if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof y)var y=function(){throw Error("cljs.core/*eval* not bound");};function z(a,b){return a+b}var A=["tempproject","tempnamespace","add_cj"],B=c;A[0]in B||"undefined"==typeof B.execScript||B.execScript("var "+A[0]);for(var C;A.length&&(C=A.shift());)A.length||void 0===z?B=B[C]&&B[C]!==Object.prototype[C]?B[C]:B[C]={}:B[C]=z; return tempproject.tempnamespace.add_cj(arg__0,arg__1); } 


console.log(add_cj(1,2));

Takis_19:06:01

this is my code , it runs from example in http://playcode.io.

thheller19:06:19

thats irrelevant to my question. I don't know the mongodb parts so I expect that it maybe requires something special to be exported or so

thheller19:06:46

and this isn't advanced output, so you did some custom wrapping?

Takis_19:06:00

yes i didnt do anything big

Takis_19:06:24

only wrap it on function add_cj and in the end i added return tempproject.tempnamespace.add_cj(arg__0,arg__1);

Takis_19:06:35

to make the code a function

thheller19:06:36

yeah but why?

Takis_19:06:49

mongodb need 1 function as argument

Takis_19:06:01

not any js code

thheller19:06:11

unless you can point me to some mongodb docs or example I really cannot help you

Takis_19:06:44

ok i know , but me accesing the function with tempproject.tempnamespace.add_cj(arg__0,arg__1); is ok?

Takis_19:06:30

ok do you know how to access it properly? it works this for example in http://playcode.io

thheller19:06:47

> unless you can point me to some mongodb docs or example I really cannot help you

Takis_19:06:07

i dont have a place to explain limitations

Takis_19:06:18

i was searching for that in mongodb

Takis_19:06:38

but for normal js , how i should acces the exported function ?

Takis_19:06:36

but this wont help

Takis_19:06:27

it just says give a javascript function as string

Takis_19:06:08

it expects this "function(arg1, arg2, ...) { ... }"

thheller19:06:58

that looks like it'll just serialize the entire code and send it to the server? that'll be tricky with cljs

Takis_19:06:56

the weird thing is that the code works, even in mongo shell , when i do load(myfunction.js);

Takis_19:06:24

i can call it as add_cj(1,2); fine , but when i send it as string it says reference not found

thheller19:06:00

the ^:export is likely the problem. that wants to export the whole thing into the global scope, which may not be allowed or blocked for security reasons

Takis_19:06:13

in the past it worked, i dont know why , i used that code in MongoDB , maybe i changed something i dont know or MongoDB new version blocked something

Takis_19:06:41

all i want is 1 Clojurescript function to become 1 Javascript function

thheller19:06:49

maybe something like

(ns tempproject.tempnamespace)

(defn my-fn [a b]
  (+ a b))

(my-fn js/arg__0 js/arg__1)
with your add_cj wrapper

Takis_19:06:04

yes but this will not generate 1 javascript function

Takis_19:06:20

mongoDB expects 1 javascript function not any js code

thheller19:06:34

your wrapper creates that fn

Takis_19:06:14

ok i will try to make the call from clojure thank you : )

Juλian (he/him)20:06:41

is there an easy way to do sha256 in ClojureScript?

thheller20:06:17

goog.crypt.Sha256, goog.crypt in general

Takis_23:06:25

i am trying long time the js/arg__0 js/arg__1 arguments dissapear on advanced compile, i tried to make the code more complicated like (apply myfn [js/arg__0 js/arg__1]) and it worked, but code from 2k characters gone to 91k characters

Takis_23:06:39

also i need to add a function(arg__0,arg__1) and a return , i need return also

thheller23:06:41

note that you should expect 91k for any function you write that uses any of the cljs datastructures. it'll only stay small if you stick to very basic JS interop. you probably need externs to prevent the unwanted renaming.

thheller23:06:18

oh right I forgot about the return, too tired to think about that one now 😛

Takis_23:06:07

is there a way to prevent the rename? i dont know how to use externs

Takis_23:06:28

dont worry you helped me anyways

Takis_23:06:44

i might benchmark the 91k , because probably i wouldnt avoid it anyways

thheller23:06:42

yeah I'd expect that as a baseline