forked from swiftwasm/JavaScriptKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJSException.swift
More file actions
92 lines (82 loc) · 3.18 KB
/
JSException.swift
File metadata and controls
92 lines (82 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/// `JSException` is a wrapper that handles exceptions thrown during JavaScript execution as Swift
/// `Error` objects.
/// When a JavaScript function throws an exception, it's wrapped as a `JSException` and propagated
/// through Swift's error handling mechanism.
///
/// Example:
/// ```swift
/// do {
/// try jsFunction.throws()
/// } catch let error as JSException {
/// // Access the value thrown from JavaScript
/// let jsErrorValue = error.thrownValue
/// }
/// ```
public struct JSException: Error, Equatable, CustomStringConvertible {
/// Boxes the exception payload in a class so `JSException` stays within the direct
/// typed-error convention on wasm32.
private final class Storage {
/// The actual JavaScript value that was thrown.
let thrownValue: JSValue
/// A description of the exception.
let description: String
/// The stack trace of the exception.
let stack: String?
init(thrownValue: JSValue, description: String, stack: String?) {
self.thrownValue = thrownValue
self.description = description
self.stack = stack
}
}
/// The boxed payload of the exception.
///
/// Marked as `nonisolated(unsafe)` to satisfy `Sendable` requirement
/// from `Error` protocol.
private nonisolated(unsafe) let storage: Storage
/// The value thrown from JavaScript.
/// This can be any JavaScript value (error object, string, number, etc.).
public var thrownValue: JSValue {
return storage.thrownValue
}
/// A description of the exception.
public var description: String {
return storage.description
}
/// The stack trace of the exception.
public var stack: String? {
return storage.stack
}
/// Initializes a new JSException instance with a value thrown from JavaScript.
///
/// Only available within the package. This must be called on the thread where the exception object created.
/// The stringified representation is captured on the object owner thread to bring useful info
/// to the catching thread even if they are different threads.
@usableFromInline
package init(_ thrownValue: JSValue) {
if let errorObject = thrownValue.object, let stack = errorObject.stack.string {
self.storage = Storage(
thrownValue: thrownValue,
description: "JSException(\(stack))",
stack: stack
)
} else {
self.storage = Storage(
thrownValue: thrownValue,
description: "JSException(\(thrownValue))",
stack: nil
)
}
}
/// Initializes a new JavaScript `Error` instance with a message and prepare it to be thrown.
///
/// - Parameters:
/// - message: The message to throw.
public init(message: String) {
self.init(JSError(message: message).jsValue)
}
public static func == (lhs: JSException, rhs: JSException) -> Bool {
return lhs.storage.thrownValue == rhs.storage.thrownValue
&& lhs.storage.description == rhs.storage.description
&& lhs.storage.stack == rhs.storage.stack
}
}