peachsim 0.1.673 → 0.1.675

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 (83) hide show
  1. package/dist-lib/agent-daemon-client.cjs +1 -1
  2. package/dist-lib/agent-events.cjs +1 -1
  3. package/dist-lib/agent-identity.cjs +1 -1
  4. package/dist-lib/agent-sessions.cjs +1 -1
  5. package/dist-lib/attached-projects.cjs +1 -1
  6. package/dist-lib/auth/shared-session.cjs +1 -1
  7. package/dist-lib/backend-origin.cjs +1 -1
  8. package/dist-lib/beta.cjs +1 -1
  9. package/dist-lib/beta.mjs +1 -1
  10. package/dist-lib/bridge-constants.cjs +1 -1
  11. package/dist-lib/bridge-contract-input.cjs +1 -1
  12. package/dist-lib/bridge-contract-input.mjs +1 -1
  13. package/dist-lib/bridge-contract.cjs +1 -1
  14. package/dist-lib/bridge-contract.mjs +1 -1
  15. package/dist-lib/capture-contract.cjs +1 -1
  16. package/dist-lib/capture-contract.mjs +1 -1
  17. package/dist-lib/cli-constants.cjs +1 -1
  18. package/dist-lib/cloud-contract.cjs +1 -1
  19. package/dist-lib/cloud-contract.mjs +1 -1
  20. package/dist-lib/cloud-test-args.cjs +1 -1
  21. package/dist-lib/cloud-test-args.mjs +1 -1
  22. package/dist-lib/cloud.cjs +1 -1
  23. package/dist-lib/cloud.mjs +1 -1
  24. package/dist-lib/config.cjs +1 -1
  25. package/dist-lib/detox/index.cjs +1 -1
  26. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  27. package/dist-lib/home-paths.cjs +1 -1
  28. package/dist-lib/host/bridge-host.cjs +257 -236
  29. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  30. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  31. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  32. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  33. package/dist-lib/host/websocket-proxy.cjs +1 -1
  34. package/dist-lib/index.cjs +1 -1
  35. package/dist-lib/jump-to-source-babel.cjs +1 -1
  36. package/dist-lib/jump-to-source-native.cjs +1 -1
  37. package/dist-lib/kotlin-host.cjs +78 -2
  38. package/dist-lib/menu.cjs +1 -1
  39. package/dist-lib/menu.mjs +1 -1
  40. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  41. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  42. package/dist-lib/metro-production-bundle.cjs +1 -1
  43. package/dist-lib/metro-production-bundle.mjs +1 -1
  44. package/dist-lib/metro.cjs +1 -1
  45. package/dist-lib/native-app-identity.cjs +1 -1
  46. package/dist-lib/native-app-identity.mjs +1 -1
  47. package/dist-lib/native-firebase-metadata.cjs +1 -1
  48. package/dist-lib/native-firebase-metadata.mjs +1 -1
  49. package/dist-lib/plist.cjs +1 -1
  50. package/dist-lib/plist.mjs +1 -1
  51. package/dist-lib/profiles.cjs +1 -1
  52. package/dist-lib/public-brand.cjs +1 -1
  53. package/dist-lib/react-native-host-modules.cjs +1 -1
  54. package/dist-lib/react-native-host-modules.mjs +1 -1
  55. package/dist-lib/render-mode.cjs +1 -1
  56. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  57. package/dist-lib/sdk.cjs +1 -1
  58. package/dist-lib/sdk.mjs +1 -1
  59. package/dist-lib/skills.cjs +434 -406
  60. package/dist-lib/swift-compile.cjs +21 -7
  61. package/dist-lib/swift-compile.mjs +21 -7
  62. package/dist-lib/swift-package.cjs +1 -1
  63. package/dist-lib/swift-package.mjs +1 -1
  64. package/dist-lib/swift-submit.cjs +1 -1
  65. package/dist-lib/swift-submit.mjs +1 -1
  66. package/dist-lib/swift.cjs +1 -1
  67. package/dist-lib/vite-swift.cjs +109 -88
  68. package/dist-lib/vite.cjs +1 -1
  69. package/kotlin/AppSources/android/content/Context.kt +4 -0
  70. package/kotlin/AppSources/android/content/res/Configuration.kt +4 -1
  71. package/kotlin/AppSources/android/content/res/Resources.kt +45 -1
  72. package/kotlin/AppSources/androidx/compose/ui/platform/AndroidCompositionLocals.kt +19 -0
  73. package/kotlin/AppSources/androidx/compose/ui/res/StringResources.kt +53 -0
  74. package/kotlin/AppSources/dev/peach/app/JavaFormat.kt +264 -0
  75. package/kotlin/AppSources/dev/peach/app/PeachApp.kt +23 -7
  76. package/kotlin/fixtures/kotlin-app-variants/Strings.kt +49 -0
  77. package/package.json +1 -1
  78. package/src/android-strings.ts +163 -0
  79. package/src/android-xml.ts +3 -3
  80. package/src/kotlin-app.ts +4 -0
  81. package/src/kotlin-host.ts +98 -0
  82. package/src/swift-compile.ts +31 -10
  83. package/src/swift-host.ts +2 -4
