diff --git a/src/lib/mcp/autofixers/add-autofixers-issues.test.ts b/src/lib/mcp/autofixers/add-autofixers-issues.test.ts index fa8e56a..cceaf19 100644 --- a/src/lib/mcp/autofixers/add-autofixers-issues.test.ts +++ b/src/lib/mcp/autofixers/add-autofixers-issues.test.ts @@ -344,4 +344,34 @@ describe('add_autofixers_issues', () => { ); }); }); + + describe('use_runes_instead_of_store', () => { + describe.each([{ import: 'derived' }, { import: 'writable' }, { import: 'readable' }])( + 'importing $import from svelte/store', + ({ import: imported }) => { + it(`should add suggestions when importing '${imported}' from 'svelte/store'`, () => { + const content = run_autofixers_on_code(` + `); + + expect(content.suggestions.length).toBeGreaterThanOrEqual(1); + expect(content.suggestions).toContain( + `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.`, + ); + }); + }, + ); + + it(`should not add suggestions when importing other identifiers from 'svelte/store'`, () => { + const content = run_autofixers_on_code(` + `); + + expect(content.suggestions).not.toContain( + `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.`, + ); + }); + }); }); diff --git a/src/lib/mcp/autofixers/visitors/index.ts b/src/lib/mcp/autofixers/visitors/index.ts index 5f2e3e2..b29f303 100644 --- a/src/lib/mcp/autofixers/visitors/index.ts +++ b/src/lib/mcp/autofixers/visitors/index.ts @@ -15,3 +15,4 @@ export * from './assign-in-effect.js'; export * from './set-or-update-state.js'; export * from './imported-runes.js'; export * from './derived-with-function.js'; +export * from './use-runes-instead-of-store.js'; diff --git a/src/lib/mcp/autofixers/visitors/use-runes-instead-of-store.ts b/src/lib/mcp/autofixers/visitors/use-runes-instead-of-store.ts new file mode 100644 index 0000000..79deb6b --- /dev/null +++ b/src/lib/mcp/autofixers/visitors/use-runes-instead-of-store.ts @@ -0,0 +1,21 @@ +import type { Autofixer } from '.'; + +export const use_runes_instead_of_store: Autofixer = { + ImportDeclaration(node, { state, next }) { + const source = (node.source.value || node.source.raw?.slice(1, -1))?.toString(); + if (source && source === 'svelte/store') { + for (const specifier of node.specifiers) { + if ( + specifier.type === 'ImportSpecifier' && + specifier.imported.type === 'Identifier' && + ['derived', 'writable', 'readable'].includes(specifier.imported.name) + ) { + state.output.suggestions.push( + `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.`, + ); + } + } + } + next(); + }, +};