@putout/printer 18.4.3 → 18.4.4

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.11, v18.4.4
2
+
3
+ feature:
4
+ - 05d3e90 @putout/printer: BinaryExpression: isConcatenation
5
+ - b293a10 @putout/printer: ClassDeclaration: simplify
6
+ - e47c537 @putout/printer: ClassDeclaration: simplify
7
+
1
8
  2026.03.10, v18.4.3
2
9
 
3
10
  fix:
@@ -2,8 +2,10 @@ import {types} from '@putout/babel';
2
2
  import {createTypeChecker} from '#type-checker';
3
3
 
4
4
  const {isBinaryExpression} = types;
5
+ const isPlus = (a) => a === '+';
5
6
 
6
7
  export const isConcatenation = createTypeChecker([
8
+ ['-: node.operator -> !', isPlus],
7
9
  ['-: node.loc', isSameLine],
8
10
  ['+', isBinaryExpression],
9
11
  ]);
@@ -1,25 +1,38 @@
1
1
  import {types} from '@putout/babel';
2
2
  import {markAfter} from '#mark';
3
3
  import {maybeDeclare} from '#maybe-declare';
4
+ import {createTypeChecker} from '#type-checker';
4
5
  import {
5
6
  hasBody,
6
- isInsideExport,
7
- isInsideTSModuleBlock,
7
+ isInsideExportDeclaration,
8
8
  isNext,
9
9
  } from '#is';
10
10
  import {parseComments} from '../../comment/comment.js';
11
11
  import {maybeDecorators} from '../../maybe/maybe-decorators.js';
12
12
 
13
+ const isFunctionLike = (path) => isFunction(path.parentPath.parentPath);
14
+
15
+ const afterIf = createTypeChecker([
16
+ ['+', isFunctionLike],
17
+ ['+', isNext],
18
+ ['+: parentPath.parentPath -> TSModuleBlock'],
19
+ ]);
20
+
13
21
  const {isFunction} = types;
22
+ const isLessThenTwo = (a) => a < 2;
14
23
 
15
- const isFunctionLike = (path) => isFunction(path.parentPath.parentPath);
24
+ const isSpaceBeforeImplements = createTypeChecker([
25
+ ['+: node.typeParameters -> !', Boolean],
26
+ ['+: node.typeParameters.params.length', isLessThenTwo],
27
+ ]);
16
28
 
