Skip to content

Commit c8cb34e

Browse files
committed
fix(ios): keep the simctl device-list parser in the already-eager simctl module
Extracting the shared simctl-list-devices parser into its own module added a new static edge to platform-apple/src/core/simulator.ts, tripping the simulator-facade eager-closure budget (24 -> 25). Fold the parser into core/simctl.ts, which simulator.ts already evaluates, instead of giving it a new file.
1 parent 47edaa9 commit c8cb34e

7 files changed

Lines changed: 65 additions & 68 deletions

File tree

‎packages/platform-apple/src/core/__tests__/simctl-device-list.test.ts‎

Lines changed: 0 additions & 42 deletions
This file was deleted.

‎packages/platform-apple/src/core/__tests__/simctl.test.ts‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import assert from 'node:assert/strict';
33
import {
44
buildSimctlArgs,
55
buildSimctlArgsForDevice,
6+
readSimctlDevicesByRuntime,
7+
readSimctlDeviceState,
68
scopeSimctlArgs,
79
scopeSimctlArgsForDevice,
810
} from '../simctl.ts';
@@ -82,3 +84,42 @@ test('scopeSimctlArgsForDevice scopes simulators only', () => {
8284
'sim-1',
8385
]);
8486
});
87+
88+
const LISTING = JSON.stringify({
89+
devices: {
90+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
91+
{ udid: 'sim-a', state: 'Shutdown', name: 'iPhone 16' },
92+
],
93+
'com.apple.CoreSimulator.SimRuntime.iOS-26-0': [
94+
{ udid: 'sim-b', state: 'Booted', name: 'iPhone 17' },
95+
],
96+
},
97+
});
98+
99+
test('readSimctlDeviceState reports the listed state of the requested simulator', () => {
100+
assert.equal(readSimctlDeviceState(LISTING, 'sim-b'), 'Booted');
101+
assert.equal(readSimctlDeviceState(LISTING, 'sim-a'), 'Shutdown');
102+
});
103+
104+
test('readSimctlDeviceState is null for an unlisted, unreadable, or empty listing', () => {
105+
assert.equal(readSimctlDeviceState(LISTING, 'sim-missing'), null);
106+
assert.equal(readSimctlDeviceState('not json', 'sim-b'), null);
107+
assert.equal(readSimctlDeviceState('{}', 'sim-b'), null);
108+
assert.equal(readSimctlDeviceState(JSON.stringify({ devices: { runtime: {} } }), 'sim-b'), null);
109+
});
110+
111+
test('readSimctlDevicesByRuntime keys each device list by its runtime', () => {
112+
const devicesByRuntime = readSimctlDevicesByRuntime(LISTING);
113+
assert.deepEqual(
114+
Object.entries(devicesByRuntime).map(([runtime, devices]) => [
115+
runtime,
116+
devices.map(({ udid }) => udid),
117+
]),
118+
[
119+
['com.apple.CoreSimulator.SimRuntime.iOS-18-0', ['sim-a']],
120+
['com.apple.CoreSimulator.SimRuntime.iOS-26-0', ['sim-b']],
121+
],
122+
);
123+
assert.deepEqual(readSimctlDevicesByRuntime('{}'), {});
124+
assert.throws(() => readSimctlDevicesByRuntime('not json'), SyntaxError);
125+
});

‎packages/platform-apple/src/core/simctl-device-list.ts‎

Lines changed: 0 additions & 20 deletions
This file was deleted.

‎packages/platform-apple/src/core/simctl.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,24 @@ export function runSimctlForDevice(
4141
): Promise<ExecResult> {
4242
return runXcrun(buildSimctlArgsForDevice(device, args), options);
4343
}
44+
45+
type SimctlListedDevice = { udid?: string; state?: string };
46+
47+
/** The runtime-keyed device lists of `simctl list devices -j` output; throws unless it is a JSON object. */
48+
export function readSimctlDevicesByRuntime(stdout: string): Record<string, SimctlListedDevice[]> {
49+
const payload = JSON.parse(stdout) as { devices?: Record<string, SimctlListedDevice[]> };
50+
return payload.devices ?? {};
51+
}
52+
53+
/** The listed state of one simulator; null when the listing is unreadable or omits the device. */
54+
export function readSimctlDeviceState(stdout: string, udid: string): string | null {
55+
try {
56+
for (const devices of Object.values(readSimctlDevicesByRuntime(stdout))) {
57+
const match = devices.find((entry) => entry.udid === udid);
58+
if (match) return match.state ?? null;
59+
}
60+
return null;
61+
} catch {
62+
return null;
63+
}
64+
}

‎packages/platform-apple/src/core/simulator.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import {
1212
IOS_SIMCTL_LIST_TIMEOUT_MS,
1313
IOS_SIMULATOR_FOCUS_TIMEOUT_MS,
1414
} from './config.ts';
15-
import { buildSimctlArgsForDevice } from './simctl.ts';
16-
import { readSimctlDeviceState } from './simctl-device-list.ts';
15+
import { buildSimctlArgsForDevice, readSimctlDeviceState } from './simctl.ts';
1716
import { runAppleToolCommand, runXcrun } from './tool-provider.ts';
1817

1918
const IOS_SIMULATOR_HOST_APPS = ['Simulator'] as const;

‎packages/platform-apple/src/simulator-state.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { DeviceInfo } from '@agent-device/kernel/device';
22
import type { AppleToolHost } from '@agent-device/contracts/platform-runtime-host';
3-
import { scopeSimctlArgsForDevice } from './core/simctl.ts';
4-
import { readSimctlDeviceState } from './core/simctl-device-list.ts';
3+
import { readSimctlDeviceState, scopeSimctlArgsForDevice } from './core/simctl.ts';
54

65
export async function getSimulatorState(
76
appleTools: AppleToolHost,

‎packages/platform-apple/src/snapshot-target.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import type { DeviceInfo } from '@agent-device/kernel/device';
22
import { AppError } from '@agent-device/kernel/errors';
33
import { createDetachedAttempts, waitForDetachedAttempt } from './detached-attempt.ts';
4-
import { runSimctlForDevice } from './core/simctl.ts';
5-
import { readSimctlDevicesByRuntime } from './core/simctl-device-list.ts';
4+
import { readSimctlDevicesByRuntime, runSimctlForDevice } from './core/simctl.ts';
65
import { readSnapshotTargetProcessStartTime } from './snapshot-process.ts';
76

87
/** Identity re-check of a cached target: one local `ps`, never CoreSimulator IPC. */

0 commit comments

Comments
 (0)