| 182 | } |
| 183 | |
| 184 | class DirectoryFileSearch implements FileSearch { |
| 185 | private ignore: Ignore | undefined; |
| 186 | |
| 187 | constructor(private readonly options: FileSearchOptions) {} |
| 188 | |
| 189 | async initialize(): Promise<void> { |
| 190 | this.ignore = loadIgnoreRules(this.options); |
| 191 | } |
| 192 | |
| 193 | async search( |
| 194 | pattern: string, |
| 195 | options: SearchOptions = {}, |
| 196 | ): Promise<string[]> { |
| 197 | if (!this.ignore) { |
| 198 | throw new Error('Engine not initialized. Call initialize() first.'); |
| 199 | } |
| 200 | pattern = pattern || '*'; |
| 201 | |
| 202 | const dir = pattern.endsWith('/') ? pattern : path.dirname(pattern); |
| 203 | const results = await crawl({ |
| 204 | crawlDirectory: path.join(this.options.projectRoot, dir), |
| 205 | cwd: this.options.projectRoot, |
| 206 | maxDepth: 0, |
| 207 | ignore: this.ignore, |
| 208 | cache: this.options.cache, |
| 209 | cacheTtl: this.options.cacheTtl, |
| 210 | }); |
| 211 | |
| 212 | const filteredResults = await filter(results, pattern, options.signal); |
| 213 | |
| 214 | const fileFilter = this.ignore.getFileFilter(); |
| 215 | const finalResults: string[] = []; |
| 216 | for (const candidate of filteredResults) { |
| 217 | if (finalResults.length >= (options.maxResults ?? Infinity)) { |
| 218 | break; |
| 219 | } |
| 220 | if (candidate === '.') { |
| 221 | continue; |
| 222 | } |
| 223 | if (!fileFilter(candidate)) { |
| 224 | finalResults.push(candidate); |
| 225 | } |
| 226 | } |
| 227 | return finalResults; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | export class FileSearchFactory { |
| 232 | static create(options: FileSearchOptions): FileSearch { |
nothing calls this directly
no outgoing calls
no test coverage detected