Skip to content

Commit 9f580a3

Browse files
committed
feat: add use runes instead of stores autofixer
1 parent f04cb13 commit 9f580a3

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

src/lib/mcp/autofixers/add-autofixers-issues.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,34 @@ describe('add_autofixers_issues', () => {
344344
);
345345
});
346346
});
347+
348+
describe('use_runes_instead_of_store', () => {
349+
describe.each([{ import: 'derived' }, { import: 'writable' }, { import: 'readable' }])(
350+
'importing $import from svelte/store',
351+
({ import: imported }) => {
352+
it(`should add suggestions when importing '${imported}' from 'svelte/store'`, () => {
353+
const content = run_autofixers_on_code(`
354+
<script>
355+
import { ${imported} } from 'svelte/store';
356+
</script>`);
357+
358+
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
359+
expect(content.suggestions).toContain(
360+
`You are importing "${imported}" from "svelte/store". Unless the user specifically asked for stores or it's required because some library/component requires a store as input consider using runes like \`$state\` or \`$derived\` instead, all runes are globally available.`,
361+
);
362+
});
363+
},
364+
);
365+
366+
it(`should not add suggestions when importing other identifiers from 'svelte/store'`, () => {
367+
const content = run_autofixers_on_code(`
368+
<script>
369+
import { get } from 'svelte/store';
370+
</script>`);
371+
372+
expect(content.suggestions).not.toContain(
373+
`You are importing "get" from "svelte/store". Unless the user specifically asked for stores or it's required because some library/component requires a store as input consider using runes like \`$state\` or \`$derived\` instead, all runes are globally available.`,
374+
);
375+
});
376+
});
347377
});

src/lib/mcp/autofixers/visitors/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ export * from './assign-in-effect.js';
1515
export * from './set-or-update-state.js';
1616
export * from './imported-runes.js';
1717
export * from './derived-with-function.js';
18+
export * from './use-runes-instead-of-store.js';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { Autofixer } from '.';
2+
3+
export const use_runes_instead_of_store: Autofixer = {
4+
ImportDeclaration(node, { state, next }) {
5+
const source = (node.source.value || node.source.raw?.slice(1, -1))?.toString();
6+
if (source && source === 'svelte/store') {
7+
for (const specifier of node.specifiers) {
8+
if (
9+
specifier.type === 'ImportSpecifier' &&
10+
specifier.imported.type === 'Identifier' &&
11+
['derived', 'writable', 'readable'].includes(specifier.imported.name)
12+
) {
13+
state.output.suggestions.push(
14+
`You are importing "${specifier.imported.name}" from "svelte/store". Unless the user specifically asked for stores or it's required because some library/component requires a store as input consider using runes like \`$state\` or \`$derived\` instead, all runes are globally available.`,
15+
);
16+
}
17+
}
18+
}
19+
next();
20+
},
21+
};

0 commit comments

Comments
 (0)