// This closely follows the behavior of "tryLoadModuleUsingPaths()" in the
// official TypeScript compiler
This closely follows the behavior of "tryLoadModuleUsingPaths()" in the
official TypeScript compiler
// This closely follows the behavior of " tryLoadModuleUsingPaths () " in the // official TypeScript compiler
func (r resolverQuery) matchTSConfigPaths(tsConfigJSON *TSConfigJSON, path string, kind ast.ImportKind) (PathPair, bool, *fs.DifferentCase) {
	if r.debugLogs != nil {
		r.debugLogs.addNote(fmt.Sprintf("Matching %q against \"paths\" in %q", path, tsConfigJSON.AbsPath))
	}
	absBaseURL := tsConfigJSON.BaseURLForPaths
	if tsConfigJSON.BaseURL != nil {
		absBaseURL = *tsConfigJSON.BaseURL
	}
	if r.debugLogs != nil {
		r.debugLogs.addNote(fmt.Sprintf("Using %q as \"baseURL\"", absBaseURL))
	}
	for key, originalPaths := range tsConfigJSON.Paths {
		if key == path {
			if r.debugLogs != nil {
				r.debugLogs.addNote(fmt.Sprintf("Found an exact match for %q in \"paths\"", key))
			}
			for _, originalPath := range originalPaths {
				absoluteOriginalPath := originalPath
				if !r.fs.IsAbs(originalPath) {
					absoluteOriginalPath = r.fs.Join(absBaseURL, originalPath)
				}
				if absolute, ok, diffCase := r.loadAsFileOrDirectory(absoluteOriginalPath, kind); ok {
					return absolute, true, diffCase
				}
			}
			return PathPair{}, false, nil
		}
	}
	type match struct {
		prefix        string
		suffix        string
		originalPaths []string
	}
	longestMatchPrefixLength := -1
	longestMatchSuffixLength := -1
	var longestMatch match
	for key, originalPaths := range tsConfigJSON.Paths {
		if starIndex := strings.IndexByte(key, '*'); starIndex != -1 {
			prefix, suffix := key[:starIndex], key[starIndex+1:]
			if strings.HasPrefix(path, prefix) && strings.HasSuffix(path, suffix) && (len(prefix) > longestMatchPrefixLength ||
				(len(prefix) == longestMatchPrefixLength && len(suffix) > longestMatchSuffixLength)) {
				longestMatchPrefixLength = len(prefix)
				longestMatchSuffixLength = len(suffix)
				longestMatch = match{
					prefix:        prefix,
					suffix:        suffix,
					originalPaths: originalPaths,
				}
			}
		}
	}
	if longestMatchPrefixLength != -1 {
		if r.debugLogs != nil {
			r.debugLogs.addNote(fmt.Sprintf("Found a fuzzy match for %q in \"paths\"", longestMatch.prefix+"*"+longestMatch.suffix))
		}
		for _, originalPath := range longestMatch.originalPaths {
			matchedText := path[len(longestMatch.prefix) : len(path)-len(longestMatch.suffix)]
			originalPath = strings.Replace(originalPath, "*", matchedText, 1)
			absoluteOriginalPath := originalPath
			if !r.fs.IsAbs(originalPath) {
				absoluteOriginalPath = r.fs.Join(absBaseURL, originalPath)
			}
			if absolute, ok, diffCase := r.loadAsFileOrDirectory(absoluteOriginalPath, kind); ok {
				return absolute, true, diffCase
			}
		}
	}
	return PathPair{}, false, nil
}
func ( r resolverQuery ) matchTSConfigPaths ( tsConfigJSON * TSConfigJSON , path string , kind ast . ImportKind ) ( PathPair , bool , * fs . DifferentCase ) { if r . debugLogs != nil { r . debugLogs . addNote ( fmt . Sprintf ( " \" \" " , path , tsConfigJSON . AbsPath ) ) } absBaseURL := tsConfigJSON . BaseURLForPaths if tsConfigJSON . BaseURL != nil { absBaseURL = * tsConfigJSON . BaseURL } if r . debugLogs != nil { r . debugLogs . addNote ( fmt . Sprintf ( " \" \" " , absBaseURL ) ) } for key , originalPaths := range tsConfigJSON . Paths { if key == path { if r . debugLogs != nil { r . debugLogs . addNote ( fmt . Sprintf ( " \" \" " , key ) ) } for _ , originalPath := range originalPaths { absoluteOriginalPath := originalPath if ! r . fs . IsAbs ( originalPath ) { absoluteOriginalPath = r . fs . Join ( absBaseURL , originalPath ) } if absolute , ok , diffCase := r . loadAsFileOrDirectory ( absoluteOriginalPath , kind ) ; ok { return absolute , true , diffCase } } return PathPair { } , false , nil } } type match struct { prefix string suffix string originalPaths [ ] string } longestMatchPrefixLength := - 1 longestMatchSuffixLength := - 1 var longestMatch match for key , originalPaths := range tsConfigJSON . Paths { if starIndex := strings . IndexByte ( key , '*' ) ; starIndex != - 1 { prefix , suffix := key [ : starIndex ] , key [ starIndex + 1 : ] if strings . HasPrefix ( path , prefix ) && strings . HasSuffix ( path , suffix ) && ( len ( prefix ) > longestMatchPrefixLength || ( len ( prefix ) == longestMatchPrefixLength && len ( suffix ) > longestMatchSuffixLength ) ) { longestMatchPrefixLength = len ( prefix ) longestMatchSuffixLength = len ( suffix ) longestMatch = match { prefix : prefix , suffix : suffix , originalPaths : originalPaths , } } } } if longestMatchPrefixLength != - 1 { if r . debugLogs != nil { r . debugLogs . addNote ( fmt . Sprintf ( " \" \" " , longestMatch . prefix + " " + longestMatch . suffix ) ) } for _ , originalPath := range longestMatch . originalPaths { matchedText := path [ len ( longestMatch . prefix ) : len ( path ) - len ( longestMatch . suffix ) ] originalPath = strings . Replace ( originalPath , " " , matchedText , 1 ) absoluteOriginalPath := originalPath if ! r . fs . IsAbs ( originalPath ) { absoluteOriginalPath = r . fs . Join ( absBaseURL , originalPath ) } if absolute , ok , diffCase := r . loadAsFileOrDirectory ( absoluteOriginalPath , kind ) ; ok { return absolute , true , diffCase } } } return PathPair { } , false , nil }
This closely follows the behavior of "tryLoadModuleUsingPaths()" in the
official TypeScript compiler
This closely follows the behavior of " tryLoadModuleUsingPaths () " in the official TypeScript compiler
// The explicit base URL should take precedence over the implicit base URL // if present. This matters when a tsconfig.json file overrides "baseUrl" // from another extended tsconfig.json file but doesn't override "paths". // Check for exact matches first // Load the original path relative to the "baseUrl" from tsconfig.json // Check for pattern matches next // Find the match with the longest prefix. If two matches have the same // prefix length, pick the one with the longest suffix. This second edge // case isn't handled by the TypeScript compiler, but we handle it // because we want the output to always be deterministic and Go map // iteration order is deliberately non-deterministic. // If there is at least one match, only consider the one with the longest // prefix. This matches the behavior of the TypeScript compiler. // Swap out the "*" in the original path for whatever the "*" matched // Load the original path relative to the "baseUrl" from tsconfig.json