brick-module 0.1.5 → 0.1.7

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.
@@ -25,6 +25,9 @@ Pod::Spec.new do |s|
25
25
  base_config = {
26
26
  "DEFINES_MODULE" => "YES",
27
27
  "SWIFT_VERSION" => "5.0",
28
+ "SWIFT_COMPILATION_MODE" => "wholemodule",
29
+ "SWIFT_INSTALL_OBJC_HEADER" => "YES",
30
+ "SWIFT_OBJC_INTERFACE_HEADER_NAME" => "BrickModule-Swift.h",
28
31
  "OTHER_SWIFT_FLAGS" => "-enable-experimental-feature AccessLevelOnImport"
29
32
  }
30
33
 
@@ -36,22 +39,17 @@ Pod::Spec.new do |s|
36
39
  else
37
40
  s.dependency "React-Core"
38
41
 
39
- # Don't install the dependencies when we run `pod install` in the old architecture.
40
- if ENV["RCT_NEW_ARCH_ENABLED"] == "1" then
41
42
  s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
42
43
  s.pod_target_xcconfig = base_config.merge({
43
44
  "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
44
45
  "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
45
46
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
46
47
  })
47
- s.dependency 'React'
48
+
48
49
  s.dependency "React-Codegen"
49
50
  s.dependency "RCT-Folly"
50
51
  s.dependency "RCTRequired"
51
52
  s.dependency "RCTTypeSafety"
52
53
  s.dependency "ReactCommon/turbomodule/core"
53
- else
54
- s.pod_target_xcconfig = base_config
55
- end
56
- end
57
- end
54
+ end
55
+ end
@@ -43,6 +43,89 @@ ext.readPackageJson = { File packageJsonFile ->
43
43
  }
44
44
  }
45
45
 
