Skip to content

Commit 47fa0a4

Browse files
committed
fix: add $derived and $derived.by to wrong-property-access-state
1 parent 4c6232a commit 47fa0a4

File tree

2 files changed

+110
-104
lines changed

2 files changed

+110
-104
lines changed

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

Lines changed: 109 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,18 @@ function run_autofixers_on_code(code: string, desired_svelte_version = 5) {
1010
return content;
1111
}
1212

13+
function with_possible_inits(title: string, fn: (args: { init: string }) => void) {
14+
describe.each([
15+
{ init: '$state' },
16+
{ init: '$state.raw' },
17+
{ init: '$derived' },
18+
{ init: '$derived.by' },
19+
])(title, fn);
20+
}
21+
1322
describe('add_autofixers_issues', () => {
1423
describe('assign_in_effect', () => {
15-
describe.each([
16-
{ init: '$state' },
17-
{ init: '$state.raw' },
18-
{ init: '$derived' },
19-
{ init: '$derived.by' },
20-
])('($init)', ({ init }) => {
24+
with_possible_inits('($init)', ({ init }) => {
2125
it(`should add suggestions when assigning to a stateful variable inside an effect`, () => {
2226
const content = run_autofixers_on_code(`
2327
<script>
@@ -115,181 +119,183 @@ describe('add_autofixers_issues', () => {
115119
});
116120
});
117121

118-
describe.each([{ method: 'set' }, { method: 'update' }])(
119-
'wrong_property_access_state ($method)',
120-
({ method }) => {
121-
it(`should add suggestions when using .${method}() on a stateful variable with a literal init`, () => {
122-
const content = run_autofixers_on_code(`
122+
with_possible_inits('($init)', ({ init }) => {
123+
describe.each([{ method: 'set' }, { method: 'update' }])(
124+
'wrong_property_access_state ($method)',
125+
({ method }) => {
126+
it(`should add suggestions when using .${method}() on a stateful variable with a literal init`, () => {
127+
const content = run_autofixers_on_code(`
123128
<script>
124-
const count = $state(0);
129+
const count = ${init}(0);
125130
function update_count() {
126131
count.${method}(43);
127132
}
128133
</script>`);
129134

130-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
131-
expect(content.suggestions).toContain(
132-
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them.`,
133-
);
134-
});
135+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
136+
expect(content.suggestions).toContain(
137+
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them.`,
138+
);
139+
});
135140

136-
it(`should add suggestions when using .${method}() on a stateful variable with an array init`, () => {
137-
const content = run_autofixers_on_code(`
141+
it(`should add suggestions when using .${method}() on a stateful variable with an array init`, () => {
142+
const content = run_autofixers_on_code(`
138143
<script>
139-
const count = $state([0]);
144+
const count = ${init}([0]);
140145
function update_count() {
141146
count.${method}([1]);
142147
}
143148
</script>`);
144149

145-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
146-
expect(content.suggestions).toContain(
147-
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them.`,
148-
);
149-
});
150+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
151+
expect(content.suggestions).toContain(
152+
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them.`,
153+
);
154+
});
150155

151-
it(`should add suggestions when using .${method}() on a stateful variable with conditional if it's not sure if the method could actually be present on the variable ($state({}))`, () => {
152-
const content = run_autofixers_on_code(`
156+
it(`should add suggestions when using .${method}() on a stateful variable with conditional if it's not sure if the method could actually be present on the variable (${init}({}))`, () => {
157+
const content = run_autofixers_on_code(`
153158
<script>
154-
const count = $state({ value: 0 });
159+
const count = ${init}({ value: 0 });
155160
function update_count() {
156161
count.${method}({ value: 43 });
157162
}
158163
</script>`);
159164

160-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
161-
expect(content.suggestions).toContain(
162-
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
163-
);
164-
});
165+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
166+
expect(content.suggestions).toContain(
167+
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
168+
);
169+
});
165170

166-
it(`should add suggestions when using .${method}() on a stateful variable with conditional if it's not sure if the method could actually be present on the variable ($state(new Class()))`, () => {
167-
const content = run_autofixers_on_code(`
171+
it(`should add suggestions when using .${method}() on a stateful variable with conditional if it's not sure if the method could actually be present on the variable (${init}(new Class()))`, () => {
172+
const content = run_autofixers_on_code(`
168173
<script>
169-
const count = $state(new Class());
174+
const count = ${init}(new Class());
170175
function update_count() {
171176
count.${method}(new Class());
172177
}
173178
</script>`);
174179

175-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
176-
expect(content.suggestions).toContain(
177-
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
178-
);
179-
});
180+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
181+
expect(content.suggestions).toContain(
182+
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
183+
);
184+
});
180185

181-
it(`should add suggestions when using .${method}() on a stateful variable with conditional if it's not sure if the method could actually be present on the variable ($state(variable_name))`, () => {
182-
const content = run_autofixers_on_code(`
186+
it(`should add suggestions when using .${method}() on a stateful variable with conditional if it's not sure if the method could actually be present on the variable (${init}(variable_name))`, () => {
187+
const content = run_autofixers_on_code(`
183188
<script>
184189
const { init } = $props();
185-
const count = $state(init);
190+
const count = ${init}(init);
186191
function update_count() {
187192
count.${method}(43);
188193
}
189194
</script>`);
190195

191-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
192-
expect(content.suggestions).toContain(
193-
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
194-
);
195-
});
196+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
197+
expect(content.suggestions).toContain(
198+
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
199+
);
200+
});
196201

197-
it(`should not add suggestions when using .${method} on a stateful variable if it's not a method call`, () => {
198-
const content = run_autofixers_on_code(`
202+
it(`should not add suggestions when using .${method} on a stateful variable if it's not a method call`, () => {
203+
const content = run_autofixers_on_code(`
199204
<script>
200-
const count = $state({});
205+
const count = ${init}({});
201206
function update_count() {
202207
console.log(count.${method});
203208
}
204209
</script>`);
205210

206-
expect(content.suggestions).not.toContain(
207-
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
208-
);
209-
});
210-
},
211-
);
211+
expect(content.suggestions).not.toContain(
212+
`You are trying to update the stateful variable "count" using "${method}". stateful variables should be updated with a normal assignment/mutation, do not use methods to update them. However I can't verify if "count" is a state variable of an object or a class with a "${method}" method on it. Please verify that before updating the code to use a normal assignment`,
213+
);
214+
});
215+
},
216+
);
212217

213-
describe.each([{ property: '$' }])(
214-
'wrong_property_access_state property ($property)',
215-
async ({ property }) => {
216-
it(`should add suggestions when reading .${property} on a stateful variable with a literal init`, () => {
217-
const content = run_autofixers_on_code(`
218+
describe.each([{ property: '$' }])(
219+
'wrong_property_access_state property ($property)',
220+
async ({ property }) => {
221+
it(`should add suggestions when reading .${property} on a stateful variable with a literal init`, () => {
222+
const content = run_autofixers_on_code(`
218223
<script>
219-
const count = $state(0);
224+
const count = ${init}(0);
220225
function read_count() {
221226
count.${property};
222227
}
223228
</script>`);
224229

225-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
226-
expect(content.suggestions).toContain(
227-
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them.`,
228-
);
229-
});
230+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
231+
expect(content.suggestions).toContain(
232+
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them.`,
233+
);
234+
});
230235

231-
it(`should add suggestions when reading .${property} on a stateful variable with an array init`, () => {
232-
const content = run_autofixers_on_code(`
236+
it(`should add suggestions when reading .${property} on a stateful variable with an array init`, () => {
237+
const content = run_autofixers_on_code(`
233238
<script>
234-
const count = $state([1]);
239+
const count = ${init}([1]);
235240
function read_count() {
236241
count.${property};
237242
}
238243
</script>`);
239244

240-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
241-
expect(content.suggestions).toContain(
242-
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them.`,
243-
);
244-
});
245+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
246+
expect(content.suggestions).toContain(
247+
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them.`,
248+
);
249+
});
245250

246-
it(`should add suggestions when reading .${property} on a stateful variable with conditional if it's not sure if the property could actually be present on the variable ($state({}))`, () => {
247-
const content = run_autofixers_on_code(`
251+
it(`should add suggestions when reading .${property} on a stateful variable with conditional if it's not sure if the property could actually be present on the variable (${init}({}))`, () => {
252+
const content = run_autofixers_on_code(`
248253
<script>
249-
const count = $state({ value: 0 });
254+
const count = ${init}({ value: 0 });
250255
function read_count() {
251256
count.${property};
252257
}
253258
</script>`);
254259

255-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
256-
expect(content.suggestions).toContain(
257-
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them. However I can't verify if "count" is a state variable of an object or a class with a "${property}" property on it. Please verify that before updating the code to use a normal access`,
258-
);
259-
});
260+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
261+
expect(content.suggestions).toContain(
262+
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them. However I can't verify if "count" is a state variable of an object or a class with a "${property}" property on it. Please verify that before updating the code to use a normal access`,
263+
);
264+
});
260265

261-
it(`should add suggestions when reading .${property} on a stateful variable with conditional if it's not sure if the property could actually be present on the variable ($state(new Class()))`, () => {
262-
const content = run_autofixers_on_code(`
266+
it(`should add suggestions when reading .${property} on a stateful variable with conditional if it's not sure if the property could actually be present on the variable (${init}(new Class()))`, () => {
267+
const content = run_autofixers_on_code(`
263268
<script>
264-
const count = $state(new Class());
269+
const count = ${init}(new Class());
265270
function read_count() {
266271
count.${property};
267272
}
268273
</script>`);
269274

270-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
271-
expect(content.suggestions).toContain(
272-
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them. However I can't verify if "count" is a state variable of an object or a class with a "${property}" property on it. Please verify that before updating the code to use a normal access`,
273-
);
274-
});
275+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
276+
expect(content.suggestions).toContain(
277+
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them. However I can't verify if "count" is a state variable of an object or a class with a "${property}" property on it. Please verify that before updating the code to use a normal access`,
278+
);
279+
});
275280

276-
it(`should add suggestions when reading .${property} on a stateful variable with conditional if it's not sure if the property could actually be present on the variable ($state(variable_name))`, () => {
277-
const content = run_autofixers_on_code(`
281+
it(`should add suggestions when reading .${property} on a stateful variable with conditional if it's not sure if the property could actually be present on the variable (${init}(variable_name))`, () => {
282+
const content = run_autofixers_on_code(`
278283
<script>
279284
const { init } = $props();
280-
const count = $state(init);
285+
const count = ${init}(init);
281286
function read_count() {
282287
count.${property};
283288
}
284289
</script>`);
285290

286-
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
287-
expect(content.suggestions).toContain(
288-
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them. However I can't verify if "count" is a state variable of an object or a class with a "${property}" property on it. Please verify that before updating the code to use a normal access`,
289-
);
290-
});
291-
},
292-
);
291+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
292+
expect(content.suggestions).toContain(
293+
`You are trying to read the stateful variable "count" using "${property}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them. However I can't verify if "count" is a state variable of an object or a class with a "${property}" property on it. Please verify that before updating the code to use a normal access`,
294+
);
295+
});
296+
},
297+
);
298+
});
293299

294300
describe('imported_runes', () => {
295301
describe.each([{ source: 'svelte' }, { source: 'svelte/runes' }])(

packages/mcp-server/src/mcp/autofixers/visitors/wrong-property-access-state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const wrong_property_access_state: Autofixer = {
2222
const init = definition.node.init;
2323
if (
2424
init?.type === 'CallExpression' &&
25-
state.parsed.is_rune(init, ['$state', '$state.raw'])
25+
state.parsed.is_rune(init, ['$state', '$state.raw', '$derived', '$derived.by'])
2626
) {
2727
let suggestion = is_property
2828
? `You are trying to read the stateful variable "${id.name}" using "${node.property.name}". stateful variables should be read just by accessing them like normal variable, do not use properties to read them.`

0 commit comments

Comments
 (0)