Skip to content
Merged
Show file tree
Hide file tree
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
15 changes: 12 additions & 3 deletions internal/checker/checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ foo.bar;`
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile("/tsconfig.json", &core.CompilerOptions{}, host, nil)
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")

p := compiler.NewProgramFromParsedCommandLine(parsed, host)
p := compiler.NewProgram(compiler.ProgramOptions{
Config: parsed,
Host: host,
})
p.BindSourceFiles()
c, done := p.GetTypeChecker(t.Context())
defer done()
Expand Down Expand Up @@ -70,7 +73,10 @@ func TestCheckSrcCompiler(t *testing.T) {
host := compiler.NewCompilerHost(nil, rootPath, fs, bundled.LibPath())
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")
p := compiler.NewProgramFromParsedCommandLine(parsed, host)
p := compiler.NewProgram(compiler.ProgramOptions{
Config: parsed,
Host: host,
})
p.CheckSourceFiles(t.Context())
}

Expand All @@ -84,7 +90,10 @@ func BenchmarkNewChecker(b *testing.B) {
host := compiler.NewCompilerHost(nil, rootPath, fs, bundled.LibPath())
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
assert.Equal(b, len(errors), 0, "Expected no errors in parsed command line")
p := compiler.NewProgramFromParsedCommandLine(parsed, host)
p := compiler.NewProgram(compiler.ProgramOptions{
Config: parsed,
Host: host,
})

b.ReportAllocs()

Expand Down
76 changes: 28 additions & 48 deletions internal/compiler/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,21 @@ import (
)

type ProgramOptions struct {
RootFiles []string
Host CompilerHost
Options *core.CompilerOptions
SingleThreaded core.Tristate
ProjectReference []core.ProjectReference
ConfigFileParsingDiagnostics []*ast.Diagnostic
CreateCheckerPool func(*Program) CheckerPool

TypingsLocation string
ProjectName string
Host CompilerHost
Config *tsoptions.ParsedCommandLine
SingleThreaded core.Tristate
CreateCheckerPool func(*Program) CheckerPool
TypingsLocation string
ProjectName string
}

type Program struct {
host CompilerHost
programOptions ProgramOptions
compilerOptions *core.CompilerOptions
configFileName string
nodeModules map[string]*ast.SourceFile
checkerPool CheckerPool
currentDirectory string
configFileParsingDiagnostics []*ast.Diagnostic
host CompilerHost
programOptions ProgramOptions
compilerOptions *core.CompilerOptions
nodeModules map[string]*ast.SourceFile
checkerPool CheckerPool
currentDirectory string

sourceAffectingCompilerOptionsOnce sync.Once
sourceAffectingCompilerOptions *core.SourceFileAffectingCompilerOptions
Expand Down Expand Up @@ -175,8 +169,7 @@ func (p *Program) GetSourceFileFromReference(origin *ast.SourceFile, ref *ast.Fi
func NewProgram(options ProgramOptions) *Program {
p := &Program{}
p.programOptions = options
p.compilerOptions = options.Options
p.configFileParsingDiagnostics = slices.Clip(options.ConfigFileParsingDiagnostics)
p.compilerOptions = options.Config.CompilerOptions()
if p.compilerOptions == nil {
panic("compiler options required")
}
Expand Down Expand Up @@ -211,7 +204,7 @@ func NewProgram(options ProgramOptions) *Program {
}
}

p.processedFiles = processAllProgramFiles(p.host, p.programOptions, p.compilerOptions, p.resolver, options.RootFiles, libs, p.singleThreaded())
p.processedFiles = processAllProgramFiles(p.host, p.programOptions, p.compilerOptions, p.resolver, options.Config.FileNames(), libs, p.singleThreaded())
p.filesByPath = make(map[tspath.Path]*ast.SourceFile, len(p.files))
for _, file := range p.files {
p.filesByPath[file.Path()] = file
Expand All @@ -236,20 +229,18 @@ func (p *Program) UpdateProgram(changedFilePath tspath.Path) (*Program, bool) {
return NewProgram(p.programOptions), false
}
result := &Program{
host: p.host,
programOptions: p.programOptions,
compilerOptions: p.compilerOptions,
configFileName: p.configFileName,
nodeModules: p.nodeModules,
currentDirectory: p.currentDirectory,
configFileParsingDiagnostics: p.configFileParsingDiagnostics,
resolver: p.resolver,
comparePathsOptions: p.comparePathsOptions,
processedFiles: p.processedFiles,
filesByPath: p.filesByPath,
currentNodeModulesDepth: p.currentNodeModulesDepth,
usesUriStyleNodeCoreModules: p.usesUriStyleNodeCoreModules,
unsupportedExtensions: p.unsupportedExtensions,
host: p.host,
programOptions: p.programOptions,
compilerOptions: p.compilerOptions,
nodeModules: p.nodeModules,
currentDirectory: p.currentDirectory,
resolver: p.resolver,
comparePathsOptions: p.comparePathsOptions,
processedFiles: p.processedFiles,
filesByPath: p.filesByPath,
currentNodeModulesDepth: p.currentNodeModulesDepth,
usesUriStyleNodeCoreModules: p.usesUriStyleNodeCoreModules,
unsupportedExtensions: p.unsupportedExtensions,
}
result.initCheckerPool()
index := core.FindIndex(result.files, func(file *ast.SourceFile) bool { return file.Path() == newFile.Path() })
Expand Down Expand Up @@ -302,22 +293,11 @@ func equalCheckJSDirectives(d1 *ast.CheckJsDirective, d2 *ast.CheckJsDirective)
return d1 == nil && d2 == nil || d1 != nil && d2 != nil && d1.Enabled == d2.Enabled
}

func NewProgramFromParsedCommandLine(config *tsoptions.ParsedCommandLine, host CompilerHost) *Program {
programOptions := ProgramOptions{
RootFiles: config.FileNames(),
Options: config.CompilerOptions(),
Host: host,
// todo: ProjectReferences
ConfigFileParsingDiagnostics: config.GetConfigFileParsingDiagnostics(),
}
return NewProgram(programOptions)
}

func (p *Program) SourceFiles() []*ast.SourceFile { return p.files }
func (p *Program) Options() *core.CompilerOptions { return p.compilerOptions }
func (p *Program) Host() CompilerHost { return p.host }
func (p *Program) GetConfigFileParsingDiagnostics() []*ast.Diagnostic {
return slices.Clip(p.configFileParsingDiagnostics)
return slices.Clip(p.programOptions.Config.GetConfigFileParsingDiagnostics())
}

func (p *Program) singleThreaded() bool {
Expand Down Expand Up @@ -432,7 +412,7 @@ func (p *Program) getOptionsDiagnosticsOfConfigFile() []*ast.Diagnostic {
if p.Options() == nil || p.Options().ConfigFilePath == "" {
return nil
}
return p.configFileParsingDiagnostics // TODO: actually call getDiagnosticsHelper on config path
return p.GetConfigFileParsingDiagnostics() // TODO: actually call getDiagnosticsHelper on config path
}

func (p *Program) getSyntacticDiagnosticsForFile(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
Expand Down
24 changes: 16 additions & 8 deletions internal/compiler/program_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,13 @@ func TestProgram(t *testing.T) {
opts := core.CompilerOptions{Target: testCase.target}

program := NewProgram(ProgramOptions{
RootFiles: []string{"c:/dev/src/index.ts"},
Host: NewCompilerHost(&opts, "c:/dev/src", fs, bundled.LibPath()),
Options: &opts,
Config: &tsoptions.ParsedCommandLine{
ParsedConfig: &core.ParsedOptions{
FileNames: []string{"c:/dev/src/index.ts"},
CompilerOptions: &opts,
},
},
Host: NewCompilerHost(&opts, "c:/dev/src", fs, bundled.LibPath()),
})

actualFiles := []string{}
Expand Down Expand Up @@ -265,9 +269,13 @@ func BenchmarkNewProgram(b *testing.B) {

opts := core.CompilerOptions{Target: testCase.target}
programOpts := ProgramOptions{
RootFiles: []string{"c:/dev/src/index.ts"},
Host: NewCompilerHost(&opts, "c:/dev/src", fs, bundled.LibPath()),
Options: &opts,
Config: &tsoptions.ParsedCommandLine{
ParsedConfig: &core.ParsedOptions{
FileNames: []string{"c:/dev/src/index.ts"},
CompilerOptions: &opts,
},
},
Host: NewCompilerHost(&opts, "c:/dev/src", fs, bundled.LibPath()),
}

for b.Loop() {
Expand All @@ -290,8 +298,8 @@ func BenchmarkNewProgram(b *testing.B) {
assert.Equal(b, len(errors), 0, "Expected no errors in parsed command line")

opts := ProgramOptions{
Host: host,
Options: parsed.CompilerOptions(),
Config: parsed,
Host: host,
}

for b.Loop() {
Expand Down
5 changes: 4 additions & 1 deletion internal/execute/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ func RunWatchCycle(w *watcher) {
return
}
// todo: updateProgram()
w.program = compiler.NewProgramFromParsedCommandLine(w.options, w.host)
w.program = compiler.NewProgram(compiler.ProgramOptions{
Config: w.options,
Host: w.host,
})
if w.hasBeenModified(w.program) {
w.compileAndEmit()
}
Expand Down
5 changes: 4 additions & 1 deletion internal/execute/tsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ func performCompilation(sys System, cb cbType, config *tsoptions.ParsedCommandLi
host := compiler.NewCachedFSCompilerHost(config.CompilerOptions(), sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath())
// todo: cache, statistics, tracing
parseStart := time.Now()
program := compiler.NewProgramFromParsedCommandLine(config, host)
program := compiler.NewProgram(compiler.ProgramOptions{
Config: config,
Host: host,
})
parseTime := time.Since(parseStart)

result := emitFilesAndReportErrors(sys, program, reportDiagnostic)
Expand Down
5 changes: 4 additions & 1 deletion internal/execute/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ func (w *watcher) doCycle() {
return
}
// updateProgram()
w.program = compiler.NewProgramFromParsedCommandLine(w.options, w.host)
w.program = compiler.NewProgram(compiler.ProgramOptions{
Config: w.options,
Host: w.host,
})
if w.hasBeenModified(w.program) {
fmt.Fprint(w.sys.Writer(), "build starting at ", w.sys.Now(), w.sys.NewLine())
timeStart := w.sys.Now()
Expand Down
38 changes: 34 additions & 4 deletions internal/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ type Project struct {
compilerOptions *core.CompilerOptions
typeAcquisition *core.TypeAcquisition
parsedCommandLine *tsoptions.ParsedCommandLine
programConfig *tsoptions.ParsedCommandLine
program *compiler.Program
checkerPool *checkerPool

Expand Down Expand Up @@ -471,6 +472,7 @@ func (p *Project) updateGraph() bool {
case PendingReloadFileNames:
p.parsedCommandLine = tsoptions.ReloadFileNamesOfParsedCommandLine(p.parsedCommandLine, p.host.FS())
writeFileNames = p.setRootFiles(p.parsedCommandLine.FileNames())
p.programConfig = nil
case PendingReloadFull:
if err := p.loadConfig(); err != nil {
panic(fmt.Sprintf("failed to reload config: %v", err))
Expand Down Expand Up @@ -512,16 +514,40 @@ func (p *Project) updateProgram() bool {
}
var oldProgramReused bool
if p.program == nil || p.dirtyFilePath == "" {
rootFileNames := p.GetRootFileNames()
compilerOptions := p.compilerOptions
if p.programConfig == nil {
// Get from config file = config file root files + typings files
if p.parsedCommandLine != nil {
// There are no typing files so use the parsed command line as is
if len(p.typingFiles) == 0 {
p.programConfig = p.parsedCommandLine
} else {
// Update the fileNames
parsedConfig := *p.parsedCommandLine.ParsedConfig
parsedConfig.FileNames = append(p.parsedCommandLine.FileNames(), p.typingFiles...)
p.programConfig = &tsoptions.ParsedCommandLine{
ParsedConfig: &parsedConfig,
ConfigFile: p.parsedCommandLine.ConfigFile,
Errors: p.parsedCommandLine.Errors,
}
}
} else {
rootFileNames := p.GetRootFileNames()
compilerOptions := p.compilerOptions
p.programConfig = &tsoptions.ParsedCommandLine{
ParsedConfig: &core.ParsedOptions{
CompilerOptions: compilerOptions,
FileNames: rootFileNames,
},
}
}
}
var typingsLocation string
if typeAcquisition := p.getTypeAcquisition(); typeAcquisition != nil && typeAcquisition.Enable.IsTrue() {
typingsLocation = p.host.TypingsInstaller().TypingsLocation
}
p.program = compiler.NewProgram(compiler.ProgramOptions{
RootFiles: rootFileNames,
Config: p.programConfig,
Host: p,
Options: compilerOptions,
TypingsLocation: typingsLocation,
CreateCheckerPool: func(program *compiler.Program) compiler.CheckerPool {
p.checkerPool = newCheckerPool(4, program, p.Log)
Expand Down Expand Up @@ -694,6 +720,7 @@ func (p *Project) UpdateTypingFiles(typingsInfo *TypingsInfo, typingFiles []stri
if !slices.Equal(typingFiles, p.typingFiles) {
// If typing files changed, then only schedule project update
p.typingFiles = typingFiles
p.programConfig = nil

// // Invalidate files with unresolved imports
// this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile);
Expand Down Expand Up @@ -790,6 +817,7 @@ func (p *Project) removeFile(info *ScriptInfo, fileExists bool, detachFromProjec
case KindInferred:
p.rootFileNames.Delete(info.path)
p.typeAcquisition = nil
p.programConfig = nil
case KindConfigured:
p.pendingReload = PendingReloadFileNames
}
Expand All @@ -813,6 +841,7 @@ func (p *Project) AddRoot(info *ScriptInfo) {
p.mu.Lock()
defer p.mu.Unlock()
p.addRoot(info)
p.programConfig = nil
p.markAsDirtyLocked()
}

Expand Down Expand Up @@ -845,6 +874,7 @@ func (p *Project) loadConfig() error {
panic("loadConfig called on non-configured project")
}

p.programConfig = nil
if configFileContent, ok := p.host.FS().ReadFile(p.configFileName); ok {
configDir := tspath.GetDirectoryPath(p.configFileName)
tsConfigSourceFile := tsoptions.NewTsconfigSourceFileFromFilePath(p.configFileName, p.configFilePath, configFileContent)
Expand Down
8 changes: 4 additions & 4 deletions internal/testrunner/compiler_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,19 +255,19 @@ func newCompilerTest(
units := testCaseContentWithConfig.testUnitData
var toBeCompiled []*harnessutil.TestFile
var otherFiles []*harnessutil.TestFile
var tsConfigOptions core.CompilerOptions
var tsConfig *tsoptions.ParsedCommandLine
hasNonDtsFiles := core.Some(
units,
func(unit *testUnit) bool { return !tspath.FileExtensionIs(unit.name, tspath.ExtensionDts) })
var tsConfigFiles []*harnessutil.TestFile
if testCaseContentWithConfig.tsConfig != nil {
tsConfigOptions = *testCaseContentWithConfig.tsConfig.ParsedConfig.CompilerOptions
tsConfig = testCaseContentWithConfig.tsConfig
tsConfigFiles = []*harnessutil.TestFile{
createHarnessTestFile(testCaseContentWithConfig.tsConfigFileUnitData, currentDirectory),
}
for _, unit := range units {
if slices.Contains(
testCaseContentWithConfig.tsConfig.ParsedConfig.FileNames,
tsConfig.ParsedConfig.FileNames,
tspath.GetNormalizedAbsolutePath(unit.name, currentDirectory),
) {
toBeCompiled = append(toBeCompiled, createHarnessTestFile(unit, currentDirectory))
Expand Down Expand Up @@ -303,7 +303,7 @@ func newCompilerTest(
toBeCompiled,
otherFiles,
harnessConfig,
&tsConfigOptions,
tsConfig,
currentDirectory,
testCaseContentWithConfig.symlinks,
)
Expand Down
Loading