// This may return "parseErrorAlreadyLogged" in which case there was a syntax
// error, but it's already been reported. No further errors should be logged.
//
// Nested calls may also return "parseErrorImportCycle". In that case the
// caller is responsible for logging an appropriate error message.
This may return "parseErrorAlreadyLogged" in which case there was a syntax
error, but it's already been reported. No further errors should be logged.

Nested calls may also return "parseErrorImportCycle". In that case the
caller is responsible for logging an appropriate error message.
// This may return " parseErrorAlreadyLogged " in which case there was a syntax // error but it ' s already been reported . No further errors should be logged . // // Nested calls may also return " parseErrorImportCycle " . In that case the // caller is responsible for logging an appropriate error message .
func (r resolverQuery) parseTSConfig(file string, visited map[string]bool) (*TSConfigJSON, error) {
	if visited[file] {
		return nil, errParseErrorImportCycle
	}
	visited[file] = true
	contents, err, originalError := r.caches.FSCache.ReadFile(r.fs, file)
	if r.debugLogs != nil && originalError != nil {
		r.debugLogs.addNote(fmt.Sprintf("Failed to read file %q: %s", file, originalError.Error()))
	}
	if err != nil {
		return nil, err
	}
	if r.debugLogs != nil {
		r.debugLogs.addNote(fmt.Sprintf("The file %q exists", file))
	}
	keyPath := logger.Path{Text: file, Namespace: "file"}
	source := logger.Source{
		KeyPath:    keyPath,
		PrettyPath: r.PrettyPath(keyPath),
		Contents:   contents,
	}
	fileDir := r.fs.Dir(file)
	result := ParseTSConfigJSON(r.log, source, &r.caches.JSONCache, func(extends string, extendsRange logger.Range) *TSConfigJSON {
		if IsPackagePath(extends) {
			current := fileDir
			for {
				if r.fs.Base(current) != "node_modules" {
					join := r.fs.Join(current, "node_modules", extends)
					filesToCheck := []string{r.fs.Join(join, "tsconfig.json"), join, join + ".json"}
					for _, fileToCheck := range filesToCheck {
						base, err := r.parseTSConfig(fileToCheck, visited)
						if err == nil {
							return base
						} else if err == syscall.ENOENT {
							continue
						} else if err == errParseErrorImportCycle {
							r.log.AddRangeWarning(&source, extendsRange,
								fmt.Sprintf("Base config file %q forms cycle", extends))
						} else if err != errParseErrorAlreadyLogged {
							r.log.AddRangeError(&source, extendsRange,
								fmt.Sprintf("Cannot read file %q: %s",
									r.PrettyPath(logger.Path{Text: fileToCheck, Namespace: "file"}), err.Error()))
						}
						return nil
					}
				}
				next := r.fs.Dir(current)
				if current == next {
					break
				}
				current = next
			}
		} else {
			extendsFile := extends
			if !r.fs.IsAbs(extends) {
				extendsFile = r.fs.Join(fileDir, extends)
			}
			for _, fileToCheck := range []string{extendsFile, extendsFile + ".json"} {
				base, err := r.parseTSConfig(fileToCheck, visited)
				if err == nil {
					return base
				} else if err == syscall.ENOENT {
					continue
				} else if err == errParseErrorImportCycle {
					r.log.AddRangeWarning(&source, extendsRange,
						fmt.Sprintf("Base config file %q forms cycle", extends))
				} else if err != errParseErrorAlreadyLogged {
					r.log.AddRangeError(&source, extendsRange,
						fmt.Sprintf("Cannot read file %q: %s",
							r.PrettyPath(logger.Path{Text: fileToCheck, Namespace: "file"}), err.Error()))
				}
				return nil
			}
		}
		if !IsInsideNodeModules(file) {
			r.log.AddRangeWarning(&source, extendsRange,
				fmt.Sprintf("Cannot find base config file %q", extends))
		}
		return nil
	})
	if result == nil {
		return nil, errParseErrorAlreadyLogged
	}
	if result.BaseURL != nil && !r.fs.IsAbs(*result.BaseURL) {
		*result.BaseURL = r.fs.Join(fileDir, *result.BaseURL)
	}
	if result.Paths != nil && !r.fs.IsAbs(result.BaseURLForPaths) {
		result.BaseURLForPaths = r.fs.Join(fileDir, result.BaseURLForPaths)
	}
	return result, nil
}
func ( r resolverQuery ) parseTSConfig ( file string , visited map [ string ] bool ) ( * TSConfigJSON , error ) { if visited [ file ] { return nil , errParseErrorImportCycle } visited [ file ] = true contents , err , originalError := r . caches . FSCache . ReadFile ( r . fs , file ) if r . debugLogs != nil && originalError != nil { r . debugLogs . addNote ( fmt . Sprintf ( " " , file , originalError . Error ( ) ) ) } if err != nil { return nil , err } if r . debugLogs != nil { r . debugLogs . addNote ( fmt . Sprintf ( " " , file ) ) } keyPath := logger . Path { Text : file , Namespace : " " } source := logger . Source { KeyPath : keyPath , PrettyPath : r . PrettyPath ( keyPath ) , Contents : contents , } fileDir := r . fs . Dir ( file ) result := ParseTSConfigJSON ( r . log , source , & r . caches . JSONCache , func ( extends string , extendsRange logger . Range ) * TSConfigJSON { if IsPackagePath ( extends ) { current := fileDir for { if r . fs . Base ( current ) != " " { join := r . fs . Join ( current , " " , extends ) filesToCheck := [ ] string { r . fs . Join ( join , " " ) , join , join + " " } for _ , fileToCheck := range filesToCheck { base , err := r . parseTSConfig ( fileToCheck , visited ) if err == nil { return base } else if err == syscall . ENOENT { continue } else if err == errParseErrorImportCycle { r . log . AddRangeWarning ( & source , extendsRange , fmt . Sprintf ( " " , extends ) ) } else if err != errParseErrorAlreadyLogged { r . log . AddRangeError ( & source , extendsRange , fmt . Sprintf ( " " , r . PrettyPath ( logger . Path { Text : fileToCheck , Namespace : " " } ) , err . Error ( ) ) ) } return nil } } next := r . fs . Dir ( current ) if current == next { break } current = next } } else { extendsFile := extends if ! r . fs . IsAbs ( extends ) { extendsFile = r . fs . Join ( fileDir , extends ) } for _ , fileToCheck := range [ ] string { extendsFile , extendsFile + " " } { base , err := r . parseTSConfig ( fileToCheck , visited ) if err == nil { return base } else if err == syscall . ENOENT { continue } else if err == errParseErrorImportCycle { r . log . AddRangeWarning ( & source , extendsRange , fmt . Sprintf ( " " , extends ) ) } else if err != errParseErrorAlreadyLogged { r . log . AddRangeError ( & source , extendsRange , fmt . Sprintf ( " " , r . PrettyPath ( logger . Path { Text : fileToCheck , Namespace : " " } ) , err . Error ( ) ) ) } return nil } } if ! IsInsideNodeModules ( file ) { r . log . AddRangeWarning ( & source , extendsRange , fmt . Sprintf ( " " , extends ) ) } return nil } ) if result == nil { return nil , errParseErrorAlreadyLogged } if result . BaseURL != nil && ! r . fs . IsAbs ( * result . BaseURL ) { * result . BaseURL = r . fs . Join ( fileDir , * result . BaseURL ) } if result . Paths != nil && ! r . fs . IsAbs ( result . BaseURLForPaths ) { result . BaseURLForPaths = r . fs . Join ( fileDir , result . BaseURLForPaths ) } return result , nil }
This may return "parseErrorAlreadyLogged" in which case there was a syntax
error, but it's already been reported.
This may return " parseErrorAlreadyLogged " in which case there was a syntax error but it ' s already been reported .
// Don't infinite loop if a series of "extends" links forms a cycle // If this is a package path, try to resolve it to a "node_modules" // folder. This doesn't use the normal node module resolution algorithm // both because it's different (e.g. we don't want to match a directory) // and because it would deadlock since we're currently in the middle of // populating the directory info cache. // Skip "node_modules" folders // Go to the parent directory, stopping at the file system root // If this is a regular path, search relative to the enclosing directory // Suppress warnings about missing base config files inside "node_modules"