sootsim 0.1.298 → 0.1.299
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/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-U3HXOT6B.js → agent-3UVOB3T3.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-LJOPJUAN.js → agent-wrapper-XVOWC72E.js} +2 -2
- package/dist-cli/chunks/{app-fonts-4EVLV2BX.js → app-fonts-C222PFAQ.js} +2 -2
- package/dist-cli/chunks/{assert-NNKBTEO7.js → assert-2MHAZDEL.js} +2 -2
- package/dist-cli/chunks/{auth-SF2WR2K2.js → auth-7DTOEHC2.js} +2 -2
- package/dist-cli/chunks/{beta-SCLWNOHI.js → beta-WOHZHXPE.js} +2 -2
- package/dist-cli/chunks/{camera-TZJ2Z3TZ.js → camera-XCUE5ZNM.js} +2 -2
- package/dist-cli/chunks/{chunk-MHCSRMK4.js → chunk-23JBOG4P.js} +1 -1
- package/dist-cli/chunks/{chunk-IBMZ7A6M.js → chunk-2FTQEDJC.js} +2 -2
- package/dist-cli/chunks/{chunk-IRMKZSWK.js → chunk-37ACY2R3.js} +2 -2
- package/dist-cli/chunks/{chunk-APNG6X2R.js → chunk-444BQYY3.js} +2 -2
- package/dist-cli/chunks/{chunk-BUM4RR4G.js → chunk-4TYUHNHI.js} +2 -2
- package/dist-cli/chunks/{chunk-G3NMMKBL.js → chunk-5GRQIA5R.js} +2 -2
- package/dist-cli/chunks/{chunk-MFMFNCBK.js → chunk-5VX2Y3ZB.js} +2 -2
- package/dist-cli/chunks/{chunk-WV6CBQYZ.js → chunk-6RH6PEO3.js} +1 -1
- package/dist-cli/chunks/{chunk-XITV33JC.js → chunk-ALOQJP4C.js} +2 -2
- package/dist-cli/chunks/{chunk-ZCHO67PX.js → chunk-B6TCNXJO.js} +2 -2
- package/dist-cli/chunks/{chunk-JM36NHNU.js → chunk-CBRE6JLP.js} +1 -1
- package/dist-cli/chunks/{chunk-EYBWIEDO.js → chunk-DGWM3X4S.js} +2 -2
- package/dist-cli/chunks/{chunk-KVYZYYSY.js → chunk-DUGY7KHN.js} +1 -1
- package/dist-cli/chunks/{chunk-TTFO75GL.js → chunk-E2XMG2HC.js} +1 -1
- package/dist-cli/chunks/{chunk-ZBETYTSD.js → chunk-EJC4A2ZH.js} +1 -1
- package/dist-cli/chunks/{chunk-HAJSNFUY.js → chunk-F57XAX5N.js} +1 -1
- package/dist-cli/chunks/{chunk-NRC73NVF.js → chunk-FLTBPGAQ.js} +2 -2
- package/dist-cli/chunks/{chunk-4H3Y3TGT.js → chunk-FMQ772D7.js} +1 -1
- package/dist-cli/chunks/{chunk-AHMMVYVE.js → chunk-G377NNEV.js} +1 -1
- package/dist-cli/chunks/{chunk-QZCVY5BX.js → chunk-HM42NCGX.js} +1 -1
- package/dist-cli/chunks/{chunk-ANFOERLP.js → chunk-HVQA443X.js} +1 -1
- package/dist-cli/chunks/{chunk-PLEZAZTJ.js → chunk-I4NK5VBB.js} +2 -2
- package/dist-cli/chunks/chunk-IGKB2HLF.js +4 -0
- package/dist-cli/chunks/{chunk-HGSYUEQP.js → chunk-ITSHLH5U.js} +2 -2
- package/dist-cli/chunks/{chunk-AT3NTZPP.js → chunk-JXHCBXUD.js} +3 -3
- package/dist-cli/chunks/{chunk-HOQD6TZN.js → chunk-KJQJ5VPA.js} +1 -1
- package/dist-cli/chunks/{chunk-CK3MTK2D.js → chunk-L3FA7WE5.js} +2 -2
- package/dist-cli/chunks/{chunk-SQR7NH32.js → chunk-L7GNKY3A.js} +1 -1
- package/dist-cli/chunks/{chunk-U5TY536V.js → chunk-LEHK72DK.js} +2 -2
- package/dist-cli/chunks/{chunk-GR7USTCW.js → chunk-LFWATDB3.js} +2 -2
- package/dist-cli/chunks/{chunk-TB77ANGH.js → chunk-MKIABOQK.js} +2 -2
- package/dist-cli/chunks/{chunk-UTUBMEFS.js → chunk-MSYFSZKB.js} +1 -1
- package/dist-cli/chunks/{chunk-6YIZZDG2.js → chunk-MTOADQY2.js} +2 -2
- package/dist-cli/chunks/{chunk-WDKLXBQR.js → chunk-ONQYJYUM.js} +1 -1
- package/dist-cli/chunks/{chunk-EH4B5ZQ4.js → chunk-PHBVCGV3.js} +2 -2
- package/dist-cli/chunks/{chunk-HG63AS7K.js → chunk-Q34734UC.js} +1 -1
- package/dist-cli/chunks/{chunk-MTL4DPUK.js → chunk-QMDKE3C6.js} +1 -1
- package/dist-cli/chunks/{chunk-FTMTIUBK.js → chunk-QPPG5YZS.js} +2 -2
- package/dist-cli/chunks/{chunk-7ZOI5KJZ.js → chunk-RWXJ6OS4.js} +2 -2
- package/dist-cli/chunks/{chunk-VFI23QUE.js → chunk-UNFMIX7B.js} +1 -1
- package/dist-cli/chunks/{chunk-X3STT7I3.js → chunk-VR4ZUUA4.js} +1 -1
- package/dist-cli/chunks/{chunk-GXVG5LJG.js → chunk-W3H6FBWV.js} +2 -2
- package/dist-cli/chunks/{chunk-J42Y66IM.js → chunk-WCAT3UC4.js} +2 -2
- package/dist-cli/chunks/{chunk-CXSMZLI6.js → chunk-WM4RNTPN.js} +3 -3
- package/dist-cli/chunks/{chunk-3R4W2SQB.js → chunk-WMLVFFXE.js} +3 -3
- package/dist-cli/chunks/{chunk-GM2TRB5Z.js → chunk-XMOYKSSM.js} +2 -2
- package/dist-cli/chunks/{chunk-PYUI2PHI.js → chunk-YEE3MKPH.js} +2 -2
- package/dist-cli/chunks/{chunk-CAEQ7AOI.js → chunk-ZEXLS32P.js} +3 -3
- package/dist-cli/chunks/{chunk-5VGTEGDT.js → chunk-ZRDU2ENE.js} +2 -2
- package/dist-cli/chunks/{cleanup-YZPCNPWE.js → cleanup-O6SD44HN.js} +2 -2
- package/dist-cli/chunks/{cli-version-ECA6G6JQ.js → cli-version-PIYRRI52.js} +2 -2
- package/dist-cli/chunks/{compat-OM7ODBMO.js → compat-AWJLEWTH.js} +2 -2
- package/dist-cli/chunks/{config-ZIX6LPFG.js → config-6PLYOSBK.js} +2 -2
- package/dist-cli/chunks/{control-BY6UAMKN.js → control-K4QMNPXN.js} +2 -2
- package/dist-cli/chunks/daemon-HG6LHW3O.js +4 -0
- package/dist-cli/chunks/{debug-MVPFRIQA.js → debug-YCJCLH35.js} +3 -3
- package/dist-cli/chunks/{desktop-ZXH7NRHW.js → desktop-NRUWYSTV.js} +3 -3
- package/dist-cli/chunks/{detox-4RZ5UER3.js → detox-XTERPTZN.js} +2 -2
- package/dist-cli/chunks/{device-7R4BSFMS.js → device-G4KJITB6.js} +2 -2
- package/dist-cli/chunks/{diagnose-4JAFIXWD.js → diagnose-CKZOV5PL.js} +2 -2
- package/dist-cli/chunks/disk-cleanup-LX6FRBNM.js +4 -0
- package/dist-cli/chunks/drivers-X6XG4AX4.js +4 -0
- package/dist-cli/chunks/{film-Q7KZIGBH.js → film-4T3QY3VT.js} +3 -3
- package/dist-cli/chunks/flow-EQPPW77J.js +4 -0
- package/dist-cli/chunks/help-IRKWFF27.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-4ZUCLCVJ.js → hidden-runtime-alias-S2PPAYI3.js} +2 -2
- package/dist-cli/chunks/{home-paths-PVZPREN7.js → home-paths-MUZXK2LA.js} +2 -2
- package/dist-cli/chunks/inspect-VGNST6ZA.js +4 -0
- package/dist-cli/chunks/install-desktop-5H7A5R3Z.js +4 -0
- package/dist-cli/chunks/{login-UMP65DJG.js → login-RH2KRRBQ.js} +4 -4
- package/dist-cli/chunks/{logout-F45WBVJV.js → logout-GIEQBBFN.js} +2 -2
- package/dist-cli/chunks/{maestro-33RGEXP4.js → maestro-JEAOFJLT.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-5SLZMOMB.js → maestro-generate-GAYZAFOV.js} +3 -3
- package/dist-cli/chunks/{mode-LZORZYWP.js → mode-V2OWWT7B.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-DIWO7DG5.js → optional-demo-registry-CZSJJFLR.js} +2 -2
- package/dist-cli/chunks/{perf-VW3UTYCK.js → perf-SNBPEVZL.js} +2 -2
- package/dist-cli/chunks/{permissions-7JIR6QPO.js → permissions-MKMHM34X.js} +2 -2
- package/dist-cli/chunks/{record-A4MRKJ2E.js → record-55URP7AI.js} +3 -3
- package/dist-cli/chunks/{report-issue-JUWTB66Z.js → report-issue-I4JZBUDD.js} +2 -2
- package/dist-cli/chunks/runtime-XHMSVSWG.js +4 -0
- package/dist-cli/chunks/{screenshot-command-6LROQJPJ.js → screenshot-command-YGBR4Y2V.js} +3 -3
- package/dist-cli/chunks/{screenshots-capture-FMYE24EW.js → screenshots-capture-S5CP6OWZ.js} +2 -2
- package/dist-cli/chunks/{serve-64SRDCU5.js → serve-45NQNA7C.js} +2 -2
- package/dist-cli/chunks/{setup-2CUXSDQH.js → setup-HKTRNWH6.js} +2 -2
- package/dist-cli/chunks/{skills-IILJVUMS.js → skills-HUDGHVRT.js} +2 -2
- package/dist-cli/chunks/{storage-BUQQJAMD.js → storage-HOYYA2PS.js} +2 -2
- package/dist-cli/chunks/store-7QB3V42F.js +4 -0
- package/dist-cli/chunks/telemetry-HYW35ACO.js +4 -0
- package/dist-cli/chunks/{timeline-62RWUHSF.js → timeline-2S3FS3AA.js} +2 -2
- package/dist-cli/chunks/{upgrade-GHXDTO2A.js → upgrade-KZSYVT3E.js} +2 -2
- package/dist-cli/chunks/upload-P3CQI4RQ.js +4 -0
- package/dist-cli/chunks/{version-F4CKBMB6.js → version-BWNEYFPL.js} +2 -2
- package/dist-cli/chunks/{web-YM6GIFOU.js → web-DXSNL2J6.js} +2 -2
- package/dist-cli/chunks/{what-happened-UKBSKIGA.js → what-happened-VT4FO7XN.js} +2 -2
- 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/cli-constants.cjs +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 +1 -1
- 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/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +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 +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +46 -44
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/vite-plugin.ts +452 -396
- package/src/worklets-babel.ts +4 -2
- package/dist-cli/chunks/chunk-THIBWEML.js +0 -4
- package/dist-cli/chunks/daemon-BQ2T53ZA.js +0 -4
- package/dist-cli/chunks/disk-cleanup-3E7GYLGW.js +0 -4
- package/dist-cli/chunks/drivers-2OW33GOL.js +0 -4
- package/dist-cli/chunks/flow-QTOSAQ5X.js +0 -4
- package/dist-cli/chunks/help-UE32FDEY.js +0 -4
- package/dist-cli/chunks/inspect-QWR2U3DK.js +0 -4
- package/dist-cli/chunks/install-desktop-R2ZM5ZJH.js +0 -4
- package/dist-cli/chunks/runtime-7LSOODXL.js +0 -4
- package/dist-cli/chunks/store-3Z2GSFGY.js +0 -4
- package/dist-cli/chunks/telemetry-2UMKQXU7.js +0 -4
- package/dist-cli/chunks/upload-H6RTYSLO.js +0 -4
package/src/vite-plugin.ts
CHANGED
|
@@ -23,9 +23,14 @@ import {
|
|
|
23
23
|
reactNativeDeepStubsForBuildResolver,
|
|
24
24
|
} from '../../compat/src/stub-manifest.ts'
|
|
25
25
|
import { resolveSootsimBridgePort } from './bridge-constants.ts'
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
REANIMATED_WORKLETIZATION_REGEX,
|
|
28
|
+
shouldApplyWorkletsPlugin,
|
|
29
|
+
transformWorkletsCode,
|
|
30
|
+
} from './worklets-babel.ts'
|
|
27
31
|
|
|
28
32
|
const sootsimPluginRequire = createRequire(import.meta.url)
|
|
33
|
+
const virtualIdPrefix = String.fromCharCode(0)
|
|
29
34
|
|
|
30
35
|
export interface SootSimOptions {
|
|
31
36
|
// directory of an external RN app to load
|
|
@@ -347,8 +352,15 @@ export function sootsim(options: SootSimOptions = {}): Plugin[] {
|
|
|
347
352
|
{
|
|
348
353
|
name: 'sootsim-published-browser-internals',
|
|
349
354
|
enforce: 'pre',
|
|
350
|
-
resolveId
|
|
351
|
-
|
|
355
|
+
resolveId: {
|
|
356
|
+
filter: { id: /^\./ },
|
|
357
|
+
handler(source, importer) {
|
|
358
|
+
return resolvePublishedBrowserInternal(
|
|
359
|
+
source,
|
|
360
|
+
importer,
|
|
361
|
+
publishedBrowserPackages,
|
|
362
|
+
)
|
|
363
|
+
},
|
|
352
364
|
},
|
|
353
365
|
},
|
|
354
366
|
sootsimConfigPlugin(appDir, extraSources, publishedBrowserPackages),
|
|
@@ -366,8 +378,10 @@ export function sootsim(options: SootSimOptions = {}): Plugin[] {
|
|
|
366
378
|
workletsBabelTransform(isAppSource),
|
|
367
379
|
metroNativeResolve(isAppSource),
|
|
368
380
|
reactNativeRequirePlugin(isAppSource),
|
|
369
|
-
externalAppResolvePlugin(appDir, isAppSource, ownedPackages),
|
|
370
|
-
|
|
381
|
+
...(appDir ? [externalAppResolvePlugin(appDir, isAppSource, ownedPackages)] : []),
|
|
382
|
+
...(appDir || extraSources.length > 0
|
|
383
|
+
? [externalAppTransformPlugin(isAppSource)]
|
|
384
|
+
: []),
|
|
371
385
|
stubMissingNativeDeps(appDir),
|
|
372
386
|
stubMissingImages(isAppSource),
|
|
373
387
|
]
|
|
@@ -386,21 +400,26 @@ function rnghUpstreamInternalResolvePlugin(): Plugin {
|
|
|
386
400
|
return {
|
|
387
401
|
name: 'sootsim-rngh-upstream-internal-resolve',
|
|
388
402
|
enforce: 'pre',
|
|
389
|
-
resolveId
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
403
|
+
resolveId: {
|
|
404
|
+
filter: {
|
|
405
|
+
id: /(?:^\.\.\/\.\.(?:\.(?:js|jsx|mjs|ts|tsx))?$|GestureDetector(?:\.(?:js|jsx|mjs|ts|tsx))?$|GestureHandlerRootViewContext(?:\.(?:js|jsx|mjs|ts|tsx))?$)/,
|
|
406
|
+
},
|
|
407
|
+
handler(source, importer) {
|
|
408
|
+
if (!importer || !rnghLibModuleRoot) return null
|
|
409
|
+
const importerPath = stripViteQuery(importer)
|
|
410
|
+
if (!isPathInside(importerPath, rnghLibModuleRoot)) return null
|
|
411
|
+
const sourcePath = source.replace(/\.(js|jsx|mjs|ts|tsx)$/, '')
|
|
412
|
+
if (
|
|
413
|
+
sourcePath === '../..' ||
|
|
414
|
+
sourcePath.endsWith('/handlers/gestures/GestureDetector')
|
|
415
|
+
) {
|
|
416
|
+
return rnghRootStubPath
|
|
417
|
+
}
|
|
418
|
+
if (sourcePath.endsWith('GestureHandlerRootViewContext')) {
|
|
419
|
+
return rnghGestureHandlerRootViewContextShimPath
|
|
420
|
+
}
|
|
421
|
+
return null
|
|
422
|
+
},
|
|
404
423
|
},
|
|
405
424
|
}
|
|
406
425
|
}
|
|
@@ -482,28 +501,35 @@ export function keyboardControllerBindingsRedirect(): Plugin {
|
|
|
482
501
|
return {
|
|
483
502
|
name: 'sootsim-keyboard-controller-bindings-redirect',
|
|
484
503
|
enforce: 'pre',
|
|
485
|
-
resolveId
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
504
|
+
resolveId: {
|
|
505
|
+
filter: {
|
|
506
|
+
id: /(?:^|\/)(?:bindings(?:\.native)?|findNodeHandle|reanimated)$/,
|
|
507
|
+
},
|
|
508
|
+
handler(source, importer) {
|
|
509
|
+
if (!importer) return null
|
|
510
|
+
if (!importer.includes('/react-native-keyboard-controller/')) return null
|
|
511
|
+
// keep bindings imports — strip optional .native and any leading
|
|
512
|
+
// `./`, `../`, `../../` so the depth doesn't matter.
|
|
513
|
+
const basename = source.split('/').pop() ?? ''
|
|
514
|
+
if (nativePlatformBasenames.has(basename)) {
|
|
515
|
+
return (
|
|
516
|
+
resolveNativePlatformFile(source, importer) ??
|
|
517
|
+
(basename === 'findNodeHandle' ? findNodeHandleTarget : null)
|
|
518
|
+
)
|
|
519
|
+
}
|
|
520
|
+
if (basename !== 'bindings' && basename !== 'bindings.native') return null
|
|
521
|
+
// don't redirect bindings imports that already resolved to our file
|
|
522
|
+
if (importer === target) return null
|
|
523
|
+
return target
|
|
524
|
+
},
|
|
501
525
|
},
|
|
502
|
-
load
|
|
503
|
-
|
|
526
|
+
load: {
|
|
527
|
+
filter: {
|
|
528
|
+
id: new RegExp(`^${virtualIdPrefix}sootsim:rnkc-find-node-handle-native$`),
|
|
529
|
+
},
|
|
530
|
+
handler() {
|
|
504
531
|
return `export { findNodeHandle } from ${JSON.stringify(rnShimPath)};`
|
|
505
|
-
}
|
|
506
|
-
return null
|
|
532
|
+
},
|
|
507
533
|
},
|
|
508
534
|
}
|
|
509
535
|
}
|
|
@@ -549,58 +575,68 @@ export function reanimatedNativeSeamRedirect(): Plugin {
|
|
|
549
575
|
return {
|
|
550
576
|
name: 'sootsim-reanimated-native-seam-redirect',
|
|
551
577
|
enforce: 'pre',
|
|
552
|
-
resolveId
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
if (basename === 'fabricUtils' && importer !== reanimatedFabricUtilsRedirectPath) {
|
|
582
|
-
return reanimatedFabricUtilsRedirectPath
|
|
583
|
-
}
|
|
584
|
-
if (!reanimatedNativeSeamFiles.has(basename)) return null
|
|
585
|
-
if (process.env.SOOTSIM_REANIMATED_REDIRECT_DEBUG) {
|
|
586
|
-
console.log(
|
|
587
|
-
'[reanimatedRedirect]',
|
|
588
|
-
basename,
|
|
589
|
-
'<-',
|
|
590
|
-
source,
|
|
591
|
-
'from',
|
|
592
|
-
importer.slice(-80),
|
|
578
|
+
resolveId: {
|
|
579
|
+
filter: {
|
|
580
|
+
id: /(?:^react-native-worklets\/package\.json$|^react-native-reanimated\/scripts\/validate-worklets-version(?:\.js)?$|(?:^|\/)(?:fabricUtils|NativeReanimatedModule|scrollTo|measure|setNativeProps|dispatchCommand|setGestureState)(?:\.(?:native|web|ios|android))?$)/,
|
|
581
|
+
},
|
|
582
|
+
handler(source, importer) {
|
|
583
|
+
// upstream's `assertWorkletsVersion` (DEV-only) imports a build-time
|
|
584
|
+
// script that does `require('react-native-worklets/package.json')`.
|
|
585
|
+
// our flat-file stub for react-native-worklets has no such subpath,
|
|
586
|
+
// so this throws under vite's worker build. resolve the package.json
|
|
587
|
+
// import to a synthetic virtual id and load synthetic JSON below.
|
|
588
|
+
if (source === 'react-native-worklets/package.json') {
|
|
589
|
+
return '\0sootsim:react-native-worklets-package-json'
|
|
590
|
+
}
|
|
591
|
+
if (!importer) return null
|
|
592
|
+
// no-op the assertWorkletsVersion validator — same reason. matches both
|
|
593
|
+
// the bare import and the .js-suffixed resolved form some bundlers see.
|
|
594
|
+
if (
|
|
595
|
+
source === 'react-native-reanimated/scripts/validate-worklets-version' ||
|
|
596
|
+
source === 'react-native-reanimated/scripts/validate-worklets-version.js'
|
|
597
|
+
) {
|
|
598
|
+
return reanimatedValidateWorkletsVersionPath
|
|
599
|
+
}
|
|
600
|
+
if (!importer.includes('/react-native-reanimated/')) return null
|
|
601
|
+
if (importer === target) return null
|
|
602
|
+
// strip optional `.web` / `.native` extension and leading `./`s — the
|
|
603
|
+
// redirect should match regardless of relative depth or platform suffix.
|
|
604
|
+
const basename = (source.split('/').pop() ?? '').replace(
|
|
605
|
+
/\.(native|web|ios|android)$/,
|
|
606
|
+
'',
|
|
593
607
|
)
|
|
594
|
-
|
|
595
|
-
|
|
608
|
+
// keep fabricUtils on the SootSim Fabric public-instance contract. the
|
|
609
|
+
// redirected module reads the constructor-attached handle for native
|
|
610
|
+
// refs and uses ReactFabric's renderer lookup for composite refs.
|
|
611
|
+
if (
|
|
612
|
+
basename === 'fabricUtils' &&
|
|
613
|
+
importer !== reanimatedFabricUtilsRedirectPath
|
|
614
|
+
) {
|
|
615
|
+
return reanimatedFabricUtilsRedirectPath
|
|
616
|
+
}
|
|
617
|
+
if (!reanimatedNativeSeamFiles.has(basename)) return null
|
|
618
|
+
if (process.env.SOOTSIM_REANIMATED_REDIRECT_DEBUG) {
|
|
619
|
+
console.log(
|
|
620
|
+
'[reanimatedRedirect]',
|
|
621
|
+
basename,
|
|
622
|
+
'<-',
|
|
623
|
+
source,
|
|
624
|
+
'from',
|
|
625
|
+
importer.slice(-80),
|
|
626
|
+
)
|
|
627
|
+
}
|
|
628
|
+
return target
|
|
629
|
+
},
|
|
596
630
|
},
|
|
597
|
-
load
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
631
|
+
load: {
|
|
632
|
+
filter: {
|
|
633
|
+
id: new RegExp(`^${virtualIdPrefix}sootsim:react-native-worklets-package-json$`),
|
|
634
|
+
},
|
|
635
|
+
handler() {
|
|
636
|
+
// synthetic package.json for react-native-worklets — see resolveId
|
|
637
|
+
// above. just enough for upstream's version-validator to read `version`.
|
|
601
638
|
return `export default ${JSON.stringify({ version: '0.0.0-sootsim', name: 'react-native-worklets' })}`
|
|
602
|
-
}
|
|
603
|
-
return null
|
|
639
|
+
},
|
|
604
640
|
},
|
|
605
641
|
}
|
|
606
642
|
}
|
|
@@ -632,42 +668,51 @@ export function manifestNativeSeamRedirect(): Plugin {
|
|
|
632
668
|
})
|
|
633
669
|
}
|
|
634
670
|
}
|
|
671
|
+
const sourceFilter = new RegExp(
|
|
672
|
+
`(?:^|/)(?:${[...byPkg.values()]
|
|
673
|
+
.flatMap(({ basenames }) => [...basenames])
|
|
674
|
+
.map((basename) => basename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
675
|
+
.join('|')})(?:\\.(?:native|web|ios|android))?$`,
|
|
676
|
+
)
|
|
635
677
|
return {
|
|
636
678
|
name: 'sootsim-manifest-native-seam-redirect',
|
|
637
679
|
enforce: 'pre',
|
|
638
|
-
resolveId
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
680
|
+
resolveId: {
|
|
681
|
+
filter: { id: sourceFilter },
|
|
682
|
+
handler(source, importer) {
|
|
683
|
+
if (!importer || byPkg.size === 0) return null
|
|
684
|
+
// find the package whose path appears in the importer. matches both
|
|
685
|
+
// `/<pkg>/` (unscoped) and `/@scope/<pkg>/` (scoped — the leading `@`
|
|
686
|
+
// is part of the pkg name in the manifest, e.g. `@notifee/react-native`).
|
|
687
|
+
let match: { basenames: Set<string>; target: string; notes?: string } | undefined
|
|
688
|
+
let matchedPkg: string | undefined
|
|
689
|
+
for (const [pkg, entry] of byPkg) {
|
|
690
|
+
if (importer.includes(`/${pkg}/`)) {
|
|
691
|
+
match = entry
|
|
692
|
+
matchedPkg = pkg
|
|
693
|
+
break
|
|
694
|
+
}
|
|
650
695
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
'',
|
|
657
|
-
)
|
|
658
|
-
if (!match.basenames.has(basename)) return null
|
|
659
|
-
if (process.env.SOOTSIM_NATIVE_SEAM_DEBUG) {
|
|
660
|
-
console.log(
|
|
661
|
-
'[nativeSeamRedirect]',
|
|
662
|
-
`${matchedPkg}:${basename}`,
|
|
663
|
-
'<-',
|
|
664
|
-
source,
|
|
665
|
-
'from',
|
|
666
|
-
importer.slice(-80),
|
|
667
|
-
match.notes ? `(${match.notes})` : '',
|
|
696
|
+
if (!match) return null
|
|
697
|
+
if (importer === match.target) return null
|
|
698
|
+
const basename = (source.split('/').pop() ?? '').replace(
|
|
699
|
+
/\.(native|web|ios|android)$/,
|
|
700
|
+
'',
|
|
668
701
|
)
|
|
669
|
-
|
|
670
|
-
|
|
702
|
+
if (!match.basenames.has(basename)) return null
|
|
703
|
+
if (process.env.SOOTSIM_NATIVE_SEAM_DEBUG) {
|
|
704
|
+
console.log(
|
|
705
|
+
'[nativeSeamRedirect]',
|
|
706
|
+
`${matchedPkg}:${basename}`,
|
|
707
|
+
'<-',
|
|
708
|
+
source,
|
|
709
|
+
'from',
|
|
710
|
+
importer.slice(-80),
|
|
711
|
+
match.notes ? `(${match.notes})` : '',
|
|
712
|
+
)
|
|
713
|
+
}
|
|
714
|
+
return match.target
|
|
715
|
+
},
|
|
671
716
|
},
|
|
672
717
|
}
|
|
673
718
|
}
|
|
@@ -689,6 +734,7 @@ export function wsBridgePlugin(): Plugin {
|
|
|
689
734
|
let boundPort: Promise<number | null> | null = null
|
|
690
735
|
return {
|
|
691
736
|
name: 'sootsim-ws-bridge',
|
|
737
|
+
apply: 'serve',
|
|
692
738
|
configureServer(server) {
|
|
693
739
|
if (boundPort) return
|
|
694
740
|
// lazy import to avoid pulling ws into the main bundle.
|
|
@@ -1001,67 +1047,45 @@ function sootsimConfigPlugin(
|
|
|
1001
1047
|
// react-reconciler code. this enables runtime React version switching for
|
|
1002
1048
|
// external app bundles — bindReact(appReact) swaps which React all code uses.
|
|
1003
1049
|
function reactBridgePlugin(): Plugin {
|
|
1004
|
-
let isBuild = false
|
|
1005
1050
|
let redirectCount = 0
|
|
1006
|
-
let skipCount = 0
|
|
1007
1051
|
return {
|
|
1008
1052
|
name: 'sootsim-react-bridge',
|
|
1053
|
+
apply: 'serve',
|
|
1009
1054
|
enforce: 'pre',
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1055
|
+
resolveId: {
|
|
1056
|
+
filter: { id: /^react$/ },
|
|
1057
|
+
async handler(_source, importer, options) {
|
|
1058
|
+
if (!importer) return null
|
|
1059
|
+
|
|
1060
|
+
// skip during dep scanning / SSR — only active in browser serve mode
|
|
1061
|
+
if ((options as { scan?: boolean })?.scan || options?.ssr) return null
|
|
1062
|
+
|
|
1063
|
+
// only redirect imports from sootsim, sootsim-engine, compat, and react-reconciler
|
|
1064
|
+
const shouldRedirect =
|
|
1065
|
+
importer.includes('/sootsim/src/') ||
|
|
1066
|
+
importer.includes('/sootsim-engine/src/') ||
|
|
1067
|
+
importer.includes('/compat/src/') ||
|
|
1068
|
+
importer.includes('react-reconciler')
|
|
1069
|
+
|
|
1070
|
+
if (!shouldRedirect) return null
|
|
1071
|
+
|
|
1072
|
+
// don't redirect react-bridge's own import of react (avoid infinite loop)
|
|
1073
|
+
if (importer.includes('react-bridge')) return null
|
|
1074
|
+
|
|
1075
|
+
// stub-registry needs the real React (with __CLIENT_INTERNALS) for bundle stubs
|
|
1076
|
+
if (importer.includes('stub-registry')) return null
|
|
1077
|
+
|
|
1078
|
+
redirectCount++
|
|
1079
|
+
if (redirectCount <= 10) {
|
|
1080
|
+
console.log(
|
|
1081
|
+
'[react-bridge-plugin] REDIRECTING:',
|
|
1082
|
+
importer.split('/').slice(-3).join('/'),
|
|
1083
|
+
)
|
|
1084
|
+
} else if (redirectCount === 11) {
|
|
1085
|
+
console.log('[react-bridge-plugin] ... more redirects')
|
|
1034
1086
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
// skip during dep scanning / SSR — only active in browser serve mode
|
|
1038
|
-
if ((options as { scan?: boolean })?.scan || options?.ssr || isBuild) return null
|
|
1039
|
-
|
|
1040
|
-
// only redirect imports from sootsim, sootsim-engine, compat, and react-reconciler
|
|
1041
|
-
const shouldRedirect =
|
|
1042
|
-
importer.includes('/sootsim/src/') ||
|
|
1043
|
-
importer.includes('/sootsim-engine/src/') ||
|
|
1044
|
-
importer.includes('/compat/src/') ||
|
|
1045
|
-
importer.includes('react-reconciler')
|
|
1046
|
-
|
|
1047
|
-
if (!shouldRedirect) return null
|
|
1048
|
-
|
|
1049
|
-
// don't redirect react-bridge's own import of react (avoid infinite loop)
|
|
1050
|
-
if (importer.includes('react-bridge')) return null
|
|
1051
|
-
|
|
1052
|
-
// stub-registry needs the real React (with __CLIENT_INTERNALS) for bundle stubs
|
|
1053
|
-
if (importer.includes('stub-registry')) return null
|
|
1054
|
-
|
|
1055
|
-
redirectCount++
|
|
1056
|
-
if (redirectCount <= 10) {
|
|
1057
|
-
console.log(
|
|
1058
|
-
'[react-bridge-plugin] REDIRECTING:',
|
|
1059
|
-
importer.split('/').slice(-3).join('/'),
|
|
1060
|
-
)
|
|
1061
|
-
} else if (redirectCount === 11) {
|
|
1062
|
-
console.log('[react-bridge-plugin] ... more redirects')
|
|
1063
|
-
}
|
|
1064
|
-
return { id: reactBridgePath, external: false }
|
|
1087
|
+
return { id: reactBridgePath, external: false }
|
|
1088
|
+
},
|
|
1065
1089
|
},
|
|
1066
1090
|
}
|
|
1067
1091
|
}
|
|
@@ -1073,34 +1097,37 @@ export function workerReactBridgePlugin(): Plugin {
|
|
|
1073
1097
|
return {
|
|
1074
1098
|
name: 'sootsim-worker-react-bridge',
|
|
1075
1099
|
enforce: 'pre',
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1100
|
+
resolveId: {
|
|
1101
|
+
filter: { id: /^react$/ },
|
|
1102
|
+
async handler(_source, importer, options) {
|
|
1103
|
+
if (!importer) return null
|
|
1104
|
+
|
|
1105
|
+
// skip during dep scanning / SSR
|
|
1106
|
+
if ((options as { scan?: boolean })?.scan || options?.ssr) return null
|
|
1107
|
+
|
|
1108
|
+
// don't redirect react-bridge's own import of react (avoid infinite loop)
|
|
1109
|
+
if (importer.includes('react-bridge')) return null
|
|
1110
|
+
|
|
1111
|
+
// stub-registry needs the real React (with __CLIENT_INTERNALS) for bundle stubs
|
|
1112
|
+
if (importer.includes('stub-registry')) return null
|
|
1113
|
+
|
|
1114
|
+
// redirect react imports from sootsim, sootsim-engine, compat, react-reconciler,
|
|
1115
|
+
// and any pure-JS RN-ecosystem package the bundle pulls in. without this
|
|
1116
|
+
// redirect, packages like react-native-drawer-layout / use-latest-callback
|
|
1117
|
+
// call into a separate React instance than the renderer/bridge does, so
|
|
1118
|
+
// their useRef/useEffect refs collide with the engine's hooks state and
|
|
1119
|
+
// we hit "Maximum update depth exceeded" infinite-loop renders.
|
|
1120
|
+
const shouldRedirect =
|
|
1121
|
+
importer.includes('/sootsim/src/') ||
|
|
1122
|
+
importer.includes('/sootsim-engine/src/') ||
|
|
1123
|
+
importer.includes('/compat/src/') ||
|
|
1124
|
+
importer.includes('react-reconciler') ||
|
|
1125
|
+
importer.includes('/node_modules/')
|
|
1126
|
+
|
|
1127
|
+
if (!shouldRedirect) return null
|
|
1128
|
+
|
|
1129
|
+
return { id: reactBridgePath, external: false }
|
|
1130
|
+
},
|
|
1104
1131
|
},
|
|
1105
1132
|
}
|
|
1106
1133
|
}
|
|
@@ -1113,8 +1140,9 @@ export function fixJsxRuntimeExports(): Plugin {
|
|
|
1113
1140
|
return {
|
|
1114
1141
|
name: 'sootsim-fix-jsx-runtime',
|
|
1115
1142
|
enforce: 'pre',
|
|
1116
|
-
|
|
1117
|
-
|
|
1143
|
+
resolveId: {
|
|
1144
|
+
filter: { id: /^react\/jsx-(?:dev-)?runtime$/ },
|
|
1145
|
+
async handler(source, importer, options) {
|
|
1118
1146
|
const resolved = await this.resolve(source, importer, {
|
|
1119
1147
|
...options,
|
|
1120
1148
|
skipSelf: true,
|
|
@@ -1125,38 +1153,42 @@ export function fixJsxRuntimeExports(): Plugin {
|
|
|
1125
1153
|
? '\0sootsim:jsx-runtime:'
|
|
1126
1154
|
: '\0sootsim:jsx-dev-runtime:'
|
|
1127
1155
|
return prefix + resolved.id
|
|
1128
|
-
}
|
|
1129
|
-
return null
|
|
1156
|
+
},
|
|
1130
1157
|
},
|
|
1131
|
-
load
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1158
|
+
load: {
|
|
1159
|
+
filter: {
|
|
1160
|
+
id: new RegExp(`^${virtualIdPrefix}sootsim:jsx-(?:dev-)?runtime:`),
|
|
1161
|
+
},
|
|
1162
|
+
handler(id) {
|
|
1163
|
+
if (id.startsWith('\0sootsim:jsx-runtime:')) {
|
|
1164
|
+
const realId = id.slice('\0sootsim:jsx-runtime:'.length)
|
|
1165
|
+
return [
|
|
1166
|
+
`import * as _mod from ${JSON.stringify(realId)};`,
|
|
1167
|
+
`const _m = _mod.default || _mod;`,
|
|
1168
|
+
`export const jsx = _m.jsx || _mod.jsx;`,
|
|
1169
|
+
`export const jsxs = _m.jsxs || _mod.jsxs;`,
|
|
1170
|
+
`export const Fragment = _m.Fragment || _mod.Fragment;`,
|
|
1171
|
+
].join('\n')
|
|
1172
|
+
}
|
|
1173
|
+
if (id.startsWith('\0sootsim:jsx-dev-runtime:')) {
|
|
1174
|
+
const realId = id.slice('\0sootsim:jsx-dev-runtime:'.length)
|
|
1175
|
+
// react/jsx-runtime is already wrapped by this plugin (above) to expose
|
|
1176
|
+
// { jsx, jsxs, Fragment } as named exports, so read them directly from
|
|
1177
|
+
// the namespace — no `_runtime.default || _runtime` fallback needed.
|
|
1178
|
+
// rolldown statically knows the wrapped module has no default export
|
|
1179
|
+
// and would emit IMPORT_IS_UNDEFINED warnings on every build.
|
|
1180
|
+
return [
|
|
1181
|
+
`import * as _mod from ${JSON.stringify(realId)};`,
|
|
1182
|
+
`import * as _runtime from "react/jsx-runtime";`,
|
|
1183
|
+
`const _m = _mod.default || _mod;`,
|
|
1184
|
+
// production React builds may not expose jsxDEV from react/jsx-dev-runtime.
|
|
1185
|
+
// fall back to jsx so transformed modules still execute.
|
|
1186
|
+
`export const jsxDEV = _m.jsxDEV || _mod.jsxDEV || _m.jsx || _mod.jsx || _runtime.jsx;`,
|
|
1187
|
+
`export const Fragment = _m.Fragment || _mod.Fragment || _runtime.Fragment;`,
|
|
1188
|
+
].join('\n')
|
|
1189
|
+
}
|
|
1190
|
+
return null
|
|
1191
|
+
},
|
|
1160
1192
|
},
|
|
1161
1193
|
}
|
|
1162
1194
|
}
|
|
@@ -1331,21 +1363,30 @@ export function workletsBabelTransform(
|
|
|
1331
1363
|
return {
|
|
1332
1364
|
name: 'sootsim-worklets-babel-transform',
|
|
1333
1365
|
enforce: 'pre',
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1366
|
+
transform: {
|
|
1367
|
+
filter: {
|
|
1368
|
+
id: {
|
|
1369
|
+
include: /\.(?:tsx?|jsx?|mjs|cjs|mts|cts)$/,
|
|
1370
|
+
exclude: /node_modules\/(?:react|react-dom|react-native|react-native-web)\//,
|
|
1371
|
+
},
|
|
1372
|
+
code: REANIMATED_WORKLETIZATION_REGEX,
|
|
1373
|
+
},
|
|
1374
|
+
async handler(code, id) {
|
|
1375
|
+
if (!shouldApplyWorkletsPlugin(id, code)) return null
|
|
1376
|
+
try {
|
|
1377
|
+
if (process.env.SOOTSIM_WORKLETS_BABEL_DEBUG) {
|
|
1378
|
+
console.log('[worklets-babel] transforming', id.slice(-80))
|
|
1379
|
+
}
|
|
1380
|
+
return await transformWorkletsCode(code, id, true)
|
|
1381
|
+
} catch (err) {
|
|
1382
|
+
// surface but don't kill the build — fall back to raw code so the
|
|
1383
|
+
// rest of the pipeline can run. these failures are loud in the
|
|
1384
|
+
// console and easy to chase.
|
|
1385
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
1386
|
+
console.warn(`[sootsim-worklets-babel] transform failed for ${id}: ${message}`)
|
|
1387
|
+
return null
|
|
1339
1388
|
}
|
|
1340
|
-
|
|
1341
|
-
} catch (err) {
|
|
1342
|
-
// surface but don't kill the build — fall back to raw code so the
|
|
1343
|
-
// rest of the pipeline can run. these failures are loud in the
|
|
1344
|
-
// console and easy to chase.
|
|
1345
|
-
const message = err instanceof Error ? err.message : String(err)
|
|
1346
|
-
console.warn(`[sootsim-worklets-babel] transform failed for ${id}: ${message}`)
|
|
1347
|
-
return null
|
|
1348
|
-
}
|
|
1389
|
+
},
|
|
1349
1390
|
},
|
|
1350
1391
|
}
|
|
1351
1392
|
}
|
|
@@ -1375,21 +1416,24 @@ function flowStripTransform(): Plugin {
|
|
|
1375
1416
|
return {
|
|
1376
1417
|
name: 'sootsim-flow-strip',
|
|
1377
1418
|
enforce: 'pre',
|
|
1378
|
-
transform
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1419
|
+
transform: {
|
|
1420
|
+
filter: {
|
|
1421
|
+
id: /\/node_modules\/.*\.[cm]?jsx?$/,
|
|
1422
|
+
code: /@flow/,
|
|
1423
|
+
},
|
|
1424
|
+
handler(code, id) {
|
|
1425
|
+
loadFlowBabel()
|
|
1426
|
+
const result = flowBabel!.transformSync(code, {
|
|
1427
|
+
filename: id,
|
|
1428
|
+
babelrc: false,
|
|
1429
|
+
configFile: false,
|
|
1430
|
+
plugins: [flowStripPlugin!, jsxSyntaxPlugin!],
|
|
1431
|
+
sourceMaps: true,
|
|
1432
|
+
compact: false,
|
|
1433
|
+
})
|
|
1434
|
+
if (!result?.code) return null
|
|
1435
|
+
return { code: result.code, map: result.map ?? null }
|
|
1436
|
+
},
|
|
1393
1437
|
},
|
|
1394
1438
|
}
|
|
1395
1439
|
}
|
|
@@ -1398,20 +1442,23 @@ function nodeModulesJsxTransform(): Plugin {
|
|
|
1398
1442
|
return {
|
|
1399
1443
|
name: 'sootsim-node-modules-jsx',
|
|
1400
1444
|
enforce: 'pre',
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1445
|
+
transform: {
|
|
1446
|
+
filter: {
|
|
1447
|
+
id: /\/node_modules\/.*\.js$/,
|
|
1448
|
+
code: /</,
|
|
1449
|
+
},
|
|
1450
|
+
async handler(code, id) {
|
|
1451
|
+
// quick check: does it look like JSX? (angle bracket followed by uppercase or known RN component)
|
|
1452
|
+
if (!/[=(\s,]<[A-Z]/.test(code) && !/<\/[A-Z]/.test(code)) return null
|
|
1453
|
+
const needsReact =
|
|
1454
|
+
!code.includes('import React') && !code.includes('import * as React')
|
|
1455
|
+
const withReact = needsReact ? `import React from 'react';\n${code}` : code
|
|
1456
|
+
const transformed = await transformWithOxc(withReact, id, {
|
|
1457
|
+
lang: 'jsx',
|
|
1458
|
+
jsx: { runtime: 'classic' },
|
|
1459
|
+
})
|
|
1460
|
+
return { code: transformed.code, map: transformed.map }
|
|
1461
|
+
},
|
|
1415
1462
|
},
|
|
1416
1463
|
}
|
|
1417
1464
|
}
|
|
@@ -1450,29 +1497,31 @@ function metroNativeResolve(isAppSource: (p: string) => boolean): Plugin {
|
|
|
1450
1497
|
return {
|
|
1451
1498
|
name: 'sootsim-metro-native-resolve',
|
|
1452
1499
|
enforce: 'pre',
|
|
1453
|
-
resolveId
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1500
|
+
resolveId: {
|
|
1501
|
+
filter: { id: /^\./ },
|
|
1502
|
+
handler(source, importer) {
|
|
1503
|
+
if (!importer) return null
|
|
1504
|
+
if (!importer.includes('node_modules') && !isAppSource(importer)) return null
|
|
1505
|
+
if (platformExts.some((ext) => source.endsWith(ext))) return null
|
|
1506
|
+
|
|
1507
|
+
const dir = path.dirname(importer)
|
|
1508
|
+
|
|
1509
|
+
const hasBaseExt = allExts.some((ext) => source.endsWith(ext))
|
|
1510
|
+
if (hasBaseExt) {
|
|
1511
|
+
const resolved = path.resolve(dir, source)
|
|
1512
|
+
for (const ext of allExts) {
|
|
1513
|
+
if (source.endsWith(ext)) {
|
|
1514
|
+
const found = tryResolve(resolved.slice(0, -ext.length))
|
|
1515
|
+
if (found) return found
|
|
1516
|
+
break
|
|
1517
|
+
}
|
|
1469
1518
|
}
|
|
1519
|
+
} else {
|
|
1520
|
+
const found = tryResolve(path.resolve(dir, source))
|
|
1521
|
+
if (found) return found
|
|
1470
1522
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
if (found) return found
|
|
1474
|
-
}
|
|
1475
|
-
return null
|
|
1523
|
+
return null
|
|
1524
|
+
},
|
|
1476
1525
|
},
|
|
1477
1526
|
}
|
|
1478
1527
|
}
|
|
@@ -1482,54 +1531,56 @@ function reactNativeRequirePlugin(isAppSource: (p: string) => boolean): Plugin {
|
|
|
1482
1531
|
return {
|
|
1483
1532
|
name: 'sootsim-react-native-require',
|
|
1484
1533
|
enforce: 'pre',
|
|
1485
|
-
transform
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1534
|
+
transform: {
|
|
1535
|
+
filter: { code: /react-native/ },
|
|
1536
|
+
handler(code, id) {
|
|
1537
|
+
if (!id.includes('node_modules') && !isAppSource(id)) return null
|
|
1538
|
+
|
|
1539
|
+
let hasChanges = false
|
|
1540
|
+
let imports = ''
|
|
1541
|
+
let result = code
|
|
1542
|
+
let importCounter = 0
|
|
1543
|
+
|
|
1544
|
+
if (
|
|
1545
|
+
result.includes('require("react-native")') ||
|
|
1546
|
+
result.includes("require('react-native')")
|
|
1547
|
+
) {
|
|
1548
|
+
imports += `import * as __soot_rn_shim__ from ${JSON.stringify(rnShimPath)};\n`
|
|
1549
|
+
result = result.replace(/require\(["']react-native["']\)/g, '__soot_rn_shim__')
|
|
1550
|
+
hasChanges = true
|
|
1551
|
+
}
|
|
1502
1552
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1553
|
+
const deepRequireRegex = /require\(["'](react-native\/Libraries\/[^"']+)["']\)/g
|
|
1554
|
+
const replacements: Array<{ full: string; path: string; varName: string }> = []
|
|
1555
|
+
const seenPaths = new Map<string, string>()
|
|
1556
|
+
let match
|
|
1557
|
+
|
|
1558
|
+
deepRequireRegex.lastIndex = 0
|
|
1559
|
+
while ((match = deepRequireRegex.exec(result)) !== null) {
|
|
1560
|
+
const importPath = match[1]
|
|
1561
|
+
if (!seenPaths.has(importPath)) {
|
|
1562
|
+
const varName = `__soot_rn_lib_${importCounter++}__`
|
|
1563
|
+
const stubPath = rnLibraryStubs[importPath] || rnDeepStubDefault
|
|
1564
|
+
imports += `import * as ${varName} from ${JSON.stringify(stubPath)};\n`
|
|
1565
|
+
seenPaths.set(importPath, varName)
|
|
1566
|
+
}
|
|
1567
|
+
replacements.push({
|
|
1568
|
+
full: match[0],
|
|
1569
|
+
path: importPath,
|
|
1570
|
+
varName: seenPaths.get(importPath)!,
|
|
1571
|
+
})
|
|
1516
1572
|
}
|
|
1517
|
-
replacements.push({
|
|
1518
|
-
full: match[0],
|
|
1519
|
-
path: importPath,
|
|
1520
|
-
varName: seenPaths.get(importPath)!,
|
|
1521
|
-
})
|
|
1522
|
-
}
|
|
1523
1573
|
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1574
|
+
if (replacements.length > 0) {
|
|
1575
|
+
for (const rep of replacements) {
|
|
1576
|
+
result = result.replace(rep.full, rep.varName)
|
|
1577
|
+
}
|
|
1578
|
+
hasChanges = true
|
|
1527
1579
|
}
|
|
1528
|
-
hasChanges = true
|
|
1529
|
-
}
|
|
1530
1580
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1581
|
+
if (!hasChanges) return null
|
|
1582
|
+
return { code: imports + result, map: null }
|
|
1583
|
+
},
|
|
1533
1584
|
},
|
|
1534
1585
|
}
|
|
1535
1586
|
}
|
|
@@ -1540,8 +1591,6 @@ function externalAppResolvePlugin(
|
|
|
1540
1591
|
isAppSource: (p: string) => boolean,
|
|
1541
1592
|
ownedPackages: Set<string>,
|
|
1542
1593
|
): Plugin {
|
|
1543
|
-
if (!appDir) return { name: 'sootsim-external-app-resolve' }
|
|
1544
|
-
|
|
1545
1594
|
// synthetic importer inside the app dir so vite searches app's node_modules
|
|
1546
1595
|
// using its conditions-aware exports resolution (not CJS require.resolve)
|
|
1547
1596
|
const appVirtualImporter = path.join(appDir, '_virtual_.js')
|
|
@@ -1574,56 +1623,60 @@ function externalAppTransformPlugin(isAppSource: (p: string) => boolean): Plugin
|
|
|
1574
1623
|
return {
|
|
1575
1624
|
name: 'sootsim-external-app-transform',
|
|
1576
1625
|
enforce: 'pre',
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
seenPaths.
|
|
1626
|
+
transform: {
|
|
1627
|
+
filter: { code: /require\(|</ },
|
|
1628
|
+
async handler(code, id) {
|
|
1629
|
+
if (!isAppSource(id)) return null
|
|
1630
|
+
|
|
1631
|
+
let result = code
|
|
1632
|
+
let imports = ''
|
|
1633
|
+
let importCounter = 0
|
|
1634
|
+
let hasChanges = false
|
|
1635
|
+
|
|
1636
|
+
if (code.includes('require(')) {
|
|
1637
|
+
const requireRegex = /require\(["']([^"']+)["']\)/g
|
|
1638
|
+
const replacements: Array<{ full: string; varName: string }> = []
|
|
1639
|
+
const seenPaths = new Map<string, string>()
|
|
1640
|
+
let match
|
|
1641
|
+
|
|
1642
|
+
requireRegex.lastIndex = 0
|
|
1643
|
+
while ((match = requireRegex.exec(result)) !== null) {
|
|
1644
|
+
const reqPath = match[1]
|
|
1645
|
+
if (reqPath === 'react-native' || reqPath.startsWith('react-native/'))
|
|
1646
|
+
continue
|
|
1647
|
+
|
|
1648
|
+
if (!seenPaths.has(reqPath)) {
|
|
1649
|
+
const varName = `__soot_cjs_${importCounter++}__`
|
|
1650
|
+
imports += `import * as ${varName} from ${JSON.stringify(reqPath)};\n`
|
|
1651
|
+
seenPaths.set(reqPath, varName)
|
|
1652
|
+
}
|
|
1653
|
+
replacements.push({ full: match[0], varName: seenPaths.get(reqPath)! })
|
|
1600
1654
|
}
|
|
1601
|
-
replacements.push({ full: match[0], varName: seenPaths.get(reqPath)! })
|
|
1602
|
-
}
|
|
1603
1655
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1656
|
+
if (replacements.length > 0) {
|
|
1657
|
+
for (const rep of replacements) {
|
|
1658
|
+
result = result.replace(rep.full, rep.varName)
|
|
1659
|
+
}
|
|
1660
|
+
hasChanges = true
|
|
1607
1661
|
}
|
|
1608
|
-
hasChanges = true
|
|
1609
1662
|
}
|
|
1610
|
-
}
|
|
1611
1663
|
|
|
1612
|
-
|
|
1664
|
+
if (imports) result = imports + result
|
|
1613
1665
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1666
|
+
if (id.endsWith('.js') && result.includes('<')) {
|
|
1667
|
+
const needsReact =
|
|
1668
|
+
!result.includes('import React') && !result.includes('import * as React')
|
|
1669
|
+
const withReact = needsReact ? `import React from 'react';\n${result}` : result
|
|
1670
|
+
const transformed = await transformWithOxc(withReact, id, {
|
|
1671
|
+
lang: 'jsx',
|
|
1672
|
+
jsx: { runtime: 'classic' },
|
|
1673
|
+
})
|
|
1674
|
+
return { code: transformed.code, map: transformed.map }
|
|
1675
|
+
}
|
|
1624
1676
|
|
|
1625
|
-
|
|
1626
|
-
|
|
1677
|
+
if (!hasChanges) return null
|
|
1678
|
+
return { code: result, map: null }
|
|
1679
|
+
},
|
|
1627
1680
|
},
|
|
1628
1681
|
}
|
|
1629
1682
|
}
|
|
@@ -1658,17 +1711,20 @@ function stubMissingImages(isAppSource: (p: string) => boolean): Plugin {
|
|
|
1658
1711
|
return {
|
|
1659
1712
|
name: 'sootsim-stub-images',
|
|
1660
1713
|
enforce: 'pre',
|
|
1661
|
-
resolveId
|
|
1662
|
-
|
|
1714
|
+
resolveId: {
|
|
1715
|
+
filter: { id: /\.(?:jpg|png|gif)$/ },
|
|
1716
|
+
handler(id, importer) {
|
|
1663
1717
|
if (importer?.includes('node_modules') || (importer && isAppSource(importer))) {
|
|
1664
1718
|
return '\0stub-image'
|
|
1665
1719
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1720
|
+
return null
|
|
1721
|
+
},
|
|
1668
1722
|
},
|
|
1669
|
-
load
|
|
1670
|
-
|
|
1671
|
-
|
|
1723
|
+
load: {
|
|
1724
|
+
filter: { id: new RegExp(`^${virtualIdPrefix}stub-image$`) },
|
|
1725
|
+
handler() {
|
|
1726
|
+
return 'export default ""'
|
|
1727
|
+
},
|
|
1672
1728
|
},
|
|
1673
1729
|
}
|
|
1674
1730
|
}
|