185 lines
6.6 KiB
Go
185 lines
6.6 KiB
Go
package compiler
|
|
|
|
import (
|
|
"slices"
|
|
"sync"
|
|
|
|
"github.com/microsoft/typescript-go/internal/ast"
|
|
"github.com/microsoft/typescript-go/internal/collections"
|
|
"github.com/microsoft/typescript-go/internal/core"
|
|
"github.com/microsoft/typescript-go/internal/diagnostics"
|
|
"github.com/microsoft/typescript-go/internal/tsoptions"
|
|
"github.com/microsoft/typescript-go/internal/tspath"
|
|
)
|
|
|
|
type includeProcessor struct {
|
|
fileIncludeReasons map[tspath.Path][]*FileIncludeReason
|
|
processingDiagnostics []*processingDiagnostic
|
|
|
|
reasonToReferenceLocation collections.SyncMap[*FileIncludeReason, *referenceFileLocation]
|
|
includeReasonToRelatedInfo collections.SyncMap[*FileIncludeReason, *ast.Diagnostic]
|
|
redirectAndFileFormat collections.SyncMap[tspath.Path, []*ast.Diagnostic]
|
|
computedDiagnostics *ast.DiagnosticsCollection
|
|
computedDiagnosticsOnce sync.Once
|
|
compilerOptionsSyntax *ast.ObjectLiteralExpression
|
|
compilerOptionsSyntaxOnce sync.Once
|
|
}
|
|
|
|
func updateFileIncludeProcessor(p *Program) {
|
|
p.includeProcessor = &includeProcessor{
|
|
fileIncludeReasons: p.includeProcessor.fileIncludeReasons,
|
|
processingDiagnostics: p.includeProcessor.processingDiagnostics,
|
|
}
|
|
}
|
|
|
|
func (i *includeProcessor) getDiagnostics(p *Program) *ast.DiagnosticsCollection {
|
|
i.computedDiagnosticsOnce.Do(func() {
|
|
i.computedDiagnostics = &ast.DiagnosticsCollection{}
|
|
for _, d := range i.processingDiagnostics {
|
|
i.computedDiagnostics.Add(d.toDiagnostic(p))
|
|
}
|
|
for _, resolutions := range p.resolvedModules {
|
|
for _, resolvedModule := range resolutions {
|
|
for _, diag := range resolvedModule.ResolutionDiagnostics {
|
|
i.computedDiagnostics.Add(diag)
|
|
}
|
|
}
|
|
}
|
|
for _, typeResolutions := range p.typeResolutionsInFile {
|
|
for _, resolvedTypeRef := range typeResolutions {
|
|
for _, diag := range resolvedTypeRef.ResolutionDiagnostics {
|
|
i.computedDiagnostics.Add(diag)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
return i.computedDiagnostics
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
loc, _ := i.reasonToReferenceLocation.LoadOrStore(r, r.getReferencedLocation(program))
|
|
return loc
|
|
}
|
|
|
|
func (i *includeProcessor) getCompilerOptionsObjectLiteralSyntax(program *Program) *ast.ObjectLiteralExpression {
|
|
i.compilerOptionsSyntaxOnce.Do(func() {
|
|
configFile := program.opts.Config.ConfigFile
|
|
if configFile != nil {
|
|
if compilerOptionsProperty := tsoptions.ForEachTsConfigPropArray(configFile.SourceFile, "compilerOptions", core.Identity); compilerOptionsProperty != nil &&
|
|
compilerOptionsProperty.Initializer != nil &&
|
|
ast.IsObjectLiteralExpression(compilerOptionsProperty.Initializer) {
|
|
i.compilerOptionsSyntax = compilerOptionsProperty.Initializer.AsObjectLiteralExpression()
|
|
}
|
|
} else {
|
|
i.compilerOptionsSyntax = nil
|
|
}
|
|
})
|
|
return i.compilerOptionsSyntax
|
|
}
|
|
|
|
func (i *includeProcessor) getRelatedInfo(r *FileIncludeReason, program *Program) *ast.Diagnostic {
|
|
if existing, ok := i.includeReasonToRelatedInfo.Load(r); ok {
|
|
return existing
|
|
}
|
|
|
|
relatedInfo, _ := i.includeReasonToRelatedInfo.LoadOrStore(r, r.toRelatedInfo(program))
|
|
return relatedInfo
|
|
}
|
|
|
|
func (i *includeProcessor) explainRedirectAndImpliedFormat(
|
|
program *Program,
|
|
filePath tspath.Path,
|
|
toFileName func(fileName string) string,
|
|
) []*ast.Diagnostic {
|
|
if existing, ok := i.redirectAndFileFormat.Load(filePath); ok {
|
|
return existing
|
|
}
|
|
var file ast.HasFileName
|
|
var sourceFile *ast.SourceFile
|
|
redirectsFile := program.redirectFilesByPath[filePath]
|
|
if redirectsFile != nil {
|
|
file = redirectsFile
|
|
} else {
|
|
sourceFile = program.GetSourceFileByPath(filePath)
|
|
if sourceFile == nil {
|
|
return nil
|
|
}
|
|
file = sourceFile
|
|
}
|
|
var result []*ast.Diagnostic
|
|
if source := program.GetSourceOfProjectReferenceIfOutputIncluded(file); source != file.FileName() {
|
|
result = append(result, ast.NewCompilerDiagnostic(
|
|
diagnostics.File_is_output_of_project_reference_source_0,
|
|
toFileName(source),
|
|
))
|
|
}
|
|
|
|
if redirectsFile != nil {
|
|
targetFile := program.GetSourceFileByPath(redirectsFile.target)
|
|
result = append(result, ast.NewCompilerDiagnostic(
|
|
diagnostics.File_redirects_to_file_0,
|
|
toFileName(targetFile.FileName()),
|
|
))
|
|
}
|
|
|
|
if sourceFile != nil && ast.IsExternalOrCommonJSModule(sourceFile) {
|
|
metaData := program.GetSourceFileMetaData(file.Path())
|
|
switch program.GetImpliedNodeFormatForEmit(file) {
|
|
case core.ModuleKindESNext:
|
|
if metaData.PackageJsonType == "module" {
|
|
result = append(result, ast.NewCompilerDiagnostic(
|
|
diagnostics.File_is_ECMAScript_module_because_0_has_field_type_with_value_module,
|
|
toFileName(metaData.PackageJsonDirectory+"/package.json"),
|
|
))
|
|
}
|
|
case core.ModuleKindCommonJS:
|
|
if metaData.PackageJsonType != "" {
|
|
result = append(result, ast.NewCompilerDiagnostic(diagnostics.File_is_CommonJS_module_because_0_has_field_type_whose_value_is_not_module, toFileName(metaData.PackageJsonDirectory+"/package.json")))
|
|
} else if metaData.PackageJsonDirectory != "" {
|
|
if metaData.PackageJsonType == "" {
|
|
result = append(result, ast.NewCompilerDiagnostic(diagnostics.File_is_CommonJS_module_because_0_does_not_have_field_type, toFileName(metaData.PackageJsonDirectory+"/package.json")))
|
|
}
|
|
} else {
|
|
result = append(result, ast.NewCompilerDiagnostic(diagnostics.File_is_CommonJS_module_because_package_json_was_not_found))
|
|
}
|
|
}
|
|
}
|
|
|
|
result, _ = i.redirectAndFileFormat.LoadOrStore(filePath, result)
|
|
return result
|
|
}
|