Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -10374,10 +10374,6 @@ func (node *SourceFile) Path() tspath.Path {
return node.parseOptions.Path
}

func (node *SourceFile) OriginalFileName() string {
return node.FileName() // !!! redirect source files
}

func (node *SourceFile) Imports() []*LiteralLikeNode {
return node.imports
}
Expand Down
4 changes: 4 additions & 0 deletions internal/compiler/emitHost.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ func (host *emitHost) GetPackageJsonInfo(pkgJsonPath string) modulespecifiers.Pa
return host.program.GetPackageJsonInfo(pkgJsonPath)
}

func (host *emitHost) GetSourceOfProjectReferenceIfOutputIncluded(file ast.HasFileName) string {
return host.program.GetSourceOfProjectReferenceIfOutputIncluded(file)
}

func (host *emitHost) GetOutputAndProjectReference(path tspath.Path) *tsoptions.OutputDtsAndProjectReference {
return host.program.GetOutputAndProjectReference(path)
}
Expand Down
336 changes: 336 additions & 0 deletions internal/compiler/fileInclude.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
package compiler

import (
"fmt"
"sync"

"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/diagnostics"
"github.com/microsoft/typescript-go/internal/module"
"github.com/microsoft/typescript-go/internal/tsoptions"
"github.com/microsoft/typescript-go/internal/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 {
return 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))
}
}
Loading
Loading