Repository: sveltejs/eslint-plugin-svelte
Pull request #595 (2023-10-08 00:36:32)

fix(deps): update dependency postcss-safe-parser to v7
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [postcss-safe-parser](https://redirect.github.com/postcss/postcss-safe-parser) | [`^6.0.0` -> `^7.0.0`](https://renovatebot.com/diffs/npm/postcss-safe-parser/6.0.0/7.0.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/postcss-safe-parser/7.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/postcss-safe-parser/7.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/postcss-safe-parser/6.0.0/7.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/postcss-safe-parser/6.0.0/7.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>postcss/postcss-safe-parser (postcss-safe-parser)</summary>

### [`v7.0.1`](https://redirect.github.com/postcss/postcss-safe-parser/blob/HEAD/CHANGELOG.md#701)

[Compare Source](https://redirect.github.com/postcss/postcss-safe-parser/compare/7.0.0...7.0.1)

-   Fixed JSON inside CSS support (by [@&#8203;dengelke](https://redirect.github.com/dengelke)).

### [`v7.0.0`](https://redirect.github.com/postcss/postcss-safe-parser/compare/6.0.0...7.0.0)

[Compare Source](https://redirect.github.com/postcss/postcss-safe-parser/compare/6.0.0...7.0.0)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/sveltejs/eslint-plugin-svelte).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4wLjMiLCJ1cGRhdGVkSW5WZXIiOiIzOC4xMjAuMSIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: bf98860fd4b9dafdaa3edcdddcc77c0a12a4fce4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/sveltejs/eslint-plugin-svelte/new/renovate/postcss-safe-parser-7.x?filename=.changeset/loud-ghosts-chew.md&value=---%0A%22eslint-plugin-svelte%22%3A%20patch%0A---%0A%0Afix(deps)%3A%20update%20dependency%20postcss-safe-parser%20to%20v7%0A)


baseballyama: `postcss-safe-parser` requires Node 18. To merge this PR we need to drop support for ESLint 7 and 8.

Patch:
diff --git a/.changeset/lazy-eyes-wait.md b/.changeset/lazy-eyes-wait.md
new file mode 100644
index 0000000..74f2c86
--- /dev/null
+++ b/.changeset/lazy-eyes-wait.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-svelte': minor
+---
+
+Added new `no-deprecated-raw-special-elements` rule
diff --git a/.changeset/pre.json b/.changeset/pre.json
index e970ca7..ea7ba07 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -2,7 +2,12 @@
   "mode": "pre",
   "tag": "next",
   "initialVersions": {
-    "eslint-plugin-svelte": "2.46.0"
+    "eslint-plugin-svelte": "2.46.0",
+    "docs": "0.0.0"
   },
-  "changesets": []
+  "changesets": [
+    "olive-wolves-travel",
+    "small-days-agree",
+    "twenty-nails-end"
+  ]
 }
diff --git a/.changeset/quiet-toys-burn.md b/.changeset/quiet-toys-burn.md
new file mode 100644
index 0000000..6c7c311
--- /dev/null
+++ b/.changeset/quiet-toys-burn.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-svelte': minor
+---
+
+feat: support for typescript-eslint v8 to `svelte/indent` rule
diff --git a/README.md b/README.md
index 9682cbf..7c56952 100644
--- a/README.md
+++ b/README.md
@@ -380,6 +380,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
 | Rule ID | Description |    |
 |:--------|:------------|:---|
 | [svelte/infinite-reactive-loop](https://sveltejs.github.io/eslint-plugin-svelte/rules/infinite-reactive-loop/) | Svelte runtime prevents calling the same reactive statement twice in a microtask. But between different microtask, it doesn't prevent. |  |
+| [svelte/no-deprecated-raw-special-elements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-deprecated-raw-special-elements/) | Recommends not using raw special elements in Svelte versions previous to 5. | :wrench: |
 | [svelte/no-dom-manipulating](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dom-manipulating/) | disallow DOM manipulating |  |
 | [svelte/no-dupe-else-if-blocks](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks/) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
 | [svelte/no-dupe-on-directives](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-on-directives/) | disallow duplicate `on:` directives |  |
diff --git a/docs-svelte-kit/package.json b/docs-svelte-kit/package.json
index 78624dc..1e7e607 100644
--- a/docs-svelte-kit/package.json
+++ b/docs-svelte-kit/package.json
@@ -19,7 +19,7 @@
     "@sindresorhus/slugify": "^2.2.1",
     "@sveltejs/adapter-static": "^3.0.5",
     "@sveltejs/kit": "^2.7.2",
-    "@sveltejs/vite-plugin-svelte": "^4.0.0",
+    "@sveltejs/vite-plugin-svelte": "^5.0.0",
     "@types/babel__core": "^7.20.5",
     "@types/cross-spawn": "^6.0.6",
     "@types/escape-html": "^1.0.4",
diff --git a/docs/rules.md b/docs/rules.md
index fb067e5..29701ff 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -17,6 +17,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
 | Rule ID                                                                                                        | Description                                                                                                                            |                |
 | :------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- | :------------- |
 | [svelte/infinite-reactive-loop](./rules/infinite-reactive-loop.md)                                             | Svelte runtime prevents calling the same reactive statement twice in a microtask. But between different microtask, it doesn't prevent. |                |
+| [svelte/no-deprecated-raw-special-elements](./rules/no-deprecated-raw-special-elements.md)                     | Recommends not using raw special elements in Svelte versions previous to 5.                                                            | :wrench:       |
 | [svelte/no-dom-manipulating](./rules/no-dom-manipulating.md)                                                   | disallow DOM manipulating                                                                                                              |                |
 | [svelte/no-dupe-else-if-blocks](./rules/no-dupe-else-if-blocks.md)                                             | disallow duplicate conditions in `{#if}` / `{:else if}` chains                                                                         | :star:         |
 | [svelte/no-dupe-on-directives](./rules/no-dupe-on-directives.md)                                               | disallow duplicate `on:` directives                                                                                                    |                |
diff --git a/docs/rules/no-deprecated-raw-special-elements.md b/docs/rules/no-deprecated-raw-special-elements.md
new file mode 100644
index 0000000..4bf863a
--- /dev/null
+++ b/docs/rules/no-deprecated-raw-special-elements.md
@@ -0,0 +1,52 @@
+---
+pageClass: 'rule-details'
+sidebarDepth: 0
+title: 'svelte/no-deprecated-raw-special-elements'
+description: 'Recommends not using raw special elements in Svelte versions previous to 5.'
+---
+
+# svelte/no-deprecated-raw-special-elements
+
+> Recommends not using raw special elements in Svelte versions previous to 5.
+
+- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
+- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
+
+## :book: Rule Details
+
+This rule reports the usage of `head`, `body`, `window`, `document`, `element` and `options` HTML elements. These elements were valid in in versions proior to 5, but since Svelte 5 they must be used with `svelte:`.
+
+<ESLintCodeBlock fix>
+
+<!--eslint-skip-->
+
+```svelte
+<script>
+  /* eslint svelte/no-deprecated-raw-special-elements: "error" */
+</script>
+
+<!-- ✓ GOOD -->
+<svelte:head>
+  <title>Valid</title>
+</svelte:head>
+
+<!-- ✗ BAD -->
+<head>
+  <title>Invalid</title>
+</head>
+```
+
+</ESLintCodeBlock>
+
+## :wrench: Options
+
+Nothing.
+
+## :books: Further Reading
+
+- See special elements section in [Svelte docs](https://svelte.dev/docs/svelte/svelte-window)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/no-deprecated-raw-special-elements.ts)
+- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/tests/src/rules/no-deprecated-raw-special-elements.ts)
diff --git a/package.json b/package.json
index f1927cd..fe4cc5f 100644
--- a/package.json
+++ b/package.json
@@ -15,34 +15,34 @@
   },
   "devDependencies": {
     "@changesets/changelog-github": "^0.5.0",
-    "@changesets/cli": "^2.27.9",
-    "@changesets/get-release-plan": "^4.0.4",
-    "@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
+    "@changesets/cli": "^2.27.10",
+    "@changesets/get-release-plan": "^4.0.5",
+    "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
     "@ota-meshi/eslint-plugin": "^0.17.5",
     "@types/eslint": "^9.6.1",
-    "@typescript-eslint/eslint-plugin": "^7.18.0",
-    "@typescript-eslint/parser": "^7.18.0",
+    "@typescript-eslint/eslint-plugin": "^8.16.0",
+    "@typescript-eslint/parser": "^8.16.0",
     "env-cmd": "^10.1.0",
     "eslint": "~9.14.0",
     "eslint-config-prettier": "^9.1.0",
     "eslint-formatter-friendly": "^7.0.0",
-    "eslint-plugin-eslint-plugin": "^6.2.0",
-    "eslint-plugin-jsdoc": "^50.4.1",
+    "eslint-plugin-eslint-plugin": "^6.3.2",
+    "eslint-plugin-jsdoc": "^50.6.0",
     "eslint-plugin-json-schema-validator": "^5.1.3",
-    "eslint-plugin-jsonc": "^2.16.0",
+    "eslint-plugin-jsonc": "^2.18.2",
     "eslint-plugin-markdown": "^5.1.0",
     "eslint-plugin-mdx": "^3.1.5",
-    "eslint-plugin-n": "^17.11.1",
+    "eslint-plugin-n": "^17.14.0",
     "eslint-plugin-node-dependencies": "^0.12.0",
     "eslint-plugin-prettier": "^5.2.1",
-    "eslint-plugin-regexp": "^2.6.0",
-    "eslint-plugin-yml": "^1.14.0",
-    "npm-run-all2": "^7.0.0",
-    "prettier": "^3.3.3",
-    "prettier-plugin-svelte": "^3.2.7",
+    "eslint-plugin-regexp": "^2.7.0",
+    "eslint-plugin-yml": "^1.15.0",
+    "npm-run-all2": "^7.0.1",
+    "prettier": "^3.4.1",
+    "prettier-plugin-svelte": "^3.3.2",
     "rimraf": "^6.0.1",
-    "typescript": "~5.7.0",
-    "typescript-eslint": "^7.18.0"
+    "typescript": "~5.7.2",
+    "typescript-eslint": "^8.16.0"
   },
   "publishConfig": {
     "access": "public"
diff --git a/packages/eslint-plugin-svelte/CHANGELOG.md b/packages/eslint-plugin-svelte/CHANGELOG.md
index 024bab7..d1db264 100644
--- a/packages/eslint-plugin-svelte/CHANGELOG.md
+++ b/packages/eslint-plugin-svelte/CHANGELOG.md
@@ -1,5 +1,17 @@
 # eslint-plugin-svelte
 
+## 3.0.0-next.0
+
+### Major Changes
+
+- [#885](https://github.com/sveltejs/eslint-plugin-svelte/pull/885) [`ce2ffad`](https://github.com/sveltejs/eslint-plugin-svelte/commit/ce2ffad105b1c6ed2df02a9c2b84f3b654d99ad5) Thanks [@ota-meshi](https://github.com/ota-meshi)! - feat!: drop support for old node versions (<18, 19, 21)
+
+- [#930](https://github.com/sveltejs/eslint-plugin-svelte/pull/930) [`eae1b4f`](https://github.com/sveltejs/eslint-plugin-svelte/commit/eae1b4fcbfbaec926cfa63a5d08eafcb2238bf82) Thanks [@ota-meshi](https://github.com/ota-meshi)! - feat!: upgrade svelte-eslint-parser to v1
+
+### Minor Changes
+
+- [#911](https://github.com/sveltejs/eslint-plugin-svelte/pull/911) [`452ffed`](https://github.com/sveltejs/eslint-plugin-svelte/commit/452ffed53791cb9e158636bcd80a221d2840cc4a) Thanks [@marekdedic](https://github.com/marekdedic)! - feat(no-inline-styles): allowing transitions by default
+
 ## 2.46.0
 
 ### Minor Changes
diff --git a/packages/eslint-plugin-svelte/package.json b/packages/eslint-plugin-svelte/package.json
index c357c5a..26aba64 100644
--- a/packages/eslint-plugin-svelte/package.json
+++ b/packages/eslint-plugin-svelte/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint-plugin-svelte",
-  "version": "2.46.0",
+  "version": "3.0.0-next.0",
   "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",
@@ -56,52 +56,52 @@
     }
   },
   "dependencies": {
-    "@eslint-community/eslint-utils": "^4.4.0",
-    "@jridgewell/sourcemap-codec": "^1.4.15",
-    "eslint-compat-utils": "^0.6.0",
+    "@eslint-community/eslint-utils": "^4.4.1",
+    "@jridgewell/sourcemap-codec": "^1.5.0",
+    "eslint-compat-utils": "^0.6.3",
     "esutils": "^2.0.3",
     "known-css-properties": "^0.35.0",
-    "postcss": "^8.4.38",
+    "postcss": "^8.4.49",
     "postcss-load-config": "^3.1.4",
-    "postcss-safe-parser": "^6.0.0",
+    "postcss-safe-parser": "^7.0.0",
     "postcss-selector-parser": "^7.0.0",
-    "semver": "^7.6.2",
+    "semver": "^7.6.3",
     "svelte-eslint-parser": "^1.0.0-0"
   },
   "devDependencies": {
-    "@babel/core": "^7.25.8",
-    "@babel/eslint-parser": "^7.25.8",
-    "@babel/plugin-proposal-function-bind": "^7.25.8",
-    "@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
+    "@babel/core": "^7.26.0",
+    "@babel/eslint-parser": "^7.25.9",
+    "@babel/plugin-proposal-function-bind": "^7.25.9",
+    "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
     "@types/babel__core": "^7.20.5",
     "@types/eslint-utils": "^3.0.5",
     "@types/esutils": "^2.0.2",
     "@types/json-schema": "^7.0.15",
-    "@types/less": "^3.0.6",
-    "@types/mocha": "^10.0.9",
-    "@types/node": "^22.0.0",
+    "@types/less": "^3.0.7",
+    "@types/mocha": "^10.0.10",
+    "@types/node": "^22.10.0",
     "@types/postcss-safe-parser": "^5.0.4",
     "@types/semver": "^7.5.8",
     "@types/stylus": "^0.48.43",
-    "acorn": "^8.13.0",
+    "acorn": "^8.14.0",
     "assert": "^2.1.0",
     "esbuild": "^0.24.0",
     "esbuild-register": "^3.6.0",
-    "eslint-scope": "^8.1.0",
+    "eslint-scope": "^8.2.0",
     "eslint-typegen": "^0.3.2",
-    "eslint-visitor-keys": "^4.1.0",
-    "espree": "^10.2.0",
-    "less": "^4.2.0",
-    "mocha": "^10.7.3",
+    "eslint-visitor-keys": "^4.2.0",
+    "espree": "^10.3.0",
+    "less": "^4.2.1",
+    "mocha": "^10.8.2",
     "nyc": "^17.1.0",
-    "postcss-nested": "^7.0.0",
-    "sass": "^1.79.5",
+    "postcss-nested": "^7.0.2",
+    "sass": "^1.81.0",
     "source-map-js": "^1.2.1",
     "stylus": "^0.64.0",
-    "svelte": "^5.0.0",
-    "svelte-i18n": "^4.0.0",
+    "svelte": "^5.2.9",
+    "svelte-i18n": "^4.0.1",
     "type-coverage": "^2.29.7",
-    "yaml": "^2.6.0"
+    "yaml": "^2.6.1"
   },
   "publishConfig": {
     "access": "public"
diff --git a/packages/eslint-plugin-svelte/src/meta.ts b/packages/eslint-plugin-svelte/src/meta.ts
index 5cdb251..400595c 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 = '2.46.0';
+export const version = '3.0.0-next.0';
diff --git a/packages/eslint-plugin-svelte/src/rule-types.ts b/packages/eslint-plugin-svelte/src/rule-types.ts
index 8e747b6..8b7cbe8 100644
--- a/packages/eslint-plugin-svelte/src/rule-types.ts
+++ b/packages/eslint-plugin-svelte/src/rule-types.ts
@@ -104,6 +104,11 @@ export interface RuleOptions {
    * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-html-tags/
    */
   'svelte/no-at-html-tags'?: Linter.RuleEntry<[]>
+  /**
+   * Recommends not using raw special elements in Svelte versions previous to 5.
+   * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-deprecated-raw-special-elements/
+   */
+  'svelte/no-deprecated-raw-special-elements'?: Linter.RuleEntry<[]>
   /**
    * disallow DOM manipulating
    * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dom-manipulating/
diff --git a/packages/eslint-plugin-svelte/src/rules/indent-helpers/es.ts b/packages/eslint-plugin-svelte/src/rules/indent-helpers/es.ts
index a0d6845..3e30ed7 100644
--- a/packages/eslint-plugin-svelte/src/rules/indent-helpers/es.ts
+++ b/packages/eslint-plugin-svelte/src/rules/indent-helpers/es.ts
@@ -195,7 +195,10 @@ export function defineVisitor(context: IndentContext): NodeListener {
 			visitor.BreakStatement(node);
 		},
 		CallExpression(node: TSESTree.CallExpression) {
-			const typeArguments = node.typeArguments ?? node.typeParameters;
+			const typeArguments =
+				node.typeArguments ??
+				// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Support old typescript-eslint
+				(node as any).typeParameters;
 			const firstToken = sourceCode.getFirstToken(node);
 			const leftParenToken = sourceCode.getTokenAfter(typeArguments || node.callee, {
 				filter: isOpeningParenToken,
@@ -706,7 +709,10 @@ export function defineVisitor(context: IndentContext): NodeListener {
 			visitor.MethodDefinition(node);
 		},
 		NewExpression(node: TSESTree.NewExpression) {
-			const typeArguments = node.typeArguments ?? node.typeParameters;
+			const typeArguments =
+				node.typeArguments ??
+				// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Support old typescript-eslint
+				(node as any).typeParameters;
 			const newToken = sourceCode.getFirstToken(node);
 			const calleeTokens = getFirstAndLastTokens(sourceCode, node.callee);
 			offsets.setOffsetToken(calleeTokens.firstToken, 1, newToken);
diff --git a/packages/eslint-plugin-svelte/src/rules/indent-helpers/ts.ts b/packages/eslint-plugin-svelte/src/rules/indent-helpers/ts.ts
index 16cbc82..c75d031 100644
--- a/packages/eslint-plugin-svelte/src/rules/indent-helpers/ts.ts
+++ b/packages/eslint-plugin-svelte/src/rules/indent-helpers/ts.ts
@@ -62,7 +62,10 @@ export function defineVisitor(context: IndentContext): NodeListener {
 			// or
 			// const ErrorMap = Map<string, Error>
 			//                  ^^^^^^^^^^^^^^^^^^
-			const typeArguments = node.typeArguments ?? node.typeParameters;
+			const typeArguments =
+				node.typeArguments ??
+				// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Support old typescript-eslint
+				(node as any).typeParameters;
 			if (typeArguments) {
 				const firstToken = sourceCode.getFirstToken(node);
 				offsets.setOffsetToken(sourceCode.getFirstToken(typeArguments), 1, firstToken);
@@ -254,20 +257,34 @@ export function defineVisitor(context: IndentContext): NodeListener {
 			// {[key in foo]: bar}
 			const leftBraceToken = sourceCode.getFirstToken(node);
 
-			const leftBracketToken = sourceCode.getTokenBefore(node.typeParameter)!;
-			const rightBracketToken = sourceCode.getTokenAfter(node.nameType || node.typeParameter)!;
+			const leftBracketToken = sourceCode.getTokenBefore(node.key || node.typeParameter)!;
+			const rightBracketToken = sourceCode.getTokenAfter(
+				node.nameType || node.constraint || node.typeParameter
+			)!;
 			offsets.setOffsetToken(
 				[...sourceCode.getTokensBetween(leftBraceToken, leftBracketToken), leftBracketToken],
 				1,
 				leftBraceToken
 			);
 			offsets.setOffsetElementList(
-				[node.typeParameter, node.nameType],
+				[node.key, node.constraint, node.typeParameter, node.nameType],
 				leftBracketToken,
 				rightBracketToken,
 				1
 			);
 
+			if (node.key && node.constraint) {
+				const firstToken = sourceCode.getFirstToken(node.key);
+				offsets.setOffsetToken(
+					[
+						...sourceCode.getTokensBetween(firstToken, node.constraint),
+						sourceCode.getFirstToken(node.constraint)
+					],
+					1,
+					firstToken
+				);
+			}
+
 			const rightBraceToken = sourceCode.getLastToken(node);
 			if (node.typeAnnotation) {
 				const typeAnnotationToken = sourceCode.getFirstToken(node.typeAnnotation);
@@ -402,7 +419,10 @@ export function defineVisitor(context: IndentContext): NodeListener {
 		TSClassImplements(node: TSESTree.TSClassImplements | TSESTree.TSInterfaceHeritage) {
 			// class C implements T {}
 			//                    ^
-			const typeArguments = node.typeArguments ?? node.typeParameters;
+			const typeArguments =
+				node.typeArguments ??
+				// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Support old typescript-eslint
+				(node as any).typeParameters;
 			if (typeArguments) {
 				offsets.setOffsetToken(
 					sourceCode.getFirstToken(typeArguments),
@@ -427,6 +447,14 @@ export function defineVisitor(context: IndentContext): NodeListener {
 			const leftBraceToken = sourceCode.getTokenAfter(idTokens.lastToken)!;
 			const rightBraceToken = sourceCode.getLastToken(node);
 			offsets.setOffsetToken(leftBraceToken, 0, firstToken);
+			if (node.members)
+				offsets.setOffsetElementList(node.members, leftBraceToken, rightBraceToken, 1);
+		},
+		TSEnumBody(node: TSESTree.TSEnumBody) {
+			// enum E {...}
+			//        ^^^^^
+			const leftBraceToken = sourceCode.getFirstToken(node);
+			const rightBraceToken = sourceCode.getLastToken(node);
 			offsets.setOffsetElementList(node.members, leftBraceToken, rightBraceToken, 1);
 		},
 		TSModuleDeclaration(node: TSESTree.TSModuleDeclaration) {
@@ -677,7 +705,10 @@ export function defineVisitor(context: IndentContext): NodeListener {
 		},
 		TSImportType(node: TSESTree.TSImportType) {
 			// import('foo').B
-			const typeArguments = node.typeArguments ?? node.typeParameters;
+			const typeArguments =
+				node.typeArguments ??
+				// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Support old typescript-eslint
+				(node as any).typeParameters;
 			const firstToken = sourceCode.getFirstToken(node);
 			const leftParenToken = sourceCode.getTokenAfter(firstToken, {
 				filter: isOpeningParenToken,
@@ -1057,7 +1088,10 @@ export function defineVisitor(context: IndentContext): NodeListener {
 					sourceCode.getFirstToken(node.id || node)
 				);
 			}
-			const superTypeArguments = node.superTypeArguments ?? node.superTypeParameters;
+			const superTypeArguments =
+				node.superTypeArguments ??
+				// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Support old typescript-eslint
+				(node as any).superTypeParameters;
 			if (superTypeArguments != null && node.superClass != null) {
 				offsets.setOffsetToken(
 					sourceCode.getFirstToken(superTypeArguments),
diff --git a/packages/eslint-plugin-svelte/src/rules/no-deprecated-raw-special-elements.ts b/packages/eslint-plugin-svelte/src/rules/no-deprecated-raw-special-elements.ts
new file mode 100644
index 0000000..d47ef72
--- /dev/null
+++ b/packages/eslint-plugin-svelte/src/rules/no-deprecated-raw-special-elements.ts
@@ -0,0 +1,47 @@
+import type { AST } from 'svelte-eslint-parser';
+import { createRule } from '../utils';
+
+const INVALID_HTML_ELEMENTS = ['head', 'body', 'window', 'document', 'element', 'options'];
+const VALID_PREFIX = 'svelte:';
+
+export default createRule('no-deprecated-raw-special-elements', {
+	meta: {
+		docs: {
+			description: 'Recommends not using raw special elements in Svelte versions previous to 5.',
+			category: 'Possible Errors',
+			// TODO: Switch to recommended in the major version
+			recommended: false
+		},
+		schema: [],
+		messages: {
+			deprecatedElement:
+				'Special {{name}} element is deprecated in v5, use svelte:{{name}} instead.'
+		},
+		type: 'problem', // 'problem', or 'layout',
+		fixable: 'code'
+	},
+	create(context) {
+		return {
+			'SvelteElement[kind="html"]'(node: AST.SvelteHTMLElement) {
+				const { name } = node.name;
+				if (INVALID_HTML_ELEMENTS.includes(name)) {
+					context.report({
+						node,
+						messageId: 'deprecatedElement',
+						data: { name },
+						*fix(fixer) {
+							const { endTag } = node;
+							yield fixer.insertTextBeforeRange([node.range[0] + 1, node.range[1]], VALID_PREFIX);
+							if (endTag) {
+								yield fixer.insertTextBeforeRange(
+									[endTag.range[0] + 2, endTag.range[1]],
+									VALID_PREFIX
+								);
+							}
+						}
+					});
+				}
+			}
+		};
+	}
+});
diff --git a/packages/eslint-plugin-svelte/src/rules/require-event-dispatcher-types.ts b/packages/eslint-plugin-svelte/src/rules/require-event-dispatcher-types.ts
index 28c1f51..5056741 100644
--- a/packages/eslint-plugin-svelte/src/rules/require-event-dispatcher-types.ts
+++ b/packages/eslint-plugin-svelte/src/rules/require-event-dispatcher-types.ts
@@ -42,7 +42,11 @@ export default createRule('require-event-dispatcher-types', {
 					}
 				})) {
 					const node = n as TSESTree.CallExpression;
-					if ((node.typeArguments ?? node.typeParameters) === undefined) {
+					if (
+						(node.typeArguments ??
+							// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Support old typescript-eslint
+							(node as any).typeParameters) === undefined
+					) {
 						context.report({ node, messageId: 'missingTypeParameter' });
 					}
 				}
diff --git a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/babel.ts b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/babel.ts
index 3cc4c93..93a6d16 100644
--- a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/babel.ts
+++ b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/babel.ts
@@ -43,7 +43,7 @@ export function transform(
 			output: output.code!,
 			mappings: output.map!.mappings
 		};
-	} catch (_e) {
+	} catch {
 		return null;
 	}
 }
diff --git a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/less.ts b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/less.ts
index b489dfd..b846a92 100644
--- a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/less.ts
+++ b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/less.ts
@@ -50,7 +50,7 @@ export function transform(
 			output: output.css,
 			mappings: JSON.parse(output.map).mappings
 		};
-	} catch (_e) {
+	} catch {
 		return null;
 	}
 }
diff --git a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/postcss.ts b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/postcss.ts
index 4c3d699..c47fe3e 100644
--- a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/postcss.ts
+++ b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/postcss.ts
@@ -49,7 +49,7 @@ export function transform(
 			output: result.content,
 			mappings: result.map.toJSON().mappings
 		};
-	} catch (_e) {
+	} catch {
 		// console.log(e)
 		return null;
 	}
diff --git a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/sass.ts b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/sass.ts
index 2c1377e..a6504f4 100644
--- a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/sass.ts
+++ b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/sass.ts
@@ -39,7 +39,7 @@ export function transform(
 			output: output.css,
 			mappings: output.sourceMap!.mappings
 		};
-	} catch (_e) {
+	} catch {
 		return null;
 	}
 }
diff --git a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/stylus.ts b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/stylus.ts
index 14a8a02..0a92e5b 100644
--- a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/stylus.ts
+++ b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/transform/stylus.ts
@@ -45,7 +45,7 @@ export function transform(
 			output,
 			mappings: (style as unknown as { sourcemap: RawSourceMap }).sourcemap.mappings
 		};
-	} catch (_e) {
+	} catch {
 		return null;
 	}
 }
diff --git a/packages/eslint-plugin-svelte/src/types-for-node.ts b/packages/eslint-plugin-svelte/src/types-for-node.ts
index 866ea6d..a1bf991 100644
--- a/packages/eslint-plugin-svelte/src/types-for-node.ts
+++ b/packages/eslint-plugin-svelte/src/types-for-node.ts
@@ -135,6 +135,7 @@ export type ASTNodeListener = {
 	TSEmptyBodyFunctionExpression?: (
 		node: TSESTree.TSEmptyBodyFunctionExpression & ASTNodeWithParent
 	) => void;
+	TSEnumBody?: (node: TSESTree.TSEnumBody & ASTNodeWithParent) => void;
 	TSEnumDeclaration?: (node: TSESTree.TSEnumDeclaration & ASTNodeWithParent) => void;
 	TSEnumMember?: (node: TSESTree.TSEnumMember & ASTNodeWithParent) => void;
 	TSExportAssignment?: (node: TSESTree.TSExportAssignment & ASTNodeWithParent) => void;
@@ -143,9 +144,6 @@ export type ASTNodeListener = {
 		node: TSESTree.TSExternalModuleReference & ASTNodeWithParent
 	) => void;
 	TSFunctionType?: (node: TSESTree.TSFunctionType & ASTNodeWithParent) => void;
-	TSInstantiationExpression?: (
-		node: TSESTree.TSInstantiationExpression & ASTNodeWithParent
-	) => void;
 	TSImportEqualsDeclaration?: (
 		node: TSESTree.TSImportEqualsDeclaration & ASTNodeWithParent
 	) => void;
@@ -153,6 +151,9 @@ export type ASTNodeListener = {
 	TSIndexedAccessType?: (node: TSESTree.TSIndexedAccessType & ASTNodeWithParent) => void;
 	TSIndexSignature?: (node: TSESTree.TSIndexSignature & ASTNodeWithParent) => void;
 	TSInferType?: (node: TSESTree.TSInferType & ASTNodeWithParent) => void;
+	TSInstantiationExpression?: (
+		node: TSESTree.TSInstantiationExpression & ASTNodeWithParent
+	) => void;
 	TSInterfaceBody?: (node: TSESTree.TSInterfaceBody & ASTNodeWithParent) => void;
 	TSInterfaceDeclaration?: (node: TSESTree.TSInterfaceDeclaration & ASTNodeWithParent) => void;
 	TSInterfaceHeritage?: (node: TSESTree.TSInterfaceHeritage & ASTNodeWithParent) => void;
@@ -354,6 +355,7 @@ export type TSNodeListener = {
 	TSEmptyBodyFunctionExpression?: (
 		node: TSESTree.TSEmptyBodyFunctionExpression & ASTNodeWithParent
 	) => void;
+	TSEnumBody?: (node: TSESTree.TSEnumBody & ASTNodeWithParent) => void;
 	TSEnumDeclaration?: (node: TSESTree.TSEnumDeclaration & ASTNodeWithParent) => void;
 	TSEnumMember?: (node: TSESTree.TSEnumMember & ASTNodeWithParent) => void;
 	TSExportAssignment?: (node: TSESTree.TSExportAssignment & ASTNodeWithParent) => void;
@@ -362,9 +364,6 @@ export type TSNodeListener = {
 		node: TSESTree.TSExternalModuleReference & ASTNodeWithParent
 	) => void;
 	TSFunctionType?: (node: TSESTree.TSFunctionType & ASTNodeWithParent) => void;
-	TSInstantiationExpression?: (
-		node: TSESTree.TSInstantiationExpression & ASTNodeWithParent
-	) => void;
 	TSImportEqualsDeclaration?: (
 		node: TSESTree.TSImportEqualsDeclaration & ASTNodeWithParent
 	) => void;
@@ -372,6 +371,9 @@ export type TSNodeListener = {
 	TSIndexedAccessType?: (node: TSESTree.TSIndexedAccessType & ASTNodeWithParent) => void;
 	TSIndexSignature?: (node: TSESTree.TSIndexSignature & ASTNodeWithParent) => void;
 	TSInferType?: (node: TSESTree.TSInferType & ASTNodeWithParent) => void;
+	TSInstantiationExpression?: (
+		node: TSESTree.TSInstantiationExpression & ASTNodeWithParent
+	) => void;
 	TSInterfaceBody?: (node: TSESTree.TSInterfaceBody & ASTNodeWithParent) => void;
 	TSInterfaceDeclaration?: (node: TSESTree.TSInterfaceDeclaration & ASTNodeWithParent) => void;
 	TSInterfaceHeritage?: (node: TSESTree.TSInterfaceHeritage & ASTNodeWithParent) => void;
diff --git a/packages/eslint-plugin-svelte/src/utils/get-package-json.ts b/packages/eslint-plugin-svelte/src/utils/get-package-json.ts
index e764d25..9017256 100644
--- a/packages/eslint-plugin-svelte/src/utils/get-package-json.ts
+++ b/packages/eslint-plugin-svelte/src/utils/get-package-json.ts
@@ -35,7 +35,7 @@ function readPackageJson(dir: string): PackageJson | null {
 			data.filePath = filePath;
 			return data;
 		}
-	} catch (_err) {
+	} catch {
 		// do nothing.
 	}
 
diff --git a/packages/eslint-plugin-svelte/src/utils/rules.ts b/packages/eslint-plugin-svelte/src/utils/rules.ts
index 5bb5a08..862db8b 100644
--- a/packages/eslint-plugin-svelte/src/utils/rules.ts
+++ b/packages/eslint-plugin-svelte/src/utils/rules.ts
@@ -20,6 +20,7 @@ import maxAttributesPerLine from '../rules/max-attributes-per-line';
 import mustacheSpacing from '../rules/mustache-spacing';
 import noAtDebugTags from '../rules/no-at-debug-tags';
 import noAtHtmlTags from '../rules/no-at-html-tags';
+import noDeprecatedRawSpecialElements from '../rules/no-deprecated-raw-special-elements';
 import noDomManipulating from '../rules/no-dom-manipulating';
 import noDupeElseIfBlocks from '../rules/no-dupe-else-if-blocks';
 import noDupeOnDirectives from '../rules/no-dupe-on-directives';
@@ -87,6 +88,7 @@ export const rules = [
 	mustacheSpacing,
 	noAtDebugTags,
 	noAtHtmlTags,
+	noDeprecatedRawSpecialElements,
 	noDomManipulating,
 	noDupeElseIfBlocks,
 	noDupeOnDirectives,
diff --git a/packages/eslint-plugin-svelte/src/utils/svelte-kit.ts b/packages/eslint-plugin-svelte/src/utils/svelte-kit.ts
index 04a1b39..93f0236 100644
--- a/packages/eslint-plugin-svelte/src/utils/svelte-kit.ts
+++ b/packages/eslint-plugin-svelte/src/utils/svelte-kit.ts
@@ -55,7 +55,7 @@ function hasSvelteKit(filePath: string): boolean {
 		return Boolean(
 			packageJson.dependencies?.['@sveltejs/kit'] ?? packageJson.devDependencies?.['@sveltejs/kit']
 		);
-	} catch (_e) {
+	} catch {
 		return false;
 	}
 }
diff --git a/packages/eslint-plugin-svelte/tools/new-rule.ts b/packages/eslint-plugin-svelte/tools/new-rule.ts
index a76cc32..16c5ae3 100644
--- a/packages/eslint-plugin-svelte/tools/new-rule.ts
+++ b/packages/eslint-plugin-svelte/tools/new-rule.ts
@@ -141,7 +141,7 @@ This rule reports ???.
 		cp.execSync(`code "${ruleFile}"`);
 		cp.execSync(`code "${testFile}"`);
 		cp.execSync(`code "${docFile}"`);
-	} catch (_) {
+	} catch {
 		logger.error('Unable to find code command. Will not open files with VSCode.');
 	}
 })(process.argv.slice(2));


Test patch:
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-errors.yaml
new file mode 100644
index 0000000..2acb009
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-errors.yaml
@@ -0,0 +1,24 @@
+- message: Special head element is deprecated in v5, use svelte:head instead.
+  line: 1
+  column: 1
+  suggestions: null
+- message: Special body element is deprecated in v5, use svelte:body instead.
+  line: 2
+  column: 1
+  suggestions: null
+- message: Special window element is deprecated in v5, use svelte:window instead.
+  line: 3
+  column: 1
+  suggestions: null
+- message: Special document element is deprecated in v5, use svelte:document instead.
+  line: 4
+  column: 1
+  suggestions: null
+- message: Special element element is deprecated in v5, use svelte:element instead.
+  line: 5
+  column: 1
+  suggestions: null
+- message: Special options element is deprecated in v5, use svelte:options instead.
+  line: 6
+  column: 1
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-input.svelte
new file mode 100644
index 0000000..0856e15
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-input.svelte
@@ -0,0 +1,6 @@
+<head></head>
+<body></body>
+<window></window>
+<document></document>
+<element this={{}}></element>
+<options></options>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-output.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-output.svelte
new file mode 100644
index 0000000..507eea7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/invalid/test01-output.svelte
@@ -0,0 +1,6 @@
+<svelte:head></svelte:head>
+<svelte:body></svelte:body>
+<svelte:window></svelte:window>
+<svelte:document></svelte:document>
+<svelte:element this={{}}></svelte:element>
+<svelte:options></svelte:options>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/valid/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/valid/test01-input.svelte
new file mode 100644
index 0000000..ea0dfc2
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-deprecated-raw-special-elements/valid/test01-input.svelte
@@ -0,0 +1,8 @@
+<svelte:options />
+
+<svelte:body />
+<svelte:document />
+<svelte:element this={{}}></svelte:element>
+<svelte:head></svelte:head>
+
+<svelte:window />
diff --git a/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/no-unnecessary-condition.ts b/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/no-unnecessary-condition.ts
index e15bc7b..3ebabce 100644
--- a/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/no-unnecessary-condition.ts
+++ b/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/no-unnecessary-condition.ts
@@ -11,7 +11,8 @@ const tester = new RuleTester({
 				ts: '@typescript-eslint/parser',
 				js: 'espree'
 			},
-			project: RULES_PROJECT
+			project: RULES_PROJECT,
+			disallowAutomaticSingleRunInference: true
 		}
 	}
 });
diff --git a/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/original-tests/no-unnecessary-condition.ts b/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/original-tests/no-unnecessary-condition.ts
index 624ee24..2d92bcb 100644
--- a/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/original-tests/no-unnecessary-condition.ts
+++ b/packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/original-tests/no-unnecessary-condition.ts
@@ -18,7 +18,8 @@ const ruleTester = new RuleTester({
 		parser: require('@typescript-eslint/parser'),
 		parserOptions: {
 			tsconfigRootDir: rootPath,
-			project: './tsconfig.json'
+			project: './tsconfig.json',
+			disallowAutomaticSingleRunInference: true
 		}
 	}
 });
diff --git a/packages/eslint-plugin-svelte/tests/src/rules/no-deprecated-raw-special-elements.ts b/packages/eslint-plugin-svelte/tests/src/rules/no-deprecated-raw-special-elements.ts
new file mode 100644
index 0000000..dbe2fe1
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/src/rules/no-deprecated-raw-special-elements.ts
@@ -0,0 +1,12 @@
+import { RuleTester } from '../../utils/eslint-compat';
+import rule from '../../../src/rules/no-deprecated-raw-special-elements';
+import { loadTestCases } from '../../utils/utils';
+
+const tester = new RuleTester({
+	languageOptions: {
+		ecmaVersion: 2020,
+		sourceType: 'module'
+	}
+});
+
+tester.run('no-deprecated-raw-special-elements', rule as any, loadTestCases('no-deprecated-raw-special-elements'));