package incremental import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/compiler" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/tsoptions" "github.com/microsoft/typescript-go/internal/tspath" ) func buildInfoToSnapshot(buildInfo *BuildInfo, config *tsoptions.ParsedCommandLine, host compiler.CompilerHost) *snapshot { to := &toSnapshot{ buildInfo: buildInfo, buildInfoDirectory: tspath.GetDirectoryPath(tspath.GetNormalizedAbsolutePath(config.GetBuildInfoFileName(), config.GetCurrentDirectory())), filePaths: make([]tspath.Path, 0, len(buildInfo.FileNames)), filePathSet: make([]*collections.Set[tspath.Path], 0, len(buildInfo.FileIdsList)), } to.filePaths = core.Map(buildInfo.FileNames, func(fileName string) tspath.Path { if IsBuildInfoFileNameDefaultLibrary(fileName) { return tspath.ToPath(tspath.CombinePaths(host.DefaultLibraryPath(), fileName), host.GetCurrentDirectory(), host.FS().UseCaseSensitiveFileNames()) } return tspath.ToPath(fileName, to.buildInfoDirectory, config.UseCaseSensitiveFileNames()) }) to.filePathSet = core.Map(buildInfo.FileIdsList, func(fileIdList []BuildInfoFileId) *collections.Set[tspath.Path] { fileSet := collections.NewSetWithSizeHint[tspath.Path](len(fileIdList)) for _, fileId := range fileIdList { fileSet.Add(to.toFilePath(fileId)) } return fileSet }) to.setCompilerOptions() to.setFileInfoAndEmitSignatures() to.setReferencedMap() to.setChangeFileSet() to.setSemanticDiagnostics() to.setEmitDiagnostics() to.setAffectedFilesPendingEmit() if buildInfo.LatestChangedDtsFile != "" { to.snapshot.latestChangedDtsFile = to.toAbsolutePath(buildInfo.LatestChangedDtsFile) } to.snapshot.hasErrors = core.IfElse(buildInfo.Errors, core.TSTrue, core.TSFalse) to.snapshot.hasSemanticErrors = buildInfo.SemanticErrors to.snapshot.checkPending = buildInfo.CheckPending to.setPackageJsons() return &to.snapshot } type toSnapshot struct { buildInfo *BuildInfo buildInfoDirectory string snapshot snapshot filePaths []tspath.Path filePathSet []*collections.Set[tspath.Path] } func (t *toSnapshot) toAbsolutePath(path string) string { return tspath.GetNormalizedAbsolutePath(path, t.buildInfoDirectory) } func (t *toSnapshot) toFilePath(fileId BuildInfoFileId) tspath.Path { return t.filePaths[fileId-1] } func (t *toSnapshot) toFilePathSet(fileIdListId BuildInfoFileIdListId) *collections.Set[tspath.Path] { return t.filePathSet[fileIdListId-1] } func (t *toSnapshot) toBuildInfoDiagnosticsWithFileName(diagnostics []*BuildInfoDiagnostic) []*buildInfoDiagnosticWithFileName { return core.Map(diagnostics, func(d *BuildInfoDiagnostic) *buildInfoDiagnosticWithFileName { var file tspath.Path if d.File != 0 { file = t.toFilePath(d.File) } return &buildInfoDiagnosticWithFileName{ file: file, noFile: d.NoFile, pos: d.Pos, end: d.End, code: d.Code, category: d.Category, messageKey: d.MessageKey, messageArgs: d.MessageArgs, messageChain: t.toBuildInfoDiagnosticsWithFileName(d.MessageChain), relatedInformation: t.toBuildInfoDiagnosticsWithFileName(d.RelatedInformation), reportsUnnecessary: d.ReportsUnnecessary, reportsDeprecated: d.ReportsDeprecated, skippedOnNoEmit: d.SkippedOnNoEmit, repopulateInfo: fromBuildInfoRepopulateInfo(d.RepopulateInfo), } }) } func (t *toSnapshot) toDiagnosticsOrBuildInfoDiagnosticsWithFileName(dig *BuildInfoDiagnosticsOfFile) *DiagnosticsOrBuildInfoDiagnosticsWithFileName { return &DiagnosticsOrBuildInfoDiagnosticsWithFileName{ buildInfoDiagnostics: t.toBuildInfoDiagnosticsWithFileName(dig.Diagnostics), } } func fromBuildInfoRepopulateInfo(info *BuildInfoRepopulateInfo) *ast.RepopulateDiagnosticInfo { if info == nil { return nil } return &ast.RepopulateDiagnosticInfo{ Kind: info.Kind, ModuleReference: info.ModuleReference, Mode: info.Mode, PackageName: info.PackageName, } } func (t *toSnapshot) setCompilerOptions() { t.snapshot.options = t.buildInfo.GetCompilerOptions(t.buildInfoDirectory) } func (t *toSnapshot) setFileInfoAndEmitSignatures() { isComposite := t.snapshot.options.Composite.IsTrue() for index, buildInfoFileInfo := range t.buildInfo.FileInfos { path := t.toFilePath(BuildInfoFileId(index + 1)) info := buildInfoFileInfo.GetFileInfo() t.snapshot.fileInfos.Store(path, info) // Add default emit signature as file's signature if info.signature != "" && isComposite { t.snapshot.emitSignatures.Store(path, &emitSignature{signature: info.signature}) } } // Fix up emit signatures for _, value := range t.buildInfo.EmitSignatures { if value.noEmitSignature() { t.snapshot.emitSignatures.Delete(t.toFilePath(value.FileId)) } else { path := t.toFilePath(value.FileId) t.snapshot.emitSignatures.Store(path, value.toEmitSignature(path, &t.snapshot.emitSignatures)) } } } func (t *toSnapshot) setReferencedMap() { for _, entry := range t.buildInfo.ReferencedMap { t.snapshot.referencedMap.storeReferences(t.toFilePath(entry.FileId), t.toFilePathSet(entry.FileIdListId)) } } func (t *toSnapshot) setChangeFileSet() { for _, fileId := range t.buildInfo.ChangeFileSet { filePath := t.toFilePath(fileId) t.snapshot.changedFilesSet.Add(filePath) } } func (t *toSnapshot) setSemanticDiagnostics() { t.snapshot.fileInfos.Range(func(path tspath.Path, info *FileInfo) bool { // Initialize to have no diagnostics if its not changed file if !t.snapshot.changedFilesSet.Has(path) { t.snapshot.semanticDiagnosticsPerFile.Store(path, &DiagnosticsOrBuildInfoDiagnosticsWithFileName{}) } return true }) for _, diagnostic := range t.buildInfo.SemanticDiagnosticsPerFile { if diagnostic.FileId != 0 { filePath := t.toFilePath(diagnostic.FileId) t.snapshot.semanticDiagnosticsPerFile.Delete(filePath) // does not have cached diagnostics } else { filePath := t.toFilePath(diagnostic.Diagnostics.FileId) t.snapshot.semanticDiagnosticsPerFile.Store(filePath, t.toDiagnosticsOrBuildInfoDiagnosticsWithFileName(diagnostic.Diagnostics)) } } } func (t *toSnapshot) setEmitDiagnostics() { for _, diagnostic := range t.buildInfo.EmitDiagnosticsPerFile { filePath := t.toFilePath(diagnostic.FileId) t.snapshot.emitDiagnosticsPerFile.Store(filePath, t.toDiagnosticsOrBuildInfoDiagnosticsWithFileName(diagnostic)) } } func (t *toSnapshot) setAffectedFilesPendingEmit() { if len(t.buildInfo.AffectedFilesPendingEmit) == 0 { return } ownOptionsEmitKind := GetFileEmitKind(t.snapshot.options) for _, pendingEmit := range t.buildInfo.AffectedFilesPendingEmit { t.snapshot.affectedFilesPendingEmit.Store(t.toFilePath(pendingEmit.FileId), core.IfElse(pendingEmit.EmitKind == 0, ownOptionsEmitKind, pendingEmit.EmitKind)) } } func (t *toSnapshot) setPackageJsons() { if t.buildInfo.PackageJsons != nil { t.snapshot.packageJsons = core.Map(t.buildInfo.PackageJsons, t.toAbsolutePath) } else { t.snapshot.packageJsons = make([]string, 0) } if t.buildInfo.MissingPackageJsons != nil { t.snapshot.missingPackageJsons = core.Map(t.buildInfo.MissingPackageJsons, t.toAbsolutePath) } else { t.snapshot.missingPackageJsons = make([]string, 0) } }