Skip to content
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

importModuleSpecifierEnding changes .ts string completions to .js #44602

Merged
merged 6 commits into from
Jun 21, 2021

Conversation

jessetrinity
Copy link
Contributor

Fixes #44374

@typescript-bot typescript-bot added Author: Team For Milestone Bug PRs that fix a bug with a specific milestone labels Jun 15, 2021
@jessetrinity jessetrinity changed the title Do not autocomplete import paths with .ts extension importModuleSpecifierEnding changes .ts string completions to .js Jun 15, 2021
foundFileName = removeFileExtension(getBaseFileName(filePath));
foundFiles.set(foundFileName, tryGetExtensionFromPath(filePath));
}
else if (includeExtensionsOption === IncludeExtensionsOption.ModuleSpecifierCompletion && fileExtensionIs(filePath, Extension.Ts)) {
Copy link
Member

Choose a reason for hiding this comment

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

What we really need, and I’m not sure whether we have (but we might), is a function that maps input file extensions to emitted file extensions. So we would have

  • .ts → .js
  • .tsx → ? (I don’t know if this is always .js or if we might emit .jsx with --jsx=preserve?)
  • .mts → .mjs (someday soon)
  • .d.ts → undefined because it doesn’t get emitted
  • .json → .json (only if --resolveJsonModule?)
  • .js → .js

If we don’t have that function, we need to (a) figure out what the right thing for TSX is and implement it now, and (b) remember to update it for .mts and .cts if/when we add those.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Emitter.ts has getOutputExtension which does approximately that, but it works on a sourceFile. Since we're just working working with the paths here we probably just want a new similar function that handle the cases we need.

Copy link
Member

@andrewbranch andrewbranch Jun 16, 2021

Choose a reason for hiding this comment

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

👍 in absence of something better, just leave comments on each function (getOutputExtension and the new function) saying to keep them in sync with each other.

Copy link
Member

Choose a reason for hiding this comment

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

Found it:

function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension {

I would maybe just export that function so it doesn’t immediately cause merge conflicts with #44501.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, you might need to refactor it to return undefined instead of throwing on unsupported extensions, and move the debug assertions to its caller, or another wrapped version of it. But otherwise I think this function is exactly the thing we were looking for.

src/services/stringCompletions.ts Outdated Show resolved Hide resolved
default:
return Debug.assertNever(ending);
}
}

function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension {
function getJSExtensionForFileIfApplicable(fileName: string, options: CompilerOptions): Extension {
Copy link
Member

Choose a reason for hiding this comment

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

To me this one sounds like the one that never throws. I would suggest naming the undefined-returning one tryGetJSExtensionForFile and the throwing one getJSExtensionForFile.

return getJSExtensionForFile(fileName, options) ?? Debug.fail(`Extension ${extensionFromPath(fileName)} is unsupported:: FileName:: ${fileName}`);
}

export function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension | undefined {
const ext = extensionFromPath(fileName);
Copy link
Member

@andrewbranch andrewbranch Jun 21, 2021

Choose a reason for hiding this comment

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

I thought it was sketchy that this function didn’t have undefined in its return type, so I looked and found that it too has an undefined-returning counterpart, and this one throws! This may need to be swapped for tryGetExtensionFromPath for good measure. This also makes me realize we should have a test that actually returns completions for a non-source-file file extension, like index.css or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think we even read other extension types from disk, but I think you mean something like

//@filename: index.css
body {}

//@filename: index.html
<!DOCTYPE html>

//@filename: foo.ts
import "./

And expect nothing at the uncompleted string?

Copy link
Member

Choose a reason for hiding this comment

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

Hm, I looked at stringCompletions and saw tryReadDirectory, so I assumed we were offering everything we could find, with extension substitutions as appropriate. Not sure what’s going on then 🤔

Copy link
Member

Choose a reason for hiding this comment

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

You could certainly be seeing an artifact of the fourslash client 😬. Have you checked the behavior against a Real Editor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was pretty sure that tryReadDirectory only returned files that matched its extensions argument, if provided. I might be misreading though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

either way, updated to not use the throwing variant :)

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I missed that parameter 🤦‍♂️

It might actually be nice to allow all extensions here in the future, since we can no longer seriously claim to believe we’re in a world where people only import things we know how to analyze. This doesn’t even account for declare module "*.css" pattern ambient module declarations. But that’s for another day. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh geez TIL. Is that a wildcard module declaration?

@jessetrinity jessetrinity merged commit 753feb8 into microsoft:main Jun 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug PRs that fix a bug with a specific milestone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

importModuleSpecifierEnding = js doesn't apply for autocomplete within import paths
3 participants