From 563f06cf0e8864a7874cf671d50b014da41dcfb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:14:27 +0000 Subject: [PATCH 1/5] Initial plan From 5e305c8266245e46805ab27bd5f0f620aaaa30b3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:27:20 +0000 Subject: [PATCH 2/5] Phase 1: Add callability functionality to JSObject Co-authored-by: kateinoigakukun <11702759+kateinoigakukun@users.noreply.github.com> --- .../FundamentalObjects/JSFunction.swift | 131 ++---- .../FundamentalObjects/JSObject.swift | 377 ++++++++++++++++++ .../FundamentalObjects/JSSymbol.swift | 2 +- 3 files changed, 413 insertions(+), 97 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift index 17248361..23844976 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift @@ -18,7 +18,7 @@ public class JSFunction: JSObject { /// - arguments: Arguments to be passed to this function. /// - Returns: The result of this call. @discardableResult - public func callAsFunction(this: JSObject, arguments: [ConvertibleToJSValue]) -> JSValue { + override public func callAsFunction(this: JSObject, arguments: [ConvertibleToJSValue]) -> JSValue { invokeNonThrowingJSFunction(arguments: arguments, this: this).jsValue } @@ -27,20 +27,20 @@ public class JSFunction: JSObject { /// - arguments: Arguments to be passed to this function. /// - Returns: The result of this call. @discardableResult - public func callAsFunction(arguments: [ConvertibleToJSValue]) -> JSValue { + override public func callAsFunction(arguments: [ConvertibleToJSValue]) -> JSValue { invokeNonThrowingJSFunction(arguments: arguments).jsValue } /// A variadic arguments version of `callAsFunction`. @discardableResult - public func callAsFunction(this: JSObject, _ arguments: ConvertibleToJSValue...) -> JSValue { - self(this: this, arguments: arguments) + override public func callAsFunction(this: JSObject, _ arguments: ConvertibleToJSValue...) -> JSValue { + self.callAsFunction(this: this, arguments: arguments) } /// A variadic arguments version of `callAsFunction`. @discardableResult - public func callAsFunction(_ arguments: ConvertibleToJSValue...) -> JSValue { - self(arguments: arguments) + override public func callAsFunction(_ arguments: ConvertibleToJSValue...) -> JSValue { + self.callAsFunction(arguments: arguments) } /// Instantiate an object from this function as a constructor. @@ -53,7 +53,7 @@ public class JSFunction: JSObject { /// /// - Parameter arguments: Arguments to be passed to this constructor function. /// - Returns: A new instance of this constructor. - public func new(arguments: [ConvertibleToJSValue]) -> JSObject { + override public func new(arguments: [ConvertibleToJSValue]) -> JSObject { arguments.withRawJSValues { rawValues in rawValues.withUnsafeBufferPointer { bufferPointer in JSObject(id: swjs_call_new(self.id, bufferPointer.baseAddress!, Int32(bufferPointer.count))) @@ -62,7 +62,7 @@ public class JSFunction: JSObject { } /// A variadic arguments version of `new`. - public func new(_ arguments: ConvertibleToJSValue...) -> JSObject { + override public func new(_ arguments: ConvertibleToJSValue...) -> JSObject { new(arguments: arguments) } @@ -87,11 +87,11 @@ public class JSFunction: JSObject { #endif @discardableResult - public func callAsFunction(arguments: [JSValue]) -> JSValue { + override public func callAsFunction(arguments: [JSValue]) -> JSValue { invokeNonThrowingJSFunction(arguments: arguments).jsValue } - public func new(arguments: [JSValue]) -> JSObject { + override public func new(arguments: [JSValue]) -> JSObject { arguments.withRawJSValues { rawValues in rawValues.withUnsafeBufferPointer { bufferPointer in JSObject(id: swjs_call_new(self.id, bufferPointer.baseAddress!, Int32(bufferPointer.count))) @@ -107,67 +107,6 @@ public class JSFunction: JSObject { override public var jsValue: JSValue { .function(self) } - - final func invokeNonThrowingJSFunction(arguments: [JSValue]) -> RawJSValue { - arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0) } - } - - final func invokeNonThrowingJSFunction(arguments: [JSValue], this: JSObject) -> RawJSValue { - arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0, this: this) } - } - - #if !hasFeature(Embedded) - final func invokeNonThrowingJSFunction(arguments: [ConvertibleToJSValue]) -> RawJSValue { - arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0) } - } - - final func invokeNonThrowingJSFunction(arguments: [ConvertibleToJSValue], this: JSObject) -> RawJSValue { - arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0, this: this) } - } - #endif - - final private func invokeNonThrowingJSFunction(rawValues: [RawJSValue]) -> RawJSValue { - rawValues.withUnsafeBufferPointer { [id] bufferPointer in - let argv = bufferPointer.baseAddress - let argc = bufferPointer.count - var payload1 = JavaScriptPayload1() - var payload2 = JavaScriptPayload2() - let resultBitPattern = swjs_call_function_no_catch( - id, - argv, - Int32(argc), - &payload1, - &payload2 - ) - let kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) - assert(!kindAndFlags.isException) - let result = RawJSValue(kind: kindAndFlags.kind, payload1: payload1, payload2: payload2) - return result - } - } - - final private func invokeNonThrowingJSFunction(rawValues: [RawJSValue], this: JSObject) -> RawJSValue { - rawValues.withUnsafeBufferPointer { [id] bufferPointer in - let argv = bufferPointer.baseAddress - let argc = bufferPointer.count - var payload1 = JavaScriptPayload1() - var payload2 = JavaScriptPayload2() - let resultBitPattern = swjs_call_function_with_this_no_catch( - this.id, - id, - argv, - Int32(argc), - &payload1, - &payload2 - ) - let kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) - #if !hasFeature(Embedded) - assert(!kindAndFlags.isException) - #endif - let result = RawJSValue(kind: kindAndFlags.kind, payload1: payload1, payload2: payload2) - return result - } - } } #if hasFeature(Embedded) @@ -182,17 +121,17 @@ public class JSFunction: JSObject { extension JSFunction { @discardableResult - public func callAsFunction(this: JSObject) -> JSValue { + override public func callAsFunction(this: JSObject) -> JSValue { invokeNonThrowingJSFunction(arguments: [], this: this).jsValue } @discardableResult - public func callAsFunction(this: JSObject, _ arg0: some ConvertibleToJSValue) -> JSValue { + override public func callAsFunction(this: JSObject, _ arg0: some ConvertibleToJSValue) -> JSValue { invokeNonThrowingJSFunction(arguments: [arg0.jsValue], this: this).jsValue } @discardableResult - public func callAsFunction( + override public func callAsFunction( this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue @@ -201,7 +140,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, @@ -211,7 +150,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, @@ -223,7 +162,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, @@ -238,7 +177,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, @@ -254,7 +193,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, @@ -273,22 +212,22 @@ extension JSFunction { } @discardableResult - public func callAsFunction(this: JSObject, arguments: [JSValue]) -> JSValue { + override public func callAsFunction(this: JSObject, arguments: [JSValue]) -> JSValue { invokeNonThrowingJSFunction(arguments: arguments, this: this).jsValue } @discardableResult - public func callAsFunction() -> JSValue { + override public func callAsFunction() -> JSValue { invokeNonThrowingJSFunction(arguments: []).jsValue } @discardableResult - public func callAsFunction(_ arg0: some ConvertibleToJSValue) -> JSValue { + override public func callAsFunction(_ arg0: some ConvertibleToJSValue) -> JSValue { invokeNonThrowingJSFunction(arguments: [arg0.jsValue]).jsValue } @discardableResult - public func callAsFunction( + override public func callAsFunction( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue ) -> JSValue { @@ -296,7 +235,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue @@ -305,7 +244,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, @@ -315,7 +254,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, @@ -327,7 +266,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, @@ -341,7 +280,7 @@ extension JSFunction { } @discardableResult - public func callAsFunction( + override public func callAsFunction( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, @@ -355,22 +294,22 @@ extension JSFunction { ]).jsValue } - public func new() -> JSObject { + override public func new() -> JSObject { new(arguments: []) } - public func new(_ arg0: some ConvertibleToJSValue) -> JSObject { + override public func new(_ arg0: some ConvertibleToJSValue) -> JSObject { new(arguments: [arg0.jsValue]) } - public func new( + override public func new( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue ) -> JSObject { new(arguments: [arg0.jsValue, arg1.jsValue]) } - public func new( + override public func new( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue @@ -378,7 +317,7 @@ extension JSFunction { new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue]) } - public func new( + override public func new( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, @@ -387,7 +326,7 @@ extension JSFunction { new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue]) } - public func new( + override public func new( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, @@ -397,7 +336,7 @@ extension JSFunction { new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue]) } - public func new( + override public func new( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, @@ -408,7 +347,7 @@ extension JSFunction { new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue]) } - public func new( + override public func new( _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift index b9330ae8..33e89674 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift @@ -210,6 +210,140 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { } #endif + // MARK: - Function Call Support + + #if !hasFeature(Embedded) + /// Call this object as a function with given `arguments` and binding given `this` as context. + /// - Parameters: + /// - this: The value to be passed as the `this` parameter to this function. + /// - arguments: Arguments to be passed to this function. + /// - Returns: The result of this call. + @discardableResult + public func callAsFunction(this: JSObject, arguments: [ConvertibleToJSValue]) -> JSValue { + invokeNonThrowingJSFunction(arguments: arguments, this: this).jsValue + } + + /// Call this object as a function with given `arguments`. + /// - Parameters: + /// - arguments: Arguments to be passed to this function. + /// - Returns: The result of this call. + @discardableResult + public func callAsFunction(arguments: [ConvertibleToJSValue]) -> JSValue { + invokeNonThrowingJSFunction(arguments: arguments).jsValue + } + + /// A variadic arguments version of `callAsFunction`. + @discardableResult + public func callAsFunction(this: JSObject, _ arguments: ConvertibleToJSValue...) -> JSValue { + self.callAsFunction(this: this, arguments: arguments) + } + + /// A variadic arguments version of `callAsFunction`. + @discardableResult + public func callAsFunction(_ arguments: ConvertibleToJSValue...) -> JSValue { + self.callAsFunction(arguments: arguments) + } + + /// Instantiate an object from this object as a constructor. + /// + /// 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`. + /// + /// - Parameter arguments: Arguments to be passed to this constructor function. + /// - Returns: A new instance of this constructor. + public func new(arguments: [ConvertibleToJSValue]) -> JSObject { + arguments.withRawJSValues { rawValues in + rawValues.withUnsafeBufferPointer { bufferPointer in + JSObject(id: swjs_call_new(self.id, bufferPointer.baseAddress!, Int32(bufferPointer.count))) + } + } + } + + /// A variadic arguments version of `new`. + public func new(_ arguments: ConvertibleToJSValue...) -> JSObject { + new(arguments: arguments) + } + #endif + + @discardableResult + public func callAsFunction(arguments: [JSValue]) -> JSValue { + invokeNonThrowingJSFunction(arguments: arguments).jsValue + } + + public func new(arguments: [JSValue]) -> JSObject { + arguments.withRawJSValues { rawValues in + rawValues.withUnsafeBufferPointer { bufferPointer in + JSObject(id: swjs_call_new(self.id, bufferPointer.baseAddress!, Int32(bufferPointer.count))) + } + } + } + + // MARK: - Function Invocation Helper Methods + + final func invokeNonThrowingJSFunction(arguments: [JSValue]) -> RawJSValue { + arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0) } + } + + final func invokeNonThrowingJSFunction(arguments: [JSValue], this: JSObject) -> RawJSValue { + arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0, this: this) } + } + + #if !hasFeature(Embedded) + final func invokeNonThrowingJSFunction(arguments: [ConvertibleToJSValue]) -> RawJSValue { + arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0) } + } + + final func invokeNonThrowingJSFunction(arguments: [ConvertibleToJSValue], this: JSObject) -> RawJSValue { + arguments.withRawJSValues { invokeNonThrowingJSFunction(rawValues: $0, this: this) } + } + #endif + + final private func invokeNonThrowingJSFunction(rawValues: [RawJSValue]) -> RawJSValue { + rawValues.withUnsafeBufferPointer { [id] bufferPointer in + let argv = bufferPointer.baseAddress + let argc = bufferPointer.count + var payload1 = JavaScriptPayload1() + var payload2 = JavaScriptPayload2() + let resultBitPattern = swjs_call_function_no_catch( + id, + argv, + Int32(argc), + &payload1, + &payload2 + ) + let kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) + assert(!kindAndFlags.isException) + let result = RawJSValue(kind: kindAndFlags.kind, payload1: payload1, payload2: payload2) + return result + } + } + + final private func invokeNonThrowingJSFunction(rawValues: [RawJSValue], this: JSObject) -> RawJSValue { + rawValues.withUnsafeBufferPointer { [id] bufferPointer in + let argv = bufferPointer.baseAddress + let argc = bufferPointer.count + var payload1 = JavaScriptPayload1() + var payload2 = JavaScriptPayload2() + let resultBitPattern = swjs_call_function_with_this_no_catch( + this.id, + id, + argv, + Int32(argc), + &payload1, + &payload2 + ) + let kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) + #if !hasFeature(Embedded) + assert(!kindAndFlags.isException) + #endif + let result = RawJSValue(kind: kindAndFlags.kind, payload1: payload1, payload2: payload2) + return result + } + } + /// Return `true` if this value is an instance of the passed `constructor` function. /// - Parameter constructor: The constructor function to check. /// - Returns: The result of `instanceof` in the JavaScript environment. @@ -415,5 +549,248 @@ extension JSObject { { function(this: self, $0, $1, $2, $3, $4, $5, $6) } } } + + // MARK: - Embedded Swift Function Call Overloads + + @discardableResult + public func callAsFunction(this: JSObject) -> JSValue { + invokeNonThrowingJSFunction(arguments: [], this: this).jsValue + } + + @discardableResult + public func callAsFunction(this: JSObject, _ arg0: some ConvertibleToJSValue) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue], this: this).jsValue + } + + @discardableResult + public func callAsFunction( + this: JSObject, + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue], this: this).jsValue + } + + @discardableResult + public func callAsFunction( + this: JSObject, + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue], this: this).jsValue + } + + @discardableResult + public func callAsFunction( + this: JSObject, + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue], this: this) + .jsValue + } + + @discardableResult + public func callAsFunction( + this: JSObject, + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction( + arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue], + this: this + ).jsValue + } + + @discardableResult + public func callAsFunction( + this: JSObject, + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue, + _ arg5: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction( + arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue], + this: this + ).jsValue + } + + @discardableResult + public func callAsFunction( + this: JSObject, + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue, + _ arg5: some ConvertibleToJSValue, + _ arg6: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction( + arguments: [ + arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue, arg6.jsValue, + ], + this: this + ).jsValue + } + + @discardableResult + public func callAsFunction(this: JSObject, arguments: [JSValue]) -> JSValue { + invokeNonThrowingJSFunction(arguments: arguments, this: this).jsValue + } + + @discardableResult + public func callAsFunction() -> JSValue { + invokeNonThrowingJSFunction(arguments: []).jsValue + } + + @discardableResult + public func callAsFunction(_ arg0: some ConvertibleToJSValue) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue]).jsValue + } + + @discardableResult + public func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue]).jsValue + } + + @discardableResult + public func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue]).jsValue + } + + @discardableResult + public func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue]).jsValue + } + + @discardableResult + public func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue]) + .jsValue + } + + @discardableResult + public func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue, + _ arg5: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [ + arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue, + ]).jsValue + } + + @discardableResult + public func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue, + _ arg5: some ConvertibleToJSValue, + _ arg6: some ConvertibleToJSValue + ) -> JSValue { + invokeNonThrowingJSFunction(arguments: [ + arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue, arg6.jsValue, + ]).jsValue + } + + public func new() -> JSObject { + new(arguments: []) + } + + public func new(_ arg0: some ConvertibleToJSValue) -> JSObject { + new(arguments: [arg0.jsValue]) + } + + public func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue + ) -> JSObject { + new(arguments: [arg0.jsValue, arg1.jsValue]) + } + + public func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue + ) -> JSObject { + new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue]) + } + + public func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue + ) -> JSObject { + new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue]) + } + + public func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue + ) -> JSObject { + new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue]) + } + + public func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue, + _ arg5: some ConvertibleToJSValue + ) -> JSObject { + new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue]) + } + + public func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue, + _ arg3: some ConvertibleToJSValue, + _ arg4: some ConvertibleToJSValue, + _ arg5: some ConvertibleToJSValue, + _ arg6: some ConvertibleToJSValue + ) -> JSObject { + new(arguments: [ + arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue, arg6.jsValue, + ]) + } } #endif diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift b/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift index a9461317..8907b9fe 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift @@ -12,7 +12,7 @@ public class JSSymbol: JSObject { public init(_ description: JSString) { // can’t do `self =` so we have to get the ID manually let result = Symbol.invokeNonThrowingJSFunction(arguments: [description.jsValue]) - precondition(result.kind == .symbol) + precondition(result.kind == JavaScriptValueKind(rawValue: 7)!) // .symbol super.init(id: UInt32(result.payload1)) } @_disfavoredOverload From 11d38ddbff2377328729117e1d3fd55f789722e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:29:35 +0000 Subject: [PATCH 3/5] Phase 3: Make JSClosure inherit from JSObject for consistency Co-authored-by: kateinoigakukun <11702759+kateinoigakukun@users.noreply.github.com> --- Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift index d290046a..b9121b4d 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift @@ -103,7 +103,7 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol { /// button.removeEventListener!("click", JSValue.function(eventListener)) /// ``` /// -public class JSClosure: JSFunction, JSClosureProtocol { +public class JSClosure: JSObject, JSClosureProtocol { class SharedJSClosure { // Note: 6.0 compilers built with assertions enabled crash when calling @@ -165,6 +165,10 @@ public class JSClosure: JSFunction, JSClosureProtocol { fatalError("JSClosure does not support dictionary literal initialization") } + override public var jsValue: JSValue { + .function(JSFunction(id: self.id)) + } + #if compiler(>=5.5) && (!hasFeature(Embedded) || os(WASI)) /// Creates a new `JSClosure` that calls the given Swift function asynchronously. /// From f9b76bf7e7b9b4b5e1b7a7089874ae3e504ed998 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:32:31 +0000 Subject: [PATCH 4/5] Phase 2: Unify JSValue representation - functions now use .object case Co-authored-by: kateinoigakukun <11702759+kateinoigakukun@users.noreply.github.com> --- Sources/JavaScriptKit/ConvertibleToJSValue.swift | 2 +- Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift | 2 +- Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift | 2 +- Sources/JavaScriptKit/JSValue.swift | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index afa63274..a921362f 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -209,7 +209,7 @@ extension RawJSValue: ConvertibleToJSValue { case .undefined: return .undefined case .function: - return .function(JSFunction(id: UInt32(payload1))) + return .object(JSFunction(id: UInt32(payload1))) case .symbol: return .symbol(JSSymbol(id: UInt32(payload1))) case .bigInt: diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift index b9121b4d..20da0bb3 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift @@ -166,7 +166,7 @@ public class JSClosure: JSObject, JSClosureProtocol { } override public var jsValue: JSValue { - .function(JSFunction(id: self.id)) + .object(self) } #if compiler(>=5.5) && (!hasFeature(Embedded) || os(WASI)) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift index 23844976..3cc3153f 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift @@ -105,7 +105,7 @@ public class JSFunction: JSObject { } override public var jsValue: JSValue { - .function(self) + .object(self) } } diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index b9f8dd4a..b7d8d87d 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -65,6 +65,7 @@ public enum JSValue: Equatable { public var function: JSFunction? { switch self { case .function(let function): return function + case .object(let object as JSFunction): return object default: return nil } } From 609cff1316c4e93fea88e2830a7b64b3a5bb8596 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:33:52 +0000 Subject: [PATCH 5/5] Final: Add documentation and migration guidance for unification Co-authored-by: kateinoigakukun <11702759+kateinoigakukun@users.noreply.github.com> --- Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift | 3 +++ Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift index 20da0bb3..f7ac8764 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift @@ -103,6 +103,9 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol { /// button.removeEventListener!("click", JSValue.function(eventListener)) /// ``` /// +/// - Note: JSClosure now inherits from JSObject directly instead of JSFunction, +/// providing a consistent and unified object model that aligns with JavaScript's +/// dynamic callability semantics. public class JSClosure: JSObject, JSClosureProtocol { class SharedJSClosure { diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift index 3cc3153f..08d828d6 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift @@ -10,6 +10,9 @@ import _CJavaScriptKit /// alert("Hello, world") /// ``` /// +/// - Note: In a future version, JSFunction will be unified with JSObject. +/// Consider using JSObject directly for new code, as all objects in JavaScript +/// can potentially be callable. JSFunction functionality is now available on JSObject. public class JSFunction: JSObject { #if !hasFeature(Embedded) /// Call this function with given `arguments` and binding given `this` as context.