expo-modules-core 56.0.3 → 56.0.5
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 +11 -0
- package/android/build.gradle +39 -40
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +4 -43
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +83 -23
- package/android/src/main/java/expo/modules/kotlin/views/decorators/CSSProps.kt +1 -1
- package/ios/Core/Conversions.swift +20 -7
- package/ios/Core/DynamicTypes/AnyDynamicType.swift +20 -0
- package/ios/Core/DynamicTypes/DynamicArrayType.swift +12 -6
- package/ios/Core/DynamicTypes/DynamicDictionaryType.swift +12 -6
- package/ios/Core/DynamicTypes/DynamicRawType.swift +6 -2
- package/ios/Core/DynamicTypes/DynamicStringType.swift +5 -1
- package/ios/Core/Functions/SyncFunctionDefinition.swift +1 -1
- package/ios/Core/MainValueConverter.swift +8 -0
- package/package.json +3 -3
- package/prebuilds/output/debug/xcframeworks/ExpoModulesCore.tar.gz +0 -0
- package/prebuilds/output/debug/xcframeworks/ExpoModulesWorklets.tar.gz +0 -0
- package/prebuilds/output/release/xcframeworks/ExpoModulesCore.tar.gz +0 -0
- package/prebuilds/output/release/xcframeworks/ExpoModulesWorklets.tar.gz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,17 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 56.0.5 — 2026-05-08
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Fix dictionary/array returns from sync functions invoked in the worklet runtime. ([#45419](https://github.com/expo/expo/pull/45419) by [@nishan](https://github.com/intergalacticspacehighway))
|
|
18
|
+
- [Android] Fix unsetting border width on views with border radius causing views to disappear ([#45467](https://github.com/expo/expo/pull/45467) by [@fractalbeauty](https://github.com/fractalbeauty))
|
|
19
|
+
|
|
20
|
+
## 56.0.4 — 2026-05-07
|
|
21
|
+
|
|
22
|
+
_This version does not introduce any user-facing changes._
|
|
23
|
+
|
|
13
24
|
## 56.0.3 — 2026-05-06
|
|
14
25
|
|
|
15
26
|
_This version does not introduce any user-facing changes._
|
package/android/build.gradle
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import com.android.build.gradle.tasks.ExternalNativeBuildJsonTask
|
|
2
|
-
import expo.modules.plugin.gradle.ExpoModuleExtension
|
|
3
1
|
import groovy.json.JsonSlurper
|
|
2
|
+
import expo.modules.plugin.gradle.ExpoModuleExtension
|
|
4
3
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
5
4
|
|
|
6
5
|
buildscript {
|
|
@@ -17,7 +16,6 @@ buildscript {
|
|
|
17
16
|
classpath("org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:${kotlinVersion}")
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
classpath("org.apache.commons:commons-text:1.14.0")
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
21
|
|
|
@@ -29,7 +27,7 @@ if (shouldIncludeCompose) {
|
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
group = 'host.exp.exponent'
|
|
32
|
-
version = '56.0.
|
|
30
|
+
version = '56.0.5'
|
|
33
31
|
|
|
34
32
|
def isExpoModulesCoreTests = {
|
|
35
33
|
Gradle gradle = getGradle()
|
|
@@ -96,7 +94,7 @@ android {
|
|
|
96
94
|
defaultConfig {
|
|
97
95
|
consumerProguardFiles 'proguard-rules.pro'
|
|
98
96
|
versionCode 1
|
|
99
|
-
versionName "56.0.
|
|
97
|
+
versionName "56.0.5"
|
|
100
98
|
buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\""
|
|
101
99
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", "true"
|
|
102
100
|
|
|
@@ -265,55 +263,56 @@ if (shouldTurnWarningsIntoErrors) {
|
|
|
265
263
|
}
|
|
266
264
|
}
|
|
267
265
|
|
|
268
|
-
// Generates
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
266
|
+
// Generates minimal stub PCH files from an empty header so the IDE's C++ engine
|
|
267
|
+
// doesn't fail during sync. Near-instant unlike the full ExpoHeader.pch.
|
|
268
|
+
// The actual build regenerates proper PCH files via ninja.
|
|
269
|
+
def cxxDir = project.file(".cxx")
|
|
270
|
+
def generateStubPCHTask = tasks.register("generateStubPCH") {
|
|
271
|
+
dependsOn("configureCMakeDebug")
|
|
272
272
|
|
|
273
273
|
doLast {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
// Gets CxxModel for the given ABI
|
|
279
|
-
File cxxBuildFolder = configureTask.abi.cxxBuildFolder
|
|
274
|
+
if (!cxxDir.exists()) {
|
|
275
|
+
return
|
|
276
|
+
}
|
|
280
277
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (!compileCommandsFile.exists()) {
|
|
278
|
+
cxxDir.eachFileRecurse { file ->
|
|
279
|
+
if (file.name != "compile_commands.json") {
|
|
284
280
|
return
|
|
285
281
|
}
|
|
286
282
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
def path = commandObj.file
|
|
292
|
-
if (!path.endsWith("cmake_pch.hxx.cxx")) {
|
|
293
|
-
continue
|
|
283
|
+
new JsonSlurper().parseText(file.text).each { entry ->
|
|
284
|
+
if (!entry.file.endsWith("cmake_pch.hxx.cxx")) {
|
|
285
|
+
return
|
|
294
286
|
}
|
|
295
287
|
|
|
296
|
-
def
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
|
|
288
|
+
def pchFile = new File(entry.file.substring(0, entry.file.length() - ".cxx".length()) + ".pch")
|
|
289
|
+
|
|
290
|
+
if (!pchFile.exists() || pchFile.length() == 0) {
|
|
291
|
+
def stubHeader = new File(entry.directory, "stub_pch.hxx")
|
|
292
|
+
stubHeader.text = ""
|
|
293
|
+
|
|
294
|
+
def cmd = entry.command
|
|
295
|
+
// Replace the forced-include path: `-Xclang -include -Xclang <path>/cmake_pch.hxx`
|
|
296
|
+
.replaceAll(/-Xclang -include -Xclang [^\s]+cmake_pch\.hxx(?=\s)/, "-Xclang -include -Xclang ${stubHeader.absolutePath}")
|
|
297
|
+
// Replace the source file operand: `<path>/cmake_pch.hxx.cxx`
|
|
298
|
+
.replaceAll(/[^\s]+cmake_pch\.hxx\.cxx/, stubHeader.absolutePath)
|
|
299
|
+
|
|
300
|
+
def process = new ProcessBuilder(cmd.split(" ").toList())
|
|
301
|
+
.directory(new File(entry.directory))
|
|
302
|
+
.redirectErrorStream(true)
|
|
303
|
+
.start()
|
|
304
|
+
if (process.waitFor() != 0) {
|
|
305
|
+
throw new GradleException("Stub PCH generation failed: ${process.inputStream.text}")
|
|
306
|
+
}
|
|
300
307
|
}
|
|
301
308
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def workingDirFile = new File(commandObj.directory)
|
|
306
|
-
|
|
307
|
-
providers.exec {
|
|
308
|
-
workingDir(providers.provider { workingDirFile }.get())
|
|
309
|
-
commandLine(tokens)
|
|
310
|
-
}.getResult().get().assertNormalExitValue()
|
|
309
|
+
// Ensure PCH is older than source so ninja rebuilds the real one during build
|
|
310
|
+
pchFile.setLastModified(new File(entry.file).lastModified() - 1)
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
// This task will run on the IDE project sync, ensuring the PCH file is generated early enough
|
|
317
316
|
tasks.register("prepareKotlinBuildScriptModel") {
|
|
318
|
-
dependsOn(
|
|
317
|
+
dependsOn(generateStubPCHTask)
|
|
319
318
|
}
|
|
@@ -3,7 +3,6 @@ package expo.modules.kotlin.types
|
|
|
3
3
|
import android.net.Uri
|
|
4
4
|
import android.os.Bundle
|
|
5
5
|
import expo.modules.kotlin.jni.ReturnType
|
|
6
|
-
import expo.modules.kotlin.records.Field
|
|
7
6
|
import expo.modules.kotlin.records.Record
|
|
8
7
|
import expo.modules.kotlin.records.formatters.FormattedRecord
|
|
9
8
|
import expo.modules.kotlin.typedarray.RawTypedArrayHolder
|
|
@@ -121,7 +120,7 @@ interface JSTypeConverter<T> {
|
|
|
121
120
|
object RecordConverter : JSTypeConverter<Record> {
|
|
122
121
|
override fun convertToJS(value: Any?): Any? {
|
|
123
122
|
enforceType<Record?>(value)
|
|
124
|
-
return value?.toJSValueExperimental()
|
|
123
|
+
return value?.toJSValueExperimental(null)
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
override val returnType: ReturnType
|
|
@@ -129,49 +128,11 @@ interface JSTypeConverter<T> {
|
|
|
129
128
|
}
|
|
130
129
|
|
|
131
130
|
class IntrospectableRecordConverter(
|
|
132
|
-
introspectableData: PIntrospectionData<Record>
|
|
131
|
+
private val introspectableData: PIntrospectionData<Record>
|
|
133
132
|
) : JSTypeConverter<Record> {
|
|
134
|
-
data class Property(
|
|
135
|
-
val key: String,
|
|
136
|
-
val getter: (Record) -> Any?
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
private val properties = introspectableData
|
|
140
|
-
.properties
|
|
141
|
-
.mapNotNull { property ->
|
|
142
|
-
val fieldAnnotation = property
|
|
143
|
-
.annotations
|
|
144
|
-
.firstOrNull { annotation -> annotation.jClass == Field::class.java }
|
|
145
|
-
?: return@mapNotNull null
|
|
146
|
-
|
|
147
|
-
val propertyName = (
|
|
148
|
-
fieldAnnotation
|
|
149
|
-
.arguments
|
|
150
|
-
.getOrDefault("key", property.name) as String
|
|
151
|
-
)
|
|
152
|
-
.ifEmpty { property.name }
|
|
153
|
-
|
|
154
|
-
Property(
|
|
155
|
-
propertyName,
|
|
156
|
-
property::get
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
133
|
override fun convertToJS(value: Any?): Any? {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
enforceType<Record>(value)
|
|
166
|
-
val result = mutableMapOf<String, Any?>()
|
|
167
|
-
|
|
168
|
-
properties.forEach { property ->
|
|
169
|
-
val propValue = property.getter(value)
|
|
170
|
-
val convertedValue = JSTypeConverterProvider.convertToJSValue(propValue, useExperimentalConverter = true)
|
|
171
|
-
result[property.key] = convertedValue
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return result
|
|
134
|
+
enforceType<Record?>(value)
|
|
135
|
+
return value?.toJSValueExperimental(introspectableData)
|
|
175
136
|
}
|
|
176
137
|
|
|
177
138
|
override val returnType: ReturnType
|
|
@@ -10,6 +10,9 @@ import expo.modules.kotlin.records.Field
|
|
|
10
10
|
import expo.modules.kotlin.records.Record
|
|
11
11
|
import expo.modules.kotlin.records.formatters.FormattedRecord
|
|
12
12
|
import expo.modules.kotlin.records.formatters.ValueOrSkip
|
|
13
|
+
import io.github.lukmccall.pika.PIntrospectionData
|
|
14
|
+
import io.github.lukmccall.pika.PIntrospectionProvider
|
|
15
|
+
import io.github.lukmccall.pika.PProperty
|
|
13
16
|
import java.io.File
|
|
14
17
|
import java.net.URI
|
|
15
18
|
import java.net.URL
|
|
@@ -20,22 +23,63 @@ import kotlin.reflect.full.memberProperties
|
|
|
20
23
|
import kotlin.reflect.full.primaryConstructor
|
|
21
24
|
import kotlin.reflect.jvm.isAccessible
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Returns field key if property is annotated with [Field]
|
|
28
|
+
*/
|
|
29
|
+
private fun PProperty<Record, *>.asFieldKey(): String? {
|
|
30
|
+
val fieldAnnotation = annotations
|
|
31
|
+
.firstOrNull { annotation -> annotation.jClass == Field::class.java }
|
|
32
|
+
?: return null
|
|
33
|
+
|
|
34
|
+
val propertyName = (
|
|
35
|
+
fieldAnnotation
|
|
36
|
+
.arguments
|
|
37
|
+
.getOrDefault("key", name) as String
|
|
38
|
+
)
|
|
39
|
+
.ifEmpty { name }
|
|
40
|
+
|
|
41
|
+
return propertyName
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private fun Record.getIntrospectionData(): PIntrospectionData<Record>? {
|
|
45
|
+
return if (this is PIntrospectionProvider) {
|
|
46
|
+
@Suppress("UNCHECKED_CAST")
|
|
47
|
+
getIntrospectionData() as? PIntrospectionData<Record>
|
|
48
|
+
} else {
|
|
49
|
+
null
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fun Record.toJSValueExperimental(
|
|
54
|
+
introspectionData: PIntrospectionData<Record>? = this.getIntrospectionData()
|
|
55
|
+
): Map<String, Any?> {
|
|
24
56
|
val result = mutableMapOf<String, Any?>()
|
|
25
57
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
58
|
+
if (introspectionData == null) {
|
|
59
|
+
javaClass
|
|
60
|
+
.kotlin
|
|
61
|
+
.memberProperties
|
|
62
|
+
.forEach { property ->
|
|
63
|
+
val fieldInformation = property.findAnnotation<Field>() ?: return@forEach
|
|
64
|
+
val jsKey = fieldInformation.key.takeUnless { it == "" } ?: property.name
|
|
32
65
|
|
|
33
|
-
|
|
66
|
+
property.isAccessible = true
|
|
34
67
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
68
|
+
val value = property.get(this)
|
|
69
|
+
val convertedValue = JSTypeConverterProvider.convertToJSValue(value, useExperimentalConverter = true)
|
|
70
|
+
result[jsKey] = convertedValue
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
introspectionData
|
|
74
|
+
.properties
|
|
75
|
+
.forEach { property ->
|
|
76
|
+
val propertyKey = property.asFieldKey() ?: return@forEach
|
|
77
|
+
|
|
78
|
+
val propValue = property.get(this)
|
|
79
|
+
val convertedValue = JSTypeConverterProvider.convertToJSValue(propValue, useExperimentalConverter = true)
|
|
80
|
+
result[propertyKey] = convertedValue
|
|
81
|
+
}
|
|
82
|
+
}
|
|
39
83
|
|
|
40
84
|
return result
|
|
41
85
|
}
|
|
@@ -74,21 +118,37 @@ fun FormattedRecord<*>.toJSValueExperimental(): Map<String, Any?> {
|
|
|
74
118
|
return result
|
|
75
119
|
}
|
|
76
120
|
|
|
77
|
-
fun Record.toJSValue(
|
|
121
|
+
fun Record.toJSValue(
|
|
122
|
+
containerProvider: JSTypeConverterProvider.ContainerProvider,
|
|
123
|
+
introspectionData: PIntrospectionData<Record>? = this.getIntrospectionData()
|
|
124
|
+
): WritableMap {
|
|
78
125
|
val result = containerProvider.createMap()
|
|
79
126
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
127
|
+
if (introspectionData == null) {
|
|
128
|
+
javaClass
|
|
129
|
+
.kotlin
|
|
130
|
+
.memberProperties
|
|
131
|
+
.forEach { property ->
|
|
132
|
+
val fieldInformation = property.findAnnotation<Field>() ?: return@forEach
|
|
133
|
+
val jsKey = fieldInformation.key.takeUnless { it == "" } ?: property.name
|
|
85
134
|
|
|
86
|
-
|
|
135
|
+
property.isAccessible = true
|
|
87
136
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
137
|
+
val value = property.get(this)
|
|
138
|
+
val convertedValue = JSTypeConverterProvider.legacyConvertToJSValue(value, containerProvider)
|
|
139
|
+
result.putGeneric(jsKey, convertedValue)
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
introspectionData
|
|
143
|
+
.properties
|
|
144
|
+
.forEach { property ->
|
|
145
|
+
val propertyKey = property.asFieldKey() ?: return@forEach
|
|
146
|
+
|
|
147
|
+
val value = property.get(this)
|
|
148
|
+
val convertedValue = JSTypeConverterProvider.legacyConvertToJSValue(value, containerProvider)
|
|
149
|
+
result.putGeneric(propertyKey, convertedValue)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
92
152
|
|
|
93
153
|
return result
|
|
94
154
|
}
|
|
@@ -138,13 +138,20 @@ public struct Conversions {
|
|
|
138
138
|
`unknownToJavaScriptValue` which handles type-erased values through `NSNumber`/`NSDictionary` matching.
|
|
139
139
|
*/
|
|
140
140
|
static func anyToJavaScriptValue<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
141
|
+
return try anyToJavaScriptValue(value, appContext: appContext, in: appContext.runtime)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
Variant that creates JS values in the given `runtime`, used by the worklet conversion.
|
|
146
|
+
*/
|
|
147
|
+
static func anyToJavaScriptValue<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
141
148
|
if ValueType.self is AnyOptional.Type, Optional.isNil(value) {
|
|
142
149
|
return .null
|
|
143
150
|
}
|
|
144
151
|
if let value = value as? AnyArgument {
|
|
145
|
-
return try type(of: value).getDynamicType().castToJS(value, appContext: appContext)
|
|
152
|
+
return try type(of: value).getDynamicType().castToJS(value, appContext: appContext, in: runtime)
|
|
146
153
|
}
|
|
147
|
-
return try unknownToJavaScriptValue(value, appContext: appContext)
|
|
154
|
+
return try unknownToJavaScriptValue(value, appContext: appContext, in: runtime)
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
/**
|
|
@@ -153,12 +160,18 @@ public struct Conversions {
|
|
|
153
160
|
can call this without re-entering the `AnyArgument` check and causing infinite recursion.
|
|
154
161
|
*/
|
|
155
162
|
static func unknownToJavaScriptValue(_ value: Any, appContext: AppContext) throws -> JavaScriptValue {
|
|
163
|
+
return try unknownToJavaScriptValue(value, appContext: appContext, in: appContext.runtime)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
Variant that creates JS values in the given `runtime` — used by the worklet conversion
|
|
168
|
+
path so produced dicts/arrays live in the calling runtime, not the main runtime.
|
|
169
|
+
*/
|
|
170
|
+
static func unknownToJavaScriptValue(_ value: Any, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
156
171
|
if let value = value as? JavaScriptRepresentable {
|
|
157
|
-
return .representing(value: value, in:
|
|
172
|
+
return .representing(value: value, in: runtime)
|
|
158
173
|
}
|
|
159
174
|
|
|
160
|
-
let runtime = try appContext.runtime
|
|
161
|
-
|
|
162
175
|
switch value {
|
|
163
176
|
case is Void:
|
|
164
177
|
return .undefined
|
|
@@ -179,14 +192,14 @@ public struct Conversions {
|
|
|
179
192
|
case let array as NSArray:
|
|
180
193
|
let jsArray = runtime.createArray(length: array.count)
|
|
181
194
|
for (index, element) in array.enumerated() {
|
|
182
|
-
try jsArray.set(value: anyToJavaScriptValue(element, appContext: appContext), at: index)
|
|
195
|
+
try jsArray.set(value: anyToJavaScriptValue(element, appContext: appContext, in: runtime), at: index)
|
|
183
196
|
}
|
|
184
197
|
return jsArray.asValue()
|
|
185
198
|
case let dict as NSDictionary:
|
|
186
199
|
let jsObject = runtime.createObject()
|
|
187
200
|
for (key, element) in dict {
|
|
188
201
|
guard let key = key as? String else { continue }
|
|
189
|
-
jsObject.setProperty(key, value: try anyToJavaScriptValue(element, appContext: appContext))
|
|
202
|
+
jsObject.setProperty(key, value: try anyToJavaScriptValue(element, appContext: appContext, in: runtime))
|
|
190
203
|
}
|
|
191
204
|
return jsObject.asValue()
|
|
192
205
|
default:
|
|
@@ -36,6 +36,11 @@ public protocol AnyDynamicType: CustomStringConvertible, Sendable {
|
|
|
36
36
|
|
|
37
37
|
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
Runtime-aware `castToJS`.
|
|
41
|
+
*/
|
|
42
|
+
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue
|
|
43
|
+
|
|
39
44
|
/**
|
|
40
45
|
Converts the given native value directly to `JavaScriptValue`.
|
|
41
46
|
The default implementation uses `convertResult` and then `castToJS`, but dynamic types
|
|
@@ -43,6 +48,11 @@ public protocol AnyDynamicType: CustomStringConvertible, Sendable {
|
|
|
43
48
|
*/
|
|
44
49
|
func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue
|
|
45
50
|
|
|
51
|
+
/**
|
|
52
|
+
Runtime-aware `convertToJS`.
|
|
53
|
+
*/
|
|
54
|
+
func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue
|
|
55
|
+
|
|
46
56
|
/**
|
|
47
57
|
Converts function's result to the type that can later be converted to a JS value.
|
|
48
58
|
For instance, types such as records, enumerables and shared objects need special handling
|
|
@@ -60,11 +70,21 @@ extension AnyDynamicType {
|
|
|
60
70
|
return try Conversions.unknownToJavaScriptValue(value, appContext: appContext)
|
|
61
71
|
}
|
|
62
72
|
|
|
73
|
+
// Default forwards to the legacy `castToJS`, dropping `runtime`
|
|
74
|
+
public func castToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
75
|
+
return try castToJS(value, appContext: appContext)
|
|
76
|
+
}
|
|
77
|
+
|
|
63
78
|
public func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
64
79
|
let result = Conversions.convertFunctionResult(value, appContext: appContext, dynamicType: self)
|
|
65
80
|
return try castToJS(result, appContext: appContext)
|
|
66
81
|
}
|
|
67
82
|
|
|
83
|
+
public func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
84
|
+
let result = Conversions.convertFunctionResult(value, appContext: appContext, dynamicType: self)
|
|
85
|
+
return try castToJS(result, appContext: appContext, in: runtime)
|
|
86
|
+
}
|
|
87
|
+
|
|
68
88
|
func convertResult<ResultType>(_ result: ResultType, appContext: AppContext) throws -> Any {
|
|
69
89
|
return result
|
|
70
90
|
}
|
|
@@ -55,13 +55,16 @@ internal struct DynamicArrayType: AnyDynamicType {
|
|
|
55
55
|
are already in their post-conversion shape, such as `JavaScriptValue.undefined`.
|
|
56
56
|
*/
|
|
57
57
|
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
58
|
+
return try castToJS(value, appContext: appContext, in: try appContext.runtime)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
58
62
|
guard let array = value as? [Any] else {
|
|
59
|
-
return try Conversions.anyToJavaScriptValue(value, appContext: appContext)
|
|
63
|
+
return try Conversions.anyToJavaScriptValue(value, appContext: appContext, in: runtime)
|
|
60
64
|
}
|
|
61
|
-
let runtime = try appContext.runtime
|
|
62
65
|
let jsArray = runtime.createArray(length: array.count)
|
|
63
66
|
for (index, element) in array.enumerated() {
|
|
64
|
-
try jsArray.set(value: try elementType.castToJS(element, appContext: appContext), at: index)
|
|
67
|
+
try jsArray.set(value: try elementType.castToJS(element, appContext: appContext, in: runtime), at: index)
|
|
65
68
|
}
|
|
66
69
|
return jsArray.asValue()
|
|
67
70
|
}
|
|
@@ -71,13 +74,16 @@ internal struct DynamicArrayType: AnyDynamicType {
|
|
|
71
74
|
to use their own direct conversion paths before any array-level normalization.
|
|
72
75
|
*/
|
|
73
76
|
func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
77
|
+
return try convertToJS(value, appContext: appContext, in: try appContext.runtime)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
74
81
|
guard let array = value as? [Any] else {
|
|
75
|
-
return try Conversions.anyToJavaScriptValue(value, appContext: appContext)
|
|
82
|
+
return try Conversions.anyToJavaScriptValue(value, appContext: appContext, in: runtime)
|
|
76
83
|
}
|
|
77
|
-
let runtime = try appContext.runtime
|
|
78
84
|
let jsArray = runtime.createArray(length: array.count)
|
|
79
85
|
for (index, element) in array.enumerated() {
|
|
80
|
-
try jsArray.set(value: try elementType.convertToJS(element, appContext: appContext), at: index)
|
|
86
|
+
try jsArray.set(value: try elementType.convertToJS(element, appContext: appContext, in: runtime), at: index)
|
|
81
87
|
}
|
|
82
88
|
return jsArray.asValue()
|
|
83
89
|
}
|
|
@@ -61,14 +61,17 @@ internal struct DynamicDictionaryType: AnyDynamicType {
|
|
|
61
61
|
are already in their post-conversion shape, such as `JavaScriptValue.undefined`.
|
|
62
62
|
*/
|
|
63
63
|
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
64
|
+
return try castToJS(value, appContext: appContext, in: try appContext.runtime)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
64
68
|
guard let dict = value as? [AnyHashable: Any] else {
|
|
65
|
-
return try Conversions.anyToJavaScriptValue(value, appContext: appContext)
|
|
69
|
+
return try Conversions.anyToJavaScriptValue(value, appContext: appContext, in: runtime)
|
|
66
70
|
}
|
|
67
|
-
let runtime = try appContext.runtime
|
|
68
71
|
let jsObject = runtime.createObject()
|
|
69
72
|
for (key, element) in dict {
|
|
70
73
|
guard let key = key as? String else { continue }
|
|
71
|
-
jsObject.setProperty(key, value: try valueType.castToJS(element, appContext: appContext))
|
|
74
|
+
jsObject.setProperty(key, value: try valueType.castToJS(element, appContext: appContext, in: runtime))
|
|
72
75
|
}
|
|
73
76
|
return jsObject.asValue()
|
|
74
77
|
}
|
|
@@ -78,14 +81,17 @@ internal struct DynamicDictionaryType: AnyDynamicType {
|
|
|
78
81
|
to use their own direct conversion paths before any dictionary-level normalization.
|
|
79
82
|
*/
|
|
80
83
|
func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
84
|
+
return try convertToJS(value, appContext: appContext, in: try appContext.runtime)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
func convertToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
81
88
|
guard let dict = value as? [AnyHashable: Any] else {
|
|
82
|
-
return try Conversions.anyToJavaScriptValue(value, appContext: appContext)
|
|
89
|
+
return try Conversions.anyToJavaScriptValue(value, appContext: appContext, in: runtime)
|
|
83
90
|
}
|
|
84
|
-
let runtime = try appContext.runtime
|
|
85
91
|
let jsObject = runtime.createObject()
|
|
86
92
|
for (key, element) in dict {
|
|
87
93
|
guard let key = key as? String else { continue }
|
|
88
|
-
jsObject.setProperty(key, value: try valueType.convertToJS(element, appContext: appContext))
|
|
94
|
+
jsObject.setProperty(key, value: try valueType.convertToJS(element, appContext: appContext, in: runtime))
|
|
89
95
|
}
|
|
90
96
|
return jsObject.asValue()
|
|
91
97
|
}
|
|
@@ -38,6 +38,10 @@ internal struct DynamicRawType<InnerType>: AnyDynamicType {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
41
|
+
return try castToJS(value, appContext: appContext, in: try appContext.runtime)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
41
45
|
if Optional.isNil(value) {
|
|
42
46
|
return .null
|
|
43
47
|
}
|
|
@@ -46,9 +50,9 @@ internal struct DynamicRawType<InnerType>: AnyDynamicType {
|
|
|
46
50
|
// handlers like `DynamicEnumType.castToJS`. Guarded against infinite recursion: the
|
|
47
51
|
// dispatch only kicks in when the value's runtime type differs from `innerType`.
|
|
48
52
|
if InnerType.self != type(of: value as Any), let argument = value as? AnyArgument {
|
|
49
|
-
return try type(of: argument).getDynamicType().castToJS(argument, appContext: appContext)
|
|
53
|
+
return try type(of: argument).getDynamicType().castToJS(argument, appContext: appContext, in: runtime)
|
|
50
54
|
}
|
|
51
|
-
return try Conversions.unknownToJavaScriptValue(value, appContext: appContext)
|
|
55
|
+
return try Conversions.unknownToJavaScriptValue(value, appContext: appContext, in: runtime)
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
func convertResult<ResultType>(_ result: ResultType, appContext: AppContext) throws -> Any {
|
|
@@ -28,8 +28,12 @@ internal struct DynamicStringType: AnyDynamicType {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
31
|
+
return try castToJS(value, appContext: appContext, in: try appContext.runtime)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
31
35
|
if let string = value as? String {
|
|
32
|
-
return JavaScriptValue(
|
|
36
|
+
return JavaScriptValue(runtime, string)
|
|
33
37
|
}
|
|
34
38
|
throw Conversions.ConversionToJSFailedException((kind: .string, nativeType: ValueType.self))
|
|
35
39
|
}
|
|
@@ -101,7 +101,7 @@ public class SyncFunctionDefinition<Args, FirstArgType, ReturnType>: AnySyncFunc
|
|
|
101
101
|
func call(_ appContext: AppContext, in runtime: JavaScriptRuntime, this: JavaScriptValue, arguments: consuming JavaScriptValuesBuffer) throws(Exception) -> JavaScriptValue {
|
|
102
102
|
let result = try runBody(appContext, in: runtime, this: this, arguments: arguments)
|
|
103
103
|
do {
|
|
104
|
-
return try appContext.converter.toJS(result, returnType)
|
|
104
|
+
return try appContext.converter.toJS(result, returnType, in: runtime)
|
|
105
105
|
} catch let error as Exception {
|
|
106
106
|
throw FunctionCallException(name).causedBy(error)
|
|
107
107
|
} catch {
|
|
@@ -42,4 +42,12 @@ public struct MainValueConverter: ~Copyable {
|
|
|
42
42
|
public func toJS(_ value: Any, _ type: AnyDynamicType) throws -> JavaScriptValue {
|
|
43
43
|
return try type.convertToJS(value, appContext: appContext)
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
`toJS` variant that targets a specific runtime. Useful for Worklet runtime conversions.
|
|
48
|
+
*/
|
|
49
|
+
@JavaScriptActor
|
|
50
|
+
public func toJS(_ value: Any, _ type: AnyDynamicType, in runtime: JavaScriptRuntime) throws -> JavaScriptValue {
|
|
51
|
+
return try type.convertToJS(value, appContext: appContext, in: runtime)
|
|
52
|
+
}
|
|
45
53
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "56.0.
|
|
3
|
+
"version": "56.0.5",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@expo/expo-modules-macros-plugin": "~0.0.8",
|
|
50
|
-
"expo-modules-jsi": "~56.0.
|
|
50
|
+
"expo-modules-jsi": "~56.0.2",
|
|
51
51
|
"invariant": "^2.2.4"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@types/invariant": "^2.2.33",
|
|
67
67
|
"expo-module-scripts": "56.0.2"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "a30353e69ca0d72b9fac5830abc631feda1ba3ae",
|
|
70
70
|
"scripts": {
|
|
71
71
|
"build": "expo-module build",
|
|
72
72
|
"clean": "expo-module clean",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|