clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
2021-03-16T01:34:23.002100Z

Anyone familiar with the cljs-ajax library? Is there a way to set the request content-type to text/csv

emccue 2021-03-16T01:41:33.002600Z

Add a header with {"Content-Type" "text/csv"}

emccue 2021-03-16T01:41:42.002900Z

or {"Accept" "text/csv"}

emccue 2021-03-16T01:41:48.003200Z

depending on the api

2021-03-16T01:52:40.006Z

I went down a rabbit hole and to change the request Header’s content type, it’s under format

2021-03-16T01:53:20.007100Z

The default is transit and was able to change it to text/plain, but not csv

2021-03-16T04:47:55.010300Z

I found a way of doing it, not sure if its good, but it works. pass in a valid text-request-format to :format

:format {:write #(str %)
         :content-type "text/csv; charset=utf-8")}
This will pass in "text/csv; charset=utf-8 in the request header’s content-type

tomrbowden 2021-03-16T07:07:21.011800Z

Is there a good online resource detailing the evolution of ClojureScript since it was created? I can’t find a changelog on the ClojureScript github repo.

tomrbowden 2021-03-16T07:17:10.012200Z

Thanks @p-himik - I must have missed that.

zendevil 2021-03-16T10:50:02.014200Z

I have the following code:

(let [r (t/reader :json)
         res->js (clj->js res)]
     (js/console.log "res->js is " (clj->js res))
     (js/console.log "response is " (t/read r res->js))
     )
basically the res variable is a json response from a server. I convert it into js using (clj->js) and this is the output that I get:
{"predictions": [{"description": "Sydney NSW, Australia", "matched_substrings": [Array], "place_id": "ChIJP3Sa8ziYEmsRUKgyFmh9AQM", "reference": "ChIJP3Sa8ziYEmsRUKgyFmh9AQM", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "San Francisco, CA, USA", "matched_substrings": [Array], "place_id": "ChIJIQBpAG2ahYAR_6128GcTUEo", "reference": "ChIJIQBpAG2ahYAR_6128GcTUEo", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "Seattle, WA, USA", "matched_substrings": [Array], "place_id": "ChIJVTPokywQkFQRmtVEaUZlJRA", "reference": "ChIJVTPokywQkFQRmtVEaUZlJRA", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "Surat, Gujarat, India", "matched_substrings": [Array], "place_id": "ChIJYxUdQVlO4DsRQrA4CSlYRf4", "reference": "ChIJYxUdQVlO4DsRQrA4CSlYRf4", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "San Antonio, TX, USA", "matched_substrings": [Array], "place_id": "ChIJrw7QBK9YXIYRvBagEDvhVgg", "reference": "ChIJrw7QBK9YXIYRvBagEDvhVgg", "structured_formatting": [Object], "terms": [Array], "types": [Array]}], "status": "OK"}
So I’m using the cognitect transit library to parse this json into clojurescript. And I do it using
(t/read r res->js)
However, I’m getting this error on this line:
SyntaxError: JSON Parse error: Unexpected identifier "object"
How to fix this?

thheller 2021-03-16T10:59:01.015400Z

that is not how transit works. t/read can only be used to read the output produced by t/write. clj->js already gave you the CLJ datastructures

thheller 2021-03-16T11:00:19.015800Z

eh sorry js->clj will give you the CLJS data.

zendevil 2021-03-16T11:02:53.017200Z

@thheller this is what I get when I use clj->js:

