@mobileai/react-native 0.9.17 → 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 (213) hide show
  1. package/package.json +2 -5
  2. package/lib/module/__cli_tmp__.js.map +0 -1
  3. package/lib/module/components/AIAgent.js.map +0 -1
  4. package/lib/module/components/AIZone.js.map +0 -1
  5. package/lib/module/components/AgentChatBar.js.map +0 -1
  6. package/lib/module/components/AgentErrorBoundary.js.map +0 -1
  7. package/lib/module/components/AgentOverlay.js.map +0 -1
  8. package/lib/module/components/DiscoveryTooltip.js.map +0 -1
  9. package/lib/module/components/HighlightOverlay.js.map +0 -1
  10. package/lib/module/components/Icons.js.map +0 -1
  11. package/lib/module/components/ProactiveHint.js.map +0 -1
  12. package/lib/module/components/cards/InfoCard.js.map +0 -1
  13. package/lib/module/components/cards/ReviewSummary.js.map +0 -1
  14. package/lib/module/config/endpoints.js.map +0 -1
  15. package/lib/module/core/ActionRegistry.js.map +0 -1
  16. package/lib/module/core/AgentRuntime.js.map +0 -1
  17. package/lib/module/core/FiberTreeWalker.js.map +0 -1
  18. package/lib/module/core/IdleDetector.js.map +0 -1
  19. package/lib/module/core/MCPBridge.js.map +0 -1
  20. package/lib/module/core/ScreenDehydrator.js.map +0 -1
  21. package/lib/module/core/ZoneRegistry.js.map +0 -1
  22. package/lib/module/core/systemPrompt.js.map +0 -1
  23. package/lib/module/core/types.js.map +0 -1
  24. package/lib/module/hooks/useAction.js.map +0 -1
  25. package/lib/module/index.js.map +0 -1
  26. package/lib/module/plugin/withAppIntents.js.map +0 -1
  27. package/lib/module/providers/GeminiProvider.js.map +0 -1
  28. package/lib/module/providers/OpenAIProvider.js.map +0 -1
  29. package/lib/module/providers/ProviderFactory.js.map +0 -1
  30. package/lib/module/services/AudioInputService.js.map +0 -1
  31. package/lib/module/services/AudioOutputService.js.map +0 -1
  32. package/lib/module/services/KnowledgeBaseService.js.map +0 -1
  33. package/lib/module/services/VoiceService.js.map +0 -1
  34. package/lib/module/services/flags/FlagService.js.map +0 -1
  35. package/lib/module/services/telemetry/MobileAI.js.map +0 -1
  36. package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
  37. package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
  38. package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
  39. package/lib/module/services/telemetry/device.js.map +0 -1
  40. package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
  41. package/lib/module/services/telemetry/index.js.map +0 -1
  42. package/lib/module/services/telemetry/types.js.map +0 -1
  43. package/lib/module/support/CSATSurvey.js.map +0 -1
  44. package/lib/module/support/EscalationEventSource.js.map +0 -1
  45. package/lib/module/support/EscalationSocket.js.map +0 -1
  46. package/lib/module/support/SupportChatModal.js.map +0 -1
  47. package/lib/module/support/SupportGreeting.js.map +0 -1
  48. package/lib/module/support/TicketStore.js.map +0 -1
  49. package/lib/module/support/escalateTool.js.map +0 -1
  50. package/lib/module/support/index.js.map +0 -1
  51. package/lib/module/support/supportPrompt.js.map +0 -1
  52. package/lib/module/support/types.js.map +0 -1
  53. package/lib/module/tools/datePickerTool.js.map +0 -1
  54. package/lib/module/tools/guideTool.js.map +0 -1
  55. package/lib/module/tools/index.js.map +0 -1
  56. package/lib/module/tools/keyboardTool.js.map +0 -1
  57. package/lib/module/tools/longPressTool.js.map +0 -1
  58. package/lib/module/tools/pickerTool.js.map +0 -1
  59. package/lib/module/tools/restoreTool.js.map +0 -1
  60. package/lib/module/tools/scrollTool.js.map +0 -1
  61. package/lib/module/tools/simplifyTool.js.map +0 -1
  62. package/lib/module/tools/sliderTool.js.map +0 -1
  63. package/lib/module/tools/tapTool.js.map +0 -1
  64. package/lib/module/tools/typeTool.js.map +0 -1
  65. package/lib/module/tools/types.js.map +0 -1
  66. package/lib/module/types/jsx.d.js.map +0 -1
  67. package/lib/module/utils/audioUtils.js.map +0 -1
  68. package/lib/module/utils/logger.js.map +0 -1
  69. package/lib/typescript/babel.config.d.ts.map +0 -1
  70. package/lib/typescript/bin/generate-map.d.cts.map +0 -1
  71. package/lib/typescript/eslint.config.d.mts.map +0 -1
  72. package/lib/typescript/generate-map.d.ts.map +0 -1
  73. package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
  74. package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
  75. package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
  76. package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
  77. package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
  78. package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
  79. package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
  80. package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
  81. package/lib/typescript/src/components/Icons.d.ts.map +0 -1
  82. package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
  83. package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
  84. package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
  85. package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
  86. package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
  87. package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
  88. package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
  89. package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
  90. package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
  91. package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
  92. package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
  93. package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
  94. package/lib/typescript/src/core/types.d.ts.map +0 -1
  95. package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
  96. package/lib/typescript/src/index.d.ts.map +0 -1
  97. package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
  98. package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
  99. package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
  100. package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
  101. package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
  102. package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
  103. package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
  104. package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
  105. package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
  106. package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
  107. package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
  108. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
  109. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
  110. package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
  111. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
  112. package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
  113. package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
  114. package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
  115. package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
  116. package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
  117. package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
  118. package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
  119. package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
  120. package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
  121. package/lib/typescript/src/support/index.d.ts.map +0 -1
  122. package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
  123. package/lib/typescript/src/support/types.d.ts.map +0 -1
  124. package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
  125. package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
  126. package/lib/typescript/src/tools/index.d.ts.map +0 -1
  127. package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
  128. package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
  129. package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
  130. package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
  131. package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
  132. package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
  133. package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
  134. package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
  135. package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
  136. package/lib/typescript/src/tools/types.d.ts.map +0 -1
  137. package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
  138. package/lib/typescript/src/utils/logger.d.ts.map +0 -1
  139. package/src/__cli_tmp__.tsx +0 -9
  140. package/src/cli/analyzers/chain-analyzer.ts +0 -183
  141. package/src/cli/extractors/ai-extractor.ts +0 -6
  142. package/src/cli/extractors/ast-extractor.ts +0 -551
  143. package/src/cli/generate-intents.ts +0 -140
  144. package/src/cli/generate-map.ts +0 -121
  145. package/src/cli/generate-swift.ts +0 -116
  146. package/src/cli/scanners/expo-scanner.ts +0 -203
  147. package/src/cli/scanners/rn-scanner.ts +0 -445
  148. package/src/components/AIAgent.tsx +0 -1716
  149. package/src/components/AIZone.tsx +0 -147
  150. package/src/components/AgentChatBar.tsx +0 -1143
  151. package/src/components/AgentErrorBoundary.tsx +0 -78
  152. package/src/components/AgentOverlay.tsx +0 -73
  153. package/src/components/DiscoveryTooltip.tsx +0 -148
  154. package/src/components/HighlightOverlay.tsx +0 -136
  155. package/src/components/Icons.tsx +0 -253
  156. package/src/components/ProactiveHint.tsx +0 -145
  157. package/src/components/cards/InfoCard.tsx +0 -58
  158. package/src/components/cards/ReviewSummary.tsx +0 -76
  159. package/src/config/endpoints.ts +0 -22
  160. package/src/core/ActionRegistry.ts +0 -105
  161. package/src/core/AgentRuntime.ts +0 -1471
  162. package/src/core/FiberTreeWalker.ts +0 -930
  163. package/src/core/IdleDetector.ts +0 -72
  164. package/src/core/MCPBridge.ts +0 -163
  165. package/src/core/ScreenDehydrator.ts +0 -53
  166. package/src/core/ZoneRegistry.ts +0 -44
  167. package/src/core/systemPrompt.ts +0 -431
  168. package/src/core/types.ts +0 -521
  169. package/src/hooks/useAction.ts +0 -182
  170. package/src/index.ts +0 -83
  171. package/src/plugin/withAppIntents.ts +0 -98
  172. package/src/providers/GeminiProvider.ts +0 -357
  173. package/src/providers/OpenAIProvider.ts +0 -379
  174. package/src/providers/ProviderFactory.ts +0 -36
  175. package/src/services/AudioInputService.ts +0 -226
  176. package/src/services/AudioOutputService.ts +0 -236
  177. package/src/services/KnowledgeBaseService.ts +0 -156
  178. package/src/services/VoiceService.ts +0 -451
  179. package/src/services/flags/FlagService.ts +0 -137
  180. package/src/services/telemetry/MobileAI.ts +0 -66
  181. package/src/services/telemetry/PiiScrubber.ts +0 -17
  182. package/src/services/telemetry/TelemetryService.ts +0 -323
  183. package/src/services/telemetry/TouchAutoCapture.ts +0 -165
  184. package/src/services/telemetry/device.ts +0 -93
  185. package/src/services/telemetry/deviceMetadata.ts +0 -13
  186. package/src/services/telemetry/index.ts +0 -13
  187. package/src/services/telemetry/types.ts +0 -75
  188. package/src/support/CSATSurvey.tsx +0 -304
  189. package/src/support/EscalationEventSource.ts +0 -190
  190. package/src/support/EscalationSocket.ts +0 -152
  191. package/src/support/SupportChatModal.tsx +0 -563
  192. package/src/support/SupportGreeting.tsx +0 -161
  193. package/src/support/TicketStore.ts +0 -100
  194. package/src/support/escalateTool.ts +0 -174
  195. package/src/support/index.ts +0 -29
  196. package/src/support/supportPrompt.ts +0 -55
  197. package/src/support/types.ts +0 -155
  198. package/src/tools/datePickerTool.ts +0 -60
  199. package/src/tools/guideTool.ts +0 -76
  200. package/src/tools/index.ts +0 -20
  201. package/src/tools/keyboardTool.ts +0 -30
  202. package/src/tools/longPressTool.ts +0 -61
  203. package/src/tools/pickerTool.ts +0 -115
  204. package/src/tools/restoreTool.ts +0 -33
  205. package/src/tools/scrollTool.ts +0 -156
  206. package/src/tools/simplifyTool.ts +0 -33
  207. package/src/tools/sliderTool.ts +0 -65
  208. package/src/tools/tapTool.ts +0 -93
  209. package/src/tools/typeTool.ts +0 -113
  210. package/src/tools/types.ts +0 -58
  211. package/src/types/jsx.d.ts +0 -20
  212. package/src/utils/audioUtils.ts +0 -54
  213. package/src/utils/logger.ts +0 -38
