diff --git a/.changeset/chilly-bats-allow.md b/.changeset/chilly-bats-allow.md
new file mode 100644
index 000000000..6f720597a
--- /dev/null
+++ b/.changeset/chilly-bats-allow.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-svelte": minor
+---
+
+feat: add `svelte/no-svelte-internal` rule
diff --git a/README.md b/README.md
index 435777a47..4ba4c5a2c 100644
--- a/README.md
+++ b/README.md
@@ -385,6 +385,7 @@ These rules relate to better ways of doing things to help you avoid problems:
| [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-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. | |
| [svelte/no-unused-class-name](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unused-class-name/) | disallow the use of a class in the template without a corresponding style | |
| [svelte/no-unused-svelte-ignore](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unused-svelte-ignore/) | disallow unused svelte-ignore comments | :star: |
| [svelte/no-useless-mustaches](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-useless-mustaches/) | disallow unnecessary mustache interpolations | :wrench: |
diff --git a/docs/rules.md b/docs/rules.md
index e932ded0a..7f115da5c 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -58,6 +58,7 @@ These rules relate to better ways of doing things to help you avoid problems:
| [svelte/no-inline-styles](./rules/no-inline-styles.md) | disallow attributes and directives that produce inline styles | |
| [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. | |
| [svelte/no-unused-class-name](./rules/no-unused-class-name.md) | disallow the use of a class in the template without a corresponding style | |
| [svelte/no-unused-svelte-ignore](./rules/no-unused-svelte-ignore.md) | disallow unused svelte-ignore comments | :star: |
| [svelte/no-useless-mustaches](./rules/no-useless-mustaches.md) | disallow unnecessary mustache interpolations | :wrench: |
diff --git a/docs/rules/no-svelte-internal.md b/docs/rules/no-svelte-internal.md
new file mode 100644
index 000000000..2089bef8a
--- /dev/null
+++ b/docs/rules/no-svelte-internal.md
@@ -0,0 +1,55 @@
+---
+pageClass: 'rule-details'
+sidebarDepth: 0
+title: 'svelte/no-svelte-internal'
+description: 'svelte/internal will be removed in Svelte 6.'
+---
+
+# svelte/no-svelte-internal
+
+> svelte/internal will be removed in Svelte 6.
+
+- :exclamation: **_This rule has not been released yet._**
+
+## :book: Rule Details
+
+This rule reports the use of the deprecated API `svelte/internal` and `svelte/internal/xxx`. `svelte/internal` is deprecated in Svelte 5. And it will be deleted in Svelte 6. These APIs can change in breaking ways at any time without notice.
+
+
+
+
+
+```svelte
+
+```
+
+
+
+## :wrench: Options
+
+Nothing.
+
+## :books: Further Reading
+
+
+
+Nothing.
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/src/rules/no-svelte-internal.ts)
+- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/tests/src/rules/no-svelte-internal.ts)
diff --git a/src/rule-types.ts b/src/rule-types.ts
index 8f9e88911..77d3c4ca4 100644
--- a/src/rule-types.ts
+++ b/src/rule-types.ts
@@ -209,6 +209,11 @@ export interface RuleOptions {
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-store-async/
*/
'svelte/no-store-async'?: Linter.RuleEntry<[]>
+ /**
+ * svelte/internal will be removed in Svelte 6.
+ * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-svelte-internal/
+ */
+ 'svelte/no-svelte-internal'?: Linter.RuleEntry<[]>
/**
* disallow `target="_blank"` attribute without `rel="noopener noreferrer"`
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-target-blank/
diff --git a/src/rules/no-svelte-internal.ts b/src/rules/no-svelte-internal.ts
new file mode 100644
index 000000000..114496e62
--- /dev/null
+++ b/src/rules/no-svelte-internal.ts
@@ -0,0 +1,59 @@
+import { createRule } from '../utils';
+import type { TSESTree } from '@typescript-eslint/types';
+
+export default createRule('no-svelte-internal', {
+ meta: {
+ docs: {
+ description: 'svelte/internal will be removed in Svelte 6.',
+ category: 'Best Practices',
+ // TODO Switch to recommended in the major version.
+ // recommended: true,
+ recommended: false
+ },
+ schema: [],
+ messages: {
+ unexpected: 'Using svelte/internal is prohibited. This will be removed in Svelte 6.'
+ },
+ type: 'problem'
+ },
+ create(context) {
+ function report(node: TSESTree.Node) {
+ context.report({
+ node,
+ messageId: 'unexpected'
+ });
+ }
+
+ function isSvelteInternal(value: string) {
+ return value === 'svelte/internal' || value.startsWith('svelte/internal/');
+ }
+
+ return {
+ ImportDeclaration(node) {
+ if (node.source && isSvelteInternal(node.source.value)) {
+ report(node);
+ }
+ },
+ ImportExpression(node) {
+ if (
+ node.source &&
+ node.source.type === 'Literal' &&
+ typeof node.source.value === 'string' &&
+ isSvelteInternal(node.source.value)
+ ) {
+ report(node);
+ }
+ },
+ ExportNamedDeclaration(node) {
+ if (node.source && isSvelteInternal(node.source.value)) {
+ report(node);
+ }
+ },
+ ExportAllDeclaration(node) {
+ if (node.source && isSvelteInternal(node.source.value)) {
+ report(node);
+ }
+ }
+ };
+ }
+});
diff --git a/src/utils/rules.ts b/src/utils/rules.ts
index cb19a67a3..af0dd20e6 100644
--- a/src/utils/rules.ts
+++ b/src/utils/rules.ts
@@ -41,6 +41,7 @@ import noRestrictedHtmlElements from '../rules/no-restricted-html-elements';
import noShorthandStylePropertyOverrides from '../rules/no-shorthand-style-property-overrides';
import noSpacesAroundEqualSignsInAttribute from '../rules/no-spaces-around-equal-signs-in-attribute';
import noStoreAsync from '../rules/no-store-async';
+import noSvelteInternal from '../rules/no-svelte-internal';
import noTargetBlank from '../rules/no-target-blank';
import noTrailingSpaces from '../rules/no-trailing-spaces';
import noUnknownStyleDirectiveProperty from '../rules/no-unknown-style-directive-property';
@@ -105,6 +106,7 @@ export const rules = [
noShorthandStylePropertyOverrides,
noSpacesAroundEqualSignsInAttribute,
noStoreAsync,
+ noSvelteInternal,
noTargetBlank,
noTrailingSpaces,
noUnknownStyleDirectiveProperty,
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal01-errors.yaml b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal01-errors.yaml
new file mode 100644
index 000000000..30df267ed
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal01-errors.yaml
@@ -0,0 +1,4 @@
+- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
+ line: 3
+ column: 2
+ suggestions: null
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal01-input.svelte b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal01-input.svelte
new file mode 100644
index 000000000..85c373b15
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal01-input.svelte
@@ -0,0 +1,4 @@
+
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal02-errors.yaml b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal02-errors.yaml
new file mode 100644
index 000000000..e1c7cf351
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal02-errors.yaml
@@ -0,0 +1,4 @@
+- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
+ line: 2
+ column: 2
+ suggestions: null
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal02-input.svelte b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal02-input.svelte
new file mode 100644
index 000000000..12be14e98
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal02-input.svelte
@@ -0,0 +1,3 @@
+
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal03-errors.yaml b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal03-errors.yaml
new file mode 100644
index 000000000..e1c7cf351
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal03-errors.yaml
@@ -0,0 +1,4 @@
+- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
+ line: 2
+ column: 2
+ suggestions: null
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal03-input.svelte b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal03-input.svelte
new file mode 100644
index 000000000..ed4e7e825
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal03-input.svelte
@@ -0,0 +1,3 @@
+
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal04-errors.yaml b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal04-errors.yaml
new file mode 100644
index 000000000..e1c7cf351
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal04-errors.yaml
@@ -0,0 +1,4 @@
+- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
+ line: 2
+ column: 2
+ suggestions: null
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal04-input.svelte b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal04-input.svelte
new file mode 100644
index 000000000..91c4f50e9
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal04-input.svelte
@@ -0,0 +1,3 @@
+
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal05-errors.yaml b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal05-errors.yaml
new file mode 100644
index 000000000..e1c7cf351
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal05-errors.yaml
@@ -0,0 +1,4 @@
+- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
+ line: 2
+ column: 2
+ suggestions: null
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal05-input.svelte b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal05-input.svelte
new file mode 100644
index 000000000..3a2d38453
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal05-input.svelte
@@ -0,0 +1,3 @@
+
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal06-errors.yaml b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal06-errors.yaml
new file mode 100644
index 000000000..e1c7cf351
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal06-errors.yaml
@@ -0,0 +1,4 @@
+- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
+ line: 2
+ column: 2
+ suggestions: null
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal06-input.svelte b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal06-input.svelte
new file mode 100644
index 000000000..38ceb2302
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal06-input.svelte
@@ -0,0 +1,3 @@
+
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal07-errors.yaml b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal07-errors.yaml
new file mode 100644
index 000000000..e1c7cf351
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal07-errors.yaml
@@ -0,0 +1,4 @@
+- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
+ line: 2
+ column: 2
+ suggestions: null
diff --git a/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal07-input.svelte b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal07-input.svelte
new file mode 100644
index 000000000..b60364814
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/invalid/no-svelte-internal07-input.svelte
@@ -0,0 +1,3 @@
+
diff --git a/tests/fixtures/rules/no-svelte-internal/valid/no-svelte-internal01-input.svelte b/tests/fixtures/rules/no-svelte-internal/valid/no-svelte-internal01-input.svelte
new file mode 100644
index 000000000..da984faff
--- /dev/null
+++ b/tests/fixtures/rules/no-svelte-internal/valid/no-svelte-internal01-input.svelte
@@ -0,0 +1,3 @@
+
diff --git a/tests/src/rules/no-svelte-internal.ts b/tests/src/rules/no-svelte-internal.ts
new file mode 100644
index 000000000..3f4e67863
--- /dev/null
+++ b/tests/src/rules/no-svelte-internal.ts
@@ -0,0 +1,12 @@
+import { RuleTester } from '../../utils/eslint-compat';
+import rule from '../../../src/rules/no-svelte-internal';
+import { loadTestCases } from '../../utils/utils';
+
+const tester = new RuleTester({
+ languageOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module'
+ }
+});
+
+tester.run('no-svelte-internal', rule as any, loadTestCases('no-svelte-internal'));