Skip to content

Fixed: [bug/lsp]panic: vfs: path is not absolute #670 #671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
12 changes: 9 additions & 3 deletions internal/tsoptions/tsconfigparsing.go
Original file line number Diff line number Diff line change
Expand Up @@ -1503,13 +1503,19 @@ func getFileNamesFromConfigSpecs(
}
files := make([]string, 0, literalFileMap.Size()+wildcardFileMap.Size()+wildCardJsonFileMap.Size())
for file := range literalFileMap.Values() {
files = append(files, file)
if file != "" {
files = append(files, file)
}
}
for file := range wildcardFileMap.Values() {
files = append(files, file)
if file != "" {
files = append(files, file)
}
}
for file := range wildCardJsonFileMap.Values() {
files = append(files, file)
if file != "" {
files = append(files, file)
}
}
Comment on lines 1505 to 1519
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also not what the original code said.

    const literalFiles = arrayFrom(literalFileMap.values());
    const wildcardFiles = arrayFrom(wildcardFileMap.values());

    return literalFiles.concat(wildcardFiles, arrayFrom(wildCardJsonFileMap.values()));

A real fix needs to find the actual place where an empty string check is happening, not keep shifting it back and back...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, then i have to check it in details. Okay i will take a look

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rezwanahmedsami maybe the problem is in GetNormalizedAbsolutePath
so If basePath (passed to GetNormalizedAbsolutePath) is empty or relative, the combined path may still be relative. Example:
GetNormalizedAbsolutePath("config.json", "") -> returns "config.json" (relative)
so maybe we need to garentee it's basePath is always absolute

Copy link
Contributor

@gabrielluizsf gabrielluizsf Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rezwanahmedsami try this code:

	extraFileExtensions = []fileExtensionInfo{}

	if basePath == "" {
		basePath, _ = os.Getwd()
	} else if !filepath.IsAbs(basePath) {
		basePath, _ = filepath.Abs(basePath)
	}

	basePath = tspath.NormalizePath(basePath)
	keyMapper := func(value string) string { return tspath.GetCanonicalFileName(value, host.UseCaseSensitiveFileNames()) }

	var literalFileMap collections.OrderedMap[string, string]
	var wildcardFileMap collections.OrderedMap[string, string]
	var wildCardJsonFileMap collections.OrderedMap[string, string]

	validatedFilesSpec := configFileSpecs.validatedFilesSpec
	validatedIncludeSpecs := configFileSpecs.validatedIncludeSpecs
	validatedExcludeSpecs := configFileSpecs.validatedExcludeSpecs

	supportedExtensions := GetSupportedExtensions(options, extraFileExtensions)
	supportedExtensionsWithJsonIfResolveJsonModule := GetSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions)

	for _, fileName := range validatedFilesSpec {
		file := tspath.GetNormalizedAbsolutePath(fileName, basePath)
		literalFileMap.Set(keyMapper(fileName), file)
	}

	var jsonOnlyIncludeRegexes []*regexp2.Regexp
	if len(validatedIncludeSpecs) > 0 {
		files := readDirectory(host, basePath, basePath, core.Flatten(supportedExtensionsWithJsonIfResolveJsonModule), validatedExcludeSpecs, validatedIncludeSpecs, nil)
		for _, file := range files {
			if tspath.FileExtensionIs(file, tspath.ExtensionJson) {
				if jsonOnlyIncludeRegexes == nil {
					includes := core.Filter(validatedIncludeSpecs, func(include string) bool { return strings.HasSuffix(include, tspath.ExtensionJson) })
					includeFilePatterns := core.Map(getRegularExpressionsForWildcards(includes, basePath, "files"), func(pattern string) string { return "^" + pattern + "$" })
					if includeFilePatterns != nil {
						jsonOnlyIncludeRegexes = core.Map(includeFilePatterns, func(pattern string) *regexp2.Regexp {
							return getRegexFromPattern(pattern, host.UseCaseSensitiveFileNames())
						})
					} else {
						jsonOnlyIncludeRegexes = nil
					}
				}
				includeIndex := core.FindIndex(jsonOnlyIncludeRegexes, func(re *regexp2.Regexp) bool { return core.Must(re.MatchString(file)) })
				if includeIndex != -1 {
					key := keyMapper(file)
					if !literalFileMap.Has(key) && !wildCardJsonFileMap.Has(key) {
						wildCardJsonFileMap.Set(key, file)
					}
				}
				continue
			}
			if hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper) {
				continue
			}
			removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper)
			key := keyMapper(file)
			if !literalFileMap.Has(key) && !wildcardFileMap.Has(key) {
				wildcardFileMap.Set(key, file)
			}
		}
	}

	files := make([]string, 0, literalFileMap.Size()+wildcardFileMap.Size()+wildCardJsonFileMap.Size())
	for file := range literalFileMap.Values() {
		if file != "" {
			files = append(files, file)
		}
	}
	for file := range wildcardFileMap.Values() {
		if file != "" {
			files = append(files, file)
		}
	}
	for file := range wildCardJsonFileMap.Values() {
		if file != "" {
			files = append(files, file)
		}
	}

	return files

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your code looks great but still Even with GetNormalizedAbsolutePath, invalid paths could still enter the maps. Add absolute path validation before inserting into maps:

