342 lines
14 KiB
Go
342 lines
14 KiB
Go
package compiler
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
|
)
|
|
|
|
type fileIncludeKind int
|
|
|
|
const (
|
|
// References from file
|
|
fileIncludeKindImport = iota
|
|
fileIncludeKindReferenceFile
|
|
fileIncludeKindTypeReferenceDirective
|
|
fileIncludeKindLibReferenceDirective
|
|
|
|
fileIncludeKindRootFile
|
|
fileIncludeKindSourceFromProjectReference
|
|
fileIncludeKindOutputFromProjectReference
|
|
fileIncludeKindLibFile
|
|
fileIncludeKindAutomaticTypeDirectiveFile
|
|
)
|
|
|
|
type fileIncludeReason struct {
|
|
kind fileIncludeKind
|
|
data any
|
|
|
|
// Uses relative file name
|
|
relativeFileNameDiag *ast.Diagnostic
|
|
relativeFileNameDiagOnce sync.Once
|
|
|
|
// Uses file name as is
|
|
diag *ast.Diagnostic
|
|
diagOnce sync.Once
|
|
}
|
|
|
|
type referencedFileData struct {
|
|
file tspath.Path
|
|
index int
|
|
synthetic *ast.Node
|
|
}
|
|
|
|
type referenceFileLocation struct {
|
|
file *ast.SourceFile
|
|
node *ast.Node
|
|
ref *ast.FileReference
|
|
packageId module.PackageId
|
|
isSynthetic bool
|
|
}
|
|
|
|
func (r *referenceFileLocation) text() string {
|
|
if r.node != nil {
|
|
if !ast.NodeIsSynthesized(r.node) {
|
|
return r.file.Text()[scanner.SkipTrivia(r.file.Text(), r.node.Loc.Pos()):r.node.End()]
|
|
} else {
|
|
return fmt.Sprintf(`"%s"`, r.node.Text())
|
|
}
|
|
} else {
|
|
return r.file.Text()[r.ref.Pos():r.ref.End()]
|
|
}
|
|
}
|
|
|
|
func (r *referenceFileLocation) diagnosticAt(message *diagnostics.Message, args ...any) *ast.Diagnostic {
|
|
if r.node != nil {
|
|
return tsoptions.CreateDiagnosticForNodeInSourceFile(r.file, r.node, message, args...)
|
|
} else {
|
|
return ast.NewDiagnostic(r.file, r.ref.TextRange, message, args...)
|
|
}
|
|
}
|
|
|
|
type automaticTypeDirectiveFileData struct {
|
|
typeReference string
|
|
packageId module.PackageId
|
|
}
|
|
|
|
func (r *fileIncludeReason) asIndex() int {
|
|
return r.data.(int)
|
|
}
|
|
|
|
func (r *fileIncludeReason) asLibFileIndex() (int, bool) {
|
|
index, ok := r.data.(int)
|
|
return index, ok
|
|
}
|
|
|
|
func (r *fileIncludeReason) isReferencedFile() bool {
|
|
return r != nil && r.kind <= fileIncludeKindLibReferenceDirective
|
|
}
|
|
|
|
func (r *fileIncludeReason) asReferencedFileData() *referencedFileData {
|
|
return r.data.(*referencedFileData)
|
|
}
|
|
|
|
func (r *fileIncludeReason) asAutomaticTypeDirectiveFileData() *automaticTypeDirectiveFileData {
|
|
return r.data.(*automaticTypeDirectiveFileData)
|
|
}
|
|
|
|
func (r *fileIncludeReason) getReferencedLocation(program *Program) *referenceFileLocation {
|
|
ref := r.asReferencedFileData()
|
|
file := program.GetSourceFileByPath(ref.file)
|
|
switch r.kind {
|
|
case fileIncludeKindImport:
|
|
var specifier *ast.Node
|
|
var isSynthetic bool
|
|
if ref.synthetic != nil {
|
|
specifier = ref.synthetic
|
|
isSynthetic = true
|
|
} else if ref.index < len(file.Imports()) {
|
|
specifier = file.Imports()[ref.index]
|
|
} else {
|
|
augIndex := len(file.Imports())
|
|
for _, imp := range file.ModuleAugmentations {
|
|
if imp.Kind == ast.KindStringLiteral {
|
|
if augIndex == ref.index {
|
|
specifier = imp
|
|
break
|
|
}
|
|
augIndex++
|
|
}
|
|
}
|
|
}
|
|
resolution := program.GetResolvedModuleFromModuleSpecifier(file, specifier)
|
|
return &referenceFileLocation{
|
|
file: file,
|
|
node: specifier,
|
|
packageId: resolution.PackageId,
|
|
isSynthetic: isSynthetic,
|
|
}
|
|
case fileIncludeKindReferenceFile:
|
|
return &referenceFileLocation{
|
|
file: file,
|
|
ref: file.ReferencedFiles[ref.index],
|
|
}
|
|
case fileIncludeKindTypeReferenceDirective:
|
|
return &referenceFileLocation{
|
|
file: file,
|
|
ref: file.TypeReferenceDirectives[ref.index],
|
|
}
|
|
case fileIncludeKindLibReferenceDirective:
|
|
return &referenceFileLocation{
|
|
file: file,
|
|
ref: file.LibReferenceDirectives[ref.index],
|
|
}
|
|
default:
|
|
panic(fmt.Sprintf("unknown reason: %v", r.kind))
|
|
}
|
|
}
|
|
|
|
func (r *fileIncludeReason) toDiagnostic(program *Program, relativeFileName bool) *ast.Diagnostic {
|
|
if relativeFileName {
|
|
r.relativeFileNameDiagOnce.Do(func() {
|
|
r.relativeFileNameDiag = r.computeDiagnostic(program, func(fileName string) string {
|
|
return tspath.GetRelativePathFromDirectory(program.GetCurrentDirectory(), fileName, program.comparePathsOptions)
|
|
})
|
|
})
|
|
return r.relativeFileNameDiag
|
|
} else {
|
|
r.diagOnce.Do(func() {
|
|
r.diag = r.computeDiagnostic(program, func(fileName string) string { return fileName })
|
|
})
|
|
return r.diag
|
|
}
|
|
}
|
|
|
|
func (r *fileIncludeReason) computeDiagnostic(program *Program, toFileName func(string) string) *ast.Diagnostic {
|
|
if r.isReferencedFile() {
|
|
return r.computeReferenceFileDiagnostic(program, toFileName)
|
|
}
|
|
switch r.kind {
|
|
case fileIncludeKindRootFile:
|
|
if program.opts.Config.ConfigFile != nil {
|
|
config := program.opts.Config
|
|
fileName := tspath.GetNormalizedAbsolutePath(config.FileNames()[r.asIndex()], program.GetCurrentDirectory())
|
|
if matchedFileSpec := config.GetMatchedFileSpec(fileName); matchedFileSpec != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Part_of_files_list_in_tsconfig_json, matchedFileSpec, toFileName(fileName))
|
|
} else if matchedIncludeSpec, isDefaultIncludeSpec := config.GetMatchedIncludeSpec(fileName); matchedIncludeSpec != "" {
|
|
if isDefaultIncludeSpec {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Matched_by_default_include_pattern_Asterisk_Asterisk_Slash_Asterisk)
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Matched_by_include_pattern_0_in_1, matchedIncludeSpec, toFileName(config.ConfigName()))
|
|
}
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Root_file_specified_for_compilation)
|
|
}
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Root_file_specified_for_compilation)
|
|
}
|
|
case fileIncludeKindSourceFromProjectReference,
|
|
fileIncludeKindOutputFromProjectReference:
|
|
diag := core.IfElse(
|
|
r.kind == fileIncludeKindOutputFromProjectReference,
|
|
diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none,
|
|
diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none,
|
|
)
|
|
referencedResolvedRef := program.projectReferenceFileMapper.getResolvedProjectReferences()[r.asIndex()]
|
|
return ast.NewCompilerDiagnostic(diag, toFileName(referencedResolvedRef.ConfigName()))
|
|
case fileIncludeKindAutomaticTypeDirectiveFile:
|
|
data := r.asAutomaticTypeDirectiveFileData()
|
|
if program.Options().Types != nil {
|
|
if data.packageId.Name != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1, data.typeReference, data.packageId.String())
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions, data.typeReference)
|
|
}
|
|
} else {
|
|
if data.packageId.Name != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1, data.typeReference, data.packageId.String())
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Entry_point_for_implicit_type_library_0, data.typeReference)
|
|
}
|
|
}
|
|
case fileIncludeKindLibFile:
|
|
if index, ok := r.asLibFileIndex(); ok {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Library_0_specified_in_compilerOptions, program.Options().Lib[index])
|
|
} else if target := program.Options().GetEmitScriptTarget().String(); target != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Default_library_for_target_0, target)
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Default_library)
|
|
}
|
|
default:
|
|
panic(fmt.Sprintf("unknown reason: %v", r.kind))
|
|
}
|
|
}
|
|
|
|
func (r *fileIncludeReason) computeReferenceFileDiagnostic(program *Program, toFileName func(string) string) *ast.Diagnostic {
|
|
referenceLocation := program.includeProcessor.getReferenceLocation(r, program)
|
|
referenceText := referenceLocation.text()
|
|
switch r.kind {
|
|
case fileIncludeKindImport:
|
|
if !referenceLocation.isSynthetic {
|
|
if referenceLocation.packageId.Name != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_with_packageId_2, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
|
|
}
|
|
} else if specifier, ok := program.importHelpersImportSpecifiers[referenceLocation.file.Path()]; ok && specifier == referenceLocation.node {
|
|
if referenceLocation.packageId.Name != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions, referenceText, toFileName(referenceLocation.file.FileName()))
|
|
}
|
|
} else {
|
|
if referenceLocation.packageId.Name != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions, referenceText, toFileName(referenceLocation.file.FileName()))
|
|
}
|
|
}
|
|
case fileIncludeKindReferenceFile:
|
|
return ast.NewCompilerDiagnostic(diagnostics.Referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
|
|
case fileIncludeKindTypeReferenceDirective:
|
|
if referenceLocation.packageId.Name != "" {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String())
|
|
} else {
|
|
return ast.NewCompilerDiagnostic(diagnostics.Type_library_referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
|
|
}
|
|
case fileIncludeKindLibReferenceDirective:
|
|
return ast.NewCompilerDiagnostic(diagnostics.Library_referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName()))
|
|
default:
|
|
panic(fmt.Sprintf("unknown reason: %v", r.kind))
|
|
}
|
|
}
|
|
|
|
func (r *fileIncludeReason) toRelatedInfo(program *Program) *ast.Diagnostic {
|
|
if r.isReferencedFile() {
|
|
return r.computeReferenceFileRelatedInfo(program)
|
|
}
|
|
if program.opts.Config.ConfigFile == nil {
|
|
return nil
|
|
}
|
|
config := program.opts.Config
|
|
switch r.kind {
|
|
case fileIncludeKindRootFile:
|
|
fileName := tspath.GetNormalizedAbsolutePath(config.FileNames()[r.asIndex()], program.GetCurrentDirectory())
|
|
if matchedFileSpec := config.GetMatchedFileSpec(fileName); matchedFileSpec != "" {
|
|
if filesNode := tsoptions.GetTsConfigPropArrayElementValue(config.ConfigFile.SourceFile, "files", matchedFileSpec); filesNode != nil {
|
|
return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, filesNode.AsNode(), diagnostics.File_is_matched_by_files_list_specified_here)
|
|
}
|
|
} else if matchedIncludeSpec, isDefaultIncludeSpec := config.GetMatchedIncludeSpec(fileName); matchedIncludeSpec != "" && !isDefaultIncludeSpec {
|
|
if includeNode := tsoptions.GetTsConfigPropArrayElementValue(config.ConfigFile.SourceFile, "include", matchedIncludeSpec); includeNode != nil {
|
|
return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, includeNode.AsNode(), diagnostics.File_is_matched_by_include_pattern_specified_here)
|
|
}
|
|
}
|
|
case fileIncludeKindSourceFromProjectReference,
|
|
fileIncludeKindOutputFromProjectReference:
|
|
return tsoptions.CreateDiagnosticAtReferenceSyntax(
|
|
config,
|
|
r.asIndex(),
|
|
core.IfElse(
|
|
r.kind == fileIncludeKindOutputFromProjectReference,
|
|
diagnostics.File_is_output_from_referenced_project_specified_here,
|
|
diagnostics.File_is_source_from_referenced_project_specified_here,
|
|
))
|
|
case fileIncludeKindAutomaticTypeDirectiveFile:
|
|
if program.Options().Types != nil {
|
|
data := r.asAutomaticTypeDirectiveFileData()
|
|
if typesSyntax := tsoptions.GetOptionsSyntaxByArrayElementValue(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "types", data.typeReference); typesSyntax != nil {
|
|
return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, typesSyntax.AsNode(), diagnostics.File_is_entry_point_of_type_library_specified_here)
|
|
}
|
|
}
|
|
case fileIncludeKindLibFile:
|
|
if index, ok := r.asLibFileIndex(); ok {
|
|
if libSyntax := tsoptions.GetOptionsSyntaxByArrayElementValue(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "lib", program.Options().Lib[index]); libSyntax != nil {
|
|
return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, libSyntax.AsNode(), diagnostics.File_is_library_specified_here)
|
|
}
|
|
} else if target := program.Options().GetEmitScriptTarget().String(); target != "" {
|
|
if targetValueSyntax := tsoptions.ForEachPropertyAssignment(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "target", tsoptions.GetCallbackForFindingPropertyAssignmentByValue(target)); targetValueSyntax != nil {
|
|
return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, targetValueSyntax.AsNode(), diagnostics.File_is_default_library_for_target_specified_here)
|
|
}
|
|
}
|
|
default:
|
|
panic(fmt.Sprintf("unknown reason: %v", r.kind))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *fileIncludeReason) computeReferenceFileRelatedInfo(program *Program) *ast.Diagnostic {
|
|
referenceLocation := program.includeProcessor.getReferenceLocation(r, program)
|
|
if referenceLocation.isSynthetic {
|
|
return nil
|
|
}
|
|
switch r.kind {
|
|
case fileIncludeKindImport:
|
|
return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_import_here)
|
|
case fileIncludeKindReferenceFile:
|
|
return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_reference_here)
|
|
case fileIncludeKindTypeReferenceDirective:
|
|
return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_type_library_reference_here)
|
|
case fileIncludeKindLibReferenceDirective:
|
|
return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_library_reference_here)
|
|
default:
|
|
panic(fmt.Sprintf("unknown reason: %v", r.kind))
|
|
}
|
|
}
|