diff --git a/.gitignore b/.gitignore index 4f8aecf97..a24baa7da 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules /Packages /*.xcodeproj xcuserdata/ +.swiftpm diff --git a/IntegrationTests/TestSuites/Sources/BenchmarkTests/main.swift b/IntegrationTests/TestSuites/Sources/BenchmarkTests/main.swift index 27347ff91..ded1eb5b1 100644 --- a/IntegrationTests/TestSuites/Sources/BenchmarkTests/main.swift +++ b/IntegrationTests/TestSuites/Sources/BenchmarkTests/main.swift @@ -7,7 +7,7 @@ serialization.testSuite("Swift Int to JavaScript") { let jsNumber = JSValue.number(swiftInt) let object = JSObjectRef.global for i in 0 ..< 100 { - object.set("numberValue\(i)", jsNumber) + object["numberValue\(i)"] = jsNumber } } @@ -16,11 +16,10 @@ serialization.testSuite("Swift String to JavaScript") { let jsString = JSValue.string(swiftString) let object = JSObjectRef.global for i in 0 ..< 100 { - object.set("stringValue\(i)", jsString) + object["stringValue\(i)"] = jsString } } - let objectHeap = Benchmark("Object heap") let global = JSObjectRef.global diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift index 60806e671..19ca6bc6a 100644 --- a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift +++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift @@ -239,8 +239,8 @@ New_Object_Construction: do { let cat1 = objectConstructor.new("Tama", 3, true) try expectEqual(getJSValue(this: cat1, name: "name"), .string("Tama")) try expectEqual(getJSValue(this: cat1, name: "age"), .number(3)) - try expectEqual(cat1.instanceof(objectConstructor), true) - try expectEqual(cat1.instanceof(try expectFunction(getJSValue(this: .global, name: "Array"))), false) + try expectEqual(cat1.isInstanceOf(objectConstructor), true) + try expectEqual(cat1.isInstanceOf(try expectFunction(getJSValue(this: .global, name: "Array"))), false) let cat1Bark = try expectFunction(getJSValue(this: cat1, name: "bark")) try expectEqual(cat1Bark(), .string("nyan")) @@ -273,7 +273,7 @@ Call_Function_With_This: do { try expectEqual(getIsCat(), .undefined) // Call with this - let gotIsCat = getIsCat.apply(this: cat1) + let gotIsCat = getIsCat(this: cat1) try expectEqual(gotIsCat, .boolean(true)) } catch { @@ -281,12 +281,12 @@ Call_Function_With_This: do { } Object_Conversion: do { - let array1 = [1, 2, 3] - let jsArray1 = array1.jsValue().object! - try expectEqual(jsArray1.length, .number(3)) - try expectEqual(jsArray1[0], .number(1)) - try expectEqual(jsArray1[1], .number(2)) - try expectEqual(jsArray1[2], .number(3)) + let array1 = [1, 2, 3] + let jsArray1 = array1.jsValue().object! + try expectEqual(jsArray1.length, .number(3)) + try expectEqual(jsArray1[0], .number(1)) + try expectEqual(jsArray1[1], .number(2)) + try expectEqual(jsArray1[2], .number(3)) let array2: [JSValueConvertible] = [1, "str", false] let jsArray2 = array2.jsValue().object! @@ -296,9 +296,9 @@ Object_Conversion: do { try expectEqual(jsArray2[2], .boolean(false)) _ = jsArray2.push!(5) try expectEqual(jsArray2.length, .number(4)) - _ = jsArray2.push!(jsArray1) + _ = jsArray2.push!(jsArray1) - try expectEqual(jsArray2[4], .object(jsArray1)) + try expectEqual(jsArray2[4], .object(jsArray1)) let dict1: [String: JSValueConvertible] = [ "prop1": 1, diff --git a/Sources/JavaScriptKit/JSArrayRef.swift b/Sources/JavaScriptKit/JSArrayRef.swift index d4abc7e66..a84fb27d2 100644 --- a/Sources/JavaScriptKit/JSArrayRef.swift +++ b/Sources/JavaScriptKit/JSArrayRef.swift @@ -3,7 +3,7 @@ public class JSArrayRef { static let classObject = JSObjectRef.global.Array.function! static func isArray(_ object: JSObjectRef) -> Bool { - classObject.isArray.function!(object).boolean! + classObject.isArray!(object).boolean! } let ref: JSObjectRef @@ -33,13 +33,13 @@ extension JSArrayRef: RandomAccessCollection { guard index < Int(ref.length.number!) else { return nil } - let value = ref.get(index) + let value = ref[index] return value.isNull ? nil : value } } public subscript(position: Int) -> JSValue { - ref.get(position) + ref[position] } public var startIndex: Int { 0 } diff --git a/Sources/JavaScriptKit/JSFunction.swift b/Sources/JavaScriptKit/JSFunction.swift index 09586c6cb..e6f31ed32 100644 --- a/Sources/JavaScriptKit/JSFunction.swift +++ b/Sources/JavaScriptKit/JSFunction.swift @@ -1,45 +1,44 @@ import _CJavaScriptKit -@dynamicCallable public class JSFunctionRef: JSObjectRef { @discardableResult - public func dynamicallyCall(withArguments arguments: [JSValueConvertible]) -> JSValue { - let result = arguments.withRawJSValues { rawValues -> RawJSValue in + public func callAsFunction(this: JSObjectRef? = nil, arguments: [JSValueConvertible]) -> JSValue { + let result = arguments.withRawJSValues { rawValues in rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in let argv = bufferPointer.baseAddress let argc = bufferPointer.count var result = RawJSValue() - _call_function( - self.id, argv, Int32(argc), - &result.kind, &result.payload1, &result.payload2, &result.payload3 - ) + if let thisId = this?.id { + _call_function_with_this(thisId, + self.id, argv, Int32(argc), + &result.kind, &result.payload1, &result.payload2, &result.payload3) + } else { + _call_function( + self.id, argv, Int32(argc), + &result.kind, &result.payload1, &result.payload2, &result.payload3 + ) + } return result } } return result.jsValue() } - public func apply(this: JSObjectRef, arguments: JSValueConvertible...) -> JSValue { - apply(this: this, argumentList: arguments) + @discardableResult + public func callAsFunction(this: JSObjectRef? = nil, _ arguments: JSValueConvertible...) -> JSValue { + self(this: this, arguments: arguments) } - public func apply(this: JSObjectRef, argumentList: [JSValueConvertible]) -> JSValue { - let result = argumentList.withRawJSValues { rawValues in - rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in - let argv = bufferPointer.baseAddress - let argc = bufferPointer.count - var result = RawJSValue() - _call_function_with_this(this.id, - self.id, argv, Int32(argc), - &result.kind, &result.payload1, &result.payload2, &result.payload3) - return result - } - } - return result.jsValue() + public func new(_ arguments: JSValueConvertible...) -> JSObjectRef { + new(arguments: arguments) } - public func new(_ arguments: JSValueConvertible...) -> JSObjectRef { - return arguments.withRawJSValues { rawValues in + // Guaranteed to return an object because either: + // a) the constructor explicitly returns an object, or + // b) the constructor returns nothing, which causes JS to return the `this` value, or + // c) the constructor returns undefined, null or a non-object, in which case JS also returns `this`. + public func new(arguments: [JSValueConvertible]) -> JSObjectRef { + arguments.withRawJSValues { rawValues in rawValues.withUnsafeBufferPointer { bufferPointer in let argv = bufferPointer.baseAddress let argc = bufferPointer.count @@ -106,10 +105,10 @@ public func _call_host_function( guard let hostFunc = JSClosure.sharedFunctions[hostFuncRef] else { fatalError("The function was already released") } - let args = UnsafeBufferPointer(start: argv, count: Int(argc)).map { + let arguments = UnsafeBufferPointer(start: argv, count: Int(argc)).map { $0.jsValue() } - let result = hostFunc(args) + let result = hostFunc(arguments) let callbackFuncRef = JSFunctionRef(id: callbackFuncRef) _ = callbackFuncRef(result) } diff --git a/Sources/JavaScriptKit/JSObject.swift b/Sources/JavaScriptKit/JSObject.swift index 47ae2b4a6..4a6f47f9f 100644 --- a/Sources/JavaScriptKit/JSObject.swift +++ b/Sources/JavaScriptKit/JSObject.swift @@ -9,40 +9,29 @@ public class JSObjectRef: Equatable { @_disfavoredOverload public subscript(dynamicMember name: String) -> ((JSValueConvertible...) -> JSValue)? { - guard let function = self[dynamicMember: name].function else { return nil } + guard let function = self[name].function else { return nil } return { (arguments: JSValueConvertible...) in - function.apply(this: self, argumentList: arguments) + function(this: self, arguments: arguments) } } public subscript(dynamicMember name: String) -> JSValue { - get { get(name) } - set { set(name, newValue) } + get { self[name] } + set { self[name] = newValue } } - public func get(_ name: String) -> JSValue { - getJSValue(this: self, name: name) - } - - public func set(_ name: String, _ value: JSValue) { - setJSValue(this: self, name: name, value: value) - } - - public func get(_ index: Int) -> JSValue { - getJSValue(this: self, index: Int32(index)) - } - - public func instanceof(_ constructor: JSFunctionRef) -> Bool { - _instanceof(self.id, constructor.id) + public subscript(_ name: String) -> JSValue { + get { getJSValue(this: self, name: name) } + set { setJSValue(this: self, name: name, value: newValue) } } public subscript(_ index: Int) -> JSValue { - get { get(index) } - set { set(index, newValue) } + get { getJSValue(this: self, index: Int32(index)) } + set { setJSValue(this: self, index: Int32(index), value: newValue) } } - public func set(_ index: Int, _ value: JSValue) { - setJSValue(this: self, index: Int32(index), value: value) + public func isInstanceOf(_ constructor: JSFunctionRef) -> Bool { + _instanceof(id, constructor.id) } static let _JS_Predef_Value_Global: UInt32 = 0 diff --git a/Sources/JavaScriptKit/JSValueConvertible.swift b/Sources/JavaScriptKit/JSValueConvertible.swift index 06d62d22b..08897aa92 100644 --- a/Sources/JavaScriptKit/JSValueConvertible.swift +++ b/Sources/JavaScriptKit/JSValueConvertible.swift @@ -69,7 +69,7 @@ extension Dictionary: JSValueConvertible where Value == JSValueConvertible, Key public func jsValue() -> JSValue { let object = Object.new() for (key, value) in self { - object.set(key, value.jsValue()) + object[key] = value.jsValue() } return .object(object) } diff --git a/Sources/JavaScriptKit/JSValueDecoder.swift b/Sources/JavaScriptKit/JSValueDecoder.swift index ae99f01f7..e71a0c991 100644 --- a/Sources/JavaScriptKit/JSValueDecoder.swift +++ b/Sources/JavaScriptKit/JSValueDecoder.swift @@ -34,7 +34,7 @@ private struct _Decoder: Decoder { } private enum Object { - static let ref = JSObjectRef.global.get("Object").object! + static let ref = JSObjectRef.global.Object.object! static func keys(_ object: JSObjectRef) -> [String] { let keys = ref.keys!(object).array! return keys.map { $0.string! } @@ -90,7 +90,7 @@ private struct _KeyedDecodingContainer: KeyedDecodingContainerPr } func _decode(forKey key: CodingKey) throws -> JSValue { - let result = ref.get(key.stringValue) + let result = ref[key.stringValue] guard !result.isUndefined else { throw _keyNotFound(at: codingPath, key) } @@ -106,7 +106,7 @@ private struct _KeyedDecodingContainer: KeyedDecodingContainerPr } func contains(_ key: Key) -> Bool { - !ref.get(key.stringValue).isUndefined + !ref[key.stringValue].isUndefined } func decodeNil(forKey key: Key) throws -> Bool { @@ -162,7 +162,7 @@ private struct _UnkeyedDecodingContainer: UnkeyedDecodingContainer { mutating func _currentValue() -> JSValue { defer { currentIndex += 1 } - return ref.get(currentIndex) + return ref[currentIndex] } mutating func _throwTypeMismatchIfNil(_ transform: (JSValue) -> T?) throws -> T { diff --git a/Sources/JavaScriptKit/XcodeSupport.swift b/Sources/JavaScriptKit/XcodeSupport.swift index 180072ebf..4f45d907f 100644 --- a/Sources/JavaScriptKit/XcodeSupport.swift +++ b/Sources/JavaScriptKit/XcodeSupport.swift @@ -66,7 +66,7 @@ import _CJavaScriptKit ) { fatalError() } func _instanceof( _: JavaScriptObjectRef, - _: JavaScriptObjectRef + _: JavaScriptObjectRef ) -> Bool { fatalError() } func _create_function( _: JavaScriptHostFuncRef,