From 4afe04580a51bbe35e5e728868fc7705c0c2cc2f Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Mon, 13 Jan 2025 21:02:33 +0100 Subject: [PATCH 1/2] Fix inconsistent argument label This is the only of many overloads that does *not* remove the external argument label for one of its parameters. Looks like a copy/paste error. --- Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift index cbbf4a60f..1463a75c6 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift @@ -228,7 +228,7 @@ public extension JSFunction { new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue]) } - func new(_ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, arg3: some ConvertibleToJSValue) -> JSObject { + 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]) } From dccced130149d64da8f696261972183a8a54227b Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Wed, 15 Jan 2025 19:51:43 +0100 Subject: [PATCH 2/2] Allow calling JS functions with up to 7 arguments in Embedded Swift --- .../FundamentalObjects/JSFunction.swift | 178 +++++++++++++++++- .../FundamentalObjects/JSObject.swift | 79 +++++++- Sources/JavaScriptKit/JSValue.swift | 72 ++++++- 3 files changed, 315 insertions(+), 14 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift index 1463a75c6..498bbc3ea 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift @@ -164,7 +164,14 @@ public class JSFunction: JSObject { } #if hasFeature(Embedded) -// NOTE: once embedded supports variadic generics, we can remove these overloads +// Overloads of `callAsFunction(ConvertibleToJSValue...) -> JSValue` +// for 0 through 7 arguments for Embedded Swift. +// +// These are required because the `ConvertibleToJSValue...` version is not +// available in Embedded Swift due to lack of support for existentials. +// +// Once Embedded Swift supports parameter packs/variadic generics, we can +// replace all variants with a single method each that takes a generic pack. public extension JSFunction { @discardableResult @@ -178,15 +185,74 @@ public extension JSFunction { } @discardableResult - func callAsFunction(this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue) -> JSValue { + func callAsFunction( + this: JSObject, + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue + ) -> JSValue { invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue], this: this).jsValue } @discardableResult - func callAsFunction(this: JSObject, _ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue) -> JSValue { + 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 + 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 + 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 + 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 + 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 func callAsFunction(this: JSObject, arguments: [JSValue]) -> JSValue { invokeNonThrowingJSFunction(arguments: arguments, this: this).jsValue @@ -203,15 +269,68 @@ public extension JSFunction { } @discardableResult - func callAsFunction(_ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue) -> JSValue { + func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue + ) -> JSValue { invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue]).jsValue } @discardableResult - func callAsFunction(_ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue) -> JSValue { + func callAsFunction( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue + ) -> JSValue { invokeNonThrowingJSFunction(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue]).jsValue } + @discardableResult + 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 + 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 + 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 + 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 + } + func new() -> JSObject { new(arguments: []) } @@ -220,19 +339,60 @@ public extension JSFunction { new(arguments: [arg0.jsValue]) } - func new(_ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue) -> JSObject { + func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue + ) -> JSObject { new(arguments: [arg0.jsValue, arg1.jsValue]) } - func new(_ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue) -> JSObject { + func new( + _ arg0: some ConvertibleToJSValue, + _ arg1: some ConvertibleToJSValue, + _ arg2: some ConvertibleToJSValue + ) -> JSObject { new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue]) } - func new(_ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, _ arg3: some ConvertibleToJSValue) -> JSObject { + 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]) } - func new(_ arg0: some ConvertibleToJSValue, _ arg1: some ConvertibleToJSValue, _ arg2: some ConvertibleToJSValue, _ arg3: some ConvertibleToJSValue, _ arg4: some ConvertibleToJSValue, _ arg5: some ConvertibleToJSValue, _ arg6: some ConvertibleToJSValue) -> JSObject { + 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]) + } + + 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]) + } + + 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]) } } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift index 143cbdb39..eb8fb643a 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift @@ -298,7 +298,14 @@ public class JSThrowingObject { #if hasFeature(Embedded) -// NOTE: once embedded supports variadic generics, we can remove these overloads +// Overloads of `JSObject.subscript(_ name: String) -> ((ConvertibleToJSValue...) -> JSValue)?` +// for 0 through 7 arguments for Embedded Swift. +// +// These are required because the `ConvertibleToJSValue...` subscript is not +// available in Embedded Swift due to lack of support for existentials. +// +// NOTE: Once Embedded Swift supports parameter packs/variadic generics, we can +// replace all of these with a single method that takes a generic pack. public extension JSObject { @_disfavoredOverload subscript(dynamicMember name: String) -> (() -> JSValue)? { @@ -315,10 +322,78 @@ public extension JSObject { } @_disfavoredOverload - subscript(dynamicMember name: String) -> ((A0, A1) -> JSValue)? { + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1) -> JSValue)? { self[name].function.map { function in { function(this: self, $0, $1) } } } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2) -> JSValue)? { + self[name].function.map { function in + { function(this: self, $0, $1, $2) } + } + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3) -> JSValue)? { + self[name].function.map { function in + { function(this: self, $0, $1, $2, $3) } + } + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue, + A4: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3, A4) -> JSValue)? { + self[name].function.map { function in + { function(this: self, $0, $1, $2, $3, $4) } + } + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue, + A4: ConvertibleToJSValue, + A5: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3, A4, A5) -> JSValue)? { + self[name].function.map { function in + { function(this: self, $0, $1, $2, $3, $4, $5) } + } + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue, + A4: ConvertibleToJSValue, + A5: ConvertibleToJSValue, + A6: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3, A4, A5, A6) -> JSValue)? { + self[name].function.map { function in + { function(this: self, $0, $1, $2, $3, $4, $5, $6) } + } + } } #endif diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index fe1400e24..ed44f50ea 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -272,9 +272,17 @@ extension JSValue: CustomStringConvertible { } #if hasFeature(Embedded) +// Overloads of `JSValue.subscript(dynamicMember name: String) -> ((ConvertibleToJSValue...) -> JSValue)` +// for 0 through 7 arguments for Embedded Swift. +// +// These are required because the `ConvertibleToJSValue...` subscript is not +// available in Embedded Swift due to lack of support for existentials. +// +// Note: Once Embedded Swift supports parameter packs/variadic generics, we can +// replace all of these with a single method that takes a generic pack. public extension JSValue { @_disfavoredOverload - subscript(dynamicMember name: String) -> (() -> JSValue) { + subscript(dynamicMember name: String) -> (() -> JSValue) { object![dynamicMember: name]! } @@ -284,8 +292,66 @@ public extension JSValue { } @_disfavoredOverload - subscript(dynamicMember name: String) -> ((A0, A1) -> JSValue) { + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1) -> JSValue) { + object![dynamicMember: name]! + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2) -> JSValue) { + object![dynamicMember: name]! + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3) -> JSValue) { + object![dynamicMember: name]! + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue, + A4: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3, A4) -> JSValue) { + object![dynamicMember: name]! + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue, + A4: ConvertibleToJSValue, + A5: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3, A4, A5) -> JSValue) { + object![dynamicMember: name]! + } + + @_disfavoredOverload + subscript< + A0: ConvertibleToJSValue, + A1: ConvertibleToJSValue, + A2: ConvertibleToJSValue, + A3: ConvertibleToJSValue, + A4: ConvertibleToJSValue, + A5: ConvertibleToJSValue, + A6: ConvertibleToJSValue + >(dynamicMember name: String) -> ((A0, A1, A2, A3, A4, A5, A6) -> JSValue) { object![dynamicMember: name]! } } -#endif \ No newline at end of file +#endif