@lifo-sh/node-runner 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/runner.ts
2
- import { createVFS } from "@lifo-sh/vfs";
2
+ import { VFS } from "@lifo-sh/vfs";
3
3
 
4
4
  // src/builtins.ts
5
5
  var minimalPath = {
@@ -52,19 +52,30 @@ var minimalPath = {
52
52
  posix: null
53
53
  };
54
54
  minimalPath.posix = minimalPath;
55
- function createScriptConsole(stdout, stderr) {
56
- const format = (...args) => args.map(
55
+ function formatArgs(...args) {
56
+ return args.map(
57
57
  (a) => typeof a === "string" ? a : JSON.stringify(a, null, 2) ?? String(a)
58
58
  ).join(" ");
59
+ }
60
+ function createCaptureConsole(stdout, stderr) {
61
+ return {
62
+ log: (...args) => stdout.push(formatArgs(...args)),
63
+ error: (...args) => stderr.push(formatArgs(...args)),
64
+ warn: (...args) => stderr.push(formatArgs(...args)),
65
+ info: (...args) => stdout.push(formatArgs(...args)),
66
+ debug: (...args) => stdout.push(formatArgs(...args))
67
+ };
68
+ }
69
+ function createStreamConsole(stdout, stderr) {
59
70
  return {
60
- log: (...args) => stdout.push(format(...args)),
61
- error: (...args) => stderr.push(format(...args)),
62
- warn: (...args) => stderr.push(format(...args)),
63
- info: (...args) => stdout.push(format(...args)),
64
- debug: (...args) => stdout.push(format(...args))
71
+ log: (...args) => stdout.write(formatArgs(...args) + "\n"),
72
+ error: (...args) => stderr.write(formatArgs(...args) + "\n"),
73
+ warn: (...args) => stderr.write(formatArgs(...args) + "\n"),
74
+ info: (...args) => stdout.write(formatArgs(...args) + "\n"),
75
+ debug: (...args) => stdout.write(formatArgs(...args) + "\n")
65
76
  };
66
77
  }
67
- function createMinimalProcess(env, cwd, argv) {
78
+ function createMinimalProcess(env, cwd, argv, stdout, stderr) {
68
79
  return {
69
80
  env,
70
81
  cwd: () => cwd,
@@ -79,12 +90,14 @@ function createMinimalProcess(env, cwd, argv) {
79
90
  pid: 1,
80
91
  ppid: 0,
81
92
  stdout: {
82
- write: (_s) => {
93
+ write: (s) => {
94
+ if (stdout) stdout.write(String(s));
83
95
  return true;
84
96
  }
85
97
  },
86
98
  stderr: {
87
- write: (_s) => {
99
+ write: (s) => {
100
+ if (stderr) stderr.write(String(s));
88
101
  return true;
89
102
  }
90
103
  },
@@ -102,13 +115,12 @@ var ProcessExitError = class extends Error {
102
115
  this.code = code;
103
116
  }
104
117
  };
105
- function createBuiltinModules(_vfs, env, cwd, argv, scriptConsole, nodeCompat) {
118
+ function createBuiltinModules(_vfs, env, cwd, argv, scriptConsole, nodeCompat, stdout, stderr) {
106
119
  const builtins = /* @__PURE__ */ new Map();
107
120
  builtins.set("path", nodeCompat?.path ?? minimalPath);
108
- const process = nodeCompat?.process ?? createMinimalProcess(env, cwd, argv);
121
+ const process = nodeCompat?.process ?? createMinimalProcess(env, cwd, argv, stdout, stderr);
109
122
  builtins.set("process", process);
110
- const console_ = scriptConsole;
111
- builtins.set("console", console_);
123
+ builtins.set("console", scriptConsole);
112
124
  if (nodeCompat?.fs) builtins.set("fs", nodeCompat.fs);
113
125
  if (nodeCompat?.fsPromises) builtins.set("fs/promises", nodeCompat.fsPromises);
114
126
  if (nodeCompat?.events) builtins.set("events", nodeCompat.events);
@@ -126,20 +138,40 @@ function createBuiltinModules(_vfs, env, cwd, argv, scriptConsole, nodeCompat) {
126
138
  // src/resolver.ts
127
139
  var textDecoder = new TextDecoder();
128
140
  function resolveModule(vfs, id, fromDir) {
129
- const candidates = buildCandidates(id, fromDir);
130
- for (const candidate of candidates) {
141
+ if (id.startsWith("#")) {
142
+ return resolvePackageImport(vfs, id, fromDir);
143
+ }
144
+ if (id.startsWith("./") || id.startsWith("../") || id.startsWith("/")) {
145
+ return resolveRelative(vfs, id, fromDir);
146
+ }
147
+ return resolveNodeModule(vfs, id, fromDir);
148
+ }
149
+ function resolveRelative(vfs, id, fromDir) {
150
+ const absPath = id.startsWith("/") ? id : normalizePath(fromDir + "/" + id);
151
+ return resolveFile(vfs, absPath);
152
+ }
153
+ function resolveFile(vfs, absPath) {
154
+ if (vfs.exists(absPath)) {
131
155
  try {
132
- if (!vfs.existsSync(candidate)) continue;
133
- const stat = vfs.statSync(candidate);
134
- if (stat.isDirectory()) {
135
- const fromPkg = tryPackageMain(vfs, candidate);
156
+ const stat = vfs.stat(absPath);
157
+ if (stat.type === "file") {
158
+ const source = textDecoder.decode(vfs.readFile(absPath));
159
+ return { path: absPath, source };
160
+ }
161
+ if (stat.type === "directory") {
162
+ const fromPkg = tryPackageMain(vfs, absPath);
136
163
  if (fromPkg) return fromPkg;
137
- const fromIndex = tryIndexFile(vfs, candidate);
164
+ const fromIndex = tryIndexFile(vfs, absPath);
138
165
  if (fromIndex) return fromIndex;
139
- continue;
140
166
  }
141
- if (stat.isFile()) {
142
- const source = textDecoder.decode(vfs.readFileSync(candidate));
167
+ } catch {
168
+ }
169
+ }
170
+ for (const ext of [".js", ".ts", ".mjs", ".json"]) {
171
+ const candidate = absPath + ext;
172
+ try {
173
+ if (vfs.exists(candidate) && vfs.stat(candidate).type === "file") {
174
+ const source = textDecoder.decode(vfs.readFile(candidate));
143
175
  return { path: candidate, source };
144
176
  }
145
177
  } catch {
@@ -147,33 +179,149 @@ function resolveModule(vfs, id, fromDir) {
147
179
  }
148
180
  return null;
149
181
  }
150
- function buildCandidates(id, fromDir) {
151
- const candidates = [];
152
- if (id.startsWith("./") || id.startsWith("../") || id.startsWith("/")) {
153
- const resolved = id.startsWith("/") ? id : normalizePath(fromDir + "/" + id);
154
- candidates.push(resolved);
155
- candidates.push(resolved + ".js");
156
- candidates.push(resolved + ".ts");
157
- candidates.push(resolved + ".mjs");
158
- candidates.push(resolved + ".json");
182
+ function resolveNodeModule(vfs, name, fromDir) {
183
+ let packageName;
184
+ let subpath = null;
185
+ if (name.startsWith("@")) {
186
+ const parts = name.split("/");
187
+ if (parts.length < 2) return null;
188
+ packageName = parts[0] + "/" + parts[1];
189
+ if (parts.length > 2) subpath = parts.slice(2).join("/");
159
190
  } else {
160
- let dir = fromDir;
161
- while (true) {
162
- candidates.push(normalizePath(dir + "/node_modules/" + id));
163
- candidates.push(normalizePath(dir + "/node_modules/" + id + ".js"));
164
- candidates.push(normalizePath(dir + "/node_modules/" + id + ".json"));
165
- const parent = dir.slice(0, dir.lastIndexOf("/"));
166
- if (parent === dir || parent === "") break;
167
- dir = parent;
191
+ const slashIdx = name.indexOf("/");
192
+ if (slashIdx !== -1) {
193
+ packageName = name.slice(0, slashIdx);
194
+ subpath = name.slice(slashIdx + 1);
195
+ } else {
196
+ packageName = name;
197
+ }
198
+ }
199
+ let current = fromDir;
200
+ for (; ; ) {
201
+ const candidate = normalizePath(current + "/node_modules/" + packageName);
202
+ if (vfs.exists(candidate)) {
203
+ const resolved = resolvePackageEntry(vfs, candidate, subpath);
204
+ if (resolved) return resolved;
205
+ }
206
+ const parent = current.slice(0, current.lastIndexOf("/"));
207
+ if (parent === current || parent === "") break;
208
+ current = parent;
209
+ }
210
+ for (const globalDir of ["/usr/lib/node_modules", "/usr/share/pkg/node_modules"]) {
211
+ const candidate = normalizePath(globalDir + "/" + packageName);
212
+ if (vfs.exists(candidate)) {
213
+ const resolved = resolvePackageEntry(vfs, candidate, subpath);
214
+ if (resolved) return resolved;
168
215
  }
169
216
  }
170
- return candidates;
217
+ return null;
218
+ }
219
+ function resolveExportsCondition(value) {
220
+ if (typeof value === "string") return value;
221
+ if (value && typeof value === "object" && !Array.isArray(value)) {
222
+ const cond = value;
223
+ if (typeof cond.require === "string") return cond.require;
224
+ if (typeof cond.default === "string") return cond.default;
225
+ if (typeof cond.import === "string") return cond.import;
226
+ for (const key of Object.keys(cond)) {
227
+ if (key === "types") continue;
228
+ const nested = resolveExportsCondition(cond[key]);
229
+ if (nested) return nested;
230
+ }
231
+ }
232
+ return null;
233
+ }
234
+ function resolvePackageEntry(vfs, pkgDir, subpath) {
235
+ const pkgJsonPath = pkgDir + "/package.json";
236
+ let pkgJson = null;
237
+ if (vfs.exists(pkgJsonPath)) {
238
+ try {
239
+ pkgJson = JSON.parse(textDecoder.decode(vfs.readFile(pkgJsonPath)));
240
+ } catch {
241
+ }
242
+ }
243
+ if (subpath) {
244
+ if (pkgJson?.exports && typeof pkgJson.exports === "object") {
245
+ const exportsMap = pkgJson.exports;
246
+ const key = "./" + subpath;
247
+ if (key in exportsMap) {
248
+ const target = resolveExportsCondition(exportsMap[key]);
249
+ if (target) {
250
+ const resolved = resolveFile(vfs, normalizePath(pkgDir + "/" + target));
251
+ if (resolved) return resolved;
252
+ }
253
+ }
254
+ for (const pattern of Object.keys(exportsMap)) {
255
+ if (pattern.endsWith("/*") && key.startsWith(pattern.slice(0, -1))) {
256
+ const targetPattern = resolveExportsCondition(exportsMap[pattern]);
257
+ if (targetPattern && targetPattern.endsWith("/*")) {
258
+ const suffix = key.slice(pattern.length - 1);
259
+ const target = targetPattern.slice(0, -1) + suffix;
260
+ const resolved = resolveFile(vfs, normalizePath(pkgDir + "/" + target));
261
+ if (resolved) return resolved;
262
+ }
263
+ }
264
+ }
265
+ }
266
+ return resolveFile(vfs, normalizePath(pkgDir + "/" + subpath));
267
+ }
268
+ if (pkgJson?.exports) {
269
+ const exportsVal = pkgJson.exports;
270
+ let rootExport = null;
271
+ if (typeof exportsVal === "string") {
272
+ rootExport = exportsVal;
273
+ } else if (typeof exportsVal === "object" && !Array.isArray(exportsVal)) {
274
+ const exportsMap = exportsVal;
275
+ rootExport = exportsMap["."] ?? null;
276
+ if (!rootExport && ("require" in exportsMap || "import" in exportsMap || "default" in exportsMap)) {
277
+ rootExport = exportsMap;
278
+ }
279
+ }
280
+ if (rootExport) {
281
+ const target = resolveExportsCondition(rootExport);
282
+ if (target) {
283
+ const resolved = resolveFile(vfs, normalizePath(pkgDir + "/" + target));
284
+ if (resolved) return resolved;
285
+ }
286
+ }
287
+ }
288
+ if (pkgJson?.main && typeof pkgJson.main === "string") {
289
+ const resolved = resolveFile(vfs, normalizePath(pkgDir + "/" + pkgJson.main));
290
+ if (resolved) return resolved;
291
+ }
292
+ return tryIndexFile(vfs, pkgDir);
293
+ }
294
+ function resolvePackageImport(vfs, name, fromDir) {
295
+ let current = fromDir;
296
+ for (; ; ) {
297
+ const pkgPath = current + "/package.json";
298
+ if (vfs.exists(pkgPath)) {
299
+ try {
300
+ const pkg = JSON.parse(textDecoder.decode(vfs.readFile(pkgPath)));
301
+ if (pkg.imports && typeof pkg.imports === "object") {
302
+ const importsMap = pkg.imports;
303
+ if (name in importsMap) {
304
+ const target = resolveExportsCondition(importsMap[name]);
305
+ if (target) {
306
+ return resolveFile(vfs, normalizePath(current + "/" + target));
307
+ }
308
+ }
309
+ }
310
+ } catch {
311
+ }
312
+ break;
313
+ }
314
+ const parent = current.slice(0, current.lastIndexOf("/"));
315
+ if (parent === current || parent === "") break;
316
+ current = parent;
317
+ }
318
+ return null;
171
319
  }
172
320
  function tryPackageMain(vfs, dirPath) {
173
321
  const pkgPath = dirPath + "/package.json";
174
322
  try {
175
- if (!vfs.existsSync(pkgPath)) return null;
176
- const raw = textDecoder.decode(vfs.readFileSync(pkgPath));
323
+ if (!vfs.exists(pkgPath)) return null;
324
+ const raw = textDecoder.decode(vfs.readFile(pkgPath));
177
325
  const pkg = JSON.parse(raw);
178
326
  const main = pkg.main || pkg.module || "index.js";
179
327
  return resolveModule(vfs, "./" + main, dirPath);
@@ -185,8 +333,8 @@ function tryIndexFile(vfs, dirPath) {
185
333
  for (const name of ["index.js", "index.ts", "index.mjs", "index.json"]) {
186
334
  const fullPath = dirPath + "/" + name;
187
335
  try {
188
- if (!vfs.existsSync(fullPath)) continue;
189
- const source = textDecoder.decode(vfs.readFileSync(fullPath));
336
+ if (!vfs.exists(fullPath)) continue;
337
+ const source = textDecoder.decode(vfs.readFile(fullPath));
190
338
  return { path: fullPath, source };
191
339
  } catch {
192
340
  continue;
@@ -204,20 +352,458 @@ function normalizePath(p) {
204
352
  return (p.startsWith("/") ? "/" : "") + result.join("/");
205
353
  }
206
354
 
355
+ // src/transformer.ts
356
+ var CJS_WRAPPER_PARAMS = /* @__PURE__ */ new Set([
357
+ "exports",
358
+ "require",
359
+ "module",
360
+ "__filename",
361
+ "__dirname",
362
+ "console",
363
+ "process",
364
+ "Buffer",
365
+ "setTimeout",
366
+ "setInterval",
367
+ "clearTimeout",
368
+ "clearInterval",
369
+ "global",
370
+ "__importMetaUrl",
371
+ "__importMeta",
372
+ "__importMetaResolve"
373
+ ]);
374
+ function cjsDecl(name) {
375
+ return CJS_WRAPPER_PARAMS.has(name) ? "var" : "const";
376
+ }
377
+ function dirname(p) {
378
+ const idx = p.lastIndexOf("/");
379
+ if (idx === -1) return ".";
380
+ if (idx === 0) return "/";
381
+ return p.slice(0, idx);
382
+ }
383
+ function join(...parts) {
384
+ const joined = parts.join("/").replace(/\/+/g, "/");
385
+ return normalize(joined);
386
+ }
387
+ function extname(p) {
388
+ const base = p.slice(p.lastIndexOf("/") + 1);
389
+ const dot = base.lastIndexOf(".");
390
+ if (dot <= 0) return "";
391
+ return base.slice(dot);
392
+ }
393
+ function normalize(p) {
394
+ const parts = p.split("/");
395
+ const result = [];
396
+ for (const part of parts) {
397
+ if (part === "..") result.pop();
398
+ else if (part !== "." && part !== "") result.push(part);
399
+ }
400
+ return (p.startsWith("/") ? "/" : "") + result.join("/");
401
+ }
402
+ function maskStringLiterals(src) {
403
+ const literals = [];
404
+ let masked = "";
405
+ let i = 0;
406
+ while (i < src.length) {
407
+ const ch = src[i];
408
+ if (ch === "/" && i + 1 < src.length && src[i + 1] === "/") {
409
+ const nl = src.indexOf("\n", i);
410
+ const end = nl === -1 ? src.length : nl;
411
+ masked += src.slice(i, end);
412
+ i = end;
413
+ continue;
414
+ }
415
+ if (ch === "/" && i + 1 < src.length && src[i + 1] === "*") {
416
+ const end = src.indexOf("*/", i + 2);
417
+ const close = end === -1 ? src.length : end + 2;
418
+ masked += src.slice(i, close);
419
+ i = close;
420
+ continue;
421
+ }
422
+ if (ch === "/" && i + 1 < src.length && src[i + 1] !== "/" && src[i + 1] !== "*") {
423
+ let k = i - 1;
424
+ while (k >= 0 && (src[k] === " " || src[k] === " " || src[k] === "\n" || src[k] === "\r")) k--;
425
+ const prev = k >= 0 ? src[k] : "\0";
426
+ if ("\0=([{,;!&|^~?:+-*%<>/)]}".includes(prev) || k >= 1 && /\b(?:return|typeof|void|delete|throw|new|case|of|in|yield|await)\s*$/.test(src.slice(Math.max(0, k - 11), k + 1))) {
427
+ const regStart = i;
428
+ i++;
429
+ while (i < src.length && src[i] !== "\n") {
430
+ if (src[i] === "\\") {
431
+ i += 2;
432
+ continue;
433
+ }
434
+ if (src[i] === "/") {
435
+ i++;
436
+ break;
437
+ }
438
+ if (src[i] === "[") {
439
+ i++;
440
+ while (i < src.length && src[i] !== "]" && src[i] !== "\n") {
441
+ if (src[i] === "\\") i++;
442
+ i++;
443
+ }
444
+ if (i < src.length && src[i] === "]") i++;
445
+ continue;
446
+ }
447
+ i++;
448
+ }
449
+ while (i < src.length && /[gimsuyv]/.test(src[i])) i++;
450
+ masked += src.slice(regStart, i);
451
+ continue;
452
+ }
453
+ }
454
+ if (ch === '"' || ch === "'" || ch === "`") {
455
+ const start = i;
456
+ const quote = ch;
457
+ i++;
458
+ while (i < src.length) {
459
+ if (src[i] === "\\") {
460
+ i += 2;
461
+ continue;
462
+ }
463
+ if (src[i] === quote) {
464
+ i++;
465
+ break;
466
+ }
467
+ if (quote === "`" && src[i] === "$" && i + 1 < src.length && src[i + 1] === "{") {
468
+ let depth = 1;
469
+ i += 2;
470
+ while (i < src.length && depth > 0) {
471
+ if (src[i] === "{") depth++;
472
+ else if (src[i] === "}") depth--;
473
+ else if (src[i] === "\\") i++;
474
+ else if (src[i] === "'" || src[i] === '"') {
475
+ const q = src[i];
476
+ i++;
477
+ while (i < src.length && src[i] !== q) {
478
+ if (src[i] === "\\") i++;
479
+ i++;
480
+ }
481
+ if (i < src.length) i++;
482
+ continue;
483
+ } else if (src[i] === "`") {
484
+ i++;
485
+ while (i < src.length && src[i] !== "`") {
486
+ if (src[i] === "\\") i++;
487
+ i++;
488
+ }
489
+ if (i < src.length) i++;
490
+ continue;
491
+ }
492
+ i++;
493
+ }
494
+ continue;
495
+ }
496
+ i++;
497
+ }
498
+ const literal = src.slice(start, i);
499
+ const idx = literals.length;
500
+ literals.push(literal);
501
+ masked += quote + "__LIFO_S" + idx + "__" + quote;
502
+ continue;
503
+ }
504
+ masked += ch;
505
+ i++;
506
+ }
507
+ return { masked, literals };
508
+ }
509
+ function unmaskStringLiterals(src, literals) {
510
+ return src.replace(
511
+ /(['"`])__LIFO_S(\d+)__\1/g,
512
+ (_match, _quote, idxStr) => literals[parseInt(idxStr, 10)]
513
+ );
514
+ }
515
+ function isEsmSource(source) {
516
+ return /(?:^|\n|;)\s*(?:import\s*[\w{*('".]|export\s+|export\s*\{)/.test(source);
517
+ }
518
+ function shouldTreatAsEsm(source, filename, vfs) {
519
+ const ext = extname(filename);
520
+ if (ext === ".mjs") return true;
521
+ if (ext === ".cjs") return false;
522
+ if (vfs && ext === ".js") {
523
+ let dir = dirname(filename);
524
+ for (; ; ) {
525
+ const pkgPath = join(dir, "package.json");
526
+ if (vfs.exists(pkgPath)) {
527
+ try {
528
+ const pkg = JSON.parse(vfs.readFileString(pkgPath));
529
+ if (pkg.type === "module") return true;
530
+ if (pkg.type === "commonjs") return false;
531
+ } catch {
532
+ }
533
+ break;
534
+ }
535
+ const parent = dirname(dir);
536
+ if (parent === dir) break;
537
+ dir = parent;
538
+ }
539
+ }
540
+ return isEsmSource(source);
541
+ }
542
+ function transformEsmToCjs(source) {
543
+ let result = source.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
544
+ result = result.split("import.meta.url").join("__importMetaUrl");
545
+ result = result.split("import.meta.dirname").join("__dirname");
546
+ result = result.split("import.meta.filename").join("__filename");
547
+ result = result.split("import.meta.require").join("require");
548
+ result = result.split("import.meta.resolve").join("__importMetaResolve");
549
+ result = result.split("import.meta").join("__importMeta");
550
+ const { masked, literals } = maskStringLiterals(result);
551
+ result = masked;
552
+ result = result.replace(
553
+ /;([ \t]*(?:import\s*[\w${*('".]|export[\s{*]))/g,
554
+ ";\n$1"
555
+ );
556
+ const trailingExports = [];
557
+ let hasDefaultExport = false;
558
+ let hasNamedExport = false;
559
+ const importSources = /* @__PURE__ */ new Map();
560
+ hasDefaultExport = /(?:^|\n)\s*export\s+default\s+/.test(result);
561
+ hasNamedExport = /(?:^|\n)\s*export\s+(?:const|let|var|function|class|\{|\*\s+from)/.test(result);
562
+ result = result.replace(/^[ \t]*import\s+type\s+.*?from\s+(['"`]).*?\1[ \t]*;?$/gm, "");
563
+ result = result.replace(/^[ \t]*export\s+type\s+\{[^}]*\}(?:\s+from\s+(['"`]).*?\1)?[ \t]*;?$/gm, "");
564
+ result = result.replace(/^[ \t]*export\s+type\s+\*\s+from\s+(['"`]).*?\1[ \t]*;?$/gm, "");
565
+ result = result.replace(
566
+ /(?:^|\n)([ \t]*)import\s+([\w$]+)\s*,\s*\{([^}]+)\}\s*from\s*(['"][^'"]+['"])[ \t]*;?/g,
567
+ (match, indent, defaultName, imports, mod) => {
568
+ if (imports.includes("${")) return match;
569
+ const tmp = "__mod_" + defaultName;
570
+ const mapped = imports.split(",").map((s) => {
571
+ const parts = s.trim().split(/\s+as\s+/);
572
+ const sourceProp = parts[0].trim();
573
+ const localName = parts.length === 2 ? parts[1].trim() : sourceProp;
574
+ if (localName) importSources.set(localName, { modRef: tmp, prop: sourceProp });
575
+ if (parts.length === 2) return `${sourceProp}: ${localName}`;
576
+ return sourceProp;
577
+ }).filter((s) => s).join(", ");
578
+ return `
579
+ ${indent}${cjsDecl(tmp)} ${tmp} = require(${mod});
580
+ ${indent}${cjsDecl(defaultName)} ${defaultName} = ${tmp}.default || ${tmp};
581
+ ${indent}const { ${mapped} } = ${tmp};`;
582
+ }
583
+ );
584
+ result = result.replace(
585
+ /(?:^|\n)([ \t]*)import\s+([\w$]+)\s*,\s*\*\s*as\s+([\w$]+)\s+from\s*(['"][^'"]+['"])[ \t]*;?/g,
586
+ (_match, indent, defaultName, nsName, mod) => {
587
+ return `
588
+ ${indent}${cjsDecl(nsName)} ${nsName} = require(${mod});
589
+ ${indent}${cjsDecl(defaultName)} ${defaultName} = ${nsName}.default || ${nsName};`;
590
+ }
591
+ );
592
+ result = result.replace(
593
+ /(?:^|\n)([ \t]*)import\s*\{([^}]+)\}\s*from\s*(['"][^'"]+['"])[ \t]*;?/g,
594
+ (match, indent, imports, mod) => {
595
+ if (imports.includes("${")) return match;
596
+ const modRef = "__imp_" + Math.random().toString(36).slice(2, 8);
597
+ const mapped = imports.split(",").map((s) => {
598
+ const parts = s.trim().split(/\s+as\s+/);
599
+ const sourceProp = parts[0].trim();
600
+ const localName = parts.length === 2 ? parts[1].trim() : sourceProp;
601
+ if (localName) importSources.set(localName, { modRef, prop: sourceProp });
602
+ if (parts.length === 2) return `${sourceProp}: ${localName}`;
603
+ return sourceProp;
604
+ }).filter((s) => s).join(", ");
605
+ return `
606
+ ${indent}const ${modRef} = require(${mod});
607
+ ${indent}const { ${mapped} } = ${modRef};`;
608
+ }
609
+ );
610
+ result = result.replace(
611
+ /(?:^|\n)([ \t]*)import\s*\*\s*as\s+([\w$]+)\s+from\s*(['"][^'"]+['"])[ \t]*;?/g,
612
+ (_match, indent, name, mod) => `
613
+ ${indent}${cjsDecl(name)} ${name} = require(${mod});`
614
+ );
615
+ result = result.replace(
616
+ /(?:^|\n)([ \t]*)import\s+([\w$]+)\s+from\s*(['"][^'"]+['"])[ \t]*;?/g,
617
+ (_match, indent, name, mod) => `
618
+ ${indent}${cjsDecl(name)} ${name} = require(${mod});`
619
+ );
620
+ result = result.replace(
621
+ /(?:^|\n)([ \t]*)import\s*(['"][^'"]+['"])[ \t]*;?/g,
622
+ (_match, indent, mod) => `
623
+ ${indent}require(${mod});`
624
+ );
625
+ result = result.replace(/(?:^|\n)[ \t]*export\s*\{\s*\}[ \t]*;?/g, "");
626
+ result = result.replace(
627
+ /(?:^|\n)([ \t]*)export\s*\*\s*from\s*(['"][^'"]+['"])[ \t]*;?/g,
628
+ (_match, indent, mod) => {
629
+ const tmpVar = "__star_" + Math.random().toString(36).slice(2, 8);
630
+ return `
631
+ ${indent}const ${tmpVar} = require(${mod});
632
+ ${indent}Object.keys(${tmpVar}).forEach(function(k) { if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, { get: function() { return ${tmpVar}[k]; }, enumerable: true, configurable: true }); });`;
633
+ }
634
+ );
635
+ result = result.replace(
636
+ /(?:^|\n)([ \t]*)export\s*\{([^}]+)\}\s*from\s*(['"][^'"]+['"])[ \t]*;?/g,
637
+ (match, indent, names, mod) => {
638
+ if (names.includes("${")) return match;
639
+ const tmpVar = "__re_" + Math.random().toString(36).slice(2, 8);
640
+ const assignments = names.split(",").map((s) => {
641
+ const parts = s.trim().split(/\s+as\s+/);
642
+ const local = parts[0].trim();
643
+ const exported = parts.length === 2 ? parts[1].trim() : local;
644
+ return `${indent}Object.defineProperty(exports, '${exported}', { get() { return ${tmpVar}.${local}; }, enumerable: true, configurable: true });`;
645
+ }).join("\n");
646
+ return `
647
+ ${indent}const ${tmpVar} = require(${mod});
648
+ ${assignments}`;
649
+ }
650
+ );
651
+ if (hasDefaultExport && hasNamedExport) {
652
+ result = result.replace(
653
+ /(?:^|\n)([ \t]*)export\s+default\s+/g,
654
+ (_match, indent) => `
655
+ ${indent}exports.default = `
656
+ );
657
+ } else {
658
+ result = result.replace(
659
+ /(?:^|\n)([ \t]*)export\s+default\s+/g,
660
+ (_match, indent) => `
661
+ ${indent}module.exports = `
662
+ );
663
+ }
664
+ result = result.replace(
665
+ /(?:^|\n)([ \t]*)export\s+(const|let|var)\s+([\w$]+)\s*=/g,
666
+ (match, indent, keyword, name) => {
667
+ if (match.includes("${")) return match;
668
+ return `
669
+ ${indent}${keyword} ${name} = exports.${name} =`;
670
+ }
671
+ );
672
+ result = result.replace(
673
+ /(?:^|\n)([ \t]*)export\s+(async\s+function\s+([\w$]+)|function\s+([\w$]+)|class\s+([\w$]+))/g,
674
+ (match, indent, decl, asyncFnName, fnName, className, offset) => {
675
+ const nextChar = result.charAt(offset + match.length);
676
+ if (nextChar === "{") return match;
677
+ const name = asyncFnName || fnName || className;
678
+ trailingExports.push(`exports.${name} = ${name};`);
679
+ return `
680
+ ${indent}${decl}`;
681
+ }
682
+ );
683
+ result = result.replace(
684
+ /(?:^|\n)([ \t]*)export\s*\{([^}]+)\}[ \t]*;?/g,
685
+ (match, _indent, names) => {
686
+ if (names.includes("${")) return match;
687
+ names.split(",").forEach((s) => {
688
+ const parts = s.trim().split(/\s+as\s+/);
689
+ const local = parts[0].trim();
690
+ const exported = parts.length === 2 ? parts[1].trim() : local;
691
+ if (!local) return;
692
+ const src = importSources.get(local);
693
+ if (src) {
694
+ trailingExports.push(`Object.defineProperty(exports, '${exported}', { get: function() { return ${src.modRef}.${src.prop}; }, enumerable: true, configurable: true });`);
695
+ } else {
696
+ trailingExports.push(`exports.${exported} = ${local};`);
697
+ }
698
+ });
699
+ return "";
700
+ }
701
+ );
702
+ result = result.replace(
703
+ /(?<!\.)(?<!\w)\bimport\s*\(\s*(['"][^'"]+['"])\s*\)/g,
704
+ (_match, mod) => `Promise.resolve(require(${mod}))`
705
+ );
706
+ {
707
+ let i = 0;
708
+ let out = "";
709
+ while (i < result.length) {
710
+ const importIdx = result.indexOf("import(", i);
711
+ if (importIdx === -1) {
712
+ out += result.slice(i);
713
+ break;
714
+ }
715
+ if (importIdx > 0 && /[\w$.]/.test(result[importIdx - 1])) {
716
+ out += result.slice(i, importIdx + 7);
717
+ i = importIdx + 7;
718
+ continue;
719
+ }
720
+ {
721
+ let depth2 = 1;
722
+ let k = importIdx + 7;
723
+ while (k < result.length && depth2 > 0) {
724
+ if (result[k] === "(") depth2++;
725
+ else if (result[k] === ")") depth2--;
726
+ k++;
727
+ }
728
+ if (depth2 === 0) {
729
+ let afterClose = k;
730
+ while (afterClose < result.length && /[ \t]/.test(result[afterClose])) afterClose++;
731
+ if (result[afterClose] === "{") {
732
+ out += result.slice(i, importIdx + 7);
733
+ i = importIdx + 7;
734
+ continue;
735
+ }
736
+ }
737
+ }
738
+ out += result.slice(i, importIdx);
739
+ let depth = 1;
740
+ let j = importIdx + 7;
741
+ while (j < result.length && depth > 0) {
742
+ if (result[j] === "(") depth++;
743
+ else if (result[j] === ")") depth--;
744
+ j++;
745
+ }
746
+ if (depth === 0) {
747
+ const arg = result.slice(importIdx + 7, j - 1);
748
+ out += `Promise.resolve().then(function() { return require(${arg}); })`;
749
+ } else {
750
+ out += result.slice(importIdx, j);
751
+ }
752
+ i = j;
753
+ }
754
+ result = out;
755
+ }
756
+ result = result.replace(
757
+ /\b(const|let)\s+(__dirname|__filename|exports|require|module|console|process|Buffer|global)\b/g,
758
+ (_match, _kw, name) => `var ${name}`
759
+ );
760
+ if (trailingExports.length > 0) {
761
+ result += "\n" + trailingExports.join("\n");
762
+ }
763
+ result = unmaskStringLiterals(result, literals);
764
+ return result;
765
+ }
766
+ function transformToCjs(source, filename, vfs) {
767
+ if (shouldTreatAsEsm(source, filename, vfs)) {
768
+ return { code: transformEsmToCjs(source), wasEsm: true };
769
+ }
770
+ return { code: source, wasEsm: false };
771
+ }
772
+
207
773
  // src/runner.ts
208
774
  var textEncoder = new TextEncoder();
775
+ function stripShebang(src) {
776
+ if (src.charCodeAt(0) === 35 && src.charCodeAt(1) === 33) {
777
+ const nl = src.indexOf("\n");
778
+ if (nl === -1) return "";
779
+ return "\n" + src.slice(nl + 1);
780
+ }
781
+ return src;
782
+ }
209
783
  var NodeRunner = class {
210
784
  vfs;
785
+ moduleMapFactory;
211
786
  nodeCompat;
212
787
  env;
213
788
  cwd;
214
789
  argv;
790
+ stdout;
791
+ stderr;
792
+ signal;
793
+ globalShims;
794
+ /** Module cache from the last execution. Can be inspected by the caller. */
795
+ moduleCache = /* @__PURE__ */ new Map();
215
796
  constructor(options) {
216
- this.vfs = options.vfs ?? createVFS();
797
+ this.vfs = options.vfs ?? new VFS();
798
+ this.moduleMapFactory = options.moduleMap;
217
799
  this.nodeCompat = options.nodeCompat;
218
800
  this.env = options.env ?? {};
219
801
  this.cwd = options.cwd ?? "/";
220
802
  this.argv = options.argv ?? [];
803
+ this.stdout = options.stdout;
804
+ this.stderr = options.stderr;
805
+ this.signal = options.signal;
806
+ this.globalShims = options.globalShims;
221
807
  if (options.files) {
222
808
  this.writeFilesSync(options.files);
223
809
  }
@@ -229,26 +815,16 @@ var NodeRunner = class {
229
815
  for (let i = 1; i < parts.length; i++) {
230
816
  const dir = "/" + parts.slice(0, i).join("/");
231
817
  try {
232
- this.vfs.mkdirSync(dir);
818
+ this.vfs.mkdir(dir);
233
819
  } catch {
234
820
  }
235
821
  }
236
- this.vfs.writeFileSync(filePath, textEncoder.encode(content));
822
+ this.vfs.writeFile(filePath, textEncoder.encode(content));
237
823
  }
238
824
  }
239
- /** Write files to the VFS asynchronously (persists to IndexedDB backend) */
825
+ /** Write files to the VFS asynchronously (for IndexedDB-backed VFS) */
240
826
  async writeFiles(files) {
241
- for (const [filePath, content] of Object.entries(files)) {
242
- const parts = filePath.split("/").filter(Boolean);
243
- for (let i = 1; i < parts.length; i++) {
244
- const dir = "/" + parts.slice(0, i).join("/");
245
- try {
246
- await this.vfs.mkdir(dir);
247
- } catch {
248
- }
249
- }
250
- await this.vfs.writeFile(filePath, textEncoder.encode(content));
251
- }
827
+ this.writeFilesSync(files);
252
828
  }
253
829
  /** Run a script file from the VFS, resolving extensions and index files */
254
830
  async runFile(filePath) {
@@ -257,10 +833,14 @@ var NodeRunner = class {
257
833
  const id = absPath.startsWith("/") ? absPath : "./" + absPath;
258
834
  const resolved = resolveModule(this.vfs, id, scriptDir);
259
835
  if (!resolved) {
836
+ const msg = `Error: ENOENT: no such file or directory, open '${absPath}'`;
837
+ if (this.stderr) {
838
+ this.stderr.write(msg + "\n");
839
+ }
260
840
  return {
261
841
  exitCode: 1,
262
842
  stdout: "",
263
- stderr: `Error: ENOENT: no such file or directory, open '${absPath}'`
843
+ stderr: this.stderr ? "" : msg
264
844
  };
265
845
  }
266
846
  return this.execute(resolved.source, resolved.path);
@@ -275,116 +855,348 @@ var NodeRunner = class {
275
855
  this.writeFilesSync({ [filePath]: source });
276
856
  return this.runFile(filePath);
277
857
  }
278
- execute(source, absPath) {
858
+ async execute(source, absPath) {
859
+ this.moduleCache.clear();
279
860
  const stdoutLines = [];
280
861
  const stderrLines = [];
281
- const scriptConsole = createScriptConsole(stdoutLines, stderrLines);
282
- const builtins = createBuiltinModules(
283
- this.vfs,
862
+ const scriptConsole = this.stdout && this.stderr ? createStreamConsole(this.stdout, this.stderr) : this.stdout ? createStreamConsole(this.stdout, { write: (s) => stderrLines.push(s) }) : this.stderr ? createStreamConsole({ write: (s) => stdoutLines.push(s) }, this.stderr) : createCaptureConsole(stdoutLines, stderrLines);
863
+ const isStreaming = !!(this.stdout || this.stderr);
864
+ let getBuiltin;
865
+ if (this.moduleMapFactory) {
866
+ const moduleMap = this.moduleMapFactory;
867
+ getBuiltin = (id) => {
868
+ const name = id.startsWith("node:") ? id.slice(5) : id;
869
+ if (name in moduleMap) {
870
+ if (this.moduleCache.has(name)) return this.moduleCache.get(name);
871
+ const mod = moduleMap[name]();
872
+ this.moduleCache.set(name, mod);
873
+ return mod;
874
+ }
875
+ return void 0;
876
+ };
877
+ } else {
878
+ const builtins = createBuiltinModules(
879
+ this.vfs,
880
+ this.env,
881
+ this.cwd,
882
+ [absPath, ...this.argv],
883
+ scriptConsole,
884
+ this.nodeCompat,
885
+ this.stdout,
886
+ this.stderr
887
+ );
888
+ getBuiltin = (id) => {
889
+ const name = id.startsWith("node:") ? id.slice(5) : id;
890
+ return builtins.has(name) ? builtins.get(name) : void 0;
891
+ };
892
+ }
893
+ const processObj = getBuiltin("process") ?? createMinimalProcess(
284
894
  this.env,
285
895
  this.cwd,
286
896
  [absPath, ...this.argv],
287
- scriptConsole,
288
- this.nodeCompat
897
+ this.stdout,
898
+ this.stderr
289
899
  );
290
- const moduleCache = /* @__PURE__ */ new Map();
900
+ const bufferObj = getBuiltin("buffer");
901
+ const BufferClass = bufferObj && typeof bufferObj === "object" && "Buffer" in bufferObj ? bufferObj.Buffer : void 0;
902
+ const pObj = processObj;
903
+ if (pObj.stdout && typeof pObj.stdout === "object") {
904
+ const pStdout = pObj.stdout;
905
+ if (this.stdout) {
906
+ pStdout.write = (s) => {
907
+ this.stdout.write(String(s));
908
+ return true;
909
+ };
910
+ } else {
911
+ pStdout.write = (s) => {
912
+ stdoutLines.push(String(s));
913
+ return true;
914
+ };
915
+ }
916
+ }
917
+ if (pObj.stderr && typeof pObj.stderr === "object") {
918
+ const pStderr = pObj.stderr;
919
+ if (this.stderr) {
920
+ pStderr.write = (s) => {
921
+ this.stderr.write(String(s));
922
+ return true;
923
+ };
924
+ } else {
925
+ pStderr.write = (s) => {
926
+ stderrLines.push(String(s));
927
+ return true;
928
+ };
929
+ }
930
+ }
931
+ const self = this;
291
932
  const createRequire = (fromDir) => {
292
- const require2 = (id) => {
293
- if (builtins.has(id)) return builtins.get(id);
294
- const resolved = resolveModule(this.vfs, id, fromDir);
933
+ const require3 = (id) => {
934
+ const name = id.startsWith("node:") ? id.slice(5) : id;
935
+ const builtin = getBuiltin(name);
936
+ if (builtin !== void 0) return builtin;
937
+ const resolved = resolveModule(self.vfs, id, fromDir);
295
938
  if (!resolved) {
296
939
  throw new Error(`Cannot find module '${id}'`);
297
940
  }
298
- if (moduleCache.has(resolved.path)) {
299
- return moduleCache.get(resolved.path);
941
+ if (self.moduleCache.has(resolved.path)) {
942
+ return self.moduleCache.get(resolved.path);
300
943
  }
301
944
  if (resolved.path.endsWith(".json")) {
302
945
  const json = JSON.parse(resolved.source);
303
- moduleCache.set(resolved.path, json);
946
+ self.moduleCache.set(resolved.path, json);
304
947
  return json;
305
948
  }
306
- const moduleExports = {};
307
- const moduleObj = { exports: moduleExports };
308
- moduleCache.set(resolved.path, moduleExports);
309
- const moduleDir = resolved.path.slice(
310
- 0,
311
- resolved.path.lastIndexOf("/")
312
- );
949
+ const moduleExports2 = {};
950
+ const moduleObj2 = { exports: moduleExports2 };
951
+ self.moduleCache.set(resolved.path, moduleExports2);
952
+ const moduleDir = resolved.path.slice(0, resolved.path.lastIndexOf("/"));
313
953
  const childRequire = createRequire(moduleDir);
314
- const factory = compileModule(resolved.source, resolved.path);
315
- factory(
316
- moduleObj.exports,
317
- childRequire,
318
- moduleObj,
319
- resolved.path,
320
- moduleDir,
321
- scriptConsole,
322
- builtins.get("process")
323
- );
324
- moduleCache.set(resolved.path, moduleObj.exports);
325
- return moduleObj.exports;
954
+ let cleanSource = stripShebang(resolved.source);
955
+ const { code: cjsSource } = transformToCjs(cleanSource, resolved.path, self.vfs);
956
+ cleanSource = cjsSource;
957
+ const factory = compileModule(cleanSource, resolved.path, self.stderr);
958
+ const importMetaUrl = "file://" + resolved.path;
959
+ const importMeta = { url: importMetaUrl, dirname: moduleDir, filename: resolved.path };
960
+ const importMetaResolve = (specifier) => {
961
+ throw new Error(`import.meta.resolve('${specifier}') is not supported`);
962
+ };
963
+ const global2 = { process: processObj, Buffer: BufferClass, console: scriptConsole };
964
+ const ga2 = globalThis;
965
+ const isRealNode2 = typeof ga2.process?.pid === "number";
966
+ const saved2 = {};
967
+ if (!isRealNode2) {
968
+ saved2.process = ga2.process;
969
+ ga2.process = processObj;
970
+ saved2.Buffer = ga2.Buffer;
971
+ if (BufferClass) ga2.Buffer = BufferClass;
972
+ saved2.console = ga2.console;
973
+ ga2.console = scriptConsole;
974
+ }
975
+ const savedShims2 = {};
976
+ if (self.globalShims) {
977
+ for (const k of Object.keys(self.globalShims)) {
978
+ savedShims2[k] = ga2[k];
979
+ ga2[k] = self.globalShims[k];
980
+ }
981
+ }
982
+ try {
983
+ factory(
984
+ moduleObj2.exports,
985
+ childRequire,
986
+ moduleObj2,
987
+ resolved.path,
988
+ moduleDir,
989
+ scriptConsole,
990
+ processObj,
991
+ BufferClass,
992
+ globalThis.setTimeout,
993
+ globalThis.setInterval,
994
+ globalThis.clearTimeout,
995
+ globalThis.clearInterval,
996
+ global2,
997
+ importMetaUrl,
998
+ importMeta,
999
+ importMetaResolve
1000
+ );
1001
+ } catch (e) {
1002
+ if (e instanceof ProcessExitError) throw e;
1003
+ const err = e instanceof Error ? e : new Error(String(e));
1004
+ if (!err.message.includes("[/")) {
1005
+ err.message = `[${resolved.path}] ${err.message}`;
1006
+ }
1007
+ throw err;
1008
+ } finally {
1009
+ if (self.globalShims) {
1010
+ for (const k of Object.keys(savedShims2)) ga2[k] = savedShims2[k];
1011
+ }
1012
+ if (!isRealNode2) {
1013
+ ga2.process = saved2.process;
1014
+ ga2.Buffer = saved2.Buffer;
1015
+ ga2.console = saved2.console;
1016
+ }
1017
+ }
1018
+ if (moduleObj2.exports !== moduleExports2) {
1019
+ self.moduleCache.set(resolved.path, moduleObj2.exports);
1020
+ }
1021
+ return moduleObj2.exports;
326
1022
  };
327
- require2.resolve = (id) => {
328
- if (builtins.has(id)) return id;
329
- const resolved = resolveModule(this.vfs, id, fromDir);
1023
+ require3.resolve = (id) => {
1024
+ const name = id.startsWith("node:") ? id.slice(5) : id;
1025
+ if (getBuiltin(name) !== void 0) return id;
1026
+ const resolved = resolveModule(self.vfs, id, fromDir);
330
1027
  if (!resolved) throw new Error(`Cannot find module '${id}'`);
331
1028
  return resolved.path;
332
1029
  };
333
- return require2;
1030
+ return require3;
334
1031
  };
1032
+ if (this.moduleMapFactory) {
1033
+ const moduleMap = this.moduleMapFactory;
1034
+ moduleMap.module = () => {
1035
+ const makeCreateRequire = (_filename) => {
1036
+ const dir = typeof _filename === "string" ? _filename.slice(0, _filename.lastIndexOf("/")) || "/" : "/";
1037
+ return createRequire(dir);
1038
+ };
1039
+ const builtinNames = Object.keys(moduleMap);
1040
+ const isBuiltin = (s) => {
1041
+ const n = s.startsWith("node:") ? s.slice(5) : s;
1042
+ return builtinNames.includes(n);
1043
+ };
1044
+ return { createRequire: makeCreateRequire, builtinModules: builtinNames, isBuiltin, default: { createRequire: makeCreateRequire } };
1045
+ };
1046
+ }
335
1047
  let exitCode = 0;
1048
+ let cleanMainSource = stripShebang(source);
1049
+ const { code: cjsMainSource, wasEsm: isEsm } = transformToCjs(cleanMainSource, absPath, this.vfs);
1050
+ cleanMainSource = cjsMainSource;
1051
+ const wrapped = isEsm ? `(async function(exports, require, module, __filename, __dirname, console, process, Buffer, setTimeout, setInterval, clearTimeout, clearInterval, global, __importMetaUrl, __importMeta, __importMetaResolve) {
1052
+ ${cleanMainSource}
1053
+ })` : `(function(exports, require, module, __filename, __dirname, console, process, Buffer, setTimeout, setInterval, clearTimeout, clearInterval, global, __importMetaUrl, __importMeta, __importMetaResolve) {
1054
+ ${cleanMainSource}
1055
+ })`;
1056
+ const scriptDir = absPath.slice(0, absPath.lastIndexOf("/")) || "/";
1057
+ const require2 = createRequire(scriptDir);
1058
+ const moduleExports = {};
1059
+ const moduleObj = { exports: moduleExports };
1060
+ const global = { process: processObj, Buffer: BufferClass, console: scriptConsole };
1061
+ const mainImportMetaUrl = "file://" + absPath;
1062
+ const mainImportMeta = { url: mainImportMetaUrl, dirname: scriptDir, filename: absPath };
1063
+ const mainImportMetaResolve = (specifier) => {
1064
+ throw new Error(`import.meta.resolve('${specifier}') is not supported`);
1065
+ };
1066
+ const ga = globalThis;
1067
+ const isRealNode = typeof ga.process?.pid === "number";
1068
+ const saved = {};
1069
+ if (!isRealNode) {
1070
+ saved.process = ga.process;
1071
+ ga.process = processObj;
1072
+ saved.Buffer = ga.Buffer;
1073
+ if (BufferClass) ga.Buffer = BufferClass;
1074
+ saved.console = ga.console;
1075
+ ga.console = scriptConsole;
1076
+ }
1077
+ const savedShims = {};
1078
+ if (this.globalShims) {
1079
+ for (const k of Object.keys(this.globalShims)) {
1080
+ savedShims[k] = ga[k];
1081
+ ga[k] = this.globalShims[k];
1082
+ }
1083
+ }
1084
+ let pendingRejection = null;
1085
+ const rejectionHandler = (event) => {
1086
+ pendingRejection = event.reason;
1087
+ event.preventDefault();
1088
+ const msg = event.reason instanceof Error ? event.reason.stack || event.reason.message : String(event.reason);
1089
+ const errMsg = `[unhandledRejection] ${msg}
1090
+ `;
1091
+ if (this.stderr) this.stderr.write(errMsg);
1092
+ else stderrLines.push(errMsg);
1093
+ };
1094
+ if (typeof globalThis.addEventListener === "function") {
1095
+ globalThis.addEventListener("unhandledrejection", rejectionHandler);
1096
+ }
336
1097
  try {
337
- const scriptDir = absPath.slice(0, absPath.lastIndexOf("/")) || "/";
338
- const require2 = createRequire(scriptDir);
339
- const factory = compileModule(source, absPath);
340
- const moduleExports = {};
341
- const moduleObj = { exports: moduleExports };
342
- const processObj = builtins.get("process");
343
- if (processObj) {
344
- const stdout = processObj.stdout;
345
- const stderr = processObj.stderr;
346
- if (stdout)
347
- stdout.write = (s) => {
348
- stdoutLines.push(String(s));
349
- return true;
350
- };
351
- if (stderr)
352
- stderr.write = (s) => {
353
- stderrLines.push(String(s));
354
- return true;
355
- };
356
- }
357
- factory(moduleObj.exports, require2, moduleObj, absPath, scriptDir, scriptConsole, builtins.get("process"));
358
- } catch (err) {
359
- if (err instanceof ProcessExitError) {
360
- exitCode = err.code;
1098
+ const fn = new Function("return " + wrapped)();
1099
+ const result = fn(
1100
+ moduleExports,
1101
+ require2,
1102
+ moduleObj,
1103
+ absPath,
1104
+ scriptDir,
1105
+ scriptConsole,
1106
+ processObj,
1107
+ BufferClass,
1108
+ globalThis.setTimeout,
1109
+ globalThis.setInterval,
1110
+ globalThis.clearTimeout,
1111
+ globalThis.clearInterval,
1112
+ global,
1113
+ mainImportMetaUrl,
1114
+ mainImportMeta,
1115
+ mainImportMetaResolve
1116
+ );
1117
+ if (isEsm && result && typeof result.then === "function") {
1118
+ await result;
1119
+ }
1120
+ if (pendingRejection) {
1121
+ if (pendingRejection instanceof ProcessExitError) {
1122
+ exitCode = pendingRejection.code;
1123
+ } else {
1124
+ exitCode = 1;
1125
+ }
1126
+ }
1127
+ } catch (e) {
1128
+ if (e instanceof ProcessExitError) {
1129
+ exitCode = e.code;
361
1130
  } else {
362
1131
  exitCode = 1;
363
- const message = err instanceof Error ? err.message : String(err);
364
- const stack = err instanceof Error && err.stack ? err.stack : "";
365
- stderrLines.push(stack || message);
1132
+ const msg = e instanceof Error ? e.stack || e.message : String(e);
1133
+ if (this.stderr) {
1134
+ this.stderr.write(msg + "\n");
1135
+ } else {
1136
+ stderrLines.push(msg);
1137
+ }
1138
+ }
1139
+ } finally {
1140
+ if (this.globalShims) {
1141
+ for (const k of Object.keys(savedShims)) ga[k] = savedShims[k];
1142
+ }
1143
+ if (!isRealNode) {
1144
+ ga.process = saved.process;
1145
+ ga.Buffer = saved.Buffer;
1146
+ ga.console = saved.console;
1147
+ }
1148
+ if (typeof globalThis.removeEventListener === "function") {
1149
+ globalThis.removeEventListener("unhandledrejection", rejectionHandler);
366
1150
  }
367
1151
  }
368
1152
  return {
369
1153
  exitCode,
370
- stdout: stdoutLines.join("\n"),
371
- stderr: stderrLines.join("\n")
1154
+ stdout: isStreaming ? "" : stdoutLines.join("\n"),
1155
+ stderr: isStreaming ? "" : stderrLines.join("\n")
372
1156
  };
373
1157
  }
374
1158
  };
375
- function compileModule(source, filename) {
376
- const wrapped = `(function(exports, require, module, __filename, __dirname, console, process) {
1159
+ function compileModule(source, filename, stderr) {
1160
+ const wrapped = `(function(exports, require, module, __filename, __dirname, console, process, Buffer, setTimeout, setInterval, clearTimeout, clearInterval, global, __importMetaUrl, __importMeta, __importMetaResolve) {
377
1161
  ${source}
378
1162
  })`;
379
1163
  try {
380
1164
  return (0, eval)(wrapped);
381
1165
  } catch (err) {
382
- throw new SyntaxError(
383
- `Failed to compile '${filename}': ${err instanceof Error ? err.message : String(err)}`
384
- );
1166
+ const errMsg = err instanceof Error ? err.message : String(err);
1167
+ const msg = `Failed to compile '${filename}': ${errMsg}`;
1168
+ if (stderr) {
1169
+ stderr.write(`[CJS-FAIL] file=${filename} srcLen=${source.length} err=${errMsg}
1170
+ `);
1171
+ const lines = source.split("\n");
1172
+ let lo = 0, hi = lines.length;
1173
+ while (hi - lo > 3) {
1174
+ const mid = lo + hi >>> 1;
1175
+ const partial = lines.slice(0, mid).join("\n");
1176
+ try {
1177
+ new Function(partial);
1178
+ lo = mid;
1179
+ } catch (e2) {
1180
+ if (e2 instanceof Error && e2.message === errMsg) hi = mid;
1181
+ else lo = mid;
1182
+ }
1183
+ }
1184
+ stderr.write(`[CJS-FAIL] error at L${lo}-${hi}, showing L${Math.max(1, lo - 25)} to L${hi + 3}:
1185
+ `);
1186
+ for (let li = Math.max(0, lo - 25); li < Math.min(lines.length, hi + 3); li++) {
1187
+ stderr.write(`[CJS-FAIL] ${li + 1 === lo || li + 1 === hi ? ">>>" : " "} L${li + 1}: ${lines[li]?.slice(0, 200)}
1188
+ `);
1189
+ }
1190
+ }
1191
+ throw new SyntaxError(msg);
385
1192
  }
386
1193
  }
387
1194
  export {
388
- NodeRunner
1195
+ NodeRunner,
1196
+ ProcessExitError,
1197
+ resolveModule,
1198
+ shouldTreatAsEsm,
1199
+ transformEsmToCjs,
1200
+ transformToCjs
389
1201
  };
390
1202
  //# sourceMappingURL=index.js.map