"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.EslintChecker = void 0;
const chokidar_1 = __importDefault(require("chokidar"));
const eslint_1 = require("eslint");
// @ts-ignore
const options_1 = __importDefault(require("./options"));
const path_1 = __importDefault(require("path"));
const worker_threads_1 = require("worker_threads");
const Checker_1 = require("../../Checker");
const FileDiagnosticManager_1 = require("../../FileDiagnosticManager");
const logger_1 = require("../../logger");
const types_1 = require("../../types");
const cli_1 = require("./cli");
const manager = new FileDiagnosticManager_1.FileDiagnosticManager();
const createDiagnostic = (pluginConfig) => {
    let overlay = true;
    let terminal = true;
    return {
        config: ({ enableOverlay, enableTerminal }) => __awaiter(void 0, void 0, void 0, function* () {
            overlay = enableOverlay;
            terminal = enableTerminal;
        }),
        configureServer({ root }) {
            var _a;
            return __awaiter(this, void 0, void 0, function* () {
                if (!pluginConfig.eslint)
                    return;
                const options = options_1.default.parse(pluginConfig.eslint.lintCommand);
                const translatedOptions = (0, cli_1.translateOptions)(options);
                const logLevel = (() => {
                    var _a;
                    if (typeof pluginConfig.eslint !== 'object')
                        return undefined;
                    const userLogLevel = (_a = pluginConfig.eslint.dev) === null || _a === void 0 ? void 0 : _a.logLevel;
                    if (!userLogLevel)
                        return undefined;
                    const map = {
                        error: types_1.DiagnosticLevel.Error,
                        warning: types_1.DiagnosticLevel.Warning,
                    };
                    return userLogLevel.map((l) => map[l]);
                })();
                const eslint = new eslint_1.ESLint(Object.assign(Object.assign({ cwd: root }, translatedOptions), (_a = pluginConfig.eslint.dev) === null || _a === void 0 ? void 0 : _a.overrideConfig));
                const dispatchDiagnostics = () => {
                    const diagnostics = (0, logger_1.filterLogLevel)(manager.getDiagnostics(), logLevel);
                    if (terminal) {
                        diagnostics.forEach((d) => {
                            (0, logger_1.consoleLog)((0, logger_1.diagnosticToTerminalLog)(d, 'ESLint'));
                        });
                        const errorCount = diagnostics.filter((d) => d.level === types_1.DiagnosticLevel.Error).length;
                        const warningCount = diagnostics.filter((d) => d.level === types_1.DiagnosticLevel.Warning).length;
                        (0, logger_1.consoleLog)((0, logger_1.composeCheckerSummary)('ESLint', errorCount, warningCount));
                    }
                    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)('eslint', diagnostics.map((d) => (0, logger_1.diagnosticToRuntimeError)(d))),
                        });
                    }
                };
                const handleFileChange = (filePath, type) => __awaiter(this, void 0, void 0, function* () {
                    const absPath = path_1.default.resolve(root, filePath);
                    if (type === 'unlink') {
                        manager.updateByFileId(absPath, []);
                    }
                    else if (type === 'change') {
                        const diagnosticsOfChangedFile = yield eslint.lintFiles(filePath);
                        const newDiagnostics = diagnosticsOfChangedFile
                            .map((d) => (0, logger_1.normalizeEslintDiagnostic)(d))
                            .flat(1);
                        manager.updateByFileId(absPath, newDiagnostics);
                    }
                    dispatchDiagnostics();
                });
                // initial lint
                const files = options._.slice(1);
                const diagnostics = yield eslint.lintFiles(files);
                manager.initWith(diagnostics.map((p) => (0, logger_1.normalizeEslintDiagnostic)(p)).flat(1));
                dispatchDiagnostics();
                // watch lint
                const watcher = chokidar_1.default.watch([], {
                    cwd: root,
                    ignored: (path) => path.includes('node_modules'),
                });
                watcher.add(files);
                watcher.on('change', (filePath) => __awaiter(this, void 0, void 0, function* () {
                    handleFileChange(filePath, 'change');
                }));
                watcher.on('unlink', (filePath) => __awaiter(this, void 0, void 0, function* () {
                    handleFileChange(filePath, 'unlink');
                }));
            });
        },
    };
};
class EslintChecker extends Checker_1.Checker {
    constructor() {
        super({
            name: 'eslint',
            absFilePath: __filename,
            build: {
                buildBin: (pluginConfig) => {
                    if (pluginConfig.eslint) {
                        const { lintCommand } = pluginConfig.eslint;
                        return ['eslint', lintCommand.split(' ').slice(1)];
                    }
                    return ['eslint', ['']];
                },
            },
            createDiagnostic,
        });
    }
    init() {
        const createServeAndBuild = super.initMainThread();
        module.exports.createServeAndBuild = createServeAndBuild;
        super.initWorkerThread();
    }
}
exports.EslintChecker = EslintChecker;
const eslintChecker = new EslintChecker();
eslintChecker.prepare();
eslintChecker.init();
