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
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// build carries, and unpacks it under the peach home
|
|
6
6
|
// (docs/swift-distribution.md). no path here asks Contrast to compile.
|
|
7
7
|
import fs from 'node:fs'
|
|
8
|
+
import os from 'node:os'
|
|
8
9
|
import path from 'node:path'
|
|
9
10
|
import { installVerifiedTarball } from '@contrast/runtime-delivery'
|
|
10
11
|
import { rnxHomeDir } from './home-paths'
|
|
@@ -16,7 +17,17 @@ import {
|
|
|
16
17
|
swiftDistributionKey,
|
|
17
18
|
} from './swift-distribution-contract'
|
|
18
19
|
import lockJson from './swift-distribution.lock.json' with { type: 'json' }
|
|
19
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
confineSwiftScratch,
|
|
22
|
+
installSwiftWasmSdk,
|
|
23
|
+
swiftCompiler,
|
|
24
|
+
swiftCompilerInstallSteps,
|
|
25
|
+
swiftHostCompilerArchive,
|
|
26
|
+
swiftToolchain,
|
|
27
|
+
swiftToolchainBin,
|
|
28
|
+
verifySwiftHostCompiler,
|
|
29
|
+
type SwiftWasmSdk,
|
|
30
|
+
} from './swift-toolchain'
|
|
20
31
|
|
|
21
32
|
export const SWIFT_ENDPOINT_ENV = 'PEACH_SWIFT_ENDPOINT'
|
|
22
33
|
|
|
@@ -51,9 +62,9 @@ export async function swiftDistributionRoot(
|
|
|
51
62
|
`peach has no Swift distribution for ${process.platform}-${process.arch}; it ships for macOS arm64 and Linux x64 and arm64`,
|
|
52
63
|
)
|
|
53
64
|
}
|
|
54
|
-
// the archive is useless without its compiler, so
|
|
55
|
-
//
|
|
56
|
-
|
|
65
|
+
// the archive is useless without its compiler, so the toolchain installs
|
|
66
|
+
// or fails before the download
|
|
67
|
+
await installSwiftToolchain(lock.release, lock, signal)
|
|
57
68
|
const dir = path.join(rnxHomeDir(), 'swift', `${lock.id}-${host}`)
|
|
58
69
|
let pending = installs.get(dir)
|
|
59
70
|
if (pending?.controller.signal.aborted) pending = undefined
|
|
@@ -126,6 +137,93 @@ export async function swiftDistributionRoot(
|
|
|
126
137
|
}
|
|
127
138
|
}
|
|
128
139
|
|
|
140
|
+
/**
|
|
141
|
+
* the pinned compiler and wasm SDK, installed on first use without root: the
|
|
142
|
+
* compiler under PEACH_HOME/swift/toolchains (macOS: ~/Library/Developer/Toolchains) unless CONTRAST_SWIFT_TOOLCHAINS
|
|
143
|
+
* or an existing /opt/swift install selects another (swiftToolchainBin), the
|
|
144
|
+
* SDK in the --swift-sdks-path directory, PEACH_HOME/swift/sdks by default.
|
|
145
|
+
* a compiler in a directory the user selected is verified, never replaced.
|
|
146
|
+
*/
|
|
147
|
+
async function installSwiftToolchain(
|
|
148
|
+
release: string,
|
|
149
|
+
sdk: SwiftWasmSdk,
|
|
150
|
+
signal?: AbortSignal,
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
process.env.PEACH_SWIFT_SDKS_PATH ??= path.join(rnxHomeDir(), 'swift', 'sdks')
|
|
153
|
+
if (swiftToolchainReady(release, sdk)) return
|
|
154
|
+
const root = path.resolve(swiftToolchainBin(release), '../..')
|
|
155
|
+
// macOS installs where the locator looks first, the user's Toolchains
|
|
156
|
+
// directory, and only into a directory without a compiler; linux installs
|
|
157
|
+
// into the Peach-owned directory.
|
|
158
|
+
const owned =
|
|
159
|
+
process.platform === 'darwin'
|
|
160
|
+
? path.join(os.homedir(), 'Library/Developer/Toolchains', `${release}.xctoolchain`)
|
|
161
|
+
: path.join(rnxHomeDir(), 'swift', 'toolchains', release)
|
|
162
|
+
const selectedCompiler =
|
|
163
|
+
process.platform === 'darwin' && fs.existsSync(path.join(root, 'usr/bin/swift'))
|
|
164
|
+
if (
|
|
165
|
+
release.includes('-custom-') &&
|
|
166
|
+
root === owned &&
|
|
167
|
+
!selectedCompiler &&
|
|
168
|
+
!swiftCompilerReady(release)
|
|
169
|
+
) {
|
|
170
|
+
const archive = swiftHostCompilerArchive(release)
|
|
171
|
+
process.stderr.write(`peach: installing Swift compiler ${release} to ${root}…\n`)
|
|
172
|
+
await installVerifiedTarball({
|
|
173
|
+
signal,
|
|
174
|
+
url: archive.url,
|
|
175
|
+
digest: { algorithm: 'sha256', encoding: 'hex', value: archive.checksum },
|
|
176
|
+
destDir: root,
|
|
177
|
+
installedMarker: 'compiler.json',
|
|
178
|
+
stripComponents: 1,
|
|
179
|
+
label: `Swift compiler ${release}`,
|
|
180
|
+
verify: (dir) => verifySwiftHostCompiler(release, dir),
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
swiftCompiler(release)
|
|
185
|
+
} catch (error) {
|
|
186
|
+
const reason = error instanceof Error ? error.message : String(error)
|
|
187
|
+
throw new Error(
|
|
188
|
+
`Swift compiler ${release} is unavailable or differs from its pin: ${reason}\n${swiftCompilerInstallSteps(release)}\nthen run the command again; it installs the SDK.`,
|
|
189
|
+
{ cause: error },
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
if (swiftToolchainReady(release, sdk)) return
|
|
193
|
+
signal?.throwIfAborted()
|
|
194
|
+
const directory = process.env.PEACH_SWIFT_SDKS_PATH
|
|
195
|
+
process.stderr.write(`peach: installing Swift SDK ${sdk.wasmSdkId} to ${directory}…\n`)
|
|
196
|
+
try {
|
|
197
|
+
installSwiftWasmSdk(release, sdk)
|
|
198
|
+
} catch (error) {
|
|
199
|
+
const reason = error instanceof Error ? error.message : String(error)
|
|
200
|
+
throw new Error(
|
|
201
|
+
`could not install Swift SDK ${sdk.wasmSdkId} to ${directory}: ${reason}`,
|
|
202
|
+
{
|
|
203
|
+
cause: error,
|
|
204
|
+
},
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function swiftCompilerReady(release: string): boolean {
|
|
210
|
+
try {
|
|
211
|
+
swiftCompiler(release)
|
|
212
|
+
return true
|
|
213
|
+
} catch {
|
|
214
|
+
return false
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function swiftToolchainReady(release: string, sdk: SwiftWasmSdk): boolean {
|
|
219
|
+
try {
|
|
220
|
+
swiftToolchain(release, sdk)
|
|
221
|
+
return true
|
|
222
|
+
} catch {
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
129
227
|
/** the module this process compiles app Swift against: the checkout beside a
|
|
130
228
|
* source peach, else the distribution, else null. `required` callers compile
|
|
131
229
|
* nothing without it, so a checkout's toolchain error surfaces to them. */
|
|
@@ -134,6 +232,7 @@ export async function resolveSwiftModule({
|
|
|
134
232
|
signal,
|
|
135
233
|
}: { required?: boolean; signal?: AbortSignal } = {}): Promise<SwiftModule | null> {
|
|
136
234
|
signal?.throwIfAborted()
|
|
235
|
+
confineSwiftScratch(path.join(rnxHomeDir(), 'cache', 'swift-tmp'))
|
|
137
236
|
const checkout = path.resolve(import.meta.dirname, '../../sootsim-swift')
|
|
138
237
|
if (fs.existsSync(path.join(checkout, 'toolchain.json'))) {
|
|
139
238
|
// a checkout is implicit: without its toolchain, apps run without their
|
package/src/swift-host.ts
CHANGED
|
@@ -15,6 +15,8 @@ import { authHeaderValue, resolveCliAuth } from '../cli/auth'
|
|
|
15
15
|
import { resolveContrastBackendOrigin } from './backend-origin'
|
|
16
16
|
import { cacheDir } from './home-paths'
|
|
17
17
|
import iosSdk from './ios-sdk-frameworks.json' with { type: 'json' }
|
|
18
|
+
import { type NativeAppIdentity } from './native-app-identity'
|
|
19
|
+
import { readNativeAppIdentityFromXcodeTarget } from './native-app-identity-project'
|
|
18
20
|
import { swiftBinaryModules } from './swift-binary-modules'
|
|
19
21
|
import {
|
|
20
22
|
compileSwiftProjectUnit,
|
|
@@ -28,6 +30,7 @@ import {
|
|
|
28
30
|
} from './swift-compile'
|
|
29
31
|
import { designTimeValues } from './swift-design-time'
|
|
30
32
|
import { swiftDistributionRoot, swiftModuleToolchain } from './swift-distribution'
|
|
33
|
+
import { compileXcodeObjCImplementations } from './swift-objc-compile'
|
|
31
34
|
import {
|
|
32
35
|
swiftImplicitResourcePaths,
|
|
33
36
|
swiftMetalSourceFiles,
|
|
@@ -267,7 +270,9 @@ export function openXcodeProject(
|
|
|
267
270
|
moduleRoot: string | undefined,
|
|
268
271
|
configuration?: string,
|
|
269
272
|
): string {
|
|
270
|
-
const app = readXcodeAppTarget(xcodeproj, target, configuration
|
|
273
|
+
const app = readXcodeAppTarget(xcodeproj, target, configuration, {
|
|
274
|
+
prepareGeneratedSources: true,
|
|
275
|
+
})
|
|
271
276
|
const root = app.rootDir
|
|
272
277
|
xcodeProjects.set(root, {
|
|
273
278
|
xcodeproj,
|
|
@@ -312,20 +317,20 @@ function swiftPackages(
|
|
|
312
317
|
projectGaps: Map<string, string>
|
|
313
318
|
binaries: SwiftPackageBinary[]
|
|
314
319
|
} {
|
|
315
|
-
const stamp = (file: string
|
|
316
|
-
|
|
320
|
+
const stamp = (file: string) =>
|
|
321
|
+
fs.existsSync(file)
|
|
322
|
+
? createHash('sha256').update(fs.readFileSync(file)).digest('hex')
|
|
323
|
+
: null
|
|
317
324
|
const key = JSON.stringify([
|
|
318
325
|
app.linkedProducts,
|
|
319
|
-
app.packageResolved,
|
|
320
|
-
stamp(app.packageResolved),
|
|
326
|
+
app.packageResolved.map((file) => [file, stamp(file)]),
|
|
321
327
|
app.localPackageDirs.map((dir) => stamp(path.join(dir, 'Package.swift'))),
|
|
322
328
|
app.linkedProducts.map(({ source }) =>
|
|
323
329
|
source.kind === 'local' ? stamp(path.join(source.dir, 'Package.swift')) : 0,
|
|
324
330
|
),
|
|
325
331
|
])
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
// emitter), so a changed input rebuilds instead of reusing stale output.
|
|
332
|
+
// resolution follows lock and manifest contents even when a checkout restores
|
|
333
|
+
// timestamps. the stand-in key also covers artifacts, peach modules and emitter.
|
|
329
334
|
let cached = entry.packages
|
|
330
335
|
if (cached?.key !== key) {
|
|
331
336
|
const packages = resolveSwiftPackages({
|
|
@@ -345,6 +350,13 @@ function swiftPackages(
|
|
|
345
350
|
}
|
|
346
351
|
entry.packages = cached
|
|
347
352
|
}
|
|
353
|
+
if (
|
|
354
|
+
entry.moduleRoot &&
|
|
355
|
+
[app, ...app.frameworks].some((target) =>
|
|
356
|
+
target.allSources.some((file) => /\.mm?$/.test(file)),
|
|
357
|
+
)
|
|
358
|
+
)
|
|
359
|
+
compileXcodeObjCImplementations(app, cached.binaries, entry.moduleRoot)
|
|
348
360
|
// a reached binary target with stand-ins for every module it ships
|
|
349
361
|
// resolves as provided, so what depends on it compiles; the rest keep
|
|
350
362
|
// their reason with why no stand-in was built. surfaces peach already
|
|
@@ -450,11 +462,26 @@ function xcodeLayout(root: string): XcodeLayout | null {
|
|
|
450
462
|
registered.xcodeproj,
|
|
451
463
|
registered.target,
|
|
452
464
|
registered.configuration,
|
|
465
|
+
{ prepareGeneratedSources: true },
|
|
453
466
|
)
|
|
467
|
+
const implementations = [app, ...app.frameworks].flatMap((target) =>
|
|
468
|
+
target.allSources
|
|
469
|
+
.filter((file) => /\.mm?$/i.test(file))
|
|
470
|
+
.map((file) => `${target.name}: ${path.relative(app.rootDir, file)}`),
|
|
471
|
+
)
|
|
472
|
+
if (implementations.length > 0 && !registered.moduleRoot)
|
|
473
|
+
throw new Error(
|
|
474
|
+
`Peach cannot compile Objective-C implementations in Xcode targets until the runtime and shared Swift object bridge are available:\n${implementations.map((file) => ` ${file}`).join('\n')}`,
|
|
475
|
+
)
|
|
454
476
|
const appSources = app.allSources.filter(
|
|
455
477
|
(file) => file.endsWith('.swift') || file.endsWith('.metal'),
|
|
456
478
|
)
|
|
457
|
-
const files = new Set([
|
|
479
|
+
const files = new Set([
|
|
480
|
+
...app.projectFiles,
|
|
481
|
+
...app.packageResolved,
|
|
482
|
+
...appSources,
|
|
483
|
+
...app.resources,
|
|
484
|
+
])
|
|
458
485
|
if (app.infoPlistFile) files.add(app.infoPlistFile)
|
|
459
486
|
const targetDirs = new Map(
|
|
460
487
|
[...appSources, ...app.resources].map((file) => [file, XCODE_APP_DIR]),
|
|
@@ -605,10 +632,18 @@ function xcodeManifest(layout: XcodeLayout): string {
|
|
|
605
632
|
|
|
606
633
|
// preflight the entire input tree before reading any source or resource bytes.
|
|
607
634
|
// a nested package is a separate compile unit; ignored build trees never enter it.
|
|
608
|
-
function packageFiles(root: string): string[] {
|
|
635
|
+
function packageFiles(root: string, includeBuildInputs = true): string[] {
|
|
609
636
|
const canonicalRoot = fs.realpathSync(root)
|
|
610
637
|
const xcode = xcodeLayout(canonicalRoot)
|
|
611
|
-
|
|
638
|
+
if (!xcode) return sourceTreeFiles(canonicalRoot, canonicalRoot)
|
|
639
|
+
if (includeBuildInputs) return xcode.files
|
|
640
|
+
const buildInputs = new Set(xcode.app.projectFiles)
|
|
641
|
+
return xcode.files.filter(
|
|
642
|
+
(file) =>
|
|
643
|
+
!buildInputs.has(file) ||
|
|
644
|
+
xcode.targetDirs.has(file) ||
|
|
645
|
+
xcode.packages.targets.some((target) => target.files.includes(file)),
|
|
646
|
+
)
|
|
612
647
|
}
|
|
613
648
|
|
|
614
649
|
// remote dependencies are enumerated from peach's checkout cache, while app
|
|
@@ -668,16 +703,18 @@ function isPackageSource(file: string): boolean {
|
|
|
668
703
|
}
|
|
669
704
|
|
|
670
705
|
export function sourceFiles(root: string): string[] {
|
|
671
|
-
return packageFiles(root).filter(isPackageSource)
|
|
706
|
+
return packageFiles(root, false).filter(isPackageSource)
|
|
672
707
|
}
|
|
673
708
|
|
|
674
709
|
// project files and the xcconfigs their settings read are build inputs, never resources
|
|
675
710
|
function resourceCandidateFiles(root: string): string[] {
|
|
676
|
-
return packageFiles(root).filter(
|
|
711
|
+
return packageFiles(root, false).filter(
|
|
677
712
|
(file) =>
|
|
678
713
|
!isPackageSource(file) &&
|
|
679
714
|
!file.endsWith('.xcconfig') &&
|
|
680
|
-
!['project.pbxproj', 'project.xcproj'].includes(
|
|
715
|
+
!['project.pbxproj', 'project.xcproj', 'Package.resolved'].includes(
|
|
716
|
+
path.basename(file),
|
|
717
|
+
),
|
|
681
718
|
)
|
|
682
719
|
}
|
|
683
720
|
|
|
@@ -685,6 +722,7 @@ function resourceCandidateFiles(root: string): string[] {
|
|
|
685
722
|
export function swiftProjectAppInfo(packagePath: string): {
|
|
686
723
|
name: string
|
|
687
724
|
icon: { bytes: Buffer; contentType: string } | null
|
|
725
|
+
identity: NativeAppIdentity | null
|
|
688
726
|
} {
|
|
689
727
|
const registered = xcodeProjects.get(packagePath)
|
|
690
728
|
const app = registered
|
|
@@ -747,12 +785,17 @@ export function swiftProjectAppInfo(packagePath: string): {
|
|
|
747
785
|
}
|
|
748
786
|
break
|
|
749
787
|
}
|
|
750
|
-
return {
|
|
788
|
+
return {
|
|
789
|
+
name: app?.name ?? path.basename(packagePath),
|
|
790
|
+
icon,
|
|
791
|
+
identity: app ? readNativeAppIdentityFromXcodeTarget(app) : null,
|
|
792
|
+
}
|
|
751
793
|
}
|
|
752
794
|
|
|
753
795
|
// the hosted compile service caps what a project sends it; a local compile
|
|
754
796
|
// reads the author's own files, so nothing caps them there.
|
|
755
797
|
const HOSTED_LIMITS = {
|
|
798
|
+
sourceBytes: MAX_SWIFT_COMPILE_SOURCE_BYTES,
|
|
756
799
|
resources: MAX_SWIFT_COMPILE_RESOURCES,
|
|
757
800
|
resourceBytes: MAX_SWIFT_COMPILE_RESOURCE_BYTES,
|
|
758
801
|
resourceTotalBytes: MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES,
|
|
@@ -761,6 +804,7 @@ const HOSTED_LIMITS = {
|
|
|
761
804
|
imageTotalBytes: MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES,
|
|
762
805
|
}
|
|
763
806
|
const LOCAL_LIMITS: typeof HOSTED_LIMITS = {
|
|
807
|
+
sourceBytes: Infinity,
|
|
764
808
|
resources: Infinity,
|
|
765
809
|
resourceBytes: Infinity,
|
|
766
810
|
resourceTotalBytes: Infinity,
|
|
@@ -969,7 +1013,7 @@ export function buildSwiftBundleFiles(
|
|
|
969
1013
|
const xcode = xcodeLayout(packagePath)
|
|
970
1014
|
const bundles =
|
|
971
1015
|
xcode?.resourceBundles ??
|
|
972
|
-
swiftResourceBundles(inputs ?? packageSources(packagePath), relative)
|
|
1016
|
+
swiftResourceBundles(inputs ?? packageSources(packagePath, hosted), relative)
|
|
973
1017
|
const addFile = (key: string, bytes: Buffer) => {
|
|
974
1018
|
if (
|
|
975
1019
|
Object.keys(files).length >= limits.resources ||
|
|
@@ -1175,6 +1219,7 @@ export function standinLibraries(
|
|
|
1175
1219
|
|
|
1176
1220
|
function packageSources(
|
|
1177
1221
|
packagePath: string,
|
|
1222
|
+
hosted = false,
|
|
1178
1223
|
linked: ReadonlySet<SwiftStandin> = new Set(),
|
|
1179
1224
|
): Record<string, string> {
|
|
1180
1225
|
const xcode = xcodeLayout(packagePath)
|
|
@@ -1184,13 +1229,14 @@ function packageSources(
|
|
|
1184
1229
|
),
|
|
1185
1230
|
)
|
|
1186
1231
|
const files: Record<string, string> = {}
|
|
1232
|
+
const limits = inputLimits(hosted)
|
|
1187
1233
|
for (const file of sourceFiles(packagePath)) {
|
|
1188
1234
|
const relative = path.relative(packagePath, file).split(path.sep).join(path.posix.sep)
|
|
1189
1235
|
if (manifests.has(file)) continue
|
|
1190
1236
|
files[xcode ? xcodeInputKey(xcode, file, relative) : relative] = readPackageFile(
|
|
1191
1237
|
packagePath,
|
|
1192
1238
|
file,
|
|
1193
|
-
|
|
1239
|
+
limits.sourceBytes,
|
|
1194
1240
|
).toString('utf8')
|
|
1195
1241
|
}
|
|
1196
1242
|
if (xcode) {
|
|
@@ -1221,7 +1267,11 @@ function packageSnapshot(project: SwiftProject, entry: string): SwiftPackageSnap
|
|
|
1221
1267
|
const linked = layout
|
|
1222
1268
|
? standinLibraries(layout.binaries, layout.standins, layout.app.rootDir)
|
|
1223
1269
|
: new Map<string, SwiftStandin[]>()
|
|
1224
|
-
const files = packageSources(
|
|
1270
|
+
const files = packageSources(
|
|
1271
|
+
project.packagePath,
|
|
1272
|
+
Boolean(project.hosted),
|
|
1273
|
+
new Set([...linked.values()].flat()),
|
|
1274
|
+
)
|
|
1225
1275
|
const native = nativeSourceDescriptor(project.packagePath)
|
|
1226
1276
|
return {
|
|
1227
1277
|
files,
|
|
@@ -1262,7 +1312,7 @@ function packageSnapshot(project: SwiftProject, entry: string): SwiftPackageSnap
|
|
|
1262
1312
|
glue: readPackageFile(
|
|
1263
1313
|
project.packagePath,
|
|
1264
1314
|
path.join(project.packagePath, NATIVE_GLUE),
|
|
1265
|
-
|
|
1315
|
+
inputLimits(Boolean(project.hosted)).sourceBytes,
|
|
1266
1316
|
).toString('utf8'),
|
|
1267
1317
|
}
|
|
1268
1318
|
: {}),
|
|
@@ -1351,10 +1401,11 @@ async function compile(
|
|
|
1351
1401
|
throw new SwiftMissingModulesError(await missingModulesMessage(packagePath, missing))
|
|
1352
1402
|
const artifact = await compileSwiftProjectUnit(input, {
|
|
1353
1403
|
// the compile rewrites Sources/App in its root before swiftpm builds, and
|
|
1354
|
-
//
|
|
1355
|
-
// server and a capture, or two checkouts)
|
|
1356
|
-
// each app and module checkout gets
|
|
1357
|
-
//
|
|
1404
|
+
// a root lock orders every process using it, so two vites on one root
|
|
1405
|
+
// (a lane's dev server and a capture, or two checkouts) queue instead of
|
|
1406
|
+
// building each other's sources. each app and module checkout still gets
|
|
1407
|
+
// its own root, so they do not queue and the same app keeps its
|
|
1408
|
+
// incremental build across restarts.
|
|
1358
1409
|
buildRoot: (() => {
|
|
1359
1410
|
if (process.env.CONTRAST_SWIFT_BUILD_ROOT)
|
|
1360
1411
|
return process.env.CONTRAST_SWIFT_BUILD_ROOT
|
|
@@ -1411,6 +1462,21 @@ const API_GAP_PATTERNS: [RegExp, (match: RegExpExecArray) => string][] = [
|
|
|
1411
1462
|
(match) => `${match[1]}.${match[2]}`,
|
|
1412
1463
|
],
|
|
1413
1464
|
[/^'([^']+)' is unavailable/, (match) => match[1]!],
|
|
1465
|
+
// an instance api Peach declares static, or the reverse
|
|
1466
|
+
[
|
|
1467
|
+
/^(?:static|instance) member '([^']+)' cannot be used on (?:instance of )?type '([^']+)'/,
|
|
1468
|
+
(match) => `${match[2]}.${match[1]}`,
|
|
1469
|
+
],
|
|
1470
|
+
// an overridable api Peach declares in an extension
|
|
1471
|
+
[
|
|
1472
|
+
/^(?:non-@objc )?[\w ]+ '([^']+)' is declared in extension of '([^']+)' and cannot be overridden/,
|
|
1473
|
+
(match) => `${match[2]}.${match[1]}`,
|
|
1474
|
+
],
|
|
1475
|
+
// a form of a macro Peach's expansion does not accept
|
|
1476
|
+
[
|
|
1477
|
+
/^(@\w+) requires an initial value/,
|
|
1478
|
+
(match) => `${match[1]} without an initial value`,
|
|
1479
|
+
],
|
|
1414
1480
|
[/^no such module '([^']+)'/, (match) => `module ${match[1]}`],
|
|
1415
1481
|
]
|
|
1416
1482
|
|
|
@@ -1425,7 +1491,7 @@ export function swiftApiGapReport(output: string): string | null {
|
|
|
1425
1491
|
const file = diagnostic[1]!
|
|
1426
1492
|
.replace(new RegExp(`^(?:${XCODE_APP_DIR}|${XCODE_FRAMEWORKS_DIR}/[^/]+)/`), '')
|
|
1427
1493
|
.replace(new RegExp(`^${XCODE_PACKAGES_DIR}/`), '')
|
|
1428
|
-
const message = diagnostic[4]
|
|
1494
|
+
const message = diagnostic[4]!.trim()
|
|
1429
1495
|
const rule = API_GAP_PATTERNS.find(([pattern]) => pattern.test(message))
|
|
1430
1496
|
const key = rule ? rule[1](rule[0].exec(message)!) : message
|
|
1431
1497
|
const table = rule ? gaps : other
|
|
@@ -1591,6 +1657,7 @@ async function compileRemote(
|
|
|
1591
1657
|
},
|
|
1592
1658
|
origin,
|
|
1593
1659
|
signal,
|
|
1660
|
+
(stage) => console.error(`Peach: compiling ${path.basename(packagePath)}: ${stage}`),
|
|
1594
1661
|
)
|
|
1595
1662
|
// the app's JS calls with the hash its own `one typegen` wrote; glue the
|
|
1596
1663
|
// service rendered from another One would reject every call as stale.
|
|
@@ -1726,9 +1793,8 @@ export function swiftPackageWatchFiles(
|
|
|
1726
1793
|
packagePath = fs.realpathSync(packagePath)
|
|
1727
1794
|
return [
|
|
1728
1795
|
...(xcodeProjects.has(packagePath) ? [] : [path.join(packagePath, 'Package.swift')]),
|
|
1729
|
-
...
|
|
1796
|
+
...packageFiles(packagePath),
|
|
1730
1797
|
...nativeSourceFiles(packagePath),
|
|
1731
|
-
...resourceCandidateFiles(packagePath),
|
|
1732
1798
|
...(moduleRoot
|
|
1733
1799
|
? swiftModuleInputFiles(moduleRoot).map((file) => path.join(moduleRoot, file))
|
|
1734
1800
|
: []),
|
|
@@ -1744,14 +1810,14 @@ export async function swiftPackageMetadata(
|
|
|
1744
1810
|
signal?: AbortSignal,
|
|
1745
1811
|
): Promise<SwiftEntryModuleArgs> {
|
|
1746
1812
|
packagePath = fs.realpathSync(packagePath)
|
|
1813
|
+
const project = projectFor(packagePath, hosted, signal)
|
|
1814
|
+
const limits = inputLimits(Boolean(project.hosted))
|
|
1747
1815
|
const mains = sourceFiles(packagePath).filter(
|
|
1748
1816
|
(file) =>
|
|
1749
1817
|
file.endsWith('.swift') &&
|
|
1750
1818
|
swiftApplicationEntry(
|
|
1751
1819
|
file,
|
|
1752
|
-
readPackageFile(packagePath, file,
|
|
1753
|
-
'utf8',
|
|
1754
|
-
),
|
|
1820
|
+
readPackageFile(packagePath, file, limits.sourceBytes).toString('utf8'),
|
|
1755
1821
|
),
|
|
1756
1822
|
)
|
|
1757
1823
|
const native = nativeSourceDescriptor(packagePath)
|
|
@@ -1760,7 +1826,6 @@ export async function swiftPackageMetadata(
|
|
|
1760
1826
|
`swift package ${packageName} needs exactly one application entry source or generated native modules; found ${mains.length}`,
|
|
1761
1827
|
)
|
|
1762
1828
|
}
|
|
1763
|
-
const project = projectFor(packagePath, hosted, signal)
|
|
1764
1829
|
const entry =
|
|
1765
1830
|
mains.length === 1
|
|
1766
1831
|
? path.relative(packagePath, mains[0]).split(path.sep).join(path.posix.sep)
|
package/src/swift-icu.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { existsSync, readFileSync } from 'node:fs'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { promisify } from 'node:util'
|
|
6
6
|
import { gzip } from 'node:zlib'
|
|
7
|
-
import { swiftSdkOptions } from './swift-toolchain.ts'
|
|
7
|
+
import { swiftEnvironment, swiftSdkOptions } from './swift-toolchain.ts'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* the icu common data a swift artifact reserves and its host fills
|
|
@@ -73,17 +73,23 @@ async function load(toolchainBin: string, sdk: string): Promise<Buffer> {
|
|
|
73
73
|
// missing piece instead of shelling out to sdk configure.
|
|
74
74
|
if (!existsSync(swift))
|
|
75
75
|
throw new Error(`swift-icu: no swift at ${swift} for the ${sdk} SDK's icu data`)
|
|
76
|
-
const { stdout: listed } = await run(swift, ['sdk', 'list', ...swiftSdkOptions()]
|
|
76
|
+
const { stdout: listed } = await run(swift, ['sdk', 'list', ...swiftSdkOptions()], {
|
|
77
|
+
env: swiftEnvironment(),
|
|
78
|
+
})
|
|
77
79
|
if (!listed.split('\n').some((line) => line.trim() === sdk))
|
|
78
80
|
throw new Error(`swift-icu: ${sdk} is not installed for ${swift}`)
|
|
79
|
-
const { stdout } = await run(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
const { stdout } = await run(
|
|
82
|
+
swift,
|
|
83
|
+
[
|
|
84
|
+
'sdk',
|
|
85
|
+
'configure',
|
|
86
|
+
...swiftSdkOptions(),
|
|
87
|
+
'--show-configuration',
|
|
88
|
+
sdk,
|
|
89
|
+
'wasm32-unknown-wasip1',
|
|
90
|
+
],
|
|
91
|
+
{ env: swiftEnvironment() },
|
|
92
|
+
)
|
|
87
93
|
const resources = /^swiftStaticResourcesPath: (.+)$/m.exec(stdout)?.[1]?.trim()
|
|
88
94
|
if (!resources) throw new Error(`swift-icu: ${sdk} names no static resources`)
|
|
89
95
|
// a copy, so the 42 MB archive it was sliced from can be collected
|