peachsim 0.1.2225 → 0.1.2229
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/cli/bridge-flow-runner.ts +56 -3
- package/cli/commands/control.ts +27 -1
- package/cli/commands/device.ts +1 -1
- package/cli/commands/flow.ts +27 -1
- package/cli/commands/package.ts +9 -2
- package/cli/drivers/playwright.ts +1 -0
- package/cli/drivers/types.ts +3 -0
- 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 +1 -1
- 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 +108 -13
- 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 +5 -2
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +106 -11
- package/dist-lib/expo-swift-metadata.cjs +1 -1
- package/dist-lib/expo-swift-metadata.mjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +108 -13
- package/dist-lib/host/fetch-proxy-handler.cjs +5 -5
- 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 +8 -6
- 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 +16 -14
- package/dist-lib/menu.mjs +16 -14
- 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 +11 -4
- package/dist-lib/metro-production-bundle.mjs +10 -4
- package/dist-lib/metro.cjs +8 -6
- package/dist-lib/native-app-identity-project.cjs +6 -4
- package/dist-lib/native-app-identity-project.mjs +6 -4
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/pdfium-raster.cjs +1 -1
- package/dist-lib/pdfium-raster.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/public-origins-lib-esm.json +25 -24
- package/dist-lib/public-origins-lib.json +56 -53
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/reap-browser.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +183 -27
- package/dist-lib/swift-compile.cjs +68 -4
- package/dist-lib/swift-compile.mjs +67 -4
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift-toolchain.cjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +105 -10
- package/dist-lib/vite.cjs +5 -5
- package/dist-lib/worklet-executable.cjs +1 -1
- package/dist-lib/worklet-executable.mjs +1 -1
- package/dist-types/packages/peach-engine/src/bundle-parse-receipt.d.ts +17 -0
- package/dist-types/packages/peach-engine/src/engine/canvaskit-api.d.ts +5 -1
- package/dist-types/packages/peach-engine/src/engine/font-config.d.ts +2 -2
- package/dist-types/packages/peach-engine/src/engine/native-layout.d.ts +11 -3
- package/dist-types/packages/peach-engine/src/engine/native-paragraph.d.ts +4 -0
- package/dist-types/packages/peach-engine/src/engine/node.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/engine/scene-table.d.ts +1 -1
- package/dist-types/packages/peach-engine/src/engine/types.d.ts +9 -1
- package/dist-types/packages/peach-engine/src/engine/yoga-layout.d.ts +2 -0
- package/dist-types/packages/peach-engine/src/metro-fingerprint.d.ts +3 -2
- package/dist-types/packages/peach-engine/src/render-worker/compositor-protocol.d.ts +1 -0
- package/dist-types/packages/peach-engine/src/render-worker/protocol.d.ts +3 -3
- package/dist-types/packages/peach-engine/src/rolldown-bundle-inventory.d.ts +0 -5
- package/dist-types/packages/peach-kit/src/capabilities.d.ts +2 -0
- package/dist-types/packages/peach-kit/src/internal.d.ts +1 -1
- package/dist-types/packages/peach-kit/src/ios-tint.d.ts +2 -0
- package/kotlin/sdk.tar.gz +0 -0
- package/package.json +1 -1
- package/runtime-companion.json +1 -1
- package/sdk/ios/System/Library/Frameworks/UIKit.framework/Headers/UIControl.h +0 -26
- package/sdk/ios/System/Library/Frameworks/UIKitTypes.framework/Headers/UIKitTypes.h +27 -0
- package/sdk/ios/usr/include/ObjectiveC.apinotes +380 -7
- package/src/appPackageContract.ts +1 -1
- package/src/menu.ts +17 -99
- package/src/menuContract.ts +102 -0
- package/src/metro-production-bundle.ts +15 -2
- package/src/settingsContract.ts +8 -8
- package/src/swift-compile.ts +77 -2
- package/src/swift-host.ts +27 -2
- package/src/swift-standin-emit.ts +1 -0
- package/src/swift-standins.ts +8 -0
- package/src/xcode-project.ts +8 -2
package/src/menu.ts
CHANGED
|
@@ -1,107 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type SootSimMenuPlatform,
|
|
3
|
+
type SootSimScaleMode,
|
|
4
|
+
type SootSimAmbientGlowLevel,
|
|
5
|
+
SOOTSIM_AMBIENT_GLOW_LEVELS,
|
|
6
|
+
SOOTSIM_AMBIENT_GLOW_LABELS,
|
|
7
|
+
type SootSimStageBackground,
|
|
8
|
+
SOOTSIM_STAGE_BACKGROUNDS,
|
|
9
|
+
SOOTSIM_STAGE_BACKGROUND_LABELS,
|
|
10
|
+
type SootSimRenderResolution,
|
|
11
|
+
SOOTSIM_RENDER_RESOLUTION_LEVELS,
|
|
12
|
+
SOOTSIM_RENDER_RESOLUTION_LABELS,
|
|
13
|
+
type SootSimScreenEffect,
|
|
14
|
+
SOOTSIM_SCREEN_EFFECTS,
|
|
15
|
+
SOOTSIM_SCREEN_EFFECT_LABELS,
|
|
16
|
+
} from './menuContract'
|
|
1
17
|
import { rnxPublicBrand } from './public-brand'
|
|
2
18
|
|
|
3
19
|
// public sootsim menu protocol. this file is deliberately pure data and pure
|
|
4
20
|
// functions so hosts can import it without pulling the engine or canvaskit graph.
|
|
5
21
|
|
|
6
|
-
export
|
|
7
|
-
export const SOOTSIM_SHELL_COMMAND_NAME = 'sootsim:shell-command'
|
|
8
|
-
|
|
9
|
-
export type SootSimMenuPlatform = 'browser' | 'electron'
|
|
10
|
-
export type SootSimScaleMode = 'physical' | 'point' | 'pixel' | 'fit'
|
|
11
|
-
|
|
12
|
-
// ambient glow strength. one setting with three states rather than an on/off
|
|
13
|
-
// pair plus a separate strength: every host that carries the preference (the
|
|
14
|
-
// menus, the persisted setting, the ?ambientGlow= boot seed, the live
|
|
15
|
-
// set-ambient-glow push, electron's shared config) then carries exactly one
|
|
16
|
-
// value and cannot end up half-configured.
|
|
17
|
-
export type SootSimAmbientGlowLevel = 'off' | 'soft' | 'full'
|
|
18
|
-
export const SOOTSIM_AMBIENT_GLOW_LEVELS = ['off', 'soft', 'full'] as const
|
|
19
|
-
|
|
20
|
-
export function isSootSimAmbientGlowLevel(
|
|
21
|
-
value: unknown,
|
|
22
|
-
): value is SootSimAmbientGlowLevel {
|
|
23
|
-
return value === 'off' || value === 'soft' || value === 'full'
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const SOOTSIM_AMBIENT_GLOW_LABELS: Record<SootSimAmbientGlowLevel, string> = {
|
|
27
|
-
off: 'Off',
|
|
28
|
-
soft: 'Soft',
|
|
29
|
-
full: 'Full',
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// the stage behind the device: system follows the mac's appearance (white in
|
|
33
|
-
// light mode, black in dark), or one pinned color. one value per host, like
|
|
34
|
-
// the glow level above.
|
|
35
|
-
export type SootSimStageBackground = 'system' | 'light' | 'dark' | 'gray'
|
|
36
|
-
export const SOOTSIM_STAGE_BACKGROUNDS = ['system', 'light', 'dark', 'gray'] as const
|
|
37
|
-
|
|
38
|
-
export function isSootSimStageBackground(
|
|
39
|
-
value: unknown,
|
|
40
|
-
): value is SootSimStageBackground {
|
|
41
|
-
return value === 'system' || value === 'light' || value === 'dark' || value === 'gray'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const SOOTSIM_STAGE_BACKGROUND_LABELS: Record<SootSimStageBackground, string> = {
|
|
45
|
-
system: 'System',
|
|
46
|
-
light: 'Light',
|
|
47
|
-
dark: 'Dark',
|
|
48
|
-
gray: 'Gray',
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// render resolution: how many pixels peach renders per iphone point. one
|
|
52
|
-
// setting with three states, carried by every host exactly like the ambient
|
|
53
|
-
// glow level above: the menus, the persisted setting, the ?renderResolution=
|
|
54
|
-
// boot seed, the live set-render-resolution push, electron's shared config.
|
|
55
|
-
export type SootSimRenderResolution = 'high' | 'medium' | 'low'
|
|
56
|
-
export const SOOTSIM_RENDER_RESOLUTION_LEVELS = ['high', 'medium', 'low'] as const
|
|
57
|
-
|
|
58
|
-
// the installed desktop app presents the phone scaled to fit its window, so a
|
|
59
|
-
// fixed 2 px/pt canvas is browser-resampled and its icons read soft. its
|
|
60
|
-
// default is the level that tracks the pixels on screen; browsers and capture
|
|
61
|
-
// keep medium, whose 2 px/pt is the deterministic capture contract.
|
|
62
|
-
export const DESKTOP_RENDER_RESOLUTION: SootSimRenderResolution = 'low'
|
|
63
|
-
|
|
64
|
-
export function isSootSimRenderResolution(
|
|
65
|
-
value: unknown,
|
|
66
|
-
): value is SootSimRenderResolution {
|
|
67
|
-
return value === 'high' || value === 'medium' || value === 'low'
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const SOOTSIM_RENDER_RESOLUTION_LABELS: Record<SootSimRenderResolution, string> = {
|
|
71
|
-
high: 'High',
|
|
72
|
-
medium: 'Medium',
|
|
73
|
-
low: 'Low',
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// screen effect: the real rendering, or one of the presentation looks the
|
|
77
|
-
// engine's wireframe store draws. 'wireframe' is the clean structural sketch;
|
|
78
|
-
// the others are its screen-space styles that ship as named effects.
|
|
79
|
-
export type SootSimScreenEffect = 'none' | 'wireframe' | 'blueprint' | 'panel' | 'green'
|
|
80
|
-
export const SOOTSIM_SCREEN_EFFECTS = [
|
|
81
|
-
'none',
|
|
82
|
-
'wireframe',
|
|
83
|
-
'blueprint',
|
|
84
|
-
'panel',
|
|
85
|
-
'green',
|
|
86
|
-
] as const
|
|
87
|
-
|
|
88
|
-
export function isSootSimScreenEffect(value: unknown): value is SootSimScreenEffect {
|
|
89
|
-
return (
|
|
90
|
-
value === 'none' ||
|
|
91
|
-
value === 'wireframe' ||
|
|
92
|
-
value === 'blueprint' ||
|
|
93
|
-
value === 'panel' ||
|
|
94
|
-
value === 'green'
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export const SOOTSIM_SCREEN_EFFECT_LABELS: Record<SootSimScreenEffect, string> = {
|
|
99
|
-
none: 'None',
|
|
100
|
-
wireframe: 'Wireframe',
|
|
101
|
-
blueprint: 'Blueprint',
|
|
102
|
-
panel: 'Panel',
|
|
103
|
-
green: 'Green',
|
|
104
|
-
}
|
|
22
|
+
export * from './menuContract'
|
|
105
23
|
|
|
106
24
|
export type SootSimMenuItemDef =
|
|
107
25
|
| { type: 'separator' }
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// the values and event names the menu protocol carries. kept apart from the menu builder so a
|
|
2
|
+
// runtime that only validates a setting or names an event does not carry the menus at boot.
|
|
3
|
+
|
|
4
|
+
export const SOOTSIM_ENGINE_EVENT_NAME = 'sootsim:engine-event'
|
|
5
|
+
export const SOOTSIM_SHELL_COMMAND_NAME = 'sootsim:shell-command'
|
|
6
|
+
|
|
7
|
+
export type SootSimMenuPlatform = 'browser' | 'electron'
|
|
8
|
+
export type SootSimScaleMode = 'physical' | 'point' | 'pixel' | 'fit'
|
|
9
|
+
|
|
10
|
+
// ambient glow strength. one setting with three states rather than an on/off
|
|
11
|
+
// pair plus a separate strength: every host that carries the preference (the
|
|
12
|
+
// menus, the persisted setting, the ?ambientGlow= boot seed, the live
|
|
13
|
+
// set-ambient-glow push, electron's shared config) then carries exactly one
|
|
14
|
+
// value and cannot end up half-configured.
|
|
15
|
+
export type SootSimAmbientGlowLevel = 'off' | 'soft' | 'full'
|
|
16
|
+
export const SOOTSIM_AMBIENT_GLOW_LEVELS = ['off', 'soft', 'full'] as const
|
|
17
|
+
|
|
18
|
+
export function isSootSimAmbientGlowLevel(
|
|
19
|
+
value: unknown,
|
|
20
|
+
): value is SootSimAmbientGlowLevel {
|
|
21
|
+
return value === 'off' || value === 'soft' || value === 'full'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const SOOTSIM_AMBIENT_GLOW_LABELS: Record<SootSimAmbientGlowLevel, string> = {
|
|
25
|
+
off: 'Off',
|
|
26
|
+
soft: 'Soft',
|
|
27
|
+
full: 'Full',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// the stage behind the device: system follows the mac's appearance (white in
|
|
31
|
+
// light mode, black in dark), or one pinned color. one value per host, like
|
|
32
|
+
// the glow level above.
|
|
33
|
+
export type SootSimStageBackground = 'system' | 'light' | 'dark' | 'gray'
|
|
34
|
+
export const SOOTSIM_STAGE_BACKGROUNDS = ['system', 'light', 'dark', 'gray'] as const
|
|
35
|
+
|
|
36
|
+
export function isSootSimStageBackground(
|
|
37
|
+
value: unknown,
|
|
38
|
+
): value is SootSimStageBackground {
|
|
39
|
+
return value === 'system' || value === 'light' || value === 'dark' || value === 'gray'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const SOOTSIM_STAGE_BACKGROUND_LABELS: Record<SootSimStageBackground, string> = {
|
|
43
|
+
system: 'System',
|
|
44
|
+
light: 'Light',
|
|
45
|
+
dark: 'Dark',
|
|
46
|
+
gray: 'Gray',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// render resolution: how many pixels peach renders per iphone point. one
|
|
50
|
+
// setting with three states, carried by every host exactly like the ambient
|
|
51
|
+
// glow level above: the menus, the persisted setting, the ?renderResolution=
|
|
52
|
+
// boot seed, the live set-render-resolution push, electron's shared config.
|
|
53
|
+
export type SootSimRenderResolution = 'high' | 'medium' | 'low'
|
|
54
|
+
export const SOOTSIM_RENDER_RESOLUTION_LEVELS = ['high', 'medium', 'low'] as const
|
|
55
|
+
|
|
56
|
+
// the installed desktop app presents the phone scaled to fit its window, so a
|
|
57
|
+
// fixed 2 px/pt canvas is browser-resampled and its icons read soft. its
|
|
58
|
+
// default is the level that tracks the pixels on screen; browsers and capture
|
|
59
|
+
// keep medium, whose 2 px/pt is the deterministic capture contract.
|
|
60
|
+
export const DESKTOP_RENDER_RESOLUTION: SootSimRenderResolution = 'low'
|
|
61
|
+
|
|
62
|
+
export function isSootSimRenderResolution(
|
|
63
|
+
value: unknown,
|
|
64
|
+
): value is SootSimRenderResolution {
|
|
65
|
+
return value === 'high' || value === 'medium' || value === 'low'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const SOOTSIM_RENDER_RESOLUTION_LABELS: Record<SootSimRenderResolution, string> = {
|
|
69
|
+
high: 'High',
|
|
70
|
+
medium: 'Medium',
|
|
71
|
+
low: 'Low',
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// screen effect: the real rendering, or one of the presentation looks the
|
|
75
|
+
// engine's wireframe store draws. 'wireframe' is the clean structural sketch;
|
|
76
|
+
// the others are its screen-space styles that ship as named effects.
|
|
77
|
+
export type SootSimScreenEffect = 'none' | 'wireframe' | 'blueprint' | 'panel' | 'green'
|
|
78
|
+
export const SOOTSIM_SCREEN_EFFECTS = [
|
|
79
|
+
'none',
|
|
80
|
+
'wireframe',
|
|
81
|
+
'blueprint',
|
|
82
|
+
'panel',
|
|
83
|
+
'green',
|
|
84
|
+
] as const
|
|
85
|
+
|
|
86
|
+
export function isSootSimScreenEffect(value: unknown): value is SootSimScreenEffect {
|
|
87
|
+
return (
|
|
88
|
+
value === 'none' ||
|
|
89
|
+
value === 'wireframe' ||
|
|
90
|
+
value === 'blueprint' ||
|
|
91
|
+
value === 'panel' ||
|
|
92
|
+
value === 'green'
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const SOOTSIM_SCREEN_EFFECT_LABELS: Record<SootSimScreenEffect, string> = {
|
|
97
|
+
none: 'None',
|
|
98
|
+
wireframe: 'Wireframe',
|
|
99
|
+
blueprint: 'Blueprint',
|
|
100
|
+
panel: 'Panel',
|
|
101
|
+
green: 'Green',
|
|
102
|
+
}
|
|
@@ -394,7 +394,14 @@ export async function validateRNXMetroModulePaths(
|
|
|
394
394
|
source: string,
|
|
395
395
|
modulePaths: RNXMetroModulePathMap,
|
|
396
396
|
): Promise<void> {
|
|
397
|
-
|
|
397
|
+
checkRNXMetroModulePaths(await readRNXMetroBundleLayout(source), modulePaths)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** the identity contract against a layout the caller already read. */
|
|
401
|
+
export function checkRNXMetroModulePaths(
|
|
402
|
+
layout: RNXMetroBundleLayout,
|
|
403
|
+
modulePaths: RNXMetroModulePathMap,
|
|
404
|
+
): void {
|
|
398
405
|
if (layout.moduleIdFailures > 0) {
|
|
399
406
|
throw new Error(
|
|
400
407
|
`Metro module identity could not read ${layout.moduleIdFailures} module IDs`,
|
|
@@ -431,8 +438,14 @@ export async function validateRNXMetroModulePaths(
|
|
|
431
438
|
|
|
432
439
|
export async function validateRNXMetroModuleIdentity(
|
|
433
440
|
identity: RNXMetroModuleIdentity,
|
|
441
|
+
// the layout of the bundle this identity was read from. its footers follow
|
|
442
|
+
// the graph and register nothing, so its defines are the identity source's.
|
|
443
|
+
layout?: RNXMetroBundleLayout,
|
|
434
444
|
): Promise<void> {
|
|
435
|
-
|
|
445
|
+
checkRNXMetroModulePaths(
|
|
446
|
+
layout ?? (await readRNXMetroBundleLayout(identity.source)),
|
|
447
|
+
identity.modulePaths,
|
|
448
|
+
)
|
|
436
449
|
for (const moduleId of Object.keys(identity.logicalSpecifiers)) {
|
|
437
450
|
if (!Object.prototype.hasOwnProperty.call(identity.modulePaths, moduleId)) {
|
|
438
451
|
throw new Error(
|
package/src/settingsContract.ts
CHANGED
|
@@ -2,14 +2,6 @@ import {
|
|
|
2
2
|
DEFAULT_PROFILER_CATEGORIES,
|
|
3
3
|
formatProfilerCategories,
|
|
4
4
|
} from '@peach/globals/profiler'
|
|
5
|
-
import {
|
|
6
|
-
SOOTSIM_AMBIENT_GLOW_LEVELS,
|
|
7
|
-
SOOTSIM_RENDER_RESOLUTION_LEVELS,
|
|
8
|
-
SOOTSIM_STAGE_BACKGROUNDS,
|
|
9
|
-
type SootSimAmbientGlowLevel,
|
|
10
|
-
type SootSimRenderResolution,
|
|
11
|
-
type SootSimStageBackground,
|
|
12
|
-
} from 'peachsim/menu'
|
|
13
5
|
import {
|
|
14
6
|
type DeviceModel,
|
|
15
7
|
type DevicePosture,
|
|
@@ -19,6 +11,14 @@ import {
|
|
|
19
11
|
DYNAMIC_WINDOW_LIMITS,
|
|
20
12
|
devices,
|
|
21
13
|
} from './device-catalog.ts'
|
|
14
|
+
import {
|
|
15
|
+
SOOTSIM_AMBIENT_GLOW_LEVELS,
|
|
16
|
+
SOOTSIM_RENDER_RESOLUTION_LEVELS,
|
|
17
|
+
SOOTSIM_STAGE_BACKGROUNDS,
|
|
18
|
+
type SootSimAmbientGlowLevel,
|
|
19
|
+
type SootSimRenderResolution,
|
|
20
|
+
type SootSimStageBackground,
|
|
21
|
+
} from './menuContract'
|
|
22
22
|
import { DEFAULT_REACT_NATIVE_CONFIGURATION } from './reactNativeConfigurationContract.ts'
|
|
23
23
|
import {
|
|
24
24
|
BACKGROUND_PRESET_NAMES,
|
package/src/swift-compile.ts
CHANGED
|
@@ -437,6 +437,26 @@ const clangInterfaceHeader = (header: string): string =>
|
|
|
437
437
|
.replace(/\b_TtC10Foundation\d+(NS\w+)\b/g, '$1')
|
|
438
438
|
.replace(/\b__attribute__\(\(objc_subclassing_restricted\)\)\s*/g, '')
|
|
439
439
|
|
|
440
|
+
export function swiftHeaderWithSuperclassImports(
|
|
441
|
+
header: string,
|
|
442
|
+
interfaceFor: (name: string) => { file: string; header: string } | null,
|
|
443
|
+
): string {
|
|
444
|
+
const superclasses = new Set(
|
|
445
|
+
[...header.matchAll(/@interface\s+\w+\s*:\s*(\w+)/g)].map((match) => match[1]!),
|
|
446
|
+
)
|
|
447
|
+
return header.replace(/^@import (\w+);$/gm, (statement, name: string) => {
|
|
448
|
+
const dependency = interfaceFor(name)
|
|
449
|
+
if (
|
|
450
|
+
!dependency ||
|
|
451
|
+
![...swiftInterfaceDeclarations(dependency.header)].some((name) =>
|
|
452
|
+
superclasses.has(name),
|
|
453
|
+
)
|
|
454
|
+
)
|
|
455
|
+
return statement
|
|
456
|
+
return `${statement}\n#import ${JSON.stringify(dependency.file)}`
|
|
457
|
+
})
|
|
458
|
+
}
|
|
459
|
+
|
|
440
460
|
/** the Objective-C protocols and classes a generated interface header defines. */
|
|
441
461
|
export const swiftInterfaceDeclarations = (header: string): Set<string> =>
|
|
442
462
|
new Set([
|
|
@@ -908,7 +928,7 @@ export function swiftOptionalFramework(name: string): boolean {
|
|
|
908
928
|
// an import may carry attributes (`@_exported`, `@preconcurrency`) and a
|
|
909
929
|
// declaration kind (`import struct Nuke.ImageRequest`).
|
|
910
930
|
const SWIFT_IMPORT =
|
|
911
|
-
/^\s*(?:@\w+(?:\([^)]*\))?\s+)*import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?([A-Za-z_][A-Za-z0-9_]*)/
|
|
931
|
+
/^\s*(?:@\w+(?:\([^)]*\))?\s+|(?:public|package|internal|fileprivate|private)\s+)*import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?([A-Za-z_][A-Za-z0-9_]*)/
|
|
912
932
|
|
|
913
933
|
// three-valued (kleene) logic shared by the swift and c condition
|
|
914
934
|
// evaluators: an undecided operand only decides when the other forces the
|
|
@@ -7437,6 +7457,58 @@ function compileSwiftProjectOnce(
|
|
|
7437
7457
|
if (existsSync(linked) && statSync(linked).size <= 8)
|
|
7438
7458
|
rmSync(linked, { force: true })
|
|
7439
7459
|
report('compiling and linking Swift modules')
|
|
7460
|
+
const frameworkInterfaces = new Map<
|
|
7461
|
+
string,
|
|
7462
|
+
{ file: string; header: string } | null
|
|
7463
|
+
>()
|
|
7464
|
+
const frameworkInterface = (
|
|
7465
|
+
name: string,
|
|
7466
|
+
): { file: string; header: string } | null => {
|
|
7467
|
+
if (frameworkInterfaces.has(name)) return frameworkInterfaces.get(name)!
|
|
7468
|
+
const source = distribution
|
|
7469
|
+
? path.join(frameworkRoot, 'modules', `${name}-Swift.h`)
|
|
7470
|
+
: path.join(
|
|
7471
|
+
prebuilt!.modules,
|
|
7472
|
+
'..',
|
|
7473
|
+
`${name}.build/include/${name}-Swift.h`,
|
|
7474
|
+
)
|
|
7475
|
+
if (!existsSync(source)) {
|
|
7476
|
+
frameworkInterfaces.set(name, null)
|
|
7477
|
+
return null
|
|
7478
|
+
}
|
|
7479
|
+
const headers = path.join(
|
|
7480
|
+
swiftSdkPaths(frameworkRoot, options.toolchainBin).darwin,
|
|
7481
|
+
`System/Library/Frameworks/${name}.framework/Headers`,
|
|
7482
|
+
)
|
|
7483
|
+
const declared = new Set<string>()
|
|
7484
|
+
if (existsSync(headers))
|
|
7485
|
+
for (const file of readdirSync(headers, {
|
|
7486
|
+
recursive: true,
|
|
7487
|
+
encoding: 'utf8',
|
|
7488
|
+
}))
|
|
7489
|
+
if (file.endsWith('.h'))
|
|
7490
|
+
for (const name of swiftInterfaceDeclarations(
|
|
7491
|
+
readFileSync(path.join(headers, file), 'utf8'),
|
|
7492
|
+
))
|
|
7493
|
+
declared.add(name)
|
|
7494
|
+
const header = withoutSwiftDeclarations(
|
|
7495
|
+
clangInterfaceHeader(readFileSync(source, 'utf8')),
|
|
7496
|
+
declared,
|
|
7497
|
+
`#import <${name}/${name}.h>`,
|
|
7498
|
+
)
|
|
7499
|
+
const value = {
|
|
7500
|
+
file: path.join(root, '.build/peach-framework-objc', `${name}-Swift.h`),
|
|
7501
|
+
header,
|
|
7502
|
+
}
|
|
7503
|
+
frameworkInterfaces.set(name, value)
|
|
7504
|
+
writeBuildFile(
|
|
7505
|
+
value.file,
|
|
7506
|
+
(existsSync(path.join(headers, `${name}.h`))
|
|
7507
|
+
? `#import <${name}/${name}.h>\n`
|
|
7508
|
+
: '') + swiftHeaderWithSuperclassImports(header, frameworkInterface),
|
|
7509
|
+
)
|
|
7510
|
+
return value
|
|
7511
|
+
}
|
|
7440
7512
|
try {
|
|
7441
7513
|
// clang consumes the real emitted headers after swift finishes.
|
|
7442
7514
|
// swiftpm's transitive swift module maps are not C declarations:
|
|
@@ -7475,7 +7547,10 @@ function compileSwiftProjectOnce(
|
|
|
7475
7547
|
writeBuildFile(
|
|
7476
7548
|
emitted,
|
|
7477
7549
|
withoutSwiftDeclarations(
|
|
7478
|
-
|
|
7550
|
+
swiftHeaderWithSuperclassImports(
|
|
7551
|
+
clangInterfaceHeader(readFileSync(original, 'utf8')),
|
|
7552
|
+
frameworkInterface,
|
|
7553
|
+
),
|
|
7479
7554
|
new Set(preparation.nativeHeaderDeclarations[producer]),
|
|
7480
7555
|
`#import <${producer}/${producer}.h>`,
|
|
7481
7556
|
),
|
package/src/swift-host.ts
CHANGED
|
@@ -132,8 +132,10 @@ import {
|
|
|
132
132
|
} from './swiftContract'
|
|
133
133
|
import {
|
|
134
134
|
enclosingXcodeWorkspace,
|
|
135
|
+
expandXcodeBuildSetting,
|
|
135
136
|
readXcodeAppTarget,
|
|
136
137
|
resolveXcodeSwiftPackages,
|
|
138
|
+
xcodeFileListEntries,
|
|
137
139
|
type XcodeAppTarget,
|
|
138
140
|
type XcodeModuleTarget,
|
|
139
141
|
} from './xcode-project'
|
|
@@ -2312,11 +2314,34 @@ export function buildSwiftBundleFiles(
|
|
|
2312
2314
|
CONTENTS_FOLDER_PATH: wrapper,
|
|
2313
2315
|
UNLOCALIZED_RESOURCES_FOLDER_PATH: wrapper,
|
|
2314
2316
|
INFOPLIST_PATH: `${wrapper}/Info.plist`,
|
|
2315
|
-
SCRIPT_INPUT_FILE_COUNT:
|
|
2316
|
-
SCRIPT_INPUT_FILE_LIST_COUNT:
|
|
2317
|
+
SCRIPT_INPUT_FILE_COUNT: String(phase.inputPaths.length),
|
|
2318
|
+
SCRIPT_INPUT_FILE_LIST_COUNT: String(phase.inputFileListPaths.length),
|
|
2317
2319
|
SCRIPT_OUTPUT_FILE_COUNT: '0',
|
|
2318
2320
|
SCRIPT_OUTPUT_FILE_LIST_COUNT: '0',
|
|
2319
2321
|
}
|
|
2322
|
+
const inputPath = (raw: string) => {
|
|
2323
|
+
const file = path.resolve(
|
|
2324
|
+
phase.directory,
|
|
2325
|
+
expandXcodeBuildSetting(raw, (key) => env[key] ?? ''),
|
|
2326
|
+
)
|
|
2327
|
+
if (!fs.existsSync(file))
|
|
2328
|
+
throw new Error(
|
|
2329
|
+
`${xcode.app.name}: Run Script "${phase.name}" missing input ${file}`,
|
|
2330
|
+
)
|
|
2331
|
+
if (!file.startsWith(`${dir}${path.sep}`))
|
|
2332
|
+
watched.push(path.relative(packagePath, file).split(path.sep).join('/'))
|
|
2333
|
+
return file
|
|
2334
|
+
}
|
|
2335
|
+
phase.inputPaths.forEach((raw, index) => {
|
|
2336
|
+
env[`SCRIPT_INPUT_FILE_${index}`] = inputPath(raw)
|
|
2337
|
+
})
|
|
2338
|
+
phase.inputFileListPaths.forEach((raw, index) => {
|
|
2339
|
+
const source = inputPath(raw)
|
|
2340
|
+
const entries = xcodeFileListEntries(source, inputPath)
|
|
2341
|
+
const expanded = path.join(dir, `Input-${index}.xcfilelist`)
|
|
2342
|
+
fs.writeFileSync(expanded, `${entries.join('\n')}\n`)
|
|
2343
|
+
env[`SCRIPT_INPUT_FILE_LIST_${index}`] = expanded
|
|
2344
|
+
})
|
|
2320
2345
|
try {
|
|
2321
2346
|
const [shell, ...args] = phase.command
|
|
2322
2347
|
execFileSync(shell, args, {
|
|
@@ -1529,6 +1529,7 @@ export function emitSwiftStandin(
|
|
|
1529
1529
|
].includes(name)
|
|
1530
1530
|
) &&
|
|
1531
1531
|
!(name === nsObjectProtocol && externalRoot(id) === nsObject) &&
|
|
1532
|
+
!options.unconformed?.get(path)?.has(name.split(/::|\./).pop()!) &&
|
|
1532
1533
|
!options.unconformed?.get(path)?.has(name),
|
|
1533
1534
|
),
|
|
1534
1535
|
].filter((name, at, all) => all.indexOf(name) === at)
|
package/src/swift-standins.ts
CHANGED
|
@@ -1703,6 +1703,14 @@ function graphStandin(
|
|
|
1703
1703
|
unconformed.set(owner, new Set([...(unconformed.get(owner) ?? []), conformance]))
|
|
1704
1704
|
continue
|
|
1705
1705
|
}
|
|
1706
|
+
// a superclass another module declares already brings this conformance
|
|
1707
|
+
const redundant = /^redundant conformance of '\w+' to protocol '(\w+)'$/.exec(
|
|
1708
|
+
match[3]!,
|
|
1709
|
+
)?.[1]
|
|
1710
|
+
if (owner && redundant) {
|
|
1711
|
+
unconformed.set(owner, new Set([...(unconformed.get(owner) ?? []), redundant]))
|
|
1712
|
+
continue
|
|
1713
|
+
}
|
|
1706
1714
|
if (owner && swiftPaths.has(owner))
|
|
1707
1715
|
throw new Error(
|
|
1708
1716
|
`Swift declaration ${module}.${owner} does not typecheck: ${match[3]}`,
|
package/src/xcode-project.ts
CHANGED
|
@@ -180,6 +180,8 @@ export interface XcodeAppTarget extends XcodeModuleTarget {
|
|
|
180
180
|
command: [string, ...string[]]
|
|
181
181
|
directory: string
|
|
182
182
|
environment: Record<string, string>
|
|
183
|
+
inputPaths: string[]
|
|
184
|
+
inputFileListPaths: string[]
|
|
183
185
|
}[]
|
|
184
186
|
appIconName: string
|
|
185
187
|
/** the app project PBXProject developmentRegion, xcode's "en" when it declares none. */
|
|
@@ -890,6 +892,8 @@ function compilationConditions(settings: (key: string) => string): string[] {
|
|
|
890
892
|
]
|
|
891
893
|
}
|
|
892
894
|
|
|
895
|
+
export { expand as expandXcodeBuildSetting }
|
|
896
|
+
|
|
893
897
|
function expand(value: string, lookup: (name: string) => string): string {
|
|
894
898
|
return value.replace(
|
|
895
899
|
/\$(?:\(([A-Za-z_][A-Za-z0-9_]*)((?::[^)]*)?)\)|\{([A-Za-z_][A-Za-z0-9_]*)((?::[^}]*)?)\}|([A-Za-z_][A-Za-z0-9_]*))/g,
|
|
@@ -1013,6 +1017,8 @@ function shellCopies(
|
|
|
1013
1017
|
}
|
|
1014
1018
|
|
|
1015
1019
|
// an xcfilelist names one path per line; blank lines and comments are skipped.
|
|
1020
|
+
export { fileListEntries as xcodeFileListEntries }
|
|
1021
|
+
|
|
1016
1022
|
function fileListEntries(file: string, absolute: (raw: string) => string): string[] {
|
|
1017
1023
|
return fs
|
|
1018
1024
|
.readFileSync(file, 'utf8')
|
|
@@ -2851,8 +2857,6 @@ export function readXcodeAppTarget(
|
|
|
2851
2857
|
const phase = app.project.object(id)
|
|
2852
2858
|
if (
|
|
2853
2859
|
phase?.isa !== 'PBXShellScriptBuildPhase' ||
|
|
2854
|
-
list(phase.inputPaths).length ||
|
|
2855
|
-
list(phase.inputFileListPaths).length ||
|
|
2856
2860
|
list(phase.outputPaths).length ||
|
|
2857
2861
|
list(phase.outputFileListPaths).length
|
|
2858
2862
|
)
|
|
@@ -2864,6 +2868,8 @@ export function readXcodeAppTarget(
|
|
|
2864
2868
|
str(phase.shellScript) ?? '',
|
|
2865
2869
|
),
|
|
2866
2870
|
directory: app.project.projectDir,
|
|
2871
|
+
inputPaths: list(phase.inputPaths),
|
|
2872
|
+
inputFileListPaths: list(phase.inputFileListPaths),
|
|
2867
2873
|
environment: Object.fromEntries(
|
|
2868
2874
|
[...settingKeys]
|
|
2869
2875
|
.filter((key) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|