Compare commits

...

2 Commits

Author SHA1 Message Date
paoloricciuti
a321244543 feat: suggest against js variables in css 2025-10-17 15:31:35 +02:00
paoloricciuti
ed25933466 fix: use right url + add manual triggering 2025-10-17 08:24:31 +02:00
4 changed files with 105 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
---
'@sveltejs/mcp': patch
---
feat: suggest against js variables in css

View File

@@ -5,6 +5,7 @@ on:
secrets:
MCP_KEY:
required: true
workflow_dispatch:
jobs:
publish-mcp:
@@ -19,7 +20,7 @@ jobs:
env:
MCP_KEY: ${{ secrets.MCP_KEY }}
run: |
NAME=mcp-publisher_1.3.3_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz
NAME=mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz
# Download MCP Publisher pinned to v1.3.3 using latest https for security and save it to a file named mcp-publisher.tar.gz
curl --proto '=https' --proto-redir '=https' --tlsv1.2 -fL "https://github.com/modelcontextprotocol/registry/releases/download/v1.3.3/$NAME" -O

View File

@@ -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<const T>(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(`<script>
$state count = 0;
</script>`);
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(`<script>
let my_color = $state('red');
</script>
<style>
.my-class {
color: {my_color};
}
</style>`);
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 `<div style:--color={my_color}></div>` 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"',
);
});
});

View File

@@ -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 `<div style:--color={my_color}></div>` and then use the variable as usual in CSS with `color: var(--color)`.",
);
}
}