"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
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 ts = require("typescript");
const vscode_uri_1 = require("vscode-uri");
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;
    return 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() {
            return Promise.all([
                ...tsconfigProjects.values(),
                simpleLanguageService,
            ].filter(promise => !!promise));
        },
        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);
        },
        getComponentEvents(...args) {
            return sendTsServerRequest('_vue:getComponentEvents', 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);
        },
        getReactiveReferences(...args) {
            return sendTsServerRequest('_vue:getReactiveReferences', args);
        },
        isRefAtPosition(...args) {
            return sendTsServerRequest('_vue:isRefAtPosition', 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;
        },
    }));
    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=index.js.map