@putout/printer 18.0.14 → 18.0.16

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,23 @@
1
+ 2026.03.06, v18.0.16
2
+
3
+ feature:
4
+ - 2a81cf2 @putout/printer: ExpressionStatement: rm is-inside-assign-next-assign-function
5
+ - 17d19f2 @putout/printer: ExpressionStatement: rm not
6
+ - 1c07e30 @putout/printer: ExpressionStatement: isBreakline: add
7
+ - 15f67f0 @putout/printer: ExpressionStatement: afterIf: move out
8
+ - c6783ee @putout/printer: ExpressionStatement: hasTrailingCommentNotCoupleLines
9
+ - 8e08572 @putout/printer: ExpressionStatement: isTopParentLast: simplify
10
+ - fe1b0ca @putout/printer: ExpressionStatement: isTopParentLast
11
+ - b84b9a6 @putout/printer: ExpressionStatement: isIndent
12
+ - d4d0106 @putout/printer: ExpressionStatement: beforeIf: simplify
13
+ - 9a4721a @putout/printer: ExpressionStatement: afterIf: simplify
14
+ - a9d2cf8 @putout/printer: ExpressionStatement: isBeforeElse: simplify
15
+
16
+ 2026.03.06, v18.0.15
17
+
18
+ feature:
19
+ - 22d510e @putout/printer: ObjectExpression: isLogicalArgument
20
+
1
21
  2026.03.06, v18.0.14
2
22
 
3
23
  feature:
