From b490ba62dedb3b43b9ee832e8c3630d017557b69 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Tue, 30 Sep 2025 00:20:13 -0700 Subject: [PATCH] lib(log/stack): add `capture` function --- framework/incremental.ts | 5 +++-- lib/log/stack.ts | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/framework/incremental.ts b/framework/incremental.ts index 3b5b56c5509ca87bf29e61c6d80316759ca47692..c7f91df9e857cc3a899c4b6a14d1f1657bf21f63 100644 --- a/framework/incremental.ts +++ b/framework/incremental.ts @@ -38,7 +38,7 @@ export function work( job: Job, input?: I, ): Ref { - const source = JSON.stringify(UNWRAP(util.getCallSites(2)[1])); + const source = JSON.stringify(UNWRAP(stack.capture()[0])); const keySource = [source, util.inspect(input)].join(":"); const key = crypto.createHash("sha1").update(keySource).digest("base64url"); ASSERT(running); @@ -734,7 +734,8 @@ import * as util from "node:util"; import * as crypto from "node:crypto"; import * as zlib from "node:zlib"; -import * as progress from "../lib/log/progress.ts"; +import * as progress from "lib/log/progress.ts"; +import * as stack from "lib/log/stack.ts"; import { formatSize } from "@/file-viewer/format.ts"; import * as msgpackr from "msgpackr"; diff --git a/lib/log/stack.ts b/lib/log/stack.ts index ee06d44535a1da236924875a02da8efbacb12bc8..dc9ab5b42cfcd7e266ce63d4bdd5e6e6b5ed4a89 100644 --- a/lib/log/stack.ts +++ b/lib/log/stack.ts @@ -45,12 +45,24 @@ export interface Frame { * https://github.com/oven-sh/bun/blob/b5f31a6ee2f52ea67eabeb61f6e6e71215d55b26/src/bake/client/stack-trace.ts * https://github.com/stacktracejs/error-stack-parser/blob/9f33c224b5d7b607755eb277f9d51fcdb7287e24/error-stack-parser.js */ -export function parse(error: Error): Frame[] | null { - const stack = error?.stack; +/** + * supports parsing v8, JavaScriptCore, SpiderMonkey, and IE error stack + * frames, effectively working in every JavaScript environment. + */ +export function parse(error: Error | string): Frame[] | null { + const stack = (error as Error)?.stack ?? error; if (typeof stack !== "string") return null; return stack.match(regexV8Stack) ? parseV8OrIe(stack) : parseJscOrSpidermonkey(stack); } +/** + * capture and store for later, or use to trace the caller. with the + * default `trimStart` of `2`, the caller file is `capture()[0]?.file`. + */ +export function capture(trimStart = 2): Frame[] { + return parse(new Error())?.slice(trimStart) ?? []; +} + /** * convert an error into a human readable and debuggable string. * @@ -64,7 +76,7 @@ export function parse(error: Error): Frame[] | null { * * to make understanding runtime code easier, `node:*` and `ext:deno` paths are * resolved into GitHub source code URLs, and node builtins will also display - * their source code inline (via `process.binding("natives")`). + * their source code inline (via `node:fs` and `process.binding("natives")`). * * with zero external imports, it is safely included as a default error * formatter. it is used not only in `lib/log.ts`, but also in the headless @@ -396,6 +408,7 @@ function extractLocation(urlLike: string) { return [parts[1], parts[2] || undefined, parts[3] || undefined]; } +// TODO: extract function nodeBuiltin(name: "node:path"): typeof import("node:path") | null; function nodeBuiltin(name: "node:fs"): typeof import("node:fs") | null; function nodeBuiltin(name: string) { -- 2.54.0