Skip to content

Commit 2c58db7

Browse files
committed
refactor: deeper structural simplification pass
Bigger wins from restructuring, not just mechanical dedup: - cli.ts: move logTailStopper to try/finally (eliminates 28 duplicate calls), extract writeCommandCliOutput/writeLogsCliOutput/writeNetworkCliOutput from 350-line if/else chain, fix remaining throwDaemonError site - session-store.ts: replace 67-line sanitizeFlags destructure/reconstruct with 10-line pick-from-array loop - record-trace: extract finalizeRecordingOverlay helper, replacing 4 copies of the telemetry+overlay block across ios/android/recording files - Deduplicate normalizeText (finders.ts + selectors-match.ts) - Fix isEnvTruthy to preserve whitespace-tolerant parsing (.trim())
1 parent 4814eb7 commit 2c58db7

9 files changed

Lines changed: 302 additions & 509 deletions

File tree

src/cli.ts

Lines changed: 219 additions & 357 deletions
Large diffs are not rendered by default.

src/daemon/handlers/record-trace-android.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import fs from 'node:fs';
22
import { emitDiagnostic } from '../../utils/diagnostics.ts';
3-
import { getRecordingOverlaySupportWarning } from '../../recording/overlay.ts';
43
import type { DaemonResponse, SessionState } from '../types.ts';
5-
import { persistRecordingTelemetry } from '../recording-telemetry.ts';
6-
import { formatRecordTraceError, formatRecordTraceExecFailure } from '../record-trace-errors.ts';
4+
import { formatRecordTraceExecFailure } from '../record-trace-errors.ts';
75
import type { RecordTraceDeps } from './record-trace-recording.ts';
6+
import { finalizeRecordingOverlay } from './record-trace-finalize.ts';
87
import { errorResponse } from './response.ts';
98

