peachsim 0.1.1635 → 0.1.1641

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +10 -1
  2. package/cli/app-config.ts +14 -5
  3. package/cli/app-stubs.ts +96 -22
  4. package/cli/bridge-flow-runner.ts +2 -2
  5. package/cli/cloud-client.ts +60 -40
  6. package/cli/cloud-session.ts +16 -0
  7. package/cli/commands/assert.ts +17 -4
  8. package/cli/commands/box.ts +33 -19
  9. package/cli/commands/doctor.ts +37 -20
  10. package/cli/commands/flow.ts +1 -1
  11. package/cli/commands/inspect/actions.ts +3 -2
  12. package/cli/commands/inspect/core.ts +0 -8
  13. package/cli/commands/inspect/shared.ts +9 -4
  14. package/cli/commands/inspect.ts +65 -61
  15. package/cli/commands/platform.ts +2 -1
  16. package/cli/commands/preview.ts +1 -1
  17. package/cli/commands/record.ts +154 -68
  18. package/cli/commands/swift.ts +18 -4
  19. package/cli/commands/three-mode.ts +4 -38
  20. package/cli/commands/upload.ts +55 -49
  21. package/cli/drivers/playwright-sim-host.ts +65 -42
  22. package/cli/flow-live-status.ts +0 -2
  23. package/cli/main.ts +2 -2
  24. package/cli/outbound-endpoints.ts +7 -5
  25. package/cli/pause-aware-timeout.ts +4 -0
  26. package/cli/ws-bridge.ts +19 -16
  27. package/detox/attempt-events.cjs +99 -6
  28. package/detox/attempt-events.d.cts +7 -0
  29. package/detox/expectations.ts +7 -3
  30. package/detox/index.ts +259 -139
  31. package/detox/jest-environment.cjs +5 -1
  32. package/detox/motion-change.cjs +170 -21
  33. package/detox/motion-change.d.cts +32 -0
  34. package/detox/navigation-lifecycle.ts +35 -3
  35. package/dist-lib/agent-daemon-client.cjs +1 -1
  36. package/dist-lib/agent-events.cjs +1 -1
  37. package/dist-lib/attached-projects.cjs +1 -1
  38. package/dist-lib/auth/shared-session.cjs +1 -1
  39. package/dist-lib/backend-origin.cjs +17 -7
  40. package/dist-lib/beta.cjs +1 -1
  41. package/dist-lib/beta.mjs +1 -1
  42. package/dist-lib/bridge-constants.cjs +1 -1
  43. package/dist-lib/bridge-contract-input.cjs +1 -1
  44. package/dist-lib/bridge-contract-input.mjs +1 -1
  45. package/dist-lib/bridge-contract.cjs +1 -1
  46. package/dist-lib/bridge-contract.mjs +1 -1
  47. package/dist-lib/bundle-channel.cjs +5014 -2268
  48. package/dist-lib/capture-contract.cjs +1 -1
  49. package/dist-lib/capture-contract.mjs +1 -1
  50. package/dist-lib/cloud-contract.cjs +1 -1
  51. package/dist-lib/cloud-contract.mjs +1 -1
  52. package/dist-lib/cloud-test-args.cjs +1 -1
  53. package/dist-lib/cloud-test-args.mjs +1 -1
  54. package/dist-lib/cloud.cjs +1 -1
  55. package/dist-lib/cloud.mjs +1 -1
  56. package/dist-lib/config.cjs +1 -1
  57. package/dist-lib/config.mjs +1 -1
  58. package/dist-lib/detox/index.cjs +1036 -166
  59. package/dist-lib/detox/jest-environment.cjs +5 -1
  60. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  61. package/dist-lib/expo-swift-bundle.cjs +4613 -1963
  62. package/dist-lib/expo-swift-metadata.cjs +9 -7
  63. package/dist-lib/expo-swift-metadata.mjs +9 -7
  64. package/dist-lib/home-paths.cjs +1 -1
  65. package/dist-lib/host/bridge-host.cjs +58072 -16400
  66. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  67. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  68. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  69. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  70. package/dist-lib/host/websocket-proxy.cjs +1 -1
  71. package/dist-lib/index.cjs +2790 -143
  72. package/dist-lib/jump-to-source-babel.cjs +1 -1
  73. package/dist-lib/jump-to-source-native.cjs +1 -1
  74. package/dist-lib/kotlin-host.cjs +1 -1
  75. package/dist-lib/menu.cjs +1 -1
  76. package/dist-lib/menu.mjs +1 -1
  77. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  78. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  79. package/dist-lib/metro-production-bundle.cjs +1 -1
  80. package/dist-lib/metro-production-bundle.mjs +1 -1
  81. package/dist-lib/metro.cjs +2579 -95
  82. package/dist-lib/native-app-identity-project.cjs +243 -53
  83. package/dist-lib/native-app-identity-project.mjs +243 -53
  84. package/dist-lib/native-app-identity.cjs +29 -30
  85. package/dist-lib/native-app-identity.mjs +29 -30
  86. package/dist-lib/native-firebase-metadata.cjs +1 -1
  87. package/dist-lib/native-firebase-metadata.mjs +1 -1
  88. package/dist-lib/plist.cjs +1 -1
  89. package/dist-lib/plist.mjs +1 -1
  90. package/dist-lib/profiles.cjs +1 -1
  91. package/dist-lib/public-brand.cjs +1 -1
  92. package/dist-lib/react-native-host-modules.cjs +2 -2
  93. package/dist-lib/react-native-host-modules.mjs +2 -2
  94. package/dist-lib/scripts/dev-server-scanner.cjs +8 -6
  95. package/dist-lib/sdk.cjs +4 -3
  96. package/dist-lib/sdk.mjs +4 -3
  97. package/dist-lib/skills.cjs +66475 -23097
  98. package/dist-lib/swift-compile.cjs +452 -260
  99. package/dist-lib/swift-compile.mjs +451 -252
  100. package/dist-lib/swift-package.cjs +1 -1
  101. package/dist-lib/swift-package.mjs +1 -1
  102. package/dist-lib/swift-submit.cjs +14 -7
  103. package/dist-lib/swift-submit.mjs +14 -7
  104. package/dist-lib/swift-toolchain.cjs +316 -41
  105. package/dist-lib/swift.cjs +1 -1
  106. package/dist-lib/vite-swift.cjs +8188 -5636
  107. package/dist-lib/vite.cjs +2857 -12
  108. package/dist-lib/worklet-executable.cjs +14 -2
  109. package/dist-lib/worklet-executable.mjs +14 -2
  110. package/package.json +1 -1
  111. package/src/backend-origin.ts +21 -6
  112. package/src/expo-swift-host.ts +5 -2
  113. package/src/expoKotlinContract.ts +4 -7
  114. package/src/expoSwiftContract.ts +4 -6
  115. package/src/host/staged-host-files.ts +9 -0
  116. package/src/native-app-identity-project.ts +1 -4
  117. package/src/native-app-identity.ts +1 -4
  118. package/src/nativeAppIconContract.ts +1 -4
  119. package/src/output-lock-stdio.ts +36 -0
  120. package/src/react-native-bridge-modules.ts +106 -78
  121. package/src/react-native-host-modules.ts +4 -1
  122. package/src/settings-bundle.ts +1 -4
  123. package/src/swift-compile.ts +224 -139
  124. package/src/swift-distribution.lock.json +23 -12
  125. package/src/swift-distribution.ts +103 -4
  126. package/src/swift-host.ts +95 -30
  127. package/src/swift-icu.ts +16 -10
  128. package/src/swift-objc-compile.ts +547 -0
  129. package/src/swift-objc-metadata.ts +204 -0
  130. package/src/swift-objc-sdk.ts +883 -19
  131. package/src/swift-objc-standin.ts +126 -14
  132. package/src/swift-package-manifest.ts +42 -1
  133. package/src/swift-packages.ts +35 -21
  134. package/src/swift-root-lock.ts +153 -0
  135. package/src/swift-standin-emit.ts +40 -7
  136. package/src/swift-standins.ts +404 -138
  137. package/src/swift-submit.ts +18 -7
  138. package/src/swift-toolchain.ts +378 -46
  139. package/src/swiftContract.ts +12 -0
  140. package/src/worker-system-chunks.ts +11 -12
  141. package/src/worklet-executable.ts +19 -1
  142. package/src/xcode-project.ts +280 -33
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1635 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1641 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/native-app-identity-project.ts
4
4
  import fs2 from "node:fs";
