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.
Files changed (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/CLAUDE.md +4 -0
  3. package/apple/Package.swift +15 -11
  4. package/apple/Sources/ExpoModulesJSI/Contexts/CleanupContext.swift +2 -4
  5. package/apple/Sources/ExpoModulesJSI/Contexts/HostFunctionContext.swift +1 -3
  6. package/apple/Sources/ExpoModulesJSI/Contexts/HostObjectContext.swift +1 -3
  7. package/apple/Sources/ExpoModulesJSI/Extensions/Task+immediate.swift +2 -0
  8. package/apple/Sources/ExpoModulesJSI/Protocols/JSIRepresentable.swift +17 -14
  9. package/apple/Sources/ExpoModulesJSI/Protocols/JavaScriptRepresentable.swift +3 -9
  10. package/apple/Sources/ExpoModulesJSI/Protocols/JavaScriptThrowable.swift +21 -27
  11. package/apple/Sources/ExpoModulesJSI/Protocols/JavaScriptType.swift +10 -18
  12. package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptActor.swift +22 -41
  13. package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptNativeState.swift +7 -15
  14. package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptPropNameID.swift +5 -15
  15. package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRef.swift +21 -43
  16. package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift +152 -202
  17. package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift +38 -41
  18. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptArray.swift +340 -381
  19. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptArrayBuffer.swift +9 -21
  20. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptBigInt.swift +162 -190
  21. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptError.swift +12 -15
  22. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptFunction.swift +23 -27
  23. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptObject.swift +175 -207
  24. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptPromise.swift +22 -24
  25. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptTypedArray.swift +34 -49
  26. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptValue.swift +122 -176
  27. package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptWeakObject.swift +6 -14
  28. package/apple/Sources/ExpoModulesJSI/Utilities/ErrorHandling.swift +12 -20
  29. package/apple/Sources/ExpoModulesJSI/Utilities/Errors.swift +10 -22
  30. package/apple/Sources/ExpoModulesJSI/Utilities/NonisolatedUnsafeVar.swift +2 -4
  31. package/apple/Sources/ExpoModulesJSI-Cxx/include/JSIUtils.h +11 -0
  32. package/apple/Tests/JavaScriptActorTests.swift +3 -3
  33. package/apple/Tests/JavaScriptArrayBufferTests.swift +1 -1
  34. package/apple/Tests/JavaScriptArrayTests.swift +6 -4
  35. package/apple/Tests/JavaScriptBigIntTests.swift +20 -20
  36. package/apple/Tests/JavaScriptErrorTests.swift +15 -11
  37. package/apple/Tests/JavaScriptFunctionTests.swift +26 -26
  38. package/apple/Tests/JavaScriptNativeStateTests.swift +1 -1
  39. package/apple/Tests/JavaScriptObjectTests.swift +25 -13
  40. package/apple/Tests/JavaScriptPromiseTests.swift +56 -28
  41. package/apple/Tests/JavaScriptRefTests.swift +1 -1
  42. package/apple/Tests/JavaScriptRuntimeTests.swift +93 -60
  43. package/apple/Tests/JavaScriptTypedArrayTests.swift +20 -14
  44. package/apple/Tests/JavaScriptValueTests.swift +1 -1
  45. package/apple/Tests/JavaScriptValuesBufferTests.swift +1 -1
  46. package/apple/Tests/JavaScriptWeakObjectTests.swift +1 -1
  47. package/apple/scripts/build-xcframework.sh +96 -13
  48. package/apple/scripts/xcframework-helpers.sh +4 -0
  49. 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.
@@ -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 = ProcessInfo.processInfo.environment["RN_ROOT"]
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 = env["EXPO_ROOT_DIR"] ?? URL(fileURLWithPath: packageDir)
151
- .deletingLastPathComponent() // expo-modules-jsi
152
- .deletingLastPathComponent() // packages
153
- .deletingLastPathComponent() // repo root
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] = ["ExpoModulesJSI"]
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
- A box that holds a cleanup closure and invokes it on deallocation.
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 where Self: FixedWidthInteger {
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 where Self: BinaryFloatingPoint {
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) -> Array<Element> {
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) -> Dictionary<Key, Value> {
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
- A protocol that native error types can conform to in order to control
3
- how they are represented when thrown into the JavaScript world.
4
-
5
- When a native function throws an error that conforms to this protocol,
6
- a JavaScript `Error` object is created with the specified `message`
7
- and `code`.
8
-
9
- Types that don't conform to this protocol are still throwable, but
10
- will use a generic error representation.
11
-
12
- ```swift
13
- struct MyError: JavaScriptThrowable {
14
- var message: String { "Something went wrong" }
15
- var code: String { "ERR_MY_ERROR" }
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
- The error message describing what went wrong. Defaults to the debug description of the
22
- conforming type, which typically includes richer context (class name, origin, cause chain)
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
- An error code for programmatic error handling in JavaScript.
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
- Creates a reference to this non-copyable JS value. Ownership on the value is transferred (is consumed) to the reference.
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
- Creates a reference to a copy of this JS value. Ownership is **not transferred** (is borrowed) as the ref owns its copy.
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
- public extension JavaScriptType where Self: ~Copyable {
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
- Global actor that is used to isolate the code that should only be executed from the JavaScript thread.
10
- Theoretically it does not act as a real actor; it uses a serial executor that executes jobs **synchronously**
11
- without hopping to the proper thread. Meaning that running these jobs on the JavaScript thread must be ensured
12
- externally before switching to the isolated context, e.g. using `schedule` function on `JavaScriptRuntime`
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
- An equivalent of `MainActor.assumeIsolated`, but for the `JavaScriptActor`. Assumes that the currently executing
29
- synchronous function is actually executing on the JavaScript thread and invokes an isolated version of the operation,
30
- allowing synchronous access to JavaScript runtime state without hopping through asynchronous boundaries.
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
- Executor for the `JavaScriptActor` that executes given jobs synchronously and immediately.
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
- Checks whether the executor isolates the current context, i.e. the current thread is a JavaScript thread.
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() || ProcessInfo.processInfo.processName == "xctest"
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
- Sets a deallocator, a closure that is invoked when this native state is no longer attached to any JS object.
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
- Turns given C++ `expo.NativeState` into its Swift counterpart.
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()