mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 04:43:37 -05:00
importModuleSpecifierEnding changes .ts string completions to .js (#44602)
* don't add .ts extensions to imports * Update src/services/stringCompletions.ts Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com> * add other supported extension types * add final newlines * adress PR comment * add unsupported extension test Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>
This commit is contained in:
@@ -694,7 +694,11 @@ namespace ts.moduleSpecifiers {
|
||||
}
|
||||
|
||||
function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
const ext = extensionFromPath(fileName);
|
||||
return tryGetJSExtensionForFile(fileName, options) ?? Debug.fail(`Extension ${extensionFromPath(fileName)} is unsupported:: FileName:: ${fileName}`);
|
||||
}
|
||||
|
||||
export function tryGetJSExtensionForFile(fileName: string, options: CompilerOptions): Extension | undefined {
|
||||
const ext = tryGetExtensionFromPath(fileName);
|
||||
switch (ext) {
|
||||
case Extension.Ts:
|
||||
case Extension.Dts:
|
||||
@@ -705,10 +709,8 @@ namespace ts.moduleSpecifiers {
|
||||
case Extension.Jsx:
|
||||
case Extension.Json:
|
||||
return ext;
|
||||
case Extension.TsBuildInfo:
|
||||
return Debug.fail(`Extension ${Extension.TsBuildInfo} is unsupported:: FileName:: ${fileName}`);
|
||||
default:
|
||||
return Debug.assertNever(ext);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -321,13 +321,14 @@ namespace ts.Completions.StringCompletions {
|
||||
|
||||
interface ExtensionOptions {
|
||||
readonly extensions: readonly Extension[];
|
||||
readonly includeExtensions: boolean;
|
||||
readonly includeExtensionsOption: IncludeExtensionsOption;
|
||||
}
|
||||
function getExtensionOptions(compilerOptions: CompilerOptions, includeExtensions = false): ExtensionOptions {
|
||||
return { extensions: getSupportedExtensionsForModuleResolution(compilerOptions), includeExtensions };
|
||||
function getExtensionOptions(compilerOptions: CompilerOptions, includeExtensionsOption = IncludeExtensionsOption.Exclude): ExtensionOptions {
|
||||
return { extensions: getSupportedExtensionsForModuleResolution(compilerOptions), includeExtensionsOption };
|
||||
}
|
||||
function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path, preferences: UserPreferences) {
|
||||
const extensionOptions = getExtensionOptions(compilerOptions, preferences.importModuleSpecifierEnding === "js");
|
||||
const includeExtensions = preferences.importModuleSpecifierEnding === "js" ? IncludeExtensionsOption.ModuleSpecifierCompletion : IncludeExtensionsOption.Exclude;
|
||||
const extensionOptions = getExtensionOptions(compilerOptions, includeExtensions);
|
||||
if (compilerOptions.rootDirs) {
|
||||
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
|
||||
compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath);
|
||||
@@ -370,10 +371,15 @@ namespace ts.Completions.StringCompletions {
|
||||
return flatMap(baseDirectories, baseDirectory => getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, exclude));
|
||||
}
|
||||
|
||||
const enum IncludeExtensionsOption {
|
||||
Exclude,
|
||||
Include,
|
||||
ModuleSpecifierCompletion,
|
||||
}
|
||||
/**
|
||||
* Given a path ending at a directory, gets the completions for the path, and filters for those entries containing the basename.
|
||||
*/
|
||||
function getCompletionEntriesForDirectoryFragment(fragment: string, scriptPath: string, { extensions, includeExtensions }: ExtensionOptions, host: LanguageServiceHost, exclude?: string, result: NameAndKind[] = []): NameAndKind[] {
|
||||
function getCompletionEntriesForDirectoryFragment(fragment: string, scriptPath: string, { extensions, includeExtensionsOption }: ExtensionOptions, host: LanguageServiceHost, exclude?: string, result: NameAndKind[] = []): NameAndKind[] {
|
||||
if (fragment === undefined) {
|
||||
fragment = "";
|
||||
}
|
||||
@@ -407,7 +413,7 @@ namespace ts.Completions.StringCompletions {
|
||||
if (files) {
|
||||
/**
|
||||
* Multiple file entries might map to the same truncated name once we remove extensions
|
||||
* (happens iff includeExtensions === false)so we use a set-like data structure. Eg:
|
||||
* (happens iff includeExtensionsOption === includeExtensionsOption.Exclude) so we use a set-like data structure. Eg:
|
||||
*
|
||||
* both foo.ts and foo.tsx become foo
|
||||
*/
|
||||
@@ -418,8 +424,20 @@ namespace ts.Completions.StringCompletions {
|
||||
continue;
|
||||
}
|
||||
|
||||
const foundFileName = includeExtensions || fileExtensionIs(filePath, Extension.Json) ? getBaseFileName(filePath) : removeFileExtension(getBaseFileName(filePath));
|
||||
foundFiles.set(foundFileName, tryGetExtensionFromPath(filePath));
|
||||
let foundFileName: string;
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(filePath, host.getCompilationSettings());
|
||||
if (includeExtensionsOption === IncludeExtensionsOption.Exclude && !fileExtensionIs(filePath, Extension.Json)) {
|
||||
foundFileName = removeFileExtension(getBaseFileName(filePath));
|
||||
foundFiles.set(foundFileName, tryGetExtensionFromPath(filePath));
|
||||
}
|
||||
else if (includeExtensionsOption === IncludeExtensionsOption.ModuleSpecifierCompletion && outputExtension) {
|
||||
foundFileName = changeExtension(getBaseFileName(filePath), outputExtension);
|
||||
foundFiles.set(foundFileName, outputExtension);
|
||||
}
|
||||
else {
|
||||
foundFileName = getBaseFileName(filePath);
|
||||
foundFiles.set(foundFileName, tryGetExtensionFromPath(filePath));
|
||||
}
|
||||
}
|
||||
|
||||
foundFiles.forEach((ext, foundFile) => {
|
||||
@@ -635,7 +653,7 @@ namespace ts.Completions.StringCompletions {
|
||||
|
||||
const [, prefix, kind, toComplete] = match;
|
||||
const scriptPath = getDirectoryPath(sourceFile.path);
|
||||
const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, /*includeExtensions*/ true), host, sourceFile.path)
|
||||
const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, IncludeExtensionsOption.Include), host, sourceFile.path)
|
||||
: kind === "types" ? getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, getFragmentDirectory(toComplete), getExtensionOptions(compilerOptions))
|
||||
: Debug.fail();
|
||||
return addReplacementSpans(toComplete, range.pos + prefix.length, names);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
//@Filename:test.d.ts
|
||||
//// export declare class Test {}
|
||||
|
||||
//@Filename:module.ts
|
||||
////import { Test } from ".//**/"
|
||||
|
||||
verify.completions({ marker: "", includes:{name:"test.js"}, preferences: {importModuleSpecifierEnding: "js" }, isNewIdentifierLocation: true});
|
||||
verify.completions({ marker: "", includes:{name:"test"}, preferences: {importModuleSpecifierEnding: "index" }, isNewIdentifierLocation: true});
|
||||
@@ -8,5 +8,5 @@
|
||||
//@Filename:module.js
|
||||
////import { f } from ".//**/"
|
||||
|
||||
|
||||
verify.completions({ marker: "", includes:{name:"test.js"}, preferences: {importModuleSpecifierEnding: "js" }, isNewIdentifierLocation: true})
|
||||
verify.completions({ marker: "", includes:{name:"test.js"}, preferences: {importModuleSpecifierEnding: "js" }, isNewIdentifierLocation: true});
|
||||
verify.completions({ marker: "", includes:{name:"test"}, preferences: {importModuleSpecifierEnding: "index" }, isNewIdentifierLocation: true});
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
//@allowJs: true
|
||||
//@jsx:preserve
|
||||
//@Filename:test.jsx
|
||||
//// export class Test { }
|
||||
|
||||
//@Filename:module.jsx
|
||||
////import { Test } from ".//**/"
|
||||
|
||||
verify.completions({ marker: "", includes:{name:"test.jsx"}, preferences: {importModuleSpecifierEnding: "js"}, isNewIdentifierLocation: true});
|
||||
verify.completions({ marker: "", includes:{name:"test"}, preferences: {importModuleSpecifierEnding: "index" }, isNewIdentifierLocation: true});
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
//@Filename:test.ts
|
||||
////export function f(){
|
||||
//// return 1
|
||||
////}
|
||||
|
||||
//@Filename:module.ts
|
||||
////import { f } from ".//**/"
|
||||
|
||||
verify.completions({ marker: "", includes:{name:"test.js"}, preferences: {importModuleSpecifierEnding: "js" }, isNewIdentifierLocation: true});
|
||||
verify.completions({ marker: "", includes:{name:"test"}, preferences: {importModuleSpecifierEnding: "index" }, isNewIdentifierLocation: true});
|
||||
@@ -0,0 +1,10 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
//@jsx:preserve
|
||||
//@Filename:test.tsx
|
||||
//// export class Test { }
|
||||
|
||||
//@Filename:module.tsx
|
||||
////import { Test } from ".//**/"
|
||||
|
||||
verify.completions({ marker: "", includes:{name:"test.jsx"}, preferences: {importModuleSpecifierEnding: "js"}, isNewIdentifierLocation: true});
|
||||
verify.completions({ marker: "", includes:{name:"test"}, preferences: {importModuleSpecifierEnding: "index" }, isNewIdentifierLocation: true});
|
||||
@@ -0,0 +1,10 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
//@jsx:react
|
||||
//@Filename:test.tsx
|
||||
//// export class Test { }
|
||||
|
||||
//@Filename:module.tsx
|
||||
////import { Test } from ".//**/"
|
||||
|
||||
verify.completions({ marker: "", includes:{name:"test.js"}, preferences: {importModuleSpecifierEnding: "js"}, isNewIdentifierLocation: true});
|
||||
verify.completions({ marker: "", includes:{name:"test"}, preferences: {importModuleSpecifierEnding: "index" }, isNewIdentifierLocation: true});
|
||||
@@ -0,0 +1,9 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
//@Filename:index.css
|
||||
//// body {}
|
||||
|
||||
//@Filename:module.ts
|
||||
////import ".//**/"
|
||||
|
||||
verify.completions({ marker: "", excludes:"index.css", preferences: {importModuleSpecifierEnding: "js" }, isNewIdentifierLocation: true});
|
||||
verify.completions({ marker: "", excludes:"index", preferences: {importModuleSpecifierEnding: "index" }, isNewIdentifierLocation: true});
|
||||
Reference in New Issue
Block a user