expo-modules-core 2.3.13 → 2.4.1

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 (35) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/android/build.gradle +3 -2
  3. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +22 -11
  4. package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +9 -1
  5. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +6 -0
  6. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +28 -24
  7. package/android/src/main/java/expo/modules/kotlin/jni/ExpectedType.kt +122 -5
  8. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +6 -1
  9. package/android/src/main/java/expo/modules/kotlin/modules/ModuleConvertersBuilder.kt +50 -0
  10. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +31 -7
  11. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +28 -30
  12. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +15 -0
  13. package/android/src/main/java/expo/modules/kotlin/traits/SavableTrait.kt +57 -0
  14. package/android/src/main/java/expo/modules/kotlin/traits/Trait.kt +8 -0
  15. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +9 -0
  16. package/android/src/main/java/expo/modules/kotlin/types/EitherTypeConverter.kt +3 -3
  17. package/android/src/main/java/expo/modules/kotlin/types/ExpoDynamic.kt +57 -0
  18. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterCollection.kt +81 -0
  19. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +18 -3
  20. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +40 -25
  21. package/ios/Api/Factories/ViewFactories.swift +16 -0
  22. package/ios/Core/Conversions.swift +51 -7
  23. package/ios/Core/Convertibles/Convertibles+Color.swift +1 -1
  24. package/ios/Core/DynamicTypes/DynamicSharedObjectType.swift +25 -14
  25. package/ios/Core/Functions/AsyncFunctionDefinition.swift +1 -1
  26. package/ios/Core/Promise.swift +0 -11
  27. package/ios/Core/Views/ConcreteViewProp.swift +16 -0
  28. package/ios/Core/Views/SwiftUI/Convertibles+SwiftUI.swift +62 -0
  29. package/ios/Core/Views/SwiftUI/SwiftUIHostingView.swift +7 -0
  30. package/ios/DevTools/ExpoRequestInterceptorProtocol.swift +14 -4
  31. package/ios/DevTools/ModuleDefinitionEncoder.swift +182 -0
  32. package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
  33. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +1 -1
  34. package/ios/Tests/FunctionSpec.swift +27 -1
  35. package/package.json +3 -3
@@ -17,6 +17,8 @@ import expo.modules.kotlin.events.OnActivityResultPayload
17
17
  import expo.modules.kotlin.objects.ObjectDefinitionBuilder
18
18
  import expo.modules.kotlin.sharedobjects.SharedObject
19
19
  import expo.modules.kotlin.types.LazyKType
20
+ import expo.modules.kotlin.types.TypeConverterProvider
21
+ import expo.modules.kotlin.types.mergeWithDefault
20
22
  import expo.modules.kotlin.types.toAnyType
21
23
  import expo.modules.kotlin.views.ModuleDefinitionBuilderWithCompose
22
24
  import expo.modules.kotlin.views.ViewDefinitionBuilder
