@putout/plugin-variables 1.0.0 β 1.2.0
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 +87 -2
- package/lib/convert-const-to-let/index.js +69 -0
- package/lib/index.js +6 -0
- package/lib/remove-unreferenced/index.js +105 -0
- package/lib/split-declarations/index.js +67 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
[NPMIMGURL]: https://img.shields.io/npm/v/@putout/plugin-variables.svg?style=flat&longCache=true
|
|
4
4
|
[NPMURL]: https://npmjs.org/package/@putout/plugin-variables "npm"
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
> A **variable** is a named reference to a **value**.
|
|
7
|
+
>
|
|
8
|
+
> (c) [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Variable)
|
|
9
|
+
|
|
10
|
+
π[**Putout**](https://github.com/coderaiser/putout) plugin adds ability to transform `variables`.
|
|
7
11
|
|
|
8
12
|
## Install
|
|
9
13
|
|
|
@@ -18,6 +22,7 @@ npm i @putout/plugin-variables -D
|
|
|
18
22
|
- β
[remove-useless-duplicate](#remove-useless-duplicate);
|
|
19
23
|
- β
[remove-useless-variables](#remove-useless-variables);
|
|
20
24
|
- β
[remove-useless-rename](#remove-useless-rename);
|
|
25
|
+
- β
[split-declarations](#split-declarations);
|
|
21
26
|
|
|
22
27
|
## Config
|
|
23
28
|
|
|
@@ -30,7 +35,8 @@ npm i @putout/plugin-variables -D
|
|
|
30
35
|
}],
|
|
31
36
|
"variables/remove-useless-duplicate": "on",
|
|
32
37
|
"variables/remove-useless-rename": "on",
|
|
33
|
-
"variables/remove-useless-remove": "on"
|
|
38
|
+
"variables/remove-useless-remove": "on",
|
|
39
|
+
"variables/split-declarations": "on"
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
```
|
|
@@ -155,6 +161,85 @@ function DestructuringErrors(a, b) {
|
|
|
155
161
|
bc = b.c.replace('x', 'y');
|
|
156
162
|
```
|
|
157
163
|
|
|
164
|
+
## remove-unreferenced
|
|
165
|
+
|
|
166
|
+
### β Example of incorrect code
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
let a;
|
|
170
|
+
let b;
|
|
171
|
+
|
|
172
|
+
a = 5;
|
|
173
|
+
b = 6;
|
|
174
|
+
|
|
175
|
+
console.log(a);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### β
Example of correct code
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
let a;
|
|
182
|
+
|
|
183
|
+
a = 5;
|
|
184
|
+
|
|
185
|
+
console.log(a);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## split-declarations
|
|
189
|
+
|
|
190
|
+
> - The [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) statement declares a block-scoped local variable, optionally initializing it to a value.
|
|
191
|
+
> - [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) statements are also block-scoped. The value of a constant can't be changed through reassignment, and it can't be redeclared. However, if a constant is an **object** or **array** its properties or items can be updated or removed.
|
|
192
|
+
>
|
|
193
|
+
> (c) MDN
|
|
194
|
+
|
|
195
|
+
Add ability to find and split variable declarations because (re)moving a line is simpler and less error prone then changing coma (`,`) to colon (`;`).
|
|
196
|
+
For the same reason, **diff** of changed declarations are more comfortable to read.
|
|
197
|
+
|
|
198
|
+
### β Example of incorrect code
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
let a, b;
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### β
Example of correct code
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
let a;
|
|
208
|
+
let b;
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Comparison
|
|
212
|
+
|
|
213
|
+
Linter | Rule | Fix
|
|
214
|
+
--------|-------|------------|
|
|
215
|
+
π **Putout** | [`remove-debugger`](https://github.com/coderaiser/putout/tree/master/packages/plugin-split-variable-declarations#readme) | β
|
|
216
|
+
β£ **ESLint** | [`no-var`](https://eslint.org/docs/latest/rules/one-var) | β
|
|
217
|
+
|
|
218
|
+
## convert-const-to-let
|
|
219
|
+
|
|
220
|
+
> The `TypeError` object represents an error when attempting to modify a value that cannot be changed.
|
|
221
|
+
>
|
|
222
|
+
> (c) [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError)
|
|
223
|
+
|
|
224
|
+
Convert `const` to `let` to avoid `TypeError`.
|
|
225
|
+
Check out in π[**Putout Editor**](https://putout.cloudcmd.io/#/gist/61ffff64a356c47e66af4ea17a9a755d/e7f5fa455c208a7faa9319d94130996d39afcbf7).
|
|
226
|
+
|
|
227
|
+
### β Example of incorrect code
|
|
228
|
+
|
|
229
|
+
```js
|
|
230
|
+
let a = 5;
|
|
231
|
+
|
|
232
|
+
a = 3;
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### β
Example of correct code
|
|
236
|
+
|
|
237
|
+
```js
|
|
238
|
+
let a = 5;
|
|
239
|
+
|
|
240
|
+
a = 3;
|
|
241
|
+
```
|
|
242
|
+
|
|
158
243
|
## License
|
|
159
244
|
|
|
160
245
|
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {types} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
isBlockStatement,
|
|
5
|
+
isProgram,
|
|
6
|
+
} = types;
|
|
7
|
+
|
|
8
|
+
const {values} = Object;
|
|
9
|
+
|
|
10
|
+
const isKeyword = (a) => [
|
|
11
|
+
'export',
|
|
12
|
+
'const',
|
|
13
|
+
'let',
|
|
14
|
+
'var',
|
|
15
|
+
].includes(a);
|
|
16
|
+
|
|
17
|
+
const isInsideBlock = ({parentPath}) => isProgram(parentPath) || isBlockStatement(parentPath);
|
|
18
|
+
|
|
19
|
+
export const report = () => `Use 'let' when reassign`;
|
|
20
|
+
|
|
21
|
+
export const fix = (path) => {
|
|
22
|
+
path.node.kind = 'let';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const traverse = ({push}) => ({
|
|
26
|
+
VariableDeclaration: (path) => {
|
|
27
|
+
if (path.parentPath.isTSModuleBlock())
|
|
28
|
+
return;
|
|
29
|
+
|
|
30
|
+
const {scope} = path;
|
|
31
|
+
const {declare} = path.node;
|
|
32
|
+
|
|
33
|
+
if (declare)
|
|
34
|
+
return;
|
|
35
|
+
|
|
36
|
+
for (const binding of values(scope.bindings)) {
|
|
37
|
+
const {parentPath, node} = binding.path;
|
|
38
|
+
const {init} = node;
|
|
39
|
+
|
|
40
|
+
if (init && binding.constant)
|
|
41
|
+
continue;
|
|
42
|
+
|
|
43
|
+
if (isLoop(parentPath) && binding.constant)
|
|
44
|
+
continue;
|
|
45
|
+
|
|
46
|
+
if (!binding.path.isVariableDeclarator())
|
|
47
|
+
continue;
|
|
48
|
+
|
|
49
|
+
if (isKeyword(binding.path.node.id.name))
|
|
50
|
+
continue;
|
|
51
|
+
|
|
52
|
+
if (!binding.path.node.init && isInsideBlock(binding.path.parentPath))
|
|
53
|
+
continue;
|
|
54
|
+
|
|
55
|
+
if (parentPath.node.kind === 'const')
|
|
56
|
+
push(binding.path.parentPath);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const isLoop = ({parentPath}) => {
|
|
62
|
+
if (!parentPath)
|
|
63
|
+
return false;
|
|
64
|
+
|
|
65
|
+
if (parentPath.isForOfStatement())
|
|
66
|
+
return true;
|
|
67
|
+
|
|
68
|
+
return parentPath.isForInStatement();
|
|
69
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
import * as convertConstToLet from './convert-const-to-let/index.js';
|
|
1
2
|
import * as removeUseless from './remove-useless/index.js';
|
|
2
3
|
import * as removeUselessAssignment from './remove-useless-assignment/index.js';
|
|
3
4
|
import * as removeUselessDeclarations from './remove-useless-declarations/index.js';
|
|
4
5
|
import * as removeUselessDuplicates from './remove-useless-duplicates/index.js';
|
|
5
6
|
import * as removeUselessRename from './remove-useless-rename/index.js';
|
|
7
|
+
import * as removeUnreferenced from './remove-unreferenced/index.js';
|
|
8
|
+
import * as splitDeclarations from './split-declarations/index.js';
|
|
6
9
|
|
|
7
10
|
export const rules = {
|
|
11
|
+
'convert-const-to-let': convertConstToLet,
|
|
8
12
|
'remove-useless': removeUseless,
|
|
9
13
|
'remove-useless-assignment': removeUselessAssignment,
|
|
10
14
|
'remove-useless-declarations': removeUselessDeclarations,
|
|
11
15
|
'remove-useless-duplicates': removeUselessDuplicates,
|
|
12
16
|
'remove-useless-rename': removeUselessRename,
|
|
17
|
+
'remove-unreferenced': removeUnreferenced,
|
|
18
|
+
'split-declarations': splitDeclarations,
|
|
13
19
|
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {operator} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {remove} = operator;
|
|
4
|
+
|
|
5
|
+
export const report = () => 'Avoid unreferenced variables';
|
|
6
|
+
|
|
7
|
+
export const fix = (path) => {
|
|
8
|
+
remove(path);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const traverse = ({push}) => ({
|
|
12
|
+
'return __a'(path) {
|
|
13
|
+
const arg = path.get('argument');
|
|
14
|
+
|
|
15
|
+
if (!arg.isIdentifier())
|
|
16
|
+
return false;
|
|
17
|
+
|
|
18
|
+
const binding = path.scope.bindings[arg.node.name];
|
|
19
|
+
|
|
20
|
+
if (!binding)
|
|
21
|
+
return false;
|
|
22
|
+
|
|
23
|
+
if (binding.constantViolations.length)
|
|
24
|
+
return false;
|
|
25
|
+
|
|
26
|
+
if (binding.referencePaths.length !== 1)
|
|
27
|
+
return false;
|
|
28
|
+
|
|
29
|
+
if (!binding.path.isVariableDeclarator())
|
|
30
|
+
return false;
|
|
31
|
+
|
|
32
|
+
if (binding.path.node.init)
|
|
33
|
+
return false;
|
|
34
|
+
|
|
35
|
+
push(path);
|
|
36
|
+
},
|
|
37
|
+
'__identifier = __a'(path) {
|
|
38
|
+
const {parentPath} = path;
|
|
39
|
+
|
|
40
|
+
if (parentPath.isMemberExpression())
|
|
41
|
+
return;
|
|
42
|
+
|
|
43
|
+
if (parentPath.isConditionalExpression())
|
|
44
|
+
return;
|
|
45
|
+
|
|
46
|
+
const {name} = path.node.left;
|
|
47
|
+
const binding = path.scope.getAllBindings()[name];
|
|
48
|
+
|
|
49
|
+
if (!binding)
|
|
50
|
+
return;
|
|
51
|
+
|
|
52
|
+
if (path.find(isInsideForOf))
|
|
53
|
+
return;
|
|
54
|
+
|
|
55
|
+
const {referenced} = binding;
|
|
56
|
+
|
|
57
|
+
if (referenced)
|
|
58
|
+
return;
|
|
59
|
+
|
|
60
|
+
if (binding.path.isObjectPattern()) {
|
|
61
|
+
const propPath = getPropertyPath(binding.path, name);
|
|
62
|
+
|
|
63
|
+
push(path);
|
|
64
|
+
push(propPath);
|
|
65
|
+
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const idPath = binding.path.get('id');
|
|
70
|
+
|
|
71
|
+
if (binding.path.isVariableDeclarator() && idPath.isObjectPattern()) {
|
|
72
|
+
const propPath = getPropertyPath(idPath, name);
|
|
73
|
+
|
|
74
|
+
push(path);
|
|
75
|
+
push(propPath);
|
|
76
|
+
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
push(path);
|
|
81
|
+
push(binding.path);
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
function getPropertyPath(path, name) {
|
|
86
|
+
let propPath;
|
|
87
|
+
|
|
88
|
+
for (propPath of path.get('properties')) {
|
|
89
|
+
const {key, shorthand} = propPath.node;
|
|
90
|
+
|
|
91
|
+
if (shorthand && key.name !== name)
|
|
92
|
+
continue;
|
|
93
|
+
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return propPath;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function isInsideForOf(path) {
|
|
101
|
+
if (path.isForOfStatement())
|
|
102
|
+
return true;
|
|
103
|
+
|
|
104
|
+
return path.__putout_for_of_reduce;
|
|
105
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {types, operator} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
isForStatement,
|
|
5
|
+
variableDeclaration,
|
|
6
|
+
} = types;
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
replaceWithMultiple,
|
|
10
|
+
isKeyword,
|
|
11
|
+
} = operator;
|
|
12
|
+
|
|
13
|
+
export const report = () => 'Variables should be declared separately';
|
|
14
|
+
|
|
15
|
+
export const fix = (path) => {
|
|
16
|
+
const {node} = path;
|
|
17
|
+
const varNodes = getVarNodes(node);
|
|
18
|
+
|
|
19
|
+
replaceWithMultiple(path, varNodes);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const traverse = ({push}) => ({
|
|
23
|
+
VariableDeclaration(path) {
|
|
24
|
+
const {
|
|
25
|
+
node,
|
|
26
|
+
parent,
|
|
27
|
+
parentPath,
|
|
28
|
+
} = path;
|
|
29
|
+
|
|
30
|
+
const {declarations} = node;
|
|
31
|
+
|
|
32
|
+
if (parentPath.isExportDeclaration())
|
|
33
|
+
return;
|
|
34
|
+
|
|
35
|
+
if (declarations.length === 1)
|
|
36
|
+
return;
|
|
37
|
+
|
|
38
|
+
for (const declaration of declarations) {
|
|
39
|
+
const {name} = declaration.id;
|
|
40
|
+
|
|
41
|
+
if (isKeyword(name))
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const init = node;
|
|
46
|
+
|
|
47
|
+
if (isForStatement(parent, {init}))
|
|
48
|
+
return;
|
|
49
|
+
|
|
50
|
+
push(path);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function getVarNodes({kind, declarations}) {
|
|
55
|
+
const result = [];
|
|
56
|
+
|
|
57
|
+
for (const declaration of declarations) {
|
|
58
|
+
const declarations = [declaration];
|
|
59
|
+
|
|
60
|
+
result.push(variableDeclaration(
|
|
61
|
+
kind,
|
|
62
|
+
declarations,
|
|
63
|
+
));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return result;
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@putout/plugin-variables",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
|
|
6
6
|
"description": "πPutout plugin adds ability to find and remove useless",
|
|
@@ -37,7 +37,10 @@
|
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@putout/eslint-flat": "^3.0.0",
|
|
39
39
|
"@putout/plugin-declare": "*",
|
|
40
|
+
"@putout/plugin-for-of": "*",
|
|
40
41
|
"@putout/plugin-maybe": "*",
|
|
42
|
+
"@putout/plugin-minify": "*",
|
|
43
|
+
"@putout/plugin-remove-unused-variables": "*",
|
|
41
44
|
"@putout/plugin-remove-useless-array-from": "*",
|
|
42
45
|
"@putout/plugin-reuse-duplicate-init": "*",
|
|
43
46
|
"@putout/test": "^14.0.0",
|