// Source-mapped exception handling for code running in Play.
//
// This is a similar implementation to the one in Compute's bootstrap image, but
// using the @gunsch/source-map fork that added synchronous handling and browser
// support.
import { SourceMapConsumer } from '@gunsch/source-map';
import sourceMapWasm from '@gunsch/source-map/lib/mappings.wasm';
SourceMapConsumer.initialize({ 'lib/mappings.wasm': sourceMapWasm.buffer });
export function sourceMapExceptionHandler(sourceMap, err) {
    const error = err instanceof Error ? err : undefined;
    if (error?.stack && sourceMap) {
        const consumer = new SourceMapConsumer(sourceMap);
        const adjustedError = new Error(error.message);
        adjustedError.stack = parseStack(error.stack, consumer);
        // Wipe the stack since it's redundant, but still attach the original
        // error as cause in case it's an interesting subclass / has other
        // interesting properties to include.
        error.stack = '';
        adjustedError.cause = error;
        consumer.destroy();
        console.error(adjustedError);
        throw adjustedError;
    }
    throw err;
}
const DEBUG = false;
function parseStack(stack, consumer) {
    const stackLines = stack.split('\n');
    if (DEBUG)
        console.log(stackLines);
    return stackLines
        .map((line) => {
        // Matches the following different kinds of stack lines:
        //   at someFunction (at eval:12345:15) (at source.ts:129874:12)',
        //   at someFunction (source.ts:129874:12)',
        //   at Object.type (pen.js:2:6598)',
        //   at v.lde [as RenderPost] (pen.js:2:6651)',
        //   at new (../devvit-test/node_modules/@devvit/public-api/devvit/Devvit.js:389:46)',
        //   at /Users/andrew.gunsch/src/gunsch-sourcemaps/test6-runner.js:24:5',
        const regex = 
        // eslint-disable-next-line security/detect-unsafe-regex
        /at\s?(?<identifier>.*?(?:\s\[.*?\])?)\s+\(?(?<nonsense>.*?):(?<lineNum>\d+):(?<columnNum>\d+)\)?$/;
        const match = line.match(regex);
        if (DEBUG)
            console.log(match);
        if (match) {
            const { identifier, lineNum, columnNum } = match.groups ?? {};
            const originalPos = consumer.originalPositionFor({
                line: parseInt(lineNum, 10),
                column: parseInt(columnNum, 10),
            });
            if (DEBUG)
                console.log('matching ', [lineNum, columnNum], ' to ', originalPos);
            if (originalPos.source) {
                return `    at ${identifier || '<unknown>'} (${originalPos.source}:${originalPos.line}:${originalPos.column})`;
            }
        }
        return line;
    })
        .join('\n');
}
export const exportedForTesting = {
    parseStack,
};
