@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.
- package/package.json +2 -5
- package/lib/module/__cli_tmp__.js.map +0 -1
- package/lib/module/components/AIAgent.js.map +0 -1
- package/lib/module/components/AIZone.js.map +0 -1
- package/lib/module/components/AgentChatBar.js.map +0 -1
- package/lib/module/components/AgentErrorBoundary.js.map +0 -1
- package/lib/module/components/AgentOverlay.js.map +0 -1
- package/lib/module/components/DiscoveryTooltip.js.map +0 -1
- package/lib/module/components/HighlightOverlay.js.map +0 -1
- package/lib/module/components/Icons.js.map +0 -1
- package/lib/module/components/ProactiveHint.js.map +0 -1
- package/lib/module/components/cards/InfoCard.js.map +0 -1
- package/lib/module/components/cards/ReviewSummary.js.map +0 -1
- package/lib/module/config/endpoints.js.map +0 -1
- package/lib/module/core/ActionRegistry.js.map +0 -1
- package/lib/module/core/AgentRuntime.js.map +0 -1
- package/lib/module/core/FiberTreeWalker.js.map +0 -1
- package/lib/module/core/IdleDetector.js.map +0 -1
- package/lib/module/core/MCPBridge.js.map +0 -1
- package/lib/module/core/ScreenDehydrator.js.map +0 -1
- package/lib/module/core/ZoneRegistry.js.map +0 -1
- package/lib/module/core/systemPrompt.js.map +0 -1
- package/lib/module/core/types.js.map +0 -1
- package/lib/module/hooks/useAction.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/plugin/withAppIntents.js.map +0 -1
- package/lib/module/providers/GeminiProvider.js.map +0 -1
- package/lib/module/providers/OpenAIProvider.js.map +0 -1
- package/lib/module/providers/ProviderFactory.js.map +0 -1
- package/lib/module/services/AudioInputService.js.map +0 -1
- package/lib/module/services/AudioOutputService.js.map +0 -1
- package/lib/module/services/KnowledgeBaseService.js.map +0 -1
- package/lib/module/services/VoiceService.js.map +0 -1
- package/lib/module/services/flags/FlagService.js.map +0 -1
- package/lib/module/services/telemetry/MobileAI.js.map +0 -1
- package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
- package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
- package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
- package/lib/module/services/telemetry/device.js.map +0 -1
- package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
- package/lib/module/services/telemetry/index.js.map +0 -1
- package/lib/module/services/telemetry/types.js.map +0 -1
- package/lib/module/support/CSATSurvey.js.map +0 -1
- package/lib/module/support/EscalationEventSource.js.map +0 -1
- package/lib/module/support/EscalationSocket.js.map +0 -1
- package/lib/module/support/SupportChatModal.js.map +0 -1
- package/lib/module/support/SupportGreeting.js.map +0 -1
- package/lib/module/support/TicketStore.js.map +0 -1
- package/lib/module/support/escalateTool.js.map +0 -1
- package/lib/module/support/index.js.map +0 -1
- package/lib/module/support/supportPrompt.js.map +0 -1
- package/lib/module/support/types.js.map +0 -1
- package/lib/module/tools/datePickerTool.js.map +0 -1
- package/lib/module/tools/guideTool.js.map +0 -1
- package/lib/module/tools/index.js.map +0 -1
- package/lib/module/tools/keyboardTool.js.map +0 -1
- package/lib/module/tools/longPressTool.js.map +0 -1
- package/lib/module/tools/pickerTool.js.map +0 -1
- package/lib/module/tools/restoreTool.js.map +0 -1
- package/lib/module/tools/scrollTool.js.map +0 -1
- package/lib/module/tools/simplifyTool.js.map +0 -1
- package/lib/module/tools/sliderTool.js.map +0 -1
- package/lib/module/tools/tapTool.js.map +0 -1
- package/lib/module/tools/typeTool.js.map +0 -1
- package/lib/module/tools/types.js.map +0 -1
- package/lib/module/types/jsx.d.js.map +0 -1
- package/lib/module/utils/audioUtils.js.map +0 -1
- package/lib/module/utils/logger.js.map +0 -1
- package/lib/typescript/babel.config.d.ts.map +0 -1
- package/lib/typescript/bin/generate-map.d.cts.map +0 -1
- package/lib/typescript/eslint.config.d.mts.map +0 -1
- package/lib/typescript/generate-map.d.ts.map +0 -1
- package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
- package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
- package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
- package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
- package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
- package/lib/typescript/src/components/Icons.d.ts.map +0 -1
- package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
- package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
- package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
- package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
- package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
- package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
- package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
- package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
- package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
- package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
- package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
- package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
- package/lib/typescript/src/core/types.d.ts.map +0 -1
- package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
- package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
- package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
- package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
- package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
- package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
- package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
- package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
- package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
- package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
- package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
- package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
- package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
- package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
- package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
- package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
- package/lib/typescript/src/support/index.d.ts.map +0 -1
- package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
- package/lib/typescript/src/support/types.d.ts.map +0 -1
- package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/index.d.ts.map +0 -1
- package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/types.d.ts.map +0 -1
- package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
- package/lib/typescript/src/utils/logger.d.ts.map +0 -1
- package/src/__cli_tmp__.tsx +0 -9
- package/src/cli/analyzers/chain-analyzer.ts +0 -183
- package/src/cli/extractors/ai-extractor.ts +0 -6
- package/src/cli/extractors/ast-extractor.ts +0 -551
- package/src/cli/generate-intents.ts +0 -140
- package/src/cli/generate-map.ts +0 -121
- package/src/cli/generate-swift.ts +0 -116
- package/src/cli/scanners/expo-scanner.ts +0 -203
- package/src/cli/scanners/rn-scanner.ts +0 -445
- package/src/components/AIAgent.tsx +0 -1716
- package/src/components/AIZone.tsx +0 -147
- package/src/components/AgentChatBar.tsx +0 -1143
- package/src/components/AgentErrorBoundary.tsx +0 -78
- package/src/components/AgentOverlay.tsx +0 -73
- package/src/components/DiscoveryTooltip.tsx +0 -148
- package/src/components/HighlightOverlay.tsx +0 -136
- package/src/components/Icons.tsx +0 -253
- package/src/components/ProactiveHint.tsx +0 -145
- package/src/components/cards/InfoCard.tsx +0 -58
- package/src/components/cards/ReviewSummary.tsx +0 -76
- package/src/config/endpoints.ts +0 -22
- package/src/core/ActionRegistry.ts +0 -105
- package/src/core/AgentRuntime.ts +0 -1471
- package/src/core/FiberTreeWalker.ts +0 -930
- package/src/core/IdleDetector.ts +0 -72
- package/src/core/MCPBridge.ts +0 -163
- package/src/core/ScreenDehydrator.ts +0 -53
- package/src/core/ZoneRegistry.ts +0 -44
- package/src/core/systemPrompt.ts +0 -431
- package/src/core/types.ts +0 -521
- package/src/hooks/useAction.ts +0 -182
- package/src/index.ts +0 -83
- package/src/plugin/withAppIntents.ts +0 -98
- package/src/providers/GeminiProvider.ts +0 -357
- package/src/providers/OpenAIProvider.ts +0 -379
- package/src/providers/ProviderFactory.ts +0 -36
- package/src/services/AudioInputService.ts +0 -226
- package/src/services/AudioOutputService.ts +0 -236
- package/src/services/KnowledgeBaseService.ts +0 -156
- package/src/services/VoiceService.ts +0 -451
- package/src/services/flags/FlagService.ts +0 -137
- package/src/services/telemetry/MobileAI.ts +0 -66
- package/src/services/telemetry/PiiScrubber.ts +0 -17
- package/src/services/telemetry/TelemetryService.ts +0 -323
- package/src/services/telemetry/TouchAutoCapture.ts +0 -165
- package/src/services/telemetry/device.ts +0 -93
- package/src/services/telemetry/deviceMetadata.ts +0 -13
- package/src/services/telemetry/index.ts +0 -13
- package/src/services/telemetry/types.ts +0 -75
- package/src/support/CSATSurvey.tsx +0 -304
- package/src/support/EscalationEventSource.ts +0 -190
- package/src/support/EscalationSocket.ts +0 -152
- package/src/support/SupportChatModal.tsx +0 -563
- package/src/support/SupportGreeting.tsx +0 -161
- package/src/support/TicketStore.ts +0 -100
- package/src/support/escalateTool.ts +0 -174
- package/src/support/index.ts +0 -29
- package/src/support/supportPrompt.ts +0 -55
- package/src/support/types.ts +0 -155
- package/src/tools/datePickerTool.ts +0 -60
- package/src/tools/guideTool.ts +0 -76
- package/src/tools/index.ts +0 -20
- package/src/tools/keyboardTool.ts +0 -30
- package/src/tools/longPressTool.ts +0 -61
- package/src/tools/pickerTool.ts +0 -115
- package/src/tools/restoreTool.ts +0 -33
- package/src/tools/scrollTool.ts +0 -156
- package/src/tools/simplifyTool.ts +0 -33
- package/src/tools/sliderTool.ts +0 -65
- package/src/tools/tapTool.ts +0 -93
- package/src/tools/typeTool.ts +0 -113
- package/src/tools/types.ts +0 -58
- package/src/types/jsx.d.ts +0 -20
- package/src/utils/audioUtils.ts +0 -54
- 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
|
-
}
|