Skip to content

Commit e249e6d

Browse files
committed
perf: add fast path checks when resolving config (#437)
- part of #295 For a directory with ~860 files in it, a ~26% improvement: <img width="1185" height="239" alt="Screenshot 2025-11-18 at 12 18 22 AM" src="https://github.com/user-attachments/assets/01b05dd9-6c83-4669-a4ce-8471afe9ef40" /> I tested a subset of `kibana` locally on my laptop that had 6.6k files in it and it was a much more modest improvement of about 4%. So this is a "small project" optimization that will largely benefit small libraries or projects, and will slightly improve performance for large monorepos. Here are some examples running on the same set of ~850 files in each case: ### Before Taking up over a gigabyte in total allocations, and represents over 40% of all allocations: <img width="713" height="286" alt="Screenshot 2025-11-18 at 12 12 17 AM" src="https://github.com/user-attachments/assets/6b44863c-98a8-4dfd-9292-e9b365aefa8d" /> <img width="1227" height="350" alt="Screenshot 2025-11-17 at 11 27 19 PM" src="https://github.com/user-attachments/assets/cbcd14c5-9ba7-4408-b124-f140cbbc3748" /> ### After Takes up only 0.6% of the total allocations and a few megabytes: <img width="467" height="211" alt="Screenshot 2025-11-18 at 9 56 06 AM" src="https://github.com/user-attachments/assets/69d88e09-d9bd-4194-a600-845ddd065cbd" /> <img width="546" height="279" alt="Screenshot 2025-11-18 at 9 54 53 AM" src="https://github.com/user-attachments/assets/c15fae1b-82ff-42e2-92b4-5fac1736306e" />
1 parent 06d4607 commit e249e6d

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

internal/utils/find_tsconfig.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package utils
22

33
import (
4+
"path/filepath"
45
"slices"
6+
"strings"
57

68
"github.com/microsoft/typescript-go/shim/core"
79
"github.com/microsoft/typescript-go/shim/project"
@@ -106,8 +108,38 @@ func (r *TsConfigResolver) findConfigWithReferences(
106108
}
107109
}
108110

109-
if slices.ContainsFunc(config.FileNames(), func(fn string) bool {
110-
return r.toPath(fn) == path
111+
if slices.ContainsFunc(config.FileNames(), func(file string) bool {
112+
// Fast checks:
113+
// 1) check if the strings happen to already be equal (subject to case sensitivity of FS)
114+
// 2) check if the base names are equal (subject to case sensitivity of FS)
115+
116+
// If we're on a case-insensitive FS and the strings are equal, we can return true immediately,
117+
// no need to allocate and do any path conversions.
118+
if r.fs.UseCaseSensitiveFileNames() {
119+
if file == string(path) {
120+
return true
121+
}
122+
} else {
123+
if strings.EqualFold(file, string(path)) {
124+
return true
125+
}
126+
}
127+
128+
// If the base names don't match, we can return false immediately.
129+
pathBaseName := filepath.Base(string(path))
130+
fileBaseName := filepath.Base(file)
131+
if r.fs.UseCaseSensitiveFileNames() {
132+
if fileBaseName != pathBaseName {
133+
return false
134+
}
135+
} else {
136+
if !strings.EqualFold(fileBaseName, pathBaseName) {
137+
return false
138+
}
139+
}
140+
141+
// Finally, do a full path conversion and comparison (note: this allocates)
142+
return r.toPath(file) == path
111143
}) {
112144
return true, true
113145
}

0 commit comments

Comments
 (0)