HQL compiles to JavaScript and can call JavaScript values directly.
(let user {name: "Ada", age: 37})
user.name
user.age
Dot syntax compiles to JavaScript property access.
(let now (new js/Date))
(js-call now "getFullYear")
js/Name resolves a JavaScript global.
(let items [1, 2])
(.push items 3)
items.length
Use method-call syntax for calls that need a receiver.
(js-call JSON "parse" "{\"ok\":true}")
(js-call JSON "stringify" {ok: true})
js-call calls a property by name on a target object.
The reader rule controls whether a literal is persistent HQL data or native JS data:
[1 2 3] ; persistent vector
[1, 2, 3] ; JS array
{:name "Ada"} ; persistent map
{name: "Ada"} ; JS object
Use to-js and from-js when crossing data boundaries explicitly.
to-js is for sending persistent HQL data to JavaScript APIs:
(let user {:name "Ada" :scores [10 20]})
(js-call JSON "stringify" (to-js user))
; {"name":"Ada","scores":[10,20]}
from-js is for bringing JavaScript data back into HQL collection operations:
(let user (from-js {name: "Ada", scores: [10, 20]}))
[(persistent-map? user)
(get user "name")
(to-js (get user "scores"))]
; [true, "Ada", [10, 20]]
The conversion is recursive for arrays, plain objects, Maps, and Sets:
(let data (from-js {user: {name: "Ada"}, tags: ["hql", "js"]}))
(get-in data ["user" "name"])
; "Ada"
Persistent maps with string or keyword keys become plain JavaScript objects.
Persistent maps with other key types become JavaScript Map values:
(let by-id (hash-map 1 "Ada"))
[(instanceof (to-js by-id) js/Map)
(js-call (to-js by-id) "get" 1)]
; [true, "Ada"]
Persistent sets become JavaScript Set values:
(let tags (from-js #["red", "blue"]))
[(persistent-set? tags)
(instanceof (to-js tags) js/Set)
(js-call (to-js tags) "has" "red")]
; [true, true, true]
JavaScript exceptions can be caught with HQL error handling:
(let input "{bad")
(try
(js-call JSON "parse" input)
(catch err
{:error (str err)}))