-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add tsconfig.json compilerOptions.paths support #144
Changes from 5 commits
f13ade7
47af843
181ba06
c521d19
9a36433
2587e08
444bfae
05da9ee
16c3db4
7dcd776
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
package resolver | ||
|
||
import ( | ||
"os" | ||
fp "path/filepath" | ||
"regexp" | ||
"strings" | ||
"sync" | ||
|
||
|
@@ -230,7 +233,8 @@ type packageJson struct { | |
} | ||
|
||
type tsConfigJson struct { | ||
absPathBaseUrl *string // The absolute path of "compilerOptions.baseUrl" | ||
absPathBaseUrl *string // The absolute path of "compilerOptions.baseUrl" | ||
paths map[string][]string // The absolute paths of "compilerOptions.paths" | ||
} | ||
|
||
type dirInfo struct { | ||
|
@@ -301,6 +305,25 @@ func (r *resolver) parseJsTsConfig(file string, path string, info *dirInfo) { | |
info.tsConfigJson.absPathBaseUrl = &baseUrl | ||
} | ||
} | ||
if pathsJson, ok := getProperty(compilerOptionsJson, "paths"); ok { | ||
if paths, ok := pathsJson.Data.(*ast.EObject); ok { | ||
info.tsConfigJson.paths = map[string][]string{} | ||
for _, prop := range paths.Properties { | ||
if key, ok := getString(prop.Key); ok { | ||
if value, ok := getProperty(pathsJson, key); ok { | ||
if array, ok := value.Data.(*ast.EArray); ok { | ||
for _, item := range array.Items { | ||
if str, ok := getString(item); ok { | ||
// If this is a string, it's a replacement module | ||
info.tsConfigJson.paths[key] = append(info.tsConfigJson.paths[key], str) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -578,13 +601,43 @@ func (r *resolver) loadAsFileOrDirectory(path string) (string, bool) { | |
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 && dirInfo.tsConfigJson.absPathBaseUrl != nil { | ||
basePath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, path) | ||
if absolute, ok := r.loadAsFileOrDirectory(basePath); ok { | ||
return absolute, true | ||
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't follow the behavior of the TypeScript compiler which prefers exact matches over pattern matches and prefers matches with longer prefixes over matches with shorter prefixes. That's ok though, I'll fix it. |
||
if matched, err := regexp.MatchString("^"+key, path); matched && err == nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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 Other relevant code is 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 function isPatternMatch({ prefix, suffix }: Pattern, candidate: string) {
return candidate.length >= prefix.length + suffix.length &&
startsWith(candidate, prefix) &&
endsWith(candidate, suffix);
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thank you! i've added some commits to handle this more like ts compiler, but i haven't written the test case where |
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like the TypeScript compiler still respects There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks! resolved on 2587e08 |
||
if absolute, ok := r.loadAsFileOrDirectory(basePath); ok { | ||
return absolute, true | ||
} | ||
} | ||
|
||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code in this file is careful to always use the
fs
interface in theresolver
instead ofpath/filepath
. All platform-dependent things are supposed to happen inside thefs
interface so that the resolver can be platform-independent. That interface uses the realpath/filepath
module for the esbuild command and thepath
module for tests. That way tests don't do different things on Windows.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you! resolved in 444bfae