diff --git a/internal/tsoptions/parsedcommandline.go b/internal/tsoptions/parsedcommandline.go index db80c91be4..f40fbc2639 100644 --- a/internal/tsoptions/parsedcommandline.go +++ b/internal/tsoptions/parsedcommandline.go @@ -37,6 +37,7 @@ type ParsedCommandLine struct { resolvedProjectReferencePaths []string resolvedProjectReferencePathsOnce sync.Once + literalFileNamesLen int fileNamesByPath map[tspath.Path]string // maps file names to their paths, used for quick lookups fileNamesByPathOnce sync.Once } @@ -217,7 +218,7 @@ func (p *ParsedCommandLine) WildcardDirectories() map[string]bool { // Normalized file names explicitly specified in `files` func (p *ParsedCommandLine) LiteralFileNames() []string { if p != nil && p.ConfigFile != nil { - return p.FileNames()[0:len(p.ConfigFile.configFileSpecs.validatedFilesSpec)] + return p.FileNames()[0:p.literalFileNamesLen] } return nil } @@ -349,13 +350,14 @@ func (p *ParsedCommandLine) GetMatchedIncludeSpec(fileName string) (string, bool func (p *ParsedCommandLine) ReloadFileNamesOfParsedCommandLine(fs vfs.FS) *ParsedCommandLine { parsedConfig := *p.ParsedConfig - parsedConfig.FileNames = getFileNamesFromConfigSpecs( + fileNames, literalFileNamesLen := getFileNamesFromConfigSpecs( *p.ConfigFile.configFileSpecs, p.GetCurrentDirectory(), p.CompilerOptions(), fs, p.extraFileExtensions, ) + parsedConfig.FileNames = fileNames parsedCommandLine := ParsedCommandLine{ ParsedConfig: &parsedConfig, ConfigFile: p.ConfigFile, @@ -365,6 +367,7 @@ func (p *ParsedCommandLine) ReloadFileNamesOfParsedCommandLine(fs vfs.FS) *Parse comparePathsOptions: p.comparePathsOptions, wildcardDirectories: p.wildcardDirectories, extraFileExtensions: p.extraFileExtensions, + literalFileNamesLen: literalFileNamesLen, } return &parsedCommandLine } diff --git a/internal/tsoptions/parsedcommandline_test.go b/internal/tsoptions/parsedcommandline_test.go index 0185e6abe0..18c83ba633 100644 --- a/internal/tsoptions/parsedcommandline_test.go +++ b/internal/tsoptions/parsedcommandline_test.go @@ -111,6 +111,28 @@ func TestParsedCommandLine(t *testing.T) { "/dev/b.ts", }) }) + + t.Run("duplicates", func(t *testing.T) { + t.Parallel() + parsedCommandLine := tsoptionstest.GetParsedCommandLine( + t, + `{ + "files": [ + "a.ts", + "a.ts", + "b.ts", + ] + }`, + files, + "/dev", + /*useCaseSensitiveFileNames*/ true, + ) + + assert.DeepEqual(t, parsedCommandLine.LiteralFileNames(), []string{ + "/dev/a.ts", + "/dev/b.ts", + }) + }) }) t.Run("with literal include list", func(t *testing.T) { diff --git a/internal/tsoptions/tsconfigparsing.go b/internal/tsoptions/tsconfigparsing.go index d81f75880a..663802b9d8 100644 --- a/internal/tsoptions/tsconfigparsing.go +++ b/internal/tsoptions/tsconfigparsing.go @@ -1269,9 +1269,9 @@ func parseJsonConfigFileContentWorker( sourceFile.configFileSpecs = &configFileSpecs } - getFileNames := func(basePath string) []string { + getFileNames := func(basePath string) ([]string, int) { parsedConfigOptions := parsedConfig.options - fileNames := getFileNamesFromConfigSpecs(configFileSpecs, basePath, parsedConfigOptions, host.FS(), extraFileExtensions) + fileNames, literalFileNamesLen := getFileNamesFromConfigSpecs(configFileSpecs, basePath, parsedConfigOptions, host.FS(), extraFileExtensions) if shouldReportNoInputFiles(fileNames, canJsonReportNoInputFiles(rawConfig), resolutionStack) { includeSpecs := configFileSpecs.includeSpecs excludeSpecs := configFileSpecs.excludeSpecs @@ -1283,7 +1283,7 @@ func parseJsonConfigFileContentWorker( } errors = append(errors, ast.NewCompilerDiagnostic(diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, configFileName, core.Must(core.StringifyJson(includeSpecs, "", "")), core.Must(core.StringifyJson(excludeSpecs, "", "")))) } - return fileNames + return fileNames, literalFileNamesLen } getProjectReferences := func(basePath string) []*core.ProjectReference { @@ -1310,12 +1310,13 @@ func parseJsonConfigFileContentWorker( return projectReferences } + fileNames, literalFileNamesLen := getFileNames(basePathForFileNames) return &ParsedCommandLine{ ParsedConfig: &core.ParsedOptions{ CompilerOptions: parsedConfig.options, TypeAcquisition: parsedConfig.typeAcquisition, // WatchOptions: nil, - FileNames: getFileNames(basePathForFileNames), + FileNames: fileNames, ProjectReferences: getProjectReferences(basePathForFileNames), }, ConfigFile: sourceFile, @@ -1327,6 +1328,7 @@ func parseJsonConfigFileContentWorker( UseCaseSensitiveFileNames: host.FS().UseCaseSensitiveFileNames(), CurrentDirectory: basePathForFileNames, }, + literalFileNamesLen: literalFileNamesLen, } } @@ -1608,7 +1610,7 @@ func getFileNamesFromConfigSpecs( options *core.CompilerOptions, host vfs.FS, extraFileExtensions []FileExtensionInfo, -) []string { +) ([]string, int) { extraFileExtensions = []FileExtensionInfo{} basePath = tspath.NormalizePath(basePath) keyMappper := func(value string) string { return tspath.GetCanonicalFileName(value, host.UseCaseSensitiveFileNames()) } @@ -1696,7 +1698,7 @@ func getFileNamesFromConfigSpecs( for file := range wildCardJsonFileMap.Values() { files = append(files, file) } - return files + return files, literalFileMap.Size() } func GetSupportedExtensions(compilerOptions *core.CompilerOptions, extraFileExtensions []FileExtensionInfo) [][]string {