@putout/printer 2.55.0 → 2.57.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/ChangeLog +13 -0
- package/README.md +21 -14
- package/lib/tokenize/comments/comments.js +6 -122
- package/lib/tokenize/comments/maybe-inside-fn.js +13 -0
- package/lib/tokenize/comments/parse-comments.js +28 -0
- package/lib/tokenize/comments/parse-leading-comments.js +61 -0
- package/lib/tokenize/comments/parse-trailing-comments.js +40 -0
- package/lib/tokenize/literals/index.js +2 -1
- package/lib/tokenize/statements/block-statement/block-statement.js +1 -4
- package/lib/tokenize/statements/block-statement/get-directives.js +3 -0
- package/lib/tokenize/statements/index.js +1 -1
- package/lib/tokenize/statements/program/program.js +26 -0
- package/package.json +1 -1
- package/lib/tokenize/statements/program.js +0 -14
package/ChangeLog
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
2023.07.08, v2.57.0
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- 0e980f4 @putout/printer: ObjectProperty: improve support of multiline comments
|
|
5
|
+
|
|
6
|
+
2023.07.08, v2.56.0
|
|
7
|
+
|
|
8
|
+
feature:
|
|
9
|
+
- 90bd7fb @putout/printer: comments: after directive
|
|
10
|
+
- ec4bebd @putout/printer: program
|
|
11
|
+
- e95e634 @putout/printer: comments: directives
|
|
12
|
+
- 7ecc615 @putout/printer: comments
|
|
13
|
+
|
|
1
14
|
2023.07.07, v2.55.0
|
|
2
15
|
|
|
3
16
|
feature:
|
package/README.md
CHANGED
|
@@ -41,14 +41,14 @@ And update `.putout.json`:
|
|
|
41
41
|
|
|
42
42
|
To benefit from it.
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Example
|
|
45
45
|
|
|
46
46
|
```js
|
|
47
47
|
const {print} = require('@putout/printer');
|
|
48
48
|
const {parse} = require('@babel/parser');
|
|
49
49
|
const ast = parse('const a = (b, c) => {const d = 5; return a;}');
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
print(ast);
|
|
52
52
|
// returns
|
|
53
53
|
`
|
|
54
54
|
const a = (b, c) => {
|
|
@@ -90,9 +90,9 @@ print(ast, {
|
|
|
90
90
|
maxPropertiesInOneLine: 2,
|
|
91
91
|
},
|
|
92
92
|
visitors: {
|
|
93
|
-
AssignmentPattern(path, {
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
AssignmentPattern(path, {print}) {
|
|
94
|
+
print('/* [hello world] */= ');
|
|
95
|
+
print('__right');
|
|
96
96
|
},
|
|
97
97
|
},
|
|
98
98
|
});
|
|
@@ -157,11 +157,17 @@ if(a>3)console.log('ok');else console.log('not ok');
|
|
|
157
157
|
|
|
158
158
|
Options used to configure logic of output, similar to ESLint rules:
|
|
159
159
|
|
|
160
|
-
- `maxElementsInOneLine` - count of `ArrayExpression` and `ArrayPattern` elements placed in one line.
|
|
160
|
+
- ✅ `maxElementsInOneLine` - count of `ArrayExpression` and `ArrayPattern` elements placed in one line.
|
|
161
|
+
- ✅ `maxVariablesInOneLine` - count of `VariableDeclarators` in one line.
|
|
162
|
+
- ✅ `maxPropertiesInOneLine` - count of `ObjectProperties` in one line.
|
|
161
163
|
|
|
162
|
-
|
|
164
|
+
## Visitors API
|
|
165
|
+
|
|
166
|
+
When you want to improve support of existing visitor or extend **Printer** with a new ones, you need next base operations:
|
|
163
167
|
|
|
164
|
-
|
|
168
|
+
### `print`
|
|
169
|
+
|
|
170
|
+
Used in previous example `print` can be used for a couple purposes:
|
|
165
171
|
|
|
166
172
|
- to write `string`;
|
|
167
173
|
- to write `node` when `object` passed;
|
|
@@ -170,10 +176,10 @@ Used in previous example `write` can be used for a couple purposes:
|
|
|
170
176
|
```js
|
|
171
177
|
print(ast, {
|
|
172
178
|
visitors: {
|
|
173
|
-
AssignmentPattern(path, {
|
|
179
|
+
AssignmentPattern(path, {print, maybe}) {
|
|
174
180
|
maybe.write.newline(path.parentPath.isCallExpression());
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
print('/* [hello world] */= ');
|
|
182
|
+
print('__right');
|
|
177
183
|
},
|
|
178
184
|
},
|
|
179
185
|
});
|
|
@@ -198,7 +204,7 @@ print(ast, {
|
|
|
198
204
|
|
|
199
205
|
### `write`
|
|
200
206
|
|
|
201
|
-
When
|
|
207
|
+
When you going to output string you can use low-level function `write`:
|
|
202
208
|
|
|
203
209
|
```js
|
|
204
210
|
print(ast, {
|
|
@@ -232,7 +238,7 @@ print(ast, {
|
|
|
232
238
|
|
|
233
239
|
### `traverse`
|
|
234
240
|
|
|
235
|
-
When
|
|
241
|
+
When you need to traverse node path, you can use `traverse`:
|
|
236
242
|
|
|
237
243
|
```js
|
|
238
244
|
print(ast, {
|
|
@@ -251,8 +257,9 @@ This is the same as `write('__left')` but more low-level, and supports only obje
|
|
|
251
257
|
About speed, for file `speed.js`:
|
|
252
258
|
|
|
253
259
|
```js
|
|
254
|
-
const putout = require('putout');
|
|
255
260
|
const {readFileSync} = require('fs');
|
|
261
|
+
|
|
262
|
+
const putout = require('putout');
|
|
256
263
|
const parser = require('@babel/parser');
|
|
257
264
|
|
|
258
265
|
const code = readFileSync('./lib/tokenize/tokenize.js', 'utf8');
|
|
@@ -1,126 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} = require('../is');
|
|
3
|
+
const {parseLeadingComments} = require('./parse-leading-comments');
|
|
4
|
+
const {parseTrailingComments} = require('./parse-trailing-comments');
|
|
5
|
+
const {parseComments} = require('./parse-comments');
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
module.exports.parseLeadingComments = parseLeadingComments;
|
|
8
|
+
module.exports.parseTrailingComments = parseTrailingComments;
|
|
9
|
+
module.exports.parseComments = parseComments;
|
|
10
10
|
|
|
11
|
-
module.exports.parseLeadingComments = (path, {print, maybe, indent}, semantics) => {
|
|
12
|
-
if (!semantics.comments)
|
|
13
|
-
return;
|
|
14
|
-
|
|
15
|
-
const {leadingComments} = path.node;
|
|
16
|
-
|
|
17
|
-
if (!leadingComments?.length)
|
|
18
|
-
return;
|
|
19
|
-
|
|
20
|
-
if (hasTrailingComment(path.getPrevSibling()))
|
|
21
|
-
return;
|
|
22
|
-
|
|
23
|
-
const insideFn = path.parentPath.isFunction();
|
|
24
|
-
const isProperty = path.isObjectProperty() || isVariableDeclarator(path);
|
|
25
|
-
const isIndent = !path.isClassMethod() && !insideFn && !isProperty;
|
|
26
|
-
|
|
27
|
-
for (const {type, value} of leadingComments) {
|
|
28
|
-
maybe.indent(isIndent);
|
|
29
|
-
|
|
30
|
-
if (type === 'CommentLine') {
|
|
31
|
-
maybeInsideFn(insideFn, {
|
|
32
|
-
print,
|
|
33
|
-
indent,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
maybe.print.space(isProperty);
|
|
37
|
-
print(`//${value}`);
|
|
38
|
-
|
|
39
|
-
maybe.print.breakline(isProperty);
|
|
40
|
-
maybe.print.newline(!isProperty);
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (type === 'CommentBlock') {
|
|
45
|
-
print(`/*${value}*/`);
|
|
46
|
-
|
|
47
|
-
if (path.isStatement() || path.isClassMethod()) {
|
|
48
|
-
print.newline();
|
|
49
|
-
markBefore(path);
|
|
50
|
-
maybe.indent(path.isClassMethod());
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
module.exports.parseTrailingComments = (path, {write, maybe}, semantics) => {
|
|
59
|
-
if (!semantics.comments)
|
|
60
|
-
return;
|
|
61
|
-
|
|
62
|
-
const {trailingComments} = path.node;
|
|
63
|
-
|
|
64
|
-
if (!trailingComments?.length)
|
|
65
|
-
return;
|
|
66
|
-
|
|
67
|
-
for (const {type, value, loc} of trailingComments) {
|
|
68
|
-
const sameLine = isSameLine(path, loc);
|
|
69
|
-
|
|
70
|
-
if (type === 'CommentLine') {
|
|
71
|
-
maybe.write.space(sameLine);
|
|
72
|
-
maybe.indent(!sameLine);
|
|
73
|
-
|
|
74
|
-
write(`//${value}`);
|
|
75
|
-
maybe.write.newline(!isLast(path));
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (type === 'CommentBlock') {
|
|
80
|
-
maybe.write.space(sameLine);
|
|
81
|
-
write(`/*${value}*/`);
|
|
82
|
-
maybe.write.newline(!sameLine);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
module.exports.parseComments = (path, {write}, semantics) => {
|
|
88
|
-
if (!semantics.comments)
|
|
89
|
-
return;
|
|
90
|
-
|
|
91
|
-
const comments = path.node.comments || path.node.innerComments;
|
|
92
|
-
|
|
93
|
-
if (!comments)
|
|
94
|
-
return;
|
|
95
|
-
|
|
96
|
-
for (const {type, value} of comments) {
|
|
97
|
-
if (type === 'CommentLine') {
|
|
98
|
-
write.breakline();
|
|
99
|
-
write('//');
|
|
100
|
-
write(value);
|
|
101
|
-
write.newline();
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (type === 'CommentBlock') {
|
|
106
|
-
write('/*');
|
|
107
|
-
write(value);
|
|
108
|
-
write('*/');
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
function isSameLine(path, loc) {
|
|
114
|
-
return path.node.loc?.start.line === loc.start.line || path.node.loc?.end.line === loc.end.line;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function maybeInsideFn(insideFn, {print, indent}) {
|
|
118
|
-
if (!insideFn)
|
|
119
|
-
return;
|
|
120
|
-
|
|
121
|
-
indent.inc();
|
|
122
|
-
indent.inc();
|
|
123
|
-
print.breakline();
|
|
124
|
-
indent.dec();
|
|
125
|
-
indent.dec();
|
|
126
|
-
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports.parseComments = (path, {write}, semantics) => {
|
|
4
|
+
if (!semantics.comments)
|
|
5
|
+
return;
|
|
6
|
+
|
|
7
|
+
const comments = path.node.comments || path.node.innerComments;
|
|
8
|
+
|
|
9
|
+
if (!comments)
|
|
10
|
+
return;
|
|
11
|
+
|
|
12
|
+
for (const {type, value} of comments) {
|
|
13
|
+
if (type === 'CommentLine') {
|
|
14
|
+
write.breakline();
|
|
15
|
+
write('//');
|
|
16
|
+
write(value);
|
|
17
|
+
write.newline();
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (type === 'CommentBlock') {
|
|
22
|
+
write('/*');
|
|
23
|
+
write(value);
|
|
24
|
+
write('*/');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {hasTrailingComment} = require('../is');
|
|
4
|
+
const {isVariableDeclarator} = require('@babel/types');
|
|
5
|
+
const {markBefore} = require('../mark');
|
|
6
|
+
const {maybeInsideFn} = require('./maybe-inside-fn');
|
|
7
|
+
|
|
8
|
+
module.exports.parseLeadingComments = (path, {print, maybe, indent}, semantics) => {
|
|
9
|
+
if (!semantics.comments)
|
|
10
|
+
return;
|
|
11
|
+
|
|
12
|
+
const {leadingComments} = path.node;
|
|
13
|
+
|
|
14
|
+
if (!leadingComments?.length)
|
|
15
|
+
return;
|
|
16
|
+
|
|
17
|
+
if (hasTrailingComment(path.getPrevSibling()))
|
|
18
|
+
return;
|
|
19
|
+
|
|
20
|
+
const insideFn = path.parentPath.isFunction();
|
|
21
|
+
const isProperty = path.isObjectProperty() || isVariableDeclarator(path);
|
|
22
|
+
const isIndent = !path.isClassMethod() && !insideFn && !isProperty;
|
|
23
|
+
|
|
24
|
+
for (const {type, value} of leadingComments) {
|
|
25
|
+
maybe.indent(isIndent);
|
|
26
|
+
|
|
27
|
+
if (type === 'CommentLine') {
|
|
28
|
+
maybeInsideFn(insideFn, {
|
|
29
|
+
print,
|
|
30
|
+
indent,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
maybe.print.space(isProperty);
|
|
34
|
+
print(`//${value}`);
|
|
35
|
+
|
|
36
|
+
maybe.print.breakline(isProperty);
|
|
37
|
+
maybe.print.newline(!isProperty);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (type === 'CommentBlock') {
|
|
42
|
+
const looksLikeMethod = path.isClassMethod();
|
|
43
|
+
const looksLikeDirective = path.isDirective();
|
|
44
|
+
const looksLikeProp = path.isObjectProperty();
|
|
45
|
+
|
|
46
|
+
if (looksLikeProp)
|
|
47
|
+
print.breakline();
|
|
48
|
+
|
|
49
|
+
print(`/*${value}*/`);
|
|
50
|
+
|
|
51
|
+
if (path.isStatement() || looksLikeDirective || looksLikeMethod || looksLikeProp) {
|
|
52
|
+
print.newline();
|
|
53
|
+
markBefore(path);
|
|
54
|
+
maybe.indent(looksLikeMethod || looksLikeProp);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {isLast} = require('../is');
|
|
4
|
+
|
|
5
|
+
function isSameLine(path, loc) {
|
|
6
|
+
return path.node.loc?.start.line === loc.start.line || path.node.loc?.end.line === loc.end.line;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports.parseTrailingComments = (path, {write, maybe}, semantics) => {
|
|
10
|
+
if (!semantics.comments)
|
|
11
|
+
return;
|
|
12
|
+
|
|
13
|
+
const {trailingComments} = path.node;
|
|
14
|
+
|
|
15
|
+
if (!trailingComments?.length)
|
|
16
|
+
return;
|
|
17
|
+
|
|
18
|
+
if (path.isDirective())
|
|
19
|
+
return;
|
|
20
|
+
|
|
21
|
+
for (const {type, value, loc} of trailingComments) {
|
|
22
|
+
const sameLine = isSameLine(path, loc);
|
|
23
|
+
|
|
24
|
+
if (type === 'CommentLine') {
|
|
25
|
+
maybe.write.space(sameLine);
|
|
26
|
+
maybe.indent(!sameLine);
|
|
27
|
+
|
|
28
|
+
write(`//${value}`);
|
|
29
|
+
maybe.write.newline(!isLast(path));
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (type === 'CommentBlock') {
|
|
34
|
+
maybe.write.space(sameLine);
|
|
35
|
+
write(`/*${value}*/`);
|
|
36
|
+
maybe.write.newline(!sameLine);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
@@ -15,15 +15,12 @@ const {
|
|
|
15
15
|
const {markAfter} = require('../../mark');
|
|
16
16
|
const {parseComments} = require('../../comments/comments');
|
|
17
17
|
const {insideIfWithNoBody} = require('./inside-if-with-no-body');
|
|
18
|
+
const {getDirectives} = require('./get-directives');
|
|
18
19
|
|
|
19
20
|
const isFirstStatement = (path) => path.node.body[0];
|
|
20
21
|
const isFirstDirective = (path) => path.node.directives?.[0];
|
|
21
22
|
const isMethodOrArrow = (path) => isArrowFunctionExpression(path) || isObjectMethod(path);
|
|
22
23
|
|
|
23
|
-
const getDirectives = (path) => !path.node.directives ? [] : path.get('directives');
|
|
24
|
-
|
|
25
|
-
module.exports._getDirectives = getDirectives;
|
|
26
|
-
|
|
27
24
|
module.exports.BlockStatement = {
|
|
28
25
|
print(path, {indent, maybe, write, traverse}, semantics) {
|
|
29
26
|
const body = path.get('body');
|
|
@@ -19,7 +19,7 @@ const {ForInStatement} = require('./for-in-statement');
|
|
|
19
19
|
const {ExportDefaultDeclaration} = require('./export-declaration/export-default-declaration');
|
|
20
20
|
const {BreakStatement} = require('./break-statement');
|
|
21
21
|
const {DoWhileStatement} = require('./do-while-statement');
|
|
22
|
-
const {Program} = require('./program');
|
|
22
|
+
const {Program} = require('./program/program');
|
|
23
23
|
|
|
24
24
|
const {
|
|
25
25
|
ExportNamespaceSpecifier,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {parseComments} = require('../../comments/comments');
|
|
4
|
+
const {getDirectives} = require('../block-statement/get-directives');
|
|
5
|
+
|
|
6
|
+
module.exports.Program = (path, {print, write, traverse, maybe}, semantics) => {
|
|
7
|
+
const {body} = path.node;
|
|
8
|
+
print('__interpreter');
|
|
9
|
+
parseComments(path, {write}, semantics);
|
|
10
|
+
|
|
11
|
+
const directives = getDirectives(path);
|
|
12
|
+
|
|
13
|
+
for (const directive of directives) {
|
|
14
|
+
traverse(directive);
|
|
15
|
+
maybe.print.newline(body.length);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
path
|
|
19
|
+
.get('body')
|
|
20
|
+
.forEach(print);
|
|
21
|
+
|
|
22
|
+
if (directives.length && !body.length)
|
|
23
|
+
return;
|
|
24
|
+
|
|
25
|
+
print.newline();
|
|
26
|
+
};
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const {parseComments} = require('../comments/comments');
|
|
4
|
-
|
|
5
|
-
module.exports.Program = (path, {print, write}, semantics) => {
|
|
6
|
-
print('__interpreter');
|
|
7
|
-
parseComments(path, {write}, semantics);
|
|
8
|
-
|
|
9
|
-
path
|
|
10
|
-
.get('body')
|
|
11
|
-
.forEach(print);
|
|
12
|
-
|
|
13
|
-
print.newline();
|
|
14
|
-
};
|