vendor tsgo
This commit is contained in:
180
tools/tsgo/internal/project/autoimport.go
Normal file
180
tools/tsgo/internal/project/autoimport.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/ast"
|
||||
"github.com/microsoft/typescript-go/internal/collections"
|
||||
"github.com/microsoft/typescript-go/internal/compiler"
|
||||
"github.com/microsoft/typescript-go/internal/ls/autoimport"
|
||||
"github.com/microsoft/typescript-go/internal/packagejson"
|
||||
"github.com/microsoft/typescript-go/internal/tspath"
|
||||
"github.com/microsoft/typescript-go/internal/vfs"
|
||||
)
|
||||
|
||||
type autoImportBuilderFS struct {
|
||||
snapshotFSBuilder *snapshotFSBuilder
|
||||
untrackedFiles collections.SyncMap[tspath.Path, FileHandle]
|
||||
}
|
||||
|
||||
var _ FileSource = (*autoImportBuilderFS)(nil)
|
||||
|
||||
// FS implements FileSource.
|
||||
func (a *autoImportBuilderFS) FS() vfs.FS {
|
||||
return a.snapshotFSBuilder.fs
|
||||
}
|
||||
|
||||
// GetFile implements FileSource.
|
||||
func (a *autoImportBuilderFS) GetFile(fileName string) FileHandle {
|
||||
path := a.snapshotFSBuilder.toPath(fileName)
|
||||
return a.GetFileByPath(fileName, path)
|
||||
}
|
||||
|
||||
// GetFileByPath implements FileSource.
|
||||
func (a *autoImportBuilderFS) GetFileByPath(fileName string, path tspath.Path) FileHandle {
|
||||
// We want to avoid long-term caching of files referenced only by auto-imports, so we
|
||||
// override GetFileByPath to avoid collecting more files into the snapshotFSBuilder's
|
||||
// diskFiles. (Note the reason we can't just use the finalized SnapshotFS is that changed
|
||||
// files not read during other parts of the snapshot clone will be marked as dirty, but
|
||||
// not yet refreshed from disk.)
|
||||
if overlay, ok := a.snapshotFSBuilder.overlays[path]; ok {
|
||||
return overlay
|
||||
}
|
||||
if diskFile, ok := a.snapshotFSBuilder.diskFiles.Load(path); ok {
|
||||
return a.snapshotFSBuilder.reloadEntryIfNeeded(diskFile)
|
||||
}
|
||||
if fh, ok := a.untrackedFiles.Load(path); ok {
|
||||
return fh
|
||||
}
|
||||
var fh FileHandle
|
||||
content, ok := a.snapshotFSBuilder.fs.ReadFile(fileName)
|
||||
if ok {
|
||||
fh = newDiskFile(fileName, content)
|
||||
}
|
||||
fh, _ = a.untrackedFiles.LoadOrStore(path, fh)
|
||||
return fh
|
||||
}
|
||||
|
||||
func (a *autoImportBuilderFS) GetAccessibleEntries(path string) vfs.Entries {
|
||||
return a.snapshotFSBuilder.GetAccessibleEntries(path)
|
||||
}
|
||||
|
||||
// FileExists implements FileSource.
|
||||
func (a *autoImportBuilderFS) FileExists(fileName string, path tspath.Path) bool {
|
||||
return a.snapshotFSBuilder.FileExists(fileName, path)
|
||||
}
|
||||
|
||||
type autoImportRegistryCloneHost struct {
|
||||
projectCollection *ProjectCollection
|
||||
parseCache *ParseCache
|
||||
fs *sourceFS
|
||||
currentDirectory string
|
||||
|
||||
filesMu sync.Mutex
|
||||
files []ParseCacheKey
|
||||
}
|
||||
|
||||
var _ autoimport.RegistryCloneHost = (*autoImportRegistryCloneHost)(nil)
|
||||
|
||||
func newAutoImportRegistryCloneHost(
|
||||
projectCollection *ProjectCollection,
|
||||
parseCache *ParseCache,
|
||||
snapshotFSBuilder *snapshotFSBuilder,
|
||||
currentDirectory string,
|
||||
toPath func(fileName string) tspath.Path,
|
||||
) *autoImportRegistryCloneHost {
|
||||
return &autoImportRegistryCloneHost{
|
||||
projectCollection: projectCollection,
|
||||
parseCache: parseCache,
|
||||
fs: newSourceFS(false, &autoImportBuilderFS{snapshotFSBuilder: snapshotFSBuilder}, toPath),
|
||||
currentDirectory: currentDirectory,
|
||||
}
|
||||
}
|
||||
|
||||
// FS implements autoimport.RegistryCloneHost.
|
||||
func (a *autoImportRegistryCloneHost) FS() vfs.FS {
|
||||
return a.fs
|
||||
}
|
||||
|
||||
// GetCurrentDirectory implements autoimport.RegistryCloneHost.
|
||||
func (a *autoImportRegistryCloneHost) GetCurrentDirectory() string {
|
||||
return a.currentDirectory
|
||||
}
|
||||
|
||||
// GetDefaultProject implements autoimport.RegistryCloneHost.
|
||||
func (a *autoImportRegistryCloneHost) GetDefaultProject(path tspath.Path) (tspath.Path, *compiler.Program) {
|
||||
project := a.projectCollection.GetDefaultProject(path)
|
||||
if project == nil {
|
||||
return "", nil
|
||||
}
|
||||
return project.configFilePath, project.GetProgram()
|
||||
}
|
||||
|
||||
// GetPackageJson implements autoimport.RegistryCloneHost.
|
||||
func (a *autoImportRegistryCloneHost) GetPackageJson(fileName string) *packagejson.InfoCacheEntry {
|
||||
// !!! ref-counted shared cache
|
||||
fh := a.fs.GetFile(fileName)
|
||||
packageDirectory := tspath.GetDirectoryPath(fileName)
|
||||
if fh == nil {
|
||||
return &packagejson.InfoCacheEntry{
|
||||
DirectoryExists: a.fs.DirectoryExists(packageDirectory),
|
||||
PackageDirectory: packageDirectory,
|
||||
}
|
||||
}
|
||||
fields, err := packagejson.Parse([]byte(fh.Content()))
|
||||
if err != nil {
|
||||
return &packagejson.InfoCacheEntry{
|
||||
DirectoryExists: true,
|
||||
PackageDirectory: tspath.GetDirectoryPath(fileName),
|
||||
Contents: &packagejson.PackageJson{
|
||||
Parseable: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
return &packagejson.InfoCacheEntry{
|
||||
DirectoryExists: true,
|
||||
PackageDirectory: tspath.GetDirectoryPath(fileName),
|
||||
Contents: &packagejson.PackageJson{
|
||||
Fields: fields,
|
||||
Parseable: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetProgramForProject implements autoimport.RegistryCloneHost.
|
||||
func (a *autoImportRegistryCloneHost) GetProgramForProject(projectPath tspath.Path) *compiler.Program {
|
||||
project := a.projectCollection.GetProjectByPath(projectPath)
|
||||
if project == nil {
|
||||
return nil
|
||||
}
|
||||
return project.GetProgram()
|
||||
}
|
||||
|
||||
// GetSourceFile implements autoimport.RegistryCloneHost.
|
||||
func (a *autoImportRegistryCloneHost) GetSourceFile(fileName string, path tspath.Path) *ast.SourceFile {
|
||||
fh := a.fs.GetFile(fileName)
|
||||
if fh == nil {
|
||||
return nil
|
||||
}
|
||||
opts := ast.SourceFileParseOptions{
|
||||
FileName: fileName,
|
||||
Path: path,
|
||||
}
|
||||
key := NewParseCacheKey(opts, fh.Hash(), fh.Kind())
|
||||
result := a.parseCache.Acquire(key, fh)
|
||||
|
||||
a.filesMu.Lock()
|
||||
a.files = append(a.files, key)
|
||||
a.filesMu.Unlock()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Dispose implements autoimport.RegistryCloneHost.
|
||||
func (a *autoImportRegistryCloneHost) Dispose() {
|
||||
a.filesMu.Lock()
|
||||
defer a.filesMu.Unlock()
|
||||
for _, key := range a.files {
|
||||
a.parseCache.Deref(key)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user