init claude-code
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { detectFileEncoding } from './file.js'
|
||||
import { getFsImplementation } from './fsOperations.js'
|
||||
|
||||
type CachedFileData = {
|
||||
content: string
|
||||
encoding: BufferEncoding
|
||||
mtime: number
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple in-memory cache for file contents with automatic invalidation based on modification time.
|
||||
* This eliminates redundant file reads in FileEditTool operations.
|
||||
*/
|
||||
class FileReadCache {
|
||||
private cache = new Map<string, CachedFileData>()
|
||||
private readonly maxCacheSize = 1000
|
||||
|
||||
/**
|
||||
* Reads a file with caching. Returns both content and encoding.
|
||||
* Cache key includes file path and modification time for automatic invalidation.
|
||||
*/
|
||||
readFile(filePath: string): { content: string; encoding: BufferEncoding } {
|
||||
const fs = getFsImplementation()
|
||||
|
||||
// Get file stats for cache invalidation
|
||||
let stats
|
||||
try {
|
||||
stats = fs.statSync(filePath)
|
||||
} catch (error) {
|
||||
// File was deleted, remove from cache and re-throw
|
||||
this.cache.delete(filePath)
|
||||
throw error
|
||||
}
|
||||
|
||||
const cacheKey = filePath
|
||||
const cachedData = this.cache.get(cacheKey)
|
||||
|
||||
// Check if we have valid cached data
|
||||
if (cachedData && cachedData.mtime === stats.mtimeMs) {
|
||||
return {
|
||||
content: cachedData.content,
|
||||
encoding: cachedData.encoding,
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss or stale data - read the file
|
||||
const encoding = detectFileEncoding(filePath)
|
||||
const content = fs
|
||||
.readFileSync(filePath, { encoding })
|
||||
.replaceAll('\r\n', '\n')
|
||||
|
||||
// Update cache
|
||||
this.cache.set(cacheKey, {
|
||||
content,
|
||||
encoding,
|
||||
mtime: stats.mtimeMs,
|
||||
})
|
||||
|
||||
// Evict oldest entries if cache is too large
|
||||
if (this.cache.size > this.maxCacheSize) {
|
||||
const firstKey = this.cache.keys().next().value
|
||||
if (firstKey) {
|
||||
this.cache.delete(firstKey)
|
||||
}
|
||||
}
|
||||
|
||||
return { content, encoding }
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the entire cache. Useful for testing or memory management.
|
||||
*/
|
||||
clear(): void {
|
||||
this.cache.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific file from the cache.
|
||||
*/
|
||||
invalidate(filePath: string): void {
|
||||
this.cache.delete(filePath)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets cache statistics for debugging/monitoring.
|
||||
*/
|
||||
getStats(): { size: number; entries: string[] } {
|
||||
return {
|
||||
size: this.cache.size,
|
||||
entries: Array.from(this.cache.keys()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export a singleton instance
|
||||
export const fileReadCache = new FileReadCache()
|
||||
Reference in New Issue
Block a user