@putout/printer 18.7.4 → 18.7.6

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,16 @@
1
+ 2026.03.17, v18.7.6
2
+
3
+ feature:
4
+ - 8166fbad @putout/printer: MemberExpression: simplify
5
+
6
+ 2026.03.16, v18.7.5
7
+
8
+ feature:
9
+ - f0cb1bfa @putout/printer: BlockStatement: isCallInsideChain: simplify
10
+ - 246851f5 @putout/printer: MemberExpression: simplify
11
+ - 3fd6353a @putout/printer: MemberExpression: simplify
12
+ - 2ddd2e69 @putout/printer: LogicalExpression: simplify
13
+
1
14
  2026.03.16, v18.7.4
2
15
 
3
16
  feature:
@@ -308,4 +308,3 @@ export const isIndentBeforeElement = createTypeChecker([
308
308
  ['+: -> SpreadElement'],
309
309
  ['+: -> !ObjectExpression'],
310
310
  ]);
311
-
@@ -1,14 +1,12 @@
1
1
  import {types} from '@putout/babel';
2
+ import {createTypeChecker} from '#type-checker';
2
3
 
3
- const {
4
- isLogicalExpression,
5
- isReturnStatement,
6
- isVariableDeclarator,
7
- } = types;
4
+ const {isLogicalExpression} = types;
8
5
 
9
- export const isRootOk = (path) => {
10
- return isReturnStatement(path) || isVariableDeclarator(path);
11
- };
6
+ export const isRootOk = createTypeChecker([
7
+ '+: -> ReturnStatement',
8
+ '+: -> VariableDeclarator',
9
+ ]);
12
10
 
