"use strict";
const createLanguageServicePlugin_1 = require("@volar/typescript/lib/quickstart/createLanguageServicePlugin");
const vue = require("@vue/language-core");
const common_1 = require("./lib/common");
const collectExtractProps_1 = require("./lib/requests/collectExtractProps");
const getComponentDirectives_1 = require("./lib/requests/getComponentDirectives");
const getComponentEvents_1 = require("./lib/requests/getComponentEvents");
const getComponentNames_1 = require("./lib/requests/getComponentNames");
const getComponentProps_1 = require("./lib/requests/getComponentProps");
const getComponentSlots_1 = require("./lib/requests/getComponentSlots");
const getElementAttrs_1 = require("./lib/requests/getElementAttrs");
const getElementNames_1 = require("./lib/requests/getElementNames");
const getImportPathForFile_1 = require("./lib/requests/getImportPathForFile");
const getReactiveReferences_1 = require("./lib/requests/getReactiveReferences");
const isRefAtPosition_1 = require("./lib/requests/isRefAtPosition");
const windowsPathReg = /\\/g;
const project2Service = new WeakMap();
module.exports = (0, createLanguageServicePlugin_1.createLanguageServicePlugin)((ts, info) => {
    const vueOptions = getVueCompilerOptions();
    const languagePlugin = vue.createVueLanguagePlugin(ts, info.languageServiceHost.getCompilationSettings(), vueOptions, id => id);
    vue.writeGlobalTypes(vueOptions, ts.sys.writeFile);
    addVueCommands();
    return {
        languagePlugins: [languagePlugin],
        setup: language => {
            project2Service.set(info.project, [language, info.languageServiceHost, info.languageService]);
            info.languageService = (0, common_1.createVueLanguageServiceProxy)(ts, language, info.languageService, vueOptions, fileName => fileName);
            // #3963
            const timer = setInterval(() => {
                if (info.project['program']) {
                    clearInterval(timer);
                    info.project['program'].__vue__ = { language };
                }
            }, 50);
        },
    };
    function getVueCompilerOptions() {
        if (info.project.projectKind === ts.server.ProjectKind.Configured) {
            const tsconfig = info.project.getProjectName();
            return vue.createParsedCommandLine(ts, ts.sys, tsconfig.replace(windowsPathReg, '/')).vueOptions;
        }
        else {
            return vue.createParsedCommandLineByJson(ts, ts.sys, info.languageServiceHost.getCurrentDirectory(), {})
                .vueOptions;
        }
    }
    // https://github.com/JetBrains/intellij-plugins/blob/6435723ad88fa296b41144162ebe3b8513f4949b/Angular/src-js/angular-service/src/index.ts#L69
    function addVueCommands() {
        const projectService = info.project.projectService;
        projectService.logger.info('Vue: called handler processing ' + info.project.projectKind);
        if (!info.session) {
            projectService.logger.info('Vue: there is no session in info.');
            return;
        }
        const session = info.session;
        if (!session.addProtocolHandler) {
            // addProtocolHandler was introduced in TS 4.4 or 4.5 in 2021, see https://github.com/microsoft/TypeScript/issues/43893
            projectService.logger.info('Vue: there is no addProtocolHandler method.');
            return;
        }
        // @ts-expect-error
        const handlers = session.handlers;
        if (handlers.has('_vue:projectInfo')) {
            return;
        }
        session.addProtocolHandler('_vue:projectInfo', request => {
            return handlers.get('projectInfo')(request);
        });
        session.addProtocolHandler('_vue:documentHighlights-full', request => {
            return handlers.get('documentHighlights-full')(request);
        });
        session.addProtocolHandler('_vue:encodedSemanticClassifications-full', request => {
            return handlers.get('encodedSemanticClassifications-full')(request);
        });
        session.addProtocolHandler('_vue:quickinfo', request => {
            return handlers.get('quickinfo')(request);
        });
        session.addProtocolHandler('_vue:collectExtractProps', request => {
            const [fileName, templateCodeRange] = request.arguments;
            const { language, languageService, sourceScript, virtualCode } = getLanguageServiceAndVirtualCode(fileName);
            return createResponse((0, collectExtractProps_1.collectExtractProps)(ts, language, languageService.getProgram(), sourceScript, virtualCode, templateCodeRange, sourceScript.generated ? sourceScript.snapshot.getLength() : 0));
        });
        session.addProtocolHandler('_vue:getImportPathForFile', request => {
            const [fileName, incomingFileName, preferences] = request.arguments;
            const { languageServiceHost, languageService } = getLanguageService(fileName);
            return createResponse((0, getImportPathForFile_1.getImportPathForFile)(ts, languageServiceHost, languageService.getProgram(), fileName, incomingFileName, preferences));
        });
        session.addProtocolHandler('_vue:isRefAtPosition', request => {
            const [fileName, position] = request.arguments;
            const { language, languageService, sourceScript, virtualCode } = getLanguageServiceAndVirtualCode(fileName);
            return createResponse((0, isRefAtPosition_1.isRefAtPosition)(ts, language, languageService.getProgram(), sourceScript, virtualCode, position, sourceScript.generated ? sourceScript.snapshot.getLength() : 0));
        });
        session.addProtocolHandler('_vue:getComponentDirectives', request => {
            const [fileName] = request.arguments;
            const { languageService } = getLanguageService(fileName);
            return createResponse((0, getComponentDirectives_1.getComponentDirectives)(ts, languageService.getProgram(), fileName));
        });
        session.addProtocolHandler('_vue:getComponentEvents', request => {
            const [fileName, tag] = request.arguments;
            const { languageService } = getLanguageService(fileName);
            return createResponse((0, getComponentEvents_1.getComponentEvents)(ts, languageService.getProgram(), fileName, tag));
        });
        session.addProtocolHandler('_vue:getComponentNames', request => {
            const [fileName] = request.arguments;
            const { languageService } = getLanguageService(fileName);
            return createResponse((0, getComponentNames_1.getComponentNames)(ts, languageService.getProgram(), fileName));
        });
        session.addProtocolHandler('_vue:getComponentProps', request => {
            const [fileName, tag] = request.arguments;
            const { languageService } = getLanguageService(fileName);
            return createResponse((0, getComponentProps_1.getComponentProps)(ts, languageService.getProgram(), fileName, tag));
        });
        session.addProtocolHandler('_vue:getComponentSlots', request => {
            const [fileName] = request.arguments;
            const { languageService, virtualCode } = getLanguageServiceAndVirtualCode(fileName);
            return createResponse((0, getComponentSlots_1.getComponentSlots)(ts, languageService.getProgram(), virtualCode));
        });
        session.addProtocolHandler('_vue:getElementAttrs', request => {
            const [fileName, tag] = request.arguments;
            const { languageService } = getLanguageService(fileName);
            return createResponse((0, getElementAttrs_1.getElementAttrs)(ts, languageService.getProgram(), fileName, tag));
        });
        session.addProtocolHandler('_vue:getElementNames', request => {
            const [fileName] = request.arguments;
            const { languageService } = getLanguageService(fileName);
            return createResponse((0, getElementNames_1.getElementNames)(ts, languageService.getProgram(), fileName));
        });
        session.addProtocolHandler('_vue:getReactiveReferences', request => {
            const [fileName, position] = request.arguments;
            const { language } = getLanguageService(fileName);
            const sourceScript = language.scripts.get(fileName);
            return createResponse((0, getReactiveReferences_1.getReactiveReferences)(ts, language, sourceScript, position, sourceScript.generated ? sourceScript.snapshot.getLength() : 0));
        });
        projectService.logger.info('Vue specific commands are successfully added.');
        function createResponse(res) {
            return {
                response: res,
                responseRequired: true,
            };
        }
        function getLanguageServiceAndVirtualCode(fileName) {
            const service = getLanguageService(fileName);
            const sourceScript = service.language.scripts.get(fileName);
            if (!sourceScript) {
                throw new Error('No source script found for file: ' + fileName);
            }
            const virtualCode = sourceScript.generated?.root;
            if (!(virtualCode instanceof vue.VueVirtualCode)) {
                throw new Error('No virtual code found for file: ' + fileName);
            }
            return {
                ...service,
                sourceScript,
                virtualCode,
            };
        }
        function getLanguageService(fileName) {
            // @ts-expect-error
            const { project } = session.getFileAndProject({
                file: fileName,
                projectFileName: undefined,
            });
            const service = project2Service.get(project);
            if (!service) {
                throw new Error('No vue service for project: ' + project.getProjectName());
            }
            const [language, languageServiceHost, languageService] = service;
            return {
                typescript: ts,
                languageService,
                languageServiceHost,
                language,
            };
        }
    }
});
//# sourceMappingURL=index.js.map