"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNodeFileSystemHost = void 0;
const vscode = require("vscode-languageserver");
const uriMap_1 = require("../common/utils/uriMap");
let currentCwd = '';
function createNodeFileSystemHost(ts, capabilities, env, _initOptions) {
    const instances = (0, uriMap_1.createUriMap)(env.fileNameToUri);
    const onDidChangeWatchedFilesCb = new Set();
    return {
        ready(connection) {
            connection.onDidChangeWatchedFiles(async (params) => {
                if (params.changes.some(change => change.type === vscode.FileChangeType.Created || change.type === vscode.FileChangeType.Deleted)) {
                    for (const sys of instances.values()) {
                        sys[1].forEach(cache => cache.clear());
                    }
                }
                for (const cb of [...onDidChangeWatchedFilesCb]) {
                    if (onDidChangeWatchedFilesCb.has(cb)) {
                        await cb(params);
                    }
                }
            });
        },
        reload() {
            for (const sys of instances.values()) {
                sys[1].forEach(cache => cache.clear());
            }
        },
        getWorkspaceFileSystem(rootUri) {
            let sys = instances.uriGet(rootUri.toString());
            if (!sys) {
                sys = createWorkspaceFileSystem(ts, capabilities, rootUri);
                instances.uriSet(rootUri.toString(), sys);
            }
            return sys[0];
        },
        onDidChangeWatchedFiles: cb => {
            onDidChangeWatchedFilesCb.add(cb);
            return () => onDidChangeWatchedFilesCb.delete(cb);
        },
    };
    function createWorkspaceFileSystem(ts, capabilities, rootUri) {
        const rootPath = env.uriToFileName(rootUri.toString());
        const workspaceSys = new Proxy(ts.sys, {
            get(target, prop) {
                const fn = target[prop];
                if (typeof fn === 'function') {
                    return new Proxy(fn, {
                        apply(target, thisArg, args) {
                            if (currentCwd !== rootPath) {
                                // https://github.com/vuejs/language-tools/issues/2039
                                // https://github.com/vuejs/language-tools/issues/2234
                                if (ts.sys.directoryExists(rootPath)) {
                                    // https://github.com/vuejs/language-tools/issues/2480
                                    try {
                                        process.chdir(rootPath);
                                    }
                                    catch { }
                                }
                                currentCwd = rootPath;
                            }
                            return target.apply(thisArg, args);
                        }
                    });
                }
                return fn;
            },
        });
        const fileExistsCache = new Map();
        const directoryExistsCache = new Map();
        // don't cache fs result if client did not supports file watcher
        const sys = capabilities.workspace?.didChangeWatchedFiles
            ? new Proxy({
                fileExists(path) {
                    if (!fileExistsCache.has(path)) {
                        fileExistsCache.set(path, workspaceSys.fileExists(path));
                    }
                    return fileExistsCache.get(path);
                },
                directoryExists(path) {
                    if (!directoryExistsCache.has(path)) {
                        directoryExistsCache.set(path, workspaceSys.directoryExists(path));
                    }
                    return directoryExistsCache.get(path);
                },
            }, {
                get(target, prop) {
                    if (prop in target) {
                        return target[prop];
                    }
                    return workspaceSys[prop];
                },
            })
            : workspaceSys;
        return [sys, [fileExistsCache, directoryExistsCache]];
    }
}
exports.createNodeFileSystemHost = createNodeFileSystemHost;
//# sourceMappingURL=fileSystem.js.map