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