Skip to content

Allow 'paths' without 'baseUrl' #40101

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

Merged

Conversation

andrewbranch
Copy link
Member

Allows the paths compiler option to be used without baseUrl by resolving paths relative to the config file location.

  • Produces an error on any path value that is not relative or absolute. (If baseUrl were set, these so-called “non-relative” paths would still be resolved relative to baseUrl, so there’s never a reason to write a non-relative path in the first place. Explicitly disallowing it leaves room for us to add new, useful behavior later, if needed.)
  • If paths is inherited from an extended config file in another directory, the relative paths therein are resolved relative to the config file where they were written, not relative to the extending config file. (I don’t think this even needs to be said; the result is that relative paths look correct for where they’re written.)

Fixes #31869

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Aug 17, 2020
@andrewbranch andrewbranch force-pushed the feature/paths-without-baseurl branch from a1427a6 to a5b1b5e Compare August 18, 2020 17:29
// the config file location, we'll need to know where that config file was.
// Since 'paths' can be inherited from an extended config in another directory,
// we wouldn't know which directory to use unless we store it here.
ownConfig.options.pathsBasePath = basePath;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if this should be non enumerable and should be in tsconfig build info or not. You would also want test case with incremental set.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a baseline that shows it in the .tsbuildinfo. It seems like it would be necessary if an incremental build doesn’t re-resolve everything in tsconfig, but I’m not sure how that works. Exactly what would you want to see in a test case?

@jakebailey
Copy link
Member

Not to pester you too much, but if possible I'd love to see a test for my case in #31869 (comment) (which you said should work), just so that doesn't end up regressing. 🙂

@andrewbranch
Copy link
Member Author

@jakebailey there are a couple other auto-import issues related to paths assigned to me for this release. This PR is intentionally limited to just module resolution rules to make it easier to review.

@jakebailey
Copy link
Member

Sure thing, I wasn't sure if this small change managed to do it all. Thanks.

@andrewbranch
Copy link
Member Author

This small change actually will do what you want, I just wanted to look at (and test) auto-import scenarios holistically afterward, since there are some other related scenarios I want to change. The rest of the work is tracked at #36235 and #36624 if you want to keep track.

@sandersn
Copy link
Member

sandersn commented Sep 4, 2020

@andrewbranch I can't tell but it looks like this PR is waiting on an answer to @sheetalkamat's last question. Is that correct?

@sandersn sandersn assigned sheetalkamat and unassigned andrewbranch Sep 4, 2020
@andrewbranch
Copy link
Member Author

I think I’m waiting on answers to my responses to Sheetal:

The latter I didn’t exactly phrase as a question, I guess because I was hoping someone would have a better idea on what to do when we construct a program with compilerOptions that didn’t come from config parsing. If you specify paths and no baseUrl and there was no config file where those paths were written, what can we resolve relative paths to?

trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
}
return tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
const baseDirectory = baseUrl ?? Debug.checkDefined(pathsBasePath || state.host.getCurrentDirectory?.(), "Encountered 'paths' without a 'baseUrl', config file, or host 'getCurrentDirectory'.");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks sketchy, but I manually verified that the assertion should hold in all cases we currently have; it’s just hard to encode it into the types. The only times host.getCurrentDirectory is undefined are

  1. The command line parser and typings installer each call the module name resolver in an ad-hoc way under certain circumstances, but they pass a hard-coded compilerOptions that lack paths, so this code path is never taken.
  2. Project calls getAutomaticTypeDirectives with a DirectoryStructureHost, but that function never uses host.getCurrentDirectory().

Changing ModuleResolutionHost['getCurrentDirectory'] to be non-optional makes these call sites a bit of a nuisance.

Copy link
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I'm not quite sure what the incremental test cases should look like (maybe a test where you add/remove the basePath and/or paths options?), but this looks OK to me. I don't know if you wanna do it in this PR, or as a followup, but this probably wants for us to change logic in src/compiler/moduleSpecifiers.ts, too - that's what controls how we serialize module names for declaration emit, which should be affected by this new compiler option functionality, I'd think.

@andrewbranch
Copy link
Member Author

module names for declaration emit

I’m having trouble observing this, because when you use outFile, the declaration emitter overrides baseUrl with the common source directory, and when you don’t use outFile, it always prefers the relative path.

I discovered an unrelated bug while trying to come up with a test case where the module specifiers generated for the module declaration blocks in an outFile bundle are always based on filename, whereas module specifiers generated for ImportTypeNodes use paths, an inconsistency which results in declaration file errors. But that happens with or without this PR.

I do think the code in moduleSpecifiers.ts will need to be updated for use with auto-imports, but I was intentionally leaving auto-imports for a follow-up PR. But let me know if you have a good idea for a declaration emitter test case.

@andrewbranch andrewbranch merged commit 9c8d11b into microsoft:master Sep 11, 2020
@andrewbranch andrewbranch deleted the feature/paths-without-baseurl branch September 11, 2020 19:58
kodiakhq bot pushed a commit to vercel/next.js that referenced this pull request Aug 15, 2022
tsconfig behaves differently with `tsc` vs. Next.js. When `baseurl` is omitted, `paths` should be resolved against the tsconfig location. Consequentially, in this case the paths must start with `./`. This PR aligns Next.js behavior with `tsc` around `paths` without `baseurl`. 

Related: microsoft/TypeScript#40101
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Proposal: Allow paths compilerOption without baseUrl
6 participants