typeref-mcp
Version:
TypeScript type inference and symbol navigation MCP server for Claude Code
99 lines • 3.6 kB
JavaScript
import { FileChangeType, } from '../interfaces.js';
export class BaseLanguageAdapter {
config;
cache;
watcher;
logger;
projectIndexes = new Map();
isInitialized = false;
constructor(config, cache, watcher, logger) {
this.config = config;
this.cache = cache;
this.watcher = watcher;
this.logger = logger;
}
async initialize(projectPath) {
this.logger.info(`Initializing ${this.config.name} adapter for project: ${projectPath}`);
if (this.watcher) {
const changeCallback = (eventType, filePath) => {
this.handleFileChange(eventType, filePath, projectPath);
};
this.watcher.watch(projectPath, changeCallback);
}
this.isInitialized = true;
}
async dispose() {
if (this.logger && this.logger.info) {
this.logger.info(`Disposing ${this.config.name} adapter`);
}
if (this.watcher) {
this.watcher.dispose();
}
this.projectIndexes.clear();
this.cache.invalidate(`${this.config.name}:*`);
this.isInitialized = false;
}
getCacheKey(projectPath, operation, ...args) {
return `${this.config.name}:${projectPath}:${operation}:${args.join(':')}`;
}
getProjectIndex(projectPath) {
return this.projectIndexes.get(projectPath) || null;
}
setProjectIndex(projectPath, index) {
this.projectIndexes.set(projectPath, index);
}
async handleFileChange(eventType, filePath, projectPath) {
this.logger.debug(`File ${eventType}: ${filePath}`);
this.cache.invalidate(`${this.config.name}:${projectPath}:*`);
switch (eventType) {
case FileChangeType.Modified:
case FileChangeType.Created:
await this.handleFileUpdate(filePath, projectPath);
break;
case FileChangeType.Deleted:
await this.handleFileDelete(filePath, projectPath);
break;
}
}
async handleFileUpdate(filePath, _projectPath) {
this.logger.debug(`Handling file update: ${filePath}`);
}
async handleFileDelete(filePath, _projectPath) {
this.logger.debug(`Handling file deletion: ${filePath}`);
}
shouldIncludeFile(filePath) {
const ext = this.getFileExtension(filePath);
if (!this.config.fileExtensions.includes(ext)) {
this.logger.debug(`File excluded (extension): ${filePath} (ext: ${ext})`);
return false;
}
for (const pattern of this.config.excludePatterns) {
if (this.matchesPattern(filePath, pattern)) {
this.logger.debug(`File excluded (pattern ${pattern}): ${filePath}`);
return false;
}
}
this.logger.debug(`File included: ${filePath}`);
return true;
}
getFileExtension(filePath) {
const lastDot = filePath.lastIndexOf('.');
return lastDot >= 0 ? filePath.substring(lastDot) : '';
}
matchesPattern(filePath, pattern) {
const regex = new RegExp(pattern
.replace(/\./g, '\\.')
.replace(/\*/g, '.*')
.replace(/\?/g, '.'));
return regex.test(filePath);
}
validateProjectPath(projectPath) {
if (!projectPath) {
throw new Error('Project path is required');
}
if (!this.isInitialized) {
throw new Error('Adapter not initialized. Call initialize() first.');
}
}
}
//# sourceMappingURL=BaseLanguageAdapter.js.map