{"predictions": [{"description": "San Francisco, CA, USA", "matched_substrings": [Array], "place_id": "ChIJIQBpAG2ahYAR_6128GcTUEo", "reference": "ChIJIQBpAG2ahYAR_6128GcTUEo", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "San Antonio, TX, USA", "matched_substrings": [Array], "place_id": "ChIJrw7QBK9YXIYRvBagEDvhVgg", "reference": "ChIJrw7QBK9YXIYRvBagEDvhVgg", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "San Diego, CA, USA", "matched_substrings": [Array], "place_id": "ChIJSx6SrQ9T2YARed8V_f0hOg0", "reference": "ChIJSx6SrQ9T2YARed8V_f0hOg0", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "São Paulo, State of São Paulo, Brazil", "matched_substrings": [Array], "place_id": "ChIJ0WGkg4FEzpQRrlsz_whLqZs", "reference": "ChIJ0WGkg4FEzpQRrlsz_whLqZs", "structured_formatting": [Object], "terms": [Array], "types": [Array]}, {"description": "Salt Lake City, UT, USA", "matched_substrings": [Array], "place_id": "ChIJ7THRiJQ9UocRyjFNSKC3U1s", "reference": "ChIJ7THRiJQ9UocRyjFNSKC3U1s", "structured_formatting": [Object], "terms": [Array], "types": [Array]}], "status": "OK"}
This is what I get when I use (js->clj):
{"__hash": null, "arr": ["predictions", {"__hash": null, "cljs$lang$protocol_mask$partition0$": 167666463, "cljs$lang$protocol_mask$partition1$": 139268, "cnt": 5, "meta": null, "root": [Object], "shift": 5, "tail": [Array]}, "status", "OK"], "cljs$lang$protocol_mask$partition0$": 16647951, "cljs$lang$protocol_mask$partition1$": 139268, "cnt": 2, "meta": null}
I don’t know what to do with the latter

thheller 2021-03-16T11:05:40.018200Z

the js->clj is the proper CLJS datastructure. it just looks that way when printed in the console

thheller 2021-03-16T11:06:17.018900Z

you can use (js/console.log (-> res js->clj pr-str))

zendevil 2021-03-16T11:08:31.019600Z

perfect thanks @thheller

zendevil 2021-03-16T11:09:26.019900Z

in fact just (pr-str res) works

thheller 2021-03-16T11:10:55.020400Z

I assumed res was your JSON, if its already converted then pr-str alone is fine

zendevil 2021-03-16T11:12:48.021500Z

i don’t know how it was converted automatically. I’m making an http-xhrio request with the response format set to json-response-format. Not sure why it’s automatically converted

thheller 2021-03-16T11:13:12.021800Z

yes, I believe that already takes care of the conversion

dnolen 2021-03-16T12:56:13.023600Z

@witek that seems pretty strange that = would return anything other than true or false - I agree some minimal example would be useful here to uncover a bug if there is one

dnolen 2021-03-16T12:57:56.025Z

= internally uses identical? so it should have worked. also note that ClojureScript itself uses = in many situations and we don't have this problem you've observed.

witek 2021-03-16T13:51:31.027400Z

This is my code:

