@putout/plugin-variables 1.2.0 → 1.3.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 +66 -0
- package/lib/extract-keywords/index.js +178 -0
- package/lib/index.js +4 -0
- package/lib/remove-unused/get-unused.js +5 -0
- package/lib/remove-unused/get-vars/get-vars.js +589 -0
- package/lib/remove-unused/get-vars/index.js +148 -0
- package/lib/remove-unused/get-vars/jsx.js +45 -0
- package/lib/remove-unused/get-vars/traverse.js +179 -0
- package/lib/remove-unused/get-vars/typescript.js +134 -0
- package/lib/remove-unused/get-vars/use-params.js +123 -0
- package/lib/remove-unused/get-vars/visitors/export-named-declaration.js +61 -0
- package/lib/remove-unused/index.js +40 -0
- package/lib/remove-unused/transform.js +18 -0
- package/lib/remove-useless-rename/index.js +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ npm i @putout/plugin-variables -D
|
|
|
17
17
|
|
|
18
18
|
## Rules
|
|
19
19
|
|
|
20
|
+
- ✅ [convert-const-to-let](#convert-const-to-let');
|
|
21
|
+
- ✅ [extract-keywords](#extract-keywords');
|
|
20
22
|
- ✅ [remove-useless-assignment](#remove-useless-assignmenn);
|
|
21
23
|
- ✅ [remove-useless-declaration](#remove-useless-declaration);
|
|
22
24
|
- ✅ [remove-useless-duplicate](#remove-useless-duplicate);
|
|
@@ -29,6 +31,8 @@ npm i @putout/plugin-variables -D
|
|
|
29
31
|
```json
|
|
30
32
|
{
|
|
31
33
|
"rules": {
|
|
34
|
+
"variables/convert-const-to-let": "on",
|
|
35
|
+
"variables/extract-keywords": "on",
|
|
32
36
|
"variables/remove-useless-assignment": "on",
|
|
33
37
|
"variables/remove-useless-declaration": ["on", {
|
|
34
38
|
"maxLength": 20
|
|
@@ -240,6 +244,68 @@ let a = 5;
|
|
|
240
244
|
a = 3;
|
|
241
245
|
```
|
|
242
246
|
|
|
247
|
+
## remove-unused
|
|
248
|
+
|
|
249
|
+
> A variable is a container for a value, like a `number` we might use in a sum, or a `string` that we might use as part of a sentence.
|
|
250
|
+
>
|
|
251
|
+
> (c) [MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables)
|
|
252
|
+
|
|
253
|
+
🐊[**Putout**](https://github.com/coderaiser/putout) plugin adds ability to find and remove the variables that are declared, but:
|
|
254
|
+
|
|
255
|
+
- not passed as **argument** to a **function**;
|
|
256
|
+
- not used as **operand** in **expression**;
|
|
257
|
+
|
|
258
|
+
That is **unused variables**. Most likely it is a leftovers due to incomplete transforming of the code. Such variables take up space and gives no value so they must be removed.
|
|
259
|
+
|
|
260
|
+
☝️*Remember, when you [writing a transform](https://github.com/coderaiser/putout/tree/master/packages/engine-runner#readme) you can skip all parts related to **removing unused variables** and just reuse current **plugin** it will make your code simpler and less error prone.*
|
|
261
|
+
|
|
262
|
+
☝️*No, you cannot just look at [`referenced` and `constant` fields](https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#user-content-bindings) to determine if you can remove variable and [here is why](https://putout.cloudcmd.io/#/gist/4277392f74b56b74911b779c9624af8d/cfec476f857dfb4f4c7a6247bdcc6b521fed8e70) one of the biggest plugins exists*.
|
|
263
|
+
|
|
264
|
+
### ❌ Example of incorrect code
|
|
265
|
+
|
|
266
|
+
```js
|
|
267
|
+
const a = 'hello';
|
|
268
|
+
const b = 'world';
|
|
269
|
+
|
|
270
|
+
console.log(a);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### ✅ Example of correct code
|
|
274
|
+
|
|
275
|
+
```js
|
|
276
|
+
const a = 'hello';
|
|
277
|
+
console.log(a);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Comparison
|
|
281
|
+
|
|
282
|
+
Linter | Rule | Fix
|
|
283
|
+
--------|-------|------------|
|
|
284
|
+
🐊 **Putout**| [`remove-unused-variables`](https://github.com/coderaiser/putout/tree/master/packages/plugin-remove-unused-variables#readme)| ✅
|
|
285
|
+
⏣ **ESLint** | [`no-unused-vars`](https://eslint.org/docs/rules/no-unused-vars) | ❌
|
|
286
|
+
|
|
287
|
+
## extract-keywords
|
|
288
|
+
|
|
289
|
+
> The JavaScript exceptions "unexpected token" occur when the parser does not see a token it recognizes at the given position, so it cannot make sense of the structure of the program. This might be a simple typo.
|
|
290
|
+
>
|
|
291
|
+
> (c) [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_token)
|
|
292
|
+
|
|
293
|
+
Extract `keywords` from variables. Check out in 🐊[**Putout Editor**](https://putout.cloudcmd.io/#/gist/fcaedaa9daf7f3a771274aca0da9ab1b/00850a5d28aec86b1b4083ba2ef9f81bd49aaaac).
|
|
294
|
+
|
|
295
|
+
```diff
|
|
296
|
+
-export const isTemplateMiddle = (a) => a?.type === 'TemplateMiddle',
|
|
297
|
+
+export const isTemplateMiddle = (a) => a?.type === 'TemplateMiddle';
|
|
298
|
+
export const isTemplateTail = (a) => a?.type === 'TemplateTail';
|
|
299
|
+
|
|
300
|
+
-const a 5;
|
|
301
|
+
+const a = 5;
|
|
302
|
+
|
|
303
|
+
-export const packContent = (content) {
|
|
304
|
+
+export const packContent = (content) => {
|
|
305
|
+
console.log(a);
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
243
309
|
## License
|
|
244
310
|
|
|
245
311
|
MIT
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {types, operator} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
ifStatement,
|
|
5
|
+
importDefaultSpecifier,
|
|
6
|
+
importDeclaration,
|
|
7
|
+
exportNamedDeclaration,
|
|
8
|
+
variableDeclarator,
|
|
9
|
+
variableDeclaration,
|
|
10
|
+
isExportDeclaration,
|
|
11
|
+
isArrowFunctionExpression,
|
|
12
|
+
isLiteral,
|
|
13
|
+
isAssignmentExpression,
|
|
14
|
+
isExportNamedDeclaration,
|
|
15
|
+
isIdentifier,
|
|
16
|
+
isImportDeclaration,
|
|
17
|
+
isMemberExpression,
|
|
18
|
+
isBlockStatement,
|
|
19
|
+
arrowFunctionExpression,
|
|
20
|
+
} = types;
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
removeParens,
|
|
24
|
+
remove,
|
|
25
|
+
replaceWith,
|
|
26
|
+
isDeclarationKeyword,
|
|
27
|
+
isConditionKeyword,
|
|
28
|
+
isModuleDeclarationKeyword,
|
|
29
|
+
} = operator;
|
|
30
|
+
|
|
31
|
+
const isInit = (a) => isIdentifier(a) || isLiteral(a) || isMemberExpression(a) || isArrowFunctionExpression(a);
|
|
32
|
+
|
|
33
|
+
const buildDeclaration = (type) => (nextPath, path) => {
|
|
34
|
+
const {expression} = nextPath.node;
|
|
35
|
+
let left;
|
|
36
|
+
let right;
|
|
37
|
+
|
|
38
|
+
if (isBlockStatement(nextPath)) {
|
|
39
|
+
left = path.node.id;
|
|
40
|
+
const {node: init} = removeParens(path.get('init'));
|
|
41
|
+
const params = [init];
|
|
42
|
+
|
|
43
|
+
right = arrowFunctionExpression(params, nextPath.node);
|
|
44
|
+
} else if (isAssignmentExpression(expression)) {
|
|
45
|
+
({
|
|
46
|
+
left,
|
|
47
|
+
right,
|
|
48
|
+
} = expression);
|
|
49
|
+
} else {
|
|
50
|
+
left = path.node.id;
|
|
51
|
+
right = nextPath.node.expression;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
replaceWith(nextPath, variableDeclaration(type, [variableDeclarator(left, right)]));
|
|
55
|
+
|
|
56
|
+
const {name} = path.node.id;
|
|
57
|
+
|
|
58
|
+
if (isDeclarationKeyword(name))
|
|
59
|
+
return;
|
|
60
|
+
|
|
61
|
+
if (isExportNamedDeclaration(path.parentPath.parentPath))
|
|
62
|
+
replaceWith(nextPath, exportNamedDeclaration(nextPath.node));
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const builders = {
|
|
66
|
+
const: buildDeclaration('const'),
|
|
67
|
+
var: buildDeclaration('var'),
|
|
68
|
+
let: buildDeclaration('let'),
|
|
69
|
+
import: buildImport,
|
|
70
|
+
export: buildExport,
|
|
71
|
+
if: buildIf,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const report = ({name}) => `Extract '${name}' from variable`;
|
|
75
|
+
|
|
76
|
+
export const fix = ({name, path, nextPath}) => {
|
|
77
|
+
builders[name](nextPath, path);
|
|
78
|
+
remove(path);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const traverse = ({push}) => ({
|
|
82
|
+
VariableDeclarator(path) {
|
|
83
|
+
const {name} = path.node.id;
|
|
84
|
+
|
|
85
|
+
if (isDeclarationKeyword(name) || isConditionKeyword(name) || isModuleDeclarationKeyword(name)) {
|
|
86
|
+
const topPath = getTopPath(path);
|
|
87
|
+
const nextPath = topPath.getNextSibling();
|
|
88
|
+
|
|
89
|
+
if (nextPath.isVariableDeclaration())
|
|
90
|
+
push({
|
|
91
|
+
name,
|
|
92
|
+
path,
|
|
93
|
+
nextPath,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (nextPath.isExpressionStatement())
|
|
97
|
+
push({
|
|
98
|
+
name,
|
|
99
|
+
path,
|
|
100
|
+
nextPath,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const {kind} = path.parentPath.node;
|
|
107
|
+
|
|
108
|
+
if (!path.node.init) {
|
|
109
|
+
const topPath = getTopPath(path);
|
|
110
|
+
const nextPath = topPath.getNextSibling();
|
|
111
|
+
|
|
112
|
+
if (!nextPath.isExpressionStatement())
|
|
113
|
+
return;
|
|
114
|
+
|
|
115
|
+
const {expression} = nextPath.node;
|
|
116
|
+
|
|
117
|
+
if (isInit(expression))
|
|
118
|
+
push({
|
|
119
|
+
name: kind,
|
|
120
|
+
path,
|
|
121
|
+
nextPath,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (isExportDeclaration(path.parentPath.parentPath)) {
|
|
128
|
+
const nextPath = path.parentPath.parentPath.getNextSibling();
|
|
129
|
+
|
|
130
|
+
if (!isBlockStatement(nextPath))
|
|
131
|
+
return;
|
|
132
|
+
|
|
133
|
+
if (!nextPath.node.body.length)
|
|
134
|
+
return;
|
|
135
|
+
|
|
136
|
+
const count = nextPath.node.body.filter(isImportDeclaration).length;
|
|
137
|
+
|
|
138
|
+
if (!count)
|
|
139
|
+
push({
|
|
140
|
+
name: kind,
|
|
141
|
+
path,
|
|
142
|
+
nextPath,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
function getTopPath(path) {
|
|
149
|
+
if (path.parentPath.parentPath.isExportDeclaration())
|
|
150
|
+
return path.parentPath.parentPath;
|
|
151
|
+
|
|
152
|
+
return path.parentPath;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function buildExport(path) {
|
|
156
|
+
replaceWith(path, exportNamedDeclaration(path.node));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function buildImport(path) {
|
|
160
|
+
const fromPath = path.getNextSibling();
|
|
161
|
+
const sourcePath = fromPath.getNextSibling();
|
|
162
|
+
const source = sourcePath.node.expression;
|
|
163
|
+
const local = path.node.expression;
|
|
164
|
+
|
|
165
|
+
replaceWith(path, importDeclaration([importDefaultSpecifier(local, local)], source));
|
|
166
|
+
remove(sourcePath);
|
|
167
|
+
remove(fromPath);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function buildIf(path) {
|
|
171
|
+
const {expression} = path.node;
|
|
172
|
+
delete expression.extra.parenthesized;
|
|
173
|
+
const nextPath = path.getNextSibling();
|
|
174
|
+
const next = nextPath.node;
|
|
175
|
+
|
|
176
|
+
remove(nextPath);
|
|
177
|
+
replaceWith(path, ifStatement(expression, next));
|
|
178
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import * as convertConstToLet from './convert-const-to-let/index.js';
|
|
2
|
+
import * as extractKeywords from './extract-keywords/index.js';
|
|
2
3
|
import * as removeUseless from './remove-useless/index.js';
|
|
3
4
|
import * as removeUselessAssignment from './remove-useless-assignment/index.js';
|
|
4
5
|
import * as removeUselessDeclarations from './remove-useless-declarations/index.js';
|
|
5
6
|
import * as removeUselessDuplicates from './remove-useless-duplicates/index.js';
|
|
6
7
|
import * as removeUselessRename from './remove-useless-rename/index.js';
|
|
7
8
|
import * as removeUnreferenced from './remove-unreferenced/index.js';
|
|
9
|
+
import * as removeUnused from './remove-unused/index.js';
|
|
8
10
|
import * as splitDeclarations from './split-declarations/index.js';
|
|
9
11
|
|
|
10
12
|
export const rules = {
|
|
11
13
|
'convert-const-to-let': convertConstToLet,
|
|
14
|
+
'extract-keywords': extractKeywords,
|
|
12
15
|
'remove-useless': removeUseless,
|
|
13
16
|
'remove-useless-assignment': removeUselessAssignment,
|
|
14
17
|
'remove-useless-declarations': removeUselessDeclarations,
|
|
15
18
|
'remove-useless-duplicates': removeUselessDuplicates,
|
|
16
19
|
'remove-useless-rename': removeUselessRename,
|
|
17
20
|
'remove-unreferenced': removeUnreferenced,
|
|
21
|
+
'remove-unused': removeUnused,
|
|
18
22
|
'split-declarations': splitDeclarations,
|
|
19
23
|
};
|