peachsim 0.1.1640 → 0.1.1644

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 (125) hide show
  1. package/README.md +5 -0
  2. package/cli/app-bundle-resources.ts +57 -0
  3. package/cli/app-stubs.ts +38 -13
  4. package/cli/cloud-session.ts +16 -0
  5. package/cli/commands/assert.ts +17 -4
  6. package/cli/commands/box.ts +33 -19
  7. package/cli/commands/control.ts +12 -0
  8. package/cli/commands/doctor.ts +24 -15
  9. package/cli/commands/inspect/actions.ts +3 -2
  10. package/cli/commands/inspect/core.ts +0 -8
  11. package/cli/commands/inspect.ts +0 -14
  12. package/cli/commands/platform.ts +2 -1
  13. package/cli/commands/record.ts +64 -28
  14. package/cli/commands/swift.ts +10 -2
  15. package/cli/commands/three-mode.ts +4 -38
  16. package/cli/commands/upload.ts +8 -8
  17. package/cli/drivers/playwright.ts +39 -0
  18. package/cli/flow-live-status.ts +0 -2
  19. package/cli/main.ts +1 -1
  20. package/cli/outbound-endpoints.ts +4 -2
  21. package/cli/ws-bridge.ts +0 -6
  22. package/detox/attempt-events.cjs +41 -5
  23. package/detox/index.ts +155 -109
  24. package/detox/jest-environment.cjs +5 -1
  25. package/detox/motion-change.cjs +7 -5
  26. package/detox/motion-change.d.cts +1 -0
  27. package/detox/motion-leg-starts.cjs +20 -0
  28. package/detox/motion-leg-starts.d.cts +8 -0
  29. package/dist-lib/agent-daemon-client.cjs +1 -1
  30. package/dist-lib/agent-events.cjs +1 -1
  31. package/dist-lib/attached-projects.cjs +1 -1
  32. package/dist-lib/auth/shared-session.cjs +1 -1
  33. package/dist-lib/backend-origin.cjs +12 -3
  34. package/dist-lib/beta.cjs +1 -1
  35. package/dist-lib/beta.mjs +1 -1
  36. package/dist-lib/bridge-constants.cjs +1 -1
  37. package/dist-lib/bridge-contract-input.cjs +1 -1
  38. package/dist-lib/bridge-contract-input.mjs +1 -1
  39. package/dist-lib/bridge-contract.cjs +1 -1
  40. package/dist-lib/bridge-contract.mjs +1 -1
  41. package/dist-lib/bundle-channel.cjs +2671 -1833
  42. package/dist-lib/capture-contract.cjs +1 -1
  43. package/dist-lib/capture-contract.mjs +1 -1
  44. package/dist-lib/cloud-contract.cjs +1 -1
  45. package/dist-lib/cloud-contract.mjs +1 -1
  46. package/dist-lib/cloud-test-args.cjs +1 -1
  47. package/dist-lib/cloud-test-args.mjs +1 -1
  48. package/dist-lib/cloud.cjs +1 -1
  49. package/dist-lib/cloud.mjs +1 -1
  50. package/dist-lib/config.cjs +1 -1
  51. package/dist-lib/config.mjs +1 -1
  52. package/dist-lib/detox/index.cjs +578 -130
  53. package/dist-lib/detox/jest-environment.cjs +5 -1
  54. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  55. package/dist-lib/expo-swift-bundle.cjs +2374 -1554
  56. package/dist-lib/expo-swift-metadata.cjs +1 -1
  57. package/dist-lib/expo-swift-metadata.mjs +1 -1
  58. package/dist-lib/home-paths.cjs +1 -1
  59. package/dist-lib/host/bridge-host.cjs +2968 -2141
  60. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  61. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  62. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  63. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  64. package/dist-lib/host/websocket-proxy.cjs +1 -1
  65. package/dist-lib/index.cjs +132 -57
  66. package/dist-lib/jump-to-source-babel.cjs +1 -1
  67. package/dist-lib/jump-to-source-native.cjs +1 -1
  68. package/dist-lib/kotlin-host.cjs +1 -1
  69. package/dist-lib/menu.cjs +14 -6
  70. package/dist-lib/menu.mjs +14 -6
  71. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  72. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  73. package/dist-lib/metro-production-bundle.cjs +1 -1
  74. package/dist-lib/metro-production-bundle.mjs +1 -1
  75. package/dist-lib/metro.cjs +120 -53
  76. package/dist-lib/native-app-identity-project.cjs +96 -44
  77. package/dist-lib/native-app-identity-project.mjs +95 -44
  78. package/dist-lib/native-app-identity.cjs +1 -1
  79. package/dist-lib/native-app-identity.mjs +1 -1
  80. package/dist-lib/native-firebase-metadata.cjs +1 -1
  81. package/dist-lib/native-firebase-metadata.mjs +1 -1
  82. package/dist-lib/plist.cjs +1 -1
  83. package/dist-lib/plist.mjs +1 -1
  84. package/dist-lib/profiles.cjs +1 -1
  85. package/dist-lib/public-brand.cjs +1 -1
  86. package/dist-lib/react-native-host-modules.cjs +1 -1
  87. package/dist-lib/react-native-host-modules.mjs +1 -1
  88. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  89. package/dist-lib/sdk.cjs +5 -3
  90. package/dist-lib/sdk.mjs +5 -3
  91. package/dist-lib/skills.cjs +3932 -2868
  92. package/dist-lib/swift-compile.cjs +587 -374
  93. package/dist-lib/swift-compile.mjs +595 -369
  94. package/dist-lib/swift-package.cjs +1 -1
  95. package/dist-lib/swift-package.mjs +1 -1
  96. package/dist-lib/swift-submit.cjs +8 -3
  97. package/dist-lib/swift-submit.mjs +8 -3
  98. package/dist-lib/swift-toolchain.cjs +1 -1
  99. package/dist-lib/swift.cjs +1 -1
  100. package/dist-lib/vite-swift.cjs +2263 -1467
  101. package/dist-lib/vite.cjs +1 -1
  102. package/dist-lib/worklet-executable.cjs +1 -1
  103. package/dist-lib/worklet-executable.mjs +1 -1
  104. package/package.json +1 -1
  105. package/src/appBundleResourcesContract.ts +51 -0
  106. package/src/backend-origin.ts +11 -1
  107. package/src/host/bridge-host.ts +17 -11
  108. package/src/host/staged-host-files.ts +28 -4
  109. package/src/launchMetadataContract.ts +1 -0
  110. package/src/menu.ts +12 -4
  111. package/src/native-app-identity-project.ts +47 -38
  112. package/src/react-native-bridge-modules.ts +89 -76
  113. package/src/runtime-delivery.ts +6 -7
  114. package/src/swift-compile.ts +150 -112
  115. package/src/swift-compiler-digest.ts +5 -3
  116. package/src/swift-distribution.lock.json +9 -8
  117. package/src/swift-host.ts +6 -4
  118. package/src/swift-objc-compile.ts +416 -194
  119. package/src/swift-objc-metadata.ts +204 -0
  120. package/src/swift-objc-sdk.ts +195 -2
  121. package/src/swift-package-manifest.ts +6 -3
  122. package/src/swift-root-lock.ts +302 -0
  123. package/src/swift-submit.ts +15 -2
  124. package/src/swiftContract.ts +12 -0
  125. package/src/xcode-project.ts +77 -7
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1640 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1644 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -5500,15 +5500,28 @@ function packageNativeRequests(dir) {
5500
5500
  }