@@ -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],
@@ -32,10 +32,12 @@ const notLastArgInsideCall = (path) => {
32
32
  const hasNoProperties = (path) => !path.node.properties.length;
33
33
  const hasValue = (path) => path.node.properties[0].value;
34
34
 
35
- const {isMemberExpression} = types;
36
-
37
- const isLogical = (path) => path.get('argument').isLogicalExpression();
35
+ const {
36
+ isMemberExpression,
37
+ isLogicalExpression,
38
+ } = types;
38
39
 
40
+ const isLogicalArgument = (path) => isLogicalExpression(path.node.argument);
39
41
  const isParens = createTypeChecker([isInsideBody, isInsideExpression]);
40
42
  const getCallee = (fn) => (a) => fn(a.get('callee'));
41
43
 
@@ -97,7 +99,7 @@ export const ObjectExpression = (path, printer, semantics) => {
97
99
 
98
100
  for (const [index, property] of properties.entries()) {
99
101
  if (property.isSpreadElement()) {
100
- const logical = isLogical(property);
102
+ const logical = isLogicalArgument(property);
101
103
 
102
104
  if (noLeadingComment(property))
103
105
  maybe.indent(length > 1 || logical || manyLines);
@@ -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();
@@ -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,23 +1,30 @@
1
1
  import {types} from '@putout/babel';
2
+ import {createTypeChecker} from '#type-checker';
2
3
  import {
3
4
  isNext,
4
5
  isLast,
5
- isInsideBlock,
6
- isParentLast,
7
6
  isNewlineBetweenSiblings,
8
7
  satisfy,
9
8
  noTrailingComment,
10
9
  hasTrailingComment,
11
10
  isCoupleLines,
12
- isInsideLabel,
11
+ isInsideReturn,
12
+ getNext,
13
+ hasLeadingComment,
13
14
  } from '#is';
14
- import {isInsideAssignNextAssignFunction} from './is-inside-assign-next-assign-function.js';
15
15
  import {
16
16
  printLeadingCommentLine,
17
17
  printLeadingCommentBlock,
18
- } from './expression-statement-comments.js';
18
+ } from './comments.js';
19
+ import {afterIf} from './after-if.js';
20
+ import {beforeIf} from './before-if.js';
19
21
 
20
22
  const isCommentBlock = (a) => a?.type === 'CommentBlock';
23
+ const isBreakline = createTypeChecker([
24
+ ['-: -> !', hasTrailingComment],
25
+ ['-: -> !', isLast],
26
+ ['+', isCoupleLines],
27
+ ]);
21
28
 
22
29
  const {
23
30
  isCallExpression,
@@ -25,28 +32,6 @@ const {
25
32
  isAssignmentExpression,
26
33
  } = types;
27
34
 
28
- const not = (fn) => (...a) => !fn(...a);
29
-
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
- };
39
-
40
- const isInsideReturn = ({parentPath}) => parentPath.isReturnStatement();
41
- const notInsideReturn = not(isInsideReturn);
42
-
43
- const satisfyAfter = satisfy([
44
- isNotLastOrParentLast,
45
- isInsideBlock,
46
- isNext,
47
- isNextUp,
48
- ]);
49
-
50
35
  const isNextIf = (path) => path
51
36
  .getNextSibling()
52
37
  .isIfStatement();
@@ -57,17 +42,23 @@ const shouldBreakline = satisfy([
57
42
  isNextIf,
58
43
  ]);
59
44
 
45
+ const isIndent = createTypeChecker([
46
+ noTrailingComment,
47
+ isNextToAssignmentCall,
48
+ isNextStatementWithBlockComment,
49
+ ]);
50
+
51
+ export const isIndentAfter = createTypeChecker([
52
+ '-: node.expression -> !AssignmentExpression',
53
+ ['+', getNext(hasLeadingComment)],
54
+ ]);
55
+
60
56
  export const ExpressionStatement = {
61
- beforeIf(path) {
62
- if (isInsideReturn(path))
63
- return false;
64
-
65
- return !isInsideLabel(path);
66
- },
57
+ beforeIf,
67
58
  before(path, {indent}) {
68
59
  indent();
69
60
  },
70
- print(path, {print, maybe, store, indent}) {
61
+ print(path, {print, maybe, store}) {
71
62
  const insideReturn = isInsideReturn(path);
72
63
 
73
64
  print('__expression');
@@ -78,78 +69,29 @@ export const ExpressionStatement = {
78
69
 
79
70
  if (!insideReturn && shouldBreakline(path)) {
80
71
  print.newline();
81
-
82
- const condition = isNext(path)
83
- && noTrailingComment(path)
84
- || isNextToAssignmentCall(path)
85
- || isNextStatementWithBlockComment(path);
86
-
87
- if (condition)
88
- indent();
89
-
72
+ maybe.indent(isIndent(path));
90
73
  store(true);
91
74
  }
92
75
  },
93
- afterIf: (path) => {
94
- if (satisfyAfter(path))
95
- return true;
96
-
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;
76
+ afterIf,
77
+ after(path, {print, maybe, store}) {
78
+ maybe.print.breakline(isBreakline(path));
108
79
 
109
- if (isTopParentLast(path))
80
+ if (isInsideReturn(path))
110
81
  return;
111
82
 
112
- if (notInsideReturn(path)) {
113
- if (isInsideAssignNextAssignFunction(path))
114
- indent();
115
-
116
- print.newline();
117
- maybe.markAfter(store(), path);
118
- }
83
+ maybe.indent(isIndentAfter(path));
84
+ print.newline();
85
+ maybe.markAfter(store(), path);
119
86
  },
120
87
  };
121
88
  ExpressionStatement.printLeadingCommentLine = printLeadingCommentLine;
122
89
  ExpressionStatement.printLeadingCommentBlock = printLeadingCommentBlock;
123
90
 
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
91
  function isNotLastBody(path) {
142
92
  return path.parentPath.get('body') === path;
143
93
  }
144
94
 
145
- function isNotLastOrParentLast(path) {
146
- return !isLast(path) && !isParentLast(path);
147
- }
148
-
149
- function isNextUp(path) {
150
- return path.findParent(isNext);
151
- }
152
-
153
95
  function isNextToAssignmentCall(path) {
154
96
  if (isAssignmentExpression(path.node.expression))
155
97
  return false;
@@ -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.14",
3
+ "version": "18.0.16",
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
- };