@putout/printer 18.7.8 → 18.8.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 +12 -0
- package/lib/tokenize/expressions/array-expression/after-if.js +0 -2
- package/lib/tokenize/expressions/array-expression/before-if.js +1 -7
- package/lib/tokenize/expressions/array-expression/indent.js +0 -1
- package/lib/tokenize/expressions/array-expression/newline.js +62 -32
- package/lib/tokenize/expressions/member-expression/is-looks-like-chain/index.js +5 -21
- package/lib/tokenize/expressions/object-pattern/comma.js +27 -0
- package/lib/tokenize/expressions/object-pattern/is.js +12 -37
- package/lib/tokenize/expressions/object-pattern/object-pattern.js +2 -11
- package/lib/tokenize/is.js +21 -0
- package/lib/tokenize/overrides/overrides.js +1 -1
- package/package.json +1 -1
package/ChangeLog
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
2026.03.18, v18.8.0
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- cc719056 @putout/printer: ArrayExpression: newline
|
|
5
|
+
- 53cdda91 @putout/printer: maxElementsInOneLine: 3
|
|
6
|
+
- e5d67901 @putout/printer: ObjectPattern: isPrevAssignObject: simplify
|
|
7
|
+
|
|
8
|
+
2026.03.18, v18.7.9
|
|
9
|
+
|
|
10
|
+
feature:
|
|
11
|
+
- 3e47d13f @putout/printer: ObjectPattern: comma: simplify
|
|
12
|
+
|
|
1
13
|
2026.03.18, v18.7.8
|
|
2
14
|
|
|
3
15
|
feature:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isCoupleLines,
|
|
3
3
|
isIdentifierAndIdentifier,
|
|
4
|
-
isStringAndIdentifier,
|
|
5
4
|
} from '#is';
|
|
6
5
|
import {createTypeChecker} from '#type-checker';
|
|
7
6
|
import {isInsideOneElementArray} from './before-if.js';
|
|
@@ -10,6 +9,5 @@ export const afterIf = createTypeChecker([
|
|
|
10
9
|
['-: parentPath -> !ArrayExpression'],
|
|
11
10
|
['-: parentPath ->', isCoupleLines],
|
|
12
11
|
['+', isIdentifierAndIdentifier],
|
|
13
|
-
['-: -> !', isStringAndIdentifier],
|
|
14
12
|
['+', isInsideOneElementArray],
|
|
15
13
|
]);
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
isCoupleLines,
|
|
4
4
|
isIdentifierAndIdentifier,
|
|
5
5
|
isInsideArray,
|
|
6
|
-
isStringAndIdentifier,
|
|
7
6
|
} from '#is';
|
|
8
7
|
|
|
9
8
|
export const isInsideOneElementArray = ({parentPath}) => {
|
|
@@ -11,14 +10,9 @@ export const isInsideOneElementArray = ({parentPath}) => {
|
|
|
11
10
|
return elements.length === 1;
|
|
12
11
|
};
|
|
13
12
|
|
|
14
|
-
const isStringAndIdentifierInsideOneElementArray = createTypeChecker([
|
|
15
|
-
['-: -> !', isStringAndIdentifier],
|
|
16
|
-
['+', isInsideOneElementArray],
|
|
17
|
-
]);
|
|
18
|
-
|
|
19
13
|
export const beforeIf = createTypeChecker([
|
|
20
14
|
['-: -> !', isInsideArray],
|
|
21
15
|
['-: parentPath ->', isCoupleLines],
|
|
22
16
|
['+', isIdentifierAndIdentifier],
|
|
23
|
-
['+',
|
|
17
|
+
['+', isInsideOneElementArray],
|
|
24
18
|
]);
|
|
@@ -109,7 +109,6 @@ const isLastElementObjectExpression = ({node}) => isObjectExpression(node.elemen
|
|
|
109
109
|
export const isSecondIndent = createTypeChecker([
|
|
110
110
|
['-: -> !', isMultilineOption],
|
|
111
111
|
['+', isNeedsToHideIndentOption],
|
|
112
|
-
['-: ->', isArrayInsideArray],
|
|
113
112
|
['+: -> !', isLastElementObjectExpression],
|
|
114
113
|
]);
|
|
115
114
|
|
|
@@ -15,6 +15,20 @@ import {
|
|
|
15
15
|
import {isIncreaseIndent} from './indent.js';
|
|
16
16
|
import {isMultilineOption} from './is.js';
|
|
17
17
|
|
|
18
|
+
const {
|
|
19
|
+
isObjectExpression,
|
|
20
|
+
isObjectProperty,
|
|
21
|
+
isCallExpression,
|
|
22
|
+
isAwaitExpression,
|
|
23
|
+
isBooleanLiteral,
|
|
24
|
+
isNullLiteral,
|
|
25
|
+
isStringLiteral,
|
|
26
|
+
isSpreadElement,
|
|
27
|
+
isIdentifier,
|
|
28
|
+
isNumericLiteral,
|
|
29
|
+
isArrayExpression,
|
|
30
|
+
} = types;
|
|
31
|
+
|
|
18
32
|
const isParentProperty = (path) => path.find(isObjectProperty);
|
|
19
33
|
|
|
20
34
|
const isNumbersArray = createTypeChecker([
|
|
@@ -70,19 +84,6 @@ const isShortTwoSimplesInsideCall = (path, {maxElementsInOneLine}) => {
|
|
|
70
84
|
return length < maxElementsInOneLine;
|
|
71
85
|
};
|
|
72
86
|
|
|
73
|
-
const {
|
|
74
|
-
isObjectExpression,
|
|
75
|
-
isObjectProperty,
|
|
76
|
-
isCallExpression,
|
|
77
|
-
isAwaitExpression,
|
|
78
|
-
isBooleanLiteral,
|
|
79
|
-
isNullLiteral,
|
|
80
|
-
isStringLiteral,
|
|
81
|
-
isSpreadElement,
|
|
82
|
-
isIdentifier,
|
|
83
|
-
isNumericLiteral,
|
|
84
|
-
} = types;
|
|
85
|
-
|
|
86
87
|
const {round} = Math;
|
|
87
88
|
|
|
88
89
|
const isOneSpread = (path) => {
|
|
@@ -138,12 +139,13 @@ const isSiblingIsArray = (path) => {
|
|
|
138
139
|
|
|
139
140
|
const isMoreThenMaxLiteralLength = (path, {maxElementLengthInOneLine}) => {
|
|
140
141
|
const {elements} = path.node;
|
|
141
|
-
const [first] = elements;
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
for (const element of elements.filter(isStringLiteral)) {
|
|
144
|
+
if (element.value.length >= maxElementLengthInOneLine)
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
145
147
|
|
|
146
|
-
return
|
|
148
|
+
return false;
|
|
147
149
|
};
|
|
148
150
|
|
|
149
151
|
const isMoreThenMaxIdentifierLength = (path, {maxElementLengthInOneLine}) => {
|
|
@@ -197,8 +199,49 @@ const isBodyWithOneElement = createTypeChecker([
|
|
|
197
199
|
['+', isBody],
|
|
198
200
|
]);
|
|
199
201
|
|
|
202
|
+
const isLengthLessTheMax = (length, {maxElementsInOneLine}) => length <= maxElementsInOneLine;
|
|
203
|
+
|
|
204
|
+
const isAllStrings = (path) => {
|
|
205
|
+
const {elements} = path.node;
|
|
206
|
+
const {length} = elements.filter(isStringLiteral);
|
|
207
|
+
|
|
208
|
+
return elements.length === length;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const isTupleInsideArray = createTypeChecker([
|
|
212
|
+
['-: parentPath -> !ArrayExpression'],
|
|
213
|
+
['-: -> !', isAllStrings],
|
|
214
|
+
['-', isMoreThenMaxLiteralLength],
|
|
215
|
+
['+: node.elements.length', isLengthLessTheMax],
|
|
216
|
+
]);
|
|
217
|
+
|
|
218
|
+
const isMixedTuples = (path, {maxElementLengthInOneLine}) => {
|
|
219
|
+
const elements = path.get('elements');
|
|
220
|
+
|
|
221
|
+
const arrayElements = elements.filter(isArrayExpression);
|
|
222
|
+
const {length} = arrayElements;
|
|
223
|
+
|
|
224
|
+
if (!length)
|
|
225
|
+
return false;
|
|
226
|
+
|
|
227
|
+
if (isObjectProperty(path.parentPath))
|
|
228
|
+
return false;
|
|
229
|
+
|
|
230
|
+
for (const arrayElement of arrayElements) {
|
|
231
|
+
if (isMoreThenMaxLiteralLength(arrayElement, {maxElementLengthInOneLine}))
|
|
232
|
+
return false;
|
|
233
|
+
|
|
234
|
+
if (isAllStrings(arrayElement))
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return false;
|
|
239
|
+
};
|
|
240
|
+
|
|
200
241
|
export const isMultiLine = createTypeChecker([
|
|
201
242
|
['-: node.elements.length -> -'],
|
|
243
|
+
['-', isTupleInsideArray],
|
|
244
|
+
['+', isMixedTuples],
|
|
202
245
|
['+', isBodyWithOneElement],
|
|
203
246
|
['+', isMoreThenMaxElementLengthInOneLine],
|
|
204
247
|
['+', isElementsMoreThenMaxWithFirstString],
|
|
@@ -207,7 +250,6 @@ export const isMultiLine = createTypeChecker([
|
|
|
207
250
|
['-', isOneSimple],
|
|
208
251
|
['-', isOneSpread],
|
|
209
252
|
['-', isIdentifierAndIdentifier],
|
|
210
|
-
['-', isCallInsideArrow],
|
|
211
253
|
['-', isIncreaseIndent],
|
|
212
254
|
['-', isInsideLoop],
|
|
213
255
|
['-', isBooleanAndSimple],
|
|
@@ -268,32 +310,20 @@ function isInsideLoop(path) {
|
|
|
268
310
|
return path.parentPath.isForOfStatement();
|
|
269
311
|
}
|
|
270
312
|
|
|
271
|
-
function tooLong(path) {
|
|
313
|
+
function tooLong(path, {maxElementLengthInOneLine}) {
|
|
272
314
|
const elements = path.get('elements');
|
|
273
315
|
|
|
274
316
|
if (elements.length < 2)
|
|
275
317
|
return false;
|
|
276
318
|
|
|
277
319
|
for (const el of path.get('elements')) {
|
|
278
|
-
if (el.isStringLiteral() && el.node.value.length >
|
|
320
|
+
if (el.isStringLiteral() && el.node.value.length > maxElementLengthInOneLine)
|
|
279
321
|
return true;
|
|
280
322
|
}
|
|
281
323
|
|
|
282
324
|
return false;
|
|
283
325
|
}
|
|
284
326
|
|
|
285
|
-
function isCallInsideArrow(path) {
|
|
286
|
-
const {parentPath} = path;
|
|
287
|
-
|
|
288
|
-
if (!parentPath.isCallExpression())
|
|
289
|
-
return false;
|
|
290
|
-
|
|
291
|
-
if (!parentPath.parentPath.isFunction())
|
|
292
|
-
return false;
|
|
293
|
-
|
|
294
|
-
return path.node.elements.length < 4;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
327
|
function isNumbers(elements) {
|
|
298
328
|
for (const element of elements) {
|
|
299
329
|
if (isNumericLiteral(element))
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
import {createTypeChecker} from '#type-checker';
|
|
3
|
+
import {
|
|
4
|
+
isFirstArgOfCall,
|
|
5
|
+
isLastArgInCall,
|
|
6
|
+
} from '#is';
|
|
3
7
|
import {chain} from '../chain.js';
|
|
4
8
|
import {checkCallsCount} from './check-calls-count.js';
|
|
5
9
|
|
|
@@ -18,27 +22,8 @@ const {
|
|
|
18
22
|
isCallExpression,
|
|
19
23
|
} = types;
|
|
20
24
|
|
|
21
|
-
const isPathFirstArg = ({node, parentPath}) => {
|
|
22
|
-
const [first] = parentPath.node.arguments;
|
|
23
|
-
return node === first;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
function isPathLastArg({node, parentPath}) {
|
|
27
|
-
const last = parentPath.node.arguments.at(-1);
|
|
28
|
-
return node === last;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const isFirstArgOfCall = createTypeChecker([
|
|
32
|
-
['-: parentPath -> !CallExpression'],
|
|
33
|
-
['+', isPathFirstArg],
|
|
34
|
-
]);
|
|
35
|
-
|
|
36
|
-
const isLastArgInCall = createTypeChecker([
|
|
37
|
-
['-: parentPath -> !CallExpression'],
|
|
38
|
-
['+', isPathLastArg],
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
25
|
const callWithRoot = (fn) => (a, {root}) => fn(root);
|
|
26
|
+
|
|
42
27
|
const isExcludedFromChain = createTypeChecker([
|
|
43
28
|
'+: -> UnaryExpression',
|
|
44
29
|
'+: -> IfStatement',
|
|
@@ -93,4 +78,3 @@ const isIfUp = (path) => {
|
|
|
93
78
|
|
|
94
79
|
return is;
|
|
95
80
|
};
|
|
96
|
-
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {types} from '@putout/babel';
|
|
2
|
+
import {createTypeChecker} from '#type-checker';
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
isForOfStatement,
|
|
6
|
+
isAssignmentPattern,
|
|
7
|
+
} = types;
|
|
8
|
+
|
|
9
|
+
const isCoupleOption = (a, {couple}) => couple;
|
|
10
|
+
|
|
11
|
+
export function isInsideForOf({parentPath}) {
|
|
12
|
+
return isForOfStatement(parentPath.parentPath.parentPath);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isPrevAssign(path) {
|
|
16
|
+
const prev = path.getPrevSibling();
|
|
17
|
+
|
|
18
|
+
return isAssignmentPattern(prev.node.value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const isCommaAfterProperty = createTypeChecker([
|
|
22
|
+
['+', isCoupleOption],
|
|
23
|
+
['-: key -> -'],
|
|
24
|
+
['-', isPrevAssign],
|
|
25
|
+
['-: parentPath', isInsideForOf],
|
|
26
|
+
['+: node.value.right -> ObjectExpression'],
|
|
27
|
+
]);
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {
|
|
2
|
+
import {createTypeChecker} from '#type-checker';
|
|
3
|
+
import {
|
|
4
|
+
isCoupleLines,
|
|
5
|
+
exists,
|
|
6
|
+
callWithPrev,
|
|
7
|
+
callWithNext,
|
|
8
|
+
} from '#is';
|
|
3
9
|
import {hasAssign} from './has.js';
|
|
4
10
|
|
|
5
11
|
const {
|
|
6
|
-
isObjectExpression,
|
|
7
|
-
isAssignmentPattern,
|
|
8
|
-
isForOfStatement,
|
|
9
12
|
isFunction,
|
|
10
13
|
isVariableDeclarator,
|
|
11
14
|
isObjectProperty,
|
|
@@ -38,37 +41,9 @@ export const isCoupleProperties = ({path, valuePath, property}) => {
|
|
|
38
41
|
return !isObjectProperty(parentPath);
|
|
39
42
|
};
|
|
40
43
|
|
|
41
|
-
export
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
export const isPrevAssignObject = callWithPrev(createTypeChecker([
|
|
45
|
+
'-: node.value -> !AssignmentPattern',
|
|
46
|
+
'+: node.value.right -> ObjectExpression',
|
|
47
|
+
]));
|
|
44
48
|
|
|
45
|
-
export
|
|
46
|
-
const prev = path.getPrevSibling();
|
|
47
|
-
|
|
48
|
-
return isAssignmentPattern(prev.node.value);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function isPrevAssignObject(path) {
|
|
52
|
-
const prev = path.getPrevSibling();
|
|
53
|
-
|
|
54
|
-
if (!isAssignmentPattern(prev.node.value))
|
|
55
|
-
return false;
|
|
56
|
-
|
|
57
|
-
const {right} = prev.node.value;
|
|
58
|
-
|
|
59
|
-
return isObjectExpression(right);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function isNextAssignObject(path) {
|
|
63
|
-
const next = path.getNextSibling();
|
|
64
|
-
|
|
65
|
-
if (!next.node)
|
|
66
|
-
return false;
|
|
67
|
-
|
|
68
|
-
if (!isAssignmentPattern(next.node.value))
|
|
69
|
-
return false;
|
|
70
|
-
|
|
71
|
-
const {right} = next.node.value;
|
|
72
|
-
|
|
73
|
-
return isObjectExpression(right);
|
|
74
|
-
}
|
|
49
|
+
export const isNextAssignObject = callWithNext(createTypeChecker(['-: node -> -', '-: node.value -> !AssignmentPattern', '+: node.value.right -> ObjectExpression']));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {types} from '@putout/babel';
|
|
2
1
|
import {wrongShorthand} from './wrong-shorthand.js';
|
|
3
2
|
import {maybeTypeAnnotation} from '../../maybe/maybe-type-annotation.js';
|
|
4
3
|
import {printKey} from '../object-expression/print-key.js';
|
|
@@ -12,18 +11,15 @@ import {
|
|
|
12
11
|
hasAssignObject,
|
|
13
12
|
hasObjectPattern,
|
|
14
13
|
} from './has.js';
|
|
14
|
+
import {isCommaAfterProperty} from './comma.js';
|
|
15
15
|
import {
|
|
16
16
|
isCoupleProperties,
|
|
17
17
|
isIndent,
|
|
18
18
|
isInsideFn,
|
|
19
|
-
isInsideForOf,
|
|
20
19
|
isNextAssignObject,
|
|
21
|
-
isPrevAssign,
|
|
22
20
|
isPrevAssignObject,
|
|
23
21
|
} from './is.js';
|
|
24
22
|
|
|
25
|
-
const {isObjectExpression} = types;
|
|
26
|
-
|
|
27
23
|
export const ObjectPattern = {
|
|
28
24
|
print: maybeTypeAnnotation((path, printer, semantics) => {
|
|
29
25
|
const shouldIndent = isIndent(path);
|
|
@@ -97,12 +93,7 @@ export const ObjectPattern = {
|
|
|
97
93
|
} else if (isAssign) {
|
|
98
94
|
print(valuePath);
|
|
99
95
|
|
|
100
|
-
|
|
101
|
-
maybe.print.newline(couple);
|
|
102
|
-
|
|
103
|
-
const {right} = valuePath.node;
|
|
104
|
-
|
|
105
|
-
if (i && !isPrevAssign(property) && !isInsideForOf(path) && isObjectExpression(right)) {
|
|
96
|
+
if (isCommaAfterProperty(property, {couple})) {
|
|
106
97
|
print(',');
|
|
107
98
|
print.newline();
|
|
108
99
|
continue;
|
package/lib/tokenize/is.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {createTypeChecker} from '#type-checker';
|
|
2
3
|
|
|
3
4
|
const {
|
|
4
5
|
isStringLiteral,
|
|
@@ -202,3 +203,23 @@ export const hasTrailingComment = (path) => {
|
|
|
202
203
|
export const hasLeadingComment = (path) => path.node?.leadingComments?.length;
|
|
203
204
|
|
|
204
205
|
export const noTrailingComment = (path) => !path.node.trailingComments?.length;
|
|
206
|
+
|
|
207
|
+
const isPathFirstArg = ({node, parentPath}) => {
|
|
208
|
+
const [first] = parentPath.node.arguments;
|
|
209
|
+
return node === first;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
function isPathLastArg({node, parentPath}) {
|
|
213
|
+
const last = parentPath.node.arguments.at(-1);
|
|
214
|
+
return node === last;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export const isFirstArgOfCall = createTypeChecker([
|
|
218
|
+
['-: parentPath -> !CallExpression'],
|
|
219
|
+
['+', isPathFirstArg],
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
export const isLastArgInCall = createTypeChecker([
|
|
223
|
+
['-: parentPath -> !CallExpression'],
|
|
224
|
+
['+', isPathLastArg],
|
|
225
|
+
]);
|
|
@@ -32,7 +32,7 @@ const initSemantics = (format, semantics = {}) => ({
|
|
|
32
32
|
maxPropertiesInOneLine: 2,
|
|
33
33
|
maxPropertiesLengthInOneLine: 15,
|
|
34
34
|
maxSpecifiersInOneLine: 2,
|
|
35
|
-
maxElementsInOneLine:
|
|
35
|
+
maxElementsInOneLine: 3,
|
|
36
36
|
maxElementLengthInOneLine: 15,
|
|
37
37
|
maxLogicalsInOneLine: 3,
|
|
38
38
|
maxVariablesInOneLine: 4,
|
package/package.json
CHANGED