vxrn 1.26.0 → 1.26.1

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.
Files changed (42) hide show
  1. package/dist/plugins/reactNativeDevServer.mjs +123 -42
  2. package/dist/plugins/reactNativeDevServer.mjs.map +1 -1
  3. package/dist/plugins/reactNativeDevServer.native.js +209 -44
  4. package/dist/plugins/reactNativeDevServer.native.js.map +1 -1
  5. package/dist/rn-commands/bundle/buildBundle.mjs +29 -10
  6. package/dist/rn-commands/bundle/buildBundle.mjs.map +1 -1
  7. package/dist/rn-commands/bundle/buildBundle.native.js +29 -10
  8. package/dist/rn-commands/bundle/buildBundle.native.js.map +1 -1
  9. package/dist/utils/createNativeDevEngine.mjs +220 -83
  10. package/dist/utils/createNativeDevEngine.mjs.map +1 -1
  11. package/dist/utils/createNativeDevEngine.native.js +257 -84
  12. package/dist/utils/createNativeDevEngine.native.js.map +1 -1
  13. package/dist/utils/createNativeDevEngine.test.mjs +285 -23
  14. package/dist/utils/createNativeDevEngine.test.mjs.map +1 -1
  15. package/dist/utils/createNativeDevEngine.test.native.js +319 -23
  16. package/dist/utils/createNativeDevEngine.test.native.js.map +1 -1
  17. package/dist/utils/patches.test.mjs.map +1 -1
  18. package/dist/utils/patches.test.native.js.map +1 -1
  19. package/dist/utils/symbolicateNativeStack.mjs +66 -0
  20. package/dist/utils/symbolicateNativeStack.mjs.map +1 -0
  21. package/dist/utils/symbolicateNativeStack.native.js +70 -0
  22. package/dist/utils/symbolicateNativeStack.native.js.map +1 -0
  23. package/dist/utils/symbolicateNativeStack.test.mjs +96 -0
  24. package/dist/utils/symbolicateNativeStack.test.mjs.map +1 -0
  25. package/dist/utils/symbolicateNativeStack.test.native.js +96 -0
  26. package/dist/utils/symbolicateNativeStack.test.native.js.map +1 -0
  27. package/package.json +12 -11
  28. package/src/plugins/reactNativeDevServer.ts +162 -50
  29. package/src/rn-commands/bundle/buildBundle.ts +28 -9
  30. package/src/utils/createNativeDevEngine.test.ts +581 -193
  31. package/src/utils/createNativeDevEngine.ts +434 -115
  32. package/src/utils/patches.test.ts +1 -4
  33. package/src/utils/symbolicateNativeStack.test.ts +78 -0
  34. package/src/utils/symbolicateNativeStack.ts +129 -0
  35. package/types/plugins/reactNativeDevServer.d.ts.map +1 -1
  36. package/types/rn-commands/bundle/buildBundle.d.ts.map +1 -1
  37. package/types/utils/createNativeDevEngine.d.ts +23 -4
  38. package/types/utils/createNativeDevEngine.d.ts.map +1 -1
  39. package/types/utils/symbolicateNativeStack.d.ts +46 -0
  40. package/types/utils/symbolicateNativeStack.d.ts.map +1 -0
  41. package/types/utils/symbolicateNativeStack.test.d.ts +2 -0
  42. package/types/utils/symbolicateNativeStack.test.d.ts.map +1 -0
@@ -1,14 +1,95 @@
1
- import { existsSync } from "node:fs";
1
+ import { existsSync, realpathSync } from "node:fs";
2
2
  import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { createContext, runInContext, runInNewContext } from "node:vm";
6
+ import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping";
6
7
  import { rolldown } from "rolldown";
7
8
  import { dev } from "rolldown/experimental";
9
+ import { normalizePath } from "vite";
8
10
  import { describe, expect, it, vi } from "vitest";
