Repository: sveltejs/eslint-plugin-svelte (ts)

Issue:
feat: Add `svelte/brackets-same-line` rule
### Motivation

I don't like brackets on their own line as it makes the code much longer and harder to read. It may be useful for editing but it's just messy overall. Sometimes use of VSCode's built-in formatter or projects that use to use prettier can have a lot of brackets on new lines. This rule makes it easy to clean things up.

### Description

Keep closing brackets on the same line as the last attribute or the tag itself

### Examples

```svelte
<script>
</script>

<!-- ✓ GOOD -->
<div>Text</div>

<div title="foo">Text</div>

<div 
  bar 
  title="foo">Text</div>

<div>
  Text
</div>

<div />

<!-- ✗ BAD -->
<div
  bar
  title="foo"
  >Text</div>

<div
  >Text</div>

<div
  >
  Text</div>

<div>Text</div
  >

<div
  />
```

From the rule tests at https://github.com/jacob-8/eslint-plugin-svelte-stylistic/blob/main/src/rules/brackets-same-line.test.ts

### Additional comments

I've already published it to npm as [eslint-plugin-svelte-stylistic](https://npmjs.com/package/eslint-plugin-svelte-stylistic) so I'm set, but I thought others might appreciate it so wanted to propose adding it here. What do you think? (rule 1 of 2, see second at #591)

Pull request:
feat(html-closing-bracket-new-line): add rule
Adds the `svelte/html-closing-bracket-newline` rule, which enforces that HTML
tags must have a newline (or not) after the closing bracket. This rule is
inspired by `vue/html-closing-bracket-newline`, and is implemented ensuring
what's discussed in #590.

Closes #590.


Patch:
diff --git a/.changeset/witty-games-mix.md b/.changeset/witty-games-mix.md
new file mode 100644
index 0000000..6ceae68
--- /dev/null
+++ b/.changeset/witty-games-mix.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-svelte": minor
+---
+
+feat(no-inspect): add `no-inspect` rule
diff --git a/README.md b/README.md
index 610a270..9682cbf 100644
--- a/README.md
+++ b/README.md
@@ -419,6 +419,7 @@ These rules relate to better ways of doing things to help you avoid problems:
 | [svelte/no-ignored-unsubscribe](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-ignored-unsubscribe/) | disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores. |  |
 | [svelte/no-immutable-reactive-statements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-immutable-reactive-statements/) | disallow reactive statements that don't reference reactive values. |  |
 | [svelte/no-inline-styles](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inline-styles/) | disallow attributes and directives that produce inline styles |  |
+| [svelte/no-inspect](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inspect/) | Warns against the use of `$inspect` directive |  |
 | [svelte/no-reactive-functions](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-reactive-functions/) | it's not necessary to define functions in reactive statements | :bulb: |
 | [svelte/no-reactive-literals](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-reactive-literals/) | don't assign literal values in reactive statements | :bulb: |
 | [svelte/no-svelte-internal](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-svelte-internal/) | svelte/internal will be removed in Svelte 6. |  |
@@ -440,6 +441,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
 |:--------|:------------|:---|
 | [svelte/derived-has-same-inputs-outputs](https://sveltejs.github.io/eslint-plugin-svelte/rules/derived-has-same-inputs-outputs/) | derived store should use same variable names between values and callback |  |
 | [svelte/first-attribute-linebreak](https://sveltejs.github.io/eslint-plugin-svelte/rules/first-attribute-linebreak/) | enforce the location of first attribute | :wrench: |
+| [svelte/html-closing-bracket-new-line](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-new-line/) | Require or disallow a line break before tag's closing brackets | :wrench: |
 | [svelte/html-closing-bracket-spacing](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-spacing/) | require or disallow a space before tag's closing brackets | :wrench: |
 | [svelte/html-quotes](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-quotes/) | enforce quotes style of HTML attributes | :wrench: |
 | [svelte/html-self-closing](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-self-closing/) | enforce self-closing style | :wrench: |
diff --git a/docs-svelte-kit/package.json b/docs-svelte-kit/package.json
index 4a8998d..f8c00b7 100644
--- a/docs-svelte-kit/package.json
+++ b/docs-svelte-kit/package.json
@@ -11,53 +11,53 @@
     "svelte-kit": "vite"
   },
   "devDependencies": {
-    "@babel/core": "^7.24.5",
-    "@babel/types": "^7.24.5",
-    "@fontsource/fira-mono": "^5.0.13",
-    "@ota-meshi/eslint-plugin": "^0.17.1",
+    "@babel/core": "^7.25.8",
+    "@babel/types": "^7.25.8",
+    "@fontsource/fira-mono": "^5.1.0",
+    "@ota-meshi/eslint-plugin": "^0.17.5",
     "@sindresorhus/slugify": "^2.2.1",
-    "@sveltejs/adapter-static": "^3.0.1",
-    "@sveltejs/kit": "^2.5.9",
-    "@sveltejs/vite-plugin-svelte": "^3.1.0",
+    "@sveltejs/adapter-static": "^3.0.5",
+    "@sveltejs/kit": "^2.7.1",
+    "@sveltejs/vite-plugin-svelte": "^3.1.2",
     "@types/babel__core": "^7.20.5",
     "@types/cross-spawn": "^6.0.6",
     "@types/escape-html": "^1.0.4",
     "@types/eslint-scope": "^3.7.7",
     "@types/eslint-visitor-keys": "^3.3.0",
     "@types/less": "^3.0.6",
-    "@types/markdown-it": "^14.1.1",
+    "@types/markdown-it": "^14.1.2",
     "@types/markdown-it-container": "^2.0.10",
     "@types/markdown-it-emoji": "^3.0.1",
-    "@types/node": "^20.12.12",
+    "@types/node": "^20.16.11",
     "@types/prismjs": "^1.26.4",
-    "@types/stylus": "^0.48.42",
-    "@typescript/vfs": "^1.5.0",
-    "acorn": "^8.11.3",
+    "@types/stylus": "^0.48.43",
+    "@typescript/vfs": "^1.6.0",
+    "acorn": "^8.13.0",
     "assert": "^2.1.0",
     "cross-spawn": "^7.0.3",
     "env-cmd": "^10.1.0",
     "esbuild": "^0.24.0",
     "escape-html": "^1.0.3",
     "eslint-plugin-svelte": "workspace:^",
-    "eslint-scope": "^8.0.1",
-    "eslint-visitor-keys": "^4.0.0",
-    "espree": "^10.0.1",
-    "globals": "^15.2.0",
-    "markdown-it-anchor": "^9.0.0",
+    "eslint-scope": "^8.1.0",
+    "eslint-visitor-keys": "^4.1.0",
+    "espree": "^10.2.0",
+    "globals": "^15.11.0",
+    "markdown-it-anchor": "^9.2.0",
     "markdown-it-container": "^4.0.0",
     "markdown-it-emoji": "^3.0.0",
     "pako": "^2.1.0",
-    "postcss-nested": "^6.0.1",
+    "postcss-nested": "^6.2.0",
     "prism-svelte": "^0.5.0",
     "prismjs": "^1.29.0",
-    "sass": "^1.77.2",
-    "source-map-js": "^1.2.0",
+    "sass": "^1.79.5",
+    "source-map-js": "^1.2.1",
     "stylus": "^0.63.0",
-    "svelte": "^5.0.0-next.112",
+    "svelte": "^5.0.0-next.268",
     "svelte-adapter-ghpages": "0.2.2",
     "util": "^0.12.5",
-    "vite": "^5.2.11",
-    "vite-plugin-eslint4b": "^0.4.2",
+    "vite": "^5.4.9",
+    "vite-plugin-eslint4b": "^0.4.6",
     "vite-plugin-svelte-md": "^0.1.7"
   }
 }
diff --git a/docs-svelte-kit/src/lib/header/Header.svelte b/docs-svelte-kit/src/lib/header/Header.svelte
index 39a8672..78af595 100644
--- a/docs-svelte-kit/src/lib/header/Header.svelte
+++ b/docs-svelte-kit/src/lib/header/Header.svelte
@@ -77,6 +77,7 @@
 			target="_blank"
 			class="github-link"
 			rel="noopener noreferrer"
+			aria-label="GitHub"
 		>
 			<svg
 				version="1.1"
diff --git a/docs/rules.md b/docs/rules.md
index 7f115da..fb067e5 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -56,6 +56,7 @@ These rules relate to better ways of doing things to help you avoid problems:
 | [svelte/no-ignored-unsubscribe](./rules/no-ignored-unsubscribe.md)                       | disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores.                                                  |          |
 | [svelte/no-immutable-reactive-statements](./rules/no-immutable-reactive-statements.md)   | disallow reactive statements that don't reference reactive values.                                                                        |          |
 | [svelte/no-inline-styles](./rules/no-inline-styles.md)                                   | disallow attributes and directives that produce inline styles                                                                             |          |
+| [svelte/no-inspect](./rules/no-inspect.md)                                               | Warns against the use of `$inspect` directive                                                                                             |          |
 | [svelte/no-reactive-functions](./rules/no-reactive-functions.md)                         | it's not necessary to define functions in reactive statements                                                                             | :bulb:   |
 | [svelte/no-reactive-literals](./rules/no-reactive-literals.md)                           | don't assign literal values in reactive statements                                                                                        | :bulb:   |
 | [svelte/no-svelte-internal](./rules/no-svelte-internal.md)                               | svelte/internal will be removed in Svelte 6.                                                                                              |          |
@@ -77,6 +78,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
 | :------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | :------- |
 | [svelte/derived-has-same-inputs-outputs](./rules/derived-has-same-inputs-outputs.md)                     | derived store should use same variable names between values and callback           |          |
 | [svelte/first-attribute-linebreak](./rules/first-attribute-linebreak.md)                                 | enforce the location of first attribute                                            | :wrench: |
+| [svelte/html-closing-bracket-new-line](./rules/html-closing-bracket-new-line.md)                         | Require or disallow a line break before tag's closing brackets                     | :wrench: |
 | [svelte/html-closing-bracket-spacing](./rules/html-closing-bracket-spacing.md)                           | require or disallow a space before tag's closing brackets                          | :wrench: |
 | [svelte/html-quotes](./rules/html-quotes.md)                                                             | enforce quotes style of HTML attributes                                            | :wrench: |
 | [svelte/html-self-closing](./rules/html-self-closing.md)                                                 | enforce self-closing style                                                         | :wrench: |
diff --git a/docs/rules/html-closing-bracket-new-line.md b/docs/rules/html-closing-bracket-new-line.md
new file mode 100644
index 0000000..39ed84e
--- /dev/null
+++ b/docs/rules/html-closing-bracket-new-line.md
@@ -0,0 +1,89 @@
+---
+pageClass: 'rule-details'
+sidebarDepth: 0
+title: 'svelte/html-closing-bracket-new-line'
+description: "Require or disallow a line break before tag's closing brackets"
+---
+
+# svelte/html-closing-bracket-new-line
+
+> Require or disallow a line break before tag's closing brackets
+
+- :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 enforces a line break (or no line break) before tag's closing brackets, which can also be configured to be enforced on self-closing tags.
+
+<ESLintCodeBlock fix>
+
+<!-- prettier-ignore-start -->
+<!--eslint-skip-->
+
+```svelte
+<script>
+  /* eslint svelte/brackets-same-line: "error" */
+</script>
+
+<!-- ✓ GOOD -->
+<div></div>
+<div
+  multiline
+>
+  Children
+</div>
+
+<SelfClosing />
+<SelfClosing
+  multiline
+/>
+
+<!-- ✗ BAD -->
+
+<div
+></div>
+<div
+  multiline>
+  Children
+</div>
+
+<SelfClosing
+/>
+<SelfClosing
+  multiline/>
+```
+
+<!-- prettier-ignore-end -->
+
+</ESLintCodeBlock>
+
+## :wrench: Options
+
+```jsonc
+{
+  "svelte/brackets-same-line": [
+    "error",
+    {
+      "singleline": "never", // ["never", "always"]
+      "multiline": "always", // ["never", "always"]
+      "selfClosingTag": {
+        "singleline": "never", // ["never", "always"]
+        "multiline": "always" // ["never", "always"]
+      }
+    }
+  ]
+}
+```
+
+- `singleline`: (`"never"` by default) Configuration for single-line elements. It's a single-line element if the element does not have attributes or the last attribute is on the same line as the opening bracket.
+- `multiline`: (`"always"` by default) Configuration for multi-line elements. It's a multi-line element if the last attribute is not on the same line of the opening bracket.
+- `selfClosingTag.singleline`: Configuration for single-line self closing elements.
+- `selfClosingTag.multiline`: Configuration for multi-line self closing elements.
+
+The `selfClosing` is optional, and by default it will use the same configuration as `singleline` and `multiline`, respectively.
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/html-closing-bracket-new-line.ts)
+- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/tests/src/rules/html-closing-bracket-new-line.ts)
diff --git a/docs/rules/no-inspect.md b/docs/rules/no-inspect.md
new file mode 100644
index 0000000..3689268
--- /dev/null
+++ b/docs/rules/no-inspect.md
@@ -0,0 +1,39 @@
+---
+pageClass: 'rule-details'
+sidebarDepth: 0
+title: 'svelte/no-inspect'
+description: 'Warns against the use of `$inspect` directive'
+---
+
+# svelte/no-inspect
+
+> Warns against the use of `$inspect` directive
+
+- :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 reports usages of `$inspect`.
+
+<ESLintCodeBlock>
+
+<!--eslint-skip-->
+
+```svelte
+<script>
+  /* eslint svelte/no-inspect: "error" */
+  // ✗ BAD
+  $inspect(1);
+</script>
+```
+
+</ESLintCodeBlock>
+
+## :wrench: Options
+
+Nothing.
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/no-inspect.ts)
+- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/tests/src/rules/no-inspect.ts)
diff --git a/package.json b/package.json
index cfecec6..aa42ba6 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
   },
   "devDependencies": {
     "@changesets/changelog-github": "^0.5.0",
-    "@changesets/cli": "^2.27.8",
+    "@changesets/cli": "^2.27.9",
     "@changesets/get-release-plan": "^4.0.4",
     "@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
     "@ota-meshi/eslint-plugin": "^0.17.5",
@@ -23,25 +23,25 @@
     "@typescript-eslint/eslint-plugin": "^7.18.0",
     "@typescript-eslint/parser": "^7.18.0",
     "env-cmd": "^10.1.0",
-    "eslint": "^9.10.0",
+    "eslint": "^9.12.0",
     "eslint-config-prettier": "^9.1.0",
     "eslint-formatter-friendly": "^7.0.0",
     "eslint-plugin-eslint-plugin": "^6.2.0",
-    "eslint-plugin-jsdoc": "^50.2.2",
-    "eslint-plugin-json-schema-validator": "^5.1.2",
+    "eslint-plugin-jsdoc": "^50.4.1",
+    "eslint-plugin-json-schema-validator": "^5.1.3",
     "eslint-plugin-jsonc": "^2.16.0",
     "eslint-plugin-markdown": "^5.1.0",
     "eslint-plugin-mdx": "^3.1.5",
-    "eslint-plugin-n": "^17.10.2",
+    "eslint-plugin-n": "^17.11.1",
     "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": "^6.2.2",
+    "npm-run-all2": "^6.2.3",
     "prettier": "^3.3.3",
-    "prettier-plugin-svelte": "^3.2.6",
+    "prettier-plugin-svelte": "^3.2.7",
     "rimraf": "^6.0.1",
-    "typescript": "~5.6.0",
+    "typescript": "~5.6.3",
     "typescript-eslint": "^7.18.0"
   },
   "publishConfig": {
diff --git a/packages/eslint-plugin-svelte/package.json b/packages/eslint-plugin-svelte/package.json
index 0e30290..8c19fca 100644
--- a/packages/eslint-plugin-svelte/package.json
+++ b/packages/eslint-plugin-svelte/package.json
@@ -69,39 +69,39 @@
     "svelte-eslint-parser": "^0.41.1"
   },
   "devDependencies": {
-    "@babel/core": "^7.25.2",
-    "@babel/eslint-parser": "^7.25.1",
-    "@babel/plugin-proposal-function-bind": "^7.24.7",
+    "@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",
     "@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.8",
-    "@types/node": "^20.16.5",
+    "@types/mocha": "^10.0.9",
+    "@types/node": "^20.16.11",
     "@types/postcss-safe-parser": "^5.0.4",
     "@types/semver": "^7.5.8",
-    "@types/stylus": "^0.48.42",
-    "acorn": "^8.12.1",
+    "@types/stylus": "^0.48.43",
+    "acorn": "^8.13.0",
     "assert": "^2.1.0",
     "esbuild": "^0.24.0",
     "esbuild-register": "^3.6.0",
-    "eslint-scope": "^8.0.2",
+    "eslint-scope": "^8.1.0",
     "eslint-typegen": "^0.3.2",
-    "eslint-visitor-keys": "^4.0.0",
-    "espree": "^10.1.0",
+    "eslint-visitor-keys": "^4.1.0",
+    "espree": "^10.2.0",
     "less": "^4.2.0",
     "mocha": "^10.7.3",
-    "nyc": "^17.0.0",
+    "nyc": "^17.1.0",
     "postcss-nested": "^6.2.0",
-    "sass": "^1.78.0",
+    "sass": "^1.79.5",
     "source-map-js": "^1.2.1",
     "stylus": "^0.63.0",
-    "svelte": "5.0.0-next.249",
+    "svelte": "^5.0.0-next.268",
     "svelte-i18n": "^4.0.0",
-    "type-coverage": "^2.29.1",
-    "yaml": "^2.5.1"
+    "type-coverage": "^2.29.7",
+    "yaml": "^2.6.0"
   },
   "publishConfig": {
     "access": "public"
diff --git a/packages/eslint-plugin-svelte/src/configs/flat/prettier.ts b/packages/eslint-plugin-svelte/src/configs/flat/prettier.ts
index f383837..a97e410 100644
--- a/packages/eslint-plugin-svelte/src/configs/flat/prettier.ts
+++ b/packages/eslint-plugin-svelte/src/configs/flat/prettier.ts
@@ -10,6 +10,7 @@ const config: Linter.Config[] = [
 		rules: {
 			// eslint-plugin-svelte rules
 			'svelte/first-attribute-linebreak': 'off',
+			'svelte/html-closing-bracket-new-line': 'off',
 			'svelte/html-closing-bracket-spacing': 'off',
 			'svelte/html-quotes': 'off',
 			'svelte/html-self-closing': 'off',
diff --git a/packages/eslint-plugin-svelte/src/configs/prettier.ts b/packages/eslint-plugin-svelte/src/configs/prettier.ts
index eb76a58..6b4faf2 100644
--- a/packages/eslint-plugin-svelte/src/configs/prettier.ts
+++ b/packages/eslint-plugin-svelte/src/configs/prettier.ts
@@ -10,6 +10,7 @@ const config: Linter.LegacyConfig = {
 	rules: {
 		// eslint-plugin-svelte rules
 		'svelte/first-attribute-linebreak': 'off',
+		'svelte/html-closing-bracket-new-line': 'off',
 		'svelte/html-closing-bracket-spacing': 'off',
 		'svelte/html-quotes': 'off',
 		'svelte/html-self-closing': 'off',
diff --git a/packages/eslint-plugin-svelte/src/rule-types.ts b/packages/eslint-plugin-svelte/src/rule-types.ts
index c6b683f..8e747b6 100644
--- a/packages/eslint-plugin-svelte/src/rule-types.ts
+++ b/packages/eslint-plugin-svelte/src/rule-types.ts
@@ -54,6 +54,11 @@ export interface RuleOptions {
    * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/first-attribute-linebreak/
    */
   'svelte/first-attribute-linebreak'?: Linter.RuleEntry<SvelteFirstAttributeLinebreak>
+  /**
+   * Require or disallow a line break before tag's closing brackets
+   * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-new-line/
+   */
+  'svelte/html-closing-bracket-new-line'?: Linter.RuleEntry<SvelteHtmlClosingBracketNewLine>
   /**
    * require or disallow a space before tag's closing brackets
    * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-spacing/
@@ -164,6 +169,11 @@ export interface RuleOptions {
    * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inner-declarations/
    */
   'svelte/no-inner-declarations'?: Linter.RuleEntry<SvelteNoInnerDeclarations>
+  /**
+   * Warns against the use of `$inspect` directive
+   * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inspect/
+   */
+  'svelte/no-inspect'?: Linter.RuleEntry<[]>
   /**
    * disallow use of not function in event handler
    * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-not-function-handler/
@@ -361,6 +371,15 @@ type SvelteFirstAttributeLinebreak = []|[{
   multiline?: ("below" | "beside")
   singleline?: ("below" | "beside")
 }]
+// ----- svelte/html-closing-bracket-new-line -----
+type SvelteHtmlClosingBracketNewLine = []|[{
+  singleline?: ("always" | "never")
+  multiline?: ("always" | "never")
+  selfClosingTag?: {
+    singleline?: ("always" | "never")
+    multiline?: ("always" | "never")
+  }
+}]
 // ----- svelte/html-closing-bracket-spacing -----
 type SvelteHtmlClosingBracketSpacing = []|[{
   startTag?: ("always" | "never" | "ignore")
diff --git a/packages/eslint-plugin-svelte/src/rules/html-closing-bracket-new-line.ts b/packages/eslint-plugin-svelte/src/rules/html-closing-bracket-new-line.ts
new file mode 100644
index 0000000..20902d7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/src/rules/html-closing-bracket-new-line.ts
@@ -0,0 +1,163 @@
+import type { AST } from 'svelte-eslint-parser';
+import { createRule } from '../utils';
+import { getSourceCode } from '../utils/compat';
+import type { SourceCode } from '../types';
+
+type ExpectedNode = AST.SvelteStartTag | AST.SvelteEndTag;
+type OptionValue = 'always' | 'never';
+type RuleOptions = {
+	singleline: OptionValue;
+	multiline: OptionValue;
+	selfClosingTag?: Omit<RuleOptions, 'selfClosingTag'>;
+};
+
+function getPhrase(lineBreaks: number) {
+	switch (lineBreaks) {
+		case 0: {
+			return 'no line breaks';
+		}
+		case 1: {
+			return '1 line break';
+		}
+		default: {
+			return `${lineBreaks} line breaks`;
+		}
+	}
+}
+
+function getExpectedLineBreaks(
+	node: ExpectedNode,
+	options: RuleOptions,
+	type: keyof Omit<RuleOptions, 'selfClosingTag'>
+) {
+	const isSelfClosingTag = node.type === 'SvelteStartTag' && node.selfClosing;
+	if (isSelfClosingTag && options.selfClosingTag && options.selfClosingTag[type]) {
+		return options.selfClosingTag[type] === 'always' ? 1 : 0;
+	}
+
+	return options[type] === 'always' ? 1 : 0;
+}
+
+type NodeData = {
+	actualLineBreaks: number;
+	expectedLineBreaks: number;
+	startToken: AST.Token;
+	endToken: AST.Token;
+};
+
+function getSelfClosingData(
+	sourceCode: SourceCode,
+	node: AST.SvelteStartTag,
+	options: RuleOptions
+): NodeData | null {
+	const tokens = sourceCode.getTokens(node);
+	const closingToken = tokens[tokens.length - 2];
+	if (closingToken.value !== '/') {
+		return null;
+	}
+
+	const prevToken = sourceCode.getTokenBefore(closingToken)!;
+	const type = node.loc.start.line === prevToken.loc.end.line ? 'singleline' : 'multiline';
+
+	const expectedLineBreaks = getExpectedLineBreaks(node, options, type);
+	const actualLineBreaks = closingToken.loc.start.line - prevToken.loc.end.line;
+
+	return { actualLineBreaks, expectedLineBreaks, startToken: prevToken, endToken: closingToken };
+}
+
+function getNodeData(
+	sourceCode: SourceCode,
+	node: ExpectedNode,
+	options: RuleOptions
+): NodeData | null {
+	const closingToken = sourceCode.getLastToken(node);
+	if (closingToken.value !== '>') {
+		return null;
+	}
+
+	const prevToken = sourceCode.getTokenBefore(closingToken)!;
+	const type = node.loc.start.line === prevToken.loc.end.line ? 'singleline' : 'multiline';
+
+	const expectedLineBreaks = getExpectedLineBreaks(node, options, type);
+	const actualLineBreaks = closingToken.loc.start.line - prevToken.loc.end.line;
+
+	return { actualLineBreaks, expectedLineBreaks, startToken: prevToken, endToken: closingToken };
+}
+
+export default createRule('html-closing-bracket-new-line', {
+	meta: {
+		docs: {
+			description: "Require or disallow a line break before tag's closing brackets",
+			category: 'Stylistic Issues',
+			recommended: false,
+			conflictWithPrettier: true
+		},
+		schema: [
+			{
+				type: 'object',
+				properties: {
+					singleline: { enum: ['always', 'never'] },
+					multiline: { enum: ['always', 'never'] },
+					selfClosingTag: {
+						type: 'object',
+						properties: {
+							singleline: { enum: ['always', 'never'] },
+							multiline: { enum: ['always', 'never'] }
+						},
+						additionalProperties: false,
+						minProperties: 1
+					}
+				},
+				additionalProperties: false
+			}
+		],
+		messages: {
+			expectedBeforeClosingBracket:
+				'Expected {{expected}} before closing bracket, but {{actual}} found.'
+		},
+		fixable: 'code',
+		type: 'suggestion'
+	},
+	create(context) {
+		const options: RuleOptions = context.options[0] ?? {};
+		options.singleline ??= 'never';
+		options.multiline ??= 'always';
+
+		const sourceCode = getSourceCode(context);
+
+		return {
+			'SvelteStartTag, SvelteEndTag'(node: ExpectedNode) {
+				const data =
+					node.type === 'SvelteStartTag' && node.selfClosing
+						? getSelfClosingData(sourceCode, node, options)
+						: getNodeData(sourceCode, node, options);
+				if (!data) {
+					return;
+				}
+
+				const { actualLineBreaks, expectedLineBreaks, startToken, endToken } = data;
+				if (actualLineBreaks !== expectedLineBreaks) {
+					// For SvelteEndTag, does not make sense to add a line break, so we only fix if there are extra line breaks
+					if (node.type === 'SvelteEndTag' && expectedLineBreaks !== 0) {
+						return;
+					}
+
+					context.report({
+						node,
+						loc: { start: startToken.loc.end, end: endToken.loc.start },
+						messageId: 'expectedBeforeClosingBracket',
+						data: {
+							expected: getPhrase(expectedLineBreaks),
+							actual: getPhrase(actualLineBreaks)
+						},
+						fix(fixer) {
+							const range: AST.Range = [startToken.range[1], endToken.range[0]];
+							const text = '\n'.repeat(expectedLineBreaks);
+							return fixer.replaceTextRange(range, text);
+						}
+					});
+				}
+			}
+		};
+	}
+});
diff --git a/packages/eslint-plugin-svelte/src/rules/no-inspect.ts b/packages/eslint-plugin-svelte/src/rules/no-inspect.ts
new file mode 100644
index 0000000..22e30ce
--- /dev/null
+++ b/packages/eslint-plugin-svelte/src/rules/no-inspect.ts
@@ -0,0 +1,31 @@
+import type { TSESTree } from '@typescript-eslint/types';
+
+import { createRule } from '../utils';
+
+export default createRule('no-inspect', {
+	meta: {
+		docs: {
+			description: 'Warns against the use of `$inspect` directive',
+			category: 'Best Practices',
+			// TODO: Enable recommended in major version
+			recommended: false,
+			default: 'warn'
+		},
+		schema: [],
+		messages: {
+			unexpected: 'Do not use $inspect directive'
+		},
+		type: 'suggestion'
+	},
+	create(context) {
+		return {
+			Identifier(node: TSESTree.Identifier) {
+				if (node.name !== '$inspect') {
+					return;
+				}
+
+				context.report({ messageId: 'unexpected', node });
+			}
+		};
+	}
+});
diff --git a/packages/eslint-plugin-svelte/src/utils/rules.ts b/packages/eslint-plugin-svelte/src/utils/rules.ts
index af0dd20..5bb5a08 100644
--- a/packages/eslint-plugin-svelte/src/utils/rules.ts
+++ b/packages/eslint-plugin-svelte/src/utils/rules.ts
@@ -10,6 +10,7 @@ import derivedHasSameInputsOutputs from '../rules/derived-has-same-inputs-output
 import experimentalRequireSlotTypes from '../rules/experimental-require-slot-types';
 import experimentalRequireStrictEvents from '../rules/experimental-require-strict-events';
 import firstAttributeLinebreak from '../rules/first-attribute-linebreak';
+import htmlClosingBracketNewLine from '../rules/html-closing-bracket-new-line';
 import htmlClosingBracketSpacing from '../rules/html-closing-bracket-spacing';
 import htmlQuotes from '../rules/html-quotes';
 import htmlSelfClosing from '../rules/html-self-closing';
@@ -32,6 +33,7 @@ import noIgnoredUnsubscribe from '../rules/no-ignored-unsubscribe';
 import noImmutableReactiveStatements from '../rules/no-immutable-reactive-statements';
 import noInlineStyles from '../rules/no-inline-styles';
 import noInnerDeclarations from '../rules/no-inner-declarations';
+import noInspect from '../rules/no-inspect';
 import noNotFunctionHandler from '../rules/no-not-function-handler';
 import noObjectInTextMustaches from '../rules/no-object-in-text-mustaches';
 import noReactiveFunctions from '../rules/no-reactive-functions';
@@ -75,6 +77,7 @@ export const rules = [
 	experimentalRequireSlotTypes,
 	experimentalRequireStrictEvents,
 	firstAttributeLinebreak,
+	htmlClosingBracketNewLine,
 	htmlClosingBracketSpacing,
 	htmlQuotes,
 	htmlSelfClosing,
@@ -97,6 +100,7 @@ export const rules = [
 	noImmutableReactiveStatements,
 	noInlineStyles,
 	noInnerDeclarations,
+	noInspect,
 	noNotFunctionHandler,
 	noObjectInTextMustaches,
 	noReactiveFunctions,


Test patch:
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/_config.json
new file mode 100644
index 0000000..1c8db18
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/_config.json
@@ -0,0 +1,3 @@
+{
+	"options": [{ "multiline": "never" }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-errors.yaml
new file mode 100644
index 0000000..fc094d0
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-errors.yaml
@@ -0,0 +1,8 @@
+- message: Expected no line breaks before closing bracket, but 1 line break found.
+  line: 2
+  column: 12
+  suggestions: null
+- message: Expected no line breaks before closing bracket, but 1 line break found.
+  line: 7
+  column: 12
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-input.svelte
new file mode 100644
index 0000000..e3e5b5e
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-input.svelte
@@ -0,0 +1,10 @@
+<div
+class="foo"
+></div>
+<div
+class="bar"></div>
+<div
+class="bar"
+>
+Children
+</div>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-output.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-output.svelte
new file mode 100644
index 0000000..40b9c84
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/multiline-never/test01-output.svelte
@@ -0,0 +1,8 @@
+<div
+class="foo"></div>
+<div
+class="bar"></div>
+<div
+class="bar">
+Children
+</div>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/_config.json
new file mode 100644
index 0000000..0d0e60c
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/_config.json
@@ -0,0 +1,3 @@
+{
+	"options": [{ "selfClosingTag": { "singleline": "always", "multiline": "always" } }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-errors.yaml
new file mode 100644
index 0000000..1a10165
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-errors.yaml
@@ -0,0 +1,8 @@
+- message: Expected 1 line break before closing bracket, but no line breaks found.
+  line: 1
+  column: 18
+  suggestions: null
+- message: Expected 1 line break before closing bracket, but 2 line breaks found.
+  line: 6
+  column: 12
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-input.svelte
new file mode 100644
index 0000000..b150ca5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-input.svelte
@@ -0,0 +1,8 @@
+<Custom foo="bar" />
+<Custom 
+  foo="bar"
+/>
+<Custom 
+  foo="bar"
+
+/>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-output.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-output.svelte
new file mode 100644
index 0000000..f39f855
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/always/test-output.svelte
@@ -0,0 +1,8 @@
+<Custom foo="bar"
+/>
+<Custom 
+  foo="bar"
+/>
+<Custom 
+  foo="bar"
+/>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/_config.json
new file mode 100644
index 0000000..127cc8b
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/_config.json
@@ -0,0 +1,3 @@
+{
+	"options": [{ "selfClosingTag": { "singleline": "never", "multiline": "never" } }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-errors.yaml
new file mode 100644
index 0000000..a124b0c
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-errors.yaml
@@ -0,0 +1,8 @@
+- message: Expected no line breaks before closing bracket, but 1 line break found.
+  line: 3
+  column: 12
+  suggestions: null
+- message: Expected no line breaks before closing bracket, but 2 line breaks found.
+  line: 6
+  column: 12
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-input.svelte
new file mode 100644
index 0000000..b150ca5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-input.svelte
@@ -0,0 +1,8 @@
+<Custom foo="bar" />
+<Custom 
+  foo="bar"
+/>
+<Custom 
+  foo="bar"
+
+/>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-output.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-output.svelte
new file mode 100644
index 0000000..580b415
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/self-closing/never/test-output.svelte
@@ -0,0 +1,5 @@
+<Custom foo="bar" />
+<Custom 
+  foo="bar"/>
+<Custom 
+  foo="bar"/>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/_config.json
new file mode 100644
index 0000000..74ea9fd
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/_config.json
@@ -0,0 +1,3 @@
+{
+	"options": [{ "singleline": "always" }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-errors.yaml
new file mode 100644
index 0000000..e7b7863
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-errors.yaml
@@ -0,0 +1,8 @@
+- message: Expected 1 line break before closing bracket, but no line breaks found.
+  line: 1
+  column: 5
+  suggestions: null
+- message: Expected 1 line break before closing bracket, but no line breaks found.
+  line: 2
+  column: 5
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-input.svelte
new file mode 100644
index 0000000..2cf4975
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-input.svelte
@@ -0,0 +1,3 @@
+<div></div>
+<div>
+</div>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-output.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-output.svelte
new file mode 100644
index 0000000..da7c824
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/singleline-always/test01-output.svelte
@@ -0,0 +1,5 @@
+<div
+></div>
+<div
+>
+</div>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-errors.yaml
new file mode 100644
index 0000000..548d314
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-errors.yaml
@@ -0,0 +1,12 @@
+- message: Expected no line breaks before closing bracket, but 3 line breaks found.
+  line: 3
+  column: 8
+  suggestions: null
+- message: Expected no line breaks before closing bracket, but 1 line break found.
+  line: 8
+  column: 5
+  suggestions: null
+- message: Expected 1 line break before closing bracket, but no line breaks found.
+  line: 11
+  column: 14
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-input.svelte
new file mode 100644
index 0000000..fb10f84
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-input.svelte
@@ -0,0 +1,11 @@
+<div>
+  <div>
+  </div
+
+
+  >
+</div>
+<div
+></div>
+<div
+  class="foo"></div>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-output.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-output.svelte
new file mode 100644
index 0000000..45cdbc8
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test01-output.svelte
@@ -0,0 +1,8 @@
+<div>
+  <div>
+  </div>
+</div>
+<div></div>
+<div
+  class="foo"
+></div>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-errors.yaml
new file mode 100644
index 0000000..354b3d1
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-errors.yaml
@@ -0,0 +1,8 @@
+- message: Expected 1 line break before closing bracket, but 2 line breaks found.
+  line: 3
+  column: 14
+  suggestions: null
+- message: Expected no line breaks before closing bracket, but 2 line breaks found.
+  line: 7
+  column: 5
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-input.svelte
new file mode 100644
index 0000000..ab05069
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-input.svelte
@@ -0,0 +1,11 @@
+<SingleLine class="foo" />
+<Multiline
+  class="foo"
+
+  />
+
+<div
+
+  />
+
+<div />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-output.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-output.svelte
new file mode 100644
index 0000000..f145cb7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/invalid/test02-output.svelte
@@ -0,0 +1,8 @@
+<SingleLine class="foo" />
+<Multiline
+  class="foo"
+/>
+
+<div/>
+
+<div />
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/valid/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/valid/test01-input.svelte
new file mode 100644
index 0000000..aa2be93
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/html-closing-bracket-new-line/valid/test01-input.svelte
@@ -0,0 +1,4 @@
+<div></div>
+<SelfClosing 
+  class="foo"
+/>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/invalid/test01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/invalid/test01-errors.yaml
new file mode 100644
index 0000000..db86c5f
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/invalid/test01-errors.yaml
@@ -0,0 +1,12 @@
+- message: Do not use $inspect directive
+  line: 2
+  column: 3
+  suggestions: null
+- message: Do not use $inspect directive
+  line: 5
+  column: 13
+  suggestions: null
+- message: Do not use $inspect directive
+  line: 8
+  column: 5
+  suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/invalid/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/invalid/test01-input.svelte
new file mode 100644
index 0000000..c6a6943
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/invalid/test01-input.svelte
@@ -0,0 +1,10 @@
+<script>
+  $inspect(1);
+  $state(0);
+
+  const a = $inspect(1);
+
+  const _ = () => {
+    $inspect(1);
+  }
+</script>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/valid/test01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/valid/test01-input.svelte
new file mode 100644
index 0000000..d65891b
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-inspect/valid/test01-input.svelte
@@ -0,0 +1,3 @@
+<script>
+  const _ = $state(1);
+</script>
diff --git a/packages/eslint-plugin-svelte/tests/src/rules/html-closing-bracket-new-line.ts b/packages/eslint-plugin-svelte/tests/src/rules/html-closing-bracket-new-line.ts
new file mode 100644
index 0000000..dfeba14
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/src/rules/html-closing-bracket-new-line.ts
@@ -0,0 +1,12 @@
+import { RuleTester } from '../../utils/eslint-compat';
+import rule from '../../../src/rules/html-closing-bracket-new-line';
+import { loadTestCases } from '../../utils/utils';
+
+const tester = new RuleTester({
+	languageOptions: {
+		ecmaVersion: 2020,
+		sourceType: 'module'
+	}
+});
+
+tester.run('html-closing-bracket-new-line', rule as any, loadTestCases('html-closing-bracket-new-line'));
diff --git a/packages/eslint-plugin-svelte/tests/src/rules/no-inspect.ts b/packages/eslint-plugin-svelte/tests/src/rules/no-inspect.ts
new file mode 100644
index 0000000..cfaa549
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/src/rules/no-inspect.ts
@@ -0,0 +1,12 @@
+import { RuleTester } from '../../utils/eslint-compat';
+import rule from '../../../src/rules/no-inspect';
+import { loadTestCases } from '../../utils/utils';
+
+const tester = new RuleTester({
+	languageOptions: {
+		ecmaVersion: 2020,
+		sourceType: 'module'
+	}
+});
+
+tester.run('no-inspect', rule as any, loadTestCases('no-inspect'));