Skip to content

Instantly share code, notes, and snippets.

@vsviridov
Last active August 13, 2024 22:42
Show Gist options
  • Save vsviridov/b70be92920e648583d7c841193b7c911 to your computer and use it in GitHub Desktop.
Save vsviridov/b70be92920e648583d7c841193b7c911 to your computer and use it in GitHub Desktop.
Effector ESLint Rule for suggesting `restore`
import type { Rule } from 'eslint';
import type ESTree from 'estree';
export default {
'effector-restore': {
meta: {
docs: {
description: 'Replace simple store setting with restore',
category: 'Suggestions',
},
fixable: 'code',
schema: [],
},
create: (context) => {
const functionsReturningSecondArg: ESTree.ArrowFunctionExpression[] = [];
const createdStores: Record<string, ESTree.VariableDeclarator> = {};
const createdEvents: Record<string, ESTree.VariableDeclarator> = {};
const foundIssues: {
callExpr: ESTree.CallExpression;
eventName: string;
setter: ESTree.ArrowFunctionExpression;
}[] = [];
let effectorImport: ESTree.ImportDeclaration;
return {
['ImportDeclaration[source.value=effector]'](node: ESTree.ImportDeclaration) {
effectorImport = node;
},
['CallExpression MemberExpression[property.name=on]'](node: Rule.Node) {
const callExpr = node.parent as ESTree.CallExpression;
const eventName = (callExpr.arguments[0] as ESTree.Identifier).name;
const setter = callExpr.arguments[1] as ESTree.ArrowFunctionExpression;
foundIssues.push({ callExpr, eventName, setter });
},
['VariableDeclarator CallExpression[callee.name=createStore][arguments.length=1]'](node: Rule.Node) {
switch (node.parent.type) {
case 'VariableDeclarator': {
createdStores[(node.parent.id as ESTree.Identifier).name] = node.parent as ESTree.VariableDeclarator;
}
}
},
['VariableDeclarator CallExpression[callee.name=createEvent]'](node: Rule.Node) {
switch (node.parent.type) {
case 'VariableDeclarator': {
createdEvents[(node.parent.id as ESTree.Identifier).name] = node.parent;
}
}
},
['ArrowFunctionExpression[body.type=Identifier][params.length=2]'](node: ESTree.ArrowFunctionExpression) {
if ((node.body as ESTree.Identifier).name === (node.params[1] as ESTree.Identifier).name) {
functionsReturningSecondArg.push(node);
}
},
['Program:exit'](_node) {
foundIssues.forEach(({ callExpr, eventName, setter }) => {
if (functionsReturningSecondArg.includes(setter)) {
const storeName = ((callExpr.callee as ESTree.MemberExpression).object as ESTree.Identifier).name;
const store = createdStores[storeName];
if (!store) {
return;
}
// const event = createdEvents[eventName];
// if(!event) { return; }
// const eventRaw = context.sourceCode.getText(event.parent);
context.report({
node: setter,
message: `This can be replaced with "restore"`,
// fix: (fixer) => {
// return [
// // fixer.remove(event.parent),
// fixer.insertTextAfter(effectorImport.specifiers[effectorImport.specifiers.length - 1], ', restore'),
// fixer.replaceText(
// store,
// `${storeName} = restore(${eventName}, ${
// ((store.init as ESTree.CallExpression).arguments[0] as ESTree.Literal).raw
// })`
// ),
// fixer.remove((callExpr as Rule.Node).parent),
// ];
// },
});
}
});
},
} satisfies Rule.RuleListener;
},
},
} satisfies Record<string, Rule.RuleModule>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment