@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 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
- 🐊[**Putout**](https://github.com/coderaiser/putout) plugin adds ability to find and remove `useless variables`.
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.0.0",
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",