# std/jsffi

Dark Mode

- Manual
- Standard library
- Index
- Compiler docs
- Fusion docs
- devel, stable

Search:
Source Edit

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:

Example:

    import std/jsffi
    # 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 {.importjs: "$$(#)".}

    # 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!")
      )

# Imports

macros, tables

# Types

    js = JsObject

  Source Edit

    JsAssoc[K; V] = ref object of JsRoot

  Statically typed wrapper around a JavaScript object. Source Edit

    JsError {.importc: "Error".} = object of JsRoot
      message*: cstring

  Source Edit

    JsEvalError {.importc: "EvalError".} = object of JsError

  Source Edit

    JsKey = concept atypeof(T)
        cstring.toJsKey(T) is T

  Source Edit

    JsObject = ref object of JsRoot

  Dynamically typed wrapper around a JavaScript object. Source Edit

    JsRangeError {.importc: "RangeError".} = object of JsError

  Source Edit

    JsReferenceError {.importc: "ReferenceError".} = object of JsError

  Source Edit

    JsSyntaxError {.importc: "SyntaxError".} = object of JsError

  Source Edit

    JsTypeError {.importc: "TypeError".} = object of JsError

  Source Edit

    JsURIError {.importc: "URIError".} = object of JsError

  Source Edit

# Vars

    jsArguments: JsObject

  JavaScript's arguments pseudo-variable. Source Edit

    jsDirname: cstring

  JavaScript's __dirname pseudo-variable. Source Edit

    jsFilename: cstring

  JavaScript's __filename pseudo-variable. Source Edit

    jsNull: JsObject

  JavaScript's null literal. Source Edit

    jsUndefined: JsObject

  JavaScript's undefined literal. Source Edit