9
11
  import { getNativePrelude } from "../runtime/native-prelude.mjs";
10
12
  import { workletImportsPlugin } from "../plugins/workletImportsPlugin.mjs";
11
- import { buildNativeBundle, createNativeDevAssetRegistry, createNativeDevEngine, getHermesSWCIncludes, getHmrRuntimeSource, getNativeAssetData, getNativeTransformConfig, hermesCompatSWCPlugin, hmrClientNoopPlugin, nativeAnimatedGuardPlugin, normalizeNativeCommonJSInterop, vxrnCompilerPlugin, wrapNativeBundleModuleScope } from "./createNativeDevEngine.mjs";
13
+ import { buildNativeBundle, createNativeDevAssetRegistry, createNativeDevEngine, getHermesSWCIncludes, getHmrRuntimeSource, getNativeAssetData, getNativeTransformConfig, hermesCompatSWCPlugin, hmrClientNoopPlugin, nativeAnimatedGuardPlugin, normalizeNativeCommonJSInterop, postProcessNativeBundle, vxrnCompilerPlugin, wrapNativeBundleModuleScope } from "./createNativeDevEngine.mjs";
14
+ describe.each(["ios", "android"])("native plugin adapters on %s", platform => {
15
+ it.each(["dev", "build"])("binds configured plugins to the %s bundle", async mode => {
16
+ const root2 = await mkdtemp(join(tmpdir(), "vxrn-native-plugin-adapter-"));
17
+ await writeFile(join(root2, "entry.js"), `globalThis.nativePluginResult = [__GLOBAL_PLUGIN__, __DIRECT_PLUGIN__, 'plain-plugin']`);
18
+ const factories = ["global", "direct"].map(name => vi.fn(context => ({
19
+ name: `${name}-native`,
20
+ transform(code, id) {
21
+ if (id.endsWith("/entry.js")) return code.replace(`__${name.toUpperCase()}_PLUGIN__`, JSON.stringify({
22
+ name,
23
+ ...context
24
+ }));
25
+ }
26
+ })));
27
+ const plugins = factories.map((vxrnNative, index) => ({
28
+ name: `adapter-${index}`,
29
+ api: {
30
+ vxrnNative
31
+ }
32
+ }));
33
+ const previousPlugins = globalThis.__vxrnAddNativePlugins;
34
+ globalThis.__vxrnAddNativePlugins = [plugins[0]];
35
+ const configuredPlugins = [plugins[1], {
36
+ name: "plain-native-plugin",
37
+ transform(code, id) {
38
+ if (id.endsWith("/__virtual-native-entry.tsx")) return `import './entry.js'`;
39
+ if (id.endsWith("/entry.js")) return code.replace("plain-plugin", "plain");
40
+ }
41
+ }];
42
+ let native;
43
+ try {
44
+ let code;
45
+ if (mode === "dev") {
46
+ native = await createNativeDevEngine({
47
+ root: root2,
48
+ platform,
49
+ port: 0,
50
+ plugins: configuredPlugins
51
+ });
52
+ code = (await native.getBundle()).code;
53
+ } else code = (await buildNativeBundle({
54
+ root: root2,
55
+ platform,
56
+ entryFile: "entry.js",
57
+ plugins: configuredPlugins
58
+ })).code;
59
+ const context = {
60
+ console,
61
+ setTimeout,
62
+ clearTimeout,
63
+ __GLOBAL_PLUGIN__: "unadapted",
64
+ __DIRECT_PLUGIN__: "unadapted"
65
+ };
66
+ runInNewContext(code, context);
67
+ expect(Reflect.get(context, "nativePluginResult")).toEqual([{
68
+ name: "global",
69
+ root: root2,
70
+ platform,
71
+ dev: mode === "dev"
72
+ }, {
73
+ name: "direct",
74
+ root: root2,
75
+ platform,
76
+ dev: mode === "dev"
77
+ }, "plain"]);
78
+ for (const factory of factories) expect(factory).toHaveBeenCalledExactlyOnceWith({
79
+ root: root2,
80
+ platform,
81
+ dev: mode === "dev"
82
+ });
83
+ } finally {
84
+ await native?.close();
85
+ globalThis.__vxrnAddNativePlugins = previousPlugins;
86
+ await rm(root2, {
87
+ recursive: true,
88
+ force: true
89
+ });
90
+ }
91
+ });
92
+ });
12
93
  const nativeTransformProbe = `
13
94
  export const transformProbe = () => {
14
95
  'worklet'
@@ -85,12 +166,12 @@ globalThis.result = (function(parentArgument) {
85
166
  expect(result.events.filter(value => value === "finally")).toHaveLength(3);
86
167
  expect(result.events.filter(value => value === "closed")).toHaveLength(1);
87
168
  const {
88
- originalPositionFor,
89
- TraceMap
169
+ originalPositionFor: originalPositionFor2,
170
+ TraceMap: TraceMap2
90
171
  } = await import("@jridgewell/trace-mapping");
91
172
  const lines = output.code.split("\n");
92
173
  const line = lines.findIndex(value => value.includes("after-await"));
93
- const position = originalPositionFor(new TraceMap(output.map), {
174
+ const position = originalPositionFor2(new TraceMap2(output.map), {
94
175
  line: line + 1,
95
176
  column: lines[line].indexOf("events.push")
96
177
  });
@@ -110,8 +191,8 @@ describe.each(["shared", "rolldown", "metro"])("React Compiler worklets through
110
191
  default: MagicString
111
192
  } = await import("magic-string");
112
193
  const {
113
- TraceMap,
114
- originalPositionFor
194
+ TraceMap: TraceMap2,
195
+ originalPositionFor: originalPositionFor2
115
196
  } = await import("@jridgewell/trace-mapping");
116
197
  const projectRoot = await createWorkletsProject(false);
117
198
  const sourceMaps = process.env.VXRN_ENABLE_SOURCE_MAP;
@@ -210,7 +291,7 @@ return ${pipeline === "metro" ? "module.exports.useProbe" : "useProbe"}`)(memo,
210
291
  const lines = result.code.split("\n");
211
292
  const line = lines.findIndex(text => text.includes("function useProbe("));
212
293
  expect(line).toBeGreaterThanOrEqual(0);
213
- const position = originalPositionFor(new TraceMap(result.map), {
294
+ const position = originalPositionFor2(new TraceMap2(result.map), {
214
295
  line: line + 1,
215
296
  column: lines[line].indexOf("function")
216
297
  });
@@ -378,6 +459,7 @@ if (import.meta.hot) import.meta.hot.accept(() => {})
378
459
  "pure-math": ["default", "reads"]
379
460
  })]
