Anyone familiar with the cljs-ajax library? Is there a way to set the request content-type to text/csv
Add a header with {"Content-Type" "text/csv"}
or {"Accept" "text/csv"}
depending on the api
I went down a rabbit hole and to change the request
Header’s content type, it’s under format
The default is transit and was able to change it to text/plain, but not csv
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-typeIs 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.
https://github.com/clojure/clojurescript/blob/master/changes.md
Thanks @p-himik - I must have missed that.
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?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
eh sorry js->clj
will give you the CLJS data.
@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 latterthe js->clj
is the proper CLJS datastructure. it just looks that way when printed in the console
you can use (js/console.log (-> res js->clj pr-str))
perfect thanks @thheller
in fact just (pr-str res) works
I assumed res
was your JSON, if its already converted then pr-str
alone is fine
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
yes, I believe that already takes care of the conversion
@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
=
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.
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));
@witek it's hard to make sense of that output
because why are two things printed in the first line for user
?
I think thats just one thing with hh
or de
being the class/type name which the console prints first
@dnolen This is copy-paste from Chrome Console. Chrome prints hh
and then the "content" of it, which I can expand and so on...
you might be hitting the same kind of issue that clj->js
can sometimes hit where it can report false positives for certain "fast-path" protocols
ie. the :advanced
renamed the protocol mask property to J
and your JS object having a .J
property as well
@witek does the issue go away if you compile with :pseudo-names true
or :simple
?
I don't have this problem in development. It is only in advanced
.
it looks like you're using some 3rd party lib which might be minified
and it's clashing w/ Closure's minification
I'm curious as to why user
has collapsed property names
(this would explain why I felt like this didn't have anything to do w/ =
)
Yes, I am using other minified .js
files. user
for example comes from Google Firebase Authentication library which is included via <script src=
.
Is there a way I can avoid collisions with other minified libs?
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
typically externs take care of this but that doesn't really apply to this issue. kinda tricky
@dpsutton that only prefixes global variables it creates. not property names.
oh i see
@witek try adding a log for (js/console.log "debug-5" (-equiv user "oops"))
. just to confirm it is actually hitting that protocol issue
--config-merge '{:compiler-options {:pseudo-names true}}'
fixes the problem
--pseudo-names
(or --debug
) is the shortcut for that btw 😉
(js/console.log "debug-5" (-equiv user "oops"))
prints debug-5 de {a: 0, i: undefined, c: de, b: null, f: null, …}
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/<build-name>.txt
in your project with just one line cljs$core$IEquiv$_equiv$arity$2
Oh maybe there's a possibility to include Google Firebase Authentication library as an NPM dependency and not via <script>
. This should help as well, right?
no that won't change anything
the issue likely is that closure renames cljs$core$IEquiv$_equiv$arity$2
to something short like J
Even if the NPM sources aren't minified?
so the code will end up checking if (x.J) { x.J(y) }
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
well yes that would help but I believe all the firebase stuff is minified
adding the externs should confirm this is actually what is happening. kinda hard to reproduce since it must hit exactly that renamed property name 😛
externs file fixes the problem
Is this somehow specific to -equiv
? Or could other functions also run into the same problem?
hmm doh. technically this can hit other protocols as well but requires very specific circumstances
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.
@witek not specific to -equiv
but it's not even specific to ClojureScript
separate minification can always lead to this problem
any code that checks for a specific object property could be a point of clashing
clojure -M:shadow-cljs release spa --config-merge '{:compiler-options {:rename-prefix "happygast"}}'
did not solve the problem. Did I something wrong?
:rename-prefix
is not the answer
if the externs file works for you I would do that
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.
not really no. you are interacting with a foreign object that would normally require externs
so you could also create externs that "ban" the shortened names that a likely to clash. a-zA-Z
or so might be enough
so the spa
code wouldn't use those names and never clash
Oh, but what if you create a non-minifed small JS wrapper to be used along with the offending script in a web worker?
well yes but that is going to be bit extreme 😛
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?
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
well this is what externs are for
a tool would likely generate very many false positives
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.
this used to be a very common problem before people built JS
directly including separately minified JS into the page via script tags would lead to this problem
anyways there's nothing to see here 🙂 there's no magic fix
So converting objects from minified libraries like user
to a clojure map before using it would be a safe approach?
I would not do anything defensive - some foreign libraries like this simply need externs
it's painful to run into - but it's outside of our control
Thank you all very much! 🙏
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?
@private
is supported annotation in externs file - so I would say yes