Skip to content

Commit 3fb9c3b

Browse files
committed
Use package.json locations to determine uptodate ness
1 parent 4b012be commit 3fb9c3b

31 files changed

+795
-142
lines changed

internal/collections/syncmap.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ func (s *SyncMap[K, V]) Load(key K) (value V, ok bool) {
1616
if !ok {
1717
return value, ok
1818
}
19-
return val.(V), true
19+
if value, ok := val.(V); ok {
20+
return value, true
21+
}
22+
var zero V
23+
return zero, true
2024
}
2125

2226
func (s *SyncMap[K, V]) Store(key K, value V) {

internal/compiler/program.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/microsoft/typescript-go/internal/module"
2020
"github.com/microsoft/typescript-go/internal/modulespecifiers"
2121
"github.com/microsoft/typescript-go/internal/outputpaths"
22+
"github.com/microsoft/typescript-go/internal/packagejson"
2223
"github.com/microsoft/typescript-go/internal/parser"
2324
"github.com/microsoft/typescript-go/internal/printer"
2425
"github.com/microsoft/typescript-go/internal/scanner"
@@ -101,6 +102,10 @@ func (p *Program) GetPackageJsonInfo(pkgJsonPath string) modulespecifiers.Packag
101102
return nil
102103
}
103104

105+
func (p *Program) PackageJsonCacheEntries(f func(key tspath.Path, value *packagejson.InfoCacheEntry) bool) {
106+
p.resolver.PackageJsonCacheEntries(f)
107+
}
108+
104109
// GetRedirectTargets implements checker.Program.
105110
func (p *Program) GetRedirectTargets(path tspath.Path) []string {
106111
return nil // !!! TODO: project references support

internal/execute/build/buildtask.go

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ type buildTask struct {
7171
configTime time.Time
7272
extendedConfigTimes []time.Time
7373
inputFiles []time.Time
74+
packageJsonTimes []time.Time
7475

7576
buildInfoEntry *buildInfoEntry
7677
buildInfoEntryMu sync.Mutex
@@ -346,6 +347,9 @@ func (t *buildTask) getUpToDateStatus(orchestrator *Orchestrator, configPath tsp
346347

347348
// Check the build info
348349
buildInfoPath := t.resolved.GetBuildInfoFileName()
350+
getBuildInfoDirectory := core.Memoize(func() string {
351+
return tspath.GetDirectoryPath(tspath.GetNormalizedAbsolutePath(buildInfoPath, orchestrator.comparePathsOptions.CurrentDirectory))
352+
})
349353
buildInfo, buildInfoTime := t.loadOrStoreBuildInfo(orchestrator, configPath, buildInfoPath)
350354
if buildInfo == nil {
351355
return &upToDateStatus{kind: upToDateStatusTypeOutputMissing, data: buildInfoPath}
@@ -382,15 +386,17 @@ func (t *buildTask) getUpToDateStatus(orchestrator *Orchestrator, configPath tsp
382386
}
383387

384388
// Some of the emit files like source map or dts etc are not yet done
385-
if buildInfo.IsEmitPending(t.resolved, tspath.GetDirectoryPath(tspath.GetNormalizedAbsolutePath(buildInfoPath, orchestrator.comparePathsOptions.CurrentDirectory))) {
389+
if buildInfo.IsEmitPending(t.resolved, getBuildInfoDirectory()) {
386390
return &upToDateStatus{kind: upToDateStatusTypeOutOfDateOptions, data: buildInfoPath}
387391
}
388392
}
389393
var inputTextUnchanged bool
390394
oldestOutputFileAndTime := fileAndTime{buildInfoPath, buildInfoTime}
391395
var newestInputFileAndTime fileAndTime
392396
var seenRoots collections.Set[tspath.Path]
393-
var buildInfoRootInfoReader *incremental.BuildInfoRootInfoReader
397+
getBuildInfoRootInfoReader := core.Memoize(func() *incremental.BuildInfoRootInfoReader {
398+
return buildInfo.GetBuildInfoRootInfoReader(getBuildInfoDirectory(), orchestrator.comparePathsOptions)
399+
})
394400
for _, inputFile := range t.resolved.FileNames() {
395401
inputTime := orchestrator.host.GetMTime(inputFile)
396402
if inputTime.IsZero() {
@@ -401,10 +407,7 @@ func (t *buildTask) getUpToDateStatus(orchestrator *Orchestrator, configPath tsp
401407
var version string
402408
var currentVersion string
403409
if buildInfo.IsIncremental() {
404-
if buildInfoRootInfoReader == nil {
405-
buildInfoRootInfoReader = buildInfo.GetBuildInfoRootInfoReader(tspath.GetDirectoryPath(tspath.GetNormalizedAbsolutePath(buildInfoPath, orchestrator.comparePathsOptions.CurrentDirectory)), orchestrator.comparePathsOptions)
406-
}
407-
buildInfoFileInfo, resolvedInputPath := buildInfoRootInfoReader.GetBuildInfoFileInfo(inputPath)
410+
buildInfoFileInfo, resolvedInputPath := getBuildInfoRootInfoReader().GetBuildInfoFileInfo(inputPath)
408411
if fileInfo := buildInfoFileInfo.GetFileInfo(); fileInfo != nil && fileInfo.Version() != "" {
409412
version = fileInfo.Version()
410413
if text, ok := orchestrator.host.FS().ReadFile(string(resolvedInputPath)); ok {
@@ -426,10 +429,7 @@ func (t *buildTask) getUpToDateStatus(orchestrator *Orchestrator, configPath tsp
426429
seenRoots.Add(inputPath)
427430
}
428431

429-
if buildInfoRootInfoReader == nil {
430-
buildInfoRootInfoReader = buildInfo.GetBuildInfoRootInfoReader(tspath.GetDirectoryPath(tspath.GetNormalizedAbsolutePath(buildInfoPath, orchestrator.comparePathsOptions.CurrentDirectory)), orchestrator.comparePathsOptions)
431-
}
432-
for root := range buildInfoRootInfoReader.Roots() {
432+
for root := range getBuildInfoRootInfoReader().Roots() {
433433
if !seenRoots.Has(root) {
434434
// File was root file when project was built but its not any more
435435
return &upToDateStatus{kind: upToDateStatusTypeOutOfDateRoots, data: &inputOutputName{string(root), buildInfoPath}}
@@ -512,14 +512,12 @@ func (t *buildTask) getUpToDateStatus(orchestrator *Orchestrator, configPath tsp
512512
}
513513
}
514514

515-
// !!! sheetal TODO : watch??
516-
// // Check package file time
517-
// const packageJsonLookups = state.lastCachedPackageJsonLookups.get(resolvedPath);
518-
// const dependentPackageFileStatus = packageJsonLookups && forEachKey(
519-
// packageJsonLookups,
520-
// path => checkConfigFileUpToDateStatus(state, path, oldestOutputFileTime, oldestOutputFileName),
521-
// );
522-
// if (dependentPackageFileStatus) return dependentPackageFileStatus;
515+
for packageJson := range buildInfo.GetPackageJsons(getBuildInfoDirectory()) {
516+
packageJsonStatus := checkInputFileTime(packageJson)
517+
if packageJsonStatus != nil {
518+
return packageJsonStatus
519+
}
520+
}
523521

524522
return &upToDateStatus{
525523
kind: core.IfElse(
@@ -729,6 +727,11 @@ func (t *buildTask) updateWatch(orchestrator *Orchestrator, oldCache *collection
729727
}
730728
}
731729
}
730+
if t.buildInfoEntry != nil && t.buildInfoEntry.buildInfo != nil {
731+
for file := range t.buildInfoEntry.buildInfo.GetPackageJsons(tspath.GetDirectoryPath(string(t.buildInfoEntry.path))) {
732+
t.packageJsonTimes = append(t.packageJsonTimes, orchestrator.host.loadOrStoreMTime(file, oldCache, false))
733+
}
734+
}
732735
}
733736

734737
func (t *buildTask) resetStatus() {
@@ -778,6 +781,16 @@ func (t *buildTask) hasUpdate(orchestrator *Orchestrator, path tspath.Path) upda
778781
}
779782
}
780783
}
784+
if t.buildInfoEntry != nil && t.buildInfoEntry.buildInfo != nil {
785+
index := 0
786+
for file := range t.buildInfoEntry.buildInfo.GetPackageJsons(tspath.GetDirectoryPath(string(t.buildInfoEntry.path))) {
787+
if orchestrator.host.GetMTime(file) != t.packageJsonTimes[index] {
788+
t.resetStatus()
789+
needsUpdate = true
790+
}
791+
index++
792+
}
793+
}
781794
return core.IfElse(needsConfigUpdate, updateKindConfig, core.IfElse(needsUpdate, updateKindUpdate, updateKindNone))
782795
}
783796

internal/execute/incremental/buildInfo.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ type BuildInfo struct {
457457
Errors bool `json:"errors,omitzero"`
458458
CheckPending bool `json:"checkPending,omitzero"`
459459
Root []*BuildInfoRoot `json:"root,omitzero"`
460+
PackageJsons []string `json:"packageJsons,omitzero"`
460461

461462
// IncrementalProgram info
462463
FileNames []string `json:"fileNames,omitzero"`
@@ -520,6 +521,16 @@ func (b *BuildInfo) IsEmitPending(resolved *tsoptions.ParsedCommandLine, buildIn
520521
return false
521522
}
522523

524+
func (b *BuildInfo) GetPackageJsons(buildInfoDirectory string) iter.Seq[string] {
525+
return func(yield func(string) bool) {
526+
for _, packageJson := range b.PackageJsons {
527+
if !yield(tspath.GetNormalizedAbsolutePath(packageJson, buildInfoDirectory)) {
528+
return
529+
}
530+
}
531+
}
532+
}
533+
523534
func (b *BuildInfo) GetBuildInfoRootInfoReader(buildInfoDirectory string, comparePathOptions tspath.ComparePathsOptions) *BuildInfoRootInfoReader {
524535
resolvedRootFileInfos := make(map[tspath.Path]*BuildInfoFileInfo, len(b.FileNames))
525536
// Roots of the File

internal/execute/incremental/buildinfotosnapshot.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func buildInfoToSnapshot(buildInfo *BuildInfo, config *tsoptions.ParsedCommandLi
4343
to.snapshot.hasErrors = core.IfElse(buildInfo.Errors, core.TSTrue, core.TSFalse)
4444
to.snapshot.hasSemanticErrors = buildInfo.SemanticErrors
4545
to.snapshot.checkPending = buildInfo.CheckPending
46+
to.setPackageJsons()
4647
return &to.snapshot
4748
}
4849

@@ -169,3 +170,11 @@ func (t *toSnapshot) setAffectedFilesPendingEmit() {
169170
t.snapshot.affectedFilesPendingEmit.Store(t.toFilePath(pendingEmit.FileId), core.IfElse(pendingEmit.EmitKind == 0, ownOptionsEmitKind, pendingEmit.EmitKind))
170171
}
171172
}
173+
174+
func (t *toSnapshot) setPackageJsons() {
175+
if t.buildInfo.PackageJsons != nil {
176+
t.snapshot.packageJsons = core.Map(t.buildInfo.PackageJsons, t.toAbsolutePath)
177+
} else {
178+
t.snapshot.packageJsons = make([]string, 0)
179+
}
180+
}

internal/execute/incremental/host.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"time"
55

66
"github.com/microsoft/typescript-go/internal/compiler"
7+
"github.com/microsoft/typescript-go/internal/vfs"
78
)
89

910
type Host interface {
11+
FS() vfs.FS
1012
GetMTime(fileName string) time.Time
1113
SetMTime(fileName string, mTime time.Time) error
1214
}
@@ -17,12 +19,16 @@ type host struct {
1719

1820
var _ Host = (*host)(nil)
1921

20-
func (b *host) GetMTime(fileName string) time.Time {
21-
return GetMTime(b.host, fileName)
22+
func (h *host) FS() vfs.FS {
23+
return h.host.FS()
2224
}
2325

24-
func (b *host) SetMTime(fileName string, mTime time.Time) error {
25-
return b.host.FS().Chtimes(fileName, time.Time{}, mTime)
26+
func (h *host) GetMTime(fileName string) time.Time {
27+
return GetMTime(h.host, fileName)
28+
}
29+
30+
func (h *host) SetMTime(fileName string, mTime time.Time) error {
31+
return h.host.FS().Chtimes(fileName, time.Time{}, mTime)
2632
}
2733

2834
func CreateHost(compilerHost compiler.CompilerHost) Host {

internal/execute/incremental/program.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/microsoft/typescript-go/internal/core"
1313
"github.com/microsoft/typescript-go/internal/diagnostics"
1414
"github.com/microsoft/typescript-go/internal/outputpaths"
15+
"github.com/microsoft/typescript-go/internal/packagejson"
1516
"github.com/microsoft/typescript-go/internal/tspath"
1617
)
1718

@@ -260,11 +261,17 @@ func (p *Program) emitBuildInfo(ctx context.Context, options compiler.EmitOption
260261
return nil
261262
}
262263
if p.snapshot.hasErrors == core.TSUnknown {
263-
p.ensureHasErrorsForState(ctx, p.program)
264+
p.ensureHasErrorsForState(ctx)
264265
if p.snapshot.hasErrors != p.snapshot.hasErrorsFromOldState || p.snapshot.hasSemanticErrors != p.snapshot.hasSemanticErrorsFromOldState {
265266
p.snapshot.buildInfoEmitPending.Store(true)
266267
}
267268
}
269+
if p.snapshot.packageJsons == nil {
270+
p.ensurePackageJsonsForState()
271+
if !slices.Equal(p.snapshot.packageJsons, p.snapshot.packageJsonsFromOldState) {
272+
p.snapshot.buildInfoEmitPending.Store(true)
273+
}
274+
}
268275
if !p.snapshot.buildInfoEmitPending.Load() {
269276
return nil
270277
}
@@ -298,9 +305,9 @@ func (p *Program) emitBuildInfo(ctx context.Context, options compiler.EmitOption
298305
}
299306
}
300307

301-
func (p *Program) ensureHasErrorsForState(ctx context.Context, program *compiler.Program) {
308+
func (p *Program) ensureHasErrorsForState(ctx context.Context) {
302309
var hasIncludeProcessingDiagnostics bool
303-
if slices.ContainsFunc(program.GetSourceFiles(), func(file *ast.SourceFile) bool {
310+
if slices.ContainsFunc(p.program.GetSourceFiles(), func(file *ast.SourceFile) bool {
304311
if _, ok := p.snapshot.emitDiagnosticsPerFile.Load(file.Path()); ok {
305312
// emit diagnostics will be encoded in buildInfo;
306313
return true
@@ -317,12 +324,12 @@ func (p *Program) ensureHasErrorsForState(ctx context.Context, program *compiler
317324
return
318325
}
319326
if hasIncludeProcessingDiagnostics ||
320-
len(program.GetConfigFileParsingDiagnostics()) > 0 ||
321-
len(program.GetSyntacticDiagnostics(ctx, nil)) > 0 ||
322-
len(program.GetProgramDiagnostics()) > 0 ||
323-
len(program.GetBindDiagnostics(ctx, nil)) > 0 ||
324-
len(program.GetOptionsDiagnostics(ctx)) > 0 ||
325-
len(program.GetGlobalDiagnostics(ctx)) > 0 {
327+
len(p.program.GetConfigFileParsingDiagnostics()) > 0 ||
328+
len(p.program.GetSyntacticDiagnostics(ctx, nil)) > 0 ||
329+
len(p.program.GetProgramDiagnostics()) > 0 ||
330+
len(p.program.GetBindDiagnostics(ctx, nil)) > 0 ||
331+
len(p.program.GetOptionsDiagnostics(ctx)) > 0 ||
332+
len(p.program.GetGlobalDiagnostics(ctx)) > 0 {
326333
p.snapshot.hasErrors = core.TSTrue
327334
// Dont need to encode semantic errors state since the syntax and program diagnostics are encoded as present
328335
p.snapshot.hasSemanticErrors = false
@@ -331,7 +338,7 @@ func (p *Program) ensureHasErrorsForState(ctx context.Context, program *compiler
331338

332339
p.snapshot.hasErrors = core.TSFalse
333340
// Check semantic and emit diagnostics first as we dont need to ask program about it
334-
if slices.ContainsFunc(program.GetSourceFiles(), func(file *ast.SourceFile) bool {
341+
if slices.ContainsFunc(p.program.GetSourceFiles(), func(file *ast.SourceFile) bool {
335342
semanticDiagnostics, ok := p.snapshot.semanticDiagnosticsPerFile.Load(file.Path())
336343
if !ok {
337344
// Missing semantic diagnostics in cache will be encoded in incremental buildInfo
@@ -348,3 +355,21 @@ func (p *Program) ensureHasErrorsForState(ctx context.Context, program *compiler
348355
p.snapshot.hasSemanticErrors = !p.snapshot.options.IsIncremental()
349356
}
350357
}
358+
359+
func (p *Program) ensurePackageJsonsForState() {
360+
config := tspath.GetDirectoryPath(p.program.CommandLine().ConfigName())
361+
if config != "" {
362+
p.program.PackageJsonCacheEntries(func(key tspath.Path, value *packagejson.InfoCacheEntry) bool {
363+
if value.Exists() {
364+
p.snapshot.packageJsons = append(p.snapshot.packageJsons, p.host.FS().Realpath(tspath.CombinePaths(value.PackageDirectory, "package.json")))
365+
}
366+
return true
367+
})
368+
}
369+
if p.snapshot.packageJsons == nil {
370+
p.snapshot.packageJsons = make([]string, 0)
371+
} else {
372+
slices.Sort(p.snapshot.packageJsons)
373+
p.snapshot.packageJsons = core.Deduplicate(p.snapshot.packageJsons)
374+
}
375+
}

internal/execute/incremental/programtosnapshot.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func (t *toProgramSnapshot) reuseFromOldProgram() {
6262
t.snapshot.buildInfoEmitPending.Store(t.oldProgram.snapshot.buildInfoEmitPending.Load())
6363
t.snapshot.hasErrorsFromOldState = t.oldProgram.snapshot.hasErrors
6464
t.snapshot.hasSemanticErrorsFromOldState = t.oldProgram.snapshot.hasSemanticErrors
65+
t.snapshot.packageJsonsFromOldState = t.oldProgram.snapshot.packageJsons
6566
} else {
6667
t.snapshot.buildInfoEmitPending.Store(t.snapshot.options.IsIncremental())
6768
}

internal/execute/incremental/snapshot.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ type snapshot struct {
216216
hasSemanticErrors bool
217217
// If semantic diagnostic check is pending
218218
checkPending bool
219+
// Looked up package.json files from
220+
packageJsons []string
219221

220222
// Additional fields that are not serialized but needed to track state
221223

@@ -224,6 +226,7 @@ type snapshot struct {
224226
hasErrorsFromOldState core.Tristate
225227
hasSemanticErrorsFromOldState bool
226228
allFilesExcludingDefaultLibraryFileOnce sync.Once
229+
packageJsonsFromOldState []string
227230
// Cache of all files excluding default library file for the current program
228231
allFilesExcludingDefaultLibraryFile []*ast.SourceFile
229232
hasChangedDtsFile bool

internal/execute/incremental/snapshottobuildinfo.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func snapshotToBuildInfo(snapshot *snapshot, program *compiler.Program, buildInf
4949
to.buildInfo.Errors = snapshot.hasErrors.IsTrue()
5050
to.buildInfo.SemanticErrors = snapshot.hasSemanticErrors
5151
to.buildInfo.CheckPending = snapshot.checkPending
52+
to.setPackageJsons()
5253
return &to.buildInfo
5354
}
5455

@@ -350,3 +351,9 @@ func (t *toBuildInfo) setRootOfNonIncrementalProgram() {
350351
}
351352
})
352353
}
354+
355+
func (t *toBuildInfo) setPackageJsons() {
356+
if len(t.snapshot.packageJsons) > 0 {
357+
t.buildInfo.PackageJsons = core.Map(t.snapshot.packageJsons, t.relativeToBuildInfo)
358+
}
359+
}

0 commit comments

Comments
 (0)