Skip to content

Commit d42c901

Browse files
committed
fix: add async parameter to svelte-autofixer
1 parent 3c7b503 commit d42c901

File tree

7 files changed

+98
-7
lines changed

7 files changed

+98
-7
lines changed

.changeset/icy-queens-greet.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/mcp': patch
3+
---
4+
5+
fix: add `async` parameter to `svelte-autofixer`

packages/mcp-server/src/mcp/autofixers/add-autofixers-issues.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ export function add_autofixers_issues(
88
code: string,
99
desired_svelte_version: number,
1010
filename = 'Component.svelte',
11+
async = false,
1112
) {
1213
const parsed = parse(code, filename);
1314

1415
// Run each autofixer separately to avoid interrupting logic flow
1516
for (const autofixer of Object.values(autofixers)) {
1617
walk(
1718
parsed.ast as unknown as Node,
18-
{ output: content, parsed, desired_svelte_version },
19+
{ output: content, parsed, desired_svelte_version, async },
1920
autofixer,
2021
);
2122
}

packages/mcp-server/src/mcp/autofixers/add-compile-issues.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export function add_compile_issues(
77
code: string,
88
desired_svelte_version: number,
99
filename = 'Component.svelte',
10+
async = false,
1011
) {
1112
let compile = compile_component;
1213
const extension = extname(filename);
@@ -27,6 +28,7 @@ export function add_compile_issues(
2728
filename: filename || 'Component.svelte',
2829
generate: false,
2930
runes: desired_svelte_version >= 5,
31+
experimental: { async },
3032
});
3133

3234
for (const warning of compilation_result.warnings) {

packages/mcp-server/src/mcp/autofixers/add-eslint-issues.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function base_config(svelte_config: Config): ESLint.Options['baseConfig'] {
5151
];
5252
}
5353

54-
function get_linter(version: number) {
54+
function get_linter(version: number, async = false) {
5555
if (version < 5) {
5656
return (svelte_4_linter ??= new ESLint({
5757
overrideConfigFile: true,
@@ -67,6 +67,7 @@ function get_linter(version: number) {
6767
baseConfig: base_config({
6868
compilerOptions: {
6969
runes: true,
70+
experimental: { async },
7071
},
7172
}),
7273
}));
@@ -77,8 +78,9 @@ export async function add_eslint_issues(
7778
code: string,
7879
desired_svelte_version: number,
7980
filename = 'Component.svelte',
81+
async = false,
8082
) {
81-
const eslint = get_linter(desired_svelte_version);
83+
const eslint = get_linter(desired_svelte_version, async);
8284
const results = await eslint.lintText(code, { filePath: filename || './Component.svelte' });
8385

8486
for (const message of results[0]?.messages ?? []) {

packages/mcp-server/src/mcp/autofixers/visitors/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type AutofixerState = {
77
output: { issues: string[]; suggestions: string[] };
88
parsed: ParseResult;
99
desired_svelte_version: number;
10+
async?: boolean;
1011
};
1112

1213
export type Autofixer = Visitors<Node | AST.SvelteNode, AutofixerState>;

packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.test.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ function request<const T>(request: T) {
88
return request;
99
}
1010

11-
async function autofixer_tool_call(code: string, is_error = false, desired_svelte_version = 5) {
11+
async function autofixer_tool_call(
12+
code: string,
13+
is_error = false,
14+
desired_svelte_version = 5,
15+
async = false,
16+
) {
1217
const result = await server.receive({
1318
jsonrpc: '2.0',
1419
id: 2,
@@ -19,6 +24,7 @@ async function autofixer_tool_call(code: string, is_error = false, desired_svelt
1924
code,
2025
desired_svelte_version,
2126
filename: 'App.svelte',
27+
async,
2228
},
2329
},
2430
});
@@ -65,6 +71,61 @@ describe('svelte-autofixer tool', () => {
6571
);
6672
});
6773

74+
it('should error out if async is true with a version less than 5', async () => {
75+
const content = await autofixer_tool_call(
76+
`<script>
77+
$state count = 0;
78+
</script>`,
79+
true,
80+
4,
81+
true,
82+
);
83+
expect(content.isError).toBeTruthy();
84+
expect(content.content[0]).toBeDefined();
85+
expect(content.content[0].text).toBe(
86+
'The async option can only be used with Svelte version 5 or higher.',
87+
);
88+
});
89+
90+
it('should not add suggestion/issues if async is true and await is used in the template/derived', async () => {
91+
const content = await autofixer_tool_call(
92+
`<script>
93+
import { slow_double } from './utils.js';
94+
let count = $state(0);
95+
let double = $derived(await slow_double(count));
96+
</script>
97+
98+
{double}
99+
{await slow_double(count)}`,
100+
false,
101+
5,
102+
true,
103+
);
104+
expect(content.issues).toHaveLength(0);
105+
expect(content.suggestions).toHaveLength(0);
106+
expect(content.require_another_tool_call_after_fixing).toBeFalsy();
107+
});
108+
109+
it('should add suggestion/issues if async is false and await is used in the template/derived', async () => {
110+
const content = await autofixer_tool_call(
111+
`<script>
112+
import { slow_double } from './utils.js';
113+
let count = $state(0);
114+
let double = $derived(await slow_double(count));
115+
</script>
116+
117+
{double}
118+
{await slow_double(count)}`,
119+
false,
120+
5,
121+
);
122+
expect(content.issues.length).toBeGreaterThanOrEqual(1);
123+
expect(content.issues).toEqual(
124+
expect.arrayContaining([expect.stringContaining('experimental_async')]),
125+
);
126+
expect(content.require_another_tool_call_after_fixing).toBeTruthy();
127+
});
128+
68129
it('should add suggestions for css invalid identifier', async () => {
69130
const content = await autofixer_tool_call(`<script>
70131
let my_color = $state('red');

packages/mcp-server/src/mcp/handlers/tools/svelte-autofixer.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ export function svelte_autofixer(server: SvelteMcp) {
2121
'The desired svelte version...if possible read this from the package.json of the user project, otherwise use some hint from the wording (if the user asks for runes it wants version 5). Default to 5 in case of doubt.',
2222
),
2323
),
24+
async: v.pipe(
25+
v.optional(v.boolean()),
26+
v.description(
27+
'If true the code is an async component/module and might use await in the markup or top-level awaits in the script tag. If possible check the svelte.config.js/svelte.config.ts to check if the option is enabled otherwise asks the user if they prefer using it or not. You can only use this option if the version is 5.',
28+
),
29+
),
2430
filename: v.pipe(
2531
v.optional(v.string()),
2632
v.description(
@@ -45,6 +51,7 @@ export function svelte_autofixer(server: SvelteMcp) {
4551
code,
4652
filename: filename_or_path,
4753
desired_svelte_version: desired_svelte_version_unchecked,
54+
async,
4855
}) => {
4956
if (server.ctx.sessionId && server.ctx.custom?.track) {
5057
await server.ctx.custom?.track?.(server.ctx.sessionId, 'svelte-autofixer');
@@ -71,6 +78,18 @@ export function svelte_autofixer(server: SvelteMcp) {
7178

7279
const desired_svelte_version = parsed_version.output;
7380

81+
if (async && +desired_svelte_version < 5) {
82+
return {
83+
isError: true,
84+
content: [
85+
{
86+
type: 'text',
87+
text: `The async option can only be used with Svelte version 5 or higher.`,
88+
},
89+
],
90+
};
91+
}
92+
7493
const content: {
7594
issues: string[];
7695
suggestions: string[];
@@ -82,11 +101,11 @@ export function svelte_autofixer(server: SvelteMcp) {
82101

83102
const filename = filename_or_path ? basename(filename_or_path) : 'Component.svelte';
84103

85-
add_compile_issues(content, code, +desired_svelte_version, filename);
104+
add_compile_issues(content, code, +desired_svelte_version, filename, async);
86105

87-
add_autofixers_issues(content, code, +desired_svelte_version, filename);
106+
add_autofixers_issues(content, code, +desired_svelte_version, filename, async);
88107

89-
await add_eslint_issues(content, code, +desired_svelte_version, filename);
108+
await add_eslint_issues(content, code, +desired_svelte_version, filename, async);
90109
} catch (e: unknown) {
91110
const error = e as Error & { start?: { line: number; column: number } };
92111
content.issues.push(

0 commit comments

Comments
 (0)