-
Couldn't load subscription status.
- Fork 724
Fix #1034: Improve symlink resolution in module specifier generation #1902
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
base: main
Are you sure you want to change the base?
Changes from all commits
4269eff
07a2207
b7b39d5
0b0dcbf
1b8d265
bab6338
24985b7
80b7c37
54d5ddd
e8086c4
29a4113
618cef6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ import ( | |
| "github.com/microsoft/typescript-go/internal/printer" | ||
| "github.com/microsoft/typescript-go/internal/scanner" | ||
| "github.com/microsoft/typescript-go/internal/sourcemap" | ||
| "github.com/microsoft/typescript-go/internal/symlinks" | ||
| "github.com/microsoft/typescript-go/internal/tsoptions" | ||
| "github.com/microsoft/typescript-go/internal/tspath" | ||
| ) | ||
|
|
@@ -66,6 +67,7 @@ type Program struct { | |
| // Cached unresolved imports for ATA | ||
| unresolvedImportsOnce sync.Once | ||
| unresolvedImports *collections.Set[string] | ||
| knownSymlinks *symlinks.KnownSymlinks | ||
| } | ||
|
|
||
| // FileExists implements checker.Program. | ||
|
|
@@ -210,6 +212,10 @@ func NewProgram(opts ProgramOptions) *Program { | |
| p.initCheckerPool() | ||
| p.processedFiles = processAllProgramFiles(p.opts, p.SingleThreaded()) | ||
| p.verifyCompilerOptions() | ||
| p.knownSymlinks = symlinks.NewKnownSymlink(p.GetCurrentDirectory(), p.UseCaseSensitiveFileNames()) | ||
| if len(p.resolvedModules) > 0 || len(p.typeResolutionsInFile) > 0 { | ||
| p.knownSymlinks.SetSymlinksFromResolutions(p.ForEachResolvedModule, p.ForEachResolvedTypeReferenceDirective) | ||
| } | ||
| return p | ||
| } | ||
|
|
||
|
|
@@ -240,6 +246,10 @@ func (p *Program) UpdateProgram(changedFilePath tspath.Path, newHost CompilerHos | |
| result.filesByPath = maps.Clone(result.filesByPath) | ||
| result.filesByPath[newFile.Path()] = newFile | ||
| updateFileIncludeProcessor(result) | ||
| result.knownSymlinks = symlinks.NewKnownSymlink(result.GetCurrentDirectory(), result.UseCaseSensitiveFileNames()) | ||
| if len(result.resolvedModules) > 0 || len(result.typeResolutionsInFile) > 0 { | ||
| result.knownSymlinks.SetSymlinksFromResolutions(result.ForEachResolvedModule, result.ForEachResolvedTypeReferenceDirective) | ||
| } | ||
| return result, true | ||
| } | ||
|
|
||
|
|
@@ -1630,6 +1640,50 @@ func (p *Program) SourceFileMayBeEmitted(sourceFile *ast.SourceFile, forceDtsEmi | |
| return sourceFileMayBeEmitted(sourceFile, p, forceDtsEmit) | ||
| } | ||
|
|
||
| func (p *Program) GetSymlinkCache() *symlinks.KnownSymlinks { | ||
| // if p.Host().GetSymlinkCache() != nil { | ||
| // return p.Host().GetSymlinkCache() | ||
| // } | ||
| if p.knownSymlinks == nil { | ||
| p.knownSymlinks = symlinks.NewKnownSymlink(p.GetCurrentDirectory(), p.UseCaseSensitiveFileNames()) | ||
| // In declaration-only builds, the symlink cache might not be populated yet | ||
| // because module resolution was skipped. Populate it now if we have resolutions. | ||
|
Comment on lines
+1649
to
+1650
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don’t recall exactly how this happened in Strada, but I don’t think this comment applies in Corsa. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This occurs regularly in pnpm workspaces when running |
||
| if len(p.resolvedModules) > 0 || len(p.typeResolutionsInFile) > 0 { | ||
| p.knownSymlinks.SetSymlinksFromResolutions(p.ForEachResolvedModule, p.ForEachResolvedTypeReferenceDirective) | ||
| } | ||
| } | ||
| return p.knownSymlinks | ||
| } | ||
|
|
||
| func (p *Program) ResolveModuleName(moduleName string, containingFile string, resolutionMode core.ResolutionMode) *module.ResolvedModule { | ||
| resolved, _ := p.resolver.ResolveModuleName(moduleName, containingFile, resolutionMode, nil) | ||
| return resolved | ||
| } | ||
|
|
||
| func (p *Program) ForEachResolvedModule(callback func(resolution *module.ResolvedModule, moduleName string, mode core.ResolutionMode, filePath tspath.Path), file *ast.SourceFile) { | ||
| forEachResolution(p.resolvedModules, callback, file) | ||
| } | ||
|
|
||
| func (p *Program) ForEachResolvedTypeReferenceDirective(callback func(resolution *module.ResolvedTypeReferenceDirective, moduleName string, mode core.ResolutionMode, filePath tspath.Path), file *ast.SourceFile) { | ||
| forEachResolution(p.typeResolutionsInFile, callback, file) | ||
| } | ||
|
|
||
| func forEachResolution[T any](resolutionCache map[tspath.Path]module.ModeAwareCache[T], callback func(resolution T, moduleName string, mode core.ResolutionMode, filePath tspath.Path), file *ast.SourceFile) { | ||
| if file != nil { | ||
| if resolutions, ok := resolutionCache[file.Path()]; ok { | ||
| for key, resolution := range resolutions { | ||
| callback(resolution, key.Name, key.Mode, file.Path()) | ||
| } | ||
| } | ||
| } else { | ||
| for filePath, resolutions := range resolutionCache { | ||
| for key, resolution := range resolutions { | ||
| callback(resolution, key.Name, key.Mode, filePath) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| var plainJSErrors = collections.NewSetFromItems( | ||
| // binder errors | ||
| diagnostics.Cannot_redeclare_block_scoped_variable_0.Code(), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition looks to be impossible as-written, but I think lazy initialization is a good idea. However, you need to guard the field initialization with a
sync.Oncelike the other lazy computed caches.