5501
5501
  function dependencyNativeOwners(appDir, manifest) {
5502
5502
  const owners = /* @__PURE__ */ new Map();
5503
- for (const name2 of Object.keys({
5503
+ const pending = Object.keys({
5504
5504
  ...manifest?.devDependencies,
5505
5505
  ...manifest?.dependencies
5506
- })) {
5507
- const dir = installedPackageDir(appDir, name2);
5508
- if (!dir || !dir.split("/").includes("node_modules")) continue;
5509
- for (const request of packageNativeRequests(dir))
5510
- if (!owners.has(`${request.kind}:${request.name}`))
5511
- owners.set(`${request.kind}:${request.name}`, name2);
5506
+ }).map((name2) => ({ from: appDir, name: name2 }));
5507
+ const visited = /* @__PURE__ */ new Set();
5508
+ for (let index = 0; index < pending.length; index++) {
5509
+ const { from, name: name2 } = pending[index];
5510
+ const dir = installedPackageDir(from, name2);
5511
+ if (!dir || visited.has(dir)) continue;
5512
+ visited.add(dir);
5513
+ const dependency = readProjectManifest(dir);
5514
+ const optional = readPackageJson(dir)?.optionalDependencies;
5515
+ if (dir.split("/").includes("node_modules") && (from === appDir || hasNativeCode(dir, "ios"))) {
5516
+ for (const request of packageNativeRequests(dir))
5517
+ if (!owners.has(`${request.kind}:${request.name}`))
5518
+ owners.set(`${request.kind}:${request.name}`, dependency?.name ?? name2);
5519
+ }
5520
+ for (const child of Object.keys({
5521
+ ...dependency?.dependencies,
5522
+ ...isRecord(optional) ? optional : {}
5523
+ }))
5524
+ pending.push({ from: dir, name: child });
5512
5525
  }
5513
5526
  return owners;
5514
5527
  }
@@ -5640,7 +5653,9 @@ function scanLocalNative(appDir, pkg, answered, platform, knownPackages = /* @__
5640
5653
  expoModuleDirs.map((dir) => [
5641
5654
  dir,
5642
5655
  scanRepository(dir).directories.flatMap(
5643
- (sub) => listDir(sub).filter((name2) => NATIVE_SOURCE_FILE.test(name2)).map((name2) => (0, import_node_path10.join)(sub, name2))
5656
+ (sub) => listDir(sub).filter(
5657
+ (name2) => NATIVE_SOURCE_FILE.test(name2) && (!platform || (platform === "ios" ? name2.endsWith(".swift") : name2.endsWith(".kt")))
5658
+ ).map((name2) => (0, import_node_path10.join)(sub, name2))
5644
5659
  )
5645
5660
  ])
5646
5661
  );
@@ -5669,7 +5684,9 @@ function scanLocalNative(appDir, pkg, answered, platform, knownPackages = /* @__
5669
5684
  path: `${(0, import_node_path10.relative)(appDir, file)}:${line}`,
5670
5685
  expoModule: moduleDir ? (0, import_node_path10.relative)(appDir, moduleDir) || "." : null,
5671
5686
  swift: moduleDir ? (nativeFilesByModule.get(moduleDir) ?? []).some(
5672
- (path14) => path14.endsWith(".swift")
5687
+ (path14) => path14.endsWith(".swift") && [...(readSmallFile(path14) ?? "").matchAll(/\bName\(\s*"(\w+)"\s*\)/g)].some(
5688
+ (match) => match[1] === name2
5689
+ )
5673
5690
  ) : false,
5674
5691
  answered: answered[kind].has(name2)
5675
5692
  });
@@ -9948,11 +9965,14 @@ function targetSettings(ref, configuration, builtins, options = {}) {
9948
9965
  if (!config) return [];
9949
9966
  const name2 = str(config.name) ?? configuration;
9950
9967
  const base = str(config.baseConfigurationReference);
9968
+ const anchor = str(config.baseConfigurationReferenceAnchor);
9969
+ const relative3 = str(config.baseConfigurationReferenceRelativePath);
9951
9970
  const own = isDict(config.buildSettings) ? config.buildSettings : {};
9952
- const baseFile = base ? project.resolvePath(base) : null;
9953
- if (options.requireSources !== false && base && (!baseFile || !import_node_fs5.default.existsSync(baseFile)))
9971
+ const directory = anchor ? project.resolvePath(anchor) : null;
9972
+ const baseFile = base ? project.resolvePath(base) : directory && relative3 ? import_node_path5.default.resolve(directory, relative3) : null;
9973
+ if (options.requireSources !== false && (base || anchor || relative3) && (!baseFile || !import_node_fs5.default.existsSync(baseFile)))
9954
9974
  throw new Error(
9955
- `Unable to open base configuration reference file '${baseFile ?? base}'`
9975
+ `Unable to open base configuration reference file '${baseFile ?? base ?? relative3 ?? anchor}'`
9956
9976
  );
9957
9977
  const read = [];
9958
9978
  const fromFile = baseFile ? readXcconfig(baseFile, read) : {};
@@ -9999,6 +10019,9 @@ function targetSettings(ref, configuration, builtins, options = {}) {
9999
10019
  return applyOperator(get("PRODUCT_NAME"), "c99extidentifier");
10000
10020
  case "EXECUTABLE_NAME":
10001
10021
  return get("PRODUCT_NAME");
10022
+ // the native default of CoreBuildSystem.xcspec
10023
+ case "EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES":
10024
+ return "*.nib *.lproj *.framework *.gch *.xcode* *.xcassets *.icon (*) .DS_Store CVS .svn .git .hg *.pbproj *.pbxproj";
10002
10025
  case "AppIdentifierPrefix":
10003
10026
  case "TeamIdentifierPrefix": {
10004
10027
  const team = get("DEVELOPMENT_TEAM");
@@ -10021,6 +10044,45 @@ function settingList(value) {
10021
10044
  items2.push((quoted ?? plain).replace(/\\(.)/g, "$1"));
10022
10045
  return items2;
10023
10046
  }
10047
+ function expandSearchPath(directory, rules) {
10048
+ if (import_node_path5.default.basename(directory) !== "**") return [directory];
10049
+ const expanded = [];
10050
+ const seen = /* @__PURE__ */ new Set();
10051
+ const queue = [import_node_path5.default.dirname(directory)];
10052
+ for (let at = 0; at < queue.length; at++) {
10053
+ const current = queue[at];
10054
+ let real;
10055
+ try {
10056
+ real = import_node_fs5.default.realpathSync(current);
10057
+ } catch {
10058
+ continue;
10059
+ }
10060
+ if (!import_node_fs5.default.statSync(real).isDirectory() || seen.has(real)) continue;
10061
+ seen.add(real);
10062
+ expanded.push(current);
10063
+ for (const entry of import_node_fs5.default.readdirSync(real, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
10064
+ if (entry.isSymbolicLink() ? !rules.followLinks : !entry.isDirectory()) continue;
10065
+ if (rules.excluded.some((pattern) => pattern.test(entry.name)) && !rules.included.some((pattern) => pattern.test(entry.name)))
10066
+ continue;
10067
+ queue.push(import_node_path5.default.join(current, entry.name));
10068
+ }
10069
+ }
10070
+ return expanded;
10071
+ }
10072
+ function recursiveSearchRules(settings) {
10073
+ const glob = (pattern) => new RegExp(
10074
+ `^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("*", ".*").replaceAll("?", ".")}$`
10075
+ );
10076
+ return {
10077
+ excluded: settingList(settings("EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES")).map(
10078
+ glob
10079
+ ),
10080
+ included: settingList(settings("INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES")).map(
10081
+ glob
10082
+ ),
10083
+ followLinks: settings("RECURSIVE_SEARCH_PATHS_FOLLOW_SYMLINKS") !== "NO"
10084
+ };
10085
+ }
10024
10086
  function compilationConditions(settings) {
10025
10087
  const flags = settingList(settings("OTHER_SWIFT_FLAGS"));
10026
10088
  const defined = flags.flatMap(
@@ -10383,6 +10445,7 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
10383
10445
  for (const file of read) xcconfigs.add(file);
10384
10446
  const swiftVersion = Number.parseFloat(settings2("SWIFT_VERSION") || "5");
10385
10447
  const members = targetMembers(ref, settings2, options, keys, xcconfigs);
10448
+ const searchRules = recursiveSearchRules(settings2);
10386
10449
  const implementations = members.allSources.filter(
10387
10450
  (file) => /\.(c|cc|cpp|cxx|m|mm)$/.test(file)
10388
10451
  );
@@ -10425,10 +10488,10 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
10425
10488
  headerSearchPaths: [
10426
10489
  ...settingList(settings2("HEADER_SEARCH_PATHS")),
10427
10490
  ...settingList(settings2("USER_HEADER_SEARCH_PATHS"))
10428
- ].map(absolute),
10429
- frameworkSearchPaths: settingList(settings2("FRAMEWORK_SEARCH_PATHS")).map(
10430
- absolute
10431
- ),
10491
+ ].flatMap((raw) => expandSearchPath(absolute(raw), searchRules)),
10492
+ frameworkSearchPaths: settingList(
10493
+ settings2("FRAMEWORK_SEARCH_PATHS")
10494
+ ).flatMap((raw) => expandSearchPath(absolute(raw), searchRules)),
10432
10495
  flags: [
10433
10496
  ...settings2("CLANG_ENABLE_OBJC_ARC") === "YES" ? ["-fobjc-arc"] : [],
10434
10497
  ...settings2("CLANG_ENABLE_OBJC_WEAK") === "YES" ? ["-fobjc-weak"] : [],
@@ -10801,42 +10864,8 @@ function readAndroidNativeAppIdentity(projectRoot, androidMergedManifest) {
10801
10864
  );
10802
10865
  }
10803
10866
  function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
10804
- const iosRoot = import_node_path6.default.join(projectRoot, "ios");
10805
- if (!import_node_fs6.default.existsSync(iosRoot)) return null;
10806
- const projects = import_node_fs6.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
10807
- if (projects.length === 0) return null;
10808
- if (projects.length > 1 && !iosTarget) {
10809
- throw new NativeAppTargetSelectionError(
10810
- `native app identity requires a selected Xcode project; set withPeach's iosTarget to an app target in one of: ${projects.map((entry) => entry.name).join(", ")}`
10811
- );
10812
- }
10813
- let project = projects[0];
10814
- if (iosTarget && projects.length > 1) {
10815
- const matches = projects.filter(
10816
- (entry) => listXcodeAppTargets(import_node_path6.default.join(iosRoot, entry.name), {
10817
- requireSources: false
10818
- }).includes(iosTarget)
10819
- );
10820
- if (matches.length === 0) {
10821
- throw new Error(`native app identity has no application target ${iosTarget}`);
10822
- }
10823
- if (matches.length > 1) {
10824
- throw new Error(
10825
- `native app identity target ${iosTarget} is ambiguous across ${matches.map((entry) => entry.name).join(", ")}`
10826
- );
10827
- }
10828
- project = matches[0];
10829
- }
10830
- const xcodeproj = import_node_path6.default.join(iosRoot, project.name);
10831
- const appTargets = listXcodeAppTargets(xcodeproj, { requireSources: false });
10832
- if (!iosTarget && appTargets.length > 1) {
10833
- throw new NativeAppTargetSelectionError(
10834
- `native app identity requires a selected app target; set withPeach's iosTarget to one of: ${appTargets.join(", ")}`
10835
- );
10836
- }
10837
- const app = readXcodeAppTarget(xcodeproj, iosTarget ?? appTargets[0], "Release", {
10838
- requireSources: false
10839
- });
10867
+ const app = readIosAppTarget(projectRoot, iosTarget);
10868
+ if (!app) return null;
10840
10869
  const identity = readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist);
10841
10870
  const projectManifestPath = import_node_path6.default.join(projectRoot, "package.json");
10842
10871
  const projectRequire = (0, import_node_module2.createRequire)(projectManifestPath);
@@ -10889,6 +10918,44 @@ function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
10889
10918
  }
10890
10919
  return { ...identity, reanimatedStaticFeatureFlags: flags };
10891
10920
  }
