Repository: evanw/esbuild
File: internal/resolver/resolver.go (Go)

Code before:
		return *dirInfo.packageJson.absPathMain, true
	}

	// Return the "index.js" file
	if dirInfo.absPathIndex != nil {
		return *dirInfo.absPathIndex, true
	}

	return "", false
}

func resolvePathWithoutStar(from, path string) (string, error) {
	replaced := strings.Replace(path, "/*", "", -1)
	return fp.Join(from, replaced), nil
}

func (r *resolver) loadNodeModules(path string, dirInfo *dirInfo) (string, bool) {
	for {
		// Handle TypeScript base URLs for TypeScript code
		if dirInfo.tsConfigJson != nil {

			if dirInfo.tsConfigJson.absPathBaseUrl != nil {
				if dirInfo.tsConfigJson.paths != nil {
					for key, originalPaths := range dirInfo.tsConfigJson.paths {
						for _, originalPath := range originalPaths {
							if matched, err := regexp.MatchString("^"+key, path); matched && err == nil {
								if absoluteOriginalPath, err := resolvePathWithoutStar(*dirInfo.tsConfigJson.absPathBaseUrl, originalPath); err == nil {
									elements := strings.Split(path, "/")

									elements = elements[1:]

									resolved := append(strings.Split(absoluteOriginalPath, string(os.PathSeparator)), elements...)
									basePath := strings.Join(resolved, "/")
									if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
										return absolute, true
									}
								}
							}
						}

					}
				} else {
					basePath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, path)
					if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
						return absolute, true
					}
				}

			}
		}


Review comment (bug):
Using a regex to match this isn't correct. The pattern is an asterisk, which causes a regex to repeat the previous character zero or more times. That would mean a pattern `foo*` would also match a directory named `foooo` and `fo`. I took some time to look at what the TypeScript compiler itself does. The relevant code is in `tryLoadModuleUsingPaths()` [here](https://github.com/microsoft/TypeScript/blob/c194abb38c54c1607831b4ec678c0bdd15f7fe49/src/compiler/moduleNameResolver.ts#L1361-L1387).

Other relevant code is `tryParsePattern()` [here](https://github.com/microsoft/TypeScript/blob/c194abb38c54c1607831b4ec678c0bdd15f7fe49/src/compiler/utilities.ts#L6122-L6130):

```ts
    export function tryParsePattern(pattern: string): Pattern | undefined {
        // This should be verified outside of here and a proper error thrown.
        Debug.assert(hasZeroOrOneAsteriskCharacter(pattern));
        const indexOfStar = pattern.indexOf("*");
        return indexOfStar === -1 ? undefined : {
            prefix: pattern.substr(0, indexOfStar),
            suffix: pattern.substr(indexOfStar + 1)
        };
    }
```

and `isPatternMatch()` [here](https://github.com/microsoft/TypeScript/blob/c194abb38c54c1607831b4ec678c0bdd15f7fe49/src/compiler/core.ts#L2015-L2019):

```ts
    function isPatternMatch({ prefix, suffix }: Pattern, candidate: string) {
        return candidate.length >= prefix.length + suffix.length &&
            startsWith(candidate, prefix) &&
            endsWith(candidate, suffix);
    }
```


Code after:
	// Return the "index.js" file
	if dirInfo.absPathIndex != nil {
		return *dirInfo.absPathIndex, true
	}

	return "", false
}

func isTsConfigPathMatch(pattern string, path string) (string, bool) {
	starIndex := strings.IndexRune(pattern, '*')
	if starIndex == -1 {
		firstPath := strings.Split(path, "/")[0]
		return strings.Replace(path, pattern+"/", "", 1), firstPath == pattern
	}

	elements := strings.Split(pattern, "*")
	if starIndex == 0 {
		suffix := elements[1]
		return strings.Replace(path, suffix, "", 1), strings.HasSuffix(path, suffix)
	}
	prefix := elements[0]
	return strings.Replace(path, prefix, "", 1), strings.HasPrefix(path, prefix)
}

func (r *resolver) loadNodeModules(path string, dirInfo *dirInfo) (string, bool) {
	for {
		// Handle TypeScript base URLs for TypeScript code
		if dirInfo.tsConfigJson != nil {

			if dirInfo.tsConfigJson.absPathBaseUrl != nil {
				if dirInfo.tsConfigJson.paths != nil {
					for key, originalPaths := range dirInfo.tsConfigJson.paths {
						for _, originalPath := range originalPaths {
							if parts, ok := isTsConfigPathMatch(key, path); ok {
								absoluteOriginalPath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, originalPath)
								basePath := strings.Replace(absoluteOriginalPath, "*", parts, 1)
								if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
									return absolute, true
								}
							}
						}

					}
				}
				basePath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, path)
				if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
					return absolute, true
				}

			}
		}