Files
kjol/tools/tsgo/internal/execute/watchmanager/watchbackend.go
2026-07-09 16:50:43 -04:00

119 lines
3.2 KiB
Go

package watchmanager
import (
"io"
"strings"
"github.com/microsoft/typescript-go/internal/fswatch"
"github.com/microsoft/typescript-go/internal/tspath"
)
// WatchBackend abstracts fswatch.Watcher for testing
type WatchBackend interface {
WatchDirectory(dir string, fn fswatch.WatchCallback, recursive bool, ignore func(string) bool) (io.Closer, error)
WatchDirectories(requests []WatchDirectoryRequest) ([]io.Closer, error)
}
type WatchDirectoryRequest struct {
Dir string
Callback fswatch.WatchCallback
Recursive bool
Ignore func(string) bool
}
// CommandLineTestingWithWatchBackend is an optional extension of
// [CommandLineTesting] that supplies a [WatchBackend] for test mode
type CommandLineTestingWithWatchBackend interface {
WatchBackend() WatchBackend
}
type FSWatchBackend struct{ Inner fswatch.Watcher }
func (b *FSWatchBackend) WatchDirectory(dir string, fn fswatch.WatchCallback, recursive bool, ignore func(string) bool) (io.Closer, error) {
closers, err := b.WatchDirectories([]WatchDirectoryRequest{{
Dir: dir,
Callback: fn,
Recursive: recursive,
Ignore: ignore,
}})
if err != nil {
return nil, err
}
return closers[0], nil
}
func (b *FSWatchBackend) WatchDirectories(requests []WatchDirectoryRequest) ([]io.Closer, error) {
fswatchRequests := make([]fswatch.WatchDirectoryRequest, len(requests))
for i, request := range requests {
var opts []fswatch.WatchOption
if request.Recursive {
opts = append(opts, fswatch.WithRecursive())
}
if request.Ignore != nil {
opts = append(opts, fswatch.WithIgnore(request.Ignore))
}
fswatchRequests[i] = fswatch.WatchDirectoryRequest{
Dir: request.Dir,
Callback: request.Callback,
Options: opts,
}
}
watches, err := b.Inner.WatchDirectories(fswatchRequests)
if err != nil {
return nil, err
}
closers := make([]io.Closer, len(watches))
for i, watch := range watches {
closers[i] = watch
}
return closers, nil
}
func ShouldIgnoreWatchPath(path string) bool {
p := tspath.NormalizeSlashes(path)
return strings.HasSuffix(p, "/.git") ||
strings.Contains(p, "/.git/") ||
strings.Contains(p, "/node_modules/.") ||
strings.Contains(p, "/.#")
}
func CanWatchDirectory(dir string) bool {
components := tspath.GetPathComponents(dir, "")
length := len(components)
if length <= 2 {
return false
}
rootLength := PerceivedOsRootLengthForWatching(components)
return length > rootLength+1
}
func PerceivedOsRootLengthForWatching(components []string) int {
length := len(components)
if length <= 1 {
return 1
}
root := components[0]
indexAfterOsRoot := 1
isDosStyle := len(root) >= 2 && tspath.IsVolumeCharacter(root[0]) && root[1] == ':'
if root != "/" && !isDosStyle && len(components) > 1 {
if len(components[1]) >= 2 && tspath.IsVolumeCharacter(components[1][0]) && strings.HasSuffix(components[1], "$") {
if length == 2 {
return 2
}
indexAfterOsRoot = 2
isDosStyle = true
}
}
if isDosStyle && (indexAfterOsRoot >= length || !strings.EqualFold(components[indexAfterOsRoot], "users")) {
return indexAfterOsRoot
}
if indexAfterOsRoot < length && strings.EqualFold(components[indexAfterOsRoot], "workspaces") {
return indexAfterOsRoot + 1
}
return indexAfterOsRoot + 2
}