brick-module 0.1.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/BrickModule.podspec +56 -0
- package/android/brick_modules.gradle +280 -0
- package/android/build/generated/source/codegen/jni/CMakeLists.txt +14 -0
- package/android/build.gradle +144 -0
- package/android/gradle.properties +5 -0
- package/android/react-native-helpers.gradle +42 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/brickmodule/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/brickmodule/BrickModuleBase.kt +23 -0
- package/android/src/main/java/com/brickmodule/BrickModulePackage.kt +87 -0
- package/android/src/main/java/com/brickmodule/BrickModuleRegistry.kt +224 -0
- package/android/src/main/resources/META-INF/gradle-plugins/com.brickmodule.properties +1 -0
- package/bin/brick-codegen.js +8 -0
- package/dist/BrickModule.d.ts +64 -0
- package/dist/BrickModule.js +91 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +18 -0
- package/ios/BrickModule/Internal/BrickCoreModule.swift +51 -0
- package/ios/BrickModule/Internal/BrickModuleRegistry.swift +138 -0
- package/ios/BrickModule/Public/BrickModule-Swift.h +339 -0
- package/package.json +75 -0
- package/podfile_helper.rb +176 -0
- package/src/BrickModule.ts +175 -0
- package/src/index.ts +37 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
package com.brickmodule
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Central registry for all Brick modules Manages module lifecycle and provides simple module
|
|
9
|
+
* storage
|
|
10
|
+
*/
|
|
11
|
+
object BrickModuleRegistry {
|
|
12
|
+
private val modules: MutableMap<String, Any> = mutableMapOf()
|
|
13
|
+
private var isRegistered: Boolean = false
|
|
14
|
+
private var reactContext: ReactApplicationContext? = null
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Registers an array of Brick modules Each module must implement their respective TypeModule
|
|
18
|
+
* interface This should be called once during app initialization
|
|
19
|
+
*/
|
|
20
|
+
fun register(modules: List<Any>) {
|
|
21
|
+
modules.forEach { module -> registerSingleModule(module) }
|
|
22
|
+
|
|
23
|
+
if (!isRegistered) {
|
|
24
|
+
isRegistered = true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
println("✅ BrickModuleRegistry: Successfully registered ${modules.size} modules (total: ${this.modules.size})")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Registers a single module (push-style registration)
|
|
32
|
+
* Useful for manual module registration or testing
|
|
33
|
+
*/
|
|
34
|
+
fun push(module: Any) {
|
|
35
|
+
registerSingleModule(module)
|
|
36
|
+
println("✅ BrickModuleRegistry: Module pushed successfully (total: ${this.modules.size})")
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private fun registerSingleModule(module: Any) {
|
|
40
|
+
// Use reflection to get moduleName
|
|
41
|
+
val moduleNameProperty =
|
|
42
|
+
try {
|
|
43
|
+
module.javaClass.getMethod("getModuleName").invoke(module) as? String
|
|
44
|
+
} catch (e: Exception) {
|
|
45
|
+
try {
|
|
46
|
+
module.javaClass
|
|
47
|
+
.getDeclaredField("moduleName")
|
|
48
|
+
.apply { isAccessible = true }
|
|
49
|
+
.get(module) as?
|
|
50
|
+
String
|
|
51
|
+
} catch (e: Exception) {
|
|
52
|
+
null
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
val moduleName =
|
|
57
|
+
moduleNameProperty
|
|
58
|
+
?: run {
|
|
59
|
+
println(
|
|
60
|
+
"❌ BrickModuleRegistry: Module has no accessible moduleName property"
|
|
61
|
+
)
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Validate module name
|
|
66
|
+
if (moduleName.isEmpty()) {
|
|
67
|
+
println("❌ BrickModuleRegistry: Module has empty moduleName")
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check for module name conflicts
|
|
72
|
+
if (modules.containsKey(moduleName)) {
|
|
73
|
+
println("⚠️ BrickModuleRegistry: Module '$moduleName' is already registered. Skipping.")
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Get version using reflection
|
|
78
|
+
val version =
|
|
79
|
+
try {
|
|
80
|
+
module.javaClass.getMethod("getVersion").invoke(module) as? String ?: "1.0.0"
|
|
81
|
+
} catch (e: Exception) {
|
|
82
|
+
try {
|
|
83
|
+
module.javaClass
|
|
84
|
+
.getDeclaredField("version")
|
|
85
|
+
.apply { isAccessible = true }
|
|
86
|
+
.get(module) as?
|
|
87
|
+
String
|
|
88
|
+
?: "1.0.0"
|
|
89
|
+
} catch (e: Exception) {
|
|
90
|
+
"1.0.0"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Register the module
|
|
95
|
+
modules[moduleName] = module
|
|
96
|
+
println("📦 BrickModuleRegistry: Registered module '$moduleName' (v$version)")
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Returns the actual module instance for reflection-based method calls Used by BrickModuleImpl
|
|
101
|
+
* for direct protocol casting
|
|
102
|
+
*/
|
|
103
|
+
fun getModuleInstance(moduleName: String): Any? {
|
|
104
|
+
return modules[moduleName]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Returns list of registered module names */
|
|
108
|
+
fun getRegisteredModules(): List<String> {
|
|
109
|
+
return modules.keys.toList().sorted()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Sets the React Native context for event emission This should be called during app
|
|
114
|
+
* initialization from the main BrickModule
|
|
115
|
+
*/
|
|
116
|
+
fun setReactContext(context: ReactApplicationContext) {
|
|
117
|
+
reactContext = context
|
|
118
|
+
println("📡 BrickModuleRegistry: React context connected for event emission")
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Sends an event to JavaScript Used by modules to emit events to JavaScript */
|
|
122
|
+
fun sendEvent(eventName: String, data: Any?) {
|
|
123
|
+
reactContext?.let { context ->
|
|
124
|
+
try {
|
|
125
|
+
// Convert data to React Native compatible format
|
|
126
|
+
val eventData =
|
|
127
|
+
when (data) {
|
|
128
|
+
is Map<*, *> -> {
|
|
129
|
+
val writableMap = Arguments.createMap()
|
|
130
|
+
data.forEach { (key, value) ->
|
|
131
|
+
when (value) {
|
|
132
|
+
is String -> writableMap.putString(key.toString(), value)
|
|
133
|
+
is Number ->
|
|
134
|
+
writableMap.putDouble(
|
|
135
|
+
key.toString(),
|
|
136
|
+
value.toDouble()
|
|
137
|
+
)
|
|
138
|
+
is Boolean -> writableMap.putBoolean(key.toString(), value)
|
|
139
|
+
is List<*> -> {
|
|
140
|
+
val writableArray = Arguments.createArray()
|
|
141
|
+
value.forEach { item ->
|
|
142
|
+
when (item) {
|
|
143
|
+
is String -> writableArray.pushString(item)
|
|
144
|
+
is Number ->
|
|
145
|
+
writableArray.pushDouble(
|
|
146
|
+
item.toDouble()
|
|
147
|
+
)
|
|
148
|
+
is Boolean -> writableArray.pushBoolean(item)
|
|
149
|
+
else ->
|
|
150
|
+
writableArray.pushString(
|
|
151
|
+
item.toString()
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
writableMap.putArray(key.toString(), writableArray)
|
|
156
|
+
}
|
|
157
|
+
null -> writableMap.putNull(key.toString())
|
|
158
|
+
else ->
|
|
159
|
+
writableMap.putString(
|
|
160
|
+
key.toString(),
|
|
161
|
+
value.toString()
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
writableMap
|
|
166
|
+
}
|
|
167
|
+
else -> data
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
171
|
+
.emit(eventName, eventData)
|
|
172
|
+
|
|
173
|
+
println("📡 BrickModuleRegistry: Event sent successfully: $eventName")
|
|
174
|
+
} catch (e: Exception) {
|
|
175
|
+
println("❌ BrickModuleRegistry: Failed to send event $eventName: ${e.message}")
|
|
176
|
+
e.printStackTrace()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
?: run {
|
|
180
|
+
println(
|
|
181
|
+
"⚠️ BrickModuleRegistry: No React context available for event: $eventName"
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Returns all constants from registered modules */
|
|
187
|
+
fun getAllConstants(): Map<String, Any> {
|
|
188
|
+
val allConstants = mutableMapOf<String, Any>()
|
|
189
|
+
|
|
190
|
+
modules.forEach { (moduleName, module) ->
|
|
191
|
+
// Use reflection to get constants from the module
|
|
192
|
+
val moduleConstants = mutableMapOf<String, Any>()
|
|
193
|
+
val moduleClass = module.javaClass
|
|
194
|
+
|
|
195
|
+
// Get all public fields that might be constants
|
|
196
|
+
moduleClass.declaredFields.forEach { field ->
|
|
197
|
+
try {
|
|
198
|
+
field.isAccessible = true
|
|
199
|
+
val fieldName = field.name
|
|
200
|
+
// Skip internal fields
|
|
201
|
+
if (!fieldName.startsWith("_") && !fieldName.contains("$")) {
|
|
202
|
+
val value = field.get(module)
|
|
203
|
+
if (value != null) {
|
|
204
|
+
moduleConstants[fieldName] = value
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} catch (e: Exception) {
|
|
208
|
+
// Ignore reflection errors
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
allConstants[moduleName] = moduleConstants
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return allConstants
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Clears all registered modules (for testing purposes only) */
|
|
219
|
+
fun clearRegistry() {
|
|
220
|
+
modules.clear()
|
|
221
|
+
isRegistered = false
|
|
222
|
+
println("🧹 BrickModuleRegistry: Registry cleared")
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
implementation-class=com.brickmodule.BrickModulePlugin
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { TurboModule } from "react-native";
|
|
2
|
+
|
|
3
|
+
//#region src/BrickModule.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base interface that all Brick module specs must extend
|
|
7
|
+
*/
|
|
8
|
+
interface BrickModuleInterface extends TurboModule {
|
|
9
|
+
readonly moduleName: string;
|
|
10
|
+
readonly supportedEvents?: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Type alias for module specifications
|
|
14
|
+
* Use this as the base interface when defining your module specs
|
|
15
|
+
* @example
|
|
16
|
+
* export interface MyModuleSpec extends BrickModuleSpec {
|
|
17
|
+
* readonly moduleName: "MyModule";
|
|
18
|
+
* readonly supportedEvents: ["eventA", "eventB"];
|
|
19
|
+
* myMethod(param: string): Promise<string>;
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
type BrickModuleSpec = BrickModuleInterface;
|
|
23
|
+
/**
|
|
24
|
+
* Enhanced typed module interface with event listeners
|
|
25
|
+
*/
|
|
26
|
+
type BrickModuleWithEvents<T extends BrickModuleInterface> = T & {
|
|
27
|
+
/**
|
|
28
|
+
* Adds a type-safe event listener for this module
|
|
29
|
+
* @param eventName - One of the supported events defined in the module spec
|
|
30
|
+
* @param listener - Callback function to handle the event
|
|
31
|
+
* @returns Unsubscription function to remove the listener
|
|
32
|
+
*/
|
|
33
|
+
addEventListener<TEvent = unknown>(eventName: T["supportedEvents"] extends readonly (infer U)[] ? U : never, listener: (event: TEvent) => void): () => void;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Gets a typed module instance by name with explicit type parameter
|
|
37
|
+
* @param moduleName - The exact name of the module as defined in its spec
|
|
38
|
+
* @returns Typed module interface with all methods, constants, and event listeners
|
|
39
|
+
*/
|
|
40
|
+
declare function get<T extends BrickModuleInterface>(moduleName: string): BrickModuleWithEvents<T>;
|
|
41
|
+
/**
|
|
42
|
+
* Gets list of all registered modules
|
|
43
|
+
* @returns Promise resolving to array of module names
|
|
44
|
+
*/
|
|
45
|
+
declare function getRegisteredModules(): string[];
|
|
46
|
+
/**
|
|
47
|
+
* Clears the module cache (useful for testing or hot reloading)
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
declare function clearCache(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Main Brick Module API object
|
|
53
|
+
* Provides type-safe access to native modules
|
|
54
|
+
*/
|
|
55
|
+
declare const BrickModule: {
|
|
56
|
+
readonly get: typeof get;
|
|
57
|
+
readonly getRegisteredModules: typeof getRegisteredModules;
|
|
58
|
+
readonly clearCache: typeof clearCache;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Default export for convenience
|
|
62
|
+
*/
|
|
63
|
+
//#endregion
|
|
64
|
+
export { BrickModule, BrickModuleInterface, BrickModuleSpec };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { NativeEventEmitter, TurboModuleRegistry } from "react-native";
|
|
2
|
+
|
|
3
|
+
//#region src/BrickModule.ts
|
|
4
|
+
const moduleCache = /* @__PURE__ */ new Map();
|
|
5
|
+
let nativeModule = null;
|
|
6
|
+
let eventEmitter = null;
|
|
7
|
+
/**
|
|
8
|
+
* Gets the native TurboModule instance
|
|
9
|
+
* @private
|
|
10
|
+
*/
|
|
11
|
+
function getNativeModule() {
|
|
12
|
+
if (!nativeModule) nativeModule = TurboModuleRegistry.getEnforcing("BrickModule");
|
|
13
|
+
return nativeModule;
|
|
14
|
+
}
|
|
15
|
+
function getEventEmitter() {
|
|
16
|
+
if (!eventEmitter) {
|
|
17
|
+
const nativeModuleInstance = getNativeModule();
|
|
18
|
+
eventEmitter = new NativeEventEmitter(nativeModuleInstance);
|
|
19
|
+
console.log("eventEmitter", eventEmitter);
|
|
20
|
+
}
|
|
21
|
+
return eventEmitter;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Gets a typed module instance by name with explicit type parameter
|
|
25
|
+
* @param moduleName - The exact name of the module as defined in its spec
|
|
26
|
+
* @returns Typed module interface with all methods, constants, and event listeners
|
|
27
|
+
*/
|
|
28
|
+
function get(moduleName) {
|
|
29
|
+
const cacheKey = moduleName;
|
|
30
|
+
if (moduleCache.has(cacheKey)) return moduleCache.get(cacheKey);
|
|
31
|
+
const nativeModuleInstance = getNativeModule();
|
|
32
|
+
const moduleProxy = new Proxy({}, {
|
|
33
|
+
get: (_target, property) => {
|
|
34
|
+
if (typeof property !== "string") return void 0;
|
|
35
|
+
if (property === "addEventListener") return (eventName, listener) => {
|
|
36
|
+
const emitter = getEventEmitter();
|
|
37
|
+
const subscription = emitter.addListener(`${moduleName}_${eventName}`, listener);
|
|
38
|
+
return () => {
|
|
39
|
+
subscription.remove();
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
const allConstants = nativeModuleInstance?.getConstants?.() ?? {};
|
|
43
|
+
const constantKey = `${moduleName}_${property}`;
|
|
44
|
+
if (constantKey in allConstants) return allConstants[constantKey];
|
|
45
|
+
return (...args) => {
|
|
46
|
+
const methodKey = `${moduleName}_${property}`;
|
|
47
|
+
if (typeof nativeModuleInstance[methodKey] === "function") return nativeModuleInstance[methodKey](...args);
|
|
48
|
+
throw new Error(`Method ${methodKey} not found`);
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
has: (_target, property) => {
|
|
52
|
+
return typeof property === "string";
|
|
53
|
+
},
|
|
54
|
+
ownKeys: (_target) => {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
moduleCache.set(cacheKey, moduleProxy);
|
|
59
|
+
return moduleProxy;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Gets list of all registered modules
|
|
63
|
+
* @returns Promise resolving to array of module names
|
|
64
|
+
*/
|
|
65
|
+
function getRegisteredModules() {
|
|
66
|
+
const nativeModuleInstance = getNativeModule();
|
|
67
|
+
return nativeModuleInstance?.getRegisteredModules() ?? [];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Clears the module cache (useful for testing or hot reloading)
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
function clearCache() {
|
|
74
|
+
moduleCache.clear();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Main Brick Module API object
|
|
78
|
+
* Provides type-safe access to native modules
|
|
79
|
+
*/
|
|
80
|
+
const BrickModule = {
|
|
81
|
+
get,
|
|
82
|
+
getRegisteredModules,
|
|
83
|
+
clearCache
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Default export for convenience
|
|
87
|
+
*/
|
|
88
|
+
var BrickModule_default = BrickModule;
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { BrickModule_default as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BrickModule, BrickModuleInterface, BrickModuleSpec } from "./BrickModule.js";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Error types for Brick modules
|
|
7
|
+
*/
|
|
8
|
+
declare class BrickModuleError extends Error {
|
|
9
|
+
code: string;
|
|
10
|
+
moduleName?: string | undefined;
|
|
11
|
+
methodName?: string | undefined;
|
|
12
|
+
constructor(message: string, code?: string, moduleName?: string | undefined, methodName?: string | undefined);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Configuration interface for brick-codegen
|
|
16
|
+
*/
|
|
17
|
+
interface BrickCodegenConfig {
|
|
18
|
+
outputIos?: string;
|
|
19
|
+
outputAndroid?: string;
|
|
20
|
+
cacheDir?: string;
|
|
21
|
+
incremental?: boolean;
|
|
22
|
+
watch?: boolean;
|
|
23
|
+
excludeModules?: string[];
|
|
24
|
+
typeCheck?: boolean;
|
|
25
|
+
verbose?: boolean;
|
|
26
|
+
newArchOnly?: boolean;
|
|
27
|
+
oldArchOnly?: boolean;
|
|
28
|
+
dev?: boolean;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { BrickCodegenConfig, BrickModule, BrickModuleError, BrickModuleInterface, BrickModuleSpec };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import BrickModule_default from "./BrickModule.js";
|
|
2
|
+
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* Error types for Brick modules
|
|
6
|
+
*/
|
|
7
|
+
var BrickModuleError = class extends Error {
|
|
8
|
+
constructor(message, code = "GRANITE_ERROR", moduleName, methodName) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.moduleName = moduleName;
|
|
12
|
+
this.methodName = methodName;
|
|
13
|
+
this.name = "BrickModuleError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { BrickModule_default as BrickModule, BrickModuleError };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal protocol that all Brick modules must implement
|
|
5
|
+
* Contains only essential properties for module identification
|
|
6
|
+
*/
|
|
7
|
+
public protocol BrickModuleBase {
|
|
8
|
+
/// The name of the module (required for registration)
|
|
9
|
+
var moduleName: String { get }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Error types for Brick modules
|
|
14
|
+
*/
|
|
15
|
+
public enum BrickModuleError: Error, LocalizedError {
|
|
16
|
+
case typeMismatch(String)
|
|
17
|
+
case executionError(String)
|
|
18
|
+
case invalidDefinition(String)
|
|
19
|
+
case methodNotFound(String)
|
|
20
|
+
case moduleNotFound(String)
|
|
21
|
+
|
|
22
|
+
public var errorDescription: String? {
|
|
23
|
+
switch self {
|
|
24
|
+
case .typeMismatch(let message):
|
|
25
|
+
return "Type mismatch: \(message)"
|
|
26
|
+
case .executionError(let message):
|
|
27
|
+
return "Execution error: \(message)"
|
|
28
|
+
case .invalidDefinition(let message):
|
|
29
|
+
return "Invalid definition: \(message)"
|
|
30
|
+
case .methodNotFound(let message):
|
|
31
|
+
return "Method not found: \(message)"
|
|
32
|
+
case .moduleNotFound(let message):
|
|
33
|
+
return "Module not found: \(message)"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public var errorCode: String {
|
|
38
|
+
switch self {
|
|
39
|
+
case .typeMismatch:
|
|
40
|
+
return "TYPE_ERROR"
|
|
41
|
+
case .executionError:
|
|
42
|
+
return "EXECUTION_ERROR"
|
|
43
|
+
case .invalidDefinition:
|
|
44
|
+
return "DEFINITION_ERROR"
|
|
45
|
+
case .methodNotFound:
|
|
46
|
+
return "METHOD_NOT_FOUND"
|
|
47
|
+
case .moduleNotFound:
|
|
48
|
+
return "MODULE_NOT_FOUND"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import React
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Central registry for all Brick modules
|
|
6
|
+
* Manages module lifecycle and provides simple module storage
|
|
7
|
+
*/
|
|
8
|
+
@objc public class BrickModuleRegistry: NSObject {
|
|
9
|
+
@objc public static let shared = BrickModuleRegistry()
|
|
10
|
+
|
|
11
|
+
private var modules: [String: Any] = [:]
|
|
12
|
+
private var isRegistered: Bool = false
|
|
13
|
+
private weak var eventEmitter: RCTEventEmitter?
|
|
14
|
+
|
|
15
|
+
private override init() {
|
|
16
|
+
super.init()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// MARK: - Module Registration
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Registers an array of Brick modules (Swift API)
|
|
23
|
+
* Each module must implement BrickModuleBase and its respective TypeModule protocol
|
|
24
|
+
* This should be called once during app initialization
|
|
25
|
+
*/
|
|
26
|
+
public func register(_ modules: [BrickModuleBase]) {
|
|
27
|
+
guard !isRegistered else {
|
|
28
|
+
print("⚠️ BrickModuleRegistry: Modules already registered. Skipping re-registration.")
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for module in modules {
|
|
33
|
+
registerSingleModule(module)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
isRegistered = true
|
|
37
|
+
print("✅ BrickModuleRegistry: Successfully registered \(self.modules.count) modules")
|
|
38
|
+
|
|
39
|
+
if ProcessInfo.processInfo.environment["GRANITE_DEBUG"] == "1" {
|
|
40
|
+
debugPrintRegisteredModules()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Registers an array of Brick modules (Objective-C API)
|
|
46
|
+
* Each module must implement BrickModuleBase protocol
|
|
47
|
+
* This should be called once during app initialization
|
|
48
|
+
*/
|
|
49
|
+
@objc(registerModules:)
|
|
50
|
+
public func registerModules(_ modules: NSArray) {
|
|
51
|
+
let brickModules = modules.compactMap { $0 as? BrickModuleBase }
|
|
52
|
+
register(brickModules)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private func registerSingleModule(_ module: BrickModuleBase) {
|
|
56
|
+
let moduleName = module.moduleName
|
|
57
|
+
|
|
58
|
+
// Validate module name
|
|
59
|
+
guard !moduleName.isEmpty else {
|
|
60
|
+
print("❌ BrickModuleRegistry: Module has empty moduleName")
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check for module name conflicts
|
|
65
|
+
if modules.keys.contains(moduleName) {
|
|
66
|
+
print("⚠️ BrickModuleRegistry: Module '\(moduleName)' is already registered. Skipping.")
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Register the module
|
|
71
|
+
modules[moduleName] = module
|
|
72
|
+
print("📦 BrickModuleRegistry: Registered module '\(moduleName)'")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// MARK: - Module Information
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Returns the actual module instance for reflection-based method calls
|
|
79
|
+
* Used by BrickModuleImpl for direct protocol casting
|
|
80
|
+
*/
|
|
81
|
+
public func getModuleInstance(_ moduleName: String) -> Any? {
|
|
82
|
+
return modules[moduleName]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns list of registered module names
|
|
87
|
+
*/
|
|
88
|
+
@objc public func getRegisteredModules() -> [String] {
|
|
89
|
+
return Array(modules.keys).sorted()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// MARK: - Event Emitter Management
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Sets the React Native event emitter instance for event emission
|
|
96
|
+
* This should be called during app initialization from the main BrickModule
|
|
97
|
+
*/
|
|
98
|
+
@objc public func setEventEmitter(_ eventEmitter: RCTEventEmitter) {
|
|
99
|
+
self.eventEmitter = eventEmitter
|
|
100
|
+
print("📡 BrickModuleRegistry: Event emitter connected for event emission")
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns the React Native event emitter instance for event emission
|
|
105
|
+
* Used by generated module code to emit events to JavaScript
|
|
106
|
+
*/
|
|
107
|
+
@objc public func getEventEmitter() -> RCTEventEmitter? {
|
|
108
|
+
return eventEmitter
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// MARK: - Debug & Development
|
|
112
|
+
|
|
113
|
+
private func debugPrintRegisteredModules() {
|
|
114
|
+
print("🔍 BrickModuleRegistry Debug Info:")
|
|
115
|
+
print(" Total Modules: \(modules.count)")
|
|
116
|
+
|
|
117
|
+
for (moduleName, module) in modules.sorted(by: { $0.key < $1.key }) {
|
|
118
|
+
let moduleType = String(describing: type(of: module))
|
|
119
|
+
print(" 📦 \(moduleName) (\(moduleType))")
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Clears all registered modules (for testing purposes only)
|
|
125
|
+
*/
|
|
126
|
+
@objc public func clearRegistry() {
|
|
127
|
+
guard ProcessInfo.processInfo.environment["NODE_ENV"] == "test" ||
|
|
128
|
+
ProcessInfo.processInfo.environment["GRANITE_ALLOW_CLEAR"] == "1" else {
|
|
129
|
+
print("⚠️ BrickModuleRegistry: clearRegistry() is only allowed in test environment")
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
modules.removeAll()
|
|
134
|
+
isRegistered = false
|
|
135
|
+
|
|
136
|
+
print("🧹 BrickModuleRegistry: Registry cleared")
|
|
137
|
+
}
|
|
138
|
+
}
|