"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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const babelCore = require('@babel/core');
const vscode = require("vscode");
const path = require("path");
const Config_1 = require("./Config");
const IntlStorage_1 = require("./IntlStorage");
const index_1 = require("../utils/index");
const Service_1 = require("./Service");
const index_2 = require("../plugins/webview/index");
const index_3 = require("../plugins/hover-menu-command/index");
const index_4 = require("../plugins/config-menu-command/index");
const WebView_1 = require("./WebView");
const ParserManager_1 = require("./ParserManager");
const no_cache_require_1 = require("../utils/no-cache-require");
const tapable_1 = require("tapable");
class Parser extends Service_1.default {
    constructor(filepath) {
        super();
        this.errorCount = 0;
        this._prevDecorations = [];
        this.utils = index_1.default;
        this.plugins = []; // 可以传入对象，也可以传入数组
        this.decorations = {};
        this.diagnostics = [];
        this.errorsMap = {};
        this.errors = [];
        this.isComplete = true;
        this.parserCatch = (err) => {
            vscode.window.showWarningMessage(err.toString());
            this.isComplete = true;
        };
        this.parserManager = ParserManager_1.default.getSingleInstance();
        this.webview = new WebView_1.default(this);
        this.filepath = filepath;
        this.config = new Config_1.default(this, filepath);
        this.intlStorage = new IntlStorage_1.default(this.config);
    }
    handlePlugins() {
        return __awaiter(this, void 0, void 0, function* () {
            for (var i = 0; i < this.plugins.length; i++) {
                const plugin = this.plugins[i];
                // @ts-ignore todo
                if (!plugin.length) {
                    yield plugin.apply(this);
                }
                else {
                    const [PluginClassPath, option] = plugin;
                    if (!path.isAbsolute(PluginClassPath)) {
                        throw (new Error('请提供插件的绝对路径'));
                    }
                    else {
                        const PluginClass = no_cache_require_1.default(PluginClassPath).default;
                        const pluginInstance = new PluginClass(option);
                        yield pluginInstance.apply(this);
                    }
                }
            }
        });
    }
    initHooks() {
        this.babelHooks = {
            babelPresetHook: new tapable_1.SyncWaterfallHook(['presets']),
            babelPluginHook: new tapable_1.SyncWaterfallHook(['plugins']),
        };
        this.webViewHooks = {
            htmlHook: new tapable_1.AsyncSeriesWaterfallHook(['html']),
            titleHook: new tapable_1.AsyncSeriesWaterfallHook(['title']),
            headHook: new tapable_1.AsyncSeriesWaterfallHook(['headers']),
            metaHook: new tapable_1.AsyncSeriesWaterfallHook(['metas']),
            jsHook: new tapable_1.AsyncSeriesWaterfallHook(['jss']),
            btnHook: new tapable_1.AsyncSeriesWaterfallHook(['btns']),
            cssHook: new tapable_1.AsyncSeriesWaterfallHook(['csss']),
            bodyHtmlHook: new tapable_1.AsyncSeriesWaterfallHook(['body']),
            bodyFooterJsHook: new tapable_1.AsyncSeriesWaterfallHook(['footerJss']),
            bodyHeaderJsHook: new tapable_1.AsyncSeriesWaterfallHook(['headerJss']),
            listenerHook: new tapable_1.AsyncSeriesWaterfallHook(['listeners']),
            sendLangInfoHook: new tapable_1.AsyncSeriesWaterfallHook(['params', 'nodeInfo', 'parser']),
            vueHooks: {
                createdHook: new tapable_1.AsyncSeriesWaterfallHook(['createdInits']),
                methodsHook: new tapable_1.AsyncSeriesWaterfallHook(['methods']),
            }
        };
        this.updateHook = new tapable_1.AsyncSeriesWaterfallHook(['updateQueues']);
        this.processListenerHook = new tapable_1.HookMap((type) => new tapable_1.AsyncParallelHook(["params"]));
    }
    addDiagnostic(message, range) {
        this.diagnostics.push(new vscode.Diagnostic(new vscode.Range(new vscode.Position(range.startRow - 1, range.startCol), new vscode.Position(range.endRow - 1, range.endCol)), message, vscode.DiagnosticSeverity.Warning));
    }
    addDecoration(color, range) {
        if (!this.decorations[color]) {
            this.decorations[color] = [];
        }
        this.decorations[color].push(range);
    }
    pushError(errorNode) {
        // 重复的ErrorNode 不添加
        if (this.errors.find((item) => {
            return item.id === errorNode.id;
        })) {
            return;
        }
        const key = `${errorNode.start}-${errorNode.end}`;
        if (!this.errorsMap[key]) {
            this.errorsMap[key] = errorNode;
            this.errors.push(errorNode);
        }
    }
    parse() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.isComplete)
                return Promise.reject();
            this.isComplete = false;
            try {
                this.resetDataForConfig(); // 重置缓存对象
                yield this.config.init();
                yield this.intlStorage.initLang();
                yield this.handlePlugins();
                yield this.babelParser();
                this.isComplete = true;
                return this;
            }
            catch (err) {
                this.isComplete = true;
                vscode.window.showWarningMessage(`解析失败 - ${this.filepath}: ` + (err.stack || err.message || (err ? err.toString() : '')));
                return Promise.reject();
            }
        });
    }
    resetDataForConfig() {
        this.errors = [];
        this.diagnostics = [];
        this.plugins = [
            new index_4.default(),
            new index_3.default(),
            new index_2.default(),
        ];
        this.decorations = {};
        this._prevDecorations.forEach(decoration => {
            var _a;
            (_a = index_1.default.getActiveEditor()) === null || _a === void 0 ? void 0 : _a.setDecorations(decoration, []);
        });
        this._prevDecorations = [];
        this.errorsMap = {};
        this.initHooks();
    }
    logErrors(isClear = false) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            if (isClear) {
                yield index_1.default.diagnostic.clear();
            }
            this.errorCount = 0;
            (_a = this.errors) === null || _a === void 0 ? void 0 : _a.forEach((error) => {
                error.logError();
                if (!error.isRight) {
                    this.errorCount++;
                }
            });
            const uri = vscode.Uri.file(this.filepath);
            yield index_1.default.diagnostic.set(uri, this.diagnostics);
        });
    }
    putColors() {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            this.errorCount = 0;
            (_a = this.errors) === null || _a === void 0 ? void 0 : _a.forEach((error) => {
                error.putColor();
                if (!error.isRight) {
                    this.errorCount++;
                }
            });
            Object.keys(this.decorations).forEach((decorationType) => {
                var _a;
                const decoration = vscode.window.createTextEditorDecorationType({
                    color: decorationType
                });
                this._prevDecorations.push(decoration);
                (_a = index_1.default.getActiveEditor()) === null || _a === void 0 ? void 0 : _a.setDecorations(decoration, this.decorations[decorationType]);
            });
        });
    }
    babelParser() {
        return new Promise((resolve, rejects) => {
            babelCore.transformFile(this.filepath, {
                presets: this.babelHooks.babelPresetHook.call([]),
                plugins: this.babelHooks.babelPluginHook.call([])
            }, (err) => {
                if (err) {
                    this.isComplete = true;
                    rejects(err);
                }
                else {
                    resolve(err);
                }
            });
        });
    }
}
exports.default = Parser;
//# sourceMappingURL=Parser.js.map