vendor tsgo
This commit is contained in:
198
tools/tsgo/internal/tspath/extension.go
Normal file
198
tools/tsgo/internal/tspath/extension.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package tspath
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
ExtensionTs = ".ts"
|
||||
ExtensionTsx = ".tsx"
|
||||
ExtensionDts = ".d.ts"
|
||||
ExtensionJs = ".js"
|
||||
ExtensionJsx = ".jsx"
|
||||
ExtensionJson = ".json"
|
||||
ExtensionTsBuildInfo = ".tsbuildinfo"
|
||||
ExtensionMjs = ".mjs"
|
||||
ExtensionMts = ".mts"
|
||||
ExtensionDmts = ".d.mts"
|
||||
ExtensionCjs = ".cjs"
|
||||
ExtensionCts = ".cts"
|
||||
ExtensionDcts = ".d.cts"
|
||||
)
|
||||
|
||||
var (
|
||||
SupportedDeclarationExtensions = []string{ExtensionDts, ExtensionDcts, ExtensionDmts}
|
||||
SupportedTSImplementationExtensions = []string{ExtensionTs, ExtensionTsx, ExtensionMts, ExtensionCts}
|
||||
supportedTSExtensionsForExtractExtension = []string{ExtensionDts, ExtensionDcts, ExtensionDmts, ExtensionTs, ExtensionTsx, ExtensionMts, ExtensionCts}
|
||||
AllSupportedExtensions = [][]string{{ExtensionTs, ExtensionTsx, ExtensionDts, ExtensionJs, ExtensionJsx}, {ExtensionCts, ExtensionDcts, ExtensionCjs}, {ExtensionMts, ExtensionDmts, ExtensionMjs}}
|
||||
SupportedTSExtensions = [][]string{{ExtensionTs, ExtensionTsx, ExtensionDts}, {ExtensionCts, ExtensionDcts}, {ExtensionMts, ExtensionDmts}}
|
||||
SupportedTSExtensionsFlat = []string{ExtensionTs, ExtensionTsx, ExtensionDts, ExtensionCts, ExtensionDcts, ExtensionMts, ExtensionDmts}
|
||||
SupportedJSExtensions = [][]string{{ExtensionJs, ExtensionJsx}, {ExtensionMjs}, {ExtensionCjs}}
|
||||
SupportedJSExtensionsFlat = []string{ExtensionJs, ExtensionJsx, ExtensionMjs, ExtensionCjs}
|
||||
AllSupportedExtensionsWithJson = slices.Concat(AllSupportedExtensions, [][]string{{ExtensionJson}})
|
||||
SupportedTSExtensionsWithJson = slices.Concat(SupportedTSExtensions, [][]string{{ExtensionJson}})
|
||||
SupportedTSExtensionsWithJsonFlat = slices.Concat(SupportedTSExtensionsFlat, []string{ExtensionJson})
|
||||
ExtensionsNotSupportingExtensionlessResolution = []string{ExtensionMts, ExtensionDmts, ExtensionMjs, ExtensionCts, ExtensionDcts, ExtensionCjs}
|
||||
)
|
||||
|
||||
func ExtensionIsTs(ext string) bool {
|
||||
return ext == ExtensionTs || ext == ExtensionTsx || ext == ExtensionDts || ext == ExtensionMts || ext == ExtensionDmts || ext == ExtensionCts || ext == ExtensionDcts || len(ext) >= 7 && ext[:3] == ".d." && ext[len(ext)-3:] == ".ts"
|
||||
}
|
||||
|
||||
var extensionsToRemove = []string{ExtensionDts, ExtensionDmts, ExtensionDcts, ExtensionMjs, ExtensionMts, ExtensionCjs, ExtensionCts, ExtensionTs, ExtensionJs, ExtensionTsx, ExtensionJsx, ExtensionJson}
|
||||
|
||||
func RemoveFileExtension(path string) string {
|
||||
// Remove any known extension even if it has more than one dot
|
||||
for _, ext := range extensionsToRemove {
|
||||
if strings.HasSuffix(path, ext) {
|
||||
return path[:len(path)-len(ext)]
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func TryGetExtensionFromPath(p string) string {
|
||||
for _, ext := range extensionsToRemove {
|
||||
if FileExtensionIs(p, ext) {
|
||||
return ext
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func RemoveExtension(path string, extension string) string {
|
||||
return path[:len(path)-len(extension)]
|
||||
}
|
||||
|
||||
func FileExtensionIsOneOf(path string, extensions []string) bool {
|
||||
for _, ext := range extensions {
|
||||
if FileExtensionIs(path, ext) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TryExtractTSExtension(fileName string) string {
|
||||
for _, ext := range supportedTSExtensionsForExtractExtension {
|
||||
if FileExtensionIs(fileName, ext) {
|
||||
return ext
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func HasTSFileExtension(path string) bool {
|
||||
return FileExtensionIsOneOf(path, SupportedTSExtensionsFlat)
|
||||
}
|
||||
|
||||
func HasImplementationTSFileExtension(path string) bool {
|
||||
return FileExtensionIsOneOf(path, SupportedTSImplementationExtensions) && !IsDeclarationFileName(path)
|
||||
}
|
||||
|
||||
func HasJSFileExtension(path string) bool {
|
||||
return FileExtensionIsOneOf(path, SupportedJSExtensionsFlat)
|
||||
}
|
||||
|
||||
func HasJSONFileExtension(path string) bool {
|
||||
return FileExtensionIs(path, ExtensionJson)
|
||||
}
|
||||
|
||||
func IsDeclarationFileName(fileName string) bool {
|
||||
return GetDeclarationFileExtension(fileName) != ""
|
||||
}
|
||||
|
||||
func ExtensionIsOneOf(ext string, extensions []string) bool {
|
||||
return slices.Contains(extensions, ext)
|
||||
}
|
||||
|
||||
func GetDeclarationFileExtension(fileName string) string {
|
||||
base := GetBaseFileName(fileName)
|
||||
for _, ext := range SupportedDeclarationExtensions {
|
||||
if strings.HasSuffix(base, ext) {
|
||||
return ext
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(base, ExtensionTs) {
|
||||
index := strings.Index(base, ".d.")
|
||||
if index >= 0 {
|
||||
return base[index:]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetDeclarationEmitExtensionForPath(path string) string {
|
||||
switch {
|
||||
case FileExtensionIsOneOf(path, []string{ExtensionMjs, ExtensionMts}):
|
||||
return ExtensionDmts
|
||||
case FileExtensionIsOneOf(path, []string{ExtensionCjs, ExtensionCts}):
|
||||
return ExtensionDcts
|
||||
case FileExtensionIsOneOf(path, []string{ExtensionTs, ExtensionTsx, ExtensionJs, ExtensionJsx}):
|
||||
return ExtensionDts
|
||||
default:
|
||||
ext := GetAnyExtensionFromPath(path, nil, false)
|
||||
if ext != "" {
|
||||
return ".d" + ext + ".ts"
|
||||
}
|
||||
return ExtensionDts
|
||||
}
|
||||
}
|
||||
|
||||
// ChangeAnyExtension changes the extension of a path to the provided extension if it has one of the provided extensions.
|
||||
//
|
||||
// ChangeAnyExtension("/path/to/file.ext", ".js", ".ext") === "/path/to/file.js"
|
||||
// ChangeAnyExtension("/path/to/file.ext", ".js", ".ts") === "/path/to/file.ext"
|
||||
// ChangeAnyExtension("/path/to/file.ext", ".js", [".ext", ".ts"]) === "/path/to/file.js"
|
||||
func ChangeAnyExtension(path string, ext string, extensions []string, ignoreCase bool) string {
|
||||
pathext := GetAnyExtensionFromPath(path, extensions, ignoreCase)
|
||||
if pathext != "" {
|
||||
result := path[:len(path)-len(pathext)]
|
||||
if ext == "" {
|
||||
return result
|
||||
}
|
||||
if strings.HasPrefix(ext, ".") {
|
||||
return result + ext
|
||||
}
|
||||
return result + "." + ext
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func ChangeExtension(path string, newExtension string) string {
|
||||
return ChangeAnyExtension(path, newExtension, extensionsToRemove, false /*ignoreCase*/)
|
||||
}
|
||||
|
||||
// Like `changeAnyExtension`, but declaration file extensions are recognized
|
||||
// and replaced starting from the `.d`.
|
||||
//
|
||||
// changeAnyExtension("file.d.ts", ".js") === "file.d.js"
|
||||
// changeFullExtension("file.d.ts", ".js") === "file.js"
|
||||
func ChangeFullExtension(path string, newExtension string) string {
|
||||
declarationExtension := GetDeclarationFileExtension(path)
|
||||
if declarationExtension != "" {
|
||||
ext := newExtension
|
||||
if !strings.HasPrefix(ext, ".") {
|
||||
ext = "." + ext
|
||||
}
|
||||
return path[:len(path)-len(declarationExtension)] + ext
|
||||
}
|
||||
return ChangeExtension(path, newExtension)
|
||||
}
|
||||
|
||||
func GetPossibleOriginalInputExtensionForExtension(path string) []string {
|
||||
if FileExtensionIsOneOf(path, []string{ExtensionDmts, ExtensionMjs, ExtensionMts}) {
|
||||
return []string{ExtensionMts, ExtensionMjs}
|
||||
}
|
||||
if FileExtensionIsOneOf(path, []string{ExtensionDcts, ExtensionCjs, ExtensionCts}) {
|
||||
return []string{ExtensionCts, ExtensionCjs}
|
||||
}
|
||||
// Handle any custom .d.x.ts extension (e.g., .d.json.ts -> .json, .d.css.ts -> .css)
|
||||
if ext := GetDeclarationFileExtension(path); ext != "" && ext != ExtensionDts {
|
||||
inner := ext[len(".d.") : len(ext)-len(".ts")]
|
||||
return []string{"." + inner}
|
||||
}
|
||||
return []string{ExtensionTsx, ExtensionTs, ExtensionJsx, ExtensionJs}
|
||||
}
|
||||
18
tools/tsgo/internal/tspath/ignoredpaths.go
Normal file
18
tools/tsgo/internal/tspath/ignoredpaths.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package tspath
|
||||
|
||||
import "strings"
|
||||
|
||||
var ignoredPaths = []string{
|
||||
"/node_modules/.",
|
||||
"/.git",
|
||||
".#",
|
||||
}
|
||||
|
||||
func ContainsIgnoredPath(path string) bool {
|
||||
for _, pattern := range ignoredPaths {
|
||||
if strings.Contains(path, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
133
tools/tsgo/internal/tspath/ignoredpaths_test.go
Normal file
133
tools/tsgo/internal/tspath/ignoredpaths_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package tspath
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestContainsIgnoredPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "node_modules dot path",
|
||||
path: "/project/node_modules/.pnpm/file.ts",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "git directory",
|
||||
path: "/project/.git/hooks/pre-commit",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "emacs lock file",
|
||||
path: "/project/src/file.ts.#",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "regular file path",
|
||||
path: "/project/src/file.ts",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "node_modules without dot",
|
||||
path: "/project/node_modules/lodash/index.js",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty path",
|
||||
path: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "path with multiple ignored patterns",
|
||||
path: "/project/node_modules/.pnpm/.git/.#file.ts",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "case sensitive test",
|
||||
path: "/project/NODE_MODULES/.PNPM/file.ts",
|
||||
expected: false, // Should be case sensitive
|
||||
},
|
||||
{
|
||||
name: "path with ignored pattern in middle",
|
||||
path: "/project/src/node_modules/.pnpm/dist/file.js",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "path with ignored pattern at end",
|
||||
path: "/project/src/file.ts.#",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result := ContainsIgnoredPath(tt.path)
|
||||
if result != tt.expected {
|
||||
t.Errorf("ContainsIgnoredPath(%q) = %v, expected %v", tt.path, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoredPathsPatterns(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Test that all expected patterns are present
|
||||
expectedPatterns := []string{"/node_modules/.", "/.git", ".#"}
|
||||
|
||||
for _, pattern := range expectedPatterns {
|
||||
testPath := "/test" + pattern + "/file.ts"
|
||||
if !ContainsIgnoredPath(testPath) {
|
||||
t.Errorf("Expected pattern '%s' to be detected in path '%s'", pattern, testPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoredPathsEdgeCases(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "pattern at start",
|
||||
path: "/node_modules./file.ts",
|
||||
expected: false, // Pattern is "/node_modules/." not "/node_modules."
|
||||
},
|
||||
{
|
||||
name: "pattern at end",
|
||||
path: "/project/file.ts.#",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "multiple occurrences",
|
||||
path: "/project/.git/node_modules./.git/file.ts",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "no slashes",
|
||||
path: "node_modules.file.ts",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "single slash",
|
||||
path: "/file.ts",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result := ContainsIgnoredPath(tt.path)
|
||||
if result != tt.expected {
|
||||
t.Errorf("ContainsIgnoredPath(%q) = %v, expected %v", tt.path, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
1219
tools/tsgo/internal/tspath/path.go
Normal file
1219
tools/tsgo/internal/tspath/path.go
Normal file
File diff suppressed because it is too large
Load Diff
818
tools/tsgo/internal/tspath/path_test.go
Normal file
818
tools/tsgo/internal/tspath/path_test.go
Normal file
@@ -0,0 +1,818 @@
|
||||
package tspath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestNormalizeSlashes(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, NormalizeSlashes("a"), "a")
|
||||
assert.Equal(t, NormalizeSlashes("a/b"), "a/b")
|
||||
assert.Equal(t, NormalizeSlashes("a\\b"), "a/b")
|
||||
assert.Equal(t, NormalizeSlashes("\\\\server\\path"), "//server/path")
|
||||
}
|
||||
|
||||
func TestGetRootLength(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, GetRootLength("a"), 0)
|
||||
assert.Equal(t, GetRootLength("/"), 1)
|
||||
assert.Equal(t, GetRootLength("/path"), 1)
|
||||
assert.Equal(t, GetRootLength("c:"), 2)
|
||||
assert.Equal(t, GetRootLength("c:d"), 0)
|
||||
assert.Equal(t, GetRootLength("c:/"), 3)
|
||||
assert.Equal(t, GetRootLength("c:\\"), 3)
|
||||
assert.Equal(t, GetRootLength("//server"), 8)
|
||||
assert.Equal(t, GetRootLength("//server/share"), 9)
|
||||
assert.Equal(t, GetRootLength("\\\\server"), 8)
|
||||
assert.Equal(t, GetRootLength("\\\\server\\share"), 9)
|
||||
assert.Equal(t, GetRootLength("file:///"), 8)
|
||||
assert.Equal(t, GetRootLength("file:///path"), 8)
|
||||
assert.Equal(t, GetRootLength("file:///c:"), 10)
|
||||
assert.Equal(t, GetRootLength("file:///c:d"), 8)
|
||||
assert.Equal(t, GetRootLength("file:///c:/path"), 11)
|
||||
assert.Equal(t, GetRootLength("file:///c%3a"), 12)
|
||||
assert.Equal(t, GetRootLength("file:///c%3ad"), 8)
|
||||
assert.Equal(t, GetRootLength("file:///c%3a/path"), 13)
|
||||
assert.Equal(t, GetRootLength("file:///c%3A"), 12)
|
||||
assert.Equal(t, GetRootLength("file:///c%3Ad"), 8)
|
||||
assert.Equal(t, GetRootLength("file:///c%3A/path"), 13)
|
||||
assert.Equal(t, GetRootLength("file://localhost"), 16)
|
||||
assert.Equal(t, GetRootLength("file://localhost/"), 17)
|
||||
assert.Equal(t, GetRootLength("file://localhost/path"), 17)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c:"), 19)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c:d"), 17)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c:/path"), 20)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c%3a"), 21)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c%3ad"), 17)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c%3a/path"), 22)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c%3A"), 21)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c%3Ad"), 17)
|
||||
assert.Equal(t, GetRootLength("file://localhost/c%3A/path"), 22)
|
||||
assert.Equal(t, GetRootLength("file://server"), 13)
|
||||
assert.Equal(t, GetRootLength("file://server/"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/path"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c:"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c:d"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c:/d"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c%3a"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c%3ad"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c%3a/d"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c%3A"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c%3Ad"), 14)
|
||||
assert.Equal(t, GetRootLength("file://server/c%3A/d"), 14)
|
||||
assert.Equal(t, GetRootLength("http://server"), 13)
|
||||
assert.Equal(t, GetRootLength("http://server/path"), 14)
|
||||
}
|
||||
|
||||
func TestPathIsAbsolute(t *testing.T) {
|
||||
t.Parallel()
|
||||
// POSIX
|
||||
assert.Equal(t, PathIsAbsolute("/path/to/file.ext"), true)
|
||||
// DOS
|
||||
assert.Equal(t, PathIsAbsolute("c:/path/to/file.ext"), true)
|
||||
// URL
|
||||
assert.Equal(t, PathIsAbsolute("file:///path/to/file.ext"), true)
|
||||
// Non-absolute
|
||||
assert.Equal(t, PathIsAbsolute("path/to/file.ext"), false)
|
||||
assert.Equal(t, PathIsAbsolute("./path/to/file.ext"), false)
|
||||
}
|
||||
|
||||
func TestIsUrl(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, IsUrl("a"), false)
|
||||
assert.Equal(t, IsUrl("/"), false)
|
||||
assert.Equal(t, IsUrl("c:"), false)
|
||||
assert.Equal(t, IsUrl("c:d"), false)
|
||||
assert.Equal(t, IsUrl("c:/"), false)
|
||||
assert.Equal(t, IsUrl("c:\\"), false)
|
||||
assert.Equal(t, IsUrl("//server"), false)
|
||||
assert.Equal(t, IsUrl("//server/share"), false)
|
||||
assert.Equal(t, IsUrl("\\\\server"), false)
|
||||
assert.Equal(t, IsUrl("\\\\server\\share"), false)
|
||||
|
||||
assert.Equal(t, IsUrl("file:///path"), true)
|
||||
assert.Equal(t, IsUrl("file:///c:"), true)
|
||||
assert.Equal(t, IsUrl("file:///c:d"), true)
|
||||
assert.Equal(t, IsUrl("file:///c:/path"), true)
|
||||
assert.Equal(t, IsUrl("file://server"), true)
|
||||
assert.Equal(t, IsUrl("file://server/path"), true)
|
||||
assert.Equal(t, IsUrl("http://server"), true)
|
||||
assert.Equal(t, IsUrl("http://server/path"), true)
|
||||
}
|
||||
|
||||
func TestIsRootedDiskPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, IsRootedDiskPath("a"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("/"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("c:"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("c:d"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("c:/"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("c:\\"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("//server"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("//server/share"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("\\\\server"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("\\\\server\\share"), true)
|
||||
assert.Equal(t, IsRootedDiskPath("file:///path"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("file:///c:"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("file:///c:d"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("file:///c:/path"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("file://server"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("file://server/path"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("http://server"), false)
|
||||
assert.Equal(t, IsRootedDiskPath("http://server/path"), false)
|
||||
}
|
||||
|
||||
func TestGetDirectoryPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, GetDirectoryPath(""), "")
|
||||
assert.Equal(t, GetDirectoryPath("a"), "")
|
||||
assert.Equal(t, GetDirectoryPath("a/b"), "a")
|
||||
assert.Equal(t, GetDirectoryPath("/"), "/")
|
||||
assert.Equal(t, GetDirectoryPath("/a"), "/")
|
||||
assert.Equal(t, GetDirectoryPath("/a/"), "/")
|
||||
assert.Equal(t, GetDirectoryPath("/a/b"), "/a")
|
||||
assert.Equal(t, GetDirectoryPath("/a/b/"), "/a")
|
||||
assert.Equal(t, GetDirectoryPath("c:"), "c:")
|
||||
assert.Equal(t, GetDirectoryPath("c:d"), "")
|
||||
assert.Equal(t, GetDirectoryPath("c:/"), "c:/")
|
||||
assert.Equal(t, GetDirectoryPath("c:/path"), "c:/")
|
||||
assert.Equal(t, GetDirectoryPath("c:/path/"), "c:/")
|
||||
assert.Equal(t, GetDirectoryPath("//server"), "//server")
|
||||
assert.Equal(t, GetDirectoryPath("//server/"), "//server/")
|
||||
assert.Equal(t, GetDirectoryPath("//server/share"), "//server/")
|
||||
assert.Equal(t, GetDirectoryPath("//server/share/"), "//server/")
|
||||
assert.Equal(t, GetDirectoryPath("\\\\server"), "//server")
|
||||
assert.Equal(t, GetDirectoryPath("\\\\server\\"), "//server/")
|
||||
assert.Equal(t, GetDirectoryPath("\\\\server\\share"), "//server/")
|
||||
assert.Equal(t, GetDirectoryPath("\\\\server\\share\\"), "//server/")
|
||||
assert.Equal(t, GetDirectoryPath("file:///"), "file:///")
|
||||
assert.Equal(t, GetDirectoryPath("file:///path"), "file:///")
|
||||
assert.Equal(t, GetDirectoryPath("file:///path/"), "file:///")
|
||||
assert.Equal(t, GetDirectoryPath("file:///c:"), "file:///c:")
|
||||
assert.Equal(t, GetDirectoryPath("file:///c:d"), "file:///")
|
||||
assert.Equal(t, GetDirectoryPath("file:///c:/"), "file:///c:/")
|
||||
assert.Equal(t, GetDirectoryPath("file:///c:/path"), "file:///c:/")
|
||||
assert.Equal(t, GetDirectoryPath("file:///c:/path/"), "file:///c:/")
|
||||
assert.Equal(t, GetDirectoryPath("file://server"), "file://server")
|
||||
assert.Equal(t, GetDirectoryPath("file://server/"), "file://server/")
|
||||
assert.Equal(t, GetDirectoryPath("file://server/path"), "file://server/")
|
||||
assert.Equal(t, GetDirectoryPath("file://server/path/"), "file://server/")
|
||||
assert.Equal(t, GetDirectoryPath("http://server"), "http://server")
|
||||
assert.Equal(t, GetDirectoryPath("http://server/"), "http://server/")
|
||||
assert.Equal(t, GetDirectoryPath("http://server/path"), "http://server/")
|
||||
assert.Equal(t, GetDirectoryPath("http://server/path/"), "http://server/")
|
||||
}
|
||||
|
||||
// !!!
|
||||
// getBaseFileName
|
||||
// getAnyExtensionFromPath
|
||||
|
||||
func TestGetPathComponents(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.DeepEqual(t, GetPathComponents("", ""), []string{""})
|
||||
assert.DeepEqual(t, GetPathComponents("a", ""), []string{"", "a"})
|
||||
assert.DeepEqual(t, GetPathComponents("./a", ""), []string{"", ".", "a"})
|
||||
assert.DeepEqual(t, GetPathComponents("/", ""), []string{"/"})
|
||||
assert.DeepEqual(t, GetPathComponents("/a", ""), []string{"/", "a"})
|
||||
assert.DeepEqual(t, GetPathComponents("/a/", ""), []string{"/", "a"})
|
||||
assert.DeepEqual(t, GetPathComponents("c:", ""), []string{"c:"})
|
||||
assert.DeepEqual(t, GetPathComponents("c:d", ""), []string{"", "c:d"})
|
||||
assert.DeepEqual(t, GetPathComponents("c:/", ""), []string{"c:/"})
|
||||
assert.DeepEqual(t, GetPathComponents("c:/path", ""), []string{"c:/", "path"})
|
||||
assert.DeepEqual(t, GetPathComponents("//server", ""), []string{"//server"})
|
||||
assert.DeepEqual(t, GetPathComponents("//server/", ""), []string{"//server/"})
|
||||
assert.DeepEqual(t, GetPathComponents("//server/share", ""), []string{"//server/", "share"})
|
||||
assert.DeepEqual(t, GetPathComponents("file:///", ""), []string{"file:///"})
|
||||
assert.DeepEqual(t, GetPathComponents("file:///path", ""), []string{"file:///", "path"})
|
||||
assert.DeepEqual(t, GetPathComponents("file:///c:", ""), []string{"file:///c:"})
|
||||
assert.DeepEqual(t, GetPathComponents("file:///c:d", ""), []string{"file:///", "c:d"})
|
||||
assert.DeepEqual(t, GetPathComponents("file:///c:/", ""), []string{"file:///c:/"})
|
||||
assert.DeepEqual(t, GetPathComponents("file:///c:/path", ""), []string{"file:///c:/", "path"})
|
||||
assert.DeepEqual(t, GetPathComponents("file://server", ""), []string{"file://server"})
|
||||
assert.DeepEqual(t, GetPathComponents("file://server/", ""), []string{"file://server/"})
|
||||
assert.DeepEqual(t, GetPathComponents("file://server/path", ""), []string{"file://server/", "path"})
|
||||
assert.DeepEqual(t, GetPathComponents("http://server", ""), []string{"http://server"})
|
||||
assert.DeepEqual(t, GetPathComponents("http://server/", ""), []string{"http://server/"})
|
||||
assert.DeepEqual(t, GetPathComponents("http://server/path", ""), []string{"http://server/", "path"})
|
||||
}
|
||||
|
||||
func TestReducePathComponents(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.DeepEqual(t, reducePathComponents([]string{""}), []string{""})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", "."}), []string{""})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", ".", "a"}), []string{"", "a"})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", "a", "."}), []string{"", "a"})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", ".."}), []string{"", ".."})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", "..", ".."}), []string{"", "..", ".."})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", "..", ".", ".."}), []string{"", "..", ".."})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", "a", ".."}), []string{""})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"", "..", "a"}), []string{"", "..", "a"})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"/"}), []string{"/"})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"/", "."}), []string{"/"})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"/", ".."}), []string{"/"})
|
||||
assert.DeepEqual(t, reducePathComponents([]string{"/", "a", ".."}), []string{"/"})
|
||||
}
|
||||
|
||||
func TestCombinePaths(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Non-rooted
|
||||
assert.Equal(t, CombinePaths("path", "to", "file.ext"), "path/to/file.ext")
|
||||
assert.Equal(t, CombinePaths("path", "dir", "..", "to", "file.ext"), "path/dir/../to/file.ext")
|
||||
// POSIX
|
||||
assert.Equal(t, CombinePaths("/path", "to", "file.ext"), "/path/to/file.ext")
|
||||
assert.Equal(t, CombinePaths("/path", "/to", "file.ext"), "/to/file.ext")
|
||||
// DOS
|
||||
assert.Equal(t, CombinePaths("c:/path", "to", "file.ext"), "c:/path/to/file.ext")
|
||||
assert.Equal(t, CombinePaths("c:/path", "c:/to", "file.ext"), "c:/to/file.ext")
|
||||
// URL
|
||||
assert.Equal(t, CombinePaths("file:///path", "to", "file.ext"), "file:///path/to/file.ext")
|
||||
assert.Equal(t, CombinePaths("file:///path", "file:///to", "file.ext"), "file:///to/file.ext")
|
||||
|
||||
assert.Equal(t, CombinePaths("/", "/node_modules/@types"), "/node_modules/@types")
|
||||
assert.Equal(t, CombinePaths("/a/..", ""), "/a/..")
|
||||
assert.Equal(t, CombinePaths("/a/..", "b"), "/a/../b")
|
||||
assert.Equal(t, CombinePaths("/a/..", "b/"), "/a/../b/")
|
||||
assert.Equal(t, CombinePaths("/a/..", "/"), "/")
|
||||
assert.Equal(t, CombinePaths("/a/..", "/b"), "/b")
|
||||
}
|
||||
|
||||
func BenchmarkCombinePaths(b *testing.B) {
|
||||
tests := [][]string{
|
||||
{"path", "to", "file.ext"},
|
||||
{"path", "dir", "..", "to", "file.ext"},
|
||||
{"/path", "to", "file.ext"},
|
||||
{"/path", "/to", "file.ext"},
|
||||
{"c:/path", "to", "file.ext"},
|
||||
{"file:///path", "to", "file.ext"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
name := shortenName(strings.Join(test, "/"))
|
||||
b.Run(name, func(b *testing.B) {
|
||||
first, rest := test[0], test[1:]
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
CombinePaths(first, rest...)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePath(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, ResolvePath(""), "")
|
||||
assert.Equal(t, ResolvePath("."), "")
|
||||
assert.Equal(t, ResolvePath("./"), "")
|
||||
assert.Equal(t, ResolvePath(".."), "..")
|
||||
assert.Equal(t, ResolvePath("../"), "../")
|
||||
assert.Equal(t, ResolvePath("/"), "/")
|
||||
assert.Equal(t, ResolvePath("/."), "/")
|
||||
assert.Equal(t, ResolvePath("/./"), "/")
|
||||
assert.Equal(t, ResolvePath("/../"), "/")
|
||||
assert.Equal(t, ResolvePath("/a"), "/a")
|
||||
assert.Equal(t, ResolvePath("/a/"), "/a/")
|
||||
assert.Equal(t, ResolvePath("/a/."), "/a")
|
||||
assert.Equal(t, ResolvePath("/a/./"), "/a/")
|
||||
assert.Equal(t, ResolvePath("/a/./b"), "/a/b")
|
||||
assert.Equal(t, ResolvePath("/a/./b/"), "/a/b/")
|
||||
assert.Equal(t, ResolvePath("/a/.."), "/")
|
||||
assert.Equal(t, ResolvePath("/a/../"), "/")
|
||||
assert.Equal(t, ResolvePath("/a/../b"), "/b")
|
||||
assert.Equal(t, ResolvePath("/a/../b/"), "/b/")
|
||||
assert.Equal(t, ResolvePath("/a/..", "b"), "/b")
|
||||
assert.Equal(t, ResolvePath("/a/..", "/"), "/")
|
||||
assert.Equal(t, ResolvePath("/a/..", "b/"), "/b/")
|
||||
assert.Equal(t, ResolvePath("/a/..", "/b"), "/b")
|
||||
assert.Equal(t, ResolvePath("/a/.", "b"), "/a/b")
|
||||
assert.Equal(t, ResolvePath("/a/.", "."), "/a")
|
||||
assert.Equal(t, ResolvePath("a", "b", "c"), "a/b/c")
|
||||
assert.Equal(t, ResolvePath("a", "b", "/c"), "/c")
|
||||
assert.Equal(t, ResolvePath("a", "b", "../c"), "a/c")
|
||||
}
|
||||
|
||||
func TestGetNormalizedAbsolutePath(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/.", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/./", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/../", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a", ""), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/", ""), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/.", ""), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/foo.", ""), "/a/foo.")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/./", ""), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/./b", ""), "/a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/./b/", ""), "/a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/..", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/../", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/../", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/../b", ""), "/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/../b/", ""), "/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/..", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/..", "/"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/..", "b/"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/..", "/b"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/.", "b"), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/.", "."), "/a")
|
||||
|
||||
// Tests as above, but with backslashes.
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\.", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\.\\", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\..\\", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\.\\", ""), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\.\\b", ""), "/a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\.\\b\\", ""), "/a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..\\", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..\\", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..\\b", ""), "/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..\\b\\", ""), "/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..", "\\"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..", "b\\"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\..", "\\b"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\.", "b"), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\.", "."), "/a")
|
||||
|
||||
// Relative paths on an empty currentDirectory.
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("", ""), "")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath(".", ""), "")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("./", ""), "")
|
||||
// Strangely, these do not normalize to the empty string.
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("..", ""), "..")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("../", ""), "..")
|
||||
|
||||
// Interaction between relative paths and currentDirectory.
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("", "/home"), "/home")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath(".", "/home"), "/home")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("./", "/home"), "/home")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("..", "/home"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("../", "/home"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a", "b"), "b/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a", "b/c"), "b/c/a")
|
||||
|
||||
// Base names starting or ending with a dot do not affect normalization.
|
||||
assert.Equal(t, GetNormalizedAbsolutePath(".a", ""), ".a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("..a", ""), "..a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a.", ""), "a.")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a..", ""), "a..")
|
||||
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/./.a", ""), "/base/.a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/../.a", ""), "/.a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/./..a", ""), "/base/..a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/../..a", ""), "/..a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/./..a/b", ""), "/base/..a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/../..a/b", ""), "/..a/b")
|
||||
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/./a.", ""), "/base/a.")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/../a.", ""), "/a.")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/./a..", ""), "/base/a..")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/../a..", ""), "/a..")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/./a../b", ""), "/base/a../b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/base/../a../b", ""), "/a../b")
|
||||
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a/..", ""), "")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a//", ""), "/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("//a", "a"), "//a/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/\\", ""), "//")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a///", "a"), "a/a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/.//", ""), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("//\\\\", ""), "///")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath(".//a", "."), "a")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a/../..", ""), "..")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("../..", "\\a"), "/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a:", "b"), "a:/")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a/../..", ".."), "../..")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a/../..", "b"), "")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a//../..", ".."), "../..")
|
||||
|
||||
// Consecutive intermediate slashes are normalized to a single slash.
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a//b", ""), "a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a///b", ""), "a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a/b//c", ""), "a/b/c")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("/a/b//c", ""), "/a/b/c")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("//a/b//c", ""), "//a/b/c")
|
||||
|
||||
// Backslashes are converted to slashes,
|
||||
// and then consecutive intermediate slashes are normalized to a single slash
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a\\\\b", ""), "a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a\\\\\\b", ""), "a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a\\b\\\\c", ""), "a/b/c")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\b\\\\c", ""), "/a/b/c")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\\\a\\b\\\\c", ""), "//a/b/c")
|
||||
|
||||
// The same occurs for mixed slashes.
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a/\\b", ""), "a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a\\/b", ""), "a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a\\/\\b", ""), "a/b")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("a\\b//c", ""), "a/b/c")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\a\\b\\\\c", ""), "/a/b/c")
|
||||
assert.Equal(t, GetNormalizedAbsolutePath("\\\\a\\b\\\\c", ""), "//a/b/c")
|
||||
}
|
||||
|
||||
func TestGetNormalizedAbsolutePathWithoutRoot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, GetNormalizedAbsolutePathWithoutRoot("/a/b/c.txt", "/a/b"), "a/b/c.txt")
|
||||
assert.Equal(t, GetNormalizedAbsolutePathWithoutRoot("c:/work/hello.txt", "c:/work"), "work/hello.txt")
|
||||
assert.Equal(t, GetNormalizedAbsolutePathWithoutRoot("c:/work/hello.txt", "d:/worspaces"), "work/hello.txt")
|
||||
}
|
||||
|
||||
var getNormalizedAbsolutePathTests = map[string][][]string{
|
||||
"non-normalized inputs": {
|
||||
{"/.", ""},
|
||||
{"/./", ""},
|
||||
{"/../", ""},
|
||||
{"/a/", ""},
|
||||
{"/a/.", ""},
|
||||
{"/a/foo.", ""},
|
||||
{"/a/./", ""},
|
||||
{"/a/./b", ""},
|
||||
{"/a/./b/", ""},
|
||||
{"/a/..", ""},
|
||||
{"/a/../", ""},
|
||||
{"/a/../", ""},
|
||||
{"/a/../b", ""},
|
||||
{"/a/../b/", ""},
|
||||
{"/a/..", ""},
|
||||
{"/a/..", "/"},
|
||||
{"/a/..", "b/"},
|
||||
{"/a/..", "/b"},
|
||||
{"/a/.", "b"},
|
||||
{"/a/.", "."},
|
||||
},
|
||||
"normalized inputs": {
|
||||
{"/a/b", ""},
|
||||
{"/one/two/three", ""},
|
||||
{"/users/root/project/src/foo.ts", ""},
|
||||
},
|
||||
"normalized inputs (long)": {
|
||||
{"/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z", ""},
|
||||
{"/one/two/three/four/five/six/seven/eight/nine/ten/eleven/twelve/thirteen/fourteen/fifteen/sixteen/seventeen/eighteen/nineteen/twenty", ""},
|
||||
{"/users/root/project/src/foo/bar/baz/qux/quux/corge/grault/garply/waldo/fred/plugh/xyzzy/thud", ""},
|
||||
{"/lorem/ipsum/dolor/sit/amet/consectetur/adipiscing/elit/sed/do/eiusmod/tempor/incididunt/ut/labore/et/dolore/magna/aliqua/ut/enim/ad/minim/veniam", ""},
|
||||
},
|
||||
}
|
||||
|
||||
func BenchmarkGetNormalizedAbsolutePath(b *testing.B) {
|
||||
funcs := map[string]func(string, string) string{
|
||||
"GetNormalizedAbsolutePath": GetNormalizedAbsolutePath,
|
||||
"GetNormalizedAbsolutePath (old)": getNormalizedAbsolutePath_old,
|
||||
}
|
||||
for name, tests := range getNormalizedAbsolutePathTests {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
for fnName, fn := range funcs {
|
||||
b.Run(fnName, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
for _, test := range tests {
|
||||
fn(test[0], test[1])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzGetNormalizedAbsolutePath(f *testing.F) {
|
||||
for _, tests := range getNormalizedAbsolutePathTests {
|
||||
for _, test := range tests {
|
||||
f.Add(test[0], test[1])
|
||||
}
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, p string, dir string) {
|
||||
assert.Equal(t, GetNormalizedAbsolutePath(p, dir), getNormalizedAbsolutePath_old(p, dir), fmt.Sprintf("p=%q, dir=%q", p, dir))
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetRelativePathToDirectoryOrUrl(t *testing.T) {
|
||||
t.Parallel()
|
||||
// !!!
|
||||
// Based on tests for `getRelativePathFromDirectory`.
|
||||
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/", "/", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a", "/a", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a/", "/a", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a", "/", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "..")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a", "/b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../b")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a/b", "/b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../../b")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a/b/c", "/b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../../../b")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a/b/c", "/b/c", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../../../b/c")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("/a/b/c", "/a/b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "..")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("c:", "d:", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "d:/")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///", "file:///", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a", "file:///a", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a/", "file:///a", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a", "file:///", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "..")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a", "file:///b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../b")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a/b", "file:///b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../../b")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a/b/c", "file:///b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../../../b")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a/b/c", "file:///b/c", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "../../../b/c")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///a/b/c", "file:///a/b", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "..")
|
||||
assert.Equal(t, GetRelativePathToDirectoryOrUrl("file:///c:", "file:///d:", false /*isAbsolutePathAnUrl*/, ComparePathsOptions{}), "file:///d:/")
|
||||
}
|
||||
|
||||
func TestToFileNameLowerCase(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, ToFileNameLowerCase("/user/UserName/projects/Project/file.ts"), "/user/username/projects/project/file.ts")
|
||||
assert.Equal(t, ToFileNameLowerCase("/user/UserName/projects/projectß/file.ts"), "/user/username/projects/projectß/file.ts")
|
||||
assert.Equal(t, ToFileNameLowerCase("/user/UserName/projects/İproject/file.ts"), "/user/username/projects/İproject/file.ts")
|
||||
assert.Equal(t, ToFileNameLowerCase("/user/UserName/projects/ı/file.ts"), "/user/username/projects/ı/file.ts")
|
||||
}
|
||||
|
||||
var toFileNameLowerCaseTests = []string{
|
||||
"/path/to/file.ext",
|
||||
"/PATH/TO/FILE.EXT",
|
||||
"/path/to/FILE.EXT",
|
||||
"/user/UserName/projects/Project/file.ts",
|
||||
"/user/UserName/projects/projectß/file.ts",
|
||||
"/user/UserName/projects/İproject/file.ts",
|
||||
"/user/UserName/projects/ı/file.ts",
|
||||
strings.Repeat("FoO/", 100),
|
||||
}
|
||||
|
||||
// See [toFileNameLowerCase] for more info.
|
||||
//
|
||||
// To avoid having to do string building for most common cases, also ignore
|
||||
// a-z, 0-9, \u0131, \u00DF, \, /, ., : and space
|
||||
var fileNameLowerCaseRegExp = regexp.MustCompile(`[^\x{0130}\x{0131}\x{00DF}a-z0-9\\/:\-_. ]+`)
|
||||
|
||||
func oldToFileNameLowerCase(fileName string) string {
|
||||
return fileNameLowerCaseRegExp.ReplaceAllStringFunc(fileName, strings.ToLower)
|
||||
}
|
||||
|
||||
func BenchmarkToFileNameLowerCase(b *testing.B) {
|
||||
for _, test := range toFileNameLowerCaseTests {
|
||||
name := shortenName(test)
|
||||
b.Run(name, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
ToFileNameLowerCase(test)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzToFileNameLowerCase(f *testing.F) {
|
||||
for _, test := range toFileNameLowerCaseTests {
|
||||
f.Add(test)
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, p string) {
|
||||
assert.Equal(t, oldToFileNameLowerCase(p), ToFileNameLowerCase(p))
|
||||
})
|
||||
}
|
||||
|
||||
func TestToPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, string(ToPath("file.ext", "path/to", false /*useCaseSensitiveFileNames*/)), "path/to/file.ext")
|
||||
assert.Equal(t, string(ToPath("file.ext", "/path/to", true /*useCaseSensitiveFileNames*/)), "/path/to/file.ext")
|
||||
assert.Equal(t, string(ToPath("/path/to/../file.ext", "path/to", true /*useCaseSensitiveFileNames*/)), "/path/file.ext")
|
||||
}
|
||||
|
||||
var relativePathSegmentRegExp = regexp.MustCompile(`//|(?:^|/)\.\.?(?:$|/)`)
|
||||
|
||||
func oldHasRelativePathSegment(p string) bool {
|
||||
return relativePathSegmentRegExp.MatchString(p)
|
||||
}
|
||||
|
||||
var hasRelativePathSegmentTests = []struct {
|
||||
p string
|
||||
bench bool
|
||||
}{
|
||||
{"//", false},
|
||||
{"foo/bar/baz", true},
|
||||
{"foo/./baz", false},
|
||||
{"foo/../baz", false},
|
||||
{"foo/bar/baz/.", false},
|
||||
{"./some/path", true},
|
||||
{"/foo//bar/", false},
|
||||
{"/foo/./bar/../../.", true},
|
||||
{strings.Repeat("foo/", 100) + "..", true},
|
||||
}
|
||||
|
||||
func BenchmarkHasRelativePathSegment(b *testing.B) {
|
||||
for _, tt := range hasRelativePathSegmentTests {
|
||||
if !tt.bench {
|
||||
continue
|
||||
}
|
||||
name := shortenName(tt.p)
|
||||
b.Run(name, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
hasRelativePathSegment(tt.p)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzHasRelativePathSegment(f *testing.F) {
|
||||
for _, tt := range hasRelativePathSegmentTests {
|
||||
f.Add(tt.p)
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, p string) {
|
||||
assert.Equal(t, oldHasRelativePathSegment(p), hasRelativePathSegment(p))
|
||||
})
|
||||
}
|
||||
|
||||
var pathIsRelativeTests = []struct {
|
||||
p string
|
||||
isRelative bool
|
||||
benchmark bool
|
||||
}{
|
||||
// relative
|
||||
{".", true, false},
|
||||
{"..", true, false},
|
||||
{"./", true, false},
|
||||
{"../", true, false},
|
||||
{"./foo/bar", true, true},
|
||||
{"../foo/bar", true, true},
|
||||
{"../" + strings.Repeat("foo/", 100), true, true},
|
||||
// non-relative
|
||||
{"", false, false},
|
||||
{"foo", false, false},
|
||||
{"foo/bar", false, false},
|
||||
{"/foo/bar", false, false},
|
||||
{"c:/foo/bar", false, false},
|
||||
}
|
||||
|
||||
func init() {
|
||||
old := pathIsRelativeTests
|
||||
|
||||
for _, t := range old {
|
||||
t.p = strings.ReplaceAll(t.p, "/", "\\")
|
||||
pathIsRelativeTests = append(pathIsRelativeTests, t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathIsRelative(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, tt := range pathIsRelativeTests {
|
||||
name := shortenName(tt.p)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, PathIsRelative(tt.p), tt.isRelative)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPathIsRelative(b *testing.B) {
|
||||
for _, tt := range pathIsRelativeTests {
|
||||
if !tt.benchmark {
|
||||
continue
|
||||
}
|
||||
name := shortenName(tt.p)
|
||||
b.Run(name, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
PathIsRelative(tt.p)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func shortenName(name string) string {
|
||||
if len(name) > 20 {
|
||||
return name[:20] + "...etc"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func normalizePath_old(path string) string {
|
||||
path = NormalizeSlashes(path)
|
||||
// Most paths don't require normalization
|
||||
if !hasRelativePathSegment(path) {
|
||||
return path
|
||||
}
|
||||
// Some paths only require cleanup of `/./` or leading `./`
|
||||
simplified := strings.ReplaceAll(path, "/./", "/")
|
||||
simplified = strings.TrimPrefix(simplified, "./")
|
||||
if simplified != path && !hasRelativePathSegment(simplified) {
|
||||
path = simplified
|
||||
return path
|
||||
}
|
||||
// Other paths require full normalization
|
||||
normalized := GetPathFromPathComponents(reducePathComponents(GetPathComponents(path, "")))
|
||||
if normalized != "" && HasTrailingDirectorySeparator(path) {
|
||||
normalized = EnsureTrailingDirectorySeparator(normalized)
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
func getNormalizedAbsolutePath_old(fileName string, currentDirectory string) string {
|
||||
return GetPathFromPathComponents(GetNormalizedPathComponents(fileName, currentDirectory))
|
||||
}
|
||||
|
||||
func TestGetCommonParents(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
opts := ComparePathsOptions{}
|
||||
|
||||
t.Run("empty input", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var paths []string
|
||||
got, ignored := GetCommonParents(paths, 1, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
assert.DeepEqual(t, got, ([]string)(nil))
|
||||
})
|
||||
|
||||
t.Run("single path returns itself", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d"}
|
||||
got, ignored := GetCommonParents(paths, 1, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{paths[0]}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("paths shorter than minComponents are ignored", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d", "/a/b/c/e", "/a/b/f/g", "/x/y"}
|
||||
got, ignored := GetCommonParents(paths, 4, GetPathComponents, opts)
|
||||
assert.DeepEqual(t, ignored, map[string]struct{}{"/x/y": {}})
|
||||
expected := []string{"/a/b/c", "/a/b/f/g"}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("three paths share /a/b", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d", "/a/b/c/e", "/a/b/f/g"}
|
||||
got, ignored := GetCommonParents(paths, 1, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{"/a/b"}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("mixed with short path collapses to root when minComponents=1", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d", "/a/b/c/e", "/a/b/f/g", "/x/y/z"}
|
||||
got, ignored := GetCommonParents(paths, 1, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{"/"}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("mixed with short path preserves both when minComponents=3", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d", "/a/b/c/e", "/a/b/f/g", "/x/y/z"}
|
||||
got, ignored := GetCommonParents(paths, 3, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{"/a/b", "/x/y/z"}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("different volumes are returned individually", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"c:/a/b/c/d", "d:/a/b/c/d"}
|
||||
got, ignored := GetCommonParents(paths, 1, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{paths[0], paths[1]}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("duplicate paths deduplicate result", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d", "/a/b/c/d"}
|
||||
got, ignored := GetCommonParents(paths, 1, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{paths[0]}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("paths with few components are returned as-is when minComponents met", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d", "/x/y"}
|
||||
got, ignored := GetCommonParents(paths, 2, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{"/a/b/c/d", "/x/y"}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("minComponents=2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/c/d", "/a/z/c/e", "/a/aaa/f/g", "/x/y/z"}
|
||||
got, ignored := GetCommonParents(paths, 2, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{"/a", "/x/y/z"}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
|
||||
t.Run("trailing separators are handled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
paths := []string{"/a/b/", "/a/b/c"}
|
||||
got, ignored := GetCommonParents(paths, 1, GetPathComponents, opts)
|
||||
assert.Equal(t, len(ignored), 0)
|
||||
expected := []string{"/a/b"}
|
||||
assert.DeepEqual(t, got, expected)
|
||||
})
|
||||
}
|
||||
177
tools/tsgo/internal/tspath/startsWithDirectory_test.go
Normal file
177
tools/tsgo/internal/tspath/startsWithDirectory_test.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package tspath
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStartsWithDirectory(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
fileName string
|
||||
directoryName string
|
||||
useCaseSensitiveFileNames bool
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "exact match case sensitive",
|
||||
fileName: "/project/src/file.ts",
|
||||
directoryName: "/project/src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "exact match case insensitive",
|
||||
fileName: "/project/src/file.ts",
|
||||
directoryName: "/PROJECT/SRC",
|
||||
useCaseSensitiveFileNames: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "case sensitive mismatch",
|
||||
fileName: "/project/src/file.ts",
|
||||
directoryName: "/PROJECT/SRC",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "file not in directory",
|
||||
fileName: "/project/lib/file.ts",
|
||||
directoryName: "/project/src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "file in subdirectory",
|
||||
fileName: "/project/src/components/Button.tsx",
|
||||
directoryName: "/project/src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "file in parent directory",
|
||||
fileName: "/project/file.ts",
|
||||
directoryName: "/project/src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "windows style separators",
|
||||
fileName: "C:\\project\\src\\file.ts",
|
||||
directoryName: "C:\\project\\src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "mixed separators",
|
||||
fileName: "/project/src/file.ts",
|
||||
directoryName: "\\project\\src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty directory name",
|
||||
fileName: "/project/src/file.ts",
|
||||
directoryName: "",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty file name",
|
||||
fileName: "",
|
||||
directoryName: "/project/src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "identical paths",
|
||||
fileName: "/project/src",
|
||||
directoryName: "/project/src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false, // File name doesn't start with directory + separator
|
||||
},
|
||||
{
|
||||
name: "directory with trailing separator",
|
||||
fileName: "/project/src/file.ts",
|
||||
directoryName: "/project/src/",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "unicode characters",
|
||||
fileName: "/project/测试/file.ts",
|
||||
directoryName: "/project/测试",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "unicode case insensitive",
|
||||
fileName: "/project/测试/file.ts",
|
||||
directoryName: "/PROJECT/测试",
|
||||
useCaseSensitiveFileNames: false,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result := StartsWithDirectory(tt.fileName, tt.directoryName, tt.useCaseSensitiveFileNames)
|
||||
if result != tt.expected {
|
||||
t.Errorf("StartsWithDirectory(%q, %q, %v) = %v, expected %v",
|
||||
tt.fileName, tt.directoryName, tt.useCaseSensitiveFileNames, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartsWithDirectoryEdgeCases(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
fileName string
|
||||
directoryName string
|
||||
useCaseSensitiveFileNames bool
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "file name shorter than directory",
|
||||
fileName: "/proj",
|
||||
directoryName: "/project",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "file name starts with directory but no separator",
|
||||
fileName: "/projectsrc/file.ts",
|
||||
directoryName: "/project",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "relative paths",
|
||||
fileName: "src/file.ts",
|
||||
directoryName: "src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "absolute vs relative",
|
||||
fileName: "/project/src/file.ts",
|
||||
directoryName: "project/src",
|
||||
useCaseSensitiveFileNames: true,
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result := StartsWithDirectory(tt.fileName, tt.directoryName, tt.useCaseSensitiveFileNames)
|
||||
if result != tt.expected {
|
||||
t.Errorf("StartsWithDirectory(%q, %q, %v) = %v, expected %v",
|
||||
tt.fileName, tt.directoryName, tt.useCaseSensitiveFileNames, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
61
tools/tsgo/internal/tspath/untitled_test.go
Normal file
61
tools/tsgo/internal/tspath/untitled_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package tspath_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/tspath"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestUntitledPathHandling(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Test that untitled paths are treated as rooted
|
||||
untitledPath := "^/untitled/ts-nul-authority/Untitled-2"
|
||||
|
||||
// GetEncodedRootLength should return 2 for "^/"
|
||||
rootLength := tspath.GetEncodedRootLength(untitledPath)
|
||||
assert.Equal(t, rootLength, 2, "GetEncodedRootLength should return 2 for untitled paths")
|
||||
|
||||
// IsRootedDiskPath should return true
|
||||
isRooted := tspath.IsRootedDiskPath(untitledPath)
|
||||
assert.Assert(t, isRooted, "IsRootedDiskPath should return true for untitled paths")
|
||||
|
||||
// ToPath should not resolve untitled paths against current directory
|
||||
currentDir := "/home/user/project"
|
||||
path := tspath.ToPath(untitledPath, currentDir, true)
|
||||
// The path should be the original untitled path
|
||||
assert.Equal(t, string(path), "^/untitled/ts-nul-authority/Untitled-2", "ToPath should not resolve untitled paths against current directory")
|
||||
|
||||
// Test GetNormalizedAbsolutePath doesn't resolve untitled paths
|
||||
normalized := tspath.GetNormalizedAbsolutePath(untitledPath, currentDir)
|
||||
assert.Equal(t, normalized, "^/untitled/ts-nul-authority/Untitled-2", "GetNormalizedAbsolutePath should not resolve untitled paths")
|
||||
}
|
||||
|
||||
func TestUntitledPathEdgeCases(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Test edge cases
|
||||
testCases := []struct {
|
||||
path string
|
||||
expected int
|
||||
isRooted bool
|
||||
}{
|
||||
{"^/", 2, true}, // Minimal untitled path
|
||||
{"^/untitled/ts-nul-authority/test", 2, true}, // Normal untitled path
|
||||
{"^", 0, false}, // Just ^ is not rooted
|
||||
{"^x", 0, false}, // ^x is not untitled
|
||||
{"^^/", 0, false}, // ^^/ is not untitled
|
||||
{"x^/", 0, false}, // x^/ is not untitled (doesn't start with ^)
|
||||
{"^/untitled/ts-nul-authority/path/with/deeper/structure", 2, true}, // Deeper path
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
rootLength := tspath.GetEncodedRootLength(tc.path)
|
||||
assert.Equal(t, rootLength, tc.expected, "GetEncodedRootLength for path %s", tc.path)
|
||||
|
||||
isRooted := tspath.IsRootedDiskPath(tc.path)
|
||||
assert.Equal(t, isRooted, tc.isRooted, "IsRootedDiskPath for path %s", tc.path)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user