From a321244543c50b5128ea5c382609e94d4f4fde68 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Fri, 17 Oct 2025 15:31:35 +0200 Subject: [PATCH] feat: suggest against js variables in css --- .changeset/seven-breads-stay.md | 5 + .../handlers/tools/svelte-autofixer.test.ts | 94 +++++++++++++++++++ .../mcp/handlers/tools/svelte-autofixer.ts | 4 + 3 files changed, 103 insertions(+) create mode 100644 .changeset/seven-breads-stay.md create mode 100644 packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.test.ts diff --git a/.changeset/seven-breads-stay.md b/.changeset/seven-breads-stay.md new file mode 100644 index 00000000..c9bb400b --- /dev/null +++ b/.changeset/seven-breads-stay.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/mcp': patch +--- + +feat: suggest against js variables in css diff --git a/packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.test.ts b/packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.test.ts new file mode 100644 index 00000000..5c983048 --- /dev/null +++ b/packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.test.ts @@ -0,0 +1,94 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { server } from '../../index.js'; + +/** + * Small utility to create a JSON-RPC request without having to always specify as const + */ +function request(request: T) { + return request; +} + +async function autofixer_tool_call(code: string, is_error = false, desired_svelte_version = 5) { + const result = await server.receive({ + jsonrpc: '2.0', + id: 2, + method: 'tools/call', + params: { + name: 'svelte-autofixer', + arguments: { + code, + desired_svelte_version, + filename: 'App.svelte', + }, + }, + }); + + expect(result).toBeDefined(); + expect(result.result).toBeDefined(); + if (is_error) { + return result.result; + } + expect(result.result.structuredContent).toBeDefined(); + return result.result.structuredContent; +} + +describe('svelte-autofixer tool', () => { + beforeEach(async () => { + const initialize_request = request({ + jsonrpc: '2.0', + id: 1, + method: 'initialize', + params: { + protocolVersion: '2025-06-18', + capabilities: { + roots: { listChanged: true }, + }, + clientInfo: { + name: 'test-client', + version: '1.0.0', + }, + }, + }); + + await server.receive(initialize_request, { + sessionId: 'svelte-autofixer-session', + }); + }); + + it('should add suggestions for js parse errors', async () => { + const content = await autofixer_tool_call(``); + expect(content.issues.length).toBeGreaterThan(0); + expect(content.suggestions).toContain( + "The code can't be compiled because a Javascript parse error. In case you are using runes like this `$state variable_name = 3;` or `$derived variable_name = 3 * count` that's not how runes are used. You need to use them as function calls without importing them: `const variable_name = $state(3)` and `const variable_name = $derived(3 * count)`.", + ); + }); + + it('should add suggestions for css invalid identifier', async () => { + const content = await autofixer_tool_call(` + + `); + + expect(content.issues.length).toBeGreaterThan(0); + expect(content.suggestions).toContain( + "The code can't be compiled because a valid CSS identifier is expected. This sometimes means you are trying to use a variable in CSS like this: `color: {my_color}` but Svelte doesn't support that. You can use inline CSS variables for that `
` and then use the variable as usual in CSS with `color: var(--color)`.", + ); + }); + + it('should error in case the passed in version is different from 4 or 5', async () => { + const content = await autofixer_tool_call(`whatever`, true, 3); + + expect(content.content).toBeDefined(); + expect(content.content[0]).toBeDefined(); + expect(content.content[0].text).toContain( + 'The desired_svelte_version MUST be either 4 or 5 but received "3"', + ); + }); +}); diff --git a/packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.ts b/packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.ts index 07c47821..31f9b832 100644 --- a/packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.ts +++ b/packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.ts @@ -90,6 +90,10 @@ export function svelte_autofixer(server: SvelteMcp) { content.suggestions.push( "The code can't be compiled because a Javascript parse error. In case you are using runes like this `$state variable_name = 3;` or `$derived variable_name = 3 * count` that's not how runes are used. You need to use them as function calls without importing them: `const variable_name = $state(3)` and `const variable_name = $derived(3 * count)`.", ); + } else if (error.message.includes('css_expected_identifier')) { + content.suggestions.push( + "The code can't be compiled because a valid CSS identifier is expected. This sometimes means you are trying to use a variable in CSS like this: `color: {my_color}` but Svelte doesn't support that. You can use inline CSS variables for that `
` and then use the variable as usual in CSS with `color: var(--color)`.", + ); } }