1import type * as Path from "effect/Path";
2
3import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion";
4
5/**
6 * Directory new worktrees are created under: the `worktreesDirectory`
7 * setting (`~` expands to `home`), or `defaultDir` (`<T3 home>/worktrees`)
8 * when it is empty. Null when
9 * the setting is not an absolute path on this machine, such as `D:\worktrees`
10 * configured for a Windows server and synced to a Linux one, or when it is a
11 * filesystem root, which would make every path on that drive look managed.
12 */
13export function resolveWorktreesDirectory(
14 setting: string,
15 defaultDir: string,
16 path: Path.Path,
17 home: string,
18): string | null {
19 if (setting === "") return defaultDir;
20 const expanded = expandHomePath(setting, home);
21 if (!path.isAbsolute(expanded)) return null;
22 const resolved = path.resolve(expanded);
23 return isFilesystemRoot(resolved, path) ? null : resolved;
24}
25
26/** Callers re-check after resolving symlinks: a link can point at a root. */
27export function isFilesystemRoot(directory: string, path: Path.Path): boolean {
28 return path.dirname(directory) === directory;
29}
30
31/** Every directory that holds T3-managed worktrees on this machine. */
32export function managedWorktreesDirectories(
33 settings: {
34 readonly worktreesDirectory: string;
35 readonly previousWorktreesDirectories: ReadonlyArray<string>;
36 },
37 defaultDir: string,
38 path: Path.Path,
39 home: string,
40): ReadonlyArray<string> {
41 const directories = new Set([defaultDir]);
42 for (const setting of [settings.worktreesDirectory, ...settings.previousWorktreesDirectories]) {
43 const directory = resolveWorktreesDirectory(setting, defaultDir, path, home);
44 if (directory !== null) directories.add(directory);
45 }
46 return [...directories];
47}