# Procs

    proc `%=`(x, y: JsObject): JsObject {.importjs: "(# %= #)", discardable,
                                          ...raises: [], tags: [].}

  Source Edit

    proc `%`(x, y: JsObject): JsObject {.importjs: "(# % #)", ...raises: [], tags: [].}

  Source Edit

    proc `&`(a, b: cstring): cstring {.importjs: "(# + #)", ...raises: [], tags: [].}

  Concatenation operator for JavaScript strings. Source Edit

    proc `**`(x, y: JsObject): JsObject {.importjs: "((#) ** #)", ...raises: [],
                                          tags: [].}

  Source Edit

    proc `*=`(x, y: JsObject): JsObject {.importjs: "(# *= #)", discardable,
                                          ...raises: [], tags: [].}

  Source Edit

    proc `*`(x, y: JsObject): JsObject {.importjs: "(# * #)", ...raises: [], tags: [].}

  Source Edit

    proc `++`(x: JsObject): JsObject {.importjs: "(++#)", ...raises: [], tags: [].}

  Source Edit

    proc `+=`(x, y: JsObject): JsObject {.importjs: "(# += #)", discardable,
                                          ...raises: [], tags: [].}

  Source Edit

    proc `+`(x, y: JsObject): JsObject {.importjs: "(# + #)", ...raises: [], tags: [].}

  Source Edit

    proc `--`(x: JsObject): JsObject {.importjs: "(--#)", ...raises: [], tags: [].}

  Source Edit

    proc `-=`(x, y: JsObject): JsObject {.importjs: "(# -= #)", discardable,
                                          ...raises: [], tags: [].}

  Source Edit

    proc `-`(x, y: JsObject): JsObject {.importjs: "(# - #)", ...raises: [], tags: [].}

  Source Edit

    proc `/=`(x, y: JsObject): JsObject {.importjs: "(# /= #)", discardable,
                                          ...raises: [], tags: [].}

  Source Edit

    proc `/`(x, y: JsObject): JsObject {.importjs: "(# / #)", ...raises: [], tags: [].}

  Source Edit

    proc `<=`(x, y: JsObject): JsObject {.importjs: "(# <= #)", ...raises: [], tags: [].}

  Source Edit

    proc `<`(x, y: JsObject): JsObject {.importjs: "(# < #)", ...raises: [], tags: [].}

  Source Edit

    proc `==`(x, y: JsRoot): bool {.importjs: "(# === #)", ...raises: [], tags: [].}

  Compares two JsObjects or JsAssocs. Be careful though, as this is comparison like in JavaScript, so if your JsObjects are in fact JavaScript Objects, and not strings or numbers, this is a comparison of references. Source Edit

    proc `>=`(x, y: JsObject): JsObject {.importjs: "(# >= #)", ...raises: [], tags: [].}

  Source Edit

    proc `>`(x, y: JsObject): JsObject {.importjs: "(# > #)", ...raises: [], tags: [].}

  Source Edit

    proc `[]=`[K: JsKey; V](obj: JsAssoc[K, V]; field: K; val: V) {.
        importjs: "#[#] = #", ...raises: [], tags: [].}

  Sets the value of a property of name `field` in a JsAssoc `obj` to `v`. Source Edit

    proc `[]=`[T](obj: JsObject; field: cstring; val: T) {.importjs: "#[#] = #",
        ...raises: [], tags: [].}

  Sets the value of a property of name `field` in a JsObject `obj` to `v`. Source Edit

    proc `[]=`[T](obj: JsObject; field: int; val: T) {.importjs: "#[#] = #",
        ...raises: [], tags: [].}

  Sets the value of a property of name `field` in a JsObject `obj` to `v`. Source Edit

    proc `[]=`[V](obj: JsAssoc[cstring, V]; field: string; val: V)

  Source Edit

    proc `[]`(obj: JsObject; field: cstring): JsObject {.importjs: "#[#]",
        ...raises: [], tags: [].}

  Returns the value of a property of name `field` from a JsObject `obj`. Source Edit

    proc `[]`(obj: JsObject; field: int): JsObject {.importjs: "#[#]", ...raises: [],
        tags: [].}

  Returns the value of a property of name `field` from a JsObject `obj`. Source Edit

    proc `[]`[K: JsKey; V](obj: JsAssoc[K, V]; field: K): V {.importjs: "#[#]",
        ...raises: [], tags: [].}

  Returns the value of a property of name `field` from a JsAssoc `obj`. Source Edit

    proc `[]`[V](obj: JsAssoc[cstring, V]; field: string): V

  Source Edit

    proc `and`(x, y: JsObject): JsObject {.importjs: "(# && #)", ...raises: [],
                                           tags: [].}

  Source Edit

    proc `in`(x, y: JsObject): JsObject {.importjs: "(# in #)", ...raises: [], tags: [].}

  Source Edit

    proc `not`(x: JsObject): JsObject {.importjs: "(!#)", ...raises: [], tags: [].}

  Source Edit

    proc `or`(x, y: JsObject): JsObject {.importjs: "(# || #)", ...raises: [], tags: [].}

  Source Edit

    proc hasOwnProperty(x: JsObject; prop: cstring): bool {.
        importjs: "#.hasOwnProperty(#)", ...raises: [], tags: [].}

  Checks, whether `x` has a property of name `prop`. Source Edit

    proc isNull[T](x: T): bool {.noSideEffect, importjs: "(# === null)", ...raises: [],
                                 tags: [].}

  Checks if a value is exactly null. Source Edit

    proc isUndefined[T](x: T): bool {.noSideEffect, importjs: "(# === undefined)",
                                      ...raises: [], tags: [].}

  Checks if a value is exactly undefined. Source Edit

    proc jsDelete(x: auto): JsObject {.importjs: "(delete #)", ...raises: [], tags: [].}

  JavaScript's `delete` operator. Source Edit

    proc jsNew(x: auto): JsObject {.importjs: "(new #)", ...raises: [], tags: [].}

  Turns a regular function call into an invocation of the JavaScript's `new` operator. Source Edit

    proc jsTypeOf(x: JsObject): cstring {.importjs: "typeof(#)", ...raises: [],
                                          tags: [].}

  Returns the name of the JsObject's JavaScript type as a cstring. Source Edit

    proc newJsAssoc[K: JsKey; V](): JsAssoc[K, V] {.importjs: "{@}", ...raises: [],
        tags: [].}

  Creates a new empty JsAssoc with key type `K` and value type `V`. Source Edit

    proc newJsObject(): JsObject {.importjs: "{@}", ...raises: [], tags: [].}

  Creates a new empty JsObject. Source Edit

    proc require(module: cstring): JsObject {.importc, ...raises: [], tags: [].}

  JavaScript's `require` function. Source Edit

    proc to(x: JsObject; T: typedesc): T:type {.importjs: "(#)", ...raises: [],
        tags: [].}

  Converts a JsObject `x` to type `T`. Source Edit

    proc toJs[T](val: T): JsObject {.importjs: "(#)", ...raises: [], tags: [].}

  Converts a value of any type to type JsObject. Source Edit

    proc toJsKey(text: cstring; t: type cstring): cstring

  Source Edit

    proc toJsKey[T: enum](text: cstring; t: type T): T

  Source Edit

    proc toJsKey[T: SomeFloat](text: cstring; t: type T): T {.
        importjs: "parseFloat(#)", ...raises: [], tags: [].}

  Source Edit

    proc toJsKey[T: SomeInteger](text: cstring; t: type T): T {.
        importjs: "parseInt(#)", ...raises: [], tags: [].}

  Source Edit