(fn [^js user]
   (js/console.log "debug-1" user)
   (js/console.log "debug-2" @AUTH_USER)
   (js/console.log "debug-3" (= user @AUTH_USER))
   (js/console.log "debug-4" (identical? user @AUTH_USER))
This is the output:
debug-1 hh {J: Array(0), l: "AIzaSyA0OD1u2f_weTWD7NXLacez7YdbOCjlbpo", m: "[DEFAULT]", s: "<http://happygast.firebaseapp.com|happygast.firebaseapp.com>", a: Fa, …}
debug-2 null
debug-3 de {a: 0, i: undefined, c: de, b: null, f: null, …}
debug-4 false
And this is the JavaScript:
function(f){
  console.log("debug-1",f);
  console.log("debug-2",u(PR));
  console.log("debug-3",A.c(f,u(PR)));
  console.log("debug-4",f===u(PR));

dnolen 2021-03-16T13:59:58.027800Z

@witek it's hard to make sense of that output

dnolen 2021-03-16T14:00:12.028200Z

because why are two things printed in the first line for user?

thheller 2021-03-16T14:02:40.028800Z

I think thats just one thing with hh or de being the class/type name which the console prints first

witek 2021-03-16T14:04:10.030700Z

@dnolen This is copy-paste from Chrome Console. Chrome prints hh and then the "content" of it, which I can expand and so on...

thheller 2021-03-16T14:04:31.031Z

you might be hitting the same kind of issue that clj-&gt;js can sometimes hit where it can report false positives for certain "fast-path" protocols

thheller 2021-03-16T14:05:55.031600Z

ie. the :advanced renamed the protocol mask property to J and your JS object having a .J property as well

thheller 2021-03-16T14:06:41.032200Z

@witek does the issue go away if you compile with :pseudo-names true or :simple?

witek 2021-03-16T14:07:20.032900Z

I don't have this problem in development. It is only in advanced.

dnolen 2021-03-16T14:07:37.033400Z

@witek yes, but @thheller is explaining the problem

dnolen 2021-03-16T14:07:49.033800Z

it looks like you're using some 3rd party lib which might be minified

dnolen 2021-03-16T14:07:59.034100Z

and it's clashing w/ Closure's minification

dnolen 2021-03-16T14:08:46.034800Z

I'm curious as to why user has collapsed property names

dnolen 2021-03-16T14:09:16.035400Z

(this would explain why I felt like this didn't have anything to do w/ =)

witek 2021-03-16T14:09:58.036200Z

Yes, I am using other minified .js files. user for example comes from Google Firebase Authentication library which is included via &lt;script src=.

witek 2021-03-16T14:11:07.036800Z

Is there a way I can avoid collisions with other minified libs?

dpsutton 2021-03-16T14:16:21.038100Z

You can verify that its name collisions with the suggestions > :pseudo-names true or :simple? and if so, you can set a prefix for the renaming https://clojurescript.org/reference/compiler-options#rename-prefix

thheller 2021-03-16T14:17:23.038700Z

typically externs take care of this but that doesn't really apply to this issue. kinda tricky

thheller 2021-03-16T14:17:47.039200Z

@dpsutton that only prefixes global variables it creates. not property names.

dpsutton 2021-03-16T14:18:16.039500Z

oh i see

thheller 2021-03-16T14:19:00.040200Z

@witek try adding a log for (js/console.log "debug-5" (-equiv user "oops")). just to confirm it is actually hitting that protocol issue

witek 2021-03-16T14:20:29.040600Z

--config-merge '{:compiler-options {:pseudo-names true}}' fixes the problem

thheller 2021-03-16T14:20:49.040900Z

--pseudo-names (or --debug) is the shortcut for that btw 😉

👍 1
witek 2021-03-16T14:23:51.042400Z

(js/console.log "debug-5" (-equiv user "oops")) prints debug-5 de {a: 0, i: undefined, c: de, b: null, f: null, …}

thheller 2021-03-16T14:31:50.043500Z

ok yeah that sort of confirms it. only workaround I can think of is adding cljs$core$IEquiv$_equiv$arity$2 to your externs. eg. externs/&lt;build-name&gt;.txt in your project with just one line cljs$core$IEquiv$_equiv$arity$2

p-himik 2021-03-16T14:32:35.044500Z

Oh maybe there's a possibility to include Google Firebase Authentication library as an NPM dependency and not via &lt;script&gt;. This should help as well, right?

thheller 2021-03-16T14:32:50.044700Z

no that won't change anything

thheller 2021-03-16T14:33:11.045600Z

the issue likely is that closure renames cljs$core$IEquiv$_equiv$arity$2 to something short like J

p-himik 2021-03-16T14:33:31.046200Z

Even if the NPM sources aren't minified?

thheller 2021-03-16T14:33:31.046400Z

so the code will end up checking if (x.J) { x.J(y) }

thheller 2021-03-16T14:34:07.047100Z

so it just blindly calls that function which happens to not be the expected protocol impl but some other function that just happens to return a true-ish value

thheller 2021-03-16T14:35:07.047200Z

well yes that would help but I believe all the firebase stuff is minified

thheller 2021-03-16T14:36:56.049600Z

adding the externs should confirm this is actually what is happening. kinda hard to reproduce since it must hit exactly that renamed property name 😛

witek 2021-03-16T14:39:59.050200Z

externs file fixes the problem

witek 2021-03-16T14:40:12.050500Z

Is this somehow specific to -equiv ? Or could other functions also run into the same problem?

thheller 2021-03-16T14:41:53.051400Z

hmm doh. technically this can hit other protocols as well but requires very specific circumstances

p-himik 2021-03-16T14:43:17.052600Z

But it seems that if both compilers/minimizers start their identifiers from a to Z to A to Z then there will be quite a number of name clashes and such issues.

dnolen 2021-03-16T14:43:20.052800Z

@witek not specific to -equiv

dnolen 2021-03-16T14:43:27.053100Z

but it's not even specific to ClojureScript

dnolen 2021-03-16T14:44:05.053500Z

separate minification can always lead to this problem

dnolen 2021-03-16T14:45:15.054200Z

any code that checks for a specific object property could be a point of clashing

witek 2021-03-16T14:46:12.054900Z

clojure -M:shadow-cljs release spa --config-merge '{:compiler-options {:rename-prefix "happygast"}}' did not solve the problem. Did I something wrong?

dnolen 2021-03-16T14:46:37.055200Z

:rename-prefix is not the answer

dnolen 2021-03-16T14:46:54.056Z

if the externs file works for you I would do that

p-himik 2021-03-16T14:48:32.057100Z

Hypothetically speaking - is it possible to completely isolate any interaction with such scripts so they cannot at all clash with anything? I assume using them from web workers would be one way.

thheller 2021-03-16T14:49:41.057900Z

not really no. you are interacting with a foreign object that would normally require externs

thheller 2021-03-16T14:50:15.058700Z

so you could also create externs that "ban" the shortened names that a likely to clash. a-zA-Z or so might be enough

thheller 2021-03-16T14:50:40.059400Z

so the spa code wouldn't use those names and never clash

p-himik 2021-03-16T14:51:10.059600Z

Oh, but what if you create a non-minifed small JS wrapper to be used along with the offending script in a web worker?

thheller 2021-03-16T14:51:49.060200Z

well yes but that is going to be bit extreme 😛

👍 1
witek 2021-03-16T14:52:36.061500Z

Would be nice to have a tool in the build pipeline which takes all minified .js files and errors when there is a clash. Would this be somehow possible?

thheller 2021-03-16T14:52:48.061900Z

this is an extremely uncommon issue and very hard to hit. pretty much only happens because you basically have two :advanced compiled scripts on the page

thheller 2021-03-16T14:53:41.062400Z

well this is what externs are for

thheller 2021-03-16T14:54:19.062700Z

a tool would likely generate very many false positives

p-himik 2021-03-16T14:56:14.064700Z

I imagine another potential way to prevent such issues would be to never call any CLJS code on the objects returned by the code from minimized third-party scripts. So the example with user above would first use regular JS code (or careful CLJS/JS interop) to create a plain JS object with all the necessary fields, and only then use that object in the CLJS code.

dnolen 2021-03-16T14:57:02.065Z

this used to be a very common problem before people built JS

dnolen 2021-03-16T14:57:21.065300Z

directly including separately minified JS into the page via script tags would lead to this problem

dnolen 2021-03-16T14:58:45.065900Z

anyways there's nothing to see here 🙂 there's no magic fix

witek 2021-03-16T15:01:24.067800Z

So converting objects from minified libraries like user to a clojure map before using it would be a safe approach?

dnolen 2021-03-16T15:02:30.068800Z

I would not do anything defensive - some foreign libraries like this simply need externs

dnolen 2021-03-16T15:03:01.069400Z

it's painful to run into - but it's outside of our control

witek 2021-03-16T15:03:51.070400Z

Thank you all very much! 🙏

p-himik 2021-03-16T15:04:12.070900Z

If there supposed to be a field that's not public but on an object from a public API - should externs also include that private field as well?

dnolen 2021-03-16T15:05:20.071500Z

@private is supported annotation in externs file - so I would say yes

👍 1