@lifo-sh/node-runner 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +951 -134
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -6
- package/dist/index.d.ts +83 -6
- package/dist/index.js +946 -134
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/runner.ts
|
|
2
|
-
import {
|
|
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
|
|
56
|
-
|
|
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.
|
|
61
|
-
error: (...args) => stderr.
|
|
62
|
-
warn: (...args) => stderr.
|
|
63
|
-
info: (...args) => stdout.
|
|
64
|
-
debug: (...args) => stdout.
|
|
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: (
|
|
93
|
+
write: (s) => {
|
|
94
|
+
if (stdout) stdout.write(String(s));
|
|
83
95
|
return true;
|
|
84
96
|
}
|
|
85
97
|
},
|
|
86
98
|
stderr: {
|
|
87
|
-
write: (
|
|
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
|
-
|
|
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
|
-
|
|
130
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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,
|
|
164
|
+
const fromIndex = tryIndexFile(vfs, absPath);
|
|
138
165
|
if (fromIndex) return fromIndex;
|
|
139
|
-
continue;
|
|
140
166
|
}
|
|
141
|
-
|
|
142
|
-
|
|
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
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
|
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.
|
|
176
|
-
const raw = textDecoder.decode(vfs.
|
|
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.
|
|
189
|
-
const source = textDecoder.decode(vfs.
|
|
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 ??
|
|
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.
|
|
818
|
+
this.vfs.mkdir(dir);
|
|
233
819
|
} catch {
|
|
234
820
|
}
|
|
235
821
|
}
|
|
236
|
-
this.vfs.
|
|
822
|
+
this.vfs.writeFile(filePath, textEncoder.encode(content));
|
|
237
823
|
}
|
|
238
824
|
}
|
|
239
|
-
/** Write files to the VFS asynchronously (
|
|
825
|
+
/** Write files to the VFS asynchronously (for IndexedDB-backed VFS) */
|
|
240
826
|
async writeFiles(files) {
|
|
241
|
-
|
|
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:
|
|
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 =
|
|
282
|
-
const
|
|
283
|
-
|
|
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
|
-
|
|
288
|
-
this.
|
|
897
|
+
this.stdout,
|
|
898
|
+
this.stderr
|
|
289
899
|
);
|
|
290
|
-
const
|
|
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
|
|
293
|
-
|
|
294
|
-
const
|
|
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
|
|
307
|
-
const
|
|
308
|
-
moduleCache.set(resolved.path,
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
|
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
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (
|
|
360
|
-
|
|
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
|
|
364
|
-
|
|
365
|
-
|
|
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
|
-
|
|
383
|
-
|
|
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
|