# Iterators

    iterator items(obj: JsObject): JsObject {....raises: [], tags: [].}

  Yields the `values` of each field in a JsObject, wrapped into a JsObject. Source Edit

    iterator items[K, V](assoc: JsAssoc[K, V]): V

  Yields the `values` in a JsAssoc. Source Edit

    iterator keys(obj: JsObject): cstring {....raises: [], tags: [].}

  Yields the `names` of each field in a JsObject. Source Edit

    iterator keys[K: JsKey; V](assoc: JsAssoc[K, V]): K

  Yields the `keys` in a JsAssoc. Source Edit

    iterator pairs(obj: JsObject): (cstring, JsObject) {....raises: [], tags: [].}

  Yields tuples of type `(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. Source Edit

    iterator pairs[K: JsKey; V](assoc: JsAssoc[K, V]): (K, V)

  Yields tuples of type `(K, V)`, with the first entry being a `key` in the JsAssoc and the second being its corresponding value. Source Edit

# Macros

    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.

  Source Edit

    macro `.()`[K: cstring; V: proc](obj: JsAssoc[K, V]; field: untyped;
                                     args: varargs[untyped]): auto

  Experimental "method call" operator for type JsAssoc. Takes the name of a method of the JavaScript object (`field`) and calls it with `args` as arguments. Here, everything is typechecked, so you do not have to worry about `undefined` return values. Source Edit

    macro `.=`(obj: JsObject; field, value: untyped): untyped

  Experimental dot accessor (set) for type JsObject. Sets the value of a property of name `field` in a JsObject `x` to `value`. Source Edit

    macro `.=`[K: cstring; V](obj: JsAssoc[K, V]; field: untyped; value: V): untyped

  Experimental dot accessor (set) for type JsAssoc. Sets the value of a property of name `field` in a JsObject `x` to `value`. Source Edit

    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
      assert obj.a.to(int) == 20

  Source Edit

    macro `.`[K: cstring; V](obj: JsAssoc[K, V]; field: untyped): V

  Experimental dot accessor (get) for type JsAssoc. Returns the value of a property of name `field` from a JsObject `x`. Source Edit

    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};".}

  Source Edit

    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

  Source Edit

    macro jsFromAst(n: untyped): untyped

  Source Edit

# Templates

    template toJs(s: string): JsObject

  Source Edit