Skip to content

Commit be4e57f

Browse files
committed
Fix bugs, make tests pass
1 parent 2c05e61 commit be4e57f

File tree

8 files changed

+89
-303
lines changed

8 files changed

+89
-303
lines changed

internal/collections/ordered_map.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ func DiffOrderedMaps[K comparable, V comparable](m1 *OrderedMap[K, V], m2 *Order
300300
}
301301

302302
func DiffOrderedMapsFunc[K comparable, V any](m1 *OrderedMap[K, V], m2 *OrderedMap[K, V], equalValues func(a, b V) bool, onAdded func(key K, value V), onRemoved func(key K, value V), onModified func(key K, oldValue V, newValue V)) {
303+
for k, v2 := range m2.Entries() {
304+
if _, ok := m1.Get(k); !ok {
305+
onAdded(k, v2)
306+
}
307+
}
303308
for k, v1 := range m1.Entries() {
304309
if v2, ok := m2.Get(k); ok {
305310
if !equalValues(v1, v2) {
@@ -309,10 +314,4 @@ func DiffOrderedMapsFunc[K comparable, V any](m1 *OrderedMap[K, V], m2 *OrderedM
309314
onRemoved(k, v1)
310315
}
311316
}
312-
313-
for k, v2 := range m2.Entries() {
314-
if _, ok := m1.Get(k); !ok {
315-
onAdded(k, v2)
316-
}
317-
}
318317
}

internal/core/core.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,11 @@ func DiffMaps[K comparable, V comparable](m1 map[K]V, m2 map[K]V, onAdded func(K
604604
}
605605

606606
func DiffMapsFunc[K comparable, V any](m1 map[K]V, m2 map[K]V, equalValues func(V, V) bool, onAdded func(K, V), onRemoved func(K, V), onChanged func(K, V, V)) {
607+
for k, v2 := range m2 {
608+
if _, ok := m1[k]; !ok {
609+
onAdded(k, v2)
610+
}
611+
}
607612
for k, v1 := range m1 {
608613
if v2, ok := m2[k]; ok {
609614
if !equalValues(v1, v2) {
@@ -613,12 +618,6 @@ func DiffMapsFunc[K comparable, V any](m1 map[K]V, m2 map[K]V, equalValues func(
613618
onRemoved(k, v1)
614619
}
615620
}
616-
617-
for k, v2 := range m2 {
618-
if _, ok := m1[k]; !ok {
619-
onAdded(k, v2)
620-
}
621-
}
622621
}
623622

624623
// CopyMapInto is maps.Copy, unless dst is nil, in which case it clones and returns src.

internal/project/configfileregistrybuilder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ func (c *configFileRegistryBuilder) DidChangeFiles(summary FileChangeSummary, lo
387387
}
388388
logger.Logf("Checking if any of %d created files match root files for config %s", len(createdFiles), entry.Key())
389389
for _, fileName := range createdFiles {
390-
parsedGlobs := config.rootFilesWatch.ParsedGlobs()
390+
parsedGlobs := config.commandLine.WildcardDirectoryGlobs()
391391
for _, g := range parsedGlobs {
392392
if g.Match(fileName) {
393393
return true

internal/project/projectcollectionbuilder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ func (b *projectCollectionBuilder) findOrCreateDefaultConfiguredProjectWorker(
535535
// For composite projects, we can get an early negative result.
536536
// !!! what about declaration files in node_modules? wouldn't it be better to
537537
// check project inclusion if the project is already loaded?
538-
if !config.MatchesFileName(fileName) {
538+
if _, ok := config.FileNamesByPath()[path]; !ok {
539539
node.logger.Log("Project does not contain file (by composite config inclusion)")
540540
return false, false
541541
}

internal/project/projectlifetime_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func TestProjectLifetime(t *testing.T) {
7070
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 2)
7171
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
7272
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p2/tsconfig.json")) != nil)
73-
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 2)
73+
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 1)
7474
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
7575
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p2/tsconfig.json")) != nil)
7676

@@ -89,8 +89,8 @@ func TestProjectLifetime(t *testing.T) {
8989
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) == nil)
9090
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p2/tsconfig.json")) != nil)
9191
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p3/tsconfig.json")) != nil)
92-
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 3)
93-
assert.Equal(t, len(utils.Client().UnwatchFilesCalls()), 1)
92+
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 1)
93+
assert.Equal(t, len(utils.Client().UnwatchFilesCalls()), 0)
9494

9595
// Close p2 and p3 files, open p1 file again
9696
session.DidCloseFile(context.Background(), uri2)
@@ -105,8 +105,8 @@ func TestProjectLifetime(t *testing.T) {
105105
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
106106
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p2/tsconfig.json")) == nil)
107107
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p3/tsconfig.json")) == nil)
108-
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 4)
109-
assert.Equal(t, len(utils.Client().UnwatchFilesCalls()), 3)
108+
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 1)
109+
assert.Equal(t, len(utils.Client().UnwatchFilesCalls()), 0)
110110
})
111111

112112
t.Run("unrooted inferred projects", func(t *testing.T) {

internal/project/watch.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,17 @@ func (w *WatchedFiles[T]) Watchers() (WatcherID, []*lsproto.FileSystemWatcher) {
8080
ignored := result.ignored
8181
// ignored is only used for logging and doesn't affect watcher identity
8282
w.ignored = ignored
83-
newWatchers := core.Map(globs, func(glob string) *lsproto.FileSystemWatcher {
84-
return &lsproto.FileSystemWatcher{
85-
GlobPattern: lsproto.PatternOrRelativePattern{
86-
Pattern: &glob,
87-
},
88-
Kind: &w.watchKind,
89-
}
90-
})
91-
if !slices.EqualFunc(w.watchers, newWatchers, func(a, b *lsproto.FileSystemWatcher) bool {
92-
return *a.GlobPattern.Pattern == *b.GlobPattern.Pattern
83+
if !slices.EqualFunc(w.watchers, globs, func(a *lsproto.FileSystemWatcher, b string) bool {
84+
return *a.GlobPattern.Pattern == b
9385
}) {
94-
w.watchers = newWatchers
86+
w.watchers = core.Map(globs, func(glob string) *lsproto.FileSystemWatcher {
87+
return &lsproto.FileSystemWatcher{
88+
GlobPattern: lsproto.PatternOrRelativePattern{
89+
Pattern: &glob,
90+
},
91+
Kind: &w.watchKind,
92+
}
93+
})
9594
w.id = watcherID.Add(1)
9695
}
9796
})
@@ -134,6 +133,7 @@ func (w *WatchedFiles[T]) Clone(input T) *WatchedFiles[T] {
134133
name: w.name,
135134
watchKind: w.watchKind,
136135
computeGlobPatterns: w.computeGlobPatterns,
136+
watchers: w.watchers,
137137
input: input,
138138
parsedGlobs: w.parsedGlobs,
139139
}
@@ -303,5 +303,5 @@ func getNonRootFileGlobs(workspaceDir string, sourceFiles []*ast.SourceFile, roo
303303
}
304304

305305
func getRecursiveGlobPattern(directory string) string {
306-
return fmt.Sprintf("%s/%s", directory, "**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,json}")
306+
return fmt.Sprintf("%s/%s", tspath.RemoveTrailingDirectorySeparator(directory), "**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,json}")
307307
}

internal/tsoptions/parsedcommandline.go

Lines changed: 57 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
package tsoptions
22

33
import (
4+
"fmt"
45
"iter"
56
"slices"
7+
"strings"
68
"sync"
79

810
"github.com/microsoft/typescript-go/internal/ast"
9-
"github.com/microsoft/typescript-go/internal/collections"
1011
"github.com/microsoft/typescript-go/internal/core"
12+
"github.com/microsoft/typescript-go/internal/glob"
1113
"github.com/microsoft/typescript-go/internal/module"
1214
"github.com/microsoft/typescript-go/internal/outputpaths"
1315
"github.com/microsoft/typescript-go/internal/tspath"
1416
"github.com/microsoft/typescript-go/internal/vfs"
1517
)
1618

19+
const (
20+
fileGlobPattern = "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,json}"
21+
recursiveFileGlobPattern = "**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,json}"
22+
)
23+
1724
type ParsedCommandLine struct {
1825
ParsedConfig *core.ParsedOptions `json:"parsedConfig"`
1926

@@ -25,6 +32,8 @@ type ParsedCommandLine struct {
2532
comparePathsOptions tspath.ComparePathsOptions
2633
wildcardDirectoriesOnce sync.Once
2734
wildcardDirectories map[string]bool
35+
includeGlobsOnce sync.Once
36+
includeGlobs []*glob.Glob
2837
extraFileExtensions []FileExtensionInfo
2938

3039
sourceAndOutputMapsOnce sync.Once
@@ -197,21 +206,40 @@ func (p *ParsedCommandLine) WildcardDirectories() map[string]bool {
197206
return nil
198207
}
199208

200-
if p.wildcardDirectories != nil {
201-
return p.wildcardDirectories
202-
}
203-
204209
p.wildcardDirectoriesOnce.Do(func() {
205-
p.wildcardDirectories = getWildcardDirectories(
206-
p.ConfigFile.configFileSpecs.validatedIncludeSpecs,
207-
p.ConfigFile.configFileSpecs.validatedExcludeSpecs,
208-
p.comparePathsOptions,
209-
)
210+
if p.wildcardDirectories == nil {
211+
p.wildcardDirectories = getWildcardDirectories(
212+
p.ConfigFile.configFileSpecs.validatedIncludeSpecs,
213+
p.ConfigFile.configFileSpecs.validatedExcludeSpecs,
214+
p.comparePathsOptions,
215+
)
216+
}
210217
})
211218

212219
return p.wildcardDirectories
213220
}
214221

222+
func (p *ParsedCommandLine) WildcardDirectoryGlobs() []*glob.Glob {
223+
wildcardDirectories := p.WildcardDirectories()
224+
if wildcardDirectories == nil {
225+
return nil
226+
}
227+
228+
p.includeGlobsOnce.Do(func() {
229+
if p.includeGlobs == nil {
230+
globs := make([]*glob.Glob, 0, len(wildcardDirectories))
231+
for dir, recursive := range wildcardDirectories {
232+
if parsed, err := glob.Parse(fmt.Sprintf("%s/%s", tspath.NormalizePath(dir), core.IfElse(recursive, recursiveFileGlobPattern, fileGlobPattern))); err == nil {
233+
globs = append(globs, parsed)
234+
}
235+
}
236+
p.includeGlobs = globs
237+
}
238+
})
239+
240+
return p.includeGlobs
241+
}
242+
215243
// Normalized file names explicitly specified in `files`
216244
func (p *ParsedCommandLine) LiteralFileNames() []string {
217245
if p != nil && p.ConfigFile != nil {
@@ -285,48 +313,30 @@ func (p *ParsedCommandLine) GetConfigFileParsingDiagnostics() []*ast.Diagnostic
285313
return p.Errors
286314
}
287315

288-
// Porting reference: ProjectService.isMatchedByConfig
289-
func (p *ParsedCommandLine) MatchesFileName(fileName string) bool {
316+
// PossiblyMatchesFileName is a fast check to see if a file is currently included by a config
317+
// or would be included if the file were to be created. It may return false positives.
318+
func (p *ParsedCommandLine) PossiblyMatchesFileName(fileName string) bool {
290319
path := tspath.ToPath(fileName, p.GetCurrentDirectory(), p.UseCaseSensitiveFileNames())
291-
if slices.ContainsFunc(p.FileNames(), func(f string) bool {
292-
return path == tspath.ToPath(f, p.GetCurrentDirectory(), p.UseCaseSensitiveFileNames())
293-
}) {
320+
if _, ok := p.FileNamesByPath()[path]; ok {
294321
return true
295322
}
296323

297-
if p.ConfigFile == nil {
298-
return false
299-
}
300-
301-
if len(p.ConfigFile.configFileSpecs.validatedIncludeSpecs) == 0 {
302-
return false
303-
}
304-
305-
supportedExtensions := GetSupportedExtensionsWithJsonIfResolveJsonModule(
306-
p.CompilerOptions(),
307-
GetSupportedExtensions(p.CompilerOptions(), p.extraFileExtensions),
308-
)
309-
310-
if !tspath.FileExtensionIsOneOf(fileName, core.Flatten(supportedExtensions)) {
311-
return false
312-
}
313-
314-
if p.ConfigFile.configFileSpecs.matchesExclude(fileName, p.comparePathsOptions) {
315-
return false
316-
}
317-
318-
var allFileNames collections.Set[tspath.Path]
319-
for _, fileName := range p.FileNames() {
320-
allFileNames.Add(tspath.ToPath(fileName, p.GetCurrentDirectory(), p.UseCaseSensitiveFileNames()))
324+
for _, include := range p.ConfigFile.configFileSpecs.validatedIncludeSpecs {
325+
if !strings.ContainsAny(include, "*?") && !vfs.IsImplicitGlob(include) {
326+
includePath := tspath.ToPath(include, p.GetCurrentDirectory(), p.UseCaseSensitiveFileNames())
327+
if includePath == path {
328+
return true
329+
}
330+
}
321331
}
322-
323-
if hasFileWithHigherPriorityExtension(string(path), supportedExtensions, func(fileName string) bool {
324-
return allFileNames.Has(tspath.Path(fileName))
325-
}) {
326-
return false
332+
if wildcardDirectoryGlobs := p.WildcardDirectoryGlobs(); len(wildcardDirectoryGlobs) > 0 {
333+
for _, glob := range wildcardDirectoryGlobs {
334+
if glob.Match(fileName) {
335+
return true
336+
}
337+
}
327338
}
328-
329-
return p.ConfigFile.configFileSpecs.getMatchedIncludeSpec(fileName, p.comparePathsOptions) != ""
339+
return false
330340
}
331341

332342
func (p *ParsedCommandLine) GetMatchedFileSpec(fileName string) string {
@@ -363,6 +373,7 @@ func (p *ParsedCommandLine) ReloadFileNamesOfParsedCommandLine(fs vfs.FS) *Parse
363373
CompileOnSave: p.CompileOnSave,
364374
comparePathsOptions: p.comparePathsOptions,
365375
wildcardDirectories: p.wildcardDirectories,
376+
includeGlobs: p.includeGlobs,
366377
extraFileExtensions: p.extraFileExtensions,
367378
literalFileNamesLen: literalFileNamesLen,
368379
}

0 commit comments

Comments
 (0)