"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectSvelteFilesManager = void 0;
const utils_1 = require("./utils");
class ProjectSvelteFilesManager {
    static getInstance(projectName) {
        return this.instances.get(projectName);
    }
    constructor(typescript, project, serverHost, snapshotManager, logger, parsedCommandLine, configManager) {
        this.typescript = typescript;
        this.project = project;
        this.serverHost = serverHost;
        this.snapshotManager = snapshotManager;
        this.logger = logger;
        this.parsedCommandLine = parsedCommandLine;
        this.configManager = configManager;
        this.projectFileToOriginalCasing = new Map();
        this.directoryWatchers = new Set();
        this.onConfigChanged = (config) => {
            this.disposeWatchers();
            this.clearProjectFile();
            if (config.enable) {
                this.setupWatchers();
                this.updateProjectSvelteFiles();
            }
        };
        if (configManager.getConfig().enable) {
            this.setupWatchers();
            this.updateProjectSvelteFiles();
        }
        configManager.onConfigurationChanged(this.onConfigChanged);
        ProjectSvelteFilesManager.instances.set(project.getProjectName(), this);
    }
    updateProjectConfig(serviceHost) {
        const parsedCommandLine = serviceHost.getParsedCommandLine?.((0, utils_1.getConfigPathForProject)(this.project));
        if (!parsedCommandLine) {
            return;
        }
        this.disposeWatchers();
        this.clearProjectFile();
        this.parsedCommandLine = parsedCommandLine;
        this.setupWatchers();
        this.updateProjectSvelteFiles();
    }
    getFiles() {
        return Array.from(this.projectFileToOriginalCasing.values());
    }
    /**
     * Create directory watcher for include and exclude
     * The watcher in tsserver doesn't support svelte file
     * It won't add new created svelte file to root
     */
    setupWatchers() {
        for (const directory in this.parsedCommandLine.wildcardDirectories) {
            if (!Object.prototype.hasOwnProperty.call(this.parsedCommandLine.wildcardDirectories, directory)) {
                continue;
            }
            const watchDirectoryFlags = this.parsedCommandLine.wildcardDirectories[directory];
            const watcher = this.serverHost.watchDirectory(directory, this.watcherCallback.bind(this), watchDirectoryFlags === this.typescript.WatchDirectoryFlags.Recursive, this.parsedCommandLine.watchOptions);
            this.directoryWatchers.add(watcher);
        }
    }
    watcherCallback(fileName) {
        if (!(0, utils_1.isSvelteFilePath)(fileName)) {
            return;
        }
        // We can't just add the file to the project directly, because
        // - the casing of fileName is different
        // - we don't know whether the file was added or deleted
        this.updateProjectSvelteFiles();
    }
    updateProjectSvelteFiles() {
        const fileNamesAfter = this.readProjectSvelteFilesFromFs().map((file) => ({
            originalCasing: file,
            canonicalFileName: this.project.projectService.toCanonicalFileName(file)
        }));
        const removedFiles = new Set(this.projectFileToOriginalCasing.keys());
        const newFiles = [];
        for (const file of fileNamesAfter) {
            const existingFile = this.projectFileToOriginalCasing.get(file.canonicalFileName);
            if (!existingFile) {
                newFiles.push(file);
                continue;
            }
            removedFiles.delete(file.canonicalFileName);
            if (existingFile !== file.originalCasing) {
                this.projectFileToOriginalCasing.set(file.canonicalFileName, file.originalCasing);
            }
        }
        for (const newFile of newFiles) {
            this.addFileToProject(newFile.originalCasing);
            this.projectFileToOriginalCasing.set(newFile.canonicalFileName, newFile.originalCasing);
        }
        for (const removedFile of removedFiles) {
            this.removeFileFromProject(removedFile, false);
            this.projectFileToOriginalCasing.delete(removedFile);
        }
    }
    addFileToProject(newFile) {
        this.snapshotManager.create(newFile);
        const snapshot = this.project.projectService.getScriptInfo(newFile);
        if (!snapshot) {
            return;
        }
        if (this.project.isRoot(snapshot)) {
            this.logger.debug(`File ${newFile} is already in root`);
            return;
        }
        this.project.addRoot(snapshot);
    }
    readProjectSvelteFilesFromFs() {
        const fileSpec = this.parsedCommandLine.raw;
        const { include, exclude } = fileSpec;
        if (include?.length === 0) {
            return [];
        }
        return this.typescript.sys
            .readDirectory(this.project.getCurrentDirectory() || process.cwd(), ['.svelte'], exclude, include)
            .map(this.typescript.server.toNormalizedPath);
    }
    removeFileFromProject(file, exists = true) {
        const info = this.project.getScriptInfo(file);
        if (info) {
            this.project.removeFile(info, exists, true);
        }
    }
    disposeWatchers() {
        this.directoryWatchers.forEach((watcher) => watcher.close());
        this.directoryWatchers.clear();
    }
    clearProjectFile() {
        this.projectFileToOriginalCasing.forEach((file) => this.removeFileFromProject(file));
        this.projectFileToOriginalCasing.clear();
    }
    dispose() {
        this.disposeWatchers();
        // Don't remove files from the project here
        // because TypeScript already does that when the project is closed
        // - and because the project is closed, `project.removeFile` will result in an error
        this.projectFileToOriginalCasing.clear();
        this.configManager.removeConfigurationChangeListener(this.onConfigChanged);
        ProjectSvelteFilesManager.instances.delete(this.project.getProjectName());
    }
}
exports.ProjectSvelteFilesManager = ProjectSvelteFilesManager;
ProjectSvelteFilesManager.instances = new Map();
//# sourceMappingURL=project-svelte-files.js.map