diff --git a/packages/language-server/src/ls-config.ts b/packages/language-server/src/ls-config.ts index 834dfc7f9..30a662a1f 100644 --- a/packages/language-server/src/ls-config.ts +++ b/packages/language-server/src/ls-config.ts @@ -167,6 +167,20 @@ export interface LSSvelteConfig { }; } +/** + * A subset of the JS/TS VS Code settings which + * are transformed to ts.UserPreferences. + * It may not be available in other IDEs, that's why the keys are optional. + */ +export interface TSUserConfig { + preferences?: TsUserPreferencesConfig; + suggest?: TSSuggestConfig; +} + +/** + * A subset of the JS/TS VS Code settings which + * are transformed to ts.UserPreferences. + */ export interface TsUserPreferencesConfig { importModuleSpecifier: UserPreferences['importModuleSpecifierPreference']; importModuleSpecifierEnding: UserPreferences['importModuleSpecifierEnding']; @@ -177,6 +191,14 @@ export interface TsUserPreferencesConfig { includePackageJsonAutoImports?: UserPreferences['includePackageJsonAutoImports']; } +/** + * A subset of the JS/TS VS Code settings which + * are transformed to ts.UserPreferences. + */ +export interface TSSuggestConfig { + autoImports: UserPreferences['includeCompletionsForModuleExports']; +} + export type TsUserConfigLang = 'typescript' | 'javascript'; type DeepPartial = T extends CompilerWarningsSettings @@ -189,8 +211,12 @@ export class LSConfigManager { private config: LSConfig = defaultLSConfig; private listeners: Array<(config: LSConfigManager) => void> = []; private tsUserPreferences: Record = { - typescript: {}, - javascript: {} + typescript: { + includeCompletionsForModuleExports: true + }, + javascript: { + includeCompletionsForModuleExports: true + } }; private prettierConfig: any = {}; private emmetConfig: EmmetConfiguration = {}; @@ -258,28 +284,23 @@ export class LSConfigManager { return this.prettierConfig; } - updateTsJsUserPreferences( - config: Record< - TsUserConfigLang, - { - preferences: TsUserPreferencesConfig; - } - > - ): void { + updateTsJsUserPreferences(config: Record): void { (['typescript', 'javascript'] as const).forEach((lang) => { - if (config[lang]?.preferences) { - this._updateTsUserPreferences(lang, config[lang].preferences); + if (config[lang]) { + this._updateTsUserPreferences(lang, config[lang]); } }); } - private _updateTsUserPreferences(lang: TsUserConfigLang, config: TsUserPreferencesConfig) { - this.tsUserPreferences[lang] = Object.assign(this.tsUserPreferences[lang], { - importModuleSpecifierPreference: config.importModuleSpecifier, - importModuleSpecifierEnding: config.importModuleSpecifierEnding, - includePackageJsonAutoImports: config.includePackageJsonAutoImports, - quotePreference: config.quoteStyle - } as UserPreferences); + private _updateTsUserPreferences(lang: TsUserConfigLang, config: TSUserConfig) { + this.tsUserPreferences[lang] = { + ...this.tsUserPreferences[lang], + importModuleSpecifierPreference: config.preferences?.importModuleSpecifier, + importModuleSpecifierEnding: config.preferences?.importModuleSpecifierEnding, + includePackageJsonAutoImports: config.preferences?.includePackageJsonAutoImports, + quotePreference: config.preferences?.quoteStyle, + includeCompletionsForModuleExports: config.suggest?.autoImports ?? true + }; } getTsUserPreferences(lang: TsUserConfigLang) { diff --git a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts index 366d4396e..72d114ebb 100644 --- a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts @@ -38,7 +38,7 @@ export interface CompletionEntryWithIdentifer extends ts.CompletionEntry, TextDo type validTriggerCharacter = '.' | '"' | "'" | '`' | '/' | '@' | '<' | '#'; export class CompletionsProviderImpl implements CompletionsProvider { - constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) { } + constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {} /** * The language service throws an error if the character is not a valid trigger character. @@ -62,7 +62,7 @@ export class CompletionsProviderImpl implements CompletionsProvider { const expectedImportEdit = "import { definition } from '~/definition/index';"; - function getPreferences(): TsUserPreferencesConfig { + function getPreferences(): TSUserConfig { return { - importModuleSpecifier: 'non-relative', - importModuleSpecifierEnding: 'index', - quoteStyle: 'single' + preferences: { + importModuleSpecifier: 'non-relative', + importModuleSpecifierEnding: 'index', + quoteStyle: 'single' + }, + suggest: { + autoImports: true + } }; } - function createLSAndTSDocResolver(docManager: DocumentManager) { + function createLSAndTSDocResolver( + docManager: DocumentManager, + preferences?: Partial + ) { const configManager = new LSConfigManager(); configManager.updateTsJsUserPreferences({ - typescript: { preferences: getPreferences() }, - javascript: { preferences: {} as any } + typescript: { ...getPreferences(), ...preferences }, + javascript: { ...getPreferences(), ...preferences } }); return new LSAndTSDocResolver(docManager, [pathToUrl(testFilesDir)], configManager); } @@ -102,4 +110,20 @@ describe('ts user preferences', () => { ] }); }); + + it('provides auto import suggestions according to preferences', async () => { + const { docManager, document } = setup('code-action.svelte'); + const lsAndTsDocResolver = createLSAndTSDocResolver(docManager, { + suggest: { autoImports: false } + }); + const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver); + + const completions = await completionProvider.getCompletions( + document, + Position.create(1, 14) + ); + + const item = completions?.items.find((item) => item.label === 'definition'); + assert.strictEqual(item, undefined, 'Expected no auto import suggestions'); + }); }); diff --git a/packages/svelte-vscode/src/extension.ts b/packages/svelte-vscode/src/extension.ts index 735cb3edd..4021631f6 100644 --- a/packages/svelte-vscode/src/extension.ts +++ b/packages/svelte-vscode/src/extension.ts @@ -248,7 +248,7 @@ function addRenameFileListener(getLS: () => LanguageClient) { // In the meantime, just assume it's a single entry and simplify the // rest of the logic that way. { - oldUri: oldUri, + oldUri, newUri: evt.files[0].newUri.toString(true) } );