@putout/printer 18.7.9 → 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 CHANGED
@@ -1,3 +1,10 @@
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
+
1
8
  2026.03.18, v18.7.9
2
9
 
3
10
  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
- ['+', isStringAndIdentifierInsideOneElementArray],
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
- if (!isStringLiteral(first))
144
- return false;
143
+ for (const element of elements.filter(isStringLiteral)) {
144
+ if (element.value.length >= maxElementLengthInOneLine)
145
+ return true;
146
+ }
145
147
 
146
- return first.value.length > maxElementLengthInOneLine;
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 > 4)
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,26 +22,6 @@ 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);
42
26
 
43
27
  const isExcludedFromChain = createTypeChecker([
@@ -25,4 +25,3 @@ export const isCommaAfterProperty = createTypeChecker([
25
25
  ['-: parentPath', isInsideForOf],
26
26
  ['+: node.value.right -> ObjectExpression'],
27
27
  ]);
28
-
@@ -1,10 +1,14 @@
1
1
  import {types} from '@putout/babel';
2
- import {isCoupleLines, exists} from '#is';
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
12
  isFunction,
9
13
  isVariableDeclarator,
10
14
  isObjectProperty,
@@ -37,27 +41,9 @@ export const isCoupleProperties = ({path, valuePath, property}) => {
37
41
  return !isObjectProperty(parentPath);
38
42
  };
39
43
 
40
- export function isPrevAssignObject(path) {
41
- const prev = path.getPrevSibling();
42
-
43
- if (!isAssignmentPattern(prev.node.value))
44
- return false;
45
-
46
- const {right} = prev.node.value;
47
-
48
- return isObjectExpression(right);
49
- }
44
+ export const isPrevAssignObject = callWithPrev(createTypeChecker([
45
+ '-: node.value -> !AssignmentPattern',
46
+ '+: node.value.right -> ObjectExpression',
47
+ ]));
50
48
 
51
- export function isNextAssignObject(path) {
52
- const next = path.getNextSibling();
53
-
54
- if (!next.node)
55
- return false;
56
-
57
- if (!isAssignmentPattern(next.node.value))
58
- return false;
59
-
60
- const {right} = next.node.value;
61
-
62
- return isObjectExpression(right);
63
- }
49
+ export const isNextAssignObject = callWithNext(createTypeChecker(['-: node -> -', '-: node.value -> !AssignmentPattern', '+: node.value.right -> ObjectExpression']));
@@ -128,4 +128,3 @@ export const ObjectPattern = {
128
128
  print('}');
129
129
  }),
130
130
  };
131
-
@@ -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: 5,
35
+ maxElementsInOneLine: 3,
36
36
  maxElementLengthInOneLine: 15,
37
37
  maxLogicalsInOneLine: 3,
38
38
  maxVariablesInOneLine: 4,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/printer",
3
- "version": "18.7.9",
3
+ "version": "18.8.0",
4
4
  "type": "module",
5
5
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
6
  "description": "Simplest possible opinionated Babel AST printer for 🐊Putout",