13
11
  export const chain = (path) => {
14
12
  const [downCount] = down(path);
@@ -1,38 +1,42 @@
1
1
  import {maybeParens} from '#maybe-parens';
2
+ import {createTypeChecker} from '#type-checker';
2
3
  import {chain, isRootOk} from './chain.js';
3
4
 
5
+ const condition = createTypeChecker([
6
+ '+: parentPath -> UnaryExpression',
7
+ '+: parentPath -> AwaitExpression',
8
+ ]);
9
+
4
10
  export const LogicalExpression = maybeParens({
5
- condition(path) {
6
- if (path.parentPath.isUnaryExpression())
7
- return true;
8
-
9
- return path.parentPath.isAwaitExpression();
10
- },
11
+ condition,
11
12
  print(path, {print, maybe}, semantics) {
13
+ const {operator} = path.node;
14
+
12
15
  print('__left');
13
16
 
14
- const needNewLine = isNewLine(path, semantics);
17
+ const needNewLine = isNewline(path, semantics);
15
18
 
16
19
  maybe.indent.inc(needNewLine);
17
20
  needNewLine ? print.breakline() : print.space();
18
21
  maybe.indent.dec(needNewLine);
19
22
 
20
- print(path.node.operator);
23
+ print(operator);
21
24
  print.space();
22
25
  print('__right');
23
26
  },
24
27
  });
25
28
 
26
- function isNewLine(path, semantics) {
29
+ const callWithRoot = (fn) => (path, {maxLogicalsInOneLine}) => {
27
30
  const [root, count] = chain(path);
28
31
 
29
- if (!isRootOk(root))
32
+ if (!fn(root))
30
33
  return false;
31
34
 
32
- if (count <= semantics.maxLogicalsInOneLine)
33
- return false;
34
-
35
- const {operator} = path.node;
36
-
37
- return operator === '||' || operator === '&&';
38
- }
35
+ return count > maxLogicalsInOneLine;
36
+ };
37
+
38
+ const isNewline = createTypeChecker([
39
+ ['-: -> !', callWithRoot(isRootOk)],
40
+ ['+: node.operator ->', '=', '||'],
41
+ ['+: node.operator ->', '=', '&&'],
42
+ ]);
@@ -1,20 +1,49 @@
1
1
  import {types} from '@putout/babel';
2
- import {satisfy} from '#is';
2
+ import {createTypeChecker} from '#type-checker';
3
3
  import {chain} from './chain.js';
4
4
 
5
+ const hasPropertyWithComment = (properties) => {
6
+ return properties.find(hasComment);
7
+ };
8
+
9
+ const isPathGet = ([property]) => {
10
+ return isCallExpression(property, {
11
+ name: 'get',
12
+ });
13
+ };
14
+
5
15
  const {
6
- isUnaryExpression,
7
16
  isIfStatement,
8
17
  isCallExpression,
9
18
  isIdentifier,
10
19
  } = types;
11
20
 
12
- const isArgOfCall = (path) => path.parentPath?.isCallExpression() && path.parentPath.get('arguments.0') === path;
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
+
13
41
  const isCall = (a) => a.type === 'CallExpression';
14
42
 
15
- const isExcludedFromChain = satisfy([
16
- isUnaryExpression,
17
- isIfStatement,
43
+ const callWithRoot = (fn) => (a, {root}) => fn(root);
44
+ const isExcludedFromChain = createTypeChecker([
45
+ '+: -> UnaryExpression',
46
+ '+: -> IfStatement',
18
47
  ]);
19
48
 
20
49
  const hasComment = ({type}) => type === 'CommentLine';
@@ -32,51 +61,38 @@ const isInsideMemberCall = (path) => {
32
61
  return isCallExpression(path.parentPath.parentPath);
33
62
  };
34
63
 
35
- function isLastArgInCall(path) {
36
- const {parentPath} = path;
37
-
38
- if (!isCallExpression(parentPath))
39
- return false;
40
-
41
- return path === parentPath.get('arguments').at(-1);
42
- }
64
+ const callWithProperties = (fn) => (a, {properties}) => fn(properties);
65
+ const isFindUpIf = (path) => path.find(isIfUp);
43
66
 
44
- export const isLooksLikeChain = (path) => {
45
- const [root, properties] = chain(path);
46
-
47
- if (isInsideMemberCall(path))
48
- return false;
49
-
50
- if (isExcludedFromChain(root))
51
- return false;
52
-
53
- if (isPathGet(properties))
54
- return false;
55
-
56
- if (properties.find(hasComment))
57
- return true;
58
-
59
- if (path.find(isIfUp))
60
- return false;
61
-
67
+ const checkCallsCount = (path, {properties}) => {
62
68
  const calls = properties.filter(isCall);
63
69
  const [firstCall] = calls;
64
70
 
65
71
  if (calls.length === 2 && !firstCall.name)
66
72
  return false;
67
73
 
68
- if (isArgOfCall(path))
69
- return false;
70
-
71
74
  return calls.length > 1;
72
75
  };
73
76
 
74
- const isPathGet = ([property]) => {
75
- return isCallExpression(property, {
76
- name: 'get',
77
+ export const isLooksLikeChain = (path) => {
78
+ const [root, properties] = chain(path);
79
+
80
+ return isLikeChain(path, {
81
+ root,
82
+ properties,
77
83
  });
78
84
  };
79
85
 
86
+ const isLikeChain = createTypeChecker([
87
+ ['-', isInsideMemberCall],
88
+ ['-', callWithRoot(isExcludedFromChain)],
89
+ ['-', callWithProperties(isPathGet)],
90
+ ['+', callWithProperties(hasPropertyWithComment)],
91
+ ['-', isFindUpIf],
92
+ ['-', isFirstArgOfCall],
93
+ ['+', checkCallsCount],
94
+ ]);
95
+
80
96
  const isIfUp = (path) => {
81
97
  const ifPath = path.find(isIfStatement);
82
98
  let is = false;
@@ -1,12 +1,12 @@
1
- import {types} from '@putout/babel';
2
1
  import {maybeParens} from '#maybe-parens';
2
+ import {createTypeChecker} from '#type-checker';
3
3
  import {maybePrintComputed} from '../object-expression/maybe-print-computed.js';
4
4
  import {isLooksLikeChain} from './is-looks-like-chain.js';
5
5
 
6
- const {
7
- isObjectExpression,
8
- isArrowFunctionExpression,
9
- } = types;
6
+ const isObjectInsideArrow = createTypeChecker([
7
+ '-: node.object -> !ObjectExpression',
8
+ '+: parentPath -> ArrowFunctionExpression',
9
+ ]);
10
10
 
11
11
  export const MemberExpression = maybeParens({
12
12
  checkParens: false,
@@ -22,7 +22,6 @@ export const MemberExpression = maybeParens({
22
22
  const property = path.get('property');
23
23
 
24
24
  const {computed} = path.node;
25
-
26
25
  const isChain = isLooksLikeChain(path);
27
26
 
28
27
  traverse(object);
@@ -57,10 +56,3 @@ export const OptionalMemberExpression = maybeParens((path, {print, maybe}) => {
57
56
 
58
57
  print('__property');
59
58
  });
60
-
61
- const isObjectInsideArrow = ({node, parentPath}) => {
62
- if (!isObjectExpression(node.object))
63
- return false;
64
-
65
- return isArrowFunctionExpression(parentPath);
66
- };
@@ -1,12 +1,8 @@
1
1
  import {types} from '@putout/babel';
2
+ import {createTypeChecker} from '#type-checker';
2
3
  import {isLooksLikeChain} from '../../expressions/member-expression/is-looks-like-chain.js';
3
4
 
4
- const {
5
- isReturnStatement,
6
- isExpressionStatement,
7
- isMemberExpression,
8
- isCallExpression,
9
- } = types;
5
+ const {isCallExpression} = types;
10
6
 
11
7
  export const isCallInsideChain = (path) => {
12
8
  if (!isCallExpression(path.parentPath.parentPath))
@@ -27,21 +23,14 @@ export const isCallInsideChain = (path) => {
27
23
  return isLooksLikeChain(calleeMember);
28
24
  };
29
25
 
30
- function isTopMemberInsideCall(path) {
31
- if (!isMemberExpression(path))
32
- return false;
33
-
34
- return isExpressionStatement(path.parentPath.parentPath);
35
- }
26
+ const isTopMemberInsideCall = createTypeChecker([
27
+ '-: -> !MemberExpression',
28
+ '+: parentPath.parentPath -> ExpressionStatement',
29
+ ]);
30
+
31
+ const isTopCall = createTypeChecker([
32
+ '-: -> !CallExpression',
33
+ '+: parentPath -> ReturnStatement',
34
+ '+: parentPath -> ExpressionStatement',
35
+ ]);
36
36
 
37
- function isTopCall(path) {
38
- if (!isCallExpression(path))
39
- return false;
40
-
41
- const {parentPath} = path;
42
-
43
- if (isReturnStatement(parentPath))
44
- return true;
45
-
46
- return isExpressionStatement(parentPath);
47
- }
@@ -1,14 +1,17 @@
1
1
  const isFn = (a) => typeof a === 'function';
2
2
  const isString = (a) => typeof a === 'string';
3
+ const maybeNot = (not, a) => not ? !a : a;
3
4
 
4
5
  export const equal = (not, a, b) => {
6
+ if (!a)
7
+ return maybeNot(not, false);
8
+
9
+ const {type} = a;
10
+
5
11
  if (!isString(b))
6
12
  return false;
7
13
 
8
- if (not)
9
- return a !== b;
10
-
11
- return a === b;
14
+ return maybeNot(not, type === b);
12
15
  };
13
16
 
14
17
  export const maybeCall = (fn, not, a, options) => {
@@ -37,7 +37,7 @@ export const createTypeChecker = (typeNames, overrides = {}) => {
37
37
  if (selector)
38
38
  currentPath = jessy(selector, path);
39
39
 
40
- if (currentPath && equal(not, currentPath.type, typeName))
40
+ if (equal(not, currentPath, typeName))
41
41
  return [index, result];
42
42
 
43
43
  if (maybeCall(typeName, not, currentPath, options))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/printer",
3
- "version": "18.7.4",
3
+ "version": "18.7.6",
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",