| 78 | } |
| 79 | |
| 80 | export class CacheManager { |
| 81 | private cachePath: vscode.Uri | null = null; |
| 82 | private graphPath: vscode.Uri | null = null; |
| 83 | private files: Record<string, FileCache> = {}; |
| 84 | private crossFileEdges: CrossFileEdge[] = []; |
| 85 | private workflows: Record<string, WorkflowInfo> = {}; |
| 86 | private initPromise: Promise<void>; |
| 87 | private staticAnalyzer: StaticAnalyzer; |
| 88 | |
| 89 | // Debounced save |
| 90 | private saveTimer: NodeJS.Timeout | null = null; |
| 91 | private saveDebounceMs = 500; |
| 92 | private maxSaveWaitMs = 5000; |
| 93 | private lastSaveTime = 0; |
| 94 | |
| 95 | // Cached merged graph for sync access (instant feedback) |
| 96 | private lastMergedGraph: WorkflowGraph | null = null; |
| 97 | |
| 98 | // Multi-batch analysis state tracking |
| 99 | // Prevents premature workflow filtering during first analysis |
| 100 | private analysisInProgress: boolean = false; |
| 101 | private pendingBatchCount: number = 0; |
| 102 | |
| 103 | constructor(private context: vscode.ExtensionContext) { |
| 104 | this.initPromise = this.initializeCache(); |
| 105 | this.staticAnalyzer = new StaticAnalyzer(); |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * Convert full path to relative path using workspace root. |
| 110 | * Ensures consistent cache keys using relative paths for security and portability. |
| 111 | */ |
| 112 | private toRelativePath(filePath: string): string { |
| 113 | // Already relative (doesn't start with / or drive letter) |
| 114 | if (!filePath.startsWith('/') && !filePath.match(/^[A-Z]:\\/i)) { |
| 115 | return filePath; |
| 116 | } |
| 117 | // Convert absolute to relative |
| 118 | const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; |
| 119 | if (workspaceRoot && filePath.startsWith(workspaceRoot)) { |
| 120 | return filePath.slice(workspaceRoot.length).replace(/^[/\\]/, ''); |
| 121 | } |
| 122 | return filePath; |
| 123 | } |
| 124 | |
| 125 | private async initializeCache() { |
| 126 | const workspaceFolders = vscode.workspace.workspaceFolders; |
| 127 | if (!workspaceFolders || workspaceFolders.length === 0) { |
| 128 | return; |
| 129 | } |
| 130 | |
| 131 | const workspaceFolder = workspaceFolders[0]; |
| 132 | const vscodeFolderPath = path.join(workspaceFolder.uri.fsPath, '.vscode'); |
| 133 | this.cachePath = vscode.Uri.file(path.join(vscodeFolderPath, 'codag-cache.json')); |
| 134 | this.graphPath = vscode.Uri.file(path.join(vscodeFolderPath, 'codag-graph.json')); |
| 135 | |
| 136 | try { |
| 137 | await vscode.workspace.fs.createDirectory(vscode.Uri.file(vscodeFolderPath)); |
nothing calls this directly
no outgoing calls
no test coverage detected