(projectRoot: string)
| 253 | * The returned string is a human phrase that slots into "… looks like {reason}". |
| 254 | */ |
| 255 | export function unsafeIndexRootReason(projectRoot: string): string | null { |
| 256 | const resolve = (p: string): string => { |
| 257 | try { |
| 258 | return fs.realpathSync(path.resolve(p)); |
| 259 | } catch { |
| 260 | return path.resolve(p); |
| 261 | } |
| 262 | }; |
| 263 | const resolved = resolve(projectRoot); |
| 264 | |
| 265 | // Filesystem root: `/` on POSIX, a drive root like `C:\` on Windows. |
| 266 | if (path.parse(resolved).root === resolved) { |
| 267 | return 'the filesystem root'; |
| 268 | } |
| 269 | |
| 270 | const home = resolve(os.homedir()); |
| 271 | // Case-insensitive on macOS/Windows (case-preserving but case-insensitive FS). |
| 272 | const norm = (p: string): string => |
| 273 | process.platform === 'darwin' || process.platform === 'win32' ? p.toLowerCase() : p; |
| 274 | const r = norm(resolved); |
| 275 | const h = norm(home); |
| 276 | |
| 277 | if (r === h) { |
| 278 | return 'your home directory'; |
| 279 | } |
| 280 | // An ancestor of home (e.g. `/Users`, `/home`) — even broader than home. |
| 281 | if (h.startsWith(r + path.sep)) { |
| 282 | return 'a parent of your home directory'; |
| 283 | } |
| 284 | return null; |
| 285 | } |
| 286 | |
| 287 | /** |
| 288 | * `dev:ino` for a path, or null if it can't be stat'd or the platform doesn't |
no test coverage detected