import { join } from 'node:path';
import { pathExists } from "../../node-compat/fs.js";
import { run } from "../../node-compat/proc.js";
import { parse } from "../../tsc-output-parser.js";
import { formatTypeScriptErrors, hasErrors } from "../../typescript-errors.js";
/**
 * Filter tsc output to remove lines referencing node_modules paths.
 *
 * Some packages (e.g. @agentuity/runtime) ship .ts source files, which
 * --skipLibCheck does not skip. Errors from those paths can crash the
 * PEG-based tsc-output-parser because the parser expects every non-blank
 * line to be a valid tsc error item.  Stripping these lines before parsing
 * prevents the crash and avoids surfacing errors the user cannot fix.
 *
 * We also strip continuation lines (indented with 2+ leading spaces) that
 * follow a node_modules error line, as they are part of the same diagnostic.
 */
async function runTypeGeneration(dir, typegenCommand) {
    const commands = typeof typegenCommand === 'string' ? [typegenCommand] : (typegenCommand ?? []);
    if (commands.length === 0)
        return;
    const localBin = join(dir, 'node_modules', '.bin');
    const env = { PATH: `${localBin}:${process.env.PATH ?? ''}` };
    for (const command of commands) {
        await run({ cmd: ['sh', '-c', command], cwd: dir, env });
    }
}
function filterNodeModulesErrors(output) {
    const lines = output.split('\n');
    const filtered = [];
    let skipping = false;
    for (const line of lines) {
        // A tsc error line starts with a path, e.g. "node_modules/..." or "../node_modules/..."
        // Also handle Windows-style paths with backslashes
        const isNodeModulesError = /^\.{0,2}[/\\]?node_modules[/\\]/.test(line) ||
            /^[A-Za-z]:[/\\].*node_modules[/\\]/.test(line);
        if (isNodeModulesError) {
            skipping = true;
            continue;
        }
        // Continuation lines of a multi-line tsc diagnostic start with whitespace
        if (skipping && /^\s{2,}/.test(line)) {
            continue;
        }
        skipping = false;
        filtered.push(line);
    }
    return filtered.join('\n');
}
/**
 * run the typescript compiler and result formatted results
 *
 * @param dir the absolute path to the directory containing the project (must have tsconfig.json in this folder)
 * @param options optional configuration including error collector
 * @returns
 */
export async function typecheck(dir, options) {
    // Skip typecheck for projects without tsconfig.json (plain JS projects)
    const tsconfigPath = join(dir, 'tsconfig.json');
    if (!(await pathExists(tsconfigPath))) {
        return { success: true };
    }
    const { collector, typegenCommand } = options ?? {};
    await runTypeGeneration(dir, typegenCommand);
    const result = await run({
        cmd: ['bunx', 'tsc', '--noEmit', '--skipLibCheck', '--pretty', 'false'],
        cwd: dir,
    });
    const output = result.stdout;
    // Filter out node_modules errors before parsing to prevent parser crashes.
    // The PEG parser is strict and fails on lines it cannot match as tsc error items.
    const filteredOutput = filterNodeModulesErrors(output);
    let errors;
    try {
        errors = parse(filteredOutput);
    }
    catch {
        // If the parser still fails (e.g. unexpected tsc output format), treat as
        // an unknown error and show the raw output instead of crashing.
        if (collector) {
            collector.addGeneralError('typescript', output || result.stderr);
        }
        return {
            success: false,
            output: output || result.stderr,
        };
    }
    if (result.exitCode === 0) {
        return {
            success: true,
        };
    }
    else if (errors && hasErrors(errors)) {
        // Add errors to collector if provided
        if (collector) {
            collector.addTypeScriptErrors(errors);
        }
        const formattedErrors = await formatTypeScriptErrors(errors, {
            projectDir: dir,
        });
        return {
            success: false,
            errors,
            output: formattedErrors,
        };
    }
    else {
        // Unknown error - add to collector as general error
        if (collector) {
            collector.addGeneralError('typescript', output || result.stderr);
        }
        return {
            success: false,
            output: output || result.stderr,
        };
    }
}
//# sourceMappingURL=typecheck.js.map