@@ -187,10 +187,12 @@ function androidMergedResourceValuesDirectory(manifestFile) {
187
187
  return `${intermediates}incremental/${variant}/merge${taskVariant}Resources/merged.dir`;
188
188
  }
189
189
 
190
- // src/nativeAppIconContract.ts
190
+ // src/is-record.ts
191
191
  function isRecord(value) {
192
192
  return typeof value === "object" && value !== null && !Array.isArray(value);
193
193
  }
194
+
195
+ // src/nativeAppIconContract.ts
194
196
  function resolveNativeAppIconArtwork(resources, readText, resourceUri, icons, primaryName, alternateNames, resolveReference) {
195
197
  const members = new Set(resources);
196
198
  const dictionary = isRecord(icons) ? icons : {};
@@ -444,21 +446,18 @@ function visitXcodeTargetMembers(objects, targetId, resolvePath, filesUnder, joi
444
446
  }
445
447
 
446
448
  // src/native-app-identity.ts
447
- function isRecord2(value) {
448
- return typeof value === "object" && value !== null && !Array.isArray(value);
449
- }
450
449
  function nonEmptyString(value) {
451
450
  return typeof value === "string" && value.length > 0 ? value : null;
452
451
  }
453
452
  function readGoogleSignInConfiguration(plist3, resources) {
454
453
  const clientIds = {};
455
454
  for (const [file, value] of Object.entries(resources)) {
456
- if (isRecord2(value) && typeof value.CLIENT_ID === "string")
455
+ if (isRecord(value) && typeof value.CLIENT_ID === "string")
457
456
  clientIds[file.split("/").pop()?.replace(/\.plist$/, "") ?? file] = value.CLIENT_ID;
458
457
  }
459
458
  const urlSchemes = [];
460
459
  for (const entry of Array.isArray(plist3.CFBundleURLTypes) ? plist3.CFBundleURLTypes : []) {
461
- if (!isRecord2(entry) || !Array.isArray(entry.CFBundleURLSchemes)) continue;
460
+ if (!isRecord(entry) || !Array.isArray(entry.CFBundleURLSchemes)) continue;
462
461
  for (const scheme of entry.CFBundleURLSchemes)
463
462
  if (typeof scheme === "string") urlSchemes.push(scheme);
464
463
  }
@@ -566,14 +565,14 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
566
565
  let objects = {};
567
566
  try {
568
567
  const parsed = parseOpenStepPlist(pbxproj);
569
- if (isRecord2(parsed)) {
570
- objects = isRecord2(parsed.objects) ? parsed.objects : parsed;
568
+ if (isRecord(parsed)) {
569
+ objects = isRecord(parsed.objects) ? parsed.objects : parsed;
571
570
  }
572
571
  } catch {
573
572
  }
574
573
  const targets = [];
575
574
  for (const [id, obj] of Object.entries(objects)) {
576
- if (isRecord2(obj) && obj.isa === "PBXNativeTarget" && typeof obj.name === "string") {
575
+ if (isRecord(obj) && obj.isa === "PBXNativeTarget" && typeof obj.name === "string") {
577
576
  targets.push({
578
577
  id,
579
578
  name: obj.name,
@@ -619,13 +618,13 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
619
618
  PRODUCT_NAME: targetName
620
619
  };
621
620
  for (const obj of Object.values(objects)) {
622
- if (isRecord2(obj) && obj.isa === "PBXProject" && typeof obj.buildConfigurationList === "string") {
621
+ if (isRecord(obj) && obj.isa === "PBXProject" && typeof obj.buildConfigurationList === "string") {
623
622
  const listObj = objects[obj.buildConfigurationList];
624
- if (isRecord2(listObj) && Array.isArray(listObj.buildConfigurations)) {
623
+ if (isRecord(listObj) && Array.isArray(listObj.buildConfigurations)) {
625
624
  for (const configId of listObj.buildConfigurations) {
626
625
  if (typeof configId === "string") {
627
626
  const configObj = objects[configId];
628
- if (isRecord2(configObj) && configObj.name === "Release" && isRecord2(configObj.buildSettings)) {
627
+ if (isRecord(configObj) && configObj.name === "Release" && isRecord(configObj.buildSettings)) {
629
628
  for (const [k, v] of Object.entries(configObj.buildSettings)) {
630
629
  if (typeof v === "string") settings[k] = v;
631
630
  }
@@ -637,11 +636,11 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
637
636
  }
638
637
  if (selectedTarget?.buildConfigurationList) {
639
638
  const listObj = objects[selectedTarget.buildConfigurationList];
640
- if (isRecord2(listObj) && Array.isArray(listObj.buildConfigurations)) {
639
+ if (isRecord(listObj) && Array.isArray(listObj.buildConfigurations)) {
641
640
  for (const configId of listObj.buildConfigurations) {
642
641
  if (typeof configId === "string") {
643
642
  const configObj = objects[configId];
644
- if (isRecord2(configObj) && configObj.name === "Release" && isRecord2(configObj.buildSettings)) {
643
+ if (isRecord(configObj) && configObj.name === "Release" && isRecord(configObj.buildSettings)) {
645
644
  for (const [k, v] of Object.entries(configObj.buildSettings)) {
646
645
  if (typeof v === "string") settings[k] = v;
647
646
  }
@@ -692,7 +691,7 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
692
691
  if (!bundleName) return null;
693
692
  const applicationName = identityFieldFrom(settings, plistString(plist3, "CFBundleDisplayName"), void 0) ?? bundleName;
694
693
  const dictionary = parseInfoPlist(plist3);
695
- if (!isRecord2(dictionary)) throw new Error("native app Info.plist is not a dictionary");
694
+ if (!isRecord(dictionary)) throw new Error("native app Info.plist is not a dictionary");
696
695
  const declaredDisplayName = dictionary.CFBundleDisplayName;
697
696
  const applicationDisplayName = typeof declaredDisplayName === "string" ? resolveBuildSetting(declaredDisplayName, settings) : void 0;
698
697
  if (applicationDisplayName === null)
@@ -705,9 +704,9 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
705
704
  if (dtPlatformVersion === null)
706
705
  throw new Error("native app Info.plist DTPlatformVersion is unresolved");
707
706
  const icons = dictionary.CFBundleIcons;
708
- const alternates = isRecord2(icons) ? icons.CFBundleAlternateIcons : void 0;
707
+ const alternates = isRecord(icons) ? icons.CFBundleAlternateIcons : void 0;
709
708
  const alternateIconNames = /* @__PURE__ */ new Set();
710
- for (const name of isRecord2(alternates) ? Object.keys(alternates) : []) {
709
+ for (const name of isRecord(alternates) ? Object.keys(alternates) : []) {
711
710
  const resolved = resolveBuildSetting(name, settings);
712
711
  if (resolved === null) throw new Error("native alternate icon name is unresolved");
713
712
  alternateIconNames.add(resolved);
@@ -811,11 +810,11 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
811
810
  return `${base.startsWith("/") ? "/" : ""}${segments.join("/")}`;
812
811
  };
813
812
  const project = Object.values(objects).find(
814
- (object) => isRecord2(object) && object.isa === "PBXProject"
813
+ (object) => isRecord(object) && object.isa === "PBXProject"
815
814
  );
816
815
  const projectDir = join(
817
816
  pbxprojPath.replace(/(?:^|\/)[^/]+\.xcodeproj\/project\.pbxproj$/, ""),
818
- isRecord2(project) && typeof project.projectDirPath === "string" ? project.projectDirPath : ""
817
+ isRecord(project) && typeof project.projectDirPath === "string" ? project.projectDirPath : ""
819
818
  );
820
819
  const paths = Object.keys(files);
821
820
  visitXcodeTargetMembers(
@@ -928,6 +927,8 @@ function parsePlistSource(source) {
928
927
  }
929
928
 
930
929
  // src/xcode-project.ts
930
+ import { execFileSync } from "node:child_process";
931
+ import { createHash } from "node:crypto";
931
932
  import fs from "node:fs";
932
933
  import path2 from "node:path";
933
934
  import plist2 from "plist";
@@ -1440,11 +1441,14 @@ function targetSettings(ref, configuration, builtins, options = {}) {
1440
1441
  if (!config) return [];
1441
1442
  const name = str(config.name) ?? configuration;
1442
1443
  const base = str(config.baseConfigurationReference);
1444
+ const anchor = str(config.baseConfigurationReferenceAnchor);
1445
+ const relative = str(config.baseConfigurationReferenceRelativePath);
1443
1446
  const own = isDict(config.buildSettings) ? config.buildSettings : {};
1444
- const baseFile = base ? project.resolvePath(base) : null;
1445
- if (options.requireSources !== false && base && (!baseFile || !fs.existsSync(baseFile)))
1447
+ const directory = anchor ? project.resolvePath(anchor) : null;
1448
+ const baseFile = base ? project.resolvePath(base) : directory && relative ? path2.resolve(directory, relative) : null;
1449
+ if (options.requireSources !== false && (base || anchor || relative) && (!baseFile || !fs.existsSync(baseFile)))
1446
1450
  throw new Error(
1447
- `Unable to open base configuration reference file '${baseFile ?? base}'`
1451
+ `Unable to open base configuration reference file '${baseFile ?? base ?? relative ?? anchor}'`
1448
1452
  );
1449
1453
  const read = [];
1450
1454
  const fromFile = baseFile ? readXcconfig(baseFile, read) : {};
@@ -1535,33 +1539,131 @@ function expand(value, lookup) {
1535
1539
  }
1536
1540
  );
1537
1541
  }
1538
- function targetMembers(ref, settings, options = {}) {
1542
+ var preparedSourcePhases = /* @__PURE__ */ new Map();
1543
+ function targetMembers(ref, settings, options, settingKeys, projectInputs) {
1539
1544
  const { project, target, id: targetId } = ref;
1540
1545
  const targetName = str(target.name) ?? targetId;
1541
1546
  const sources = /* @__PURE__ */ new Set();
1542
1547
  const allSources = /* @__PURE__ */ new Set();
1543
1548
  const resources = /* @__PURE__ */ new Set();
1544
1549
  const scriptForOutput = /* @__PURE__ */ new Map();
1545
- const noteScriptOutput = (raw, script) => {
1546
- const expanded = expand(raw, settings);
1547
- if (!expanded.endsWith(".swift")) return;
1548
- const absolute = path2.isAbsolute(expanded) ? path2.normalize(expanded) : path2.resolve(project.projectDir, expanded);
1549
- if (!scriptForOutput.has(absolute)) scriptForOutput.set(absolute, script);
1550
- };
1551
1550
  for (const phaseId of list(target.buildPhases)) {
1552
1551
  const phase = project.object(phaseId);
1553
1552
  if (phase?.isa !== "PBXShellScriptBuildPhase") continue;
1554
1553
  const script = str(phase.name) ?? phaseId;
1555
- for (const raw of list(phase.outputPaths)) noteScriptOutput(raw, script);
1556
- for (const listPath of list(phase.outputFileListPaths)) {
1557
- const expandedList = expand(listPath, settings);
1558
- const absoluteList = path2.isAbsolute(expandedList) ? expandedList : path2.resolve(project.projectDir, expandedList);
1559
- if (!fs.existsSync(absoluteList)) continue;
1560
- for (const line of fs.readFileSync(absoluteList, "utf8").split("\n")) {
1561
- const trimmed = line.trim();
1562
- if (trimmed === "" || trimmed.startsWith("#")) continue;
1563
- noteScriptOutput(trimmed, script);
1554
+ const absolute = (raw) => path2.resolve(project.projectDir, expand(raw, settings));
1555
+ const inputs = list(phase.inputPaths).map(absolute);
1556
+ const outputs = list(phase.outputPaths).map(absolute);
1557
+ const fileLists = /* @__PURE__ */ new Map();
1558
+ for (const kind of ["INPUT", "OUTPUT"]) {
1559
+ const lists = list(
1560
+ kind === "INPUT" ? phase.inputFileListPaths : phase.outputFileListPaths
1561
+ ).map((raw) => {
1562
+ const file = absolute(raw);
1563
+ if (!fs.existsSync(file)) {
1564
+ return { file, entries: [] };
1565
+ }
1566
+ const entries = fs.readFileSync(file, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line !== "" && !line.startsWith("#")).map(absolute);
1567
+ return { file, entries };
1568
+ });
1569
+ fileLists.set(kind, lists);
1570
+ }
1571
+ const allOutputs = [
1572
+ ...outputs,
1573
+ ...fileLists.get("OUTPUT").flatMap((item) => item.entries)
1574
+ ];
1575
+ for (const output of allOutputs)
1576
+ if (output.endsWith(".swift") && !scriptForOutput.has(output))
1577
+ scriptForOutput.set(output, script);
1578
+ const inputFiles = [
1579
+ ...inputs,
1580
+ ...fileLists.get("INPUT").flatMap((item) => [item.file, ...item.entries]),
1581
+ ...fileLists.get("OUTPUT").map((item) => item.file)
1582
+ ];
1583
+ if (allOutputs.some((file) => file.endsWith(".swift"))) {
1584
+ for (const file of inputFiles) if (fs.existsSync(file)) projectInputs.add(file);
1585
+ }
1586
+ if (options.prepareGeneratedSources && options.requireSources !== false && allOutputs.some((file) => file.endsWith(".swift"))) {
1587
+ const phaseDir = path2.join(settings("TARGET_TEMP_DIR"), `Script-${phaseId}`);
1588
+ for (const lists of fileLists.values())
1589
+ for (const { file } of lists)
1590
+ if (!fs.existsSync(file))
1591
+ throw new Error(
1592
+ `${targetName}: Run Script "${script}" missing file list ${file}`
1593
+ );
1594
+ const env = {
1595
+ ...process.env,
1596
+ ...Object.fromEntries(
1597
+ [...settingKeys].filter((key2) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key2)).map((key2) => [key2, settings(key2)])
1598
+ )
1599
+ };
1600
+ const declared = { INPUT: inputs, OUTPUT: outputs };
1601
+ for (const kind of ["INPUT", "OUTPUT"]) {
1602
+ env[`SCRIPT_${kind}_FILE_COUNT`] = String(declared[kind].length);
1603
+ declared[kind].forEach((file, index) => {
1604
+ env[`SCRIPT_${kind}_FILE_${index}`] = file;
1605
+ });
1606
+ const lists = fileLists.get(kind);
1607
+ env[`SCRIPT_${kind}_FILE_LIST_COUNT`] = String(lists.length);
1608
+ lists.forEach((_item, index) => {
1609
+ env[`SCRIPT_${kind}_FILE_LIST_${index}`] = path2.join(
1610
+ phaseDir,
1611
+ `${kind}-${index}.xcfilelist`
1612
+ );
1613
+ });
1564
1614
  }
1615
+ const signature = createHash("sha256").update(
1616
+ JSON.stringify([phase, [...settingKeys].map((key2) => [key2, settings(key2)])])
1617
+ );
1618
+ for (const file of inputFiles) {
1619
+ signature.update(file);
1620
+ if (fs.existsSync(file)) {
1621
+ const stat = fs.statSync(file);
1622
+ signature.update(`${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`);
1623
+ } else signature.update("missing");
1624
+ }
1625
+ const stamp = signature.digest("hex");
1626
+ const key = `${project.projectFile}:${targetId}:${phaseId}:${settings("CONFIGURATION")}`;
1627
+ if (preparedSourcePhases.get(key) === stamp && allOutputs.every((file) => fs.existsSync(file)))
1628
+ continue;
1629
+ fs.mkdirSync(phaseDir, { recursive: true });
1630
+ fs.mkdirSync(settings("BUILT_PRODUCTS_DIR"), { recursive: true });
1631
+ fs.mkdirSync(settings("DERIVED_FILE_DIR"), { recursive: true });
1632
+ for (const [kind, lists] of fileLists)
1633
+ lists.forEach((item, index) => {
1634
+ fs.writeFileSync(
1635
+ env[`SCRIPT_${kind}_FILE_LIST_${index}`],
1636
+ `${item.entries.join("\n")}
1637
+ `
1638
+ );
1639
+ });
1640
+ try {
1641
+ execFileSync(
1642
+ str(phase.shellPath) ?? "/bin/sh",
1643
+ ["-c", str(phase.shellScript) ?? ""],
1644
+ {
1645
+ cwd: project.projectDir,
1646
+ env,
1647
+ stdio: ["ignore", "pipe", "pipe"],
1648
+ timeout: 12e4
1649
+ }
1650
+ );
1651
+ } catch (error) {
1652
+ const output = error instanceof Error ? `${error.message}
1653
+ ${"stdout" in error ? String(error.stdout) : ""}${"stderr" in error ? String(error.stderr) : ""}` : String(error);
1654
+ throw new Error(
1655
+ `${targetName}: Run Script "${script}" failed preparing generated Swift sources:
1656
+ ${output}`
1657
+ );
1658
+ }
1659
+ const missing = allOutputs.filter(
1660
+ (file) => file.endsWith(".swift") && !fs.existsSync(file)
1661
+ );
1662
+ if (missing.length > 0)
1663
+ throw new Error(
1664
+ `${targetName}: Run Script "${script}" did not produce ${missing.join(", ")}`
1665
+ );
1666
+ preparedSourcePhases.set(key, stamp);
1565
1667
  }
1566
1668
  }
1567
1669
  visitXcodeTargetMembers(
@@ -1751,22 +1853,95 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1751
1853
  SRCROOT: ref.project.projectDir,
1752
1854
  SOURCE_ROOT: ref.project.projectDir,
1753
1855
  PROJECT_DIR: ref.project.projectDir,
1856
+ SYMROOT: path2.join(ref.project.projectDir, ".build/peach-xcode/Build/Products"),
1857
+ BUILD_DIR: "$(SYMROOT)",
1858
+ OBJROOT: path2.join(
1859
+ ref.project.projectDir,
1860
+ ".build/peach-xcode/Build/Intermediates.noindex"
1861
+ ),
1862
+ CONFIGURATION_BUILD_DIR: "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)",
1863
+ BUILT_PRODUCTS_DIR: "$(CONFIGURATION_BUILD_DIR)",
1864
+ TARGET_BUILD_DIR: "$(CONFIGURATION_BUILD_DIR)",
1865
+ PROJECT_TEMP_DIR: "$(OBJROOT)/$(PROJECT_NAME).build",
1866
+ CONFIGURATION_TEMP_DIR: "$(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)",
1867
+ TARGET_TEMP_DIR: "$(CONFIGURATION_TEMP_DIR)/$(TARGET_NAME).build",
1868
+ DERIVED_FILE_DIR: "$(TARGET_TEMP_DIR)/DerivedSources",
1869
+ DERIVED_FILES_DIR: "$(DERIVED_FILE_DIR)",
1870
+ PLATFORM_NAME: "iphonesimulator",
1871
+ EFFECTIVE_PLATFORM_NAME: "-iphonesimulator",
1872
+ CURRENT_ARCH: "arm64",
1873
+ ARCHS: "arm64",
1874
+ ACTION: "build",
1754
1875
  DEVELOPMENT_LANGUAGE: str(ref.project.project.developmentRegion) ?? "en"
1755
1876
  },
1756
1877
  options
1757
1878
  );
1758
1879
  for (const file of read) xcconfigs.add(file);
1759
1880
  const swiftVersion = Number.parseFloat(settings2("SWIFT_VERSION") || "5");
1881
+ const members = targetMembers(ref, settings2, options, keys, xcconfigs);
1882
+ const implementations = members.allSources.filter(
1883
+ (file) => /\.(c|cc|cpp|cxx|m|mm)$/.test(file)
1884
+ );
1885
+ const absolute = (file) => path2.resolve(ref.project.projectDir, file);
1886
+ const fileFlags = {};
1887
+ for (const phaseId of list(ref.target.buildPhases)) {
1888
+ const phase = ref.project.object(phaseId);
1889
+ if (phase?.isa !== "PBXSourcesBuildPhase") continue;
1890
+ for (const id of list(phase.files)) {
1891
+ const file = ref.project.object(id);
1892
+ const resolved = ref.project.resolvePath(str(file?.fileRef) ?? "");
1893
+ if (resolved && implementations.includes(resolved))
1894
+ fileFlags[resolved] = settingList(
1895
+ expand(
1896
+ str(isDict(file?.settings) ? file.settings.COMPILER_FLAGS : void 0) ?? "",
1897
+ settings2
1898
+ )
1899
+ );
1900
+ }
1901
+ }
1760
1902
  return {
1761
1903
  settings: settings2,
1762
1904
  keys,
1763
1905
  module: {
1764
1906
  name,
1765
1907
  moduleName: applyOperator(settings2("PRODUCT_MODULE_NAME"), "c99extidentifier"),
1766
- ...targetMembers(ref, settings2, options),
1908
+ ...members,
1767
1909
  languageMode: swiftVersion >= 6 ? 6 : 5,
1768
1910
  mainActorIsolation: settings2("SWIFT_DEFAULT_ACTOR_ISOLATION") === "MainActor",
1769
- defines: compilationConditions(settings2)
1911
+ defines: compilationConditions(settings2),
1912
+ iosDeploymentTarget: settings2("IPHONEOS_DEPLOYMENT_TARGET") || null,
1913
+ ...implementations.some((file) => /\.mm?$/.test(file)) ? {
1914
+ objc: {
1915
+ headers: Object.keys(ref.project.objects).flatMap((id) => {
1916
+ const file = ref.project.resolvePath(id);
1917
+ return file && /\.(h|hh|hpp|hxx|pch)$/.test(file) && fs.existsSync(file) ? [file] : [];
1918
+ }),
1919
+ prefixHeader: settings2("GCC_PREFIX_HEADER") ? absolute(settings2("GCC_PREFIX_HEADER")) : null,
1920
+ bridgingHeader: settings2("SWIFT_OBJC_BRIDGING_HEADER") ? absolute(settings2("SWIFT_OBJC_BRIDGING_HEADER")) : null,
1921
+ headerSearchPaths: [
1922
+ ...settingList(settings2("HEADER_SEARCH_PATHS")),
1923
+ ...settingList(settings2("USER_HEADER_SEARCH_PATHS"))
1924
+ ].map(absolute),
1925
+ frameworkSearchPaths: settingList(settings2("FRAMEWORK_SEARCH_PATHS")).map(
1926
+ absolute
1927
+ ),
1928
+ flags: [
1929
+ ...settings2("CLANG_ENABLE_OBJC_ARC") === "YES" ? ["-fobjc-arc"] : [],
1930
+ ...settings2("CLANG_ENABLE_OBJC_WEAK") === "YES" ? ["-fobjc-weak"] : [],
1931
+ ...settings2("CLANG_ENABLE_MODULES") === "YES" ? ["-fmodules"] : [],
1932
+ ...settings2("GCC_C_LANGUAGE_STANDARD") ? [`-std=${settings2("GCC_C_LANGUAGE_STANDARD")}`] : [],
1933
+ ...settingList(settings2("GCC_PREPROCESSOR_DEFINITIONS")).map(
1934
+ (value) => `-D${value}`
1935
+ ),
1936
+ ...settingList(settings2("OTHER_CFLAGS"))
1937
+ ],
1938
+ cxxFlags: [
1939
+ ...settings2("CLANG_CXX_LANGUAGE_STANDARD") ? [`-std=${settings2("CLANG_CXX_LANGUAGE_STANDARD")}`] : [],
1940
+ ...settingList(settings2("OTHER_CPLUSPLUSFLAGS"))
1941
+ ],
1942
+ fileFlags
1943
+ }
1944
+ } : {}
1770
1945
  }
1771
1946
  };
1772
1947
  };
@@ -1815,6 +1990,23 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1815
1990
  ...projects.flatMap(
1816
1991
  (project) => Object.entries(project.objects).flatMap(([id, entry]) => {
1817
1992
  if (!isDict(entry)) return [];
1993
+ if (entry.isa === "PBXFileSystemSynchronizedRootGroup") {
1994
+ const folder = project.resolvePath(id);
1995
+ const pending = folder ? [folder] : [];
1996
+ const packages = [];
1997
+ while (pending.length > 0) {
1998
+ const dir = pending.pop();
1999
+ if (fs.existsSync(path2.join(dir, "Package.swift"))) {
2000
+ packages.push(dir);
2001
+ continue;
2002
+ }
2003
+ if (!isDirectory(dir)) continue;
2004
+ for (const child of fs.readdirSync(dir, { withFileTypes: true }))
2005
+ if (child.isDirectory() && !child.name.startsWith("."))
2006
+ pending.push(path2.join(dir, child.name));
2007
+ }
2008
+ return packages;
2009
+ }
1818
2010
  const candidate = entry.isa === "XCLocalSwiftPackageReference" ? path2.resolve(project.projectDir, str(entry.relativePath) ?? "") : entry.isa === "PBXFileReference" ? project.resolvePath(id) : null;
1819
2011
  return candidate && fs.existsSync(path2.join(candidate, "Package.swift")) ? [candidate] : [];
1820
2012
  })
@@ -1869,6 +2061,7 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1869
2061
  "swiftpm",
1870
2062
  "Package.resolved"
1871
2063
  );
2064
+ const packageResolved = fs.existsSync(resolvedFile) ? [fs.realpathSync(resolvedFile)] : [...new Set(localPackageDirs.map((dir) => path2.join(dir, "Package.resolved")))].filter((file) => fs.existsSync(file)).map((file) => fs.realpathSync(file)).sort();
1872
2065
  const used = order.map((ref) => ref.project);
1873
2066
  return {
1874
2067
  ...module,
@@ -1894,7 +2087,7 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1894
2087
  ...new Set(localPackageDirs.map((dir) => fs.realpathSync(dir)))
1895
2088
  ].sort(),
1896
2089
  binaryFrameworks: [...binaryFrameworks].map(([name, file]) => ({ name, path: file })).sort((left, right) => left.name.localeCompare(right.name)),
1897
- packageResolved: fs.existsSync(resolvedFile) ? resolvedFile : null,
2090
+ packageResolved,
1898
2091
  appTargets: appTargetNames,
1899
2092
  configuration,
1900
2093
  settings
@@ -1902,15 +2095,12 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1902
2095
  }
1903
2096
 
1904
2097
  // src/native-app-identity-project.ts
1905
- function isRecord3(value) {
1906
- return typeof value === "object" && value !== null && !Array.isArray(value);
1907
- }
1908
2098
  function nonEmptyString2(value) {
1909
2099
  return typeof value === "string" && value.length > 0 ? value : void 0;
1910
2100
  }
1911
2101
  function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSource) {
1912
2102
  const dictionary = parseInfoPlist(app.infoPlist);
1913
- if (!isRecord3(dictionary)) throw new Error("native app Info.plist is not a dictionary");
2103
+ if (!isRecord(dictionary)) throw new Error("native app Info.plist is not a dictionary");
1914
2104
  const settings = app.settings;
1915
2105
  const bundleIdentifier = nonEmptyString2(dictionary.CFBundleIdentifier) ?? nonEmptyString2(settings?.("PRODUCT_BUNDLE_IDENTIFIER"));
1916
2106
  if (!bundleIdentifier) throw new Error("native app has no bundle identifier");
@@ -1927,8 +2117,8 @@ function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSo
1927
2117
  const designRequiresCompatibility = dictionary.UIDesignRequiresCompatibility === true;
1928
2118
  const alternateIconNames = /* @__PURE__ */ new Set();
1929
2119
  const icons = dictionary.CFBundleIcons;
1930
- const alternates = isRecord3(icons) ? icons.CFBundleAlternateIcons : void 0;
1931
- if (isRecord3(alternates)) {
2120
+ const alternates = isRecord(icons) ? icons.CFBundleAlternateIcons : void 0;
2121
+ if (isRecord(alternates)) {
1932
2122
  for (const name of Object.keys(alternates)) {
1933
2123
  if (name) alternateIconNames.add(name);
1934
2124
  }
@@ -2160,7 +2350,7 @@ function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
2160
2350
  const installedManifest = JSON.parse(
2161
2351
  fs2.readFileSync(reanimatedManifestPath, "utf8")
2162
2352
  );
2163
- const installedVersion = isRecord3(installedManifest) ? nonEmptyString2(installedManifest.version) : void 0;
2353
+ const installedVersion = isRecord(installedManifest) ? nonEmptyString2(installedManifest.version) : void 0;
2164
2354
  if (!installedVersion) throw new Error("Reanimated package version is malformed");
2165
2355
  if (Number.parseInt(installedVersion, 10) < 4) return identity;
2166
2356
  const defaults = JSON.parse(
@@ -2172,11 +2362,11 @@ function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
2172
2362
  "utf8"
2173
2363
  )
2174
2364
  );
2175
- if (!isRecord3(defaults)) throw new Error("Reanimated static flags are malformed");
2365
+ if (!isRecord(defaults)) throw new Error("Reanimated static flags are malformed");
2176
2366
  const manifest = JSON.parse(fs2.readFileSync(projectManifestPath, "utf8"));
2177
- const reanimated = isRecord3(manifest) ? manifest.reanimated : void 0;
2178
- const overrides = isRecord3(reanimated) ? reanimated.staticFeatureFlags : void 0;
2179
- if (overrides !== void 0 && !isRecord3(overrides)) {
2367
+ const reanimated = isRecord(manifest) ? manifest.reanimated : void 0;
2368
+ const overrides = isRecord(reanimated) ? reanimated.staticFeatureFlags : void 0;
2369
+ if (overrides !== void 0 && !isRecord(overrides)) {
2180
2370
  throw new Error("Reanimated static flag overrides are malformed");
2181
2371
  }
2182
2372
  const flags = {};