380
461
  });
462
+ expect(production.code).not.toContain("__esmMin");
381
463
  const productionRN = {
382
464
  console
383
465
  };
@@ -386,6 +468,23 @@ if (import.meta.hot) import.meta.hot.accept(() => {})
386
468
  expect(reconstruct(productionRN.calculate)(10)).toBe(109);
387
469
  expect(reconstruct(productionRN.reads)()).toBe(3);
388
470
  expect(productionRN.reads()).toBe(1);
471
+ const unminifiedProduction = await buildNativeBundle({
472
+ root: root2,
473
+ platform: "android",
474
+ entryFile: "production.mjs",
475
+ minify: false,
476
+ plugins: [workletImportsPlugin({
477
+ "pure-math": ["default", "reads"]
478
+ })]
479
+ });
480
+ expect(unminifiedProduction.code).toContain("__esmMin");
481
+ const unminifiedRN = {
482
+ console
483
+ };
484
+ runInNewContext(unminifiedProduction.code, unminifiedRN);
485
+ expect(unminifiedRN.calculate(10)).toBe(109);
486
+ expect(reconstruct(unminifiedRN.calculate)(10)).toBe(109);
487
+ expect(reconstruct(unminifiedRN.reads)()).toBe(3);
389
488
  const sharedPlugin = workletImportsPlugin({
390
489
  "pure-math": ["default", "reads"]
391
490
  });
