mirror of
https://github.com/sveltejs/ai-tools.git
synced 2026-07-04 03:19:38 +08:00
Compare commits
1 Commits
@sveltejs/
...
better-imp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df7b64eb73 |
5
.changeset/tasty-mice-share.md
Normal file
5
.changeset/tasty-mice-share.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@sveltejs/mcp': patch
|
||||
---
|
||||
|
||||
fix: broaden checks for imported runes because LLMs are unhinged
|
||||
@@ -344,87 +344,111 @@ describe('add_autofixers_issues', () => {
|
||||
});
|
||||
|
||||
describe('imported_runes', () => {
|
||||
describe.each([{ source: 'svelte' }, { source: 'svelte/runes' }])(
|
||||
'from "$source"',
|
||||
({ source }) => {
|
||||
describe.each(dollarless_runes)('single import ($rune)', ({ rune }) => {
|
||||
it(`should add suggestions when importing '${rune}' from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
describe.each([
|
||||
{ source: 'svelte' },
|
||||
{ source: 'svelte/runes' },
|
||||
{ source: '@sveltejs/runes' },
|
||||
{ source: '@sveltejs/vite-plugin-svelte' },
|
||||
])('from "$source"', ({ source }) => {
|
||||
describe.each(dollarless_runes)('single import ($rune)', ({ rune }) => {
|
||||
it(`should add suggestions when importing '${rune}' from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import { ${rune} } from '${source}';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
);
|
||||
});
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
);
|
||||
});
|
||||
|
||||
it(`should add suggestions when importing "${rune}" as the default export from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
it(`should add suggestions when importing "${rune}" as the default export from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import ${rune} from '${source}';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
);
|
||||
});
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
);
|
||||
});
|
||||
|
||||
it(`should add suggestions when importing '${rune}' as the namespace export from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
it(`should add suggestions when importing '${rune}' as the namespace export from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import * as ${rune} from '${source}';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
);
|
||||
});
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it(`should add suggestions when importing multiple runes from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
it(`should add suggestions when importing multiple runes from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import { onMount, state, effect } from '${source}';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(2);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "state" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$state" directly.`,
|
||||
);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "effect" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$effect" directly.`,
|
||||
);
|
||||
});
|
||||
expect(content.suggestions.length).toBeGreaterThanOrEqual(2);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "state" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$state" directly.`,
|
||||
);
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "effect" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$effect" directly.`,
|
||||
);
|
||||
});
|
||||
|
||||
it(`should not add suggestions when importing other identifiers from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
it(`should not add suggestions when importing other identifiers from '${source}'`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import { onMount } from '${source}';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions).not.toContain(
|
||||
`You are importing "onMount" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$onMount" directly.`,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
expect(content.suggestions).not.toContain(
|
||||
`You are importing "onMount" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$onMount" directly.`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe.each(dollarless_runes)('importing $rune from external lib', ({ rune }) => {
|
||||
it(`should not add suggestions when importing from packages that are not svelte`, () => {
|
||||
it(`should not add suggestions when importing from packages whose name doesn't contain svelte`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import { ${rune} } from 'something-something';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions).not.toContain(
|
||||
`You are importing "${rune}" from "something-something". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
);
|
||||
});
|
||||
|
||||
it(`should add suggestions with a different hint when importing from packages whose name contains svelte but it's not official`, () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import { ${rune} } from 'svelte-something-something';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions).not.toContain(
|
||||
`You are importing "${rune}" from "svelte-something-something". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
|
||||
expect(content.suggestions).toContain(
|
||||
`You are importing "${rune}" from "svelte-something-something". If you are trying to import runes to use them this is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly. If you are importing the function from a separate library ignore this suggestion.`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not add the imported_runes suggestion when importing derived from svelte/store', () => {
|
||||
const content = run_autofixers_on_code(`
|
||||
<script>
|
||||
import { derived } from 'svelte/store';
|
||||
</script>`);
|
||||
|
||||
expect(content.suggestions).not.toContain(
|
||||
'You are importing "derived" from "svelte/store". This is not necessary, all runes are globally available. Please remove this import and use "$derived" directly.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('derived_with_function', () => {
|
||||
|
||||
@@ -3,10 +3,20 @@ import type { Autofixer } from './index.js';
|
||||
|
||||
const dollarless_runes = base_runes.map((r) => r.replace('$', ''));
|
||||
|
||||
function should_suggest_for_source(source: string, rune: string) {
|
||||
if (!source.includes('svelte')) {
|
||||
return false;
|
||||
}
|
||||
if (source === 'svelte/store' && rune === 'derived') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export const imported_runes: Autofixer = {
|
||||
ImportDeclaration(node, { state, next }) {
|
||||
const source = (node.source.value || node.source.raw?.slice(1, -1))?.toString();
|
||||
if (source && (source === 'svelte' || source.startsWith('svelte/'))) {
|
||||
if (source) {
|
||||
for (const specifier of node.specifiers) {
|
||||
const id =
|
||||
specifier.type === 'ImportDefaultSpecifier'
|
||||
@@ -16,10 +26,25 @@ export const imported_runes: Autofixer = {
|
||||
: specifier.type === 'ImportSpecifier'
|
||||
? specifier.imported
|
||||
: null;
|
||||
if (id && id.type === 'Identifier' && dollarless_runes.includes(id.name)) {
|
||||
state.output.suggestions.push(
|
||||
`You are importing "${id.name}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${id.name}" directly.`,
|
||||
);
|
||||
if (
|
||||
id &&
|
||||
id.type === 'Identifier' &&
|
||||
dollarless_runes.includes(id.name) &&
|
||||
should_suggest_for_source(source, id.name)
|
||||
) {
|
||||
if (
|
||||
source === 'svelte' ||
|
||||
source.startsWith('svelte/') ||
|
||||
source.startsWith('@sveltejs')
|
||||
) {
|
||||
state.output.suggestions.push(
|
||||
`You are importing "${id.name}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${id.name}" directly.`,
|
||||
);
|
||||
} else {
|
||||
state.output.suggestions.push(
|
||||
`You are importing "${id.name}" from "${source}". If you are trying to import runes to use them this is not necessary, all runes are globally available. Please remove this import and use "$${id.name}" directly. If you are importing the function from a separate library ignore this suggestion.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user