@putout/printer 18.0.15 → 18.1.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,34 @@
1
+ 2026.03.06, v18.1.0
2
+
3
+ feature:
4
+ - 604e849 @putout/printer: ArrayExpression: long identifier: improve support
5
+ - bdd07e7 @putout/printer: isMultiLine: siplify
6
+ - 945a833 @putout/printer: ArrayExpression: newline: isCoupleLines
7
+ - 2ca2751 @putout/printer: ArrayExpression: newline: isStringsInsideArray
8
+ - 488eb71 @putout/printer: ArrayExpression: newline: isSimpleAndObject
9
+ - 246f9df @putout/printer: ArrayExpression: newline: isIdentifierAndString
10
+ - 56637d1 @putout/printer: ArrayExpression: newline: isStringAndIdentifier
11
+ - caa4682 @putout/printer: ArrayExpression: newline: isStringAndIdentifier
12
+ - 0e9dc1d @putout/printer: ArrayExpression: newline: isMultiline: simplify
13
+ - 103ad2e @putout/printer: ExpressionStatement: isBreakline
14
+ - 04c19c3 @putout/printer: ExpressionStatement: isNextToAssignmentCall: simplify
15
+ - 4bcbd61 @putout/printer: ExpressionStatement: isNextStatementWithBlockComment: simplify
16
+
17
+ 2026.03.06, v18.0.16
18
+
19
+ feature:
20
+ - 2a81cf2 @putout/printer: ExpressionStatement: rm is-inside-assign-next-assign-function
21
+ - 17d19f2 @putout/printer: ExpressionStatement: rm not
22
+ - 1c07e30 @putout/printer: ExpressionStatement: isBreakline: add
23
+ - 15f67f0 @putout/printer: ExpressionStatement: afterIf: move out
24
+ - c6783ee @putout/printer: ExpressionStatement: hasTrailingCommentNotCoupleLines
25
+ - 8e08572 @putout/printer: ExpressionStatement: isTopParentLast: simplify
26
+ - fe1b0ca @putout/printer: ExpressionStatement: isTopParentLast
27
+ - b84b9a6 @putout/printer: ExpressionStatement: isIndent
28
+ - d4d0106 @putout/printer: ExpressionStatement: beforeIf: simplify
29
+ - 9a4721a @putout/printer: ExpressionStatement: afterIf: simplify
30
+ - a9d2cf8 @putout/printer: ExpressionStatement: isBeforeElse: simplify
31
+
1
32
  2026.03.06, v18.0.15
2
33
 
3
34
  feature:
