expo-modules-jsi 56.0.7 → 56.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/CLAUDE.md +4 -0
- package/apple/Package.swift +15 -11
- package/apple/Sources/ExpoModulesJSI/Contexts/CleanupContext.swift +2 -4
- package/apple/Sources/ExpoModulesJSI/Contexts/HostFunctionContext.swift +1 -3
- package/apple/Sources/ExpoModulesJSI/Contexts/HostObjectContext.swift +1 -3
- package/apple/Sources/ExpoModulesJSI/Extensions/Task+immediate.swift +2 -0
- package/apple/Sources/ExpoModulesJSI/Protocols/JSIRepresentable.swift +17 -14
- package/apple/Sources/ExpoModulesJSI/Protocols/JavaScriptRepresentable.swift +3 -9
- package/apple/Sources/ExpoModulesJSI/Protocols/JavaScriptThrowable.swift +21 -27
- package/apple/Sources/ExpoModulesJSI/Protocols/JavaScriptType.swift +10 -18
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptActor.swift +22 -41
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptNativeState.swift +7 -15
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptPropNameID.swift +5 -15
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRef.swift +21 -43
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift +152 -202
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift +38 -41
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptArray.swift +340 -381
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptArrayBuffer.swift +9 -21
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptBigInt.swift +162 -190
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptError.swift +12 -15
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptFunction.swift +23 -27
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptObject.swift +175 -207
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptPromise.swift +22 -24
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptTypedArray.swift +34 -49
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptValue.swift +122 -176
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptWeakObject.swift +6 -14
- package/apple/Sources/ExpoModulesJSI/Utilities/ErrorHandling.swift +12 -20
- package/apple/Sources/ExpoModulesJSI/Utilities/Errors.swift +10 -22
- package/apple/Sources/ExpoModulesJSI/Utilities/NonisolatedUnsafeVar.swift +2 -4
- package/apple/Sources/ExpoModulesJSI-Cxx/include/JSIUtils.h +11 -0
- package/apple/Tests/JavaScriptActorTests.swift +3 -3
- package/apple/Tests/JavaScriptArrayBufferTests.swift +1 -1
- package/apple/Tests/JavaScriptArrayTests.swift +6 -4
- package/apple/Tests/JavaScriptBigIntTests.swift +20 -20
- package/apple/Tests/JavaScriptErrorTests.swift +15 -11
- package/apple/Tests/JavaScriptFunctionTests.swift +26 -26
- package/apple/Tests/JavaScriptNativeStateTests.swift +1 -1
- package/apple/Tests/JavaScriptObjectTests.swift +25 -13
- package/apple/Tests/JavaScriptPromiseTests.swift +56 -28
- package/apple/Tests/JavaScriptRefTests.swift +1 -1
- package/apple/Tests/JavaScriptRuntimeTests.swift +93 -60
- package/apple/Tests/JavaScriptTypedArrayTests.swift +20 -14
- package/apple/Tests/JavaScriptValueTests.swift +1 -1
- package/apple/Tests/JavaScriptValuesBufferTests.swift +1 -1
- package/apple/Tests/JavaScriptWeakObjectTests.swift +1 -1
- package/apple/scripts/build-xcframework.sh +96 -13
- package/apple/scripts/xcframework-helpers.sh +4 -0
- package/package.json +4 -2
|
@@ -1,79 +1,66 @@
|
|
|
1
1
|
// Copyright 2025-present 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
|
+
internal import ExpoModulesJSI_Cxx
|
|
3
4
|
import Foundation
|
|
4
|
-
|
|
5
5
|
internal import jsi
|
|
6
|
-
internal import ExpoModulesJSI_Cxx
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
A Swift wrapper around a JavaScript runtime. Provides access to a JavaScript execution environment, allowing you to evaluate
|
|
10
|
-
JavaScript code, create and manipulate JavaScript objects, functions, and values, and bridge between Swift and JavaScript.
|
|
11
6
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
7
|
+
/// A Swift wrapper around a JavaScript runtime. Provides access to a JavaScript execution environment, allowing you to evaluate
|
|
8
|
+
/// JavaScript code, create and manipulate JavaScript objects, functions, and values, and bridge between Swift and JavaScript.
|
|
9
|
+
///
|
|
10
|
+
/// ## Threading
|
|
11
|
+
///
|
|
12
|
+
/// JavaScript runtimes are single-threaded. All operations must be performed on the JavaScript
|
|
13
|
+
/// thread. Use `schedule()` or `execute()` methods to safely run code on the correct thread.
|
|
14
|
+
/// The runtime uses `@JavaScriptActor` to enforce thread safety at compile time.
|
|
15
|
+
///
|
|
16
|
+
/// ## Lifecycle
|
|
17
|
+
///
|
|
18
|
+
/// The runtime maintains a weak reference pattern for values, objects, and arrays to prevent
|
|
19
|
+
/// retain cycles. Ensure the runtime remains alive while any derived JavaScript objects are in use.
|
|
23
20
|
open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- are non-copyable. As value types, we would have to "borrow" them from React Native in an unsafe manner.
|
|
41
|
-
*/
|
|
21
|
+
/// The underlying JSI runtime this `JavaScriptRuntime` points to, exposed as
|
|
22
|
+
/// `IRuntime` — the abstract base interface that virtually all JSI value/object/
|
|
23
|
+
/// function methods take (`Value::getString`, `Object::setProperty`,
|
|
24
|
+
/// `Function::call`, …) since RN 0.86 split the API. Stored as the upcast result
|
|
25
|
+
/// of `runtimePointee` because Swift's C++ interop does not auto-upcast between
|
|
26
|
+
/// two `SwiftImportAs: reference` types.
|
|
27
|
+
///
|
|
28
|
+
/// Use ``runtimePointee`` instead when you specifically need a `jsi::Runtime&`
|
|
29
|
+
/// (e.g. constructing an `expo.RuntimeScheduler` whose binding lookup is typed on
|
|
30
|
+
/// `Runtime&` upstream).
|
|
31
|
+
///
|
|
32
|
+
/// Note that `facebook.jsi.IRuntime` and `facebook.jsi.Runtime` are imported as
|
|
33
|
+
/// reference types so for the Swift compiler they are treated like classes.
|
|
34
|
+
/// This is important because they:
|
|
35
|
+
/// - are abstract classes with many virtual methods. Swift/C++ interop does not support calling pure virtual methods on value types.
|
|
36
|
+
/// - are non-copyable. As value types, we would have to "borrow" them from React Native in an unsafe manner.
|
|
42
37
|
internal let pointee: facebook.jsi.IRuntime
|
|
43
38
|
internal let runtimePointee: facebook.jsi.Runtime
|
|
44
39
|
internal let scheduler: expo.RuntimeScheduler
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Assumes runtime initializers always run on the JS thread.
|
|
50
|
-
*/
|
|
41
|
+
/// Thread ID of the JavaScript thread, captured at construction time. Used by `isOnJavaScriptThread()`
|
|
42
|
+
/// for a fast integer comparison instead of `Thread.current.name == "..."`.
|
|
43
|
+
/// Assumes runtime initializers always run on the JS thread.
|
|
51
44
|
private let jsThreadID: UInt64 = {
|
|
52
45
|
var id: UInt64 = 0
|
|
53
46
|
pthread_threadid_np(nil, &id)
|
|
54
47
|
return id
|
|
55
48
|
}()
|
|
56
49
|
|
|
57
|
-
|
|
58
|
-
Actor for running runtime work.
|
|
59
|
-
*/
|
|
50
|
+
/// Actor for running runtime work.
|
|
60
51
|
lazy var runtimeActor: JavaScriptRuntimeActor = JavaScriptRuntimeActor(runtime: self)
|
|
61
52
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
`init(unsafePointer:nativeScheduler:dispatch:)` instead.
|
|
66
|
-
*/
|
|
53
|
+
/// Creates a runtime from the JSI runtime. The scheduler runs tasks synchronously
|
|
54
|
+
/// on the caller's thread — for the React-backed runtime, use
|
|
55
|
+
/// `init(unsafePointer:nativeScheduler:dispatch:)` instead.
|
|
67
56
|
internal init(_ runtime: facebook.jsi.Runtime) {
|
|
68
57
|
self.runtimePointee = runtime
|
|
69
58
|
self.pointee = expo.iruntime(runtime)
|
|
70
59
|
self.scheduler = expo.RuntimeScheduler()
|
|
71
60
|
}
|
|
72
61
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
no React scheduler is wired up.
|
|
76
|
-
*/
|
|
62
|
+
/// Creates a standalone Hermes runtime. Scheduled tasks run synchronously —
|
|
63
|
+
/// no React scheduler is wired up.
|
|
77
64
|
public init() {
|
|
78
65
|
let runtime = expo.createHermesRuntime()
|
|
79
66
|
self.runtimePointee = runtime
|
|
@@ -81,11 +68,9 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
81
68
|
self.scheduler = expo.RuntimeScheduler()
|
|
82
69
|
}
|
|
83
70
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`init(unsafePointer:nativeScheduler:dispatch:)` instead.
|
|
88
|
-
*/
|
|
71
|
+
/// Creates a runtime from a raw pointer to the underlying `facebook.jsi.Runtime`.
|
|
72
|
+
/// Scheduled tasks run synchronously — for the React-backed runtime, use
|
|
73
|
+
/// `init(unsafePointer:nativeScheduler:dispatch:)` instead.
|
|
89
74
|
public init(unsafePointer: UnsafeMutableRawPointer) {
|
|
90
75
|
let runtime = unsafeBitCast(unsafePointer, to: facebook.jsi.Runtime.self)
|
|
91
76
|
self.runtimePointee = runtime
|
|
@@ -93,17 +78,15 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
93
78
|
self.scheduler = expo.RuntimeScheduler()
|
|
94
79
|
}
|
|
95
80
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`void (*)(void *scheduler, int priority, void (^callback)())`.
|
|
106
|
-
*/
|
|
81
|
+
/// Creates a runtime bound to a host-provided React `RuntimeScheduler`. Calls to
|
|
82
|
+
/// `schedule(...)` / `.execute(...)` dispatch through `dispatch`, which the host
|
|
83
|
+
/// implements against the real `react::RuntimeScheduler`. This is the path the
|
|
84
|
+
/// React Native factory uses.
|
|
85
|
+
///
|
|
86
|
+
/// - `unsafePointer`: raw pointer to the underlying `facebook::jsi::Runtime`.
|
|
87
|
+
/// - `scheduler`: raw pointer to the `react::RuntimeScheduler` instance.
|
|
88
|
+
/// - `dispatch`: raw pointer to a C function with signature
|
|
89
|
+
/// `void (*)(void *scheduler, int priority, void (^callback)())`.
|
|
107
90
|
public init(
|
|
108
91
|
unsafePointer: UnsafeMutableRawPointer,
|
|
109
92
|
scheduler: UnsafeMutableRawPointer,
|
|
@@ -116,34 +99,26 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
116
99
|
self.scheduler = expo.RuntimeScheduler(scheduler, fn)
|
|
117
100
|
}
|
|
118
101
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
The pointer is valid only for the duration of the closure and must not be stored or escaped.
|
|
122
|
-
*/
|
|
102
|
+
/// Provides scoped access to a raw pointer to the underlying `facebook.jsi.Runtime`.
|
|
103
|
+
/// The pointer is valid only for the duration of the closure and must not be stored or escaped.
|
|
123
104
|
public func withUnsafePointee<R>(_ body: (UnsafeMutableRawPointer) throws -> R) rethrows -> R {
|
|
124
105
|
return try body(Unmanaged<facebook.jsi.Runtime>.passUnretained(runtimePointee).toOpaque())
|
|
125
106
|
}
|
|
126
107
|
|
|
127
|
-
|
|
128
|
-
Returns the runtime `global` object.
|
|
129
|
-
*/
|
|
108
|
+
/// Returns the runtime `global` object.
|
|
130
109
|
public func global() -> JavaScriptObject {
|
|
131
110
|
return JavaScriptObject(self, pointee.global())
|
|
132
111
|
}
|
|
133
112
|
|
|
134
113
|
// MARK: - Creating objects
|
|
135
114
|
|
|
136
|
-
|
|
137
|
-
Creates a plain JavaScript object.
|
|
138
|
-
*/
|
|
115
|
+
/// Creates a plain JavaScript object.
|
|
139
116
|
public func createObject() -> JavaScriptObject {
|
|
140
117
|
return JavaScriptObject(self, facebook.jsi.Object(pointee))
|
|
141
118
|
}
|
|
142
119
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
Calls `Object.create(prototype)` under the hood.
|
|
146
|
-
*/
|
|
120
|
+
/// Creates a new JavaScript object, using the provided object as the prototype.
|
|
121
|
+
/// Calls `Object.create(prototype)` under the hood.
|
|
147
122
|
public func createObject(prototype: borrowing JavaScriptObject) -> JavaScriptObject {
|
|
148
123
|
return try! global()
|
|
149
124
|
.getPropertyAsObject("Object")
|
|
@@ -152,16 +127,14 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
152
127
|
.getObject()
|
|
153
128
|
}
|
|
154
129
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
writable. `getPropertyNames` and `dealloc` default to no-ops.
|
|
164
|
-
*/
|
|
130
|
+
/// Creates a JavaScript host object with given implementations for property getter, property setter, property names getter and dealloc.
|
|
131
|
+
///
|
|
132
|
+
/// Errors thrown from `get` or `set` propagate to JavaScript as a thrown `Error`. Conform
|
|
133
|
+
/// the thrown type to `JavaScriptThrowable` to control the resulting `message` and `code`.
|
|
134
|
+
///
|
|
135
|
+
/// Pass `nil` for `set` to make the host object read-only — assignment from JavaScript
|
|
136
|
+
/// then throws an `Error` whose message names the property and explains how to make it
|
|
137
|
+
/// writable. `getPropertyNames` and `dealloc` default to no-ops.
|
|
165
138
|
public func createHostObject(
|
|
166
139
|
get: @escaping @JavaScriptActor (_ propertyName: String) throws -> JavaScriptValue,
|
|
167
140
|
set: (@JavaScriptActor (_ propertyName: String, _ value: JavaScriptValue) throws -> Void)? = nil,
|
|
@@ -182,7 +155,9 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
182
155
|
}
|
|
183
156
|
}
|
|
184
157
|
|
|
185
|
-
func setter(
|
|
158
|
+
func setter(
|
|
159
|
+
context: UnsafeMutableRawPointer, propertyName: UnsafePointer<CChar>, valuePointer: UnsafeMutableRawPointer
|
|
160
|
+
) {
|
|
186
161
|
let context = Unmanaged<HostObjectContext>.fromOpaque(context).takeUnretainedValue()
|
|
187
162
|
|
|
188
163
|
guard let runtime = context.runtime else {
|
|
@@ -236,10 +211,12 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
236
211
|
}
|
|
237
212
|
}
|
|
238
213
|
|
|
239
|
-
let context = Unmanaged.passRetained(HostObjectContext(runtime: self, get, set, getPropertyNames, dealloc))
|
|
214
|
+
let context = Unmanaged.passRetained(HostObjectContext(runtime: self, get, set, getPropertyNames, dealloc))
|
|
215
|
+
.toOpaque()
|
|
240
216
|
// Pass a null setter to C++ when the Swift setter is nil so that JS assignment
|
|
241
217
|
// raises a `jsi::JSError` directly, without crossing the Swift boundary.
|
|
242
|
-
let callbacks = expo.HostObjectCallbacks(
|
|
218
|
+
let callbacks = expo.HostObjectCallbacks(
|
|
219
|
+
context, getter, set == nil ? nil : setter, propertyNamesGetter, deallocate)
|
|
243
220
|
let hostObject = expo.HostObject.makeObject(pointee, consume callbacks)
|
|
244
221
|
|
|
245
222
|
return JavaScriptObject(self, hostObject)
|
|
@@ -247,19 +224,17 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
247
224
|
|
|
248
225
|
// MARK: - Creating array buffers
|
|
249
226
|
|
|
250
|
-
|
|
251
|
-
Creates a new array buffer of the given size with zero-initialized memory.
|
|
252
|
-
*/
|
|
227
|
+
/// Creates a new array buffer of the given size with zero-initialized memory.
|
|
253
228
|
public func createArrayBuffer(size: Int) -> JavaScriptArrayBuffer {
|
|
254
229
|
let jsiArrayBuffer = expo.createArrayBuffer(pointee, size)
|
|
255
230
|
return JavaScriptArrayBuffer(self, jsiArrayBuffer)
|
|
256
231
|
}
|
|
257
232
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
233
|
+
/// Creates a new array buffer that wraps the given native data pointer.
|
|
234
|
+
/// The cleanup closure is called when the array buffer is garbage collected.
|
|
235
|
+
public func createArrayBuffer(data: UnsafeMutablePointer<UInt8>, size: Int, cleanup: @escaping @Sendable () -> Void)
|
|
236
|
+
-> JavaScriptArrayBuffer
|
|
237
|
+
{
|
|
263
238
|
let context = Unmanaged.passRetained(CleanupContext(cleanup)).toOpaque()
|
|
264
239
|
let jsiArrayBuffer = expo.createArrayBuffer(pointee, data, size, context) { context in
|
|
265
240
|
Unmanaged<CleanupContext>.fromOpaque(context).release()
|
|
@@ -269,28 +244,26 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
269
244
|
|
|
270
245
|
// MARK: - Creating arrays
|
|
271
246
|
|
|
272
|
-
|
|
273
|
-
Creates a new Array instance.
|
|
274
|
-
*/
|
|
247
|
+
/// Creates a new Array instance.
|
|
275
248
|
public func createArray(length: Int = 0) -> JavaScriptArray {
|
|
276
249
|
return JavaScriptArray(self, facebook.jsi.Array(pointee, length))
|
|
277
250
|
}
|
|
278
251
|
|
|
279
252
|
// MARK: - Creating functions
|
|
280
253
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
Creates a class with the given name and native constructor.
|
|
291
|
-
*/
|
|
254
|
+
/// Type of the closure that is passed to the `createFunction` function.
|
|
255
|
+
public typealias SyncFunctionClosure =
|
|
256
|
+
@JavaScriptActor (
|
|
257
|
+
_ this: JavaScriptValue,
|
|
258
|
+
_ arguments: consuming JavaScriptValuesBuffer
|
|
259
|
+
) throws -> JavaScriptValue
|
|
260
|
+
|
|
261
|
+
/// Creates a class with the given name and native constructor.
|
|
292
262
|
@JavaScriptActor
|
|
293
|
-
public func createClass(
|
|
263
|
+
public func createClass(
|
|
264
|
+
name: String, inheriting baseClass: consuming JavaScriptFunction? = nil,
|
|
265
|
+
_ constructor: @escaping SyncFunctionClosure
|
|
266
|
+
) throws -> JavaScriptFunction {
|
|
294
267
|
// Host functions are not standard functions, thus cannot be used as class constructors.
|
|
295
268
|
// We're creating one by evaluating a script that calls a "native constructor" that is a host function.
|
|
296
269
|
let nativeConstructorKey = "__native_constructor__"
|
|
@@ -300,7 +273,9 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
300
273
|
throw InvalidIdentifierError(identifier: name)
|
|
301
274
|
}
|
|
302
275
|
|
|
303
|
-
let klassValue = try eval(
|
|
276
|
+
let klassValue = try eval(
|
|
277
|
+
label: "\(name).\(nativeConstructorKey)",
|
|
278
|
+
"(function \(name)(...args) { return this.\(nativeConstructorKey)(...args); })")
|
|
304
279
|
let klassObject = klassValue.getObject()
|
|
305
280
|
|
|
306
281
|
// Create a host function that is called by the constructor
|
|
@@ -309,7 +284,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
309
284
|
}
|
|
310
285
|
|
|
311
286
|
// Set native constructor as read-only, non-configurable, non-enumerable, non-writable property.
|
|
312
|
-
let prototype = klassObject.getPropertyAsObject("prototype")
|
|
287
|
+
let prototype = try klassObject.getPropertyAsObject("prototype")
|
|
313
288
|
prototype.defineProperty(nativeConstructorKey, value: nativeConstructor)
|
|
314
289
|
|
|
315
290
|
// If the base class is provided, set the inherited prototype.
|
|
@@ -324,11 +299,9 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
324
299
|
return klassValue.getFunction()
|
|
325
300
|
}
|
|
326
301
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
- Returns: A JavaScript function represented as a `JavaScriptFunction`.
|
|
331
|
-
*/
|
|
302
|
+
/// Creates a synchronous host function that runs the given closure when it's called.
|
|
303
|
+
/// The value returned by the closure is synchronously returned to JS.
|
|
304
|
+
/// - Returns: A JavaScript function represented as a `JavaScriptFunction`.
|
|
332
305
|
@JavaScriptActor
|
|
333
306
|
public func createFunction(_ name: String, _ function: sending @escaping SyncFunctionClosure) -> JavaScriptFunction {
|
|
334
307
|
let closure = createFunctionClosure(runtime: self, name: name, function)
|
|
@@ -337,11 +310,9 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
337
310
|
return JavaScriptFunction(self, hostFunction)
|
|
338
311
|
}
|
|
339
312
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
- Returns: A JavaScript function represented as a `JavaScriptFunction`.
|
|
344
|
-
*/
|
|
313
|
+
/// Creates a synchronous anonymous host function that runs the given closure when it's called.
|
|
314
|
+
/// The value returned by the closure is synchronously returned to JS.
|
|
315
|
+
/// - Returns: A JavaScript function represented as a `JavaScriptFunction`.
|
|
345
316
|
@JavaScriptActor
|
|
346
317
|
public func createFunction(_ function: sending @escaping SyncFunctionClosure) -> JavaScriptFunction {
|
|
347
318
|
let closure = createFunctionClosure(runtime: self, name: nil, function)
|
|
@@ -350,24 +321,23 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
350
321
|
return JavaScriptFunction(self, hostFunction)
|
|
351
322
|
}
|
|
352
323
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
The value returned by the closure is returned to JS asynchronously.
|
|
365
|
-
- Returns: A JavaScript function represented as a `JavaScriptFunction` that returns a promise.
|
|
366
|
-
*/
|
|
324
|
+
/// Type of the closure that is passed to the `createAsyncFunction` function.
|
|
325
|
+
/// It is invoked from asynchronous context, so it can await and call other asynchronous functions.
|
|
326
|
+
public typealias AsyncFunctionClosure =
|
|
327
|
+
@JavaScriptActor (
|
|
328
|
+
_ this: JavaScriptValue,
|
|
329
|
+
_ arguments: consuming JavaScriptValuesBuffer,
|
|
330
|
+
) async throws -> JavaScriptValue
|
|
331
|
+
|
|
332
|
+
/// Creates an asynchronous host function that runs given block when it's called.
|
|
333
|
+
/// The value returned by the closure is returned to JS asynchronously.
|
|
334
|
+
/// - Returns: A JavaScript function represented as a `JavaScriptFunction` that returns a promise.
|
|
367
335
|
@JavaScriptActor
|
|
368
|
-
public func createAsyncFunction(_ name: String, _ function: sending @escaping AsyncFunctionClosure)
|
|
336
|
+
public func createAsyncFunction(_ name: String, _ function: sending @escaping AsyncFunctionClosure)
|
|
337
|
+
-> JavaScriptFunction
|
|
338
|
+
{
|
|
369
339
|
return createFunction(name) { this, arguments in
|
|
370
|
-
let promise = JavaScriptPromise(self)
|
|
340
|
+
let promise = try JavaScriptPromise(self)
|
|
371
341
|
|
|
372
342
|
// Arguments buffer needs to be copied to ensure safe async access.
|
|
373
343
|
let argumentsRef = arguments.copy().ref()
|
|
@@ -390,18 +360,17 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
390
360
|
|
|
391
361
|
// MARK: - Runtime execution
|
|
392
362
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
Returns false for standalone runtimes (e.g. in tests) where scheduled tasks run synchronously.
|
|
396
|
-
*/
|
|
363
|
+
/// Whether the runtime scheduler can dispatch work asynchronously to the JS thread.
|
|
364
|
+
/// Returns false for standalone runtimes (e.g. in tests) where scheduled tasks run synchronously.
|
|
397
365
|
public var supportsAsyncScheduling: Bool {
|
|
398
366
|
return scheduler.supportsAsyncScheduling()
|
|
399
367
|
}
|
|
400
368
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
369
|
+
/// Schedules a closure to be executed with granted synchronized access to the runtime.
|
|
370
|
+
public func schedule(
|
|
371
|
+
priority: SchedulerPriority = .normal,
|
|
372
|
+
@_implicitSelfCapture _ closure: @escaping @JavaScriptActor () -> sending Void
|
|
373
|
+
) {
|
|
405
374
|
let cxxPriority = expo.RuntimeScheduler.Priority(rawValue: priority.rawValue) ?? .NormalPriority
|
|
406
375
|
scheduler.scheduleTask(cxxPriority) {
|
|
407
376
|
JavaScriptActor.assumeIsolated(closure)
|
|
@@ -411,7 +380,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
411
380
|
public func schedule(
|
|
412
381
|
priority: SchedulerPriority = .normal,
|
|
413
382
|
@_implicitSelfCapture _ closure: @escaping @JavaScriptActor () async throws -> Void
|
|
414
|
-
)
|
|
383
|
+
) {
|
|
415
384
|
schedule(priority: priority) {
|
|
416
385
|
Task.immediate_polyfill {
|
|
417
386
|
try await closure()
|
|
@@ -419,13 +388,13 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
419
388
|
}
|
|
420
389
|
}
|
|
421
390
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
Not available in async contexts to prevent blocking the cooperative thread pool.
|
|
425
|
-
*/
|
|
391
|
+
/// Synchronously executes a closure on the JavaScript runtime thread, blocking the current thread until completion.
|
|
392
|
+
/// Not available in async contexts to prevent blocking the cooperative thread pool.
|
|
426
393
|
@available(*, noasync)
|
|
427
394
|
@discardableResult
|
|
428
|
-
public func execute<R: Sendable>(@_implicitSelfCapture _ closure: @escaping @JavaScriptActor () throws -> R) throws
|
|
395
|
+
public func execute<R: Sendable>(@_implicitSelfCapture _ closure: @escaping @JavaScriptActor () throws -> R) throws
|
|
396
|
+
-> sending R
|
|
397
|
+
{
|
|
429
398
|
if isOnJavaScriptThread() {
|
|
430
399
|
return try JavaScriptActor.assumeIsolated(closure)
|
|
431
400
|
}
|
|
@@ -460,10 +429,8 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
460
429
|
return try result.get()
|
|
461
430
|
}
|
|
462
431
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
Not available in async contexts to prevent blocking the cooperative thread pool.
|
|
466
|
-
*/
|
|
432
|
+
/// Synchronously executes an async closure on the JavaScript runtime thread, blocking the current thread until completion.
|
|
433
|
+
/// Not available in async contexts to prevent blocking the cooperative thread pool.
|
|
467
434
|
@available(*, noasync)
|
|
468
435
|
@discardableResult
|
|
469
436
|
public func execute<R: Sendable>(
|
|
@@ -475,7 +442,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
475
442
|
// to work around a Swift 6.2.3 compiler bug.
|
|
476
443
|
let callerRunLoop = NonisolatedUnsafeVar(CFRunLoopGetCurrent())
|
|
477
444
|
|
|
478
|
-
func body()
|
|
445
|
+
func body() {
|
|
479
446
|
Task.immediate_polyfill(priority: .high) {
|
|
480
447
|
do {
|
|
481
448
|
result.value = .success(try await closure())
|
|
@@ -503,9 +470,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
503
470
|
return try result.value.get()
|
|
504
471
|
}
|
|
505
472
|
|
|
506
|
-
|
|
507
|
-
Asynchronously executes a sync closure on the JavaScript runtime thread, awaiting its completion without blocking.
|
|
508
|
-
*/
|
|
473
|
+
/// Asynchronously executes a sync closure on the JavaScript runtime thread, awaiting its completion without blocking.
|
|
509
474
|
@discardableResult
|
|
510
475
|
public func execute<R: Sendable>(
|
|
511
476
|
@_implicitSelfCapture _ closure: @escaping @JavaScriptActor () throws -> R
|
|
@@ -524,9 +489,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
524
489
|
}
|
|
525
490
|
}
|
|
526
491
|
|
|
527
|
-
|
|
528
|
-
Asynchronously executes an async closure on the JavaScript runtime thread, awaiting its completion without blocking.
|
|
529
|
-
*/
|
|
492
|
+
/// Asynchronously executes an async closure on the JavaScript runtime thread, awaiting its completion without blocking.
|
|
530
493
|
@discardableResult
|
|
531
494
|
public func execute<R: Sendable>(
|
|
532
495
|
@_implicitSelfCapture _ closure: @escaping @JavaScriptActor () async throws -> R
|
|
@@ -547,9 +510,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
547
510
|
}
|
|
548
511
|
}
|
|
549
512
|
|
|
550
|
-
|
|
551
|
-
Checks whether the function is called on the JavaScript thread.
|
|
552
|
-
*/
|
|
513
|
+
/// Checks whether the function is called on the JavaScript thread.
|
|
553
514
|
@inline(__always)
|
|
554
515
|
public final func isOnJavaScriptThread() -> Bool {
|
|
555
516
|
var current: UInt64 = 0
|
|
@@ -557,18 +518,14 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
557
518
|
return current == jsThreadID
|
|
558
519
|
}
|
|
559
520
|
|
|
560
|
-
|
|
561
|
-
Asserts whether we are on the JavaScript thread. Helpful for debugging threading issues.
|
|
562
|
-
*/
|
|
521
|
+
/// Asserts whether we are on the JavaScript thread. Helpful for debugging threading issues.
|
|
563
522
|
@inline(__always)
|
|
564
523
|
public final func assertThread(file: String = #file, function: String = #function, line: Int = #line) {
|
|
565
524
|
assert(isOnJavaScriptThread(), "Function '\(function)' is not run on the JavaScript thread (\(file):\(line))")
|
|
566
525
|
}
|
|
567
526
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
- Note: Keep it in sync with the equivalent C++ enum from React Native (see `SchedulerPriority.h` from `React-callinvoker`).
|
|
571
|
-
*/
|
|
527
|
+
/// Priority of the scheduled task.
|
|
528
|
+
/// - Note: Keep it in sync with the equivalent C++ enum from React Native (see `SchedulerPriority.h` from `React-callinvoker`).
|
|
572
529
|
public enum SchedulerPriority: Int32 {
|
|
573
530
|
case immediate = 1
|
|
574
531
|
case userBlocking = 2
|
|
@@ -579,9 +536,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
579
536
|
|
|
580
537
|
// MARK: - Script evaluation
|
|
581
538
|
|
|
582
|
-
|
|
583
|
-
Evaluates given JavaScript source code.
|
|
584
|
-
*/
|
|
539
|
+
/// Evaluates given JavaScript source code.
|
|
585
540
|
@discardableResult
|
|
586
541
|
@JavaScriptActor
|
|
587
542
|
public func eval(label: String? = nil, _ source: String) throws -> JavaScriptValue {
|
|
@@ -597,9 +552,7 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
597
552
|
}
|
|
598
553
|
}
|
|
599
554
|
|
|
600
|
-
|
|
601
|
-
Evaluates the given JavaScript source code made by joining an array of strings with a newline separator.
|
|
602
|
-
*/
|
|
555
|
+
/// Evaluates the given JavaScript source code made by joining an array of strings with a newline separator.
|
|
603
556
|
@available(*, deprecated, message: "Spread the array into arguments instead")
|
|
604
557
|
@discardableResult
|
|
605
558
|
@JavaScriptActor
|
|
@@ -607,18 +560,14 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
607
560
|
try eval(label: label, lines.joined(separator: "\n"))
|
|
608
561
|
}
|
|
609
562
|
|
|
610
|
-
|
|
611
|
-
Evaluates the given JavaScript source code made by joining arguments with a newline separator.
|
|
612
|
-
*/
|
|
563
|
+
/// Evaluates the given JavaScript source code made by joining arguments with a newline separator.
|
|
613
564
|
@discardableResult
|
|
614
565
|
@JavaScriptActor
|
|
615
566
|
public func eval(label: String? = nil, _ lines: String...) throws -> JavaScriptValue {
|
|
616
567
|
try eval(label: label, lines.joined(separator: "\n"))
|
|
617
568
|
}
|
|
618
569
|
|
|
619
|
-
|
|
620
|
-
Evaluates given JavaScript source code in an async context. If the evaluated source returns a Promise, it awaits until the promise is resolved/rejected.
|
|
621
|
-
*/
|
|
570
|
+
/// Evaluates given JavaScript source code in an async context. If the evaluated source returns a Promise, it awaits until the promise is resolved/rejected.
|
|
622
571
|
@discardableResult
|
|
623
572
|
@JavaScriptActor
|
|
624
573
|
public func evalAsync(label: String? = nil, _ source: String) async throws -> JavaScriptValue {
|
|
@@ -638,10 +587,15 @@ open class JavaScriptRuntime: Equatable, @unchecked Sendable {
|
|
|
638
587
|
internal var propNameIdsRegistry: [String: JavaScriptPropNameID] = [:]
|
|
639
588
|
}
|
|
640
589
|
|
|
641
|
-
private func createFunctionClosure(
|
|
590
|
+
private func createFunctionClosure(
|
|
591
|
+
runtime: JavaScriptRuntime, name: String? = nil, _ closure: @escaping JavaScriptRuntime.SyncFunctionClosure
|
|
592
|
+
) -> expo.HostFunctionClosure {
|
|
642
593
|
let context = Unmanaged.passRetained(HostFunctionContext(runtime: runtime, name: name, closure)).toOpaque()
|
|
643
594
|
|
|
644
|
-
func call(
|
|
595
|
+
func call(
|
|
596
|
+
context: UnsafeMutableRawPointer, thisPtr: UnsafePointer<facebook.jsi.Value>,
|
|
597
|
+
argumentsPtr: UnsafePointer<facebook.jsi.Value>, argumentsCount: Int
|
|
598
|
+
) -> facebook.jsi.Value {
|
|
645
599
|
let context = Unmanaged<HostFunctionContext>.fromOpaque(context).takeUnretainedValue()
|
|
646
600
|
|
|
647
601
|
guard let runtime = context.runtime else {
|
|
@@ -668,14 +622,10 @@ private func createFunctionClosure(runtime: JavaScriptRuntime, name: String? = n
|
|
|
668
622
|
// MARK: - Errors
|
|
669
623
|
|
|
670
624
|
extension JavaScriptRuntime {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
the name into evaluated JavaScript source, such as ``createClass(name:inheriting:_:)``.
|
|
674
|
-
*/
|
|
625
|
+
/// Thrown when an invalid JavaScript identifier is passed to APIs that interpolate
|
|
626
|
+
/// the name into evaluated JavaScript source, such as ``createClass(name:inheriting:_:)``.
|
|
675
627
|
public struct InvalidIdentifierError: Error, CustomStringConvertible {
|
|
676
|
-
|
|
677
|
-
The identifier string that failed validation.
|
|
678
|
-
*/
|
|
628
|
+
/// The identifier string that failed validation.
|
|
679
629
|
public let identifier: String
|
|
680
630
|
|
|
681
631
|
public var description: String {
|