diff --git a/.changeset/rich-colts-nail.md b/.changeset/rich-colts-nail.md
new file mode 100644
index 000000000..51c8eea60
--- /dev/null
+++ b/.changeset/rich-colts-nail.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-svelte': minor
+---
+
+feat: added the `prefer-svelte-reactivity` rule
diff --git a/README.md b/README.md
index db731dd26..4a048d6e1 100644
--- a/README.md
+++ b/README.md
@@ -272,6 +272,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/no-shorthand-style-property-overrides](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-shorthand-style-property-overrides/) | disallow shorthand style properties that override related longhand properties | :star: |
| [svelte/no-store-async](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-store-async/) | disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features | :star: |
| [svelte/no-unknown-style-directive-property](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unknown-style-directive-property/) | disallow unknown `style:property` | :star: |
+| [svelte/prefer-svelte-reactivity](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-svelte-reactivity/) | disallow using built-in classes where a reactive alternative is provided by svelte/reactivity | :star: |
| [svelte/require-store-callbacks-use-set-param](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | store callbacks must use `set` param | |
| [svelte/require-store-reactive-access](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-reactive-access/) | disallow to use of the store itself as an operand. Need to use $ prefix or get function. | :star::wrench: |
| [svelte/valid-compile](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | |
diff --git a/docs/rules.md b/docs/rules.md
index 58d896b10..cea6c075a 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -29,6 +29,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/no-shorthand-style-property-overrides](./rules/no-shorthand-style-property-overrides.md) | disallow shorthand style properties that override related longhand properties | :star: |
| [svelte/no-store-async](./rules/no-store-async.md) | disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features | :star: |
| [svelte/no-unknown-style-directive-property](./rules/no-unknown-style-directive-property.md) | disallow unknown `style:property` | :star: |
+| [svelte/prefer-svelte-reactivity](./rules/prefer-svelte-reactivity.md) | disallow using built-in classes where a reactive alternative is provided by svelte/reactivity | :star: |
| [svelte/require-store-callbacks-use-set-param](./rules/require-store-callbacks-use-set-param.md) | store callbacks must use `set` param | |
| [svelte/require-store-reactive-access](./rules/require-store-reactive-access.md) | disallow to use of the store itself as an operand. Need to use $ prefix or get function. | :star::wrench: |
| [svelte/valid-compile](./rules/valid-compile.md) | disallow warnings when compiling. | |
diff --git a/docs/rules/prefer-svelte-reactivity.md b/docs/rules/prefer-svelte-reactivity.md
new file mode 100644
index 000000000..9688d00e5
--- /dev/null
+++ b/docs/rules/prefer-svelte-reactivity.md
@@ -0,0 +1,68 @@
+---
+pageClass: 'rule-details'
+sidebarDepth: 0
+title: 'svelte/prefer-svelte-reactivity'
+description: 'disallow using built-in classes where a reactive alternative is provided by svelte/reactivity'
+---
+
+# svelte/prefer-svelte-reactivity
+
+> disallow using built-in classes where a reactive alternative is provided by svelte/reactivity
+
+- :exclamation: **_This rule has not been released yet._**
+- :gear: This rule is included in `"plugin:svelte/recommended"`.
+
+## :book: Rule Details
+
+The built-in `Date`, `Map`, `Set`, `URL` and `URLSearchParams` classes are often used in frontend code, however, their properties and methods are not reactive. Because of that, Svelte provides reactive versions of these 5 builtins as part of the "svelte/reactivity" package. This rule reports usage of the built-in versions in Svelte code.
+
+
+
+```svelte
+
+```
+
+## :wrench: Options
+
+Nothing.
+
+## :books: Further Reading
+
+- [svelte/reactivity documentation](https://svelte.dev/docs/svelte/svelte-reactivity)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts)
+- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/tests/src/rules/prefer-svelte-reactivity.ts)
diff --git a/packages/eslint-plugin-svelte/src/configs/flat/recommended.ts b/packages/eslint-plugin-svelte/src/configs/flat/recommended.ts
index b1b2d51ad..81c2b7dbc 100644
--- a/packages/eslint-plugin-svelte/src/configs/flat/recommended.ts
+++ b/packages/eslint-plugin-svelte/src/configs/flat/recommended.ts
@@ -37,6 +37,7 @@ const config: Linter.Config[] = [
'svelte/no-unused-svelte-ignore': 'error',
'svelte/no-useless-children-snippet': 'error',
'svelte/no-useless-mustaches': 'error',
+ 'svelte/prefer-svelte-reactivity': 'error',
'svelte/require-each-key': 'error',
'svelte/require-event-dispatcher-types': 'error',
'svelte/require-store-reactive-access': 'error',
diff --git a/packages/eslint-plugin-svelte/src/rule-types.ts b/packages/eslint-plugin-svelte/src/rule-types.ts
index 19e30a345..39e216f70 100644
--- a/packages/eslint-plugin-svelte/src/rule-types.ts
+++ b/packages/eslint-plugin-svelte/src/rule-types.ts
@@ -306,6 +306,11 @@ export interface RuleOptions {
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-style-directive/
*/
'svelte/prefer-style-directive'?: Linter.RuleEntry<[]>
+ /**
+ * disallow using built-in classes where a reactive alternative is provided by svelte/reactivity
+ * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-svelte-reactivity/
+ */
+ 'svelte/prefer-svelte-reactivity'?: Linter.RuleEntry<[]>
/**
* require keyed `{#each}` block
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/require-each-key/
diff --git a/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts b/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts
new file mode 100644
index 000000000..b8b83c90a
--- /dev/null
+++ b/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts
@@ -0,0 +1,72 @@
+import { ReferenceTracker } from '@eslint-community/eslint-utils';
+import { getSourceCode } from '../utils/compat.js';
+import { createRule } from '../utils/index.js';
+
+export default createRule('prefer-svelte-reactivity', {
+ meta: {
+ docs: {
+ description:
+ 'disallow using built-in classes where a reactive alternative is provided by svelte/reactivity',
+ category: 'Possible Errors',
+ recommended: true
+ },
+ schema: [],
+ messages: {
+ dateUsed: 'Found a usage of the built-in Date class. Use a SvelteDate instead.',
+ mapUsed: 'Found a usage of the built-in Map class. Use a SvelteMap instead.',
+ setUsed: 'Found a usage of the built-in Set class. Use a SvelteSet instead.',
+ urlUsed: 'Found a usage of the built-in URL class. Use a SvelteURL instead.',
+ urlSearchParamsUsed:
+ 'Found a usage of the built-in URLSearchParams class. Use a SvelteURLSearchParams instead.'
+ },
+ type: 'problem', // 'problem', or 'layout',
+ conditions: [
+ {
+ svelteVersions: ['5'],
+ svelteFileTypes: ['.svelte', '.svelte.[js|ts]']
+ }
+ ]
+ },
+ create(context) {
+ return {
+ Program() {
+ const referenceTracker = new ReferenceTracker(
+ getSourceCode(context).scopeManager.globalScope!
+ );
+ for (const { node, path } of referenceTracker.iterateGlobalReferences({
+ Date: {
+ [ReferenceTracker.CONSTRUCT]: true
+ },
+ Map: {
+ [ReferenceTracker.CONSTRUCT]: true
+ },
+ Set: {
+ [ReferenceTracker.CONSTRUCT]: true
+ },
+ URL: {
+ [ReferenceTracker.CALL]: true,
+ [ReferenceTracker.CONSTRUCT]: true,
+ [ReferenceTracker.READ]: true
+ },
+ URLSearchParams: {
+ [ReferenceTracker.CALL]: true,
+ [ReferenceTracker.CONSTRUCT]: true,
+ [ReferenceTracker.READ]: true
+ }
+ })) {
+ const typeToMessageId: Record = {
+ Date: 'dateUsed',
+ Map: 'mapUsed',
+ Set: 'setUsed',
+ URL: 'urlUsed',
+ URLSearchParams: 'urlSearchParamsUsed'
+ };
+ context.report({
+ messageId: typeToMessageId[path[0]],
+ node
+ });
+ }
+ }
+ };
+ }
+});
diff --git a/packages/eslint-plugin-svelte/src/utils/rules.ts b/packages/eslint-plugin-svelte/src/utils/rules.ts
index 3151d17f1..f437d0d82 100644
--- a/packages/eslint-plugin-svelte/src/utils/rules.ts
+++ b/packages/eslint-plugin-svelte/src/utils/rules.ts
@@ -60,6 +60,7 @@ import preferClassDirective from '../rules/prefer-class-directive.js';
import preferConst from '../rules/prefer-const.js';
import preferDestructuredStoreProps from '../rules/prefer-destructured-store-props.js';
import preferStyleDirective from '../rules/prefer-style-directive.js';
+import preferSvelteReactivity from '../rules/prefer-svelte-reactivity.js';
import requireEachKey from '../rules/require-each-key.js';
import requireEventDispatcherTypes from '../rules/require-event-dispatcher-types.js';
import requireOptimizedStyleAttribute from '../rules/require-optimized-style-attribute.js';
@@ -135,6 +136,7 @@ export const rules = [
preferConst,
preferDestructuredStoreProps,
preferStyleDirective,
+ preferSvelteReactivity,
requireEachKey,
requireEventDispatcherTypes,
requireOptimizedStyleAttribute,
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/date01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/date01-input.svelte
new file mode 100644
index 000000000..3d0b6ce89
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/date01-input.svelte
@@ -0,0 +1,5 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/map01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/map01-input.svelte
new file mode 100644
index 000000000..5403fc3ea
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/map01-input.svelte
@@ -0,0 +1,5 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/set01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/set01-input.svelte
new file mode 100644
index 000000000..7a1ad366b
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/set01-input.svelte
@@ -0,0 +1,5 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/url-search-params01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/url-search-params01-input.svelte
new file mode 100644
index 000000000..2423d7960
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/url-search-params01-input.svelte
@@ -0,0 +1,5 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/url01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/url01-input.svelte
new file mode 100644
index 000000000..9851e3103
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/url01-input.svelte
@@ -0,0 +1,5 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-date01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-date01-input.svelte
new file mode 100644
index 000000000..0ab09e823
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-date01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-map01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-map01-input.svelte
new file mode 100644
index 000000000..5f431b8b1
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-map01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-set01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-set01-input.svelte
new file mode 100644
index 000000000..bf3379c3c
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-set01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-url-search-params01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-url-search-params01-input.svelte
new file mode 100644
index 000000000..8d3d4d2d2
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-url-search-params01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-url01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-url01-input.svelte
new file mode 100644
index 000000000..ea960e9fd
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/aliased-url01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-date01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-date01-input.svelte
new file mode 100644
index 000000000..911cb5461
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-date01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-map01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-map01-input.svelte
new file mode 100644
index 000000000..43ff00a06
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-map01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-set01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-set01-input.svelte
new file mode 100644
index 000000000..6c6728c53
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-set01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-url-search-params01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-url-search-params01-input.svelte
new file mode 100644
index 000000000..0f66db767
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-url-search-params01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-url01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-url01-input.svelte
new file mode 100644
index 000000000..014046937
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/svelte-url01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-date01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-date01-input.svelte
new file mode 100644
index 000000000..851db5e63
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-date01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-map01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-map01-input.svelte
new file mode 100644
index 000000000..32eab3dc7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-map01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-set01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-set01-input.svelte
new file mode 100644
index 000000000..fc378f046
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-set01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-url-search-params01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-url-search-params01-input.svelte
new file mode 100644
index 000000000..de69ce09e
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-url-search-params01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-url01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-url01-input.svelte
new file mode 100644
index 000000000..eab451693
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/unrelated-url01-input.svelte
@@ -0,0 +1,7 @@
+
+
+{variable}
diff --git a/packages/eslint-plugin-svelte/tests/src/rules/prefer-svelte-reactivity.ts b/packages/eslint-plugin-svelte/tests/src/rules/prefer-svelte-reactivity.ts
new file mode 100644
index 000000000..7517fdc3a
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/src/rules/prefer-svelte-reactivity.ts
@@ -0,0 +1,16 @@
+import { RuleTester } from '../../utils/eslint-compat.js';
+import rule from '../../../src/rules/prefer-svelte-reactivity.js';
+import { loadTestCases } from '../../utils/utils.js';
+
+const tester = new RuleTester({
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: {
+ URL: "readonly",
+ URLSearchParams: "readonly",
+ },
+ sourceType: 'module'
+ }
+});
+
+tester.run('prefer-svelte-reactivity', rule as any, loadTestCases('prefer-svelte-reactivity'));