(root: string, relativePath: string)
| 169 | } |
| 170 | |
| 171 | async function statFile(root: string, relativePath: string): Promise<FeedbackCodebaseFile | null> { |
| 172 | const absolutePath = resolve(root, relativePath); |
| 173 | // A tracked file can be deleted from the working tree but still listed by |
| 174 | // `git ls-files`; lstat then throws ENOENT. Treat unreadable/vanished paths |
| 175 | // like any other non-regular entry so one bad path does not abort the scan. |
| 176 | const stat = await lstat(absolutePath).catch(() => null); |
| 177 | if (stat === null || stat.isSymbolicLink() || !stat.isFile()) return null; |
| 178 | |
| 179 | return { |
| 180 | path: toPosixPath(relativePath), |
| 181 | absolutePath, |
| 182 | size: stat.size, |
| 183 | mtimeMs: stat.mtimeMs, |
| 184 | }; |
| 185 | } |
| 186 | |
| 187 | function throwIfAborted(signal?: AbortSignal): void { |
| 188 | if (signal?.aborted) { |
no test coverage detected