@@ -410,6 +410,7 @@ export async function kotlinAppArtifact(
410
410
  'PeachEntry.kt': entrySource([]),
411
411
  'PeachViews.kt': viewsSource([]),
412
412
  'PeachAppEntry.kt': appEntry([]),
413
+ ...appResourceSources(app),
413
414
  }
414
415
  const shims = [
415
416
  ...kotlinSources(path.join(moduleRoot, 'Sources')),
@@ -435,6 +436,103 @@ export async function kotlinAppArtifact(
435
436
  )
436
437
  }
437
438
 
439
+ // the module's R class in its namespace and the string, plurals and array
440
+ // tables Resources reads. an id is 0x7f, the type, then the entry in name
441
+ // order. a device's ids also count the module's other resource types and the
442
+ // resources its libraries merge in, which Peach does not build, so the
443
+ // numbers themselves differ
444
+ function appResourceSources(app: KotlinAppProject): Record<string, string> {
445
+ const escapes: Record<string, string> = {
446
+ '\\': '\\\\',
447
+ '"': '\\"',
448
+ $: '\\$',
449
+ '\n': '\\n',
450
+ '\r': '\\r',
451
+ '\t': '\\t',
452
+ }
453
+ const literal = (value: string) =>
454
+ `"${value.replace(
455
+ /[\\"$\u0000-\u001f]/g,
456
+ (char) => escapes[char] ?? `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`,
457
+ )}"`
458
+ // aapt2 writes a resource name's dots and dashes as underscores in R
459
+ const field = (name: string) => `\`${name.replace(/[.-]/g, '_')}\``
460
+ const id = (type: number, entry: number) =>
461
+ `0x7f${type.toString(16).padStart(2, '0')}${entry.toString(16).padStart(4, '0')}`
462
+ const kinds = [
463
+ {
464
+ type: 'string',
465
+ table: 'peachAppStrings',
466
+ value: 'String',
467
+ resources: app.strings.strings,
468
+ },
469
+ {
470
+ type: 'plurals',
471
+ table: 'peachAppPlurals',
472
+ value: 'Map<String, String>',
473
+ resources: app.strings.plurals,
474
+ },
475
+ {
476
+ type: 'array',
477
+ table: 'peachAppArrays',
478
+ value: 'List<String>',
479
+ resources: app.strings.arrays,
480
+ },
481
+ ].map((kind, index) => ({
482
+ ...kind,
483
+ entries: kind.resources.map((resource, entry) => ({
484
+ name: resource.name,
485
+ id: id(index + 1, entry),
486
+ values: Object.entries(resource.values).map(
487
+ ([locale, value]: [
488
+ string,
489
+ string | string[] | Partial<Record<string, string>>,
490
+ ]) =>
491
+ `${literal(locale)} to ${
492
+ typeof value === 'string'
493
+ ? literal(value)
494
+ : Array.isArray(value)
495
+ ? `listOf(${value.map(literal).join(', ')})`
496
+ : `mapOf(${Object.entries(value)
497
+ .map(
498
+ ([quantity, text]) =>
499
+ `${literal(quantity)} to ${literal(text ?? '')}`,
500
+ )
501
+ .join(', ')})`
502
+ }`,
503
+ ),
504
+ })),
505
+ }))
506
+ return {
507
+ 'R.kt': [
508
+ `package ${app.namespace}`,
509
+ '',
510
+ 'object R {',
511
+ ...kinds.flatMap((kind) => [
512
+ ` object ${kind.type} {`,
513
+ ...kind.entries.map(
514
+ (entry) => ` const val ${field(entry.name)}: Int = ${entry.id}`,
515
+ ),
516
+ ' }',
517
+ ]),
518
+ '}',
519
+ '',
520
+ ].join('\n'),
521
+ 'PeachAppResources.kt': [
522
+ 'package dev.peach.app',
523
+ '',
524
+ ...kinds.flatMap((kind) => [
525
+ `internal val ${kind.table}: Map<Int, Map<String, ${kind.value}>> = mapOf(`,
526
+ ...kind.entries.map(
527
+ (entry) => ` ${entry.id} to mapOf(${entry.values.join(', ')}),`,
528
+ ),
529
+ ')',
530
+ '',
531
+ ]),
532
+ ].join('\n'),
533
+ }
534
+ }
535
+
438
536
  async function compileKotlin(
439
537
  input: {
440
538
  root: string
@@ -229,10 +229,11 @@ export function swiftArtifactHash(
229
229
  moduleRoot: string,
230
230
  ): string {
231
231
  const hash = createHash('sha256')
232
+ // v7: runtime class lookup uses the same objc class registry as messages
232
233
  // v6: app and scene delegate classes compile final
233
234
  // (v5: a target declaring resources gets SwiftPM's Bundle.module accessor;
234
235
  // v4: sources compile through swiftSourceAsIOS)
235
- hash.update(`swift-compile/v6\n${release}\n`)
236
+ hash.update(`swift-compile/v7\n${release}\n`)
236
237
  if (input.oneModule) hash.update('one-module\n')
237
238
  hash.update(linkedModuleDigest(moduleRoot))
238
239
  for (const file of Object.keys(input.files).sort()) {
@@ -392,6 +393,17 @@ export function swiftSourceAsIOS(source: string): string {
392
393
  let copied = 0
393
394
  for (const at of tokens) {
394
395
  const rest = conditioned.slice(at, at + 400)
396
+ const imported = /^import\s+CoreImage\.CIFilterBuiltins\b/.exec(rest)
397
+ if (imported) {
398
+ out += conditioned.slice(copied, at) + 'import CoreImage'.padEnd(imported[0].length)
399
+ copied = at + imported[0].length
400
+ continue
401
+ }
402
+ if (/^NSClassFromString\b/.test(rest)) {
403
+ out += conditioned.slice(copied, at) + '_peachClassFromString'
404
+ copied = at + 'NSClassFromString'.length
405
+ continue
406
+ }
395
407
  if (rest.startsWith('class')) {
396
408
  const modifiers = conditioned.slice(conditioned.lastIndexOf('\n', at - 1) + 1, at)
397
409
  if (DELEGATE_CLASS.test(rest) && !/\b(?:final|open)\b/.test(modifiers)) {
@@ -504,16 +516,25 @@ function swiftCodeScan(source: string): { lineStarts: Set<number>; tokens: numbe
504
516
  if (top.parens === 0 && stack.length > 1) stack.pop()
505
517
  else top.parens--
506
518
  i++
507
- } else if (
508
- source.startsWith('class', i) &&
509
- !/[\w$]/.test(source[i - 1] ?? '') &&
510
- !/[\w$]/.test(source[i + 5] ?? '')
511
- ) {
512
- tokens.push(i)
513
- i += 5
514
519
  } else {
515
- if (char === '@') tokens.push(i)
516
- i++
520
+ const keyword = source.startsWith('class', i)
521
+ ? 'class'
522
+ : source.startsWith('import', i)
523
+ ? 'import'
524
+ : source.startsWith('NSClassFromString', i)
525
+ ? 'NSClassFromString'
526
+ : null
527
+ if (
528
+ keyword &&
529
+ !/[\w$]/.test(source[i - 1] ?? '') &&
530
+ !/[\w$]/.test(source[i + keyword.length] ?? '')
531
+ ) {
532
+ tokens.push(i)
533
+ i += keyword.length
534
+ } else {
535
+ if (char === '@') tokens.push(i)
536
+ i++
537
+ }
517
538
  }
518
539
  }
519
540
  return { lineStarts: starts, tokens }
package/src/swift-host.ts CHANGED
@@ -5,6 +5,7 @@ import { createHash } from 'node:crypto'
5
5
  import fs from 'node:fs'
6
6
  import os from 'node:os'
7
7
  import path from 'node:path'
8
+ import { swiftToolchainBin } from '../../../src/compile/swiftToolchain'
8
9
  import {
9
10
  enumerateBundleColors,
10
11
  enumerateBundleSymbols,
@@ -642,10 +643,7 @@ export function localSwiftToolchain(
642
643
  if (typeof release !== 'string') {
643
644
  throw new Error(`swift toolchain manifest at ${moduleRoot} has no release`)
644
645
  }
645
- const toolchainBin = path.join(
646
- os.homedir(),
647
- `Library/Developer/Toolchains/${release}.xctoolchain/usr/bin`,
648
- )
646
+ const toolchainBin = swiftToolchainBin(release)
649
647
  return fs.existsSync(path.join(toolchainBin, 'swift'))
650
648
  ? { release, toolchainBin }
651
649
  : null