Skip to content

Commit ea54bce

Browse files
committed
feat(prefer-svelte-reactivity): added rule implementation
1 parent 31d0625 commit ea54bce

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
@@ -273,6 +273,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
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-top-level-browser-globals](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-top-level-browser-globals/) | disallow using top-level browser global variables | |
275275
| [svelte/no-unknown-style-directive-property](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unknown-style-directive-property/) | disallow unknown `style:property` | :star: |
276+
| [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: |
276277
| [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: |
277278
| [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: |
278279
| [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
@@ -30,6 +30,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
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-top-level-browser-globals](./rules/no-top-level-browser-globals.md) | disallow using top-level browser global variables | |
3232
| [svelte/no-unknown-style-directive-property](./rules/no-unknown-style-directive-property.md) | disallow unknown `style:property` | :star: |
33+
| [svelte/prefer-svelte-reactivity](./rules/prefer-svelte-reactivity.md) | disallow using built-in classes where a reactive alternative is provided by svelte/reactivity | :star: |
3334
| [svelte/require-store-callbacks-use-set-param](./rules/require-store-callbacks-use-set-param.md) | store callbacks must use `set` param | :bulb: |
3435
| [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: |
3536
| [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
@@ -316,6 +316,11 @@ export interface RuleOptions {
316316
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-style-directive/
317317
*/
318318
'svelte/prefer-style-directive'?: Linter.RuleEntry<[]>
319+
/**
320+
* disallow using built-in classes where a reactive alternative is provided by svelte/reactivity
321+
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-svelte-reactivity/
322+
*/
323+
'svelte/prefer-svelte-reactivity'?: Linter.RuleEntry<[]>
319324
/**
320325
* Prefer using writable $derived instead of $state and $effect
321326
* @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
@@ -62,6 +62,7 @@ import preferClassDirective from '../rules/prefer-class-directive.js';
6262
import preferConst from '../rules/prefer-const.js';
6363
import preferDestructuredStoreProps from '../rules/prefer-destructured-store-props.js';
6464
import preferStyleDirective from '../rules/prefer-style-directive.js';
65+
import preferSvelteReactivity from '../rules/prefer-svelte-reactivity.js';
6566
import preferWritableDerived from '../rules/prefer-writable-derived.js';
6667
import requireEachKey from '../rules/require-each-key.js';
6768
import requireEventDispatcherTypes from '../rules/require-event-dispatcher-types.js';
@@ -141,6 +142,7 @@ export const rules = [
141142
preferConst,
142143
preferDestructuredStoreProps,
143144
preferStyleDirective,
145+
preferSvelteReactivity,
144146
preferWritableDerived,
145147
requireEachKey,
146148
requireEventDispatcherTypes,

0 commit comments

Comments
 (0)