|
| 1 | +package compiler |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "sync" |
| 6 | + |
| 7 | + "github.com/microsoft/typescript-go/internal/ast" |
| 8 | + "github.com/microsoft/typescript-go/internal/core" |
| 9 | + "github.com/microsoft/typescript-go/internal/diagnostics" |
| 10 | + "github.com/microsoft/typescript-go/internal/module" |
| 11 | + "github.com/microsoft/typescript-go/internal/tsoptions" |
| 12 | + "github.com/microsoft/typescript-go/internal/tspath" |
| 13 | +) |
| 14 | + |
| 15 | +type fileIncludeKind int |
| 16 | + |
| 17 | +const ( |
| 18 | + // References from file |
| 19 | + fileIncludeKindImport = iota |
| 20 | + fileIncludeKindReferenceFile |
| 21 | + fileIncludeKindTypeReferenceDirective |
| 22 | + fileIncludeKindLibReferenceDirective |
| 23 | + |
| 24 | + fileIncludeKindRootFile |
| 25 | + fileIncludeKindSourceFromProjectReference |
| 26 | + fileIncludeKindOutputFromProjectReference |
| 27 | + fileIncludeKindLibFile |
| 28 | + fileIncludeKindAutomaticTypeDirectiveFile |
| 29 | +) |
| 30 | + |
| 31 | +type fileIncludeReason struct { |
| 32 | + kind fileIncludeKind |
| 33 | + data any |
| 34 | + |
| 35 | + // Uses relative file name |
| 36 | + relativeFileNameDiag *ast.Diagnostic |
| 37 | + relativeFileNameDiagOnce sync.Once |
| 38 | + |
| 39 | + // Uses file name as is |
| 40 | + diag *ast.Diagnostic |
| 41 | + diagOnce sync.Once |
| 42 | +} |
| 43 | + |
| 44 | +type referencedFileData struct { |
| 45 | + file tspath.Path |
| 46 | + index int |
| 47 | + synthetic *ast.Node |
| 48 | +} |
| 49 | + |
| 50 | +type referenceFileLocation struct { |
| 51 | + file *ast.SourceFile |
| 52 | + node *ast.Node |
| 53 | + ref *ast.FileReference |
| 54 | + packageId module.PackageId |
| 55 | + isSynthetic bool |
| 56 | +} |
| 57 | + |
| 58 | +func (r *referenceFileLocation) text() string { |
| 59 | + if r.node != nil { |
| 60 | + return r.node.Text() |
| 61 | + } else { |
| 62 | + return r.file.Text()[r.ref.Pos():r.ref.End()] |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +func (r *referenceFileLocation) diagnosticAt(message *diagnostics.Message, args ...any) *ast.Diagnostic { |
| 67 | + if r.node != nil { |
| 68 | + return tsoptions.CreateDiagnosticForNodeInSourceFile(r.file, r.node, message, args...) |
| 69 | + } else { |
| 70 | + return ast.NewDiagnostic(r.file, r.ref.TextRange, message, args...) |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +type automaticTypeDirectiveFileData struct { |
| 75 | + typeReference string |
| 76 | + packageId module.PackageId |
| 77 | +} |
| 78 | + |
| 79 | +func (r *fileIncludeReason) asIndex() int { |
| 80 | + return r.data.(int) |
| 81 | +} |
| 82 | + |
| 83 | +func (r *fileIncludeReason) asLibFileIndex() (int, bool) { |
| 84 | + index, ok := r.data.(int) |
| 85 | + return index, ok |
| 86 | +} |
| 87 | + |
| 88 | +func (r *fileIncludeReason) isReferencedFile() bool { |
| 89 | + return r != nil && r.kind <= fileIncludeKindLibReferenceDirective |
| 90 | +} |
| 91 | + |
| 92 | +func (r *fileIncludeReason) asReferencedFileData() *referencedFileData { |
| 93 | + return r.data.(*referencedFileData) |
| 94 | +} |
| 95 | + |
| 96 | +func (r *fileIncludeReason) asAutomaticTypeDirectiveFileData() *automaticTypeDirectiveFileData { |
| 97 | + return r.data.(*automaticTypeDirectiveFileData) |
| 98 | +} |
| 99 | + |
| 100 | +func (r *fileIncludeReason) getReferencedLocation(program *Program) *referenceFileLocation { |
| 101 | + ref := r.asReferencedFileData() |
| 102 | + file := program.GetSourceFileByPath(ref.file) |
| 103 | + switch r.kind { |
| 104 | + case fileIncludeKindImport: |
| 105 | + var specifier *ast.Node |
| 106 | + var isSynthetic bool |
| 107 | + if ref.synthetic != nil { |
| 108 | + specifier = ref.synthetic |
| 109 | + isSynthetic = true |
| 110 | + } else if ref.index < len(file.Imports()) { |
| 111 | + specifier = file.Imports()[ref.index] |
| 112 | + } else { |
| 113 | + augIndex := len(file.Imports()) |
| 114 | + for _, imp := range file.ModuleAugmentations { |
| 115 | + if imp.Kind == ast.KindStringLiteral { |
| 116 | + if augIndex == ref.index { |
| 117 | + specifier = imp |
| 118 | + break |
| 119 | + } |
| 120 | + augIndex++ |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + resolution := program.GetResolvedModuleFromModuleSpecifier(file, specifier) |
| 125 | + return &referenceFileLocation{ |
| 126 | + file: file, |
| 127 | + node: specifier, |
| 128 | + packageId: resolution.PackageId, |
| 129 | + isSynthetic: isSynthetic, |
| 130 | + } |
| 131 | + case fileIncludeKindReferenceFile: |
| 132 | + return &referenceFileLocation{ |
| 133 | + file: file, |
| 134 | + ref: file.ReferencedFiles[ref.index], |
| 135 | + } |
| 136 | + case fileIncludeKindTypeReferenceDirective: |
| 137 | + return &referenceFileLocation{ |
| 138 | + file: file, |
| 139 | + ref: file.TypeReferenceDirectives[ref.index], |
| 140 | + } |
| 141 | + case fileIncludeKindLibReferenceDirective: |
| 142 | + return &referenceFileLocation{ |
| 143 | + file: file, |
| 144 | + ref: file.LibReferenceDirectives[ref.index], |
| 145 | + } |
| 146 | + default: |
| 147 | + panic(fmt.Sprintf("unknown reason: %v", r.kind)) |
| 148 | + } |
| 149 | +} |
| 150 | + |
| 151 | +func (r *fileIncludeReason) toDiagnostic(program *Program, relativeFileName bool) *ast.Diagnostic { |
| 152 | + if relativeFileName { |
| 153 | + r.relativeFileNameDiagOnce.Do(func() { |
| 154 | + r.relativeFileNameDiag = r.computeDiagnostic(program, func(fileName string) string { |
| 155 | + return tspath.GetRelativePathFromDirectory(program.GetCurrentDirectory(), fileName, program.comparePathsOptions) |
| 156 | + }) |
| 157 | + }) |
| 158 | + return r.relativeFileNameDiag |
| 159 | + } else { |
| 160 | + r.diagOnce.Do(func() { |
| 161 | + r.diag = r.computeDiagnostic(program, func(fileName string) string { return fileName }) |
| 162 | + }) |
| 163 | + return r.diag |
| 164 | + } |
| 165 | +} |
| 166 | + |
| 167 | +func (r *fileIncludeReason) computeDiagnostic(program *Program, toFileName func(string) string) *ast.Diagnostic { |
| 168 | + if r.isReferencedFile() { |
| 169 | + return r.computeReferenceFileDiagnostic(program, toFileName) |
| 170 | + } |
| 171 | + switch r.kind { |
| 172 | + case fileIncludeKindRootFile: |
| 173 | + if program.opts.Config.ConfigFile != nil { |
| 174 | + config := program.opts.Config |
| 175 | + fileName := tspath.GetNormalizedAbsolutePath(config.FileNames()[r.asIndex()], program.GetCurrentDirectory()) |
| 176 | + if matchedFileSpec := config.GetMatchedFileSpec(fileName); matchedFileSpec != "" { |
| 177 | + return ast.NewCompilerDiagnostic(diagnostics.Part_of_files_list_in_tsconfig_json, matchedFileSpec, toFileName(fileName)) |
| 178 | + } else if matchedIncludeSpec, isDefaultIncludeSpec := config.GetMatchedIncludeSpec(fileName); matchedIncludeSpec != "" { |
| 179 | + if isDefaultIncludeSpec { |
| 180 | + return ast.NewCompilerDiagnostic(diagnostics.Matched_by_default_include_pattern_Asterisk_Asterisk_Slash_Asterisk) |
| 181 | + } else { |
| 182 | + return ast.NewCompilerDiagnostic(diagnostics.Matched_by_include_pattern_0_in_1, matchedIncludeSpec, toFileName(config.ConfigName())) |
| 183 | + } |
| 184 | + } else { |
| 185 | + return ast.NewCompilerDiagnostic(diagnostics.Root_file_specified_for_compilation) |
| 186 | + } |
| 187 | + } else { |
| 188 | + return ast.NewCompilerDiagnostic(diagnostics.Root_file_specified_for_compilation) |
| 189 | + } |
| 190 | + case fileIncludeKindSourceFromProjectReference, |
| 191 | + fileIncludeKindOutputFromProjectReference: |
| 192 | + diag := core.IfElse( |
| 193 | + r.kind == fileIncludeKindOutputFromProjectReference, |
| 194 | + diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none, |
| 195 | + diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none, |
| 196 | + ) |
| 197 | + referencedResolvedRef := program.projectReferenceFileMapper.getResolvedProjectReferences()[r.asIndex()] |
| 198 | + return ast.NewCompilerDiagnostic(diag, toFileName(referencedResolvedRef.ConfigName())) |
| 199 | + case fileIncludeKindAutomaticTypeDirectiveFile: |
| 200 | + data := r.asAutomaticTypeDirectiveFileData() |
| 201 | + if program.Options().Types != nil { |
| 202 | + if data.packageId.Name != "" { |
| 203 | + return ast.NewCompilerDiagnostic(diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1, data.typeReference, data.packageId.String()) |
| 204 | + } else { |
| 205 | + return ast.NewCompilerDiagnostic(diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions, data.typeReference) |
| 206 | + } |
| 207 | + } else { |
| 208 | + if data.packageId.Name != "" { |
| 209 | + return ast.NewCompilerDiagnostic(diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1, data.typeReference, data.packageId.String()) |
| 210 | + } else { |
| 211 | + return ast.NewCompilerDiagnostic(diagnostics.Entry_point_for_implicit_type_library_0, data.typeReference) |
| 212 | + } |
| 213 | + } |
| 214 | + case fileIncludeKindLibFile: |
| 215 | + if index, ok := r.asLibFileIndex(); ok { |
| 216 | + return ast.NewCompilerDiagnostic(diagnostics.Library_0_specified_in_compilerOptions, program.Options().Lib[index]) |
| 217 | + } else if target := program.Options().GetEmitScriptTarget().String(); target != "" { |
| 218 | + return ast.NewCompilerDiagnostic(diagnostics.Default_library_for_target_0, target) |
| 219 | + } else { |
| 220 | + return ast.NewCompilerDiagnostic(diagnostics.Default_library) |
| 221 | + } |
| 222 | + default: |
| 223 | + panic(fmt.Sprintf("unknown reason: %v", r.kind)) |
| 224 | + } |
| 225 | +} |
| 226 | + |
| 227 | +func (r *fileIncludeReason) computeReferenceFileDiagnostic(program *Program, toFileName func(string) string) *ast.Diagnostic { |
| 228 | + referenceLocation := program.includeProcessor.getReferenceLocation(r, program) |
| 229 | + referenceText := referenceLocation.text() |
| 230 | + switch r.kind { |
| 231 | + case fileIncludeKindImport: |
| 232 | + if !referenceLocation.isSynthetic { |
| 233 | + if referenceLocation.packageId.Name != "" { |
| 234 | + return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_with_packageId_2, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String()) |
| 235 | + } else { |
| 236 | + return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName())) |
| 237 | + } |
| 238 | + } else if specifier, ok := program.importHelpersImportSpecifiers[referenceLocation.file.Path()]; ok && specifier == referenceLocation.node { |
| 239 | + if referenceLocation.packageId.Name != "" { |
| 240 | + 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()) |
| 241 | + } else { |
| 242 | + return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions, referenceText, toFileName(referenceLocation.file.FileName())) |
| 243 | + } |
| 244 | + } else { |
| 245 | + if referenceLocation.packageId.Name != "" { |
| 246 | + 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()) |
| 247 | + } else { |
| 248 | + return ast.NewCompilerDiagnostic(diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions, referenceText, toFileName(referenceLocation.file.FileName())) |
| 249 | + } |
| 250 | + } |
| 251 | + case fileIncludeKindReferenceFile: |
| 252 | + return ast.NewCompilerDiagnostic(diagnostics.Referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName())) |
| 253 | + case fileIncludeKindTypeReferenceDirective: |
| 254 | + if referenceLocation.packageId.Name != "" { |
| 255 | + return ast.NewCompilerDiagnostic(diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2, referenceText, toFileName(referenceLocation.file.FileName()), referenceLocation.packageId.String()) |
| 256 | + } else { |
| 257 | + return ast.NewCompilerDiagnostic(diagnostics.Type_library_referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName())) |
| 258 | + } |
| 259 | + case fileIncludeKindLibReferenceDirective: |
| 260 | + return ast.NewCompilerDiagnostic(diagnostics.Library_referenced_via_0_from_file_1, referenceText, toFileName(referenceLocation.file.FileName())) |
| 261 | + default: |
| 262 | + panic(fmt.Sprintf("unknown reason: %v", r.kind)) |
| 263 | + } |
| 264 | +} |
| 265 | + |
| 266 | +func (r *fileIncludeReason) toRelatedInfo(program *Program) *ast.Diagnostic { |
| 267 | + if r.isReferencedFile() { |
| 268 | + return r.computeReferenceFileRelatedInfo(program) |
| 269 | + } |
| 270 | + if program.opts.Config.ConfigFile == nil { |
| 271 | + return nil |
| 272 | + } |
| 273 | + config := program.opts.Config |
| 274 | + switch r.kind { |
| 275 | + case fileIncludeKindRootFile: |
| 276 | + fileName := tspath.GetNormalizedAbsolutePath(config.FileNames()[r.asIndex()], program.GetCurrentDirectory()) |
| 277 | + if matchedFileSpec := config.GetMatchedFileSpec(fileName); matchedFileSpec != "" { |
| 278 | + if filesNode := tsoptions.GetTsConfigPropArrayElementValue(config.ConfigFile.SourceFile, "files", matchedFileSpec); filesNode != nil { |
| 279 | + return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, filesNode.AsNode(), diagnostics.File_is_matched_by_files_list_specified_here) |
| 280 | + } |
| 281 | + } else if matchedIncludeSpec, isDefaultIncludeSpec := config.GetMatchedIncludeSpec(fileName); matchedIncludeSpec != "" && !isDefaultIncludeSpec { |
| 282 | + if includeNode := tsoptions.GetTsConfigPropArrayElementValue(config.ConfigFile.SourceFile, "include", matchedIncludeSpec); includeNode != nil { |
| 283 | + return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, includeNode.AsNode(), diagnostics.File_is_matched_by_include_pattern_specified_here) |
| 284 | + } |
| 285 | + } |
| 286 | + case fileIncludeKindSourceFromProjectReference, |
| 287 | + fileIncludeKindOutputFromProjectReference: |
| 288 | + return tsoptions.CreateDiagnosticAtReferenceSyntax( |
| 289 | + config, |
| 290 | + r.asIndex(), |
| 291 | + core.IfElse( |
| 292 | + r.kind == fileIncludeKindOutputFromProjectReference, |
| 293 | + diagnostics.File_is_output_from_referenced_project_specified_here, |
| 294 | + diagnostics.File_is_source_from_referenced_project_specified_here, |
| 295 | + )) |
| 296 | + case fileIncludeKindAutomaticTypeDirectiveFile: |
| 297 | + if program.Options().Types != nil { |
| 298 | + data := r.asAutomaticTypeDirectiveFileData() |
| 299 | + if typesSyntax := tsoptions.GetOptionsSyntaxByArrayElementValue(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "types", data.typeReference); typesSyntax != nil { |
| 300 | + return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, typesSyntax.AsNode(), diagnostics.File_is_entry_point_of_type_library_specified_here) |
| 301 | + } |
| 302 | + } |
| 303 | + case fileIncludeKindLibFile: |
| 304 | + if index, ok := r.asLibFileIndex(); ok { |
| 305 | + if libSyntax := tsoptions.GetOptionsSyntaxByArrayElementValue(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "lib", program.Options().Lib[index]); libSyntax != nil { |
| 306 | + return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, libSyntax.AsNode(), diagnostics.File_is_library_specified_here) |
| 307 | + } |
| 308 | + } else if target := program.Options().GetEmitScriptTarget().String(); target != "" { |
| 309 | + if targetValueSyntax := tsoptions.ForEachPropertyAssignment(program.includeProcessor.getCompilerOptionsObjectLiteralSyntax(program), "target", tsoptions.GetCallbackForFindingPropertyAssignmentByValue(target)); targetValueSyntax != nil { |
| 310 | + return tsoptions.CreateDiagnosticForNodeInSourceFile(config.ConfigFile.SourceFile, targetValueSyntax.AsNode(), diagnostics.File_is_default_library_for_target_specified_here) |
| 311 | + } |
| 312 | + } |
| 313 | + default: |
| 314 | + panic(fmt.Sprintf("unknown reason: %v", r.kind)) |
| 315 | + } |
| 316 | + return nil |
| 317 | +} |
| 318 | + |
| 319 | +func (r *fileIncludeReason) computeReferenceFileRelatedInfo(program *Program) *ast.Diagnostic { |
| 320 | + referenceLocation := program.includeProcessor.getReferenceLocation(r, program) |
| 321 | + if referenceLocation.isSynthetic { |
| 322 | + return nil |
| 323 | + } |
| 324 | + switch r.kind { |
| 325 | + case fileIncludeKindImport: |
| 326 | + return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_import_here) |
| 327 | + case fileIncludeKindReferenceFile: |
| 328 | + return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_reference_here) |
| 329 | + case fileIncludeKindTypeReferenceDirective: |
| 330 | + return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_type_library_reference_here) |
| 331 | + case fileIncludeKindLibReferenceDirective: |
| 332 | + return referenceLocation.diagnosticAt(diagnostics.File_is_included_via_library_reference_here) |
| 333 | + default: |
| 334 | + panic(fmt.Sprintf("unknown reason: %v", r.kind)) |
| 335 | + } |
| 336 | +} |
0 commit comments