peachsim 0.1.637 → 0.1.639
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 +8 -5
- package/cli/bridge-flow-runner.ts +442 -14
- package/cli/command-registry.ts +1 -0
- package/cli/commands/control.ts +42 -5
- package/cli/commands/inspect/core.ts +93 -24
- package/cli/commands/maestro.ts +2 -2
- package/cli/commands/serve.ts +13 -1
- package/cli/commands/swift.ts +326 -0
- package/cli/drivers/playwright-provisioning.ts +8 -16
- package/cli/drivers/playwright-sim-host.ts +3 -0
- package/cli/drivers/playwright.ts +1 -0
- package/cli/internal-child.ts +51 -8
- package/cli/main.ts +11 -0
- package/cli/outbound-endpoints.ts +5 -1
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.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 +3 -2
- package/dist-lib/bridge-contract-input.mjs +3 -2
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +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/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +4 -2
- 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 +88 -23
- 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 +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.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 +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +78 -20
- package/dist-lib/sdk.mjs +77 -20
- package/dist-lib/skills.cjs +441 -94
- package/dist-lib/swift-compile.cjs +89 -7
- package/dist-lib/swift-compile.mjs +89 -7
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +89 -8
- package/dist-lib/swift-submit.mjs +78 -8
- package/dist-lib/swift.cjs +16 -33220
- package/dist-lib/vite-swift.cjs +510 -253
- package/dist-lib/vite.cjs +13 -4
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +1 -0
- package/src/assetCatalogContract.ts +16 -0
- package/src/bridge-contract-input.ts +3 -2
- package/src/bridge-contract.ts +8 -0
- package/src/host/bridge-host.ts +5 -5
- package/src/metro-runtime-source.ts +15 -0
- package/src/native-seam-manifest.ts +4 -6
- package/src/swift-compile.ts +105 -9
- package/src/swift-guest.ts +51 -0
- package/src/swift-host.ts +900 -0
- package/src/swift-submit.ts +97 -6
- package/src/swift.ts +36 -8
- package/src/swiftContract.ts +52 -0
- package/src/vite-plugin-one.ts +4 -3
- package/src/vite-plugin-swift.ts +43 -755
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.639 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -801,8 +801,16 @@ function streamFile(res, stream) {
|
|
|
801
801
|
stream.pipe(res);
|
|
802
802
|
}
|
|
803
803
|
|
|
804
|
-
// src/
|
|
804
|
+
// src/swift-submit.ts
|
|
805
|
+
var SWIFT_PACKAGE_PATH = "/__peach/swift-package/";
|
|
805
806
|
var SWIFT_HMR_PATH = "/__peach/swift-hmr";
|
|
807
|
+
var MAX_SWIFT_COMPILE_SOURCE_BYTES = 2 * 1024 * 1024;
|
|
808
|
+
var MAX_SWIFT_COMPILE_RESOURCE_BYTES = 2 * 1024 * 1024;
|
|
809
|
+
var MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
810
|
+
var MAX_SWIFT_COMPILE_IMAGE_BYTES = 4 * 1024 * 1024;
|
|
811
|
+
var MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES = 16 * 1024 * 1024;
|
|
812
|
+
|
|
813
|
+
// src/vite-plugin-one.ts
|
|
806
814
|
var SWIFT_ROUTE_PREFIX = "/__peach/swift";
|
|
807
815
|
var swiftHost;
|
|
808
816
|
var loadSwiftHost = () => swiftHost ??= import("peachsim/vite-swift");
|
|
@@ -904,7 +912,8 @@ function rnxPlugin(options = {}) {
|
|
|
904
912
|
if (!served) next();
|
|
905
913
|
}).catch(next);
|
|
906
914
|
});
|
|
907
|
-
server.watcher.on("
|
|
915
|
+
server.watcher.on("all", (event, file) => {
|
|
916
|
+
if (event !== "add" && event !== "unlink" && event !== "change") return;
|
|
908
917
|
if (activeSwiftPackages.size === 0) return;
|
|
909
918
|
const moduleRoot = moduleRootFor();
|
|
910
919
|
let packages;
|
|
@@ -952,7 +961,7 @@ function rnxPlugin(options = {}) {
|
|
|
952
961
|
if (!pathname.startsWith(SWIFT_ROUTE_PREFIX)) return next();
|
|
953
962
|
loadSwiftHost().then((host) => {
|
|
954
963
|
if (host.serveSwiftPackageAsset(pathname, res)) return;
|
|
955
|
-
const prefix2 =
|
|
964
|
+
const prefix2 = SWIFT_PACKAGE_PATH;
|
|
956
965
|
if (!pathname.startsWith(prefix2)) return next();
|
|
957
966
|
if (!swiftSockets) {
|
|
958
967
|
res.statusCode = 501;
|
package/package.json
CHANGED
package/skills/contrast/SKILL.md
CHANGED
|
@@ -19,6 +19,7 @@ automation, inspecting the render tree, and managing sims.
|
|
|
19
19
|
|
|
20
20
|
| command | description |
|
|
21
21
|
| --- | --- |
|
|
22
|
+
| `peach swift` | preview a SwiftPM app with hosted compilation and live Swift edits |
|
|
22
23
|
| `peach maestro` | author, generate, and run Maestro YAML flows against peach |
|
|
23
24
|
| `peach detox` | run existing Detox suites against peach on headless Chromium |
|
|
24
25
|
| `peach cleanup` | inspect and reclaim local peach disk usage |
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// the asset data exchanged by project hosts and the private renderer.
|
|
2
|
+
export interface SwiftImageSource {
|
|
3
|
+
uri: string
|
|
4
|
+
scale: number
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// an app catalog color resolves by appearance or names a system color.
|
|
8
|
+
export type AppCatalogColor = { light: string; dark: string } | { system: string }
|
|
9
|
+
|
|
10
|
+
export interface SfSymbolVector {
|
|
11
|
+
viewBox: '0 0 24 24'
|
|
12
|
+
advance: number
|
|
13
|
+
box?: readonly [number, number, number, number]
|
|
14
|
+
controlBoxes?: Record<string, readonly [number, number, number]>
|
|
15
|
+
layers: readonly { d: string; color?: string }[]
|
|
16
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SIM_LONG_PRESS_MAX_MS } from './bridge-contract'
|
|
2
|
+
import { isRecord } from './is-record'
|
|
2
3
|
// untrusted JSON -> bridge-contract argument. one owner for that conversion, so
|
|
3
4
|
// every transport in front of a sim (the Peach Cloud sim service's HTTP and
|
|
4
5
|
// WebSocket routes) validates its request bodies here rather than growing a
|
|
@@ -13,7 +14,6 @@ import type {
|
|
|
13
14
|
} from './bridge-contract'
|
|
14
15
|
import type { SimPerformStep, SimScreenshotOptions } from './sim-client'
|
|
15
16
|
import type { SootSimReplayTarget } from '@peach/globals'
|
|
16
|
-
import { isRecord } from './is-record'
|
|
17
17
|
|
|
18
18
|
/** the caller sent a value this bridge argument cannot be read from. */
|
|
19
19
|
export class BridgeInputError extends Error {
|
|
@@ -371,6 +371,7 @@ export function parseSemanticQuery(value: unknown): SimSemanticQuery {
|
|
|
371
371
|
const query = recordValue(value, 'query')
|
|
372
372
|
const kind = stringValue(query.kind, 'query.kind')
|
|
373
373
|
if (kind === 'count') return { kind }
|
|
374
|
+
if (kind === 'accessibility') return { kind }
|
|
374
375
|
if (kind === 'tree') {
|
|
375
376
|
const depth = optionalNumber(query, 'depth', 'query')
|
|
376
377
|
return { kind, ...(depth === undefined ? {} : { depth }) }
|
|
@@ -378,7 +379,7 @@ export function parseSemanticQuery(value: unknown): SimSemanticQuery {
|
|
|
378
379
|
if (kind === 'find') {
|
|
379
380
|
return { kind, selector: parseSemanticSelector(query.selector, 'query.selector') }
|
|
380
381
|
}
|
|
381
|
-
return validationFailure('query.kind', 'must be tree, find, or
|
|
382
|
+
return validationFailure('query.kind', 'must be tree, find, count, or accessibility')
|
|
382
383
|
}
|
|
383
384
|
|
|
384
385
|
function semanticResolveSelector(
|
package/src/bridge-contract.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// this is the direction that ships.
|
|
10
10
|
|
|
11
11
|
import type {
|
|
12
|
+
PeachAccessibilityNode,
|
|
12
13
|
SootSimAgentActionDetail,
|
|
13
14
|
SootSimCaptureFilter,
|
|
14
15
|
SootSimExternalAppLifecycleOptions,
|
|
@@ -489,10 +490,17 @@ export type SimSemanticQuery =
|
|
|
489
490
|
| { kind: 'tree'; depth?: number }
|
|
490
491
|
| { kind: 'find'; selector: SimSemanticSelector }
|
|
491
492
|
| { kind: 'count' }
|
|
493
|
+
// the XCTest accessibility projection. it is not a SimSemanticNode tree, so
|
|
494
|
+
// the snapshot rides in `accessibility` and `nodes` stays empty.
|
|
495
|
+
| { kind: 'accessibility' }
|
|
492
496
|
|
|
493
497
|
export interface SimSemanticQueryResult {
|
|
494
498
|
nodes: SimSemanticNode[]
|
|
495
499
|
total: number
|
|
500
|
+
// present only for { kind: 'accessibility' }: the engine's recursive
|
|
501
|
+
// accessibility snapshot (PeachAccessibilityNode), the same tree the
|
|
502
|
+
// Maestro structural selectors resolve against.
|
|
503
|
+
accessibility?: PeachAccessibilityNode[]
|
|
496
504
|
}
|
|
497
505
|
|
|
498
506
|
export type SimSemanticResolveSelector = { testID: string } | { text: string }
|
package/src/host/bridge-host.ts
CHANGED
|
@@ -229,6 +229,8 @@ interface BridgeForwardedCommand {
|
|
|
229
229
|
export interface BridgeHostOptions {
|
|
230
230
|
/** use 0 for an OS-assigned port; startAsync returns the bound address. */
|
|
231
231
|
port?: number
|
|
232
|
+
/** listener address; defaults to 127.0.0.1. */
|
|
233
|
+
host?: string
|
|
232
234
|
openUrl?: (url: string, options?: OpenUrlOptions) => Promise<void> | void
|
|
233
235
|
/** Contrast-specific excludes for the agent host's dev-server scan. passed
|
|
234
236
|
* through to AgentHost; see packages/peach-engine/src/dev-scan-excludes.ts
|
|
@@ -404,6 +406,7 @@ export class SootSimBridgeHost {
|
|
|
404
406
|
// of reconnecting the zombie straight back in.
|
|
405
407
|
private static SIM_IDLE_REAP_TTL_MS = 30 * 60_000
|
|
406
408
|
|
|
409
|
+
private bindHost: string
|
|
407
410
|
private preferredPort: number
|
|
408
411
|
private portFallbackCount: number
|
|
409
412
|
private shouldWriteLockfile: boolean
|
|
@@ -438,6 +441,7 @@ export class SootSimBridgeHost {
|
|
|
438
441
|
private static SCAN_FRESH_MS = 2000
|
|
439
442
|
|
|
440
443
|
constructor(opts: BridgeHostOptions = {}) {
|
|
444
|
+
this.bindHost = opts.host ?? '127.0.0.1'
|
|
441
445
|
this.preferredPort = opts.port ?? DEFAULT_SOOTSIM_BRIDGE_PORT
|
|
442
446
|
this.port = this.preferredPort
|
|
443
447
|
// default off — callers that want the lockfile (peach serve) opt in.
|
|
@@ -533,11 +537,7 @@ export class SootSimBridgeHost {
|
|
|
533
537
|
}
|
|
534
538
|
server.once('error', onError)
|
|
535
539
|
|
|
536
|
-
|
|
537
|
-
// daemon serves the active runtime's dist as plain static files —
|
|
538
|
-
// never expose that to LAN peers. tests + the electron renderer use
|
|
539
|
-
// 127.0.0.1 explicitly to avoid the localhost-vs-::1 DNS coinflip.
|
|
540
|
-
server.listen(port, '127.0.0.1', () => {
|
|
540
|
+
server.listen(port, this.bindHost, () => {
|
|
541
541
|
if (settled) return
|
|
542
542
|
const address = server.address()
|
|
543
543
|
if (!address || typeof address === 'string') {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// GENERATED by scripts/generate-runtime-source.ts — do not edit.
|
|
2
|
+
// verbatim metro-runtime@0.84.4 sources, inlined so the worker never touches a filesystem.
|
|
3
|
+
|
|
4
|
+
export const METRO_RUNTIME_VERSION = '0.84.4'
|
|
5
|
+
|
|
6
|
+
// metro-runtime/src/polyfills/require.js — defines global.__d / __r / __c / __accept
|
|
7
|
+
export const METRO_REQUIRE_POLYFILL =
|
|
8
|
+
'"use strict";\n\nglobal.__r = metroRequire;\nglobal[`${__METRO_GLOBAL_PREFIX__}__d`] = define;\nglobal.__c = clear;\nglobal.__registerSegment = registerSegment;\nvar modules = clear();\nconst EMPTY = {};\nconst CYCLE_DETECTED = {};\nconst { hasOwnProperty } = {};\nif (__DEV__) {\n global.$RefreshReg$ = global.$RefreshReg$ ?? (() => {});\n global.$RefreshSig$ = global.$RefreshSig$ ?? (() => (type) => type);\n}\nfunction clear() {\n modules = new Map();\n return modules;\n}\nif (__DEV__) {\n var verboseNamesToModuleIds = new Map();\n var getModuleIdForVerboseName = (verboseName) => {\n const moduleId = verboseNamesToModuleIds.get(verboseName);\n if (moduleId == null) {\n throw new Error(`Unknown named module: "${verboseName}"`);\n }\n return moduleId;\n };\n var initializingModuleIds = [];\n}\nfunction define(factory, moduleId, dependencyMap) {\n if (modules.has(moduleId)) {\n if (__DEV__) {\n const inverseDependencies = arguments[4];\n if (inverseDependencies) {\n global.__accept(moduleId, factory, dependencyMap, inverseDependencies);\n }\n }\n return;\n }\n const mod = {\n dependencyMap,\n factory,\n hasError: false,\n importedAll: EMPTY,\n importedDefault: EMPTY,\n isInitialized: false,\n publicModule: {\n exports: {},\n },\n };\n modules.set(moduleId, mod);\n if (__DEV__) {\n mod.hot = createHotReloadingObject();\n const verboseName = arguments[3];\n if (verboseName) {\n mod.verboseName = verboseName;\n verboseNamesToModuleIds.set(verboseName, moduleId);\n }\n }\n}\nfunction metroRequire(moduleId, maybeNameForDev) {\n if (moduleId === null) {\n if (__DEV__ && typeof maybeNameForDev === "string") {\n throw new Error("Cannot find module \'" + maybeNameForDev + "\'");\n }\n throw new Error("Cannot find module");\n }\n if (__DEV__ && typeof moduleId === "string") {\n const verboseName = moduleId;\n moduleId = getModuleIdForVerboseName(verboseName);\n console.warn(\n `Requiring module "${verboseName}" by name is only supported for ` +\n "debugging purposes and will BREAK IN PRODUCTION!",\n );\n }\n const moduleIdReallyIsNumber = moduleId;\n if (__DEV__) {\n const initializingIndex = initializingModuleIds.indexOf(\n moduleIdReallyIsNumber,\n );\n if (initializingIndex !== -1) {\n const cycle = initializingModuleIds\n .slice(initializingIndex)\n .map((id) => modules.get(id)?.verboseName ?? "[unknown]");\n if (shouldPrintRequireCycle(cycle)) {\n cycle.push(cycle[0]);\n console.warn(\n `Require cycle: ${cycle.join(" -> ")}\\n\\n` +\n "Require cycles are allowed, but can result in uninitialized values. " +\n "Consider refactoring to remove the need for a cycle.",\n );\n }\n }\n }\n const module = modules.get(moduleIdReallyIsNumber);\n return module && module.isInitialized\n ? module.publicModule.exports\n : guardedLoadModule(moduleIdReallyIsNumber, module);\n}\nfunction shouldPrintRequireCycle(modules) {\n const regExps =\n global[__METRO_GLOBAL_PREFIX__ + "__requireCycleIgnorePatterns"];\n if (!Array.isArray(regExps)) {\n return true;\n }\n const isIgnored = (module) =>\n module != null && regExps.some((regExp) => regExp.test(module));\n return modules.every((module) => !isIgnored(module));\n}\nfunction metroImportDefault(moduleId) {\n if (__DEV__ && typeof moduleId === "string") {\n const verboseName = moduleId;\n moduleId = getModuleIdForVerboseName(verboseName);\n }\n const moduleIdReallyIsNumber = moduleId;\n const maybeInitializedModule = modules.get(moduleIdReallyIsNumber);\n if (\n maybeInitializedModule &&\n maybeInitializedModule.importedDefault !== EMPTY\n ) {\n return maybeInitializedModule.importedDefault;\n }\n const exports = metroRequire(moduleIdReallyIsNumber);\n const importedDefault =\n exports && exports.__esModule ? exports.default : exports;\n const initializedModule = modules.get(moduleIdReallyIsNumber);\n return (initializedModule.importedDefault = importedDefault);\n}\nmetroRequire.importDefault = metroImportDefault;\nfunction metroImportAll(moduleId) {\n if (__DEV__ && typeof moduleId === "string") {\n const verboseName = moduleId;\n moduleId = getModuleIdForVerboseName(verboseName);\n }\n const moduleIdReallyIsNumber = moduleId;\n const maybeInitializedModule = modules.get(moduleIdReallyIsNumber);\n if (maybeInitializedModule && maybeInitializedModule.importedAll !== EMPTY) {\n return maybeInitializedModule.importedAll;\n }\n const exports = metroRequire(moduleIdReallyIsNumber);\n let importedAll;\n if (exports && exports.__esModule) {\n importedAll = exports;\n } else {\n importedAll = {};\n if (exports) {\n for (const key in exports) {\n if (hasOwnProperty.call(exports, key)) {\n importedAll[key] = exports[key];\n }\n }\n }\n importedAll.default = exports;\n }\n const initializedModule = modules.get(moduleIdReallyIsNumber);\n return (initializedModule.importedAll = importedAll);\n}\nmetroRequire.importAll = metroImportAll;\nmetroRequire.context = function fallbackRequireContext() {\n if (__DEV__) {\n throw new Error(\n "The experimental Metro feature `require.context` is not enabled in your project.\\nThis can be enabled by setting the `transformer.unstable_allowRequireContext` property to `true` in your Metro configuration.",\n );\n }\n throw new Error(\n "The experimental Metro feature `require.context` is not enabled in your project.",\n );\n};\nmetroRequire.resolveWeak = function fallbackRequireResolveWeak() {\n if (__DEV__) {\n throw new Error(\n "require.resolveWeak cannot be called dynamically. Ensure you are using the same version of `metro` and `metro-runtime`.",\n );\n }\n throw new Error("require.resolveWeak cannot be called dynamically.");\n};\nlet inGuard = false;\nfunction guardedLoadModule(moduleId, module) {\n if (!inGuard && global.ErrorUtils) {\n inGuard = true;\n let returnValue;\n try {\n returnValue = loadModuleImplementation(moduleId, module);\n } catch (e) {\n global.ErrorUtils.reportFatalError(e);\n }\n inGuard = false;\n return returnValue;\n } else {\n return loadModuleImplementation(moduleId, module);\n }\n}\nconst ID_MASK_SHIFT = 16;\nconst LOCAL_ID_MASK = ~0 >>> ID_MASK_SHIFT;\nfunction unpackModuleId(moduleId) {\n const segmentId = moduleId >>> ID_MASK_SHIFT;\n const localId = moduleId & LOCAL_ID_MASK;\n return {\n segmentId,\n localId,\n };\n}\nmetroRequire.unpackModuleId = unpackModuleId;\nfunction packModuleId(value) {\n return (value.segmentId << ID_MASK_SHIFT) + value.localId;\n}\nmetroRequire.packModuleId = packModuleId;\nconst moduleDefinersBySegmentID = [];\nconst definingSegmentByModuleID = new Map();\nfunction registerSegment(segmentId, moduleDefiner, moduleIds) {\n moduleDefinersBySegmentID[segmentId] = moduleDefiner;\n if (__DEV__) {\n if (segmentId === 0 && moduleIds) {\n throw new Error(\n "registerSegment: Expected moduleIds to be null for main segment",\n );\n }\n if (segmentId !== 0 && !moduleIds) {\n throw new Error(\n "registerSegment: Expected moduleIds to be passed for segment #" +\n segmentId,\n );\n }\n }\n if (moduleIds) {\n moduleIds.forEach((moduleId) => {\n if (!modules.has(moduleId) && !definingSegmentByModuleID.has(moduleId)) {\n definingSegmentByModuleID.set(moduleId, segmentId);\n }\n });\n }\n}\nfunction loadModuleImplementation(moduleId, module) {\n if (!module && moduleDefinersBySegmentID.length > 0) {\n const segmentId = definingSegmentByModuleID.get(moduleId) ?? 0;\n const definer = moduleDefinersBySegmentID[segmentId];\n if (definer != null) {\n definer(moduleId);\n module = modules.get(moduleId);\n definingSegmentByModuleID.delete(moduleId);\n }\n }\n const nativeRequire = global.nativeRequire;\n if (!module && nativeRequire) {\n const { segmentId, localId } = unpackModuleId(moduleId);\n nativeRequire(localId, segmentId);\n module = modules.get(moduleId);\n }\n if (!module) {\n throw unknownModuleError(moduleId);\n }\n if (module.hasError) {\n throw module.error;\n }\n if (__DEV__) {\n var Systrace = requireSystrace();\n var Refresh = requireRefresh();\n }\n module.isInitialized = true;\n const { factory, dependencyMap } = module;\n if (__DEV__) {\n initializingModuleIds.push(moduleId);\n }\n try {\n if (__DEV__) {\n Systrace.beginEvent("JS_require_" + (module.verboseName || moduleId));\n }\n const moduleObject = module.publicModule;\n if (__DEV__) {\n moduleObject.hot = module.hot;\n var prevRefreshReg = global.$RefreshReg$;\n var prevRefreshSig = global.$RefreshSig$;\n if (Refresh != null) {\n const RefreshRuntime = Refresh;\n global.$RefreshReg$ = (type, id) => {\n const prefixedModuleId =\n __METRO_GLOBAL_PREFIX__ + " " + moduleId + " " + id;\n RefreshRuntime.register(type, prefixedModuleId);\n };\n global.$RefreshSig$ =\n RefreshRuntime.createSignatureFunctionForTransform;\n }\n }\n moduleObject.id = moduleId;\n factory(\n global,\n metroRequire,\n metroImportDefault,\n metroImportAll,\n moduleObject,\n moduleObject.exports,\n dependencyMap,\n );\n if (!__DEV__) {\n module.factory = undefined;\n module.dependencyMap = undefined;\n }\n if (__DEV__) {\n Systrace.endEvent();\n if (Refresh != null) {\n const prefixedModuleId = __METRO_GLOBAL_PREFIX__ + " " + moduleId;\n registerExportsForReactRefresh(\n Refresh,\n moduleObject.exports,\n prefixedModuleId,\n );\n }\n }\n return moduleObject.exports;\n } catch (e) {\n module.hasError = true;\n module.error = e;\n module.isInitialized = false;\n module.publicModule.exports = undefined;\n throw e;\n } finally {\n if (__DEV__) {\n if (initializingModuleIds.pop() !== moduleId) {\n throw new Error(\n "initializingModuleIds is corrupt; something is terribly wrong",\n );\n }\n global.$RefreshReg$ = prevRefreshReg;\n global.$RefreshSig$ = prevRefreshSig;\n }\n }\n}\nfunction unknownModuleError(id) {\n let message = \'Requiring unknown module "\' + id + \'".\';\n if (__DEV__) {\n message +=\n " If you are sure the module exists, try restarting Metro. " +\n "You may also want to run `yarn` or `npm install`.";\n }\n return Error(message);\n}\nif (__DEV__) {\n metroRequire.Systrace = {\n beginEvent: () => {},\n endEvent: () => {},\n };\n metroRequire.getModules = () => {\n return modules;\n };\n var createHotReloadingObject = function () {\n const hot = {\n _acceptCallback: null,\n _disposeCallback: null,\n _didAccept: false,\n accept: (callback) => {\n hot._didAccept = true;\n hot._acceptCallback = callback;\n },\n dispose: (callback) => {\n hot._disposeCallback = callback;\n },\n };\n return hot;\n };\n let reactRefreshTimeout = null;\n const metroHotUpdateModule = function (\n id,\n factory,\n dependencyMap,\n inverseDependencies,\n ) {\n const mod = modules.get(id);\n if (!mod) {\n if (factory) {\n return;\n }\n throw unknownModuleError(id);\n }\n const forceFullRefreshPatterns =\n global[__METRO_GLOBAL_PREFIX__ + "__unstable_forceFullRefreshPatterns"];\n if (\n forceFullRefreshPatterns != null &&\n Array.isArray(forceFullRefreshPatterns) &&\n mod.verboseName != null &&\n forceFullRefreshPatterns.some((pattern) =>\n pattern.test(mod.verboseName ?? ""),\n )\n ) {\n performFullRefresh("Module matched unstable_forceFullRefreshPatterns", {\n source: mod,\n });\n return;\n }\n if (!mod.hasError && !mod.isInitialized) {\n mod.factory = factory;\n mod.dependencyMap = dependencyMap;\n return;\n }\n const Refresh = requireRefresh();\n const refreshBoundaryIDs = new Set();\n let didBailOut = false;\n let updatedModuleIDs;\n try {\n updatedModuleIDs = topologicalSort(\n [id],\n (pendingID) => {\n const pendingModule = modules.get(pendingID);\n if (pendingModule == null) {\n return [];\n }\n const pendingHot = pendingModule.hot;\n if (pendingHot == null) {\n throw new Error(\n "[Refresh] Expected module.hot to always exist in DEV.",\n );\n }\n let canAccept = pendingHot._didAccept;\n if (!canAccept && Refresh != null) {\n const isBoundary = isReactRefreshBoundary(\n Refresh,\n pendingModule.publicModule.exports,\n );\n if (isBoundary) {\n canAccept = true;\n refreshBoundaryIDs.add(pendingID);\n }\n }\n if (canAccept) {\n return [];\n }\n const parentIDs = inverseDependencies[pendingID];\n if (parentIDs.length === 0) {\n performFullRefresh("No root boundary", {\n source: mod,\n failed: pendingModule,\n });\n didBailOut = true;\n return [];\n }\n return parentIDs;\n },\n () => didBailOut,\n ).reverse();\n } catch (e) {\n if (e === CYCLE_DETECTED) {\n performFullRefresh("Dependency cycle", {\n source: mod,\n });\n return;\n }\n throw e;\n }\n if (didBailOut) {\n return;\n }\n const seenModuleIDs = new Set();\n for (let i = 0; i < updatedModuleIDs.length; i++) {\n const updatedID = updatedModuleIDs[i];\n if (seenModuleIDs.has(updatedID)) {\n continue;\n }\n seenModuleIDs.add(updatedID);\n const updatedMod = modules.get(updatedID);\n if (updatedMod == null) {\n throw new Error("[Refresh] Expected to find the updated module.");\n }\n const prevExports = updatedMod.publicModule.exports;\n const didError = runUpdatedModule(\n updatedID,\n updatedID === id ? factory : undefined,\n updatedID === id ? dependencyMap : undefined,\n );\n const nextExports = updatedMod.publicModule.exports;\n if (didError) {\n return;\n }\n if (refreshBoundaryIDs.has(updatedID)) {\n const isNoLongerABoundary = !isReactRefreshBoundary(\n Refresh,\n nextExports,\n );\n const didInvalidate = shouldInvalidateReactRefreshBoundary(\n Refresh,\n prevExports,\n nextExports,\n );\n if (isNoLongerABoundary || didInvalidate) {\n const parentIDs = inverseDependencies[updatedID];\n if (parentIDs.length === 0) {\n performFullRefresh(\n isNoLongerABoundary\n ? "No longer a boundary"\n : "Invalidated boundary",\n {\n source: mod,\n failed: updatedMod,\n },\n );\n return;\n }\n for (let j = 0; j < parentIDs.length; j++) {\n const parentID = parentIDs[j];\n const parentMod = modules.get(parentID);\n if (parentMod == null) {\n throw new Error("[Refresh] Expected to find parent module.");\n }\n const canAcceptParent = isReactRefreshBoundary(\n Refresh,\n parentMod.publicModule.exports,\n );\n if (canAcceptParent) {\n refreshBoundaryIDs.add(parentID);\n updatedModuleIDs.push(parentID);\n } else {\n performFullRefresh("Invalidated boundary", {\n source: mod,\n failed: parentMod,\n });\n return;\n }\n }\n }\n }\n }\n if (Refresh != null) {\n if (reactRefreshTimeout == null) {\n reactRefreshTimeout = setTimeout(() => {\n reactRefreshTimeout = null;\n Refresh.performReactRefresh();\n }, 30);\n }\n }\n };\n const topologicalSort = function (roots, getEdges, earlyStop) {\n const result = [];\n const visited = new Set();\n const stack = new Set();\n function traverseDependentNodes(node) {\n if (stack.has(node)) {\n throw CYCLE_DETECTED;\n }\n if (visited.has(node)) {\n return;\n }\n visited.add(node);\n stack.add(node);\n const dependentNodes = getEdges(node);\n if (earlyStop(node)) {\n stack.delete(node);\n return;\n }\n dependentNodes.forEach((dependent) => {\n traverseDependentNodes(dependent);\n });\n stack.delete(node);\n result.push(node);\n }\n roots.forEach((root) => {\n traverseDependentNodes(root);\n });\n return result;\n };\n const runUpdatedModule = function (id, factory, dependencyMap) {\n const mod = modules.get(id);\n if (mod == null) {\n throw new Error("[Refresh] Expected to find the module.");\n }\n const { hot } = mod;\n if (!hot) {\n throw new Error("[Refresh] Expected module.hot to always exist in DEV.");\n }\n if (hot._disposeCallback) {\n try {\n hot._disposeCallback();\n } catch (error) {\n console.error(\n `Error while calling dispose handler for module ${id}: `,\n error,\n );\n }\n }\n if (factory) {\n mod.factory = factory;\n }\n if (dependencyMap) {\n mod.dependencyMap = dependencyMap;\n }\n mod.hasError = false;\n mod.error = undefined;\n mod.importedAll = EMPTY;\n mod.importedDefault = EMPTY;\n mod.isInitialized = false;\n const prevExports = mod.publicModule.exports;\n mod.publicModule.exports = {};\n hot._didAccept = false;\n hot._acceptCallback = null;\n hot._disposeCallback = null;\n metroRequire(id);\n if (mod.hasError) {\n mod.hasError = false;\n mod.isInitialized = true;\n mod.error = null;\n mod.publicModule.exports = prevExports;\n return true;\n }\n if (hot._acceptCallback) {\n try {\n hot._acceptCallback();\n } catch (error) {\n console.error(\n `Error while calling accept handler for module ${id}: `,\n error,\n );\n }\n }\n return false;\n };\n const performFullRefresh = (reason, modules) => {\n if (\n typeof window !== "undefined" &&\n window.location != null &&\n typeof window.location.reload === "function"\n ) {\n window.location.reload();\n } else {\n const Refresh = requireRefresh();\n if (Refresh != null) {\n const sourceName = modules.source?.verboseName ?? "unknown";\n const failedName = modules.failed?.verboseName ?? "unknown";\n Refresh.performFullRefresh(\n `Fast Refresh - ${reason} <${sourceName}> <${failedName}>`,\n );\n } else {\n console.warn("Could not reload the application after an edit.");\n }\n }\n };\n const isExportSafeToAccess = (moduleExports, key) => {\n return (\n moduleExports?.__esModule ||\n Object.getOwnPropertyDescriptor(moduleExports, key)?.get == null\n );\n };\n var isReactRefreshBoundary = function (Refresh, moduleExports) {\n if (Refresh.isLikelyComponentType(moduleExports)) {\n return true;\n }\n if (moduleExports == null || typeof moduleExports !== "object") {\n return false;\n }\n let hasExports = false;\n let areAllExportsComponents = true;\n for (const key in moduleExports) {\n hasExports = true;\n if (key === "__esModule") {\n continue;\n } else if (!isExportSafeToAccess(moduleExports, key)) {\n return false;\n }\n const exportValue = moduleExports[key];\n if (!Refresh.isLikelyComponentType(exportValue)) {\n areAllExportsComponents = false;\n }\n }\n return hasExports && areAllExportsComponents;\n };\n var shouldInvalidateReactRefreshBoundary = (\n Refresh,\n prevExports,\n nextExports,\n ) => {\n const prevSignature = getRefreshBoundarySignature(Refresh, prevExports);\n const nextSignature = getRefreshBoundarySignature(Refresh, nextExports);\n if (prevSignature.length !== nextSignature.length) {\n return true;\n }\n for (let i = 0; i < nextSignature.length; i++) {\n if (prevSignature[i] !== nextSignature[i]) {\n return true;\n }\n }\n return false;\n };\n var getRefreshBoundarySignature = (Refresh, moduleExports) => {\n const signature = [];\n signature.push(Refresh.getFamilyByType(moduleExports));\n if (moduleExports == null || typeof moduleExports !== "object") {\n return signature;\n }\n for (const key in moduleExports) {\n if (key === "__esModule") {\n continue;\n } else if (!isExportSafeToAccess(moduleExports, key)) {\n continue;\n }\n const exportValue = moduleExports[key];\n signature.push(key);\n signature.push(Refresh.getFamilyByType(exportValue));\n }\n return signature;\n };\n var registerExportsForReactRefresh = (Refresh, moduleExports, moduleID) => {\n Refresh.register(moduleExports, moduleID + " %exports%");\n if (moduleExports == null || typeof moduleExports !== "object") {\n return;\n }\n for (const key in moduleExports) {\n if (!isExportSafeToAccess(moduleExports, key)) {\n continue;\n }\n const exportValue = moduleExports[key];\n const typeID = moduleID + " %exports% " + key;\n Refresh.register(exportValue, typeID);\n }\n };\n global.__accept = metroHotUpdateModule;\n}\nif (__DEV__) {\n var requireSystrace = function requireSystrace() {\n return (\n global[__METRO_GLOBAL_PREFIX__ + "__SYSTRACE"] || metroRequire.Systrace\n );\n };\n var requireRefresh = function requireRefresh() {\n return (\n global[__METRO_GLOBAL_PREFIX__ + "__ReactRefresh"] ||\n global[global.__METRO_GLOBAL_PREFIX__ + "__ReactRefresh"] ||\n metroRequire.Refresh\n );\n };\n}\n'
|
|
9
|
+
|
|
10
|
+
// metro-runtime/src/modules/asyncRequire.js — the module import() compiles down to
|
|
11
|
+
export const METRO_ASYNC_REQUIRE =
|
|
12
|
+
'"use strict";\n\nfunction maybeLoadBundle(moduleID, paths) {\n const loadBundle = global[`${__METRO_GLOBAL_PREFIX__}__loadBundleAsync`];\n if (loadBundle != null) {\n const stringModuleID = String(moduleID);\n if (paths != null) {\n const bundlePath = paths[stringModuleID];\n if (bundlePath != null) {\n return loadBundle(bundlePath);\n }\n }\n }\n return undefined;\n}\nfunction asyncRequireImpl(moduleID, paths) {\n const maybeLoadBundlePromise = maybeLoadBundle(moduleID, paths);\n const importAll = () => require.importAll(moduleID);\n if (maybeLoadBundlePromise != null) {\n return maybeLoadBundlePromise.then(importAll);\n }\n return importAll();\n}\nasync function asyncRequire(moduleID, paths, moduleName) {\n return asyncRequireImpl(moduleID, paths);\n}\nasyncRequire.unstable_importMaybeSync = function unstable_importMaybeSync(\n moduleID,\n paths,\n) {\n return asyncRequireImpl(moduleID, paths);\n};\nasyncRequire.prefetch = function (moduleID, paths, moduleName) {\n maybeLoadBundle(moduleID, paths)?.then(\n () => {},\n () => {},\n );\n};\nmodule.exports = asyncRequire;\n'
|
|
13
|
+
|
|
14
|
+
// metro-runtime/src/modules/empty-module.js — what a browser-field `false` redirect resolves to
|
|
15
|
+
export const METRO_EMPTY_MODULE = '"use strict";\n'
|
|
@@ -153,15 +153,13 @@ export const NATIVE_SEAM_MANIFEST: NativeSeamEntry[] = [
|
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
pkg: '@bam.tech/react-native-image-resizer',
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
// for documentation parity; vite-path redirect would key on
|
|
160
|
-
// `NativeImageResizer`.
|
|
156
|
+
// a Metro bundle reaches the same seam through the ImageResizer
|
|
157
|
+
// TurboModule that `stubs/bam-react-native-image-resizer-register.ts`
|
|
158
|
+
// registers.
|
|
161
159
|
seamBasenames: ['NativeImageResizer'],
|
|
162
160
|
target: seamPath('bam-react-native-image-resizer'),
|
|
163
161
|
notes:
|
|
164
|
-
'ImageResizer TurboModule
|
|
162
|
+
'ImageResizer TurboModule following ios/ImageResizer.mm: loader decode, rotation, scaling, and the file written to the app container',
|
|
165
163
|
},
|
|
166
164
|
{
|
|
167
165
|
pkg: 'react-native-adjust',
|
package/src/swift-compile.ts
CHANGED
|
@@ -224,8 +224,8 @@ export function swiftArtifactHash(
|
|
|
224
224
|
moduleRoot: string,
|
|
225
225
|
): string {
|
|
226
226
|
const hash = createHash('sha256')
|
|
227
|
-
//
|
|
228
|
-
hash.update(`swift-compile/
|
|
227
|
+
// v3: sources compile with os(iOS) true on code lines (swiftSourceAsIOS)
|
|
228
|
+
hash.update(`swift-compile/v3\n${release}\n`)
|
|
229
229
|
if (input.oneModule) hash.update('one-module\n')
|
|
230
230
|
hash.update(linkedModuleDigest(moduleRoot))
|
|
231
231
|
for (const file of Object.keys(input.files).sort()) {
|
|
@@ -347,15 +347,111 @@ function syncSwiftTree(base: string, files: Map<string, string>): void {
|
|
|
347
347
|
// every iOS branch of the app would compile out. a condition line names iOS
|
|
348
348
|
// as `true` padded to the same length, so diagnostics keep their columns;
|
|
349
349
|
// os(WASI) still holds for code written for wasm. only `#if` and `#elseif`
|
|
350
|
-
// lines change
|
|
351
|
-
|
|
350
|
+
// lines that begin in code change: a line inside a string literal or a block
|
|
351
|
+
// comment is content. the artifact hash stays over the original text.
|
|
352
|
+
const DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/
|
|
352
353
|
const OS_IOS = /\bos\(\s*iOS\s*\)/g
|
|
353
354
|
export function swiftSourceAsIOS(source: string): string {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
355
|
+
const code = swiftCodeLineStarts(source)
|
|
356
|
+
let offset = 0
|
|
357
|
+
return source
|
|
358
|
+
.split('\n')
|
|
359
|
+
.map((line) => {
|
|
360
|
+
const start = offset
|
|
361
|
+
offset += line.length + 1
|
|
362
|
+
if (!code.has(start) || !DIRECTIVE.test(line)) return line
|
|
363
|
+
return line.replace(OS_IOS, (match) => 'true'.padEnd(match.length))
|
|
364
|
+
})
|
|
365
|
+
.join('\n')
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// the offsets of the lines that begin in code, from a scan of Swift's lexical
|
|
369
|
+
// contexts: nested block comments, line comments, string literals (single and
|
|
370
|
+
// multiline, raw with any number of #, interpolations holding code and
|
|
371
|
+
// strings of their own) and #/ /# regex literals. a bare /regex/ literal
|
|
372
|
+
// reads as code.
|
|
373
|
+
type Lexical =
|
|
374
|
+
| { kind: 'code'; parens: number }
|
|
375
|
+
| { kind: 'block'; depth: number }
|
|
376
|
+
| { kind: 'string'; hashes: number; multiline: boolean }
|
|
377
|
+
| { kind: 'regex'; hashes: number }
|
|
378
|
+
function swiftCodeLineStarts(source: string): Set<number> {
|
|
379
|
+
const starts = new Set<number>()
|
|
380
|
+
const stack: Lexical[] = [{ kind: 'code', parens: 0 }]
|
|
381
|
+
const hashesAt = (at: number) => {
|
|
382
|
+
let end = at
|
|
383
|
+
while (source[end] === '#') end++
|
|
384
|
+
return end - at
|
|
385
|
+
}
|
|
386
|
+
const closes = (at: number, hashes: number) => source.startsWith('#'.repeat(hashes), at)
|
|
387
|
+
let i = 0
|
|
388
|
+
while (i < source.length) {
|
|
389
|
+
const top = stack[stack.length - 1]
|
|
390
|
+
if ((i === 0 || source[i - 1] === '\n') && top.kind === 'code' && stack.length === 1)
|
|
391
|
+
starts.add(i)
|
|
392
|
+
const char = source[i]
|
|
393
|
+
if (top.kind === 'block') {
|
|
394
|
+
if (source.startsWith('/*', i)) {
|
|
395
|
+
top.depth++
|
|
396
|
+
i += 2
|
|
397
|
+
} else if (source.startsWith('*/', i)) {
|
|
398
|
+
if (--top.depth === 0) stack.pop()
|
|
399
|
+
i += 2
|
|
400
|
+
} else i++
|
|
401
|
+
continue
|
|
402
|
+
}
|
|
403
|
+
if (top.kind === 'string') {
|
|
404
|
+
if (char === '\\' && closes(i + 1, top.hashes)) {
|
|
405
|
+
const after = i + 1 + top.hashes
|
|
406
|
+
if (source[after] === '(') {
|
|
407
|
+
stack.push({ kind: 'code', parens: 0 })
|
|
408
|
+
i = after + 1
|
|
409
|
+
} else i = after + 1
|
|
410
|
+
continue
|
|
411
|
+
}
|
|
412
|
+
const quote = top.multiline ? '"""' : '"'
|
|
413
|
+
if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
|
|
414
|
+
stack.pop()
|
|
415
|
+
i += quote.length + top.hashes
|
|
416
|
+
} else i++
|
|
417
|
+
continue
|
|
418
|
+
}
|
|
419
|
+
if (top.kind === 'regex') {
|
|
420
|
+
if (char === '/' && closes(i + 1, top.hashes)) {
|
|
421
|
+
stack.pop()
|
|
422
|
+
i += 1 + top.hashes
|
|
423
|
+
} else i++
|
|
424
|
+
continue
|
|
425
|
+
}
|
|
426
|
+
if (source.startsWith('//', i)) {
|
|
427
|
+
const end = source.indexOf('\n', i)
|
|
428
|
+
i = end === -1 ? source.length : end
|
|
429
|
+
} else if (source.startsWith('/*', i)) {
|
|
430
|
+
stack.push({ kind: 'block', depth: 1 })
|
|
431
|
+
i += 2
|
|
432
|
+
} else if (char === '"' || char === '#') {
|
|
433
|
+
const hashes = hashesAt(i)
|
|
434
|
+
const at = i + hashes
|
|
435
|
+
if (source.startsWith('"""', at)) {
|
|
436
|
+
stack.push({ kind: 'string', hashes, multiline: true })
|
|
437
|
+
i = at + 3
|
|
438
|
+
} else if (source[at] === '"') {
|
|
439
|
+
stack.push({ kind: 'string', hashes, multiline: false })
|
|
440
|
+
i = at + 1
|
|
441
|
+
} else if (hashes > 0 && source[at] === '/') {
|
|
442
|
+
stack.push({ kind: 'regex', hashes })
|
|
443
|
+
i = at + 1
|
|
444
|
+
} else i = Math.max(at, i + 1)
|
|
445
|
+
} else if (char === '(') {
|
|
446
|
+
top.parens++
|
|
447
|
+
i++
|
|
448
|
+
} else if (char === ')') {
|
|
449
|
+
if (top.parens === 0 && stack.length > 1) stack.pop()
|
|
450
|
+
else top.parens--
|
|
451
|
+
i++
|
|
452
|
+
} else i++
|
|
453
|
+
}
|
|
454
|
+
return starts
|
|
359
455
|
}
|
|
360
456
|
|
|
361
457
|
const compiledSource = (file: string, contents: string) =>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// the built-in guest uses the existing Metro runtime and host module seam.
|
|
2
|
+
// the author supplies Swift; this entry carries no engine or compiler code.
|
|
3
|
+
import {
|
|
4
|
+
appendRNXMetroModuleIdentityFooter,
|
|
5
|
+
RNX_METRO_MODULE_IDENTITY_VERSION,
|
|
6
|
+
} from './metro-production-bundle'
|
|
7
|
+
import { METRO_REQUIRE_POLYFILL } from './metro-runtime-source'
|
|
8
|
+
|
|
9
|
+
export function swiftGuestBundle(packageName: string): string {
|
|
10
|
+
const modules = [
|
|
11
|
+
{
|
|
12
|
+
name: 'peach-swift-entry.js',
|
|
13
|
+
code: `const { AppRegistry } = require(1)
|
|
14
|
+
const { createSwiftPreviewEntry } = require(2)
|
|
15
|
+
AppRegistry.registerComponent('PeachSwift', () => createSwiftPreviewEntry(${JSON.stringify(packageName)}))`,
|
|
16
|
+
deps: [1, 2],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'react-native',
|
|
20
|
+
code: `module.exports = global.__contrastHostModules['react-native']`,
|
|
21
|
+
deps: [],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'peachsim/swift',
|
|
25
|
+
code: `module.exports = global.__contrastHostModules['peachsim/swift']`,
|
|
26
|
+
deps: [],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'react',
|
|
30
|
+
code: `module.exports = global.__contrastHostModules['react']`,
|
|
31
|
+
deps: [],
|
|
32
|
+
},
|
|
33
|
+
]
|
|
34
|
+
const bundle = [
|
|
35
|
+
`var __METRO_GLOBAL_PREFIX__='';`,
|
|
36
|
+
`(function(global){${METRO_REQUIRE_POLYFILL}})(globalThis);`,
|
|
37
|
+
...modules.map(
|
|
38
|
+
(module, id) =>
|
|
39
|
+
`__d(function(global,require,_importDefault,_importAll,module,exports,_dependencyMap){\n${module.code}\n},${id},${JSON.stringify(module.deps)},${JSON.stringify(module.name)});`,
|
|
40
|
+
),
|
|
41
|
+
'__r(0);',
|
|
42
|
+
].join('\n')
|
|
43
|
+
return appendRNXMetroModuleIdentityFooter(bundle, {
|
|
44
|
+
version: RNX_METRO_MODULE_IDENTITY_VERSION,
|
|
45
|
+
identitySource: 'contrast-bundler',
|
|
46
|
+
modulePaths: Object.fromEntries(modules.map((module, id) => [id, module.name])),
|
|
47
|
+
logicalSpecifiers: Object.fromEntries(
|
|
48
|
+
modules.flatMap((module, id) => (id === 0 ? [] : [[id, [module.name]]])),
|
|
49
|
+
),
|
|
50
|
+
})
|
|
51
|
+
}
|