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
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,18 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 56.0.8 — 2026-06-05
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Fixed the xcframework build failing with a `sed` error when building in an environment that uses GNU `sed` instead of BSD `sed` (e.g. a Nix shell). ([#46389](https://github.com/expo/expo/pull/46389) by [@niteshbalusu11](https://github.com/niteshbalusu11))
|
|
18
|
+
- [iOS] Propagate `JavaScriptPromise` setup failures instead of trapping the app. ([#46106](https://github.com/expo/expo/issues/46106) by [@qutrek](https://github.com/qutrek)) ([#46145](https://github.com/expo/expo/pull/46145) by [@mvincentong](https://github.com/mvincentong))
|
|
19
|
+
- Fix build framework for macOS ([#46413](https://github.com/expo/expo/pull/46413) by [@gabrieldonadel](https://github.com/gabrieldonadel))
|
|
20
|
+
- Fix build framework for Mac Catalyst ([#46289](https://github.com/expo/expo/pull/46289) by [@theeket](https://github.com/theeket))
|
|
21
|
+
- [iOS] Throw instead of aborting when `getPropertyAsFunction` targets a missing or non-callable property. ([#46437](https://github.com/expo/expo/pull/46437) by [@tsapeta](https://github.com/tsapeta))
|
|
22
|
+
- [iOS] Throw instead of aborting when `getPropertyAsObject` targets a non-object property. ([#46438](https://github.com/expo/expo/pull/46438) by [@tsapeta](https://github.com/tsapeta))
|
|
23
|
+
- [iOS] Include the Swift toolchain version in the xcframework cache key so upgrading Xcode rebuilds slices instead of reusing ones built by an older compiler. ([#46523](https://github.com/expo/expo/pull/46523) by [@tsapeta](https://github.com/tsapeta))
|
|
24
|
+
|
|
13
25
|
## 56.0.7 — 2026-05-20
|
|
14
26
|
|
|
15
27
|
### 🐛 Bug fixes
|
package/CLAUDE.md
CHANGED
|
@@ -60,3 +60,7 @@ struct JavaScriptRuntimeTests {
|
|
|
60
60
|
Tests are in `apple/Tests/` and each file covers one type. Some suites use the global actor `@JavaScriptActor` for executor isolation.
|
|
61
61
|
|
|
62
62
|
Run them with `pnpm test` from the package root, which calls `apple/scripts/test.sh`. The script needs an installed host app's `Pods` directory (defaults to `$EXPO_ROOT_DIR/apps/bare-expo/ios/Pods`); override with `PODS_ROOT`. It symlinks React / hermesvm / ReactNativeDependencies xcframeworks into `apple/.test-frameworks/` so SPM can resolve them as relative-path binary targets, generates the `jsi` modulemap, and runs `xcodebuild test` against an iOS Simulator (override with `DESTINATION`). Extra args pass through to xcodebuild — e.g. `pnpm test -only-testing TestName`.
|
|
63
|
+
|
|
64
|
+
## Formatting
|
|
65
|
+
|
|
66
|
+
Swift sources are formatted with swift-format. From the package root, `pnpm swift:format` rewrites files in place and `pnpm swift:lint` checks without modifying; both delegate to the repo-root `scripts/swift-format.sh`, which reads the repo-root `.swift-format` config and only touches tracked `.swift` files. CI enforces this via `.github/workflows/swift-format.yml`, which pins a specific swift-format version — mismatched local versions can produce different output, so prefer the pinned one. Style conventions beyond what the formatter enforces live in [`guides/Swift Style Guide.md`](../../guides/Swift%20Style%20Guide.md) at the repo root.
|
package/apple/Package.swift
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// swift-tools-version: 6.2
|
|
2
2
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
|
3
3
|
|
|
4
|
-
import PackageDescription
|
|
5
4
|
import Foundation
|
|
5
|
+
import PackageDescription
|
|
6
6
|
|
|
7
7
|
let packageDir = URL(fileURLWithPath: #filePath).deletingLastPathComponent().path
|
|
8
8
|
let podsRoot = resolvePodsRoot()
|
|
@@ -17,7 +17,8 @@ let podsRoot = resolvePodsRoot()
|
|
|
17
17
|
// `REACT_NATIVE_PATH` is exported by Xcode for hosts that build RN from a
|
|
18
18
|
// non-npm location, e.g. Expo Go.
|
|
19
19
|
let publicHeaders = "\(podsRoot)/Headers/Public"
|
|
20
|
-
let reactNative =
|
|
20
|
+
let reactNative =
|
|
21
|
+
ProcessInfo.processInfo.environment["RN_ROOT"]
|
|
21
22
|
?? ProcessInfo.processInfo.environment["REACT_NATIVE_PATH"]
|
|
22
23
|
?? "\(podsRoot)/../../node_modules/react-native"
|
|
23
24
|
let headerSearchPaths = [
|
|
@@ -72,7 +73,7 @@ let package = Package(
|
|
|
72
73
|
name: "ExpoModulesJSI",
|
|
73
74
|
type: .dynamic,
|
|
74
75
|
targets: ["ExpoModulesJSI"],
|
|
75
|
-
)
|
|
76
|
+
)
|
|
76
77
|
],
|
|
77
78
|
dependencies: [],
|
|
78
79
|
targets: [
|
|
@@ -80,7 +81,7 @@ let package = Package(
|
|
|
80
81
|
.target(
|
|
81
82
|
name: "ExpoModulesJSI",
|
|
82
83
|
dependencies: [
|
|
83
|
-
"ExpoModulesJSI-Cxx"
|
|
84
|
+
"ExpoModulesJSI-Cxx"
|
|
84
85
|
],
|
|
85
86
|
swiftSettings: [
|
|
86
87
|
.interoperabilityMode(.Cxx),
|
|
@@ -115,7 +116,7 @@ let package = Package(
|
|
|
115
116
|
// builds without those static libs being available here.
|
|
116
117
|
.unsafeFlags([
|
|
117
118
|
"-Xlinker", "-undefined", "-Xlinker", "dynamic_lookup",
|
|
118
|
-
])
|
|
119
|
+
])
|
|
119
120
|
],
|
|
120
121
|
),
|
|
121
122
|
|
|
@@ -124,7 +125,7 @@ let package = Package(
|
|
|
124
125
|
name: "ExpoModulesJSI-Cxx",
|
|
125
126
|
dependencies: [],
|
|
126
127
|
cxxSettings: [
|
|
127
|
-
.unsafeFlags(cxxIncludeFlags)
|
|
128
|
+
.unsafeFlags(cxxIncludeFlags)
|
|
128
129
|
],
|
|
129
130
|
),
|
|
130
131
|
|
|
@@ -147,10 +148,12 @@ func resolvePodsRoot() -> String {
|
|
|
147
148
|
if let explicit = env["PODS_ROOT"] {
|
|
148
149
|
return explicit
|
|
149
150
|
}
|
|
150
|
-
let repoRoot =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
.deletingLastPathComponent()
|
|
151
|
+
let repoRoot =
|
|
152
|
+
env["EXPO_ROOT_DIR"]
|
|
153
|
+
?? URL(fileURLWithPath: packageDir)
|
|
154
|
+
.deletingLastPathComponent() // expo-modules-jsi
|
|
155
|
+
.deletingLastPathComponent() // packages
|
|
156
|
+
.deletingLastPathComponent() // repo root
|
|
154
157
|
.path
|
|
155
158
|
return "\(repoRoot)/apps/bare-expo/ios/Pods"
|
|
156
159
|
}
|
|
@@ -171,7 +174,8 @@ func resolveTestFrameworks() -> (binaryTargets: [Target], dependencies: [Target.
|
|
|
171
174
|
let binaryTargets: [Target] = available.map({
|
|
172
175
|
.binaryTarget(name: $0, path: ".test-frameworks/\($0).xcframework")
|
|
173
176
|
})
|
|
174
|
-
let dependencies: [Target.Dependency] =
|
|
177
|
+
let dependencies: [Target.Dependency] =
|
|
178
|
+
["ExpoModulesJSI"]
|
|
175
179
|
+ available.map({ .target(name: $0) })
|
|
176
180
|
return (binaryTargets, dependencies)
|
|
177
181
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// Copyright 2025-present 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Used to bridge Swift closures to C++ cleanup callbacks via `Unmanaged` pointers.
|
|
6
|
-
*/
|
|
3
|
+
/// A box that holds a cleanup closure and invokes it on deallocation.
|
|
4
|
+
/// Used to bridge Swift closures to C++ cleanup callbacks via `Unmanaged` pointers.
|
|
7
5
|
internal final class CleanupContext: Sendable {
|
|
8
6
|
let cleanup: @Sendable () -> Void
|
|
9
7
|
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Context that captures Swift values to pass them to JSI host function as an unmanaged pointer for interoperability with C++.
|
|
3
|
-
*/
|
|
1
|
+
/// Context that captures Swift values to pass them to JSI host function as an unmanaged pointer for interoperability with C++.
|
|
4
2
|
internal final class HostFunctionContext: Sendable {
|
|
5
3
|
weak let runtime: JavaScriptRuntime?
|
|
6
4
|
let name: String?
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Context that captures Swift types to pass them to JSI host object as an unmanaged pointer for interoperability with C++.
|
|
3
|
-
*/
|
|
1
|
+
/// Context that captures Swift types to pass them to JSI host object as an unmanaged pointer for interoperability with C++.
|
|
4
2
|
internal final class HostObjectContext: Sendable {
|
|
5
3
|
typealias Getter = @JavaScriptActor (_ propertyName: String) throws -> JavaScriptValue
|
|
6
4
|
typealias Setter = @JavaScriptActor (_ propertyName: String, _ value: JavaScriptValue) throws -> Void
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// swift-format-ignore-file: AlwaysUseLowerCamelCase
|
|
2
|
+
|
|
1
3
|
// `Task.immediate` is a pretty useful API that lets us immediately switch from synchronous to asynchronous context.
|
|
2
4
|
// Read the proposal for more: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0472-task-start-synchronously-on-caller-context.md
|
|
3
5
|
// Unfortunately, it is available only as of Apple OS 26.0 and there are no plans to backport it yet.
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import CoreGraphics
|
|
2
|
-
internal import jsi
|
|
3
2
|
internal import ExpoModulesJSI_Cxx
|
|
3
|
+
internal import jsi
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
A type whose values can be represented as `facebook.jsi.Value`.
|
|
7
|
-
*/
|
|
5
|
+
/// A type whose values can be represented as `facebook.jsi.Value`.
|
|
8
6
|
internal protocol JSIRepresentable: JavaScriptRepresentable, Sendable, ~Copyable {
|
|
9
|
-
|
|
10
|
-
Creates an instance of this type from the given `facebook.jsi.Value` in `facebook.jsi.IRuntime`.
|
|
11
|
-
*/
|
|
7
|
+
/// Creates an instance of this type from the given `facebook.jsi.Value` in `facebook.jsi.IRuntime`.
|
|
12
8
|
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) -> Self
|
|
13
|
-
|
|
14
|
-
Creates a JSI value representing this value in the given JSI runtime.
|
|
15
|
-
*/
|
|
9
|
+
/// Creates a JSI value representing this value in the given JSI runtime.
|
|
16
10
|
func toJSIValue(in runtime: facebook.jsi.IRuntime) -> facebook.jsi.Value
|
|
17
11
|
}
|
|
18
12
|
|
|
@@ -52,11 +46,13 @@ extension Bool: JSIRepresentable {
|
|
|
52
46
|
internal protocol JSIRepresentableNumber: JSIRepresentable {}
|
|
53
47
|
|
|
54
48
|
extension JSIRepresentableNumber {
|
|
55
|
-
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) -> Int
|
|
49
|
+
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) -> Int
|
|
50
|
+
where Self: FixedWidthInteger {
|
|
56
51
|
return Int(value.getNumber())
|
|
57
52
|
}
|
|
58
53
|
|
|
59
|
-
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) -> Double
|
|
54
|
+
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) -> Double
|
|
55
|
+
where Self: BinaryFloatingPoint {
|
|
60
56
|
return value.getNumber()
|
|
61
57
|
}
|
|
62
58
|
|
|
@@ -79,7 +75,9 @@ extension UInt8: JSIRepresentableNumber {}
|
|
|
79
75
|
extension UInt16: JSIRepresentableNumber {}
|
|
80
76
|
extension UInt32: JSIRepresentableNumber {}
|
|
81
77
|
extension UInt64: JSIRepresentableNumber {}
|
|
78
|
+
#if arch(arm64) || (!os(macOS) && !targetEnvironment(macCatalyst))
|
|
82
79
|
extension Float16: JSIRepresentableNumber {}
|
|
80
|
+
#endif
|
|
83
81
|
extension Float32: JSIRepresentableNumber {}
|
|
84
82
|
extension Float64: JSIRepresentableNumber {}
|
|
85
83
|
extension CGFloat: JSIRepresentableNumber {}
|
|
@@ -108,7 +106,7 @@ extension Optional: JSIRepresentable where Wrapped: JSIRepresentable {
|
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
extension Array: JSIRepresentable where Element: JSIRepresentable {
|
|
111
|
-
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) ->
|
|
109
|
+
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) -> [Element] {
|
|
112
110
|
let jsiArray = value.getObject(runtime).getArray(runtime)
|
|
113
111
|
let size = jsiArray.size(runtime)
|
|
114
112
|
var result: Self = []
|
|
@@ -132,7 +130,7 @@ extension Array: JSIRepresentable where Element: JSIRepresentable {
|
|
|
132
130
|
}
|
|
133
131
|
|
|
134
132
|
extension Dictionary: JSIRepresentable where Key == String, Value: JSIRepresentable {
|
|
135
|
-
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) ->
|
|
133
|
+
static func fromJSIValue(_ value: borrowing facebook.jsi.Value, in runtime: facebook.jsi.IRuntime) -> [Key: Value] {
|
|
136
134
|
let object = value.getObject(runtime)
|
|
137
135
|
let propertyNames = object.getPropertyNames(runtime)
|
|
138
136
|
let size = propertyNames.size(runtime)
|
|
@@ -141,7 +139,12 @@ extension Dictionary: JSIRepresentable where Key == String, Value: JSIRepresenta
|
|
|
141
139
|
for index in 0..<size {
|
|
142
140
|
let jsiKey = propertyNames.getValueAtIndex(runtime, index)
|
|
143
141
|
let key = String.fromJSIValue(jsiKey, in: runtime)
|
|
142
|
+
#if os(macOS)
|
|
143
|
+
// TODO: remove when bumping to react-native-macos 0.85
|
|
144
|
+
let jsiValue = expo.getProperty(runtime, object, key)
|
|
145
|
+
#else
|
|
144
146
|
let jsiValue = object.getProperty(runtime, jsiKey)
|
|
147
|
+
#endif
|
|
145
148
|
|
|
146
149
|
result[key] = Value.fromJSIValue(jsiValue, in: runtime)
|
|
147
150
|
}
|
|
@@ -2,17 +2,11 @@ internal import jsi
|
|
|
2
2
|
|
|
3
3
|
// MARK: - JavaScriptRepresentable
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
A type whose values can be represented in the JS runtime.
|
|
7
|
-
*/
|
|
5
|
+
/// A type whose values can be represented in the JS runtime.
|
|
8
6
|
public protocol JavaScriptRepresentable: Sendable, ~Copyable {
|
|
9
|
-
|
|
10
|
-
Creates an instance of this type from the given JS value.
|
|
11
|
-
*/
|
|
7
|
+
/// Creates an instance of this type from the given JS value.
|
|
12
8
|
static func fromJavaScriptValue(_ value: JavaScriptValue) -> Self
|
|
13
|
-
|
|
14
|
-
Creates a JS value representing this value in the given runtime.
|
|
15
|
-
*/
|
|
9
|
+
/// Creates a JS value representing this value in the given runtime.
|
|
16
10
|
func toJavaScriptValue(in runtime: JavaScriptRuntime) -> JavaScriptValue
|
|
17
11
|
}
|
|
18
12
|
|
|
@@ -1,33 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
*/
|
|
1
|
+
/// A protocol that native error types can conform to in order to control
|
|
2
|
+
/// how they are represented when thrown into the JavaScript world.
|
|
3
|
+
///
|
|
4
|
+
/// When a native function throws an error that conforms to this protocol,
|
|
5
|
+
/// a JavaScript `Error` object is created with the specified `message`
|
|
6
|
+
/// and `code`.
|
|
7
|
+
///
|
|
8
|
+
/// Types that don't conform to this protocol are still throwable, but
|
|
9
|
+
/// will use a generic error representation.
|
|
10
|
+
///
|
|
11
|
+
/// ```swift
|
|
12
|
+
/// struct MyError: JavaScriptThrowable {
|
|
13
|
+
/// var message: String { "Something went wrong" }
|
|
14
|
+
/// var code: String { "ERR_MY_ERROR" }
|
|
15
|
+
/// }
|
|
16
|
+
/// ```
|
|
19
17
|
public protocol JavaScriptThrowable: Error, Sendable {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
than a plain description. Override to provide a custom user-facing message.
|
|
24
|
-
*/
|
|
18
|
+
/// The error message describing what went wrong. Defaults to the debug description of the
|
|
19
|
+
/// conforming type, which typically includes richer context (class name, origin, cause chain)
|
|
20
|
+
/// than a plain description. Override to provide a custom user-facing message.
|
|
25
21
|
var message: String { get }
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Return an empty string to omit the `code` property from the JS error.
|
|
30
|
-
*/
|
|
23
|
+
/// An error code for programmatic error handling in JavaScript.
|
|
24
|
+
/// Return an empty string to omit the `code` property from the JS error.
|
|
31
25
|
var code: String { get }
|
|
32
26
|
}
|
|
33
27
|
|
|
@@ -1,35 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
Protocol conformed by the types that represent any JavaScript values.
|
|
3
|
-
*/
|
|
1
|
+
/// Protocol conformed by the types that represent any JavaScript values.
|
|
4
2
|
public protocol JavaScriptType: Sendable, ~Copyable {
|
|
5
3
|
associatedtype Ref
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
Returns a value that this instance represents as a `JavaScriptValue`.
|
|
9
|
-
*/
|
|
5
|
+
/// Returns a value that this instance represents as a `JavaScriptValue`.
|
|
10
6
|
func asValue() -> JavaScriptValue
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
The original type and value are preserved; Referencing `JavaScriptFunction` and then dereferencing returns exactly the same struct.
|
|
15
|
-
*/
|
|
8
|
+
/// Creates a reference to this non-copyable JS value. Ownership on the value is transferred (is consumed) to the reference.
|
|
9
|
+
/// The original type and value are preserved; Referencing `JavaScriptFunction` and then dereferencing returns exactly the same struct.
|
|
16
10
|
consuming func ref() -> JavaScriptRef<Self>
|
|
17
11
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
The original type and value are **not preserved**, meaning that dereferencing will return a `JavaScriptValue`.
|
|
21
|
-
*/
|
|
12
|
+
/// Creates a reference to a copy of this JS value. Ownership is **not transferred** (is borrowed) as the ref owns its copy.
|
|
13
|
+
/// The original type and value are **not preserved**, meaning that dereferencing will return a `JavaScriptValue`.
|
|
22
14
|
borrowing func refToValue() -> JavaScriptValue.Ref
|
|
23
15
|
}
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
typealias Ref = JavaScriptRef<Self>
|
|
17
|
+
extension JavaScriptType where Self: ~Copyable {
|
|
18
|
+
public typealias Ref = JavaScriptRef<Self>
|
|
27
19
|
|
|
28
|
-
consuming func ref() -> JavaScriptRef<Self> {
|
|
20
|
+
public consuming func ref() -> JavaScriptRef<Self> {
|
|
29
21
|
return JavaScriptRef(self)
|
|
30
22
|
}
|
|
31
23
|
|
|
32
|
-
borrowing func refToValue() -> JavaScriptValue.Ref {
|
|
24
|
+
public borrowing func refToValue() -> JavaScriptValue.Ref {
|
|
33
25
|
return JavaScriptRef(self.asValue())
|
|
34
26
|
}
|
|
35
27
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Name of the JavaScript thread created by React Native. Copied from `RCTJSThreadManager.mm`.
|
|
5
|
-
*/
|
|
3
|
+
/// Name of the JavaScript thread created by React Native. Copied from `RCTJSThreadManager.mm`.
|
|
6
4
|
private let jsThreadName = "com.facebook.react.runtime.JavaScript"
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
or enforcing the isolation with `JavaScriptActor.assumeIsolated`.
|
|
14
|
-
*/
|
|
6
|
+
/// Global actor that is used to isolate the code that should only be executed from the JavaScript thread.
|
|
7
|
+
/// Theoretically it does not act as a real actor; it uses a serial executor that executes jobs **synchronously**
|
|
8
|
+
/// without hopping to the proper thread. Meaning that running these jobs on the JavaScript thread must be ensured
|
|
9
|
+
/// externally before switching to the isolated context, e.g. using `schedule` function on `JavaScriptRuntime`
|
|
10
|
+
/// or enforcing the isolation with `JavaScriptActor.assumeIsolated`.
|
|
15
11
|
@globalActor
|
|
16
12
|
public actor JavaScriptActor: GlobalActor {
|
|
17
13
|
public static let shared = JavaScriptActor()
|
|
@@ -24,13 +20,11 @@ public actor JavaScriptActor: GlobalActor {
|
|
|
24
20
|
return executor.asUnownedSerialExecutor()
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
See https://stackoverflow.com/a/79346971 for more information about the implementation.
|
|
33
|
-
*/
|
|
23
|
+
/// An equivalent of `MainActor.assumeIsolated`, but for the `JavaScriptActor`. Assumes that the currently executing
|
|
24
|
+
/// synchronous function is actually executing on the JavaScript thread and invokes an isolated version of the operation,
|
|
25
|
+
/// allowing synchronous access to JavaScript runtime state without hopping through asynchronous boundaries.
|
|
26
|
+
///
|
|
27
|
+
/// See https://stackoverflow.com/a/79346971 for more information about the implementation.
|
|
34
28
|
public static func assumeIsolated<T: ~Copyable>(_ operation: @JavaScriptActor () throws -> T) rethrows -> T {
|
|
35
29
|
typealias YesActor = @JavaScriptActor () throws -> T
|
|
36
30
|
typealias NoActor = () throws -> T
|
|
@@ -45,33 +39,25 @@ public actor JavaScriptActor: GlobalActor {
|
|
|
45
39
|
}
|
|
46
40
|
}
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
Stops program execution if the actor's executor is not isolating the current context.
|
|
50
|
-
*/
|
|
42
|
+
/// Stops program execution if the actor's executor is not isolating the current context.
|
|
51
43
|
public static func checkIsolated() {
|
|
52
44
|
shared.executor.checkIsolated()
|
|
53
45
|
}
|
|
54
46
|
}
|
|
55
47
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- Note: It does not ensure that given jobs are executed on the JavaScript thread; it must be done externally.
|
|
59
|
-
*/
|
|
48
|
+
/// Executor for the `JavaScriptActor` that executes given jobs synchronously and immediately.
|
|
49
|
+
/// - Note: It does not ensure that given jobs are executed on the JavaScript thread; it must be done externally.
|
|
60
50
|
internal class JavaScriptExecutor: SerialExecutor, @unchecked Sendable {
|
|
61
51
|
func enqueue(_ job: UnownedJob) {
|
|
62
52
|
job.runSynchronously(on: self.asUnownedSerialExecutor())
|
|
63
53
|
}
|
|
64
54
|
|
|
65
|
-
|
|
66
|
-
Converts the executor to the optimized form of borrowed executor reference.
|
|
67
|
-
*/
|
|
55
|
+
/// Converts the executor to the optimized form of borrowed executor reference.
|
|
68
56
|
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
|
|
69
57
|
return UnownedSerialExecutor(ordinary: self)
|
|
70
58
|
}
|
|
71
59
|
|
|
72
|
-
|
|
73
|
-
Stops program execution if the executor is not isolating the current context.
|
|
74
|
-
*/
|
|
60
|
+
/// Stops program execution if the executor is not isolating the current context.
|
|
75
61
|
func checkIsolated() {
|
|
76
62
|
// Using `assert` instead of `precondition` because this check is a heuristic based on
|
|
77
63
|
// thread name, not a precise isolation guarantee. Worklet runtimes legitimately run on
|
|
@@ -79,19 +65,16 @@ internal class JavaScriptExecutor: SerialExecutor, @unchecked Sendable {
|
|
|
79
65
|
assert(isIsolatingCurrentContext() == true, "JavaScriptActor operations must be run on the JavaScript thread")
|
|
80
66
|
}
|
|
81
67
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
The condition is also met when running tests and in single threaded environments.
|
|
85
|
-
*/
|
|
68
|
+
/// Checks whether the executor isolates the current context, i.e. the current thread is a JavaScript thread.
|
|
69
|
+
/// The condition is also met when running tests and in single threaded environments.
|
|
86
70
|
func isIsolatingCurrentContext() -> Bool? {
|
|
87
71
|
// We must be careful as it relies on the thread name given by React Native.
|
|
88
|
-
return Thread.current.name == jsThreadName || !Thread.isMultiThreaded()
|
|
72
|
+
return Thread.current.name == jsThreadName || !Thread.isMultiThreaded()
|
|
73
|
+
|| ProcessInfo.processInfo.processName == "xctest"
|
|
89
74
|
}
|
|
90
75
|
}
|
|
91
76
|
|
|
92
|
-
|
|
93
|
-
An actor that is dedicated for the specific runtime.
|
|
94
|
-
*/
|
|
77
|
+
/// An actor that is dedicated for the specific runtime.
|
|
95
78
|
internal actor JavaScriptRuntimeActor {
|
|
96
79
|
private weak let runtime: JavaScriptRuntime?
|
|
97
80
|
nonisolated private let executor: JavaScriptExecutor
|
|
@@ -110,9 +93,7 @@ internal actor JavaScriptRuntimeActor {
|
|
|
110
93
|
}
|
|
111
94
|
}
|
|
112
95
|
|
|
113
|
-
|
|
114
|
-
Serial executor dedicated for the specific runtime.
|
|
115
|
-
*/
|
|
96
|
+
/// Serial executor dedicated for the specific runtime.
|
|
116
97
|
internal final class JavaScriptRuntimeExecutor: JavaScriptExecutor, @unchecked Sendable {
|
|
117
98
|
private weak let runtime: JavaScriptRuntime?
|
|
118
99
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
internal import jsi
|
|
2
1
|
internal import ExpoModulesJSI_Cxx
|
|
2
|
+
internal import jsi
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
Base class for JS object's native state.
|
|
6
|
-
*/
|
|
4
|
+
/// Base class for JS object's native state.
|
|
7
5
|
open class JavaScriptNativeState {
|
|
8
6
|
// Stored as an opaque pointer to avoid ARC retaining the bridged C++ type,
|
|
9
7
|
// which could cause memory leaks due to unbalanced reference counting.
|
|
@@ -43,17 +41,13 @@ open class JavaScriptNativeState {
|
|
|
43
41
|
self.pointee = expo.NativeState(ptr, deallocate)
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
Checks whether the underlying native state has already been released.
|
|
48
|
-
*/
|
|
44
|
+
/// Checks whether the underlying native state has already been released.
|
|
49
45
|
public var isReleased: Bool {
|
|
50
46
|
return pointee == nil
|
|
51
47
|
}
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Replaces any previously set deallocator.
|
|
56
|
-
*/
|
|
49
|
+
/// Sets a deallocator, a closure that is invoked when this native state is no longer attached to any JS object.
|
|
50
|
+
/// Replaces any previously set deallocator.
|
|
57
51
|
public func setDeallocator(_ deallocator: @escaping Deallocator) throws(NativeStateReleasedError) {
|
|
58
52
|
if isReleased {
|
|
59
53
|
throw NativeStateReleasedError()
|
|
@@ -61,10 +55,8 @@ open class JavaScriptNativeState {
|
|
|
61
55
|
self.deallocator = deallocator
|
|
62
56
|
}
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
May return `nil` if the native state is of unrelated type.
|
|
67
|
-
*/
|
|
58
|
+
/// Turns given C++ `expo.NativeState` into its Swift counterpart.
|
|
59
|
+
/// May return `nil` if the native state is of unrelated type.
|
|
68
60
|
internal static func from(cxx nativeState: expo.NativeState) -> Self? {
|
|
69
61
|
// Get the opaque pointer stored by the C++ native state.
|
|
70
62
|
let context = nativeState.getContext()
|
|
@@ -1,31 +1,23 @@
|
|
|
1
1
|
internal import jsi
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Represents something that can be a JS property key.
|
|
5
|
-
*/
|
|
3
|
+
/// Represents something that can be a JS property key.
|
|
6
4
|
public final class JavaScriptPropNameID: JavaScriptType {
|
|
7
5
|
private weak let runtime: JavaScriptRuntime?
|
|
8
6
|
internal let pointee: facebook.jsi.PropNameID
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
Creates a PropNameID from existing `facebook.jsi.PropNameID`.
|
|
12
|
-
*/
|
|
8
|
+
/// Creates a PropNameID from existing `facebook.jsi.PropNameID`.
|
|
13
9
|
internal init(_ runtime: JavaScriptRuntime, _ pointee: consuming facebook.jsi.PropNameID) {
|
|
14
10
|
self.runtime = runtime
|
|
15
11
|
self.pointee = pointee
|
|
16
12
|
}
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
Creates a PropNameID from the string.
|
|
20
|
-
*/
|
|
14
|
+
/// Creates a PropNameID from the string.
|
|
21
15
|
public init(_ runtime: JavaScriptRuntime, string: String) {
|
|
22
16
|
self.runtime = runtime
|
|
23
17
|
self.pointee = facebook.jsi.PropNameID.forUtf8(runtime.pointee, string, string.count)
|
|
24
18
|
}
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
Copies the data in a PropNameID as UTF8 into a string.
|
|
28
|
-
*/
|
|
20
|
+
/// Copies the data in a PropNameID as UTF8 into a string.
|
|
29
21
|
public func utf8() -> String {
|
|
30
22
|
guard let runtime else {
|
|
31
23
|
FatalError.runtimeLost()
|
|
@@ -33,9 +25,7 @@ public final class JavaScriptPropNameID: JavaScriptType {
|
|
|
33
25
|
return String(pointee.utf8(runtime.pointee))
|
|
34
26
|
}
|
|
35
27
|
|
|
36
|
-
|
|
37
|
-
Copies the data in a PropNameID as UTF16 into a string.
|
|
38
|
-
*/
|
|
28
|
+
/// Copies the data in a PropNameID as UTF16 into a string.
|
|
39
29
|
public func utf16() -> String {
|
|
40
30
|
guard let runtime else {
|
|
41
31
|
FatalError.runtimeLost()
|