Good idea. +1
Demo
import Foundation
import JavaScriptCore
//@dynamicCallable
@dynamicMemberLookup
public protocol JSDynamicValue: AnyObject {}
extension JSDynamicValue where Self: JSValue {
@discardableResult
func call(
dynamicMember name: String,
withArguments args: [Any]
) -> JSValue {
if name.isEmpty {
return call(withArguments: args)
} else if name == "init" {
return construct(withArguments: args)
} else {
return invokeMethod(name, withArguments: args)
}
}
public subscript(dynamicMember name: String) -> JSValue {
get {
return objectForKeyedSubscript(name as NSString)
}
set {
setObject(newValue, forKeyedSubscript: name as NSString)
}
}
}
extension JSValue: JSDynamicValue {}
//@dynamicCallable
@dynamicMemberLookup
public protocol JSDynamicContext: AnyObject {}
extension JSDynamicContext where Self: JSContext {
@discardableResult
func call(
dynamicMember name: String,
withArguments args: [Any]
) -> JSValue {
return globalObject!.call(dynamicMember: name, withArguments: args)
}
public subscript(dynamicMember name: String) -> JSValue {
get {
return globalObject![dynamicMember: name]
}
set {
globalObject![dynamicMember: name] = newValue
}
}
}
extension JSContext: JSDynamicContext {}
let context = JSContext()!
#if false
context.parseInt("0x2A", 16).toInt32()
#else
context.call(dynamicMember: "parseInt", withArguments: ["0x2A", 16]).toInt32()
#endif
#if true
let parseInt = context.parseInt
#else
let parseInt = context[dynamicMember: "parseInt"]
#endif
#if false
parseInt("0x2A", 16).toInt32()
#else
parseInt.call(dynamicMember: "", withArguments: ["0x2A", 16]).toInt32()
#endif