"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startServer = startServer;
const simpleProject_1 = require("@volar/language-server/lib/project/simpleProject");
const node_1 = require("@volar/language-server/node");
const language_core_1 = require("@vue/language-core");
const language_service_1 = require("@vue/language-service");
const vscode_uri_1 = require("vscode-uri");
function startServer(ts) {
    const connection = (0, node_1.createConnection)();
    const server = (0, node_1.createServer)(connection);
    const tsserverRequestHandlers = new Map();
    let tsserverRequestId = 0;
    connection.listen();
    connection.onNotification('tsserver/response', ([id, res]) => {
        tsserverRequestHandlers.get(id)?.(res);
        tsserverRequestHandlers.delete(id);
    });
    connection.onInitialize(params => {
        const tsconfigProjects = (0, language_service_1.createUriMap)();
        const file2ProjectInfo = new Map();
        server.fileWatcher.onDidChangeWatchedFiles(({ changes }) => {
            for (const change of changes) {
                const changeUri = vscode_uri_1.URI.parse(change.uri);
                if (tsconfigProjects.has(changeUri)) {
                    tsconfigProjects.get(changeUri).dispose();
                    tsconfigProjects.delete(changeUri);
                    file2ProjectInfo.clear();
                }
            }
        });
        let simpleLanguageService;
        const result = server.initialize(params, {
            setup() { },
            async getLanguageService(uri) {
                if (uri.scheme === 'file') {
                    const fileName = uri.fsPath.replace(/\\/g, '/');
                    let projectInfoPromise = file2ProjectInfo.get(fileName);
                    if (!projectInfoPromise) {
                        projectInfoPromise = sendTsServerRequest('_vue:' + ts.server.protocol.CommandTypes.ProjectInfo, {
                            file: fileName,
                            needFileNameList: false,
                        });
                        file2ProjectInfo.set(fileName, projectInfoPromise);
                    }
                    const projectInfo = await projectInfoPromise;
                    if (projectInfo) {
                        const { configFileName } = projectInfo;
                        let languageService = tsconfigProjects.get(vscode_uri_1.URI.file(configFileName));
                        if (!languageService) {
                            languageService = createProjectLanguageService(server, configFileName);
                            tsconfigProjects.set(vscode_uri_1.URI.file(configFileName), languageService);
                        }
                        return languageService;
                    }
                }
                return simpleLanguageService ??= createProjectLanguageService(server, undefined);
            },
            getExistingLanguageServices() {
                const projects = [...tsconfigProjects.values()];
                if (simpleLanguageService) {
                    projects.push(simpleLanguageService);
                }
                return projects;
            },
            reload() {
                for (const languageService of tsconfigProjects.values()) {
                    languageService.dispose();
                }
                tsconfigProjects.clear();
                if (simpleLanguageService) {
                    simpleLanguageService.dispose();
                    simpleLanguageService = undefined;
                }
            },
        }, (0, language_service_1.createVueLanguageServicePlugins)(ts, {
            collectExtractProps(...args) {
                return sendTsServerRequest('_vue:collectExtractProps', args);
            },
            getComponentDirectives(...args) {
                return sendTsServerRequest('_vue:getComponentDirectives', args);
            },
            getComponentMeta(...args) {
                return sendTsServerRequest('_vue:getComponentMeta', args);
            },
            getComponentNames(...args) {
                return sendTsServerRequest('_vue:getComponentNames', args);
            },
            getComponentProps(...args) {
                return sendTsServerRequest('_vue:getComponentProps', args);
            },
            getComponentSlots(...args) {
                return sendTsServerRequest('_vue:getComponentSlots', args);
            },
            getElementAttrs(...args) {
                return sendTsServerRequest('_vue:getElementAttrs', args);
            },
            getElementNames(...args) {
                return sendTsServerRequest('_vue:getElementNames', args);
            },
            getImportPathForFile(...args) {
                return sendTsServerRequest('_vue:getImportPathForFile', args);
            },
            getAutoImportSuggestions(...args) {
                return sendTsServerRequest('_vue:getAutoImportSuggestions', args);
            },
            resolveAutoImportCompletionEntry(...args) {
                return sendTsServerRequest('_vue:resolveAutoImportCompletionEntry', args);
            },
            isRefAtPosition(...args) {
                return sendTsServerRequest('_vue:isRefAtPosition', args);
            },
            resolveModuleName(...args) {
                return sendTsServerRequest('_vue:resolveModuleName', args);
            },
            getDocumentHighlights(fileName, position) {
                return sendTsServerRequest('_vue:documentHighlights-full', {
                    file: fileName,
                    ...{ position },
                    filesToSearch: [fileName],
                });
            },
            getEncodedSemanticClassifications(fileName, span) {
                return sendTsServerRequest('_vue:encodedSemanticClassifications-full', {
                    file: fileName,
                    ...span,
                    format: ts.SemanticClassificationFormat.TwentyTwenty,
                });
            },
            async getQuickInfoAtPosition(fileName, { line, character }) {
                const result = await sendTsServerRequest('_vue:' + ts.server.protocol.CommandTypes.Quickinfo, {
                    file: fileName,
                    line: line + 1,
                    offset: character + 1,
                });
                return result?.displayString;
            },
        }));
        const packageJson = require('../package.json');
        result.serverInfo = {
            name: packageJson.name,
            version: packageJson.version,
        };
        return result;
        async function sendTsServerRequest(command, args) {
            return await new Promise(resolve => {
                const requestId = ++tsserverRequestId;
                tsserverRequestHandlers.set(requestId, resolve);
                connection.sendNotification('tsserver/request', [requestId, command, args]);
            });
        }
        function createProjectLanguageService(server, tsconfig) {
            const commonLine = tsconfig && !ts.server.isInferredProjectName(tsconfig)
                ? (0, language_core_1.createParsedCommandLine)(ts, ts.sys, tsconfig)
                : (0, language_core_1.createParsedCommandLineByJson)(ts, ts.sys, ts.sys.getCurrentDirectory(), {});
            const language = (0, language_core_1.createLanguage)([
                {
                    getLanguageId: uri => server.documents.get(uri)?.languageId,
                },
                (0, language_core_1.createVueLanguagePlugin)(ts, commonLine.options, commonLine.vueOptions, uri => uri.fsPath.replace(/\\/g, '/')),
            ], (0, language_service_1.createUriMap)(), uri => {
                const document = server.documents.get(uri);
                if (document) {
                    language.scripts.set(uri, document.getSnapshot(), document.languageId);
                }
                else {
                    language.scripts.delete(uri);
                }
            });
            return (0, language_service_1.createLanguageService)(language, server.languageServicePlugins, (0, simpleProject_1.createLanguageServiceEnvironment)(server, [...server.workspaceFolders.all]), {});
        }
    });
    connection.onInitialized(server.initialized);
    connection.onShutdown(server.shutdown);
}
//# sourceMappingURL=server.js.map