diff --git a/internal/compiler/fileloader.go b/internal/compiler/fileloader.go index ef866d1921..c1122f44ce 100644 --- a/internal/compiler/fileloader.go +++ b/internal/compiler/fileloader.go @@ -129,128 +129,12 @@ func processAllProgramFiles( } loader.filesParser.parse(&loader, loader.rootTasks) + // Clear out loader and host to ensure its not used post program creation loader.projectReferenceFileMapper.loader = nil loader.projectReferenceFileMapper.host = nil - totalFileCount := int(loader.totalFileCount.Load()) - libFileCount := int(loader.libFileCount.Load()) - - var missingFiles []string - files := make([]*ast.SourceFile, 0, totalFileCount-libFileCount) - libFiles := make([]*ast.SourceFile, 0, totalFileCount) // totalFileCount here since we append files to it later to construct the final list - - filesByPath := make(map[tspath.Path]*ast.SourceFile, totalFileCount) - loader.includeProcessor.fileIncludeReasons = make(map[tspath.Path][]*FileIncludeReason, totalFileCount) - var outputFileToProjectReferenceSource map[tspath.Path]string - if !opts.canUseProjectReferenceSource() { - outputFileToProjectReferenceSource = make(map[tspath.Path]string, totalFileCount) - } - resolvedModules := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule], totalFileCount+1) - typeResolutionsInFile := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], totalFileCount) - sourceFileMetaDatas := make(map[tspath.Path]ast.SourceFileMetaData, totalFileCount) - var jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier - var importHelpersImportSpecifiers map[tspath.Path]*ast.Node - var sourceFilesFoundSearchingNodeModules collections.Set[tspath.Path] - libFilesMap := make(map[tspath.Path]*LibFile, libFileCount) - - loader.filesParser.collect(&loader, loader.rootTasks, func(task *parseTask) { - if task.redirectedParseTask != nil { - if !opts.canUseProjectReferenceSource() { - outputFileToProjectReferenceSource[task.redirectedParseTask.path] = task.FileName() - } - return - } - - if task.isForAutomaticTypeDirective { - typeResolutionsInFile[task.path] = task.typeResolutionsInFile - return - } - file := task.file - path := task.path - if file == nil { - // !!! sheetal file preprocessing diagnostic explaining getSourceFileFromReferenceWorker - missingFiles = append(missingFiles, task.normalizedFilePath) - return - } - - // !!! sheetal todo porting file case errors - // if _, ok := filesByPath[path]; ok { - // Check if it differs only in drive letters its ok to ignore that error: - // const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory); - // const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(fileName, currentDirectory); - // if (checkedAbsolutePath !== inputAbsolutePath) { - // reportFileNamesDifferOnlyInCasingError(fileName, file, reason); - // } - // } else if loader.comparePathsOptions.UseCaseSensitiveFileNames { - // pathIgnoreCase := tspath.ToPath(file.FileName(), loader.comparePathsOptions.CurrentDirectory, false) - // // for case-sensitsive file systems check if we've already seen some file with similar filename ignoring case - // if _, ok := filesByNameIgnoreCase[pathIgnoreCase]; ok { - // reportFileNamesDifferOnlyInCasingError(fileName, existingFile, reason); - // } else { - // filesByNameIgnoreCase[pathIgnoreCase] = file - // } - // } - - if task.libFile != nil { - libFiles = append(libFiles, file) - libFilesMap[path] = task.libFile - } else { - files = append(files, file) - } - filesByPath[path] = file - resolvedModules[path] = task.resolutionsInFile - typeResolutionsInFile[path] = task.typeResolutionsInFile - sourceFileMetaDatas[path] = task.metadata - - if task.jsxRuntimeImportSpecifier != nil { - if jsxRuntimeImportSpecifiers == nil { - jsxRuntimeImportSpecifiers = make(map[tspath.Path]*jsxRuntimeImportSpecifier, totalFileCount) - } - jsxRuntimeImportSpecifiers[path] = task.jsxRuntimeImportSpecifier - } - if task.importHelpersImportSpecifier != nil { - if importHelpersImportSpecifiers == nil { - importHelpersImportSpecifiers = make(map[tspath.Path]*ast.Node, totalFileCount) - } - importHelpersImportSpecifiers[path] = task.importHelpersImportSpecifier - } - if task.fromExternalLibrary { - sourceFilesFoundSearchingNodeModules.Add(path) - } - }) - loader.sortLibs(libFiles) - - allFiles := append(libFiles, files...) - - keys := slices.Collect(loader.pathForLibFileResolutions.Keys()) - slices.Sort(keys) - for _, key := range keys { - value, _ := loader.pathForLibFileResolutions.Load(key) - resolvedModules[key] = module.ModeAwareCache[*module.ResolvedModule]{ - module.ModeAwareCacheKey{Name: value.libraryName, Mode: core.ModuleKindCommonJS}: value.resolution, - } - for _, trace := range value.trace { - opts.Host.Trace(trace.Message, trace.Args...) - } - } - - return processedFiles{ - resolver: loader.resolver, - files: allFiles, - filesByPath: filesByPath, - projectReferenceFileMapper: loader.projectReferenceFileMapper, - resolvedModules: resolvedModules, - typeResolutionsInFile: typeResolutionsInFile, - sourceFileMetaDatas: sourceFileMetaDatas, - jsxRuntimeImportSpecifiers: jsxRuntimeImportSpecifiers, - importHelpersImportSpecifiers: importHelpersImportSpecifiers, - sourceFilesFoundSearchingNodeModules: sourceFilesFoundSearchingNodeModules, - libFiles: libFilesMap, - missingFiles: missingFiles, - includeProcessor: loader.includeProcessor, - outputFileToProjectReferenceSource: outputFileToProjectReferenceSource, - } + return loader.filesParser.getProcessedFiles(&loader) } func (p *fileLoader) toPath(file string) tspath.Path { @@ -466,11 +350,10 @@ func (p *fileLoader) resolveTypeReferenceDirectives(t *parseTask) { if resolved.IsResolved() { t.addSubTask(resolvedRef{ - fileName: resolved.ResolvedFileName, - increaseDepth: resolved.IsExternalLibraryImport, - elideOnDepth: false, - isFromExternalLibrary: resolved.IsExternalLibraryImport, - includeReason: includeReason, + fileName: resolved.ResolvedFileName, + increaseDepth: resolved.IsExternalLibraryImport, + elideOnDepth: false, + includeReason: includeReason, }, nil) } else { p.includeProcessor.addProcessingDiagnostic(&processingDiagnostic{ @@ -566,10 +449,9 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(t *parseTask) { if shouldAddFile { t.addSubTask(resolvedRef{ - fileName: resolvedFileName, - increaseDepth: resolvedModule.IsExternalLibraryImport, - elideOnDepth: isJsFileFromNodeModules, - isFromExternalLibrary: resolvedModule.IsExternalLibraryImport, + fileName: resolvedFileName, + increaseDepth: resolvedModule.IsExternalLibraryImport, + elideOnDepth: isJsFileFromNodeModules, includeReason: &FileIncludeReason{ kind: fileIncludeKindImport, data: &referencedFileData{ diff --git a/internal/compiler/filesparser.go b/internal/compiler/filesparser.go index 554ca47327..0aa19b024a 100644 --- a/internal/compiler/filesparser.go +++ b/internal/compiler/filesparser.go @@ -2,6 +2,7 @@ package compiler import ( "math" + "slices" "sync" "github.com/microsoft/typescript-go/internal/ast" @@ -20,6 +21,7 @@ type parseTask struct { redirectedParseTask *parseTask subTasks []*parseTask loaded bool + startedSubTasks bool isForAutomaticTypeDirective bool includeReason *FileIncludeReason @@ -31,12 +33,9 @@ type parseTask struct { resolutionDiagnostics []*ast.Diagnostic importHelpersImportSpecifier *ast.Node jsxRuntimeImportSpecifier *jsxRuntimeImportSpecifier - increaseDepth bool - elideOnDepth bool - // Track if this file is from an external library (node_modules) - // This mirrors the TypeScript currentNodeModulesDepth > 0 check - fromExternalLibrary bool + increaseDepth bool + elideOnDepth bool loadedTask *parseTask allIncludeReasons []*FileIncludeReason @@ -50,14 +49,8 @@ func (t *parseTask) Path() tspath.Path { return t.path } -func (t *parseTask) isRoot() bool { - // Intentionally not checking t.includeReason != nil to ensure we can catch cases for missing include reason - return !t.isForAutomaticTypeDirective && (t.includeReason.kind == fileIncludeKindRootFile || t.includeReason.kind == fileIncludeKindLibFile) -} - func (t *parseTask) load(loader *fileLoader) { t.loaded = true - t.path = loader.toPath(t.normalizedFilePath) if t.isForAutomaticTypeDirective { t.loadAutomaticTypeDirectives(loader) return @@ -119,10 +112,9 @@ func (t *parseTask) load(loader *fileLoader) { func (t *parseTask) redirect(loader *fileLoader, fileName string) { t.redirectedParseTask = &parseTask{ - normalizedFilePath: tspath.NormalizePath(fileName), - libFile: t.libFile, - fromExternalLibrary: t.fromExternalLibrary, - includeReason: t.includeReason, + normalizedFilePath: tspath.NormalizePath(fileName), + libFile: t.libFile, + includeReason: t.includeReason, } // increaseDepth and elideOnDepth are not copied to redirects, otherwise their depth would be double counted. t.subTasks = []*parseTask{t.redirectedParseTask} @@ -138,132 +130,262 @@ func (t *parseTask) loadAutomaticTypeDirectives(loader *fileLoader) { } type resolvedRef struct { - fileName string - increaseDepth bool - elideOnDepth bool - isFromExternalLibrary bool - includeReason *FileIncludeReason + fileName string + increaseDepth bool + elideOnDepth bool + includeReason *FileIncludeReason } func (t *parseTask) addSubTask(ref resolvedRef, libFile *LibFile) { normalizedFilePath := tspath.NormalizePath(ref.fileName) subTask := &parseTask{ - normalizedFilePath: normalizedFilePath, - libFile: libFile, - increaseDepth: ref.increaseDepth, - elideOnDepth: ref.elideOnDepth, - fromExternalLibrary: ref.isFromExternalLibrary, - includeReason: ref.includeReason, + normalizedFilePath: normalizedFilePath, + libFile: libFile, + increaseDepth: ref.increaseDepth, + elideOnDepth: ref.elideOnDepth, + includeReason: ref.includeReason, } t.subTasks = append(t.subTasks, subTask) } type filesParser struct { - wg core.WorkGroup - tasksByFileName collections.SyncMap[string, *queuedParseTask] - maxDepth int + wg core.WorkGroup + taskDataByPath collections.SyncMap[tspath.Path, *parseTaskData] + maxDepth int } -type queuedParseTask struct { - task *parseTask - mu sync.Mutex - lowestDepth int - fromExternalLibrary bool +type parseTaskData struct { + // map of tasks by file casing + tasks map[string]*parseTask + mu sync.Mutex + lowestDepth int + startedSubTasks bool } func (w *filesParser) parse(loader *fileLoader, tasks []*parseTask) { - w.start(loader, tasks, 0, false) + w.start(loader, tasks, 0) w.wg.RunAndWait() } -func (w *filesParser) start(loader *fileLoader, tasks []*parseTask, depth int, isFromExternalLibrary bool) { +func (w *filesParser) start(loader *fileLoader, tasks []*parseTask, depth int) { for i, task := range tasks { - taskIsFromExternalLibrary := isFromExternalLibrary || task.fromExternalLibrary - newTask := &queuedParseTask{task: task, lowestDepth: math.MaxInt} - loadedTask, loaded := w.tasksByFileName.LoadOrStore(task.FileName(), newTask) - task = loadedTask.task - if loaded { - tasks[i].loadedTask = task - // Add in the loaded task's external-ness. - taskIsFromExternalLibrary = taskIsFromExternalLibrary || task.fromExternalLibrary - } + task.path = loader.toPath(task.normalizedFilePath) + data, loaded := w.taskDataByPath.LoadOrStore(task.path, &parseTaskData{ + tasks: map[string]*parseTask{task.normalizedFilePath: task}, + lowestDepth: math.MaxInt, + }) w.wg.Queue(func() { - loadedTask.mu.Lock() - defer loadedTask.mu.Unlock() + data.mu.Lock() + defer data.mu.Unlock() startSubtasks := false - - currentDepth := depth - if task.increaseDepth { - currentDepth++ + if loaded { + if existingTask, ok := data.tasks[task.normalizedFilePath]; ok { + tasks[i].loadedTask = existingTask + } else { + data.tasks[task.normalizedFilePath] = task + // This is new task for file name - so load subtasks if there was loading for any other casing + startSubtasks = data.startedSubTasks + } } - if currentDepth < loadedTask.lowestDepth { + + currentDepth := core.IfElse(task.increaseDepth, depth+1, depth) + if currentDepth < data.lowestDepth { // If we're seeing this task at a lower depth than before, // reprocess its subtasks to ensure they are loaded. - loadedTask.lowestDepth = currentDepth - startSubtasks = true - } - - if !task.isRoot() && taskIsFromExternalLibrary && !loadedTask.fromExternalLibrary { - // If we're seeing this task now as an external library, - // reprocess its subtasks to ensure they are also marked as external. - loadedTask.fromExternalLibrary = true + data.lowestDepth = currentDepth startSubtasks = true + data.startedSubTasks = true } if task.elideOnDepth && currentDepth > w.maxDepth { return } - if !task.loaded { - task.load(loader) - } - - if startSubtasks { - w.start(loader, task.subTasks, loadedTask.lowestDepth, loadedTask.fromExternalLibrary) + for _, taskByFileName := range data.tasks { + loadSubTasks := startSubtasks + if !taskByFileName.loaded { + taskByFileName.load(loader) + if taskByFileName.redirectedParseTask != nil { + // Always load redirected task + loadSubTasks = true + data.startedSubTasks = true + } + } + if !taskByFileName.startedSubTasks && loadSubTasks { + taskByFileName.startedSubTasks = true + w.start(loader, taskByFileName.subTasks, data.lowestDepth) + } } }) } } -func (w *filesParser) collect(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask)) { - // Mark all tasks we saw as external after the fact. - w.tasksByFileName.Range(func(key string, value *queuedParseTask) bool { - if value.fromExternalLibrary { - value.task.fromExternalLibrary = true - } - return true - }) - w.collectWorker(loader, tasks, iterate, collections.Set[*parseTask]{}) -} +func (w *filesParser) getProcessedFiles(loader *fileLoader) processedFiles { + totalFileCount := int(loader.totalFileCount.Load()) + libFileCount := int(loader.libFileCount.Load()) + + var missingFiles []string + files := make([]*ast.SourceFile, 0, totalFileCount-libFileCount) + libFiles := make([]*ast.SourceFile, 0, totalFileCount) // totalFileCount here since we append files to it later to construct the final list + + filesByPath := make(map[tspath.Path]*ast.SourceFile, totalFileCount) + // stores 'filename -> file association' ignoring case + // used to track cases when two file names differ only in casing + var tasksSeenByNameIgnoreCase map[string]*parseTask + if loader.comparePathsOptions.UseCaseSensitiveFileNames { + tasksSeenByNameIgnoreCase = make(map[string]*parseTask, totalFileCount) + } -func (w *filesParser) collectWorker(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask), seen collections.Set[*parseTask]) { - for _, task := range tasks { - // Exclude automatic type directive tasks from include reason processing, - // as these are internal implementation details and should not contribute - // to the reasons for including files. - if task.redirectedParseTask == nil && !task.isForAutomaticTypeDirective { + loader.includeProcessor.fileIncludeReasons = make(map[tspath.Path][]*FileIncludeReason, totalFileCount) + var outputFileToProjectReferenceSource map[tspath.Path]string + if !loader.opts.canUseProjectReferenceSource() { + outputFileToProjectReferenceSource = make(map[tspath.Path]string, totalFileCount) + } + resolvedModules := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule], totalFileCount+1) + typeResolutionsInFile := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], totalFileCount) + sourceFileMetaDatas := make(map[tspath.Path]ast.SourceFileMetaData, totalFileCount) + var jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier + var importHelpersImportSpecifiers map[tspath.Path]*ast.Node + var sourceFilesFoundSearchingNodeModules collections.Set[tspath.Path] + libFilesMap := make(map[tspath.Path]*LibFile, libFileCount) + + var collectFiles func(tasks []*parseTask, seen map[*parseTaskData]string) + collectFiles = func(tasks []*parseTask, seen map[*parseTaskData]string) { + for _, task := range tasks { includeReason := task.includeReason - if task.loadedTask != nil { - task = task.loadedTask + // Exclude automatic type directive tasks from include reason processing, + // as these are internal implementation details and should not contribute + // to the reasons for including files. + if task.redirectedParseTask == nil && !task.isForAutomaticTypeDirective { + if task.loadedTask != nil { + task = task.loadedTask + } + w.addIncludeReason(loader, task, includeReason) + } + data, _ := w.taskDataByPath.Load(task.path) + if !task.loaded { + continue + } + + // ensure we only walk each task once + if checkedName, ok := seen[data]; ok { + if !loader.opts.Config.CompilerOptions().ForceConsistentCasingInFileNames.IsFalse() { + // Check if it differs only in drive letters its ok to ignore that error: + checkedAbsolutePath := tspath.GetNormalizedAbsolutePathWithoutRoot(checkedName, loader.comparePathsOptions.CurrentDirectory) + inputAbsolutePath := tspath.GetNormalizedAbsolutePathWithoutRoot(task.normalizedFilePath, loader.comparePathsOptions.CurrentDirectory) + if checkedAbsolutePath != inputAbsolutePath { + loader.includeProcessor.addProcessingDiagnosticsForFileCasing(task.path, checkedName, task.normalizedFilePath, includeReason) + } + } + continue + } else { + seen[data] = task.normalizedFilePath + } + + if tasksSeenByNameIgnoreCase != nil { + pathLowerCase := tspath.ToFileNameLowerCase(string(task.path)) + if taskByIgnoreCase, ok := tasksSeenByNameIgnoreCase[pathLowerCase]; ok { + loader.includeProcessor.addProcessingDiagnosticsForFileCasing(taskByIgnoreCase.path, taskByIgnoreCase.normalizedFilePath, task.normalizedFilePath, includeReason) + } else { + tasksSeenByNameIgnoreCase[pathLowerCase] = task + } + } + + for _, trace := range task.typeResolutionsTrace { + loader.opts.Host.Trace(trace.Message, trace.Args...) + } + for _, trace := range task.resolutionsTrace { + loader.opts.Host.Trace(trace.Message, trace.Args...) + } + if subTasks := task.subTasks; len(subTasks) > 0 { + collectFiles(subTasks, seen) + } + + // Exclude automatic type directive tasks from include reason processing, + // as these are internal implementation details and should not contribute + // to the reasons for including files. + if task.redirectedParseTask != nil { + if !loader.opts.canUseProjectReferenceSource() { + outputFileToProjectReferenceSource[task.redirectedParseTask.path] = task.FileName() + } + continue + } + + if task.isForAutomaticTypeDirective { + typeResolutionsInFile[task.path] = task.typeResolutionsInFile + continue + } + file := task.file + path := task.path + if file == nil { + // !!! sheetal file preprocessing diagnostic explaining getSourceFileFromReferenceWorker + missingFiles = append(missingFiles, task.normalizedFilePath) + continue + } + + if task.libFile != nil { + libFiles = append(libFiles, file) + libFilesMap[path] = task.libFile + } else { + files = append(files, file) + } + filesByPath[path] = file + resolvedModules[path] = task.resolutionsInFile + typeResolutionsInFile[path] = task.typeResolutionsInFile + sourceFileMetaDatas[path] = task.metadata + + if task.jsxRuntimeImportSpecifier != nil { + if jsxRuntimeImportSpecifiers == nil { + jsxRuntimeImportSpecifiers = make(map[tspath.Path]*jsxRuntimeImportSpecifier, totalFileCount) + } + jsxRuntimeImportSpecifiers[path] = task.jsxRuntimeImportSpecifier + } + if task.importHelpersImportSpecifier != nil { + if importHelpersImportSpecifiers == nil { + importHelpersImportSpecifiers = make(map[tspath.Path]*ast.Node, totalFileCount) + } + importHelpersImportSpecifiers[path] = task.importHelpersImportSpecifier + } + if data.lowestDepth > 0 { + sourceFilesFoundSearchingNodeModules.Add(path) } - w.addIncludeReason(loader, task, includeReason) - } - // ensure we only walk each task once - if !task.loaded || !seen.AddIfAbsent(task) { - continue } - for _, trace := range task.typeResolutionsTrace { - loader.opts.Host.Trace(trace.Message, trace.Args...) + } + + collectFiles(loader.rootTasks, make(map[*parseTaskData]string, totalFileCount)) + loader.sortLibs(libFiles) + + allFiles := append(libFiles, files...) + + keys := slices.Collect(loader.pathForLibFileResolutions.Keys()) + slices.Sort(keys) + for _, key := range keys { + value, _ := loader.pathForLibFileResolutions.Load(key) + resolvedModules[key] = module.ModeAwareCache[*module.ResolvedModule]{ + module.ModeAwareCacheKey{Name: value.libraryName, Mode: core.ModuleKindCommonJS}: value.resolution, } - for _, trace := range task.resolutionsTrace { + for _, trace := range value.trace { loader.opts.Host.Trace(trace.Message, trace.Args...) } - if subTasks := task.subTasks; len(subTasks) > 0 { - w.collectWorker(loader, subTasks, iterate, seen) - } - iterate(task) + } + + return processedFiles{ + resolver: loader.resolver, + files: allFiles, + filesByPath: filesByPath, + projectReferenceFileMapper: loader.projectReferenceFileMapper, + resolvedModules: resolvedModules, + typeResolutionsInFile: typeResolutionsInFile, + sourceFileMetaDatas: sourceFileMetaDatas, + jsxRuntimeImportSpecifiers: jsxRuntimeImportSpecifiers, + importHelpersImportSpecifiers: importHelpersImportSpecifiers, + sourceFilesFoundSearchingNodeModules: sourceFilesFoundSearchingNodeModules, + libFiles: libFilesMap, + missingFiles: missingFiles, + includeProcessor: loader.includeProcessor, + outputFileToProjectReferenceSource: outputFileToProjectReferenceSource, } } diff --git a/internal/compiler/includeprocessor.go b/internal/compiler/includeprocessor.go index 83691f45a1..a40534bbde 100644 --- a/internal/compiler/includeprocessor.go +++ b/internal/compiler/includeprocessor.go @@ -1,6 +1,7 @@ package compiler import ( + "slices" "sync" "github.com/microsoft/typescript-go/internal/ast" @@ -59,6 +60,32 @@ func (i *includeProcessor) addProcessingDiagnostic(d ...*processingDiagnostic) { i.processingDiagnostics = append(i.processingDiagnostics, d...) } +func (i *includeProcessor) addProcessingDiagnosticsForFileCasing(file tspath.Path, existingCasing string, currentCasing string, reason *FileIncludeReason) { + if !reason.isReferencedFile() && slices.ContainsFunc(i.fileIncludeReasons[file], func(r *FileIncludeReason) bool { + return r.isReferencedFile() + }) { + i.addProcessingDiagnostic(&processingDiagnostic{ + kind: processingDiagnosticKindExplainingFileInclude, + data: &includeExplainingDiagnostic{ + file: file, + diagnosticReason: reason, + message: diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, + args: []any{existingCasing, currentCasing}, + }, + }) + } else { + i.addProcessingDiagnostic(&processingDiagnostic{ + kind: processingDiagnosticKindExplainingFileInclude, + data: &includeExplainingDiagnostic{ + file: file, + diagnosticReason: reason, + message: diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, + args: []any{currentCasing, existingCasing}, + }, + }) + } +} + func (i *includeProcessor) getReferenceLocation(r *FileIncludeReason, program *Program) *referenceFileLocation { if existing, ok := i.reasonToReferenceLocation.Load(r); ok { return existing diff --git a/internal/compiler/processingDiagnostic.go b/internal/compiler/processingDiagnostic.go index 20e5c8d18c..a2f7d89e90 100644 --- a/internal/compiler/processingDiagnostic.go +++ b/internal/compiler/processingDiagnostic.go @@ -79,7 +79,7 @@ func (d *processingDiagnostic) createDiagnosticExplainingFile(program *Program) processRelatedInfo := func(includeReason *FileIncludeReason) { if preferredLocation == nil && includeReason.isReferencedFile() && !program.includeProcessor.getReferenceLocation(includeReason, program).isSynthetic { preferredLocation = includeReason - } else { + } else if preferredLocation != includeReason { info := program.includeProcessor.getRelatedInfo(includeReason, program) if info != nil { relatedInfo = append(relatedInfo, info) diff --git a/internal/execute/incremental/snapshottobuildinfo.go b/internal/execute/incremental/snapshottobuildinfo.go index fc83153362..528097d564 100644 --- a/internal/execute/incremental/snapshottobuildinfo.go +++ b/internal/execute/incremental/snapshottobuildinfo.go @@ -197,7 +197,7 @@ func (t *toBuildInfo) collectRootFiles() { } func (t *toBuildInfo) setFileInfoAndEmitSignatures() { - t.buildInfo.FileInfos = core.MapNonNil(t.program.GetSourceFiles(), func(file *ast.SourceFile) *BuildInfoFileInfo { + t.buildInfo.FileInfos = core.Map(t.program.GetSourceFiles(), func(file *ast.SourceFile) *BuildInfoFileInfo { info, _ := t.snapshot.fileInfos.Load(file.Path()) fileId := t.toFileId(file.Path()) // tryAddRoot(key, fileId); @@ -206,11 +206,6 @@ func (t *toBuildInfo) setFileInfoAndEmitSignatures() { panic(fmt.Sprintf("File name at index %d does not match expected relative path or libName: %s != %s", fileId-1, t.buildInfo.FileNames[fileId-1], t.relativeToBuildInfo(string(file.Path())))) } } - if int(fileId) != len(t.buildInfo.FileNames) { - // Duplicate - for now ignore - return nil - } - if t.snapshot.options.Composite.IsTrue() { if !ast.IsJsonSourceFile(file) && t.program.SourceFileMayBeEmitted(file, false) { if emitSignature, loaded := t.snapshot.emitSignatures.Load(file.Path()); !loaded { @@ -235,9 +230,6 @@ func (t *toBuildInfo) setFileInfoAndEmitSignatures() { } return newBuildInfoFileInfo(info) }) - if t.buildInfo.FileInfos == nil { - t.buildInfo.FileInfos = []*BuildInfoFileInfo{} - } } func (t *toBuildInfo) setRootOfIncrementalProgram() { diff --git a/internal/execute/tsctests/tsc_test.go b/internal/execute/tsctests/tsc_test.go index e618ce7829..87fca6fdca 100644 --- a/internal/execute/tsctests/tsc_test.go +++ b/internal/execute/tsctests/tsc_test.go @@ -981,6 +981,93 @@ func TestTscExtends(t *testing.T) { } } +func TestForceConsistentCasingInFileNames(t *testing.T) { + t.Parallel() + testCases := []*tscInput{ + { + subScenario: "with relative and non relative file resolutions", + files: FileMap{ + "/user/username/projects/myproject/src/struct.d.ts": stringtestutil.Dedent(` + import * as xs1 from "fp-ts/lib/Struct"; + import * as xs2 from "fp-ts/lib/struct"; + import * as xs3 from "./Struct"; + import * as xs4 from "./struct"; + `), + "/user/username/projects/myproject/node_modules/fp-ts/lib/struct.d.ts": `export function foo(): void`, + }, + cwd: "/user/username/projects/myproject", + commandLineArgs: []string{"/user/username/projects/myproject/src/struct.d.ts", "--forceConsistentCasingInFileNames", "--explainFiles"}, + ignoreCase: true, + }, + { + subScenario: "when file is included from multiple places with different casing", + files: FileMap{ + "/home/src/projects/project/src/struct.d.ts": stringtestutil.Dedent(` + import * as xs1 from "fp-ts/lib/Struct"; + import * as xs2 from "fp-ts/lib/struct"; + import * as xs3 from "./Struct"; + import * as xs4 from "./struct"; + `), + "/home/src/projects/project/src/anotherFile.ts": stringtestutil.Dedent(` + import * as xs1 from "fp-ts/lib/Struct"; + import * as xs2 from "fp-ts/lib/struct"; + import * as xs3 from "./Struct"; + import * as xs4 from "./struct"; + `), + "/home/src/projects/project/src/oneMore.ts": stringtestutil.Dedent(` + import * as xs1 from "fp-ts/lib/Struct"; + import * as xs2 from "fp-ts/lib/struct"; + import * as xs3 from "./Struct"; + import * as xs4 from "./struct"; + `), + "/home/src/projects/project/tsconfig.json": `{}`, + "/home/src/projects/project/node_modules/fp-ts/lib/struct.d.ts": `export function foo(): void`, + }, + cwd: "/home/src/projects/project", + commandLineArgs: []string{"--explainFiles"}, + ignoreCase: true, + }, + { + subScenario: "with type ref from file", + files: FileMap{ + "/user/username/projects/myproject/src/fileOne.d.ts": `declare class c { }`, + "/user/username/projects/myproject/src/file2.d.ts": stringtestutil.Dedent(` + /// + declare const y: c; + `), + "/user/username/projects/myproject/tsconfig.json": "{ }", + }, + cwd: "/user/username/projects/myproject", + commandLineArgs: []string{"-p", "/user/username/projects/myproject", "--explainFiles", "--traceResolution"}, + ignoreCase: true, + }, + { + subScenario: "with triple slash ref from file", + files: FileMap{ + "/home/src/workspaces/project/src/c.ts": `/// `, + "/home/src/workspaces/project/src/d.ts": `declare class c { }`, + "/home/src/workspaces/project/tsconfig.json": "{ }", + }, + ignoreCase: true, + }, + { + subScenario: "two files exist on disk that differs only in casing", + files: FileMap{ + "/home/src/workspaces/project/c.ts": `import {x} from "./D"`, + "/home/src/workspaces/project/D.ts": `export const x = 10;`, + "/home/src/workspaces/project/d.ts": `export const y = 20;`, + "/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(` + { + "files": ["c.ts", "d.ts"] + }`), + }, + }, + } + for _, test := range testCases { + test.run(t, "forceConsistentCasingInFileNames") + } +} + func TestTscIgnoreConfig(t *testing.T) { t.Parallel() filesWithoutConfig := func() FileMap { @@ -1745,6 +1832,54 @@ func TestTscIncremental(t *testing.T) { }, }, }, + { + subScenario: "Compile incremental with case insensitive file names", + commandLineArgs: []string{"-p", "."}, + files: FileMap{ + "/home/project/tsconfig.json": stringtestutil.Dedent(` + { + "compilerOptions": { + "incremental": true + }, + }`), + "/home/project/src/index.ts": stringtestutil.Dedent(` + import type { Foo1 } from 'lib1'; + import type { Foo2 } from 'lib2'; + export const foo1: Foo1 = { foo: "a" }; + export const foo2: Foo2 = { foo: "b" };`), + "/home/node_modules/lib1/index.d.ts": stringtestutil.Dedent(` + import type { Foo } from 'someLib'; + export type { Foo as Foo1 };`), + "/home/node_modules/lib1/package.json": stringtestutil.Dedent(` + { + "name": "lib1" + }`), + "/home/node_modules/lib2/index.d.ts": stringtestutil.Dedent(` + import type { Foo } from 'somelib'; + export type { Foo as Foo2 }; + export declare const foo2: Foo;`), + "/home/node_modules/lib2/package.json": stringtestutil.Dedent(` + { + "name": "lib2" + } + `), + "/home/node_modules/someLib/index.d.ts": stringtestutil.Dedent(` + import type { Str } from 'otherLib'; + export type Foo = { foo: Str; };`), + "/home/node_modules/someLib/package.json": stringtestutil.Dedent(` + { + "name": "somelib" + }`), + "/home/node_modules/otherLib/index.d.ts": stringtestutil.Dedent(` + export type Str = string;`), + "/home/node_modules/otherLib/package.json": stringtestutil.Dedent(` + { + "name": "otherlib" + }`), + }, + cwd: "/home/project", + ignoreCase: true, + }, } for _, test := range testCases { diff --git a/internal/tspath/path.go b/internal/tspath/path.go index de09221507..26abe6778d 100644 --- a/internal/tspath/path.go +++ b/internal/tspath/path.go @@ -334,6 +334,12 @@ func GetNormalizedPathComponents(path string, currentDirectory string) []string return reducePathComponents(GetPathComponents(path, currentDirectory)) } +func GetNormalizedAbsolutePathWithoutRoot(fileName string, currentDirectory string) string { + absolutePath := GetNormalizedAbsolutePath(fileName, currentDirectory) + rootLength := GetRootLength(absolutePath) + return absolutePath[rootLength:] +} + func GetNormalizedAbsolutePath(fileName string, currentDirectory string) string { rootLength := GetRootLength(fileName) if rootLength == 0 && currentDirectory != "" { diff --git a/internal/tspath/path_test.go b/internal/tspath/path_test.go index 85d7829de6..711030a1cd 100644 --- a/internal/tspath/path_test.go +++ b/internal/tspath/path_test.go @@ -417,6 +417,14 @@ func TestGetNormalizedAbsolutePath(t *testing.T) { assert.Equal(t, GetNormalizedAbsolutePath("\\\\a\\b\\\\c", ""), "//a/b/c") } +func TestGetNormalizedAbsolutePathWithoutRoot(t *testing.T) { + t.Parallel() + + assert.Equal(t, GetNormalizedAbsolutePathWithoutRoot("/a/b/c.txt", "/a/b"), "a/b/c.txt") + assert.Equal(t, GetNormalizedAbsolutePathWithoutRoot("c:/work/hello.txt", "c:/work"), "work/hello.txt") + assert.Equal(t, GetNormalizedAbsolutePathWithoutRoot("c:/work/hello.txt", "d:/worspaces"), "work/hello.txt") +} + var getNormalizedAbsolutePathTests = map[string][][]string{ "non-normalized inputs": { {"/.", ""}, diff --git a/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/two-files-exist-on-disk-that-differs-only-in-casing.js b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/two-files-exist-on-disk-that-differs-only-in-casing.js new file mode 100644 index 0000000000..cf19f856c1 --- /dev/null +++ b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/two-files-exist-on-disk-that-differs-only-in-casing.js @@ -0,0 +1,72 @@ +currentDirectory::/home/src/workspaces/project +useCaseSensitiveFileNames::true +Input:: +//// [/home/src/workspaces/project/D.ts] *new* +export const x = 10; +//// [/home/src/workspaces/project/c.ts] *new* +import {x} from "./D" +//// [/home/src/workspaces/project/d.ts] *new* +export const y = 20; +//// [/home/src/workspaces/project/tsconfig.json] *new* +{ + "files": ["c.ts", "d.ts"] +} + +tsgo +ExitStatus:: DiagnosticsPresent_OutputsGenerated +Output:: +c.ts:1:17 - error TS1261: Already included file name '/home/src/workspaces/project/D.ts' differs from file name '/home/src/workspaces/project/d.ts' only in casing. + The file is in the program because: + Imported via "./D" from file '/home/src/workspaces/project/c.ts' + Part of 'files' list in tsconfig.json + +1 import {x} from "./D" +   ~~~~~ + + tsconfig.json:2:23 - File is matched by 'files' list specified here. + 2 "files": ["c.ts", "d.ts"] +    ~~~~~~ + + +Found 1 error in c.ts:1 + +//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; +//// [/home/src/workspaces/project/D.js] *new* +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.x = void 0; +exports.x = 10; + +//// [/home/src/workspaces/project/c.js] *new* +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); + +//// [/home/src/workspaces/project/d.js] *new* +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.y = void 0; +exports.y = 20; + + diff --git a/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/when-file-is-included-from-multiple-places-with-different-casing.js b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/when-file-is-included-from-multiple-places-with-different-casing.js new file mode 100644 index 0000000000..2c5f0bfa46 --- /dev/null +++ b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/when-file-is-included-from-multiple-places-with-different-casing.js @@ -0,0 +1,315 @@ +currentDirectory::/home/src/projects/project +useCaseSensitiveFileNames::false +Input:: +//// [/home/src/projects/project/node_modules/fp-ts/lib/struct.d.ts] *new* +export function foo(): void +//// [/home/src/projects/project/src/anotherFile.ts] *new* +import * as xs1 from "fp-ts/lib/Struct"; +import * as xs2 from "fp-ts/lib/struct"; +import * as xs3 from "./Struct"; +import * as xs4 from "./struct"; +//// [/home/src/projects/project/src/oneMore.ts] *new* +import * as xs1 from "fp-ts/lib/Struct"; +import * as xs2 from "fp-ts/lib/struct"; +import * as xs3 from "./Struct"; +import * as xs4 from "./struct"; +//// [/home/src/projects/project/src/struct.d.ts] *new* +import * as xs1 from "fp-ts/lib/Struct"; +import * as xs2 from "fp-ts/lib/struct"; +import * as xs3 from "./Struct"; +import * as xs4 from "./struct"; +//// [/home/src/projects/project/tsconfig.json] *new* +{} + +tsgo --explainFiles +ExitStatus:: DiagnosticsPresent_OutputsGenerated +Output:: +src/Struct.d.ts:2:22 - error TS1149: File name '/home/src/projects/project/node_modules/fp-ts/lib/struct.d.ts' differs from already included file name '/home/src/projects/project/node_modules/fp-ts/lib/Struct.d.ts' only in casing. + The file is in the program because: + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/oneMore.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/oneMore.ts' + +2 import * as xs2 from "fp-ts/lib/struct"; +   ~~~~~~~~~~~~~~~~~~ + + src/anotherFile.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/anotherFile.ts:2:22 - File is included via import here. + 2 import * as xs2 from "fp-ts/lib/struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/Struct.d.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/oneMore.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/oneMore.ts:2:22 - File is included via import here. + 2 import * as xs2 from "fp-ts/lib/struct"; +    ~~~~~~~~~~~~~~~~~~ + +src/Struct.d.ts:4:22 - error TS1149: File name '/home/src/projects/project/src/struct.d.ts' differs from already included file name '/home/src/projects/project/src/Struct.d.ts' only in casing. + The file is in the program because: + Imported via "./Struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/oneMore.ts' + Imported via "./struct" from file '/home/src/projects/project/src/oneMore.ts' + Matched by default include pattern '**/*' + +4 import * as xs4 from "./struct"; +   ~~~~~~~~~~ + + src/anotherFile.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/Struct.d.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/anotherFile.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + + src/oneMore.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/oneMore.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + +src/anotherFile.ts:2:22 - error TS1149: File name '/home/src/projects/project/node_modules/fp-ts/lib/struct.d.ts' differs from already included file name '/home/src/projects/project/node_modules/fp-ts/lib/Struct.d.ts' only in casing. + The file is in the program because: + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/oneMore.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/oneMore.ts' + +2 import * as xs2 from "fp-ts/lib/struct"; +   ~~~~~~~~~~~~~~~~~~ + + src/anotherFile.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/Struct.d.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/Struct.d.ts:2:22 - File is included via import here. + 2 import * as xs2 from "fp-ts/lib/struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/oneMore.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/oneMore.ts:2:22 - File is included via import here. + 2 import * as xs2 from "fp-ts/lib/struct"; +    ~~~~~~~~~~~~~~~~~~ + +src/anotherFile.ts:3:22 - error TS1261: Already included file name '/home/src/projects/project/src/Struct.d.ts' differs from file name '/home/src/projects/project/src/struct.d.ts' only in casing. + The file is in the program because: + Imported via "./Struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/oneMore.ts' + Imported via "./struct" from file '/home/src/projects/project/src/oneMore.ts' + Matched by default include pattern '**/*' + +3 import * as xs3 from "./Struct"; +   ~~~~~~~~~~ + + src/Struct.d.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/Struct.d.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + + src/anotherFile.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + + src/oneMore.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/oneMore.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + +src/anotherFile.ts:4:22 - error TS1149: File name '/home/src/projects/project/src/struct.d.ts' differs from already included file name '/home/src/projects/project/src/Struct.d.ts' only in casing. + The file is in the program because: + Imported via "./Struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/oneMore.ts' + Imported via "./struct" from file '/home/src/projects/project/src/oneMore.ts' + Matched by default include pattern '**/*' + +4 import * as xs4 from "./struct"; +   ~~~~~~~~~~ + + src/anotherFile.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/Struct.d.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/Struct.d.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + + src/oneMore.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/oneMore.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + +src/oneMore.ts:2:22 - error TS1149: File name '/home/src/projects/project/node_modules/fp-ts/lib/struct.d.ts' differs from already included file name '/home/src/projects/project/node_modules/fp-ts/lib/Struct.d.ts' only in casing. + The file is in the program because: + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "fp-ts/lib/Struct" from file '/home/src/projects/project/src/oneMore.ts' + Imported via "fp-ts/lib/struct" from file '/home/src/projects/project/src/oneMore.ts' + +2 import * as xs2 from "fp-ts/lib/struct"; +   ~~~~~~~~~~~~~~~~~~ + + src/anotherFile.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/anotherFile.ts:2:22 - File is included via import here. + 2 import * as xs2 from "fp-ts/lib/struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/Struct.d.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/Struct.d.ts:2:22 - File is included via import here. + 2 import * as xs2 from "fp-ts/lib/struct"; +    ~~~~~~~~~~~~~~~~~~ + + src/oneMore.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + +src/oneMore.ts:4:22 - error TS1149: File name '/home/src/projects/project/src/struct.d.ts' differs from already included file name '/home/src/projects/project/src/Struct.d.ts' only in casing. + The file is in the program because: + Imported via "./Struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/Struct.d.ts' + Imported via "./struct" from file '/home/src/projects/project/src/anotherFile.ts' + Imported via "./Struct" from file '/home/src/projects/project/src/oneMore.ts' + Imported via "./struct" from file '/home/src/projects/project/src/oneMore.ts' + Matched by default include pattern '**/*' + +4 import * as xs4 from "./struct"; +   ~~~~~~~~~~ + + src/anotherFile.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/Struct.d.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + + src/Struct.d.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + + src/anotherFile.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + + src/oneMore.ts:3:22 - File is included via import here. + 3 import * as xs3 from "./Struct"; +    ~~~~~~~~~~ + +../../tslibs/TS/Lib/lib.d.ts + Default library for target 'ES5' +node_modules/fp-ts/lib/Struct.d.ts + Imported via "fp-ts/lib/Struct" from file 'src/anotherFile.ts' + Imported via "fp-ts/lib/struct" from file 'src/anotherFile.ts' + Imported via "fp-ts/lib/Struct" from file 'src/Struct.d.ts' + Imported via "fp-ts/lib/struct" from file 'src/Struct.d.ts' + Imported via "fp-ts/lib/Struct" from file 'src/oneMore.ts' + Imported via "fp-ts/lib/struct" from file 'src/oneMore.ts' +src/Struct.d.ts + Imported via "./Struct" from file 'src/anotherFile.ts' + Imported via "./Struct" from file 'src/Struct.d.ts' + Imported via "./struct" from file 'src/Struct.d.ts' + Imported via "./struct" from file 'src/anotherFile.ts' + Imported via "./Struct" from file 'src/oneMore.ts' + Imported via "./struct" from file 'src/oneMore.ts' + Matched by default include pattern '**/*' +src/anotherFile.ts + Matched by default include pattern '**/*' +src/oneMore.ts + Matched by default include pattern '**/*' + +Found 7 errors in 3 files. + +Errors Files + 2 src/Struct.d.ts:2 + 3 src/anotherFile.ts:2 + 2 src/oneMore.ts:2 + +//// [/home/src/projects/project/src/anotherFile.js] *new* +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); + +//// [/home/src/projects/project/src/oneMore.js] *new* +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); + +//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; + diff --git a/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-relative-and-non-relative-file-resolutions.js b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-relative-and-non-relative-file-resolutions.js new file mode 100644 index 0000000000..19ce089f68 --- /dev/null +++ b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-relative-and-non-relative-file-resolutions.js @@ -0,0 +1,75 @@ +currentDirectory::/user/username/projects/myproject +useCaseSensitiveFileNames::false +Input:: +//// [/user/username/projects/myproject/node_modules/fp-ts/lib/struct.d.ts] *new* +export function foo(): void +//// [/user/username/projects/myproject/src/struct.d.ts] *new* +import * as xs1 from "fp-ts/lib/Struct"; +import * as xs2 from "fp-ts/lib/struct"; +import * as xs3 from "./Struct"; +import * as xs4 from "./struct"; + +tsgo /user/username/projects/myproject/src/struct.d.ts --forceConsistentCasingInFileNames --explainFiles +ExitStatus:: DiagnosticsPresent_OutputsGenerated +Output:: +src/struct.d.ts:2:22 - error TS1149: File name '/user/username/projects/myproject/node_modules/fp-ts/lib/struct.d.ts' differs from already included file name '/user/username/projects/myproject/node_modules/fp-ts/lib/Struct.d.ts' only in casing. + The file is in the program because: + Imported via "fp-ts/lib/Struct" from file '/user/username/projects/myproject/src/struct.d.ts' + Imported via "fp-ts/lib/struct" from file '/user/username/projects/myproject/src/struct.d.ts' + +2 import * as xs2 from "fp-ts/lib/struct"; +   ~~~~~~~~~~~~~~~~~~ + + src/struct.d.ts:1:22 - File is included via import here. + 1 import * as xs1 from "fp-ts/lib/Struct"; +    ~~~~~~~~~~~~~~~~~~ + +src/struct.d.ts:3:22 - error TS1149: File name '/user/username/projects/myproject/src/Struct.d.ts' differs from already included file name '/user/username/projects/myproject/src/struct.d.ts' only in casing. + The file is in the program because: + Root file specified for compilation + Imported via "./Struct" from file '/user/username/projects/myproject/src/struct.d.ts' + Imported via "./struct" from file '/user/username/projects/myproject/src/struct.d.ts' + +3 import * as xs3 from "./Struct"; +   ~~~~~~~~~~ + + src/struct.d.ts:4:22 - File is included via import here. + 4 import * as xs4 from "./struct"; +    ~~~~~~~~~~ + +../../../../home/src/tslibs/TS/Lib/lib.d.ts + Default library for target 'ES5' +node_modules/fp-ts/lib/Struct.d.ts + Imported via "fp-ts/lib/Struct" from file 'src/struct.d.ts' + Imported via "fp-ts/lib/struct" from file 'src/struct.d.ts' +src/struct.d.ts + Root file specified for compilation + Imported via "./Struct" from file 'src/struct.d.ts' + Imported via "./struct" from file 'src/struct.d.ts' + +Found 2 errors in the same file, starting at: src/struct.d.ts:2 + +//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; + diff --git a/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-triple-slash-ref-from-file.js b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-triple-slash-ref-from-file.js new file mode 100644 index 0000000000..1d16927567 --- /dev/null +++ b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-triple-slash-ref-from-file.js @@ -0,0 +1,53 @@ +currentDirectory::/home/src/workspaces/project +useCaseSensitiveFileNames::false +Input:: +//// [/home/src/workspaces/project/src/c.ts] *new* +/// +//// [/home/src/workspaces/project/src/d.ts] *new* +declare class c { } +//// [/home/src/workspaces/project/tsconfig.json] *new* +{ } + +tsgo +ExitStatus:: DiagnosticsPresent_OutputsGenerated +Output:: +src/c.ts:1:22 - error TS1261: Already included file name '/home/src/workspaces/project/src/D.ts' differs from file name '/home/src/workspaces/project/src/d.ts' only in casing. + The file is in the program because: + Referenced via './D.ts' from file '/home/src/workspaces/project/src/c.ts' + Matched by default include pattern '**/*' + +1 /// +   ~~~~~~ + + +Found 1 error in src/c.ts:1 + +//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; +//// [/home/src/workspaces/project/src/D.js] *new* + +//// [/home/src/workspaces/project/src/c.js] *new* +/// + + diff --git a/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-type-ref-from-file.js b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-type-ref-from-file.js new file mode 100644 index 0000000000..2f55514b08 --- /dev/null +++ b/testdata/baselines/reference/tsc/forceConsistentCasingInFileNames/with-type-ref-from-file.js @@ -0,0 +1,58 @@ +currentDirectory::/user/username/projects/myproject +useCaseSensitiveFileNames::false +Input:: +//// [/user/username/projects/myproject/src/file2.d.ts] *new* +/// +declare const y: c; +//// [/user/username/projects/myproject/src/fileOne.d.ts] *new* +declare class c { } +//// [/user/username/projects/myproject/tsconfig.json] *new* +{ } + +tsgo -p /user/username/projects/myproject --explainFiles --traceResolution +ExitStatus:: Success +Output:: +======== Resolving type reference directive './fileOne.d.ts', containing file '/user/username/projects/myproject/src/file2.d.ts', root directory '/user/username/projects/myproject/node_modules/@types,/user/username/projects/node_modules/@types,/user/username/node_modules/@types,/user/node_modules/@types,/node_modules/@types'. ======== +Resolving with primary search path '/user/username/projects/myproject/node_modules/@types, /user/username/projects/node_modules/@types, /user/username/node_modules/@types, /user/node_modules/@types, /node_modules/@types'. +Directory '/user/username/projects/myproject/node_modules/@types' does not exist, skipping all lookups in it. +Directory '/user/username/projects/node_modules/@types' does not exist, skipping all lookups in it. +Directory '/user/username/node_modules/@types' does not exist, skipping all lookups in it. +Directory '/user/node_modules/@types' does not exist, skipping all lookups in it. +Directory '/node_modules/@types' does not exist, skipping all lookups in it. +Looking up in 'node_modules' folder, initial location '/user/username/projects/myproject/src'. +Loading module as file / folder, candidate module location '/user/username/projects/myproject/src/fileOne.d.ts', target file types: Declaration. +File name '/user/username/projects/myproject/src/fileOne.d.ts' has a '.d.ts' extension - stripping it. +File '/user/username/projects/myproject/src/fileOne.d.ts' exists - use it as a name resolution result. +Resolving real path for '/user/username/projects/myproject/src/fileOne.d.ts', result '/user/username/projects/myproject/src/fileOne.d.ts'. +======== Type reference directive './fileOne.d.ts' was successfully resolved to '/user/username/projects/myproject/src/fileOne.d.ts', primary: false. ======== +../../../../home/src/tslibs/TS/Lib/lib.d.ts + Default library for target 'ES5' +src/fileOne.d.ts + Type library referenced via './fileOne.d.ts' from file 'src/file2.d.ts' + Matched by default include pattern '**/*' +src/file2.d.ts + Matched by default include pattern '**/*' +//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; + diff --git a/testdata/baselines/reference/tsc/incremental/Compile-incremental-with-case-insensitive-file-names.js b/testdata/baselines/reference/tsc/incremental/Compile-incremental-with-case-insensitive-file-names.js new file mode 100644 index 0000000000..416b8b8923 --- /dev/null +++ b/testdata/baselines/reference/tsc/incremental/Compile-incremental-with-case-insensitive-file-names.js @@ -0,0 +1,196 @@ +currentDirectory::/home/project +useCaseSensitiveFileNames::false +Input:: +//// [/home/node_modules/lib1/index.d.ts] *new* +import type { Foo } from 'someLib'; +export type { Foo as Foo1 }; +//// [/home/node_modules/lib1/package.json] *new* +{ + "name": "lib1" +} +//// [/home/node_modules/lib2/index.d.ts] *new* +import type { Foo } from 'somelib'; +export type { Foo as Foo2 }; +export declare const foo2: Foo; +//// [/home/node_modules/lib2/package.json] *new* +{ + "name": "lib2" +} +//// [/home/node_modules/otherLib/index.d.ts] *new* +export type Str = string; +//// [/home/node_modules/otherLib/package.json] *new* +{ + "name": "otherlib" +} +//// [/home/node_modules/someLib/index.d.ts] *new* +import type { Str } from 'otherLib'; +export type Foo = { foo: Str; }; +//// [/home/node_modules/someLib/package.json] *new* +{ + "name": "somelib" +} +//// [/home/project/src/index.ts] *new* +import type { Foo1 } from 'lib1'; +import type { Foo2 } from 'lib2'; +export const foo1: Foo1 = { foo: "a" }; +export const foo2: Foo2 = { foo: "b" }; +//// [/home/project/tsconfig.json] *new* +{ + "compilerOptions": { + "incremental": true + }, +} + +tsgo -p . +ExitStatus:: DiagnosticsPresent_OutputsGenerated +Output:: +../node_modules/lib2/index.d.ts:1:26 - error TS1149: File name '/home/node_modules/somelib/index.d.ts' differs from already included file name '/home/node_modules/someLib/index.d.ts' only in casing. + The file is in the program because: + Imported via 'someLib' from file '/home/node_modules/lib1/index.d.ts' + Imported via 'somelib' from file '/home/node_modules/lib2/index.d.ts' + +1 import type { Foo } from 'somelib'; +   ~~~~~~~~~ + + ../node_modules/lib1/index.d.ts:1:26 - File is included via import here. + 1 import type { Foo } from 'someLib'; +    ~~~~~~~~~ + + +Found 1 error in ../node_modules/lib2/index.d.ts:1 + +//// [/home/project/src/index.js] *new* +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.foo2 = exports.foo1 = void 0; +exports.foo1 = { foo: "a" }; +exports.foo2 = { foo: "b" }; + +//// [/home/project/tsconfig.tsbuildinfo] *new* +{"version":"FakeTSVersion","errors":true,"root":[6],"fileNames":["lib.d.ts","../node_modules/otherlib/index.d.ts","../node_modules/somelib/index.d.ts","../node_modules/lib1/index.d.ts","../node_modules/lib2/index.d.ts","./src/index.ts"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"1fe659ed0634bb57b6dc25e9062f1162-export type Str = string;","12e112ff6e2744bb42d8e0b511e44117-import type { Str } from 'otherLib';\nexport type Foo = { foo: Str; };","b6305455d920a6729c435e6acf45eff6-import type { Foo } from 'someLib';\nexport type { Foo as Foo1 };","a5393e550a9c20a242a120bf6410db48-import type { Foo } from 'somelib';\nexport type { Foo as Foo2 };\nexport declare const foo2: Foo;","42aef197ff5f079223e2c29fb2e77cc5-import type { Foo1 } from 'lib1';\nimport type { Foo2 } from 'lib2';\nexport const foo1: Foo1 = { foo: \"a\" };\nexport const foo2: Foo2 = { foo: \"b\" };"],"fileIdsList":[[3],[2],[4,5]],"referencedMap":[[4,1],[5,1],[3,2],[6,3]]} +//// [/home/project/tsconfig.tsbuildinfo.readable.baseline.txt] *new* +{ + "version": "FakeTSVersion", + "errors": true, + "root": [ + { + "files": [ + "./src/index.ts" + ], + "original": 6 + } + ], + "fileNames": [ + "lib.d.ts", + "../node_modules/otherlib/index.d.ts", + "../node_modules/somelib/index.d.ts", + "../node_modules/lib1/index.d.ts", + "../node_modules/lib2/index.d.ts", + "./src/index.ts" + ], + "fileInfos": [ + { + "fileName": "lib.d.ts", + "version": "8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };", + "signature": "8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };", + "affectsGlobalScope": true, + "impliedNodeFormat": "CommonJS", + "original": { + "version": "8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };", + "affectsGlobalScope": true, + "impliedNodeFormat": 1 + } + }, + { + "fileName": "../node_modules/otherlib/index.d.ts", + "version": "1fe659ed0634bb57b6dc25e9062f1162-export type Str = string;", + "signature": "1fe659ed0634bb57b6dc25e9062f1162-export type Str = string;", + "impliedNodeFormat": "CommonJS" + }, + { + "fileName": "../node_modules/somelib/index.d.ts", + "version": "12e112ff6e2744bb42d8e0b511e44117-import type { Str } from 'otherLib';\nexport type Foo = { foo: Str; };", + "signature": "12e112ff6e2744bb42d8e0b511e44117-import type { Str } from 'otherLib';\nexport type Foo = { foo: Str; };", + "impliedNodeFormat": "CommonJS" + }, + { + "fileName": "../node_modules/lib1/index.d.ts", + "version": "b6305455d920a6729c435e6acf45eff6-import type { Foo } from 'someLib';\nexport type { Foo as Foo1 };", + "signature": "b6305455d920a6729c435e6acf45eff6-import type { Foo } from 'someLib';\nexport type { Foo as Foo1 };", + "impliedNodeFormat": "CommonJS" + }, + { + "fileName": "../node_modules/lib2/index.d.ts", + "version": "a5393e550a9c20a242a120bf6410db48-import type { Foo } from 'somelib';\nexport type { Foo as Foo2 };\nexport declare const foo2: Foo;", + "signature": "a5393e550a9c20a242a120bf6410db48-import type { Foo } from 'somelib';\nexport type { Foo as Foo2 };\nexport declare const foo2: Foo;", + "impliedNodeFormat": "CommonJS" + }, + { + "fileName": "./src/index.ts", + "version": "42aef197ff5f079223e2c29fb2e77cc5-import type { Foo1 } from 'lib1';\nimport type { Foo2 } from 'lib2';\nexport const foo1: Foo1 = { foo: \"a\" };\nexport const foo2: Foo2 = { foo: \"b\" };", + "signature": "42aef197ff5f079223e2c29fb2e77cc5-import type { Foo1 } from 'lib1';\nimport type { Foo2 } from 'lib2';\nexport const foo1: Foo1 = { foo: \"a\" };\nexport const foo2: Foo2 = { foo: \"b\" };", + "impliedNodeFormat": "CommonJS" + } + ], + "fileIdsList": [ + [ + "../node_modules/somelib/index.d.ts" + ], + [ + "../node_modules/otherlib/index.d.ts" + ], + [ + "../node_modules/lib1/index.d.ts", + "../node_modules/lib2/index.d.ts" + ] + ], + "referencedMap": { + "../node_modules/lib1/index.d.ts": [ + "../node_modules/somelib/index.d.ts" + ], + "../node_modules/lib2/index.d.ts": [ + "../node_modules/somelib/index.d.ts" + ], + "../node_modules/somelib/index.d.ts": [ + "../node_modules/otherlib/index.d.ts" + ], + "./src/index.ts": [ + "../node_modules/lib1/index.d.ts", + "../node_modules/lib2/index.d.ts" + ] + }, + "size": 1685 +} +//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +interface SymbolConstructor { + (desc?: string | number): symbol; + for(name: string): symbol; + readonly toStringTag: symbol; +} +declare var Symbol: SymbolConstructor; +interface Symbol { + readonly [Symbol.toStringTag]: string; +} +declare const console: { log(msg: any): void; }; + +tsconfig.json:: +SemanticDiagnostics:: +*refresh* /home/src/tslibs/TS/Lib/lib.d.ts +*refresh* /home/node_modules/otherLib/index.d.ts +*refresh* /home/node_modules/someLib/index.d.ts +*refresh* /home/node_modules/lib1/index.d.ts +*refresh* /home/node_modules/lib2/index.d.ts +*refresh* /home/project/src/index.ts +Signatures::