109
const ANDROID_REMOTE_FILE_POLL_MS = 250;
@@ -361,25 +360,11 @@ export async function stopAndroidRecording(params: {
361360
return errorResponse('COMMAND_FAILED', copyError);
362361
}
363362

364-
persistRecordingTelemetry({
363+
await finalizeRecordingOverlay({
365364
recording,
365+
deps,
366+
targetLabel: 'Android recording',
366367
});
367-
if (recording.showTouches && recording.telemetryPath) {
368-
const overlaySupportWarning = getRecordingOverlaySupportWarning();
369-
if (overlaySupportWarning) {
370-
recording.overlayWarning = overlaySupportWarning;
371-
} else {
372-
try {
373-
await deps.overlayRecordingTouches({
374-
videoPath: recording.outPath,
375-
telemetryPath: recording.telemetryPath,
376-
targetLabel: 'Android recording',
377-
});
378-
} catch (error) {
379-
recording.overlayWarning = `failed to overlay recording touches: ${formatRecordTraceError(error)}`;
380-
}
381-
}
382-
}
383368
}
384369

385370
await cleanupRemoteRecording();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { persistRecordingTelemetry } from '../recording-telemetry.ts';
2+
import { getRecordingOverlaySupportWarning } from '../../recording/overlay.ts';
3+
import { formatRecordTraceError } from '../record-trace-errors.ts';
4+
import type { RecordTraceDeps } from './record-trace-recording.ts';
5+
6+
type FinalizeRecordingOverlayParams = {
7+
recording: {
8+
outPath: string;
9+
gestureEvents: import('../types.ts').RecordingGestureEvent[];
10+
telemetryPath?: string;
11+
showTouches: boolean;
12+
overlayWarning?: string;
13+
};
14+
deps: Pick<RecordTraceDeps, 'overlayRecordingTouches'>;
15+
trimStartMs?: number;
16+
targetLabel: string;
17+
};
18+
19+
export async function finalizeRecordingOverlay(
20+
params: FinalizeRecordingOverlayParams,
21+
): Promise<void> {
22+
const { recording, deps, trimStartMs, targetLabel } = params;
23+
24+
const telemetryPath = persistRecordingTelemetry({
25+
recording,
26+
trimStartMs,
27+
});
28+
29+
if (recording.showTouches) {
30+
const overlaySupportWarning = getRecordingOverlaySupportWarning();
31+
if (overlaySupportWarning) {
32+
recording.overlayWarning = overlaySupportWarning;
33+
} else {
34+
try {
35+
await deps.overlayRecordingTouches({
36+
videoPath: recording.outPath,
37+
telemetryPath,
38+
targetLabel,
39+
});
40+
} catch (error) {
41+
recording.overlayWarning = `failed to overlay recording touches: ${formatRecordTraceError(error)}`;
42+
}
43+
}
44+
}
45+
}

src/daemon/handlers/record-trace-ios.ts

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { SessionStore } from '../session-store.ts';
22
import type { DaemonRequest, DaemonResponse, SessionState } from '../types.ts';
33
import { emitDiagnostic } from '../../utils/diagnostics.ts';
4-
import { persistRecordingTelemetry } from '../recording-telemetry.ts';
54
import { IOS_RUNNER_CONTAINER_BUNDLE_IDS } from '../../platforms/ios/runner-client.ts';
6-
import { getRecordingOverlaySupportWarning } from '../../recording/overlay.ts';
75
import { formatRecordTraceError } from '../record-trace-errors.ts';
86
import type { RecordTraceDeps, RecordingBase } from './record-trace-recording.ts';
7+
import { finalizeRecordingOverlay } from './record-trace-finalize.ts';
98
import { errorResponse } from './response.ts';
109

1110
export function normalizeAppBundleId(session: SessionState): string | undefined {
@@ -319,28 +318,13 @@ export async function stopIosDeviceRecording(params: {
319318
});
320319
}
321320

322-
const telemetryPath = persistRecordingTelemetry({
321+
await finalizeRecordingOverlay({
323322
recording,
323+
deps,
324324
trimStartMs,
325+
targetLabel: 'iOS recording',
325326
});
326327

327-
if (recording.showTouches) {
328-
const overlaySupportWarning = getRecordingOverlaySupportWarning();
329-
if (overlaySupportWarning) {
330-
recording.overlayWarning = overlaySupportWarning;
331-
} else {
332-
try {
333-
await deps.overlayRecordingTouches({
334-
videoPath: recording.outPath,
335-
telemetryPath,
336-
targetLabel: 'iOS recording',
337-
});
338-
} catch (error) {
339-
recording.overlayWarning = `failed to overlay recording touches: ${formatRecordTraceError(error)}`;
340-
}
341-
}
342-
}
343-
344328
return null;
345329
}
346330

@@ -375,26 +359,11 @@ export async function stopMacOsRecording(params: {
375359
});
376360
}
377361

378-
const telemetryPath = persistRecordingTelemetry({
362+
await finalizeRecordingOverlay({
379363
recording,
364+
deps,
365+
targetLabel: 'macOS recording',
380366
});
381367

382-
if (recording.showTouches) {
383-
const overlaySupportWarning = getRecordingOverlaySupportWarning();
384-
if (overlaySupportWarning) {
385-
recording.overlayWarning = overlaySupportWarning;
386-
} else {
387-
try {
388-
await deps.overlayRecordingTouches({
389-
videoPath: recording.outPath,
390-
telemetryPath,
391-
targetLabel: 'macOS recording',
392-
});
393-
} catch (error) {
394-
recording.overlayWarning = `failed to overlay recording touches: ${formatRecordTraceError(error)}`;
395-
}
396-
}
397-
}
398-
399368
return null;
400369
}

src/daemon/handlers/record-trace-recording.ts

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@ import type {
1313
} from '../types.ts';
1414
import { runCmd, runCmdBackground } from '../../utils/exec.ts';
1515
import { isPlayableVideo, waitForStableFile } from '../../utils/video.ts';
16-
import { deriveRecordingTelemetryPath, persistRecordingTelemetry } from '../recording-telemetry.ts';
16+
import { deriveRecordingTelemetryPath } from '../recording-telemetry.ts';
1717
import { runIosRunnerCommand } from '../../platforms/ios/runner-client.ts';
18-
import {
19-
getRecordingOverlaySupportWarning,
20-
overlayRecordingTouches,
21-
trimRecordingStart,
22-
} from '../../recording/overlay.ts';
18+
import { overlayRecordingTouches, trimRecordingStart } from '../../recording/overlay.ts';
2319
import { buildSimctlArgsForDevice } from '../../platforms/ios/simctl.ts';
24-
import { formatRecordTraceError, formatRecordTraceExecFailure } from '../record-trace-errors.ts';
20+
import { formatRecordTraceExecFailure } from '../record-trace-errors.ts';
21+
import { finalizeRecordingOverlay } from './record-trace-finalize.ts';
2522
import { errorResponse, unsupportedOperationResponse } from './response.ts';
2623
import { startAndroidRecording, stopAndroidRecording } from './record-trace-android.ts';
2724
import {
@@ -302,27 +299,12 @@ async function stopNonRunnerRecording(params: {
302299
);
303300
}
304301

305-
const telemetryPath = persistRecordingTelemetry({
302+
await finalizeRecordingOverlay({
306303
recording,
304+
deps,
305+
targetLabel: 'iOS recording',
307306
});
308307

309-
if (recording.showTouches) {
310-
const overlaySupportWarning = getRecordingOverlaySupportWarning();
311-
if (overlaySupportWarning) {
312-
recording.overlayWarning = overlaySupportWarning;
313-
} else {
314-
try {
315-
await deps.overlayRecordingTouches({
316-
videoPath: recording.outPath,
317-
telemetryPath,
318-
targetLabel: 'iOS recording',
319-
});
320-
} catch (error) {
321-
recording.overlayWarning = `failed to overlay recording touches: ${formatRecordTraceError(error)}`;
322-
}
323-
}
324-
}
325-
326308
return null;
327309
}
328310

src/daemon/selectors-match.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Platform } from '../utils/device.ts';
22
import type { SnapshotNode } from '../utils/snapshot.ts';
33
import { extractNodeText, isFillableType, normalizeType } from './snapshot-processing.ts';
4+
import { normalizeText } from '../utils/finders.ts';
45
import type { Selector, SelectorTerm } from './selectors-parse.ts';
56

67
export function matchesSelector(
@@ -58,6 +59,3 @@ function textEquals(value: string | undefined, query: string): boolean {
5859
return normalizeText(value ?? '') === normalizeText(query);
5960
}
6061

61-
function normalizeText(value: string): string {
62-
return value.trim().toLowerCase().replace(/\s+/g, ' ');
63-
}

src/daemon/session-store.ts

Lines changed: 16 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -216,72 +216,24 @@ export class SessionStore {
216216
}
217217
}
218218

219+
const SANITIZED_FLAG_KEYS = [
220+
'platform', 'device', 'udid', 'serial', 'out', 'verbose',
221+
'metroHost', 'metroPort', 'bundleUrl', 'launchUrl',
222+
'snapshotInteractiveOnly', 'snapshotCompact', 'snapshotDepth', 'snapshotScope', 'snapshotRaw',
223+
'screenshotFullscreen', 'relaunch', 'saveScript', 'noRecord',
224+
'fps', 'hideTouches', 'count', 'intervalMs', 'delayMs', 'holdMs', 'jitterPx',
225+
'doubleTap', 'clickButton', 'pauseMs', 'pattern',
226+
] as const;
227+
219228
function sanitizeFlags(flags: CommandFlags | undefined): SessionAction['flags'] {
220229
if (!flags) return {};
221-
const {
222-
platform,
223-
device,
224-
udid,
225-
serial,
226-
out,
227-
verbose,
228-
metroHost,
229-
metroPort,
230-
bundleUrl,
231-
launchUrl,
232-
snapshotInteractiveOnly,
233-
snapshotCompact,
234-
snapshotDepth,
235-
snapshotScope,
236-
snapshotRaw,
237-
screenshotFullscreen,
238-
relaunch,
239-
saveScript,
240-
noRecord,
241-
fps,
242-
hideTouches,
243-
count,
244-
intervalMs,
245-
delayMs,
246-
holdMs,
247-
jitterPx,
248-
doubleTap,
249-
clickButton,
250-
pauseMs,
251-
pattern,
252-
} = flags;
253-
return {
254-
platform,
255-
device,
256-
udid,
257-
serial,
258-
out,
259-
verbose,
260-
metroHost,
261-
metroPort,
262-
bundleUrl,
263-
launchUrl,
264-
snapshotInteractiveOnly,
265-
snapshotCompact,
266-
snapshotDepth,
267-
snapshotScope,
268-
snapshotRaw,
269-
screenshotFullscreen,
270-
relaunch,
271-
saveScript,
272-
noRecord,
273-
fps,
274-
hideTouches,
275-
count,
276-
intervalMs,
277-
delayMs,
278-
holdMs,
279-
jitterPx,
280-
doubleTap,
281-
clickButton,
282-
pauseMs,
283-
pattern,
284-
};
230+
const result: Record<string, unknown> = {};
231+
for (const key of SANITIZED_FLAG_KEYS) {
232+
if (flags[key] !== undefined) {
233+
result[key] = flags[key];
234+
}
235+
}
236+
return result as SessionAction['flags'];
285237
}
286238

287239
function formatScript(session: SessionState, actions: SessionAction[]): string {

src/utils/finders.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ function matchRole(value: string | undefined, query: string): number {
8585
return 0;
8686
}
8787

88-
function normalizeText(value: string): string {
88+
export function normalizeText(value: string): string {
8989
return value.trim().toLowerCase().replace(/\s+/g, ' ');
9090
}
9191

src/utils/retry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type RetryTelemetryEvent = {
4343
const RETRY_LOGS_ENABLED = isEnvTruthy(process.env.AGENT_DEVICE_RETRY_LOGS);
4444

4545
export function isEnvTruthy(value: string | undefined): boolean {
46-
return ['1', 'true', 'yes', 'on'].includes((value ?? '').toLowerCase());
46+
return ['1', 'true', 'yes', 'on'].includes((value ?? '').trim().toLowerCase());
4747
}
4848

4949
export const TIMEOUT_PROFILES: Record<string, TimeoutProfile> = {

0 commit comments

Comments
 (0)