"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.searchExternalFiles = exports.decorateLanguageServiceHost = void 0;
const resolveModuleName_1 = require("../resolveModuleName");
function decorateLanguageServiceHost(ts, language, languageServiceHost) {
    const pluginExtensions = language.plugins
        .map(plugin => plugin.typescript?.extraFileExtensions.map(ext => '.' + ext.extension) ?? [])
        .flat();
    const scripts = new Map();
    const crashFileNames = new Set();
    const readDirectory = languageServiceHost.readDirectory?.bind(languageServiceHost);
    const resolveModuleNameLiterals = languageServiceHost.resolveModuleNameLiterals?.bind(languageServiceHost);
    const resolveModuleNames = languageServiceHost.resolveModuleNames?.bind(languageServiceHost);
    const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
    const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
    // path completion
    if (readDirectory) {
        languageServiceHost.readDirectory = (path, extensions, exclude, include, depth) => {
            if (extensions) {
                for (const ext of pluginExtensions) {
                    if (!extensions.includes(ext)) {
                        extensions = [...extensions, ext];
                    }
                }
            }
            return readDirectory(path, extensions, exclude, include, depth);
        };
    }
    if (pluginExtensions.length) {
        const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, languageServiceHost, language.plugins, fileName => language.scripts.get(fileName));
        const getCanonicalFileName = languageServiceHost.useCaseSensitiveFileNames?.()
            ? (fileName) => fileName
            : (fileName) => fileName.toLowerCase();
        const moduleResolutionCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), getCanonicalFileName, languageServiceHost.getCompilationSettings());
        if (resolveModuleNameLiterals) {
            languageServiceHost.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, options, ...rest) => {
                if (moduleLiterals.every(name => !pluginExtensions.some(ext => name.text.endsWith(ext)))) {
                    return resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, options, ...rest);
                }
                return moduleLiterals.map(moduleLiteral => {
                    return resolveModuleName(moduleLiteral.text, containingFile, options, moduleResolutionCache, redirectedReference);
                });
            };
        }
        if (resolveModuleNames) {
            languageServiceHost.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile) => {
                if (moduleNames.every(name => !pluginExtensions.some(ext => name.endsWith(ext)))) {
                    return resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile);
                }
                return moduleNames.map(moduleName => {
                    return resolveModuleName(moduleName, containingFile, options, moduleResolutionCache, redirectedReference).resolvedModule;
                });
            };
        }
    }
    languageServiceHost.getScriptSnapshot = fileName => {
        const virtualScript = updateVirtualScript(fileName);
        if (virtualScript) {
            return virtualScript.snapshot;
        }
        return getScriptSnapshot(fileName);
    };
    if (getScriptKind) {
        languageServiceHost.getScriptKind = fileName => {
            const virtualScript = updateVirtualScript(fileName);
            if (virtualScript) {
                return virtualScript.kind;
            }
            return getScriptKind(fileName);
        };
    }
    function updateVirtualScript(fileName) {
        if (crashFileNames.has(fileName)) {
            return;
        }
        let version;
        try {
            version = languageServiceHost.getScriptVersion(fileName);
        }
        catch {
            // fix https://github.com/vuejs/language-tools/issues/4278
            crashFileNames.add(fileName);
        }
        if (version === undefined) {
            // somehow getScriptVersion returns undefined
            return;
        }
        let script = scripts.get(fileName);
        if (!script || script[0] !== version) {
            script = [version];
            const sourceScript = language.scripts.get(fileName);
            if (sourceScript?.generated) {
                const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
                if (serviceScript) {
                    const sourceContents = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength());
                    let virtualContents = sourceContents.split('\n').map(line => ' '.repeat(line.length)).join('\n');
                    virtualContents += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
                    script[1] = {
                        extension: serviceScript.extension,
                        kind: serviceScript.scriptKind,
                        snapshot: ts.ScriptSnapshot.fromString(virtualContents),
                    };
                }
                if (sourceScript.generated.languagePlugin.typescript?.getExtraServiceScripts) {
                    console.warn('getExtraServiceScripts() is not available in TS plugin.');
                }
            }
            scripts.set(fileName, script);
        }
        return script[1];
    }
}
exports.decorateLanguageServiceHost = decorateLanguageServiceHost;
function searchExternalFiles(ts, project, exts) {
    if (project.projectKind !== ts.server.ProjectKind.Configured) {
        return [];
    }
    const configFile = project.getProjectName();
    const config = ts.readJsonConfigFile(configFile, project.readFile.bind(project));
    const parseHost = {
        useCaseSensitiveFileNames: project.useCaseSensitiveFileNames(),
        fileExists: project.fileExists.bind(project),
        readFile: project.readFile.bind(project),
        readDirectory: (...args) => {
            args[1] = exts;
            return project.readDirectory(...args);
        },
    };
    const parsed = ts.parseJsonSourceFileConfigFileContent(config, parseHost, project.getCurrentDirectory());
    return parsed.fileNames;
}
exports.searchExternalFiles = searchExternalFiles;
//# sourceMappingURL=decorateLanguageServiceHost.js.map