/**
 * Stack trace parser that transforms raw stack trace strings into structured frames.
 * Supports JavaScript/Node.js, Python, Java, Go, Ruby, C#/.NET, and PHP stack traces.
 */
// Known library/framework path patterns that indicate non-app code
const LIBRARY_PATTERNS = [
    // Node.js internals
    /^node:/,
    /^internal\//,
    /node_modules\//,
    /^events\.js$/,
    /^timers\.js$/,
    /^util\.js$/,
    /^net\.js$/,
    /^stream\.js$/,
    /^buffer\.js$/,
    // Python
    /\/site-packages\//,
    /\/dist-packages\//,
    /\/lib\/python\d+\.\d+\//,
    /\/usr\/lib\//,
    /\/usr\/local\/lib\//,
    /\/venv\//,
    /\/\.venv\//,
    /\/virtualenv\//,
    // Java
    /^java\./,
    /^javax\./,
    /^sun\./,
    /^com\.sun\./,
    /^org\.springframework\./,
    /^org\.apache\./,
    /^org\.hibernate\./,
    /^org\.eclipse\./,
    /^io\.netty\./,
    /^com\.google\./,
    /^org\.junit\./,
    // Go
    /^runtime\//,
    /^net\/http\//,
    /^testing\//,
    /\/vendor\//,
    /\/pkg\/mod\//,
    // Ruby
    /\/gems\//,
    /\/rubygems\//,
    /\/ruby\/\d+\.\d+\.\d+\//,
    // C#/.NET
    /^System\./,
    /^Microsoft\./,
    /^Newtonsoft\./,
    // PHP
    /\/vendor\//,
    /^phar:\/\//,
];
export default class StackTraceParser {
    /**
     * Parse a raw stack trace string into structured frames.
     * Auto-detects the language and applies the appropriate parser.
     */
    static parse(rawStackTrace) {
        if (!rawStackTrace || rawStackTrace.trim().length === 0) {
            return { frames: [], raw: rawStackTrace || "" };
        }
        const lines = rawStackTrace.split("\n").map((l) => {
            return l.trim();
        });
        // Try each parser and use the one that produces the most frames
        const parsers = [
            StackTraceParser.parseJavaScript,
            StackTraceParser.parsePython,
            StackTraceParser.parseJava,
            StackTraceParser.parseGo,
            StackTraceParser.parseRuby,
            StackTraceParser.parseCSharp,
            StackTraceParser.parsePHP,
        ];
        let bestFrames = [];
        for (const parser of parsers) {
            try {
                const frames = parser(lines);
                if (frames.length > bestFrames.length) {
                    bestFrames = frames;
                }
            }
            catch (_a) {
                // Skip failing parsers
            }
        }
        return {
            frames: bestFrames,
            raw: rawStackTrace,
        };
    }
    /**
     * Determine if a file path is application code (not library/framework).
     */
    static isAppCode(filePath) {
        if (!filePath) {
            return true;
        }
        for (const pattern of LIBRARY_PATTERNS) {
            if (pattern.test(filePath)) {
                return false;
            }
        }
        return true;
    }
    /**
     * Parse JavaScript/Node.js stack traces.
     * Format: `at functionName (filePath:line:col)` or `at filePath:line:col`
     */
    static parseJavaScript(lines) {
        const frames = [];
        // Pattern 1: at functionName (filePath:line:col)
        const patternWithParens = /^at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)$/;
        // Pattern 2: at filePath:line:col
        const patternWithoutParens = /^at\s+(.+?):(\d+):(\d+)$/;
        // Pattern 3: at functionName (filePath:line)
        const patternWithParensNoCol = /^at\s+(.+?)\s+\((.+?):(\d+)\)$/;
        // Pattern 4: at eval (eval at functionName (filePath:line:col))
        const patternEval = /^at\s+eval\s+\(eval\s+at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/;
        for (const line of lines) {
            let match = null;
            match = line.match(patternEval);
            if (match) {
                frames.push({
                    functionName: `eval at ${match[1]}`,
                    fileName: match[2],
                    lineNumber: parseInt(match[3], 10),
                    columnNumber: parseInt(match[4], 10),
                    inApp: StackTraceParser.isAppCode(match[2]),
                });
                continue;
            }
            match = line.match(patternWithParens);
            if (match) {
                frames.push({
                    functionName: match[1],
                    fileName: match[2],
                    lineNumber: parseInt(match[3], 10),
                    columnNumber: parseInt(match[4], 10),
                    inApp: StackTraceParser.isAppCode(match[2]),
                });
                continue;
            }
            match = line.match(patternWithParensNoCol);
            if (match) {
                frames.push({
                    functionName: match[1],
                    fileName: match[2],
                    lineNumber: parseInt(match[3], 10),
                    inApp: StackTraceParser.isAppCode(match[2]),
                });
                continue;
            }
            match = line.match(patternWithoutParens);
            if (match) {
                frames.push({
                    functionName: "<anonymous>",
                    fileName: match[1],
                    lineNumber: parseInt(match[2], 10),
                    columnNumber: parseInt(match[3], 10),
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
                continue;
            }
        }
        return frames;
    }
    /**
     * Parse Python stack traces.
     * Format: `File "path", line N, in function`
     */
    static parsePython(lines) {
        const frames = [];
        const pattern = /^File\s+"(.+?)",\s+line\s+(\d+)(?:,\s+in\s+(.+))?$/;
        for (const line of lines) {
            const match = line.match(pattern);
            if (match) {
                frames.push({
                    functionName: match[3] || "<module>",
                    fileName: match[1],
                    lineNumber: parseInt(match[2], 10),
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
            }
        }
        return frames;
    }
    /**
     * Parse Java stack traces.
     * Format: `at package.Class.method(File.java:line)`
     */
    static parseJava(lines) {
        const frames = [];
        // Pattern: at com.package.Class.method(File.java:123)
        const pattern = /^at\s+([\w.$]+)\(([\w.]+):(\d+)\)$/;
        // Pattern for native methods: at com.package.Class.method(Native Method)
        const patternNative = /^at\s+([\w.$]+)\(Native Method\)$/;
        // Pattern for unknown source: at com.package.Class.method(Unknown Source)
        const patternUnknown = /^at\s+([\w.$]+)\(Unknown Source\)$/;
        for (const line of lines) {
            let match = null;
            match = line.match(pattern);
            if (match) {
                const fullMethod = match[1];
                frames.push({
                    functionName: fullMethod,
                    fileName: match[2],
                    lineNumber: parseInt(match[3], 10),
                    inApp: StackTraceParser.isAppCode(fullMethod),
                });
                continue;
            }
            match = line.match(patternNative);
            if (match) {
                frames.push({
                    functionName: match[1],
                    fileName: "Native Method",
                    lineNumber: 0,
                    inApp: false,
                });
                continue;
            }
            match = line.match(patternUnknown);
            if (match) {
                frames.push({
                    functionName: match[1],
                    fileName: "Unknown Source",
                    lineNumber: 0,
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
                continue;
            }
        }
        return frames;
    }
    /**
     * Parse Go stack traces.
     * Format: `package/file.go:line +0xNN` or `goroutine N [reason]:`
     * Go stack traces have pairs of lines:
     *   functionName(args)
     *   /path/to/file.go:line +0xNN
     */
    static parseGo(lines) {
        const frames = [];
        const filePattern = /^(.+\.go):(\d+)\s*(?:\+0x[0-9a-f]+)?$/;
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            // Skip goroutine headers
            if (line.startsWith("goroutine ")) {
                continue;
            }
            // Look for file:line pattern
            const match = line.match(filePattern);
            if (match) {
                // The previous line should be the function name
                let functionName = "<unknown>";
                if (i > 0 && lines[i - 1]) {
                    // Remove arguments from function name
                    const funcLine = lines[i - 1];
                    const parenIndex = funcLine.indexOf("(");
                    functionName =
                        parenIndex > 0 ? funcLine.substring(0, parenIndex) : funcLine;
                }
                frames.push({
                    functionName: functionName,
                    fileName: match[1],
                    lineNumber: parseInt(match[2], 10),
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
            }
        }
        return frames;
    }
    /**
     * Parse Ruby stack traces.
     * Format: `file:line:in 'method'` or `file:line:in \`method'`
     */
    static parseRuby(lines) {
        const frames = [];
        const pattern = /^(.+?):(\d+):in\s+[`'](.+?)'$/;
        for (const line of lines) {
            const match = line.match(pattern);
            if (match) {
                frames.push({
                    functionName: match[3],
                    fileName: match[1],
                    lineNumber: parseInt(match[2], 10),
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
            }
        }
        return frames;
    }
    /**
     * Parse C#/.NET stack traces.
     * Format: `at Namespace.Class.Method(params) in file:line N`
     */
    static parseCSharp(lines) {
        const frames = [];
        // Pattern: at Namespace.Class.Method(params) in /path/to/file.cs:line 42
        const patternWithFile = /^at\s+(.+?)\s+in\s+(.+?):line\s+(\d+)$/;
        // Pattern: at Namespace.Class.Method(params)
        const patternWithoutFile = /^at\s+([\w.<>+]+\(.*?\))$/;
        for (const line of lines) {
            let match = null;
            match = line.match(patternWithFile);
            if (match) {
                frames.push({
                    functionName: match[1],
                    fileName: match[2],
                    lineNumber: parseInt(match[3], 10),
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
                continue;
            }
            match = line.match(patternWithoutFile);
            if (match) {
                frames.push({
                    functionName: match[1],
                    fileName: "",
                    lineNumber: 0,
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
                continue;
            }
        }
        return frames;
    }
    /**
     * Parse PHP stack traces.
     * Format: `#N /path/to/file.php(line): Class->method()`
     */
    static parsePHP(lines) {
        const frames = [];
        // Pattern: #0 /path/to/file.php(42): ClassName->method()
        const pattern = /^#\d+\s+(.+?)\((\d+)\):\s+(.+)$/;
        // Pattern: #0 {main}
        const patternMain = /^#\d+\s+\{main\}$/;
        for (const line of lines) {
            if (patternMain.test(line)) {
                frames.push({
                    functionName: "{main}",
                    fileName: "",
                    lineNumber: 0,
                    inApp: true,
                });
                continue;
            }
            const match = line.match(pattern);
            if (match) {
                frames.push({
                    functionName: match[3].replace(/\(\)$/, ""),
                    fileName: match[1],
                    lineNumber: parseInt(match[2], 10),
                    inApp: StackTraceParser.isAppCode(match[1]),
                });
            }
        }
        return frames;
    }
}
//# sourceMappingURL=StackTraceParser.js.map