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 f38dc58f3..7c643a069 100644 --- a/packages/sv/src/addons/better-auth.ts +++ b/packages/sv/src/addons/better-auth.ts @@ -297,8 +297,8 @@ export default defineAddon({ ? ` signInEmail: async (event) => {${d1AuthLine} const formData = await event.request.formData(); - const email = formData.get('email')?.toString() ?? ''; - const password = formData.get('password')?.toString() ?? ''; + const email = typeof formData.get('email') === 'string' ? formData.get('email') : ''; + const password = typeof formData.get('password') === 'string' ? formData.get('password') : ''; try { await auth.api.signInEmail({ @@ -319,9 +319,9 @@ export default defineAddon({ }, signUpEmail: async (event) => {${d1AuthLine} const formData = await event.request.formData(); - const email = formData.get('email')?.toString() ?? ''; - const password = formData.get('password')?.toString() ?? ''; - const name = formData.get('name')?.toString() ?? ''; + const email = typeof formData.get('email') === 'string' ? formData.get('email') : ''; + const password = typeof formData.get('password') === 'string' ? formData.get('password') : ''; + const name = typeof formData.get('name') === 'string' ? formData.get('name') : ''; try { await auth.api.signUpEmail({ @@ -347,8 +347,9 @@ export default defineAddon({ ? ` signInSocial: async (event) => {${d1AuthLine} const formData = await event.request.formData(); - const provider = formData.get('provider')?.toString() ?? 'github'; - const callbackURL = formData.get('callbackURL')?.toString() ?? '/demo/better-auth'; + + const provider = typeof formData.get('provider') === 'string' ? formData.get('provider') : 'github'; + const callbackURL = typeof formData.get('callbackURL') === 'string' ? formData.get('callbackURL') : '/demo/better-auth'; const result = await auth.api.signInSocial({ body: { @@ -373,7 +374,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'); } @@ -465,7 +466,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 23605fe11..beba5ae6d 100644 --- a/packages/sv/src/addons/common.ts +++ b/packages/sv/src/addons/common.ts @@ -16,19 +16,42 @@ export function addEslintConfigPrettier(content: string): string { 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 content; + } const prettier = js.common.parseExpression('prettier'); const sveltePrettierConfig = js.common.parseExpression(`${svelteImportName}.configs.prettier`); @@ -38,19 +61,25 @@ export function addEslintConfigPrettier(content: string): string { 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 f57eec50f..322b7c6ca 100644 --- a/packages/sv/src/addons/eslint.ts +++ b/packages/sv/src/addons/eslint.ts @@ -109,6 +109,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/rule-name': '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..2687e9fd1 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/rule-name': '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..4a884034a 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'); } @@ -14,8 +14,8 @@ export const load: PageServerLoad = async (event) => { export const actions: Actions = { signInEmail: async (event) => { const formData = await event.request.formData(); - const email = formData.get('email')?.toString() ?? ''; - const password = formData.get('password')?.toString() ?? ''; + const email = typeof formData.get('email') === 'string' ? formData.get('email') : ''; + const password = typeof formData.get('password') === 'string' ? formData.get('password') : ''; try { await auth.api.signInEmail({ @@ -36,9 +36,9 @@ export const actions: Actions = { }, signUpEmail: async (event) => { const formData = await event.request.formData(); - const email = formData.get('email')?.toString() ?? ''; - const password = formData.get('password')?.toString() ?? ''; - const name = formData.get('name')?.toString() ?? ''; + const email = typeof formData.get('email') === 'string' ? formData.get('email') : ''; + const password = typeof formData.get('password') === 'string' ? formData.get('password') : ''; + const name = typeof formData.get('name') === 'string' ? formData.get('name') : ''; try { await auth.api.signUpEmail({ @@ -60,8 +60,9 @@ export const actions: Actions = { }, signInSocial: async (event) => { const formData = await event.request.formData(); - const provider = formData.get('provider')?.toString() ?? 'github'; - const callbackURL = formData.get('callbackURL')?.toString() ?? '/demo/better-auth'; + + const provider = typeof formData.get('provider') === 'string' ? formData.get('provider') : 'github'; + const callbackURL = typeof formData.get('callbackURL') === 'string' ? formData.get('callbackURL') : '/demo/better-auth'; const result = await auth.api.signInSocial({ body: {