diff --git a/packages/language-server/src/plugins/svelte/SveltePlugin.ts b/packages/language-server/src/plugins/svelte/SveltePlugin.ts index 20b7e2bcc..ddeb6df92 100644 --- a/packages/language-server/src/plugins/svelte/SveltePlugin.ts +++ b/packages/language-server/src/plugins/svelte/SveltePlugin.ts @@ -1,3 +1,4 @@ +import { isAbsolute } from 'path'; import { CancellationToken, CodeAction, @@ -17,6 +18,7 @@ import { getPackageInfo, importPrettier } from '../../importPackage'; import { Document } from '../../lib/documents'; import { Logger } from '../../logger'; import { LSConfigManager, LSSvelteConfig } from '../../ls-config'; +import { isNotNullOrUndefined } from '../../utils'; import { CodeActionsProvider, CompletionsProvider, @@ -106,7 +108,14 @@ export class SveltePlugin const formattedCode = prettier.format(document.getText(), { ...config, - plugins: [...(config.plugins ?? []), ...getSveltePlugin()], + plugins: Array.from( + new Set([ + ...((config.plugins as string[]) ?? []) + .map(resolvePlugin) + .filter(isNotNullOrUndefined), + ...getSveltePlugin() + ]) + ), parser: 'svelte' as any }); @@ -132,6 +141,21 @@ export class SveltePlugin .languages.some((l) => l.name === 'svelte'); return hasPluginLoadedAlready ? [] : [require.resolve('prettier-plugin-svelte')]; } + + function resolvePlugin(plugin: string) { + // https://github.com/prettier/prettier-vscode/blob/160b0e92d88fa19003dce2745d5ab8c67e886a04/src/ModuleResolver.ts#L373 + if (typeof plugin != 'string' || isAbsolute(plugin) || plugin.startsWith('.')) { + return plugin; + } + + try { + return require.resolve(plugin, { + paths: [filePath] + }); + } catch (error) { + Logger.error(`failed to resolve plugin ${plugin} with error:\n`, error); + } + } } async getCompletions( diff --git a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts index 7b9e5e975..2eb58bb09 100644 --- a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts +++ b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts @@ -10,10 +10,16 @@ import { import { LSConfigManager } from '../../../src/ls-config'; import * as importPackage from '../../../src/importPackage'; import sinon from 'sinon'; +import { join } from 'path'; +import { pathToUrl, urlToPath } from '../../../src/utils'; describe('Svelte Plugin', () => { - function setup(content: string, prettierConfig?: any, trusted = true) { - const document = new Document('file:///hello.svelte', content); + function setup( + content: string, + prettierConfig?: any, + { trusted = true, documentUri = 'file:///hello.svelte' } = {} + ) { + const document = new Document(documentUri, content); const docManager = new DocumentManager(() => document); const pluginManager = new LSConfigManager(); pluginManager.updateIsTrusted(trusted); @@ -54,7 +60,7 @@ describe('Svelte Plugin', () => { }); it('provides no diagnostic errors when untrusted', async () => { - const { plugin, document } = setup('
', {}, false); + const { plugin, document } = setup('', {}, { trusted: false }); const diagnostics = await plugin.getDiagnostics(document); @@ -75,8 +81,12 @@ describe('Svelte Plugin', () => { return formatStub; } - async function testFormat(config: any, fallbackPrettierConfig: any) { - const { plugin, document } = setup('unformatted', fallbackPrettierConfig); + async function testFormat( + config: any, + fallbackPrettierConfig: any, + options?: Parameters