Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tsc/internal/compiler/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -1746,8 +1746,8 @@ func (p *Program) CommonSourceDirectory() string {
func (p *Program) checkSourceFilesBelongToPath(sourceFiles []string, rootDirectory string) bool {
allFilesBelongToPath := true
for _, file := range sourceFiles {
absoluteSourceFilePath := tspath.GetCanonicalFileName(tspath.GetNormalizedAbsolutePath(file, p.GetCurrentDirectory()), p.UseCaseSensitiveFileNames())
if !tspath.ContainsPath(rootDirectory, file, p.comparePathsOptions) {
absoluteSourceFilePath := tspath.GetCanonicalFileName(tspath.GetNormalizedAbsolutePath(file, p.GetCurrentDirectory()), p.UseCaseSensitiveFileNames())
p.includeProcessor.addProcessingDiagnostic(&processingDiagnostic{
kind: processingDiagnosticKindExplainingFileInclude,
data: &includeExplainingDiagnostic{
Expand Down
38 changes: 38 additions & 0 deletions tsc/internal/tspath/combinepaths_diff_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package tspath

import (
"testing"

"gotest.tools/v3/assert"
)

// CombinePaths' fast paths must be pure shortcuts of combinePathsSlow, which is
// the unmodified pre-fast-path implementation. This test compares the two
// directly over all combinations of representative path pieces.

var combinePathsPieces = []string{
"", "/", "a", "a/b", "/abs", "/abs/child", "c:/drive", "c:relative",
"..", "../up", ".", "./same", "file:///url", "with\\backslash", "\\\\server\\share",
"trailing/", "/trailing/", "//",
}

func TestCombinePathsMatchesSlowPath(t *testing.T) {
t.Parallel()

// All (first), (first, p1), and (first, p1, p2) combinations.
for _, first := range combinePathsPieces {
got := CombinePaths(first)
want := combinePathsSlow(first, nil)
assert.Equal(t, got, want, "CombinePaths(%q)", first)
for _, p1 := range combinePathsPieces {
got := CombinePaths(first, p1)
want := combinePathsSlow(first, []string{p1})
assert.Equal(t, got, want, "CombinePaths(%q, %q)", first, p1)
for _, p2 := range combinePathsPieces {
got := CombinePaths(first, p1, p2)
want := combinePathsSlow(first, []string{p1, p2})
assert.Equal(t, got, want, "CombinePaths(%q, %q, %q)", first, p1, p2)
}
}
}
}
19 changes: 17 additions & 2 deletions tsc/internal/tspath/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,23 @@ func HasTrailingDirectorySeparator(path string) bool {
// CombinePaths("file:///path", "file:///to", "file.ext") === "file:///to/file.ext"
// ```
func CombinePaths(firstPath string, paths ...string) string {
// TODO (drosen): There is potential for a fast path here.
// In the case where we find the last absolute path and just path.Join from there.
// Fast paths: no trailing paths, or the last trailing path is slash-rooted
// and supersedes everything before it. NormalizeSlashes does not allocate unless
// the path contains backslashes.
if len(paths) == 0 {
return NormalizeSlashes(firstPath)
}
// Only recognize slash-rooted paths here to keep the check cheap;
// drive-letter and URL-rooted paths take the general path below.
if p := paths[len(paths)-1]; p != "" && p[0] == '/' && strings.IndexByte(p, '\\') < 0 {
return p
}
// The general case is kept byte-for-byte unchanged as combinePathsSlow,
// which also serves as the differential-test oracle for the fast paths.
return combinePathsSlow(firstPath, paths)
}

func combinePathsSlow(firstPath string, paths []string) string {
firstPath = NormalizeSlashes(firstPath)

var b strings.Builder
Expand Down
2 changes: 2 additions & 0 deletions tsc/internal/tspath/path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ func BenchmarkCombinePaths(b *testing.B) {
{"/path", "/to", "file.ext"},
{"c:/path", "to", "file.ext"},
{"file:///path", "to", "file.ext"},
{"/path", "/abs/to/file.ext"},
{"/lone/path/to/file.ext"},
}

for _, test := range tests {
Expand Down