46
+ ext.findBrickJson = { startDir ->
47
+ // Walk up the directory tree looking for brick.json
48
+ if (!startDir) {
49
+ return null
50
+ }
51
+
52
+ try {
53
+ // startDir can be either a File or String, handle both
54
+ def current = startDir instanceof File ? startDir.canonicalFile : new File(startDir).canonicalFile
55
+ def root = new File('/').canonicalFile
56
+
57
+ while (current != root && current != null) {
58
+ def brickJsonFile = new File(current, 'brick.json')
59
+ if (brickJsonFile.exists()) {
60
+ return brickJsonFile
61
+ }
62
+ def parent = current.parentFile
63
+ if (parent == current || parent == null) break // Reached filesystem root
64
+ current = parent
65
+ }
66
+ } catch (Exception e) {
67
+ // Failed to process directory, return null
68
+ }
69
+
70
+ return null
71
+ }
72
+
73
+ ext.resolveProjectRoot = { projectRootPath, configDir ->
74
+ // Handle both absolute and relative paths
75
+ if (!projectRootPath || !configDir) {
76
+ return null
77
+ }
78
+
79
+ try {
80
+ def projectRootFile = new File(projectRootPath)
81
+ if (projectRootFile.isAbsolute()) {
82
+ return projectRootFile.exists() ? projectRootFile : null
83
+ } else {
84
+ // Relative to brick.json location
85
+ def resolvedFile = new File(configDir, projectRootPath).canonicalFile
86
+ return resolvedFile.exists() ? resolvedFile : null
87
+ }
88
+ } catch (Exception e) {
89
+ return null
90
+ }
91
+ }
92
+
93
+ ext.getBrickAndroidPath = { searchRoot ->
94
+ // Walk up directory tree to find brick.json
95
+ def brickConfigFile = findBrickJson(searchRoot)
96
+
97
+ if (brickConfigFile && brickConfigFile.exists()) {
98
+ try {
99
+ def config = new JsonSlurper().parse(brickConfigFile)
100
+
101
+ // Get the effective project root
102
+ def effectiveRoot = brickConfigFile.parentFile
103
+ if (config.projectRoot) {
104
+ def resolvedRoot = resolveProjectRoot(config.projectRoot, brickConfigFile.parentFile)
105
+ if (resolvedRoot) {
106
+ effectiveRoot = resolvedRoot
107
+ }
108
+ }
109
+
110
+ def androidPath = config?.output?.android
111
+ if (androidPath && !androidPath.isEmpty()) {
112
+ // Handle absolute paths (though not recommended)
113
+ if (new File(androidPath).isAbsolute()) {
114
+ println("[Brick] Warning: Using absolute path for Android output is not recommended: ${androidPath}")
115
+ return androidPath
116
+ }
117
+ // Otherwise, treat as relative to effective project root
118
+ return new File(effectiveRoot, androidPath).canonicalPath
119
+ }
120
+ } catch (Exception e) {
121
+ println("[Brick] Warning: Failed to parse brick.json: ${e.message}")
122
+ }
123
+ }
124
+
125
+ // Default: .brick directory in the Android project root
126
+ return new File(searchRoot, '.brick').canonicalPath
127
+ }
128
+
46
129
  ext.getAllDependencies = { packageJson ->
47
130
  def deps = []
48
131
  deps.addAll(packageJson.dependencies?.keySet() ?: [])
@@ -54,6 +137,44 @@ ext.isBrickModule = { packageJson ->
54
137
  return packageJson?.brickModule != null
55
138
  }
56
139
 
140
+ ext.findProjectRoot = { androidDir ->
141
+ // 1. Walk up directory tree to find brick.json
142
+ def brickConfigFile = findBrickJson(androidDir)
143
+ if (brickConfigFile) {
144
+ brickLog("Found brick.json at: ${brickConfigFile.canonicalPath}")
145
+ try {
146
+ def config = new JsonSlurper().parse(brickConfigFile)
147
+ if (config.projectRoot) {
148
+ def projectRoot = resolveProjectRoot(config.projectRoot, brickConfigFile.parentFile)
149
+ if (projectRoot) {
150
+ brickLog("Using projectRoot from brick.json: ${projectRoot.canonicalPath}")
151
+ return projectRoot
152
+ }
153
+ }
154
+ // If brick.json exists but has no projectRoot, use its directory as project root
155
+ return brickConfigFile.parentFile
156
+ } catch (Exception e) {
157
+ println("[Brick] Warning: Failed to parse brick.json: ${e.message}")
158
+ }
159
+ }
160
+
161
+ // 2. Walk up to find package.json with node_modules
162
+ def current = androidDir
163
+ while (current != null && current != new File('/')) {
164
+ if (new File(current, 'package.json').exists() && new File(current, 'node_modules').exists()) {
165
+ brickLog("Found project root via package.json: ${current.canonicalPath}")
166
+ return current
167
+ }
168
+ def parent = current.parentFile
169
+ if (parent == current) break
170
+ current = parent
171
+ }
172
+
173
+ // If no project root found, use default fallback
174
+ brickLog("Warning: Failed to find project root via brick.json or package.json. Using default: ${androidDir.parentFile.canonicalPath}")
175
+ return androidDir.parentFile
176
+ }
177
+
57
178
  ext.runBrickCodegen = { workingDir ->
58
179
  def brickModuleDir = resolveModule(workingDir, "brick-module")
59
180
  if (brickModuleDir == null) {
@@ -82,7 +203,7 @@ ext.runBrickCodegen = { workingDir ->
82
203
  // =============================================================================
83
204
 
84
205
  ext.applyBrickModules = { settings ->
85
- def projectRoot = settings.rootDir.parentFile
206
+ def projectRoot = findProjectRoot(settings.rootDir)
86
207
  def foundModules = []
87
208
  def brickModulesData = [:]
88
209
 
@@ -144,15 +265,16 @@ ext.applyBrickModules = { settings ->
144
265
  }
145
266
  }
146
267
 
147
- // Check if codegen is needed
148
- def brickDir = new File(settings.rootDir, ".brick")
268
+ // Check if codegen is needed (use configured path)
269
+ def androidBrickPath = getBrickAndroidPath(settings.rootDir)
270
+ def brickDir = new File(androidBrickPath)
149
271
  def needsCodegen = !brickDir.exists() || !new File(brickDir, "src/main/kotlin/BrickModule.kt").exists()
150
272
 
151
273
  if (needsCodegen) {
152
274
  runBrickCodegen(projectRoot)
153
275
  }
154
276
 
155
- // Include generated module
277
+ // Include generated module (use configured path)
156
278
  if (brickDir.exists()) {
157
279
  settings.include(":brick-codegen")
158
280
  settings.project(":brick-codegen").projectDir = brickDir
@@ -65,7 +65,6 @@ android {
65
65
  defaultConfig {
66
66
  minSdkVersion getExtOrIntegerDefault("minSdkVersion")
67
67
  targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
68
- buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
69
68
  consumerProguardFiles 'proguard-rules.pro'
70
69
  buildConfigField "long", "BUILD_TIMESTAMP", "${System.currentTimeMillis()}L"
71
70
  }
@@ -39,8 +39,7 @@ class BrickModulePackage : TurboReactPackage() {
39
39
  val currentClassLoader = Thread.currentThread().contextClassLoader
40
40
  val generatedClass =
41
41
  Class.forName("com.brickmodule.BrickModule", true, currentClassLoader)
42
- val constructor =
43
- generatedClass.getConstructor(ReactContext::class.java)
42
+ val constructor = generatedClass.getConstructor(ReactContext::class.java)
44
43
  val instance = constructor.newInstance(reactContext) as NativeModule
45
44
  println(
46
45
  "✅ BrickModule successfully created with thread classloader: ${instance.javaClass.name}"
@@ -68,7 +67,7 @@ class BrickModulePackage : TurboReactPackage() {
68
67
  println("🔍 BrickModulePackage.getReactModuleInfoProvider called")
69
68
  val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
70
69
  // Force TurboModule to true since we're using NativeBrickModuleSpec
71
- val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
70
+ val isTurboModule: Boolean = true
72
71
  moduleInfos["BrickModule"] =
73
72
  ReactModuleInfo(
74
73
  "BrickModule",
@@ -82,6 +82,10 @@ const BrickModule = {
82
82
  getRegisteredModules,
83
83
  clearCache
84
84
  };
85
+ /**
86
+ * Default export for convenience
87
+ */
88
+ var BrickModule_default = BrickModule;
85
89
 
86
90
  //#endregion
87
- export { BrickModule as default };
91
+ export { BrickModule_default as default };
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import BrickModule from "./BrickModule.js";
1
+ import BrickModule_default from "./BrickModule.js";
2
2
 
3
3
  //#region src/index.ts
4
4
  /**
5
5
  * Error types for Brick modules
6
6
  */
7
7
  var BrickModuleError = class extends Error {
8
- constructor(message, code = "GRANITE_ERROR", moduleName, methodName) {
8
+ constructor(message, code = "BRICK_ERROR", moduleName, methodName) {
9
9
  super(message);
10
10
  this.code = code;
11
11
  this.moduleName = moduleName;
@@ -15,4 +15,4 @@ var BrickModuleError = class extends Error {
15
15
  };
16
16
 
17
17
  //#endregion
18
- export { BrickModule, BrickModuleError };
18
+ export { BrickModule_default as BrickModule, BrickModuleError };
@@ -1,18 +1,39 @@
1
1
  import Foundation
2
+ import React
2
3
 
3
- @objc public protocol BrickModuleRegistableViewControllerType {
4
- @objc var moduleRegistry: BrickModuleRegistry? { get }
5
- }
6
4
  /**
7
- * Minimal protocol that all Brick modules must implement
8
- * Contains only essential properties for module identification
5
+ * Base class for all Brick modules
6
+ * Provides common functionality including event emission
9
7
  */
10
- public protocol BrickModuleBase {
8
+ open class BrickModuleBase: NSObject {
11
9
  /// The name of the module (required for registration)
12
- var moduleName: String { get }
13
- var controller: BrickModuleRegistableViewControllerType { get set }
10
+ public let moduleName: String
11
+
12
+ public weak var eventEmitter: RCTEventEmitter?
13
+ public weak var bridgeProxy: RCTBridgeProxy?
14
+
15
+ /// Initialize with module name
16
+ public init(moduleName: String) {
17
+ self.moduleName = moduleName
18
+ super.init()
19
+ }
14
20
 
15
- init (controller: BrickModuleRegistableViewControllerType)
21
+ /// Sends an event with the given name and data
22
+ /// Automatically prefixes with module name and uses the registry's event emitter
23
+ public func sendEvent(_ eventName: String, data: [String: Any]?) {
24
+ // Format event name with module prefix
25
+ let fullEventName = "\(moduleName)_\(eventName)"
26
+
27
+ // Get the shared event emitter instance and send event
28
+ if let eventEmitter = self.eventEmitter {
29
+ eventEmitter.sendEvent(withName: fullEventName, body: data)
30
+ } else {
31
+ let error = NSError(domain: "BrickModule", code: 500, userInfo: [
32
+ NSLocalizedDescriptionKey: "Event emitter not available, cannot send event: \(fullEventName)"
33
+ ])
34
+ print("Error: \(error.localizedDescription)")
35
+ }
36
+ }
16
37
  }
17
38
 
18
39
  /**
@@ -0,0 +1,26 @@
1
+ //
2
+ // BrickModuleRegistrable.swift
3
+ // BrickModule
4
+ //
5
+ // Protocol for BrickModule registration - Swift-style naming convention
6
+ //
7
+
8
+ import UIKit
9
+ import React
10
+
11
+ /// Protocol for BrickModule registration and management
12
+ /// This matches Android's BrickModuleRegistrar interface with Swift naming conventions
13
+ public protocol BrickModuleRegistrable {
14
+
15
+ // MARK: - Module Registry Management
16
+
17
+ /// Module registry - property instead of getter method
18
+ /// This registry manages all registered BrickModules
19
+ var moduleRegistry: BrickModuleRegistry { get }
20
+
21
+ /// Register modules when bridge is ready - using 'on' parameter label
22
+ /// Called after didInitializeBridge to register BrickModules
23
+ func registerModules()
24
+
25
+
26
+ }
@@ -0,0 +1,5 @@
1
+ import UIKit
2
+
3
+ public protocol BrickModuleRegistrableViewController: AnyObject {
4
+ var moduleRegistry: BrickModuleRegistry { get }
5
+ }
@@ -1,15 +1,17 @@
1
1
  import Foundation
2
2
  import React
3
3
 
4
+
4
5
  /**
5
6
  * Central registry for all Brick modules
6
7
  * Manages module lifecycle and provides simple module storage
7
8
  */
8
9
  @objc public class BrickModuleRegistry: NSObject {
9
10
 
10
- private var modules: [String: Any] = [:]
11
+ private var modules: [String: BrickModuleBase] = [:]
11
12
  private var isRegistered: Bool = false
12
- public weak var eventEmitter: RCTEventEmitter?
13
+ private weak var eventEmitter: RCTEventEmitter?
14
+ private weak var bridgeProxy: RCTBridgeProxy?;
13
15
 
14
16
  public override init() {
15
17
  super.init()
@@ -23,9 +25,8 @@ import React
23
25
  * This should be called once during app initialization
24
26
  */
25
27
  public func register(_ modules: [BrickModuleBase]) {
26
- guard !isRegistered else {
27
- print("⚠️ BrickModuleRegistry: Modules already registered. Skipping re-registration.")
28
- return
28
+ if isRegistered {
29
+ print("♻️ BrickModuleRegistry: Re-registering modules. Existing modules may be overwritten.")
29
30
  }
30
31
 
31
32
  for module in modules {
@@ -34,10 +35,6 @@ import React
34
35
 
35
36
  isRegistered = true
36
37
  print("✅ BrickModuleRegistry: Successfully registered \(self.modules.count) modules")
37
-
38
- if ProcessInfo.processInfo.environment["GRANITE_DEBUG"] == "1" {
39
- debugPrintRegisteredModules()
40
- }
41
38
  }
42
39
 
43
40
  /**
@@ -49,7 +46,7 @@ import React
49
46
  public func registerModules(_ modules: NSArray) {
50
47
  let brickModules = modules.compactMap { $0 as? BrickModuleBase }
51
48
  register(brickModules)
52
- }
49
+ }
53
50
 
54
51
  private func registerSingleModule(_ module: BrickModuleBase) {
55
52
  let moduleName = module.moduleName
@@ -60,14 +57,10 @@ import React
60
57
  return
61
58
  }
62
59
 
63
- // Check for module name conflicts
64
- if modules.keys.contains(moduleName) {
65
- print("⚠️ BrickModuleRegistry: Module '\(moduleName)' is already registered. Skipping.")
66
- return
67
- }
68
-
69
60
  // Register the module
70
61
  modules[moduleName] = module
62
+ modules[moduleName]?.eventEmitter = self.eventEmitter;
63
+ modules[moduleName]?.bridgeProxy = self.bridgeProxy;
71
64
  print("📦 BrickModuleRegistry: Registered module '\(moduleName)'")
72
65
  }
73
66
 
@@ -81,6 +74,14 @@ import React
81
74
  return modules[moduleName]
82
75
  }
83
76
 
77
+
78
+ public func setBridge(_ bridge: Any) {
79
+ self.bridgeProxy = bridge as? RCTBridgeProxy;
80
+ for module in modules {
81
+ module.value.bridgeProxy = self.bridgeProxy;
82
+ }
83
+ }
84
+
84
85
  /**
85
86
  * Returns list of registered module names
86
87
  */
@@ -92,11 +93,13 @@ import React
92
93
 
93
94
  /**
94
95
  * Sets the React Native event emitter instance for event emission
95
- * This should be called during app initialization from the main BrickModule
96
+ * This should be called during app initialization frBrickModuleom the main BrickModule
96
97
  */
97
- @objc public func setEventEmitter(_ eventEmitter: RCTEventEmitter) {
98
- self.eventEmitter = eventEmitter
99
- print("📡 BrickModuleRegistry: Event emitter connected for event emission")
98
+ public func setEventEmitter(_ eventEmitter: Any) {
99
+ self.eventEmitter = eventEmitter as? RCTEventEmitter
100
+ for module in modules {
101
+ module.value.eventEmitter = self.eventEmitter
102
+ }
100
103
  }
101
104
 
102
105
  /**
@@ -106,36 +109,24 @@ import React
106
109
  @objc public func getEventEmitter() -> RCTEventEmitter? {
107
110
  return eventEmitter
108
111
  }
109
-
110
- // MARK: - Debug & Development
111
-
112
- private func debugPrintRegisteredModules() {
113
- print("🔍 BrickModuleRegistry Debug Info:")
114
- print(" Total Modules: \(modules.count)")
115
112
 
116
- for (moduleName, module) in modules.sorted(by: { $0.key < $1.key }) {
117
- let moduleType = String(describing: type(of: module))
118
- print(" 📦 \(moduleName) (\(moduleType))")
119
- }
113
+ /**
114
+ * Unregisters all modules and clears their registry references
115
+ */
116
+ @objc public func unregister() {
117
+ modules.removeAll()
118
+ isRegistered = false
120
119
  }
121
120
 
122
121
  /**
123
122
  * Clears all registered modules (for testing purposes only)
124
123
  */
125
124
  @objc public func clearRegistry() {
126
- guard ProcessInfo.processInfo.environment["NODE_ENV"] == "test" ||
127
- ProcessInfo.processInfo.environment["GRANITE_ALLOW_CLEAR"] == "1" else {
128
- print("⚠️ BrickModuleRegistry: clearRegistry() is only allowed in test environment")
129
- return
130
- }
131
-
132
- modules.removeAll()
133
- isRegistered = false
134
-
135
- print("🧹 BrickModuleRegistry: Registry cleared")
125
+ unregister()
136
126
  }
137
127
  }
138
128
 
139
129
  public class ModuleRegistry {
140
130
 
141
131
  }
132
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brick-module",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Better React Native native module development",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,8 +16,19 @@
16
16
  },
17
17
  "files": [
18
18
  "dist/",
19
- "ios/",
20
- "android/",
19
+ "ios",
20
+ "android",
21
+ "react-native.config.js",
22
+ "!ios/build",
23
+ "!android/build",
24
+ "!android/gradle",
25
+ "!android/gradlew",
26
+ "!android/gradlew.bat",
27
+ "!android/local.properties",
28
+ "!**/__tests__",
29
+ "!**/__fixtures__",
30
+ "!**/__mocks__",
31
+ "!**/.*",
21
32
  "src/",
22
33
  "bin/",
23
34
  "BrickModule.podspec",
@@ -51,7 +62,7 @@
51
62
  "brick-codegen": "./bin/brick-codegen.js"
52
63
  },
53
64
  "dependencies": {
54
- "brick-codegen": "0.1.5"
65
+ "brick-codegen": "0.1.7"
55
66
  },
56
67
  "peerDependencies": {
57
68
  "react": ">=18.2.0",
package/podfile_helper.rb CHANGED
@@ -6,14 +6,82 @@
6
6
  require 'json'
7
7
  require 'pathname'
8
8
 
9
+ def find_brick_json(start_dir)
10
+ # Walk up the directory tree looking for brick.json
11
+ current = File.expand_path(start_dir)
12
+ root = File.expand_path('/')
13
+
14
+ while current != root
15
+ brick_json_path = File.join(current, 'brick.json')
16
+ if File.exist?(brick_json_path)
17
+ return brick_json_path
18
+ end
19
+ parent = File.dirname(current)
20
+ break if parent == current # Reached filesystem root
21
+ current = parent
22
+ end
23
+
24
+ return nil
25
+ end
26
+
27
+ def find_project_root
28
+ ios_root = Pod::Config.instance.installation_root
29
+
30
+ # 1. Walk up directory tree to find brick.json
31
+ brick_json_path = find_brick_json(ios_root)
32
+ if brick_json_path
33
+ Pod::UI.puts "[Brick] Found brick.json at: #{brick_json_path}"
34
+ begin
35
+ config = JSON.parse(File.read(brick_json_path))
36
+ if config['projectRoot']
37
+ project_root = resolve_project_root(config['projectRoot'], File.dirname(brick_json_path))
38
+ if project_root
39
+ Pod::UI.puts "[Brick] Using projectRoot from brick.json: #{project_root}"
40
+ return project_root
41
+ end
42
+ end
43
+ # If brick.json exists but has no projectRoot, use its directory as project root
44
+ return File.dirname(brick_json_path)
45
+ rescue => e
46
+ Pod::UI.warn "[Brick] Failed to parse brick.json: #{e.message}"
47
+ end
48
+ end
49
+
50
+ # 2. Walk up to find package.json with node_modules
51
+ current = ios_root
52
+ while current != '/'
53
+ if File.exist?(File.join(current, 'package.json')) && File.exist?(File.join(current, 'node_modules'))
54
+ Pod::UI.puts "[Brick] Found project root via package.json: #{current}"
55
+ return current
56
+ end
57
+ parent = File.dirname(current)
58
+ break if parent == current
59
+ current = parent
60
+ end
61
+
62
+ # If no project root found, use default fallback
63
+ default_root = File.expand_path(File.join(ios_root, '..'))
64
+ Pod::UI.warn "[Brick] Warning: Failed to find project root via brick.json or package.json. Using default: #{default_root}"
65
+ return default_root
66
+ end
67
+
68
+ def resolve_project_root(project_root_path, config_dir)
69
+ # Handle both absolute and relative paths
70
+ if Pathname.new(project_root_path).absolute?
71
+ return project_root_path if File.exist?(project_root_path)
72
+ else
73
+ # Relative to brick.json location
74
+ resolved_path = File.expand_path(File.join(config_dir, project_root_path))
75
+ return resolved_path if File.exist?(resolved_path)
76
+ end
77
+ return nil
78
+ end
79
+
9
80
  def use_brick_modules!
10
- brick_root = "#{Pod::Config.instance.installation_root}/.."
81
+ brick_root = find_project_root
11
82
  discovered_modules = []
12
83
 
13
84
  begin
14
- # Discover Brick modules before running codegen
15
- discovered_modules = discover_brick_modules(brick_root)
16
-
17
85
  # Run brick-codegen with real-time output and colors (iOS only)
18
86
  exit_status = system("cd #{brick_root} && FORCE_COLOR=1 npx brick-codegen --platform ios")
19
87
 
@@ -21,9 +89,18 @@ def use_brick_modules!
21
89
  # Generate BrickModuleProvider.swift for auto-registration
22
90
  generate_brick_module_provider(brick_root, discovered_modules)
23
91
 
92
+ # Get iOS output path from brick.json if it exists
93
+ ios_brick_path = get_brick_ios_path(brick_root)
94
+
95
+ # Handle relative vs absolute paths
96
+ if Pathname.new(ios_brick_path).absolute?
97
+ brick_codegen_pod_path = ios_brick_path
98
+ else
99
+ brick_codegen_pod_path = File.expand_path(File.join(brick_root, ios_brick_path))
100
+ end
101
+
24
102
  # Add generated BrickCodegen pod if it exists
25
- brick_codegen_podspec_path = "#{brick_root}/ios/.brick/BrickCodegen.podspec"
26
- brick_codegen_pod_path = "#{brick_root}/ios/.brick"
103
+ brick_codegen_podspec_path = File.join(brick_codegen_pod_path, "BrickCodegen.podspec")
27
104
 
28
105
  if File.exist?(brick_codegen_podspec_path)
29
106
  begin
@@ -98,11 +175,48 @@ def discover_brick_modules(project_root)
98
175
  modules
99
176
  end
100
177
 
178
+ def get_brick_ios_path(project_root)
179
+ # Walk up from project_root to find brick.json
180
+ brick_config_path = find_brick_json(project_root)
181
+
182
+ if brick_config_path && File.exist?(brick_config_path)
183
+ begin
184
+ config = JSON.parse(File.read(brick_config_path))
185
+
186
+ ios_path = config.dig('output', 'ios')
187
+ if ios_path && !ios_path.empty?
188
+ # Handle absolute paths (though not recommended)
189
+ if Pathname.new(ios_path).absolute?
190
+ Pod::UI.warn "[Brick] Using absolute path for iOS output is not recommended: #{ios_path}"
191
+ return ios_path
192
+ else
193
+ # Relative to brick.json location, not project root
194
+ return File.expand_path(File.join(File.dirname(brick_config_path), ios_path))
195
+ end
196
+ end
197
+ rescue => e
198
+ Pod::UI.warn "[Brick] Failed to parse brick.json: #{e.message}"
199
+ end
200
+ end
201
+
202
+ # Return default path - just the relative path, caller will resolve it
203
+ return 'ios/.brick'
204
+ end
205
+
101
206
  def generate_brick_module_provider(project_root, modules)
102
207
  return if modules.empty?
103
208
 
104
- # Create the .brick directory if it doesn't exist
105
- brick_dir = File.join(project_root, 'ios', '.brick')
209
+ # Get iOS output path from brick.json
210
+ ios_brick_path = get_brick_ios_path(project_root)
211
+
212
+ # Handle relative vs absolute paths
213
+ if Pathname.new(ios_brick_path).absolute?
214
+ brick_dir = ios_brick_path
215
+ else
216
+ brick_dir = File.expand_path(File.join(project_root, ios_brick_path))
217
+ end
218
+
219
+ # Create the brick directory if it doesn't exist
106
220
  FileUtils.mkdir_p(brick_dir) unless File.exist?(brick_dir)
107
221
 
108
222
  # Generate imports and module instances