@@ -1047,8 +1146,8 @@ describe("native required transform failures", () => {
1047
1146
  });
1048
1147
  it("composes source maps across React Compiler, Fast Refresh, and module wrapper back to original source lines", async () => {
1049
1148
  const {
1050
- TraceMap,
1051
- originalPositionFor
1149
+ TraceMap: TraceMap2,
1150
+ originalPositionFor: originalPositionFor2
1052
1151
  } = await import("@jridgewell/trace-mapping");
1053
1152
  const compiler = await import("@vxrn/compiler");
1054
1153
  compiler.configureVXRNCompilerPlugin({
@@ -1068,10 +1167,10 @@ export function Counter() {
1068
1167
  const result = await Reflect.apply(plugin.transform, void 0, [inputCode, id]);
1069
1168
  expect(result).toBeDefined();
1070
1169
  expect(result.map).toBeDefined();
1071
- const tracer = new TraceMap(result.map);
1170
+ const tracer = new TraceMap2(result.map);
1072
1171
  const counterLineIndex = result.code.split("\n").findIndex(l => l.includes("function Counter"));
1073
1172
  expect(counterLineIndex).toBeGreaterThan(0);
1074
- const pos = originalPositionFor(tracer, {
1173
+ const pos = originalPositionFor2(tracer, {
1075
1174
  line: counterLineIndex + 1,
1076
1175
  column: 16
1077
1176
  });
@@ -1085,8 +1184,8 @@ export function Counter() {
1085
1184
  });
1086
1185
  it("composes source maps accurately across mixed path (React Compiler + Babel + Fast Refresh + module wrapper)", async () => {
1087
1186
  const {
1088
- TraceMap,
1089
- originalPositionFor
1187
+ TraceMap: TraceMap2,
1188
+ originalPositionFor: originalPositionFor2
1090
1189
  } = await import("@jridgewell/trace-mapping");
1091
1190
  const compiler = await import("@vxrn/compiler");
1092
1191
  const origEnv = process.env.VXRN_USE_BABEL_FOR_GENERATORS;
@@ -1113,12 +1212,12 @@ export async function* probe() { throw new Error("MARKER"); }
1113
1212
  expect(result).toBeDefined();
1114
1213
  expect(result.map).toBeDefined();
1115
1214
  expect(result.code.includes("_wrapAsyncGenerator") || result.code.includes("regeneratorRuntime")).toBe(true);
1116
- const tracer = new TraceMap(result.map);
1215
+ const tracer = new TraceMap2(result.map);
1117
1216
  const lines = result.code.split("\n");
1118
1217
  const markerLineIndex = lines.findIndex(l => l.includes("MARKER"));
1119
1218
  expect(markerLineIndex).toBeGreaterThan(0);
1120
1219
  const markerCol = lines[markerLineIndex].indexOf("throw");
1121
- const pos = originalPositionFor(tracer, {
1220
+ const pos = originalPositionFor2(tracer, {
1122
1221
  line: markerLineIndex + 1,
1123
1222
  column: markerCol
1124
1223
  });
@@ -1127,7 +1226,7 @@ export async function* probe() { throw new Error("MARKER"); }
1127
1226
  expect(pos.column).toBe(33);
1128
1227
  const compilerOut = await compiler.transformOxcReactCompiler(id, inputCode, "19", true);
1129
1228
  const remapping = (await import("@jridgewell/remapping")).default;
1130
- const badPos = originalPositionFor(new TraceMap(remapping([result.map, compilerOut.map], () => null)), {
1229
+ const badPos = originalPositionFor2(new TraceMap2(remapping([result.map, compilerOut.map], () => null)), {
1131
1230
  line: markerLineIndex + 1,
1132
1231
  column: markerCol
1133
1232
  });
@@ -1142,8 +1241,8 @@ export async function* probe() { throw new Error("MARKER"); }
1142
1241
  });
1143
1242
  it("transforms worklets via native Rust/Wasm SWC with zero Babel execution and accurate sourcemaps", async () => {
1144
1243
  const {
1145
- TraceMap,
1146
- originalPositionFor
1244
+ TraceMap: TraceMap2,
1245
+ originalPositionFor: originalPositionFor2
1147
1246
  } = await import("@jridgewell/trace-mapping");
1148
1247
  const compiler = await import("@vxrn/compiler");
1149
1248
  const {
@@ -1175,10 +1274,10 @@ export function Box() {
1175
1274
  expect(result.code).toContain("__closure");
1176
1275
  expect(babelSpy).not.toHaveBeenCalled();
1177
1276
  expect(result.map).toBeDefined();
1178
- const tracer = new TraceMap(result.map);
1277
+ const tracer = new TraceMap2(result.map);
1179
1278
  const boxLineIndex = result.code.split("\n").findIndex(l => l.includes("export function Box"));
1180
1279
  expect(boxLineIndex).toBeGreaterThan(0);
1181
- const pos = originalPositionFor(tracer, {
1280
+ const pos = originalPositionFor2(tracer, {
1182
1281
  line: boxLineIndex + 1,
1183
1282
  column: 16
1184
1283
  });
@@ -1270,6 +1369,90 @@ export function Box() {
1270
1369
  }
1271
1370
  });
1272
1371
  });
1372
+ describe("native production minification", () => {
1373
+ async function writeMinifyFixture() {
1374
+ const root2 = await mkdtemp(join(tmpdir(), "vxrn-native-minify-"));
1375
+ const dep = join(root2, "node_modules", "legacy-color");
1376
+ await mkdir(dep, {
1377
+ recursive: true
1378
+ });
1379
+ await writeFile(join(dep, "package.json"), JSON.stringify({
1380
+ name: "legacy-color",
1381
+ main: "index.js"
1382
+ }));
1383
+ await writeFile(join(dep, "index.js"), `function LegacyColor(value) { this.value = value }
1384
+ LegacyColor.prototype.describe = function () { return 'legacy:' + this.value }
1385
+ module.exports = LegacyColor`);
1386
+ await writeFile(join(root2, "views.js"), `'use strict';
1387
+ import LegacyColor from 'legacy-color'
1388
+ import { level } from './entry.js'
1389
+ export const describeHeader = () => new LegacyColor(level()).describe()`);
1390
+ await writeFile(join(root2, "entry.js"), `import { describeHeader } from './views.js'
1391
+ export const level = () => 'header'
1392
+ globalThis.minifyProbe = describeHeader()`);
1393
+ return root2;
1394
+ }
1395
+ function runFixture(code) {
1396
+ const context = {
1397
+ console
1398
+ };
1399
+ runInNewContext(code, context);
1400
+ return Reflect.get(context, "minifyProbe");
1401
+ }
1402
+ it("minifies when asked, leaves the bundle alone when not, and both behave the same", async () => {
1403
+ const root2 = await writeMinifyFixture();
1404
+ try {
1405
+ const [plain, minified] = await Promise.all([false, true].map(minify => buildNativeBundle({
1406
+ root: root2,
1407
+ platform: "ios",
1408
+ entryFile: "entry.js",
1409
+ minify
1410
+ })));
1411
+ expect(plain.code).toContain("__toESM");
1412
+ expect(plain.code).toContain("describeHeader");
1413
+ expect(plain.code.split("\n").length).toBeGreaterThan(40);
1414
+ expect(minified.code).not.toContain("describeHeader");
1415
+ expect(minified.code).not.toContain("//#region");
1416
+ expect(minified.code.length).toBeLessThan(plain.code.length * .7);
1417
+ expect(runFixture(minified.code)).toBe("legacy:header");
1418
+ expect(runFixture(plain.code)).toBe("legacy:header");
1419
+ } finally {
1420
+ await rm(root2, {
1421
+ recursive: true,
1422
+ force: true
1423
+ });
1424
+ }
1425
+ });
1426
+ it("defaults to react native's rule: minify a production bundle, never a dev one", async () => {
1427
+ const root2 = await writeMinifyFixture();
1428
+ try {
1429
+ const [prod, devBundle, explicitOff] = await Promise.all([buildNativeBundle({
1430
+ root: root2,
1431
+ platform: "ios",
1432
+ entryFile: "entry.js"
1433
+ }), buildNativeBundle({
1434
+ root: root2,
1435
+ platform: "ios",
1436
+ entryFile: "entry.js",
1437
+ dev: true
1438
+ }), buildNativeBundle({
1439
+ root: root2,
1440
+ platform: "ios",
1441
+ entryFile: "entry.js",
1442
+ minify: false
1443
+ })]);
1444
+ expect(prod.code).not.toContain("describeHeader");
1445
+ expect(devBundle.code).toContain("describeHeader");
1446
+ expect(explicitOff.code).toContain("describeHeader");
1447
+ expect(prod.code.length).toBeLessThan(explicitOff.code.length);
1448
+ } finally {
1449
+ await rm(root2, {
1450
+ recursive: true,
1451
+ force: true
1452
+ });
1453
+ }
1454
+ });
1455
+ });
1273
1456
  describe("native production assets", () => {
1274
1457
  it("registers scale siblings and keeps monorepo assets inside assetsDest", async () => {
1275
1458
  const testRoot = await mkdtemp(join(tmpdir(), "vxrn-native-assets-"));
@@ -1303,12 +1486,23 @@ globalThis.__nativeAssetProbe = [icon, back]
1303
1486
  expect(registry.resolve("/assets/assets/icon@2x.png", assetData.hash)?.filePath).toBe(join(appAssets, "icon@2x.png"));
1304
1487
  expect(registry.resolve("/assets/assets/icon.png", "stale-content-hash")).toBeUndefined();
1305
1488
  expect(registry.resolve("/assets/../../package.json", assetData.hash)).toBeUndefined();
1306
- expect((await buildNativeBundle({
1489
+ const result = await buildNativeBundle({
1307
1490
  root: appRoot,
1308
1491
  platform: "ios",
1309
1492
  entryFile: "entry.js",
1310
1493
  assetsDest
1311
- })).code).toMatch(/"scales":\s*\[\s*1,\s*2,\s*3\s*\]/);
1494
+ });
1495
+ const registered = [];
1496
+ runInNewContext(result.code, {
1497
+ console,
1498
+ require: id => id === "react-native/Libraries/Image/AssetRegistry" ? {
1499
+ registerAsset: asset => {
1500
+ registered.push(asset);
1501
+ return asset;
1502
+ }
1503
+ } : {}
1504
+ });
1505
+ expect(registered.map(asset => [asset.name, asset.scales])).toEqual([["icon", [1, 2, 3]], ["back", [1, 2]]]);
1312
1506
  for (const file of ["icon.png", "icon@2x.png", "icon@3x.png"]) expect(existsSync(join(assetsDest, "assets/assets", file))).toBe(true);
1313
1507
  for (const file of ["back.png", "back@2x.png"]) expect(existsSync(join(assetsDest, "assets/_/_/node_modules/example/assets", file))).toBe(true);
1314
1508
  expect(existsSync(join(testRoot, "node_modules/example/assets/back.png"))).toBe(false);
@@ -1523,4 +1717,72 @@ globalThis.__vxrnFlowProbe = new Flowy().measure({ value: 41 }) + 1
1523
1717
  }
1524
1718
  });
1525
1719
  });
1720
+ describe("native bundle source maps", () => {
1721
+ const generatedPositionOf = (code, marker) => {
1722
+ const index = code.indexOf(marker);
1723
+ expect(index).toBeGreaterThan(-1);
1724
+ const before = code.slice(0, index);
1725
+ const lastNewline = before.lastIndexOf("\n");
1726
+ return {
1727
+ line: (before.match(/\n/g)?.length ?? 0) + 1,
1728
+ column: index - lastNewline - 1
1729
+ };
1730
+ };
1731
+ it("resolves a frame to the authored file and line across an app file and a package file", {
1732
+ timeout: 6e4
1733
+ }, async () => {
1734
+ const testRoot = realpathSync(await mkdtemp(join(tmpdir(), "vxrn-native-sourcemap-")));
1735
+ const packageRoot = join(testRoot, "node_modules/probe-package");
1736
+ await mkdir(packageRoot, {
1737
+ recursive: true
1738
+ });
1739
+ await writeFile(join(packageRoot, "package.json"), JSON.stringify({
1740
+ name: "probe-package",
1741
+ main: "index.js",
1742
+ type: "module"
1743
+ }));
1744
+ await writeFile(join(packageRoot, "index.js"), [`function packageThrow() {`, ` throw new Error('__probe_package__')`, `}`, ``, `export default packageThrow`].join("\n"));
1745
+ await writeFile(join(testRoot, "entry.js"), [`import packageThrow from 'probe-package'`, ``, `function appThrow() {`, ` throw new Error('__probe_app__')`, `}`, ``, `globalThis.__probe = [appThrow, packageThrow]`].join("\n"));
1746
+ try {
1747
+ const result = await buildNativeBundle({
1748
+ root: testRoot,
1749
+ platform: "ios",
1750
+ entryFile: "entry.js",
1751
+ dev: true,
1752
+ sourcemap: true
1753
+ });
1754
+ expect(result.map).toBeTruthy();
1755
+ const traced = new TraceMap(JSON.parse(result.map));
1756
+ const app = originalPositionFor(traced, generatedPositionOf(result.code, "__probe_app__"));
1757
+ const pkg = originalPositionFor(traced, generatedPositionOf(result.code, "__probe_package__"));
1758
+ expect(app.source?.endsWith("/entry.js")).toBe(true);
1759
+ expect(app.line).toBe(4);
1760
+ expect(pkg.source?.endsWith("/index.js")).toBe(true);
1761
+ expect(pkg.line).toBe(2);
1762
+ expect(app.source).toBe(normalizePath(join(testRoot, "entry.js")));
1763
+ expect(pkg.source).toBe(normalizePath(join(packageRoot, "index.js")));
1764
+ } finally {
1765
+ await rm(testRoot, {
1766
+ recursive: true,
1767
+ force: true
1768
+ });
1769
+ }
1770
+ });
1771
+ });
1772
+ describe("postProcessNativeBundle", () => {
1773
+ const lines = code => code.split("\n").length;
1774
+ it("keeps the blank line above an export default", () => {
1775
+ const input = ["var a = 1;", "", "export default a;", "var b = 2;", ""].join("\n");
1776
+ const out = postProcessNativeBundle(input);
1777
+ expect(lines(out)).toBe(lines(input));
1778
+ expect(out.split("\n")[2]).toBe("a;");
1779
+ });
1780
+ it("keeps the lines of a multi-line export statement", () => {
1781
+ const input = ["var a = 1;", "export {", " a", "};", "var b = 2;", ""].join("\n");
1782
+ const out = postProcessNativeBundle(input);
1783
+ expect(lines(out)).toBe(lines(input));
1784
+ expect(out).not.toContain("export {");
1785
+ expect(out.split("\n")[4]).toBe("var b = 2;");
1786
+ });
1787
+ });
1526
1788
  //# sourceMappingURL=createNativeDevEngine.test.mjs.map