@@ -77,7 +77,6 @@ const isInsideOneElementArray = ({parentPath}) => parentPath.node.elements.lengt
77
77
  export const ArrayExpression = {
78
78
  beforeIf(path) {
79
79
  const {parentPath} = path;
80
- const {elements} = path.node;
81
80
 
82
81
  if (!parentPath.isArrayExpression())
83
82
  return false;
@@ -85,10 +84,10 @@ export const ArrayExpression = {
85
84
  if (isCoupleLines(parentPath))
86
85
  return false;
87
86
 
88
- if (isStringAndIdentifier(elements) && isInsideOneElementArray(path))
87
+ if (isStringAndIdentifier(path) && isInsideOneElementArray(path))
89
88
  return true;
90
89
 
91
- return isIdentifierAndIdentifier(elements);
90
+ return isIdentifierAndIdentifier(path);
92
91
  },
93
92
  before(path, {print}) {
94
93
  print.breakline();
@@ -110,7 +109,6 @@ export const ArrayExpression = {
110
109
  maybe.indent.inc(indented && shouldIncreaseIndent);
111
110
 
112
111
  const isNewLine = isMultiLine(path, {
113
- elements,
114
112
  maxElementsInOneLine,
115
113
  maxElementLengthInOneLine,
116
114
  });
@@ -148,7 +146,7 @@ export const ArrayExpression = {
148
146
 
149
147
  const parentElements = path.parentPath.get('elements');
150
148
 
151
- if (isInsideArray(path) && isStringAndArray(parentElements)) {
149
+ if (isInsideArray(path) && isStringAndArray(path.parentPath)) {
152
150
  const parentCountTwo = parentElements.length === 2;
153
151
  const isHideIdent = !isAroundStrings(path) || parentCountTwo;
154
152
 
@@ -159,7 +157,7 @@ export const ArrayExpression = {
159
157
  maybe.indent(elements.length && isNewLine);
160
158
  }
161
159
 
162
- if (isSimpleAndNotEmptyObject(elements) && !isSpreadElement(elements.at(-1)) && !isCallExpression(elements.at(-1))) {
160
+ if (isSimpleAndNotEmptyObject(path) && !isSpreadElement(elements.at(-1)) && !isCallExpression(elements.at(-1))) {
163
161
  print(',');
164
162
  print.breakline();
165
163
  }
@@ -168,7 +166,6 @@ export const ArrayExpression = {
168
166
  },
169
167
  afterIf(path) {
170
168
  const {parentPath} = path;
171
- const {elements} = path.node;
172
169
 
173
170
  if (!parentPath.isArrayExpression())
174
171
  return false;
@@ -176,10 +173,10 @@ export const ArrayExpression = {
176
173
  if (isCoupleLines(parentPath))
177
174
  return false;
178
175
 
179
- if (isStringAndIdentifier(elements) && isInsideOneElementArray(path))
176
+ if (isStringAndIdentifier(path) && isInsideOneElementArray(path))
180
177
  return true;
181
178
 
182
- return isIdentifierAndIdentifier(elements);
179
+ return isIdentifierAndIdentifier(path);
183
180
  },
184
181
  after(path, {print, indent}) {
185
182
  indent.dec();
@@ -11,10 +11,69 @@ import {
11
11
  isSimpleAndNotEmptyObject,
12
12
  isInsideCall,
13
13
  } from '#is';
14
+ import {isInsideArray} from './indent.js';
15
+ import {isInsideForOf} from '../object-pattern/is.js';
16
+
17
+ const isLastArg = ({parentPath}) => !parentPath.isCallExpression();
18
+ const isParentProperty = (path) => path.find(isObjectProperty);
19
+
20
+ const isNumbersArray = createTypeChecker([
21
+ ['-: node.elements', isNumbers],
22
+ ['-', isInsideForOf],
23
+ ['-: -> !', isLastArg],
24
+ ['+: -> !', isParentProperty],
25
+ ]);
26
+
27
+ const isStringAndString = (path) => {
28
+ const {elements} = path.node;
29
+ const [a, b] = elements;
30
+
31
+ return isStringLiteral(a) && isStringLiteral(b);
32
+ };
33
+
34
+ const isStringsInsideArray = createTypeChecker([
35
+ ['-: -> !', isStringAndString],
36
+ ['-: -> !', isInsideArray],
37
+ '+: parentPath.node.elements.0 -> ArrayExpression',
38
+ ]);
39
+
40
+ const isTwoSimplesInsideObjectProperty = (path) => {
41
+ const {node, parentPath} = path;
42
+
43
+ const {elements} = node;
44
+ const {length} = elements;
45
+ const [a, b] = elements;
46
+
47
+ if (length > 2)
48
+ return false;
49
+
50
+ if (!parentPath.isObjectProperty())
51
+ return false;
52
+
53
+ if (!isStringLiteral(a) || !isStringLiteral(b))
54
+ return false;
55
+
56
+ return !isCoupleLines(path);
57
+ };
58
+
59
+ const isShortTwoSimplesInsideCall = (path, {maxElementsInOneLine}) => {
60
+ const {node, parentPath} = path;
61
+
62
+ const {elements} = node;
63
+ const {length} = elements;
64
+ const [a, b] = elements;
65
+
66
+ if (!parentPath.isCallExpression())
67
+ return false;
68
+
69
+ if (!isStringLiteral(a) || !isStringLiteral(b))
70
+ return false;
71
+
72
+ return length < maxElementsInOneLine;
73
+ };
14
74
 
15
75
  const {
16
76
  isObjectExpression,
17
- isArrayExpression,
18
77
  isObjectProperty,
19
78
  isCallExpression,
20
79
  isAwaitExpression,
@@ -23,11 +82,14 @@ const {
23
82
  isStringLiteral,
24
83
  isSpreadElement,
25
84
  isIdentifier,
85
+ isNumericLiteral,
26
86
  } = types;
27
87
 
28
88
  const {round} = Math;
29
89
 
30
- const isOneSpread = (elements) => {
90
+ const isOneSpread = (path) => {
91
+ const {elements} = path.node;
92
+
31
93
  if (elements.length > 1)
32
94
  return false;
33
95
 
@@ -36,19 +98,38 @@ const isOneSpread = (elements) => {
36
98
  return isSpreadElement(first);
37
99
  };
38
100
 
39
- const isSimpleAndCall = ([a, b]) => {
101
+ const isSimpleAndCall = (path) => {
102
+ const {elements} = path.node;
103
+ const [a, b] = elements;
104
+
40
105
  if (!isSimple(a))
41
106
  return;
42
107
 
43
108
  return isCallExpression(b) || isAwaitExpression(b);
44
109
  };
45
110
 
46
- const isBooleanAndSimple = ([a, b]) => isBooleanLiteral(a) && isSimple(b);
111
+ const isBooleanAndSimple = (path) => {
112
+ const {elements} = path.node;
113
+ const [a, b] = elements;
114
+
115
+ return isBooleanLiteral(a) && isSimple(b);
116
+ };
117
+
47
118
  const isBooleanAndObject = ([a, b]) => isBooleanLiteral(a) && isObjectExpression(b);
48
- const isNullAndSimple = ([a, b]) => isNullLiteral(a) && isSimple(b);
49
- const isSimpleAndObject = ([a, b]) => isSimple(a) && isObjectExpression(b);
50
- const ONE_LINE = false;
51
- const MULTI_LINE = true;
119
+
120
+ const isNullAndSimple = (path) => {
121
+ const {elements} = path.node;
122
+ const [a, b] = elements;
123
+
124
+ return isNullLiteral(a) && isSimple(b);
125
+ };
126
+
127
+ const isSimpleAndObject = (path) => {
128
+ const {elements} = path.node;
129
+ const [a, b] = elements;
130
+
131
+ return isSimple(a) && isObjectExpression(b);
132
+ };
52
133
 
53
134
  const isSiblingIsArray = (path) => {
54
135
  if (path.getNextSibling().isArrayExpression())
@@ -70,13 +151,22 @@ const isMoreThenMaxLiteralLength = (path, {maxElementLengthInOneLine}) => {
70
151
  return first.value.length > maxElementLengthInOneLine;
71
152
  };
72
153
 
154
+ const isMoreThenMaxIdentifierLength = (path) => {
155
+ const [first] = path.node.elements;
156
+
157
+ return isIdentifier(first);
158
+ };
159
+
73
160
  const isMoreThenMaxElementLengthInOneLine = createTypeChecker([
74
161
  ['-', isEmptyArray],
75
162
  ['-: -> !', isInsideCall],
76
163
  ['+', isMoreThenMaxLiteralLength],
164
+ ['+', isMoreThenMaxIdentifierLength],
77
165
  ]);
78
166
 
79
- function isMaxElementLengthInOneLine(elements, maxElementLengthInOneLine) {
167
+ function isMaxElementLengthInOneLine(path, {maxElementLengthInOneLine}) {
168
+ const elements = path.get('elements');
169
+
80
170
  if (elements.length > 1)
81
171
  return false;
82
172
 
@@ -88,125 +178,55 @@ function isMaxElementLengthInOneLine(elements, maxElementLengthInOneLine) {
88
178
  return first.node.name.length < maxElementLengthInOneLine;
89
179
  }
90
180
 
91
- export const isMultiLine = (path, {elements, maxElementsInOneLine, maxElementLengthInOneLine}) => {
92
- const [first] = elements;
93
-
94
- if (isMaxElementLengthInOneLine(elements, maxElementLengthInOneLine))
95
- return ONE_LINE;
96
-
97
- if (isMoreThenMaxElementLengthInOneLine(path, {elements, maxElementLengthInOneLine}))
98
- return MULTI_LINE;
99
-
100
- if (elements.length > maxElementsInOneLine && isStringLiteral(first))
101
- return MULTI_LINE;
102
-
103
- if (elements.length > 3 && !isObjectExpression(first))
104
- return MULTI_LINE;
105
-
106
- if (isSimpleAndNotEmptyObject(elements))
107
- return MULTI_LINE;
108
-
109
- if (isOneSimple(path))
110
- return ONE_LINE;
111
-
112
- if (isOneSpread(elements))
113
- return ONE_LINE;
114
-
115
- if (elements.length === 2 && isIdentifierAndIdentifier(elements))
116
- return ONE_LINE;
117
-
118
- if (isCallInsideArrow(path))
119
- return ONE_LINE;
120
-
121
- if (isIncreaseIndent(path))
122
- return ONE_LINE;
123
-
124
- if (isInsideLoop(path))
125
- return ONE_LINE;
126
-
127
- if (isBooleanAndSimple(elements))
128
- return ONE_LINE;
129
-
130
- if (isNullAndSimple(elements))
131
- return ONE_LINE;
132
-
133
- if (isSimpleAndCall(elements))
134
- return ONE_LINE;
135
-
136
- if (isShortTwoSimplesInsideCall(path, maxElementsInOneLine))
137
- return ONE_LINE;
138
-
139
- if (isTwoStringsDifferentLength(elements))
140
- return ONE_LINE;
141
-
142
- if (isTwoSimplesInsideObjectProperty(path))
143
- return ONE_LINE;
144
-
145
- if (isStringAndArray(elements) && elements.length < 3)
146
- return ONE_LINE;
147
-
148
- if (isStringAndMember(elements))
149
- return ONE_LINE;
150
-
151
- if (isStringAndIdentifier(elements))
152
- return ONE_LINE;
153
-
154
- if (isIdentifierAndString(elements))
155
- return ONE_LINE;
156
-
157
- if (isSimpleAndObject(elements))
158
- return ONE_LINE;
159
-
160
- if (isStringAndString(elements) && path.parentPath.isArrayExpression() && isArrayExpression(path.parentPath.node.elements[0]))
161
- return ONE_LINE;
162
-
163
- if (isSiblingIsArray(path))
164
- return ONE_LINE;
165
-
166
- if (tooLong(path) || isCoupleLines(path) || !isNumbers(elements) && !isForOf(path) && isLastArg(path) && !isParentProperty(path))
167
- return MULTI_LINE;
168
-
169
- return ONE_LINE;
181
+ const isElementsMoreThenMax = (path, {maxElementsInOneLine}) => {
182
+ const {elements} = path.node;
183
+ return elements.length > maxElementsInOneLine;
170
184
  };
171
185
 
172
- const isForOf = ({parentPath}) => parentPath.isForOfStatement();
186
+ const isElementsMoreThenThree = (path) => {
187
+ const {elements} = path.node;
188
+ return elements.length > 3;
189
+ };
173
190
 
174
- const isStringAndString = ([a, b]) => isStringLiteral(a) && isStringLiteral(b);
191
+ const isElementsMoreThenThreeWithNotFirstObject = createTypeChecker([
192
+ '-: node.elements.0 -> ObjectExpression',
193
+ isElementsMoreThenThree,
194
+ ]);
175
195
 
176
- const isShortTwoSimplesInsideCall = (path, maxElementsInOneLine) => {
177
- const {node, parentPath} = path;
178
-
179
- const {elements} = node;
180
- const {length} = elements;
181
- const [a, b] = elements;
182
-
183
- if (!parentPath.isCallExpression())
184
- return false;
185
-
186
- if (!isStringLiteral(a) || !isStringLiteral(b))
187
- return false;
188
-
189
- return length < maxElementsInOneLine;
190
- };
196
+ const isElementsMoreThenMaxWithFirstString = createTypeChecker([
197
+ '-: node.elements.0 -> !StringLiteral',
198
+ isElementsMoreThenMax,
199
+ ]);
191
200
 
192
- const isTwoSimplesInsideObjectProperty = (path) => {
193
- const {node, parentPath} = path;
194
-
195
- const {elements} = node;
196
- const {length} = elements;
197
- const [a, b] = elements;
198
-
199
- if (length > 2)
200
- return false;
201
-
202
- if (!parentPath.isObjectProperty())
203
- return false;
204
-
205
- if (!isStringLiteral(a) || !isStringLiteral(b))
206
- return false;
207
-
208
- return !isCoupleLines(path);
209
- };
201
+ export const isMultiLine = createTypeChecker([
202
+ ['-', isMaxElementLengthInOneLine],
203
+ isMoreThenMaxElementLengthInOneLine,
204
+ isElementsMoreThenMaxWithFirstString,
205
+ isElementsMoreThenThreeWithNotFirstObject,
206
+ isSimpleAndNotEmptyObject,
207
+ ['-', isOneSimple],
208
+ ['-', isOneSpread],
209
+ ['-', isIdentifierAndIdentifier],
210
+ ['-', isCallInsideArrow],
211
+ ['-', isIncreaseIndent],
212
+ ['-', isInsideLoop],
213
+ ['-', isBooleanAndSimple],
214
+ ['-', isNullAndSimple],
215
+ ['-', isSimpleAndCall],
216
+ ['-', isShortTwoSimplesInsideCall],
217
+ ['-', isTwoStringsDifferentLength],
218
+ ['-', isTwoSimplesInsideObjectProperty],
219
+ ['-', isStringAndArray],
220
+ ['-', isStringAndMember],
221
+ ['-', isStringAndIdentifier],
222
+ ['-', isIdentifierAndString],
223
+ ['-', isSimpleAndObject],
224
+ ['-', isSiblingIsArray],
225
+ ['-', isStringsInsideArray],
226
+ tooLong,
227
+ isCoupleLines,
228
+ isNumbersArray,
229
+ ]);
210
230
 
211
231
  function isOneSimple(path) {
212
232
  const elements = path.get('elements');
@@ -228,17 +248,18 @@ function isOneSimple(path) {
228
248
  return first.isMemberExpression();
229
249
  }
230
250
 
231
- function isTwoStringsDifferentLength(strings) {
232
- const [a, b] = strings;
251
+ function isTwoStringsDifferentLength(path) {
252
+ const {elements} = path.node;
253
+ const [a, b] = elements;
233
254
 
234
- if (strings.length > 2)
255
+ if (elements.length > 2)
235
256
  return false;
236
257
 
237
- if (!a?.isStringLiteral() || !b?.isStringLiteral())
258
+ if (!isStringLiteral(a) || !isStringLiteral(b))
238
259
  return false;
239
260
 
240
- const aLength = a.node.value.length;
241
- const bLength = b.node.value.length;
261
+ const aLength = a.value.length;
262
+ const bLength = b.value.length;
242
263
 
243
264
  return round(bLength / aLength) > 2;
244
265
  }
@@ -275,17 +296,13 @@ function isCallInsideArrow(path) {
275
296
 
276
297
  function isNumbers(elements) {
277
298
  for (const element of elements) {
278
- if (element.isNumericLiteral())
299
+ if (isNumericLiteral(element))
279
300
  return true;
280
301
  }
281
302
 
282
303
  return false;
283
304
  }
284
305
 
285
- const isLastArg = ({parentPath}) => !parentPath.isCallExpression();
286
-
287
- const isParentProperty = (path) => path.find(isObjectProperty);
288
-
289
306
  export function isIncreaseIndent(path) {
290
307
  const elements = path.get('elements');
291
308
 
@@ -1,7 +1,11 @@
1
1
  import {types} from '@putout/babel';
2
2
  import {printParams} from '#print-params';
3
3
  import {markAfter} from '#mark';
4
- import {isNext, isNextParent} from '#is';
4
+ import {
5
+ getNext,
6
+ isNext,
7
+ isNextParent,
8
+ } from '#is';
5
9
  import {createTypeChecker} from '#type-checker';
6
10
 
7
11
  const {
@@ -12,8 +16,6 @@ const {
12
16
 
13
17
  const hasFnBody = ({node}) => node.body.body.length;
14
18
 
15
- const getNext = (fn) => (path) => fn(path.getNextSibling());
16
-
17
19
  const isIndentAfter = createTypeChecker([
18
20
  ['+', getNext(isFunctionDeclaration)],
19
21
  ['+', isNext],
@@ -149,4 +149,3 @@ const hasNextLeadingComment = (path) => {
149
149
 
150
150
  return hasLeadingComment(next);
151
151
  };
152
-
@@ -28,6 +28,8 @@ export const isInsideExpression = ({parentPath}) => isExpressionStatement(parent
28
28
  export const isInsideTSModuleBlock = ({parentPath}) => isTSModuleBlock(parentPath);
29
29
 
30
30
  export const isInsideCall = ({parentPath}) => parentPath.isCallExpression();
31
+ export const isInsideReturn = ({parentPath}) => parentPath.isReturnStatement();
32
+ export const getNext = (fn) => (path) => fn(path.getNextSibling());
31
33
 
32
34
  export const isNext = (path) => {
33
35
  const next = path.getNextSibling();
@@ -89,7 +91,10 @@ export function isCoupleLines(path) {
89
91
 
90
92
  export const exists = (a) => a.node;
91
93
 
92
- export function isStringAndIdentifier([a, b]) {
94
+ export function isStringAndIdentifier(path) {
95
+ const {elements} = path.node;
96
+ const [a, b] = elements;
97
+
93
98
  return isStringLiteral(a) && isIdentifier(b);
94
99
  }
95
100
 
@@ -105,7 +110,8 @@ const checkObject = (elements) => {
105
110
  return a.node.properties.length;
106
111
  };
107
112
 
108
- export const isSimpleAndNotEmptyObject = (elements) => {
113
+ export const isSimpleAndNotEmptyObject = (path) => {
114
+ const elements = path.get('elements');
109
115
  const [a] = elements;
110
116
 
111
117
  const simpleTypes = [
@@ -122,20 +128,44 @@ export const isSimpleAndNotEmptyObject = (elements) => {
122
128
  return checkObject(elements);
123
129
  };
124
130
 
125
- export const isIdentifierAndIdentifier = ([a, b]) => {
131
+ export const isIdentifierAndIdentifier = (path) => {
132
+ const {elements} = path.node;
133
+
134
+ if (elements.length !== 2)
135
+ return;
136
+
137
+ const [a, b] = elements;
138
+
126
139
  return isIdentifier(a) && isIdentifier(b);
127
140
  };
128
141
 
129
- export const isStringAndMember = ([a, b]) => isStringLiteral(a) && isMemberExpression(b);
130
- export const isIdentifierAndString = ([a, b]) => isIdentifier(a) && isStringLiteral(b);
131
- export const isStringAndArray = ([a, b]) => {
142
+ export const isStringAndMember = (path) => {
143
+ const {elements} = path.node;
144
+ const [a, b] = elements;
145
+
146
+ return isStringLiteral(a) && isMemberExpression(b);
147
+ };
148
+ export const isIdentifierAndString = (path) => {
149
+ const {elements} = path.node;
150
+ const [a, b] = elements;
151
+
152
+ return isIdentifier(a) && isStringLiteral(b);
153
+ };
154
+ export const isStringAndArray = (path) => {
155
+ const elements = path.get('elements');
156
+
157
+ if (elements.length !== 2)
158
+ return false;
159
+
160
+ const [a, b] = elements;
161
+
132
162
  if (!isStringLiteral(a))
133
163
  return false;
134
164
 
135
165
  if (!isArrayExpression(b))
136
166
  return false;
137
167
 
138
- return !isStringAndIdentifier(b.node.elements);
168
+ return !isStringAndIdentifier(b);
139
169
  };
140
170
 
141
171
  const isIfOrStatement = (a) => isIfStatement(a) || isStatement(a);
@@ -0,0 +1,52 @@
1
+ import {createTypeChecker} from '#type-checker';
2
+ import {
3
+ hasTrailingComment,
4
+ isCoupleLines,
5
+ isInsideBlock,
6
+ isLast,
7
+ isNext,
8
+ isParentLast,
9
+ satisfy,
10
+ } from '#is';
11
+
12
+ function isNotLastOrParentLast(path) {
13
+ return !isLast(path) && !isParentLast(path);
14
+ }
15
+
16
+ const isNextUp = (path) => path.findParent(isNext);
17
+
18
+ const isTopParentLast = createTypeChecker([
19
+ '-: parentPath -> !IfStatement',
20
+ '-: parentPath.parentPath -> !IfStatement',
21
+ '-: parentPath.parentPath.parentPath -> !IfStatement',
22
+ ['+: parentPath.parentPath.parentPath', isLast],
23
+ ]);
24
+
25
+ const satisfyAfter = satisfy([
26
+ isNotLastOrParentLast,
27
+ isInsideBlock,
28
+ isNext,
29
+ isNextUp,
30
+ ]);
31
+
32
+ const isPathIsConsequent = ({node, parentPath}) => node !== parentPath.node.consequent;
33
+
34
+ const isBeforeElse = createTypeChecker([
35
+ '-: parentPath -> !IfStatement',
36
+ ['-:', isPathIsConsequent],
37
+ ['+: parentPath.node.alternate', Boolean],
38
+ ]);
39
+
40
+ const hasTrailingCommentNotCoupleLines = createTypeChecker([
41
+ ['-: -> !', hasTrailingComment],
42
+ ['+: -> !', isCoupleLines],
43
+ ]);
44
+
45
+ export const afterIf = createTypeChecker([
46
+ ['-', isTopParentLast],
47
+ ['-', hasTrailingCommentNotCoupleLines],
48
+ ['+', satisfyAfter],
49
+ ['+', isBeforeElse],
50
+ ['-: -> !', hasTrailingComment],
51
+ ['+', isLast],
52
+ ]);
@@ -0,0 +1,7 @@
1
+ import {createTypeChecker} from '#type-checker';
2
+ import {isInsideLabel, isInsideReturn} from '#is';
3
+
4
+ export const beforeIf = createTypeChecker([
5
+ ['-', isInsideReturn],
6
+ ['+: -> !', isInsideLabel],
7
+ ]);
@@ -1,73 +1,67 @@
1
- import {types} from '@putout/babel';
1
+ import {createTypeChecker} from '#type-checker';
2
2
  import {
3
3
  isNext,
4
4
  isLast,
5
- isInsideBlock,
6
- isParentLast,
7
5
  isNewlineBetweenSiblings,
8
- satisfy,
9
6
  noTrailingComment,
10
7
  hasTrailingComment,
11
8
  isCoupleLines,
12
- isInsideLabel,
9
+ isInsideReturn,
10
+ getNext,
11
+ hasLeadingComment,
13
12
  } from '#is';
14
- import {isInsideAssignNextAssignFunction} from './is-inside-assign-next-assign-function.js';
15
13
  import {
16
14
  printLeadingCommentLine,
17
15
  printLeadingCommentBlock,
18
- } from './expression-statement-comments.js';
16
+ } from './comments.js';
17
+ import {afterIf} from './after-if.js';
18
+ import {beforeIf} from './before-if.js';
19
19
 
20
- const isCommentBlock = (a) => a?.type === 'CommentBlock';
21
-
22
- const {
23
- isCallExpression,
24
- isExpressionStatement,
25
- isAssignmentExpression,
26
- } = types;
27
-
28
- const not = (fn) => (...a) => !fn(...a);
20
+ const isCallInsideExpression = createTypeChecker([
21
+ '-: -> !ExpressionStatement',
22
+ '+: node.expression -> CallExpression',
23
+ ]);
29
24
 
30
- const isBeforeElse = (path) => {
31
- if (!path.parentPath.isIfStatement())
32
- return false;
33
-
34
- if (path !== path.parentPath.get('consequent'))
35
- return false;
36
-
37
- return Boolean(path.parentPath.node.alternate);
38
- };
25
+ const isNextToAssignmentCall = createTypeChecker([
26
+ '-: node.expression -> AssignmentExpression',
27
+ ['+', getNext(isCallInsideExpression)],
28
+ ]);
39
29
 
40
- const isInsideReturn = ({parentPath}) => parentPath.isReturnStatement();
41
- const notInsideReturn = not(isInsideReturn);
30
+ const isNextStatementWithBlockComment = createTypeChecker([
31
+ '-: node.expression -> !CallExpression',
32
+ '-: node.expression.arguments.0 -> !CallExpression',
33
+ '+: node.trailingComments.0 -> CommentBlock',
34
+ ]);
42
35
 
43
- const satisfyAfter = satisfy([
44
- isNotLastOrParentLast,
45
- isInsideBlock,
46
- isNext,
47
- isNextUp,
36
+ const isBreaklineAfter = createTypeChecker([
37
+ ['-: -> !', hasTrailingComment],
38
+ ['-: -> !', isLast],
39
+ ['+', isCoupleLines],
48
40
  ]);
49
41
 
50
42
  const isNextIf = (path) => path
51
43
  .getNextSibling()
52
44
  .isIfStatement();
53
45
 
54
- const shouldBreakline = satisfy([
55
- isNewlineBetweenSiblings,
56
- isNotLastBody,
57
- isNextIf,
46
+ const isBreakline = createTypeChecker([isNewlineBetweenSiblings, isNextIf]);
47
+
48
+ const isIndent = createTypeChecker([
49
+ noTrailingComment,
50
+ isNextToAssignmentCall,
51
+ isNextStatementWithBlockComment,
52
+ ]);
53
+
54
+ export const isIndentAfter = createTypeChecker([
55
+ '-: node.expression -> !AssignmentExpression',
56
+ ['+', getNext(hasLeadingComment)],
58
57
  ]);
59
58
 
60
59
  export const ExpressionStatement = {
61
- beforeIf(path) {
62
- if (isInsideReturn(path))
63
- return false;
64
-
65
- return !isInsideLabel(path);
66
- },
60
+ beforeIf,
67
61
  before(path, {indent}) {
68
62
  indent();
69
63
  },
70
- print(path, {print, maybe, store, indent}) {
64
+ print(path, {print, maybe, store}) {
71
65
  const insideReturn = isInsideReturn(path);
72
66
 
73
67
  print('__expression');
@@ -76,109 +70,23 @@ export const ExpressionStatement = {
76
70
  if (!isNext(path))
77
71
  return;
78
72
 
79
- if (!insideReturn && shouldBreakline(path)) {
73
+ if (isBreakline(path)) {
80
74
  print.newline();
81
-
82
- const condition = isNext(path)
83
- && noTrailingComment(path)
84
- || isNextToAssignmentCall(path)
85
- || isNextStatementWithBlockComment(path);
86
-
87
- if (condition)
88
- indent();
89
-
75
+ maybe.indent(isIndent(path));
90
76
  store(true);
91
77
  }
92
78
  },
93
- afterIf: (path) => {
94
- if (satisfyAfter(path))
95
- return true;
79
+ afterIf,
80
+ after(path, {print, maybe, store}) {
81
+ maybe.print.breakline(isBreaklineAfter(path));
96
82
 
97
- if (hasTrailingComment(path) && isLast(path))
98
- return true;
99
-
100
- return isBeforeElse(path);
101
- },
102
- after(path, {print, maybe, store, indent}) {
103
- if (hasTrailingComment(path) && isLast(path) && isCoupleLines(path))
104
- print.breakline();
105
-
106
- if (hasTrailingComment(path) && !isCoupleLines(path))
107
- return;
108
-
109
- if (isTopParentLast(path))
83
+ if (isInsideReturn(path))
110
84
  return;
111
85
 
112
- if (notInsideReturn(path)) {
113
- if (isInsideAssignNextAssignFunction(path))
114
- indent();
115
-
116
- print.newline();
117
- maybe.markAfter(store(), path);
118
- }
86
+ maybe.indent(isIndentAfter(path));
87
+ print.newline();
88
+ maybe.markAfter(store(), path);
119
89
  },
120
90
  };
121
91
  ExpressionStatement.printLeadingCommentLine = printLeadingCommentLine;
122
92
  ExpressionStatement.printLeadingCommentBlock = printLeadingCommentBlock;
123
-
124
- function isTopParentLast({parentPath}) {
125
- if (!parentPath.isIfStatement())
126
- return false;
127
-
128
- const nextParent = parentPath.parentPath;
129
-
130
- if (!nextParent.isIfStatement())
131
- return false;
132
-
133
- const nextNext = nextParent.parentPath;
134
-
135
- if (!nextNext.isIfStatement())
136
- return false;
137
-
138
- return isLast(nextNext);
139
- }
140
-
141
- function isNotLastBody(path) {
142
- return path.parentPath.get('body') === path;
143
- }
144
-
145
- function isNotLastOrParentLast(path) {
146
- return !isLast(path) && !isParentLast(path);
147
- }
148
-
149
- function isNextUp(path) {
150
- return path.findParent(isNext);
151
- }
152
-
153
- function isNextToAssignmentCall(path) {
154
- if (isAssignmentExpression(path.node.expression))
155
- return false;
156
-
157
- const nextPath = path.getNextSibling();
158
-
159
- if (!isExpressionStatement(nextPath))
160
- return false;
161
-
162
- const {expression} = nextPath.node;
163
-
164
- return isCallExpression(expression);
165
- }
166
-
167
- function isNextStatementWithBlockComment(path) {
168
- const {expression} = path.node;
169
-
170
- if (!isCallExpression(expression))
171
- return false;
172
-
173
- if (!isCallExpression(expression.arguments[0]))
174
- return false;
175
-
176
- return hasTrailingBlock(path);
177
- }
178
-
179
- function hasTrailingBlock(path) {
180
- const {trailingComments} = path.node;
181
- const [first] = trailingComments;
182
-
183
- return isCommentBlock(first);
184
- }
@@ -1,4 +1,8 @@
1
- import {isInsideLabel, exists} from '#is';
1
+ import {
2
+ isInsideLabel,
3
+ exists,
4
+ getNext,
5
+ } from '#is';
2
6
  import {markAfter} from '#mark';
3
7
 
4
8
  export const ForStatement = {
@@ -36,9 +40,7 @@ export const ForStatement = {
36
40
  print('__body');
37
41
  maybe.indent.dec(is);
38
42
  },
39
- afterIf(path) {
40
- return exists(path.getNextSibling());
41
- },
43
+ afterIf: getNext(exists),
42
44
  after(path, {print}) {
43
45
  print.linebreak();
44
46
  markAfter(path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/printer",
3
- "version": "18.0.15",
3
+ "version": "18.1.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",
@@ -1,32 +0,0 @@
1
- import {types} from '@putout/babel';
2
-
3
- const {
4
- isExpressionStatement,
5
- isFunction,
6
- isAssignmentExpression,
7
- } = types;
8
-
9
- export const isInsideAssignNextAssignFunction = (path) => {
10
- const {expression} = path.node;
11
-
12
- if (!isAssignmentExpression(expression))
13
- return false;
14
-
15
- const next = path.getNextSibling();
16
-
17
- if (isFunction(next) && next.node.leadingComments)
18
- return true;
19
-
20
- if (!isExpressionStatement(next))
21
- return false;
22
-
23
- const {leadingComments} = next.node;
24
-
25
- if (!leadingComments)
26
- return false;
27
-
28
- if (!isAssignmentExpression(next.node.expression))
29
- return false;
30
-
31
- return isFunction(next.node.expression.right);
32
- };