expo-modules-core 0.9.2 → 0.10.0

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 (167) hide show
  1. package/CHANGELOG.md +18 -5
  2. package/android/CMakeLists.txt +154 -0
  3. package/android/build.gradle +293 -5
  4. package/android/src/main/cpp/Exceptions.cpp +22 -0
  5. package/android/src/main/cpp/Exceptions.h +38 -0
  6. package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
  7. package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
  8. package/android/src/main/cpp/JNIFunctionBody.cpp +29 -0
  9. package/android/src/main/cpp/JNIFunctionBody.h +50 -0
  10. package/android/src/main/cpp/JNIInjector.cpp +19 -0
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
  12. package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
  13. package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
  14. package/android/src/main/cpp/JSITypeConverter.h +84 -0
  15. package/android/src/main/cpp/JavaScriptModuleObject.cpp +138 -0
  16. package/android/src/main/cpp/JavaScriptModuleObject.h +122 -0
  17. package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
  18. package/android/src/main/cpp/JavaScriptObject.h +131 -0
  19. package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
  20. package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
  21. package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
  22. package/android/src/main/cpp/JavaScriptValue.h +78 -0
  23. package/android/src/main/cpp/MethodMetadata.cpp +230 -0
  24. package/android/src/main/cpp/MethodMetadata.h +92 -0
  25. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
  26. package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
  27. package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
  28. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +49 -1
  29. package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
  30. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
  31. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +39 -3
  32. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
  33. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
  34. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
  35. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +19 -14
  36. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +29 -7
  37. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -13
  38. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +18 -0
  39. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +18 -0
  40. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +56 -0
  41. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +28 -0
  42. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +18 -0
  43. package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
  44. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
  45. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +44 -0
  46. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
  47. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
  48. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +15 -5
  49. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +65 -111
  50. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +35 -2
  51. package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
  52. package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
  53. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
  54. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
  55. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
  56. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
  57. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
  58. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
  59. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
  60. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
  61. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
  62. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +5 -0
  63. package/build/NativeModulesProxy.native.d.ts.map +1 -1
  64. package/build/NativeModulesProxy.native.js +9 -3
  65. package/build/NativeModulesProxy.native.js.map +1 -1
  66. package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
  67. package/ios/ExpoModulesCore.podspec +1 -1
  68. package/ios/JSI/EXJSIConversions.mm +6 -0
  69. package/ios/JSI/EXJSIInstaller.h +15 -21
  70. package/ios/JSI/EXJSIInstaller.mm +39 -3
  71. package/ios/JSI/EXJSIUtils.h +47 -3
  72. package/ios/JSI/EXJSIUtils.mm +88 -4
  73. package/ios/JSI/EXJavaScriptObject.h +11 -18
  74. package/ios/JSI/EXJavaScriptObject.mm +37 -18
  75. package/ios/JSI/EXJavaScriptRuntime.h +43 -9
  76. package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
  77. package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
  78. package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
  79. package/ios/JSI/EXJavaScriptValue.h +3 -2
  80. package/ios/JSI/EXJavaScriptValue.mm +17 -20
  81. package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
  82. package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
  83. package/ios/JSI/EXObjectDeallocator.h +27 -0
  84. package/ios/JSI/ExpoModulesHostObject.h +3 -3
  85. package/ios/JSI/ExpoModulesHostObject.mm +4 -4
  86. package/ios/JSI/JavaScriptRuntime.swift +38 -1
  87. package/ios/JSI/JavaScriptValue.swift +7 -0
  88. package/ios/JSI/TypedArray.cpp +67 -0
  89. package/ios/JSI/TypedArray.h +46 -0
  90. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
  91. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
  92. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +85 -77
  93. package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
  94. package/ios/Services/EXReactNativeEventEmitter.h +2 -2
  95. package/ios/Services/EXReactNativeEventEmitter.m +11 -6
  96. package/ios/Swift/AppContext.swift +208 -28
  97. package/ios/Swift/Arguments/AnyArgument.swift +18 -0
  98. package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
  99. package/ios/Swift/Classes/ClassComponent.swift +95 -0
  100. package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
  101. package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
  102. package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
  103. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
  104. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
  105. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
  106. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
  107. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
  108. package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
  109. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
  110. package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
  111. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
  112. package/ios/Swift/Exceptions/CodedError.swift +1 -1
  113. package/ios/Swift/Exceptions/Exception.swift +8 -6
  114. package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
  115. package/ios/Swift/ExpoBridgeModule.m +5 -0
  116. package/ios/Swift/ExpoBridgeModule.swift +65 -0
  117. package/ios/Swift/Functions/AnyFunction.swift +33 -31
  118. package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
  119. package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
  120. package/ios/Swift/JavaScriptUtils.swift +32 -57
  121. package/ios/Swift/Logging/LogHandlers.swift +39 -0
  122. package/ios/Swift/Logging/LogType.swift +62 -0
  123. package/ios/Swift/Logging/Logger.swift +198 -0
  124. package/ios/Swift/ModuleHolder.swift +19 -54
  125. package/ios/Swift/ModuleRegistry.swift +7 -1
  126. package/ios/Swift/Modules/AnyModule.swift +3 -3
  127. package/ios/Swift/ModulesProvider.swift +2 -0
  128. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
  129. package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
  130. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
  131. package/ios/Swift/Objects/PropertyComponent.swift +147 -0
  132. package/ios/Swift/Promise.swift +12 -3
  133. package/ios/Swift/Records/Field.swift +2 -2
  134. package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
  135. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
  136. package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
  137. package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
  138. package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
  139. package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
  140. package/ios/Swift/Utilities.swift +28 -0
  141. package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
  142. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
  143. package/ios/Tests/ClassComponentSpec.swift +210 -0
  144. package/ios/Tests/DynamicTypeSpec.swift +336 -0
  145. package/ios/Tests/EnumArgumentSpec.swift +48 -0
  146. package/ios/Tests/ExpoModulesSpec.swift +17 -3
  147. package/ios/Tests/FunctionSpec.swift +167 -118
  148. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  149. package/ios/Tests/PropertyComponentSpec.swift +95 -0
  150. package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
  151. package/ios/Tests/TypedArraysSpec.swift +136 -0
  152. package/package.json +2 -2
  153. package/src/NativeModulesProxy.native.ts +13 -3
  154. package/src/ts-declarations/ExpoModules.d.ts +7 -0
  155. package/tsconfig.json +1 -1
  156. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
  157. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
  158. package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
  159. package/ios/Swift/Arguments/ArgumentType.swift +0 -28
  160. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
  161. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
  162. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
  163. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
  164. package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
  165. package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
  166. package/ios/Swift/SwiftInteropBridge.swift +0 -155
  167. package/ios/Tests/ArgumentTypeSpec.swift +0 -143
