peachsim 0.1.1620 → 0.1.1635
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/LICENSE +1 -1
- package/README.md +45 -6
- package/cli/app-config.ts +4 -1
- package/cli/app-fonts.ts +39 -18
- package/cli/app-stubs.ts +224 -9
- package/cli/bridge-flow-runner.ts +248 -156
- package/cli/cloud-client.ts +68 -57
- package/cli/command-registry.ts +1 -0
- package/cli/commands/box/search-command.ts +3 -2
- package/cli/commands/box.ts +10 -29
- package/cli/commands/control.ts +391 -92
- package/cli/commands/doctor.ts +17 -184
- package/cli/commands/flow.ts +79 -11
- package/cli/commands/inspect/core.ts +10 -5
- package/cli/commands/inspect/settling.ts +71 -22
- package/cli/commands/inspect/wait-ready.ts +12 -0
- package/cli/commands/inspect.ts +26 -3
- package/cli/commands/install-desktop.ts +1 -0
- package/cli/commands/maestro-compare.ts +105 -67
- package/cli/commands/maestro.ts +9 -1
- package/cli/commands/platform.ts +71 -36
- package/cli/commands/record.ts +21 -1
- package/cli/commands/screenshot.ts +23 -1
- package/cli/commands/serve.ts +7 -2
- package/cli/commands/setup.ts +19 -42
- package/cli/commands/swift.ts +5 -0
- package/cli/commands/upload.ts +51 -8
- package/cli/desktop-companion.ts +102 -17
- package/cli/dev-build-freshness.ts +37 -2
- package/cli/drivers/desktop.ts +14 -1
- package/cli/drivers/playwright-sim-host.ts +44 -8
- package/cli/drivers/playwright.ts +9 -8
- package/cli/drivers/types.ts +5 -0
- package/cli/maestro-accessibility.ts +53 -0
- package/cli/maestro-compare.ts +108 -12
- package/cli/main.ts +2 -1
- package/cli/outbound-endpoints.ts +35 -6
- package/cli/parent-pid.ts +0 -9
- package/cli/pause-aware-timeout.ts +102 -0
- package/cli/remote-simulators.ts +112 -0
- package/cli/remoteSimulatorContract.ts +21 -0
- package/cli/scene-video.ts +89 -0
- package/cli/ws-bridge.ts +23 -14
- package/detox/attempt-events.cjs +4 -0
- package/detox/expectations.ts +5 -1
- package/detox/index.ts +241 -181
- package/detox/motion-change.cjs +73 -0
- package/detox/motion-change.d.cts +21 -0
- package/detox/navigation-lifecycle.ts +22 -4
- package/dist-lib/agent-daemon-client.cjs +3 -2
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +3 -2
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +13 -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 +14 -8
- package/dist-lib/bridge-contract.mjs +13 -7
- package/dist-lib/bundle-channel.cjs +10480 -7962
- 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 +3 -2
- package/dist-lib/cloud.mjs +3 -2
- package/dist-lib/config.cjs +10 -6
- package/dist-lib/config.mjs +10 -6
- package/dist-lib/detox/index.cjs +1854 -966
- package/dist-lib/dev-bundle-resolution.cjs +64 -24
- package/dist-lib/expo-swift-bundle.cjs +8715 -6271
- package/dist-lib/expo-swift-metadata.cjs +7 -4
- package/dist-lib/expo-swift-metadata.mjs +7 -4
- package/dist-lib/home-paths.cjs +32 -3
- package/dist-lib/host/bridge-host.cjs +10135 -7060
- 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 +1843 -408
- 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 +3 -2
- package/dist-lib/menu.mjs +3 -2
- 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 +5 -4
- package/dist-lib/metro-production-bundle.mjs +5 -4
- package/dist-lib/metro.cjs +1182 -418
- package/dist-lib/native-app-identity-project.cjs +782 -23
- package/dist-lib/native-app-identity-project.mjs +781 -23
- package/dist-lib/native-app-identity.cjs +276 -9
- package/dist-lib/native-app-identity.mjs +273 -8
- package/dist-lib/native-firebase-metadata.cjs +5 -4
- package/dist-lib/native-firebase-metadata.mjs +5 -4
- 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 +3 -2
- package/dist-lib/react-native-host-modules.cjs +8 -1
- package/dist-lib/react-native-host-modules.mjs +8 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +106 -28
- package/dist-lib/sdk.cjs +115 -34
- package/dist-lib/sdk.mjs +115 -33
- package/dist-lib/skills.cjs +15274 -9904
- package/dist-lib/swift-compile.cjs +1165 -173
- package/dist-lib/swift-compile.mjs +1212 -203
- package/dist-lib/swift-package.cjs +12 -3
- package/dist-lib/swift-package.mjs +12 -3
- package/dist-lib/swift-submit.cjs +7 -1
- package/dist-lib/swift-submit.mjs +5 -1
- package/dist-lib/swift-toolchain.cjs +133 -18
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +2648 -862
- package/dist-lib/vite.cjs +70 -14
- package/dist-lib/worklet-executable.cjs +25 -2
- package/dist-lib/worklet-executable.mjs +25 -2
- package/kotlin/AppSources/dev/peach/app/PeachDrawable.kt +21 -14
- package/kotlin/Sources/androidx/annotation/DrawableRes.kt +14 -0
- package/package.json +2 -2
- package/scripts/dev-server-scanner.ts +35 -14
- package/skills/peach-perf/SKILL.md +11 -5
- package/skills/peach-setup/SKILL.md +16 -19
- package/src/admitted-mac-build.ts +34 -8
- package/src/android-app-identity.ts +146 -0
- package/src/android-autolinking.ts +75 -0
- package/src/android-string-value.ts +36 -0
- package/src/android-strings.ts +5 -36
- package/src/androidAutolinkingContract.ts +40 -0
- package/src/bridge-constants.ts +11 -0
- package/src/bridge-contract.ts +22 -34
- package/src/bundleGlobalFooter.ts +26 -7
- package/src/codex-client.ts +3 -2
- package/src/config.ts +15 -0
- package/src/desktop-host-delivery.ts +5 -1
- package/src/dev-bundle-resolution.ts +60 -26
- package/src/expo-kotlin-host.ts +6 -36
- package/src/expo-manifest-body.ts +13 -0
- package/src/expo-swift-bundle.ts +17 -12
- package/src/expo-swift-host.ts +640 -192
- package/src/expo-swift-ready.ts +78 -0
- package/src/expoSwiftContract.ts +19 -0
- package/src/home-paths.ts +48 -2
- package/src/host/bridge-host.ts +12 -57
- package/src/host/staged-host-files.ts +29 -2
- package/src/installed-package-versions.ts +54 -14
- package/src/launchMetadataContract.ts +24 -0
- package/src/metro-plugin.ts +37 -42
- package/src/native-app-identity-project.ts +142 -5
- package/src/native-app-identity.ts +176 -11
- package/src/native-firebase-config.ts +209 -13
- package/src/nitro-compile.ts +2 -5
- package/src/nitro-source.ts +147 -63
- package/src/process-group.ts +114 -61
- package/src/process-output.ts +0 -9
- package/src/public-brand.ts +1 -0
- package/src/react-native-bridge-modules.ts +416 -0
- package/src/react-native-host-modules.ts +7 -0
- package/src/sim-client.ts +6 -4
- package/src/swift-binary-modules.ts +2 -2
- package/src/swift-compile.ts +1007 -108
- package/src/swift-compiler-digest.ts +14 -0
- package/src/swift-distribution.lock.json +40 -12
- package/src/swift-distribution.ts +61 -9
- package/src/swift-host.ts +149 -56
- package/src/swift-icu.ts +14 -6
- package/src/swift-objc-sdk.ts +133 -10
- package/src/swift-objc-standin.ts +38 -3
- package/src/swift-package-manifest.ts +21 -6
- package/src/swift-package.ts +15 -1
- package/src/swift-packages.ts +119 -60
- package/src/swift-standin-emit.ts +57 -9
- package/src/swift-standins.ts +185 -25
- package/src/swift-submit.ts +10 -0
- package/src/swift-toolchain.ts +149 -23
- package/src/vite-plugin.ts +20 -20
- package/src/worklet-executable.ts +30 -3
- package/src/worklets-babel.ts +35 -14
- package/src/xcode-project.ts +10 -0
package/src/swift-packages.ts
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
// each linked product resolves through swiftpm's own reading of its package
|
|
3
3
|
// (swift-package-manifest.ts) to the source targets that build it; remote
|
|
4
4
|
// packages are fetched at the revision the app's Package.resolved pins, into
|
|
5
|
-
//
|
|
5
|
+
// PEACH_HOME/cache/swift-packages, isolated by the app root. swift and c-family source
|
|
6
6
|
// targets use the common compiler backend. objective-c, assembly and binary
|
|
7
7
|
// targets the host built no stand-in for stay missing with their reason;
|
|
8
8
|
// the targets beside them still compile.
|
|
9
9
|
|
|
10
10
|
import { execFileSync } from 'node:child_process'
|
|
11
|
+
import { createHash } from 'node:crypto'
|
|
11
12
|
import fs from 'node:fs'
|
|
12
13
|
import path from 'node:path'
|
|
14
|
+
import { cacheDir } from './home-paths'
|
|
13
15
|
import {
|
|
14
16
|
swiftImplicitResourcePaths,
|
|
15
17
|
swiftPackageIdentity,
|
|
@@ -19,7 +21,7 @@ import {
|
|
|
19
21
|
import {
|
|
20
22
|
swiftPackageManifest,
|
|
21
23
|
swiftTargetFiles,
|
|
22
|
-
type
|
|
24
|
+
type SwiftManifestSetting,
|
|
23
25
|
type SwiftPackageManifest,
|
|
24
26
|
} from './swift-package-manifest'
|
|
25
27
|
|
|
@@ -43,7 +45,8 @@ export interface SwiftPackageSourceTarget extends SwiftPackageTarget {
|
|
|
43
45
|
packageDir: string
|
|
44
46
|
remote: boolean
|
|
45
47
|
/** the conditions its manifest defines, before a build configuration picks them. */
|
|
46
|
-
packageDefines:
|
|
48
|
+
packageDefines: SwiftManifestSetting[]
|
|
49
|
+
packageLibraries: SwiftManifestSetting[]
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
/** why a product or module does not compile, and where it comes from. */
|
|
@@ -74,22 +77,29 @@ export interface SwiftPackageBinary {
|
|
|
74
77
|
dir: string
|
|
75
78
|
/** a linked product's closure reaches it, so the app links it. */
|
|
76
79
|
reached: boolean
|
|
80
|
+
/** a source Objective-C target: public headers relative to dir. */
|
|
81
|
+
publicHeaders?: string
|
|
82
|
+
/** dependency module public headers, relative to dir. */
|
|
83
|
+
headerDependencies?: { module: string; path: string }[]
|
|
77
84
|
}
|
|
78
85
|
|
|
79
|
-
/**
|
|
80
|
-
export
|
|
86
|
+
/** dependency checkouts belong to peach, isolated by the canonical app root. */
|
|
87
|
+
export function remoteSwiftCheckouts(root: string): string {
|
|
88
|
+
const key = createHash('sha256')
|
|
89
|
+
.update(fs.realpathSync(root))
|
|
90
|
+
.digest('hex')
|
|
91
|
+
.slice(0, 32)
|
|
92
|
+
fs.mkdirSync(cacheDir(), { recursive: true })
|
|
93
|
+
return path.join(fs.realpathSync(cacheDir()), 'swift-packages', key, 'checkouts')
|
|
94
|
+
}
|
|
81
95
|
|
|
82
96
|
// sources requiring an objective-c runtime or assembly lowering.
|
|
83
97
|
const UNSUPPORTED_NATIVE = /\.(m|mm|s|S)$/
|
|
84
98
|
|
|
85
99
|
const BINARY = 'is a binary framework'
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
const blocker = (reasons: (string | null)[]): string | null =>
|
|
90
|
-
reasons.find((reason) => reason?.includes(BINARY)) ??
|
|
91
|
-
reasons.find((reason) => reason !== null) ??
|
|
92
|
-
null
|
|
100
|
+
// retain every independent blocker in dependency order. a product can reach
|
|
101
|
+
// several unsupported targets, and fixing one must not reveal a hidden next one.
|
|
102
|
+
const blockers = (reasons: readonly string[][]): string[] => [...new Set(reasons.flat())]
|
|
93
103
|
|
|
94
104
|
interface Pin {
|
|
95
105
|
location: string
|
|
@@ -185,7 +195,7 @@ export function resolveSwiftPackages(options: {
|
|
|
185
195
|
binaries: [],
|
|
186
196
|
}
|
|
187
197
|
const pins = resolved ? readPins(resolved) : null
|
|
188
|
-
const checkouts =
|
|
198
|
+
const checkouts = remoteSwiftCheckouts(rootDir)
|
|
189
199
|
|
|
190
200
|
const packages = new Map<string, LoadedPackage | string>()
|
|
191
201
|
// a package by local directory or remote url, or why it cannot load
|
|
@@ -205,8 +215,6 @@ export function resolveSwiftPackages(options: {
|
|
|
205
215
|
: 'no Package.resolved pins it; resolve packages in Xcode once'
|
|
206
216
|
} else {
|
|
207
217
|
fs.mkdirSync(checkouts, { recursive: true })
|
|
208
|
-
// fetched sources never show up as changes in the app's repository
|
|
209
|
-
fs.writeFileSync(path.join(path.dirname(checkouts), '.gitignore'), '*\n')
|
|
210
218
|
loaded = {
|
|
211
219
|
source: source.url,
|
|
212
220
|
remote: true,
|
|
@@ -219,35 +227,40 @@ export function resolveSwiftPackages(options: {
|
|
|
219
227
|
}
|
|
220
228
|
|
|
221
229
|
const targets = new Map<string, SwiftPackageSourceTarget>()
|
|
222
|
-
//
|
|
223
|
-
const targetOutcomes = new Map<string, string
|
|
224
|
-
const resolveTarget = (pkg: LoadedPackage, name: string): string
|
|
230
|
+
// every reason each target cannot compile; empty once it can
|
|
231
|
+
const targetOutcomes = new Map<string, string[]>()
|
|
232
|
+
const resolveTarget = (pkg: LoadedPackage, name: string): string[] => {
|
|
225
233
|
const key = `${pkg.manifest.dir}\0${name}`
|
|
226
234
|
if (targetOutcomes.has(key)) return targetOutcomes.get(key)!
|
|
227
235
|
// a dependency cycle resolves as compiling; swiftpm rejects real cycles
|
|
228
|
-
targetOutcomes.set(key,
|
|
229
|
-
const outcome = ((): string
|
|
230
|
-
if (provided.has(name)) return
|
|
236
|
+
targetOutcomes.set(key, [])
|
|
237
|
+
const outcome = ((): string[] => {
|
|
238
|
+
if (provided.has(name)) return []
|
|
231
239
|
const target = pkg.manifest.targets.get(name)
|
|
232
|
-
if (!target)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
if (!target)
|
|
241
|
+
return [`${path.basename(pkg.manifest.dir)} declares no target ${name}`]
|
|
242
|
+
const files =
|
|
243
|
+
target.type === 'regular' || target.type === 'system'
|
|
244
|
+
? swiftTargetFiles(pkg.manifest, target)
|
|
245
|
+
: []
|
|
246
|
+
const gap = options.binaryGaps?.get(name)
|
|
247
|
+
const ownReason =
|
|
248
|
+
target.type === 'binary'
|
|
249
|
+
? `${name} ${BINARY}${gap ? `; ${gap}` : ''}`
|
|
250
|
+
: target.type !== 'regular' && target.type !== 'system'
|
|
251
|
+
? `${name} is a ${target.type} target`
|
|
252
|
+
: files.some((file) => UNSUPPORTED_NATIVE.test(file))
|
|
253
|
+
? `${name} is an Objective-C or assembly target${gap ? `; ${gap}` : ''}`
|
|
254
|
+
: null
|
|
242
255
|
// every dependency resolves, so a failing one never hides the rest
|
|
243
256
|
// of the closure from the compile or from the report
|
|
244
257
|
const reasons = target.dependencies.map((dependency) => {
|
|
245
258
|
if (dependency.kind === 'target') return resolveTarget(pkg, dependency.name)
|
|
246
259
|
const nested = resolveDependencyProduct(pkg, dependency.package, dependency.name)
|
|
247
|
-
return nested
|
|
260
|
+
return nested.map((reason) => `${dependency.name}: ${reason}`)
|
|
248
261
|
})
|
|
249
|
-
const blocked =
|
|
250
|
-
if (blocked) return blocked
|
|
262
|
+
const blocked = blockers([ownReason ? [ownReason] : [], ...reasons])
|
|
263
|
+
if (blocked.length > 0) return blocked
|
|
251
264
|
const relative = files.map((file) => path.relative(target.dir, file))
|
|
252
265
|
targets.set(`${pkg.manifest.dir}\0${name}`, {
|
|
253
266
|
name,
|
|
@@ -257,6 +270,7 @@ export function resolveSwiftPackages(options: {
|
|
|
257
270
|
packageDir: pkg.manifest.dir,
|
|
258
271
|
remote: pkg.remote,
|
|
259
272
|
packageDefines: target.defines,
|
|
273
|
+
packageLibraries: target.libraries,
|
|
260
274
|
dependencies: target.dependencies.flatMap((dependency) => {
|
|
261
275
|
if (dependency.kind === 'target') return [dependency]
|
|
262
276
|
if (provided.has(dependency.name)) return []
|
|
@@ -265,32 +279,35 @@ export function resolveSwiftPackages(options: {
|
|
|
265
279
|
source &&
|
|
266
280
|
packages.get('dir' in source ? path.resolve(source.dir) : source.url)
|
|
267
281
|
return nested && typeof nested !== 'string'
|
|
268
|
-
? (nested.manifest.products.get(dependency.name) ?? []).map(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
282
|
+
? (nested.manifest.products.get(dependency.name) ?? []).map(
|
|
283
|
+
(name): SwiftTargetDependency => ({
|
|
284
|
+
kind: 'target',
|
|
285
|
+
name,
|
|
286
|
+
}),
|
|
287
|
+
)
|
|
272
288
|
: []
|
|
273
289
|
}),
|
|
274
290
|
executable: false,
|
|
291
|
+
...(target.type === 'system' ? { systemLibrary: true } : {}),
|
|
275
292
|
languageMode: target.languageMode,
|
|
276
293
|
mainActorIsolation: target.mainActorIsolation,
|
|
277
294
|
resources:
|
|
278
295
|
target.declaresResources || swiftImplicitResourcePaths(relative).length > 0,
|
|
279
296
|
})
|
|
280
|
-
return
|
|
297
|
+
return []
|
|
281
298
|
})()
|
|
282
299
|
targetOutcomes.set(key, outcome)
|
|
283
300
|
return outcome
|
|
284
301
|
}
|
|
285
302
|
// products resolved anywhere in the closure, by package, with why one
|
|
286
303
|
// cannot compile: a wrapper package's product is often the module name
|
|
287
|
-
const productOutcomes = new Map<string, { pkg: LoadedPackage; reason: string
|
|
288
|
-
const resolveProduct = (pkg: LoadedPackage, product: string): string
|
|
289
|
-
if (provided.has(product)) return
|
|
304
|
+
const productOutcomes = new Map<string, { pkg: LoadedPackage; reason: string[] }>()
|
|
305
|
+
const resolveProduct = (pkg: LoadedPackage, product: string): string[] => {
|
|
306
|
+
if (provided.has(product)) return []
|
|
290
307
|
const roots = pkg.manifest.products.get(product)
|
|
291
308
|
const reason = !roots
|
|
292
|
-
? `${path.basename(pkg.manifest.dir)} has no library ${product}`
|
|
293
|
-
:
|
|
309
|
+
? [`${path.basename(pkg.manifest.dir)} has no library ${product}`]
|
|
310
|
+
: blockers(roots.map((name) => resolveTarget(pkg, name)))
|
|
294
311
|
productOutcomes.set(`${pkg.manifest.dir}\0${product}`, { pkg, reason })
|
|
295
312
|
return reason
|
|
296
313
|
}
|
|
@@ -299,18 +316,18 @@ export function resolveSwiftPackages(options: {
|
|
|
299
316
|
pkg: LoadedPackage,
|
|
300
317
|
packageName: string,
|
|
301
318
|
product: string,
|
|
302
|
-
): string
|
|
303
|
-
if (provided.has(product)) return
|
|
319
|
+
): string[] => {
|
|
320
|
+
if (provided.has(product)) return []
|
|
304
321
|
const dependency = pkg.manifest.packages.get(packageName)
|
|
305
322
|
if (!dependency)
|
|
306
|
-
return `${path.basename(pkg.manifest.dir)} names no package ${packageName}`
|
|
323
|
+
return [`${path.basename(pkg.manifest.dir)} names no package ${packageName}`]
|
|
307
324
|
if ('dir' in dependency) {
|
|
308
325
|
const loaded = load({ kind: 'local', dir: dependency.dir })
|
|
309
|
-
return typeof loaded === 'string' ? loaded : resolveProduct(loaded, product)
|
|
326
|
+
return typeof loaded === 'string' ? [loaded] : resolveProduct(loaded, product)
|
|
310
327
|
}
|
|
311
|
-
if (!options.provided) return
|
|
328
|
+
if (!options.provided) return []
|
|
312
329
|
const loaded = load({ kind: 'remote', url: dependency.url })
|
|
313
|
-
return typeof loaded === 'string' ? loaded : resolveProduct(loaded, product)
|
|
330
|
+
return typeof loaded === 'string' ? [loaded] : resolveProduct(loaded, product)
|
|
314
331
|
}
|
|
315
332
|
|
|
316
333
|
const unnamed = () =>
|
|
@@ -326,11 +343,11 @@ export function resolveSwiftPackages(options: {
|
|
|
326
343
|
: load(source)
|
|
327
344
|
const reason =
|
|
328
345
|
pkg === undefined
|
|
329
|
-
? 'no package the workspace references vends it'
|
|
346
|
+
? ['no package the workspace references vends it']
|
|
330
347
|
: typeof pkg === 'string'
|
|
331
|
-
? pkg
|
|
348
|
+
? [pkg]
|
|
332
349
|
: resolveProduct(pkg, product)
|
|
333
|
-
if (reason)
|
|
350
|
+
if (reason.length > 0)
|
|
334
351
|
result.unavailable.set(product, {
|
|
335
352
|
source:
|
|
336
353
|
source.kind === 'remote'
|
|
@@ -340,7 +357,7 @@ export function resolveSwiftPackages(options: {
|
|
|
340
357
|
: source.kind === 'local'
|
|
341
358
|
? source.dir
|
|
342
359
|
: 'the workspace',
|
|
343
|
-
reason,
|
|
360
|
+
reason: reason.join('; '),
|
|
344
361
|
})
|
|
345
362
|
}
|
|
346
363
|
|
|
@@ -352,24 +369,35 @@ export function resolveSwiftPackages(options: {
|
|
|
352
369
|
if (target.type === 'test' || target.type === 'plugin' || target.type === 'macro')
|
|
353
370
|
continue
|
|
354
371
|
if (target.type === 'executable') continue
|
|
355
|
-
|
|
372
|
+
const objc =
|
|
373
|
+
target.type === 'regular' &&
|
|
374
|
+
swiftTargetFiles(pkg.manifest, target).some((file) => /\.(m|mm)$/.test(file))
|
|
375
|
+
if (target.type === 'binary' || objc)
|
|
356
376
|
result.binaries.push({
|
|
357
377
|
target: name,
|
|
358
378
|
source: pkg.source,
|
|
359
379
|
url: target.url,
|
|
360
380
|
checksum: target.checksum,
|
|
361
|
-
dir: target.dir,
|
|
381
|
+
dir: objc ? pkg.manifest.dir : target.dir,
|
|
362
382
|
reached: false,
|
|
383
|
+
...(objc
|
|
384
|
+
? {
|
|
385
|
+
publicHeaders: path.relative(
|
|
386
|
+
pkg.manifest.dir,
|
|
387
|
+
path.join(target.dir, target.publicHeadersPath),
|
|
388
|
+
),
|
|
389
|
+
}
|
|
390
|
+
: {}),
|
|
363
391
|
})
|
|
364
392
|
const reason = resolveTarget(pkg, name)
|
|
365
|
-
if (reason && !result.modules.has(name))
|
|
366
|
-
result.modules.set(name, { source: pkg.source, reason })
|
|
393
|
+
if (reason.length > 0 && !result.modules.has(name))
|
|
394
|
+
result.modules.set(name, { source: pkg.source, reason: reason.join('; ') })
|
|
367
395
|
}
|
|
368
396
|
}
|
|
369
397
|
for (const [key, { pkg, reason }] of productOutcomes) {
|
|
370
398
|
const product = key.slice(key.indexOf('\0') + 1)
|
|
371
|
-
if (reason && !result.modules.has(product))
|
|
372
|
-
result.modules.set(product, { source: pkg.source, reason })
|
|
399
|
+
if (reason.length > 0 && !result.modules.has(product))
|
|
400
|
+
result.modules.set(product, { source: pkg.source, reason: reason.join('; ') })
|
|
373
401
|
}
|
|
374
402
|
// what compiles is every buildable target in a linked product's closure,
|
|
375
403
|
// decided per target: a product with one target behind a binary still
|
|
@@ -410,6 +438,37 @@ export function resolveSwiftPackages(options: {
|
|
|
410
438
|
if (pkg && typeof pkg !== 'string')
|
|
411
439
|
binary.reached = reached.has(`${pkg.manifest.dir}\0${binary.target}`)
|
|
412
440
|
}
|
|
441
|
+
for (const binary of result.binaries) {
|
|
442
|
+
if (binary.publicHeaders === undefined) continue
|
|
443
|
+
const pkg = packages.get(binary.source)
|
|
444
|
+
if (!pkg || typeof pkg === 'string') continue
|
|
445
|
+
const headers = new Map<string, string>()
|
|
446
|
+
const visited = new Set<string>()
|
|
447
|
+
const visit = (owner: LoadedPackage, name: string) => {
|
|
448
|
+
const key = `${owner.manifest.dir}\0${name}`
|
|
449
|
+
if (visited.has(key)) return
|
|
450
|
+
visited.add(key)
|
|
451
|
+
const target = owner.manifest.targets.get(name)
|
|
452
|
+
if (!target) return
|
|
453
|
+
const dir = path.join(target.dir, target.publicHeadersPath)
|
|
454
|
+
for (const dependency of target.dependencies) {
|
|
455
|
+
if (dependency.kind === 'target') visit(owner, dependency.name)
|
|
456
|
+
else {
|
|
457
|
+
const source = owner.manifest.packages.get(dependency.package)
|
|
458
|
+
const nested =
|
|
459
|
+
source &&
|
|
460
|
+
packages.get('dir' in source ? path.resolve(source.dir) : source.url)
|
|
461
|
+
if (nested && typeof nested !== 'string')
|
|
462
|
+
for (const root of nested.manifest.products.get(dependency.name) ?? [])
|
|
463
|
+
visit(nested, root)
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (name !== binary.target && fs.existsSync(dir))
|
|
467
|
+
headers.set(name, path.relative(binary.dir, dir))
|
|
468
|
+
}
|
|
469
|
+
visit(pkg, binary.target)
|
|
470
|
+
binary.headerDependencies = [...headers].map(([module, path]) => ({ module, path }))
|
|
471
|
+
}
|
|
413
472
|
result.targets = [...targets.entries()]
|
|
414
473
|
.filter(([key]) => reached.has(key))
|
|
415
474
|
.map(([, target]) => target)
|
|
@@ -20,6 +20,7 @@ export type GraphSymbol = {
|
|
|
20
20
|
pathComponents: string[]
|
|
21
21
|
declarationFragments?: SymbolFragment[]
|
|
22
22
|
accessLevel: string
|
|
23
|
+
functionSignature?: { returns?: SymbolFragment[] }
|
|
23
24
|
availability?: {
|
|
24
25
|
domain?: string
|
|
25
26
|
isUnconditionallyUnavailable?: boolean
|
|
@@ -43,6 +44,8 @@ export type StandinOptions = {
|
|
|
43
44
|
module: string
|
|
44
45
|
/** where the declarations came from, for the banner: sdk, version, artifact. */
|
|
45
46
|
source: string
|
|
47
|
+
/** source Objective-C targets keep declarations with inert native bodies. */
|
|
48
|
+
inert?: boolean
|
|
46
49
|
/** modules the source imports beside Foundation and UIKit. */
|
|
47
50
|
imports?: string[]
|
|
48
51
|
/** precise symbol id → swift literal for enum cases and option values. */
|
|
@@ -87,7 +90,7 @@ export type StandinResult = {
|
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
/** bump when emitted source changes: the stand-in cache keys on it. */
|
|
90
|
-
export const STANDIN_EMIT_VERSION = '
|
|
93
|
+
export const STANDIN_EMIT_VERSION = '10'
|
|
91
94
|
|
|
92
95
|
/** the modules every stand-in source imports. */
|
|
93
96
|
export const STANDIN_IMPORTS = ['Foundation', 'UIKit']
|
|
@@ -331,6 +334,47 @@ export function emitSwiftStandin(
|
|
|
331
334
|
])
|
|
332
335
|
}
|
|
333
336
|
|
|
337
|
+
// DEGRADED(swift-objc-runtime): source objc targets retain their api with inert native bodies.
|
|
338
|
+
// return values follow the imported declaration, never the app's call sites.
|
|
339
|
+
const inertValue = (type: string): string => {
|
|
340
|
+
const value = type.trim().replace(/!$/, '?')
|
|
341
|
+
if (value.endsWith('?')) return 'nil'
|
|
342
|
+
if (value === 'Void' || value === '()') return '()'
|
|
343
|
+
if (value === 'Bool') return 'false'
|
|
344
|
+
if (
|
|
345
|
+
/^(?:U?Int(?:8|16|32|64)?|Float|Double|CGFloat|TimeInterval|NSTimeInterval)$/.test(
|
|
346
|
+
value,
|
|
347
|
+
)
|
|
348
|
+
)
|
|
349
|
+
return '0'
|
|
350
|
+
if (value === 'String') return '""'
|
|
351
|
+
if (value.startsWith('[')) return value.includes(':') ? '[:]' : '[]'
|
|
352
|
+
if (value === 'Any' || value === 'AnyObject') return 'NSObject()'
|
|
353
|
+
const typeId = typeByPath.get(value.replace(`${options.module}.`, ''))
|
|
354
|
+
const symbol = typeId && byId.get(typeId)
|
|
355
|
+
if (typeId && symbol && symbol.kind.identifier === 'swift.enum') {
|
|
356
|
+
const first = membersOf(typeId).find(
|
|
357
|
+
(member) => member.kind.identifier === 'swift.enum.case',
|
|
358
|
+
)
|
|
359
|
+
if (first) return `.${leaf(first).replace(/\(.*/, '')}`
|
|
360
|
+
}
|
|
361
|
+
return `${value}()`
|
|
362
|
+
}
|
|
363
|
+
const inertBody = (symbol: GraphSymbol): string => {
|
|
364
|
+
const declaration = text(symbol)
|
|
365
|
+
if (symbol.kind.identifier === 'swift.init') {
|
|
366
|
+
if (/\bconvenience\b/.test(declaration)) return 'self.init()'
|
|
367
|
+
const parent = owner.get(symbol.identifier.precise)
|
|
368
|
+
return parent && superclass.has(parent) ? 'super.init()' : ''
|
|
369
|
+
}
|
|
370
|
+
const type =
|
|
371
|
+
symbol.kind.identifier.includes('property') ||
|
|
372
|
+
symbol.kind.identifier === 'swift.var'
|
|
373
|
+
? /:\s*(.*?)\s*(?:\{|$)/.exec(declaration)?.[1]
|
|
374
|
+
: symbol.functionSignature?.returns?.map((fragment) => fragment.spelling).join('')
|
|
375
|
+
return type ? `return ${inertValue(type)}` : ''
|
|
376
|
+
}
|
|
377
|
+
|
|
334
378
|
const lines: string[] = []
|
|
335
379
|
const owners: string[] = []
|
|
336
380
|
const omit = options.omit ?? new Map<string, string>()
|
|
@@ -426,7 +470,8 @@ export function emitSwiftStandin(
|
|
|
426
470
|
: /\bResult</.test(core)
|
|
427
471
|
? measured?.resultBody
|
|
428
472
|
: undefined
|
|
429
|
-
const body =
|
|
473
|
+
const body =
|
|
474
|
+
overloadBody ?? measured?.body ?? (options.inert ? inertBody(member) : trap(path))
|
|
430
475
|
switch (member.kind.identifier) {
|
|
431
476
|
case 'swift.property':
|
|
432
477
|
case 'swift.type.property':
|
|
@@ -452,7 +497,7 @@ export function emitSwiftStandin(
|
|
|
452
497
|
return
|
|
453
498
|
}
|
|
454
499
|
emit(
|
|
455
|
-
`${head}${computed} { get${effects} { ${body} }${settable && !effects ? ` ${parsed.nonmutating ? 'nonmutating ' : ''}set { ${measured?.set ?? trap(path)} }` : ''} }`,
|
|
500
|
+
`${head}${computed} { get${effects} { ${body} }${settable && !effects ? ` ${parsed.nonmutating ? 'nonmutating ' : ''}set { ${measured?.set ?? (options.inert ? '' : trap(path))} }` : ''} }`,
|
|
456
501
|
)
|
|
457
502
|
return
|
|
458
503
|
}
|
|
@@ -646,7 +691,7 @@ export function emitSwiftStandin(
|
|
|
646
691
|
externalRoot(id) !== null
|
|
647
692
|
)
|
|
648
693
|
emit(
|
|
649
|
-
`${inner}public required init?(coder: NSCoder) { ${trap(`${path}.init(coder:)`)} }`,
|
|
694
|
+
`${inner}public required init?(coder: NSCoder) { ${options.inert ? 'return nil' : trap(`${path}.init(coder:)`)} }`,
|
|
650
695
|
)
|
|
651
696
|
emit(`${indent}}`)
|
|
652
697
|
return
|
|
@@ -814,7 +859,7 @@ export function emitSwiftStandin(
|
|
|
814
859
|
.replace(/^(?:weak |unowned )/, '')
|
|
815
860
|
.replace(/^((?:static )?)let /, '$1var ')
|
|
816
861
|
const witness = `${owner}.${leaf(member)}`
|
|
817
|
-
const body = trap(witness)
|
|
862
|
+
const body = options.inert ? inertBody(member) : trap(witness)
|
|
818
863
|
if (
|
|
819
864
|
member.kind.identifier === 'swift.property' ||
|
|
820
865
|
member.kind.identifier === 'swift.type.property'
|
|
@@ -872,7 +917,7 @@ export function emitSwiftStandin(
|
|
|
872
917
|
? measured?.resultBody
|
|
873
918
|
: undefined
|
|
874
919
|
emit(
|
|
875
|
-
`${attrs}public ${spelled} { ${overloadBody ?? measured?.body ?? trap(path)} }`,
|
|
920
|
+
`${attrs}public ${spelled} { ${overloadBody ?? measured?.body ?? (options.inert ? inertBody(symbol) : trap(path))} }`,
|
|
876
921
|
)
|
|
877
922
|
} else if (kind === 'swift.var') {
|
|
878
923
|
const parsed = splitAccessors(text(symbol).replace(/^let /, 'var '))
|
|
@@ -882,7 +927,9 @@ export function emitSwiftStandin(
|
|
|
882
927
|
// as `var` with no setter.
|
|
883
928
|
const measured = behavior.get(path)
|
|
884
929
|
if (measured) used.add(path)
|
|
885
|
-
emit(
|
|
930
|
+
emit(
|
|
931
|
+
`public ${parsed.decl} { ${measured?.body ?? (options.inert ? inertBody(symbol) : trap(path))} }`,
|
|
932
|
+
)
|
|
886
933
|
} else skipped.push({ path, reason: `unhandled top-level ${kind}` })
|
|
887
934
|
})
|
|
888
935
|
|
|
@@ -929,8 +976,9 @@ export function emitSwiftStandin(
|
|
|
929
976
|
const imports = [...STANDIN_IMPORTS, ...(options.imports ?? [])]
|
|
930
977
|
const banner = [
|
|
931
978
|
`// stand-in for the binary ${options.module} module, generated from ${options.source}.`,
|
|
932
|
-
|
|
933
|
-
|
|
979
|
+
options.inert
|
|
980
|
+
? '// generated from public headers; native behavior is inert in peach.'
|
|
981
|
+
: '// unconfigured bodies trap because the vendor binary cannot run in peach.',
|
|
934
982
|
'',
|
|
935
983
|
...imports.map((name) => `import ${name}`),
|
|
936
984
|
'',
|