| ... | @@ -45,12 +45,24 @@ export interface Frame { | ... | @@ -45,12 +45,24 @@ export interface Frame { |
| 45 | * https://github.com/oven-sh/bun/blob/b5f31a6ee2f52ea67eabeb61f6e6e71215d55b26/src/bake/client/stack-trace.ts | 45 | * https://github.com/oven-sh/bun/blob/b5f31a6ee2f52ea67eabeb61f6e6e71215d55b26/src/bake/client/stack-trace.ts |
| 46 | * https://github.com/stacktracejs/error-stack-parser/blob/9f33c224b5d7b607755eb277f9d51fcdb7287e24/error-stack-parser.js | 46 | * https://github.com/stacktracejs/error-stack-parser/blob/9f33c224b5d7b607755eb277f9d51fcdb7287e24/error-stack-parser.js |
| 47 | */ | 47 | */ |
| 48 | export function parse(error: Error): Frame[] | null { | 48 | /** |
| 49 | const stack = error?.stack; | 49 | * supports parsing v8, JavaScriptCore, SpiderMonkey, and IE error stack |
| | 50 | * frames, effectively working in every JavaScript environment. |
| | 51 | */ |
| | 52 | export function parse(error: Error | string): Frame[] | null { |
| | 53 | const stack = (error as Error)?.stack ?? error; |
| 50 | if (typeof stack !== "string") return null; | 54 | if (typeof stack !== "string") return null; |
| 51 | return stack.match(regexV8Stack) ? parseV8OrIe(stack) : parseJscOrSpidermonkey(stack); | 55 | return stack.match(regexV8Stack) ? parseV8OrIe(stack) : parseJscOrSpidermonkey(stack); |
| 52 | } | 56 | } |
| 53 | | 57 | |
| | 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 | */ |
| | 62 | export function capture(trimStart = 2): Frame[] { |
| | 63 | return parse(new Error())?.slice(trimStart) ?? []; |
| | 64 | } |
| | 65 | |
| 54 | /** | 66 | /** |
| 55 | * convert an error into a human readable and debuggable string. | 67 | * convert an error into a human readable and debuggable string. |
| 56 | * | 68 | * |
| ... | @@ -64,7 +76,7 @@ export function parse(error: Error): Frame[] | null { | ... | @@ -64,7 +76,7 @@ export function parse(error: Error): Frame[] | null { |
| 64 | * | 76 | * |
| 65 | * to make understanding runtime code easier, `node:*` and `ext:deno` paths are | 77 | * to make understanding runtime code easier, `node:*` and `ext:deno` paths are |
| 66 | * resolved into GitHub source code URLs, and node builtins will also display | 78 | * 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")`). |
| 68 | * | 80 | * |
| 69 | * with zero external imports, it is safely included as a default error | 81 | * with zero external imports, it is safely included as a default error |
| 70 | * formatter. it is used not only in `lib/log.ts`, but also in the headless | 82 | * formatter. it is used not only in `lib/log.ts`, but also in the headless |
| ... | @@ -396,6 +408,7 @@ function extractLocation(urlLike: string) { | ... | @@ -396,6 +408,7 @@ function extractLocation(urlLike: string) { |
| 396 | return [parts[1], parts[2] || undefined, parts[3] || undefined]; | 408 | return [parts[1], parts[2] || undefined, parts[3] || undefined]; |
| 397 | } | 409 | } |
| 398 | | 410 | |
| | 411 | // TODO: extract |
| 399 | function nodeBuiltin(name: "node:path"): typeof import("node:path") | null; | 412 | function nodeBuiltin(name: "node:path"): typeof import("node:path") | null; |
| 400 | function nodeBuiltin(name: "node:fs"): typeof import("node:fs") | null; | 413 | function nodeBuiltin(name: "node:fs"): typeof import("node:fs") | null; |
| 401 | function nodeBuiltin(name: string) { | 414 | function nodeBuiltin(name: string) { |