diff --git a/.changeset/fluffy-donuts-hope.md b/.changeset/fluffy-donuts-hope.md new file mode 100644 index 000000000..36fcdd43a --- /dev/null +++ b/.changeset/fluffy-donuts-hope.md @@ -0,0 +1,5 @@ +--- +"sv": patch +--- + +fix(eslint): properly handle configs that doesn't use `defineConfig` diff --git a/documentation/docs/30-add-ons/10-eslint.md b/documentation/docs/30-add-ons/10-eslint.md index d12aed33f..70438105d 100644 --- a/documentation/docs/30-add-ons/10-eslint.md +++ b/documentation/docs/30-add-ons/10-eslint.md @@ -14,5 +14,5 @@ npx sv add eslint - the relevant packages installed including `eslint-plugin-svelte` - an `eslint.config.js` file -- updated `.vscode/settings.json` +- updated `.vscode/extensions.json` - configured to work with TypeScript and `prettier` if you're using those packages diff --git a/packages/sv/src/addons/better-auth.ts b/packages/sv/src/addons/better-auth.ts index 838a407d3..3b08d70c4 100644 --- a/packages/sv/src/addons/better-auth.ts +++ b/packages/sv/src/addons/better-auth.ts @@ -381,7 +381,7 @@ export default defineAddon({ ${!d1 ? "import { auth } from '$lib/server/auth';" : ''} ${needsAPIError ? "import { APIError } from 'better-auth/api';" : ''} - export const load${ts(': PageServerLoad')} = async (event) => { + export const load${ts(': PageServerLoad')} = (event) => { if (event.locals.user) { return redirect(302, '/demo/better-auth'); } @@ -473,7 +473,7 @@ export default defineAddon({ ${ts("import type { PageServerLoad } from './$types';")} ${!d1 ? "import { auth } from '$lib/server/auth';" : ''} - export const load${ts(': PageServerLoad')} = async (event) => { + export const load${ts(': PageServerLoad')} = (event) => { if (!event.locals.user) { return redirect(302, '/demo/better-auth/login'); } diff --git a/packages/sv/src/addons/common.ts b/packages/sv/src/addons/common.ts index 664dcdefc..59431341f 100644 --- a/packages/sv/src/addons/common.ts +++ b/packages/sv/src/addons/common.ts @@ -14,19 +14,42 @@ export const addEslintConfigPrettier = transforms.script(({ ast, js }) => { let svelteImportName: string; for (const specifier of sveltePluginImport?.specifiers ?? []) { if (specifier.type === 'ImportDefaultSpecifier' && specifier.local?.name) { - svelteImportName = specifier.local.name as string; + svelteImportName = specifier.local.name; } } - svelteImportName ??= 'svelte'; + js.imports.addDefault(ast, { from: 'eslint-plugin-svelte', as: svelteImportName }); js.imports.addDefault(ast, { from: 'eslint-config-prettier', as: 'prettier' }); const fallbackConfig = js.common.parseExpression('[]'); const defaultExport = js.exports.createDefault(ast, { fallback: fallbackConfig }); const eslintConfig = defaultExport.value; - if (eslintConfig.type !== 'ArrayExpression' && eslintConfig.type !== 'CallExpression') + + type Elements = + | Extract['arguments'] + | Extract['elements']; + + let elements: Elements = []; + + if (eslintConfig.type === 'ArrayExpression') { + // export default [...] + elements = eslintConfig.elements; + } else if (eslintConfig.type === 'CallExpression') { + if ( + eslintConfig.arguments.length === 1 && + eslintConfig.arguments[0].type === 'ArrayExpression' + ) { + // export default defineConfig([...]) + elements = eslintConfig.arguments[0].elements; + } else { + // export default defineConfig({...}) + elements = eslintConfig.arguments; + } + } else { + // fallback: Not an array or a function call return false; + } const prettier = js.common.parseExpression('prettier'); const sveltePrettierConfig = js.common.parseExpression(`${svelteImportName}.configs.prettier`); @@ -36,19 +59,25 @@ export const addEslintConfigPrettier = transforms.script(({ ast, js }) => { if (!js.common.contains(eslintConfig, sveltePrettierConfig)) nodesToInsert.push(sveltePrettierConfig); - const elements = - eslintConfig.type === 'ArrayExpression' ? eslintConfig.elements : eslintConfig.arguments; - // finds index of `svelte.configs["..."]` - const idx = elements.findIndex( - (el) => + const isSvelteConfig = (maybeSpread: Elements[number]) => { + const el = + maybeSpread?.type === 'SpreadElement' + ? // ...svelte.configs.* + maybeSpread?.argument + : // svelte.configs.* + maybeSpread; + return ( el?.type === 'MemberExpression' && el.object.type === 'MemberExpression' && - el.object.property.type === 'Identifier' && - el.object.property.name === 'configs' && + // Check for [svelte].configs.* el.object.object.type === 'Identifier' && - el.object.object.name === svelteImportName - ); - + el.object.object.name === svelteImportName && + // Check for svelte.[configs].* + el.object.property.type === 'Identifier' && + el.object.property.name === 'configs' + ); + }; + const idx = elements.findIndex(isSvelteConfig); if (idx !== -1) { elements.splice(idx + 1, 0, ...nodesToInsert); } else { diff --git a/packages/sv/src/addons/eslint.ts b/packages/sv/src/addons/eslint.ts index 45855a28c..58b1d00a4 100644 --- a/packages/sv/src/addons/eslint.ts +++ b/packages/sv/src/addons/eslint.ts @@ -108,6 +108,23 @@ export default defineAddon({ eslintConfigs.push(svelteTSParserConfig); } + const rulesOverride = js.object.create({ + rules: {} + }); + eslintConfigs.push(rulesOverride); + + if (rulesOverride.properties[0].type !== 'Property') { + throw new Error('rulesOverride.properties[0].type !== "Property"'); + } + comments.add(rulesOverride.properties[0].key, { + type: 'Line', + value: ' Override or add rule settings here, such as:' + }); + comments.add(rulesOverride.properties[0].key, { + type: 'Line', + value: " 'svelte/button-has-type': 'error'" + }); + const exportExpression = js.functions.createCall({ name: 'defineConfig', args: [] }); if (typescript) { exportExpression.arguments.push(...eslintConfigs); diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/eslint.config.js b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/eslint.config.js index bd3865858..50991ca60 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/eslint.config.js +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/eslint.config.js @@ -35,5 +35,10 @@ export default defineConfig( svelteConfig } } + }, + { + // Override or add rule settings here, such as: + // 'svelte/button-has-type': 'error' + rules: {} } ); diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/+page.server.ts b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/+page.server.ts index 7c3083543..92a1f2ec3 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/+page.server.ts +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/+page.server.ts @@ -3,7 +3,7 @@ import type { Actions } from './$types'; import type { PageServerLoad } from './$types'; import { auth } from '$lib/server/auth'; -export const load: PageServerLoad = async (event) => { +export const load: PageServerLoad = (event) => { if (!event.locals.user) { return redirect(302, '/demo/better-auth/login'); } diff --git a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/login/+page.server.ts b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/login/+page.server.ts index 2ddbc0e7c..d97509ba9 100644 --- a/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/login/+page.server.ts +++ b/packages/sv/src/cli/tests/snapshots/create-with-all-addons/src/routes/demo/better-auth/login/+page.server.ts @@ -4,7 +4,7 @@ import type { PageServerLoad } from './$types'; import { auth } from '$lib/server/auth'; import { APIError } from 'better-auth/api'; -export const load: PageServerLoad = async (event) => { +export const load: PageServerLoad = (event) => { if (event.locals.user) { return redirect(302, '/demo/better-auth'); }