expo-modules-core 0.9.2 → 0.11.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.
- package/CHANGELOG.md +33 -3
- package/README.md +3 -3
- package/android/CMakeLists.txt +163 -0
- package/android/build.gradle +343 -5
- package/android/src/main/cpp/CachedReferencesRegistry.cpp +65 -0
- package/android/src/main/cpp/CachedReferencesRegistry.h +80 -0
- package/android/src/main/cpp/Exceptions.cpp +22 -0
- package/android/src/main/cpp/Exceptions.h +38 -0
- package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
- package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
- package/android/src/main/cpp/JNIFunctionBody.cpp +44 -0
- package/android/src/main/cpp/JNIFunctionBody.h +50 -0
- package/android/src/main/cpp/JNIInjector.cpp +23 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
- package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
- package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
- package/android/src/main/cpp/JSITypeConverter.h +84 -0
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +219 -0
- package/android/src/main/cpp/JavaScriptModuleObject.h +144 -0
- package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
- package/android/src/main/cpp/JavaScriptObject.h +131 -0
- package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
- package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
- package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
- package/android/src/main/cpp/JavaScriptValue.h +78 -0
- package/android/src/main/cpp/MethodMetadata.cpp +340 -0
- package/android/src/main/cpp/MethodMetadata.h +131 -0
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
- package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
- package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +98 -3
- package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +45 -3
- package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAware.kt +49 -0
- package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAwareHelper.kt +43 -0
- package/android/src/main/java/expo/modules/kotlin/activityaware/OnActivityAvailableListener.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/ActivityResultsManager.kt +99 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultContract.kt +27 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultFallbackCallback.kt +17 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultLauncher.kt +30 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultRegistry.kt +358 -0
- package/android/src/main/java/expo/modules/kotlin/activityresult/DataPersistor.kt +135 -0
- package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +53 -15
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +35 -7
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -121
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +63 -0
- package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +19 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +46 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +16 -6
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +5 -500
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +30 -5
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +271 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponent.kt +54 -0
- package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponentBuilder.kt +32 -0
- package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
- package/android/src/main/java/expo/modules/kotlin/types/AnyTypeConverter.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
- package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
- package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +12 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -41
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -33
- package/build/NativeModulesProxy.native.d.ts.map +1 -1
- package/build/NativeModulesProxy.native.js +9 -3
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/build/PermissionsInterface.d.ts +29 -0
- package/build/PermissionsInterface.d.ts.map +1 -1
- package/build/PermissionsInterface.js +9 -0
- package/build/PermissionsInterface.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
- package/ios/ExpoModulesCore.podspec +3 -2
- package/ios/JSI/EXJSIConversions.mm +6 -0
- package/ios/JSI/EXJSIInstaller.h +15 -21
- package/ios/JSI/EXJSIInstaller.mm +39 -3
- package/ios/JSI/EXJSIUtils.h +48 -3
- package/ios/JSI/EXJSIUtils.mm +88 -4
- package/ios/JSI/EXJavaScriptObject.h +11 -18
- package/ios/JSI/EXJavaScriptObject.mm +37 -18
- package/ios/JSI/EXJavaScriptRuntime.h +43 -9
- package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
- package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
- package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
- package/ios/JSI/EXJavaScriptValue.h +3 -2
- package/ios/JSI/EXJavaScriptValue.mm +17 -20
- package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
- package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
- package/ios/JSI/EXObjectDeallocator.h +27 -0
- package/ios/JSI/ExpoModulesHostObject.h +3 -3
- package/ios/JSI/ExpoModulesHostObject.mm +4 -4
- package/ios/JSI/JavaScriptRuntime.swift +38 -1
- package/ios/JSI/JavaScriptValue.swift +7 -0
- package/ios/JSI/TypedArray.cpp +67 -0
- package/ios/JSI/TypedArray.h +46 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +86 -77
- package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
- package/ios/Services/EXReactNativeEventEmitter.h +2 -2
- package/ios/Services/EXReactNativeEventEmitter.m +11 -6
- package/ios/Swift/AppContext.swift +206 -28
- package/ios/Swift/Arguments/AnyArgument.swift +18 -0
- package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
- package/ios/Swift/Classes/ClassComponent.swift +95 -0
- package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
- package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
- package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
- package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
- package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
- package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
- package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
- package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
- package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
- package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
- package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
- package/ios/Swift/Exceptions/ChainableException.swift +3 -3
- package/ios/Swift/Exceptions/CodedError.swift +1 -1
- package/ios/Swift/Exceptions/Exception.swift +8 -6
- package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
- package/ios/Swift/ExpoBridgeModule.m +5 -0
- package/ios/Swift/ExpoBridgeModule.swift +79 -0
- package/ios/Swift/Functions/AnyFunction.swift +33 -31
- package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
- package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
- package/ios/Swift/JavaScriptUtils.swift +32 -57
- package/ios/Swift/Logging/LogHandlers.swift +39 -0
- package/ios/Swift/Logging/LogType.swift +62 -0
- package/ios/Swift/Logging/Logger.swift +201 -0
- package/ios/Swift/ModuleHolder.swift +19 -54
- package/ios/Swift/ModuleRegistry.swift +7 -1
- package/ios/Swift/Modules/AnyModule.swift +3 -3
- package/ios/Swift/ModulesProvider.swift +2 -0
- package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
- package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
- package/ios/Swift/Objects/PropertyComponent.swift +147 -0
- package/ios/Swift/Promise.swift +17 -4
- package/ios/Swift/Records/Field.swift +2 -2
- package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
- package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
- package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
- package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
- package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
- package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
- package/ios/Swift/Utilities.swift +28 -0
- package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
- package/ios/Tests/ClassComponentSpec.swift +210 -0
- package/ios/Tests/DynamicTypeSpec.swift +336 -0
- package/ios/Tests/EnumArgumentSpec.swift +48 -0
- package/ios/Tests/ExpoModulesSpec.swift +17 -3
- package/ios/Tests/FunctionSpec.swift +167 -118
- package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
- package/ios/Tests/PropertyComponentSpec.swift +95 -0
- package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
- package/ios/Tests/TypedArraysSpec.swift +136 -0
- package/package.json +2 -2
- package/src/NativeModulesProxy.native.ts +13 -3
- package/src/PermissionsInterface.ts +29 -0
- package/src/ts-declarations/ExpoModules.d.ts +7 -0
- package/tsconfig.json +1 -1
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
- package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
- package/ios/Swift/Arguments/ArgumentType.swift +0 -28
- package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
- package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
- package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
- package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
- package/ios/Swift/SwiftInteropBridge.swift +0 -155
- package/ios/Tests/ArgumentTypeSpec.swift +0 -143
|
@@ -1,97 +1,72 @@
|
|
|
1
1
|
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
|
-
// FIXME: Calling module's functions needs solid refactoring to not reference the module holder.
|
|
4
|
-
// Instead, it should be possible to directly call the function instance from here. (added by @tsapeta)
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
Creates a block that is executed when the module's async function is called.
|
|
8
|
-
*/
|
|
9
|
-
internal func createAsyncFunctionBlock(holder: ModuleHolder, name functionName: String) -> JSAsyncFunctionBlock {
|
|
10
|
-
let moduleName = holder.name
|
|
11
|
-
return { [weak holder, moduleName] args, resolve, reject in
|
|
12
|
-
guard let holder = holder else {
|
|
13
|
-
let exception = ModuleUnavailableException(moduleName)
|
|
14
|
-
reject(exception.code, exception.description, exception)
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
holder.call(function: functionName, args: args) { result, error in
|
|
18
|
-
if let error = error {
|
|
19
|
-
reject(error.code, error.description, error)
|
|
20
|
-
} else {
|
|
21
|
-
resolve(result)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
Creates a block that is executed when the module's sync function is called.
|
|
29
|
-
*/
|
|
30
|
-
internal func createSyncFunctionBlock(holder: ModuleHolder, name functionName: String) -> JSSyncFunctionBlock {
|
|
31
|
-
return { [weak holder] args in
|
|
32
|
-
guard let holder = holder else {
|
|
33
|
-
return nil
|
|
34
|
-
}
|
|
35
|
-
return holder.callSync(function: functionName, args: args)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
3
|
// MARK: - Arguments
|
|
40
4
|
|
|
41
5
|
/**
|
|
42
|
-
Tries to cast given
|
|
6
|
+
Tries to cast a given value to the type that is wrapped by the dynamic type.
|
|
43
7
|
- Parameters:
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
- Returns: A new value converted according to the
|
|
47
|
-
- Throws: Rethrows various exceptions that could be thrown by the
|
|
8
|
+
- value: A value to be cast. If it's a ``JavaScriptValue``, it's first unpacked to the raw value.
|
|
9
|
+
- type: Something that implements ``AnyDynamicType`` and knows how to cast the argument.
|
|
10
|
+
- Returns: A new value converted according to the dynamic type.
|
|
11
|
+
- Throws: Rethrows various exceptions that could be thrown by the dynamic types.
|
|
48
12
|
*/
|
|
49
|
-
internal func
|
|
13
|
+
internal func cast(_ value: Any, toType type: AnyDynamicType) throws -> Any {
|
|
50
14
|
// TODO: Accept JavaScriptValue and JavaScriptObject as argument types.
|
|
51
|
-
if let
|
|
52
|
-
return try
|
|
15
|
+
if !(type is DynamicTypedArrayType), let value = value as? JavaScriptValue {
|
|
16
|
+
return try type.cast(value.getRaw())
|
|
53
17
|
}
|
|
54
|
-
return try
|
|
18
|
+
return try type.cast(value)
|
|
55
19
|
}
|
|
56
20
|
|
|
57
21
|
/**
|
|
58
|
-
|
|
22
|
+
Tries to cast the given arguments to the types expected by the function.
|
|
59
23
|
- Parameters:
|
|
60
24
|
- arguments: An array of arguments to be cast.
|
|
61
|
-
-
|
|
25
|
+
- function: A function for which to cast the arguments.
|
|
62
26
|
- Returns: An array of arguments after casting. Its size is the same as the input arrays.
|
|
63
|
-
- Throws:
|
|
64
|
-
|
|
27
|
+
- Throws: `InvalidArgsNumberException` when the number of arguments is not equal to the actual number
|
|
28
|
+
of function's arguments (without an owner and promise). Rethrows exceptions thrown by `cast(_:toType:)`.
|
|
65
29
|
*/
|
|
66
|
-
internal func
|
|
67
|
-
if arguments.count !=
|
|
68
|
-
throw InvalidArgsNumberException((received: arguments.count, expected:
|
|
30
|
+
internal func cast(arguments: [Any], forFunction function: AnyFunction) throws -> [Any] {
|
|
31
|
+
if arguments.count != function.argumentsCount {
|
|
32
|
+
throw InvalidArgsNumberException((received: arguments.count, expected: function.argumentsCount))
|
|
69
33
|
}
|
|
34
|
+
let argumentTypeOffset = function.takesOwner ? 1 : 0
|
|
70
35
|
return try arguments.enumerated().map { index, argument in
|
|
71
|
-
let argumentType =
|
|
36
|
+
let argumentType = function.dynamicArgumentTypes[index + argumentTypeOffset]
|
|
72
37
|
|
|
73
38
|
do {
|
|
74
|
-
return try
|
|
39
|
+
return try cast(argument, toType: argumentType)
|
|
75
40
|
} catch {
|
|
76
41
|
throw ArgumentCastException((index: index, type: argumentType)).causedBy(error)
|
|
77
42
|
}
|
|
78
43
|
}
|
|
79
44
|
}
|
|
80
45
|
|
|
46
|
+
/**
|
|
47
|
+
Prepends the owner to the array of arguments if the given function can take it.
|
|
48
|
+
*/
|
|
49
|
+
internal func concat(arguments: [Any], withOwner owner: AnyObject?, forFunction function: AnyFunction) -> [Any] {
|
|
50
|
+
if function.takesOwner, let owner = try? function.dynamicArgumentTypes.first?.cast(owner) {
|
|
51
|
+
return [owner] + arguments
|
|
52
|
+
}
|
|
53
|
+
return arguments
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// MARK: - Exceptions
|
|
57
|
+
|
|
81
58
|
internal class InvalidArgsNumberException: GenericException<(received: Int, expected: Int)> {
|
|
82
59
|
override var reason: String {
|
|
83
60
|
"Received \(param.received) arguments, but \(param.expected) was expected"
|
|
84
61
|
}
|
|
85
62
|
}
|
|
86
63
|
|
|
87
|
-
internal class ArgumentCastException: GenericException<(index: Int, type:
|
|
64
|
+
internal class ArgumentCastException: GenericException<(index: Int, type: AnyDynamicType)> {
|
|
88
65
|
override var reason: String {
|
|
89
66
|
"Argument at index '\(param.index)' couldn't be cast to type \(param.type.description)"
|
|
90
67
|
}
|
|
91
68
|
}
|
|
92
69
|
|
|
93
|
-
// MARK: - Exceptions
|
|
94
|
-
|
|
95
70
|
private class ModuleUnavailableException: GenericException<String> {
|
|
96
71
|
override var reason: String {
|
|
97
72
|
"Module '\(param)' is no longer available"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import os.log
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
The protocol that needs to be implemented by log handlers.
|
|
7
|
+
*/
|
|
8
|
+
internal protocol LogHandler {
|
|
9
|
+
init(category: String)
|
|
10
|
+
|
|
11
|
+
func log(type: LogType, _ message: String)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
The log handler that uses the new `os.Logger` API.
|
|
16
|
+
*/
|
|
17
|
+
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
|
18
|
+
internal class OSLogHandler: LogHandler {
|
|
19
|
+
private let osLogger: os.Logger
|
|
20
|
+
|
|
21
|
+
required init(category: String) {
|
|
22
|
+
osLogger = os.Logger(subsystem: "dev.expo.modules", category: category)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func log(type: LogType, _ message: String) {
|
|
26
|
+
osLogger.log(level: type.toOSLogType(), "\(message)")
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
Simple log handler that forwards all logs to `print` function.
|
|
32
|
+
*/
|
|
33
|
+
internal class PrintLogHandler: LogHandler {
|
|
34
|
+
required init(category: String) {}
|
|
35
|
+
|
|
36
|
+
func log(type: LogType, _ message: String) {
|
|
37
|
+
print(message)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import os.log
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
An enum with available log types.
|
|
7
|
+
*/
|
|
8
|
+
public enum LogType: Int {
|
|
9
|
+
case trace = 0
|
|
10
|
+
case timer = 1
|
|
11
|
+
case stacktrace = 2
|
|
12
|
+
case debug = 3
|
|
13
|
+
case info = 4
|
|
14
|
+
case warn = 5
|
|
15
|
+
case error = 6
|
|
16
|
+
case fatal = 7
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
The string that is used to prefix the messages of this log type.
|
|
20
|
+
Logs in Xcode and Console apps are always with the white text,
|
|
21
|
+
so we use colored circle emojis to distinguish different types of logs.
|
|
22
|
+
*/
|
|
23
|
+
var prefix: String {
|
|
24
|
+
switch self {
|
|
25
|
+
case .trace:
|
|
26
|
+
return "⚪️"
|
|
27
|
+
case .timer:
|
|
28
|
+
return "🟤"
|
|
29
|
+
case .stacktrace:
|
|
30
|
+
return "🟣"
|
|
31
|
+
case .debug:
|
|
32
|
+
return "🔵"
|
|
33
|
+
case .info:
|
|
34
|
+
return "🟢"
|
|
35
|
+
case .warn:
|
|
36
|
+
return "🟡"
|
|
37
|
+
case .error:
|
|
38
|
+
return "🟠"
|
|
39
|
+
case .fatal:
|
|
40
|
+
return "🔴"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
Maps the log types to the log types used by the `os.log` logger.
|
|
46
|
+
*/
|
|
47
|
+
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
|
48
|
+
func toOSLogType() -> OSLogType {
|
|
49
|
+
switch self {
|
|
50
|
+
case .trace, .timer, .stacktrace, .debug:
|
|
51
|
+
return .debug
|
|
52
|
+
case .info:
|
|
53
|
+
return .info
|
|
54
|
+
case .warn:
|
|
55
|
+
return .default
|
|
56
|
+
case .error:
|
|
57
|
+
return .error
|
|
58
|
+
case .fatal:
|
|
59
|
+
return .fault
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
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? String {
|
|
192
|
+
return value
|
|
193
|
+
}
|
|
194
|
+
if let value = value as? CustomDebugStringConvertible {
|
|
195
|
+
return value.debugDescription
|
|
196
|
+
}
|
|
197
|
+
if let value = value as? CustomStringConvertible {
|
|
198
|
+
return value.description
|
|
199
|
+
}
|
|
200
|
+
return String(describing: value)
|
|
201
|
+
}
|
|
@@ -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.
|
|
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],
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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(
|
|
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
|
|
106
|
-
|
|
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
|
|
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
|
-
|
|
134
|
+
definition.functions["startObserving"]?.call(withArguments: [])
|
|
170
135
|
} else if count < 0 && listenersCount + count <= 0 {
|
|
171
|
-
|
|
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]
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
40
|
+
AsyncFunction("myFunction") { (promise: Promise) in
|
|
41
41
|
DispatchQueue.main.async {
|
|
42
42
|
promise.resolve("return value obtained in async callback")
|
|
43
43
|
}
|
|
@@ -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
|
+
}
|