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.
- package/README.md +10 -1
- package/cli/app-config.ts +14 -5
- package/cli/app-stubs.ts +96 -22
- package/cli/bridge-flow-runner.ts +2 -2
- package/cli/cloud-client.ts +60 -40
- package/cli/cloud-session.ts +16 -0
- package/cli/commands/assert.ts +17 -4
- package/cli/commands/box.ts +33 -19
- package/cli/commands/doctor.ts +37 -20
- package/cli/commands/flow.ts +1 -1
- package/cli/commands/inspect/actions.ts +3 -2
- package/cli/commands/inspect/core.ts +0 -8
- package/cli/commands/inspect/shared.ts +9 -4
- package/cli/commands/inspect.ts +65 -61
- package/cli/commands/platform.ts +2 -1
- package/cli/commands/preview.ts +1 -1
- package/cli/commands/record.ts +154 -68
- package/cli/commands/swift.ts +18 -4
- package/cli/commands/three-mode.ts +4 -38
- package/cli/commands/upload.ts +55 -49
- package/cli/drivers/playwright-sim-host.ts +65 -42
- package/cli/flow-live-status.ts +0 -2
- package/cli/main.ts +2 -2
- package/cli/outbound-endpoints.ts +7 -5
- package/cli/pause-aware-timeout.ts +4 -0
- package/cli/ws-bridge.ts +19 -16
- package/detox/attempt-events.cjs +99 -6
- package/detox/attempt-events.d.cts +7 -0
- package/detox/expectations.ts +7 -3
- package/detox/index.ts +259 -139
- package/detox/jest-environment.cjs +5 -1
- package/detox/motion-change.cjs +170 -21
- package/detox/motion-change.d.cts +32 -0
- package/detox/navigation-lifecycle.ts +35 -3
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +17 -7
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/bundle-channel.cjs +5014 -2268
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/config.mjs +1 -1
- package/dist-lib/detox/index.cjs +1036 -166
- package/dist-lib/detox/jest-environment.cjs +5 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +4613 -1963
- package/dist-lib/expo-swift-metadata.cjs +9 -7
- package/dist-lib/expo-swift-metadata.mjs +9 -7
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +58072 -16400
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2790 -143
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +2579 -95
- package/dist-lib/native-app-identity-project.cjs +243 -53
- package/dist-lib/native-app-identity-project.mjs +243 -53
- package/dist-lib/native-app-identity.cjs +29 -30
- package/dist-lib/native-app-identity.mjs +29 -30
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +2 -2
- package/dist-lib/react-native-host-modules.mjs +2 -2
- package/dist-lib/scripts/dev-server-scanner.cjs +8 -6
- package/dist-lib/sdk.cjs +4 -3
- package/dist-lib/sdk.mjs +4 -3
- package/dist-lib/skills.cjs +66475 -23097
- package/dist-lib/swift-compile.cjs +452 -260
- package/dist-lib/swift-compile.mjs +451 -252
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +14 -7
- package/dist-lib/swift-submit.mjs +14 -7
- package/dist-lib/swift-toolchain.cjs +316 -41
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +8188 -5636
- package/dist-lib/vite.cjs +2857 -12
- package/dist-lib/worklet-executable.cjs +14 -2
- package/dist-lib/worklet-executable.mjs +14 -2
- package/package.json +1 -1
- package/src/backend-origin.ts +21 -6
- package/src/expo-swift-host.ts +5 -2
- package/src/expoKotlinContract.ts +4 -7
- package/src/expoSwiftContract.ts +4 -6
- package/src/host/staged-host-files.ts +9 -0
- package/src/native-app-identity-project.ts +1 -4
- package/src/native-app-identity.ts +1 -4
- package/src/nativeAppIconContract.ts +1 -4
- package/src/output-lock-stdio.ts +36 -0
- package/src/react-native-bridge-modules.ts +106 -78
- package/src/react-native-host-modules.ts +4 -1
- package/src/settings-bundle.ts +1 -4
- package/src/swift-compile.ts +224 -139
- package/src/swift-distribution.lock.json +23 -12
- package/src/swift-distribution.ts +103 -4
- package/src/swift-host.ts +95 -30
- package/src/swift-icu.ts +16 -10
- package/src/swift-objc-compile.ts +547 -0
- package/src/swift-objc-metadata.ts +204 -0
- package/src/swift-objc-sdk.ts +883 -19
- package/src/swift-objc-standin.ts +126 -14
- package/src/swift-package-manifest.ts +42 -1
- package/src/swift-packages.ts +35 -21
- package/src/swift-root-lock.ts +153 -0
- package/src/swift-standin-emit.ts +40 -7
- package/src/swift-standins.ts +404 -138
- package/src/swift-submit.ts +18 -7
- package/src/swift-toolchain.ts +378 -46
- package/src/swiftContract.ts +12 -0
- package/src/worker-system-chunks.ts +11 -12
- package/src/worklet-executable.ts +19 -1
- package/src/xcode-project.ts +280 -33
|
@@ -92,6 +92,7 @@ interface Scope {
|
|
|
92
92
|
|
|
93
93
|
type Binding =
|
|
94
94
|
| { kind: 'value'; init: SyntaxNode; scope: Scope }
|
|
95
|
+
| { kind: 'uninitialized' }
|
|
95
96
|
// `key` is set when the parameter is a destructured member of that argument.
|
|
96
97
|
| { kind: 'param'; fn: SyntaxNode; index: number; key?: string }
|
|
97
98
|
| { kind: 'opaque' }
|
|
@@ -106,6 +107,9 @@ interface InitCollection {
|
|
|
106
107
|
writes: Array<{ name: string; scope: Scope; value?: SyntaxNode }>
|
|
107
108
|
// bindings written after their declaration; their value is not static.
|
|
108
109
|
reassigned: Set<Binding>
|
|
110
|
+
// rolldown hoists declarations out of esm initializers. a single plain
|
|
111
|
+
// assignment still identifies the literal; multiple writes remain opaque.
|
|
112
|
+
assigned: Map<Binding, { value: SyntaxNode; scope: Scope } | null>
|
|
109
113
|
// names the parsed source never declares but writes exactly once with a plain
|
|
110
114
|
// assignment. a bundler that hoists a module's declarations out of its
|
|
111
115
|
// initializer leaves only that write in the initializer.
|
|
@@ -227,6 +231,8 @@ function enter(node: SyntaxNode, scope: Scope): Scope {
|
|
|
227
231
|
const name = identifierName(id)
|
|
228
232
|
if (name !== undefined && isNode(init))
|
|
229
233
|
declare(target, name, { kind: 'value', init, scope })
|
|
234
|
+
else if (name !== undefined && init === null)
|
|
235
|
+
declare(target, name, { kind: 'uninitialized' })
|
|
230
236
|
else declareOpaque(target, patternNames(id))
|
|
231
237
|
}
|
|
232
238
|
return scope
|
|
@@ -311,12 +317,18 @@ function collectInitData(root: SyntaxNode): InitCollection {
|
|
|
311
317
|
immediate: new Map(),
|
|
312
318
|
writes: [],
|
|
313
319
|
reassigned: new Set(),
|
|
320
|
+
assigned: new Map(),
|
|
314
321
|
free: new Map(),
|
|
315
322
|
}
|
|
316
323
|
visit(root, newScope(undefined, true), collection)
|
|
317
324
|
for (const { name, scope, value } of collection.writes) {
|
|
318
325
|
const binding = lookup(scope, name)
|
|
319
|
-
if (binding
|
|
326
|
+
if (binding?.kind === 'uninitialized')
|
|
327
|
+
collection.assigned.set(
|
|
328
|
+
binding,
|
|
329
|
+
collection.assigned.has(binding) || !value ? null : { value, scope },
|
|
330
|
+
)
|
|
331
|
+
else if (binding) collection.reassigned.add(binding)
|
|
320
332
|
else
|
|
321
333
|
collection.free.set(
|
|
322
334
|
name,
|
|
@@ -415,6 +427,12 @@ function resolveObject(
|
|
|
415
427
|
: undefined
|
|
416
428
|
}
|
|
417
429
|
if (collection.reassigned.has(binding)) return undefined
|
|
430
|
+
if (binding.kind === 'uninitialized') {
|
|
431
|
+
const assigned = collection.assigned.get(binding)
|
|
432
|
+
return assigned
|
|
433
|
+
? resolveObject(assigned.value, assigned.scope, collection, depth + 1)
|
|
434
|
+
: undefined
|
|
435
|
+
}
|
|
418
436
|
if (binding.kind === 'value')
|
|
419
437
|
return resolveObject(binding.init, binding.scope, collection, depth + 1)
|
|
420
438
|
if (binding.kind === 'param') {
|
package/src/xcode-project.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// reads an xcode project's application target the way xcode builds it: the
|
|
2
2
|
// swift sources and resources that are members of the target, the local
|
|
3
3
|
// swift packages its products come from, the remote package products it links,
|
|
4
|
-
// and the build settings that change how its swift compiles.
|
|
5
|
-
//
|
|
4
|
+
// and the build settings that change how its swift compiles. project opening
|
|
5
|
+
// prepares declared generated swift sources without running xcode. the project
|
|
6
|
+
// file is data: project.pbxproj, or
|
|
6
7
|
// xcode 27.2's json project.xcproj, which xcode-json-project.ts reads into
|
|
7
8
|
// the same object table.
|
|
8
9
|
|
|
10
|
+
import { execFileSync } from 'node:child_process'
|
|
11
|
+
import { createHash } from 'node:crypto'
|
|
9
12
|
import fs from 'node:fs'
|
|
10
13
|
import path from 'node:path'
|
|
11
14
|
import plist from 'plist'
|
|
@@ -45,6 +48,19 @@ export interface XcodeModuleTarget {
|
|
|
45
48
|
mainActorIsolation: boolean
|
|
46
49
|
/** the compilation conditions the build configuration defines, as `-D` passes them. */
|
|
47
50
|
defines: string[]
|
|
51
|
+
/** the resolved source iOS minimum, including for native package dependencies. */
|
|
52
|
+
iosDeploymentTarget: string | null
|
|
53
|
+
/** original implementation inputs and clang settings, before any declaration import. */
|
|
54
|
+
objc?: {
|
|
55
|
+
headers: string[]
|
|
56
|
+
prefixHeader: string | null
|
|
57
|
+
bridgingHeader: string | null
|
|
58
|
+
headerSearchPaths: string[]
|
|
59
|
+
frameworkSearchPaths: string[]
|
|
60
|
+
flags: string[]
|
|
61
|
+
cxxFlags: string[]
|
|
62
|
+
fileFlags: Record<string, string[]>
|
|
63
|
+
}
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
/** an application target, resolved to files on disk with everything it builds. */
|
|
@@ -72,8 +88,8 @@ export interface XcodeAppTarget extends XcodeModuleTarget {
|
|
|
72
88
|
localPackageDirs: string[]
|
|
73
89
|
/** prebuilt frameworks and xcframeworks the projects vendor and link, at their path when it resolves. */
|
|
74
90
|
binaryFrameworks: { name: string; path: string | null }[]
|
|
75
|
-
/**
|
|
76
|
-
packageResolved: string
|
|
91
|
+
/** workspace pins, or local package locks when the workspace has no lock. */
|
|
92
|
+
packageResolved: string[]
|
|
77
93
|
/** every application target in the workspace, for a chooser. */
|
|
78
94
|
appTargets: string[]
|
|
79
95
|
/** the build configuration every target's settings are read in. */
|
|
@@ -383,15 +399,22 @@ function targetSettings(
|
|
|
383
399
|
if (!config) return []
|
|
384
400
|
const name = str(config.name) ?? configuration
|
|
385
401
|
const base = str(config.baseConfigurationReference)
|
|
402
|
+
const anchor = str(config.baseConfigurationReferenceAnchor)
|
|
403
|
+
const relative = str(config.baseConfigurationReferenceRelativePath)
|
|
386
404
|
const own = isDict(config.buildSettings) ? config.buildSettings : {}
|
|
387
|
-
const
|
|
405
|
+
const directory = anchor ? project.resolvePath(anchor) : null
|
|
406
|
+
const baseFile = base
|
|
407
|
+
? project.resolvePath(base)
|
|
408
|
+
: directory && relative
|
|
409
|
+
? path.resolve(directory, relative)
|
|
410
|
+
: null
|
|
388
411
|
if (
|
|
389
412
|
options.requireSources !== false &&
|
|
390
|
-
base &&
|
|
413
|
+
(base || anchor || relative) &&
|
|
391
414
|
(!baseFile || !fs.existsSync(baseFile))
|
|
392
415
|
)
|
|
393
416
|
throw new Error(
|
|
394
|
-
`Unable to open base configuration reference file '${baseFile ?? base}'`,
|
|
417
|
+
`Unable to open base configuration reference file '${baseFile ?? base ?? relative ?? anchor}'`,
|
|
395
418
|
)
|
|
396
419
|
const read: string[] = []
|
|
397
420
|
const fromFile = baseFile ? readXcconfig(baseFile, read) : {}
|
|
@@ -498,14 +521,17 @@ function expand(value: string, lookup: (name: string) => string): string {
|
|
|
498
521
|
)
|
|
499
522
|
}
|
|
500
523
|
|
|
524
|
+
const preparedSourcePhases = new Map<string, string>()
|
|
525
|
+
|
|
501
526
|
// the swift sources and resources that are members of a target.
|
|
502
|
-
//
|
|
503
|
-
//
|
|
504
|
-
// the script instead of silently dropping the file.
|
|
527
|
+
// metadata-only reads never execute scripts. opening a project prepares the
|
|
528
|
+
// declared swift outputs with the project's own shell and build settings.
|
|
505
529
|
function targetMembers(
|
|
506
530
|
ref: TargetRef,
|
|
507
531
|
settings: (key: string) => string,
|
|
508
|
-
options: { requireSources?: boolean
|
|
532
|
+
options: { requireSources?: boolean; prepareGeneratedSources?: boolean },
|
|
533
|
+
settingKeys: Set<string>,
|
|
534
|
+
projectInputs: Set<string>,
|
|
509
535
|
): {
|
|
510
536
|
sources: string[]
|
|
511
537
|
resources: string[]
|
|
@@ -517,30 +543,137 @@ function targetMembers(
|
|
|
517
543
|
const allSources = new Set<string>()
|
|
518
544
|
const resources = new Set<string>()
|
|
519
545
|
const scriptForOutput = new Map<string, string>()
|
|
520
|
-
const noteScriptOutput = (raw: string, script: string) => {
|
|
521
|
-
const expanded = expand(raw, settings)
|
|
522
|
-
if (!expanded.endsWith('.swift')) return
|
|
523
|
-
const absolute = path.isAbsolute(expanded)
|
|
524
|
-
? path.normalize(expanded)
|
|
525
|
-
: path.resolve(project.projectDir, expanded)
|
|
526
|
-
if (!scriptForOutput.has(absolute)) scriptForOutput.set(absolute, script)
|
|
527
|
-
}
|
|
528
546
|
for (const phaseId of list(target.buildPhases)) {
|
|
529
547
|
const phase = project.object(phaseId)
|
|
530
548
|
if (phase?.isa !== 'PBXShellScriptBuildPhase') continue
|
|
531
549
|
const script = str(phase.name) ?? phaseId
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
550
|
+
const absolute = (raw: string) =>
|
|
551
|
+
path.resolve(project.projectDir, expand(raw, settings))
|
|
552
|
+
const inputs = list(phase.inputPaths).map(absolute)
|
|
553
|
+
const outputs = list(phase.outputPaths).map(absolute)
|
|
554
|
+
const fileLists = new Map<string, { file: string; entries: string[] }[]>()
|
|
555
|
+
for (const kind of ['INPUT', 'OUTPUT']) {
|
|
556
|
+
const lists = list(
|
|
557
|
+
kind === 'INPUT' ? phase.inputFileListPaths : phase.outputFileListPaths,
|
|
558
|
+
).map((raw) => {
|
|
559
|
+
const file = absolute(raw)
|
|
560
|
+
if (!fs.existsSync(file)) {
|
|
561
|
+
return { file, entries: [] }
|
|
562
|
+
}
|
|
563
|
+
const entries = fs
|
|
564
|
+
.readFileSync(file, 'utf8')
|
|
565
|
+
.split(/\r?\n/)
|
|
566
|
+
.map((line) => line.trim())
|
|
567
|
+
.filter((line) => line !== '' && !line.startsWith('#'))
|
|
568
|
+
.map(absolute)
|
|
569
|
+
return { file, entries }
|
|
570
|
+
})
|
|
571
|
+
fileLists.set(kind, lists)
|
|
572
|
+
}
|
|
573
|
+
const allOutputs = [
|
|
574
|
+
...outputs,
|
|
575
|
+
...fileLists.get('OUTPUT')!.flatMap((item) => item.entries),
|
|
576
|
+
]
|
|
577
|
+
for (const output of allOutputs)
|
|
578
|
+
if (output.endsWith('.swift') && !scriptForOutput.has(output))
|
|
579
|
+
scriptForOutput.set(output, script)
|
|
580
|
+
const inputFiles = [
|
|
581
|
+
...inputs,
|
|
582
|
+
...fileLists.get('INPUT')!.flatMap((item) => [item.file, ...item.entries]),
|
|
583
|
+
...fileLists.get('OUTPUT')!.map((item) => item.file),
|
|
584
|
+
]
|
|
585
|
+
if (allOutputs.some((file) => file.endsWith('.swift')))
|
|
586
|
+
for (const file of inputFiles) if (fs.existsSync(file)) projectInputs.add(file)
|
|
587
|
+
if (
|
|
588
|
+
options.prepareGeneratedSources &&
|
|
589
|
+
options.requireSources !== false &&
|
|
590
|
+
allOutputs.some((file) => file.endsWith('.swift'))
|
|
591
|
+
) {
|
|
592
|
+
const phaseDir = path.join(settings('TARGET_TEMP_DIR'), `Script-${phaseId}`)
|
|
593
|
+
for (const lists of fileLists.values())
|
|
594
|
+
for (const { file } of lists)
|
|
595
|
+
if (!fs.existsSync(file))
|
|
596
|
+
throw new Error(
|
|
597
|
+
`${targetName}: Run Script "${script}" missing file list ${file}`,
|
|
598
|
+
)
|
|
599
|
+
const env = {
|
|
600
|
+
...process.env,
|
|
601
|
+
...Object.fromEntries(
|
|
602
|
+
[...settingKeys]
|
|
603
|
+
.filter((key) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|
|
604
|
+
.map((key) => [key, settings(key)]),
|
|
605
|
+
),
|
|
606
|
+
}
|
|
607
|
+
const declared = { INPUT: inputs, OUTPUT: outputs }
|
|
608
|
+
for (const kind of ['INPUT', 'OUTPUT'] satisfies (keyof typeof declared)[]) {
|
|
609
|
+
env[`SCRIPT_${kind}_FILE_COUNT`] = String(declared[kind].length)
|
|
610
|
+
declared[kind].forEach((file, index) => {
|
|
611
|
+
env[`SCRIPT_${kind}_FILE_${index}`] = file
|
|
612
|
+
})
|
|
613
|
+
const lists = fileLists.get(kind)!
|
|
614
|
+
env[`SCRIPT_${kind}_FILE_LIST_COUNT`] = String(lists.length)
|
|
615
|
+
lists.forEach((_item, index) => {
|
|
616
|
+
env[`SCRIPT_${kind}_FILE_LIST_${index}`] = path.join(
|
|
617
|
+
phaseDir,
|
|
618
|
+
`${kind}-${index}.xcfilelist`,
|
|
619
|
+
)
|
|
620
|
+
})
|
|
621
|
+
}
|
|
622
|
+
const signature = createHash('sha256').update(
|
|
623
|
+
JSON.stringify([phase, [...settingKeys].map((key) => [key, settings(key)])]),
|
|
624
|
+
)
|
|
625
|
+
for (const file of inputFiles) {
|
|
626
|
+
signature.update(file)
|
|
627
|
+
if (fs.existsSync(file)) {
|
|
628
|
+
const stat = fs.statSync(file)
|
|
629
|
+
signature.update(`${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`)
|
|
630
|
+
} else signature.update('missing')
|
|
631
|
+
}
|
|
632
|
+
const stamp = signature.digest('hex')
|
|
633
|
+
const key = `${project.projectFile}:${targetId}:${phaseId}:${settings('CONFIGURATION')}`
|
|
634
|
+
if (
|
|
635
|
+
preparedSourcePhases.get(key) === stamp &&
|
|
636
|
+
allOutputs.every((file) => fs.existsSync(file))
|
|
637
|
+
)
|
|
638
|
+
continue
|
|
639
|
+
fs.mkdirSync(phaseDir, { recursive: true })
|
|
640
|
+
fs.mkdirSync(settings('BUILT_PRODUCTS_DIR'), { recursive: true })
|
|
641
|
+
fs.mkdirSync(settings('DERIVED_FILE_DIR'), { recursive: true })
|
|
642
|
+
for (const [kind, lists] of fileLists)
|
|
643
|
+
lists.forEach((item, index) => {
|
|
644
|
+
fs.writeFileSync(
|
|
645
|
+
env[`SCRIPT_${kind}_FILE_LIST_${index}`]!,
|
|
646
|
+
`${item.entries.join('\n')}\n`,
|
|
647
|
+
)
|
|
648
|
+
})
|
|
649
|
+
try {
|
|
650
|
+
execFileSync(
|
|
651
|
+
str(phase.shellPath) ?? '/bin/sh',
|
|
652
|
+
['-c', str(phase.shellScript) ?? ''],
|
|
653
|
+
{
|
|
654
|
+
cwd: project.projectDir,
|
|
655
|
+
env,
|
|
656
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
657
|
+
timeout: 120_000,
|
|
658
|
+
},
|
|
659
|
+
)
|
|
660
|
+
} catch (error) {
|
|
661
|
+
const output =
|
|
662
|
+
error instanceof Error
|
|
663
|
+
? `${error.message}\n${'stdout' in error ? String(error.stdout) : ''}${'stderr' in error ? String(error.stderr) : ''}`
|
|
664
|
+
: String(error)
|
|
665
|
+
throw new Error(
|
|
666
|
+
`${targetName}: Run Script "${script}" failed preparing generated Swift sources:\n${output}`,
|
|
667
|
+
)
|
|
543
668
|
}
|
|
669
|
+
const missing = allOutputs.filter(
|
|
670
|
+
(file) => file.endsWith('.swift') && !fs.existsSync(file),
|
|
671
|
+
)
|
|
672
|
+
if (missing.length > 0)
|
|
673
|
+
throw new Error(
|
|
674
|
+
`${targetName}: Run Script "${script}" did not produce ${missing.join(', ')}`,
|
|
675
|
+
)
|
|
676
|
+
preparedSourcePhases.set(key, stamp)
|
|
544
677
|
}
|
|
545
678
|
}
|
|
546
679
|
visitXcodeTargetMembers(
|
|
@@ -769,7 +902,7 @@ export function readXcodeAppTarget(
|
|
|
769
902
|
input: string,
|
|
770
903
|
targetName?: string,
|
|
771
904
|
configurationName?: string,
|
|
772
|
-
options: { requireSources?: boolean } = {},
|
|
905
|
+
options: { requireSources?: boolean; prepareGeneratedSources?: boolean } = {},
|
|
773
906
|
): XcodeAppTarget {
|
|
774
907
|
// canonical, so every path returned agrees with the host's realpath checks
|
|
775
908
|
const xcodeprojOrWorkspace = fs.realpathSync(input)
|
|
@@ -881,22 +1014,112 @@ export function readXcodeAppTarget(
|
|
|
881
1014
|
SRCROOT: ref.project.projectDir,
|
|
882
1015
|
SOURCE_ROOT: ref.project.projectDir,
|
|
883
1016
|
PROJECT_DIR: ref.project.projectDir,
|
|
1017
|
+
SYMROOT: path.join(ref.project.projectDir, '.build/peach-xcode/Build/Products'),
|
|
1018
|
+
BUILD_DIR: '$(SYMROOT)',
|
|
1019
|
+
OBJROOT: path.join(
|
|
1020
|
+
ref.project.projectDir,
|
|
1021
|
+
'.build/peach-xcode/Build/Intermediates.noindex',
|
|
1022
|
+
),
|
|
1023
|
+
CONFIGURATION_BUILD_DIR:
|
|
1024
|
+
'$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)',
|
|
1025
|
+
BUILT_PRODUCTS_DIR: '$(CONFIGURATION_BUILD_DIR)',
|
|
1026
|
+
TARGET_BUILD_DIR: '$(CONFIGURATION_BUILD_DIR)',
|
|
1027
|
+
PROJECT_TEMP_DIR: '$(OBJROOT)/$(PROJECT_NAME).build',
|
|
1028
|
+
CONFIGURATION_TEMP_DIR:
|
|
1029
|
+
'$(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)',
|
|
1030
|
+
TARGET_TEMP_DIR: '$(CONFIGURATION_TEMP_DIR)/$(TARGET_NAME).build',
|
|
1031
|
+
DERIVED_FILE_DIR: '$(TARGET_TEMP_DIR)/DerivedSources',
|
|
1032
|
+
DERIVED_FILES_DIR: '$(DERIVED_FILE_DIR)',
|
|
1033
|
+
PLATFORM_NAME: 'iphonesimulator',
|
|
1034
|
+
EFFECTIVE_PLATFORM_NAME: '-iphonesimulator',
|
|
1035
|
+
CURRENT_ARCH: 'arm64',
|
|
1036
|
+
ARCHS: 'arm64',
|
|
1037
|
+
ACTION: 'build',
|
|
884
1038
|
DEVELOPMENT_LANGUAGE: str(ref.project.project.developmentRegion) ?? 'en',
|
|
885
1039
|
},
|
|
886
1040
|
options,
|
|
887
1041
|
)
|
|
888
1042
|
for (const file of read) xcconfigs.add(file)
|
|
889
1043
|
const swiftVersion = Number.parseFloat(settings('SWIFT_VERSION') || '5')
|
|
1044
|
+
const members = targetMembers(ref, settings, options, keys, xcconfigs)
|
|
1045
|
+
const implementations = members.allSources.filter((file) =>
|
|
1046
|
+
/\.(c|cc|cpp|cxx|m|mm)$/.test(file),
|
|
1047
|
+
)
|
|
1048
|
+
const absolute = (file: string) => path.resolve(ref.project.projectDir, file)
|
|
1049
|
+
const fileFlags: Record<string, string[]> = {}
|
|
1050
|
+
for (const phaseId of list(ref.target.buildPhases)) {
|
|
1051
|
+
const phase = ref.project.object(phaseId)
|
|
1052
|
+
if (phase?.isa !== 'PBXSourcesBuildPhase') continue
|
|
1053
|
+
for (const id of list(phase.files)) {
|
|
1054
|
+
const file = ref.project.object(id)
|
|
1055
|
+
const resolved = ref.project.resolvePath(str(file?.fileRef) ?? '')
|
|
1056
|
+
if (resolved && implementations.includes(resolved))
|
|
1057
|
+
fileFlags[resolved] = settingList(
|
|
1058
|
+
expand(
|
|
1059
|
+
str(isDict(file?.settings) ? file.settings.COMPILER_FLAGS : undefined) ??
|
|
1060
|
+
'',
|
|
1061
|
+
settings,
|
|
1062
|
+
),
|
|
1063
|
+
)
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
890
1066
|
return {
|
|
891
1067
|
settings,
|
|
892
1068
|
keys,
|
|
893
1069
|
module: {
|
|
894
1070
|
name,
|
|
895
1071
|
moduleName: applyOperator(settings('PRODUCT_MODULE_NAME'), 'c99extidentifier'),
|
|
896
|
-
...
|
|
1072
|
+
...members,
|
|
897
1073
|
languageMode: swiftVersion >= 6 ? 6 : 5,
|
|
898
1074
|
mainActorIsolation: settings('SWIFT_DEFAULT_ACTOR_ISOLATION') === 'MainActor',
|
|
899
1075
|
defines: compilationConditions(settings),
|
|
1076
|
+
iosDeploymentTarget: settings('IPHONEOS_DEPLOYMENT_TARGET') || null,
|
|
1077
|
+
...(implementations.some((file) => /\.mm?$/.test(file))
|
|
1078
|
+
? {
|
|
1079
|
+
objc: {
|
|
1080
|
+
headers: Object.keys(ref.project.objects).flatMap((id) => {
|
|
1081
|
+
const file = ref.project.resolvePath(id)
|
|
1082
|
+
return file && /\.(h|hh|hpp|hxx|pch)$/.test(file) && fs.existsSync(file)
|
|
1083
|
+
? [file]
|
|
1084
|
+
: []
|
|
1085
|
+
}),
|
|
1086
|
+
prefixHeader: settings('GCC_PREFIX_HEADER')
|
|
1087
|
+
? absolute(settings('GCC_PREFIX_HEADER'))
|
|
1088
|
+
: null,
|
|
1089
|
+
bridgingHeader: settings('SWIFT_OBJC_BRIDGING_HEADER')
|
|
1090
|
+
? absolute(settings('SWIFT_OBJC_BRIDGING_HEADER'))
|
|
1091
|
+
: null,
|
|
1092
|
+
headerSearchPaths: [
|
|
1093
|
+
...settingList(settings('HEADER_SEARCH_PATHS')),
|
|
1094
|
+
...settingList(settings('USER_HEADER_SEARCH_PATHS')),
|
|
1095
|
+
].map(absolute),
|
|
1096
|
+
frameworkSearchPaths: settingList(settings('FRAMEWORK_SEARCH_PATHS')).map(
|
|
1097
|
+
absolute,
|
|
1098
|
+
),
|
|
1099
|
+
flags: [
|
|
1100
|
+
...(settings('CLANG_ENABLE_OBJC_ARC') === 'YES' ? ['-fobjc-arc'] : []),
|
|
1101
|
+
...(settings('CLANG_ENABLE_OBJC_WEAK') === 'YES'
|
|
1102
|
+
? ['-fobjc-weak']
|
|
1103
|
+
: []),
|
|
1104
|
+
...(settings('CLANG_ENABLE_MODULES') === 'YES' ? ['-fmodules'] : []),
|
|
1105
|
+
...(settings('GCC_C_LANGUAGE_STANDARD')
|
|
1106
|
+
? [`-std=${settings('GCC_C_LANGUAGE_STANDARD')}`]
|
|
1107
|
+
: []),
|
|
1108
|
+
...settingList(settings('GCC_PREPROCESSOR_DEFINITIONS')).map(
|
|
1109
|
+
(value) => `-D${value}`,
|
|
1110
|
+
),
|
|
1111
|
+
...settingList(settings('OTHER_CFLAGS')),
|
|
1112
|
+
],
|
|
1113
|
+
cxxFlags: [
|
|
1114
|
+
...(settings('CLANG_CXX_LANGUAGE_STANDARD')
|
|
1115
|
+
? [`-std=${settings('CLANG_CXX_LANGUAGE_STANDARD')}`]
|
|
1116
|
+
: []),
|
|
1117
|
+
...settingList(settings('OTHER_CPLUSPLUSFLAGS')),
|
|
1118
|
+
],
|
|
1119
|
+
fileFlags,
|
|
1120
|
+
},
|
|
1121
|
+
}
|
|
1122
|
+
: {}),
|
|
900
1123
|
} satisfies XcodeModuleTarget,
|
|
901
1124
|
}
|
|
902
1125
|
}
|
|
@@ -967,6 +1190,23 @@ export function readXcodeAppTarget(
|
|
|
967
1190
|
...projects.flatMap((project) =>
|
|
968
1191
|
Object.entries(project.objects).flatMap(([id, entry]) => {
|
|
969
1192
|
if (!isDict(entry)) return []
|
|
1193
|
+
if (entry.isa === 'PBXFileSystemSynchronizedRootGroup') {
|
|
1194
|
+
const folder = project.resolvePath(id)
|
|
1195
|
+
const pending = folder ? [folder] : []
|
|
1196
|
+
const packages: string[] = []
|
|
1197
|
+
while (pending.length > 0) {
|
|
1198
|
+
const dir = pending.pop()!
|
|
1199
|
+
if (fs.existsSync(path.join(dir, 'Package.swift'))) {
|
|
1200
|
+
packages.push(dir)
|
|
1201
|
+
continue
|
|
1202
|
+
}
|
|
1203
|
+
if (!isDirectory(dir)) continue
|
|
1204
|
+
for (const child of fs.readdirSync(dir, { withFileTypes: true }))
|
|
1205
|
+
if (child.isDirectory() && !child.name.startsWith('.'))
|
|
1206
|
+
pending.push(path.join(dir, child.name))
|
|
1207
|
+
}
|
|
1208
|
+
return packages
|
|
1209
|
+
}
|
|
970
1210
|
const candidate =
|
|
971
1211
|
entry.isa === 'XCLocalSwiftPackageReference'
|
|
972
1212
|
? path.resolve(project.projectDir, str(entry.relativePath) ?? '')
|
|
@@ -1046,6 +1286,13 @@ export function readXcodeAppTarget(
|
|
|
1046
1286
|
'Package.resolved',
|
|
1047
1287
|
)
|
|
1048
1288
|
|
|
1289
|
+
const packageResolved = fs.existsSync(resolvedFile)
|
|
1290
|
+
? [fs.realpathSync(resolvedFile)]
|
|
1291
|
+
: [...new Set(localPackageDirs.map((dir) => path.join(dir, 'Package.resolved')))]
|
|
1292
|
+
.filter((file) => fs.existsSync(file))
|
|
1293
|
+
.map((file) => fs.realpathSync(file))
|
|
1294
|
+
.sort()
|
|
1295
|
+
|
|
1049
1296
|
// the app is last in its own dependency order
|
|
1050
1297
|
const used = order.map((ref) => ref.project)
|
|
1051
1298
|
return {
|
|
@@ -1074,7 +1321,7 @@ export function readXcodeAppTarget(
|
|
|
1074
1321
|
binaryFrameworks: [...binaryFrameworks]
|
|
1075
1322
|
.map(([name, file]) => ({ name, path: file }))
|
|
1076
1323
|
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
1077
|
-
packageResolved
|
|
1324
|
+
packageResolved,
|
|
1078
1325
|
appTargets: appTargetNames,
|
|
1079
1326
|
configuration,
|
|
1080
1327
|
settings,
|