585 lines
20 KiB
Go
585 lines
20 KiB
Go
package incremental
|
|
|
|
import (
|
|
"fmt"
|
|
"iter"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
|
"github.com/go-json-experiment/json"
|
|
"github.com/go-json-experiment/json/jsontext"
|
|
)
|
|
|
|
type (
|
|
BuildInfoFileId int
|
|
BuildInfoFileIdListId int
|
|
)
|
|
|
|
// buildInfoRoot is
|
|
// - for incremental program buildinfo
|
|
// - start and end of FileId for consecutive fileIds to be included as root
|
|
// - start - single fileId that is root
|
|
//
|
|
// - for non incremental program buildinfo
|
|
// - string that is the root file name
|
|
type BuildInfoRoot struct {
|
|
Start BuildInfoFileId
|
|
End BuildInfoFileId
|
|
NonIncremental string // Root of a non incremental program
|
|
}
|
|
|
|
func (b *BuildInfoRoot) MarshalJSON() ([]byte, error) {
|
|
if b.Start != 0 {
|
|
if b.End != 0 {
|
|
return json.Marshal([2]BuildInfoFileId{b.Start, b.End})
|
|
} else {
|
|
return json.Marshal(b.Start)
|
|
}
|
|
} else {
|
|
return json.Marshal(b.NonIncremental)
|
|
}
|
|
}
|
|
|
|
func (b *BuildInfoRoot) UnmarshalJSON(data []byte) error {
|
|
var startAndEnd *[2]int
|
|
if err := json.Unmarshal(data, &startAndEnd); err != nil {
|
|
var start int
|
|
if err := json.Unmarshal(data, &start); err != nil {
|
|
var name string
|
|
if err := json.Unmarshal(data, &name); err != nil {
|
|
return fmt.Errorf("invalid BuildInfoRoot: %s", data)
|
|
}
|
|
*b = BuildInfoRoot{
|
|
NonIncremental: name,
|
|
}
|
|
return nil
|
|
}
|
|
*b = BuildInfoRoot{
|
|
Start: BuildInfoFileId(start),
|
|
}
|
|
return nil
|
|
}
|
|
*b = BuildInfoRoot{
|
|
Start: BuildInfoFileId(startAndEnd[0]),
|
|
End: BuildInfoFileId(startAndEnd[1]),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type buildInfoFileInfoNoSignature struct {
|
|
Version string `json:"version,omitzero"`
|
|
NoSignature bool `json:"noSignature,omitzero"`
|
|
AffectsGlobalScope bool `json:"affectsGlobalScope,omitzero"`
|
|
ImpliedNodeFormat core.ResolutionMode `json:"impliedNodeFormat,omitzero"`
|
|
}
|
|
|
|
// Signature is
|
|
// - undefined if FileInfo.version === FileInfo.signature
|
|
// - string actual signature
|
|
type buildInfoFileInfoWithSignature struct {
|
|
Version string `json:"version,omitzero"`
|
|
Signature string `json:"signature,omitzero"`
|
|
AffectsGlobalScope bool `json:"affectsGlobalScope,omitzero"`
|
|
ImpliedNodeFormat core.ResolutionMode `json:"impliedNodeFormat,omitzero"`
|
|
}
|
|
|
|
type BuildInfoFileInfo struct {
|
|
signature string
|
|
noSignature *buildInfoFileInfoNoSignature
|
|
fileInfo *buildInfoFileInfoWithSignature
|
|
}
|
|
|
|
func newBuildInfoFileInfo(fileInfo *fileInfo) *BuildInfoFileInfo {
|
|
if fileInfo.version == fileInfo.signature {
|
|
if !fileInfo.affectsGlobalScope && fileInfo.impliedNodeFormat == core.ResolutionModeCommonJS {
|
|
return &BuildInfoFileInfo{signature: fileInfo.signature}
|
|
}
|
|
} else if fileInfo.signature == "" {
|
|
return &BuildInfoFileInfo{noSignature: &buildInfoFileInfoNoSignature{
|
|
Version: fileInfo.version,
|
|
NoSignature: true,
|
|
AffectsGlobalScope: fileInfo.affectsGlobalScope,
|
|
ImpliedNodeFormat: fileInfo.impliedNodeFormat,
|
|
}}
|
|
}
|
|
return &BuildInfoFileInfo{fileInfo: &buildInfoFileInfoWithSignature{
|
|
Version: fileInfo.version,
|
|
Signature: core.IfElse(fileInfo.signature == fileInfo.version, "", fileInfo.signature),
|
|
AffectsGlobalScope: fileInfo.affectsGlobalScope,
|
|
ImpliedNodeFormat: fileInfo.impliedNodeFormat,
|
|
}}
|
|
}
|
|
|
|
func (b *BuildInfoFileInfo) GetFileInfo() *fileInfo {
|
|
if b == nil {
|
|
return nil
|
|
}
|
|
if b.signature != "" {
|
|
return &fileInfo{
|
|
version: b.signature,
|
|
signature: b.signature,
|
|
impliedNodeFormat: core.ResolutionModeCommonJS,
|
|
}
|
|
}
|
|
if b.noSignature != nil {
|
|
return &fileInfo{
|
|
version: b.noSignature.Version,
|
|
affectsGlobalScope: b.noSignature.AffectsGlobalScope,
|
|
impliedNodeFormat: b.noSignature.ImpliedNodeFormat,
|
|
}
|
|
}
|
|
return &fileInfo{
|
|
version: b.fileInfo.Version,
|
|
signature: core.IfElse(b.fileInfo.Signature == "", b.fileInfo.Version, b.fileInfo.Signature),
|
|
affectsGlobalScope: b.fileInfo.AffectsGlobalScope,
|
|
impliedNodeFormat: b.fileInfo.ImpliedNodeFormat,
|
|
}
|
|
}
|
|
|
|
func (b *BuildInfoFileInfo) HasSignature() bool {
|
|
return b.signature != ""
|
|
}
|
|
|
|
func (b *BuildInfoFileInfo) MarshalJSON() ([]byte, error) {
|
|
if b.signature != "" {
|
|
return json.Marshal(b.signature)
|
|
}
|
|
if b.noSignature != nil {
|
|
return json.Marshal(b.noSignature)
|
|
}
|
|
return json.Marshal(b.fileInfo)
|
|
}
|
|
|
|
func (b *BuildInfoFileInfo) UnmarshalJSON(data []byte) error {
|
|
var vSignature string
|
|
if err := json.Unmarshal(data, &vSignature); err != nil {
|
|
var noSignature buildInfoFileInfoNoSignature
|
|
if err := json.Unmarshal(data, &noSignature); err != nil || !noSignature.NoSignature {
|
|
var fileInfo buildInfoFileInfoWithSignature
|
|
if err := json.Unmarshal(data, &fileInfo); err != nil {
|
|
return fmt.Errorf("invalid BuildInfoFileInfo: %s", data)
|
|
}
|
|
*b = BuildInfoFileInfo{fileInfo: &fileInfo}
|
|
return nil
|
|
}
|
|
*b = BuildInfoFileInfo{noSignature: &noSignature}
|
|
return nil
|
|
}
|
|
*b = BuildInfoFileInfo{signature: vSignature}
|
|
return nil
|
|
}
|
|
|
|
type BuildInfoReferenceMapEntry struct {
|
|
FileId BuildInfoFileId
|
|
FileIdListId BuildInfoFileIdListId
|
|
}
|
|
|
|
func (b *BuildInfoReferenceMapEntry) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal([2]int{int(b.FileId), int(b.FileIdListId)})
|
|
}
|
|
|
|
func (b *BuildInfoReferenceMapEntry) UnmarshalJSON(data []byte) error {
|
|
var v *[2]int
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return err
|
|
}
|
|
*b = BuildInfoReferenceMapEntry{
|
|
FileId: BuildInfoFileId(v[0]),
|
|
FileIdListId: BuildInfoFileIdListId(v[1]),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type BuildInfoDiagnostic struct {
|
|
// BuildInfoFileId if it is for a File thats other than its stored for
|
|
File BuildInfoFileId `json:"file,omitzero"`
|
|
NoFile bool `json:"noFile,omitzero"`
|
|
Pos int `json:"pos,omitzero"`
|
|
End int `json:"end,omitzero"`
|
|
Code int32 `json:"code,omitzero"`
|
|
Category diagnostics.Category `json:"category,omitzero"`
|
|
Message string `json:"message,omitzero"`
|
|
MessageChain []*BuildInfoDiagnostic `json:"messageChain,omitzero"`
|
|
RelatedInformation []*BuildInfoDiagnostic `json:"relatedInformation,omitzero"`
|
|
ReportsUnnecessary bool `json:"reportsUnnecessary,omitzero"`
|
|
ReportsDeprecated bool `json:"reportsDeprecated,omitzero"`
|
|
SkippedOnNoEmit bool `json:"skippedOnNoEmit,omitzero"`
|
|
}
|
|
|
|
type BuildInfoDiagnosticsOfFile struct {
|
|
FileId BuildInfoFileId
|
|
Diagnostics []*BuildInfoDiagnostic
|
|
}
|
|
|
|
func (b *BuildInfoDiagnosticsOfFile) MarshalJSON() ([]byte, error) {
|
|
fileIdAndDiagnostics := make([]any, 0, 2)
|
|
fileIdAndDiagnostics = append(fileIdAndDiagnostics, b.FileId)
|
|
fileIdAndDiagnostics = append(fileIdAndDiagnostics, b.Diagnostics)
|
|
return json.Marshal(fileIdAndDiagnostics)
|
|
}
|
|
|
|
func (b *BuildInfoDiagnosticsOfFile) UnmarshalJSON(data []byte) error {
|
|
var fileIdAndDiagnostics []jsontext.Value
|
|
if err := json.Unmarshal(data, &fileIdAndDiagnostics); err != nil {
|
|
return fmt.Errorf("invalid BuildInfoDiagnosticsOfFile: %s", data)
|
|
}
|
|
if len(fileIdAndDiagnostics) != 2 {
|
|
return fmt.Errorf("invalid BuildInfoDiagnosticsOfFile: expected 2 elements, got %d", len(fileIdAndDiagnostics))
|
|
}
|
|
var fileId BuildInfoFileId
|
|
if err := json.Unmarshal(fileIdAndDiagnostics[0], &fileId); err != nil {
|
|
return fmt.Errorf("invalid fileId in BuildInfoDiagnosticsOfFile: %w", err)
|
|
}
|
|
|
|
var diagnostics []*BuildInfoDiagnostic
|
|
if err := json.Unmarshal(fileIdAndDiagnostics[1], &diagnostics); err != nil {
|
|
return fmt.Errorf("invalid diagnostics in BuildInfoDiagnosticsOfFile: %w", err)
|
|
}
|
|
*b = BuildInfoDiagnosticsOfFile{
|
|
FileId: fileId,
|
|
Diagnostics: diagnostics,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type BuildInfoSemanticDiagnostic struct {
|
|
FileId BuildInfoFileId // File is not in changedSet and still doesnt have cached diagnostics
|
|
Diagnostics *BuildInfoDiagnosticsOfFile // Diagnostics for file
|
|
}
|
|
|
|
func (b *BuildInfoSemanticDiagnostic) MarshalJSON() ([]byte, error) {
|
|
if b.FileId != 0 {
|
|
return json.Marshal(b.FileId)
|
|
}
|
|
return json.Marshal(b.Diagnostics)
|
|
}
|
|
|
|
func (b *BuildInfoSemanticDiagnostic) UnmarshalJSON(data []byte) error {
|
|
var fileId BuildInfoFileId
|
|
if err := json.Unmarshal(data, &fileId); err != nil {
|
|
var diagnostics BuildInfoDiagnosticsOfFile
|
|
if err := json.Unmarshal(data, &diagnostics); err != nil {
|
|
return fmt.Errorf("invalid BuildInfoSemanticDiagnostic: %s", data)
|
|
}
|
|
*b = BuildInfoSemanticDiagnostic{
|
|
Diagnostics: &diagnostics,
|
|
}
|
|
return nil
|
|
}
|
|
*b = BuildInfoSemanticDiagnostic{
|
|
FileId: fileId,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// fileId if pending emit is same as what compilerOptions suggest
|
|
// [fileId] if pending emit is only dts file emit
|
|
// [fileId, emitKind] if any other type emit is pending
|
|
type BuildInfoFilePendingEmit struct {
|
|
FileId BuildInfoFileId
|
|
EmitKind FileEmitKind
|
|
}
|
|
|
|
func (b *BuildInfoFilePendingEmit) MarshalJSON() ([]byte, error) {
|
|
if b.EmitKind == 0 {
|
|
return json.Marshal(b.FileId)
|
|
}
|
|
if b.EmitKind == FileEmitKindDts {
|
|
fileListIds := []BuildInfoFileId{b.FileId}
|
|
return json.Marshal(fileListIds)
|
|
}
|
|
fileAndEmitKind := []int{int(b.FileId), int(b.EmitKind)}
|
|
return json.Marshal(fileAndEmitKind)
|
|
}
|
|
|
|
func (b *BuildInfoFilePendingEmit) UnmarshalJSON(data []byte) error {
|
|
var fileId BuildInfoFileId
|
|
if err := json.Unmarshal(data, &fileId); err != nil {
|
|
var intTuple []int
|
|
if err := json.Unmarshal(data, &intTuple); err != nil || len(intTuple) == 0 {
|
|
return fmt.Errorf("invalid BuildInfoFilePendingEmit: %s", data)
|
|
}
|
|
switch len(intTuple) {
|
|
case 1:
|
|
*b = BuildInfoFilePendingEmit{
|
|
FileId: BuildInfoFileId(intTuple[0]),
|
|
EmitKind: FileEmitKindDts,
|
|
}
|
|
return nil
|
|
case 2:
|
|
*b = BuildInfoFilePendingEmit{
|
|
FileId: BuildInfoFileId(intTuple[0]),
|
|
EmitKind: FileEmitKind(intTuple[1]),
|
|
}
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("invalid BuildInfoFilePendingEmit: expected 1 or 2 integers, got %d", len(intTuple))
|
|
}
|
|
}
|
|
*b = BuildInfoFilePendingEmit{
|
|
FileId: fileId,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// [fileId, signature] if different from file's signature
|
|
// fileId if file wasnt emitted
|
|
type BuildInfoEmitSignature struct {
|
|
FileId BuildInfoFileId
|
|
Signature string // Signature if it is different from file's Signature
|
|
DiffersOnlyInDtsMap bool // true if signature is different only in dtsMap value
|
|
DiffersInOptions bool // true if signature is different in options used to emit file
|
|
}
|
|
|
|
func (b *BuildInfoEmitSignature) noEmitSignature() bool {
|
|
return b.Signature == "" && !b.DiffersOnlyInDtsMap && !b.DiffersInOptions
|
|
}
|
|
|
|
func (b *BuildInfoEmitSignature) toEmitSignature(path tspath.Path, emitSignatures *collections.SyncMap[tspath.Path, *emitSignature]) *emitSignature {
|
|
var signature string
|
|
var signatureWithDifferentOptions []string
|
|
if b.DiffersOnlyInDtsMap {
|
|
signatureWithDifferentOptions = make([]string, 0, 1)
|
|
info, _ := emitSignatures.Load(path)
|
|
signatureWithDifferentOptions = append(signatureWithDifferentOptions, info.signature)
|
|
} else if b.DiffersInOptions {
|
|
signatureWithDifferentOptions = make([]string, 0, 1)
|
|
signatureWithDifferentOptions = append(signatureWithDifferentOptions, b.Signature)
|
|
} else {
|
|
signature = b.Signature
|
|
}
|
|
return &emitSignature{
|
|
signature: signature,
|
|
signatureWithDifferentOptions: signatureWithDifferentOptions,
|
|
}
|
|
}
|
|
|
|
func (b *BuildInfoEmitSignature) MarshalJSON() ([]byte, error) {
|
|
if b.noEmitSignature() {
|
|
return json.Marshal(b.FileId)
|
|
}
|
|
fileIdAndSignature := make([]any, 2)
|
|
fileIdAndSignature[0] = b.FileId
|
|
var signature any
|
|
if b.DiffersOnlyInDtsMap {
|
|
signature = []string{}
|
|
} else if b.DiffersInOptions {
|
|
signature = []string{b.Signature}
|
|
} else {
|
|
signature = b.Signature
|
|
}
|
|
fileIdAndSignature[1] = signature
|
|
return json.Marshal(fileIdAndSignature)
|
|
}
|
|
|
|
func (b *BuildInfoEmitSignature) UnmarshalJSON(data []byte) error {
|
|
var fileId BuildInfoFileId
|
|
if err := json.Unmarshal(data, &fileId); err != nil {
|
|
var fileIdAndSignature []any
|
|
if err := json.Unmarshal(data, &fileIdAndSignature); err != nil {
|
|
return fmt.Errorf("invalid BuildInfoEmitSignature: %s", data)
|
|
}
|
|
if len(fileIdAndSignature) != 2 {
|
|
return fmt.Errorf("invalid BuildInfoEmitSignature: expected 2 elements, got %d", len(fileIdAndSignature))
|
|
}
|
|
var fileId BuildInfoFileId
|
|
if id, ok := fileIdAndSignature[0].(float64); !ok {
|
|
return fmt.Errorf("invalid fileId in BuildInfoEmitSignature: expected float64, got %T", fileIdAndSignature[0])
|
|
} else {
|
|
fileId = BuildInfoFileId(id)
|
|
}
|
|
var signature string
|
|
var differsOnlyInDtsMap, differsInOptions bool
|
|
if signatureV, ok := fileIdAndSignature[1].(string); !ok {
|
|
if signatureList, ok := fileIdAndSignature[1].([]any); !ok {
|
|
return fmt.Errorf("invalid signature in BuildInfoEmitSignature: expected string or []string, got %T", fileIdAndSignature[1])
|
|
} else {
|
|
switch len(signatureList) {
|
|
case 0:
|
|
differsOnlyInDtsMap = true
|
|
case 1:
|
|
if sig, ok := signatureList[0].(string); !ok {
|
|
return fmt.Errorf("invalid signature in BuildInfoEmitSignature: expected string, got %T", signatureList[0])
|
|
} else {
|
|
signature = sig
|
|
differsInOptions = true
|
|
}
|
|
default:
|
|
return fmt.Errorf("invalid signature in BuildInfoEmitSignature: expected string or []string with 0 or 1 element, got %d elements", len(signatureList))
|
|
}
|
|
}
|
|
} else {
|
|
signature = signatureV
|
|
}
|
|
*b = BuildInfoEmitSignature{
|
|
FileId: fileId,
|
|
Signature: signature,
|
|
DiffersOnlyInDtsMap: differsOnlyInDtsMap,
|
|
DiffersInOptions: differsInOptions,
|
|
}
|
|
return nil
|
|
|
|
}
|
|
*b = BuildInfoEmitSignature{
|
|
FileId: fileId,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type BuildInfoResolvedRoot struct {
|
|
Resolved BuildInfoFileId
|
|
Root BuildInfoFileId
|
|
}
|
|
|
|
func (b *BuildInfoResolvedRoot) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal([2]BuildInfoFileId{b.Resolved, b.Root})
|
|
}
|
|
|
|
func (b *BuildInfoResolvedRoot) UnmarshalJSON(data []byte) error {
|
|
var resolvedAndRoot [2]int
|
|
if err := json.Unmarshal(data, &resolvedAndRoot); err != nil {
|
|
return fmt.Errorf("invalid BuildInfoResolvedRoot: %s", data)
|
|
}
|
|
*b = BuildInfoResolvedRoot{
|
|
Resolved: BuildInfoFileId(resolvedAndRoot[0]),
|
|
Root: BuildInfoFileId(resolvedAndRoot[1]),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type BuildInfo struct {
|
|
Version string `json:"version,omitzero"`
|
|
|
|
// Common between incremental and tsc -b buildinfo for non incremental programs
|
|
Errors bool `json:"errors,omitzero"`
|
|
CheckPending bool `json:"checkPending,omitzero"`
|
|
Root []*BuildInfoRoot `json:"root,omitzero"`
|
|
|
|
// IncrementalProgram info
|
|
FileNames []string `json:"fileNames,omitzero"`
|
|
FileInfos []*BuildInfoFileInfo `json:"fileInfos,omitzero"`
|
|
FileIdsList [][]BuildInfoFileId `json:"fileIdsList,omitzero"`
|
|
Options *collections.OrderedMap[string, any] `json:"options,omitzero"`
|
|
ReferencedMap []*BuildInfoReferenceMapEntry `json:"referencedMap,omitzero"`
|
|
SemanticDiagnosticsPerFile []*BuildInfoSemanticDiagnostic `json:"semanticDiagnosticsPerFile,omitzero"`
|
|
EmitDiagnosticsPerFile []*BuildInfoDiagnosticsOfFile `json:"emitDiagnosticsPerFile,omitzero"`
|
|
ChangeFileSet []BuildInfoFileId `json:"changeFileSet,omitzero"`
|
|
AffectedFilesPendingEmit []*BuildInfoFilePendingEmit `json:"affectedFilesPendingEmit,omitzero"`
|
|
LatestChangedDtsFile string `json:"latestChangedDtsFile,omitzero"` // Because this is only output file in the program, we dont need fileId to deduplicate name
|
|
EmitSignatures []*BuildInfoEmitSignature `json:"emitSignatures,omitzero"`
|
|
ResolvedRoot []*BuildInfoResolvedRoot `json:"resolvedRoot,omitzero"`
|
|
|
|
// NonIncrementalProgram info
|
|
SemanticErrors bool `json:"semanticErrors,omitzero"`
|
|
}
|
|
|
|
func (b *BuildInfo) IsValidVersion() bool {
|
|
return b.Version == core.Version()
|
|
}
|
|
|
|
func (b *BuildInfo) IsIncremental() bool {
|
|
return b != nil && len(b.FileNames) != 0
|
|
}
|
|
|
|
func (b *BuildInfo) fileName(fileId BuildInfoFileId) string {
|
|
return b.FileNames[fileId-1]
|
|
}
|
|
|
|
func (b *BuildInfo) fileInfo(fileId BuildInfoFileId) *BuildInfoFileInfo {
|
|
return b.FileInfos[fileId-1]
|
|
}
|
|
|
|
func (b *BuildInfo) GetCompilerOptions(buildInfoDirectory string) *core.CompilerOptions {
|
|
options := &core.CompilerOptions{}
|
|
for option, value := range b.Options.Entries() {
|
|
if buildInfoDirectory != "" {
|
|
result, ok := tsoptions.ConvertOptionToAbsolutePath(option, value, tsoptions.CommandLineCompilerOptionsMap, buildInfoDirectory)
|
|
if ok {
|
|
tsoptions.ParseCompilerOptions(option, result, options)
|
|
continue
|
|
}
|
|
}
|
|
tsoptions.ParseCompilerOptions(option, value, options)
|
|
|
|
}
|
|
return options
|
|
}
|
|
|
|
func (b *BuildInfo) IsEmitPending(resolved *tsoptions.ParsedCommandLine, buildInfoDirectory string) bool {
|
|
// Some of the emit files like source map or dts etc are not yet done
|
|
if !resolved.CompilerOptions().NoEmit.IsTrue() || resolved.CompilerOptions().GetEmitDeclarations() {
|
|
pendingEmit := getPendingEmitKindWithOptions(resolved.CompilerOptions(), b.GetCompilerOptions(buildInfoDirectory))
|
|
if resolved.CompilerOptions().NoEmit.IsTrue() {
|
|
pendingEmit &= FileEmitKindDtsErrors
|
|
}
|
|
return pendingEmit != 0
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (b *BuildInfo) GetBuildInfoRootInfoReader(buildInfoDirectory string, comparePathOptions tspath.ComparePathsOptions) *BuildInfoRootInfoReader {
|
|
resolvedRootFileInfos := make(map[tspath.Path]*BuildInfoFileInfo, len(b.FileNames))
|
|
// Roots of the File
|
|
rootToResolved := collections.NewOrderedMapWithSizeHint[tspath.Path, tspath.Path](len(b.FileNames))
|
|
resolvedToRoot := make(map[tspath.Path]tspath.Path, len(b.ResolvedRoot))
|
|
toPath := func(fileName string) tspath.Path {
|
|
return tspath.ToPath(fileName, buildInfoDirectory, comparePathOptions.UseCaseSensitiveFileNames)
|
|
}
|
|
|
|
// Create map from resolvedRoot to Root
|
|
for _, resolved := range b.ResolvedRoot {
|
|
resolvedToRoot[toPath(b.fileName(resolved.Resolved))] = toPath(b.fileName(resolved.Root))
|
|
}
|
|
|
|
addRoot := func(resolvedRoot string, fileInfo *BuildInfoFileInfo) {
|
|
resolvedRootPath := toPath(resolvedRoot)
|
|
if rootPath, ok := resolvedToRoot[resolvedRootPath]; ok {
|
|
rootToResolved.Set(rootPath, resolvedRootPath)
|
|
} else {
|
|
rootToResolved.Set(resolvedRootPath, resolvedRootPath)
|
|
}
|
|
if fileInfo != nil {
|
|
resolvedRootFileInfos[resolvedRootPath] = fileInfo
|
|
}
|
|
}
|
|
|
|
for _, root := range b.Root {
|
|
if root.NonIncremental != "" {
|
|
addRoot(root.NonIncremental, nil)
|
|
} else if root.End == 0 {
|
|
addRoot(b.fileName(root.Start), b.fileInfo(root.Start))
|
|
} else {
|
|
for i := root.Start; i <= root.End; i++ {
|
|
addRoot(b.fileName(i), b.fileInfo(i))
|
|
}
|
|
}
|
|
}
|
|
|
|
return &BuildInfoRootInfoReader{
|
|
resolvedRootFileInfos: resolvedRootFileInfos,
|
|
rootToResolved: rootToResolved,
|
|
}
|
|
}
|
|
|
|
type BuildInfoRootInfoReader struct {
|
|
resolvedRootFileInfos map[tspath.Path]*BuildInfoFileInfo
|
|
rootToResolved *collections.OrderedMap[tspath.Path, tspath.Path]
|
|
}
|
|
|
|
func (b *BuildInfoRootInfoReader) GetBuildInfoFileInfo(inputFilePath tspath.Path) (*BuildInfoFileInfo, tspath.Path) {
|
|
if info, ok := b.resolvedRootFileInfos[inputFilePath]; ok {
|
|
return info, inputFilePath
|
|
}
|
|
if resolved, ok := b.rootToResolved.Get(inputFilePath); ok {
|
|
return b.resolvedRootFileInfos[resolved], resolved
|
|
}
|
|
return nil, ""
|
|
}
|
|
|
|
func (b *BuildInfoRootInfoReader) Roots() iter.Seq[tspath.Path] {
|
|
return b.rootToResolved.Keys()
|
|
}
|