authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2025-09-30 00:20:13-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2025-10-14 02:40:48-07:00
logb490ba62dedb3b43b9ee832e8c3630d017557b69
treeabbc3a54b22245ad627f4c98c8f930de2dd03847
parent9365f5f867b8b7f4c55d03ee1dec7151f3b987ce
signature Commit is signed but in an unrecognized format.

lib(log/stack): add `capture` function


2 files changed, 19 insertions(+), 5 deletions(-)

framework/incremental.ts+3-2
......@@ -38,7 +38,7 @@ export function work<I, O>(
3838 job: Job<I, O>,
3939 input?: I,
4040): Ref<O> {
41 const source = JSON.stringify(UNWRAP(util.getCallSites(2)[1]));
41 const source = JSON.stringify(UNWRAP(stack.capture()[0]));
4242 const keySource = [source, util.inspect(input)].join(":");
4343 const key = crypto.createHash("sha1").update(keySource).digest("base64url");
4444 ASSERT(running);
......@@ -734,7 +734,8 @@ import * as util from "node:util";
734734import * as crypto from "node:crypto";
735735import * as zlib from "node:zlib";
736736
737import * as progress from "../lib/log/progress.ts";
737import * as progress from "lib/log/progress.ts";
738import * as stack from "lib/log/stack.ts";
738739import { formatSize } from "@/file-viewer/format.ts";
739740
740741import * as msgpackr from "msgpackr";
lib/log/stack.ts+16-3
......@@ -45,12 +45,24 @@ export interface Frame {
4545 * https://github.com/oven-sh/bun/blob/b5f31a6ee2f52ea67eabeb61f6e6e71215d55b26/src/bake/client/stack-trace.ts
4646 * https://github.com/stacktracejs/error-stack-parser/blob/9f33c224b5d7b607755eb277f9d51fcdb7287e24/error-stack-parser.js
4747 */
48export function parse(error: Error): Frame[] | null {
49 const stack = error?.stack;
48/**
49 * supports parsing v8, JavaScriptCore, SpiderMonkey, and IE error stack
50 * frames, effectively working in every JavaScript environment.
51 */
52export function parse(error: Error | string): Frame[] | null {
53 const stack = (error as Error)?.stack ?? error;
5054 if (typeof stack !== "string") return null;
5155 return stack.match(regexV8Stack) ? parseV8OrIe(stack) : parseJscOrSpidermonkey(stack);
5256}
5357
58/**
59 * capture and store for later, or use to trace the caller. with the
60 * default `trimStart` of `2`, the caller file is `capture()[0]?.file`.
61 */
62export function capture(trimStart = 2): Frame[] {
63 return parse(new Error())?.slice(trimStart) ?? [];
64}
65
5466/**
5567 * convert an error into a human readable and debuggable string.
5668 *
......@@ -64,7 +76,7 @@ export function parse(error: Error): Frame[] | null {
6476 *
6577 * to make understanding runtime code easier, `node:*` and `ext:deno` paths are
6678 * resolved into GitHub source code URLs, and node builtins will also display
67 * their source code inline (via `process.binding("natives")`).
79 * their source code inline (via `node:fs` and `process.binding("natives")`).
6880 *
6981 * with zero external imports, it is safely included as a default error
7082 * formatter. it is used not only in `lib/log.ts`, but also in the headless
......@@ -396,6 +408,7 @@ function extractLocation(urlLike: string) {
396408 return [parts[1], parts[2] || undefined, parts[3] || undefined];
397409}
398410
411// TODO: extract
399412function nodeBuiltin(name: "node:path"): typeof import("node:path") | null;
400413function nodeBuiltin(name: "node:fs"): typeof import("node:fs") | null;
401414function nodeBuiltin(name: string) {