Patching console.log into Swift's JavaScriptCore JSContext

By default, you cannot print to the Xcode console from within a JavaScriptCore-evaluated script. print, echo, console.log – nothing of the like is available.

Caveman debugging is tremendously useful, though, so we all know that we want to print from the JavaScript we evaluat, right?

With my subscript extensions, you can patch this into your JSContext in a rather simple manner.

Note that the usual console.log("hello!") call is a method call (log) on the console object. Without my subscript extensions, you’d have to use the objectForKeyedSubscript getter on the JSContext first to get to the console object, and then use setObject(_:forKeyedSubscript:) on the JSValue to add a block that prints a String. With the extension, we can write this instead:

let logHandler: @convention(block) (String) -> Void = { string in
    print(string)
}
jsContext["console"]?["log"] = logHandler

We still have to add the @convention(block) annotation, though. Without it, the logHandler would be passed in as an NSObject reference – but these cannot be called like a regular function can, so that won’t help.

I think this subscript stuff is quite useful. Reduces the noise tremendously.

Please keep in mind that the actual console.log API documentation clearly states that you can pass more than mere strings to this method. It supports variadic arguments for formatted strings, and it supports printing objects. I leave this as an exercise for the reader, heh.