@@ -33,10 +35,10 @@ class ModuleDefinitionBuilder(
33
35
 
34
36
  @DefinitionMarker
35
37
  open class InternalModuleDefinitionBuilder(
36
- @PublishedApi internal val module: Module? = null
38
+ @PublishedApi internal val module: Module? = null,
39
+ converters: TypeConverterProvider? = module?.converters()?.mergeWithDefault()
37
40
  ) : ObjectDefinitionBuilder(
38
- module
39
- ?.customConverterProvider()
41
+ converters
40
42
  ) {
41
43
  @PublishedApi
42
44
  internal var name: String? = null
@@ -89,7 +91,11 @@ open class InternalModuleDefinitionBuilder(
89
91
  * Creates the view manager definition that scopes other view-related definitions.
90
92
  */
91
93
  inline fun <reified T : View> View(viewClass: KClass<T>, body: ViewDefinitionBuilder<T>.() -> Unit) {
92
- val viewDefinitionBuilder = ViewDefinitionBuilder(viewClass, LazyKType(classifier = T::class, kTypeProvider = { typeOf<T>() }))
94
+ val viewDefinitionBuilder = ViewDefinitionBuilder(
95
+ viewClass,
96
+ LazyKType(classifier = T::class, kTypeProvider = { typeOf<T>() }),
97
+ converters
98
+ )
93
99
 
94
100
  viewDefinitionBuilder.UseCSSProps()
95
101
 
@@ -162,7 +168,13 @@ open class InternalModuleDefinitionBuilder(
162
168
  }
163
169
 
164
170
  inline fun Class(name: String, body: ClassComponentBuilder<Unit>.() -> Unit = {}) {
165
- val clazzBuilder = ClassComponentBuilder(name, Unit::class, toAnyType<Unit>())
171
+ val clazzBuilder = ClassComponentBuilder(
172
+ requireNotNull(module).appContext,
173
+ name,
174
+ Unit::class,
175
+ toAnyType<Unit>(),
176
+ converters
177
+ )
166
178
  body.invoke(clazzBuilder)
167
179
  classData.add(clazzBuilder.buildClass())
168
180
  }
@@ -172,7 +184,13 @@ open class InternalModuleDefinitionBuilder(
172
184
  sharedObjectClass: KClass<SharedObjectType> = SharedObjectType::class,
173
185
  body: ClassComponentBuilder<SharedObjectType>.() -> Unit = {}
174
186
  ) {
175
- val clazzBuilder = ClassComponentBuilder(name, sharedObjectClass, toAnyType<SharedObjectType>())
187
+ val clazzBuilder = ClassComponentBuilder(
188
+ requireNotNull(module).appContext,
189
+ name,
190
+ sharedObjectClass,
191
+ toAnyType<SharedObjectType>(),
192
+ converters
193
+ )
176
194
  body.invoke(clazzBuilder)
177
195
  classData.add(clazzBuilder.buildClass())
178
196
  }
@@ -181,7 +199,13 @@ open class InternalModuleDefinitionBuilder(
181
199
  sharedObjectClass: KClass<SharedObjectType> = SharedObjectType::class,
182
200
  body: ClassComponentBuilder<SharedObjectType>.() -> Unit = {}
183
201
  ) {
184
- val clazzBuilder = ClassComponentBuilder(sharedObjectClass.java.simpleName, sharedObjectClass, toAnyType<SharedObjectType>())
202
+ val clazzBuilder = ClassComponentBuilder(
203
+ requireNotNull(module).appContext,
204
+ sharedObjectClass.java.simpleName,
205
+ sharedObjectClass,
206
+ toAnyType<SharedObjectType>(),
207
+ converters
208
+ )
185
209
  body.invoke(clazzBuilder)
186
210
  classData.add(clazzBuilder.buildClass())
187
211
  }
@@ -22,7 +22,6 @@ import expo.modules.kotlin.modules.convertEnumToString
22
22
  import expo.modules.kotlin.types.Enumerable
23
23
  import expo.modules.kotlin.types.TypeConverterProvider
24
24
  import expo.modules.kotlin.types.enforceType
25
- import expo.modules.kotlin.types.mergeWithDefault
26
25
  import expo.modules.kotlin.types.toArgsArray
27
26
  import expo.modules.kotlin.types.toReturnType
28
27
  import kotlin.reflect.full.declaredMemberProperties
@@ -31,10 +30,9 @@ import kotlin.reflect.full.primaryConstructor
31
30
  /**
32
31
  * Base class for other definitions representing an object, such as `ModuleDefinition`.
33
32
  */
34
- open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = null) {
35
- @PublishedApi
36
- internal val converterProvider = customConverter.mergeWithDefault()
37
-
33
+ open class ObjectDefinitionBuilder(
34
+ @PublishedApi internal val converters: TypeConverterProvider? = null
35
+ ) {
38
36
  private var legacyConstantsProvider = { emptyMap<String, Any?>() }
39
37
 
40
38
  @PublishedApi
@@ -126,7 +124,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
126
124
  name: String,
127
125
  crossinline body: (p0: P0) -> R
128
126
  ): SyncFunctionComponent {
129
- return SyncFunctionComponent(name, toArgsArray<P0>(converterProvider = converterProvider), toReturnType<R>()) { (p0) ->
127
+ return SyncFunctionComponent(name, toArgsArray<P0>(converterProvider = converters), toReturnType<R>()) { (p0) ->
130
128
  enforceType<P0>(p0)
131
129
  body(p0)
132
130
  }.also {
@@ -138,7 +136,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
138
136
  name: String,
139
137
  crossinline body: (p0: P0, p1: P1) -> R
140
138
  ): SyncFunctionComponent {
141
- return SyncFunctionComponent(name, toArgsArray<P0, P1>(), toReturnType<R>()) { (p0, p1) ->
139
+ return SyncFunctionComponent(name, toArgsArray<P0, P1>(converterProvider = converters), toReturnType<R>()) { (p0, p1) ->
142
140
  enforceType<P0, P1>(p0, p1)
143
141
  body(p0, p1)
144
142
  }.also {
@@ -150,7 +148,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
150
148
  name: String,
151
149
  crossinline body: (p0: P0, p1: P1, p2: P2) -> R
152
150
  ): SyncFunctionComponent {
153
- return SyncFunctionComponent(name, toArgsArray<P0, P1, P2>(), toReturnType<R>()) { (p0, p1, p2) ->
151
+ return SyncFunctionComponent(name, toArgsArray<P0, P1, P2>(converterProvider = converters), toReturnType<R>()) { (p0, p1, p2) ->
154
152
  enforceType<P0, P1, P2>(p0, p1, p2)
155
153
  body(p0, p1, p2)
156
154
  }.also {
@@ -162,7 +160,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
162
160
  name: String,
163
161
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R
164
162
  ): SyncFunctionComponent {
165
- return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>(), toReturnType<R>()) { (p0, p1, p2, p3) ->
163
+ return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>(converterProvider = converters), toReturnType<R>()) { (p0, p1, p2, p3) ->
166
164
  enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
167
165
  body(p0, p1, p2, p3)
168
166
  }.also {
@@ -174,7 +172,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
174
172
  name: String,
175
173
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R
176
174
  ): SyncFunctionComponent {
177
- return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>(), toReturnType<R>()) { (p0, p1, p2, p3, p4) ->
175
+ return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>(converterProvider = converters), toReturnType<R>()) { (p0, p1, p2, p3, p4) ->
178
176
  enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
179
177
  body(p0, p1, p2, p3, p4)
180
178
  }.also {
@@ -186,7 +184,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
186
184
  name: String,
187
185
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
188
186
  ): SyncFunctionComponent {
189
- return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>(), toReturnType<R>()) { (p0, p1, p2, p3, p4, p5) ->
187
+ return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>(converterProvider = converters), toReturnType<R>()) { (p0, p1, p2, p3, p4, p5) ->
190
188
  enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
191
189
  body(p0, p1, p2, p3, p4, p5)
192
190
  }.also {
@@ -198,7 +196,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
198
196
  name: String,
199
197
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R
200
198
  ): SyncFunctionComponent {
201
- return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>(), toReturnType<R>()) { (p0, p1, p2, p3, p4, p5, p6) ->
199
+ return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>(converterProvider = converters), toReturnType<R>()) { (p0, p1, p2, p3, p4, p5, p6) ->
202
200
  enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
203
201
  body(p0, p1, p2, p3, p4, p5, p6)
204
202
  }.also {
@@ -210,7 +208,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
210
208
  name: String,
211
209
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R
212
210
  ): SyncFunctionComponent {
213
- return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>(), toReturnType<R>()) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
211
+ return SyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>(converterProvider = converters), toReturnType<R>()) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
214
212
  enforceType<P0, P1, P2, P3, P4, P5, P6, P7>(p0, p1, p2, p3, p4, p5, p6, p7)
215
213
  body(p0, p1, p2, p3, p4, p5, p6, p7)
216
214
  }.also {
@@ -245,7 +243,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
245
243
  return if (P0::class.java == Promise::class.java) {
246
244
  AsyncFunctionWithPromiseComponent(name, arrayOf()) { _, promise -> body(promise as P0) }
247
245
  } else {
248
- createAsyncFunctionComponent(name, toArgsArray<P0>()) { (p0) ->
246
+ createAsyncFunctionComponent(name, toArgsArray<P0>(converterProvider = converters)) { (p0) ->
249
247
  enforceType<P0>(p0)
250
248
  body(p0)
251
249
  }
@@ -258,7 +256,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
258
256
  name: String,
259
257
  crossinline body: (p0: P0, p1: P1) -> R
260
258
  ): AsyncFunctionComponent {
261
- return createAsyncFunctionComponent(name, toArgsArray<P0, P1>()) { (p0, p1) ->
259
+ return createAsyncFunctionComponent(name, toArgsArray<P0, P1>(converterProvider = converters)) { (p0, p1) ->
262
260
  enforceType<P0, P1>(p0, p1)
263
261
  body(p0, p1)
264
262
  }.also {
@@ -271,7 +269,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
271
269
  name: String,
272
270
  crossinline body: (p0: P0, p1: Promise) -> R
273
271
  ): AsyncFunctionComponent {
274
- return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0>()) { (p0), promise ->
272
+ return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0>(converterProvider = converters)) { (p0), promise ->
275
273
  enforceType<P0>(p0)
276
274
  body(p0, promise)
277
275
  }.also {
@@ -283,7 +281,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
283
281
  name: String,
284
282
  crossinline body: (p0: P0, p1: P1, p2: P2) -> R
285
283
  ): AsyncFunctionComponent {
286
- return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2) ->
284
+ return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2>(converterProvider = converters)) { (p0, p1, p2) ->
287
285
  enforceType<P0, P1, P2>(p0, p1, p2)
288
286
  body(p0, p1, p2)
289
287
  }.also {
@@ -296,7 +294,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
296
294
  name: String,
297
295
  crossinline body: (p0: P0, p1: P1, p2: Promise) -> R
298
296
  ): AsyncFunctionComponent {
299
- return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1>()) { (p0, p1), promise ->
297
+ return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1>(converterProvider = converters)) { (p0, p1), promise ->
300
298
  enforceType<P0, P1>(p0, p1)
301
299
  body(p0, p1, promise)
302
300
  }.also {
@@ -308,7 +306,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
308
306
  name: String,
309
307
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R
310
308
  ): AsyncFunctionComponent {
311
- return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3) ->
309
+ return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>(converterProvider = converters)) { (p0, p1, p2, p3) ->
312
310
  enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
313
311
  body(p0, p1, p2, p3)
314
312
  }.also {
@@ -321,7 +319,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
321
319
  name: String,
322
320
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: Promise) -> R
323
321
  ): AsyncFunctionComponent {
324
- return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2), promise ->
322
+ return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2>(converterProvider = converters)) { (p0, p1, p2), promise ->
325
323
  enforceType<P0, P1, P2>(p0, p1, p2)
326
324
  body(p0, p1, p2, promise)
327
325
  }.also {
@@ -333,7 +331,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
333
331
  name: String,
334
332
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R
335
333
  ): AsyncFunctionComponent {
336
- return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4) ->
334
+ return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>(converterProvider = converters)) { (p0, p1, p2, p3, p4) ->
337
335
  enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
338
336
  body(p0, p1, p2, p3, p4)
339
337
  }.also {
@@ -346,7 +344,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
346
344
  name: String,
347
345
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: Promise) -> R
348
346
  ): AsyncFunctionComponent {
349
- return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3), promise ->
347
+ return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3>(converterProvider = converters)) { (p0, p1, p2, p3), promise ->
350
348
  enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
351
349
  body(p0, p1, p2, p3, promise)
352
350
  }.also {
@@ -358,7 +356,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
358
356
  name: String,
359
357
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
360
358
  ): AsyncFunctionComponent {
361
- return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5) ->
359
+ return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5) ->
362
360
  enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
363
361
  body(p0, p1, p2, p3, p4, p5)
364
362
  }.also {
@@ -371,7 +369,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
371
369
  name: String,
372
370
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: Promise) -> R
373
371
  ): AsyncFunctionComponent {
374
- return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4), promise ->
372
+ return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4>(converterProvider = converters)) { (p0, p1, p2, p3, p4), promise ->
375
373
  enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
376
374
  body(p0, p1, p2, p3, p4, promise)
377
375
  }.also {
@@ -383,7 +381,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
383
381
  name: String,
384
382
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R
385
383
  ): AsyncFunctionComponent {
386
- return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6) ->
384
+ return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5, p6) ->
387
385
  enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
