"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createServerPlugin = void 0;
const vue = require("@vue/language-service");
const vue2 = require("@vue/language-core");
const nameCasing = require("@vue/language-service");
const protocol_1 = require("./protocol");
const componentMeta = require("vue-component-meta");
const typescript_1 = require("@volar/typescript");
function createServerPlugin(connection) {
    const plugin = (initOptions, modules) => {
        if (!modules.typescript) {
            console.warn('No typescript found, vue-language-server will not work.');
            return {};
        }
        const ts = modules.typescript;
        const vueFileExtensions = ['vue'];
        const hostToVueOptions = new WeakMap();
        if (initOptions.additionalExtensions) {
            for (const additionalExtension of initOptions.additionalExtensions) {
                vueFileExtensions.push(additionalExtension);
            }
        }
        return {
            extraFileExtensions: vueFileExtensions.map(ext => ({ extension: ext, isMixedContent: true, scriptKind: ts.ScriptKind.Deferred })),
            watchFileExtensions: ['js', 'cjs', 'mjs', 'ts', 'cts', 'mts', 'jsx', 'tsx', 'json', ...vueFileExtensions],
            async resolveConfig(config, ctx) {
                const vueOptions = await getVueCompilerOptions();
                const vueLanguageServiceSettings = getVueLanguageServiceSettings();
                if (ctx) {
                    hostToVueOptions.set(ctx.host, vue.resolveVueCompilerOptions(vueOptions));
                }
                return vue.resolveConfig(config, ctx?.host.getCompilationSettings() ?? {}, vueOptions, ts, vueLanguageServiceSettings, initOptions.codegenStack);
                async function getVueCompilerOptions() {
                    const ts = modules.typescript;
                    let vueOptions = {};
                    if (ts && ctx) {
                        const sys = (0, typescript_1.createSys)(ts, ctx.env);
                        let sysVersion;
                        let newSysVersion = await sys.sync();
                        while (sysVersion !== newSysVersion) {
                            sysVersion = newSysVersion;
                            if (typeof ctx?.project.tsConfig === 'string' && ts) {
                                vueOptions = vue2.createParsedCommandLine(ts, sys, ctx.project.tsConfig).vueOptions;
                            }
                            else if (typeof ctx?.project.tsConfig === 'object' && ts) {
                                vueOptions = vue2.createParsedCommandLineByJson(ts, sys, ctx.host.getCurrentDirectory(), ctx.project.tsConfig).vueOptions;
                            }
                            newSysVersion = await sys.sync();
                        }
                    }
                    vueOptions.extensions = [
                        ...vueOptions.extensions ?? ['.vue'],
                        ...vueFileExtensions.map(ext => '.' + ext),
                    ];
                    vueOptions.extensions = [...new Set(vueOptions.extensions)];
                    return vueOptions;
                }
                function getVueLanguageServiceSettings() {
                    const settings = {};
                    if (initOptions.json && ctx) {
                        settings.json = { schemas: [] };
                        for (const blockType in initOptions.json.customBlockSchemaUrls) {
                            const url = initOptions.json.customBlockSchemaUrls[blockType];
                            settings.json.schemas?.push({
                                fileMatch: [`*.customBlock_${blockType}_*.json*`],
                                uri: new URL(url, ctx.project.rootUri.toString() + '/').toString(),
                            });
                        }
                    }
                    return settings;
                }
            },
            onInitialized(getService, env) {
                connection.onRequest(protocol_1.ParseSFCRequest.type, params => {
                    return vue2.parse(params);
                });
                connection.onRequest(protocol_1.DetectNameCasingRequest.type, async (params) => {
                    const languageService = await getService(params.textDocument.uri);
                    if (languageService) {
                        return nameCasing.detect(ts, languageService.context, params.textDocument.uri, hostToVueOptions.get(languageService.context.rawHost));
                    }
                });
                connection.onRequest(protocol_1.GetConvertTagCasingEditsRequest.type, async (params) => {
                    const languageService = await getService(params.textDocument.uri);
                    if (languageService) {
                        return nameCasing.convertTagName(ts, languageService.context, params.textDocument.uri, params.casing, hostToVueOptions.get(languageService.context.rawHost));
                    }
                });
                connection.onRequest(protocol_1.GetConvertAttrCasingEditsRequest.type, async (params) => {
                    const languageService = await getService(params.textDocument.uri);
                    if (languageService) {
                        const vueOptions = hostToVueOptions.get(languageService.context.host);
                        if (vueOptions) {
                            return nameCasing.convertAttrName(ts, languageService.context, params.textDocument.uri, params.casing, hostToVueOptions.get(languageService.context.rawHost));
                        }
                    }
                });
                const checkers = new WeakMap();
                connection.onRequest(protocol_1.GetComponentMeta.type, async (params) => {
                    const languageService = await getService(params.uri);
                    if (!languageService)
                        return;
                    const host = languageService.context.rawHost;
                    let checker = checkers.get(host);
                    if (!checker) {
                        checker = componentMeta.baseCreate(host, hostToVueOptions.get(host), {}, host.getCurrentDirectory() + '/tsconfig.json.global.vue', ts);
                        checkers.set(host, checker);
                    }
                    return checker.getComponentMeta(env.uriToFileName(params.uri));
                });
            },
        };
    };
    return plugin;
}
exports.createServerPlugin = createServerPlugin;
//# sourceMappingURL=languageServerPlugin.js.map