8000 feat: add `excludedRunes` option to the `prefer-const` rule (#1064) · sveltejs/eslint-plugin-svelte@df1647f · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit df1647f

Browse files
feat: add excludedRunes option to the prefer-const rule (#1064)
Co-authored-by: Yosuke Ota <otameshiyo23@gmail.com>
1 parent f1c7846 commit df1647f

File tree

17 files changed

+122
-12
lines changed

17 files changed

+122
-12
lines changed

.changeset/sixty-cars-fail.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: add `excludedRunes` option to the `prefer-const` rule

docs/rules/prefer-const.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ since: 'v3.0.0-next.6'
1414

1515
## :book: Rule Details
1616

17-
This rule reports the same as the base ESLint `prefer-const` rule, except that ignores Svelte reactive values such as `$derived` and `$props`. If this rule is active, make sure to disable the base `prefer-const` rule, as it will conflict with this rule.
17+
This rule reports the same as the base ESLint `prefer-const` rule, except that ignores Svelte reactive values such as `$derived` and `$props` as default. If this rule is active, make sure to disable the base `prefer-const` rule, as it will conflict with this rule.
1818

1919
<!--eslint-skip-->
2020

@@ -46,7 +46,8 @@ This rule reports the same as the base ESLint `prefer-const` rule, except that i
4646
"error",
4747
{
4848
"destructuring": "any",
49-
"ignoreReadonly": true
49+
"ignoreReadonly": true,
50+
"excludedRunes": ["$props", "$derived"]
5051
}
5152
]
5253
}
@@ -56,6 +57,7 @@ This rule reports the same as the base ESLint `prefer-const` rule, except that i
5657
- `any` (default): if any variables in destructuring should be const, this rule warns for those variables.
5758
- `all`: if all variables in destructuring should be const, this rule warns the variables. Otherwise, ignores them.
5859
- `ignoreReadonly`: If `true`, this rule will ignore variables that are read between the declaration and the _first_ assignment.
60+
- `excludedRunes`: An array of rune names that should be ignored. Even if a rune is declared with `let`, it will still be ignored.
5961

