rollipop 0.1.0-alpha.2 → 0.1.0-alpha.20

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.
@@ -0,0 +1,3919 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ require("@commander-js/extra-typings");
24
+ let es_toolkit = require("es-toolkit");
25
+ let chalk = require("chalk");
26
+ chalk = __toESM(chalk);
27
+ let gradient_string = require("gradient-string");
28
+ gradient_string = __toESM(gradient_string);
29
+ let node_path = require("node:path");
30
+ node_path = __toESM(node_path);
31
+ let dayjs = require("dayjs");
32
+ dayjs = __toESM(dayjs);
33
+ let node_readline = require("node:readline");
34
+ node_readline = __toESM(node_readline);
35
+ let node_tty = require("node:tty");
36
+ let _inquirer_prompts = require("@inquirer/prompts");
37
+ let node_fs = require("node:fs");
38
+ node_fs = __toESM(node_fs);
39
+ let fast_flow_transform = require("fast-flow-transform");
40
+ fast_flow_transform = __toESM(fast_flow_transform);
41
+ let wrap_ansi = require("wrap-ansi");
42
+ wrap_ansi = __toESM(wrap_ansi);
43
+ let c12 = require("c12");
44
+ c12 = __toESM(c12);
45
+ let _rollipop_rolldown = require("@rollipop/rolldown");
46
+ _rollipop_rolldown = __toESM(_rollipop_rolldown);
47
+ let _rollipop_rolldown_experimental = require("@rollipop/rolldown/experimental");
48
+ _rollipop_rolldown_experimental = __toESM(_rollipop_rolldown_experimental);
49
+ let node_crypto = require("node:crypto");
50
+ node_crypto = __toESM(node_crypto);
51
+ require("@node-rs/xxhash");
52
+ let dedent = require("dedent");
53
+ dedent = __toESM(dedent);
54
+ let dotenv = require("dotenv");
55
+ dotenv = __toESM(dotenv);
56
+ let dotenv_expand = require("dotenv-expand");
57
+ dotenv_expand = __toESM(dotenv_expand);
58
+ let _rollipop_rolldown_pluginutils = require("@rollipop/rolldown-pluginutils");
59
+ let image_size = require("image-size");
60
+ let url = require("url");
61
+ url = __toESM(url);
62
+ let _react_native_community_cli_server_api = require("@react-native-community/cli-server-api");
63
+ let _react_native_dev_middleware = require("@react-native/dev-middleware");
64
+ let fastify = require("fastify");
65
+ fastify = __toESM(fastify);
66
+ let mitt = require("mitt");
67
+ mitt = __toESM(mitt);
68
+ let node_http = require("node:http");
69
+ node_http = __toESM(node_http);
70
+ let node_events = require("node:events");
71
+ node_events = __toESM(node_events);
72
+ let strip_ansi = require("strip-ansi");
73
+ strip_ansi = __toESM(strip_ansi);
74
+ let source_map = require("source-map");
75
+ let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
76
+ let _modelcontextprotocol_sdk_server_streamableHttp_js = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
77
+ let _modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
78
+ let fastify_plugin = require("fastify-plugin");
79
+ fastify_plugin = __toESM(fastify_plugin);
80
+ let zod = require("zod");
81
+ let json_schema_to_ts = require("json-schema-to-ts");
82
+ let mime = require("mime");
83
+ mime = __toESM(mime);
84
+ let ajv = require("ajv");
85
+ ajv = __toESM(ajv);
86
+ let _babel_code_frame = require("@babel/code-frame");
87
+ let ws = require("ws");
88
+ ws = __toESM(ws);
89
+ let _babel_core = require("@babel/core");
90
+ _babel_core = __toESM(_babel_core);
91
+ let _swc_core = require("@swc/core");
92
+ _swc_core = __toESM(_swc_core);
93
+ //#region src/common/logo.ts
94
+ const CANDY = `
95
+ _....._
96
+ .' _..._ '.
97
+ / /\` __ \`\\ \\
98
+ ; ; /\` \\ | ;
99
+ | | | (_/ ; |
100
+ ; ; \\_ _.' .;
101
+ \\ '. \`\` _.'/
102
+ '._\`"'"\`_.'`;
103
+ const STICK = `
104
+ / /\`\`
105
+ / /
106
+ /__/`;
107
+ const DESCRIPTIONS = [
108
+ "Rollipop",
109
+ "Modern build toolkit for React Native",
110
+ "Powered by Rolldown"
111
+ ];
112
+ const PRIMARY_COLOR = "#42A5F5";
113
+ const BASE_GRADIENT_COLORS = [PRIMARY_COLOR, "#BBDEFB"];
114
+ const PADDING = 20;
115
+ function printLogo() {
116
+ let maxLogoWidth = 0;
117
+ const padding = " ".repeat(PADDING);
118
+ const gradientColors = [...BASE_GRADIENT_COLORS];
119
+ const styledCandy = CANDY.split("\n").map((line) => {
120
+ maxLogoWidth = Math.max(line.length, maxLogoWidth);
121
+ return (0, gradient_string.default)(gradientColors.reverse())(line);
122
+ }).join("\n") + STICK;
123
+ console.log(styledCandy.split("\n").map((line) => padding + line).join("\n"));
124
+ console.log("");
125
+ DESCRIPTIONS.forEach((description, index) => {
126
+ const descriptionHalfLength = description.length / 2;
127
+ const logoHalfWidth = maxLogoWidth / 2;
128
+ const padding = " ".repeat(PADDING - descriptionHalfLength + logoHalfWidth);
129
+ if (index === 0) console.log(padding + chalk.default.bold.hex(PRIMARY_COLOR)(description));
130
+ else console.log(padding + description);
131
+ });
132
+ console.log("");
133
+ }
134
+ let _printed = false;
135
+ const Logo = {
136
+ print: printLogo,
137
+ printOnce: () => {
138
+ if (_printed) return;
139
+ _printed = true;
140
+ printLogo();
141
+ }
142
+ };
143
+ const SHARED_DATA_PATH = ".rollipop";
144
+ //#endregion
145
+ //#region src/common/env.ts
146
+ const TRUTHY_VALUES = [
147
+ "yes",
148
+ "on",
149
+ "true",
150
+ "enabled"
151
+ ];
152
+ const FALSY_VALUES = [
153
+ "no",
154
+ "off",
155
+ "false",
156
+ "disabled"
157
+ ];
158
+ function parseDebugKeys() {
159
+ return Object.keys(process.env).filter((key) => /^debug_/i.test(key)).reduce((acc, key) => {
160
+ const prop = key.slice(6).toLowerCase().replace(/_([a-z])/g, (_, key) => key.toUpperCase());
161
+ let value = process.env[key];
162
+ const lowerCase = typeof value === "string" ? value.toLowerCase() : value.toString();
163
+ if (TRUTHY_VALUES.includes(lowerCase)) value = true;
164
+ else if (FALSY_VALUES.includes(lowerCase)) value = false;
165
+ else value = Boolean(Number(value));
166
+ acc[prop] = value;
167
+ return acc;
168
+ }, {});
169
+ }
170
+ let debugKeys = null;
171
+ function isDebugEnabled() {
172
+ if (debugKeys == null) debugKeys = parseDebugKeys();
173
+ return debugKeys["rollipop"] ?? false;
174
+ }
175
+ //#endregion
176
+ //#region src/common/logger.ts
177
+ var Logger = class Logger {
178
+ static blocked = false;
179
+ static queuedMessages = [];
180
+ static Colors = {
181
+ trace: chalk.default.gray,
182
+ debug: chalk.default.blue,
183
+ log: chalk.default.green,
184
+ info: chalk.default.cyan,
185
+ warn: chalk.default.yellow,
186
+ error: chalk.default.red
187
+ };
188
+ format = "HH:mm:ss.SSS";
189
+ debugEnabled;
190
+ static block() {
191
+ this.blocked = true;
192
+ }
193
+ static unblock(flush = true) {
194
+ this.blocked = false;
195
+ if (flush) for (const args of Logger.queuedMessages) console.log(...args);
196
+ Logger.queuedMessages.length = 0;
197
+ }
198
+ constructor(scope) {
199
+ this.scope = scope;
200
+ this.debugEnabled = isDebugEnabled();
201
+ }
202
+ getFormat() {
203
+ return this.format;
204
+ }
205
+ setFormat(format) {
206
+ this.format = format;
207
+ }
208
+ getTimestamp() {
209
+ return (0, dayjs.default)().format(this.getFormat());
210
+ }
211
+ print(logLevel, ...args) {
212
+ const timestamp = chalk.default.gray(this.getTimestamp());
213
+ const level = Logger.Colors[logLevel](logLevel);
214
+ if (this.scope) args = [
215
+ timestamp,
216
+ level,
217
+ chalk.default.magenta(this.scope),
218
+ ...args
219
+ ];
220
+ else args = [
221
+ timestamp,
222
+ level,
223
+ ...args
224
+ ];
225
+ if (Logger.blocked) Logger.queuedMessages.push(args);
226
+ else console.log(...args);
227
+ }
228
+ trace(...args) {
229
+ this.debugEnabled && this.print("trace", ...args);
230
+ }
231
+ debug(...args) {
232
+ this.debugEnabled && this.print("debug", ...args);
233
+ }
234
+ log(...args) {
235
+ this.print("log", ...args);
236
+ }
237
+ info(...args) {
238
+ this.print("info", ...args);
239
+ }
240
+ warn(...args) {
241
+ this.print("warn", ...args);
242
+ }
243
+ error(...args) {
244
+ this.print("error", ...args);
245
+ }
246
+ child(scope) {
247
+ (0, es_toolkit.invariant)(this.scope, "Logger must have a scope to create a child logger");
248
+ return new Logger(`${this.scope}:${scope}`);
249
+ }
250
+ };
251
+ //#endregion
252
+ //#region src/node/logger.ts
253
+ const logger$2 = new Logger("cli");
254
+ //#endregion
255
+ //#region src/node/utils.ts
256
+ function parseBoolean(value) {
257
+ return value === "true" || value === "1";
258
+ }
259
+ function resolvePath(value) {
260
+ return node_path.default.resolve(value);
261
+ }
262
+ //#endregion
263
+ //#region src/core/fs/data.ts
264
+ function getSharedDataPath(basePath) {
265
+ return node_path.default.join(basePath, SHARED_DATA_PATH);
266
+ }
267
+ //#endregion
268
+ //#region src/core/settings.ts
269
+ function getSettingsPath(basePath) {
270
+ return node_path.default.join(getSharedDataPath(basePath), "settings.json");
271
+ }
272
+ function loadSettings(basePath) {
273
+ const settingsPath = getSettingsPath(basePath);
274
+ if (!node_fs.default.existsSync(settingsPath)) return {};
275
+ return JSON.parse(node_fs.default.readFileSync(settingsPath, "utf-8"));
276
+ }
277
+ function saveSettings(basePath, settings) {
278
+ const newSettings = (0, es_toolkit.merge)(loadSettings(basePath), settings);
279
+ node_fs.default.writeFileSync(getSettingsPath(basePath), JSON.stringify(newSettings, null, 2));
280
+ }
281
+ //#endregion
282
+ //#region src/node/commands/start/debugger.ts
283
+ var DebuggerOpener = class DebuggerOpener {
284
+ static MAX_TARGETS_SHOWN = 10;
285
+ _prompting = false;
286
+ settings;
287
+ autoOpened = false;
288
+ static setAutoOpenEnabled(projectRoot, enabled) {
289
+ saveSettings(projectRoot, { devtools: { autoOpen: enabled } });
290
+ }
291
+ constructor(projectRoot, serverUrl) {
292
+ this.projectRoot = projectRoot;
293
+ this.serverUrl = serverUrl;
294
+ this.settings = loadSettings(projectRoot);
295
+ }
296
+ async openDebuggerForTarget(target) {
297
+ logger$2.debug(`Opening debugger for target: ${target.id}`);
298
+ try {
299
+ await fetch(new URL("/open-debugger?target=" + encodeURIComponent(target.id), this.serverUrl), { method: "POST" });
300
+ } catch (error) {
301
+ logger$2.error(`Failed to open debugger for ${target.title}`);
302
+ logger$2.debug("Reason", error);
303
+ }
304
+ }
305
+ async autoOpen() {
306
+ if (this.autoOpened) return;
307
+ this.autoOpened = true;
308
+ if (this.isAutoOpenEnabled()) await this.open();
309
+ }
310
+ async open() {
311
+ logger$2.debug("Fetching available debugging targets...");
312
+ const response = await fetch(new URL("/json/list", this.serverUrl), { method: "POST" });
313
+ if (response.status !== 200) throw new Error(`Unexpected status code: ${response.status}`);
314
+ const targets = await response.json();
315
+ if (!Array.isArray(targets)) throw new Error("Unexpected response format");
316
+ logger$2.debug(`Found ${targets.length} debugging targets:`);
317
+ if (targets.length === 0) logger$2.warn("No connected targets");
318
+ else if (targets.length === 1) {
319
+ const target = targets[0];
320
+ await this.openDebuggerForTarget(target);
321
+ } else {
322
+ if (targets.length > DebuggerOpener.MAX_TARGETS_SHOWN) logger$2.warn(`More than ${DebuggerOpener.MAX_TARGETS_SHOWN} debug targets available, showing the first ${DebuggerOpener.MAX_TARGETS_SHOWN}.`);
323
+ const slicedTargets = targets.slice(0, DebuggerOpener.MAX_TARGETS_SHOWN);
324
+ Logger.block();
325
+ this._prompting = true;
326
+ try {
327
+ const targetIndex = await (0, _inquirer_prompts.select)({
328
+ message: "Multiple debug targets available, please select:",
329
+ choices: slicedTargets.map((target, index) => ({
330
+ value: index,
331
+ name: `${target.title} (${target.description})`
332
+ }))
333
+ });
334
+ await this.openDebuggerForTarget(slicedTargets[targetIndex]);
335
+ } catch {} finally {
336
+ Logger.unblock();
337
+ this._prompting = false;
338
+ }
339
+ }
340
+ }
341
+ isPrompting() {
342
+ return this._prompting;
343
+ }
344
+ isAutoOpenEnabled() {
345
+ return this.settings.devtools?.autoOpen ?? false;
346
+ }
347
+ setAutoOpenEnabled(enabled) {
348
+ const newSettings = this.settings = (0, es_toolkit.merge)(this.settings, { devtools: { autoOpen: enabled } });
349
+ saveSettings(this.projectRoot, newSettings);
350
+ }
351
+ };
352
+ //#endregion
353
+ //#region src/node/commands/start/setup-interactive-mode.ts
354
+ const CTRL_C = "";
355
+ const CTRL_D = "";
356
+ const BROADCAST_THROTTLE_DELAY = 500;
357
+ function setupInteractiveMode(options) {
358
+ const { devServer, extraCommands = [] } = options;
359
+ if (!devServer.instance.server.listening) throw new Error("Dev server is not listening. Please call `devServer.instance.listen()` first.");
360
+ if (!(process.stdin.isTTY && process.stdin instanceof node_tty.ReadStream)) {
361
+ logger$2.warn("Interactive mode is not supported in non-interactive environments");
362
+ return;
363
+ }
364
+ const debuggerOpener = new DebuggerOpener(devServer.config.root, devServer.instance.listeningOrigin);
365
+ const defaultCommands = getDefaultCommands(devServer, debuggerOpener);
366
+ const allCommands = [...defaultCommands, ...extraCommands];
367
+ assertHasNoDuplicateCommands(defaultCommands, extraCommands);
368
+ node_readline.default.emitKeypressEvents(process.stdin);
369
+ process.stdin.setRawMode(true);
370
+ devServer.on("device.connected", () => {
371
+ debuggerOpener.autoOpen().catch(() => {
372
+ logger$2.error("Failed to open debugger");
373
+ });
374
+ });
375
+ process.stdin.on("keypress", (_, key) => {
376
+ const { ctrl = false, shift = false } = key;
377
+ const sequence = key.sequence?.toLowerCase();
378
+ if (sequence == null || debuggerOpener.isPrompting()) return;
379
+ if (ctrl && [CTRL_C, CTRL_D].includes(sequence)) {
380
+ process.stdin.setRawMode(false);
381
+ process.stdin.pause();
382
+ process.emit("SIGINT");
383
+ process.exit(0);
384
+ }
385
+ const targetCommand = allCommands.find((command) => command.key === sequence && (command.shift ?? false) === shift);
386
+ if (targetCommand) targetCommand.handler.call({
387
+ server: devServer,
388
+ logger: logger$2
389
+ });
390
+ });
391
+ console.log();
392
+ allCommands.forEach((command, index) => {
393
+ if (defaultCommands.length === index) console.log();
394
+ const leadingLabel = command.shift ? "»" : "» Press";
395
+ const shortcut = chalk.default.bold(shortcutLabel(command.key, command.shift));
396
+ console.log(`${leadingLabel} ${shortcut} │ ${typeof command.description === "function" ? command.description() : command.description}`);
397
+ });
398
+ }
399
+ function getDefaultCommands(devServer, debuggerOpener) {
400
+ return [
401
+ {
402
+ key: "r",
403
+ description: "Reload app",
404
+ handler: (0, es_toolkit.throttle)(() => {
405
+ logger$2.info("Reloading app...");
406
+ devServer.message.broadcast("reload");
407
+ }, BROADCAST_THROTTLE_DELAY)
408
+ },
409
+ {
410
+ key: "j",
411
+ description: "Open DevTools",
412
+ handler: () => {
413
+ debuggerOpener.open().catch(() => {
414
+ logger$2.error("Failed to open debugger");
415
+ });
416
+ }
417
+ },
418
+ {
419
+ key: "d",
420
+ description: "Show developer menu",
421
+ handler: (0, es_toolkit.throttle)(() => {
422
+ logger$2.info("Showing developer menu...");
423
+ devServer.message.broadcast("devMenu");
424
+ }, BROADCAST_THROTTLE_DELAY)
425
+ },
426
+ {
427
+ key: "d",
428
+ shift: true,
429
+ description: () => {
430
+ const autoOpenEnabled = debuggerOpener.isAutoOpenEnabled();
431
+ return `Toggle auto opening developer tools on startup (${chalk.default.bold(autoOpenEnabled ? "enabled" : "disabled")})`;
432
+ },
433
+ handler: () => {
434
+ const newAutoOpenEnabled = !debuggerOpener.isAutoOpenEnabled();
435
+ debuggerOpener.setAutoOpenEnabled(newAutoOpenEnabled);
436
+ logger$2.info(`Auto opening developer tools: ${chalk.default.bold(newAutoOpenEnabled ? "enabled" : "disabled")}`);
437
+ }
438
+ }
439
+ ];
440
+ }
441
+ function shortcutLabel(key, shift) {
442
+ if (shift) return `shift+${key}`;
443
+ return key;
444
+ }
445
+ function assertHasNoDuplicateCommands(defaultCommands, commands) {
446
+ const defaultCommandKeys = defaultCommands.map(({ key, shift }) => shortcutLabel(key, shift));
447
+ const duplicateKeys = commands.map(({ key, shift }) => shortcutLabel(key, shift)).filter((key) => defaultCommandKeys.includes(key));
448
+ const invalidCommandKeys = commands.filter(({ key }) => key.length > 1).map(({ key, shift }) => shortcutLabel(key, shift));
449
+ if (invalidCommandKeys.length > 0) throw new Error(`Invalid commands: ${invalidCommandKeys.join(", ")}`);
450
+ if (duplicateKeys.length > 0) throw new Error(`Duplicate commands: ${duplicateKeys.join(", ")}`);
451
+ }
452
+ //#endregion
453
+ //#region src/node/cli-utils.ts
454
+ function createReactNativeCliCommand(commandDefinition) {
455
+ return {
456
+ name: commandDefinition.name,
457
+ description: commandDefinition.description,
458
+ options: commandDefinition.options?.map((option) => (0, es_toolkit.omit)(option, ["required"])),
459
+ func: (_argv, cliConfig, args) => {
460
+ Logo.printOnce();
461
+ return commandDefinition.action.call({ platforms: Object.keys(cliConfig.platforms) }, args);
462
+ }
463
+ };
464
+ }
465
+ //#endregion
466
+ //#region src/node/constants.ts
467
+ const UNSUPPORTED_OPTION_DESCRIPTION = "This option is not supported by Rollipop.";
468
+ //#endregion
469
+ //#region src/common/transformer.ts
470
+ async function stripFlowTypes(id, code) {
471
+ return await (0, fast_flow_transform.default)({
472
+ filename: id,
473
+ source: code,
474
+ sourcemap: true,
475
+ dialect: "flow",
476
+ format: "pretty"
477
+ });
478
+ }
479
+ //#endregion
480
+ //#region src/constants.ts
481
+ const ROLLIPOP_VERSION = globalThis.__ROLLIPOP_VERSION__;
482
+ const GLOBAL_IDENTIFIER = "global";
483
+ /**
484
+ * @see {@link https://github.com/facebook/metro/blob/0.81.x/docs/Configuration.md#resolvermainfields}
485
+ */
486
+ const DEFAULT_RESOLVER_MAIN_FIELDS = [
487
+ "react-native",
488
+ "browser",
489
+ "main"
490
+ ];
491
+ const DEFAULT_RESOLVER_CONDITION_NAMES = [
492
+ "react-native",
493
+ "import",
494
+ "require"
495
+ ];
496
+ /**
497
+ * Unlike the Metro bundler configuration, this prioritizes resolving TypeScript and ESM first.
498
+ *
499
+ * @see {@link https://github.com/facebook/metro/blob/0.81.x/packages/metro-config/src/defaults/defaults.js}
500
+ * @see {@link https://github.com/facebook/metro/blob/0.81.x/packages/metro-file-map/src/workerExclusionList.js}
501
+ */
502
+ const DEFAULT_SOURCE_EXTENSIONS = [
503
+ "ts",
504
+ "tsx",
505
+ "js",
506
+ "jsx",
507
+ "mjs",
508
+ "cjs",
509
+ "json"
510
+ ];
511
+ const DEFAULT_ASSET_EXTENSIONS = [
512
+ "bmp",
513
+ "gif",
514
+ "jpg",
515
+ "jpeg",
516
+ "png",
517
+ "psd",
518
+ "svg",
519
+ "webp",
520
+ "xml",
521
+ "m4v",
522
+ "mov",
523
+ "mp4",
524
+ "mpeg",
525
+ "mpg",
526
+ "webm",
527
+ "aac",
528
+ "aiff",
529
+ "caf",
530
+ "m4a",
531
+ "mp3",
532
+ "wav",
533
+ "html",
534
+ "pdf",
535
+ "yaml",
536
+ "yml",
537
+ "otf",
538
+ "ttf",
539
+ "zip"
540
+ ];
541
+ const DEFAULT_ASSET_REGISTRY_PATH = "react-native/Libraries/Image/AssetRegistry.js";
542
+ const DEFAULT_HMR_CLIENT_PATH = "react-native/Libraries/Utilities/HMRClient.js";
543
+ const DEFAULT_REACT_NATIVE_GLOBAL_IDENTIFIERS = [
544
+ GLOBAL_IDENTIFIER,
545
+ "Promise",
546
+ "regeneratorRuntime",
547
+ "XMLHttpRequest",
548
+ "FormData",
549
+ "fetch",
550
+ "Headers",
551
+ "Request",
552
+ "Response",
553
+ "WebSocket",
554
+ "Blob",
555
+ "File",
556
+ "FileReader",
557
+ "URL",
558
+ "URLSearchParams",
559
+ "AbortController",
560
+ "AbortSignal",
561
+ "queueMicrotask",
562
+ "setImmediate",
563
+ "clearImmediate",
564
+ "requestIdleCallback",
565
+ "cancelIdleCallback",
566
+ "setTimeout",
567
+ "clearTimeout",
568
+ "setInterval",
569
+ "clearInterval",
570
+ "requestAnimationFrame",
571
+ "cancelAnimationFrame",
572
+ "DOMRect",
573
+ "DOMRectReadOnly",
574
+ "DOMRectList",
575
+ "HTMLCollection",
576
+ "NodeList",
577
+ "Node",
578
+ "Document",
579
+ "CharacterData",
580
+ "Text",
581
+ "Element",
582
+ "HTMLElement",
583
+ "IntersectionObserver",
584
+ "MutationObserver",
585
+ "MutationRecord",
586
+ "EventCounts",
587
+ "Performance",
588
+ "PerformanceEntry",
589
+ "PerformanceEventTiming",
590
+ "PerformanceLongTaskTiming",
591
+ "PerformanceMark",
592
+ "PerformanceMeasure",
593
+ "PerformanceObserver",
594
+ "PerformanceObserverEntryList",
595
+ "PerformanceResourceTiming",
596
+ "TaskAttributionTiming"
597
+ ];
598
+ const DEFAULT_ENV_PREFIX = "ROLLIPOP_";
599
+ const DEFAULT_RUNTIME_TARGET = "hermes-v1";
600
+ //#endregion
601
+ //#region src/internal/react-native.ts
602
+ function getInitializeCorePath(basePath) {
603
+ return require.resolve("react-native/Libraries/Core/InitializeCore", { paths: [basePath] });
604
+ }
605
+ function getPolyfillScriptPaths(reactNativePath) {
606
+ const scriptPath = node_path.default.join(reactNativePath, "rn-get-polyfills");
607
+ return require(scriptPath)();
608
+ }
609
+ function getGlobalVariables(dev, buildType) {
610
+ const isDevServerMode = dev && buildType === "serve";
611
+ return [
612
+ `var __BUNDLE_START_TIME__=globalThis.nativePerformanceNow?nativePerformanceNow():Date.now();`,
613
+ `var __DEV__=${dev};`,
614
+ `var ${GLOBAL_IDENTIFIER}=typeof globalThis!=='undefined'?globalThis:typeof global !== 'undefined'?global:typeof window!=='undefined'?window:this;`,
615
+ `var process=globalThis.process||{};process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"${dev ? "development" : "production"}";`,
616
+ isDevServerMode ? `var $RefreshReg$ = () => {};` : null,
617
+ isDevServerMode ? `var $RefreshSig$ = () => (v) => v;` : null
618
+ ].filter(es_toolkit.isNotNil);
619
+ }
620
+ //#endregion
621
+ //#region src/utils/node-resolve.ts
622
+ function resolveFrom(basePath, lookupPath) {
623
+ if (node_path.default.isAbsolute(lookupPath)) return lookupPath;
624
+ return require.resolve(lookupPath, { paths: [basePath] });
625
+ }
626
+ function resolvePackagePath(basePath, packageName) {
627
+ let packagePath = null;
628
+ try {
629
+ packagePath = resolvePackagePathWithNodeRequire(basePath, packageName, "package.json");
630
+ if (packagePath) return packagePath;
631
+ } catch {}
632
+ try {
633
+ packagePath = resolvePackagePathWithNodeRequire(basePath, packageName);
634
+ if (packagePath) return packagePath;
635
+ } catch {}
636
+ throw new Error(`Failed to resolve package path for '${packageName}'`);
637
+ }
638
+ function resolvePackageJson(basePath, packageName) {
639
+ try {
640
+ const packagePath = resolvePackagePath(basePath, packageName);
641
+ const packageJsonPath = node_path.default.join(packagePath, "package.json");
642
+ const rawPackageJson = node_fs.default.readFileSync(packageJsonPath, "utf-8");
643
+ return JSON.parse(rawPackageJson);
644
+ } catch {
645
+ return null;
646
+ }
647
+ }
648
+ function resolvePackagePathWithNodeRequire(basePath, packageName, subpath) {
649
+ const resolvedPath = require.resolve(subpath ? `${packageName}/${subpath}` : packageName, { paths: [basePath] });
650
+ const root = node_path.default.parse(resolvedPath).root;
651
+ let currentPath = node_path.default.dirname(resolvedPath);
652
+ while (currentPath !== root) {
653
+ if (node_fs.default.existsSync(node_path.default.join(currentPath, "package.json"))) return currentPath;
654
+ currentPath = node_path.default.dirname(currentPath);
655
+ }
656
+ return null;
657
+ }
658
+ //#endregion
659
+ //#region src/utils/terminal.ts
660
+ /**
661
+ * Based on https://github.com/sindresorhus/log-update/blob/master/index.js
662
+ * Based on https://github.com/unjs/webpackbar
663
+ */
664
+ function eraseLines(count) {
665
+ let clear = "";
666
+ for (let i = 0; i < count; i++) clear += `\u001B[2K` + (i < count - 1 ? `\u001B[1A` : "");
667
+ if (count) clear += `\u001B[G`;
668
+ return clear;
669
+ }
670
+ function ellipsisLeft(value, maxLength) {
671
+ if (value.length <= maxLength - 3) return value;
672
+ return `...${value.slice(value.length - maxLength - 1)}`;
673
+ }
674
+ const originalWrite = Symbol("original-write");
675
+ var StreamManager = class {
676
+ prevLineCount;
677
+ listening;
678
+ extraLines;
679
+ _streams;
680
+ constructor() {
681
+ this.prevLineCount = 0;
682
+ this.listening = false;
683
+ this.extraLines = "";
684
+ this._onData = this._onData.bind(this);
685
+ this._streams = [process.stdout, process.stderr];
686
+ }
687
+ render(lines) {
688
+ this.listen();
689
+ const wrappedLines = (0, wrap_ansi.default)(lines, this.columns, {
690
+ trim: false,
691
+ hard: true,
692
+ wordWrap: false
693
+ });
694
+ const data = eraseLines(this.prevLineCount) + wrappedLines + "\n" + this.extraLines;
695
+ this.write(data);
696
+ this.prevLineCount = data.split("\n").length;
697
+ }
698
+ get columns() {
699
+ return (process.stderr.columns || 80) - 2;
700
+ }
701
+ write(data) {
702
+ const stream = process.stderr;
703
+ if (stream.write[originalWrite]) stream.write[originalWrite].call(stream, data, "utf8");
704
+ else stream.write(data, "utf8");
705
+ }
706
+ clear() {
707
+ this.done();
708
+ this.write(eraseLines(this.prevLineCount));
709
+ }
710
+ done() {
711
+ this.stopListen();
712
+ this.prevLineCount = 0;
713
+ this.extraLines = "";
714
+ }
715
+ _onData(data) {
716
+ const lines = String(data).split("\n").length - 1;
717
+ if (lines > 0) {
718
+ this.prevLineCount += lines;
719
+ this.extraLines += data;
720
+ }
721
+ }
722
+ listen() {
723
+ if (this.listening) return;
724
+ for (const stream of this._streams) {
725
+ if (stream.write[originalWrite]) continue;
726
+ const write = (data, ...args) => {
727
+ if (!stream.write[originalWrite]) return stream.write(data, ...args);
728
+ this._onData(data);
729
+ return stream.write[originalWrite].call(stream, data, ...args);
730
+ };
731
+ write[originalWrite] = stream.write;
732
+ stream.write = write;
733
+ }
734
+ this.listening = true;
735
+ }
736
+ stopListen() {
737
+ for (const stream of this._streams) if (stream.write[originalWrite]) stream.write = stream.write[originalWrite];
738
+ this.listening = false;
739
+ }
740
+ };
741
+ //#endregion
742
+ //#region src/common/progress-bar.ts
743
+ const BAR_LENGTH = 25;
744
+ const BLOCK_CHAR = "█";
745
+ const idleRenderer = { render(_state, context) {
746
+ return ` ${chalk.default.gray("Waiting...")} ${chalk.default.gray(context.label)}\n`;
747
+ } };
748
+ const runningRenderer = { render(state, context) {
749
+ const { label, current, total, columns } = context;
750
+ const unknownTotal = total === 0;
751
+ const progress = unknownTotal ? 0 : current / total * 100;
752
+ const width = unknownTotal ? 0 : progress * (BAR_LENGTH / 100);
753
+ const bg = chalk.default.white(BLOCK_CHAR);
754
+ const fg = chalk.default.cyan(BLOCK_CHAR);
755
+ const bar = (0, es_toolkit.range)(BAR_LENGTH).map((n) => n < width ? fg : bg).join("");
756
+ const progressLabel = unknownTotal ? chalk.default.gray("(calculating...)") : `(${progress.toFixed(2)}%)`;
757
+ const moduleCountLabel = unknownTotal ? `${current} modules` : `${current}/${total} modules`;
758
+ return `${[
759
+ chalk.default.cyan("●"),
760
+ bar,
761
+ progressLabel,
762
+ chalk.default.gray(moduleCountLabel),
763
+ chalk.default.gray(label)
764
+ ].join(" ")}\n${state.moduleId ? " " + chalk.default.grey(ellipsisLeft(state.moduleId, columns - 10)) : ""}`;
765
+ } };
766
+ const completedRenderer = { render(state, context) {
767
+ if (state.hasErrors) return `${chalk.default.red("✘")} Build failed ${chalk.default.gray(context.label)}`;
768
+ else {
769
+ const icon = chalk.default.green("✔");
770
+ const durationInSeconds = (state.duration / 1e3).toFixed(2);
771
+ return `${`${icon} Build completed ${chalk.default.gray(context.label)}`}\n${chalk.default.grey(` Built in ${durationInSeconds}s (${context.current}/${context.total} modules)`)}`;
772
+ }
773
+ } };
774
+ var ProgressBarRenderer = class {
775
+ renderers = {
776
+ idle: idleRenderer,
777
+ running: runningRenderer,
778
+ completed: completedRenderer
779
+ };
780
+ render(state, context) {
781
+ return this.renderers[state.type].render(state, context);
782
+ }
783
+ };
784
+ var ProgressBar = class {
785
+ columns = (process.stderr.columns || 80) - 2;
786
+ renderer;
787
+ label;
788
+ state = { type: "idle" };
789
+ current = 0;
790
+ total;
791
+ stale = false;
792
+ constructor(options) {
793
+ this.total = options.total;
794
+ this.label = options.label;
795
+ this.renderer = options.renderer ?? new ProgressBarRenderer();
796
+ }
797
+ get done() {
798
+ return this.state.type === "completed";
799
+ }
800
+ setCurrent(current) {
801
+ this.current = current;
802
+ this.stale = true;
803
+ return this;
804
+ }
805
+ setTotal(total) {
806
+ this.total = total;
807
+ this.stale = true;
808
+ return this;
809
+ }
810
+ start() {
811
+ this.state = { type: "running" };
812
+ this.stale = true;
813
+ return this;
814
+ }
815
+ setModuleId(moduleId) {
816
+ if (this.state.type !== "running") return this;
817
+ this.state = {
818
+ type: "running",
819
+ moduleId
820
+ };
821
+ this.stale = true;
822
+ return this;
823
+ }
824
+ complete(duration, hasErrors = false) {
825
+ this.state = {
826
+ type: "completed",
827
+ duration,
828
+ hasErrors
829
+ };
830
+ this.stale = true;
831
+ return this;
832
+ }
833
+ render() {
834
+ this.stale = false;
835
+ const context = {
836
+ label: this.label,
837
+ current: this.current,
838
+ total: this.total,
839
+ columns: this.columns
840
+ };
841
+ return this.renderer.render(this.state, context);
842
+ }
843
+ };
844
+ var ProgressBarRenderManager = class ProgressBarRenderManager {
845
+ static instance = null;
846
+ streamManager = new StreamManager();
847
+ progressBars = /* @__PURE__ */ new Map();
848
+ throttledRender;
849
+ static getInstance() {
850
+ if (!ProgressBarRenderManager.instance) ProgressBarRenderManager.instance = new ProgressBarRenderManager();
851
+ return ProgressBarRenderManager.instance;
852
+ }
853
+ constructor() {
854
+ this.throttledRender = (0, es_toolkit.throttle)(this._render.bind(this), 50);
855
+ }
856
+ _render() {
857
+ const renderedLines = Array.from(this.progressBars.values().filter((progressBar) => progressBar.stale).map((progressBar) => progressBar.render()));
858
+ if (renderedLines.length > 0) this.streamManager.render(renderedLines.join("\n\n"));
859
+ }
860
+ register(key, options) {
861
+ const progressBar = this.progressBars.get(key);
862
+ if (progressBar == null) {
863
+ const newProgressBar = new ProgressBar(options);
864
+ this.progressBars.set(key, newProgressBar);
865
+ return newProgressBar;
866
+ }
867
+ return progressBar;
868
+ }
869
+ start() {
870
+ console.log();
871
+ this.streamManager.listen();
872
+ this._render();
873
+ }
874
+ render() {
875
+ this.throttledRender();
876
+ }
877
+ release() {
878
+ if (this.progressBars.values().every((progressBar) => progressBar.done)) {
879
+ this._render();
880
+ this.streamManager.done();
881
+ console.log();
882
+ }
883
+ }
884
+ clear() {
885
+ this.streamManager.clear();
886
+ }
887
+ };
888
+ //#endregion
889
+ //#region src/logger.ts
890
+ const logger$1 = new Logger("bundler");
891
+ //#endregion
892
+ //#region src/utils/reporters.ts
893
+ function mergeReporters(reporters) {
894
+ return { update(event) {
895
+ reporters.forEach((reporter) => reporter.update(event));
896
+ } };
897
+ }
898
+ var ClientLogReporter = class {
899
+ logger = new Logger("app");
900
+ update(event) {
901
+ if (event.type === "client_log") {
902
+ if (event.level === "group" || event.level === "groupCollapsed") {
903
+ this.logger.info(...event.data);
904
+ return;
905
+ } else if (event.level === "groupEnd") return;
906
+ this.logger[event.level](...event.data);
907
+ }
908
+ }
909
+ };
910
+ var ProgressFlags = /* @__PURE__ */ function(ProgressFlags) {
911
+ ProgressFlags[ProgressFlags["NONE"] = 0] = "NONE";
912
+ ProgressFlags[ProgressFlags["BUILD_IN_PROGRESS"] = 1] = "BUILD_IN_PROGRESS";
913
+ ProgressFlags[ProgressFlags["FILE_CHANGED"] = 2] = "FILE_CHANGED";
914
+ return ProgressFlags;
915
+ }(ProgressFlags || {});
916
+ var ProgressBarStatusReporter = class {
917
+ renderManager = ProgressBarRenderManager.getInstance();
918
+ progressBar;
919
+ flags = ProgressFlags.NONE;
920
+ constructor(id, label, initialTotalModules) {
921
+ this.progressBar = this.renderManager.register(id, {
922
+ label,
923
+ total: initialTotalModules
924
+ });
925
+ }
926
+ renderProgress(id, totalModules, transformedModules) {
927
+ if (totalModules != null) this.progressBar.setTotal(totalModules);
928
+ this.progressBar.setCurrent(transformedModules).setModuleId(id);
929
+ this.renderManager.render();
930
+ }
931
+ update(event) {
932
+ switch (event.type) {
933
+ case "bundle_build_started":
934
+ this.flags |= ProgressFlags.BUILD_IN_PROGRESS;
935
+ this.progressBar.start();
936
+ this.renderManager.start();
937
+ break;
938
+ case "bundle_build_failed":
939
+ this.flags = ProgressFlags.NONE;
940
+ this.progressBar.complete(0, true);
941
+ this.renderManager.release();
942
+ break;
943
+ case "bundle_build_done":
944
+ this.flags = ProgressFlags.NONE;
945
+ this.progressBar.setTotal(event.totalModules).complete(event.duration, false);
946
+ this.renderManager.release();
947
+ break;
948
+ case "transform":
949
+ const { id, totalModules, transformedModules } = event;
950
+ if (this.flags & ProgressFlags.FILE_CHANGED) {
951
+ logger$1.debug("Transformed changed file", { id });
952
+ return;
953
+ }
954
+ this.renderProgress(id, totalModules, transformedModules);
955
+ break;
956
+ case "watch_change":
957
+ this.flags |= ProgressFlags.FILE_CHANGED;
958
+ break;
959
+ }
960
+ }
961
+ };
962
+ var CompatStatusReporter = class {
963
+ update(event) {
964
+ switch (event.type) {
965
+ case "bundle_build_started":
966
+ logger$1.info("Build started...");
967
+ break;
968
+ case "bundle_build_failed":
969
+ logger$1.error(`Build failed`);
970
+ break;
971
+ case "bundle_build_done":
972
+ const { duration, totalModules } = event;
973
+ const time = chalk.default.blue(`${duration.toFixed(2)}ms`);
974
+ const modules = chalk.default.blue(`(${totalModules} modules)`);
975
+ logger$1.info(`Build completed in ${time} ${modules}`);
976
+ break;
977
+ }
978
+ }
979
+ };
980
+ //#endregion
981
+ //#region src/config/defaults.ts
982
+ async function getDefaultConfig(projectRoot, mode) {
983
+ let reactNativePath;
984
+ try {
985
+ reactNativePath = process.env.ROLLIPOP_REACT_NATIVE_PATH ?? resolvePackagePath(projectRoot, "react-native");
986
+ } catch {
987
+ throw new Error(`Could not resolve 'react-native' package path. Please check your project path.`);
988
+ }
989
+ return {
990
+ root: projectRoot,
991
+ mode: mode ?? "development",
992
+ entry: "index.js",
993
+ resolver: {
994
+ sourceExtensions: DEFAULT_SOURCE_EXTENSIONS,
995
+ assetExtensions: DEFAULT_ASSET_EXTENSIONS,
996
+ mainFields: DEFAULT_RESOLVER_MAIN_FIELDS,
997
+ conditionNames: DEFAULT_RESOLVER_CONDITION_NAMES,
998
+ preferNativePlatform: true,
999
+ symlinks: true
1000
+ },
1001
+ transformer: { flow: { filter: {
1002
+ id: /\.jsx?$/,
1003
+ code: /@flow/
1004
+ } } },
1005
+ serializer: {
1006
+ prelude: [getInitializeCorePath(projectRoot)],
1007
+ polyfills: await Promise.all(getPolyfillScriptPaths(reactNativePath).map(async (path) => {
1008
+ return {
1009
+ type: "iife",
1010
+ code: (await stripFlowTypes(path, node_fs.default.readFileSync(path, "utf-8"))).code
1011
+ };
1012
+ }))
1013
+ },
1014
+ watcher: {
1015
+ skipWrite: true,
1016
+ useDebounce: true,
1017
+ debounceDuration: 50
1018
+ },
1019
+ optimization: { treeshake: true },
1020
+ reactNative: {
1021
+ reactNativePath,
1022
+ codegen: { filter: { code: /\bcodegenNativeComponent</ } },
1023
+ assetRegistryPath: DEFAULT_ASSET_REGISTRY_PATH,
1024
+ hmrClientPath: DEFAULT_HMR_CLIENT_PATH,
1025
+ globalIdentifiers: DEFAULT_REACT_NATIVE_GLOBAL_IDENTIFIERS
1026
+ },
1027
+ devMode: { hmr: true },
1028
+ reporter: new ClientLogReporter(),
1029
+ terminal: { status: (() => {
1030
+ if (isDebugEnabled()) return "compat";
1031
+ if (process.stderr.isTTY) return "progress";
1032
+ return "compat";
1033
+ })() },
1034
+ envDir: projectRoot,
1035
+ envPrefix: DEFAULT_ENV_PREFIX,
1036
+ runtimeTarget: DEFAULT_RUNTIME_TARGET,
1037
+ experimental: { nativeTransformPipeline: false }
1038
+ };
1039
+ }
1040
+ //#endregion
1041
+ //#region src/core/plugins/context.ts
1042
+ const pluginLogger = new Logger();
1043
+ function createPluginContext(name) {
1044
+ return {
1045
+ debug: (log) => {
1046
+ printPluginLog("debug", log, name);
1047
+ },
1048
+ info: (log) => {
1049
+ printPluginLog("info", log, name);
1050
+ },
1051
+ warn: (log) => {
1052
+ printPluginLog("warn", log, name);
1053
+ }
1054
+ };
1055
+ }
1056
+ function printPluginLog(level, log, pluginName = "unknown") {
1057
+ const pluginLabel = chalk.default.magenta(`plugin:${pluginName}`);
1058
+ if (typeof log === "string") pluginLogger[level](pluginLabel, log);
1059
+ else pluginLogger[level](pluginLabel, log.stack ?? log.message);
1060
+ }
1061
+ //#endregion
1062
+ //#region src/config/compose-override.ts
1063
+ async function applyOverrideRolldownOptions(override, rolldownOptions) {
1064
+ if (typeof override === "function") return await override(rolldownOptions);
1065
+ return {
1066
+ input: (0, es_toolkit.merge)(rolldownOptions.input ?? {}, override.input ?? {}),
1067
+ output: (0, es_toolkit.merge)(rolldownOptions.output ?? {}, override.output ?? {})
1068
+ };
1069
+ }
1070
+ function composeOverrideRolldownOptions(target, source) {
1071
+ if (source == null) return target;
1072
+ if (target == null) return source;
1073
+ return async (rolldownOptions) => {
1074
+ return await applyOverrideRolldownOptions(source, await applyOverrideRolldownOptions(target, rolldownOptions));
1075
+ };
1076
+ }
1077
+ //#endregion
1078
+ //#region src/config/merge-config.ts
1079
+ function mergeConfig(baseConfig, ...overrideConfigs) {
1080
+ let mergedConfig = baseConfig;
1081
+ for (const overrideConfig of overrideConfigs) mergedConfig = (0, es_toolkit.mergeWith)(mergedConfig, overrideConfig, (target, source, key) => {
1082
+ if ([
1083
+ "sourceExtensions",
1084
+ "assetExtensions",
1085
+ "polyfills",
1086
+ "prelude",
1087
+ "plugins"
1088
+ ].includes(key)) return Array.from(new Set([...target ?? [], ...source ?? []]));
1089
+ if (key === "reporter") return source ?? target;
1090
+ if (key === "dangerously_overrideRolldownOptions") return composeOverrideRolldownOptions(target, source);
1091
+ });
1092
+ return mergedConfig;
1093
+ }
1094
+ //#endregion
1095
+ //#region src/config/load-config.ts
1096
+ const CONFIG_FILE_NAME = "rollipop";
1097
+ async function loadConfig(options = {}) {
1098
+ const { cwd = process.cwd(), configFile, mode, context = {} } = options;
1099
+ const defaultConfig = await getDefaultConfig(cwd, mode);
1100
+ const commonOptions = {
1101
+ context: {
1102
+ ...context,
1103
+ defaultConfig
1104
+ },
1105
+ rcFile: false
1106
+ };
1107
+ const { config: userConfig } = await c12.loadConfig(configFile ? {
1108
+ configFile: node_path.default.resolve(cwd, configFile),
1109
+ configFileRequired: true
1110
+ } : {
1111
+ cwd,
1112
+ defaultConfig,
1113
+ name: CONFIG_FILE_NAME,
1114
+ ...commonOptions
1115
+ });
1116
+ const plugins = await flattenPluginOption(userConfig.plugins);
1117
+ const resolvedConfig = {
1118
+ ...await resolvePluginConfig(mergeConfig(defaultConfig, {
1119
+ ...userConfig,
1120
+ plugins
1121
+ }), plugins),
1122
+ plugins
1123
+ };
1124
+ await invokeConfigResolved(resolvedConfig, plugins);
1125
+ return resolvedConfig;
1126
+ }
1127
+ async function flattenPluginOption(pluginOption) {
1128
+ const awaitedPluginOption = await pluginOption;
1129
+ if (Array.isArray(awaitedPluginOption)) return (await Promise.all(awaitedPluginOption.map(flattenPluginOption))).flat();
1130
+ if (awaitedPluginOption == null || awaitedPluginOption === false) return [];
1131
+ return [awaitedPluginOption];
1132
+ }
1133
+ async function resolvePluginConfig(baseConfig, plugins) {
1134
+ let mergedConfig = (0, es_toolkit.omit)(baseConfig, ["plugins"]);
1135
+ for (const plugin of plugins) {
1136
+ const context = createPluginContext(plugin.name);
1137
+ const overrideBefore = mergedConfig.dangerously_overrideRolldownOptions;
1138
+ if (typeof plugin.config === "function") {
1139
+ const config = await plugin.config.call(context, mergedConfig);
1140
+ if (config != null) mergedConfig = mergeConfig(mergedConfig, config);
1141
+ } else if (typeof plugin.config === "object") mergedConfig = mergeConfig(mergedConfig, plugin.config);
1142
+ const overrideAfter = mergedConfig.dangerously_overrideRolldownOptions;
1143
+ if (overrideAfter != null && overrideAfter !== overrideBefore) context.debug({ message: `set 'dangerously_overrideRolldownOptions'` });
1144
+ }
1145
+ return mergedConfig;
1146
+ }
1147
+ async function invokeConfigResolved(config, plugins) {
1148
+ await Promise.all(plugins.map((plugin) => {
1149
+ const context = createPluginContext(plugin.name);
1150
+ return plugin.configResolved?.call(context, config);
1151
+ }));
1152
+ }
1153
+ //#endregion
1154
+ //#region src/utils/reset-cache.ts
1155
+ /**
1156
+ * Resolve the build cache directory for the given project root. The cache
1157
+ * itself is owned by rolldown's native implementation; we keep the path
1158
+ * here only because `resetCache` — and any tooling that wants to inspect
1159
+ * the on-disk layout — needs to know where to look.
1160
+ */
1161
+ function getCacheDirectory(projectRoot) {
1162
+ return node_path.default.join(getSharedDataPath(projectRoot), "cache");
1163
+ }
1164
+ /**
1165
+ * Remove the entire build cache directory for the given project root.
1166
+ * Backs the `/reset-cache` control endpoint, the `reset_cache` MCP tool,
1167
+ * and the `--reset-cache` CLI flag.
1168
+ */
1169
+ function resetCache(projectRoot) {
1170
+ node_fs.default.rmSync(getCacheDirectory(projectRoot), {
1171
+ recursive: true,
1172
+ force: true
1173
+ });
1174
+ }
1175
+ //#endregion
1176
+ //#region src/utils/build-options.ts
1177
+ const DEFAULT_BUILD_OPTIONS = {
1178
+ cache: true,
1179
+ minify: false
1180
+ };
1181
+ function resolveBuildOptions(config, buildOptions) {
1182
+ if (buildOptions.outfile) buildOptions.outfile = node_path.default.resolve(config.root, buildOptions.outfile);
1183
+ if ((buildOptions.sourcemap === true || buildOptions.sourcemap === "hidden") && buildOptions.sourcemapOutfile) buildOptions.sourcemapOutfile = node_path.default.resolve(config.root, buildOptions.sourcemapOutfile);
1184
+ return (0, es_toolkit.merge)(DEFAULT_BUILD_OPTIONS, {
1185
+ ...buildOptions,
1186
+ dev: buildOptions.dev ?? config.mode === "development"
1187
+ });
1188
+ }
1189
+ //#endregion
1190
+ //#region src/utils/hash.ts
1191
+ function md5(data) {
1192
+ return node_crypto.default.createHash("md5").update(data).digest("hex");
1193
+ }
1194
+ //#endregion
1195
+ //#region src/utils/serialize.ts
1196
+ function serialize(value) {
1197
+ return JSON.stringify(value, (_, value) => {
1198
+ if (typeof value === "function") return value.toString();
1199
+ if (value instanceof RegExp) return value.toString();
1200
+ return value;
1201
+ });
1202
+ }
1203
+ //#endregion
1204
+ //#region src/utils/id.ts
1205
+ function createId(config, buildOptions) {
1206
+ return md5(serialize([
1207
+ ROLLIPOP_VERSION,
1208
+ filterTransformAffectedOptions(buildOptions),
1209
+ filterTransformAffectedConfig(config)
1210
+ ]));
1211
+ }
1212
+ function filterTransformAffectedOptions(buildOptions) {
1213
+ return (0, es_toolkit.pick)(buildOptions, ["platform", "dev"]);
1214
+ }
1215
+ function filterTransformAffectedConfig(config) {
1216
+ const { transformer, serializer, reactNative, devMode, plugins = [] } = config;
1217
+ return [
1218
+ transformer,
1219
+ serializer.polyfills,
1220
+ serializer.prelude,
1221
+ reactNative.assetRegistryPath,
1222
+ devMode,
1223
+ plugins.map((plugin, index) => `${plugin.name}#${index}`)
1224
+ ];
1225
+ }
1226
+ //#endregion
1227
+ //#region src/core/fs/storage.ts
1228
+ const DEFAULT_DATA = { build: {} };
1229
+ var FileStorage = class FileStorage {
1230
+ static instance = null;
1231
+ dataFilePath;
1232
+ data;
1233
+ static getInstance(basePath) {
1234
+ if (FileStorage.instance == null) FileStorage.instance = new FileStorage(basePath);
1235
+ return FileStorage.instance;
1236
+ }
1237
+ constructor(basePath) {
1238
+ this.basePath = basePath;
1239
+ this.dataFilePath = node_path.default.join(getSharedDataPath(basePath), "rollipop.json");
1240
+ if (node_fs.default.existsSync(this.dataFilePath)) this.data = JSON.parse(node_fs.default.readFileSync(this.dataFilePath, "utf-8"));
1241
+ else this.data = DEFAULT_DATA;
1242
+ }
1243
+ get() {
1244
+ return this.data;
1245
+ }
1246
+ set(data) {
1247
+ this.data = (0, es_toolkit.merge)(this.data, data);
1248
+ node_fs.default.writeFileSync(this.dataFilePath, JSON.stringify(this.data, null, 2));
1249
+ }
1250
+ };
1251
+ //#endregion
1252
+ //#region src/utils/string.ts
1253
+ function indent(text, indent, space = " ") {
1254
+ return text.replace(/^/gm, space.repeat(indent));
1255
+ }
1256
+ //#endregion
1257
+ //#region src/common/code.ts
1258
+ function asLiteral(value) {
1259
+ return JSON.stringify(value);
1260
+ }
1261
+ function nodeEnvironment(dev) {
1262
+ return dev ? "development" : "production";
1263
+ }
1264
+ function iife(body, path = "<unknown>") {
1265
+ const bodyPlaceholder = "__BODY__";
1266
+ return dedent.default`
1267
+ // ${path}
1268
+ (function (global) {
1269
+ ${bodyPlaceholder}
1270
+ })(${GLOBAL_IDENTIFIER});
1271
+ `.replace(bodyPlaceholder, indent(body, 1));
1272
+ }
1273
+ //#endregion
1274
+ //#region src/utils/config.ts
1275
+ function bindReporter(config, eventSource, onEvent) {
1276
+ const originalReporter = config.reporter;
1277
+ config.reporter = { update(event) {
1278
+ switch (event.type) {
1279
+ case "bundle_build_started":
1280
+ eventSource.emit("buildStart");
1281
+ break;
1282
+ case "bundle_build_done":
1283
+ eventSource.emit("buildDone");
1284
+ break;
1285
+ case "bundle_build_failed":
1286
+ eventSource.emit("buildFailed", event.error);
1287
+ break;
1288
+ case "transform":
1289
+ eventSource.emit("transform", event.id, event.totalModules, event.transformedModules);
1290
+ break;
1291
+ case "watch_change":
1292
+ eventSource.emit("watchChange", event.id);
1293
+ break;
1294
+ }
1295
+ originalReporter?.update(event);
1296
+ onEvent?.(event);
1297
+ } };
1298
+ return config;
1299
+ }
1300
+ function resolveHmrConfig(config) {
1301
+ if (config.mode !== "development") return null;
1302
+ const defaultRuntimeImplements = getDefaultRuntimeImplements();
1303
+ if (typeof config.devMode.hmr === "boolean") return config.devMode.hmr ? defaultRuntimeImplements : null;
1304
+ const { runtimeImplement = defaultRuntimeImplements.runtimeImplement, clientImplement = defaultRuntimeImplements.clientImplement } = config.devMode.hmr;
1305
+ return {
1306
+ runtimeImplement,
1307
+ clientImplement
1308
+ };
1309
+ }
1310
+ getDefaultRuntimeImplements.cache = null;
1311
+ function getDefaultRuntimeImplements() {
1312
+ if (getDefaultRuntimeImplements.cache == null) getDefaultRuntimeImplements.cache = {
1313
+ runtimeImplement: node_fs.default.readFileSync(require.resolve("rollipop/hmr-runtime"), "utf-8"),
1314
+ clientImplement: node_fs.default.readFileSync(require.resolve("rollipop/hmr-client"), "utf-8")
1315
+ };
1316
+ return getDefaultRuntimeImplements.cache;
1317
+ }
1318
+ //#endregion
1319
+ //#region src/utils/env.ts
1320
+ function defineEnvFromObject(env) {
1321
+ return Object.fromEntries(Object.entries(env).map(([key, value]) => [`import.meta.env.${key}`, asLiteral(value)]));
1322
+ }
1323
+ //#endregion
1324
+ //#region src/utils/runtime-target.ts
1325
+ function resolveRuntimeTarget(target) {
1326
+ switch (target) {
1327
+ case "hermes": return "Hermes";
1328
+ default: return "HermesV1";
1329
+ }
1330
+ }
1331
+ //#endregion
1332
+ //#region src/utils/server.ts
1333
+ function getBaseUrl(host, port, https) {
1334
+ return `${https ? "https" : "http"}://${host}:${port}`;
1335
+ }
1336
+ //#endregion
1337
+ //#region src/utils/storage.ts
1338
+ function getBuildTotalModules(storage, id) {
1339
+ return storage.get().build[id]?.totalModules ?? 0;
1340
+ }
1341
+ //#endregion
1342
+ //#region src/core/env.ts
1343
+ function loadEnv(options) {
1344
+ const { envDir, envPrefix, mode } = options;
1345
+ (0, es_toolkit.invariant)(envPrefix.length > 0, "`envPrefix` is required");
1346
+ const env = {};
1347
+ const envFilesToLoad = [
1348
+ `.env`,
1349
+ `.env.local`,
1350
+ mode ? `.env.${mode}` : null,
1351
+ mode ? `.env.${mode}.local` : null
1352
+ ].filter(es_toolkit.isNotNil);
1353
+ for (const envFile of envFilesToLoad) {
1354
+ const envPath = node_path.default.resolve(envDir, envFile);
1355
+ if (!node_fs.default.existsSync(envPath)) continue;
1356
+ logger$1.trace(`Loading environment variables from ${envPath}`);
1357
+ const parsed = dotenv.default.parse(node_fs.default.readFileSync(envPath, "utf-8"));
1358
+ const expanded = dotenv_expand.default.expand({
1359
+ parsed,
1360
+ processEnv: {}
1361
+ });
1362
+ if (expanded.parsed) Object.entries(expanded.parsed).forEach(([key, value]) => {
1363
+ if (key.startsWith(envPrefix)) env[key] = key in process.env ? process.env[key] : value;
1364
+ });
1365
+ }
1366
+ logger$1.trace("Loaded environment variables:", env);
1367
+ return env;
1368
+ }
1369
+ //#endregion
1370
+ //#region src/server/logger.ts
1371
+ const logger = new Logger("dev-server");
1372
+ var DevServerLogger = class {
1373
+ level = "trace";
1374
+ trace(...args) {
1375
+ logger.trace(...args);
1376
+ }
1377
+ debug(...args) {
1378
+ logger.debug(...args);
1379
+ }
1380
+ info(...args) {
1381
+ logger.info(...args);
1382
+ }
1383
+ warn(...args) {
1384
+ logger.warn(...args);
1385
+ }
1386
+ error(...args) {
1387
+ logger.error(...args);
1388
+ }
1389
+ silent(...args) {
1390
+ logger.trace(chalk.default.gray("(silent)"), ...args);
1391
+ }
1392
+ fatal(...args) {
1393
+ logger.error(chalk.default.magenta("(fatal)"), ...args);
1394
+ }
1395
+ child(_bindings) {
1396
+ return this;
1397
+ }
1398
+ };
1399
+ //#endregion
1400
+ //#region src/utils/dev-server.ts
1401
+ async function assertDevServerStatus(options) {
1402
+ const { devServerUrl, projectRoot, port } = options;
1403
+ const status = await getDevServerStatus(devServerUrl, projectRoot);
1404
+ let shouldExit = false;
1405
+ switch (status) {
1406
+ case DevServerStatus.MATCHED_SERVER_RUNNING:
1407
+ logger.warn(`A dev server is already running for this project on port ${port}. Exiting.`);
1408
+ shouldExit = true;
1409
+ break;
1410
+ case DevServerStatus.PORT_TAKEN:
1411
+ logger.error(`Another process is running on port ${port}. Please terminate this process and try again, or use another port with "--port".`);
1412
+ shouldExit = true;
1413
+ break;
1414
+ }
1415
+ if (shouldExit) process.exit(1);
1416
+ }
1417
+ var DevServerStatus = /* @__PURE__ */ function(DevServerStatus) {
1418
+ DevServerStatus[DevServerStatus["NOT_RUNNING"] = 0] = "NOT_RUNNING";
1419
+ DevServerStatus[DevServerStatus["MATCHED_SERVER_RUNNING"] = 1] = "MATCHED_SERVER_RUNNING";
1420
+ DevServerStatus[DevServerStatus["PORT_TAKEN"] = 2] = "PORT_TAKEN";
1421
+ DevServerStatus[DevServerStatus["UNKNOWN"] = 3] = "UNKNOWN";
1422
+ return DevServerStatus;
1423
+ }(DevServerStatus || {});
1424
+ async function getDevServerStatus(devServerUrl, projectRoot) {
1425
+ const { hostname, port } = new URL(devServerUrl);
1426
+ try {
1427
+ if (!await isPortOccupied(hostname, port)) return DevServerStatus.NOT_RUNNING;
1428
+ const statusResponse = await fetch(`${devServerUrl}/status`);
1429
+ return await statusResponse.text() === "packager-status:running" && statusResponse.headers.get("X-React-Native-Project-Root") === projectRoot ? DevServerStatus.MATCHED_SERVER_RUNNING : DevServerStatus.PORT_TAKEN;
1430
+ } catch {
1431
+ return DevServerStatus.UNKNOWN;
1432
+ }
1433
+ }
1434
+ async function isPortOccupied(host, port) {
1435
+ let result = false;
1436
+ const server = node_http.default.createServer();
1437
+ return new Promise((resolve, reject) => {
1438
+ server.once("error", (error) => {
1439
+ server.close();
1440
+ if (error.code === "EADDRINUSE") result = true;
1441
+ else reject(error);
1442
+ });
1443
+ server.once("listening", () => {
1444
+ result = false;
1445
+ server.close();
1446
+ });
1447
+ server.once("close", () => resolve(result));
1448
+ server.listen({
1449
+ host,
1450
+ port
1451
+ });
1452
+ });
1453
+ }
1454
+ //#endregion
1455
+ //#region src/utils/bundle.ts
1456
+ function getBaseBundleName(name) {
1457
+ return name.replace(/^\//, "").replace(/\.bundle$/, "");
1458
+ }
1459
+ //#endregion
1460
+ //#region src/utils/errors.ts
1461
+ function normalizeRolldownError(error) {
1462
+ const normalizedError = new Error((0, strip_ansi.default)(error.message));
1463
+ normalizedError.stack = error.stack;
1464
+ return normalizedError;
1465
+ }
1466
+ //#endregion
1467
+ //#region src/utils/promise.ts
1468
+ function taskHandler() {
1469
+ let resolver;
1470
+ let rejector;
1471
+ return {
1472
+ task: new Promise((resolve, reject) => {
1473
+ resolver = resolve;
1474
+ rejector = reject;
1475
+ }),
1476
+ resolve: () => resolver?.(void 0),
1477
+ reject: (reason) => rejector?.(reason)
1478
+ };
1479
+ }
1480
+ //#endregion
1481
+ //#region src/server/bundle.ts
1482
+ var FileSystemBundleStore = class {
1483
+ bundleFilePath;
1484
+ _sourceMap;
1485
+ lazySourceMapConsumer = null;
1486
+ holder;
1487
+ constructor(projectRoot, id, code, sourceMap) {
1488
+ const sharedDataPath = getSharedDataPath(projectRoot);
1489
+ const bundlesPath = node_path.default.join(sharedDataPath, "bundles");
1490
+ const bundleFilePath = node_path.default.join(bundlesPath, `${id}.bundle`);
1491
+ if (!node_fs.default.existsSync(bundlesPath)) node_fs.default.mkdirSync(bundlesPath, { recursive: true });
1492
+ node_fs.default.writeFileSync(bundleFilePath, code, { encoding: "utf-8" });
1493
+ const stats = node_fs.default.statSync(bundleFilePath);
1494
+ this.bundleFilePath = bundleFilePath;
1495
+ this._sourceMap = sourceMap;
1496
+ this.holder = {
1497
+ code,
1498
+ mtimeMs: stats.mtimeMs
1499
+ };
1500
+ logger$1.debug(`File system bundle created at ${bundleFilePath}`);
1501
+ }
1502
+ update() {
1503
+ this.holder = {
1504
+ code: node_fs.default.readFileSync(this.bundleFilePath, { encoding: "utf-8" }),
1505
+ mtimeMs: node_fs.default.statSync(this.bundleFilePath).mtimeMs
1506
+ };
1507
+ }
1508
+ get code() {
1509
+ if (this.isStale()) {
1510
+ logger$1.info("File system bundle is stale, updating...");
1511
+ this.update();
1512
+ } else logger$1.trace("File system bundle is up to date");
1513
+ return this.holder.code;
1514
+ }
1515
+ get sourceMap() {
1516
+ return this.isStale() ? void 0 : this._sourceMap;
1517
+ }
1518
+ get sourceMapConsumer() {
1519
+ if (this.isStale() || this._sourceMap == null) return;
1520
+ if (this.lazySourceMapConsumer == null) this.lazySourceMapConsumer = new source_map.SourceMapConsumer(this._sourceMap);
1521
+ return this.lazySourceMapConsumer;
1522
+ }
1523
+ isStale() {
1524
+ return this.holder.mtimeMs !== node_fs.default.statSync(this.bundleFilePath).mtimeMs;
1525
+ }
1526
+ };
1527
+ //#endregion
1528
+ //#region src/server/bundler-pool.ts
1529
+ var BundlerDevEngine = class extends node_events.default {
1530
+ initializeHandle;
1531
+ isHmrEnabled;
1532
+ _id;
1533
+ bundleStore = null;
1534
+ buildFailedError = null;
1535
+ _devEngine = null;
1536
+ _state = "idle";
1537
+ _status = "idle";
1538
+ constructor(options, config, buildOptions, onReporterEvent) {
1539
+ super();
1540
+ this.options = options;
1541
+ this.config = config;
1542
+ this.buildOptions = buildOptions;
1543
+ this.onReporterEvent = onReporterEvent;
1544
+ this._id = Bundler.createId(config, buildOptions);
1545
+ this.initializeHandle = taskHandler();
1546
+ this.isHmrEnabled = Boolean(buildOptions.dev && config.devMode.hmr);
1547
+ this.on("buildStart", () => {
1548
+ this._status = "building";
1549
+ });
1550
+ this.on("buildDone", () => {
1551
+ this._status = "build-done";
1552
+ });
1553
+ this.on("buildFailed", () => {
1554
+ this._status = "build-failed";
1555
+ });
1556
+ this.initialize();
1557
+ }
1558
+ get id() {
1559
+ return this._id;
1560
+ }
1561
+ /** Snapshot of the bundler's current lifecycle state. */
1562
+ get status() {
1563
+ return this._status;
1564
+ }
1565
+ get devEngine() {
1566
+ (0, es_toolkit.invariant)(this._devEngine, "DevEngine is not initialized");
1567
+ return this._devEngine;
1568
+ }
1569
+ get ensureInitialized() {
1570
+ return this.initializeHandle.task;
1571
+ }
1572
+ async initialize() {
1573
+ if (this._state !== "idle" || this._devEngine != null) return this;
1574
+ this._state = "initializing";
1575
+ const onEvent = this.onReporterEvent ? (event) => this.onReporterEvent(this._id, event) : void 0;
1576
+ const devEngine = await Bundler.devEngine(bindReporter(this.config, this, onEvent), this.buildOptions, {
1577
+ host: this.options.server.host,
1578
+ port: this.options.server.port,
1579
+ onHmrUpdates: (errorOrResult) => {
1580
+ if (!this.isHmrEnabled) return;
1581
+ if (errorOrResult instanceof Error) {
1582
+ logger.error("Failed to handle HMR updates", {
1583
+ bundlerId: this.id,
1584
+ error: errorOrResult
1585
+ });
1586
+ const normalizedError = normalizeRolldownError(errorOrResult);
1587
+ this.config.reporter?.update({
1588
+ type: "bundle_build_failed",
1589
+ error: normalizedError
1590
+ });
1591
+ } else {
1592
+ logger.trace("Detected changed files", {
1593
+ bundlerId: this.id,
1594
+ changedFiles: errorOrResult.changedFiles
1595
+ });
1596
+ this.emit("hmrUpdates", errorOrResult.updates);
1597
+ }
1598
+ },
1599
+ onOutput: (errorOrResult) => {
1600
+ if (errorOrResult instanceof Error) {
1601
+ const normalizedError = normalizeRolldownError(errorOrResult);
1602
+ logger.trace("onOutput", { bundlerId: this.id });
1603
+ logger.error(errorOrResult.message);
1604
+ this.buildFailedError = normalizedError;
1605
+ this.emit("buildFailed", normalizedError);
1606
+ } else {
1607
+ const output = errorOrResult.output[0];
1608
+ this.updateBundleStore(output);
1609
+ this.buildFailedError = null;
1610
+ logger.debug("Build completed", {
1611
+ bundlerId: this.id,
1612
+ bundleName: output.name
1613
+ });
1614
+ }
1615
+ },
1616
+ rebuildStrategy: "auto"
1617
+ });
1618
+ await devEngine.run();
1619
+ this._devEngine = devEngine;
1620
+ this._state = "ready";
1621
+ this.initializeHandle.resolve();
1622
+ }
1623
+ updateBundleStore(output) {
1624
+ this.bundleStore = new FileSystemBundleStore(this.config.root, this.id, output.code, output.map?.toString());
1625
+ }
1626
+ async getBundle() {
1627
+ await this.ensureInitialized;
1628
+ const state = await this.devEngine.getBundleState();
1629
+ logger.debug("Bundle state", {
1630
+ bundlerId: this.id,
1631
+ state
1632
+ });
1633
+ if (state.lastFullBuildFailed) throw new Error(this.buildFailedError?.message ?? "Build failed");
1634
+ if (state.hasStaleOutput || this.bundleStore == null) await this.devEngine.ensureLatestBuildOutput();
1635
+ (0, es_toolkit.invariant)(this.bundleStore, "Bundle is not available");
1636
+ return this.bundleStore;
1637
+ }
1638
+ };
1639
+ var BundlerPool = class BundlerPool {
1640
+ static instances = /* @__PURE__ */ new Map();
1641
+ constructor(config, resolvedServerOptions, onReporterEvent) {
1642
+ this.config = config;
1643
+ this.resolvedServerOptions = resolvedServerOptions;
1644
+ this.onReporterEvent = onReporterEvent;
1645
+ }
1646
+ instanceKey(bundleName, buildOptions) {
1647
+ return `${bundleName}-${Bundler.createId(this.config, buildOptions)}`;
1648
+ }
1649
+ get(bundleName, buildOptions) {
1650
+ const key = this.instanceKey(getBaseBundleName(bundleName), buildOptions);
1651
+ const instance = BundlerPool.instances.get(key);
1652
+ if (instance) return instance;
1653
+ else {
1654
+ logger.debug("Preparing new bundler instance", {
1655
+ bundleName,
1656
+ key
1657
+ });
1658
+ const instance = new BundlerDevEngine({ server: this.resolvedServerOptions }, this.config, buildOptions, this.onReporterEvent);
1659
+ logger.debug("Setting new bundler instance", { key });
1660
+ BundlerPool.instances.set(key, instance);
1661
+ return instance;
1662
+ }
1663
+ }
1664
+ /**
1665
+ * Look up a cached bundler by its reporter-facing id (the same id carried
1666
+ * in SSE events such as `bundle_build_done`). Returns `undefined` when no
1667
+ * instance with that id has been created yet.
1668
+ */
1669
+ getInstanceById(id) {
1670
+ for (const instance of BundlerPool.instances.values()) if (instance.id === id) return instance;
1671
+ }
1672
+ };
1673
+ //#endregion
1674
+ //#region src/server/constants.ts
1675
+ const DEFAULT_PORT = 8081;
1676
+ const DEFAULT_HOST = "localhost";
1677
+ const DEV_SERVER_ASSET_PATH = "assets";
1678
+ //#endregion
1679
+ //#region src/server/error.ts
1680
+ function errorHandler(error, request, reply) {
1681
+ logger.error(`An error occurred while processing the request (${request.method} ${request.url}):`, error.message);
1682
+ logger.debug(error);
1683
+ reply.status(500).send("Internal Server Error");
1684
+ }
1685
+ //#endregion
1686
+ //#region src/server/mcp/server.ts
1687
+ function createMcpServer(options) {
1688
+ const { projectRoot, eventBus } = options;
1689
+ const server = new _modelcontextprotocol_sdk_server_mcp_js.McpServer({
1690
+ name: "rollipop",
1691
+ version: "0.1.0"
1692
+ }, { capabilities: { logging: {} } });
1693
+ server.registerTool("reset_cache", {
1694
+ title: "Reset Cache",
1695
+ description: "Clear the entire build cache. The bundler will rebuild from scratch on next change."
1696
+ }, async () => {
1697
+ resetCache(projectRoot);
1698
+ eventBus.emit({ type: "cache_reset" });
1699
+ return { content: [{
1700
+ type: "text",
1701
+ text: "Cache cleared successfully."
1702
+ }] };
1703
+ });
1704
+ server.registerTool("get_build_events", {
1705
+ title: "Get Build Events",
1706
+ description: "Subscribe to bundler events for a duration. Returns all events (build start/done/fail, watch changes, client logs, device connections) collected during the wait period.",
1707
+ inputSchema: { duration: zod.z.number().min(1e3).max(6e4).default(1e4).describe("How long to listen for events in milliseconds (1000-60000, default 10000)") }
1708
+ }, async ({ duration }) => {
1709
+ const events = [];
1710
+ const unsubscribe = eventBus.collect(events);
1711
+ await new Promise((resolve) => setTimeout(resolve, duration));
1712
+ unsubscribe();
1713
+ if (events.length === 0) return { content: [{
1714
+ type: "text",
1715
+ text: "No events received during the listening period."
1716
+ }] };
1717
+ return { content: [{
1718
+ type: "text",
1719
+ text: JSON.stringify(events, null, 2)
1720
+ }] };
1721
+ });
1722
+ return server;
1723
+ }
1724
+ const sessions = /* @__PURE__ */ new Map();
1725
+ const plugin$6 = (0, fastify_plugin.default)((fastify, options) => {
1726
+ fastify.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
1727
+ try {
1728
+ done(null, JSON.parse(body));
1729
+ } catch (error) {
1730
+ done(error, void 0);
1731
+ }
1732
+ });
1733
+ fastify.post("/mcp", async (request, reply) => {
1734
+ const sessionId = request.headers["mcp-session-id"];
1735
+ if (sessionId && sessions.has(sessionId)) {
1736
+ const { transport } = sessions.get(sessionId);
1737
+ await transport.handleRequest(request.raw, reply.raw, request.body);
1738
+ return reply;
1739
+ }
1740
+ if (!sessionId && (0, _modelcontextprotocol_sdk_types_js.isInitializeRequest)(request.body)) {
1741
+ const transport = new _modelcontextprotocol_sdk_server_streamableHttp_js.StreamableHTTPServerTransport({
1742
+ sessionIdGenerator: () => (0, node_crypto.randomUUID)(),
1743
+ onsessioninitialized: (sid) => {
1744
+ sessions.set(sid, {
1745
+ transport,
1746
+ server
1747
+ });
1748
+ }
1749
+ });
1750
+ transport.onclose = () => {
1751
+ const sid = transport.sessionId;
1752
+ if (sid) sessions.delete(sid);
1753
+ };
1754
+ const server = createMcpServer(options);
1755
+ await server.connect(transport);
1756
+ await transport.handleRequest(request.raw, reply.raw, request.body);
1757
+ return reply;
1758
+ }
1759
+ return reply.status(400).send({
1760
+ jsonrpc: "2.0",
1761
+ error: {
1762
+ code: -32e3,
1763
+ message: "Bad Request: invalid or missing session"
1764
+ },
1765
+ id: null
1766
+ });
1767
+ });
1768
+ fastify.get("/mcp", async (request, reply) => {
1769
+ const sessionId = request.headers["mcp-session-id"];
1770
+ if (!sessionId || !sessions.has(sessionId)) return reply.status(400).send("Missing or invalid session ID");
1771
+ await sessions.get(sessionId).transport.handleRequest(request.raw, reply.raw);
1772
+ return reply;
1773
+ });
1774
+ fastify.delete("/mcp", async (request, reply) => {
1775
+ const sessionId = request.headers["mcp-session-id"];
1776
+ if (!sessionId || !sessions.has(sessionId)) return reply.status(404).send("Session not found");
1777
+ await sessions.get(sessionId).transport.handleRequest(request.raw, reply.raw);
1778
+ return reply;
1779
+ });
1780
+ }, { name: "mcp" });
1781
+ //#endregion
1782
+ //#region src/server/middlewares/bundlers.ts
1783
+ const routeParamSchema$1 = (0, json_schema_to_ts.asConst)({
1784
+ type: "object",
1785
+ required: ["id"],
1786
+ properties: { id: { type: "string" } }
1787
+ });
1788
+ const plugin$5 = (0, fastify_plugin.default)((fastify, { bundlerPool }) => {
1789
+ fastify.get("/bundlers/:id/status", { schema: { params: routeParamSchema$1 } }, (request, reply) => {
1790
+ const instance = bundlerPool.getInstanceById(request.params.id);
1791
+ if (!instance) return reply.status(404).send({ error: "not found" });
1792
+ return reply.send({
1793
+ id: instance.id,
1794
+ status: instance.status
1795
+ });
1796
+ });
1797
+ }, { name: "bundlers" });
1798
+ //#endregion
1799
+ //#region src/server/middlewares/control.ts
1800
+ const plugin$4 = (0, fastify_plugin.default)((fastify, { projectRoot, eventBus }) => {
1801
+ fastify.all("/reset-cache", async (_request, reply) => {
1802
+ resetCache(projectRoot);
1803
+ eventBus.emit({ type: "cache_reset" });
1804
+ return reply.send({
1805
+ success: true,
1806
+ message: "Cache cleared"
1807
+ });
1808
+ });
1809
+ }, { name: "control" });
1810
+ //#endregion
1811
+ //#region src/server/middlewares/request-logger.ts
1812
+ const requestLogger = (req, _res, next) => {
1813
+ if (isDebugEnabled()) {
1814
+ logger.trace(chalk.default.bgBlue(` ${req.method} `), chalk.default.gray(req.url));
1815
+ Object.entries(req.headers).forEach(([key, value]) => {
1816
+ logger.trace(`${chalk.default.bold(key)}: ${chalk.default.gray(value)}`);
1817
+ });
1818
+ }
1819
+ next();
1820
+ };
1821
+ //#endregion
1822
+ //#region src/server/middlewares/serve-assets.ts
1823
+ const queryParamSchema = (0, json_schema_to_ts.asConst)({
1824
+ type: "object",
1825
+ properties: {
1826
+ platform: { type: "string" },
1827
+ hash: { type: "string" }
1828
+ },
1829
+ required: ["platform"]
1830
+ });
1831
+ const plugin$3 = (0, fastify_plugin.default)((fastify, options) => {
1832
+ const { projectRoot, host, port, https, preferNativePlatform } = options;
1833
+ const baseUrl = https ? `https://${host}:${port}` : `http://${host}:${port}`;
1834
+ function resolveAsset(asset) {
1835
+ return node_path.default.resolve(projectRoot, asset);
1836
+ }
1837
+ fastify.get(`/${DEV_SERVER_ASSET_PATH}/*`, {
1838
+ schema: { querystring: queryParamSchema },
1839
+ async handler(request, reply) {
1840
+ const { url, query } = request;
1841
+ const { pathname } = new URL(url, baseUrl);
1842
+ const assetPath = resolveAsset(pathname.replace(new RegExp(`^/${DEV_SERVER_ASSET_PATH}/?`), ""));
1843
+ let handle = null;
1844
+ try {
1845
+ handle = await node_fs.default.promises.open(resolveAssetPath(assetPath, {
1846
+ platform: query.platform,
1847
+ preferNativePlatform
1848
+ }, 1), "r");
1849
+ const assetData = await handle.readFile();
1850
+ const { size } = await handle.stat();
1851
+ await reply.header("Content-Type", mime.default.getType(assetPath) ?? "").header("Content-Length", size).send(assetData);
1852
+ } catch (error) {
1853
+ fastify.log.error(error, "Failed to serve asset (scale assets resolving is not implemented yet)");
1854
+ await reply.status(500).send();
1855
+ } finally {
1856
+ await handle?.close();
1857
+ }
1858
+ }
1859
+ });
1860
+ }, { name: "serve-assets" });
1861
+ //#endregion
1862
+ //#region src/utils/response.ts
1863
+ var BundleResponse = class BundleResponse {
1864
+ static CRLF = "\r\n";
1865
+ static THROTTLE_DELAY = 10;
1866
+ done = 0;
1867
+ total = 0;
1868
+ boundary;
1869
+ throttleTimer = null;
1870
+ constructor(reply) {
1871
+ this.reply = reply;
1872
+ const boundary = performance.now().toString();
1873
+ this.boundary = boundary;
1874
+ this.reply.raw.writeHead(200, { "Content-Type": `multipart/mixed; boundary="${boundary}"` });
1875
+ }
1876
+ writeChunk(data, headers, end = false) {
1877
+ if (this.reply.raw.writableEnded) return;
1878
+ const CRLF = BundleResponse.CRLF;
1879
+ this.reply.raw.write(`${CRLF}--${this.boundary}${CRLF}`);
1880
+ this.reply.raw.write(Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join(CRLF) + CRLF + CRLF);
1881
+ if (data) this.reply.raw.write(data);
1882
+ if (end) {
1883
+ this.reply.raw.write(`${CRLF}--${this.boundary}--${CRLF}`);
1884
+ this.reply.raw.end();
1885
+ }
1886
+ }
1887
+ /**
1888
+ * Sample
1889
+ *
1890
+ * ```
1891
+ * --boundary
1892
+ *
1893
+ * Content-Type: application/json
1894
+ *
1895
+ * {"done":10,"total":100}
1896
+ * ```
1897
+ */
1898
+ writeBundleState(done, total) {
1899
+ const previousProgress = this.done / this.total;
1900
+ const currentProgress = done / total;
1901
+ this.done = done;
1902
+ this.total = total;
1903
+ if (total < 10 || this.throttleTimer != null || previousProgress >= currentProgress) return;
1904
+ this.writeChunk(JSON.stringify({
1905
+ done,
1906
+ total
1907
+ }), { "Content-Type": "application/json" });
1908
+ this.throttleTimer = setTimeout(() => {
1909
+ this.throttleTimer = null;
1910
+ }, BundleResponse.THROTTLE_DELAY);
1911
+ }
1912
+ /**
1913
+ * Sample
1914
+ *
1915
+ * ```
1916
+ * --boundary
1917
+ *
1918
+ * X-Metro-Files-Changed-Count: 0
1919
+ * Content-Type: application/json
1920
+ * Content-Length: 100
1921
+ * Last-Modified: Thu, 10 Aug 2023 12:00:00 GMT
1922
+ *
1923
+ * <bundle result>
1924
+ * ```
1925
+ */
1926
+ endWithBundle(bundle) {
1927
+ this.writeChunk(JSON.stringify({
1928
+ done: this.total,
1929
+ total: this.total
1930
+ }), { "Content-Type": "application/json" });
1931
+ this.writeChunk(bundle, {
1932
+ "X-Metro-Files-Changed-Count": String(0),
1933
+ "Content-Type": "application/javascript; charset=UTF-8",
1934
+ "Content-Length": String(Buffer.byteLength(bundle)),
1935
+ "Last-Modified": (/* @__PURE__ */ new Date()).toUTCString()
1936
+ }, true);
1937
+ }
1938
+ endWithError(error) {
1939
+ const errorData = JSON.stringify({
1940
+ type: error?.name ?? "InternalError",
1941
+ message: error?.message ?? "internal error",
1942
+ errors: []
1943
+ });
1944
+ this.writeChunk(errorData, {
1945
+ "Content-Type": "application/json",
1946
+ "X-Http-Status": "500"
1947
+ }, true);
1948
+ }
1949
+ };
1950
+ //#endregion
1951
+ //#region src/server/common/schema.ts
1952
+ const bundleRequestSchema = (0, json_schema_to_ts.asConst)({
1953
+ type: "object",
1954
+ properties: {
1955
+ platform: { type: "string" },
1956
+ app: { type: "string" },
1957
+ dev: { type: "boolean" },
1958
+ minify: { type: "boolean" },
1959
+ runModule: { type: "boolean" },
1960
+ inlineSourceMap: { type: "boolean" },
1961
+ modulesOnly: { type: "boolean" }
1962
+ },
1963
+ required: ["platform"]
1964
+ });
1965
+ new ajv.default().compile(bundleRequestSchema);
1966
+ //#endregion
1967
+ //#region src/server/middlewares/serve-bundle.ts
1968
+ const routeParamSchema = (0, json_schema_to_ts.asConst)({
1969
+ type: "object",
1970
+ properties: { name: { type: "string" } }
1971
+ });
1972
+ function withGetBundleErrorHandler(reply, task) {
1973
+ return task.catch((error) => {
1974
+ return reply.status(500).send(error instanceof Error ? error.message : "Internal Server Error");
1975
+ });
1976
+ }
1977
+ const plugin$2 = (0, fastify_plugin.default)((fastify, options) => {
1978
+ const { getBundler } = options;
1979
+ const getBundleOptions = (buildOptions) => {
1980
+ return {
1981
+ platform: buildOptions.platform,
1982
+ dev: buildOptions.dev,
1983
+ minify: buildOptions.minify,
1984
+ sourcemap: buildOptions.inlineSourceMap ? "inline" : true
1985
+ };
1986
+ };
1987
+ fastify.get("/:name.bundle", {
1988
+ schema: {
1989
+ params: routeParamSchema,
1990
+ querystring: bundleRequestSchema
1991
+ },
1992
+ async handler(request, reply) {
1993
+ const { params, query, headers: { accept } } = request;
1994
+ if (!params.name) {
1995
+ await reply.status(400).send("invalid bundle name");
1996
+ return;
1997
+ }
1998
+ const buildOptions = getBundleOptions(query);
1999
+ const bundler = getBundler(params.name, buildOptions);
2000
+ if (accept?.includes("multipart/mixed") ?? false) {
2001
+ const bundleResponse = new BundleResponse(reply);
2002
+ const transformHandler = (_id, totalModules = 0, transformedModules) => {
2003
+ bundleResponse.writeBundleState(transformedModules, totalModules);
2004
+ };
2005
+ bundler.on("transform", transformHandler);
2006
+ await bundler.getBundle().then((bundle) => bundleResponse.endWithBundle(bundle.code)).catch((error) => bundleResponse.endWithError(error)).finally(() => bundler.off("transform", transformHandler));
2007
+ } else {
2008
+ this.log.debug(`client is not support multipart/mixed content: ${accept ?? "<empty>"}`);
2009
+ const code = (await withGetBundleErrorHandler(reply, bundler.getBundle())).code;
2010
+ await reply.header("Content-Type", "application/javascript").header("Content-Length", Buffer.byteLength(code)).status(200).send(code);
2011
+ }
2012
+ }
2013
+ });
2014
+ fastify.get("/:name.map", {
2015
+ schema: {
2016
+ params: routeParamSchema,
2017
+ querystring: bundleRequestSchema
2018
+ },
2019
+ async handler(request, reply) {
2020
+ const { params, query } = request;
2021
+ if (!params.name) {
2022
+ await reply.status(400).send("invalid bundle name");
2023
+ return;
2024
+ }
2025
+ const buildOptions = getBundleOptions(query);
2026
+ const sourceMap = (await withGetBundleErrorHandler(reply, getBundler(params.name, buildOptions).getBundle())).sourceMap;
2027
+ (0, es_toolkit.invariant)(sourceMap, "Source map is not available");
2028
+ await reply.header("Access-Control-Allow-Origin", "devtools://devtools").header("Content-Type", "application/json").header("Content-Length", Buffer.byteLength(sourceMap)).status(200).send(sourceMap);
2029
+ }
2030
+ });
2031
+ }, { name: "serve-bundle" });
2032
+ //#endregion
2033
+ //#region src/server/middlewares/sse.ts
2034
+ const plugin$1 = (0, fastify_plugin.default)((fastify, { eventBus }) => {
2035
+ fastify.get("/sse/events", (request, reply) => {
2036
+ const res = reply.raw;
2037
+ res.writeHead(200, {
2038
+ Connection: "keep-alive",
2039
+ "Content-Type": "text/event-stream",
2040
+ "Cache-Control": "no-cache",
2041
+ "X-Accel-Buffering": "no"
2042
+ });
2043
+ request.raw.socket.setNoDelay(true);
2044
+ res.write(":ok\n\n");
2045
+ eventBus.addClient(res);
2046
+ request.raw.on("close", () => eventBus.removeClient(res));
2047
+ });
2048
+ }, { name: "sse" });
2049
+ //#endregion
2050
+ //#region src/utils/url.ts
2051
+ function parseUrl(value) {
2052
+ if (value.startsWith("/")) {
2053
+ const [pathname, query] = value.split("?");
2054
+ return {
2055
+ pathname,
2056
+ query: query ? toQueryObject(new URLSearchParams(query)) : {}
2057
+ };
2058
+ }
2059
+ const url = new URL(value);
2060
+ return {
2061
+ pathname: url.pathname,
2062
+ query: toQueryObject(url.searchParams)
2063
+ };
2064
+ }
2065
+ function toQueryObject(searchParams) {
2066
+ return searchParams.entries().reduce((acc, [key, value]) => ({
2067
+ ...acc,
2068
+ [key]: value
2069
+ }), {});
2070
+ }
2071
+ //#endregion
2072
+ //#region src/server/symbolicate.ts
2073
+ /**
2074
+ * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/metro-config/src/index.flow.js#L17
2075
+ */
2076
+ const INTERNAL_CALLSITES_REGEX = new RegExp([
2077
+ "/Libraries/BatchedBridge/MessageQueue\\.js$",
2078
+ "/Libraries/Core/.+\\.js$",
2079
+ "/Libraries/LogBox/.+\\.js$",
2080
+ "/Libraries/Network/.+\\.js$",
2081
+ "/Libraries/Pressability/.+\\.js$",
2082
+ "/Libraries/Renderer/implementations/.+\\.js$",
2083
+ "/Libraries/Utilities/.+\\.js$",
2084
+ "/Libraries/vendor/.+\\.js$",
2085
+ "/Libraries/WebSocket/.+\\.js$",
2086
+ "/src/private/renderer/errorhandling/.+\\.js$",
2087
+ "/metro-runtime/.+\\.js$",
2088
+ "/node_modules/@babel/runtime/.+\\.js$",
2089
+ "/node_modules/@react-native/js-polyfills/.+\\.js$",
2090
+ "/node_modules/invariant/.+\\.js$",
2091
+ "/node_modules/react-devtools-core/.+\\.js$",
2092
+ "/node_modules/react-native/index.js$",
2093
+ "/node_modules/react-refresh/.+\\.js$",
2094
+ "/node_modules/scheduler/.+\\.js$",
2095
+ "^\\[native code\\]$"
2096
+ ].map((pathPattern) => pathPattern.replaceAll("/", "[/\\\\]")).join("|"));
2097
+ async function symbolicate(bundleStore, stack) {
2098
+ const sourceMapConsumer = await bundleStore.sourceMapConsumer;
2099
+ const symbolicatedStack = stack.filter((frame) => frame.file?.startsWith("http")).map((frame) => sourceMapConsumer ? originalPositionFor(sourceMapConsumer, frame) : frame).map((frame) => collapseFrame(frame));
2100
+ return {
2101
+ stack: symbolicatedStack,
2102
+ codeFrame: getCodeFrame(symbolicatedStack, bundleStore, sourceMapConsumer)
2103
+ };
2104
+ }
2105
+ function originalPositionFor(sourceMapConsumer, frame) {
2106
+ if (frame.column == null || frame.lineNumber == null) return frame;
2107
+ const originalPosition = sourceMapConsumer.originalPositionFor({
2108
+ column: frame.column,
2109
+ line: frame.lineNumber
2110
+ });
2111
+ return Object.entries(originalPosition).reduce((frame, [key, value]) => {
2112
+ const targetKey = convertFrameKey(key);
2113
+ return {
2114
+ ...frame,
2115
+ ...value ? { [targetKey]: value } : null
2116
+ };
2117
+ }, frame);
2118
+ }
2119
+ function collapseFrame(frame) {
2120
+ return {
2121
+ ...frame,
2122
+ collapse: Boolean(frame.file && INTERNAL_CALLSITES_REGEX.test(frame.file))
2123
+ };
2124
+ }
2125
+ function isCollapsed(frame) {
2126
+ return "collapse" in frame && frame.collapse;
2127
+ }
2128
+ function convertFrameKey(key) {
2129
+ if (key === "line") return "lineNumber";
2130
+ else if (key === "source") return "file";
2131
+ else if (key === "name") return "methodName";
2132
+ return key;
2133
+ }
2134
+ function getCodeFrame(frames, bundleStore, sourceMapConsumer) {
2135
+ const frame = frames.find((frame) => {
2136
+ return frame.lineNumber != null && frame.column != null && !isCollapsed(frame);
2137
+ });
2138
+ if (frame?.file == null || frame.column == null || frame.lineNumber == null) return null;
2139
+ try {
2140
+ const { lineNumber, column, file } = frame;
2141
+ const unresolved = file.startsWith("http");
2142
+ const source = sourceMapConsumer == null || unresolved ? bundleStore.code : sourceMapConsumer.sourceContentFor(frame.file);
2143
+ const fileName = unresolved ? parseUrl(file).pathname ?? "unknown" : file;
2144
+ let content = "";
2145
+ if (source) content = (0, _babel_code_frame.codeFrameColumns)(source, { start: {
2146
+ column,
2147
+ line: lineNumber
2148
+ } }, { highlightCode: true });
2149
+ return {
2150
+ content,
2151
+ fileName,
2152
+ location: {
2153
+ column,
2154
+ row: lineNumber
2155
+ }
2156
+ };
2157
+ } catch {
2158
+ return null;
2159
+ }
2160
+ }
2161
+ //#endregion
2162
+ //#region src/server/middlewares/symbolicate.ts
2163
+ const bodySchema = (0, json_schema_to_ts.asConst)({
2164
+ type: "object",
2165
+ properties: {
2166
+ stack: {
2167
+ type: "array",
2168
+ items: {}
2169
+ },
2170
+ extraData: {}
2171
+ },
2172
+ required: ["stack"]
2173
+ });
2174
+ const plugin = (0, fastify_plugin.default)((fastify, options) => {
2175
+ const { getBundler } = options;
2176
+ fastify.post("/symbolicate", {
2177
+ schema: { body: bodySchema },
2178
+ async handler(request, reply) {
2179
+ const { stack } = request.body;
2180
+ const bundleUrl = stack.find((frame) => frame.file?.startsWith("http"));
2181
+ (0, es_toolkit.invariant)(bundleUrl?.file, "No bundle URL found in stack frames");
2182
+ const { pathname, query } = parseUrl(bundleUrl.file);
2183
+ (0, es_toolkit.invariant)(pathname, "No pathname found in bundle URL");
2184
+ (0, es_toolkit.invariant)(query.platform, "No platform found in query");
2185
+ (0, es_toolkit.invariant)(query.dev, "No dev found in query");
2186
+ const symbolicateResult = await symbolicate(await getBundler(getBaseBundleName(pathname), {
2187
+ platform: query.platform,
2188
+ dev: query.dev === "true"
2189
+ }).getBundle(), stack);
2190
+ if (isDebugEnabled()) printSymbolicateResult(stack, symbolicateResult);
2191
+ await reply.header("Content-Type", "application/json").send(symbolicateResult);
2192
+ }
2193
+ });
2194
+ }, { name: "symbolicate" });
2195
+ function printSymbolicateResult(rawStackFrame, symbolicateResult) {
2196
+ console.log();
2197
+ console.log("Symbolicate result:");
2198
+ console.log();
2199
+ if (symbolicateResult.codeFrame != null) {
2200
+ console.log(symbolicateResult.codeFrame.content);
2201
+ console.log();
2202
+ }
2203
+ console.log("Stack trace:");
2204
+ symbolicateResult.stack.forEach((stackFrame) => {
2205
+ const symbol = stackFrame.methodName ?? "<anonymous>";
2206
+ const file = stackFrame.file ?? "unknown";
2207
+ const location = stackFrame.lineNumber != null && stackFrame.column != null ? `(${chalk.default.gray.underline(`${file}:${stackFrame.lineNumber}:${stackFrame.column}`)})` : "";
2208
+ console.log(` at ${symbol} ${location}`);
2209
+ });
2210
+ console.log();
2211
+ console.log("Raw stack trace:");
2212
+ rawStackFrame.filter((stackFrame) => stackFrame.file?.startsWith("http")).forEach((stackFrame) => {
2213
+ const bundleName = new URL(stackFrame.file).pathname.slice(1);
2214
+ const symbol = stackFrame.methodName ?? "<anonymous>";
2215
+ const location = stackFrame.lineNumber != null && stackFrame.column != null ? `(${chalk.default.gray.underline(`${bundleName}:${stackFrame.lineNumber}:${stackFrame.column}`)})` : "";
2216
+ console.log(` at ${symbol} ${location}`);
2217
+ });
2218
+ console.log();
2219
+ }
2220
+ //#endregion
2221
+ //#region src/server/sse/event-bus.ts
2222
+ var SSEEventBus = class {
2223
+ clients = /* @__PURE__ */ new Set();
2224
+ listeners = /* @__PURE__ */ new Set();
2225
+ emit(event) {
2226
+ const data = JSON.stringify(event);
2227
+ const message = `event: ${event.type}\ndata: ${data}\n\n`;
2228
+ for (const client of this.clients) if (!client.closed) client.write(message);
2229
+ for (const listener of this.listeners) listener(event);
2230
+ }
2231
+ /**
2232
+ * Subscribe an SSE HTTP response client.
2233
+ */
2234
+ addClient(res) {
2235
+ this.clients.add(res);
2236
+ }
2237
+ /**
2238
+ * Unsubscribe an SSE HTTP response client.
2239
+ */
2240
+ removeClient(res) {
2241
+ this.clients.delete(res);
2242
+ }
2243
+ /**
2244
+ * Subscribe a listener that collects events into the given array.
2245
+ * Returns an unsubscribe function.
2246
+ */
2247
+ collect(collector) {
2248
+ const listener = (event) => collector.push(event);
2249
+ this.listeners.add(listener);
2250
+ return () => this.listeners.delete(listener);
2251
+ }
2252
+ get clientCount() {
2253
+ return this.clients.size;
2254
+ }
2255
+ };
2256
+ //#endregion
2257
+ //#region src/server/sse/reporter.ts
2258
+ function toSSEEvent(id, event) {
2259
+ switch (event.type) {
2260
+ case "bundle_build_started": return {
2261
+ type: "bundle_build_started",
2262
+ id
2263
+ };
2264
+ case "bundle_build_done": return {
2265
+ type: "bundle_build_done",
2266
+ id,
2267
+ totalModules: event.totalModules,
2268
+ duration: event.duration
2269
+ };
2270
+ case "bundle_build_failed": return {
2271
+ type: "bundle_build_failed",
2272
+ id,
2273
+ error: (0, strip_ansi.default)(event.error.message)
2274
+ };
2275
+ case "watch_change": return {
2276
+ type: "watch_change",
2277
+ id,
2278
+ file: event.id
2279
+ };
2280
+ case "client_log": return {
2281
+ type: "client_log",
2282
+ data: event.data
2283
+ };
2284
+ case "transform": return null;
2285
+ }
2286
+ }
2287
+ //#endregion
2288
+ //#region src/server/wss/server.ts
2289
+ var WebSocketServer = class extends node_events.default {
2290
+ clientId = 0;
2291
+ wss;
2292
+ logger;
2293
+ constructor(name, options) {
2294
+ super();
2295
+ const logger$3 = logger.child(name);
2296
+ const wss = new ws.WebSocketServer(options);
2297
+ wss.on("connection", (socket) => {
2298
+ const client = Object.defineProperty(socket, "id", {
2299
+ value: this.clientId++,
2300
+ writable: false
2301
+ });
2302
+ this.onConnection(client);
2303
+ this.emit("connection", client);
2304
+ client.on("message", (data) => {
2305
+ this.onMessage(client, data);
2306
+ this.emit("message", client, data);
2307
+ });
2308
+ client.on("error", (error) => {
2309
+ this.onError(client, error);
2310
+ this.emit("error", client, error);
2311
+ });
2312
+ client.on("close", () => {
2313
+ this.onClose(client);
2314
+ this.emit("close", client);
2315
+ });
2316
+ });
2317
+ this.wss = wss;
2318
+ this.logger = logger$3;
2319
+ }
2320
+ get server() {
2321
+ return this.wss;
2322
+ }
2323
+ send(client, data) {
2324
+ if (client.readyState === ws.WebSocket.OPEN) client.send(data);
2325
+ }
2326
+ sendAll(data) {
2327
+ this.wss.clients.forEach((client) => {
2328
+ if (client.readyState === ws.WebSocket.OPEN) client.send(data);
2329
+ });
2330
+ }
2331
+ rawDataToString(data) {
2332
+ if (Buffer.isBuffer(data)) return data.toString("utf8");
2333
+ if (Array.isArray(data)) return Buffer.concat(data).toString("utf8");
2334
+ return Buffer.from(data).toString("utf8");
2335
+ }
2336
+ };
2337
+ function getWebSocketUpgradeHandler(websocketEndpoints) {
2338
+ return (request, socket, head) => {
2339
+ if (request.url == null) {
2340
+ socket.destroy();
2341
+ return;
2342
+ }
2343
+ const { pathname } = parseUrl(request.url);
2344
+ if (pathname != null && websocketEndpoints[pathname]) {
2345
+ const wss = websocketEndpoints[pathname];
2346
+ wss.handleUpgrade(request, socket, head, (socket) => {
2347
+ wss.emit("connection", socket, request);
2348
+ });
2349
+ } else socket.destroy();
2350
+ };
2351
+ }
2352
+ //#endregion
2353
+ //#region src/server/wss/hmr-server.ts
2354
+ var HMRServer = class extends WebSocketServer {
2355
+ bundlerPool;
2356
+ reportEvent;
2357
+ instances = /* @__PURE__ */ new Map();
2358
+ bindings = /* @__PURE__ */ new Map();
2359
+ constructor({ bundlerPool, reportEvent }) {
2360
+ super("hmr", { noServer: true });
2361
+ this.bundlerPool = bundlerPool;
2362
+ this.reportEvent = reportEvent;
2363
+ }
2364
+ parseClientMessage(data) {
2365
+ const parsedData = JSON.parse(this.rawDataToString(data));
2366
+ const clientMessage = "type" in parsedData ? parsedData : null;
2367
+ (0, es_toolkit.invariant)(clientMessage, "Invalid HMR client message");
2368
+ return clientMessage;
2369
+ }
2370
+ async handleConnected(client, platform, bundleEntry) {
2371
+ try {
2372
+ this.logger.trace(`HMR client connected (clientId: ${client.id})`, {
2373
+ platform,
2374
+ bundleEntry
2375
+ });
2376
+ const devEngineInstance = this.bundlerPool.get(bundleEntry, {
2377
+ platform,
2378
+ dev: true
2379
+ });
2380
+ this.bindEvents(client, devEngineInstance);
2381
+ this.instances.set(client.id, devEngineInstance);
2382
+ this.logger.trace(`Bundler instance prepared (bundlerId: ${devEngineInstance.id})`);
2383
+ } catch (error) {
2384
+ this.logger.error(`Failed to prepare bundler instance`, error);
2385
+ }
2386
+ }
2387
+ bindEvents(client, instance) {
2388
+ if (this.bindings.get(client.id) == null) {
2389
+ const handleHmrUpdates = (updates) => {
2390
+ this.handleUpdates(client, updates);
2391
+ };
2392
+ const handleWatchChange = () => {
2393
+ this.send(client, JSON.stringify({ type: "hmr:update-start" }));
2394
+ };
2395
+ const handleBuildFailed = (error) => {
2396
+ this.send(client, JSON.stringify({
2397
+ type: "hmr:error",
2398
+ payload: {
2399
+ type: "BuildError",
2400
+ errors: [{ description: error.message }],
2401
+ message: error.message
2402
+ }
2403
+ }));
2404
+ };
2405
+ instance.addListener("hmrUpdates", handleHmrUpdates);
2406
+ instance.addListener("watchChange", handleWatchChange);
2407
+ instance.addListener("buildFailed", handleBuildFailed);
2408
+ this.bindings.set(client.id, {
2409
+ hmrUpdates: handleHmrUpdates,
2410
+ watchChange: handleWatchChange,
2411
+ buildFailed: handleBuildFailed
2412
+ });
2413
+ this.logger.trace(`HMR event binding established (clientId: ${client.id})`);
2414
+ }
2415
+ }
2416
+ async handleModuleRegistered(client, modules) {
2417
+ try {
2418
+ const instance = this.instances.get(client.id);
2419
+ (0, es_toolkit.invariant)(instance != null, `Bundler instance not found for client clientId: ${client.id}`);
2420
+ await instance.ensureInitialized;
2421
+ await instance.devEngine.registerModules(client.id.toString(), modules);
2422
+ } catch (error) {
2423
+ this.logger.error(`Failed to handle module registered`, error);
2424
+ }
2425
+ }
2426
+ async handleInvalidate(client, moduleId) {
2427
+ try {
2428
+ const instance = this.instances.get(client.id);
2429
+ (0, es_toolkit.invariant)(instance != null, `Bundler instance not found for client clientId: ${client.id}`);
2430
+ await instance.ensureInitialized;
2431
+ const updates = await instance.devEngine.invalidate(moduleId);
2432
+ await this.handleUpdates(client, updates);
2433
+ } catch (error) {
2434
+ this.logger.error(`Failed to handle invalidate`, error);
2435
+ }
2436
+ }
2437
+ async handleUpdates(client, updates) {
2438
+ this.logger.trace(`HMR updates found (clientId: ${client.id})`, { updatesCount: updates.length });
2439
+ for (const clientUpdate of updates) {
2440
+ const update = clientUpdate.update;
2441
+ switch (update.type) {
2442
+ case "Patch":
2443
+ this.sendUpdateToClient(client, update);
2444
+ break;
2445
+ case "FullReload":
2446
+ this.sendReloadToClient(client);
2447
+ break;
2448
+ case "Noop":
2449
+ this.logger.warn(`Client ${clientUpdate.clientId} received noop update`);
2450
+ break;
2451
+ }
2452
+ }
2453
+ }
2454
+ sendUpdateToClient(client, update) {
2455
+ (0, es_toolkit.invariant)(update.type === "Patch", "Invalid HMR update type");
2456
+ const updateMessage = {
2457
+ type: "hmr:update",
2458
+ code: update.code
2459
+ };
2460
+ this.send(client, JSON.stringify(updateMessage));
2461
+ this.done(client);
2462
+ }
2463
+ sendReloadToClient(client) {
2464
+ this.logger.trace(`Sending HMR reload message to client (clientId: ${client.id})`);
2465
+ this.send(client, JSON.stringify({ type: "hmr:reload" }));
2466
+ this.done(client);
2467
+ }
2468
+ done(client) {
2469
+ this.send(client, JSON.stringify({ type: "hmr:update-done" }));
2470
+ }
2471
+ sendError(client, error) {
2472
+ try {
2473
+ this.send(client, JSON.stringify(error));
2474
+ } catch (error) {
2475
+ this.logger.error(`Failed to send HMR error message to client (clientId: ${client.id})`, error);
2476
+ }
2477
+ }
2478
+ cleanup(client) {
2479
+ this.logger.trace(`HMR client cleanup (clientId: ${client.id})`);
2480
+ const binding = this.bindings.get(client.id);
2481
+ const instance = this.instances.get(client.id);
2482
+ if (binding != null && instance != null) {
2483
+ instance.removeListener("hmrUpdates", binding.hmrUpdates);
2484
+ instance.removeListener("watchChange", binding.watchChange);
2485
+ instance.removeListener("buildFailed", binding.buildFailed);
2486
+ }
2487
+ if (instance != null) try {
2488
+ instance.devEngine.removeClient(String(client.id));
2489
+ } catch (error) {
2490
+ this.logger.warn(`Skipped devEngine.removeClient for client ${client.id}: ` + (error instanceof Error ? error.message : String(error)));
2491
+ }
2492
+ this.bindings.delete(client.id);
2493
+ this.instances.delete(client.id);
2494
+ }
2495
+ onMessage(client, data) {
2496
+ let message;
2497
+ try {
2498
+ message = this.parseClientMessage(data);
2499
+ let traceMessage = message;
2500
+ if (message.type === "hmr:module-registered") traceMessage = {
2501
+ ...message,
2502
+ modules: `[${message.modules.length} modules]`
2503
+ };
2504
+ else if (message.type === "hmr:log") traceMessage = {
2505
+ ...message,
2506
+ data: `(${message.data.length} items)`
2507
+ };
2508
+ this.logger.trace("HMR client message received", traceMessage);
2509
+ } catch (error) {
2510
+ const message = "Failed to parse HMR client message";
2511
+ this.logger.error(message, error);
2512
+ this.sendError(client, {
2513
+ type: "InternalError",
2514
+ errors: [{ description: error instanceof Error ? error.message : String(error) }],
2515
+ message
2516
+ });
2517
+ return;
2518
+ }
2519
+ if (isCustomHMRMessage(message)) {
2520
+ this.wss.emit(message.type, message.payload);
2521
+ return;
2522
+ }
2523
+ switch (message.type) {
2524
+ case "hmr:connected":
2525
+ this.handleConnected(client, message.platform, message.bundleEntry);
2526
+ break;
2527
+ case "hmr:module-registered":
2528
+ this.handleModuleRegistered(client, message.modules);
2529
+ break;
2530
+ case "hmr:invalidate":
2531
+ this.handleInvalidate(client, message.moduleId);
2532
+ break;
2533
+ case "hmr:log":
2534
+ this.reportEvent({
2535
+ type: "client_log",
2536
+ level: message.level,
2537
+ data: message.data
2538
+ });
2539
+ break;
2540
+ }
2541
+ }
2542
+ onConnection(client) {
2543
+ this.logger.trace(`connection established (clientId: ${client.id})`);
2544
+ }
2545
+ onError(client, error) {
2546
+ this.logger.error(`connection error (clientId: ${client.id})`, error);
2547
+ this.cleanup(client);
2548
+ }
2549
+ onClose(client) {
2550
+ this.logger.trace(`connection closed (clientId: ${client.id})`);
2551
+ this.cleanup(client);
2552
+ }
2553
+ };
2554
+ function isCustomHMRMessage(message) {
2555
+ if (typeof message !== "object" || message == null) return false;
2556
+ if ("type" in message && typeof message.type === "string" && message.type.startsWith("hmr:")) return false;
2557
+ return true;
2558
+ }
2559
+ //#endregion
2560
+ //#region src/server/create-dev-server.ts
2561
+ async function createDevServer(config, options) {
2562
+ const projectRoot = config.root;
2563
+ const { port = DEFAULT_PORT, host = DEFAULT_HOST, https = false } = options ?? {};
2564
+ if (https) throw new Error("HTTPS is not supported yet");
2565
+ const serverBaseUrl = url.default.format({
2566
+ protocol: https ? "https" : "http",
2567
+ hostname: host,
2568
+ port
2569
+ });
2570
+ await assertDevServerStatus({
2571
+ devServerUrl: serverBaseUrl,
2572
+ projectRoot,
2573
+ port
2574
+ });
2575
+ const emitter = (0, mitt.default)();
2576
+ const fastify$1 = (0, fastify.default)({
2577
+ loggerInstance: new DevServerLogger(),
2578
+ disableRequestLogging: true
2579
+ });
2580
+ const sseEventBus = new SSEEventBus();
2581
+ const bundlerPool = new BundlerPool(config, {
2582
+ host,
2583
+ port
2584
+ }, (id, event) => {
2585
+ const sseEvent = toSSEEvent(id, event);
2586
+ if (sseEvent) sseEventBus.emit(sseEvent);
2587
+ });
2588
+ const getBundler = (bundleName, buildOptions) => {
2589
+ return bundlerPool.get(bundleName, (0, es_toolkit.merge)(options?.buildOptions ?? {}, buildOptions));
2590
+ };
2591
+ const { middleware: communityMiddleware, websocketEndpoints: communityWebsocketEndpoints, messageSocketEndpoint: { server: messageServer, broadcast }, eventsSocketEndpoint: { server: eventsServer, reportEvent } } = (0, _react_native_community_cli_server_api.createDevServerMiddleware)({
2592
+ port,
2593
+ host,
2594
+ watchFolders: []
2595
+ });
2596
+ const { middleware: devMiddleware, websocketEndpoints } = (0, _react_native_dev_middleware.createDevMiddleware)({
2597
+ serverBaseUrl,
2598
+ logger: {
2599
+ info(...args) {
2600
+ if (args[0].includes("JavaScript logs have moved")) return;
2601
+ logger.info(...args);
2602
+ },
2603
+ warn: logger.warn.bind(logger),
2604
+ error: logger.error.bind(logger)
2605
+ },
2606
+ unstable_experiments: {
2607
+ enableNetworkInspector: true,
2608
+ enableStandaloneFuseboxShell: true
2609
+ }
2610
+ });
2611
+ const hmrServer = new HMRServer({
2612
+ bundlerPool,
2613
+ reportEvent: (event) => {
2614
+ reportEvent?.(event);
2615
+ config.reporter?.update(event);
2616
+ }
2617
+ }).on("connection", (client) => {
2618
+ emitter.emit("device.connected", { client });
2619
+ sseEventBus.emit({
2620
+ type: "device_connected",
2621
+ clientId: client.id
2622
+ });
2623
+ }).on("message", (client, data) => emitter.emit("device.message", {
2624
+ client,
2625
+ data
2626
+ })).on("error", (client, error) => emitter.emit("device.error", {
2627
+ client,
2628
+ error
2629
+ })).on("close", (client) => {
2630
+ emitter.emit("device.disconnected", { client });
2631
+ sseEventBus.emit({
2632
+ type: "device_disconnected",
2633
+ clientId: client.id
2634
+ });
2635
+ });
2636
+ await fastify$1.register(import("@fastify/middie"));
2637
+ const devServer = {
2638
+ ...emitter,
2639
+ config,
2640
+ instance: fastify$1,
2641
+ middlewares: { use: fastify$1.use.bind(fastify$1) },
2642
+ message: Object.assign(messageServer, { broadcast }),
2643
+ events: Object.assign(eventsServer, { reportEvent }),
2644
+ hot: Object.assign(hmrServer.server, {
2645
+ send: (client, eventName, payload) => {
2646
+ hmrServer.send(client, JSON.stringify({
2647
+ type: eventName,
2648
+ payload
2649
+ }));
2650
+ },
2651
+ sendAll: (eventName, payload) => {
2652
+ hmrServer.sendAll(JSON.stringify({
2653
+ type: eventName,
2654
+ payload
2655
+ }));
2656
+ }
2657
+ })
2658
+ };
2659
+ const { invokePostConfigureServer } = await invokeConfigureServer(devServer, config.plugins ?? []);
2660
+ fastify$1.use(requestLogger).use(communityMiddleware).use(devMiddleware).register(plugin$1, { eventBus: sseEventBus }).register(plugin$4, {
2661
+ projectRoot,
2662
+ eventBus: sseEventBus
2663
+ }).register(plugin$5, { bundlerPool }).register(plugin$6, {
2664
+ projectRoot,
2665
+ eventBus: sseEventBus
2666
+ }).register(plugin, { getBundler }).register(plugin$2, { getBundler }).register(plugin$3, {
2667
+ projectRoot,
2668
+ host,
2669
+ port,
2670
+ https,
2671
+ preferNativePlatform: config.resolver.preferNativePlatform
2672
+ }).setErrorHandler(errorHandler);
2673
+ fastify$1.server.on("upgrade", getWebSocketUpgradeHandler({
2674
+ ...communityWebsocketEndpoints,
2675
+ ...websocketEndpoints,
2676
+ "/hot": hmrServer.server
2677
+ }));
2678
+ await invokePostConfigureServer();
2679
+ sseEventBus.emit({
2680
+ type: "server_ready",
2681
+ host,
2682
+ port
2683
+ });
2684
+ return devServer;
2685
+ }
2686
+ async function invokeConfigureServer(server, plugins) {
2687
+ const postConfigureServerHandlers = [];
2688
+ for (const plugin of plugins) {
2689
+ const context = createPluginContext(plugin.name);
2690
+ const result = await plugin.configureServer?.call(context, server);
2691
+ if (typeof result === "function") postConfigureServerHandlers.push(result);
2692
+ }
2693
+ return { invokePostConfigureServer: async () => {
2694
+ for (const handler of postConfigureServerHandlers) await handler();
2695
+ } };
2696
+ }
2697
+ //#endregion
2698
+ //#region src/core/assets.ts
2699
+ /**
2700
+ * **NOTE**: Type definitions are ported from `metro` implementation.
2701
+ *
2702
+ * @see https://github.com/facebook/metro/blob/0.81.x/packages/metro/src/Assets.js
2703
+ */
2704
+ const SCALE_PATTERN = "@(\\d+\\.?\\d*)x";
2705
+ /**
2706
+ * key: platform,
2707
+ * value: allowed scales
2708
+ *
2709
+ * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/filterPlatformAssetScales.js#L11
2710
+ */
2711
+ const ALLOW_SCALES = { ios: [
2712
+ 1,
2713
+ 2,
2714
+ 3
2715
+ ] };
2716
+ /**
2717
+ * @see https://developer.android.com/training/multiscreen/screendensities#TaskProvideAltBmp
2718
+ */
2719
+ const ANDROID_ASSET_QUALIFIER = {
2720
+ .75: "ldpi",
2721
+ 1: "mdpi",
2722
+ 1.5: "hdpi",
2723
+ 2: "xhdpi",
2724
+ 3: "xxhdpi",
2725
+ 4: "xxxhdpi"
2726
+ };
2727
+ async function resolveScaledAssets(options) {
2728
+ const { projectRoot, assetPath, platform, preferNativePlatform } = options;
2729
+ const context = {
2730
+ platform,
2731
+ preferNativePlatform
2732
+ };
2733
+ const extension = node_path.default.extname(assetPath);
2734
+ const relativePath = node_path.default.relative(projectRoot, assetPath);
2735
+ const dirname = node_path.default.dirname(assetPath);
2736
+ const files = node_fs.default.readdirSync(dirname);
2737
+ const stripedBasename = stripSuffix(assetPath, context);
2738
+ const suffixPattern = platformSuffixPattern(context);
2739
+ const assetRegExp = new RegExp(`${stripedBasename}(${SCALE_PATTERN})?(?:${suffixPattern})?${extension}$`);
2740
+ const scaledAssets = {};
2741
+ for (const file of files.sort((a, b) => getAssetPriority(b, context) - getAssetPriority(a, context))) {
2742
+ const match = assetRegExp.exec(file);
2743
+ if (match) {
2744
+ const [, , scale = "1"] = match;
2745
+ if (scaledAssets[scale]) continue;
2746
+ scaledAssets[scale] = file;
2747
+ }
2748
+ }
2749
+ if (!(Object.keys(scaledAssets).length && scaledAssets[1])) throw new Error(`cannot resolve base asset of ${assetPath}`);
2750
+ const imageData = node_fs.default.readFileSync(assetPath);
2751
+ const dimensions = (0, image_size.imageSize)(imageData);
2752
+ const filteredScaledAssets = Object.entries(scaledAssets).map(([scale, file]) => ({
2753
+ scale: parseFloat(scale),
2754
+ file
2755
+ })).filter(({ scale }) => ALLOW_SCALES[platform]?.includes(scale) ?? true).reduce((acc, { scale, file }) => {
2756
+ acc.files.push(file);
2757
+ acc.scales.push(scale);
2758
+ return acc;
2759
+ }, {
2760
+ scales: [],
2761
+ files: []
2762
+ });
2763
+ return {
2764
+ __packager_asset: true,
2765
+ id: assetPath,
2766
+ name: stripedBasename.replace(extension, ""),
2767
+ type: extension.substring(1),
2768
+ width: dimensions.width,
2769
+ height: dimensions.height,
2770
+ files: filteredScaledAssets.files,
2771
+ scales: filteredScaledAssets.scales,
2772
+ fileSystemLocation: node_path.default.dirname(assetPath),
2773
+ httpServerLocation: node_path.default.join(DEV_SERVER_ASSET_PATH, node_path.default.dirname(relativePath)),
2774
+ hash: md5(imageData)
2775
+ };
2776
+ }
2777
+ function platformSuffixPattern(context) {
2778
+ return [context.platform, context.preferNativePlatform ? "native" : null].filter(es_toolkit.isNotNil).map((platform) => `.${platform}`).join("|");
2779
+ }
2780
+ function stripSuffix(assetPath, context) {
2781
+ const basename = node_path.default.basename(assetPath);
2782
+ const extension = node_path.default.extname(assetPath);
2783
+ const suffixPattern = platformSuffixPattern(context);
2784
+ return basename.replace(new RegExp(`(${SCALE_PATTERN})?(?:${suffixPattern})?${extension}$`), "");
2785
+ }
2786
+ function getAssetPriority(assetPath, context) {
2787
+ const suffixPattern = platformSuffixPattern(context);
2788
+ if (new RegExp(`${SCALE_PATTERN}(?:${suffixPattern})`).test(assetPath)) return 3;
2789
+ else if (new RegExp(`(?:${suffixPattern})`).test(assetPath)) return 2;
2790
+ else if (new RegExp(`${SCALE_PATTERN}`).test(assetPath)) return 1;
2791
+ return 0;
2792
+ }
2793
+ function addSuffix(assetPath, context, options) {
2794
+ const extension = node_path.default.extname(assetPath);
2795
+ return stripSuffix(assetPath, context).concat(options?.scale ? `@${options.scale}x` : "").concat(options?.platform ? `.${options.platform}${extension}` : extension);
2796
+ }
2797
+ /**
2798
+ * add suffix to asset path
2799
+ *
2800
+ * ```js
2801
+ * // assetPath input
2802
+ * '/path/to/assets/image.png'
2803
+ *
2804
+ * // `platform` suffixed
2805
+ * '/path/to/assets/image.android.png'
2806
+ *
2807
+ * // `scale` suffixed
2808
+ * '/path/to/assets/image@1x.png'
2809
+ *
2810
+ * // both `platform` and `scale` suffixed
2811
+ * '/path/to/assets/image@1x.android.png'
2812
+ * ```
2813
+ */
2814
+ function getSuffixedPath(assetPath, context, options) {
2815
+ const suffixedBasename = addSuffix(assetPath, context, {
2816
+ scale: options?.scale,
2817
+ platform: options?.platform
2818
+ });
2819
+ const dirname = node_path.default.dirname(assetPath);
2820
+ return node_path.default.join(dirname, suffixedBasename);
2821
+ }
2822
+ function resolveAssetPath(assetPath, context, scale) {
2823
+ const suffixedPaths = [
2824
+ getSuffixedPath(assetPath, context, {
2825
+ scale,
2826
+ platform: context.platform
2827
+ }),
2828
+ context.preferNativePlatform ? getSuffixedPath(assetPath, context, {
2829
+ scale,
2830
+ platform: "native"
2831
+ }) : null,
2832
+ getSuffixedPath(assetPath, context, { scale })
2833
+ ].filter(es_toolkit.isNotNil);
2834
+ /**
2835
+ * When scale is 1, filename can be suffixed or non-suffixed(`image.png`).
2836
+ *
2837
+ * - Suffixed
2838
+ * - `filename.<platform>@<scale>x.ext`
2839
+ * - `filename.<platform>.ext`
2840
+ * - `filename@<scale>x.ext`
2841
+ * - Non suffixed
2842
+ * - `filename.ext`
2843
+ *
2844
+ * 1. Resolve non-suffixed asset first.
2845
+ * 2. If file is not exist, resolve suffixed path.
2846
+ */
2847
+ if (scale === 1) try {
2848
+ node_fs.default.statSync(assetPath);
2849
+ return assetPath;
2850
+ } catch {}
2851
+ for (const suffixedPath of suffixedPaths) try {
2852
+ node_fs.default.statSync(suffixedPath);
2853
+ return suffixedPath;
2854
+ } catch {}
2855
+ throw new Error(`cannot resolve asset path for ${assetPath}`);
2856
+ }
2857
+ /**
2858
+ * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/assetPathUtils.js
2859
+ */
2860
+ async function copyAssetsToDestination(options) {
2861
+ const { assets, platform, assetsDir, preferNativePlatform } = options;
2862
+ const context = {
2863
+ platform,
2864
+ preferNativePlatform
2865
+ };
2866
+ const mkdirWithAssertPath = (targetPath) => {
2867
+ const dirname = node_path.default.dirname(targetPath);
2868
+ node_fs.default.mkdirSync(dirname, { recursive: true });
2869
+ };
2870
+ return Promise.all(assets.map((asset) => {
2871
+ return Promise.all(asset.scales.map(async (scale) => {
2872
+ if (platform !== "android") {
2873
+ const from = resolveAssetPath(asset.id, context, scale);
2874
+ const to = node_path.default.join(assetsDir, getIosAssetDestinationPath(asset, scale));
2875
+ mkdirWithAssertPath(to);
2876
+ return node_fs.default.copyFileSync(from, to);
2877
+ }
2878
+ const from = resolveAssetPath(asset.id, context, scale);
2879
+ const to = node_path.default.join(assetsDir, getAndroidAssetDestinationPath(asset, scale));
2880
+ mkdirWithAssertPath(to);
2881
+ node_fs.default.copyFileSync(from, to);
2882
+ })).then(() => void 0);
2883
+ })).then(() => void 0);
2884
+ }
2885
+ /**
2886
+ * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/getAssetDestPathIOS.js
2887
+ */
2888
+ function getIosAssetDestinationPath(asset, scale) {
2889
+ const suffix = scale === 1 ? "" : `@${scale}x`;
2890
+ const fileName = `${asset.name + suffix}.${asset.type}`;
2891
+ const devServerBasePath = asset.httpServerLocation.at(0) === "/" ? asset.httpServerLocation.slice(1) : asset.httpServerLocation;
2892
+ return node_path.default.join(devServerBasePath.replace(/\.\.\//g, "_"), fileName);
2893
+ }
2894
+ function getAndroidAssetDestinationPath(asset, scale) {
2895
+ const assetQualifierSuffix = ANDROID_ASSET_QUALIFIER[scale];
2896
+ const assetName = `${asset.httpServerLocation.at(0) === "/" ? asset.httpServerLocation.slice(1) : asset.httpServerLocation}/${asset.name}`.toLowerCase().replace(/\//g, "_").replace(/(?:[^a-z0-9_])/g, "").replace(/^assets_/, "");
2897
+ if (!assetQualifierSuffix) throw new Error(`invalid asset qualifier: ${asset.id}`);
2898
+ return node_path.default.join(isDrawable(asset.type) ? `drawable-${assetQualifierSuffix}` : "raw", `${assetName}.${asset.type}`);
2899
+ }
2900
+ /**
2901
+ * @see https://developer.android.com/guide/topics/resources/drawable-resource
2902
+ */
2903
+ function isDrawable(type) {
2904
+ return [
2905
+ "gif",
2906
+ "heic",
2907
+ "heif",
2908
+ "jpeg",
2909
+ "jpg",
2910
+ "ktx",
2911
+ "png",
2912
+ "webp",
2913
+ "xml"
2914
+ ].includes(type);
2915
+ }
2916
+ function generateAssetRegistryCode(assetRegistryPath, asset) {
2917
+ return `module.exports = require('${assetRegistryPath}').registerAsset(${JSON.stringify(asset)});`;
2918
+ }
2919
+ //#endregion
2920
+ //#region src/core/plugins/utils/transform-utils.ts
2921
+ const TRANSFORM_FLAGS_KEY = Symbol("transform-flags");
2922
+ let TransformFlag = /* @__PURE__ */ function(TransformFlag) {
2923
+ TransformFlag[TransformFlag["NONE"] = 0] = "NONE";
2924
+ TransformFlag[TransformFlag["CODEGEN_REQUIRED"] = 1] = "CODEGEN_REQUIRED";
2925
+ TransformFlag[TransformFlag["STRIP_FLOW_REQUIRED"] = 2] = "STRIP_FLOW_REQUIRED";
2926
+ TransformFlag[TransformFlag["SKIP_ALL"] = 128] = "SKIP_ALL";
2927
+ return TransformFlag;
2928
+ }({});
2929
+ function setFlag(context, id, flag, options) {
2930
+ const moduleInfo = context.getModuleInfo(id);
2931
+ if (moduleInfo && hasFlag(moduleInfo.meta)) {
2932
+ if (options?.override) moduleInfo.meta[TRANSFORM_FLAGS_KEY] = flag;
2933
+ else moduleInfo.meta[TRANSFORM_FLAGS_KEY] |= flag;
2934
+ return moduleInfo.meta;
2935
+ } else return { [TRANSFORM_FLAGS_KEY]: flag };
2936
+ }
2937
+ function hasFlag(meta) {
2938
+ return TRANSFORM_FLAGS_KEY in meta;
2939
+ }
2940
+ function getFlag(context, id) {
2941
+ return getFlagFromModuleInfo(context.getModuleInfo(id));
2942
+ }
2943
+ function getFlagFromModuleInfo(moduleInfo) {
2944
+ if (moduleInfo && hasFlag(moduleInfo.meta)) return moduleInfo.meta[TRANSFORM_FLAGS_KEY];
2945
+ return TransformFlag.NONE;
2946
+ }
2947
+ function withTransformBoundary(context, plugins) {
2948
+ return [
2949
+ {
2950
+ name: "rollipop:transform-initializer",
2951
+ transform: {
2952
+ order: "pre",
2953
+ handler(_code, id) {
2954
+ if (context.state.hmrUpdates.has(id)) {
2955
+ context.state.hmrUpdates.delete(id);
2956
+ return { meta: setFlag(this, id, TransformFlag.NONE, { override: true }) };
2957
+ }
2958
+ }
2959
+ }
2960
+ },
2961
+ {
2962
+ name: "rollipop:transform-change-watcher",
2963
+ watchChange(id) {
2964
+ context.state.hmrUpdates.add(id);
2965
+ }
2966
+ },
2967
+ plugins
2968
+ ];
2969
+ }
2970
+ //#endregion
2971
+ //#region src/core/plugins/react-native-plugin.ts
2972
+ function reactNativePlugin(options) {
2973
+ const { projectRoot, platform, preferNativePlatform, buildType, assetsDir, assetExtensions, assetRegistryPath, flowFilter, codegenFilter, builtinPluginConfig } = options;
2974
+ const codegenPlugin = {
2975
+ name: "rollipop:react-native-codegen-marker",
2976
+ transform: {
2977
+ order: "pre",
2978
+ filter: codegenFilter,
2979
+ handler(_code, id) {
2980
+ return { meta: setFlag(this, id, TransformFlag.CODEGEN_REQUIRED) };
2981
+ }
2982
+ }
2983
+ };
2984
+ const stripFlowSyntaxPlugin = {
2985
+ name: "rollipop:react-native-strip-flow-syntax",
2986
+ transform: {
2987
+ order: "pre",
2988
+ filter: flowFilter,
2989
+ async handler(code, id) {
2990
+ const flags = getFlag(this, id);
2991
+ if (flags & TransformFlag.SKIP_ALL) return;
2992
+ if (flags & TransformFlag.CODEGEN_REQUIRED) return { meta: setFlag(this, id, TransformFlag.STRIP_FLOW_REQUIRED) };
2993
+ const result = await stripFlowTypes(id, code);
2994
+ return {
2995
+ code: result.code,
2996
+ map: result.map,
2997
+ moduleType: "tsx"
2998
+ };
2999
+ }
3000
+ }
3001
+ };
3002
+ const assets = [];
3003
+ const assetPlugin = {
3004
+ name: "rollipop:react-native-asset",
3005
+ load: {
3006
+ filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)(new RegExp(`\\.(?:${assetExtensions.join("|")})$`)))],
3007
+ async handler(id) {
3008
+ this.debug(`Asset ${id} found`);
3009
+ const assetData = await resolveScaledAssets({
3010
+ projectRoot,
3011
+ assetPath: id,
3012
+ platform,
3013
+ preferNativePlatform
3014
+ });
3015
+ assets.push(assetData);
3016
+ return {
3017
+ code: generateAssetRegistryCode(assetRegistryPath, assetData),
3018
+ meta: setFlag(this, id, TransformFlag.SKIP_ALL),
3019
+ moduleType: "js"
3020
+ };
3021
+ }
3022
+ },
3023
+ buildStart() {
3024
+ assets.length = 0;
3025
+ },
3026
+ async buildEnd(error) {
3027
+ if (error || buildType === "serve") return;
3028
+ if (assetsDir != null) {
3029
+ this.debug(`Copying assets to ${assetsDir}`);
3030
+ await copyAssetsToDestination({
3031
+ assets,
3032
+ assetsDir,
3033
+ platform,
3034
+ preferNativePlatform
3035
+ });
3036
+ }
3037
+ }
3038
+ };
3039
+ return [...builtinPluginConfig ? [(0, _rollipop_rolldown_experimental.rollipopReactNativePlugin)(builtinPluginConfig)] : [codegenPlugin, stripFlowSyntaxPlugin], assetPlugin];
3040
+ }
3041
+ //#endregion
3042
+ //#region src/core/plugins/prelude-plugin.ts
3043
+ const IS_ENTRY = Symbol("IS_ENTRY");
3044
+ function preludePlugin(options) {
3045
+ if (options.modulePaths.length === 0) return null;
3046
+ const preludeImportStatements = options.modulePaths.map((modulePath) => `import '${modulePath}';`).join("\n");
3047
+ let processed = false;
3048
+ return {
3049
+ name: "rollipop:prelude",
3050
+ buildStart() {
3051
+ processed = false;
3052
+ },
3053
+ resolveId: { handler: (source, _importer, extraOptions) => {
3054
+ if (extraOptions.isEntry) return {
3055
+ id: source,
3056
+ meta: { [IS_ENTRY]: true }
3057
+ };
3058
+ } },
3059
+ load: { handler(id) {
3060
+ if (processed) return;
3061
+ const moduleInfo = this.getModuleInfo(id);
3062
+ if (moduleInfo && isEntry(moduleInfo.meta)) {
3063
+ this.debug(`Prelude plugin found entry ${id}`);
3064
+ const modifiedSource = [preludeImportStatements, node_fs.default.readFileSync(id, "utf-8")].join("\n");
3065
+ processed = true;
3066
+ return modifiedSource;
3067
+ }
3068
+ } }
3069
+ };
3070
+ }
3071
+ function isEntry(meta) {
3072
+ return IS_ENTRY in meta;
3073
+ }
3074
+ //#endregion
3075
+ //#region src/core/plugins/json-plugin.ts
3076
+ function jsonPlugin() {
3077
+ return {
3078
+ name: "rollipop:json",
3079
+ load: {
3080
+ filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)(/\.json$/))],
3081
+ handler(id) {
3082
+ return {
3083
+ code: `export = ${node_fs.default.readFileSync(id, "utf-8")};`,
3084
+ meta: setFlag(this, id, TransformFlag.SKIP_ALL),
3085
+ moduleType: "ts"
3086
+ };
3087
+ }
3088
+ }
3089
+ };
3090
+ }
3091
+ //#endregion
3092
+ //#region src/utils/babel.ts
3093
+ function mergeBabelOptions(options) {
3094
+ return options.reduce((acc, options) => (0, es_toolkit.mergeWith)(acc, options, merge$3), {});
3095
+ }
3096
+ function merge$3(target, source, key) {
3097
+ if (key === "plugins") return [...target ?? [], ...source ?? []];
3098
+ if (key === "presets") return [...target ?? [], ...source ?? []];
3099
+ }
3100
+ //#endregion
3101
+ //#region src/core/plugins/utils/source.ts
3102
+ const TS_EXTENSION_REGEXP = /\.tsx?$/;
3103
+ function isTS(id) {
3104
+ return TS_EXTENSION_REGEXP.test(id);
3105
+ }
3106
+ function isJSX(id) {
3107
+ return id.endsWith("x");
3108
+ }
3109
+ //#endregion
3110
+ //#region src/core/plugins/babel-plugin.ts
3111
+ function babelPlugin({ useNativeTransformPipeline, transformConfig }) {
3112
+ const { rules = [] } = transformConfig ?? {};
3113
+ const babelOptionsById = /* @__PURE__ */ new Map();
3114
+ const babelRules = rules.map(({ filter, options }, index) => {
3115
+ return {
3116
+ name: `rollipop:babel-rule-${index}`,
3117
+ transform: {
3118
+ filter,
3119
+ handler(code, id) {
3120
+ const existingBabelOptions = babelOptionsById.get(id);
3121
+ const resolvedOptions = typeof options === "function" ? options(code, id) : options;
3122
+ existingBabelOptions ? existingBabelOptions.push(resolvedOptions) : babelOptionsById.set(id, [resolvedOptions]);
3123
+ }
3124
+ }
3125
+ };
3126
+ });
3127
+ const babelPlugin = {
3128
+ name: "rollipop:babel",
3129
+ buildStart() {
3130
+ babelOptionsById.clear();
3131
+ },
3132
+ transform: { handler(code, id) {
3133
+ const flags = getFlag(this, id);
3134
+ if (flags & TransformFlag.SKIP_ALL) return;
3135
+ const babelOptions = babelOptionsById.get(id) ?? [];
3136
+ if (!(useNativeTransformPipeline ? babelOptions.length > 0 : flags & TransformFlag.CODEGEN_REQUIRED || babelOptions.length > 0)) return;
3137
+ const baseOptions = useNativeTransformPipeline ? [] : [getPreset(flags, id)];
3138
+ const result = _babel_core.transformSync(code, {
3139
+ filename: id,
3140
+ babelrc: false,
3141
+ configFile: false,
3142
+ sourceMaps: true,
3143
+ ...mergeBabelOptions([...baseOptions, ...babelOptions])
3144
+ });
3145
+ (0, es_toolkit.invariant)(result?.code, `Failed to transform with babel: ${id}`);
3146
+ return {
3147
+ code: result.code,
3148
+ map: result.map
3149
+ };
3150
+ } }
3151
+ };
3152
+ return [...babelRules, babelPlugin];
3153
+ }
3154
+ function getPreset(flags, id) {
3155
+ const presets = [];
3156
+ const plugins = [];
3157
+ let parserOpts = null;
3158
+ if (flags & TransformFlag.STRIP_FLOW_REQUIRED) {
3159
+ parserOpts = { flow: "all" };
3160
+ plugins.push([require.resolve("babel-plugin-syntax-hermes-parser"), {
3161
+ parseLangTypes: "flow",
3162
+ reactRuntimeTarget: "19"
3163
+ }], require.resolve("@babel/plugin-transform-flow-strip-types"));
3164
+ } else if (isTS(id)) plugins.push([require.resolve("@babel/plugin-transform-typescript"), {
3165
+ isTSX: isJSX(id),
3166
+ allowNamespaces: true
3167
+ }]);
3168
+ if (flags & TransformFlag.CODEGEN_REQUIRED) plugins.push([require.resolve("@react-native/babel-plugin-codegen")]);
3169
+ const options = {
3170
+ presets,
3171
+ plugins
3172
+ };
3173
+ if (parserOpts) options.parserOpts = parserOpts;
3174
+ return options;
3175
+ }
3176
+ //#endregion
3177
+ //#region src/utils/swc.ts
3178
+ function mergeSwcOptions(options) {
3179
+ return options.reduce((acc, options) => (0, es_toolkit.mergeWith)(acc, options, merge$2), {});
3180
+ }
3181
+ function merge$2(target, source, key) {
3182
+ if (key === "plugins") return [...target ?? [], ...source ?? []];
3183
+ }
3184
+ //#endregion
3185
+ //#region src/core/plugins/shared/filters.ts
3186
+ const ROLLDOWN_RUNTIME_EXCLUDE_FILTER = (0, _rollipop_rolldown_pluginutils.exclude)((0, _rollipop_rolldown_pluginutils.or)((0, _rollipop_rolldown_pluginutils.id)(/rolldown\/runtime/), (0, _rollipop_rolldown_pluginutils.id)(/@oxc-project\+runtime/)));
3187
+ //#endregion
3188
+ //#region src/core/plugins/swc-plugin.ts
3189
+ function swcPlugin({ useNativeTransformPipeline, runtimeTarget, transformConfig }) {
3190
+ const { rules = [] } = transformConfig ?? {};
3191
+ const swcOptionsById = /* @__PURE__ */ new Map();
3192
+ const swcHelpersResolvePlugin = {
3193
+ name: "rollipop:swc-helpers-resolve",
3194
+ resolveId: {
3195
+ order: "pre",
3196
+ filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)(/^@swc\/helpers/)), ROLLDOWN_RUNTIME_EXCLUDE_FILTER],
3197
+ handler(source, _importer, extraOptions) {
3198
+ return this.resolve(source, __dirname, extraOptions);
3199
+ }
3200
+ }
3201
+ };
3202
+ const swcRules = rules.map(({ filter, options }, index) => {
3203
+ return {
3204
+ name: `rollipop:swc-rule-${index}`,
3205
+ transform: {
3206
+ filter,
3207
+ handler(code, id) {
3208
+ const existingBabelOptions = swcOptionsById.get(id);
3209
+ const resolvedOptions = typeof options === "function" ? options(code, id) : options;
3210
+ existingBabelOptions ? existingBabelOptions.push(resolvedOptions) : swcOptionsById.set(id, [resolvedOptions]);
3211
+ }
3212
+ }
3213
+ };
3214
+ });
3215
+ const getSwcPreset = useNativeTransformPipeline ? null : presets[runtimeTarget];
3216
+ const swcPlugin = {
3217
+ name: "rollipop:swc",
3218
+ buildStart() {
3219
+ swcOptionsById.clear();
3220
+ },
3221
+ transform: {
3222
+ filter: [ROLLDOWN_RUNTIME_EXCLUDE_FILTER],
3223
+ handler(code, id) {
3224
+ if (getFlag(this, id) & TransformFlag.SKIP_ALL) return;
3225
+ const swcOptions = swcOptionsById.get(id) ?? [];
3226
+ if (getSwcPreset == null && swcOptions.length === 0) return;
3227
+ const baseOptions = getSwcPreset != null ? [getSwcPreset(id)] : [];
3228
+ const result = _swc_core.transformSync(code, {
3229
+ filename: id,
3230
+ configFile: false,
3231
+ swcrc: false,
3232
+ sourceMaps: true,
3233
+ inputSourceMap: false,
3234
+ ...mergeSwcOptions([...baseOptions, ...swcOptions])
3235
+ });
3236
+ return {
3237
+ code: result.code,
3238
+ map: result.map
3239
+ };
3240
+ }
3241
+ }
3242
+ };
3243
+ return [
3244
+ swcHelpersResolvePlugin,
3245
+ ...swcRules,
3246
+ swcPlugin
3247
+ ];
3248
+ }
3249
+ const presets = {
3250
+ "hermes-v1": (id) => ({
3251
+ env: {
3252
+ targets: { node: 9999 },
3253
+ include: [
3254
+ "transform-block-scoping",
3255
+ "transform-class-properties",
3256
+ "transform-private-methods",
3257
+ "transform-private-property-in-object"
3258
+ ]
3259
+ },
3260
+ jsc: {
3261
+ parser: {
3262
+ syntax: "typescript",
3263
+ tsx: true
3264
+ },
3265
+ transform: { react: { runtime: "preserve" } },
3266
+ externalHelpers: true
3267
+ },
3268
+ isModule: id.endsWith(".cjs") ? "commonjs" : true
3269
+ }),
3270
+ hermes: (id) => ({
3271
+ jsc: {
3272
+ parser: {
3273
+ syntax: "typescript",
3274
+ tsx: true
3275
+ },
3276
+ transform: { react: { runtime: "preserve" } },
3277
+ externalHelpers: true,
3278
+ keepClassNames: true,
3279
+ loose: false,
3280
+ assumptions: {
3281
+ setPublicClassFields: true,
3282
+ privateFieldsAsProperties: true
3283
+ },
3284
+ target: "es5"
3285
+ },
3286
+ isModule: id.endsWith(".cjs") ? "commonjs" : true
3287
+ })
3288
+ };
3289
+ //#endregion
3290
+ //#region src/core/plugins/reporter-plugin.ts
3291
+ function reporterPlugin(options) {
3292
+ const { reporter, initialTotalModules = 0 } = options ?? {};
3293
+ let totalModules = initialTotalModules;
3294
+ let startedAt = 0;
3295
+ let transformedModules = 0;
3296
+ let unknownTotalModules = totalModules === 0;
3297
+ return {
3298
+ name: "rollipop:status",
3299
+ buildStart() {
3300
+ startedAt = performance.now();
3301
+ transformedModules = 0;
3302
+ reporter?.update({ type: "bundle_build_started" });
3303
+ },
3304
+ buildEnd(error) {
3305
+ const endedAt = performance.now();
3306
+ if (transformedModules !== 0) totalModules = transformedModules;
3307
+ unknownTotalModules = false;
3308
+ reporter?.update(error == null ? {
3309
+ type: "bundle_build_done",
3310
+ totalModules,
3311
+ duration: endedAt - startedAt
3312
+ } : {
3313
+ type: "bundle_build_failed",
3314
+ error
3315
+ });
3316
+ },
3317
+ transform: {
3318
+ order: "post",
3319
+ handler(_code, id) {
3320
+ ++transformedModules;
3321
+ if (!unknownTotalModules && totalModules < transformedModules) totalModules = transformedModules;
3322
+ reporter?.update({
3323
+ type: "transform",
3324
+ id,
3325
+ totalModules: unknownTotalModules ? void 0 : totalModules,
3326
+ transformedModules
3327
+ });
3328
+ }
3329
+ },
3330
+ watchChange(id) {
3331
+ reporter?.update({
3332
+ type: "watch_change",
3333
+ id
3334
+ });
3335
+ }
3336
+ };
3337
+ }
3338
+ //#endregion
3339
+ //#region src/core/plugins/dev-server-plugin.ts
3340
+ async function devServerPlugin(options) {
3341
+ const { cwd, hmrClientPath, hmrConfig } = options;
3342
+ if (hmrConfig == null) return null;
3343
+ return [{
3344
+ name: "rollipop:replace-hmr-client",
3345
+ load: {
3346
+ filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)((0, _rollipop_rolldown_pluginutils.exactRegex)(resolveFrom(cwd, typeof hmrClientPath === "function" ? await hmrClientPath(cwd) : hmrClientPath))))],
3347
+ handler(id) {
3348
+ this.debug(`Replacing HMR client: ${id}`);
3349
+ return {
3350
+ code: hmrConfig.clientImplement,
3351
+ moduleType: "ts"
3352
+ };
3353
+ }
3354
+ }
3355
+ }, (0, _rollipop_rolldown_experimental.rollipopReactRefreshWrapperPlugin)({
3356
+ cwd,
3357
+ include: [/\.[tj]sx?(?:$|\?)/],
3358
+ exclude: [/\/node_modules\//]
3359
+ })];
3360
+ }
3361
+ //#endregion
3362
+ //#region src/core/rolldown.ts
3363
+ resolveRolldownOptions.cache = /* @__PURE__ */ new Map();
3364
+ async function resolveRolldownOptions(context, config, buildOptions, devEngineOptions) {
3365
+ const cachedOptions = resolveRolldownOptions.cache.get(context.id);
3366
+ if (cachedOptions != null) return cachedOptions;
3367
+ const { platform, dev, cache } = buildOptions;
3368
+ const isDevServerMode = dev && context.buildType === "serve";
3369
+ (0, es_toolkit.invariant)(isDevServerMode ? devEngineOptions != null : true, "devEngineOptions is required in dev server mode");
3370
+ const env = loadEnv(config);
3371
+ const builtInEnv = {
3372
+ MODE: config.mode,
3373
+ ...isDevServerMode ? { BASE_URL: getBaseUrl(devEngineOptions.host, devEngineOptions.port, devEngineOptions.https) } : null
3374
+ };
3375
+ const hmrConfig = resolveHmrConfig(config);
3376
+ const hmrEnabled = hmrConfig != null;
3377
+ const { sourceExtensions, assetExtensions, preferNativePlatform, external: rolldownExternal, ...rolldownResolve } = config.resolver;
3378
+ const { polyfills, banner: rolldownBanner, footer: rolldownFooter, postBanner: rolldownPostBanner, postFooter: rolldownPostFooter, intro: rolldownIntro, outro: rolldownOutro, shimMissingExports: rolldownShimMissingExports } = config.serializer;
3379
+ const { flow: _flow, babel: _babel, swc: _swc, ...rolldownTransform } = config.transformer;
3380
+ const { treeshake: rolldownTreeshake, minify: rolldownMinify, lazyBarrel: rolldownLazyBarrel, ...rolldownOptimization } = config.optimization;
3381
+ const { globalIdentifiers: rolldownGlobalIdentifiers } = config.reactNative;
3382
+ const { sourcemap: rolldownSourcemap, sourcemapBaseUrl: rolldownSourcemapBaseUrl, sourcemapDebugIds: rolldownSourcemapDebugIds, sourcemapIgnoreList: rolldownSourcemapIgnoreList, sourcemapPathTransform: rolldownSourcemapPathTransform } = config;
3383
+ const userPlugins = config.plugins;
3384
+ const mergedResolveOptions = (0, es_toolkit.merge)({ extensions: getResolveExtensions({
3385
+ sourceExtensions,
3386
+ assetExtensions,
3387
+ platform,
3388
+ preferNativePlatform
3389
+ }) }, rolldownResolve);
3390
+ const mergedTransformOptions = (0, es_toolkit.merge)({
3391
+ cwd: config.root,
3392
+ target: "esnext",
3393
+ jsx: {
3394
+ runtime: "automatic",
3395
+ development: dev
3396
+ },
3397
+ define: {
3398
+ __DEV__: asLiteral(dev),
3399
+ "process.env.NODE_ENV": asLiteral(nodeEnvironment(dev)),
3400
+ "process.env.DEBUG_ROLLIPOP": asLiteral(isDebugEnabled()),
3401
+ ...hmrEnabled ? null : { "import.meta.hot": "{}" },
3402
+ ...defineEnvFromObject(env),
3403
+ ...defineEnvFromObject(builtInEnv)
3404
+ },
3405
+ helpers: { mode: "Runtime" }
3406
+ }, rolldownTransform);
3407
+ const preludePluginOptions = resolvePreludePluginOptions(config);
3408
+ const reactNativePluginOptions = await resolveReactNativePluginOptions(config, context, buildOptions);
3409
+ const babelPluginOptions = resolveBabelPluginOptions(config);
3410
+ const swcPluginOptions = resolveSwcPluginOptions(config);
3411
+ const devServerPluginOptions = resolveDevServerPluginOptions(config, hmrConfig);
3412
+ const reporterPluginOptions = resolveReporterPluginOptions(config, context, buildOptions);
3413
+ const finalOptions = await applyDangerouslyOverrideOptionsFinalizer(config, {
3414
+ platform: "neutral",
3415
+ cwd: config.root,
3416
+ input: config.entry,
3417
+ tsconfig: config.tsconfig,
3418
+ resolve: mergedResolveOptions,
3419
+ transform: mergedTransformOptions,
3420
+ treeshake: rolldownTreeshake,
3421
+ external: rolldownExternal,
3422
+ shimMissingExports: rolldownShimMissingExports,
3423
+ optimization: rolldownOptimization,
3424
+ experimental: {
3425
+ lazyBarrel: rolldownLazyBarrel,
3426
+ ...isDevServerMode ? { devMode: hmrConfig ? { implement: hmrConfig.runtimeImplement } : false } : null
3427
+ },
3428
+ plugins: withTransformBoundary(context, [
3429
+ preludePlugin(preludePluginOptions),
3430
+ reactNativePlugin(reactNativePluginOptions),
3431
+ jsonPlugin(),
3432
+ babelPlugin(babelPluginOptions),
3433
+ swcPlugin(swcPluginOptions),
3434
+ devServerPlugin(devServerPluginOptions),
3435
+ reporterPlugin(reporterPluginOptions),
3436
+ userPlugins
3437
+ ]),
3438
+ checks: {
3439
+ eval: false,
3440
+ pluginTimings: isDebugEnabled()
3441
+ },
3442
+ logLevel: isDebugEnabled() ? "debug" : "info",
3443
+ onLog(level, log, defaultHandler) {
3444
+ if (log.code?.startsWith("PLUGIN_")) printPluginLog(level, log, log.plugin);
3445
+ else defaultHandler(level, log);
3446
+ },
3447
+ id: context.id
3448
+ }, {
3449
+ format: "esm",
3450
+ file: buildOptions.outfile,
3451
+ banner: rolldownBanner,
3452
+ footer: rolldownFooter,
3453
+ postFooter: rolldownPostFooter,
3454
+ postBanner: rolldownPostBanner,
3455
+ outro: rolldownOutro,
3456
+ intro: async (chunk) => {
3457
+ return [
3458
+ ...getGlobalVariables(dev, context.buildType),
3459
+ ...loadPolyfills(polyfills),
3460
+ typeof rolldownIntro === "function" ? await rolldownIntro(chunk) : rolldownIntro
3461
+ ].filter(es_toolkit.isNotNil).join("\n");
3462
+ },
3463
+ minify: buildOptions.minify ?? rolldownMinify,
3464
+ sourcemap: buildOptions.sourcemap ?? rolldownSourcemap,
3465
+ sourcemapBaseUrl: rolldownSourcemapBaseUrl,
3466
+ sourcemapDebugIds: rolldownSourcemapDebugIds,
3467
+ sourcemapIgnoreList: rolldownSourcemapIgnoreList,
3468
+ sourcemapPathTransform: rolldownSourcemapPathTransform ?? createProjectRootSourcemapPathTransform(config.root),
3469
+ codeSplitting: false,
3470
+ strictExecutionOrder: true,
3471
+ globalIdentifiers: rolldownGlobalIdentifiers,
3472
+ persistentCache: cache
3473
+ });
3474
+ resolveRolldownOptions.cache.set(context.id, finalOptions);
3475
+ return finalOptions;
3476
+ }
3477
+ function resolvePreludePluginOptions(config) {
3478
+ return { modulePaths: config.serializer.prelude };
3479
+ }
3480
+ async function resolveReactNativePluginOptions(config, context, buildOptions) {
3481
+ return {
3482
+ projectRoot: config.root,
3483
+ platform: buildOptions.platform,
3484
+ preferNativePlatform: config.resolver.preferNativePlatform,
3485
+ buildType: context.buildType,
3486
+ assetsDir: buildOptions.assetsDir,
3487
+ assetExtensions: config.resolver.assetExtensions,
3488
+ assetRegistryPath: await resolveAssetRegistryPath(config),
3489
+ flowFilter: config.transformer.flow?.filter ?? [],
3490
+ codegenFilter: config.reactNative.codegen?.filter ?? [],
3491
+ builtinPluginConfig: resolveReactNativeBuiltinPluginConfig(config)
3492
+ };
3493
+ }
3494
+ async function resolveAssetRegistryPath(config) {
3495
+ const { assetRegistryPath } = config.reactNative;
3496
+ const path = typeof assetRegistryPath === "function" ? await assetRegistryPath(config.root) : assetRegistryPath;
3497
+ return resolveFrom(config.root, path);
3498
+ }
3499
+ function resolveReactNativeBuiltinPluginConfig(config) {
3500
+ if (!config.experimental?.nativeTransformPipeline) return null;
3501
+ return {
3502
+ envName: config.mode,
3503
+ runtimeTarget: resolveRuntimeTarget(config.runtimeTarget),
3504
+ worklets: resolveWorkletsConfig(config),
3505
+ plugins: []
3506
+ };
3507
+ }
3508
+ function resolveWorkletsConfig(config) {
3509
+ const { worklets } = config.experimental ?? {};
3510
+ if (worklets == null) return;
3511
+ return (0, es_toolkit.merge)({
3512
+ isRelease: config.mode === "production",
3513
+ pluginVersion: resolvePackageJson(config.root, "react-native-worklets")?.version
3514
+ }, worklets);
3515
+ }
3516
+ function resolveBabelPluginOptions(config) {
3517
+ return {
3518
+ useNativeTransformPipeline: config.experimental?.nativeTransformPipeline,
3519
+ transformConfig: config.transformer.babel
3520
+ };
3521
+ }
3522
+ function resolveSwcPluginOptions(config) {
3523
+ return {
3524
+ useNativeTransformPipeline: config.experimental?.nativeTransformPipeline,
3525
+ runtimeTarget: config.runtimeTarget,
3526
+ transformConfig: config.transformer.swc
3527
+ };
3528
+ }
3529
+ function resolveDevServerPluginOptions(config, hmrConfig) {
3530
+ return {
3531
+ cwd: config.root,
3532
+ hmrClientPath: config.reactNative.hmrClientPath,
3533
+ hmrConfig
3534
+ };
3535
+ }
3536
+ function resolveReporterPluginOptions(config, context, buildOptions) {
3537
+ const statusReporter = createStatusReporter(config, context, buildOptions);
3538
+ return {
3539
+ initialTotalModules: getBuildTotalModules(context.storage, context.id),
3540
+ reporter: mergeReporters([statusReporter, config.reporter].filter(es_toolkit.isNotNil))
3541
+ };
3542
+ }
3543
+ function createStatusReporter(config, context, buildOptions) {
3544
+ switch (config.terminal.status) {
3545
+ case "compat": return new CompatStatusReporter();
3546
+ case "progress": return new ProgressBarStatusReporter(context.id, `[${buildOptions.platform}, ${buildOptions.dev ? "dev" : "prod"}]`, getBuildTotalModules(context.storage, context.id));
3547
+ }
3548
+ }
3549
+ function getResolveExtensions({ platform, sourceExtensions, assetExtensions, preferNativePlatform }) {
3550
+ const supportedExtensions = [...sourceExtensions, ...assetExtensions];
3551
+ return [...[platform, preferNativePlatform ? "native" : null].filter(es_toolkit.isNotNil).map((platform) => {
3552
+ return supportedExtensions.map((extension) => `.${platform}.${extension}`);
3553
+ }), ...supportedExtensions.map((extension) => `.${extension}`)].flat();
3554
+ }
3555
+ /**
3556
+ * Default sourcemap path transform.
3557
+ *
3558
+ * Rolldown emits `sources` relative to the bundle output's directory, which
3559
+ * yields paths like `../App.tsx` when the bundle lives under e.g. `dist/`.
3560
+ * RN tooling (symbolication, devtools) expects project-root-relative paths,
3561
+ * so this rewrites each entry to be relative to `projectRoot`.
3562
+ */
3563
+ function createProjectRootSourcemapPathTransform(projectRoot) {
3564
+ return (source, sourcemapPath) => {
3565
+ const absolute = node_path.default.resolve(node_path.default.dirname(sourcemapPath), source);
3566
+ return node_path.default.relative(projectRoot, absolute);
3567
+ };
3568
+ }
3569
+ function loadPolyfills(polyfills) {
3570
+ return polyfills.map((polyfill) => {
3571
+ if (typeof polyfill === "string") return node_fs.default.readFileSync(polyfill, "utf-8");
3572
+ const path = "path" in polyfill ? polyfill.path : void 0;
3573
+ const content = "code" in polyfill ? polyfill.code : node_fs.default.readFileSync(polyfill.path, "utf-8");
3574
+ return polyfill.type === "iife" ? iife(content, path) : content;
3575
+ });
3576
+ }
3577
+ async function applyDangerouslyOverrideOptionsFinalizer(config, inputOptions, outputOptions) {
3578
+ const override = config.dangerously_overrideRolldownOptions;
3579
+ if (override == null) return {
3580
+ input: inputOptions,
3581
+ output: outputOptions
3582
+ };
3583
+ return await applyOverrideRolldownOptions(override, {
3584
+ input: inputOptions,
3585
+ output: outputOptions
3586
+ });
3587
+ }
3588
+ function getOverrideOptionsForDevServer(buildOptions) {
3589
+ return {
3590
+ input: {
3591
+ transform: { jsx: { development: true } },
3592
+ experimental: {
3593
+ incrementalBuild: true,
3594
+ nativeMagicString: true
3595
+ },
3596
+ treeshake: false
3597
+ },
3598
+ output: {
3599
+ minify: buildOptions.minify ?? false,
3600
+ sourcemap: buildOptions.sourcemap ?? true,
3601
+ generatedCode: {
3602
+ symbols: buildOptions.dev,
3603
+ profilerNames: buildOptions.dev
3604
+ }
3605
+ }
3606
+ };
3607
+ }
3608
+ //#endregion
3609
+ //#region src/core/bundler.ts
3610
+ var Bundler = class Bundler {
3611
+ static async devEngine(config, buildOptions, devEngineOptions) {
3612
+ const buildType = "serve";
3613
+ const resolvedBuildOptions = resolveBuildOptions(config, buildOptions);
3614
+ const context = Bundler.createContext(buildType, config, resolvedBuildOptions);
3615
+ const { input = {}, output = {} } = await resolveRolldownOptions(context, config, resolvedBuildOptions, devEngineOptions);
3616
+ const devServerOptions = getOverrideOptionsForDevServer(resolvedBuildOptions);
3617
+ const devEngine = await (0, _rollipop_rolldown_experimental.dev)((0, es_toolkit.merge)(input, devServerOptions.input), (0, es_toolkit.merge)(output, devServerOptions.output), {
3618
+ watch: config.watcher,
3619
+ ...devEngineOptions
3620
+ });
3621
+ Object.defineProperty(devEngine, "getContext", {
3622
+ value: () => context,
3623
+ enumerable: true,
3624
+ configurable: false
3625
+ });
3626
+ return devEngine;
3627
+ }
3628
+ static createId(config, buildOptions) {
3629
+ return createId(config, buildOptions);
3630
+ }
3631
+ static createContext(buildType, config, buildOptions) {
3632
+ return {
3633
+ id: Bundler.createId(config, buildOptions),
3634
+ root: config.root,
3635
+ storage: FileStorage.getInstance(config.root),
3636
+ buildType,
3637
+ state: { hmrUpdates: /* @__PURE__ */ new Set() }
3638
+ };
3639
+ }
3640
+ constructor(config) {
3641
+ this.config = config;
3642
+ Logo.printOnce();
3643
+ }
3644
+ async build(buildOptions) {
3645
+ const buildType = "build";
3646
+ const resolvedBuildOptions = resolveBuildOptions(this.config, buildOptions);
3647
+ const context = Bundler.createContext(buildType, this.config, resolvedBuildOptions);
3648
+ const sourcemap = resolvedBuildOptions.sourcemap ? true : false;
3649
+ const { input, output } = await resolveRolldownOptions(context, this.config, resolvedBuildOptions);
3650
+ const rolldownBuildOptions = {
3651
+ ...input,
3652
+ output: {
3653
+ ...output,
3654
+ sourcemap
3655
+ },
3656
+ write: Boolean(resolvedBuildOptions.outfile)
3657
+ };
3658
+ const chunk = (await _rollipop_rolldown.build(rolldownBuildOptions)).output[0];
3659
+ (0, es_toolkit.invariant)(chunk, "Bundled chunk is not found");
3660
+ if (resolvedBuildOptions.outfile && chunk.sourcemapFileName && resolvedBuildOptions.sourcemapOutfile) {
3661
+ const outputDir = node_path.default.dirname(resolvedBuildOptions.outfile);
3662
+ const sourcemapDir = node_path.default.dirname(resolvedBuildOptions.sourcemapOutfile);
3663
+ const sourcemapFile = node_path.default.join(outputDir, chunk.sourcemapFileName);
3664
+ if (!node_fs.default.existsSync(sourcemapDir)) node_fs.default.mkdirSync(sourcemapDir, { recursive: true });
3665
+ node_fs.default.renameSync(sourcemapFile, resolvedBuildOptions.sourcemapOutfile);
3666
+ }
3667
+ return chunk;
3668
+ }
3669
+ };
3670
+ //#endregion
3671
+ //#region src/utils/run-build.ts
3672
+ async function runBuild(config, options) {
3673
+ return await new Bundler(config).build(options);
3674
+ }
3675
+ //#endregion
3676
+ //#region src/utils/run-server.ts
3677
+ async function runServer(config, options) {
3678
+ const { port, host } = options;
3679
+ const devServer = await createDevServer(config, options);
3680
+ await devServer.instance.listen({
3681
+ port,
3682
+ host
3683
+ });
3684
+ return devServer;
3685
+ }
3686
+ //#endregion
3687
+ //#region src/node/commands/start/action.ts
3688
+ const action$1 = async function(options) {
3689
+ const cwd = process.cwd();
3690
+ const config = await loadConfig({
3691
+ cwd,
3692
+ mode: "development",
3693
+ configFile: options.config,
3694
+ context: { command: "start" }
3695
+ });
3696
+ if (options.resetCache) {
3697
+ resetCache(cwd);
3698
+ logger$2.info("The transform cache was reset");
3699
+ }
3700
+ if (options.clientLogs === false) config.reporter = { update: es_toolkit.noop };
3701
+ const devServer = await runServer(config, {
3702
+ buildOptions: { cache: options.cache },
3703
+ port: options.port,
3704
+ host: options.host,
3705
+ https: options.https,
3706
+ key: options.key,
3707
+ cert: options.cert
3708
+ });
3709
+ if (options.interactive) setupInteractiveMode({
3710
+ devServer,
3711
+ extraCommands: config.terminal?.extraCommands
3712
+ });
3713
+ };
3714
+ //#endregion
3715
+ //#region src/node/commands/start/command.ts
3716
+ const command$1 = {
3717
+ name: "start",
3718
+ description: "Start the React Native development server.",
3719
+ action: action$1,
3720
+ options: [
3721
+ {
3722
+ name: "--config <string>",
3723
+ description: "Path to the CLI configuration file",
3724
+ parse: resolvePath
3725
+ },
3726
+ {
3727
+ name: "--host <string>",
3728
+ description: "Host to start the development server on",
3729
+ default: DEFAULT_HOST
3730
+ },
3731
+ {
3732
+ name: "--port <number>",
3733
+ description: "Port to start the development server on",
3734
+ default: DEFAULT_PORT,
3735
+ parse: Number
3736
+ },
3737
+ {
3738
+ name: "--reset-cache, --resetCache",
3739
+ description: "Removes cached files"
3740
+ },
3741
+ {
3742
+ name: "--https",
3743
+ description: "Enables https connections to the server"
3744
+ },
3745
+ {
3746
+ name: "--key <path>",
3747
+ description: "Path to custom SSL key"
3748
+ },
3749
+ {
3750
+ name: "--cert <path>",
3751
+ description: "Path to custom SSL cert"
3752
+ },
3753
+ {
3754
+ name: "--no-interactive",
3755
+ description: "Disables interactive mode"
3756
+ },
3757
+ {
3758
+ name: "--client-logs",
3759
+ description: "[Deprecated] Enable plain text JavaScript log streaming for all connected apps. This feature is deprecated and will be removed in future.",
3760
+ default: false
3761
+ },
3762
+ {
3763
+ name: "--cache [boolean]",
3764
+ description: "If false, the bundler will not load or store any cache",
3765
+ parse: parseBoolean
3766
+ },
3767
+ {
3768
+ name: "--projectRoot <path>",
3769
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3770
+ },
3771
+ {
3772
+ name: "--watchFolders <list>",
3773
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3774
+ },
3775
+ {
3776
+ name: "--assetPlugins <list>",
3777
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3778
+ },
3779
+ {
3780
+ name: "--sourceExts <list>",
3781
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3782
+ },
3783
+ {
3784
+ name: "--max-workers <number>",
3785
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3786
+ },
3787
+ {
3788
+ name: "--transformer <string>",
3789
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3790
+ },
3791
+ {
3792
+ name: "--custom-log-reporter-path, --customLogReporterPath <string>",
3793
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3794
+ }
3795
+ ]
3796
+ };
3797
+ //#endregion
3798
+ //#region src/node/commands/bundle/action.ts
3799
+ const action = async function(options) {
3800
+ if (!this.platforms.includes(options.platform)) throw new Error(`Unrecognized platform: ${options.platform}`);
3801
+ const cwd = process.cwd();
3802
+ const config = await loadConfig({
3803
+ cwd,
3804
+ mode: "production",
3805
+ configFile: options.config,
3806
+ context: { command: "bundle" }
3807
+ });
3808
+ if (options.resetCache) {
3809
+ resetCache(cwd);
3810
+ logger$2.info("The transform cache was reset");
3811
+ }
3812
+ if (options.entryFile) config.entry = options.entryFile;
3813
+ await runBuild(config, {
3814
+ platform: options.platform,
3815
+ dev: options.dev,
3816
+ minify: options.minify,
3817
+ cache: options.cache,
3818
+ outfile: options.bundleOutput,
3819
+ sourcemapOutfile: options.sourcemapOutput,
3820
+ assetsDir: options.assetsDest
3821
+ });
3822
+ };
3823
+ //#endregion
3824
+ //#region src/node/commands/bundle/command.ts
3825
+ const command = {
3826
+ name: "bundle",
3827
+ description: "Build the bundle for the provided JavaScript entry file.",
3828
+ action,
3829
+ options: [
3830
+ {
3831
+ name: "--config <string>",
3832
+ description: "Path to the CLI configuration file",
3833
+ parse: resolvePath
3834
+ },
3835
+ {
3836
+ name: "--entry-file <path>",
3837
+ description: "Path to the root JS file, either absolute or relative to JS root"
3838
+ },
3839
+ {
3840
+ name: "--platform <string>",
3841
+ description: "Either \"ios\" or \"android\"",
3842
+ default: "ios"
3843
+ },
3844
+ {
3845
+ name: "--dev [boolean]",
3846
+ description: "If false, warnings are disabled and the bundle is minified",
3847
+ parse: parseBoolean
3848
+ },
3849
+ {
3850
+ name: "--minify [boolean]",
3851
+ description: "Allows overriding whether bundle is minified. This defaults to false if dev is true, and true if dev is false. Disabling minification can be useful for speeding up production builds for testing purposes.",
3852
+ parse: parseBoolean
3853
+ },
3854
+ {
3855
+ name: "--cache [boolean]",
3856
+ description: "If false, the bundler will not load or store any cache",
3857
+ parse: parseBoolean
3858
+ },
3859
+ {
3860
+ name: "--bundle-output <string>",
3861
+ description: "File name where to store the resulting bundle, ex. /tmp/groups.bundle",
3862
+ required: true
3863
+ },
3864
+ {
3865
+ name: "--sourcemap-output <string>",
3866
+ description: "File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map"
3867
+ },
3868
+ {
3869
+ name: "--sourcemap-sources-root <string>",
3870
+ description: `Path to make sourcemap's sources entries relative to, ex. /root/dir`
3871
+ },
3872
+ {
3873
+ name: "--sourcemap-use-absolute-path",
3874
+ description: "Report SourceMapURL using its full path"
3875
+ },
3876
+ {
3877
+ name: "--assets-dest <string>",
3878
+ description: "Directory name where to store assets referenced in the bundle"
3879
+ },
3880
+ {
3881
+ name: "--reset-cache",
3882
+ description: "Removes cached files",
3883
+ default: false
3884
+ },
3885
+ {
3886
+ name: "--transformer <string>",
3887
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3888
+ },
3889
+ {
3890
+ name: "--bundle-encoding <string>",
3891
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3892
+ },
3893
+ {
3894
+ name: "--max-workers <number>",
3895
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3896
+ },
3897
+ {
3898
+ name: "--unstable-transform-profile <string>",
3899
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3900
+ },
3901
+ {
3902
+ name: "--asset-catalog-dest [string]",
3903
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3904
+ },
3905
+ {
3906
+ name: "--read-global-cache",
3907
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3908
+ },
3909
+ {
3910
+ name: "--resolver-option <string...>",
3911
+ description: UNSUPPORTED_OPTION_DESCRIPTION
3912
+ }
3913
+ ]
3914
+ };
3915
+ //#endregion
3916
+ //#region src/commands.ts
3917
+ const commands = [createReactNativeCliCommand(command$1), createReactNativeCliCommand(command)];
3918
+ //#endregion
3919
+ module.exports = commands;