Skip to content

Restricting throwable exception type to JSException for closures #359

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// See: https://github.com/swiftlang/swift/pull/80266
// See: https://forums.swift.org/t/pitch-2-custom-main-and-global-executors/78437

import _Concurrency
import _CJavaScriptKit

#if compiler(>=6.2)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import _Concurrency
import _CJavaScriptEventLoop
import _CJavaScriptKit

Expand Down
24 changes: 12 additions & 12 deletions Sources/JavaScriptKit/BasicObjects/JSPromise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ public final class JSPromise: JSBridgedClass {
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
@discardableResult
public func then(
success: sending @escaping (sending JSValue) async throws -> JSValue
success: sending @escaping (sending JSValue) async throws(JSException) -> JSValue
) -> JSPromise {
let closure = JSOneshotClosure.async {
try await success($0[0]).jsValue
let closure = JSOneshotClosure.async { arguments throws(JSException) -> JSValue in
return try await success(arguments[0])
}
return JSPromise(unsafelyWrapping: jsObject.then!(closure).object!)
}
Expand All @@ -127,14 +127,14 @@ public final class JSPromise: JSBridgedClass {
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
@discardableResult
public func then(
success: sending @escaping (sending JSValue) async throws -> JSValue,
failure: sending @escaping (sending JSValue) async throws -> JSValue
success: sending @escaping (sending JSValue) async throws(JSException) -> JSValue,
failure: sending @escaping (sending JSValue) async throws(JSException) -> JSValue
) -> JSPromise {
let successClosure = JSOneshotClosure.async {
try await success($0[0]).jsValue
let successClosure = JSOneshotClosure.async { arguments throws(JSException) -> JSValue in
try await success(arguments[0]).jsValue
}
let failureClosure = JSOneshotClosure.async {
try await failure($0[0]).jsValue
let failureClosure = JSOneshotClosure.async { arguments throws(JSException) -> JSValue in
try await failure(arguments[0]).jsValue
}
return JSPromise(unsafelyWrapping: jsObject.then!(successClosure, failureClosure).object!)
}
Expand All @@ -158,10 +158,10 @@ public final class JSPromise: JSBridgedClass {
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
@discardableResult
public func `catch`(
failure: sending @escaping (sending JSValue) async throws -> JSValue
failure: sending @escaping (sending JSValue) async throws(JSException) -> JSValue
) -> JSPromise {
let closure = JSOneshotClosure.async {
try await failure($0[0]).jsValue
let closure = JSOneshotClosure.async { arguments throws(JSException) -> JSValue in
try await failure(arguments[0]).jsValue
}
return .init(unsafelyWrapping: jsObject.catch!(closure).object!)
}
Expand Down
11 changes: 7 additions & 4 deletions Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol {

#if compiler(>=5.5) && (!hasFeature(Embedded) || os(WASI))
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public static func async(_ body: sending @escaping (sending [JSValue]) async throws -> JSValue) -> JSOneshotClosure
{
public static func async(
_ body: sending @escaping (sending [JSValue]) async throws(JSException) -> JSValue
) -> JSOneshotClosure {
JSOneshotClosure(makeAsyncClosure(body))
}
#endif
Expand Down Expand Up @@ -137,7 +138,9 @@ public class JSClosure: JSFunction, JSClosureProtocol {

#if compiler(>=5.5) && (!hasFeature(Embedded) || os(WASI))
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public static func async(_ body: @Sendable @escaping (sending [JSValue]) async throws -> JSValue) -> JSClosure {
public static func async(
_ body: @Sendable @escaping (sending [JSValue]) async throws(JSException) -> JSValue
) -> JSClosure {
JSClosure(makeAsyncClosure(body))
}
#endif
Expand All @@ -154,7 +157,7 @@ public class JSClosure: JSFunction, JSClosureProtocol {
#if compiler(>=5.5) && (!hasFeature(Embedded) || os(WASI))
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
private func makeAsyncClosure(
_ body: sending @escaping (sending [JSValue]) async throws -> JSValue
_ body: sending @escaping (sending [JSValue]) async throws(JSException) -> JSValue
) -> ((sending [JSValue]) -> JSValue) {
{ arguments in
JSPromise { resolver in
Expand Down
8 changes: 4 additions & 4 deletions Tests/JavaScriptEventLoopTests/JavaScriptEventLoopTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ final class JavaScriptEventLoopTests: XCTestCase {
)
}
let promise2 = promise.then { result in
try await Task.sleep(nanoseconds: 100_000_000)
try! await Task.sleep(nanoseconds: 100_000_000)
return .string(String(result.number!))
}
let thenDiff = try await measureTime {
Expand All @@ -172,7 +172,7 @@ final class JavaScriptEventLoopTests: XCTestCase {
)
}
let failingPromise2 = failingPromise.then { _ -> JSValue in
throw MessageError("Should not be called", file: #file, line: #line, column: #column)
fatalError("Should not be called")
} failure: { err in
return err
}
Expand All @@ -192,7 +192,7 @@ final class JavaScriptEventLoopTests: XCTestCase {
)
}
let catchPromise2 = catchPromise.catch { err in
try await Task.sleep(nanoseconds: 100_000_000)
try! await Task.sleep(nanoseconds: 100_000_000)
return err
}
let catchDiff = try await measureTime {
Expand Down Expand Up @@ -225,7 +225,7 @@ final class JavaScriptEventLoopTests: XCTestCase {
func testAsyncJSClosure() async throws {
// Test Async JSClosure
let delayClosure = JSClosure.async { _ -> JSValue in
try await Task.sleep(nanoseconds: 200_000_000)
try! await Task.sleep(nanoseconds: 200_000_000)
return JSValue.number(3)
}
let delayObject = JSObject.global.Object.function!.new()
Expand Down