@mobileai/react-native 0.9.16 → 0.9.18

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 (214) hide show
  1. package/README.md +2 -2
  2. package/package.json +5 -8
  3. package/lib/module/__cli_tmp__.js.map +0 -1
  4. package/lib/module/components/AIAgent.js.map +0 -1
  5. package/lib/module/components/AIZone.js.map +0 -1
  6. package/lib/module/components/AgentChatBar.js.map +0 -1
  7. package/lib/module/components/AgentErrorBoundary.js.map +0 -1
  8. package/lib/module/components/AgentOverlay.js.map +0 -1
  9. package/lib/module/components/DiscoveryTooltip.js.map +0 -1
  10. package/lib/module/components/HighlightOverlay.js.map +0 -1
  11. package/lib/module/components/Icons.js.map +0 -1
  12. package/lib/module/components/ProactiveHint.js.map +0 -1
  13. package/lib/module/components/cards/InfoCard.js.map +0 -1
  14. package/lib/module/components/cards/ReviewSummary.js.map +0 -1
  15. package/lib/module/config/endpoints.js.map +0 -1
  16. package/lib/module/core/ActionRegistry.js.map +0 -1
  17. package/lib/module/core/AgentRuntime.js.map +0 -1
  18. package/lib/module/core/FiberTreeWalker.js.map +0 -1
  19. package/lib/module/core/IdleDetector.js.map +0 -1
  20. package/lib/module/core/MCPBridge.js.map +0 -1
  21. package/lib/module/core/ScreenDehydrator.js.map +0 -1
  22. package/lib/module/core/ZoneRegistry.js.map +0 -1
  23. package/lib/module/core/systemPrompt.js.map +0 -1
  24. package/lib/module/core/types.js.map +0 -1
  25. package/lib/module/hooks/useAction.js.map +0 -1
  26. package/lib/module/index.js.map +0 -1
  27. package/lib/module/plugin/withAppIntents.js.map +0 -1
  28. package/lib/module/providers/GeminiProvider.js.map +0 -1
  29. package/lib/module/providers/OpenAIProvider.js.map +0 -1
  30. package/lib/module/providers/ProviderFactory.js.map +0 -1
  31. package/lib/module/services/AudioInputService.js.map +0 -1
  32. package/lib/module/services/AudioOutputService.js.map +0 -1
  33. package/lib/module/services/KnowledgeBaseService.js.map +0 -1
  34. package/lib/module/services/VoiceService.js.map +0 -1
  35. package/lib/module/services/flags/FlagService.js.map +0 -1
  36. package/lib/module/services/telemetry/MobileAI.js.map +0 -1
  37. package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
  38. package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
  39. package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
  40. package/lib/module/services/telemetry/device.js.map +0 -1
  41. package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
  42. package/lib/module/services/telemetry/index.js.map +0 -1
  43. package/lib/module/services/telemetry/types.js.map +0 -1
  44. package/lib/module/support/CSATSurvey.js.map +0 -1
  45. package/lib/module/support/EscalationEventSource.js.map +0 -1
  46. package/lib/module/support/EscalationSocket.js.map +0 -1
  47. package/lib/module/support/SupportChatModal.js.map +0 -1
  48. package/lib/module/support/SupportGreeting.js.map +0 -1
  49. package/lib/module/support/TicketStore.js.map +0 -1
  50. package/lib/module/support/escalateTool.js.map +0 -1
  51. package/lib/module/support/index.js.map +0 -1
  52. package/lib/module/support/supportPrompt.js.map +0 -1
  53. package/lib/module/support/types.js.map +0 -1
  54. package/lib/module/tools/datePickerTool.js.map +0 -1
  55. package/lib/module/tools/guideTool.js.map +0 -1
  56. package/lib/module/tools/index.js.map +0 -1
  57. package/lib/module/tools/keyboardTool.js.map +0 -1
  58. package/lib/module/tools/longPressTool.js.map +0 -1
  59. package/lib/module/tools/pickerTool.js.map +0 -1
  60. package/lib/module/tools/restoreTool.js.map +0 -1
  61. package/lib/module/tools/scrollTool.js.map +0 -1
  62. package/lib/module/tools/simplifyTool.js.map +0 -1
  63. package/lib/module/tools/sliderTool.js.map +0 -1
  64. package/lib/module/tools/tapTool.js.map +0 -1
  65. package/lib/module/tools/typeTool.js.map +0 -1
  66. package/lib/module/tools/types.js.map +0 -1
  67. package/lib/module/types/jsx.d.js.map +0 -1
  68. package/lib/module/utils/audioUtils.js.map +0 -1
  69. package/lib/module/utils/logger.js.map +0 -1
  70. package/lib/typescript/babel.config.d.ts.map +0 -1
  71. package/lib/typescript/bin/generate-map.d.cts.map +0 -1
  72. package/lib/typescript/eslint.config.d.mts.map +0 -1
  73. package/lib/typescript/generate-map.d.ts.map +0 -1
  74. package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
  75. package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
  76. package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
  77. package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
  78. package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
  79. package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
  80. package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
  81. package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
  82. package/lib/typescript/src/components/Icons.d.ts.map +0 -1
  83. package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
  84. package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
  85. package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
  86. package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
  87. package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
  88. package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
  89. package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
  90. package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
  91. package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
  92. package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
  93. package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
  94. package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
  95. package/lib/typescript/src/core/types.d.ts.map +0 -1
  96. package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
  97. package/lib/typescript/src/index.d.ts.map +0 -1
  98. package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
  99. package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
  100. package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
  101. package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
  102. package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
  103. package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
  104. package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
  105. package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
  106. package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
  107. package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
  108. package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
  109. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
  110. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
  111. package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
  112. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
  113. package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
  114. package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
  115. package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
  116. package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
  117. package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
  118. package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
  119. package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
  120. package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
  121. package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
  122. package/lib/typescript/src/support/index.d.ts.map +0 -1
  123. package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
  124. package/lib/typescript/src/support/types.d.ts.map +0 -1
  125. package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
  126. package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
  127. package/lib/typescript/src/tools/index.d.ts.map +0 -1
  128. package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
  129. package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
  130. package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
  131. package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
  132. package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
  133. package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
  134. package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
  135. package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
  136. package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
  137. package/lib/typescript/src/tools/types.d.ts.map +0 -1
  138. package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
  139. package/lib/typescript/src/utils/logger.d.ts.map +0 -1
  140. package/src/__cli_tmp__.tsx +0 -9
  141. package/src/cli/analyzers/chain-analyzer.ts +0 -183
  142. package/src/cli/extractors/ai-extractor.ts +0 -6
  143. package/src/cli/extractors/ast-extractor.ts +0 -551
  144. package/src/cli/generate-intents.ts +0 -140
  145. package/src/cli/generate-map.ts +0 -121
  146. package/src/cli/generate-swift.ts +0 -116
  147. package/src/cli/scanners/expo-scanner.ts +0 -203
  148. package/src/cli/scanners/rn-scanner.ts +0 -445
  149. package/src/components/AIAgent.tsx +0 -1716
  150. package/src/components/AIZone.tsx +0 -147
  151. package/src/components/AgentChatBar.tsx +0 -1143
  152. package/src/components/AgentErrorBoundary.tsx +0 -78
  153. package/src/components/AgentOverlay.tsx +0 -73
  154. package/src/components/DiscoveryTooltip.tsx +0 -148
  155. package/src/components/HighlightOverlay.tsx +0 -136
  156. package/src/components/Icons.tsx +0 -253
  157. package/src/components/ProactiveHint.tsx +0 -145
  158. package/src/components/cards/InfoCard.tsx +0 -58
  159. package/src/components/cards/ReviewSummary.tsx +0 -76
  160. package/src/config/endpoints.ts +0 -22
  161. package/src/core/ActionRegistry.ts +0 -105
  162. package/src/core/AgentRuntime.ts +0 -1471
  163. package/src/core/FiberTreeWalker.ts +0 -930
  164. package/src/core/IdleDetector.ts +0 -72
  165. package/src/core/MCPBridge.ts +0 -163
  166. package/src/core/ScreenDehydrator.ts +0 -53
  167. package/src/core/ZoneRegistry.ts +0 -44
  168. package/src/core/systemPrompt.ts +0 -431
  169. package/src/core/types.ts +0 -521
  170. package/src/hooks/useAction.ts +0 -182
  171. package/src/index.ts +0 -83
  172. package/src/plugin/withAppIntents.ts +0 -98
  173. package/src/providers/GeminiProvider.ts +0 -357
  174. package/src/providers/OpenAIProvider.ts +0 -379
  175. package/src/providers/ProviderFactory.ts +0 -36
  176. package/src/services/AudioInputService.ts +0 -226
  177. package/src/services/AudioOutputService.ts +0 -236
  178. package/src/services/KnowledgeBaseService.ts +0 -156
  179. package/src/services/VoiceService.ts +0 -451
  180. package/src/services/flags/FlagService.ts +0 -137
  181. package/src/services/telemetry/MobileAI.ts +0 -66
  182. package/src/services/telemetry/PiiScrubber.ts +0 -17
  183. package/src/services/telemetry/TelemetryService.ts +0 -323
  184. package/src/services/telemetry/TouchAutoCapture.ts +0 -165
  185. package/src/services/telemetry/device.ts +0 -93
  186. package/src/services/telemetry/deviceMetadata.ts +0 -13
  187. package/src/services/telemetry/index.ts +0 -13
  188. package/src/services/telemetry/types.ts +0 -75
  189. package/src/support/CSATSurvey.tsx +0 -304
  190. package/src/support/EscalationEventSource.ts +0 -190
  191. package/src/support/EscalationSocket.ts +0 -152
  192. package/src/support/SupportChatModal.tsx +0 -563
  193. package/src/support/SupportGreeting.tsx +0 -161
  194. package/src/support/TicketStore.ts +0 -100
  195. package/src/support/escalateTool.ts +0 -174
  196. package/src/support/index.ts +0 -29
  197. package/src/support/supportPrompt.ts +0 -55
  198. package/src/support/types.ts +0 -155
  199. package/src/tools/datePickerTool.ts +0 -60
  200. package/src/tools/guideTool.ts +0 -76
  201. package/src/tools/index.ts +0 -20
  202. package/src/tools/keyboardTool.ts +0 -30
  203. package/src/tools/longPressTool.ts +0 -61
  204. package/src/tools/pickerTool.ts +0 -115
  205. package/src/tools/restoreTool.ts +0 -33
  206. package/src/tools/scrollTool.ts +0 -156
  207. package/src/tools/simplifyTool.ts +0 -33
  208. package/src/tools/sliderTool.ts +0 -65
  209. package/src/tools/tapTool.ts +0 -93
  210. package/src/tools/typeTool.ts +0 -113
  211. package/src/tools/types.ts +0 -58
  212. package/src/types/jsx.d.ts +0 -20
  213. package/src/utils/audioUtils.ts +0 -54
  214. package/src/utils/logger.ts +0 -38
