Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rule no-patronum-debug #121

Merged
merged 1 commit into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ This preset contains rules, which enforce _future-effector_ code-style.
- [effector/no-forward](rules/no-forward/no-forward.md)
- [effector/no-guard](rules/no-guard/no-guard.md)

#### plugin:effector/patronum

This preset is recommended for projects that use [Patronum](https://patronum.effector.dev/).

- [effector/no-patronum-debug](rules/no-patronum-debug/no-patronum-debug.md)

## Maintenance

### Release flow
Expand Down
5 changes: 5 additions & 0 deletions config/patronum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
rules: {
"effector/no-patronum-debug": "error",
},
};
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ module.exports = {
"no-guard": require("./rules/no-guard/no-guard"),
"mandatory-scope-binding": require("./rules/mandatory-scope-binding/mandatory-scope-binding"),
"prefer-useUnit": require("./rules/prefer-useUnit/prefer-useUnit"),
"no-patronum-debug": require("./rules/no-patronum-debug/no-patronum-debug"),
},
configs: {
recommended: require("./config/recommended"),
scope: require("./config/scope"),
react: require("./config/react"),
future: require("./config/future"),
patronum: require("./config/patronum"),
},
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"glob": "^8.0.3",
"jest": "^27.1.0",
"nano-staged": "^0.5.0",
"patronum": "^1.12.1",
"react": "^17.0.2",
"simple-git-hooks": "^2.7.0",
"typescript": "^4.4.2"
Expand Down
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions rules/no-patronum-debug/examples/correct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createStore } from "effector";
const debug = (...args) => ({ ...args });
debug({ test: "debug" });
const $store = createStore({});
debug({ store: $store });
6 changes: 6 additions & 0 deletions rules/no-patronum-debug/examples/incorrect-with-debug-fork.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { fork, createStore } from "effector";
import { debug } from "patronum";
const $count = createStore(0);
const scopeA = fork({ values: [[$count, 42]] });
const scopeB = fork({ values: [[$count, 1337]] });
debug.registerScope(scopeA, { name: "scope_42" });
4 changes: 4 additions & 0 deletions rules/no-patronum-debug/examples/incorrect-with-debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createStore } from "effector";
import { debug } from "patronum";
const $store = createStore({ fullname: "John Due" });
debug($store);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createEvent } from "effector";
import { debug as debuggerPatronum } from "patronum";
const event = createEvent();
debuggerPatronum(event);
126 changes: 126 additions & 0 deletions rules/no-patronum-debug/no-patronum-debug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
const { createLinkToRule } = require("../../utils/create-link-to-rule");
const { extractImportedFrom } = require("../../utils/extract-imported-from");

module.exports = {
meta: {
type: "suggestion",
docs: {
description: "Disallow the use of patronum `debug`",
category: "Quality",
recommended: false,
url: createLinkToRule("no-patronum-debug"),
},
messages: {
noPatronumDebug: "Unexpected patronum `debug` statement",
removePatronumDebug: "Remove this `debug` from patronum",
},
schema: [],
hasSuggestions: true,
},
create(context) {
const importedFromPatronum = new Map();
const importNodes = new Map();

return {
ImportDeclaration(node) {
extractImportedFrom({
packageName: ["patronum", "patronum/debug"],
importMap: importedFromPatronum,
nodeMap: importNodes,
node,
});
},
CallExpression(node) {
const currentMethodName = node.callee?.name ?? node.callee?.object.name;
const importedDebugFromPatronum = importedFromPatronum.get("debug");

if (currentMethodName !== importedDebugFromPatronum) {
return;
}

context.report({
messageId: "noPatronumDebug",
node,
suggest: [
{
messageId: "removePatronumDebug",
*fix(fixer) {
yield* removeDebugFromPatronum({
fixer,
node,
context,
importNodes,
});
},
},
],
});
},
};
},
};

function* removeDebugFromPatronum({
fixer,
node,
context,
importNodes,
targetMethod = "debug",
}) {
const sourceCode = context.getSourceCode();
const startToken = sourceCode.getTokenBefore(node);

// remove line with debug
yield fixer.removeRange([startToken.range[1], node.range[1] + 1]);

const importDebugNode = importNodes.get(targetMethod);

if (!importDebugNode) {
return null;
}

// remove import with debug
const importParentNode = importDebugNode.parent;

/**
* import { debug } from 'patronum'
* import { debug } from 'patronum/debug'
*/
if (importParentNode.specifiers.length === 1) {
yield fixer.removeRange([
importParentNode.range[0],
importParentNode.range[1] + 1,
]);

return null;
}

const amountImportFromPatronum = importParentNode.specifiers.length;
const importLast = importParentNode.specifiers[amountImportFromPatronum - 1];

const filterTokenComma = { filter: (token) => token.value === "," };

/**
* import { debug, timeout } from 'patronum'
* import { condition, debug, throttle } from 'patronum'
*/
if (importDebugNode !== importLast) {
const prevNode = sourceCode.getTokenBefore(importDebugNode);
const comma = sourceCode.getTokenAfter(importDebugNode, filterTokenComma);

yield fixer.removeRange([prevNode.range[1], importDebugNode.range[0]]);
yield fixer.remove(importDebugNode);
yield fixer.remove(comma);

return null;
}

/**
* import { condition, debug } from 'patronum'
*/
const comma = sourceCode.getTokenBefore(importDebugNode, filterTokenComma);

yield fixer.removeRange([comma.range[1], importDebugNode.range[0]]);
yield fixer.remove(importDebugNode);
yield fixer.remove(comma);
}
24 changes: 24 additions & 0 deletions rules/no-patronum-debug/no-patronum-debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# effector/no-patronum-debug

This rule will help to catch the forgotten `debug` and will automatically delete from code

```js
// from
import { createStore, createEvent } from "effector";
import { debug } from "patronum";

const increment = createEvent();
const $counter = createStore(0).on(increment, (count) => count + 1);

debug($counter);
```

```js
// to
import { createStore, createEvent } from "effector";

const increment = createEvent();
const $counter = createStore(0).on(increment, (count) => count + 1);
```

`debug` are considered to be intended for debugging units from effector and therefore not suitable for sending to the client.