@sitepong/fastnode 0.1.0
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/README.md +81 -0
- package/bin/fastnode.js +13 -0
- package/bin/fastnode.ts +5 -0
- package/dist/actions/index.cjs +7405 -0
- package/dist/actions/index.cjs.map +1 -0
- package/dist/actions/index.d.cts +15 -0
- package/dist/actions/index.d.ts +15 -0
- package/dist/actions/index.mjs +7377 -0
- package/dist/actions/index.mjs.map +1 -0
- package/dist/cert/index.cjs +219 -0
- package/dist/cert/index.cjs.map +1 -0
- package/dist/cert/index.d.cts +4 -0
- package/dist/cert/index.d.ts +4 -0
- package/dist/cert/index.mjs +191 -0
- package/dist/cert/index.mjs.map +1 -0
- package/dist/cert-BmJGtYtb.d.cts +27 -0
- package/dist/cert-owkOFNW8.d.ts +27 -0
- package/dist/cli/index.cjs +7998 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +9 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.mjs +7972 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/index.cjs +2592 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +2 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.mjs +2582 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/context-CymLkfrS.d.cts +13 -0
- package/dist/context-CymLkfrS.d.ts +13 -0
- package/dist/core/index.cjs +281 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.mjs +254 -0
- package/dist/core/index.mjs.map +1 -0
- package/dist/deliver/index.cjs +328 -0
- package/dist/deliver/index.cjs.map +1 -0
- package/dist/deliver/index.d.cts +3 -0
- package/dist/deliver/index.d.ts +3 -0
- package/dist/deliver/index.mjs +322 -0
- package/dist/deliver/index.mjs.map +1 -0
- package/dist/enums-B609j2rb.d.cts +20 -0
- package/dist/enums-B609j2rb.d.ts +20 -0
- package/dist/frameit/index.cjs +247 -0
- package/dist/frameit/index.cjs.map +1 -0
- package/dist/frameit/index.d.cts +1 -0
- package/dist/frameit/index.d.ts +1 -0
- package/dist/frameit/index.mjs +242 -0
- package/dist/frameit/index.mjs.map +1 -0
- package/dist/gym/index.cjs +356 -0
- package/dist/gym/index.cjs.map +1 -0
- package/dist/gym/index.d.cts +2 -0
- package/dist/gym/index.d.ts +2 -0
- package/dist/gym/index.mjs +346 -0
- package/dist/gym/index.mjs.map +1 -0
- package/dist/index-1Vu2cRQ2.d.ts +99 -0
- package/dist/index-A5MimeQk.d.ts +72 -0
- package/dist/index-B0yhu_LZ.d.ts +76 -0
- package/dist/index-B9yXicrQ.d.ts +62 -0
- package/dist/index-BFdNOmPJ.d.cts +53 -0
- package/dist/index-BLubSlgK.d.cts +1513 -0
- package/dist/index-BN0ubxjZ.d.ts +70 -0
- package/dist/index-BQJIJlK7.d.cts +70 -0
- package/dist/index-BYonklf3.d.cts +84 -0
- package/dist/index-BYonklf3.d.ts +84 -0
- package/dist/index-BimqCmY8.d.cts +78 -0
- package/dist/index-BimqCmY8.d.ts +78 -0
- package/dist/index-BoU8qt8r.d.cts +59 -0
- package/dist/index-BoU8qt8r.d.ts +59 -0
- package/dist/index-C2yG3wXA.d.cts +95 -0
- package/dist/index-C2yG3wXA.d.ts +95 -0
- package/dist/index-CR3BFPIz.d.cts +77 -0
- package/dist/index-CR3BFPIz.d.ts +77 -0
- package/dist/index-CWNLnSOL.d.cts +99 -0
- package/dist/index-Cp6cjtd-.d.cts +65 -0
- package/dist/index-Cp6cjtd-.d.ts +65 -0
- package/dist/index-D1Izm7qt.d.ts +1513 -0
- package/dist/index-D5eihzwM.d.cts +76 -0
- package/dist/index-DImN9PWc.d.ts +155 -0
- package/dist/index-DfCUVJX1.d.cts +62 -0
- package/dist/index-DfirmFbC.d.ts +32 -0
- package/dist/index-DkvinY7_.d.ts +54 -0
- package/dist/index-DrUpRXRG.d.cts +155 -0
- package/dist/index-EcVvViW8.d.cts +72 -0
- package/dist/index-HRiaaX-Q.d.cts +54 -0
- package/dist/index-TfXqwuac.d.ts +53 -0
- package/dist/index-lt819Jgj.d.cts +32 -0
- package/dist/index.cjs +8464 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.mjs +8410 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lane/index.cjs +7641 -0
- package/dist/lane/index.cjs.map +1 -0
- package/dist/lane/index.d.cts +51 -0
- package/dist/lane/index.d.ts +51 -0
- package/dist/lane/index.mjs +7603 -0
- package/dist/lane/index.mjs.map +1 -0
- package/dist/match/index.cjs +942 -0
- package/dist/match/index.cjs.map +1 -0
- package/dist/match/index.d.cts +5 -0
- package/dist/match/index.d.ts +5 -0
- package/dist/match/index.mjs +913 -0
- package/dist/match/index.mjs.map +1 -0
- package/dist/pem/index.cjs +195 -0
- package/dist/pem/index.cjs.map +1 -0
- package/dist/pem/index.d.cts +3 -0
- package/dist/pem/index.d.ts +3 -0
- package/dist/pem/index.mjs +170 -0
- package/dist/pem/index.mjs.map +1 -0
- package/dist/pilot/index.cjs +206 -0
- package/dist/pilot/index.cjs.map +1 -0
- package/dist/pilot/index.d.cts +3 -0
- package/dist/pilot/index.d.ts +3 -0
- package/dist/pilot/index.mjs +196 -0
- package/dist/pilot/index.mjs.map +1 -0
- package/dist/precheck/index.cjs +277 -0
- package/dist/precheck/index.cjs.map +1 -0
- package/dist/precheck/index.d.cts +3 -0
- package/dist/precheck/index.d.ts +3 -0
- package/dist/precheck/index.mjs +274 -0
- package/dist/precheck/index.mjs.map +1 -0
- package/dist/produce/index.cjs +200 -0
- package/dist/produce/index.cjs.map +1 -0
- package/dist/produce/index.d.cts +3 -0
- package/dist/produce/index.d.ts +3 -0
- package/dist/produce/index.mjs +191 -0
- package/dist/produce/index.mjs.map +1 -0
- package/dist/scan/index.cjs +187 -0
- package/dist/scan/index.cjs.map +1 -0
- package/dist/scan/index.d.cts +1 -0
- package/dist/scan/index.d.ts +1 -0
- package/dist/scan/index.mjs +183 -0
- package/dist/scan/index.mjs.map +1 -0
- package/dist/sigh/index.cjs +203 -0
- package/dist/sigh/index.cjs.map +1 -0
- package/dist/sigh/index.d.cts +3 -0
- package/dist/sigh/index.d.ts +3 -0
- package/dist/sigh/index.mjs +198 -0
- package/dist/sigh/index.mjs.map +1 -0
- package/dist/snapshot/index.cjs +448 -0
- package/dist/snapshot/index.cjs.map +1 -0
- package/dist/snapshot/index.d.cts +1 -0
- package/dist/snapshot/index.d.ts +1 -0
- package/dist/snapshot/index.mjs +438 -0
- package/dist/snapshot/index.mjs.map +1 -0
- package/dist/trainer/index.cjs +395 -0
- package/dist/trainer/index.cjs.map +1 -0
- package/dist/trainer/index.d.cts +1 -0
- package/dist/trainer/index.d.ts +1 -0
- package/dist/trainer/index.mjs +372 -0
- package/dist/trainer/index.mjs.map +1 -0
- package/dist/xcode/index.cjs +188 -0
- package/dist/xcode/index.cjs.map +1 -0
- package/dist/xcode/index.d.cts +1 -0
- package/dist/xcode/index.d.ts +1 -0
- package/dist/xcode/index.mjs +176 -0
- package/dist/xcode/index.mjs.map +1 -0
- package/package.json +223 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/xcode/platform.ts","../../src/snapshot/simulator.ts","../../src/snapshot/index.ts"],"names":["join","existsSync","mkdirSync","writeFileSync","promisify","execFile","execFileAsync","setInterfaceStyle","spawn","readdirSync","extname","basename","copyFileSync"],"mappings":"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","file":"index.cjs","sourcesContent":["export function requireMacOS(feature: string): void {\n if (process.platform !== \"darwin\") {\n throw new Error(\n `${feature} requires macOS. This operation uses Xcode command-line tools ` +\n `which are not available on ${process.platform}.`\n );\n }\n}\n\nexport function isMacOS(): boolean {\n return process.platform === \"darwin\";\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { requireMacOS } from \"../xcode/platform.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface SimDevice {\n udid: string;\n name: string;\n state: \"Booted\" | \"Shutdown\" | \"Shutting Down\" | \"Creating\";\n isAvailable: boolean;\n runtime: string;\n deviceTypeIdentifier: string;\n}\n\ninterface SimctlDevicesJson {\n devices: Record<\n string,\n Array<{\n udid: string;\n name: string;\n state: string;\n isAvailable: boolean;\n deviceTypeIdentifier: string;\n }>\n >;\n}\n\n// ── Simulator Listing & Lookup ─────────────────────────────────────────────\n\nexport async function listSimulators(): Promise<SimDevice[]> {\n requireMacOS(\"Simulator management\");\n const { stdout } = await execFileAsync(\"xcrun\", [\"simctl\", \"list\", \"devices\", \"-j\"]);\n const parsed: SimctlDevicesJson = JSON.parse(stdout);\n const devices: SimDevice[] = [];\n for (const [runtimeId, runtimeDevices] of Object.entries(parsed.devices)) {\n for (const dev of runtimeDevices) {\n devices.push({\n udid: dev.udid,\n name: dev.name,\n state: dev.state as SimDevice[\"state\"],\n isAvailable: dev.isAvailable,\n runtime: runtimeId,\n deviceTypeIdentifier: dev.deviceTypeIdentifier,\n });\n }\n }\n return devices;\n}\n\nexport async function findDevice(\n deviceName: string,\n runtimeFilter?: string,\n): Promise<SimDevice | null> {\n const devices = await listSimulators();\n const candidates = devices.filter((d) => {\n if (!d.isAvailable) return false;\n if (d.name !== deviceName) return false;\n if (runtimeFilter && !d.runtime.includes(runtimeFilter)) return false;\n return true;\n });\n if (candidates.length === 0) return null;\n const booted = candidates.find((d) => d.state === \"Booted\");\n return booted ?? candidates[0];\n}\n\n// ── Boot / Shutdown / Erase ────────────────────────────────────────────────\n\nexport async function bootSimulator(udid: string): Promise<void> {\n requireMacOS(\"Simulator management\");\n const devices = await listSimulators();\n const device = devices.find((d) => d.udid === udid);\n if (device?.state === \"Booted\") return;\n await execFileAsync(\"xcrun\", [\"simctl\", \"boot\", udid]);\n const deadline = Date.now() + 30_000;\n while (Date.now() < deadline) {\n const refreshed = await listSimulators();\n const current = refreshed.find((d) => d.udid === udid);\n if (current?.state === \"Booted\") return;\n await new Promise((r) => setTimeout(r, 1000));\n }\n}\n\nexport async function shutdownAll(): Promise<void> {\n requireMacOS(\"Simulator management\");\n await execFileAsync(\"xcrun\", [\"simctl\", \"shutdown\", \"all\"]);\n}\n\nexport async function eraseSimulator(udid: string): Promise<void> {\n requireMacOS(\"Simulator management\");\n const devices = await listSimulators();\n const device = devices.find((d) => d.udid === udid);\n if (device?.state === \"Booted\") {\n await execFileAsync(\"xcrun\", [\"simctl\", \"shutdown\", udid]);\n }\n await execFileAsync(\"xcrun\", [\"simctl\", \"erase\", udid]);\n}\n\n// ── Locale / Language ──────────────────────────────────────────────────────\n\nexport async function localizeSimulator(\n udid: string,\n language: string,\n locale?: string,\n): Promise<void> {\n requireMacOS(\"Simulator management\");\n const deviceDataPath = getDeviceDataPath(udid);\n const prefsDir = join(deviceDataPath, \"data\", \"Library\", \"Preferences\");\n const prefsFile = join(prefsDir, \".GlobalPreferences.plist\");\n if (!existsSync(prefsDir)) {\n mkdirSync(prefsDir, { recursive: true });\n }\n const effectiveLocale = locale ?? language.replace(\"-\", \"_\");\n const plistXml = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">',\n '<plist version=\"1.0\">',\n \"<dict>\",\n \" <key>AppleLanguages</key>\",\n \" <array>\",\n \" <string>\" + escapeXml(language) + \"</string>\",\n \" </array>\",\n \" <key>AppleLocale</key>\",\n \" <string>\" + escapeXml(effectiveLocale) + \"</string>\",\n \" <key>AppleKeyboards</key>\",\n \" <array>\",\n \" <string>\" + escapeXml(effectiveLocale) + \"@sw=QWERTY;hw=Automatic</string>\",\n \" </array>\",\n \" <key>AppleKeyboardsExpanded</key>\",\n \" <integer>1</integer>\",\n \"</dict>\",\n \"</plist>\",\n ].join(\"\\n\");\n writeFileSync(prefsFile, plistXml, \"utf-8\");\n try {\n await execFileAsync(\"plutil\", [\"-convert\", \"binary1\", prefsFile]);\n } catch {\n // XML plist is still readable\n }\n}\n\n// ── UI Customization ───────────────────────────────────────────────────────\n\nexport async function setInterfaceStyle(\n udid: string,\n style: \"light\" | \"dark\",\n): Promise<void> {\n requireMacOS(\"Simulator management\");\n const appearance = style === \"dark\" ? \"dark\" : \"light\";\n await execFileAsync(\"xcrun\", [\"simctl\", \"ui\", udid, \"appearance\", appearance]);\n}\n\nexport async function overrideStatusBar(\n udid: string,\n options?: {\n time?: string;\n batteryLevel?: number;\n batteryState?: \"charged\" | \"charging\" | \"discharging\";\n wifiMode?: \"active\" | \"searching\" | \"failed\";\n cellularMode?: \"active\" | \"searching\" | \"failed\" | \"notSupported\";\n dataNetwork?: \"wifi\" | \"3g\" | \"4g\" | \"lte\" | \"lte-a\" | \"lte+\" | \"5g\" | \"5g+\" | \"5g-uwb\";\n },\n): Promise<void> {\n requireMacOS(\"Simulator management\");\n const args = [\n \"simctl\", \"status_bar\", udid, \"override\",\n \"--time\", options?.time ?? \"9:41\",\n \"--batteryLevel\", String(options?.batteryLevel ?? 100),\n \"--batteryState\", options?.batteryState ?? \"charged\",\n \"--wifiMode\", options?.wifiMode ?? \"active\",\n \"--wifiBars\", \"3\",\n \"--cellularMode\", options?.cellularMode ?? \"active\",\n \"--cellularBars\", \"4\",\n ];\n if (options?.dataNetwork) {\n args.push(\"--dataNetwork\", options.dataNetwork);\n }\n await execFileAsync(\"xcrun\", args);\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\nfunction getDeviceDataPath(udid: string): string {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"/tmp\";\n return join(home, \"Library\", \"Developer\", \"CoreSimulator\", \"Devices\", udid);\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n","import { execFile, spawn } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { existsSync, mkdirSync, readdirSync, copyFileSync } from \"node:fs\";\nimport { join, basename, extname } from \"node:path\";\nimport { requireMacOS } from \"../xcode/platform.js\";\nimport {\n findDevice,\n bootSimulator,\n shutdownAll,\n localizeSimulator,\n overrideStatusBar,\n eraseSimulator,\n} from \"./simulator.js\";\nimport type { SimDevice } from \"./simulator.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ── Re-export simulator utilities ──────────────────────────────────────────\n\nexport {\n listSimulators,\n findDevice,\n bootSimulator,\n shutdownAll,\n eraseSimulator,\n localizeSimulator,\n setInterfaceStyle,\n overrideStatusBar,\n} from \"./simulator.js\";\n\nexport type { SimDevice } from \"./simulator.js\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface SnapshotOptions {\n scheme?: string;\n workspace?: string;\n project?: string;\n devices: string[];\n languages: string[];\n outputDirectory?: string;\n clearPreviousScreenshots?: boolean;\n launchArguments?: string[];\n concurrent?: boolean;\n numberOfRetries?: number;\n darkMode?: boolean;\n overrideStatusBar?: boolean;\n eraseSimulatorBeforeRun?: boolean;\n derivedDataPath?: string;\n testPlan?: string;\n configuration?: string;\n xcargs?: string;\n onOutput?: (chunk: string) => void;\n}\n\nexport interface ScreenshotResult {\n success: boolean;\n screenshots: Record<string, Record<string, string[]>>;\n failedDevices: string[];\n}\n\n// ── Main Entry Point ───────────────────────────────────────────────────────\n\n/**\n * Capture screenshots across a device x language matrix.\n *\n * Mirrors Fastlane snapshot's runner:\n * 1. Validate macOS\n * 2. Build device x language matrix\n * 3. For each combination: boot sim, set locale, run xcodebuild test, collect screenshots\n * 4. Return aggregated ScreenshotResult\n */\nexport async function captureScreenshots(\n options: SnapshotOptions,\n): Promise<ScreenshotResult> {\n requireMacOS(\"Screenshot capture\");\n\n // Validate required options\n if (!options.scheme && !options.workspace && !options.project) {\n throw new Error(\n \"At least one of scheme, workspace, or project must be specified\",\n );\n }\n if (options.devices.length === 0) {\n throw new Error(\"At least one device must be specified\");\n }\n if (options.languages.length === 0) {\n throw new Error(\"At least one language must be specified\");\n }\n\n const outputDir = options.outputDirectory ?? join(process.cwd(), \"screenshots\");\n const retries = options.numberOfRetries ?? 1;\n\n // Clear previous screenshots if requested\n if (options.clearPreviousScreenshots && existsSync(outputDir)) {\n const { rm } = await import(\"node:fs/promises\");\n await rm(outputDir, { recursive: true, force: true });\n }\n\n mkdirSync(outputDir, { recursive: true });\n\n const screenshots: Record<string, Record<string, string[]>> = {};\n const failedDevices: string[] = [];\n\n // Build the device x language matrix\n const matrix = buildMatrix(options.devices, options.languages);\n\n if (options.concurrent) {\n // Run all combinations in parallel\n const results = await Promise.allSettled(\n matrix.map((entry) =>\n runSingleCombination(entry, options, outputDir, retries),\n ),\n );\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n const entry = matrix[i];\n if (result.status === \"fulfilled\") {\n mergeScreenshots(screenshots, result.value);\n } else {\n const key = entry.device + \" / \" + entry.language;\n failedDevices.push(key);\n }\n }\n } else {\n // Run sequentially\n for (const entry of matrix) {\n try {\n const result = await runSingleCombination(\n entry,\n options,\n outputDir,\n retries,\n );\n mergeScreenshots(screenshots, result);\n } catch {\n const key = entry.device + \" / \" + entry.language;\n failedDevices.push(key);\n }\n }\n }\n\n return {\n success: failedDevices.length === 0,\n screenshots,\n failedDevices,\n };\n}\n\n// ── Internal: Matrix Construction ──────────────────────────────────────────\n\ninterface MatrixEntry {\n device: string;\n language: string;\n}\n\nfunction buildMatrix(devices: string[], languages: string[]): MatrixEntry[] {\n const entries: MatrixEntry[] = [];\n for (const device of devices) {\n for (const language of languages) {\n entries.push({ device, language });\n }\n }\n return entries;\n}\n\n// ── Internal: Single Combination Runner ────────────────────────────────────\n\nasync function runSingleCombination(\n entry: MatrixEntry,\n options: SnapshotOptions,\n outputDir: string,\n retries: number,\n): Promise<Record<string, Record<string, string[]>>> {\n const { device: deviceName, language } = entry;\n\n // Find the simulator device\n const simDevice = await findDevice(deviceName);\n if (!simDevice) {\n throw new Error(\"Simulator device not found: \" + deviceName);\n }\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n return await runOnSimulator(simDevice, language, options, outputDir);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n options.onOutput?.(\n \"Attempt \" + (attempt + 1) + \" failed for \" + deviceName + \" / \" + language + \": \" + lastError.message + \"\\n\",\n );\n }\n }\n\n throw lastError ?? new Error(\"All retries exhausted\");\n}\n\nasync function runOnSimulator(\n simDevice: SimDevice,\n language: string,\n options: SnapshotOptions,\n outputDir: string,\n): Promise<Record<string, Record<string, string[]>>> {\n const udid = simDevice.udid;\n const deviceName = simDevice.name;\n\n // Erase simulator if requested\n if (options.eraseSimulatorBeforeRun) {\n await eraseSimulator(udid);\n }\n\n // Shut down, localize, then boot\n try {\n await execFileAsync(\"xcrun\", [\"simctl\", \"shutdown\", udid]);\n } catch {\n // May already be shutdown\n }\n\n await localizeSimulator(udid, language);\n await bootSimulator(udid);\n\n // Override status bar for clean screenshots\n if (options.overrideStatusBar !== false) {\n try {\n await overrideStatusBar(udid);\n } catch {\n // Status bar override may fail on older simulators\n }\n }\n\n // Set dark mode if requested\n if (options.darkMode) {\n try {\n const { setInterfaceStyle } = await import(\"./simulator.js\");\n await setInterfaceStyle(udid, \"dark\");\n } catch {\n // Dark mode may not be available\n }\n }\n\n // Determine the derived data path (used to find screenshots)\n const derivedDataPath =\n options.derivedDataPath ??\n join(outputDir, \".derived-data\", deviceName + \"-\" + language);\n mkdirSync(derivedDataPath, { recursive: true });\n\n // Run xcodebuild test\n const exitCode = await runXcodebuildTest(\n udid,\n derivedDataPath,\n options,\n );\n\n if (exitCode !== 0 && exitCode !== 65) {\n // Exit code 65 = test failures but screenshots may still exist\n throw new Error(\n \"xcodebuild test failed with exit code \" + exitCode,\n );\n }\n\n // Collect screenshots from derived data and the simulator's data dir\n const deviceOutputDir = join(outputDir, deviceName, language);\n mkdirSync(deviceOutputDir, { recursive: true });\n\n const collectedPaths = collectScreenshots(derivedDataPath, deviceOutputDir);\n\n // Also collect from the simulator's screenshot directory\n const simScreenshotDir = getSimulatorScreenshotDir(udid);\n if (existsSync(simScreenshotDir)) {\n const simPaths = collectScreenshots(simScreenshotDir, deviceOutputDir);\n collectedPaths.push(...simPaths);\n }\n\n const result: Record<string, Record<string, string[]>> = {};\n if (!result[deviceName]) result[deviceName] = {};\n result[deviceName][language] = collectedPaths;\n\n return result;\n}\n\n// ── Internal: xcodebuild test ──────────────────────────────────────────────\n\nfunction runXcodebuildTest(\n udid: string,\n derivedDataPath: string,\n options: SnapshotOptions,\n): Promise<number> {\n return new Promise((resolve) => {\n const args = buildXcodebuildArgs(udid, derivedDataPath, options);\n\n const proc = spawn(\"xcodebuild\", args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let output = \"\";\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString();\n output += text;\n options.onOutput?.(text);\n });\n\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString();\n output += text;\n options.onOutput?.(text);\n });\n\n proc.on(\"close\", (code) => {\n resolve(code ?? 1);\n });\n\n proc.on(\"error\", () => {\n resolve(1);\n });\n });\n}\n\nfunction buildXcodebuildArgs(\n udid: string,\n derivedDataPath: string,\n options: SnapshotOptions,\n): string[] {\n const args: string[] = [];\n\n if (options.workspace) {\n args.push(\"-workspace\", options.workspace);\n } else if (options.project) {\n args.push(\"-project\", options.project);\n }\n\n if (options.scheme) {\n args.push(\"-scheme\", options.scheme);\n }\n\n if (options.configuration) {\n args.push(\"-configuration\", options.configuration);\n }\n\n args.push(\n \"-destination\",\n \"platform=iOS Simulator,id=\" + udid,\n \"-derivedDataPath\",\n derivedDataPath,\n \"test\",\n );\n\n if (options.testPlan) {\n args.push(\"-testPlan\", options.testPlan);\n }\n\n // Append launch arguments as build settings\n if (options.launchArguments && options.launchArguments.length > 0) {\n const launchArgsStr = options.launchArguments\n .map((a) => \"'\" + a + \"'\")\n .join(\" \");\n args.push(\"SNAPSHOT_LAUNCH_ARGUMENTS=\" + launchArgsStr);\n }\n\n if (options.xcargs) {\n // Split xcargs by spaces (simple split, doesn't handle quoted strings)\n args.push(...options.xcargs.split(/\\s+/).filter(Boolean));\n }\n\n return args;\n}\n\n// ── Internal: Screenshot Collection ────────────────────────────────────────\n\nfunction collectScreenshots(\n sourceDir: string,\n destDir: string,\n): string[] {\n const collected: string[] = [];\n\n if (!existsSync(sourceDir)) return collected;\n\n const screenshotExtensions = new Set([\".png\", \".jpg\", \".jpeg\"]);\n\n function walk(dir: string): void {\n let entries: string[];\n try {\n entries = readdirSync(dir, { withFileTypes: true }).map((e) => {\n if (e.isDirectory()) {\n walk(join(dir, e.name));\n return \"\";\n }\n return e.name;\n }).filter(Boolean);\n } catch {\n return;\n }\n\n for (const name of entries) {\n const ext = extname(name).toLowerCase();\n if (screenshotExtensions.has(ext)) {\n const srcPath = join(dir, name);\n const destPath = join(destDir, basename(name));\n try {\n copyFileSync(srcPath, destPath);\n collected.push(destPath);\n } catch {\n // Skip files we can't copy\n }\n }\n }\n }\n\n walk(sourceDir);\n return collected;\n}\n\nfunction getSimulatorScreenshotDir(udid: string): string {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"/tmp\";\n return join(\n home,\n \"Library\",\n \"Developer\",\n \"CoreSimulator\",\n \"Devices\",\n udid,\n \"data\",\n \"tmp\",\n \"Screenshots\",\n );\n}\n\n// ── Internal: Merge screenshot results ─────────────────────────────────────\n\nfunction mergeScreenshots(\n target: Record<string, Record<string, string[]>>,\n source: Record<string, Record<string, string[]>>,\n): void {\n for (const [device, languages] of Object.entries(source)) {\n if (!target[device]) target[device] = {};\n for (const [lang, paths] of Object.entries(languages)) {\n if (!target[device][lang]) target[device][lang] = [];\n target[device][lang].push(...paths);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { a as ScreenshotResult, h as SimDevice, S as SnapshotOptions, b as bootSimulator, c as captureScreenshots, e as eraseSimulator, f as findDevice, l as listSimulators, d as localizeSimulator, o as overrideStatusBar, g as setInterfaceStyle, s as shutdownAll } from '../index-CR3BFPIz.cjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { a as ScreenshotResult, h as SimDevice, S as SnapshotOptions, b as bootSimulator, c as captureScreenshots, e as eraseSimulator, f as findDevice, l as listSimulators, d as localizeSimulator, o as overrideStatusBar, g as setInterfaceStyle, s as shutdownAll } from '../index-CR3BFPIz.js';
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { execFile, spawn } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync, copyFileSync } from 'fs';
|
|
4
|
+
import { join, extname, basename } from 'path';
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/xcode/platform.ts
|
|
17
|
+
function requireMacOS(feature) {
|
|
18
|
+
if (process.platform !== "darwin") {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`${feature} requires macOS. This operation uses Xcode command-line tools which are not available on ${process.platform}.`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
var init_platform = __esm({
|
|
25
|
+
"src/xcode/platform.ts"() {
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// src/snapshot/simulator.ts
|
|
30
|
+
var simulator_exports = {};
|
|
31
|
+
__export(simulator_exports, {
|
|
32
|
+
bootSimulator: () => bootSimulator,
|
|
33
|
+
eraseSimulator: () => eraseSimulator,
|
|
34
|
+
findDevice: () => findDevice,
|
|
35
|
+
listSimulators: () => listSimulators,
|
|
36
|
+
localizeSimulator: () => localizeSimulator,
|
|
37
|
+
overrideStatusBar: () => overrideStatusBar,
|
|
38
|
+
setInterfaceStyle: () => setInterfaceStyle,
|
|
39
|
+
shutdownAll: () => shutdownAll
|
|
40
|
+
});
|
|
41
|
+
async function listSimulators() {
|
|
42
|
+
requireMacOS("Simulator management");
|
|
43
|
+
const { stdout } = await execFileAsync("xcrun", ["simctl", "list", "devices", "-j"]);
|
|
44
|
+
const parsed = JSON.parse(stdout);
|
|
45
|
+
const devices = [];
|
|
46
|
+
for (const [runtimeId, runtimeDevices] of Object.entries(parsed.devices)) {
|
|
47
|
+
for (const dev of runtimeDevices) {
|
|
48
|
+
devices.push({
|
|
49
|
+
udid: dev.udid,
|
|
50
|
+
name: dev.name,
|
|
51
|
+
state: dev.state,
|
|
52
|
+
isAvailable: dev.isAvailable,
|
|
53
|
+
runtime: runtimeId,
|
|
54
|
+
deviceTypeIdentifier: dev.deviceTypeIdentifier
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return devices;
|
|
59
|
+
}
|
|
60
|
+
async function findDevice(deviceName, runtimeFilter) {
|
|
61
|
+
const devices = await listSimulators();
|
|
62
|
+
const candidates = devices.filter((d) => {
|
|
63
|
+
if (!d.isAvailable) return false;
|
|
64
|
+
if (d.name !== deviceName) return false;
|
|
65
|
+
if (runtimeFilter && !d.runtime.includes(runtimeFilter)) return false;
|
|
66
|
+
return true;
|
|
67
|
+
});
|
|
68
|
+
if (candidates.length === 0) return null;
|
|
69
|
+
const booted = candidates.find((d) => d.state === "Booted");
|
|
70
|
+
return booted ?? candidates[0];
|
|
71
|
+
}
|
|
72
|
+
async function bootSimulator(udid) {
|
|
73
|
+
requireMacOS("Simulator management");
|
|
74
|
+
const devices = await listSimulators();
|
|
75
|
+
const device = devices.find((d) => d.udid === udid);
|
|
76
|
+
if (device?.state === "Booted") return;
|
|
77
|
+
await execFileAsync("xcrun", ["simctl", "boot", udid]);
|
|
78
|
+
const deadline = Date.now() + 3e4;
|
|
79
|
+
while (Date.now() < deadline) {
|
|
80
|
+
const refreshed = await listSimulators();
|
|
81
|
+
const current = refreshed.find((d) => d.udid === udid);
|
|
82
|
+
if (current?.state === "Booted") return;
|
|
83
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function shutdownAll() {
|
|
87
|
+
requireMacOS("Simulator management");
|
|
88
|
+
await execFileAsync("xcrun", ["simctl", "shutdown", "all"]);
|
|
89
|
+
}
|
|
90
|
+
async function eraseSimulator(udid) {
|
|
91
|
+
requireMacOS("Simulator management");
|
|
92
|
+
const devices = await listSimulators();
|
|
93
|
+
const device = devices.find((d) => d.udid === udid);
|
|
94
|
+
if (device?.state === "Booted") {
|
|
95
|
+
await execFileAsync("xcrun", ["simctl", "shutdown", udid]);
|
|
96
|
+
}
|
|
97
|
+
await execFileAsync("xcrun", ["simctl", "erase", udid]);
|
|
98
|
+
}
|
|
99
|
+
async function localizeSimulator(udid, language, locale) {
|
|
100
|
+
requireMacOS("Simulator management");
|
|
101
|
+
const deviceDataPath = getDeviceDataPath(udid);
|
|
102
|
+
const prefsDir = join(deviceDataPath, "data", "Library", "Preferences");
|
|
103
|
+
const prefsFile = join(prefsDir, ".GlobalPreferences.plist");
|
|
104
|
+
if (!existsSync(prefsDir)) {
|
|
105
|
+
mkdirSync(prefsDir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
const effectiveLocale = locale ?? language.replace("-", "_");
|
|
108
|
+
const plistXml = [
|
|
109
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
110
|
+
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
111
|
+
'<plist version="1.0">',
|
|
112
|
+
"<dict>",
|
|
113
|
+
" <key>AppleLanguages</key>",
|
|
114
|
+
" <array>",
|
|
115
|
+
" <string>" + escapeXml(language) + "</string>",
|
|
116
|
+
" </array>",
|
|
117
|
+
" <key>AppleLocale</key>",
|
|
118
|
+
" <string>" + escapeXml(effectiveLocale) + "</string>",
|
|
119
|
+
" <key>AppleKeyboards</key>",
|
|
120
|
+
" <array>",
|
|
121
|
+
" <string>" + escapeXml(effectiveLocale) + "@sw=QWERTY;hw=Automatic</string>",
|
|
122
|
+
" </array>",
|
|
123
|
+
" <key>AppleKeyboardsExpanded</key>",
|
|
124
|
+
" <integer>1</integer>",
|
|
125
|
+
"</dict>",
|
|
126
|
+
"</plist>"
|
|
127
|
+
].join("\n");
|
|
128
|
+
writeFileSync(prefsFile, plistXml, "utf-8");
|
|
129
|
+
try {
|
|
130
|
+
await execFileAsync("plutil", ["-convert", "binary1", prefsFile]);
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function setInterfaceStyle(udid, style) {
|
|
135
|
+
requireMacOS("Simulator management");
|
|
136
|
+
const appearance = style === "dark" ? "dark" : "light";
|
|
137
|
+
await execFileAsync("xcrun", ["simctl", "ui", udid, "appearance", appearance]);
|
|
138
|
+
}
|
|
139
|
+
async function overrideStatusBar(udid, options) {
|
|
140
|
+
requireMacOS("Simulator management");
|
|
141
|
+
const args = [
|
|
142
|
+
"simctl",
|
|
143
|
+
"status_bar",
|
|
144
|
+
udid,
|
|
145
|
+
"override",
|
|
146
|
+
"--time",
|
|
147
|
+
options?.time ?? "9:41",
|
|
148
|
+
"--batteryLevel",
|
|
149
|
+
String(options?.batteryLevel ?? 100),
|
|
150
|
+
"--batteryState",
|
|
151
|
+
options?.batteryState ?? "charged",
|
|
152
|
+
"--wifiMode",
|
|
153
|
+
options?.wifiMode ?? "active",
|
|
154
|
+
"--wifiBars",
|
|
155
|
+
"3",
|
|
156
|
+
"--cellularMode",
|
|
157
|
+
options?.cellularMode ?? "active",
|
|
158
|
+
"--cellularBars",
|
|
159
|
+
"4"
|
|
160
|
+
];
|
|
161
|
+
if (options?.dataNetwork) {
|
|
162
|
+
args.push("--dataNetwork", options.dataNetwork);
|
|
163
|
+
}
|
|
164
|
+
await execFileAsync("xcrun", args);
|
|
165
|
+
}
|
|
166
|
+
function getDeviceDataPath(udid) {
|
|
167
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp";
|
|
168
|
+
return join(home, "Library", "Developer", "CoreSimulator", "Devices", udid);
|
|
169
|
+
}
|
|
170
|
+
function escapeXml(str) {
|
|
171
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
172
|
+
}
|
|
173
|
+
var execFileAsync;
|
|
174
|
+
var init_simulator = __esm({
|
|
175
|
+
"src/snapshot/simulator.ts"() {
|
|
176
|
+
init_platform();
|
|
177
|
+
execFileAsync = promisify(execFile);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// src/snapshot/index.ts
|
|
182
|
+
init_platform();
|
|
183
|
+
init_simulator();
|
|
184
|
+
init_simulator();
|
|
185
|
+
var execFileAsync2 = promisify(execFile);
|
|
186
|
+
async function captureScreenshots(options) {
|
|
187
|
+
requireMacOS("Screenshot capture");
|
|
188
|
+
if (!options.scheme && !options.workspace && !options.project) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
"At least one of scheme, workspace, or project must be specified"
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
if (options.devices.length === 0) {
|
|
194
|
+
throw new Error("At least one device must be specified");
|
|
195
|
+
}
|
|
196
|
+
if (options.languages.length === 0) {
|
|
197
|
+
throw new Error("At least one language must be specified");
|
|
198
|
+
}
|
|
199
|
+
const outputDir = options.outputDirectory ?? join(process.cwd(), "screenshots");
|
|
200
|
+
const retries = options.numberOfRetries ?? 1;
|
|
201
|
+
if (options.clearPreviousScreenshots && existsSync(outputDir)) {
|
|
202
|
+
const { rm } = await import('fs/promises');
|
|
203
|
+
await rm(outputDir, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
mkdirSync(outputDir, { recursive: true });
|
|
206
|
+
const screenshots = {};
|
|
207
|
+
const failedDevices = [];
|
|
208
|
+
const matrix = buildMatrix(options.devices, options.languages);
|
|
209
|
+
if (options.concurrent) {
|
|
210
|
+
const results = await Promise.allSettled(
|
|
211
|
+
matrix.map(
|
|
212
|
+
(entry) => runSingleCombination(entry, options, outputDir, retries)
|
|
213
|
+
)
|
|
214
|
+
);
|
|
215
|
+
for (let i = 0; i < results.length; i++) {
|
|
216
|
+
const result = results[i];
|
|
217
|
+
const entry = matrix[i];
|
|
218
|
+
if (result.status === "fulfilled") {
|
|
219
|
+
mergeScreenshots(screenshots, result.value);
|
|
220
|
+
} else {
|
|
221
|
+
const key = entry.device + " / " + entry.language;
|
|
222
|
+
failedDevices.push(key);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
for (const entry of matrix) {
|
|
227
|
+
try {
|
|
228
|
+
const result = await runSingleCombination(
|
|
229
|
+
entry,
|
|
230
|
+
options,
|
|
231
|
+
outputDir,
|
|
232
|
+
retries
|
|
233
|
+
);
|
|
234
|
+
mergeScreenshots(screenshots, result);
|
|
235
|
+
} catch {
|
|
236
|
+
const key = entry.device + " / " + entry.language;
|
|
237
|
+
failedDevices.push(key);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
success: failedDevices.length === 0,
|
|
243
|
+
screenshots,
|
|
244
|
+
failedDevices
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function buildMatrix(devices, languages) {
|
|
248
|
+
const entries = [];
|
|
249
|
+
for (const device of devices) {
|
|
250
|
+
for (const language of languages) {
|
|
251
|
+
entries.push({ device, language });
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return entries;
|
|
255
|
+
}
|
|
256
|
+
async function runSingleCombination(entry, options, outputDir, retries) {
|
|
257
|
+
const { device: deviceName, language } = entry;
|
|
258
|
+
const simDevice = await findDevice(deviceName);
|
|
259
|
+
if (!simDevice) {
|
|
260
|
+
throw new Error("Simulator device not found: " + deviceName);
|
|
261
|
+
}
|
|
262
|
+
let lastError = null;
|
|
263
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
264
|
+
try {
|
|
265
|
+
return await runOnSimulator(simDevice, language, options, outputDir);
|
|
266
|
+
} catch (err) {
|
|
267
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
268
|
+
options.onOutput?.(
|
|
269
|
+
"Attempt " + (attempt + 1) + " failed for " + deviceName + " / " + language + ": " + lastError.message + "\n"
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
throw lastError ?? new Error("All retries exhausted");
|
|
274
|
+
}
|
|
275
|
+
async function runOnSimulator(simDevice, language, options, outputDir) {
|
|
276
|
+
const udid = simDevice.udid;
|
|
277
|
+
const deviceName = simDevice.name;
|
|
278
|
+
if (options.eraseSimulatorBeforeRun) {
|
|
279
|
+
await eraseSimulator(udid);
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
await execFileAsync2("xcrun", ["simctl", "shutdown", udid]);
|
|
283
|
+
} catch {
|
|
284
|
+
}
|
|
285
|
+
await localizeSimulator(udid, language);
|
|
286
|
+
await bootSimulator(udid);
|
|
287
|
+
if (options.overrideStatusBar !== false) {
|
|
288
|
+
try {
|
|
289
|
+
await overrideStatusBar(udid);
|
|
290
|
+
} catch {
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (options.darkMode) {
|
|
294
|
+
try {
|
|
295
|
+
const { setInterfaceStyle: setInterfaceStyle2 } = await Promise.resolve().then(() => (init_simulator(), simulator_exports));
|
|
296
|
+
await setInterfaceStyle2(udid, "dark");
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const derivedDataPath = options.derivedDataPath ?? join(outputDir, ".derived-data", deviceName + "-" + language);
|
|
301
|
+
mkdirSync(derivedDataPath, { recursive: true });
|
|
302
|
+
const exitCode = await runXcodebuildTest(
|
|
303
|
+
udid,
|
|
304
|
+
derivedDataPath,
|
|
305
|
+
options
|
|
306
|
+
);
|
|
307
|
+
if (exitCode !== 0 && exitCode !== 65) {
|
|
308
|
+
throw new Error(
|
|
309
|
+
"xcodebuild test failed with exit code " + exitCode
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
const deviceOutputDir = join(outputDir, deviceName, language);
|
|
313
|
+
mkdirSync(deviceOutputDir, { recursive: true });
|
|
314
|
+
const collectedPaths = collectScreenshots(derivedDataPath, deviceOutputDir);
|
|
315
|
+
const simScreenshotDir = getSimulatorScreenshotDir(udid);
|
|
316
|
+
if (existsSync(simScreenshotDir)) {
|
|
317
|
+
const simPaths = collectScreenshots(simScreenshotDir, deviceOutputDir);
|
|
318
|
+
collectedPaths.push(...simPaths);
|
|
319
|
+
}
|
|
320
|
+
const result = {};
|
|
321
|
+
if (!result[deviceName]) result[deviceName] = {};
|
|
322
|
+
result[deviceName][language] = collectedPaths;
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
function runXcodebuildTest(udid, derivedDataPath, options) {
|
|
326
|
+
return new Promise((resolve) => {
|
|
327
|
+
const args = buildXcodebuildArgs(udid, derivedDataPath, options);
|
|
328
|
+
const proc = spawn("xcodebuild", args, {
|
|
329
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
330
|
+
});
|
|
331
|
+
proc.stdout.on("data", (chunk) => {
|
|
332
|
+
const text = chunk.toString();
|
|
333
|
+
options.onOutput?.(text);
|
|
334
|
+
});
|
|
335
|
+
proc.stderr.on("data", (chunk) => {
|
|
336
|
+
const text = chunk.toString();
|
|
337
|
+
options.onOutput?.(text);
|
|
338
|
+
});
|
|
339
|
+
proc.on("close", (code) => {
|
|
340
|
+
resolve(code ?? 1);
|
|
341
|
+
});
|
|
342
|
+
proc.on("error", () => {
|
|
343
|
+
resolve(1);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
function buildXcodebuildArgs(udid, derivedDataPath, options) {
|
|
348
|
+
const args = [];
|
|
349
|
+
if (options.workspace) {
|
|
350
|
+
args.push("-workspace", options.workspace);
|
|
351
|
+
} else if (options.project) {
|
|
352
|
+
args.push("-project", options.project);
|
|
353
|
+
}
|
|
354
|
+
if (options.scheme) {
|
|
355
|
+
args.push("-scheme", options.scheme);
|
|
356
|
+
}
|
|
357
|
+
if (options.configuration) {
|
|
358
|
+
args.push("-configuration", options.configuration);
|
|
359
|
+
}
|
|
360
|
+
args.push(
|
|
361
|
+
"-destination",
|
|
362
|
+
"platform=iOS Simulator,id=" + udid,
|
|
363
|
+
"-derivedDataPath",
|
|
364
|
+
derivedDataPath,
|
|
365
|
+
"test"
|
|
366
|
+
);
|
|
367
|
+
if (options.testPlan) {
|
|
368
|
+
args.push("-testPlan", options.testPlan);
|
|
369
|
+
}
|
|
370
|
+
if (options.launchArguments && options.launchArguments.length > 0) {
|
|
371
|
+
const launchArgsStr = options.launchArguments.map((a) => "'" + a + "'").join(" ");
|
|
372
|
+
args.push("SNAPSHOT_LAUNCH_ARGUMENTS=" + launchArgsStr);
|
|
373
|
+
}
|
|
374
|
+
if (options.xcargs) {
|
|
375
|
+
args.push(...options.xcargs.split(/\s+/).filter(Boolean));
|
|
376
|
+
}
|
|
377
|
+
return args;
|
|
378
|
+
}
|
|
379
|
+
function collectScreenshots(sourceDir, destDir) {
|
|
380
|
+
const collected = [];
|
|
381
|
+
if (!existsSync(sourceDir)) return collected;
|
|
382
|
+
const screenshotExtensions = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg"]);
|
|
383
|
+
function walk(dir) {
|
|
384
|
+
let entries;
|
|
385
|
+
try {
|
|
386
|
+
entries = readdirSync(dir, { withFileTypes: true }).map((e) => {
|
|
387
|
+
if (e.isDirectory()) {
|
|
388
|
+
walk(join(dir, e.name));
|
|
389
|
+
return "";
|
|
390
|
+
}
|
|
391
|
+
return e.name;
|
|
392
|
+
}).filter(Boolean);
|
|
393
|
+
} catch {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
for (const name of entries) {
|
|
397
|
+
const ext = extname(name).toLowerCase();
|
|
398
|
+
if (screenshotExtensions.has(ext)) {
|
|
399
|
+
const srcPath = join(dir, name);
|
|
400
|
+
const destPath = join(destDir, basename(name));
|
|
401
|
+
try {
|
|
402
|
+
copyFileSync(srcPath, destPath);
|
|
403
|
+
collected.push(destPath);
|
|
404
|
+
} catch {
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
walk(sourceDir);
|
|
410
|
+
return collected;
|
|
411
|
+
}
|
|
412
|
+
function getSimulatorScreenshotDir(udid) {
|
|
413
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp";
|
|
414
|
+
return join(
|
|
415
|
+
home,
|
|
416
|
+
"Library",
|
|
417
|
+
"Developer",
|
|
418
|
+
"CoreSimulator",
|
|
419
|
+
"Devices",
|
|
420
|
+
udid,
|
|
421
|
+
"data",
|
|
422
|
+
"tmp",
|
|
423
|
+
"Screenshots"
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
function mergeScreenshots(target, source) {
|
|
427
|
+
for (const [device, languages] of Object.entries(source)) {
|
|
428
|
+
if (!target[device]) target[device] = {};
|
|
429
|
+
for (const [lang, paths] of Object.entries(languages)) {
|
|
430
|
+
if (!target[device][lang]) target[device][lang] = [];
|
|
431
|
+
target[device][lang].push(...paths);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export { bootSimulator, captureScreenshots, eraseSimulator, findDevice, listSimulators, localizeSimulator, overrideStatusBar, setInterfaceStyle, shutdownAll };
|
|
437
|
+
//# sourceMappingURL=index.mjs.map
|
|
438
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/xcode/platform.ts","../../src/snapshot/simulator.ts","../../src/snapshot/index.ts"],"names":["execFileAsync","promisify","execFile","join","existsSync","mkdirSync","setInterfaceStyle"],"mappings":"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","file":"index.mjs","sourcesContent":["export function requireMacOS(feature: string): void {\n if (process.platform !== \"darwin\") {\n throw new Error(\n `${feature} requires macOS. This operation uses Xcode command-line tools ` +\n `which are not available on ${process.platform}.`\n );\n }\n}\n\nexport function isMacOS(): boolean {\n return process.platform === \"darwin\";\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { requireMacOS } from \"../xcode/platform.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface SimDevice {\n udid: string;\n name: string;\n state: \"Booted\" | \"Shutdown\" | \"Shutting Down\" | \"Creating\";\n isAvailable: boolean;\n runtime: string;\n deviceTypeIdentifier: string;\n}\n\ninterface SimctlDevicesJson {\n devices: Record<\n string,\n Array<{\n udid: string;\n name: string;\n state: string;\n isAvailable: boolean;\n deviceTypeIdentifier: string;\n }>\n >;\n}\n\n// ── Simulator Listing & Lookup ─────────────────────────────────────────────\n\nexport async function listSimulators(): Promise<SimDevice[]> {\n requireMacOS(\"Simulator management\");\n const { stdout } = await execFileAsync(\"xcrun\", [\"simctl\", \"list\", \"devices\", \"-j\"]);\n const parsed: SimctlDevicesJson = JSON.parse(stdout);\n const devices: SimDevice[] = [];\n for (const [runtimeId, runtimeDevices] of Object.entries(parsed.devices)) {\n for (const dev of runtimeDevices) {\n devices.push({\n udid: dev.udid,\n name: dev.name,\n state: dev.state as SimDevice[\"state\"],\n isAvailable: dev.isAvailable,\n runtime: runtimeId,\n deviceTypeIdentifier: dev.deviceTypeIdentifier,\n });\n }\n }\n return devices;\n}\n\nexport async function findDevice(\n deviceName: string,\n runtimeFilter?: string,\n): Promise<SimDevice | null> {\n const devices = await listSimulators();\n const candidates = devices.filter((d) => {\n if (!d.isAvailable) return false;\n if (d.name !== deviceName) return false;\n if (runtimeFilter && !d.runtime.includes(runtimeFilter)) return false;\n return true;\n });\n if (candidates.length === 0) return null;\n const booted = candidates.find((d) => d.state === \"Booted\");\n return booted ?? candidates[0];\n}\n\n// ── Boot / Shutdown / Erase ────────────────────────────────────────────────\n\nexport async function bootSimulator(udid: string): Promise<void> {\n requireMacOS(\"Simulator management\");\n const devices = await listSimulators();\n const device = devices.find((d) => d.udid === udid);\n if (device?.state === \"Booted\") return;\n await execFileAsync(\"xcrun\", [\"simctl\", \"boot\", udid]);\n const deadline = Date.now() + 30_000;\n while (Date.now() < deadline) {\n const refreshed = await listSimulators();\n const current = refreshed.find((d) => d.udid === udid);\n if (current?.state === \"Booted\") return;\n await new Promise((r) => setTimeout(r, 1000));\n }\n}\n\nexport async function shutdownAll(): Promise<void> {\n requireMacOS(\"Simulator management\");\n await execFileAsync(\"xcrun\", [\"simctl\", \"shutdown\", \"all\"]);\n}\n\nexport async function eraseSimulator(udid: string): Promise<void> {\n requireMacOS(\"Simulator management\");\n const devices = await listSimulators();\n const device = devices.find((d) => d.udid === udid);\n if (device?.state === \"Booted\") {\n await execFileAsync(\"xcrun\", [\"simctl\", \"shutdown\", udid]);\n }\n await execFileAsync(\"xcrun\", [\"simctl\", \"erase\", udid]);\n}\n\n// ── Locale / Language ──────────────────────────────────────────────────────\n\nexport async function localizeSimulator(\n udid: string,\n language: string,\n locale?: string,\n): Promise<void> {\n requireMacOS(\"Simulator management\");\n const deviceDataPath = getDeviceDataPath(udid);\n const prefsDir = join(deviceDataPath, \"data\", \"Library\", \"Preferences\");\n const prefsFile = join(prefsDir, \".GlobalPreferences.plist\");\n if (!existsSync(prefsDir)) {\n mkdirSync(prefsDir, { recursive: true });\n }\n const effectiveLocale = locale ?? language.replace(\"-\", \"_\");\n const plistXml = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">',\n '<plist version=\"1.0\">',\n \"<dict>\",\n \" <key>AppleLanguages</key>\",\n \" <array>\",\n \" <string>\" + escapeXml(language) + \"</string>\",\n \" </array>\",\n \" <key>AppleLocale</key>\",\n \" <string>\" + escapeXml(effectiveLocale) + \"</string>\",\n \" <key>AppleKeyboards</key>\",\n \" <array>\",\n \" <string>\" + escapeXml(effectiveLocale) + \"@sw=QWERTY;hw=Automatic</string>\",\n \" </array>\",\n \" <key>AppleKeyboardsExpanded</key>\",\n \" <integer>1</integer>\",\n \"</dict>\",\n \"</plist>\",\n ].join(\"\\n\");\n writeFileSync(prefsFile, plistXml, \"utf-8\");\n try {\n await execFileAsync(\"plutil\", [\"-convert\", \"binary1\", prefsFile]);\n } catch {\n // XML plist is still readable\n }\n}\n\n// ── UI Customization ───────────────────────────────────────────────────────\n\nexport async function setInterfaceStyle(\n udid: string,\n style: \"light\" | \"dark\",\n): Promise<void> {\n requireMacOS(\"Simulator management\");\n const appearance = style === \"dark\" ? \"dark\" : \"light\";\n await execFileAsync(\"xcrun\", [\"simctl\", \"ui\", udid, \"appearance\", appearance]);\n}\n\nexport async function overrideStatusBar(\n udid: string,\n options?: {\n time?: string;\n batteryLevel?: number;\n batteryState?: \"charged\" | \"charging\" | \"discharging\";\n wifiMode?: \"active\" | \"searching\" | \"failed\";\n cellularMode?: \"active\" | \"searching\" | \"failed\" | \"notSupported\";\n dataNetwork?: \"wifi\" | \"3g\" | \"4g\" | \"lte\" | \"lte-a\" | \"lte+\" | \"5g\" | \"5g+\" | \"5g-uwb\";\n },\n): Promise<void> {\n requireMacOS(\"Simulator management\");\n const args = [\n \"simctl\", \"status_bar\", udid, \"override\",\n \"--time\", options?.time ?? \"9:41\",\n \"--batteryLevel\", String(options?.batteryLevel ?? 100),\n \"--batteryState\", options?.batteryState ?? \"charged\",\n \"--wifiMode\", options?.wifiMode ?? \"active\",\n \"--wifiBars\", \"3\",\n \"--cellularMode\", options?.cellularMode ?? \"active\",\n \"--cellularBars\", \"4\",\n ];\n if (options?.dataNetwork) {\n args.push(\"--dataNetwork\", options.dataNetwork);\n }\n await execFileAsync(\"xcrun\", args);\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\nfunction getDeviceDataPath(udid: string): string {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"/tmp\";\n return join(home, \"Library\", \"Developer\", \"CoreSimulator\", \"Devices\", udid);\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n","import { execFile, spawn } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { existsSync, mkdirSync, readdirSync, copyFileSync } from \"node:fs\";\nimport { join, basename, extname } from \"node:path\";\nimport { requireMacOS } from \"../xcode/platform.js\";\nimport {\n findDevice,\n bootSimulator,\n shutdownAll,\n localizeSimulator,\n overrideStatusBar,\n eraseSimulator,\n} from \"./simulator.js\";\nimport type { SimDevice } from \"./simulator.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ── Re-export simulator utilities ──────────────────────────────────────────\n\nexport {\n listSimulators,\n findDevice,\n bootSimulator,\n shutdownAll,\n eraseSimulator,\n localizeSimulator,\n setInterfaceStyle,\n overrideStatusBar,\n} from \"./simulator.js\";\n\nexport type { SimDevice } from \"./simulator.js\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface SnapshotOptions {\n scheme?: string;\n workspace?: string;\n project?: string;\n devices: string[];\n languages: string[];\n outputDirectory?: string;\n clearPreviousScreenshots?: boolean;\n launchArguments?: string[];\n concurrent?: boolean;\n numberOfRetries?: number;\n darkMode?: boolean;\n overrideStatusBar?: boolean;\n eraseSimulatorBeforeRun?: boolean;\n derivedDataPath?: string;\n testPlan?: string;\n configuration?: string;\n xcargs?: string;\n onOutput?: (chunk: string) => void;\n}\n\nexport interface ScreenshotResult {\n success: boolean;\n screenshots: Record<string, Record<string, string[]>>;\n failedDevices: string[];\n}\n\n// ── Main Entry Point ───────────────────────────────────────────────────────\n\n/**\n * Capture screenshots across a device x language matrix.\n *\n * Mirrors Fastlane snapshot's runner:\n * 1. Validate macOS\n * 2. Build device x language matrix\n * 3. For each combination: boot sim, set locale, run xcodebuild test, collect screenshots\n * 4. Return aggregated ScreenshotResult\n */\nexport async function captureScreenshots(\n options: SnapshotOptions,\n): Promise<ScreenshotResult> {\n requireMacOS(\"Screenshot capture\");\n\n // Validate required options\n if (!options.scheme && !options.workspace && !options.project) {\n throw new Error(\n \"At least one of scheme, workspace, or project must be specified\",\n );\n }\n if (options.devices.length === 0) {\n throw new Error(\"At least one device must be specified\");\n }\n if (options.languages.length === 0) {\n throw new Error(\"At least one language must be specified\");\n }\n\n const outputDir = options.outputDirectory ?? join(process.cwd(), \"screenshots\");\n const retries = options.numberOfRetries ?? 1;\n\n // Clear previous screenshots if requested\n if (options.clearPreviousScreenshots && existsSync(outputDir)) {\n const { rm } = await import(\"node:fs/promises\");\n await rm(outputDir, { recursive: true, force: true });\n }\n\n mkdirSync(outputDir, { recursive: true });\n\n const screenshots: Record<string, Record<string, string[]>> = {};\n const failedDevices: string[] = [];\n\n // Build the device x language matrix\n const matrix = buildMatrix(options.devices, options.languages);\n\n if (options.concurrent) {\n // Run all combinations in parallel\n const results = await Promise.allSettled(\n matrix.map((entry) =>\n runSingleCombination(entry, options, outputDir, retries),\n ),\n );\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n const entry = matrix[i];\n if (result.status === \"fulfilled\") {\n mergeScreenshots(screenshots, result.value);\n } else {\n const key = entry.device + \" / \" + entry.language;\n failedDevices.push(key);\n }\n }\n } else {\n // Run sequentially\n for (const entry of matrix) {\n try {\n const result = await runSingleCombination(\n entry,\n options,\n outputDir,\n retries,\n );\n mergeScreenshots(screenshots, result);\n } catch {\n const key = entry.device + \" / \" + entry.language;\n failedDevices.push(key);\n }\n }\n }\n\n return {\n success: failedDevices.length === 0,\n screenshots,\n failedDevices,\n };\n}\n\n// ── Internal: Matrix Construction ──────────────────────────────────────────\n\ninterface MatrixEntry {\n device: string;\n language: string;\n}\n\nfunction buildMatrix(devices: string[], languages: string[]): MatrixEntry[] {\n const entries: MatrixEntry[] = [];\n for (const device of devices) {\n for (const language of languages) {\n entries.push({ device, language });\n }\n }\n return entries;\n}\n\n// ── Internal: Single Combination Runner ────────────────────────────────────\n\nasync function runSingleCombination(\n entry: MatrixEntry,\n options: SnapshotOptions,\n outputDir: string,\n retries: number,\n): Promise<Record<string, Record<string, string[]>>> {\n const { device: deviceName, language } = entry;\n\n // Find the simulator device\n const simDevice = await findDevice(deviceName);\n if (!simDevice) {\n throw new Error(\"Simulator device not found: \" + deviceName);\n }\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n return await runOnSimulator(simDevice, language, options, outputDir);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n options.onOutput?.(\n \"Attempt \" + (attempt + 1) + \" failed for \" + deviceName + \" / \" + language + \": \" + lastError.message + \"\\n\",\n );\n }\n }\n\n throw lastError ?? new Error(\"All retries exhausted\");\n}\n\nasync function runOnSimulator(\n simDevice: SimDevice,\n language: string,\n options: SnapshotOptions,\n outputDir: string,\n): Promise<Record<string, Record<string, string[]>>> {\n const udid = simDevice.udid;\n const deviceName = simDevice.name;\n\n // Erase simulator if requested\n if (options.eraseSimulatorBeforeRun) {\n await eraseSimulator(udid);\n }\n\n // Shut down, localize, then boot\n try {\n await execFileAsync(\"xcrun\", [\"simctl\", \"shutdown\", udid]);\n } catch {\n // May already be shutdown\n }\n\n await localizeSimulator(udid, language);\n await bootSimulator(udid);\n\n // Override status bar for clean screenshots\n if (options.overrideStatusBar !== false) {\n try {\n await overrideStatusBar(udid);\n } catch {\n // Status bar override may fail on older simulators\n }\n }\n\n // Set dark mode if requested\n if (options.darkMode) {\n try {\n const { setInterfaceStyle } = await import(\"./simulator.js\");\n await setInterfaceStyle(udid, \"dark\");\n } catch {\n // Dark mode may not be available\n }\n }\n\n // Determine the derived data path (used to find screenshots)\n const derivedDataPath =\n options.derivedDataPath ??\n join(outputDir, \".derived-data\", deviceName + \"-\" + language);\n mkdirSync(derivedDataPath, { recursive: true });\n\n // Run xcodebuild test\n const exitCode = await runXcodebuildTest(\n udid,\n derivedDataPath,\n options,\n );\n\n if (exitCode !== 0 && exitCode !== 65) {\n // Exit code 65 = test failures but screenshots may still exist\n throw new Error(\n \"xcodebuild test failed with exit code \" + exitCode,\n );\n }\n\n // Collect screenshots from derived data and the simulator's data dir\n const deviceOutputDir = join(outputDir, deviceName, language);\n mkdirSync(deviceOutputDir, { recursive: true });\n\n const collectedPaths = collectScreenshots(derivedDataPath, deviceOutputDir);\n\n // Also collect from the simulator's screenshot directory\n const simScreenshotDir = getSimulatorScreenshotDir(udid);\n if (existsSync(simScreenshotDir)) {\n const simPaths = collectScreenshots(simScreenshotDir, deviceOutputDir);\n collectedPaths.push(...simPaths);\n }\n\n const result: Record<string, Record<string, string[]>> = {};\n if (!result[deviceName]) result[deviceName] = {};\n result[deviceName][language] = collectedPaths;\n\n return result;\n}\n\n// ── Internal: xcodebuild test ──────────────────────────────────────────────\n\nfunction runXcodebuildTest(\n udid: string,\n derivedDataPath: string,\n options: SnapshotOptions,\n): Promise<number> {\n return new Promise((resolve) => {\n const args = buildXcodebuildArgs(udid, derivedDataPath, options);\n\n const proc = spawn(\"xcodebuild\", args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let output = \"\";\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString();\n output += text;\n options.onOutput?.(text);\n });\n\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString();\n output += text;\n options.onOutput?.(text);\n });\n\n proc.on(\"close\", (code) => {\n resolve(code ?? 1);\n });\n\n proc.on(\"error\", () => {\n resolve(1);\n });\n });\n}\n\nfunction buildXcodebuildArgs(\n udid: string,\n derivedDataPath: string,\n options: SnapshotOptions,\n): string[] {\n const args: string[] = [];\n\n if (options.workspace) {\n args.push(\"-workspace\", options.workspace);\n } else if (options.project) {\n args.push(\"-project\", options.project);\n }\n\n if (options.scheme) {\n args.push(\"-scheme\", options.scheme);\n }\n\n if (options.configuration) {\n args.push(\"-configuration\", options.configuration);\n }\n\n args.push(\n \"-destination\",\n \"platform=iOS Simulator,id=\" + udid,\n \"-derivedDataPath\",\n derivedDataPath,\n \"test\",\n );\n\n if (options.testPlan) {\n args.push(\"-testPlan\", options.testPlan);\n }\n\n // Append launch arguments as build settings\n if (options.launchArguments && options.launchArguments.length > 0) {\n const launchArgsStr = options.launchArguments\n .map((a) => \"'\" + a + \"'\")\n .join(\" \");\n args.push(\"SNAPSHOT_LAUNCH_ARGUMENTS=\" + launchArgsStr);\n }\n\n if (options.xcargs) {\n // Split xcargs by spaces (simple split, doesn't handle quoted strings)\n args.push(...options.xcargs.split(/\\s+/).filter(Boolean));\n }\n\n return args;\n}\n\n// ── Internal: Screenshot Collection ────────────────────────────────────────\n\nfunction collectScreenshots(\n sourceDir: string,\n destDir: string,\n): string[] {\n const collected: string[] = [];\n\n if (!existsSync(sourceDir)) return collected;\n\n const screenshotExtensions = new Set([\".png\", \".jpg\", \".jpeg\"]);\n\n function walk(dir: string): void {\n let entries: string[];\n try {\n entries = readdirSync(dir, { withFileTypes: true }).map((e) => {\n if (e.isDirectory()) {\n walk(join(dir, e.name));\n return \"\";\n }\n return e.name;\n }).filter(Boolean);\n } catch {\n return;\n }\n\n for (const name of entries) {\n const ext = extname(name).toLowerCase();\n if (screenshotExtensions.has(ext)) {\n const srcPath = join(dir, name);\n const destPath = join(destDir, basename(name));\n try {\n copyFileSync(srcPath, destPath);\n collected.push(destPath);\n } catch {\n // Skip files we can't copy\n }\n }\n }\n }\n\n walk(sourceDir);\n return collected;\n}\n\nfunction getSimulatorScreenshotDir(udid: string): string {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"/tmp\";\n return join(\n home,\n \"Library\",\n \"Developer\",\n \"CoreSimulator\",\n \"Devices\",\n udid,\n \"data\",\n \"tmp\",\n \"Screenshots\",\n );\n}\n\n// ── Internal: Merge screenshot results ─────────────────────────────────────\n\nfunction mergeScreenshots(\n target: Record<string, Record<string, string[]>>,\n source: Record<string, Record<string, string[]>>,\n): void {\n for (const [device, languages] of Object.entries(source)) {\n if (!target[device]) target[device] = {};\n for (const [lang, paths] of Object.entries(languages)) {\n if (!target[device][lang]) target[device][lang] = [];\n target[device][lang].push(...paths);\n }\n }\n}\n"]}
|