@@ -1,445 +0,0 @@
1
- /**
2
- * React Navigation scanner.
3
- * Discovers screens by parsing navigation config files.
4
- * Supports v5/v6 (dynamic JSX) and v7 (static object) patterns.
5
- */
6
-
7
- import * as fs from 'fs';
8
- import * as path from 'path';
9
- import { parse } from '@babel/parser';
10
- import * as _traverse from '@babel/traverse';
11
- import * as t from '@babel/types';
12
-
13
- const traverse = (_traverse as any).default || _traverse;
14
- import { extractContentFromAST, buildDescription } from '../extractors/ast-extractor';
15
-
16
- export interface ScannedScreen {
17
- routeName: string;
18
- filePath: string;
19
- title?: string;
20
- description: string;
21
- navigationLinks: string[];
22
- }
23
-
24
- const NAVIGATOR_FUNCTIONS = [
25
- 'createStackNavigator',
26
- 'createNativeStackNavigator',
27
- 'createBottomTabNavigator',
28
- 'createDrawerNavigator',
29
- 'createMaterialBottomTabNavigator',
30
- 'createMaterialTopTabNavigator',
31
- ];
32
-
33
- /**
34
- * Scan a React Navigation project and return all screens.
35
- */
36
- export function scanReactNavigationApp(projectRoot: string): ScannedScreen[] {
37
- console.log(`[generate-map] Scanning React Navigation project: ${projectRoot}`);
38
-
39
- // Find all JS/TS files that contain navigator creation
40
- const navigatorFiles = findNavigatorFiles(projectRoot);
41
-
42
- if (navigatorFiles.length === 0) {
43
- throw new Error(
44
- 'Could not find any React Navigation navigator definitions. ' +
45
- 'Searched for createStackNavigator, createNativeStackNavigator, etc.'
46
- );
47
- }
48
-
49
- console.log(`[generate-map] Found ${navigatorFiles.length} navigator file(s)`);
50
-
51
- const screens: ScannedScreen[] = [];
52
- const processedRoutes = new Set<string>();
53
- const fileAstCache = new Map<string, any>();
54
-
55
- for (const navFile of navigatorFiles) {
56
- const sourceCode = fs.readFileSync(navFile, 'utf-8');
57
- const screenDefs = extractScreenDefinitions(sourceCode, navFile, projectRoot);
58
-
59
- for (const screenDef of screenDefs) {
60
- if (processedRoutes.has(screenDef.routeName)) continue;
61
- processedRoutes.add(screenDef.routeName);
62
-
63
- // Read and extract content from the screen component file
64
- if (fs.existsSync(screenDef.filePath)) {
65
- let extracted: any;
66
- if (fileAstCache.has(screenDef.filePath)) {
67
- extracted = fileAstCache.get(screenDef.filePath);
68
- } else {
69
- const screenSource = fs.readFileSync(screenDef.filePath, 'utf-8');
70
- extracted = extractContentFromAST(screenSource, screenDef.filePath);
71
- fileAstCache.set(screenDef.filePath, extracted);
72
- }
73
-
74
- screens.push({
75
- routeName: screenDef.routeName,
76
- filePath: screenDef.filePath,
77
- title: screenDef.title,
78
- description: buildDescription(extracted),
79
- navigationLinks: extracted.navigationLinks,
80
- });
81
- } else {
82
- // Component defined in same file or import not resolved
83
- screens.push({
84
- routeName: screenDef.routeName,
85
- filePath: screenDef.filePath,
86
- title: screenDef.title,
87
- description: 'Screen content',
88
- navigationLinks: [],
89
- });
90
- }
91
- }
92
- }
93
-
94
- return screens;
95
- }
96
-
97
- interface ScreenDefinition {
98
- routeName: string;
99
- componentName: string;
100
- filePath: string;
101
- title?: string;
102
- }
103
-
104
- /**
105
- * Find all files containing navigator creation functions.
106
- */
107
- function findNavigatorFiles(projectRoot: string): string[] {
108
- const result: string[] = [];
109
- const srcDir = path.join(projectRoot, 'src');
110
- const searchDirs = [
111
- fs.existsSync(srcDir) ? srcDir : projectRoot,
112
- ];
113
-
114
- for (const dir of searchDirs) {
115
- walkAndSearch(dir, result, projectRoot);
116
- }
117
-
118
- return result;
119
- }
120
-
121
- function walkAndSearch(dir: string, result: string[], projectRoot: string) {
122
- // Skip common non-source directories
123
- const skipDirs = ['node_modules', '.git', 'lib', 'build', 'dist', '__tests__', '__mocks__', 'android', 'ios'];
124
-
125
- let entries: fs.Dirent[];
126
- try {
127
- entries = fs.readdirSync(dir, { withFileTypes: true });
128
- } catch {
129
- return;
130
- }
131
-
132
- for (const entry of entries) {
133
- const fullPath = path.join(dir, entry.name);
134
-
135
- if (entry.isDirectory()) {
136
- if (skipDirs.includes(entry.name) || entry.name.startsWith('.')) continue;
137
- walkAndSearch(fullPath, result, projectRoot);
138
- continue;
139
- }
140
-
141
- if (!entry.name.match(/\.(tsx?|jsx?)$/)) continue;
142
-
143
- // Quick text search before expensive parsing
144
- const content = fs.readFileSync(fullPath, 'utf-8');
145
- const hasNavigator = NAVIGATOR_FUNCTIONS.some(fn => content.includes(fn));
146
- if (hasNavigator) {
147
- result.push(fullPath);
148
- }
149
- }
150
- }
151
-
152
- /**
153
- * Extract screen definitions from a navigator file.
154
- * Handles both static (v7) and dynamic (v5/v6/v7) patterns.
155
- */
156
- function extractScreenDefinitions(
157
- sourceCode: string,
158
- filePath: string,
159
- projectRoot: string
160
- ): ScreenDefinition[] {
161
- const screens: ScreenDefinition[] = [];
162
- const imports = new Map<string, string>(); // componentName → import path
163
-
164
- let ast: ReturnType<typeof parse>;
165
- try {
166
- ast = parse(sourceCode, {
167
- sourceType: 'module',
168
- plugins: ['jsx', 'typescript', 'decorators-legacy'],
169
- });
170
- } catch {
171
- console.warn(`[generate-map] Failed to parse ${filePath}`);
172
- return screens;
173
- }
174
-
175
- // First pass: collect all imports
176
- traverse(ast, {
177
- ImportDeclaration(nodePath: any) {
178
- const source = nodePath.node.source.value;
179
- for (const specifier of nodePath.node.specifiers) {
180
- if (t.isImportDefaultSpecifier(specifier) || t.isImportSpecifier(specifier)) {
181
- imports.set(specifier.local.name, source);
182
- }
183
- }
184
- },
185
- });
186
-
187
- // Second pass: find screen definitions
188
- traverse(ast, {
189
- // Dynamic config: <Stack.Screen name="Home" component={HomeScreen} />
190
- JSXOpeningElement(nodePath: any) {
191
- const nameNode = nodePath.node.name;
192
- if (!t.isJSXMemberExpression(nameNode)) return;
193
- if (!t.isJSXIdentifier(nameNode.property) || nameNode.property.name !== 'Screen') return;
194
-
195
- let screenName: string | null = null;
196
- let componentName: string | null = null;
197
- let title: string | null = null;
198
-
199
- for (const attr of nodePath.node.attributes) {
200
- if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name)) continue;
201
-
202
- if (attr.name.name === 'name') {
203
- if (t.isStringLiteral(attr.value)) {
204
- screenName = attr.value.value;
205
- } else if (t.isJSXExpressionContainer(attr.value)) {
206
- const expr = attr.value.expression;
207
- if (t.isStringLiteral(expr)) {
208
- screenName = expr.value;
209
- } else if (t.isMemberExpression(expr) && t.isIdentifier(expr.property)) {
210
- screenName = expr.property.name;
211
- } else if (t.isIdentifier(expr)) {
212
- screenName = expr.name;
213
- }
214
- }
215
- }
216
-
217
- if (attr.name.name === 'component' && t.isJSXExpressionContainer(attr.value)) {
218
- const expr = attr.value.expression;
219
- if (t.isIdentifier(expr)) {
220
- componentName = expr.name;
221
- } else if (t.isMemberExpression(expr)) {
222
- if (t.isIdentifier(expr.object) && t.isIdentifier(expr.property)) {
223
- componentName = `${expr.object.name}.${expr.property.name}`;
224
- }
225
- }
226
- }
227
-
228
- if (attr.name.name === 'options' && t.isJSXExpressionContainer(attr.value)) {
229
- title = extractTitleFromOptions(attr.value.expression);
230
- }
231
- }
232
-
233
- console.log(`[DEBUG-AST-Raw] Checked Screen. screenName: ${screenName}, componentName: ${componentName}`);
234
-
235
- if (screenName && componentName) {
236
- console.log(`[DEBUG-AST] Found Dynamic Screen: ${screenName} -> component: ${componentName}`);
237
- screens.push({
238
- routeName: screenName,
239
- componentName,
240
- filePath: resolveComponentPath(componentName, imports, filePath, projectRoot),
241
- title: title || undefined,
242
- });
243
- }
244
- },
245
-
246
- // Static config (v7): createNativeStackNavigator({ screens: { Home: HomeScreen } })
247
- CallExpression(nodePath: any) {
248
- const callee = nodePath.node.callee;
249
- if (!t.isIdentifier(callee)) return;
250
- if (!NAVIGATOR_FUNCTIONS.includes(callee.name)) return;
251
-
252
- const firstArg = nodePath.node.arguments[0];
253
- if (!t.isObjectExpression(firstArg)) return;
254
-
255
- // Find the 'screens' property
256
- for (const prop of firstArg.properties) {
257
- if (!t.isObjectProperty(prop)) continue;
258
- if (!t.isIdentifier(prop.key) || prop.key.name !== 'screens') continue;
259
- if (!t.isObjectExpression(prop.value)) continue;
260
-
261
- for (const screenProp of prop.value.properties) {
262
- if (!t.isObjectProperty(screenProp)) continue;
263
-
264
- let screenName: string | null = null;
265
-
266
- if (!screenProp.computed) {
267
- if (t.isIdentifier(screenProp.key)) screenName = screenProp.key.name;
268
- else if (t.isStringLiteral(screenProp.key)) screenName = screenProp.key.value;
269
- } else {
270
- // Calculated key: [StackNav.Home]: HomeScreen
271
- if (t.isIdentifier(screenProp.key)) screenName = screenProp.key.name;
272
- else if (t.isMemberExpression(screenProp.key) && t.isIdentifier(screenProp.key.property)) {
273
- screenName = screenProp.key.property.name;
274
- }
275
- }
276
-
277
- if (!screenName) continue;
278
-
279
- let componentName: string | null = null;
280
- let title: string | undefined;
281
-
282
- // Simple: Home: HomeScreen (or StackRoute.HomeScreen)
283
- if (t.isIdentifier(screenProp.value)) {
284
- componentName = screenProp.value.name;
285
- } else if (t.isMemberExpression(screenProp.value)) {
286
- if (t.isIdentifier(screenProp.value.object) && t.isIdentifier(screenProp.value.property)) {
287
- componentName = `${screenProp.value.object.name}.${screenProp.value.property.name}`;
288
- }
289
- }
290
-
291
- // Object: Home: { screen: HomeScreen, options: { title: 'Home' } }
292
- if (t.isObjectExpression(screenProp.value)) {
293
- for (const inner of screenProp.value.properties) {
294
- if (!t.isObjectProperty(inner) || !t.isIdentifier(inner.key)) continue;
295
-
296
- if (inner.key.name === 'screen' && t.isIdentifier(inner.value)) {
297
- componentName = inner.value.name;
298
- }
299
- if (inner.key.name === 'options') {
300
- title = extractTitleFromOptions(inner.value) || undefined;
301
- }
302
- }
303
- }
304
-
305
- if (componentName) {
306
- screens.push({
307
- routeName: screenName,
308
- componentName,
309
- filePath: resolveComponentPath(componentName, imports, filePath, projectRoot),
310
- title,
311
- });
312
- }
313
- }
314
- }
315
- },
316
- });
317
-
318
- return screens;
319
- }
320
-
321
- function extractTitleFromOptions(optionsNode: any): string | null {
322
- if (!t.isObjectExpression(optionsNode)) return null;
323
-
324
- for (const prop of optionsNode.properties) {
325
- if (
326
- t.isObjectProperty(prop) &&
327
- t.isIdentifier(prop.key) &&
328
- prop.key.name === 'title' &&
329
- t.isStringLiteral(prop.value)
330
- ) {
331
- return prop.value.value;
332
- }
333
- }
334
- return null;
335
- }
336
-
337
- /**
338
- * Resolve a component name to its source file path via imports.
339
- * Also handles dot-notation intermediate tracing (e.g., StackRoute.Login)
340
- */
341
- function resolveComponentPath(
342
- componentName: string,
343
- imports: Map<string, string>,
344
- currentFile: string,
345
- _projectRoot: string
346
- ): string {
347
- const parts = componentName.split('.');
348
- const baseComponent: string | undefined = parts[0];
349
- const property: string | undefined = parts[1];
350
-
351
- if (!baseComponent) return currentFile;
352
-
353
- const importPath = imports.get(baseComponent);
354
- if (!importPath) return currentFile;
355
-
356
- let resolvedBase = currentFile;
357
- if (importPath.startsWith('.')) {
358
- const dir = path.dirname(currentFile);
359
- const resolved = path.resolve(dir, importPath);
360
-
361
- const extensions = ['.tsx', '.ts', '.jsx', '.js'];
362
- let found = false;
363
- for (const ext of extensions) {
364
- if (fs.existsSync(resolved + ext)) {
365
- resolvedBase = resolved + ext;
366
- found = true;
367
- break;
368
- }
369
- }
370
- if (!found) {
371
- for (const ext of extensions) {
372
- const indexPath = path.join(resolved, `index${ext}`);
373
- if (fs.existsSync(indexPath)) {
374
- resolvedBase = indexPath;
375
- found = true;
376
- break;
377
- }
378
- }
379
- }
380
- if (!found) resolvedBase = resolved;
381
- }
382
-
383
- if (!property || resolvedBase === currentFile) return resolvedBase;
384
-
385
- return traceExportProperty(resolvedBase, baseComponent, property) || resolvedBase;
386
- }
387
-
388
- /**
389
- * Traces an exported object property through an intermediate file to its deep source file.
390
- */
391
- function traceExportProperty(filePath: string, objectName: string, propertyName: string): string | null {
392
- if (!fs.existsSync(filePath)) return null;
393
- const sourceCode = fs.readFileSync(filePath, 'utf-8');
394
- let ast: ReturnType<typeof parse>;
395
- try {
396
- ast = parse(sourceCode, { sourceType: 'module', plugins: ['jsx', 'typescript', 'decorators-legacy'] });
397
- } catch { return null; }
398
-
399
- const innerImports = new Map<string, string>();
400
- let targetIdentifier: string | null = null;
401
-
402
- traverse(ast, {
403
- ImportDeclaration(nodePath: any) {
404
- const source = nodePath.node.source.value;
405
- for (const specifier of nodePath.node.specifiers) {
406
- if (t.isImportDefaultSpecifier(specifier) || t.isImportSpecifier(specifier)) {
407
- innerImports.set(specifier.local.name, source);
408
- }
409
- }
410
- },
411
- VariableDeclarator(nodePath: any) {
412
- if (t.isIdentifier(nodePath.node.id) && nodePath.node.id.name === objectName) {
413
- if (t.isObjectExpression(nodePath.node.init)) {
414
- for (const prop of nodePath.node.init.properties) {
415
- if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {
416
- const keyName = prop.key.name;
417
- if (keyName === propertyName) {
418
- if (t.isIdentifier(prop.value)) {
419
- targetIdentifier = prop.value.name;
420
- }
421
- }
422
- }
423
- }
424
- }
425
- }
426
- }
427
- });
428
-
429
- if (!targetIdentifier) return null;
430
-
431
- const importPath = innerImports.get(targetIdentifier);
432
- if (!importPath || !importPath.startsWith('.')) return null;
433
-
434
- const dir = path.dirname(filePath);
435
- const resolved = path.resolve(dir, importPath);
436
- const extensions = ['.tsx', '.ts', '.jsx', '.js'];
437
- for (const ext of extensions) {
438
- if (fs.existsSync(resolved + ext)) return resolved + ext;
439
- }
440
- for (const ext of extensions) {
441
- const indexPath = path.join(resolved, `index${ext}`);
442
- if (fs.existsSync(indexPath)) return indexPath;
443
- }
444
- return resolved;
445
- }