Skip to content

Commit 238183e

Browse files
committed
refactor
1 parent 2c1d28b commit 238183e

File tree

1 file changed

+60
-48
lines changed

1 file changed

+60
-48
lines changed

Diff for: packages/eslint-plugin-svelte/src/rules/prefer-writable-derived.ts

+60-48
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ import semver from 'semver';
77
// Writable derived were introduced in Svelte 5.25.0
88
const shouldRun = semver.satisfies(SVELTE_VERSION, '>=5.25.0');
99

10+
type ValidFunctionType = TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression;
11+
type ValidFunction = ValidFunctionType & {
12+
body: TSESTree.BlockStatement;
13+
};
14+
15+
type ValidAssignmentExpression = TSESTree.AssignmentExpression & {
16+
operator: '=';
17+
left: TSESTree.Identifier;
18+
};
19+
20+
type ValidExpressionStatement = TSESTree.ExpressionStatement & {
21+
expression: ValidAssignmentExpression;
22+
};
23+
1024
function isEffectOrEffectPre(node: TSESTree.CallExpression) {
1125
if (node.callee.type === 'Identifier') {
1226
return node.callee.name === '$effect';
@@ -23,6 +37,40 @@ function isEffectOrEffectPre(node: TSESTree.CallExpression) {
2337
return false;
2438
}
2539

40+
function isValidFunctionArgument(argument: TSESTree.Node): argument is ValidFunction {
41+
if (
42+
(argument.type !== 'FunctionExpression' && argument.type !== 'ArrowFunctionExpression') ||
43+
argument.params.length !== 0
44+
) {
45+
return false;
46+
}
47+
48+
if (argument.body.type !== 'BlockStatement') {
49+
return false;
50+
}
51+
52+
return argument.body.body.length === 1;
53+
}
54+
55+
function isValidAssignment(statement: TSESTree.Statement): statement is ValidExpressionStatement {
56+
if (statement.type !== 'ExpressionStatement') return false;
57+
58+
const { expression } = statement;
59+
return (
60+
expression.type === 'AssignmentExpression' &&
61+
expression.operator === '=' &&
62+
expression.left.type === 'Identifier'
63+
);
64+
}
65+
66+
function isStateVariable(init: TSESTree.Expression | null): init is TSESTree.CallExpression {
67+
return (
68+
init?.type === 'CallExpression' &&
69+
init.callee.type === 'Identifier' &&
70+
init.callee.name === '$state'
71+
);
72+
}
73+
2674
export default createRule('prefer-writable-derived', {
2775
meta: {
2876
docs: {
@@ -50,69 +98,33 @@ export default createRule('prefer-writable-derived', {
5098
}
5199
return {
52100
CallExpression: (node: TSESTree.CallExpression) => {
53-
if (!isEffectOrEffectPre(node)) {
54-
return;
55-
}
56-
57-
if (node.arguments.length !== 1) {
101+
if (!isEffectOrEffectPre(node) || node.arguments.length !== 1) {
58102
return;
59103
}
60104

61105
const argument = node.arguments[0];
62-
if (argument.type !== 'FunctionExpression' && argument.type !== 'ArrowFunctionExpression') {
63-
return;
64-
}
65-
66-
if (argument.params.length !== 0) {
67-
return;
68-
}
69-
70-
if (argument.body.type !== 'BlockStatement') {
71-
return;
72-
}
73-
74-
const body = argument.body.body;
75-
if (body.length !== 1) {
76-
return;
77-
}
78-
79-
const statement = body[0];
80-
if (statement.type !== 'ExpressionStatement') {
106+
if (!isValidFunctionArgument(argument)) {
81107
return;
82108
}
83109

84-
const expression = statement.expression;
85-
if (expression.type !== 'AssignmentExpression') {
86-
return;
87-
}
88-
89-
const { left, right, operator } = expression;
90-
if (operator !== '=' || left.type !== 'Identifier') {
110+
const statement = argument.body.body[0];
111+
if (!isValidAssignment(statement)) {
91112
return;
92113
}
93114

115+
const { left, right } = statement.expression;
94116
const scope = getScope(context, statement);
95-
const reference = scope.references.find((reference) => {
96-
return (
97-
reference.identifier.type === 'Identifier' && reference.identifier.name === left.name
98-
);
99-
});
100-
const defs = reference?.resolved?.defs;
101-
if (defs == null || defs.length !== 1) {
102-
return;
103-
}
104-
105-
const def = defs[0];
106-
if (def.type !== 'Variable' || def.node.type !== 'VariableDeclarator') {
107-
return;
108-
}
117+
const reference = scope.references.find(
118+
(ref) => ref.identifier.type === 'Identifier' && ref.identifier.name === left.name
119+
);
109120

110-
const init = def.node.init;
111-
if (init == null || init.type !== 'CallExpression') {
121+
const def = reference?.resolved?.defs?.[0];
122+
if (!def || def.type !== 'Variable' || def.node.type !== 'VariableDeclarator') {
112123
return;
113124
}
114125

115-
if (init.callee.type !== 'Identifier' || init.callee.name !== '$state') {
126+
const { init } = def.node;
127+
if (!isStateVariable(init)) {
116128
return;
117129
}
118130

0 commit comments

Comments
 (0)