"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TscChecker = void 0;
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
const typescript_1 = __importDefault(require("typescript"));
const worker_threads_1 = require("worker_threads");
const Checker_1 = require("../../Checker");
const logger_1 = require("../../logger");
const types_1 = require("../../types");
const createDiagnostic = (pluginConfig) => {
    let overlay = true;
    let terminal = true;
    let currDiagnostics = [];
    return {
        config: ({ enableOverlay, enableTerminal }) => __awaiter(void 0, void 0, void 0, function* () {
            overlay = enableOverlay;
            terminal = enableTerminal;
        }),
        configureServer({ root }) {
            var _a, _b;
            (0, tiny_invariant_1.default)(pluginConfig.typescript, 'config.typescript should be `false`');
            const finalConfig = pluginConfig.typescript === true
                ? { root, tsconfigPath: 'tsconfig.json' }
                : {
                    root: (_a = pluginConfig.typescript.root) !== null && _a !== void 0 ? _a : root,
                    tsconfigPath: (_b = pluginConfig.typescript.tsconfigPath) !== null && _b !== void 0 ? _b : 'tsconfig.json',
                };
            let configFile;
            configFile = typescript_1.default.findConfigFile(finalConfig.root, typescript_1.default.sys.fileExists, finalConfig.tsconfigPath);
            if (configFile === undefined) {
                throw Error(`Failed to find a valid tsconfig.json: ${finalConfig.tsconfigPath} at ${finalConfig.root} is not a valid tsconfig`);
            }
            let logChunk = '';
            // https://github.com/microsoft/TypeScript/blob/a545ab1ac2cb24ff3b1aaf0bfbfb62c499742ac2/src/compiler/watch.ts#L12-L28
            const reportDiagnostic = (diagnostic) => {
                const normalizedDiagnostic = (0, logger_1.normalizeTsDiagnostic)(diagnostic);
                if (normalizedDiagnostic === null) {
                    return;
                }
                currDiagnostics.push((0, logger_1.diagnosticToRuntimeError)(normalizedDiagnostic));
                logChunk += os_1.default.EOL + (0, logger_1.diagnosticToTerminalLog)(normalizedDiagnostic, 'TypeScript');
            };
            const reportWatchStatusChanged = (diagnostic, newLine, options, errorCount
            // eslint-disable-next-line max-params
            ) => {
                if (diagnostic.code === 6031)
                    return;
                // https://github.com/microsoft/TypeScript/issues/32542
                // https://github.com/microsoft/TypeScript/blob/dc237b317ed4bbccd043ddda802ffde00362a387/src/compiler/diagnosticMessages.json#L4086-L4088
                switch (diagnostic.code) {
                    case 6031:
                    case 6032:
                        // clear current error and use the newer errors
                        logChunk = '';
                        // currErr = null
                        currDiagnostics = [];
                        return;
                    case 6193: // 1 Error
                    case 6194: // 0 errors or 2+ errors
                        if (overlay) {
                            worker_threads_1.parentPort === null || worker_threads_1.parentPort === void 0 ? void 0 : worker_threads_1.parentPort.postMessage({
                                type: types_1.ACTION_TYPES.overlayError,
                                payload: (0, logger_1.toViteCustomPayload)('typescript', currDiagnostics),
                            });
                        }
                }
                (0, logger_1.ensureCall)(() => {
                    if (errorCount === 0) {
                        logChunk = '';
                    }
                    if (terminal) {
                        (0, logger_1.consoleLog)(logChunk +
                            os_1.default.EOL +
                            (0, logger_1.wrapCheckerSummary)('TypeScript', diagnostic.messageText.toString()));
                    }
                });
            };
            // https://github.com/microsoft/TypeScript/issues/32385
            // https://github.com/microsoft/TypeScript/pull/33082/files
            const createProgram = typescript_1.default.createEmitAndSemanticDiagnosticsBuilderProgram;
            if (typeof pluginConfig.typescript === 'object' && pluginConfig.typescript.buildMode) {
                const host = typescript_1.default.createSolutionBuilderWithWatchHost(typescript_1.default.sys, createProgram, reportDiagnostic, undefined, reportWatchStatusChanged);
                typescript_1.default.createSolutionBuilderWithWatch(host, [configFile], {}).build();
            }
            else {
                const host = typescript_1.default.createWatchCompilerHost(configFile, { noEmit: true }, typescript_1.default.sys, createProgram, reportDiagnostic, reportWatchStatusChanged);
                typescript_1.default.createWatchProgram(host);
            }
        },
    };
};
class TscChecker extends Checker_1.Checker {
    constructor() {
        super({
            name: 'typescript',
            absFilePath: __filename,
            build: {
                buildBin: (config) => {
                    if (typeof config.typescript === 'object') {
                        const { root, tsconfigPath, buildMode } = config.typescript;
                        // Compiler option '--noEmit' may not be used with '--build'
                        let args = [buildMode ? '-b' : '--noEmit'];
                        // Custom config path
                        if (tsconfigPath) {
                            const fullConfigPath = root ? path_1.default.join(root, tsconfigPath) : tsconfigPath;
                            args = args.concat(['-p', fullConfigPath]);
                        }
                        return ['tsc', args];
                    }
                    return ['tsc', ['--noEmit']];
                },
            },
            createDiagnostic,
        });
    }
    init() {
        const createServeAndBuild = super.initMainThread();
        module.exports.createServeAndBuild = createServeAndBuild;
        super.initWorkerThread();
    }
}
exports.TscChecker = TscChecker;
const tscChecker = new TscChecker();
tscChecker.prepare();
tscChecker.init();
