JXKit is a cross-plarform swift module for interfacing with
JavaScriptCore
. It provides a fluent API for working with an embedded
JXContext
,
including script evaluation, error handling, and Codable mashalling.
JXKit is cross-platform for Darwin (macOS/iOS) and Linux, with experimental support for Windows and Android.
JSC to be used on platforms where the Objective-C runtime is unavailable (e.g., Linux).
Browse the API Documentation.
Functions can be accessed (and cached) to be invoked directly with codable arguments:
let context = JXContext()
let hypot = try context.global["Math"]["hypot"]
assert(hypot.isFunction == true)
let result = try hypot.call(withArguments: try [context.encode(3), context.encode(4)])
let hypotValue = try result.double
assert(hypotValue == 5.0)
JXKit supports encoding and decoding Swift types directly into the JXValue
instances, which enables Codable
instances to be passed back and forth to the virtual machine with minimal overhead. Since encoding & decoding doesn't use JSON stringify
& parse
, this can lead to considerable performance improvements when interfacing between Swift & JS.
The above invocation of Math.hypot
can instead be performed by wrapping the arguments in an Encodable
struct, and returning a Decodable
value.
/// An example of invoking `Math.hypot` in a wrapper function that takes an encodable argument and returns a Decodable retult.
struct AB: Encodable { let a, b: Double }
struct C: Decodable { let c: Double }
let context = JXContext()
let hypot = try context.eval("(function(args) { return { c: Math.hypot(args.a, args.b) }; })")
assert(hypot.isFunction == true)
let result: C = try hypot.call(withArguments: [context.encode(AB(a: 3, b: 4))]).toDecodable(ofType: C.self)
assert(result.c == 5)
The JXKit API is a mostly drop-in replacement for the Objective-C JavaScriptCore
framework available on most Apple devices. E.g., the following JavaScriptCore code:
import JavaScriptCore
let jsc = JSContext()
let value: JSValue = jsc.evaluateScript("1+2")
assert(value.int == 3)
becomes:
import JXKit
let jxc = JXContext()
let value: JXValue = try jxc.eval("1+2")
assert(try value.int == 3)
Note: Requires Swift 5.5+
The Swift Package Manager is a tool for managing the distribution of Swift code.
- Add the following to your
Package.swift
file:
// swift-tools-version:5.6
import PackageDescription
let package = Package(
name: "MyPackage",
products: [
.library(
name: "MyPackage",
targets: ["MyPackage"]),
],
dependencies: [
.package(name: "JXKit", url: "https://github.com/jectivex/JXKit.git", .upToNextMajor(from: "3.0.0")),
],
targets: [
.target(
name: "MyPackage",
dependencies: ["JXKit"]),
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage"]),
]
)
- Build your project:
$ swift build
Like the JavaScriptCore framework upon which it is built, JXKit is licensed under the GNU LGPL license. See LICENSE.LGPL for details.
Projects that are based on JXKit:
- [Jack][]: Cross-platform framework for scripting
Combine.ObservableObject
and SwiftUI (LGPL)
- JavaScriptCore: Cross-platform JavaScript engine (LGPL)1
- Consider evalClosureAsync variant for async code.
- Better reporting of errors from async code / Promises.
Footnotes
-
JavaScriptCore is included with macOS and iOS as part of the embedded WebCore framework (LGPL); on Linux JXKit uses WebKit GTK JavaScriptCore. ↩