@tlockney/cdp-kernel 0.4.0 → 0.5.0
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/README.md +60 -481
- package/THIRD-PARTY-NOTICES +62 -0
- package/dist/bun-target.d.ts +2 -2
- package/dist/bun-target.js +30 -8
- package/dist/cdp.d.ts +6 -1
- package/dist/cdp.js +25 -10
- package/dist/celld-target.d.ts +1 -1
- package/dist/celld-target.js +46 -8
- package/dist/children.d.ts +7 -0
- package/dist/children.js +32 -0
- package/dist/debugger.d.ts +1 -1
- package/dist/debugger.js +21 -10
- package/dist/globals.d.ts +3 -3
- package/dist/globals.js +3 -3
- package/dist/kernel.js +163 -41
- package/dist/mod.d.ts +5 -3
- package/dist/mod.js +5 -3
- package/dist/package.d.ts +2 -2
- package/dist/package.js +3 -3
- package/dist/target.d.ts +31 -3
- package/dist/target.js +233 -32
- package/dist/text.d.ts +5 -1
- package/dist/text.js +55 -2
- package/dist/transform.d.ts +9 -0
- package/dist/transform.js +37 -9
- package/dist/wire.d.ts +8 -1
- package/dist/wire.js +3 -1
- package/dist/workerd-target.d.ts +7 -1
- package/dist/workerd-target.js +102 -8
- package/dist/ws-client.d.ts +5 -1
- package/dist/ws-client.js +46 -13
- package/dist/zmtp.d.ts +7 -1
- package/dist/zmtp.js +30 -1
- package/package.json +9 -3
- package/runtime/bootstrap.mjs +121 -10
- package/runtime/bun-channel.d.mts +3 -0
- package/runtime/bun-channel.mjs +2 -2
- package/runtime/comm.mjs +11 -1
- package/runtime/deno-compat.d.mts +2 -0
- package/runtime/deno-compat.mjs +14 -1
- package/runtime/display.mjs +8 -1
- package/runtime/node-hooks.d.mts +42 -0
- package/runtime/node-hooks.mjs +246 -41
- package/runtime/workerd-worker.mjs +77 -6
package/runtime/bootstrap.mjs
CHANGED
|
@@ -55,7 +55,12 @@ function barrier(gated = false) {
|
|
|
55
55
|
function send(payload) {
|
|
56
56
|
const binding = globalThis.__cdpk_send;
|
|
57
57
|
if (typeof binding !== "function") return; // host not attached yet
|
|
58
|
-
|
|
58
|
+
// Serialize before writing the marker: if the payload can't be
|
|
59
|
+
// serialized (a BigInt, a cycle), the error reaches the cell without a
|
|
60
|
+
// gated marker the host would wait on forever (#129). `payload` always
|
|
61
|
+
// has a `kind`, so `body` is never "{}".
|
|
62
|
+
const body = JSON.stringify(payload);
|
|
63
|
+
binding(`{"barrier":${barrier(true)},${body.slice(1)}`);
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
const jupyter = createJupyter({
|
|
@@ -72,6 +77,13 @@ const jupyter = createJupyter({
|
|
|
72
77
|
const line = readStdinLine();
|
|
73
78
|
if (line === null) return null;
|
|
74
79
|
const reply = JSON.parse(line);
|
|
80
|
+
if (reply.interrupted === true) {
|
|
81
|
+
// Interrupted while waiting for the answer: unwind the cell, as
|
|
82
|
+
// KeyboardInterrupt does in Python's input() (#121).
|
|
83
|
+
const err = new Error("Execution interrupted");
|
|
84
|
+
err.name = "Interrupted";
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
75
87
|
return typeof reply.value === "string" ? reply.value : null;
|
|
76
88
|
},
|
|
77
89
|
});
|
|
@@ -131,6 +143,24 @@ function bunResolve(specifier) {
|
|
|
131
143
|
return Bun.resolveSync(specifier, cwd);
|
|
132
144
|
}
|
|
133
145
|
|
|
146
|
+
// The inspector holds a promise it awaits (callFunctionOn with awaitPromise)
|
|
147
|
+
// only weakly until its then-callback runs, so a GC after the promise
|
|
148
|
+
// settles but before that callback fails the call with "Promise was
|
|
149
|
+
// collected" (#55). hold() keeps the promise until a macrotask after it
|
|
150
|
+
// settles, by which time the inspector's callback has run.
|
|
151
|
+
const held = new Set();
|
|
152
|
+
function hold(value) {
|
|
153
|
+
const promise = Promise.resolve(value);
|
|
154
|
+
held.add(promise);
|
|
155
|
+
const release = () => setTimeout(() => held.delete(promise), 0);
|
|
156
|
+
promise.then(release, release);
|
|
157
|
+
return promise;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Adds the cause to an error from a Deno member the --deno-compat shim
|
|
161
|
+
// lacks (#172); the identity everywhere else.
|
|
162
|
+
let explainError = (text) => text;
|
|
163
|
+
|
|
134
164
|
globalThis.__cdpk = {
|
|
135
165
|
// Cell code awaits this first; see PRELUDE in src/transform.ts.
|
|
136
166
|
tick: () => new Promise((resolve) => setTimeout(resolve, 0)),
|
|
@@ -149,6 +179,7 @@ globalThis.__cdpk = {
|
|
|
149
179
|
resolve: (specifier) => new URL(specifier, replUrl).href,
|
|
150
180
|
},
|
|
151
181
|
barrier,
|
|
182
|
+
hold,
|
|
152
183
|
// inspect_request (#10). CDP targets find the value with
|
|
153
184
|
// throwOnSideEffect and describe it here; Bun resolves the path here
|
|
154
185
|
// too, by descriptor, so nothing runs.
|
|
@@ -171,7 +202,9 @@ globalThis.__cdpk = {
|
|
|
171
202
|
},
|
|
172
203
|
describeError(value) {
|
|
173
204
|
if (value instanceof Error) {
|
|
174
|
-
|
|
205
|
+
const message = explainError(value.message);
|
|
206
|
+
const stack = stackOf(value).replace(value.message, () => message);
|
|
207
|
+
return JSON.stringify({ name: value.name, message, stack });
|
|
175
208
|
}
|
|
176
209
|
return JSON.stringify({ name: "Error", message: inspect(value), stack: "" });
|
|
177
210
|
},
|
|
@@ -184,26 +217,48 @@ globalThis.confirm = jupyter.confirm;
|
|
|
184
217
|
if (isDeno) {
|
|
185
218
|
// Existing Deno notebooks use Deno.jupyter, but outside `deno jupyter`
|
|
186
219
|
// that is a non-configurable getter that throws. The global binding
|
|
187
|
-
// itself is configurable, so swap in
|
|
188
|
-
//
|
|
220
|
+
// itself is configurable, so swap in an object with its own `jupyter`
|
|
221
|
+
// that inherits everything else from the real namespace. Not a Proxy:
|
|
222
|
+
// completion can't list a Proxy's properties, and Shift-Tab's
|
|
223
|
+
// side-effect-free evaluation can't read through one (#132). So
|
|
224
|
+
// Object.keys(Deno) and console.log(Deno) show only `jupyter`, and
|
|
225
|
+
// Deno's functions are called with `this` set to this object (they
|
|
226
|
+
// don't use it).
|
|
189
227
|
const real = globalThis.Deno;
|
|
190
228
|
const descriptor = Object.getOwnPropertyDescriptor(globalThis, "Deno");
|
|
191
|
-
const
|
|
192
|
-
|
|
229
|
+
const shim = Object.create(real, {
|
|
230
|
+
jupyter: { value: jupyter.namespace, enumerable: true, configurable: true, writable: true },
|
|
193
231
|
});
|
|
194
|
-
Object.defineProperty(globalThis, "Deno", { ...descriptor, value:
|
|
232
|
+
Object.defineProperty(globalThis, "Deno", { ...descriptor, value: shim });
|
|
195
233
|
} else if (process.env.CDPK_DENO_COMPAT === "1" && globalThis.Deno === undefined) {
|
|
196
234
|
// Opt-in (install --deno-compat): a Deno namespace for notebooks written
|
|
197
235
|
// against `deno jupyter`. See runtime/deno-compat.mjs for the trade-off.
|
|
198
236
|
// Absolute URL: the resolve hook re-parents this module's relative
|
|
199
237
|
// imports to the notebook directory.
|
|
200
|
-
const { createDenoShim } = await import(new URL("./deno-compat.mjs", import.meta.url).href);
|
|
201
|
-
|
|
238
|
+
const { createDenoShim, explainMissing } = await import(new URL("./deno-compat.mjs", import.meta.url).href);
|
|
239
|
+
const shim = createDenoShim({ jupyter: jupyter.namespace });
|
|
240
|
+
globalThis.Deno = shim;
|
|
241
|
+
explainError = (text) => explainMissing(text, shim);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* An error's stack, with its first line naming the error. Bun now and then
|
|
246
|
+
* (about one throw in twenty, #216) records a stack whose first line is a
|
|
247
|
+
* bare "Error", though name and message are set; the frames are right, so
|
|
248
|
+
* only the header is rebuilt.
|
|
249
|
+
*/
|
|
250
|
+
function stackOf(err) {
|
|
251
|
+
const stack = err.stack;
|
|
252
|
+
if (typeof stack !== "string") return "";
|
|
253
|
+
const nl = stack.indexOf("\n");
|
|
254
|
+
const first = nl === -1 ? stack : stack.slice(0, nl);
|
|
255
|
+
if (first !== "Error" || !err.message) return stack;
|
|
256
|
+
return `${err.name}: ${err.message}${nl === -1 ? "" : stack.slice(nl)}`;
|
|
202
257
|
}
|
|
203
258
|
|
|
204
259
|
// An error thrown later by a cell's timer or promise must not kill the kernel.
|
|
205
260
|
function reportUncaught(kind, err) {
|
|
206
|
-
writeErr(`${kind}: ${err instanceof Error ? (err
|
|
261
|
+
writeErr(`${kind}: ${explainError(err instanceof Error ? (stackOf(err) || err.message) : inspect(err))}\n`);
|
|
207
262
|
}
|
|
208
263
|
if (isDeno) {
|
|
209
264
|
globalThis.addEventListener("unhandledrejection", (e) => {
|
|
@@ -222,6 +277,29 @@ if (isDeno) {
|
|
|
222
277
|
// Keep the event loop alive between cells.
|
|
223
278
|
setInterval(() => {}, 1 << 30);
|
|
224
279
|
|
|
280
|
+
// A host killed by SIGKILL can't stop its runtime, and nothing visible to
|
|
281
|
+
// JS here changes when its inspector sessions drop, so watch for the host
|
|
282
|
+
// itself going: reparented, or no longer there (#219). Bun exits on its
|
|
283
|
+
// channel's EOF instead.
|
|
284
|
+
if (!isBun) {
|
|
285
|
+
// Held here, so a cell that reassigns them can't break the watch.
|
|
286
|
+
const proc = process;
|
|
287
|
+
const exit = process.exit.bind(process);
|
|
288
|
+
const host = proc.ppid;
|
|
289
|
+
const hostGone = () => {
|
|
290
|
+
if (proc.ppid !== host) return true;
|
|
291
|
+
try {
|
|
292
|
+
proc.kill(host, 0);
|
|
293
|
+
return false;
|
|
294
|
+
} catch (err) {
|
|
295
|
+
return err?.code === "ESRCH";
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
setInterval(() => {
|
|
299
|
+
if (hostGone()) exit(1);
|
|
300
|
+
}, 2000);
|
|
301
|
+
}
|
|
302
|
+
|
|
225
303
|
if (isBun) {
|
|
226
304
|
const { startChannel } = await import("./bun-channel.mjs");
|
|
227
305
|
const { createHandler } = await import("./evaluator.mjs");
|
|
@@ -245,6 +323,14 @@ async function platform() {
|
|
|
245
323
|
const util = await import("node:util");
|
|
246
324
|
const fs = await import("node:fs");
|
|
247
325
|
const buf = Buffer.alloc(1);
|
|
326
|
+
// Node writes to a pipe without blocking and queues what doesn't fit for
|
|
327
|
+
// the event loop to flush. input() blocks the main thread in readSync, so
|
|
328
|
+
// queued output, and the input_request's barrier marker after it, would
|
|
329
|
+
// never reach the host (#131). Blocking writes finish before readSync
|
|
330
|
+
// starts, as Node already does on Windows. Bun has no _handle and needs
|
|
331
|
+
// its own fix (#180).
|
|
332
|
+
if (isBun) await syncBunOutput();
|
|
333
|
+
else for (const stream of [process.stdout, process.stderr]) stream._handle?.setBlocking?.(true);
|
|
248
334
|
return {
|
|
249
335
|
inspect: (v) => util.inspect(v, { colors: true, depth: 4 }),
|
|
250
336
|
inspectPlain: (v) => util.inspect(v, { colors: false, depth: 2 }),
|
|
@@ -265,6 +351,31 @@ async function platform() {
|
|
|
265
351
|
};
|
|
266
352
|
}
|
|
267
353
|
|
|
354
|
+
// Bun makes stdout and stderr non-blocking once process.stdout or
|
|
355
|
+
// process.stderr exists, and then queues what doesn't fit in the pipe for
|
|
356
|
+
// its event loop, console.log's output included. input() blocks the main
|
|
357
|
+
// thread in readSync, so queued output, and the input_request's barrier
|
|
358
|
+
// marker after it, would never reach the host (#180). Here every write
|
|
359
|
+
// finishes before it returns: process.stdout.write and process.stderr.write
|
|
360
|
+
// write through, and console is Node's Console over them, so console output
|
|
361
|
+
// is formatted as on Node.
|
|
362
|
+
async function syncBunOutput() {
|
|
363
|
+
const { writeAll } = await import("./bun-channel.mjs");
|
|
364
|
+
const { Console } = await import("node:console");
|
|
365
|
+
for (const [stream, fd] of [[process.stdout, 1], [process.stderr, 2]]) {
|
|
366
|
+
stream.write = (chunk, encoding, callback) => {
|
|
367
|
+
if (typeof encoding === "function") [callback, encoding] = [encoding, undefined];
|
|
368
|
+
writeAll(fd, typeof chunk === "string" ? Buffer.from(chunk, encoding) : chunk);
|
|
369
|
+
if (callback) process.nextTick(callback);
|
|
370
|
+
return true;
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
const sync = new Console({ stdout: process.stdout, stderr: process.stderr, colorMode: true });
|
|
374
|
+
for (const key of Object.keys(console)) {
|
|
375
|
+
if (typeof sync[key] === "function") console[key] = sync[key].bind(sync);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
268
379
|
function readLine(nextByte) {
|
|
269
380
|
const bytes = [];
|
|
270
381
|
for (;;) {
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import type { Handler } from "./evaluator.mjs";
|
|
2
2
|
|
|
3
3
|
export function startChannel(handle: Handler, ready: { [key: string]: unknown }, fd?: number): void;
|
|
4
|
+
|
|
5
|
+
/** Writes all of `text` to `fd` before returning, even if the fd is non-blocking. */
|
|
6
|
+
export function writeAll(fd: number, text: string | Uint8Array): void;
|
package/runtime/bun-channel.mjs
CHANGED
|
@@ -14,8 +14,8 @@ import fs from "node:fs";
|
|
|
14
14
|
const CHANNEL_FD = 3;
|
|
15
15
|
|
|
16
16
|
/** Synchronous, like a CDP binding call, so output order is kept. */
|
|
17
|
-
function writeAll(fd, text) {
|
|
18
|
-
const bytes = Buffer.from(text);
|
|
17
|
+
export function writeAll(fd, text) {
|
|
18
|
+
const bytes = typeof text === "string" ? Buffer.from(text) : Buffer.from(text.buffer, text.byteOffset, text.byteLength);
|
|
19
19
|
for (let offset = 0; offset < bytes.length;) {
|
|
20
20
|
try {
|
|
21
21
|
offset += fs.writeSync(fd, bytes, offset);
|
package/runtime/comm.mjs
CHANGED
|
@@ -89,7 +89,17 @@ export function createComms(send, newId = () => crypto.randomUUID()) {
|
|
|
89
89
|
if (msgType === "comm_open") {
|
|
90
90
|
const handler = targets.get(content.target_name);
|
|
91
91
|
if (!handler) return false;
|
|
92
|
-
|
|
92
|
+
const comm = track(content.comm_id, content.target_name);
|
|
93
|
+
try {
|
|
94
|
+
await handler(comm, msg);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
// The host answers a failed comm_open with comm_close, so the comm
|
|
97
|
+
// is gone on the frontend: drop it here too, without running close
|
|
98
|
+
// handlers or sending anything (#137).
|
|
99
|
+
comm.closed = true;
|
|
100
|
+
forget(comm.id);
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
93
103
|
return true;
|
|
94
104
|
}
|
|
95
105
|
const comm = comms.get(content.comm_id);
|
|
@@ -114,3 +114,5 @@ export interface DenoShim {
|
|
|
114
114
|
|
|
115
115
|
export function denoError<E>(err: E): E | NotFound | AlreadyExists | PermissionDenied | IsADirectory | NotADirectory;
|
|
116
116
|
export function createDenoShim(options: { jupyter: unknown }): DenoShim;
|
|
117
|
+
/** Adds the cause to "Deno.x is not a function" when `shim` lacks `x`. */
|
|
118
|
+
export function explainMissing(message: string, shim: object): string;
|
package/runtime/deno-compat.mjs
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
// shim installed they take their Deno code paths, which may call APIs not
|
|
8
8
|
// covered here (Deno.serve, Deno.Command, Deno.openKv, permissions...).
|
|
9
9
|
// Uncovered APIs are simply absent rather than throwing on access, so
|
|
10
|
-
// feature checks like `typeof Deno.serve === "function"` still work.
|
|
10
|
+
// feature checks like `typeof Deno.serve === "function"` still work. The
|
|
11
|
+
// error from calling one says so instead (explainMissing, #172).
|
|
11
12
|
|
|
12
13
|
import fs from "node:fs";
|
|
13
14
|
import fsp from "node:fs/promises";
|
|
@@ -100,6 +101,18 @@ const writeFlag = (options) => (options?.append ? "a" : options?.createNew ? "wx
|
|
|
100
101
|
const OS_NAMES = { darwin: "darwin", linux: "linux", win32: "windows", freebsd: "freebsd" };
|
|
101
102
|
const ARCH_NAMES = { arm64: "aarch64", x64: "x86_64" };
|
|
102
103
|
|
|
104
|
+
const MEMBERS_DOC = "https://cdp-kernel.org/docs/jupyter-api#notebooks-written-for-deno";
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Adds the cause to V8's "Deno.serve is not a function" when `shim` lacks
|
|
108
|
+
* that member (#172), or returns `message` unchanged.
|
|
109
|
+
*/
|
|
110
|
+
export function explainMissing(message, shim) {
|
|
111
|
+
return message.replace(/\b(Deno\.([\w$]+)) is not a (?:function|constructor)\b/, (all, expr, name) =>
|
|
112
|
+
name in shim ? all : `${all}: ${expr} is not implemented by cdp-kernel's --deno-compat namespace (see ${MEMBERS_DOC})`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
103
116
|
export function createDenoShim({ jupyter }) {
|
|
104
117
|
return {
|
|
105
118
|
jupyter,
|
package/runtime/display.mjs
CHANGED
|
@@ -180,7 +180,14 @@ export function createJupyter(host) {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
function image(obj) {
|
|
183
|
-
if (typeof obj === "string")
|
|
183
|
+
if (typeof obj === "string") {
|
|
184
|
+
// As Deno does: a path that can't be read gets the TypeError below.
|
|
185
|
+
try {
|
|
186
|
+
obj = host.readFile(obj);
|
|
187
|
+
} catch {
|
|
188
|
+
// fall through
|
|
189
|
+
}
|
|
190
|
+
}
|
|
184
191
|
if (isJpg(obj)) return { [$display]: () => ({ "image/jpeg": host.base64(obj) }) };
|
|
185
192
|
if (isPng(obj)) return { [$display]: () => ({ "image/png": host.base64(obj) }) };
|
|
186
193
|
throw new TypeError(
|
package/runtime/node-hooks.d.mts
CHANGED
|
@@ -8,12 +8,24 @@ export function parsePackageSpecifier(spec: string): PackageSpecifier;
|
|
|
8
8
|
export function jsrToNpm(spec: string): PackageSpecifier;
|
|
9
9
|
export function aliasFor(name: string, range: string): string;
|
|
10
10
|
export type Installer = "npm" | "bun";
|
|
11
|
+
/** Where `installer` keeps its packages: $XDG_CACHE_HOME/cdp-kernel/<installer>, or CDPK_CACHE_DIR for npm. */
|
|
12
|
+
export function cacheDirPath(
|
|
13
|
+
installer: Installer,
|
|
14
|
+
env?: { [name: string]: string | undefined },
|
|
15
|
+
home?: string,
|
|
16
|
+
): string;
|
|
11
17
|
export function installCommand(
|
|
12
18
|
installer: Installer,
|
|
13
19
|
alias: string,
|
|
14
20
|
name: string,
|
|
15
21
|
range: string,
|
|
16
22
|
): { cmd: string; args: string[]; env?: { [name: string]: string } };
|
|
23
|
+
/** How to spawn an install command; on Windows, npm runs through cmd.exe. */
|
|
24
|
+
export function spawnCommand(
|
|
25
|
+
cmd: string,
|
|
26
|
+
args: string[],
|
|
27
|
+
platform?: string,
|
|
28
|
+
): { cmd: string; args: string[]; shell: boolean };
|
|
17
29
|
/** Runs an install; `env` is added to the process environment. */
|
|
18
30
|
export type InstallRunner = (
|
|
19
31
|
cmd: string,
|
|
@@ -26,6 +38,15 @@ export function ensureInstalled(
|
|
|
26
38
|
installer?: Installer,
|
|
27
39
|
options?: { lockFile?: string | null; run?: InstallRunner },
|
|
28
40
|
): { dir: string; alias: string };
|
|
41
|
+
/** ensureInstalled without blocking the event loop; `run` may return a promise. */
|
|
42
|
+
export function ensureInstalledAsync(
|
|
43
|
+
pkg: { name: string; range: string },
|
|
44
|
+
installer?: Installer,
|
|
45
|
+
options?: {
|
|
46
|
+
lockFile?: string | null;
|
|
47
|
+
run?: (...args: Parameters<InstallRunner>) => ReturnType<InstallRunner> | Promise<ReturnType<InstallRunner>>;
|
|
48
|
+
},
|
|
49
|
+
): Promise<{ dir: string; alias: string }>;
|
|
29
50
|
|
|
30
51
|
export const LOCK_FILE: string;
|
|
31
52
|
export interface Lock {
|
|
@@ -36,4 +57,25 @@ export function findLockFile(dir: string): string | null;
|
|
|
36
57
|
export function readLock(path: string): Lock;
|
|
37
58
|
export function writeLock(path: string, lock: Lock): void;
|
|
38
59
|
export function withInstallLock<T>(dir: string, fn: () => T, options?: { timeoutMs?: number }): T;
|
|
60
|
+
export function withInstallLockAsync<T>(dir: string, fn: () => T | Promise<T>, options?: { timeoutMs?: number }): Promise<T>;
|
|
61
|
+
/** Compiles one TypeScript or JSX file with the esbuild binary at `binary`; `run` is replaceable in tests. */
|
|
62
|
+
export function compileTypeScript(
|
|
63
|
+
source: string,
|
|
64
|
+
filename: string,
|
|
65
|
+
binary: string,
|
|
66
|
+
run?: (cmd: string, args: string[], options: object) => { status: number | null; stdout: string; stderr: string; error?: Error },
|
|
67
|
+
loader?: "ts" | "tsx" | "jsx",
|
|
68
|
+
): string;
|
|
69
|
+
export interface LoadResult {
|
|
70
|
+
format?: string | null;
|
|
71
|
+
source?: string | ArrayBuffer | ArrayBufferView | null;
|
|
72
|
+
shortCircuit?: boolean;
|
|
73
|
+
}
|
|
74
|
+
/** The load hook: Node's own result unless its type stripping would reject the file; .tsx/.jsx always compiled. */
|
|
75
|
+
export function loadTypeScript(
|
|
76
|
+
url: string,
|
|
77
|
+
context: object,
|
|
78
|
+
nextLoad: (url: string, context: object) => LoadResult,
|
|
79
|
+
binary: string | undefined,
|
|
80
|
+
): LoadResult;
|
|
39
81
|
export function installNodeResolveHooks(urls: { shimUrl: string; replUrl: string }): void;
|