Skip to content

Commit 6cf3638

Browse files
committed
feature: @putout/operate: addParens, removeParens: add
1 parent 4f41b2f commit 6cf3638

File tree

7 files changed

+225
-17
lines changed

7 files changed

+225
-17
lines changed

packages/operate/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,28 @@ const object = template.ast('x({"a": "b"})');
254254
const [propertyPath] = traverseProperties(object, 'a');
255255
```
256256

257+
### `addParens(path: Path)`
258+
259+
Add parens around expression depending on used `printer`:
260+
261+
- ✅ set `node.extra.parenthesized: true` when `@putout/printer` used;
262+
- ✅ set add `ParenthesizedExpression` or `TSParenthesizedType` when `babel` used;
263+
264+
```js
265+
addParens(path);
266+
```
267+
268+
### `removeParens(path: Path)`
269+
270+
Remove parens around expression depending on used `printer`:
271+
272+
- ✅ set `node.extra.parenthesized: false` when `@putout/printer` used;
273+
- ✅ remove `ParenthesizedExpression` or `TSParenthesizedType` when `babel` used;
274+
275+
```js
276+
removeParens(path);
277+
```
278+
257279
## License
258280

259281
MIT

packages/operate/lib/operate.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const {rename} = require('./rename');
1212
const {renameProperty} = require('./rename-property');
1313
const {setLiteralValue} = require('./set-literal-value');
1414
const {getPathAfterRequires} = require('./get-path-after-requires');
15+
const {addParens, removeParens} = require('./parens');
1516

1617
const {
1718
getProperty,
@@ -48,6 +49,9 @@ module.exports.rename = rename;
4849
module.exports.renameProperty = renameProperty;
4950
module.exports.setLiteralValue = setLiteralValue;
5051

52+
module.exports.addParens = addParens;
53+
module.exports.removeParens = removeParens;
54+
5155
module.exports.getProperty = getProperty;
5256
module.exports.getProperties = getProperties;
5357
module.exports.traverseProperties = traverseProperties;

packages/operate/lib/parens.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
const {types} = require('@putout/babel');
4+
const {
5+
ParenthesizedExpression,
6+
TSParenthesizedType,
7+
} = types;
8+
9+
module.exports.addParens = (path) => {
10+
const printer = getPrinter(path);
11+
12+
if (printer !== 'babel') {
13+
const {extra = {}} = path.node;
14+
15+
extra.parenthesized = true;
16+
path.node.extra = extra;
17+
18+
return;
19+
}
20+
21+
const {node} = path;
22+
23+
if (path.type.startsWith('TS'))
24+
return path.replaceWith(TSParenthesizedType(node));
25+
26+
path.replaceWith(ParenthesizedExpression(node));
27+
};
28+
29+
module.exports.removeParens = (path) => {
30+
const printer = getPrinter(path);
31+
32+
if (printer !== 'babel')
33+
return path.node.extra.parenthesized = false;
34+
35+
const {node} = path;
36+
path.parentPath.replaceWith(node);
37+
};
38+
39+
function getPrinter(path) {
40+
const scope = path.scope.getProgramParent();
41+
const programPath = scope.path;
42+
43+
return programPath.node.extra.__putout_printer;
44+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
'use strict';
2+
3+
const test = require('supertape');
4+
5+
const {
6+
parse,
7+
print,
8+
traverse,
9+
} = require('putout');
10+
11+
const {addParens, removeParens} = require('./parens');
12+
13+
test('putout: operate: parens: removeParens: putout', (t) => {
14+
const source = '(b = 3)';
15+
const ast = parse(source);
16+
17+
traverse(ast, {
18+
AssignmentExpression: removeParens,
19+
});
20+
21+
const result = print(ast);
22+
const expected = 'b = 3;\n';
23+
24+
t.equal(result, expected);
25+
t.end();
26+
});
27+
28+
test('putout: operate: parens: removeParens: babel', (t) => {
29+
const source = '(b = 3)';
30+
const ast = parse(source, {
31+
printer: 'babel',
32+
});
33+
34+
traverse(ast, {
35+
AssignmentExpression(path) {
36+
removeParens(path);
37+
path.stop();
38+
},
39+
});
40+
41+
const result = print(ast, {
42+
printer: 'babel',
43+
});
44+
45+
const expected = 'b = 3;\n';
46+
47+
t.equal(result, expected);
48+
t.end();
49+
});
50+
51+
test('putout: operate: parens: addParens', (t) => {
52+
const source = 'const b = a';
53+
const ast = parse(source);
54+
55+
traverse(ast, {
56+
VariableDeclarator(path) {
57+
addParens(path.get('init'));
58+
path.stop();
59+
},
60+
});
61+
62+
const result = print(ast);
63+
const expected = 'const b = (a);\n';
64+
65+
t.equal(result, expected);
66+
t.end();
67+
});
68+
69+
test('putout: operate: parens: addParens: babel', (t) => {
70+
const source = 'b = 3';
71+
const ast = parse(source, {
72+
printer: 'babel',
73+
});
74+
75+
traverse(ast, {
76+
AssignmentExpression(path) {
77+
addParens(path);
78+
path.stop();
79+
},
80+
});
81+
82+
const result = print(ast, {
83+
printer: 'babel',
84+
});
85+
86+
const expected = '(b = 3);\n';
87+
88+
t.equal(result, expected);
89+
t.end();
90+
});
91+
92+
test('putout: operate: parens: addParens: babel: ts', (t) => {
93+
const source = 'const a: boolean = true;';
94+
const ast = parse(source, {
95+
printer: 'babel',
96+
isTS: true,
97+
});
98+
99+
traverse(ast, {
100+
TSBooleanKeyword(path) {
101+
addParens(path);
102+
path.stop();
103+
},
104+
});
105+
106+
const result = print(ast, {
107+
printer: 'babel',
108+
});
109+
110+
const expected = 'const a: (boolean) = true;\n';
111+
112+
t.equal(result, expected);
113+
t.end();
114+
});

packages/operate/lib/properties/traverse-properties.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,14 @@
33
const {traverse, types} = require('@putout/babel');
44
const {extract} = require('../extract');
55

6-
const {
7-
isObjectExpression,
8-
isCallExpression,
9-
} = types;
6+
const {isObjectExpression} = types;
107

118
const nodeOrPath = (path) => path.node || path;
129

1310
function getNode(path) {
1411
if (!isObjectExpression(path))
1512
return nodeOrPath(path);
1613

17-
if (isCallExpression(path.parentPath))
18-
return path.parentPath.node;
19-
2014
return {
2115
type: 'ExpressionStatement',
2216
expression: nodeOrPath(path),

packages/operate/lib/replace-with/replace-with.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,8 @@
33
const {maybeBody} = require('./maybe-body');
44
const {assign} = Object;
55

6-
const parseNode = (a) => {
7-
a = extractMark(a);
8-
9-
if (a.node)
10-
return a.node;
11-
12-
return a;
13-
};
14-
156
module.exports.replaceWith = (path, node) => {
16-
node = parseNode(node);
7+
node = extractMark(node);
178

189
if (path?.parentPath?.isExpressionStatement() && !path.parentPath.isProgram()) {
1910
addMark(path, node);

packages/operate/test/operate.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,3 +1053,42 @@ test('putout: operate: getLiteralRaw', (t) => {
10531053
t.equal(result, raw);
10541054
t.end();
10551055
});
1056+
1057+
test('putout: operate: addParens', (t) => {
1058+
const source = 'const a: boolean = true;';
1059+
const ast = parse(source, {
1060+
printer: 'babel',
1061+
isTS: true,
1062+
});
1063+
1064+
traverse(ast, {
1065+
TSBooleanKeyword(path) {
1066+
operate.addParens(path);
1067+
path.stop();
1068+
},
1069+
});
1070+
1071+
const result = print(ast, {
1072+
printer: 'babel',
1073+
});
1074+
1075+
const expected = 'const a: (boolean) = true;\n';
1076+
1077+
t.equal(result, expected);
1078+
t.end();
1079+
});
1080+
1081+
test('putout: operate: removeParens', (t) => {
1082+
const source = '(b = 3)';
1083+
const ast = parse(source);
1084+
1085+
traverse(ast, {
1086+
AssignmentExpression: operate.removeParens,
1087+
});
1088+
1089+
const result = print(ast);
1090+
const expected = 'b = 3;\n';
1091+
1092+
t.equal(result, expected);
1093+
t.end();
1094+
});

0 commit comments

Comments
 (0)