7
7
"slices"
8
8
"strings"
9
9
"sync"
10
+ "time"
10
11
11
12
"github.com/microsoft/typescript-go/internal/ast"
12
13
"github.com/microsoft/typescript-go/internal/collections"
@@ -92,15 +93,13 @@ type Project struct {
92
93
name string
93
94
kind Kind
94
95
95
- dirtyStateMu sync.Mutex
96
- initialLoadPending bool
97
- dirty bool
98
- version int
99
- hasAddedOrRemovedFiles bool
100
- hasAddedOrRemovedSymlinks bool
101
- deferredClose bool
102
- pendingReload PendingReload
103
- dirtyFilePath tspath.Path
96
+ mu sync.Mutex
97
+ initialLoadPending bool
98
+ dirty bool
99
+ version int
100
+ deferredClose bool
101
+ pendingReload PendingReload
102
+ dirtyFilePath tspath.Path
104
103
105
104
comparePathsOptions tspath.ComparePathsOptions
106
105
currentDirectory string
@@ -114,7 +113,6 @@ type Project struct {
114
113
rootFileNames * collections.OrderedMap [tspath.Path , string ]
115
114
compilerOptions * core.CompilerOptions
116
115
parsedCommandLine * tsoptions.ParsedCommandLine
117
- programMu sync.Mutex
118
116
program * compiler.Program
119
117
checkerPool * checkerPool
120
118
@@ -211,7 +209,7 @@ func (p *Project) GetSourceFile(fileName string, path tspath.Path, languageVersi
211
209
212
210
// Updates the program if needed.
213
211
func (p * Project ) GetProgram () * compiler.Program {
214
- p .updateIfDirty ()
212
+ p .updateGraph ()
215
213
return p .program
216
214
}
217
215
@@ -372,9 +370,9 @@ func (p *Project) getScriptKind(fileName string) core.ScriptKind {
372
370
return core .GetScriptKindFromFileName (fileName )
373
371
}
374
372
375
- func (p * Project ) markFileAsDirty (path tspath.Path ) {
376
- p .dirtyStateMu .Lock ()
377
- defer p .dirtyStateMu .Unlock ()
373
+ func (p * Project ) MarkFileAsDirty (path tspath.Path ) {
374
+ p .mu .Lock ()
375
+ defer p .mu .Unlock ()
378
376
if ! p .dirty {
379
377
p .dirty = true
380
378
p .dirtyFilePath = path
@@ -385,69 +383,57 @@ func (p *Project) markFileAsDirty(path tspath.Path) {
385
383
}
386
384
387
385
func (p * Project ) markAsDirty () {
388
- p .dirtyStateMu .Lock ()
389
- defer p .dirtyStateMu .Unlock ()
386
+ p .mu .Lock ()
387
+ defer p .mu .Unlock ()
388
+ p .markAsDirtyLocked ()
389
+ }
390
+
391
+ func (p * Project ) markAsDirtyLocked () {
390
392
p .dirtyFilePath = ""
391
393
if ! p .dirty {
392
394
p .dirty = true
393
395
p .version ++
394
396
}
395
397
}
396
398
397
- // updateIfDirty returns true if the project was updated.
398
- func (p * Project ) updateIfDirty () bool {
399
- // !!! p.invalidateResolutionsOfFailedLookupLocations()
400
- return p .dirty && p .updateGraph ()
401
- }
402
-
403
- func (p * Project ) onFileAddedOrRemoved (isSymlink bool ) {
404
- p .dirtyStateMu .Lock ()
405
- defer p .dirtyStateMu .Unlock ()
406
- p .hasAddedOrRemovedFiles = true
407
- if isSymlink {
408
- p .hasAddedOrRemovedSymlinks = true
409
- }
410
- }
411
-
412
399
// updateGraph updates the set of files that contribute to the project.
413
400
// Returns true if the set of files in has changed. NOTE: this is the
414
401
// opposite of the return value in Strada, which was frequently inverted,
415
402
// as in `updateProjectIfDirty()`.
416
403
func (p * Project ) updateGraph () bool {
417
- p .programMu .Lock ()
418
- defer p .programMu .Unlock ()
404
+ p .mu .Lock ()
405
+ defer p .mu .Unlock ()
406
+
419
407
if ! p .dirty {
420
408
return false
421
409
}
422
410
411
+ start := time .Now ()
423
412
p .log ("Starting updateGraph: Project: " + p .name )
413
+ var writeFileNames bool
424
414
oldProgram := p .program
425
- hasAddedOrRemovedFiles := p .hasAddedOrRemovedFiles
426
415
p .initialLoadPending = false
427
416
428
417
if p .kind == KindConfigured && p .pendingReload != PendingReloadNone {
429
418
switch p .pendingReload {
430
419
case PendingReloadFileNames :
431
420
p .parsedCommandLine = tsoptions .ReloadFileNamesOfParsedCommandLine (p .parsedCommandLine , p .host .FS ())
432
- p .setRootFiles (p .parsedCommandLine .FileNames ())
421
+ writeFileNames = p .setRootFiles (p .parsedCommandLine .FileNames ())
433
422
case PendingReloadFull :
434
- if err := p .LoadConfig (); err != nil {
423
+ if err := p .loadConfig (); err != nil {
435
424
panic (fmt .Sprintf ("failed to reload config: %v" , err ))
436
425
}
437
426
}
438
427
p .pendingReload = PendingReloadNone
439
428
}
440
429
441
- p .hasAddedOrRemovedFiles = false
442
- p .hasAddedOrRemovedSymlinks = false
443
430
oldProgramReused := p .updateProgram ()
444
431
p .dirty = false
445
432
p .dirtyFilePath = ""
446
- p .log (fmt .Sprintf ("Finishing updateGraph: Project: %s version: %d" , p .name , p .version ))
447
- if hasAddedOrRemovedFiles {
433
+ if writeFileNames {
448
434
p .log (p .print (true /*writeFileNames*/ , true /*writeFileExplanation*/ , false /*writeFileVersionAndText*/ ))
449
435
} else if p .program != oldProgram {
450
- p .log ("Different program with same set of files" )
436
+ p .log ("Different program with same set of root files" )
451
437
}
452
438
if ! oldProgramReused {
453
439
if oldProgram != nil {
@@ -461,6 +447,7 @@ func (p *Project) updateGraph() bool {
461
447
// but in Strada we throttle, so at least sometimes this should be considered top-level?
462
448
p .updateWatchers (context .TODO ())
463
449
}
450
+ p .log (fmt .Sprintf ("Finishing updateGraph: Project: %s version: %d in %s" , p .name , p .version , time .Since (start )))
464
451
return true
465
452
}
466
453
@@ -509,6 +496,13 @@ func (p *Project) isRoot(info *ScriptInfo) bool {
509
496
return p .rootFileNames .Has (info .path )
510
497
}
511
498
499
+ func (p * Project ) RemoveFile (info * ScriptInfo , fileExists bool , detachFromProject bool ) {
500
+ p .mu .Lock ()
501
+ defer p .mu .Unlock ()
502
+ p .removeFile (info , fileExists , detachFromProject )
503
+ p .markAsDirtyLocked ()
504
+ }
505
+
512
506
func (p * Project ) removeFile (info * ScriptInfo , fileExists bool , detachFromProject bool ) {
513
507
if p .isRoot (info ) {
514
508
switch p .kind {
@@ -530,7 +524,13 @@ func (p *Project) removeFile(info *ScriptInfo, fileExists bool, detachFromProjec
530
524
if detachFromProject {
531
525
info .detachFromProject (p )
532
526
}
533
- p .markAsDirty ()
527
+ }
528
+
529
+ func (p * Project ) AddRoot (info * ScriptInfo ) {
530
+ p .mu .Lock ()
531
+ defer p .mu .Unlock ()
532
+ p .addRoot (info )
533
+ p .markAsDirtyLocked ()
534
534
}
535
535
536
536
func (p * Project ) addRoot (info * ScriptInfo ) {
@@ -544,10 +544,17 @@ func (p *Project) addRoot(info *ScriptInfo) {
544
544
}
545
545
p .rootFileNames .Set (info .path , info .fileName )
546
546
info .attachToProject (p )
547
- p .markAsDirty ()
548
547
}
549
548
550
549
func (p * Project ) LoadConfig () error {
550
+ if err := p .loadConfig (); err != nil {
551
+ return err
552
+ }
553
+ p .markAsDirty ()
554
+ return nil
555
+ }
556
+
557
+ func (p * Project ) loadConfig () error {
551
558
if p .kind != KindConfigured {
552
559
panic ("loadConfig called on non-configured project" )
553
560
}
@@ -582,12 +589,12 @@ func (p *Project) LoadConfig() error {
582
589
p .compilerOptions = & core.CompilerOptions {}
583
590
return fmt .Errorf ("could not read file %q" , p .configFileName )
584
591
}
585
-
586
- p .markAsDirty ()
587
592
return nil
588
593
}
589
594
590
- func (p * Project ) setRootFiles (rootFileNames []string ) {
595
+ // setRootFiles returns true if the set of root files has changed.
596
+ func (p * Project ) setRootFiles (rootFileNames []string ) bool {
597
+ var hasChanged bool
591
598
newRootScriptInfos := make (map [tspath.Path ]struct {}, len (rootFileNames ))
592
599
for _ , file := range rootFileNames {
593
600
scriptKind := p .getScriptKind (file )
@@ -597,6 +604,7 @@ func (p *Project) setRootFiles(rootFileNames []string) {
597
604
scriptInfo := p .host .GetOrCreateScriptInfoForFile (file , path , scriptKind )
598
605
newRootScriptInfos [path ] = struct {}{}
599
606
isAlreadyRoot := p .rootFileNames .Has (path )
607
+ hasChanged = hasChanged || ! isAlreadyRoot
600
608
601
609
if ! isAlreadyRoot && scriptInfo != nil {
602
610
p .addRoot (scriptInfo )
@@ -610,6 +618,7 @@ func (p *Project) setRootFiles(rootFileNames []string) {
610
618
}
611
619
612
620
if p .rootFileNames .Size () > len (rootFileNames ) {
621
+ hasChanged = true
613
622
for root := range p .rootFileNames .Keys () {
614
623
if _ , ok := newRootScriptInfos [root ]; ! ok {
615
624
if info := p .host .GetScriptInfoByPath (root ); info != nil {
@@ -620,6 +629,7 @@ func (p *Project) setRootFiles(rootFileNames []string) {
620
629
}
621
630
}
622
631
}
632
+ return hasChanged
623
633
}
624
634
625
635
func (p * Project ) clearSourceMapperCache () {
0 commit comments