zeiger-eslint-plugin 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -1
- package/dist/index.cjs +41 -18
- package/dist/index.js +41 -18
- package/dist/rules/zeiger-deps.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# zeiger-eslint-plugin
|
|
2
2
|
|
|
3
|
-
ESLint plugin for [Zeiger](https://
|
|
3
|
+
ESLint plugin for [Zeiger](https://www.npmjs.com/package/zeiger) - ensures proper usage of Zeiger hooks with dependency arrays.
|
|
4
|
+
|
|
5
|
+
Zeiger is a library for creating memoized collection item selectors for [Zustand](https://github.com/pmndrs/zustand) that eliminates unnecessary re-renders. This ESLint plugin helps you use Zeiger correctly by catching common mistakes with dependency arrays.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
@@ -86,6 +88,34 @@ return (
|
|
|
86
88
|
);
|
|
87
89
|
```
|
|
88
90
|
|
|
91
|
+
## Autofix
|
|
92
|
+
|
|
93
|
+
The plugin supports automatic fixing of unused dependencies. When you run ESLint with the `--fix` flag, it will automatically remove unused properties from dependency arrays:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
eslint --fix .
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Example:**
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
// Before
|
|
103
|
+
const user = useUserPointer('1', ['firstName', 'surname', 'email']);
|
|
104
|
+
return (
|
|
105
|
+
<div>
|
|
106
|
+
{user?.firstName} - {user?.email}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// After autofix
|
|
111
|
+
const user = useUserPointer('1', ['firstName', 'email']);
|
|
112
|
+
return (
|
|
113
|
+
<div>
|
|
114
|
+
{user?.firstName} - {user?.email}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
```
|
|
118
|
+
|
|
89
119
|
## Why This Plugin?
|
|
90
120
|
|
|
91
121
|
Zeiger hooks use dependency arrays to specify which properties to subscribe to. This plugin helps you:
|
|
@@ -93,6 +123,7 @@ Zeiger hooks use dependency arrays to specify which properties to subscribe to.
|
|
|
93
123
|
- **Avoid unnecessary subscriptions** - Catch unused properties in dependency arrays
|
|
94
124
|
- **Prevent empty arrays** - Ensure you're always subscribing to at least one property
|
|
95
125
|
- **Maintain code quality** - Keep your Zeiger hooks clean and efficient
|
|
126
|
+
- **Automatic fixes** - Remove unused dependencies with ESLint's autofix feature
|
|
96
127
|
|
|
97
128
|
## License
|
|
98
129
|
|
package/dist/index.cjs
CHANGED
|
@@ -29,6 +29,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
29
29
|
const rule = {
|
|
30
30
|
meta: {
|
|
31
31
|
type: 'problem',
|
|
32
|
+
fixable: 'code',
|
|
32
33
|
docs: {
|
|
33
34
|
description: 'Ensure zeiger hook dependency arrays are not empty and all dependencies are used'
|
|
34
35
|
},
|
|
@@ -47,23 +48,30 @@ const rule = {
|
|
|
47
48
|
if ('Identifier' !== callee.type) return false;
|
|
48
49
|
const hookName = callee.name;
|
|
49
50
|
if (!hookName.startsWith('use')) return false;
|
|
51
|
+
const args = callNode.arguments;
|
|
52
|
+
if (0 === args.length) return false;
|
|
53
|
+
const lastArg = args[args.length - 1];
|
|
54
|
+
if ('ArrayExpression' !== lastArg.type) return false;
|
|
50
55
|
const scope = sourceCode.getScope(node);
|
|
51
56
|
const variable = scope.variables.find((v)=>v.name === hookName);
|
|
52
57
|
if (!variable) return false;
|
|
53
|
-
for (const def of variable.defs)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
for (const def of variable.defs){
|
|
59
|
+
if ('Variable' === def.type && def.node.init) {
|
|
60
|
+
const init = def.node.init;
|
|
61
|
+
if ('CallExpression' === init.type) {
|
|
62
|
+
const initCall = init;
|
|
63
|
+
const initCallee = initCall.callee;
|
|
64
|
+
if ('Identifier' === initCallee.type) {
|
|
65
|
+
const initName = initCallee.name;
|
|
66
|
+
if ('createCollectionPointer' === initName || 'createCollectionItemPointer' === initName) return true;
|
|
67
|
+
}
|
|
68
|
+
if ('MemberExpression' === initCallee.type) {
|
|
69
|
+
const member = initCallee;
|
|
70
|
+
if ('Identifier' === member.property.type && ('createCollectionPointer' === member.property.name || 'createCollectionItemPointer' === member.property.name)) return true;
|
|
71
|
+
}
|
|
65
72
|
}
|
|
66
73
|
}
|
|
74
|
+
if ('ImportBinding' === def.type) return true;
|
|
67
75
|
}
|
|
68
76
|
return false;
|
|
69
77
|
}
|
|
@@ -145,19 +153,34 @@ const rule = {
|
|
|
145
153
|
const depsArg = callNode.arguments.length > 0 ? callNode.arguments[callNode.arguments.length - 1] : null;
|
|
146
154
|
if (depsArg && 'ArrayExpression' === depsArg.type) {
|
|
147
155
|
const arrayNode = depsArg;
|
|
156
|
+
const unusedDeps = [];
|
|
148
157
|
for(let i = 0; i < deps.length; i++){
|
|
149
158
|
const dep = deps[i];
|
|
150
159
|
if (!usedProperties.has(dep)) {
|
|
151
160
|
const depElement = arrayNode.elements[i];
|
|
152
|
-
if (depElement)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
property: dep
|
|
157
|
-
}
|
|
161
|
+
if (depElement) unusedDeps.push({
|
|
162
|
+
element: depElement,
|
|
163
|
+
index: i,
|
|
164
|
+
property: dep
|
|
158
165
|
});
|
|
159
166
|
}
|
|
160
167
|
}
|
|
168
|
+
if (unusedDeps.length > 0) {
|
|
169
|
+
const usedDeps = deps.filter((dep)=>usedProperties.has(dep));
|
|
170
|
+
for (const { element, property } of unusedDeps)context.report({
|
|
171
|
+
node: element,
|
|
172
|
+
messageId: 'unusedDep',
|
|
173
|
+
data: {
|
|
174
|
+
property
|
|
175
|
+
},
|
|
176
|
+
fix (fixer) {
|
|
177
|
+
if (0 === usedDeps.length) return null;
|
|
178
|
+
const arrayText = usedDeps.map((dep)=>`'${dep}'`).join(', ');
|
|
179
|
+
const newArrayText = `[${arrayText}]`;
|
|
180
|
+
return fixer.replaceText(depsArg, newArrayText);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
161
184
|
}
|
|
162
185
|
}
|
|
163
186
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const rule = {
|
|
2
2
|
meta: {
|
|
3
3
|
type: 'problem',
|
|
4
|
+
fixable: 'code',
|
|
4
5
|
docs: {
|
|
5
6
|
description: 'Ensure zeiger hook dependency arrays are not empty and all dependencies are used'
|
|
6
7
|
},
|
|
@@ -19,23 +20,30 @@ const rule = {
|
|
|
19
20
|
if ('Identifier' !== callee.type) return false;
|
|
20
21
|
const hookName = callee.name;
|
|
21
22
|
if (!hookName.startsWith('use')) return false;
|
|
23
|
+
const args = callNode.arguments;
|
|
24
|
+
if (0 === args.length) return false;
|
|
25
|
+
const lastArg = args[args.length - 1];
|
|
26
|
+
if ('ArrayExpression' !== lastArg.type) return false;
|
|
22
27
|
const scope = sourceCode.getScope(node);
|
|
23
28
|
const variable = scope.variables.find((v)=>v.name === hookName);
|
|
24
29
|
if (!variable) return false;
|
|
25
|
-
for (const def of variable.defs)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
for (const def of variable.defs){
|
|
31
|
+
if ('Variable' === def.type && def.node.init) {
|
|
32
|
+
const init = def.node.init;
|
|
33
|
+
if ('CallExpression' === init.type) {
|
|
34
|
+
const initCall = init;
|
|
35
|
+
const initCallee = initCall.callee;
|
|
36
|
+
if ('Identifier' === initCallee.type) {
|
|
37
|
+
const initName = initCallee.name;
|
|
38
|
+
if ('createCollectionPointer' === initName || 'createCollectionItemPointer' === initName) return true;
|
|
39
|
+
}
|
|
40
|
+
if ('MemberExpression' === initCallee.type) {
|
|
41
|
+
const member = initCallee;
|
|
42
|
+
if ('Identifier' === member.property.type && ('createCollectionPointer' === member.property.name || 'createCollectionItemPointer' === member.property.name)) return true;
|
|
43
|
+
}
|
|
37
44
|
}
|
|
38
45
|
}
|
|
46
|
+
if ('ImportBinding' === def.type) return true;
|
|
39
47
|
}
|
|
40
48
|
return false;
|
|
41
49
|
}
|
|
@@ -117,19 +125,34 @@ const rule = {
|
|
|
117
125
|
const depsArg = callNode.arguments.length > 0 ? callNode.arguments[callNode.arguments.length - 1] : null;
|
|
118
126
|
if (depsArg && 'ArrayExpression' === depsArg.type) {
|
|
119
127
|
const arrayNode = depsArg;
|
|
128
|
+
const unusedDeps = [];
|
|
120
129
|
for(let i = 0; i < deps.length; i++){
|
|
121
130
|
const dep = deps[i];
|
|
122
131
|
if (!usedProperties.has(dep)) {
|
|
123
132
|
const depElement = arrayNode.elements[i];
|
|
124
|
-
if (depElement)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
property: dep
|
|
129
|
-
}
|
|
133
|
+
if (depElement) unusedDeps.push({
|
|
134
|
+
element: depElement,
|
|
135
|
+
index: i,
|
|
136
|
+
property: dep
|
|
130
137
|
});
|
|
131
138
|
}
|
|
132
139
|
}
|
|
140
|
+
if (unusedDeps.length > 0) {
|
|
141
|
+
const usedDeps = deps.filter((dep)=>usedProperties.has(dep));
|
|
142
|
+
for (const { element, property } of unusedDeps)context.report({
|
|
143
|
+
node: element,
|
|
144
|
+
messageId: 'unusedDep',
|
|
145
|
+
data: {
|
|
146
|
+
property
|
|
147
|
+
},
|
|
148
|
+
fix (fixer) {
|
|
149
|
+
if (0 === usedDeps.length) return null;
|
|
150
|
+
const arrayText = usedDeps.map((dep)=>`'${dep}'`).join(', ');
|
|
151
|
+
const newArrayText = `[${arrayText}]`;
|
|
152
|
+
return fixer.replaceText(depsArg, newArrayText);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
133
156
|
}
|
|
134
157
|
}
|
|
135
158
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zeiger-deps.d.ts","sourceRoot":"","sources":["../../src/rules/zeiger-deps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"zeiger-deps.d.ts","sourceRoot":"","sources":["../../src/rules/zeiger-deps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAyYhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
package/package.json
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
"homepage": "https://github.com/DNepovim/zeiger",
|
|
5
5
|
"repository": "https://github.com/DNepovim/zeiger",
|
|
6
6
|
"author": "Dominik Bláha <iam@dominikblaha.cz>",
|
|
7
|
-
"version": "0.1.
|
|
7
|
+
"version": "0.1.2",
|
|
8
8
|
"type": "module",
|
|
9
|
+
"license": "MIT",
|
|
9
10
|
"exports": {
|
|
10
11
|
".": {
|
|
11
12
|
"types": "./dist/index.d.ts",
|