@@ -0,0 +1,198 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ import Dispatch
4
+
5
+ public let log = Logger(category: "expo")
6
+
7
+ public class Logger {
8
+ #if DEBUG || EXPO_CONFIGURATION_DEBUG
9
+ private var minLevel: LogType = .trace
10
+ #else
11
+ private var minLevel: LogType = .info
12
+ #endif
13
+
14
+ private let category: String
15
+
16
+ private var handlers: [LogHandler] = []
17
+
18
+ init(category: String = "main") {
19
+ self.category = category
20
+
21
+ if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
22
+ addHandler(withType: OSLogHandler.self)
23
+ } else {
24
+ addHandler(withType: PrintLogHandler.self)
25
+ }
26
+ }
27
+
28
+ internal func addHandler<LogHandlerType: LogHandler>(_ handler: LogHandlerType) {
29
+ handlers.append(handler)
30
+ }
31
+
32
+ internal func addHandler<LogHandlerType: LogHandler>(withType: LogHandlerType.Type) {
33
+ addHandler(LogHandlerType(category: category))
34
+ }
35
+
36
+ // MARK: - Public logging functions
37
+
38
+ /**
39
+ The most verbose log level that captures all the details about the behavior of the implementation.
40
+ It is mostly diagnostic and is more granular and finer than `debug` log level.
41
+ These logs should not be committed to the repository and are ignored in the release builds.
42
+ */
43
+ public func trace(_ items: Any...) {
44
+ log(type: .trace, items)
45
+ }
46
+
47
+ /**
48
+ Used to log diagnostically helpful information. As opposed to `trace`,
49
+ it is acceptable to commit these logs to the repository. Ignored in the release builds.
50
+ */
51
+ public func debug(_ items: Any...) {
52
+ log(type: .debug, items)
53
+ }
54
+
55
+ /**
56
+ For information that should be logged under normal conditions such as successful initialization
57
+ and notable events that are not considered an error but might be useful for debugging purposes in the release builds.
58
+ */
59
+ public func info(_ items: Any...) {
60
+ log(type: .info, items)
61
+ }
62
+
63
+ /**
64
+ Used to log an unwanted state that has not much impact on the process so it can be continued, but could potentially become an error.
65
+ */
66
+ public func warn(_ items: Any...) {
67
+ log(type: .warn, items)
68
+ }
69
+
70
+ /**
71
+ Logs unwanted state that has an impact on the currently running process, but the entire app can continue to run.
72
+ */
73
+ public func error(_ items: Any...) {
74
+ log(type: .error, items)
75
+ }
76
+
77
+ /**
78
+ Logs critical error due to which the entire app cannot continue to run.
79
+ */
80
+ public func fatal(_ items: Any...) {
81
+ log(type: .fatal, items)
82
+ }
83
+
84
+ /**
85
+ Logs the stack of symbols on the current thread.
86
+ */
87
+ public func stacktrace(type: LogType = .stacktrace, file: String = #fileID, line: UInt = #line) {
88
+ guard type.rawValue >= minLevel.rawValue else {
89
+ return
90
+ }
91
+ let queueName = OperationQueue.current?.underlyingQueue?.label ?? "<unknown>"
92
+
93
+ // Get the call stack symbols without the first symbol as it points right here.
94
+ let symbols = Thread.callStackSymbols.dropFirst()
95
+
96
+ log(type: type, "The stacktrace from '\(file):\(line)' on queue '\(queueName)':")
97
+
98
+ symbols.forEach { symbol in
99
+ let formattedSymbol = reformatStackSymbol(symbol)
100
+ log(type: type, "≫ \(formattedSymbol)")
101
+ }
102
+ }
103
+
104
+ /**
105
+ Allows the logger instance to be called as a function. The same as `logger.debug(...)`.
106
+ */
107
+ public func callAsFunction(_ items: Any...) {
108
+ log(type: .debug, items)
109
+ }
110
+
111
+ // MARK: - Timers
112
+
113
+ /**
114
+ Stores the timers created by `timeStart` function.
115
+ */
116
+ private var timers: [String: DispatchTime] = [:]
117
+
118
+ /**
119
+ Starts the timer to measure how much time the following operations take.
120
+ */
121
+ public func timeStart(_ id: String) {
122
+ guard LogType.timer.rawValue >= minLevel.rawValue else {
123
+ return
124
+ }
125
+ log(type: .timer, "Starting timer '\(id)'")
126
+ timers[id] = DispatchTime.now()
127
+ }
128
+
129
+ /**
130
+ Stops the timer and logs how much time elapsed since it started.
131
+ */
132
+ public func timeEnd(_ id: String) {
133
+ guard LogType.timer.rawValue >= minLevel.rawValue else {
134
+ return
135
+ }
136
+ guard let startTime = timers[id] else {
137
+ log(type: .timer, "Timer '\(id)' has not been started!")
138
+ return
139
+ }
140
+ let endTime = DispatchTime.now()
141
+ let diff = Double(endTime.uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000
142
+ log(type: .timer, "Timer '\(id)' has finished in: \(diff) seconds")
143
+ timers.removeValue(forKey: id)
144
+ }
145
+
146
+ /**
147
+ Measures how much time it takes to run given closure. Returns the same value as the closure returned.
148
+ */
149
+ public func time<ReturnType>(_ id: String, _ closure: () -> ReturnType) -> ReturnType {
150
+ timeStart(id)
151
+ let result = closure()
152
+ timeEnd(id)
153
+ return result
154
+ }
155
+
156
+ // MARK: - Changing the category
157
+
158
+ public func category(_ category: String) -> Logger {
159
+ return Logger(category: category)
160
+ }
161
+
162
+ // MARK: - Private logging functions
163
+
164
+ private func log(type: LogType = .trace, _ items: [Any]) {
165
+ guard type.rawValue >= minLevel.rawValue else {
166
+ return
167
+ }
168
+ let messages = items
169
+ .map { describe(value: $0) }
170
+ .joined(separator: " ")
171
+ .split(whereSeparator: \.isNewline)
172
+ .map { "\(type.prefix) \($0)" }
173
+
174
+ handlers.forEach { handler in
175
+ messages.forEach { message in
176
+ handler.log(type: type, message)
177
+ }
178
+ }
179
+ }
180
+
181
+ private func log(type: LogType = .trace, _ items: Any...) {
182
+ log(type: type, items)
183
+ }
184
+ }
185
+
186
+ fileprivate func reformatStackSymbol(_ symbol: String) -> String {
187
+ return symbol.replacingOccurrences(of: #"^\d+\s+"#, with: "", options: .regularExpression)
188
+ }
189
+
190
+ fileprivate func describe(value: Any) -> String {
191
+ if let value = value as? CustomDebugStringConvertible {
192
+ return value.debugDescription
193
+ }
194
+ if let value = value as? CustomStringConvertible {
195
+ return value.description
196
+ }
197
+ return String(describing: value)
198
+ }
@@ -56,54 +56,33 @@ public final class ModuleHolder {
56
56
  Merges all `constants` definitions into one dictionary.
57
57
  */
58
58
  func getConstants() -> [String: Any?] {
59
- return definition.constants.reduce(into: [String: Any?]()) { dict, definition in
60
- dict.merge(definition.body()) { $1 }
61
- }
59
+ return definition.getConstants()
62
60
  }
63
61
 
64
62
  // MARK: Calling functions
65
63
 
66
- func call(function functionName: String, args: [Any], promise: Promise) {
67
- do {
68
- guard let function = definition.functions[functionName] else {
69
- throw FunctionNotFoundException((functionName: functionName, moduleName: self.name))
70
- }
71
- let queue = function.queue ?? DispatchQueue.global(qos: .default)
72
-
73
- // Given arguments can be:
74
- // - Swift primitives when invoked through the bridge and in unit tests
75
- // - `JavaScriptValue`s when the function is called through the JSI
76
- // The latter need to be unpacked to Swift primitives on the JS thread,
77
- // so we do the casting before the function call is scheduled on the queue.
78
- let arguments = try castArguments(args, toTypes: function.argumentTypes)
79
-
80
- queue.async {
81
- function.call(args: arguments, promise: promise)
82
- }
83
- } catch let error as CodedError {
84
- promise.reject(error)
85
- } catch {
86
- promise.reject(UnexpectedException(error))
87
- }
88
- }
89
-
90
- func call(function functionName: String, args: [Any], _ callback: @escaping (Any?, CodedError?) -> Void = { _, _ in }) {
91
- let promise = Promise {
92
- callback($0, nil)
93
- } rejecter: {
94
- callback(nil, $0)
64
+ func call(function functionName: String, args: [Any], _ callback: @escaping (FunctionCallResult) -> () = { _ in }) {
65
+ guard let function = definition.functions[functionName] else {
66
+ callback(.failure(FunctionNotFoundException((functionName: functionName, moduleName: self.name))))
67
+ return
95
68
  }
96
- call(function: functionName, args: args, promise: promise)
69
+ function.call(by: self, withArguments: args, callback: callback)
97
70
  }
98
71
 
99
72
  @discardableResult
100
73
  func callSync(function functionName: String, args: [Any]) -> Any? {
101
- guard let function = definition.functions[functionName] else {
74
+ guard let function = definition.functions[functionName] as? AnySyncFunctionComponent else {
102
75
  return nil
103
76
  }
104
77
  do {
105
- let arguments = try castArguments(args, toTypes: function.argumentTypes)
106
- return function.callSync(args: arguments)
78
+ let arguments = try cast(arguments: args, forFunction: function)
79
+ let result = try function.call(by: self, withArguments: arguments)
80
+
81
+ if let result = result as? SharedObject {
82
+ let jsObject = SharedObjectRegistry.ensureSharedJavaScriptObject(runtime: appContext!.runtime!, nativeObject: result)
83
+ return jsObject
84
+ }
85
+ return result
107
86
  } catch {
108
87
  return error
109
88
  }
@@ -119,24 +98,10 @@ public final class ModuleHolder {
119
98
  */
120
99
  private func createJavaScriptModuleObject() -> JavaScriptObject? {
121
100
  // It might be impossible to create any object at the moment (e.g. remote debugging, app context destroyed)
122
- guard let object = appContext?.runtime?.createObject() else {
101
+ guard let runtime = appContext?.runtime else {
123
102
  return nil
124
103
  }
125
-
126
- // Fill in with constants
127
- for (key, value) in getConstants() {
128
- object.setProperty(key, value: value)
129
- }
130
-
131
- // Fill in with functions
132
- for (_, fn) in definition.functions {
133
- if fn.isAsync {
134
- object.setAsyncFunction(fn.name, argsCount: fn.argumentsCount, block: createAsyncFunctionBlock(holder: self, name: fn.name))
135
- } else {
136
- object.setSyncFunction(fn.name, argsCount: fn.argumentsCount, block: createSyncFunctionBlock(holder: self, name: fn.name))
137
- }
138
- }
139
- return object
104
+ return definition.build(inRuntime: runtime)
140
105
  }
141
106
 
142
107
  // MARK: Listening to native events
@@ -166,9 +131,9 @@ public final class ModuleHolder {
166
131
  */
167
132
  func modifyListenersCount(_ count: Int) {
168
133
  if count > 0 && listenersCount == 0 {
169
- _ = definition.functions["startObserving"]?.callSync(args: [])
134
+ definition.functions["startObserving"]?.call(withArguments: [])
170
135
  } else if count < 0 && listenersCount + count <= 0 {
171
- _ = definition.functions["stopObserving"]?.callSync(args: [])
136
+ definition.functions["stopObserving"]?.call(withArguments: [])
172
137
  }
173
138
  listenersCount = max(0, listenersCount + count)
174
139
  }
@@ -13,6 +13,7 @@ public final class ModuleRegistry: Sequence {
13
13
  Registers an instance of module holder.
14
14
  */
15
15
  internal func register(holder: ModuleHolder) {
16
+ log.info("Registering module '\(holder.name)'")
16
17
  registry[holder.name] = holder
17
18
  }
18
19
 
@@ -47,7 +48,10 @@ public final class ModuleRegistry: Sequence {
47
48
  }
48
49
 
49
50
  public func unregister(moduleName: String) {
50
- registry[moduleName] = nil
51
+ if registry[moduleName] != nil {
52
+ log.info("Unregistering module '\(moduleName)'")
53
+ registry[moduleName] = nil
54
+ }
51
55
  }
52
56
 
53
57
  public func has(moduleWithName moduleName: String) -> Bool {
@@ -71,12 +75,14 @@ public final class ModuleRegistry: Sequence {
71
75
  }
72
76
 
73
77
  internal func post(event: EventName) {
78
+ log.info("Posting '\(event)' event to registered modules")
74
79
  forEach { holder in
75
80
  holder.post(event: event)
76
81
  }
77
82
  }
78
83
 
79
84
  internal func post<PayloadType>(event: EventName, payload: PayloadType? = nil) {
85
+ log.info("Posting '\(event)' event to registered modules")
80
86
  forEach { holder in
81
87
  holder.post(event: event, payload: payload)
82
88
  }
@@ -16,8 +16,8 @@ public protocol AnyModule: AnyObject, AnyArgument {
16
16
 
17
17
  ```
18
18
  public func definition() -> ModuleDefinition {
19
- name("MyModule")
20
- function("myFunction") { (a: String, b: String) in
19
+ Name("MyModule")
20
+ AsyncFunction("myFunction") { (a: String, b: String) in
21
21
  "\(a) \(b)"
22
22
  }
23
23
  }
@@ -37,7 +37,7 @@ public protocol AnyModule: AnyObject, AnyArgument {
37
37
  just specify an argument of type `Promise` as the last one and use its `resolve` or `reject` functions.
38
38
 
39
39
  ```
40
- function("myFunction") { (promise: Promise) in
40
+ AsyncFunction("myFunction") { (promise: Promise) in
41
41
  DispatchQueue.main.async {
42
42
  promise.resolve("return value obtained in async callback")
43
43
  }
@@ -24,6 +24,8 @@ public protocol ModulesProviderProtocol {
24
24
  */
25
25
  @objc
26
26
  open class ModulesProvider: NSObject, ModulesProviderProtocol {
27
+ public override required init() {}
28
+
27
29
  open func getModuleClasses() -> [AnyModule.Type] {
28
30
  return []
29
31
  }
@@ -0,0 +1,37 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A type that can decorate a `JavaScriptObject` with some properties.
5
+ */
6
+ internal protocol JavaScriptObjectDecorator {
7
+ /**
8
+ Decorates an existing `JavaScriptObject`.
9
+ */
10
+ func decorate(object: JavaScriptObject, inRuntime runtime: JavaScriptRuntime)
11
+ }
12
+
13
+ /**
14
+ A type that can build and decorate a `JavaScriptObject` based on its attributes.
15
+ */
16
+ internal protocol JavaScriptObjectBuilder: JavaScriptObjectDecorator {
17
+ /**
18
+ Creates a decorated `JavaScriptObject` in the given runtime.
19
+ */
20
+ func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject
21
+ }
22
+
23
+ /**
24
+ Provides the default behavior of `JavaScriptObjectBuilder`.
25
+ The `build(inRuntime:)` creates a plain object and uses `decorate(object:)` for decoration.
26
+ */
27
+ extension JavaScriptObjectBuilder {
28
+ func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
29
+ let object = runtime.createObject()
30
+ decorate(object: object, inRuntime: runtime)
31
+ return object
32
+ }
33
+
34
+ func decorate(object: JavaScriptObject, inRuntime runtime: JavaScriptRuntime) {
35
+ // no-op by default
36
+ }
37
+ }
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  Base class for other definitions representing an object, such as `ModuleDefinition`.
5
5
  */
6
- public class ObjectDefinition: AnyDefinition {
6
+ public class ObjectDefinition: AnyDefinition, JavaScriptObjectBuilder {
7
7
  /**
8
8
  A dictionary of functions defined by the object.
9
9
  */
@@ -14,6 +14,16 @@ public class ObjectDefinition: AnyDefinition {
14
14
  */
15
15
  let constants: [ConstantsDefinition]
16
16
 
17
+ /**
18
+ A map of dynamic properties defined by the object.
19
+ */
20
+ let properties: [String: PropertyComponent]
21
+
22
+ /**
23
+ A map of classes defined within the object.
24
+ */
25
+ let classes: [String: ClassComponent]
26
+
17
27
  /**
18
28
  Default initializer receiving children definitions from the result builder.
19
29
  */
@@ -26,5 +36,68 @@ public class ObjectDefinition: AnyDefinition {
26
36
 
27
37
  self.constants = definitions
28
38
  .compactMap { $0 as? ConstantsDefinition }
39
+
40
+ self.properties = definitions
41
+ .compactMap { $0 as? PropertyComponent }
42
+ .reduce(into: [String: PropertyComponent]()) { dict, property in
43
+ dict[property.name] = property
44
+ }
45
+
46
+ self.classes = definitions
47
+ .compactMap { $0 as? ClassComponent }
48
+ .reduce(into: [String: ClassComponent]()) { dict, klass in
49
+ dict[klass.name] = klass
50
+ }
51
+ }
52
+
53
+ /**
54
+ Merges all `constants` definitions into one dictionary.
55
+ */
56
+ func getConstants() -> [String: Any?] {
57
+ return constants.reduce(into: [String: Any?]()) { dict, definition in
58
+ dict.merge(definition.body()) { $1 }
59
+ }
60
+ }
61
+
62
+ // MARK: - JavaScriptObjectBuilder
63
+
64
+ public func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
65
+ let object = runtime.createObject()
66
+ decorate(object: object, inRuntime: runtime)
67
+ return object
68
+ }
69
+
70
+ public func decorate(object: JavaScriptObject, inRuntime runtime: JavaScriptRuntime) {
71
+ decorateWithConstants(runtime: runtime, object: object)
72
+ decorateWithFunctions(runtime: runtime, object: object)
73
+ decorateWithProperties(runtime: runtime, object: object)
74
+ decorateWithClasses(runtime: runtime, object: object)
75
+ }
76
+
77
+ // MARK: - Internals
78
+
79
+ internal func decorateWithConstants(runtime: JavaScriptRuntime, object: JavaScriptObject) {
80
+ for (key, value) in getConstants() {
81
+ object.setProperty(key, value: value)
82
+ }
83
+ }
84
+
85
+ internal func decorateWithFunctions(runtime: JavaScriptRuntime, object: JavaScriptObject) {
86
+ for fn in functions.values {
87
+ object.setProperty(fn.name, value: fn.build(inRuntime: runtime))
88
+ }
89
+ }
90
+
91
+ internal func decorateWithProperties(runtime: JavaScriptRuntime, object: JavaScriptObject) {
92
+ for property in properties.values {
93
+ let descriptor = property.buildDescriptor(inRuntime: runtime, withCaller: object)
94
+ object.defineProperty(property.name, descriptor: descriptor)
95
+ }
96
+ }
97
+
98
+ internal func decorateWithClasses(runtime: JavaScriptRuntime, object: JavaScriptObject) {
99
+ for klass in classes.values {
100
+ object.setProperty(klass.name, value: klass.build(inRuntime: runtime))
101
+ }
29
102
  }
30
103
  }