10921
+ function readIosAppTarget(projectRoot, iosTarget) {
10922
+ const iosRoot = import_node_path6.default.join(projectRoot, "ios");
10923
+ if (!import_node_fs6.default.existsSync(iosRoot)) return null;
10924
+ const projects = import_node_fs6.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
10925
+ if (projects.length === 0) return null;
10926
+ if (projects.length > 1 && !iosTarget) {
10927
+ throw new NativeAppTargetSelectionError(
10928
+ `native app identity requires a selected Xcode project; set withPeach's iosTarget to an app target in one of: ${projects.map((entry) => entry.name).join(", ")}`
10929
+ );
10930
+ }
10931
+ let project = projects[0];
10932
+ if (iosTarget && projects.length > 1) {
10933
+ const matches = projects.filter(
10934
+ (entry) => listXcodeAppTargets(import_node_path6.default.join(iosRoot, entry.name), {
10935
+ requireSources: false
10936
+ }).includes(iosTarget)
10937
+ );
10938
+ if (matches.length === 0) {
10939
+ throw new Error(`native app identity has no application target ${iosTarget}`);
10940
+ }
10941
+ if (matches.length > 1) {
10942
+ throw new Error(
10943
+ `native app identity target ${iosTarget} is ambiguous across ${matches.map((entry) => entry.name).join(", ")}`
10944
+ );
10945
+ }
10946
+ project = matches[0];
10947
+ }
10948
+ const xcodeproj = import_node_path6.default.join(iosRoot, project.name);
10949
+ const appTargets = listXcodeAppTargets(xcodeproj, { requireSources: false });
10950
+ if (!iosTarget && appTargets.length > 1) {
10951
+ throw new NativeAppTargetSelectionError(
10952
+ `native app identity requires a selected app target; set withPeach's iosTarget to one of: ${appTargets.join(", ")}`
10953
+ );
10954
+ }
10955
+ return readXcodeAppTarget(xcodeproj, iosTarget ?? appTargets[0], "Release", {
10956
+ requireSources: false
10957
+ });
10958
+ }
10892
10959
 