// Modified file processing loop
for _, fileName := range validatedFilesSpec {
    file := tspath.GetNormalizedAbsolutePath(fileName, basePath)
    
    // Add this validation guard
    if !filepath.IsAbs(file) {
        panic(fmt.Sprintf("Path %q is not absolute (base: %q)", file, basePath))
    }
    
    literalFileMap.Set(keyMapper(fileName), file)
}

also I think there is no need for empty string checks in order to match javascript concatination

// Before (incorrect filtering)
for file := range literalFileMap.Values() {
-    if file != "" {
        files = append(files, file)
-    }
}

// After (correct, matches JS logic)
for file := range literalFileMap.Values() {
    files = append(files, file)
}

this is just a suggestion WDYT? @gabrielluizsf

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's check with the others @rezwanahmedsami and @jakebailey

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rezwanahmedsami the @waelantar code looks really cool

extraFileExtensions = []fileExtensionInfo{}

if basePath == "" {
	basePath, _ = os.Getwd()
} else if !filepath.IsAbs(basePath) {
	basePath, _ = filepath.Abs(basePath)
}

basePath = tspath.NormalizePath(basePath)
keyMapper := func(value string) string { return tspath.GetCanonicalFileName(value, host.UseCaseSensitiveFileNames()) }

var literalFileMap collections.OrderedMap[string, string]
var wildcardFileMap collections.OrderedMap[string, string]
var wildCardJsonFileMap collections.OrderedMap[string, string]

validatedFilesSpec := configFileSpecs.validatedFilesSpec
validatedIncludeSpecs := configFileSpecs.validatedIncludeSpecs
validatedExcludeSpecs := configFileSpecs.validatedExcludeSpecs

supportedExtensions := GetSupportedExtensions(options, extraFileExtensions)
supportedExtensionsWithJsonIfResolveJsonModule := GetSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions)

for _, fileName := range validatedFilesSpec {
	file := tspath.GetNormalizedAbsolutePath(fileName, basePath)

	if !filepath.IsAbs(file) {
		panic(fmt.Sprintf("Path %q is not absolute (base: %q)", file, basePath))
	}

	literalFileMap.Set(keyMapper(fileName), file)
}

var jsonOnlyIncludeRegexes []*regexp2.Regexp
if len(validatedIncludeSpecs) > 0 {
	files := readDirectory(host, basePath, basePath, core.Flatten(supportedExtensionsWithJsonIfResolveJsonModule), validatedExcludeSpecs, validatedIncludeSpecs, nil)
	for _, file := range files {
		if tspath.FileExtensionIs(file, tspath.ExtensionJson) {
			if jsonOnlyIncludeRegexes == nil {
				includes := core.Filter(validatedIncludeSpecs, func(include string) bool { return strings.HasSuffix(include, tspath.ExtensionJson) })
				includeFilePatterns := core.Map(getRegularExpressionsForWildcards(includes, basePath, "files"), func(pattern string) string { return "^" + pattern + "$" })
				if includeFilePatterns != nil {
					jsonOnlyIncludeRegexes = core.Map(includeFilePatterns, func(pattern string) *regexp2.Regexp {
						return getRegexFromPattern(pattern, host.UseCaseSensitiveFileNames())
					})
				} else {
					jsonOnlyIncludeRegexes = nil
				}
			}
			includeIndex := core.FindIndex(jsonOnlyIncludeRegexes, func(re *regexp2.Regexp) bool { return core.Must(re.MatchString(file)) })
			if includeIndex != -1 {
				key := keyMapper(file)
				if !literalFileMap.Has(key) && !wildCardJsonFileMap.Has(key) {
					wildCardJsonFileMap.Set(key, file)
				}
			}
			continue
		}
		if hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper) {
			continue
		}
		removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper)
		key := keyMapper(file)
		if !literalFileMap.Has(key) && !wildcardFileMap.Has(key) {
			wildcardFileMap.Set(key, file)
		}
	}
}

files := make([]string, 0, literalFileMap.Size()+wildcardFileMap.Size()+wildCardJsonFileMap.Size())
for _, file := range literalFileMap.Values() {
	files = append(files, file)
}
for _, file := range wildcardFileMap.Values() {
	files = append(files, file)
}
for _, file := range wildCardJsonFileMap.Values() {
	files = append(files, file)
}

return files

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well your implementation is great i just gave small suggestions
but I feel like this is abandoned PR so if they didn't respond soon maybe you should create a new one and please send me the link here so I can see the updates
and thank you

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Contributor

@gabrielluizsf gabrielluizsf Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well your implementation is great i just gave small suggestions but I feel like this is abandoned PR so if they didn't respond soon maybe you should create a new one and please send me the link here so I can see the updates and thank you

#738

return files
}
Expand Down