/* * Copyright 2025 the original author or authors. *

* Licensed under the Moderne Source Available License (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* https://docs.moderne.io/licensing/moderne-source-available-license *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import {readFileSync} from "fs"; import {AsyncLocalStorage} from "node:async_hooks"; const stackStorage = new AsyncLocalStorage(); export function saveTrace(enabled: boolean, action: () => Promise): Promise { if (enabled) { const entryStack = new Error().stack ?? ''; return stackStorage.run(entryStack, action); } return action(); } /** * Inspect the call stack to find the nearest Receiver/Sender subclass * and log the source line that invoked receive. */ export function trace(type: "Receiver" | "Sender"): string | undefined { const stack = stackStorage.getStore()?.split("\n") ?? []; for (const frame of stack.slice(1)) { const match = frame.match(/at\s+(.*?)\s+\((.*):(\d+):(\d+)\)/); if (match) { const [, fn, file, line] = match; const className = fn.includes('.') ? fn.split('.')[0] : fn; if (className.endsWith(type)) { try { const codeLine = readFileSync(file, 'utf-8') .split('\n')[parseInt(line, 10) - 1] .trim(); return `${className}:${line}:depth(${stack.length}) => ${codeLine}`; } catch { // ignore if reading the source file fails } break; } } } return undefined; }