2025-10-15 10:12:44 +03:00

204 lines
5.5 KiB
Go

package project
import (
"time"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/compiler"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/project/logging"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs"
)
var _ compiler.CompilerHost = (*compilerHost)(nil)
type compilerHost struct {
configFilePath tspath.Path
currentDirectory string
sessionOptions *SessionOptions
fs *snapshotFSBuilder
compilerFS *compilerFS
configFileRegistry *ConfigFileRegistry
seenFiles *collections.SyncSet[tspath.Path]
project *Project
builder *projectCollectionBuilder
logger *logging.LogTree
}
type builderFileSource struct {
seenFiles *collections.SyncSet[tspath.Path]
snapshotFSBuilder *snapshotFSBuilder
}
func (c *builderFileSource) GetFile(fileName string) FileHandle {
path := c.snapshotFSBuilder.toPath(fileName)
c.seenFiles.Add(path)
return c.snapshotFSBuilder.GetFileByPath(fileName, path)
}
func (c *builderFileSource) FS() vfs.FS {
return c.snapshotFSBuilder.FS()
}
func newCompilerHost(
currentDirectory string,
project *Project,
builder *projectCollectionBuilder,
logger *logging.LogTree,
) *compilerHost {
seenFiles := &collections.SyncSet[tspath.Path]{}
compilerFS := &compilerFS{
source: &builderFileSource{
seenFiles: seenFiles,
snapshotFSBuilder: builder.fs,
},
}
return &compilerHost{
configFilePath: project.configFilePath,
currentDirectory: currentDirectory,
sessionOptions: builder.sessionOptions,
compilerFS: compilerFS,
seenFiles: seenFiles,
fs: builder.fs,
project: project,
builder: builder,
logger: logger,
}
}
// freeze clears references to mutable state to make the compilerHost safe for use
// after the snapshot has been finalized. See the usage in snapshot.go for more details.
func (c *compilerHost) freeze(snapshotFS *snapshotFS, configFileRegistry *ConfigFileRegistry) {
if c.builder == nil {
panic("freeze can only be called once")
}
c.compilerFS.source = snapshotFS
c.configFileRegistry = configFileRegistry
c.fs = nil
c.builder = nil
c.project = nil
c.logger = nil
}
func (c *compilerHost) ensureAlive() {
if c.builder == nil || c.project == nil {
panic("method must not be called after snapshot initialization")
}
}
// DefaultLibraryPath implements compiler.CompilerHost.
func (c *compilerHost) DefaultLibraryPath() string {
return c.sessionOptions.DefaultLibraryPath
}
// FS implements compiler.CompilerHost.
func (c *compilerHost) FS() vfs.FS {
return c.compilerFS
}
// GetCurrentDirectory implements compiler.CompilerHost.
func (c *compilerHost) GetCurrentDirectory() string {
return c.currentDirectory
}
// GetResolvedProjectReference implements compiler.CompilerHost.
func (c *compilerHost) GetResolvedProjectReference(fileName string, path tspath.Path) *tsoptions.ParsedCommandLine {
if c.builder == nil {
return c.configFileRegistry.GetConfig(path)
} else {
c.seenFiles.Add(path)
return c.builder.configFileRegistryBuilder.acquireConfigForProject(fileName, path, c.project, c.logger)
}
}
// GetSourceFile implements compiler.CompilerHost. GetSourceFile increments
// the ref count of source files it acquires in the parseCache. There should
// be a corresponding release for each call made.
func (c *compilerHost) GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile {
c.ensureAlive()
c.seenFiles.Add(opts.Path)
if fh := c.fs.GetFileByPath(opts.FileName, opts.Path); fh != nil {
return c.builder.parseCache.Acquire(fh, opts, fh.Kind())
}
return nil
}
// Trace implements compiler.CompilerHost.
func (c *compilerHost) Trace(msg string) {
panic("unimplemented")
}
var _ vfs.FS = (*compilerFS)(nil)
type compilerFS struct {
source FileSource
}
// DirectoryExists implements vfs.FS.
func (fs *compilerFS) DirectoryExists(path string) bool {
return fs.source.FS().DirectoryExists(path)
}
// FileExists implements vfs.FS.
func (fs *compilerFS) FileExists(path string) bool {
if fh := fs.source.GetFile(path); fh != nil {
return true
}
return fs.source.FS().FileExists(path)
}
// GetAccessibleEntries implements vfs.FS.
func (fs *compilerFS) GetAccessibleEntries(path string) vfs.Entries {
return fs.source.FS().GetAccessibleEntries(path)
}
// ReadFile implements vfs.FS.
func (fs *compilerFS) ReadFile(path string) (contents string, ok bool) {
if fh := fs.source.GetFile(path); fh != nil {
return fh.Content(), true
}
return "", false
}
// Realpath implements vfs.FS.
func (fs *compilerFS) Realpath(path string) string {
return fs.source.FS().Realpath(path)
}
// Stat implements vfs.FS.
func (fs *compilerFS) Stat(path string) vfs.FileInfo {
return fs.source.FS().Stat(path)
}
// UseCaseSensitiveFileNames implements vfs.FS.
func (fs *compilerFS) UseCaseSensitiveFileNames() bool {
return fs.source.FS().UseCaseSensitiveFileNames()
}
// WalkDir implements vfs.FS.
func (fs *compilerFS) WalkDir(root string, walkFn vfs.WalkDirFunc) error {
panic("unimplemented")
}
// WriteFile implements vfs.FS.
func (fs *compilerFS) WriteFile(path string, data string, writeByteOrderMark bool) error {
panic("unimplemented")
}
// Remove implements vfs.FS.
func (fs *compilerFS) Remove(path string) error {
panic("unimplemented")
}
// Chtimes implements vfs.FS.
func (fs *compilerFS) Chtimes(path string, atime time.Time, mtime time.Time) error {
panic("unimplemented")
}