388
386
  body(p0, p1, p2, p3, p4, p5, p6)
389
387
  }.also {
@@ -396,7 +394,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
396
394
  name: String,
397
395
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: Promise) -> R
398
396
  ): AsyncFunctionComponent {
399
- return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5), promise ->
397
+ return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5), promise ->
400
398
  enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
401
399
  body(p0, p1, p2, p3, p4, p5, promise)
402
400
  }.also {
@@ -408,7 +406,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
408
406
  name: String,
409
407
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R
410
408
  ): AsyncFunctionComponent {
411
- return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>()) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
409
+ return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
412
410
  enforceType<P0, P1, P2, P3, P4, P5, P6, P7>(p0, p1, p2, p3, p4, p5, p6, p7)
413
411
  body(p0, p1, p2, p3, p4, p5, p6, p7)
414
412
  }.also {
@@ -421,7 +419,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
421
419
  name: String,
422
420
  crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: Promise) -> R
423
421
  ): AsyncFunctionComponent {
424
- return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6), promise ->
422
+ return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5, p6), promise ->
425
423
  enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
426
424
  body(p0, p1, p2, p3, p4, p5, p6, promise)
427
425
  }.also {
@@ -431,13 +429,13 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
431
429
 
432
430
  fun AsyncFunction(
433
431
  name: String
434
- ) = AsyncFunctionBuilder(name).also { asyncFunctionBuilders[name] = it }
432
+ ) = AsyncFunctionBuilder(name, converters).also { asyncFunctionBuilders[name] = it }
435
433
 