10893
10960
  // src/native-firebase-config.ts
10894
10961
  var import_node_child_process3 = require("node:child_process");
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1640 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1644 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1387,6 +1387,7 @@ var require_lib = __commonJS({
1387
1387
  var native_app_identity_project_exports = {};
1388
1388
  __export(native_app_identity_project_exports, {
1389
1389
  NativeAppTargetSelectionError: () => NativeAppTargetSelectionError,
1390
+ readIosAppTarget: () => readIosAppTarget,
1390
1391
  readNativeAppIdentityFromProject: () => readNativeAppIdentityFromProject,
1391
1392
  readNativeAppIdentityFromSources: () => readNativeAppIdentityFromSources,
1392
1393
  readNativeAppIdentityFromXcodeTarget: () => readNativeAppIdentityFromXcodeTarget
@@ -2832,11 +2833,14 @@ function targetSettings(ref, configuration, builtins, options = {}) {
2832
2833
  if (!config) return [];
2833
2834
  const name = str(config.name) ?? configuration;
2834
2835
  const base = str(config.baseConfigurationReference);
2836
+ const anchor = str(config.baseConfigurationReferenceAnchor);
2837
+ const relative = str(config.baseConfigurationReferenceRelativePath);
2835
2838
  const own = isDict(config.buildSettings) ? config.buildSettings : {};
2836
- const baseFile = base ? project.resolvePath(base) : null;
2837
- if (options.requireSources !== false && base && (!baseFile || !import_node_fs.default.existsSync(baseFile)))
2839
+ const directory = anchor ? project.resolvePath(anchor) : null;
2840
+ const baseFile = base ? project.resolvePath(base) : directory && relative ? import_node_path2.default.resolve(directory, relative) : null;
2841
+ if (options.requireSources !== false && (base || anchor || relative) && (!baseFile || !import_node_fs.default.existsSync(baseFile)))
2838
2842
  throw new Error(
2839
- `Unable to open base configuration reference file '${baseFile ?? base}'`
2843
+ `Unable to open base configuration reference file '${baseFile ?? base ?? relative ?? anchor}'`
2840
2844
  );
2841
2845
  const read = [];
2842
2846
  const fromFile = baseFile ? readXcconfig(baseFile, read) : {};
@@ -2883,6 +2887,9 @@ function targetSettings(ref, configuration, builtins, options = {}) {
2883
2887
  return applyOperator(get("PRODUCT_NAME"), "c99extidentifier");
2884
2888
  case "EXECUTABLE_NAME":
2885
2889
  return get("PRODUCT_NAME");
2890
+ // the native default of CoreBuildSystem.xcspec
2891
+ case "EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES":
2892
+ return "*.nib *.lproj *.framework *.gch *.xcode* *.xcassets *.icon (*) .DS_Store CVS .svn .git .hg *.pbproj *.pbxproj";
2886
2893
  case "AppIdentifierPrefix":
2887
2894
  case "TeamIdentifierPrefix": {
2888
2895
  const team = get("DEVELOPMENT_TEAM");
@@ -2905,6 +2912,45 @@ function settingList(value) {
2905
2912
  items2.push((quoted ?? plain).replace(/\\(.)/g, "$1"));
2906
2913
  return items2;
2907
2914
  }
2915
+ function expandSearchPath(directory, rules) {
2916
+ if (import_node_path2.default.basename(directory) !== "**") return [directory];
2917
+ const expanded = [];
2918
+ const seen = /* @__PURE__ */ new Set();
2919
+ const queue = [import_node_path2.default.dirname(directory)];
2920
+ for (let at = 0; at < queue.length; at++) {
2921
+ const current = queue[at];
2922
+ let real;
2923
+ try {
2924
+ real = import_node_fs.default.realpathSync(current);
2925
+ } catch {
2926
+ continue;
2927
+ }
2928
+ if (!import_node_fs.default.statSync(real).isDirectory() || seen.has(real)) continue;
2929
+ seen.add(real);
2930
+ expanded.push(current);
2931
+ for (const entry of import_node_fs.default.readdirSync(real, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
2932
+ if (entry.isSymbolicLink() ? !rules.followLinks : !entry.isDirectory()) continue;
2933
+ if (rules.excluded.some((pattern) => pattern.test(entry.name)) && !rules.included.some((pattern) => pattern.test(entry.name)))
2934
+ continue;
2935
+ queue.push(import_node_path2.default.join(current, entry.name));
2936
+ }
2937
+ }
2938
+ return expanded;
2939
+ }
2940
+ function recursiveSearchRules(settings) {
2941
+ const glob = (pattern) => new RegExp(
2942
+ `^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("*", ".*").replaceAll("?", ".")}$`
2943
+ );
2944
+ return {
2945
+ excluded: settingList(settings("EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES")).map(
2946
+ glob
2947
+ ),
2948
+ included: settingList(settings("INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES")).map(
2949
+ glob
2950
+ ),
2951
+ followLinks: settings("RECURSIVE_SEARCH_PATHS_FOLLOW_SYMLINKS") !== "NO"
2952
+ };
2953
+ }
2908
2954
  function compilationConditions(settings) {
2909
2955
  const flags = settingList(settings("OTHER_SWIFT_FLAGS"));
2910
2956
  const defined = flags.flatMap(
@@ -3267,6 +3313,7 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
3267
3313
  for (const file of read) xcconfigs.add(file);
3268
3314
  const swiftVersion = Number.parseFloat(settings2("SWIFT_VERSION") || "5");
3269
3315
  const members = targetMembers(ref, settings2, options, keys, xcconfigs);
3316
+ const searchRules = recursiveSearchRules(settings2);
3270
3317
  const implementations = members.allSources.filter(
3271
3318
  (file) => /\.(c|cc|cpp|cxx|m|mm)$/.test(file)
3272
3319
  );
@@ -3309,10 +3356,10 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
3309
3356
  headerSearchPaths: [
3310
3357
  ...settingList(settings2("HEADER_SEARCH_PATHS")),
3311
3358
  ...settingList(settings2("USER_HEADER_SEARCH_PATHS"))
3312
- ].map(absolute),
3313
- frameworkSearchPaths: settingList(settings2("FRAMEWORK_SEARCH_PATHS")).map(
3314
- absolute
3315
- ),
3359
+ ].flatMap((raw) => expandSearchPath(absolute(raw), searchRules)),
3360
+ frameworkSearchPaths: settingList(
3361
+ settings2("FRAMEWORK_SEARCH_PATHS")
3362
+ ).flatMap((raw) => expandSearchPath(absolute(raw), searchRules)),
3316
3363
  flags: [
3317
3364
  ...settings2("CLANG_ENABLE_OBJC_ARC") === "YES" ? ["-fobjc-arc"] : [],
3318
3365
  ...settings2("CLANG_ENABLE_OBJC_WEAK") === "YES" ? ["-fobjc-weak"] : [],
@@ -3685,42 +3732,8 @@ function readAndroidNativeAppIdentity(projectRoot, androidMergedManifest) {
3685
3732
  );
3686
3733
  }
3687
3734
  function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
3688
- const iosRoot = import_node_path3.default.join(projectRoot, "ios");
3689
- if (!import_node_fs2.default.existsSync(iosRoot)) return null;
3690
- const projects = import_node_fs2.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
3691
- if (projects.length === 0) return null;
3692
- if (projects.length > 1 && !iosTarget) {
3693
- throw new NativeAppTargetSelectionError(
3694
- `native app identity requires a selected Xcode project; set withPeach's iosTarget to an app target in one of: ${projects.map((entry) => entry.name).join(", ")}`
3695
- );
3696
- }
3697
- let project = projects[0];
3698
- if (iosTarget && projects.length > 1) {
3699
- const matches = projects.filter(
3700
- (entry) => listXcodeAppTargets(import_node_path3.default.join(iosRoot, entry.name), {
3701
- requireSources: false
3702
- }).includes(iosTarget)
3703
- );
3704
- if (matches.length === 0) {
3705
- throw new Error(`native app identity has no application target ${iosTarget}`);
3706
- }
3707
- if (matches.length > 1) {
3708
- throw new Error(
3709
- `native app identity target ${iosTarget} is ambiguous across ${matches.map((entry) => entry.name).join(", ")}`
3710
- );
3711
- }
3712
- project = matches[0];
3713
- }
3714
- const xcodeproj = import_node_path3.default.join(iosRoot, project.name);
3715
- const appTargets = listXcodeAppTargets(xcodeproj, { requireSources: false });
3716
- if (!iosTarget && appTargets.length > 1) {
3717
- throw new NativeAppTargetSelectionError(
3718
- `native app identity requires a selected app target; set withPeach's iosTarget to one of: ${appTargets.join(", ")}`
3719
- );
3720
- }
3721
- const app = readXcodeAppTarget(xcodeproj, iosTarget ?? appTargets[0], "Release", {
3722
- requireSources: false
3723
- });
3735
+ const app = readIosAppTarget(projectRoot, iosTarget);
3736
+ if (!app) return null;
3724
3737
  const identity = readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist);
3725
3738
  const projectManifestPath = import_node_path3.default.join(projectRoot, "package.json");
3726
3739
  const projectRequire = (0, import_node_module.createRequire)(projectManifestPath);
@@ -3773,9 +3786,48 @@ function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
3773
3786
  }
3774
3787
  return { ...identity, reanimatedStaticFeatureFlags: flags };
3775
3788
  }
3789
+ function readIosAppTarget(projectRoot, iosTarget) {
3790
+ const iosRoot = import_node_path3.default.join(projectRoot, "ios");
3791
+ if (!import_node_fs2.default.existsSync(iosRoot)) return null;
3792
+ const projects = import_node_fs2.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
3793
+ if (projects.length === 0) return null;
3794
+ if (projects.length > 1 && !iosTarget) {
3795
+ throw new NativeAppTargetSelectionError(
3796
+ `native app identity requires a selected Xcode project; set withPeach's iosTarget to an app target in one of: ${projects.map((entry) => entry.name).join(", ")}`
3797
+ );
3798
+ }
3799
+ let project = projects[0];
3800
+ if (iosTarget && projects.length > 1) {
3801
+ const matches = projects.filter(
3802
+ (entry) => listXcodeAppTargets(import_node_path3.default.join(iosRoot, entry.name), {
3803
+ requireSources: false
3804
+ }).includes(iosTarget)
3805
+ );
3806
+ if (matches.length === 0) {
3807
+ throw new Error(`native app identity has no application target ${iosTarget}`);
3808
+ }
3809
+ if (matches.length > 1) {
3810
+ throw new Error(
3811
+ `native app identity target ${iosTarget} is ambiguous across ${matches.map((entry) => entry.name).join(", ")}`
3812
+ );
3813
+ }
3814
+ project = matches[0];
3815
+ }
3816
+ const xcodeproj = import_node_path3.default.join(iosRoot, project.name);
3817
+ const appTargets = listXcodeAppTargets(xcodeproj, { requireSources: false });
3818
+ if (!iosTarget && appTargets.length > 1) {
3819
+ throw new NativeAppTargetSelectionError(
3820
+ `native app identity requires a selected app target; set withPeach's iosTarget to one of: ${appTargets.join(", ")}`
3821
+ );
3822
+ }
3823
+ return readXcodeAppTarget(xcodeproj, iosTarget ?? appTargets[0], "Release", {
3824
+ requireSources: false
3825
+ });
3826
+ }
3776
3827
  // Annotate the CommonJS export names for ESM import in node:
3777
3828
  0 && (module.exports = {
3778
3829
  NativeAppTargetSelectionError,
3830
+ readIosAppTarget,
3779
3831
  readNativeAppIdentityFromProject,
3780
3832
  readNativeAppIdentityFromSources,
3781
3833
  readNativeAppIdentityFromXcodeTarget
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1640 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1644 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/native-app-identity-project.ts
4
4
  import fs2 from "node:fs";
@@ -1441,11 +1441,14 @@ function targetSettings(ref, configuration, builtins, options = {}) {
1441
1441
  if (!config) return [];
1442
1442
  const name = str(config.name) ?? configuration;
1443
1443
  const base = str(config.baseConfigurationReference);
1444
+ const anchor = str(config.baseConfigurationReferenceAnchor);
1445
+ const relative = str(config.baseConfigurationReferenceRelativePath);
1444
1446
  const own = isDict(config.buildSettings) ? config.buildSettings : {};
1445
- const baseFile = base ? project.resolvePath(base) : null;
1446
- 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)))
1447
1450
  throw new Error(
1448
- `Unable to open base configuration reference file '${baseFile ?? base}'`
1451
+ `Unable to open base configuration reference file '${baseFile ?? base ?? relative ?? anchor}'`
1449
1452
  );
1450
1453
  const read = [];
1451
1454
  const fromFile = baseFile ? readXcconfig(baseFile, read) : {};
@@ -1492,6 +1495,9 @@ function targetSettings(ref, configuration, builtins, options = {}) {
1492
1495
  return applyOperator(get("PRODUCT_NAME"), "c99extidentifier");
1493
1496
  case "EXECUTABLE_NAME":
1494
1497
  return get("PRODUCT_NAME");
1498
+ // the native default of CoreBuildSystem.xcspec
1499
+ case "EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES":
1500
+ return "*.nib *.lproj *.framework *.gch *.xcode* *.xcassets *.icon (*) .DS_Store CVS .svn .git .hg *.pbproj *.pbxproj";
1495
1501
  case "AppIdentifierPrefix":
1496
1502
  case "TeamIdentifierPrefix": {
1497
1503
  const team = get("DEVELOPMENT_TEAM");
@@ -1514,6 +1520,45 @@ function settingList(value) {
1514
1520
  items2.push((quoted ?? plain).replace(/\\(.)/g, "$1"));
1515
1521
  return items2;
1516
1522
  }
1523
+ function expandSearchPath(directory, rules) {
1524
+ if (path2.basename(directory) !== "**") return [directory];
1525
+ const expanded = [];
1526
+ const seen = /* @__PURE__ */ new Set();
1527
+ const queue = [path2.dirname(directory)];
1528
+ for (let at = 0; at < queue.length; at++) {
1529
+ const current = queue[at];
1530
+ let real;
1531
+ try {
1532
+ real = fs.realpathSync(current);
1533
+ } catch {
1534
+ continue;
1535
+ }
1536
+ if (!fs.statSync(real).isDirectory() || seen.has(real)) continue;
1537
+ seen.add(real);
1538
+ expanded.push(current);
1539
+ for (const entry of fs.readdirSync(real, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
1540
+ if (entry.isSymbolicLink() ? !rules.followLinks : !entry.isDirectory()) continue;
1541
+ if (rules.excluded.some((pattern) => pattern.test(entry.name)) && !rules.included.some((pattern) => pattern.test(entry.name)))
1542
+ continue;
1543
+ queue.push(path2.join(current, entry.name));
1544
+ }
1545
+ }
1546
+ return expanded;
1547
+ }
1548
+ function recursiveSearchRules(settings) {
1549
+ const glob = (pattern) => new RegExp(
1550
+ `^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("*", ".*").replaceAll("?", ".")}$`
1551
+ );
1552
+ return {
1553
+ excluded: settingList(settings("EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES")).map(
1554
+ glob
1555
+ ),
1556
+ included: settingList(settings("INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES")).map(
1557
+ glob
1558
+ ),
1559
+ followLinks: settings("RECURSIVE_SEARCH_PATHS_FOLLOW_SYMLINKS") !== "NO"
1560
+ };
1561
+ }
1517
1562
  function compilationConditions(settings) {
1518
1563
  const flags = settingList(settings("OTHER_SWIFT_FLAGS"));
1519
1564
  const defined = flags.flatMap(
@@ -1876,6 +1921,7 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1876
1921
  for (const file of read) xcconfigs.add(file);
1877
1922
  const swiftVersion = Number.parseFloat(settings2("SWIFT_VERSION") || "5");
1878
1923
  const members = targetMembers(ref, settings2, options, keys, xcconfigs);
1924
+ const searchRules = recursiveSearchRules(settings2);
1879
1925
  const implementations = members.allSources.filter(
1880
1926
  (file) => /\.(c|cc|cpp|cxx|m|mm)$/.test(file)
1881
1927
  );
@@ -1918,10 +1964,10 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1918
1964
  headerSearchPaths: [
1919
1965
  ...settingList(settings2("HEADER_SEARCH_PATHS")),
1920
1966
  ...settingList(settings2("USER_HEADER_SEARCH_PATHS"))
1921
- ].map(absolute),
1922
- frameworkSearchPaths: settingList(settings2("FRAMEWORK_SEARCH_PATHS")).map(
1923
- absolute
1924
- ),
1967
+ ].flatMap((raw) => expandSearchPath(absolute(raw), searchRules)),
1968
+ frameworkSearchPaths: settingList(
1969
+ settings2("FRAMEWORK_SEARCH_PATHS")
1970
+ ).flatMap((raw) => expandSearchPath(absolute(raw), searchRules)),
1925
1971
  flags: [
1926
1972
  ...settings2("CLANG_ENABLE_OBJC_ARC") === "YES" ? ["-fobjc-arc"] : [],
1927
1973
  ...settings2("CLANG_ENABLE_OBJC_WEAK") === "YES" ? ["-fobjc-weak"] : [],
@@ -2294,42 +2340,8 @@ function readAndroidNativeAppIdentity(projectRoot, androidMergedManifest) {
2294
2340
  );
2295
2341
  }
2296
2342
  function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
2297
- const iosRoot = path3.join(projectRoot, "ios");
2298
- if (!fs2.existsSync(iosRoot)) return null;
2299
- const projects = fs2.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
2300
- if (projects.length === 0) return null;
2301
- if (projects.length > 1 && !iosTarget) {
2302
- throw new NativeAppTargetSelectionError(
2303
- `native app identity requires a selected Xcode project; set withPeach's iosTarget to an app target in one of: ${projects.map((entry) => entry.name).join(", ")}`
2304
- );
2305
- }
2306
- let project = projects[0];
2307
- if (iosTarget && projects.length > 1) {
2308
- const matches = projects.filter(
2309
- (entry) => listXcodeAppTargets(path3.join(iosRoot, entry.name), {
2310
- requireSources: false
2311
- }).includes(iosTarget)
2312
- );
2313
- if (matches.length === 0) {
2314
- throw new Error(`native app identity has no application target ${iosTarget}`);
2315
- }
2316
- if (matches.length > 1) {
2317
- throw new Error(
2318
- `native app identity target ${iosTarget} is ambiguous across ${matches.map((entry) => entry.name).join(", ")}`
2319
- );
2320
- }
2321
- project = matches[0];
2322
- }
2323
- const xcodeproj = path3.join(iosRoot, project.name);
2324
- const appTargets = listXcodeAppTargets(xcodeproj, { requireSources: false });
2325
- if (!iosTarget && appTargets.length > 1) {
2326
- throw new NativeAppTargetSelectionError(
2327
- `native app identity requires a selected app target; set withPeach's iosTarget to one of: ${appTargets.join(", ")}`
2328
- );
2329
- }
2330
- const app = readXcodeAppTarget(xcodeproj, iosTarget ?? appTargets[0], "Release", {
2331
- requireSources: false
2332
- });
2343
+ const app = readIosAppTarget(projectRoot, iosTarget);
2344
+ if (!app) return null;
2333
2345
  const identity = readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist);
2334
2346
  const projectManifestPath = path3.join(projectRoot, "package.json");
2335
2347
  const projectRequire = createRequire(projectManifestPath);
@@ -2382,8 +2394,47 @@ function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
2382
2394
  }
2383
2395
  return { ...identity, reanimatedStaticFeatureFlags: flags };
2384
2396
  }
2397
+ function readIosAppTarget(projectRoot, iosTarget) {
2398
+ const iosRoot = path3.join(projectRoot, "ios");
2399
+ if (!fs2.existsSync(iosRoot)) return null;
2400
+ const projects = fs2.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
2401
+ if (projects.length === 0) return null;
2402
+ if (projects.length > 1 && !iosTarget) {
2403
+ throw new NativeAppTargetSelectionError(
2404
+ `native app identity requires a selected Xcode project; set withPeach's iosTarget to an app target in one of: ${projects.map((entry) => entry.name).join(", ")}`
2405
+ );
2406
+ }
2407
+ let project = projects[0];
2408
+ if (iosTarget && projects.length > 1) {
2409
+ const matches = projects.filter(
2410
+ (entry) => listXcodeAppTargets(path3.join(iosRoot, entry.name), {
2411
+ requireSources: false
2412
+ }).includes(iosTarget)
2413
+ );
2414
+ if (matches.length === 0) {
2415
+ throw new Error(`native app identity has no application target ${iosTarget}`);
2416
+ }
2417
+ if (matches.length > 1) {
2418
+ throw new Error(
2419
+ `native app identity target ${iosTarget} is ambiguous across ${matches.map((entry) => entry.name).join(", ")}`
2420
+ );
2421
+ }
2422
+ project = matches[0];
2423
+ }
2424
+ const xcodeproj = path3.join(iosRoot, project.name);
2425
+ const appTargets = listXcodeAppTargets(xcodeproj, { requireSources: false });
2426
+ if (!iosTarget && appTargets.length > 1) {
2427
+ throw new NativeAppTargetSelectionError(
2428
+ `native app identity requires a selected app target; set withPeach's iosTarget to one of: ${appTargets.join(", ")}`
2429
+ );
2430
+ }
2431
+ return readXcodeAppTarget(xcodeproj, iosTarget ?? appTargets[0], "Release", {
2432
+ requireSources: false
2433
+ });
2434
+ }
2385
2435
  export {
2386
2436
  NativeAppTargetSelectionError,
2437
+ readIosAppTarget,
2387
2438
  readNativeAppIdentityFromProject,
2388
2439
  readNativeAppIdentityFromSources,
2389
2440
  readNativeAppIdentityFromXcodeTarget
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1640 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1644 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1640 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1644 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/android-string-value.ts
4
4
  function compileAndroidStringValue(text, where) {