UNPKG

svelte-language-server

Version:
238 lines 10.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ignoredBuildDirectories = exports.SnapshotManager = exports.GlobalSnapshotsManager = void 0; const typescript_1 = __importDefault(require("typescript")); const DocumentSnapshot_1 = require("./DocumentSnapshot"); const logger_1 = require("../../logger"); const utils_1 = require("../../utils"); const events_1 = require("events"); const fileCollection_1 = require("../../lib/documents/fileCollection"); /** * Every snapshot corresponds to a unique file on disk. * A snapshot can be part of multiple projects, but for a given file path * there can be only one snapshot. */ class GlobalSnapshotsManager { constructor(tsSystem) { this.tsSystem = tsSystem; this.emitter = new events_1.EventEmitter(); this.documents = new fileCollection_1.FileMap(tsSystem.useCaseSensitiveFileNames); this.getCanonicalFileName = (0, utils_1.createGetCanonicalFileName)(tsSystem.useCaseSensitiveFileNames); } get(fileName) { fileName = (0, utils_1.normalizePath)(fileName); return this.documents.get(fileName); } getByPrefix(path) { path = this.getCanonicalFileName((0, utils_1.normalizePath)(path)); return Array.from(this.documents.entries()) .filter((doc) => doc[0].startsWith(path)) .map((doc) => doc[1]); } set(fileName, document) { fileName = (0, utils_1.normalizePath)(fileName); this.documents.set(fileName, document); this.emitter.emit('change', fileName, document); } delete(fileName) { fileName = (0, utils_1.normalizePath)(fileName); this.documents.delete(fileName); this.emitter.emit('change', fileName, undefined); } updateTsOrJsFile(fileName, changes) { fileName = (0, utils_1.normalizePath)(fileName); const previousSnapshot = this.get(fileName); if (changes) { if (!(previousSnapshot instanceof DocumentSnapshot_1.JSOrTSDocumentSnapshot)) { return; } previousSnapshot.update(changes); this.emitter.emit('change', fileName, previousSnapshot); return previousSnapshot; } else { const newSnapshot = DocumentSnapshot_1.DocumentSnapshot.fromNonSvelteFilePath(fileName, this.tsSystem); if (previousSnapshot) { newSnapshot.version = previousSnapshot.version + 1; } else { // ensure it's greater than initial version // so that ts server picks up the change newSnapshot.version += 1; } this.set(fileName, newSnapshot); return newSnapshot; } } onChange(listener) { this.emitter.on('change', listener); } removeChangeListener(listener) { this.emitter.off('change', listener); } } exports.GlobalSnapshotsManager = GlobalSnapshotsManager; /** * Should only be used by `service.ts` */ class SnapshotManager { constructor(globalSnapshotsManager, fileSpec, workspaceRoot, tsSystem, projectFiles, wildcardDirectories) { this.globalSnapshotsManager = globalSnapshotsManager; this.fileSpec = fileSpec; this.workspaceRoot = workspaceRoot; this.tsSystem = tsSystem; this.lastLogged = new Date(new Date().getTime() - 60_001); this.watchExtensions = [ typescript_1.default.Extension.Dts, typescript_1.default.Extension.Dcts, typescript_1.default.Extension.Dmts, typescript_1.default.Extension.Js, typescript_1.default.Extension.Cjs, typescript_1.default.Extension.Mjs, typescript_1.default.Extension.Jsx, typescript_1.default.Extension.Ts, typescript_1.default.Extension.Mts, typescript_1.default.Extension.Cts, typescript_1.default.Extension.Tsx, typescript_1.default.Extension.Json, '.svelte' ]; this.onSnapshotChange = this.onSnapshotChange.bind(this); this.globalSnapshotsManager.onChange(this.onSnapshotChange); this.documents = new fileCollection_1.FileMap(tsSystem.useCaseSensitiveFileNames); this.projectFileToOriginalCasing = new Map(); this.getCanonicalFileName = (0, utils_1.createGetCanonicalFileName)(tsSystem.useCaseSensitiveFileNames); projectFiles.forEach((originalCasing) => this.projectFileToOriginalCasing.set(this.getCanonicalFileName(originalCasing), originalCasing)); this.watchingCanonicalDirectories = new Map(Object.entries(wildcardDirectories ?? {}).map(([dir, flags]) => [ this.getCanonicalFileName(dir), flags ])); } onSnapshotChange(fileName, document) { // Only delete/update snapshots, don't add new ones, // as they could be from another TS service and this // snapshot manager can't reach this file. // For these, instead wait on a `get` method invocation // and set them "manually" in the set/update methods. if (!document) { this.documents.delete(fileName); this.projectFileToOriginalCasing.delete(this.getCanonicalFileName(fileName)); } else if (this.documents.has(fileName)) { this.documents.set(fileName, document); } } areIgnoredFromNewFileWatch(watcherNewFiles) { const { include } = this.fileSpec; // Since we default to not include anything, // just don't waste time on this if (include?.length === 0 || !this.watchingCanonicalDirectories) { return true; } for (const newFile of watcherNewFiles) { const path = this.getCanonicalFileName((0, utils_1.normalizePath)(newFile)); if (this.projectFileToOriginalCasing.has(path)) { continue; } for (const [dir, flags] of this.watchingCanonicalDirectories) { if (path.startsWith(dir)) { if (!(flags & typescript_1.default.WatchDirectoryFlags.Recursive)) { const relative = path.slice(dir.length); if (relative.includes('/')) { continue; } } return false; } } } return true; } updateProjectFiles() { const { include, exclude } = this.fileSpec; if (include?.length === 0) { return; } const projectFiles = this.tsSystem .readDirectory(this.workspaceRoot, this.watchExtensions, exclude, include) .map(utils_1.normalizePath); projectFiles.forEach((projectFile) => this.projectFileToOriginalCasing.set(this.getCanonicalFileName(projectFile), projectFile)); } updateTsOrJsFile(fileName, changes) { const snapshot = this.globalSnapshotsManager.updateTsOrJsFile(fileName, changes); // This isn't duplicated logic to the listener, because this could // be a new snapshot which the listener wouldn't add. if (snapshot) { this.documents.set((0, utils_1.normalizePath)(fileName), snapshot); } } has(fileName) { fileName = (0, utils_1.normalizePath)(fileName); return (this.projectFileToOriginalCasing.has(this.getCanonicalFileName(fileName)) || this.documents.has(fileName)); } set(fileName, snapshot) { this.globalSnapshotsManager.set(fileName, snapshot); // This isn't duplicated logic to the listener, because this could // be a new snapshot which the listener wouldn't add. this.documents.set((0, utils_1.normalizePath)(fileName), snapshot); this.logStatistics(); } get(fileName) { fileName = (0, utils_1.normalizePath)(fileName); let snapshot = this.documents.get(fileName); if (!snapshot) { snapshot = this.globalSnapshotsManager.get(fileName); if (snapshot) { this.documents.set(fileName, snapshot); } } return snapshot; } delete(fileName) { fileName = (0, utils_1.normalizePath)(fileName); this.globalSnapshotsManager.delete(fileName); } getClientFileNames() { return Array.from(this.documents.values()) .filter((doc) => doc.isOpenedInClient()) .map((doc) => doc.filePath); } getProjectFileNames() { return Array.from(this.projectFileToOriginalCasing.values()); } isProjectFile(fileName) { fileName = (0, utils_1.normalizePath)(fileName); return this.projectFileToOriginalCasing.has(this.getCanonicalFileName(fileName)); } logStatistics() { const date = new Date(); // Don't use setInterval because that will keep tests running forever if (date.getTime() - this.lastLogged.getTime() > 60_000) { this.lastLogged = date; const allFiles = Array.from(new Set([...this.projectFileToOriginalCasing.keys(), ...this.documents.keys()])); logger_1.Logger.log('SnapshotManager File Statistics:\n' + `Project files: ${this.projectFileToOriginalCasing.size}\n` + `Svelte files: ${allFiles.filter((name) => name.endsWith('.svelte')).length}\n` + `From node_modules: ${allFiles.filter((name) => name.includes('node_modules')).length}\n` + `Total: ${allFiles.length}`); } } allFilesAreJsOrDts() { for (const doc of this.documents.values()) { if (doc.scriptKind === typescript_1.default.ScriptKind.TS || doc.scriptKind === typescript_1.default.ScriptKind.TSX) { return false; } } return true; } dispose() { this.globalSnapshotsManager.removeChangeListener(this.onSnapshotChange); } } exports.SnapshotManager = SnapshotManager; exports.ignoredBuildDirectories = ['__sapper__', '.svelte-kit']; //# sourceMappingURL=SnapshotManager.js.map