This Module implements types and macros to facilitate the wrapping of, and interaction with JavaScript libraries. Using the provided types JsObject
and JsAssoc
together with the provided macros allows for smoother interfacing with JavaScript, allowing for example quick and easy imports of JavaScript variables:
# Here, we are using jQuery for just a few calls and do not want to wrap the # whole library: # import the document object and the console var document {. importc, nodecl .}: JsObject var console {. importc, nodecl .}: JsObject # import the "$" function proc jq(selector: JsObject): JsObject {. importcpp: "$(#)" .} # Use jQuery to make the following code run, after the document is ready. # This uses an experimental ``.()`` operator for ``JsObject``, to emit # JavaScript calls, when no corresponding proc exists for ``JsObject``. proc main = jq(document).ready(proc() = console.log("Hello JavaScript!") )
JsObject = ref object of JsRoot
JsAssoc[K; V] = ref object of JsRoot
js = JsObject
jsArguments: JsObject
jsNull: JsObject
jsUndefined: JsObject
jsDirname: cstring
jsFilename: cstring
proc newJsObject(): JsObject {...}{.importcpp: "{@}".}
proc newJsAssoc[K, V](): JsAssoc[K, V] {...}{.importcpp: "{@}".}
proc hasOwnProperty(x: JsObject; prop: cstring): bool {...}{. importcpp: "#.hasOwnProperty(#)".}
proc jsTypeOf(x: JsObject): cstring {...}{.importcpp: "typeof(#)".}
proc jsNew(x: auto): JsObject {...}{.importcpp: "(new #)".}
proc jsDelete(x: auto): JsObject {...}{.importcpp: "(delete #)".}
proc require(module: cstring): JsObject {...}{.importc.}
proc to(x: JsObject; T: typedesc): T:type {...}{.importcpp: "(#)".}
proc toJs[T](val: T): JsObject {...}{.importcpp: "(#)".}
proc `&`(a, b: cstring): cstring {...}{.importcpp: "(# + #)".}
proc `+`(x, y: JsObject): JsObject {...}{.importcpp: "(# + #)".}
proc `-`(x, y: JsObject): JsObject {...}{.importcpp: "(# - #)".}
proc `*`(x, y: JsObject): JsObject {...}{.importcpp: "(# * #)".}
proc `/`(x, y: JsObject): JsObject {...}{.importcpp: "(# / #)".}
proc `%`(x, y: JsObject): JsObject {...}{.importcpp: "(# % #)".}
proc `+=`(x, y: JsObject): JsObject {...}{.importcpp: "(# += #)", discardable.}
proc `-=`(x, y: JsObject): JsObject {...}{.importcpp: "(# -= #)", discardable.}
proc `*=`(x, y: JsObject): JsObject {...}{.importcpp: "(# *= #)", discardable.}
proc `/=`(x, y: JsObject): JsObject {...}{.importcpp: "(# /= #)", discardable.}
proc `%=`(x, y: JsObject): JsObject {...}{.importcpp: "(# %= #)", discardable.}
proc `++`(x: JsObject): JsObject {...}{.importcpp: "(++#)".}
proc `--`(x: JsObject): JsObject {...}{.importcpp: "(--#)".}
proc `>`(x, y: JsObject): JsObject {...}{.importcpp: "(# > #)".}
proc `<`(x, y: JsObject): JsObject {...}{.importcpp: "(# < #)".}
proc `>=`(x, y: JsObject): JsObject {...}{.importcpp: "(# >= #)".}
proc `<=`(x, y: JsObject): JsObject {...}{.importcpp: "(# <= #)".}
proc `and`(x, y: JsObject): JsObject {...}{.importcpp: "(# && #)".}
proc `or`(x, y: JsObject): JsObject {...}{.importcpp: "(# || #)".}
proc `not`(x: JsObject): JsObject {...}{.importcpp: "(!#)".}
proc `in`(x, y: JsObject): JsObject {...}{.importcpp: "(# in #)".}
proc `[]`(obj: JsObject; field: cstring): JsObject {...}{.importcpp: "#[#]".}
proc `[]`(obj: JsObject; field: int): JsObject {...}{.importcpp: "#[#]".}
proc `[]=`[T](obj: JsObject; field: cstring; val: T) {...}{.importcpp: "#[#] = #".}
proc `[]=`[T](obj: JsObject; field: int; val: T) {...}{.importcpp: "#[#] = #".}
proc `[]`[K: not string; V](obj: JsAssoc[K, V]; field: K): V {...}{.importcpp: "#[#]".}
proc `[]`[V](obj: JsAssoc[string, V]; field: cstring): V {...}{.importcpp: "#[#]".}
proc `[]=`[K: not string; V](obj: JsAssoc[K, V]; field: K; val: V) {...}{.importcpp: "#[#] = #".}
proc `[]=`[V](obj: JsAssoc[string, V]; field: cstring; val: V) {...}{.importcpp: "#[#] = #".}
proc `==`(x, y: JsRoot): bool {...}{.importcpp: "(# === #)".}
iterator pairs(obj: JsObject): (cstring, JsObject) {...}{.raises: [], tags: [].}
(cstring, JsObject)
, with the first entry being the name of a fields in the JsObject and the second being its value wrapped into a JsObject. iterator items(obj: JsObject): JsObject {...}{.raises: [], tags: [].}
iterator keys(obj: JsObject): cstring {...}{.raises: [], tags: [].}
iterator pairs[K, V](assoc: JsAssoc[K, V]): (K, V)
(K, V)
, with the first entry being a key in the JsAssoc and the second being its corresponding value. iterator items[K, V](assoc: JsAssoc[K, V]): V
iterator keys[K, V](assoc: JsAssoc[K, V]): K
macro jsFromAst(n: untyped): untyped
macro `.`(obj: JsObject; field: untyped): JsObject
Experimental dot accessor (get) for type JsObject. Returns the value of a property of name field from a JsObject x.
Example:
let obj = newJsObject() obj.a = 20 console.log(obj.a) # puts 20 onto the console.
macro `.=`(obj: JsObject; field, value: untyped): untyped
macro `.()`(obj: JsObject; field: untyped; args: varargs[JsObject, jsFromAst]): JsObject
Experimental "method call" operator for type JsObject. Takes the name of a method of the JavaScript object (field) and calls it with args as arguments, returning a JsObject (which may be discarded, and may be undefined, if the method does not return anything, so be careful when using this.)
Example:
# Let's get back to the console example: var console {. importc, nodecl .}: JsObject let res = console.log("I return undefined!") console.log(res) # This prints undefined, as console.log always returns # undefined. Thus one has to be careful, when using # JsObject calls.
macro `.`[K: string | cstring; V](obj: JsAssoc[K, V]; field: untyped): V
macro `.=`[K: string | cstring; V](obj: JsAssoc[K, V]; field: untyped; value: V): untyped
macro `.()`[K: string | cstring; V: proc](obj: JsAssoc[K, V]; field: untyped; args: varargs[untyped]): auto
macro `{}`(typ: typedesc; xs: varargs[untyped]): auto
Takes a typedesc
as its first argument, and a series of expressions of type key: value
, and returns a value of the specified type with each field key
set to value
, as specified in the arguments of {}
.
Example:
# Let's say we have a type with a ton of fields, where some fields do not # need to be set, and we do not want those fields to be set to ``nil``: type ExtremelyHugeType = ref object a, b, c, d, e, f, g: int h, i, j, k, l: cstring # And even more fields ... let obj = ExtremelyHugeType{ a: 1, k: "foo".cstring, d: 42 } # This generates roughly the same JavaScript as: {. emit: "var obj = {a: 1, k: "foo", d: 42};" .}
macro bindMethod(procedure: typed): auto
Takes the name of a procedure and wraps it into a lambda missing the first argument, which passes the JavaScript builtin this
as the first argument to the procedure. Returns the resulting lambda.
Example:
We want to generate roughly this JavaScript:
var obj = {a: 10}; obj.someMethod = function() { return this.a + 42; };
We can achieve this using the bindMethod
macro:
let obj = JsObject{ a: 10 } proc someMethodImpl(that: JsObject): int = that.a.to(int) + 42 obj.someMethod = bindMethod someMethodImpl # Alternatively: obj.someMethod = bindMethod proc(that: JsObject): int = that.a.to(int) + 42
template toJs(s: string): JsObject
© 2006–2018 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/jsffi.html