6062
## :books: Further Reading
6163

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ type SveltePreferClassDirective = []|[{
530530
type SveltePreferConst = []|[{
531531
destructuring?: ("any" | "all")
532532
ignoreReadBeforeAssign?: boolean
533+
excludedRunes?: string[]
533534
}]
534535
// ----- svelte/shorthand-attribute -----
535536
type SvelteShorthandAttribute = []|[{

packages/eslint-plugin-svelte/src/rules/prefer-const.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function findDeclarationCallee(node: TSESTree.Expression) {
2121
* Determines if a declaration should be skipped in the const preference analysis.
2222
* Specifically checks for Svelte's state management utilities ($props, $derived).
2323
*/
24-
function shouldSkipDeclaration(declaration: TSESTree.Expression | null) {
24+
function shouldSkipDeclaration(declaration: TSESTree.Expression | null, excludedRunes: string[]) {
2525
if (!declaration) {
2626
return false;
2727
}
@@ -31,19 +31,15 @@ function shouldSkipDeclaration(declaration: TSESTree.Expression | null) {
3131
return false;
3232
}
3333

34-
if (callee.type === 'Identifier' && ['$props', '$derived'].includes(callee.name)) {
34+
if (callee.type === 'Identifier' && excludedRunes.includes(callee.name)) {
3535
return true;
3636
}
3737

3838
if (callee.type !== 'MemberExpression' || callee.object.type !== 'Identifier') {
3939
return false;
4040
}
4141

42-
if (
43-
callee.object.name === '$derived' &&
44-
callee.property.type === 'Identifier' &&
45-
callee.property.name === 'by'
46-
) {
42+
if (excludedRunes.includes(callee.object.name)) {
4743
return true;
4844
}
4945

@@ -58,16 +54,35 @@ export default createRule('prefer-const', {
5854
category: 'Best Practices',
5955
recommended: false,
6056
extensionRule: 'prefer-const'
61-
}
57+
},
58+
schema: [
59+
{
60+
type: 'object',
61+
properties: {
62+
destructuring: { enum: ['any', 'all'] },
63+
ignoreReadBeforeAssign: { type: 'boolean' },
64+
excludedRunes: {
65+
type: 'array',
66+
items: {
67+
type: 'string'
68+
}
69+
}
70+
},
71+
additionalProperties: false
72+
}
73+
]
6274
},
6375
create(context) {
76+
const config = context.options[0] ?? {};
77+
const excludedRunes = config.excludedRunes ?? ['$props', '$derived'];
78+
6479
return defineWrapperListener(coreRule, context, {
6580
createListenerProxy(coreListener) {
6681
return {
6782
...coreListener,
6883
VariableDeclaration(node) {
6984
for (const decl of node.declarations) {
70-
if (shouldSkipDeclaration(decl.init)) {
85+
if (shouldSkipDeclaration(decl.init, excludedRunes)) {
7186
return;
7287
}
7388
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": [{ "excludedRunes": [] }]
3+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
- message: "'prop1' is never reassigned. Use 'const' instead."
2+
line: 2
3+
column: 8
4+
suggestions: null
5+
- message: "'prop2' is never reassigned. Use 'const' instead."
6+
line: 2
7+
column: 15
8+
suggestions: null
9+
- message: "'zero' is never reassigned. Use 'const' instead."
10+
line: 3
11+
column: 6
12+
suggestions: null
13+
- message: "'derived' is never reassigned. Use 'const' instead."
14+
line: 4
15+
column: 6
16+
suggestions: null
17+
- message: "'derivedBy' is never reassigned. Use 'const' instead."
18+
line: 5
19+
column: 6
20+
suggestions: null
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let { prop1, prop2 } = $props();
3+
let zero = $state(0);
4+
let derived = $derived(zero * 2);
5+
let derivedBy = $derived.by(calc());
6+
</script>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
const { prop1, prop2 } = $props();
3+
const zero = $state(0);
4+
const derived = $derived(zero * 2);
5+
const derivedBy = $derived.by(calc());
6+
</script>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": [{ "excludedRunes": ["$state"] }]
3+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
- message: "'prop1' is never reassigned. Use 'const' instead."
2+
line: 2
3+
column: 8
4+
suggestions: null
5+
- message: "'prop2' is never reassigned. Use 'const' instead."
6+
line: 2
7+
column: 15
8+
suggestions: null
9+
- message: "'derived' is never reassigned. Use 'const' instead."
10+
line: 4
11+
column: 6
12+
suggestions: null
13+
- message: "'derivedBy' is never reassigned. Use 'const' instead."
14+
line: 5
15+
column: 6
16+
suggestions: null
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let { prop1, prop2 } = $props();
3+
let zero = $state(0);
4+
let derived = $derived(zero * 2);
5+
let derivedBy = $derived.by(calc());
6+
</script>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
const { prop1, prop2 } = $props();
3+
let zero = $state(0);
4+
const derived = $derived(zero * 2);
5+
const derivedBy = $derived.by(calc());
6+
</script>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": [{ "excludedRunes": [] }]
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
const { prop1, prop2 } = $props();
3+
const zero = $state(0);
4+
const derived = $derived(zero * 2);
5+
const derivedBy = $derived.by(calc());
6+
</script>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": [{ "excludedRunes": ["$props", "$derived", "$state"] }]
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let { prop1, prop2 } = $props();
3+
let zero = $state(0);
4+
let derived = $derived(zero * 2);
5+
let derivedBy = $derived.by(calc());
6+
</script>
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
<script>
2-
const a = {};
2+
let { prop1, prop2 } = $props();
3+
const zero = $state(0);
4+
let derived = $derived(zero * 2);
5+
let derivedBy = $derived.by(calc());
36
</script>

0 commit comments

Comments
 (0)
0