Skip to content

Commit 5e1ffe0

Browse files
committed
feat(prefer-svelte-reactivity): added rule implementation
1 parent 09240b9 commit 5e1ffe0

File tree

7 files changed

+80
-0
lines changed

7 files changed

+80
-0
lines changed

.changeset/rich-colts-nail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': minor
3+
---
4+
5+
feat: added the `prefer-svelte-reactivity` rule

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
272272
| [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: |
273273
| [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: |
274274
| [svelte/no-unknown-style-directive-property](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unknown-style-directive-property/) | disallow unknown `style:property` | :star: |
275+
| [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: |
275276
| [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 | :bulb: |
276277
| [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: |
277278
| [svelte/valid-compile](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | |

docs/rules.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
2929
| [svelte/no-shorthand-style-property-overrides](./rules/no-shorthand-style-property-overrides.md) | disallow shorthand style properties that override related longhand properties | :star: |
3030
| [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: |
3131
| [svelte/no-unknown-style-directive-property](./rules/no-unknown-style-directive-property.md) | disallow unknown `style:property` | :star: |
32+
| [svelte/prefer-svelte-reactivity](./rules/prefer-svelte-reactivity.md) | disallow using built-in classes where a reactive alternative is provided by svelte/reactivity | :star: |
3233
| [svelte/require-store-callbacks-use-set-param](./rules/require-store-callbacks-use-set-param.md) | store callbacks must use `set` param | :bulb: |
3334
| [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: |
3435
| [svelte/valid-compile](./rules/valid-compile.md) | disallow warnings when compiling. | |

packages/eslint-plugin-svelte/src/configs/flat/recommended.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const config: Linter.Config[] = [
3737
'svelte/no-unused-svelte-ignore': 'error',
3838
'svelte/no-useless-children-snippet': 'error',
3939
'svelte/no-useless-mustaches': 'error',
40+
'svelte/prefer-svelte-reactivity': 'error',
4041
'svelte/prefer-writable-derived': 'error',
4142
'svelte/require-each-key': 'error',
4243
'svelte/require-event-dispatcher-types': 'error',

packages/eslint-plugin-svelte/src/rule-types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,11 @@ export interface RuleOptions {
306306
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-style-directive/
307307
*/
308308
'svelte/prefer-style-directive'?: Linter.RuleEntry<[]>
309+
/**
310+
* disallow using built-in classes where a reactive alternative is provided by svelte/reactivity
311+
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-svelte-reactivity/
312+
*/
313+
'svelte/prefer-svelte-reactivity'?: Linter.RuleEntry<[]>
309314
/**
310315
* Prefer using writable $derived instead of $state and $effect
311316
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-writable-derived/
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { ReferenceTracker } from '@eslint-community/eslint-utils';
2+
import { createRule } from '../utils/index.js';
3+
4+
export default createRule('prefer-svelte-reactivity', {
5+
meta: {
6+
docs: {
7+
description:
8+
'disallow using built-in classes where a reactive alternative is provided by svelte/reactivity',
9+
category: 'Possible Errors',
10+
recommended: true
11+
},
12+
schema: [],
13+
messages: {
14+
dateUsed: 'Found a usage of the built-in Date class. Use a SvelteDate instead.',
15+
mapUsed: 'Found a usage of the built-in Map class. Use a SvelteMap instead.',
16+
setUsed: 'Found a usage of the built-in Set class. Use a SvelteSet instead.',
17+
urlUsed: 'Found a usage of the built-in URL class. Use a SvelteURL instead.',
18+
urlSearchParamsUsed:
19+
'Found a usage of the built-in URLSearchParams class. Use a SvelteURLSearchParams instead.'
20+
},
21+
type: 'problem', // 'problem', or 'layout',
22+
conditions: [
23+
{
24+
svelteVersions: ['5'],
25+
svelteFileTypes: ['.svelte', '.svelte.[js|ts]']
26+
}
27+
]
28+
},
29+
create(context) {
30+
return {
31+
Program() {
32+
const referenceTracker = new ReferenceTracker(context.sourceCode.scopeManager.globalScope!);
33+
for (const { node, path } of referenceTracker.iterateGlobalReferences({
34+
Date: {
35+
[ReferenceTracker.CONSTRUCT]: true
36+
},
37+
Map: {
38+
[ReferenceTracker.CONSTRUCT]: true
39+
},
40+
Set: {
41+
[ReferenceTracker.CONSTRUCT]: true
42+
},
43+
URL: {
44+
[ReferenceTracker.CONSTRUCT]: true
45+
},
46+
URLSearchParams: {
47+
[ReferenceTracker.CONSTRUCT]: true
48+
}
49+
})) {
50+
const typeToMessageId: Record<string, string> = {
51+
Date: 'dateUsed',
52+
Map: 'mapUsed',
53+
Set: 'setUsed',
54+
URL: 'urlUsed',
55+
URLSearchParams: 'urlSearchParamsUsed'
56+
};
57+
context.report({
58+
messageId: typeToMessageId[path[0]],
59+
node
60+
});
61+
}
62+
}
63+
};
64+
}
65+
});

packages/eslint-plugin-svelte/src/utils/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import preferClassDirective from '../rules/prefer-class-directive.js';
6060
import preferConst from '../rules/prefer-const.js';
6161
import preferDestructuredStoreProps from '../rules/prefer-destructured-store-props.js';
6262
import preferStyleDirective from '../rules/prefer-style-directive.js';
63+
import preferSvelteReactivity from '../rules/prefer-svelte-reactivity.js';
6364
import preferWritableDerived from '../rules/prefer-writable-derived.js';
6465
import requireEachKey from '../rules/require-each-key.js';
6566
import requireEventDispatcherTypes from '../rules/require-event-dispatcher-types.js';
@@ -137,6 +138,7 @@ export const rules = [
137138
preferConst,
138139
preferDestructuredStoreProps,
139140
preferStyleDirective,
141+
preferSvelteReactivity,
140142
preferWritableDerived,
141143
requireEachKey,
142144
requireEventDispatcherTypes,

0 commit comments

Comments
 (0)