| 89 | } |
| 90 | |
| 91 | class RecursiveFileSearch implements FileSearch { |
| 92 | private ignore: Ignore | undefined; |
| 93 | private resultCache: ResultCache | undefined; |
| 94 | private allFiles: string[] = []; |
| 95 | private fzf: AsyncFzf<string[]> | undefined; |
| 96 | |
| 97 | constructor(private readonly options: FileSearchOptions) {} |
| 98 | |
| 99 | async initialize(): Promise<void> { |
| 100 | this.ignore = loadIgnoreRules(this.options); |
| 101 | this.allFiles = await crawl({ |
| 102 | crawlDirectory: this.options.projectRoot, |
| 103 | cwd: this.options.projectRoot, |
| 104 | ignore: this.ignore, |
| 105 | cache: this.options.cache, |
| 106 | cacheTtl: this.options.cacheTtl, |
| 107 | maxDepth: this.options.maxDepth, |
| 108 | }); |
| 109 | this.buildResultCache(); |
| 110 | } |
| 111 | |
| 112 | async search( |
| 113 | pattern: string, |
| 114 | options: SearchOptions = {}, |
| 115 | ): Promise<string[]> { |
| 116 | if (!this.resultCache || !this.fzf || !this.ignore) { |
| 117 | throw new Error('Engine not initialized. Call initialize() first.'); |
| 118 | } |
| 119 | |
| 120 | pattern = pattern || '*'; |
| 121 | |
| 122 | let filteredCandidates; |
| 123 | const { files: candidates, isExactMatch } = |
| 124 | await this.resultCache!.get(pattern); |
| 125 | |
| 126 | if (isExactMatch) { |
| 127 | // Use the cached result. |
| 128 | filteredCandidates = candidates; |
| 129 | } else { |
| 130 | let shouldCache = true; |
| 131 | if (pattern.includes('*')) { |
| 132 | filteredCandidates = await filter(candidates, pattern, options.signal); |
| 133 | } else { |
| 134 | filteredCandidates = await this.fzf |
| 135 | .find(pattern) |
| 136 | .then((results: Array<FzfResultItem<string>>) => |
| 137 | results.map((entry: FzfResultItem<string>) => entry.item), |
| 138 | ) |
| 139 | .catch(() => { |
| 140 | shouldCache = false; |
| 141 | return []; |
| 142 | }); |
| 143 | } |
| 144 | |
| 145 | if (shouldCache) { |
| 146 | this.resultCache!.set(pattern, filteredCandidates); |
| 147 | } |
| 148 | } |
nothing calls this directly
no outgoing calls
no test coverage detected