@@ -1,121 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Screen Map Generator CLI
5
- *
6
- * Scans React Native screen files and generates a JSON map
7
- * that the AI agent uses for intelligent navigation.
8
- *
9
- * Pure AST — no LLM calls, no API key needed. Runs in ~2 seconds.
10
- *
11
- * Usage:
12
- * npx react-native-ai-agent generate-map
13
- * npx react-native-ai-agent generate-map --watch
14
- */
15
-
16
- import * as fs from 'fs';
17
- import * as path from 'path';
18
- import { scanExpoRouterApp } from './scanners/expo-scanner';
19
- import { scanReactNavigationApp } from './scanners/rn-scanner';
20
-
21
- interface ScreenMapEntry {
22
- title?: string;
23
- description: string;
24
- navigatesTo?: string[];
25
- }
26
-
27
- interface ScreenMap {
28
- generatedAt: string;
29
- framework: 'expo-router' | 'react-navigation';
30
- screens: Record<string, ScreenMapEntry>;
31
- }
32
-
33
- function main() {
34
- const args = parseArgs(process.argv.slice(2));
35
- const projectRoot = args.dir || process.cwd();
36
-
37
- console.log('🗺️ Screen Map Generator');
38
- console.log('━'.repeat(40));
39
-
40
- // Detect framework
41
- const framework = detectFramework(projectRoot);
42
- console.log(`📱 Framework: ${framework}`);
43
-
44
- // Scan screens
45
- const scannedScreens = framework === 'expo-router'
46
- ? scanExpoRouterApp(projectRoot)
47
- : scanReactNavigationApp(projectRoot);
48
-
49
- console.log(`📄 Found ${scannedScreens.length} screen(s)`);
50
-
51
- // Build output — per-screen navigatesTo, filtered to known routes only
52
- const allRouteSet = new Set(scannedScreens.map(s => s.routeName));
53
- const screenMap: ScreenMap = {
54
- generatedAt: new Date().toISOString(),
55
- framework,
56
- screens: {},
57
- };
58
-
59
- for (const screen of scannedScreens) {
60
- const validLinks = screen.navigationLinks.filter(link => allRouteSet.has(link));
61
- if (screen.navigationLinks.length > 0) {
62
- const noise = screen.navigationLinks.length - validLinks.length;
63
- console.log(` 🔗 ${screen.routeName} → ${validLinks.join(', ')}${noise > 0 ? ` (${noise} noise filtered)` : ''}`);
64
- }
65
- screenMap.screens[screen.routeName] = {
66
- title: screen.title || undefined,
67
- description: screen.description,
68
- navigatesTo: validLinks.length > 0 ? validLinks : undefined,
69
- };
70
- }
71
-
72
- // Write output
73
- const outputPath = path.join(projectRoot, 'ai-screen-map.json');
74
- fs.writeFileSync(outputPath, JSON.stringify(screenMap, null, 2));
75
-
76
- const linkedCount = scannedScreens.filter(s => s.navigationLinks.some(l => allRouteSet.has(l))).length;
77
- console.log('━'.repeat(40));
78
- console.log(`✅ Generated ${outputPath}`);
79
- console.log(` ${Object.keys(screenMap.screens).length} screens, ${linkedCount} with navigation links`);
80
-
81
- console.log('\n💡 Import in your app:');
82
- console.log(' import screenMap from \'./ai-screen-map.json\';');
83
- console.log(' <AIAgent screenMap={screenMap} />');
84
- }
85
-
86
- function detectFramework(projectRoot: string): 'expo-router' | 'react-navigation' {
87
- const srcApp = path.join(projectRoot, 'src', 'app');
88
- const appDir = path.join(projectRoot, 'app');
89
-
90
- if (fs.existsSync(srcApp) || fs.existsSync(appDir)) {
91
- const layoutInSrc = path.join(srcApp, '_layout.tsx');
92
- const layoutInApp = path.join(appDir, '_layout.tsx');
93
- if (fs.existsSync(layoutInSrc) || fs.existsSync(layoutInApp)) {
94
- return 'expo-router';
95
- }
96
- }
97
-
98
- return 'react-navigation';
99
- }
100
-
101
- interface CLIArgs {
102
- dir: string;
103
- watch: boolean;
104
- }
105
-
106
- function parseArgs(argv: string[]): CLIArgs {
107
- const args: CLIArgs = {
108
- dir: '',
109
- watch: false,
110
- };
111
-
112
- for (const arg of argv) {
113
- if (arg === '--watch' || arg === '-w') args.watch = true;
114
- if (arg.startsWith('--dir=')) args.dir = arg.split('=')[1]!;
115
- }
116
-
117
- return args;
118
- }
119
-
120
- // Run
121
- main();
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
-
6
- export function generateSwiftCode(manifestPath: string, appScheme: string): string {
7
- const manifests = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
8
-
9
- let swiftCode = `import AppIntents
10
- import UIKit
11
-
12
- // Auto-generated by react-native-ai-agent
13
- // Do not edit manually.
14
-
15
- `;
16
-
17
- for (const intent of manifests) {
18
- // Convert snake_case to CamelCaseIntent
19
- const structName = intent.name
20
- .split('_')
21
- .map((w: string) => w.charAt(0).toUpperCase() + w.slice(1))
22
- .join('') + 'Intent';
23
-
24
- swiftCode += `@available(iOS 16.0, *)\n`;
25
- swiftCode += `struct ${structName}: AppIntent {\n`;
26
- swiftCode += ` static var title: LocalizedStringResource = "${intent.name}"\n`;
27
- swiftCode += ` static var description = IntentDescription("${intent.description.replace(/"/g, '\\"')}")\n`;
28
- swiftCode += ` static var openAppWhenRun: Bool = true\n\n`;
29
-
30
- // Parameters
31
- const params = intent.parameters || {};
32
- for (const [key, param] of Object.entries<any>(params)) {
33
- let swiftType = 'String';
34
- if (param.type === 'number') swiftType = 'Double';
35
- if (param.type === 'boolean') swiftType = 'Bool';
36
-
37
- swiftCode += ` @Parameter(title: "${param.description || key}")\n`;
38
- swiftCode += ` var ${key}: ${swiftType}?\n\n`;
39
- }
40
-
41
- // Perform function
42
- swiftCode += ` @MainActor\n`;
43
- swiftCode += ` func perform() async throws -> some IntentResult {\n`;
44
- swiftCode += ` var components = URLComponents()\n`;
45
- swiftCode += ` components.scheme = "${appScheme}"\n`;
46
- swiftCode += ` components.host = "ai-action"\n`;
47
- swiftCode += ` components.path = "/${intent.name}"\n`;
48
-
49
- if (Object.keys(params).length > 0) {
50
- swiftCode += ` var queryItems: [URLQueryItem] = []\n`;
51
- for (const [key, _param] of Object.entries<any>(params)) {
52
- swiftCode += ` if let val = ${key} {\n`;
53
- swiftCode += ` queryItems.append(URLQueryItem(name: "${key}", value: String(describing: val)))\n`;
54
- swiftCode += ` }\n`;
55
- }
56
- swiftCode += ` components.queryItems = queryItems\n`;
57
- }
58
-
59
- swiftCode += ` if let url = components.url {\n`;
60
- swiftCode += ` await UIApplication.shared.open(url)\n`;
61
- swiftCode += ` }\n`;
62
- swiftCode += ` return .result()\n`;
63
- swiftCode += ` }\n`;
64
- swiftCode += `}\n\n`;
65
- }
66
-
67
- // AppShortcuts provider (exposes intents to Siri automatically)
68
- if (manifests.length > 0) {
69
- swiftCode += `@available(iOS 16.0, *)\n`;
70
- swiftCode += `struct MobileAIAppShortcuts: AppShortcutsProvider {\n`;
71
- swiftCode += ` static var appShortcuts: [AppShortcut] {\n`;
72
- for (const intent of manifests) {
73
- const structName = intent.name.split('_').map((w: string) => w.charAt(0).toUpperCase() + w.slice(1)).join('') + 'Intent';
74
- // Generate a basic short phrase mapping
75
- swiftCode += ` AppShortcut(intent: ${structName}(), phrases: ["\\\\(.applicationName) ${intent.name.replace(/_/g, ' ')}"])\n`;
76
- }
77
- swiftCode += ` }\n`;
78
- swiftCode += `}\n`;
79
- }
80
-
81
- return swiftCode;
82
- }
83
-
84
- async function main() {
85
- const manifestPath = process.argv[2] || 'intent-manifest.json';
86
- const appScheme = process.argv[3] || 'mobileai';
87
- const outPath = process.argv[4] || 'ios/MobileAIPilotIntents.swift';
88
-
89
- const absoluteManifest = path.resolve(process.cwd(), manifestPath);
90
- const absoluteOut = path.resolve(process.cwd(), outPath);
91
-
92
- if (!fs.existsSync(absoluteManifest)) {
93
- console.error(`❌ Manifest file not found at ${absoluteManifest}`);
94
- process.exit(1);
95
- }
96
-
97
- console.log(`Generating Swift code for schema ${appScheme}...`);
98
- const swiftCode = generateSwiftCode(absoluteManifest, appScheme);
99
-
100
- // Ensure dir exists
101
- const targetDir = path.dirname(absoluteOut);
102
- if (!fs.existsSync(targetDir)) {
103
- fs.mkdirSync(targetDir, { recursive: true });
104
- }
105
-
106
- fs.writeFileSync(absoluteOut, swiftCode);
107
- console.log(`✅ Wrote Swift AppIntents to ${outPath}`);
108
- }
109
-
110
- // Run if called directly
111
- if (require.main === module) {
112
- main().catch(err => {
113
- console.error(err);
114
- process.exit(1);
115
- });
116
- }
@@ -1,203 +0,0 @@
1
- /**
2
- * Expo Router scanner.
3
- * Discovers screens by walking the app/ or src/app/ directory.
4
- * Maps file paths to route names following Expo Router conventions.
5
- */
6
-
7
- import * as fs from 'fs';
8
- import * as path from 'path';
9
- import { extractContentFromAST, buildDescription } from '../extractors/ast-extractor';
10
- import { parse } from '@babel/parser';
11
- import * as _traverse from '@babel/traverse';
12
- import * as t from '@babel/types';
13
-
14
- const traverse = (_traverse as any).default || _traverse;
15
-
16
- export interface ScannedScreen {
17
- routeName: string;
18
- filePath: string;
19
- title?: string;
20
- description: string;
21
- navigationLinks: string[];
22
- }
23
-
24
- /**
25
- * Scan an Expo Router app directory and return all screens.
26
- */
27
- export function scanExpoRouterApp(projectRoot: string): ScannedScreen[] {
28
- // Find app directory: src/app/ first, then app/
29
- const appDir = findAppDir(projectRoot);
30
- if (!appDir) {
31
- throw new Error('Could not find app/ or src/app/ directory. Is this an Expo Router project?');
32
- }
33
-
34
- console.log(`[generate-map] Scanning Expo Router app: ${appDir}`);
35
-
36
- const screens: ScannedScreen[] = [];
37
- const layoutTitles = new Map<string, string>(); // routeName → title from _layout.tsx
38
-
39
- // First pass: extract titles from _layout.tsx files
40
- extractLayoutTitles(appDir, appDir, layoutTitles);
41
-
42
- // Second pass: scan screen files
43
- scanDirectory(appDir, appDir, screens, layoutTitles);
44
-
45
- return screens;
46
- }
47
-
48
- function findAppDir(projectRoot: string): string | null {
49
- const srcApp = path.join(projectRoot, 'src', 'app');
50
- if (fs.existsSync(srcApp)) return srcApp;
51
-
52
- const app = path.join(projectRoot, 'app');
53
- if (fs.existsSync(app)) return app;
54
-
55
- return null;
56
- }
57
-
58
- function scanDirectory(
59
- dir: string,
60
- appRoot: string,
61
- screens: ScannedScreen[],
62
- layoutTitles: Map<string, string>
63
- ) {
64
- const entries = fs.readdirSync(dir, { withFileTypes: true });
65
-
66
- for (const entry of entries) {
67
- const fullPath = path.join(dir, entry.name);
68
-
69
- if (entry.isDirectory()) {
70
- // Skip hidden directories and node_modules
71
- if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
72
- scanDirectory(fullPath, appRoot, screens, layoutTitles);
73
- continue;
74
- }
75
-
76
- // Only process .tsx and .ts files (not .js — Expo Router uses TS by default)
77
- if (!entry.name.match(/\.(tsx?|jsx?)$/)) continue;
78
-
79
- // Skip layout files, special files, and API routes
80
- if (entry.name === '_layout.tsx' || entry.name === '_layout.ts') continue;
81
- if (entry.name.startsWith('+')) continue; // +not-found, +html, +api, etc.
82
- if (entry.name.startsWith('_')) continue; // Other special files
83
-
84
- const routeName = filePathToRouteName(fullPath, appRoot);
85
- const sourceCode = fs.readFileSync(fullPath, 'utf-8');
86
- const extracted = extractContentFromAST(sourceCode, fullPath);
87
- const title = layoutTitles.get(routeName);
88
-
89
- screens.push({
90
- routeName,
91
- filePath: fullPath,
92
- title,
93
- description: buildDescription(extracted),
94
- navigationLinks: extracted.navigationLinks,
95
- });
96
- }
97
- }
98
-
99
- /**
100
- * Convert a file path to an Expo Router route name.
101
- * Examples:
102
- * app/categories.tsx → categories
103
- * app/item-reviews/[id].tsx → item-reviews/[id]
104
- * app/(tabs)/index.tsx → (tabs)/index
105
- * app/product/[id].tsx → product/[id]
106
- */
107
- function filePathToRouteName(filePath: string, appRoot: string): string {
108
- let relative = path.relative(appRoot, filePath);
109
-
110
- // Remove extension
111
- relative = relative.replace(/\.(tsx?|jsx?)$/, '');
112
-
113
- // Normalize path separators (Windows compat)
114
- relative = relative.split(path.sep).join('/');
115
-
116
- return relative;
117
- }
118
-
119
- /**
120
- * Parse _layout.tsx files to extract screen titles from Stack.Screen options.
121
- */
122
- function extractLayoutTitles(
123
- dir: string,
124
- appRoot: string,
125
- titles: Map<string, string>
126
- ) {
127
- const entries = fs.readdirSync(dir, { withFileTypes: true });
128
-
129
- for (const entry of entries) {
130
- const fullPath = path.join(dir, entry.name);
131
-
132
- if (entry.isDirectory()) {
133
- if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
134
- extractLayoutTitles(fullPath, appRoot, titles);
135
- continue;
136
- }
137
-
138
- if (entry.name === '_layout.tsx' || entry.name === '_layout.ts') {
139
- const sourceCode = fs.readFileSync(fullPath, 'utf-8');
140
- const dirRelative = path.relative(appRoot, dir);
141
- const prefix = dirRelative ? dirRelative.split(path.sep).join('/') + '/' : '';
142
-
143
- extractTitlesFromLayout(sourceCode, prefix, titles);
144
- }
145
- }
146
- }
147
-
148
- /**
149
- * Extract screen names and titles from a layout file's JSX.
150
- * Looks for patterns like: <Stack.Screen name="categories" options={{ title: 'Categories' }} />
151
- */
152
- function extractTitlesFromLayout(sourceCode: string, routePrefix: string, titles: Map<string, string>) {
153
- let ast: ReturnType<typeof parse>;
154
- try {
155
- ast = parse(sourceCode, {
156
- sourceType: 'module',
157
- plugins: ['jsx', 'typescript', 'decorators-legacy'],
158
- });
159
- } catch {
160
- return;
161
- }
162
-
163
- traverse(ast, {
164
- JSXOpeningElement(path: any) {
165
- const nameNode = path.node.name;
166
- // Match *.Screen
167
- if (!t.isJSXMemberExpression(nameNode)) return;
168
- if (!t.isJSXIdentifier(nameNode.property) || nameNode.property.name !== 'Screen') return;
169
-
170
- // Get name prop
171
- let screenName: string | null = null;
172
- let screenTitle: string | null = null;
173
-
174
- for (const attr of path.node.attributes) {
175
- if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name)) continue;
176
-
177
- if (attr.name.name === 'name' && t.isStringLiteral(attr.value)) {
178
- screenName = attr.value.value;
179
- }
180
-
181
- if (attr.name.name === 'options' && t.isJSXExpressionContainer(attr.value)) {
182
- const expr = attr.value.expression;
183
- if (t.isObjectExpression(expr)) {
184
- for (const prop of expr.properties) {
185
- if (
186
- t.isObjectProperty(prop) &&
187
- t.isIdentifier(prop.key) &&
188
- prop.key.name === 'title' &&
189
- t.isStringLiteral(prop.value)
190
- ) {
191
- screenTitle = prop.value.value;
192
- }
193
- }
194
- }
195
- }
196
- }
197
-
198
- if (screenName && screenTitle) {
199
- titles.set(routePrefix + screenName, screenTitle);
200
- }
201
- },
202
- });
203
- }