Repository: sveltejs/eslint-plugin-svelte
Pull request #1013 (2025-01-12 08:15:02)

feat: add Svelte 5 support to `no-not-function-handler`
I updated docs also. (`on:click` -> `onclick`)

![image](https://github.com/user-attachments/assets/21d54758-b9ca-43cb-8f32-18172f4db303)


changeset-bot[bot]: ###  🦋  Changeset detected

Latest commit: f7a35562e8d0058865ed39d86016a1926ff06ccc

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name                 | Type  |
| -------------------- | ----- |
| eslint-plugin-svelte | Minor |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/sveltejs/eslint-plugin-svelte/new/feat/no-not-function-handler?filename=.changeset/spotty-cars-beg.md&value=---%0A%22eslint-plugin-svelte%22%3A%20patch%0A---%0A%0Afeat%3A%20add%20Svelte%205%20support%20to%20%60no-not-function-handler%60%0A)


pkg-pr-new[bot]: 
[Open in Stackblitz](https://pkg.pr.new/template/2df0cf7a-d394-4b2a-9446-b719fce82d6a)


```
npm i https://pkg.pr.new/eslint-plugin-svelte@1013
```


_commit: <a href="https://github.com/sveltejs/eslint-plugin-svelte/runs/35486257025"><code>f7a3556</code></a>_


Patch:
diff --git a/.changeset/brown-dots-change.md b/.changeset/brown-dots-change.md
new file mode 100644
index 0000000..dfa797d
--- /dev/null
+++ b/.changeset/brown-dots-change.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-svelte': minor
+---
+
+feat: add Svelte 5 support to `no-not-function-handler`
diff --git a/.changeset/pre.json b/.changeset/pre.json
index 9d54d47..19d9012 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -11,10 +11,14 @@
     "cold-starfishes-doubt",
     "cool-rockets-allow",
     "cool-steaks-happen",
+    "cool-tomatoes-fry",
+    "early-trainers-know",
     "eighty-trainers-push",
     "fast-coins-fly",
     "fifty-parents-itch",
+    "great-turkeys-hang",
     "green-squids-compete",
+    "grumpy-deers-film",
     "hip-avocados-call",
     "hungry-grapes-shave",
     "itchy-dragons-boil",
@@ -23,11 +27,16 @@
     "nice-clocks-buy",
     "olive-melons-explain",
     "olive-spiders-type",
+    "olive-squids-design",
     "olive-wolves-travel",
+    "perfect-mirrors-doubt",
     "quiet-toys-burn",
+    "red-jokes-tickle",
     "sixty-news-look",
     "small-days-agree",
     "small-donuts-end",
+    "smart-apes-confess",
+    "smart-brooms-relax",
     "soft-bears-hear",
     "thick-items-retire",
     "thin-dryers-know",
diff --git a/docs/rules/consistent-selector-style.md b/docs/rules/consistent-selector-style.md
index 12f7990..5b46706 100644
--- a/docs/rules/consistent-selector-style.md
+++ b/docs/rules/consistent-selector-style.md
@@ -3,14 +3,13 @@ pageClass: 'rule-details'
 sidebarDepth: 0
 title: 'svelte/consistent-selector-style'
 description: 'enforce a consistent style for CSS selectors'
+since: 'v3.0.0-next.15'
 ---
 
 # svelte/consistent-selector-style
 
 > enforce a consistent style for CSS selectors
 
-- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
-
 ## :book: Rule Details
 
 This rule allows you to set a preferred style for your CSS (& other style language) selectors. In CSS, there is a wide list of options for selecting elements, however, the three most basic types are:
@@ -92,6 +91,10 @@ This rule allows you to set a preferred style for your CSS (& other style langua
 
 - [CSS selector documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors)
 
+## :rocket: Version
+
+This rule was introduced in eslint-plugin-svelte v3.0.0-next.15
+
 ## :mag: Implementation
 
 - [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/consistent-selector-style.ts)
diff --git a/docs/rules/no-not-function-handler.md b/docs/rules/no-not-function-handler.md
index 3162a42..c1736a0 100644
--- a/docs/rules/no-not-function-handler.md
+++ b/docs/rules/no-not-function-handler.md
@@ -29,16 +29,16 @@ If you use a non-function value for the event handler, it event handler will not
 </script>
 
 <!-- ✓ GOOD -->
-<button on:click={foo} />
+<button onclick={foo} />
 <button
-  on:click={() => {
+  onclick={() => {
     /*  */
   }}
 />
 
 <!-- ✗ BAD -->
-<button on:click={{ foo }} />
-<button on:click={bar} />
+<button onclick={{ foo }} />
+<button onclick={bar} />
 ```
 
 ## :wrench: Options
diff --git a/packages/eslint-plugin-svelte/CHANGELOG.md b/packages/eslint-plugin-svelte/CHANGELOG.md
index f0dd635..f5ba6c1 100644
--- a/packages/eslint-plugin-svelte/CHANGELOG.md
+++ b/packages/eslint-plugin-svelte/CHANGELOG.md
@@ -1,5 +1,29 @@
 # eslint-plugin-svelte
 
+## 3.0.0-next.15
+
+### Minor Changes
+
+- [#925](https://github.com/sveltejs/eslint-plugin-svelte/pull/925) [`faf90ef`](https://github.com/sveltejs/eslint-plugin-svelte/commit/faf90ef9a6aab3ec647c30df67a54a25d8322324) Thanks [@marekdedic](https://github.com/marekdedic)! - feat: added the `consistent-selector-style` rule
+
+- [#984](https://github.com/sveltejs/eslint-plugin-svelte/pull/984) [`35d80a5`](https://github.com/sveltejs/eslint-plugin-svelte/commit/35d80a50f1053666153bfc7221b945055bfb76d1) Thanks [@baseballyama](https://github.com/baseballyama)! - feat: support `warningFilter` in `valid-compile` rule
+
+### Patch Changes
+
+- [#1016](https://github.com/sveltejs/eslint-plugin-svelte/pull/1016) [`91999e3`](https://github.com/sveltejs/eslint-plugin-svelte/commit/91999e3520afe42b3cc51f0823f7c912b97176b4) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: change the rule category of `valid-prop-names-in-kit-pages` to `SvelteKit`
+
+- [#1012](https://github.com/sveltejs/eslint-plugin-svelte/pull/1012) [`763cf7a`](https://github.com/sveltejs/eslint-plugin-svelte/commit/763cf7ace209dfb90cf7d1d7e6699a6c0fe240d6) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: change the rule category of `no-export-load-in-svelte-module-in-kit-pages` to `SvelteKit`
+
+- [#1017](https://github.com/sveltejs/eslint-plugin-svelte/pull/1017) [`806d72a`](https://github.com/sveltejs/eslint-plugin-svelte/commit/806d72ad55908fb967252ea0514672b026a6bd09) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: do not run `no-reactive-functions` rule on Svelte 5 with runes
+
+- [#1014](https://github.com/sveltejs/eslint-plugin-svelte/pull/1014) [`74373ec`](https://github.com/sveltejs/eslint-plugin-svelte/commit/74373ec77aa9063c64657faefc01ca331e27b599) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: do not run `no-reactive-reassign` rule on Svelte 5 with runes
+
+- [#1026](https://github.com/sveltejs/eslint-plugin-svelte/pull/1026) [`1bed311`](https://github.com/sveltejs/eslint-plugin-svelte/commit/1bed311084c58a9893e2b578f8b34c2fcb2e8d8b) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: update `svelte-eslint-parser` to `v1.0.0-next.12`
+
+- [#1018](https://github.com/sveltejs/eslint-plugin-svelte/pull/1018) [`5bdc906`](https://github.com/sveltejs/eslint-plugin-svelte/commit/5bdc906fc1e32835ab3b75dfd2a6a08b4cbb968b) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: run the `no-inspect` rule only in Svelte 5’s runes mode
+
+- [#1006](https://github.com/sveltejs/eslint-plugin-svelte/pull/1006) [`5fd91ba`](https://github.com/sveltejs/eslint-plugin-svelte/commit/5fd91baa1835cbffc58a8c473ccf70f3f02a34e6) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: do not run `infinite-reactive-loop` rule on Svelte 5 with runes
+
 ## 3.0.0-next.14
 
 ### Patch Changes
diff --git a/packages/eslint-plugin-svelte/package.json b/packages/eslint-plugin-svelte/package.json
index f3fb2db..1a2123c 100644
--- a/packages/eslint-plugin-svelte/package.json
+++ b/packages/eslint-plugin-svelte/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint-plugin-svelte",
-  "version": "3.0.0-next.14",
+  "version": "3.0.0-next.15",
   "description": "ESLint plugin for Svelte using AST",
   "repository": "git+https://github.com/sveltejs/eslint-plugin-svelte.git",
   "homepage": "https://sveltejs.github.io/eslint-plugin-svelte",
diff --git a/packages/eslint-plugin-svelte/src/meta.ts b/packages/eslint-plugin-svelte/src/meta.ts
index 245559a..85f3fb4 100644
--- a/packages/eslint-plugin-svelte/src/meta.ts
+++ b/packages/eslint-plugin-svelte/src/meta.ts
@@ -2,4 +2,4 @@
 // This file has been automatically generated,
 // in order to update its content execute "pnpm run update"
 export const name = 'eslint-plugin-svelte';
-export const version = '3.0.0-next.14';
+export const version = '3.0.0-next.15';
diff --git a/packages/eslint-plugin-svelte/src/rules/no-not-function-handler.ts b/packages/eslint-plugin-svelte/src/rules/no-not-function-handler.ts
index 7b46c3d..84394c7 100644
--- a/packages/eslint-plugin-svelte/src/rules/no-not-function-handler.ts
+++ b/packages/eslint-plugin-svelte/src/rules/no-not-function-handler.ts
@@ -2,6 +2,7 @@ import type { AST } from 'svelte-eslint-parser';
 import type { TSESTree } from '@typescript-eslint/types';
 import { createRule } from '../utils/index.js';
 import { findVariable } from '../utils/ast-utils.js';
+import { EVENT_NAMES } from '../utils/events.js';
 
 const PHRASES = {
 	ObjectExpression: 'object',
@@ -95,6 +96,18 @@ export default createRule('no-not-function-handler', {
 					return;
 				}
 				verify(node.expression);
+			},
+			SvelteAttribute(node) {
+				if (node.key.type === 'SvelteName' && EVENT_NAMES.includes(node.key.name)) {
+					const { value } = node;
+					if (Array.isArray(value)) {
+						for (const v of value) {
+							if (v.type === 'SvelteMustacheTag') {
+								verify(v.expression);
+							}
+						}
+					}
+				}
 			}
 		};
 	}
diff --git a/packages/eslint-plugin-svelte/src/utils/events.ts b/packages/eslint-plugin-svelte/src/utils/events.ts
new file mode 100644
index 0000000..d9950db
--- /dev/null
+++ b/packages/eslint-plugin-svelte/src/utils/events.ts
@@ -0,0 +1,369 @@
+// see: https://github.com/sveltejs/svelte/blob/a129592e5b248a734a68da6e9028941803a3d063/packages/svelte/elements.d.ts#L83
+export const EVENT_NAMES: string[] = [
+	// Clipboard Events
+	'on:copy',
+	'oncopy',
+	'oncopycapture',
+	'on:cut',
+	'oncut',
+	'oncutcapture',
+	'on:paste',
+	'onpaste',
+	'onpastecapture',
+
+	// Composition Events
+	'on:compositionend',
+	'oncompositionend',
+	'oncompositionendcapture',
+	'on:compositionstart',
+	'oncompositionstart',
+	'oncompositionstartcapture',
+	'on:compositionupdate',
+	'oncompositionupdate',
+	'oncompositionupdatecapture',
+
+	// Focus Events
+	'on:focus',
+	'onfocus',
+	'onfocuscapture',
+	'on:focusin',
+	'onfocusin',
+	'onfocusincapture',
+	'on:focusout',
+	'onfocusout',
+	'onfocusoutcapture',
+	'on:blur',
+	'onblur',
+	'onblurcapture',
+
+	// Form Events
+	'on:change',
+	'onchange',
+	'onchangecapture',
+	'on:beforeinput',
+	'onbeforeinput',
+	'onbeforeinputcapture',
+	// oninput can be either an InputEvent or an Event, depending on the target element (input, textarea etc).
+	'on:input',
+	'oninput',
+	'oninputcapture',
+	'on:reset',
+	'onreset',
+	'onresetcapture',
+	'on:submit',
+	'onsubmit',
+	'onsubmitcapture',
+	'on:invalid',
+	'oninvalid',
+	'oninvalidcapture',
+	'on:formdata',
+	'onformdata',
+	'onformdatacapture',
+
+	// Image Events
+	'on:load',
+	'onload',
+	'onloadcapture',
+	'on:error',
+	'onerror',
+	'onerrorcapture',
+
+	// Popover Events
+	'on:beforetoggle',
+	'onbeforetoggle',
+	'onbeforetogglecapture',
+	'on:toggle',
+	'ontoggle',
+	'ontogglecapture',
+
+	// Content visibility Events
+	'on:contentvisibilityautostatechange',
+	'oncontentvisibilityautostatechange',
+	'oncontentvisibilityautostatechangecapture',
+	// Keyboard Events
+	'on:keydown',
+	'onkeydown',
+	'onkeydowncapture',
+	'on:keypress',
+	'onkeypress',
+	'onkeypresscapture',
+	'on:keyup',
+	'onkeyup',
+	'onkeyupcapture',
+
+	// Media Events
+	'on:abort',
+	'onabort',
+	'onabortcapture',
+	'on:canplay',
+	'oncanplay',
+	'oncanplaycapture',
+	'on:canplaythrough',
+	'oncanplaythrough',
+	'oncanplaythroughcapture',
+	'on:cuechange',
+	'oncuechange',
+	'oncuechangecapture',
+	'on:durationchange',
+	'ondurationchange',
+	'ondurationchangecapture',
+	'on:emptied',
+	'onemptied',
+	'onemptiedcapture',
+	'on:encrypted',
+	'onencrypted',
+	'onencryptedcapture',
+	'on:ended',
+	'onended',
+	'onendedcapture',
+	'on:loadeddata',
+	'onloadeddata',
+	'onloadeddatacapture',
+	'on:loadedmetadata',
+	'onloadedmetadata',
+	'onloadedmetadatacapture',
+	'on:loadstart',
+	'onloadstart',
+	'onloadstartcapture',
+	'on:pause',
+	'onpause',
+	'onpausecapture',
+	'on:play',
+	'onplay',
+	'onplaycapture',
+	'on:playing',
+	'onplaying',
+	'onplayingcapture',
+	'on:progress',
+	'onprogress',
+	'onprogresscapture',
+	'on:ratechange',
+	'onratechange',
+	'onratechangecapture',
+	'on:seeked',
+	'onseeked',
+	'onseekedcapture',
+	'on:seeking',
+	'onseeking',
+	'onseekingcapture',
+	'on:stalled',
+	'onstalled',
+	'onstalledcapture',
+	'on:suspend',
+	'onsuspend',
+	'onsuspendcapture',
+	'on:timeupdate',
+	'ontimeupdate',
+	'ontimeupdatecapture',
+	'on:volumechange',
+	'onvolumechange',
+	'onvolumechangecapture',
+	'on:waiting',
+	'onwaiting',
+	'onwaitingcapture',
+
+	// MouseEvents
+	'on:auxclick',
+	'onauxclick',
+	'onauxclickcapture',
+	'on:click',
+	'onclick',
+	'onclickcapture',
+	'on:contextmenu',
+	'oncontextmenu',
+	'oncontextmenucapture',
+	'on:dblclick',
+	'ondblclick',
+	'ondblclickcapture',
+	'on:drag',
+	'ondrag',
+	'ondragcapture',
+	'on:dragend',
+	'ondragend',
+	'ondragendcapture',
+	'on:dragenter',
+	'ondragenter',
+	'ondragentercapture',
+	'on:dragexit',
+	'ondragexit',
+	'ondragexitcapture',
+	'on:dragleave',
+	'ondragleave',
+	'ondragleavecapture',
+	'on:dragover',
+	'ondragover',
+	'ondragovercapture',
+	'on:dragstart',
+	'ondragstart',
+	'ondragstartcapture',
+	'on:drop',
+	'ondrop',
+	'ondropcapture',
+	'on:mousedown',
+	'onmousedown',
+	'onmousedowncapture',
+	'on:mouseenter',
+	'onmouseenter',
+	'on:mouseleave',
+	'onmouseleave',
+	'on:mousemove',
+	'onmousemove',
+	'onmousemovecapture',
+	'on:mouseout',
+	'onmouseout',
+	'onmouseoutcapture',
+	'on:mouseover',
+	'onmouseover',
+	'onmouseovercapture',
+	'on:mouseup',
+	'onmouseup',
+	'onmouseupcapture',
+
+	// Selection Events
+	'on:select',
+	'onselect',
+	'onselectcapture',
+	'on:selectionchange',
+	'onselectionchange',
+	'onselectionchangecapture',
+	'on:selectstart',
+	'onselectstart',
+	'onselectstartcapture',
+
+	// Touch Events
+	'on:touchcancel',
+	'ontouchcancel',
+	'ontouchcancelcapture',
+	'on:touchend',
+	'ontouchend',
+	'ontouchendcapture',
+	'on:touchmove',
+	'ontouchmove',
+	'ontouchmovecapture',
+	'on:touchstart',
+	'ontouchstart',
+	'ontouchstartcapture',
+
+	// Pointer Events
+	'on:gotpointercapture',
+	'ongotpointercapture',
+	'ongotpointercapturecapture',
+	'on:pointercancel',
+	'onpointercancel',
+	'onpointercancelcapture',
+	'on:pointerdown',
+	'onpointerdown',
+	'onpointerdowncapture',
+	'on:pointerenter',
+	'onpointerenter',
+	'onpointerentercapture',
+	'on:pointerleave',
+	'onpointerleave',
+	'onpointerleavecapture',
+	'on:pointermove',
+	'onpointermove',
+	'onpointermovecapture',
+	'on:pointerout',
+	'onpointerout',
+	'onpointeroutcapture',
+	'on:pointerover',
+	'onpointerover',
+	'onpointerovercapture',
+	'on:pointerup',
+	'onpointerup',
+	'onpointerupcapture',
+	'on:lostpointercapture',
+	'onlostpointercapture',
+	'onlostpointercapturecapture',
+
+	// Gamepad Events
+	'on:gamepadconnected',
+	'ongamepadconnected',
+	'on:gamepaddisconnected',
+	'ongamepaddisconnected',
+
+	// UI Events
+	'on:scroll',
+	'onscroll',
+	'onscrollcapture',
+	'on:scrollend',
+	'onscrollend',
+	'onscrollendcapture',
+	'on:resize',
+	'onresize',
+	'onresizecapture',
+
+	// Wheel Events
+	'on:wheel',
+	'onwheel',
+	'onwheelcapture',
+
+	// Animation Events
+	'on:animationstart',
+	'onanimationstart',
+	'onanimationstartcapture',
+	'on:animationend',
+	'onanimationend',
+	'onanimationendcapture',
+	'on:animationiteration',
+	'onanimationiteration',
+	'onanimationiterationcapture',
+
+	// Transition Events
+	'on:transitionstart',
+	'ontransitionstart',
+	'ontransitionstartcapture',
+	'on:transitionrun',
+	'ontransitionrun',
+	'ontransitionruncapture',
+	'on:transitionend',
+	'ontransitionend',
+	'ontransitionendcapture',
+	'on:transitioncancel',
+	'ontransitioncancel',
+	'ontransitioncancelcapture',
+
+	// Svelte Transition Events
+	'on:outrostart',
+	'onoutrostart',
+	'onoutrostartcapture',
+	'on:outroend',
+	'onoutroend',
+	'onoutroendcapture',
+	'on:introstart',
+	'onintrostart',
+	'onintrostartcapture',
+	'on:introend',
+	'onintroend',
+	'onintroendcapture',
+
+	// Message Events
+	'on:message',
+	'onmessage',
+	'onmessagecapture',
+	'on:messageerror',
+	'onmessageerror',
+	'onmessageerrorcapture',
+
+	// Document Events
+	'on:visibilitychange',
+	'onvisibilitychange',
+	'onvisibilitychangecapture',
+
+	// Global Events
+	'on:beforematch',
+	'onbeforematch',
+	'onbeforematchcapture',
+	'on:cancel',
+	'oncancel',
+	'oncancelcapture',
+	'on:close',
+	'onclose',
+	'onclosecapture',
+	'on:fullscreenchange',
+	'onfullscreenchange',
+	'onfullscreenchangecapture',
+	'on:fullscreenerror',
+	'onfullscreenerror',
+	'onfullscreenerrorcapture'
+] as const;


Test patch:
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/array01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/array01-errors.yaml
new file mode 100644
index 0000000..4b8f175
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/array01-errors.yaml
@@ -0,0 +1,4 @@
+- message: Unexpected array in event handler.
+  line: 5
+  column: 18
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/array01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/array01-input.svelte
new file mode 100644
index 0000000..215e452
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/array01-input.svelte
@@ -0,0 +1,5 @@
+<script>
+	const a = 'hello!';
+</script>
+
+<button onclick={[a]} />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/class01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/class01-errors.yaml
new file mode 100644
index 0000000..46687e7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/class01-errors.yaml
@@ -0,0 +1,4 @@
+- message: Unexpected class in event handler.
+  line: 4
+  column: 18
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/class01-input.svelte
new file mode 100644
index 0000000..c62acc7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/class01-input.svelte
@@ -0,0 +1,4 @@
+<script>
+</script>
+
+<button onclick={class B {}} />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/object01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/object01-errors.yaml
new file mode 100644
index 0000000..b67b8ca
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/object01-errors.yaml
@@ -0,0 +1,4 @@
+- message: Unexpected object in event handler.
+  line: 5
+  column: 18
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/object01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/object01-input.svelte
new file mode 100644
index 0000000..6bab426
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/object01-input.svelte
@@ -0,0 +1,5 @@
+<script>
+	function fn() {}
+</script>
+
+<button onclick={{ fn }} />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/requirements.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/requirements.json
new file mode 100644
index 0000000..1a22bef
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/requirements.json
@@ -0,0 +1,3 @@
+{
+	"svelte": "^5.0.0"
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/string01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/string01-errors.yaml
new file mode 100644
index 0000000..81b1219
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/string01-errors.yaml
@@ -0,0 +1,8 @@
+- message: Unexpected string value in event handler.
+  line: 6
+  column: 18
+  suggestions: null
+- message: Unexpected string value in event handler.
+  line: 7
+  column: 18
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/string01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/string01-input.svelte
new file mode 100644
index 0000000..01a8dfb
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/string01-input.svelte
@@ -0,0 +1,7 @@
+<script>
+	const a = 'hello!';
+	const b = `${a} world`;
+</script>
+
+<button onclick={a} />
+<button onclick={b} />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/value01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/value01-errors.yaml
new file mode 100644
index 0000000..f6f646a
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/value01-errors.yaml
@@ -0,0 +1,12 @@
+- message: Unexpected number value in event handler.
+  line: 7
+  column: 18
+  suggestions: null
+- message: Unexpected bigint value in event handler.
+  line: 8
+  column: 18
+  suggestions: null
+- message: Unexpected regex value in event handler.
+  line: 9
+  column: 18
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/value01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/value01-input.svelte
new file mode 100644
index 0000000..56a57dc
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/invalid/svelte5/value01-input.svelte
@@ -0,0 +1,9 @@
+<script>
+	const a = 42;
+	const b = 42n;
+	const c = /reg/;
+</script>
+
+<button onclick={a} />
+<button onclick={b} />
+<button onclick={c} />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/function01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/function01-input.svelte
new file mode 100644
index 0000000..090905b
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/function01-input.svelte
@@ -0,0 +1,7 @@
+<script>
+	let a = 'hello!';
+	function fn() {}
+</script>
+
+<button onclick={() => a} />
+<button onclick={fn} />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/null01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/null01-input.svelte
new file mode 100644
index 0000000..e68461e
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/null01-input.svelte
@@ -0,0 +1,6 @@
+<script>
+	let a = null;
+</script>
+
+<button onclick={null} />
+<button onclick={a} />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/requirements.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/requirements.json
new file mode 100644
index 0000000..1a22bef
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-not-function-handler/valid/svelte5/requirements.json
@@ -0,0 +1,3 @@
+{
+	"svelte": "^5.0.0"
+}