17
29
  const classVisitor = maybeDecorators((path, printer, semantics) => {
30
+ const {node} = path;
18
31
  const {
19
32
  id,
20
33
  abstract,
21
34
  superClass,
22
- } = path.node;
35
+ } = node;
23
36
 
24
37
  const {
25
38
  print,
@@ -34,8 +47,6 @@ const classVisitor = maybeDecorators((path, printer, semantics) => {
34
47
  print('__id');
35
48
  print('__typeParameters');
36
49
 
37
- const {node} = path;
38
-
39
50
  if (node.superClass) {
40
51
  maybe.print(id, ' ');
41
52
  print('extends ');
@@ -44,9 +55,7 @@ const classVisitor = maybeDecorators((path, printer, semantics) => {
44
55
  }
45
56
 
46
57
  if (node.implements) {
47
- const {typeParameters} = node;
48
-
49
- if (!typeParameters || typeParameters.params.length < 2)
58
+ if (isSpaceBeforeImplements(path))
50
59
  print(' ');
51
60
 
52
61
  print('implements ');
@@ -62,7 +71,10 @@ const classVisitor = maybeDecorators((path, printer, semantics) => {
62
71
 
63
72
  print.space();
64
73
  print('{');
65
- maybe.print.newline(path.node.body.body.length);
74
+
75
+ if (hasBody(path))
76
+ print.newline();
77
+
66
78
  indent.inc();
67
79
 
68
80
  const classBody = path.get('body');
@@ -73,33 +85,32 @@ const classVisitor = maybeDecorators((path, printer, semantics) => {
73
85
  traverse(item);
74
86
  }
75
87
 
76
- if (!body.length)
88
+ if (!hasBody(path))
77
89
  parseComments(classBody, printer, semantics);
78
90
 
79
91
  indent.dec();
80
- maybe.indent(body.length);
92
+
93
+ if (hasBody(path))
94
+ indent();
95
+
81
96
  print('}');
82
97
  });
83
98
 
84
99
  export const ClassExpression = classVisitor;
85
100
 
101
+ const beforeIf = createTypeChecker([
102
+ ['+: -> !', isInsideExportDeclaration],
103
+ ]);
104
+
86
105
  export const ClassDeclaration = {
106
+ beforeIf,
107
+ before: (path, {indent}) => {
108
+ indent();
109
+ },
87
110
  print: maybeDeclare((path, printer, semantics) => {
88
- const {maybe} = printer;
89
- maybe.indent(!isInsideExport(path));
90
111
  classVisitor(path, printer, semantics);
91
112
  }),
92
- afterIf(path) {
93
- const {parentPath} = path;
94
-
95
- if (isFunctionLike(path))
96
- return true;
97
-
98
- if (isNext(path))
99
- return true;
100
-
101
- return isInsideTSModuleBlock(parentPath);
102
- },
113
+ afterIf,
103
114
  after(path, {write}) {
104
115
  write.newline();
105
116
 
@@ -9,7 +9,6 @@ import {
9
9
  import {createTypeChecker} from '#type-checker';
10
10
 
11
11
  const {
12
- isExportNamedDeclaration,
13
12
  isExpressionStatement,
14
13
  isFunctionDeclaration,
15
14
  } = types;
@@ -33,9 +32,15 @@ const isInsideBlockLike = createTypeChecker([
33
32
  ['+: -> !', hasFnBody],
34
33
  ]);
35
34
 
36
- const isInsideNamedExport = ({parentPath}) => isExportNamedDeclaration(parentPath);
35
+ const beforeIf = createTypeChecker([
36
+ '+: parentPath -> !ExportNamedDeclaration',
37
+ ]);
37
38
 
38
39
  export const FunctionDeclaration = {
40
+ beforeIf,
41
+ before: (path, {indent}) => {
42
+ indent();
43
+ },
39
44
  print(path, printer, semantics) {
40
45
  const {print, maybe} = printer;
41
46
 
@@ -45,7 +50,6 @@ export const FunctionDeclaration = {
45
50
  returnType,
46
51
  } = path.node;
47
52
 
48
- maybe.indent(!isInsideNamedExport(path));
49
53
  maybe.print(async, 'async ');
50
54
 
51
55
  print('function');
@@ -17,6 +17,7 @@ const {
17
17
  isTSModuleBlock,
18
18
  isSwitchCase,
19
19
  isExpressionStatement,
20
+ isExportDeclaration,
20
21
  } = types;
21
22
 
22
23
  export const isInsideProgram = (path) => isProgram(path.parentPath);
@@ -28,20 +29,19 @@ export const isInsideArray = (path) => isArrayExpression(path.parentPath);
28
29
 
29
30
  export const isInsideTSModuleBlock = ({parentPath}) => isTSModuleBlock(parentPath);
30
31
 
32
+ export const isInsideExportDeclaration = ({parentPath}) => isExportDeclaration(parentPath);
31
33
  export const isInsideCall = ({parentPath}) => parentPath.isCallExpression();
32
34
  export const isInsideReturn = ({parentPath}) => parentPath.isReturnStatement();
33
35
  export const callWithNext = (fn) => (path) => fn(path.getNextSibling());
34
36
  export const callWithPrev = (fn) => (path) => fn(path.getPrevSibling());
35
37
  export const callWithParent = (fn) => (path) => fn(path.parentPath);
36
38
 
37
- export const isNext = (path) => {
38
- const next = path.getNextSibling();
39
-
39
+ export const isNext = callWithNext((next) => {
40
40
  if (!next.node)
41
41
  return false;
42
42
 
43
43
  return !next.isEmptyStatement();
44
- };
44
+ });
45
45
 
46
46
  export const hasBody = ({node}) => node.body.body.length;
47
47
 
@@ -172,7 +172,6 @@ export const isForOf = (path) => {
172
172
  };
173
173
 
174
174
  export const isInsideIf = (path) => path.parentPath?.isIfStatement();
175
- export const isInsideExport = ({parentPath}) => parentPath.isExportDeclaration();
176
175
 
177
176
  export const isNewlineBetweenSiblings = (path) => {
178
177
  const endCurrent = path.node?.loc?.end?.line;
@@ -11,7 +11,7 @@ import {
11
11
  noTrailingComment,
12
12
  isInsideIf,
13
13
  isInsideBlock,
14
- isInsideExport,
14
+ isInsideExportDeclaration,
15
15
  isInsideTSModuleBlock,
16
16
  isInsideProgram,
17
17
  isInsideSwitchCase,
@@ -136,7 +136,7 @@ export const VariableDeclaration = {
136
136
  isNextCoupleLines,
137
137
  notLastPrevVarNotNextVar,
138
138
  isNewlineBetweenSiblings,
139
- isInsideExport,
139
+ isInsideExportDeclaration,
140
140
  isParentTSModuleBlock,
141
141
  ],
142
142
  after(path, {maybe, store, print}) {
@@ -3,8 +3,6 @@ import {instrument as _instrument} from '#type-checker/instrument';
3
3
  import {parseOperation, parseTypeNames} from './parsers.js';
4
4
  import {equal, maybeCall} from './comparators.js';
5
5
 
6
- const isUndefined = (a) => typeof a === 'undefined';
7
-
8
6
  const SKIP = [
9
7
  Infinity,
10
8
  false,
@@ -39,9 +37,6 @@ export const createTypeChecker = (typeNames, overrides = {}) => {
39
37
  if (selector)
40
38
  currentPath = jessy(selector, path);
41
39
 
42
- if (isUndefined(currentPath))
43
- return SKIP;
44
-
45
40
  if (currentPath && equal(not, currentPath.type, typeName))
46
41
  return [index, result];
47
42
 
@@ -64,4 +64,3 @@ export const TSTypeAliasDeclaration = {
64
64
  markAfter(path);
65
65
  },
66
66
  };
67
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/printer",
3
- "version": "18.4.3",
3
+ "version": "18.4.4",
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",