436
434
  /**
437
435
  * Defines event names that this module can send to JavaScript.
438
436
  */
439
437
  fun Events(vararg events: String) {
440
- eventsDefinition = EventsDefinition(events)
438
+ eventsDefinition = EventsDefinition(events.asList().toTypedArray())
441
439
  }
442
440
 
443
441
  /**
@@ -15,4 +15,19 @@ class ObjectDefinitionData(
15
15
  ) {
16
16
  val functions
17
17
  get() = ConcatIterator(syncFunctions.values.iterator(), asyncFunctions.values.iterator())
18
+
19
+ operator fun plus(other: ObjectDefinitionData?): ObjectDefinitionData {
20
+ if (other == null) {
21
+ return this
22
+ }
23
+
24
+ return ObjectDefinitionData(
25
+ legacyConstantsProvider = { legacyConstantsProvider() + other.legacyConstantsProvider() },
26
+ syncFunctions = syncFunctions + other.syncFunctions,
27
+ asyncFunctions = asyncFunctions + other.asyncFunctions,
28
+ eventsDefinition = eventsDefinition?.plus(other.eventsDefinition),
29
+ properties = properties + other.properties,
30
+ constants = constants + other.constants
31
+ )
32
+ }
18
33
  }
@@ -0,0 +1,57 @@
1
+ package expo.modules.kotlin.traits
2
+
3
+ import android.graphics.Bitmap
4
+ import expo.modules.kotlin.AppContext
5
+ import expo.modules.kotlin.exception.Exceptions
6
+ import expo.modules.kotlin.objects.ObjectDefinitionBuilder
7
+ import expo.modules.kotlin.objects.ObjectDefinitionData
8
+ import expo.modules.kotlin.records.Record
9
+ import expo.modules.kotlin.sharedobjects.SharedRef
10
+ import expo.modules.kotlin.weak
11
+ import java.io.File
12
+ import java.util.UUID
13
+ import kotlin.reflect.KClass
14
+
15
+ class SavableTrait<InputType> @PublishedApi internal constructor(
16
+ val exportImpl: (AppContext) -> ObjectDefinitionData
17
+ ) : Trait<InputType> {
18
+ override fun export(appContext: AppContext) = exportImpl(appContext)
19
+
20
+ companion object {
21
+ data class SavableBitmapOptions(
22
+ val compression: Int = 100
23
+ ) : Record
24
+
25
+ @PublishedApi
26
+ internal inline fun <reified InputType, reified OptionType> createImplementation(
27
+ appContext: AppContext,
28
+ crossinline saveToFile: (file: File, input: InputType, options: OptionType) -> Unit
29
+ ): ObjectDefinitionData {
30
+ val appContextWeakRef = appContext.weak()
31
+
32
+ return ObjectDefinitionBuilder().apply {
33
+ AsyncFunction("saveAsync") { input: InputType, options: OptionType ->
34
+ val context = appContextWeakRef.get() ?: throw Exceptions.AppContextLost()
35
+ val outputFile = File(context.cacheDirectory, UUID.randomUUID().toString())
36
+ outputFile.createNewFile()
37
+
38
+ saveToFile(outputFile, input, options)
39
+ }
40
+ }.buildObject()
41
+ }
42
+
43
+ inline fun <reified T : SharedRef<Bitmap>> create(klass: KClass<T> = T::class) =
44
+ SavableTrait<T>(
45
+ exportImpl = { appContext ->
46
+ createImplementation<T, SavableBitmapOptions>(appContext) { file, input, options ->
47
+ input.appContext
48
+ input.ref.compress(
49
+ Bitmap.CompressFormat.PNG,
50
+ options.compression,
51
+ file.outputStream()
52
+ )
53
+ }
54
+ }
55
+ )
56
+ }
57
+ }
@@ -0,0 +1,8 @@
1
+ package expo.modules.kotlin.traits
2
+
3
+ import expo.modules.kotlin.AppContext
4
+ import expo.modules.kotlin.objects.ObjectDefinitionData
5
+
6
+ interface Trait<InputType> {
7
+ fun export(appContext: AppContext): ObjectDefinitionData
8
+ }
@@ -145,6 +145,15 @@ object AnyTypeProvider {
145
145
  }
146
146
  }
147
147
 
148
+ inline fun <reified T> lazyTypeOf() = { typeOf<T>() }.toLazyType<T>()
149
+
150
+ inline fun <reified T> (() -> KType).toLazyType() =
151
+ LazyKType(
152
+ classifier = T::class,
153
+ isMarkedNullable = null is T,
154
+ kTypeProvider = this
155
+ )
156
+
148
157
  inline fun <reified T> (() -> KType).toAnyType(converterProvider: TypeConverterProvider? = null) =
149
158
  AnyType(
150
159
  LazyKType(
@@ -98,7 +98,7 @@ class EitherTypeConverter<FirstType : Any, SecondType : Any>(
98
98
  )
99
99
  }
100
100
 
101
- override fun getCppRequiredTypes(): ExpectedType = firstType + secondType
101
+ override fun getCppRequiredTypes(): ExpectedType = ExpectedType.merge(firstType, secondType)
102
102
 
103
103
  override fun isTrivial(): Boolean = false
104
104
  }
@@ -144,7 +144,7 @@ class EitherOfThreeTypeConverter<FirstType : Any, SecondType : Any, ThirdType :
144
144
  )
145
145
  }
146
146
 
147
- override fun getCppRequiredTypes(): ExpectedType = firstType + secondType + thirdType
147
+ override fun getCppRequiredTypes(): ExpectedType = ExpectedType.merge(firstType, secondType, thirdType)
148
148
  }
149
149
 
150
150
  @EitherType
@@ -194,5 +194,5 @@ class EitherOfFourTypeConverter<FirstType : Any, SecondType : Any, ThirdType : A
194
194
  )
195
195
  }
196
196
 
197
- override fun getCppRequiredTypes(): ExpectedType = firstType + secondType + thirdType
197
+ override fun getCppRequiredTypes(): ExpectedType = ExpectedType.merge(firstType, secondType, thirdType, fourthType)
198
198
  }
@@ -0,0 +1,57 @@
1
+ package expo.modules.kotlin.types
2
+
3
+ import com.facebook.react.bridge.Dynamic
4
+
5
+ class ExpoDynamic(private val dynamic: Dynamic) {
6
+ enum class Type {
7
+ Boolean,
8
+ Number,
9
+ String,
10
+ Map,
11
+ Array
12
+ }
13
+
14
+ val type: Type
15
+ get() {
16
+ return when (dynamic.type) {
17
+ com.facebook.react.bridge.ReadableType.Null -> throw IllegalStateException("ExpoDynamic is null")
18
+ com.facebook.react.bridge.ReadableType.Boolean -> Type.Boolean
19
+ com.facebook.react.bridge.ReadableType.Number -> Type.Number
20
+ com.facebook.react.bridge.ReadableType.String -> Type.String
21
+ com.facebook.react.bridge.ReadableType.Map -> Type.Map
22
+ com.facebook.react.bridge.ReadableType.Array -> Type.Array
23
+ }
24
+ }
25
+
26
+ val isNull: Boolean
27
+ get() {
28
+ if (dynamic.isNull) {
29
+ throw IllegalStateException("ExpoDynamic is null")
30
+ }
31
+ return false
32
+ }
33
+
34
+ fun asArray(): List<Any?> {
35
+ return dynamic.asArray().toArrayList()
36
+ }
37
+
38
+ fun asBoolean(): Boolean {
39
+ return dynamic.asBoolean()
40
+ }
41
+
42
+ fun asDouble(): Double {
43
+ return dynamic.asDouble()
44
+ }
45
+
46
+ fun asInt(): Int {
47
+ return dynamic.asInt()
48
+ }
49
+
50
+ fun asMap(): Map<String, Any?> {
51
+ return dynamic.asMap().toHashMap()
52
+ }
53
+
54
+ fun asString(): String {
55
+ return dynamic.asString()
56
+ }
57
+ }
@@ -0,0 +1,81 @@
1
+ package expo.modules.kotlin.types
2
+
3
+ import com.facebook.react.bridge.Dynamic
4
+ import expo.modules.kotlin.AppContext
5
+ import expo.modules.kotlin.exception.MissingTypeConverter
6
+ import expo.modules.kotlin.jni.ExpectedType
7
+ import kotlin.reflect.KClass
8
+ import kotlin.reflect.KType
9
+ import kotlin.reflect.typeOf
10
+
11
+ class TypeConverterComponent<Type : Any>(val notNullableType: KType, val nullableType: KType) {
12
+ val nonNullableConverter = lazy { TypeConverterCollection<Type>(notNullableType, false) }
13
+ val nullableConverter = lazy { TypeConverterCollection<Type>(nullableType, true) }
14
+
15
+ inline fun <reified P0 : Any> from(crossinline body: (p0: P0) -> Type): TypeConverterComponent<Type> {
16
+ nonNullableConverter.value.from(body)
17
+ nullableConverter.value.from(body)
18
+ return this
19
+ }
20
+
21
+ fun build(): List<Pair<KType, TypeConverter<*>>> {
22
+ if (nonNullableConverter.isInitialized() && nullableConverter.isInitialized()) {
23
+ return listOf(
24
+ notNullableType to nonNullableConverter.value,
25
+ nullableType to nullableConverter.value
26
+ )
27
+ }
28
+
29
+ return emptyList()
30
+ }
31
+ }
32
+
33
+ class TypeConverterCollection<Type : Any>(
34
+ val type: KType,
35
+ isOptional: Boolean
36
+ ) : NullAwareTypeConverter<Type>(isOptional) {
37
+ @PublishedApi
38
+ internal var converters: MutableMap<KType, (Any?) -> Type> = mutableMapOf()
39
+
40
+ inline fun <reified P0> from(crossinline body: (p0: P0) -> Type): TypeConverterCollection<Type> {
41
+ converters[typeOf<P0>()] = { value ->
42
+ enforceType<P0>(value)
43
+ body(value)
44
+ }
45
+
46
+ return this
47
+ }
48
+
49
+ override fun convertNonOptional(value: Any, context: AppContext?): Type {
50
+ val possibleConverters = converters
51
+ .map { (key, converter) -> key to converter }
52
+ .filter { (key, _) ->
53
+ val kClass = key.classifier as? KClass<*>
54
+ kClass?.isInstance(value) == true
55
+ }
56
+
57
+ if (possibleConverters.isEmpty()) {
58
+ // We don't have a converter for Dynamic, but we can try to convert it to ExpoDynamic
59
+ // and see if we have a converter for that.
60
+ if (value is Dynamic) {
61
+ return convertNonOptional(ExpoDynamic(value), context)
62
+ }
63
+
64
+ throw MissingTypeConverter(type)
65
+ }
66
+
67
+ if (possibleConverters.size > 1) {
68
+ throw TypeCastException("Cannot cast '$value' to '$type'. Type converters conflict")
69
+ }
70
+
71
+ return possibleConverters.first().second.invoke(value)
72
+ }
73
+
74
+ override fun getCppRequiredTypes(): ExpectedType {
75
+ return ExpectedType.merge(
76
+ *converters.keys.map { key ->
77
+ ExpectedType.fromKType(key)
78
+ }.toTypedArray()
79
+ )
80
+ }
81
+ }
@@ -7,12 +7,11 @@ import expo.modules.kotlin.exception.PropSetException
7
7
  import expo.modules.kotlin.exception.exceptionDecorator
8
8
  import expo.modules.kotlin.types.AnyType
9
9
 
10
- class ConcreteViewProp<ViewType : View, PropType>(
10
+ open class ConcreteViewProp<ViewType : View, PropType>(
11
11
  name: String,
12
12
  propType: AnyType,
13
- private val setter: (view: ViewType, prop: PropType) -> Unit
13
+ protected val setter: (view: ViewType, prop: PropType) -> Unit
14
14
  ) : AnyViewProp(name, propType) {
15
-
16
15
  @Suppress("UNCHECKED_CAST")
17
16
  override fun set(prop: Dynamic, onView: View, appContext: AppContext?) {
18
17
  exceptionDecorator({
@@ -24,3 +23,19 @@ class ConcreteViewProp<ViewType : View, PropType>(
24
23
 
25
24
  override val isNullable: Boolean = propType.kType.isMarkedNullable
26
25
  }
26
+
27
+ class ConcreteViewPropWithDefault<ViewType : View, PropType>(
28
+ name: String,
29
+ propType: AnyType,
30
+ setter: (view: ViewType, prop: PropType) -> Unit,
31
+ private val defaultValue: PropType
32
+ ) : ConcreteViewProp<ViewType, PropType>(name, propType, setter) {
33
+ @Suppress("UNCHECKED_CAST")
34
+ override fun set(prop: Dynamic, onView: View, appContext: AppContext?) {
35
+ if (prop.isNull) {
36
+ setter(onView as ViewType, defaultValue)
37
+ return
38
+ }
39
+ super.set(prop, onView, appContext)
40
+ }
41
+ }