@putout/plugin-destructuring 1.1.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 CHANGED
@@ -20,8 +20,10 @@ npm i @putout/plugin-destructuring
20
20
  - ✅ [apply-object](#apply-object);
21
21
  - ✅ [apply-array](#apply-array);
22
22
  - ✅ [convert-object-to-array](#convert-object-to-array);
23
+ - ✅ [extract-properties](#extract-properties);
23
24
  - ✅ [remove-useless-object](#remove-useless-object);
24
25
  - ✅ [remove-useless-arguments](#remove-useless-arguments);
26
+ - ✅ [remove-useless-variables](#remove-useless-variables);
25
27
  - ✅ [split-nested](#split-nested);
26
28
  - ✅ [split-call](#split-call);
27
29
  - ✅ [merge-properties](#merge-properties);
@@ -34,8 +36,10 @@ npm i @putout/plugin-destructuring
34
36
  "destructuring/apply-object": "on",
35
37
  "destructuring/apply-array": "on",
36
38
  "destructuring/convert-object-to-array": "on",
39
+ "destructuring/extract-properties": "on",
37
40
  "destructuring/remove-useless-object": "on",
38
41
  "destructuring/remove-useless-arguments": "on",
42
+ "destructuring/remove-useless-variables": "on",
39
43
  "destructuring/split-nested": "on",
40
44
  "destructuring/split-call": "on",
41
45
  "destructuring/merge-properties": "on"
@@ -219,6 +223,58 @@ onIfStatement({
219
223
  function onIfStatement({push}) {}
220
224
  ```
221
225
 
226
+ ## remove-useless-variables
227
+
228
+ ### ❌ Example of incorrect code
229
+
230
+ ```js
231
+ function hi(c) {
232
+ const {a, b} = c;
233
+ }
234
+ ```
235
+
236
+ ### ✅ Example of correct code
237
+
238
+ ```js
239
+ function hi({a, b}) {}
240
+ ```
241
+
242
+ ## extract-properties
243
+
244
+ ### Equal Deep
245
+
246
+ #### ❌ Example of incorrect code
247
+
248
+ ```js
249
+ const {replaceWith} = a.operate;
250
+ const {isIdentifier} = a.types;
251
+ ```
252
+
253
+ #### ✅ Example of correct code
254
+
255
+ ```js
256
+ const {operator, types} = a;
257
+
258
+ const {replaceWith} = operator;
259
+ const {isIdentifier} = types;
260
+ ```
261
+
262
+ ### Not Equal Deep
263
+
264
+ #### ❌ Example of incorrect code
265
+
266
+ ```js
267
+ const {replaceWith} = a;
268
+ const {isIdentifier} = a.types;
269
+ ```
270
+
271
+ #### ✅ Example of correct code
272
+
273
+ ```js
274
+ const {replaceWith, types} = a;
275
+ const {isIdentifier} = types;
276
+ ```
277
+
222
278
  ## License
223
279
 
224
280
  MIT
@@ -0,0 +1,78 @@
1
+ import {
2
+ template,
3
+ generate,
4
+ types,
5
+ operator,
6
+ } from 'putout';
7
+
8
+ const {
9
+ findBinding,
10
+ replaceWith,
11
+ getTemplateValues,
12
+ } = operator;
13
+
14
+ const {
15
+ isIdentifier,
16
+ isCallExpression,
17
+ } = types;
18
+
19
+ export const report = () => `Extract object properties into variables`;
20
+
21
+ const buildAst = template(`
22
+ const {PROPERTY} = OBJECT;
23
+ `);
24
+
25
+ export const fix = ({items}) => {
26
+ const names = [];
27
+
28
+ for (const item of items) {
29
+ const {object, property} = item.node;
30
+
31
+ if (isIdentifier(property) && !names.includes(property.name)) {
32
+ names.push(property.name);
33
+
34
+ const {body = item.scope.block.body} = item.scope.block.body;
35
+
36
+ body.unshift(buildAst({
37
+ PROPERTY: property,
38
+ OBJECT: object,
39
+ }));
40
+ }
41
+
42
+ replaceWith(item, item.node.property);
43
+ }
44
+ };
45
+
46
+ export const traverse = ({uplist, push}) => ({
47
+ 'const __object = __a.__b': (fullPath) => {
48
+ const {__a, __b} = getTemplateValues(fullPath, 'const __object = __a.__b');
49
+ const initPath = fullPath.get('declarations.0.init');
50
+ const {uid} = initPath.scope;
51
+
52
+ if (findBinding(fullPath, __b.name))
53
+ return;
54
+
55
+ if (isIdentifier(__a) || isCallExpression(__a)) {
56
+ const {code} = generate(__a);
57
+ const id = `${uid}-${code}`;
58
+
59
+ return uplist(id, initPath);
60
+ }
61
+ },
62
+ 'Program': {
63
+ exit: () => {
64
+ for (const items of uplist()) {
65
+ if (items.length < 2)
66
+ continue;
67
+
68
+ const index = items.length - 1;
69
+ const path = items[index];
70
+
71
+ push({
72
+ path,
73
+ items,
74
+ });
75
+ }
76
+ },
77
+ },
78
+ });
@@ -0,0 +1,72 @@
1
+ import {operator, types} from 'putout';
2
+
3
+ const {objectProperty} = types;
4
+
5
+ const {replaceWith, compare} = operator;
6
+
7
+ const SHORTHAND = true;
8
+ const COMPUTED = false;
9
+
10
+ export const report = () => `Extract object properties into variables`;
11
+
12
+ export const fix = ({path, expandPath, property}) => {
13
+ const newProperty = objectProperty(property, property, COMPUTED, SHORTHAND);
14
+
15
+ expandPath.node.properties.push(newProperty);
16
+ replaceWith(path, property);
17
+ };
18
+
19
+ export const traverse = ({listStore, push}) => ({
20
+ 'const __object = __a.__b': save({
21
+ listStore,
22
+ }),
23
+ 'const __object = __a(__args)': save({
24
+ listStore,
25
+ }),
26
+ 'Program': {
27
+ exit: exit({
28
+ push,
29
+ listStore,
30
+ }),
31
+ },
32
+ });
33
+
34
+ const save = ({listStore}) => (path) => {
35
+ const idPath = path.get('declarations.0.id');
36
+ const initPath = path.get('declarations.0.init');
37
+
38
+ listStore([initPath, idPath]);
39
+ };
40
+
41
+ const exit = ({push, listStore}) => () => {
42
+ const items = listStore();
43
+
44
+ for (const [initPath] of items) {
45
+ for (const [currentPath, expandPath] of items) {
46
+ const objectPath = initPath.get('object');
47
+
48
+ if (!objectPath.isMemberExpression() && !objectPath.isCallExpression())
49
+ continue;
50
+
51
+ const propertyPath = initPath.get('property');
52
+ const property = propertyPath.node;
53
+
54
+ const current = currentPath.node;
55
+ const {object} = initPath.node;
56
+ const {name} = property;
57
+
58
+ if (expandPath.scope.bindings[name])
59
+ continue;
60
+
61
+ if (expandPath.scope.uid !== initPath.scope.uid)
62
+ continue;
63
+
64
+ if (compare(object, current))
65
+ push({
66
+ expandPath,
67
+ path: initPath,
68
+ property,
69
+ });
70
+ }
71
+ }
72
+ };
package/lib/index.js CHANGED
@@ -1,8 +1,11 @@
1
- import * as convertObjectToArray from './convert-object-to-array/index.js';
2
1
  import * as applyObject from './apply-object/index.js';
3
2
  import * as applyArray from './apply-array/index.js';
3
+ import * as extractPropertiesEqualDeep from './extract-properties-equal-deep/index.js';
4
+ import * as extractPropertiesNotEqualDeep from './extract-properties-not-equal-deep/index.js';
5
+ import * as convertObjectToArray from './convert-object-to-array/index.js';
4
6
  import * as removeUselessObject from './remove-useless-object/index.js';
5
7
  import * as removeUselessArguments from './remove-useless-arguments/index.js';
8
+ import * as removeUselessVariables from './remove-useless-variables/index.js';
6
9
  import * as splitNested from './split-nested/index.js';
7
10
  import * as splitCall from './split-call/index.js';
8
11
  import * as mergeProperties from './merge-properties/index.js';
@@ -10,9 +13,12 @@ import * as mergeProperties from './merge-properties/index.js';
10
13
  export const rules = {
11
14
  'apply-object': applyObject,
12
15
  'apply-array': applyArray,
16
+ 'convert-object-to-array': convertObjectToArray,
17
+ 'extract-properties-equal-deep': extractPropertiesEqualDeep,
18
+ 'extract-properties-not-equal-deep': extractPropertiesNotEqualDeep,
13
19
  'remove-useless-object': removeUselessObject,
14
20
  'remove-useless-arguments': removeUselessArguments,
15
- 'convert-object-to-array': convertObjectToArray,
21
+ 'remove-useless-variables': removeUselessVariables,
16
22
  'split-nested': splitNested,
17
23
  'split-call': splitCall,
18
24
  'merge-properties': mergeProperties,
@@ -0,0 +1,78 @@
1
+ import {types, operator} from 'putout';
2
+
3
+ const {
4
+ isIdentifier,
5
+ isRestElement,
6
+ isAssignmentPattern,
7
+ } = types;
8
+
9
+ const {replaceWith} = operator;
10
+
11
+ const MAX_LENGTH = 20;
12
+
13
+ const getKeyLength = (a) => {
14
+ const {key, value} = a;
15
+
16
+ if (!isAssignmentPattern(value) && isIdentifier(key))
17
+ return a.key.name.length;
18
+
19
+ if (isRestElement(a) && isIdentifier(a.argument))
20
+ return a.argument.name.length + 3;
21
+
22
+ return MAX_LENGTH;
23
+ };
24
+
25
+ const sum = (a, b) => a + getKeyLength(b);
26
+
27
+ export const report = (path) => {
28
+ return `Avoid useless variable '${path.node.declarations[0].init.name}'`;
29
+ };
30
+
31
+ export const match = () => ({
32
+ 'const __object = __a': ({__a, __object}, path) => {
33
+ const {parentPath} = path.parentPath;
34
+
35
+ if (!parentPath)
36
+ return false;
37
+
38
+ if (!parentPath.isFunction())
39
+ return false;
40
+
41
+ if (path.node !== parentPath.node.body.body[0])
42
+ return false;
43
+
44
+ const {params} = parentPath.node;
45
+
46
+ if (params.length !== 1)
47
+ return false;
48
+
49
+ const [first] = params;
50
+
51
+ if (__object.properties.length > 3)
52
+ return false;
53
+
54
+ if (!isIdentifier(first))
55
+ return false;
56
+
57
+ if (__a.name !== first.name)
58
+ return false;
59
+
60
+ const binding = path.scope.bindings[first.name];
61
+
62
+ if (binding.path.node.typeAnnotation)
63
+ return false;
64
+
65
+ if (binding.references > 1)
66
+ return false;
67
+
68
+ const namesLength = __object.properties.reduce(sum, 0);
69
+
70
+ return namesLength < MAX_LENGTH;
71
+ },
72
+ });
73
+
74
+ export const replace = () => ({
75
+ 'const __object = __a': ({__object}, path) => {
76
+ replaceWith(path.parentPath.parentPath.get('params.0'), __object);
77
+ },
78
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/plugin-destructuring",
3
- "version": "1.1.0",
3
+ "version": "1.3.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 transform destructuring",
@@ -39,6 +39,7 @@
39
39
  "@putout/plugin-printer": "*",
40
40
  "@putout/plugin-putout": "*",
41
41
  "@putout/plugin-tape": "*",
42
+ "@putout/plugin-variables": "*",
42
43
  "@putout/test": "^14.0.0",
43
44
  "c8": "^10.0.0",
44
45
  "eslint": "v10.0.0-alpha.0",