@putout/printer 17.13.0 → 18.0.1
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 +23 -0
- package/README.md +1 -1
- package/lib/tokenize/expressions/array-expression/newline.js +31 -9
- package/lib/tokenize/expressions/assignment-expression/assignment-expression.js +3 -3
- package/lib/tokenize/expressions/call-expression/call-expression.js +2 -2
- package/lib/tokenize/expressions/function/function-declaration.js +1 -1
- package/lib/tokenize/expressions/object-expression/object-expression.js +1 -2
- package/lib/tokenize/is.js +6 -4
- package/lib/tokenize/overrides/overrides.js +1 -1
- package/lib/tokenize/statements/block-statement/block-statement-newline.js +98 -0
- package/lib/tokenize/statements/block-statement/block-statement.js +2 -111
- package/lib/tokenize/statements/break-statement/break-statement.js +2 -2
- package/lib/tokenize/statements/debugger-statement.js +2 -2
- package/lib/tokenize/statements/export-declaration/export-declaration.js +2 -2
- package/lib/tokenize/statements/expression-statement/expression-statement.js +2 -2
- package/lib/tokenize/statements/if-statement/if-statement-comments.js +2 -2
- package/lib/tokenize/statements/try-statement/try-statements.js +2 -2
- package/lib/tokenize/statements/variable-declaration/variable-declaration.js +32 -14
- package/lib/tokenize/type-checker/comparators.js +24 -0
- package/lib/tokenize/type-checker/create-tuple.js +17 -0
- package/lib/tokenize/type-checker/parsers.js +51 -0
- package/lib/tokenize/type-checker/type-checker.js +4 -94
- package/package.json +4 -3
package/ChangeLog
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
2026.03.04, v18.0.1
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- 5e6e906 @putout/printer: VariableDeclaration: after: simplify
|
|
5
|
+
- 852f982 @putout/printer: @putout/plugin-printer v8.0.0
|
|
6
|
+
- 7b3977d @putout/printer: VariableDeclaration: skipAfter
|
|
7
|
+
- 4f43a9f VariableDeclaration: isNeedNewline
|
|
8
|
+
- 9dece24 @putout/printer: VariableDeclaration: isSemicolon
|
|
9
|
+
- b9a27e0 @putout/printer: VariableDeclaration: isInsideIf
|
|
10
|
+
- 06d6255 @putout/printer: is: isParentProgram -> isInsideProgram
|
|
11
|
+
- 2a0ef4e is: isParentBlock -> isInsideBlock
|
|
12
|
+
|
|
13
|
+
2026.03.04, v18.0.0
|
|
14
|
+
|
|
15
|
+
feature:
|
|
16
|
+
- 1aaf942 @putout/printer: ArrayExpression: newline: is more then max element length in one line
|
|
17
|
+
- a0d465b @putout/printer: maxElementLengthInOneLine: 10 -> 15
|
|
18
|
+
- eea22ae @putout/printer: BlockStatement: newline: simplify
|
|
19
|
+
- c9c9f34 @putout/printer: BlockStatement: isMethodOrArrow: simplify
|
|
20
|
+
- 010780c @putout/printer: private-imports: #type-checker
|
|
21
|
+
- 9a4b938 BlockStatements: apply type-checker
|
|
22
|
+
- 9357d36 type-checker: simplify
|
|
23
|
+
|
|
1
24
|
2026.03.04, v17.13.0
|
|
2
25
|
|
|
3
26
|
feature:
|
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {isSimple} from '@putout/operate';
|
|
2
2
|
import {types} from '@putout/babel';
|
|
3
|
+
import {createTypeChecker} from '#type-checker';
|
|
3
4
|
import {
|
|
4
5
|
isStringAndMember,
|
|
5
6
|
isStringAndIdentifier,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
isStringAndArray,
|
|
9
10
|
isIdentifierAndIdentifier,
|
|
10
11
|
isSimpleAndNotEmptyObject,
|
|
12
|
+
isInsideCall,
|
|
11
13
|
} from '#is';
|
|
12
14
|
|
|
13
15
|
const {
|
|
@@ -57,6 +59,28 @@ const isSiblingIsArray = (path) => {
|
|
|
57
59
|
.isArrayExpression();
|
|
58
60
|
};
|
|
59
61
|
|
|
62
|
+
const isEmptyArray = (path) => !path.node.elements.length;
|
|
63
|
+
|
|
64
|
+
const isAllLiterals = (path) => {
|
|
65
|
+
const {elements} = path.node;
|
|
66
|
+
const literals = elements.filter(isStringLiteral);
|
|
67
|
+
|
|
68
|
+
return literals.length !== elements.length;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const isMoreThenMaxLiteralLength = (path, {maxElementLengthInOneLine}) => {
|
|
72
|
+
const [first] = path.node.elements;
|
|
73
|
+
|
|
74
|
+
return first.value.length > maxElementLengthInOneLine;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const isMoreThenMaxElementLengthInOneLine = createTypeChecker([
|
|
78
|
+
['-', isEmptyArray],
|
|
79
|
+
['-: -> !', isInsideCall],
|
|
80
|
+
['-', isAllLiterals],
|
|
81
|
+
['+', isMoreThenMaxLiteralLength],
|
|
82
|
+
]);
|
|
83
|
+
|
|
60
84
|
function isMaxElementLengthInOneLine(elements, maxElementLengthInOneLine) {
|
|
61
85
|
if (elements.length > 1)
|
|
62
86
|
return false;
|
|
@@ -75,6 +99,9 @@ export const isMultiLine = (path, {elements, maxElementsInOneLine, maxElementLen
|
|
|
75
99
|
if (isMaxElementLengthInOneLine(elements, maxElementLengthInOneLine))
|
|
76
100
|
return ONE_LINE;
|
|
77
101
|
|
|
102
|
+
if (isMoreThenMaxElementLengthInOneLine(path, {elements, maxElementLengthInOneLine}))
|
|
103
|
+
return MULTI_LINE;
|
|
104
|
+
|
|
78
105
|
if (elements.length > maxElementsInOneLine && isStringLiteral(first))
|
|
79
106
|
return MULTI_LINE;
|
|
80
107
|
|
|
@@ -194,9 +221,6 @@ function isOneSimple(path) {
|
|
|
194
221
|
|
|
195
222
|
const [first] = elements;
|
|
196
223
|
|
|
197
|
-
if (first.isIdentifier() && first.node.name.length < 15)
|
|
198
|
-
return true;
|
|
199
|
-
|
|
200
224
|
if (first.isStringLiteral() && first.node.value.length > 10)
|
|
201
225
|
return false;
|
|
202
226
|
|
|
@@ -288,12 +312,10 @@ export function isIncreaseIndent(path) {
|
|
|
288
312
|
return isStringAndObject(elements);
|
|
289
313
|
}
|
|
290
314
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
return path.parentPath.parentPath.isForOfStatement();
|
|
296
|
-
}
|
|
315
|
+
const isInsideCallLoop = createTypeChecker([
|
|
316
|
+
['-: -> !', isInsideCall],
|
|
317
|
+
'+: parentPath.parentPath -> ForOfStatement',
|
|
318
|
+
]);
|
|
297
319
|
|
|
298
320
|
const isStringAndObject = (elements) => {
|
|
299
321
|
const first = elements.at(0);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {maybeParens} from '#maybe-parens';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
isInsideBlock,
|
|
4
|
+
isInsideProgram,
|
|
5
5
|
} from '#is';
|
|
6
6
|
import {condition} from './maybe-parens-condition.js';
|
|
7
7
|
import {printSeparator} from './print-separator.js';
|
|
@@ -27,7 +27,7 @@ export const AssignmentExpression = maybeParens({
|
|
|
27
27
|
printSeparator(path, printer);
|
|
28
28
|
print('__right');
|
|
29
29
|
|
|
30
|
-
if (
|
|
30
|
+
if (isInsideBlock(path) || isInsideProgram(path)) {
|
|
31
31
|
print(';');
|
|
32
32
|
print.breakline();
|
|
33
33
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {exists} from '#is';
|
|
1
|
+
import {exists, isInsideCall} from '#is';
|
|
2
2
|
import {maybeParens} from '#maybe-parens';
|
|
3
3
|
|
|
4
4
|
const {isArray} = Array;
|
|
@@ -14,7 +14,7 @@ const parseArgs = (path) => {
|
|
|
14
14
|
|
|
15
15
|
export const CallExpression = maybeParens((path, {indent, print, maybe, traverse}) => {
|
|
16
16
|
const args = parseArgs(path);
|
|
17
|
-
const isParentCall = tooLong(args) && path
|
|
17
|
+
const isParentCall = tooLong(args) && isInsideCall(path);
|
|
18
18
|
|
|
19
19
|
const callee = path.get('callee');
|
|
20
20
|
const typeParameters = path.get('typeArguments');
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
noLeadingComment,
|
|
9
9
|
hasLeadingComment,
|
|
10
10
|
exists,
|
|
11
|
+
isInsideCall,
|
|
11
12
|
} from '#is';
|
|
12
13
|
import {parseComments} from '../../comment/comment.js';
|
|
13
14
|
import {isInsideTuple} from './is-inside-tuple.js';
|
|
@@ -37,8 +38,6 @@ const isMemberExpressionCallee = ({parentPath}) => {
|
|
|
37
38
|
return isLooksLikeChain(callee);
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
const isInsideCall = ({parentPath}) => parentPath.isCallExpression();
|
|
41
|
-
|
|
42
41
|
function isInsideNestedArrayCall({parentPath}) {
|
|
43
42
|
if (!isArrayExpression(parentPath))
|
|
44
43
|
return false;
|
package/lib/tokenize/is.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {createTypeChecker} from '
|
|
2
|
+
import {createTypeChecker} from '#type-checker';
|
|
3
3
|
|
|
4
4
|
const {
|
|
5
5
|
isStringLiteral,
|
|
@@ -18,8 +18,8 @@ const {
|
|
|
18
18
|
isTSModuleBlock,
|
|
19
19
|
} = types;
|
|
20
20
|
|
|
21
|
-
export const
|
|
22
|
-
export const
|
|
21
|
+
export const isInsideProgram = (path) => isProgram(path.parentPath);
|
|
22
|
+
export const isInsideBlock = (path) => isBlockStatement(path.parentPath);
|
|
23
23
|
|
|
24
24
|
export const isParentBlockLike = createTypeChecker('path.parentPath', [
|
|
25
25
|
'Program',
|
|
@@ -32,6 +32,8 @@ export const isInsideTSModuleBlock = ({parentPath}) => {
|
|
|
32
32
|
return isTSModuleBlock(parentPath?.parentPath);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
export const isInsideCall = ({parentPath}) => parentPath.isCallExpression();
|
|
36
|
+
|
|
35
37
|
export const isNext = (path) => {
|
|
36
38
|
const next = path.getNextSibling();
|
|
37
39
|
|
|
@@ -57,7 +59,7 @@ export const isPrev = (path) => {
|
|
|
57
59
|
};
|
|
58
60
|
|
|
59
61
|
export const isNextParent = (path) => isNext(path.parentPath);
|
|
60
|
-
export const isLast = (path) =>
|
|
62
|
+
export const isLast = (path) => isInsideProgram(path) && !isNext(path);
|
|
61
63
|
|
|
62
64
|
export const isNextObject = (a) => a
|
|
63
65
|
.getNextSibling()
|
|
@@ -33,7 +33,7 @@ const initSemantics = (format, semantics = {}) => ({
|
|
|
33
33
|
maxPropertiesLengthInOneLine: 15,
|
|
34
34
|
maxSpecifiersInOneLine: 2,
|
|
35
35
|
maxElementsInOneLine: 5,
|
|
36
|
-
maxElementLengthInOneLine:
|
|
36
|
+
maxElementLengthInOneLine: 15,
|
|
37
37
|
maxLogicalsInOneLine: 3,
|
|
38
38
|
maxVariablesInOneLine: 4,
|
|
39
39
|
maxTypesInOneLine: 3,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {types} from '@putout/babel';
|
|
2
|
+
import {createTypeChecker} from '#type-checker';
|
|
3
|
+
import {
|
|
4
|
+
isNext,
|
|
5
|
+
isInsideProgram,
|
|
6
|
+
isLast,
|
|
7
|
+
exists,
|
|
8
|
+
satisfy,
|
|
9
|
+
isInsideBlock,
|
|
10
|
+
} from '#is';
|
|
11
|
+
import {insideIfWithNoBody} from './inside-if-with-no-body.js';
|
|
12
|
+
|
|
13
|
+
const parentIfWithoutElse = ({parentPath}) => {
|
|
14
|
+
if (!parentPath.isIfStatement())
|
|
15
|
+
return false;
|
|
16
|
+
|
|
17
|
+
return !parentPath.node.alternate;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
isFunctionDeclaration,
|
|
22
|
+
isExportDeclaration,
|
|
23
|
+
isDoWhileStatement,
|
|
24
|
+
} = types;
|
|
25
|
+
|
|
26
|
+
const isTopLevelWithNoNext = (path) => {
|
|
27
|
+
if (isNext(path))
|
|
28
|
+
return false;
|
|
29
|
+
|
|
30
|
+
return !isNext(path.parentPath) && isInsideProgram(path.parentPath);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const isInsideDoWhile = ({parentPath}) => isDoWhileStatement(parentPath);
|
|
34
|
+
const isMethodOrArrow = createTypeChecker(['ArrowFunctionExpression', 'ObjectMethod']);
|
|
35
|
+
const isInsideFn = (path) => path.find(isMethodOrArrow);
|
|
36
|
+
|
|
37
|
+
const isInsideIfWithoutElseInsideFn = createTypeChecker([
|
|
38
|
+
['-: -> !', parentIfWithoutElse],
|
|
39
|
+
['+', isInsideFn],
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const isEmptyBodyNoNext = (path) => {
|
|
43
|
+
const {parentPath} = path;
|
|
44
|
+
return parentPath.isStatement() && !path.node.body.length && !isNext(parentPath);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const isLooksLikeInsideFn = ({parentPath}) => {
|
|
48
|
+
return /FunctionExpression/.test(parentPath.type);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const isNoNewline = satisfy([
|
|
52
|
+
isInsideDoWhile,
|
|
53
|
+
isTopLevelWithNoNext,
|
|
54
|
+
insideIfWithNoBody,
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
export const shouldAddNewlineAfter = createTypeChecker([
|
|
58
|
+
['+', isInsideBlock],
|
|
59
|
+
['-', isNoNewline],
|
|
60
|
+
['+', isInsideIfWithoutElseInsideFn],
|
|
61
|
+
['-', isEmptyBodyNoNext],
|
|
62
|
+
['-', isTry],
|
|
63
|
+
['-', isLooksLikeInsideFn],
|
|
64
|
+
['-', isLast],
|
|
65
|
+
['-', isExportFunction],
|
|
66
|
+
['+: -> !', isNextIfAlternate],
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
function isExportFunction(path) {
|
|
70
|
+
if (!isFunctionDeclaration(path.parentPath))
|
|
71
|
+
return false;
|
|
72
|
+
|
|
73
|
+
if (!isExportDeclaration(path.parentPath?.parentPath))
|
|
74
|
+
return false;
|
|
75
|
+
|
|
76
|
+
return !isNext(path.parentPath?.parentPath);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isNextIfAlternate(path) {
|
|
80
|
+
const {parentPath} = path;
|
|
81
|
+
|
|
82
|
+
if (!parentPath.isIfStatement())
|
|
83
|
+
return false;
|
|
84
|
+
|
|
85
|
+
const alternate = parentPath.get('alternate');
|
|
86
|
+
|
|
87
|
+
if (path === alternate)
|
|
88
|
+
return false;
|
|
89
|
+
|
|
90
|
+
return exists(alternate);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isTry({parentPath}) {
|
|
94
|
+
if (parentPath.isTryStatement())
|
|
95
|
+
return true;
|
|
96
|
+
|
|
97
|
+
return parentPath.parentPath?.isTryStatement();
|
|
98
|
+
}
|
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
import {markAfter} from '#mark';
|
|
3
|
-
import {
|
|
4
|
-
isNext,
|
|
5
|
-
isParentProgram,
|
|
6
|
-
isLast,
|
|
7
|
-
exists,
|
|
8
|
-
satisfy,
|
|
9
|
-
isParentBlock,
|
|
10
|
-
} from '#is';
|
|
3
|
+
import {isNext} from '#is';
|
|
11
4
|
import {parseComments} from '../../comment/comment.js';
|
|
12
|
-
import {insideIfWithNoBody} from './inside-if-with-no-body.js';
|
|
13
5
|
import {getDirectives} from './get-directives.js';
|
|
14
6
|
import {isCallInsideChain} from './is-call-inside-chain.js';
|
|
7
|
+
import {shouldAddNewlineAfter} from './block-statement-newline.js';
|
|
15
8
|
|
|
16
9
|
const {
|
|
17
|
-
isArrowFunctionExpression,
|
|
18
10
|
isObjectMethod,
|
|
19
|
-
isFunctionDeclaration,
|
|
20
|
-
isExportDeclaration,
|
|
21
|
-
isDoWhileStatement,
|
|
22
11
|
isArrayExpression,
|
|
23
12
|
} = types;
|
|
24
13
|
|
|
25
14
|
const isFirstStatement = (path) => path.node.body[0];
|
|
26
15
|
const isFirstDirective = (path) => path.node.directives?.[0];
|
|
27
|
-
const isMethodOrArrow = (path) => isArrowFunctionExpression(path) || isObjectMethod(path);
|
|
28
16
|
|
|
29
17
|
const isInsideArrayTupleOfThree = (path) => {
|
|
30
18
|
const {parentPath} = path.parentPath;
|
|
@@ -37,13 +25,6 @@ const isInsideArrayTupleOfThree = (path) => {
|
|
|
37
25
|
return length === 3;
|
|
38
26
|
};
|
|
39
27
|
|
|
40
|
-
const parentIfWithoutElse = ({parentPath}) => {
|
|
41
|
-
if (!parentPath.isIfStatement())
|
|
42
|
-
return false;
|
|
43
|
-
|
|
44
|
-
return !parentPath.node.alternate;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
28
|
export const BlockStatement = {
|
|
48
29
|
print(path, printer, semantics) {
|
|
49
30
|
const {trailingComma} = semantics;
|
|
@@ -102,93 +83,3 @@ export const BlockStatement = {
|
|
|
102
83
|
markAfter(path.parentPath);
|
|
103
84
|
},
|
|
104
85
|
};
|
|
105
|
-
|
|
106
|
-
const isTopLevelWithNoNext = (path) => {
|
|
107
|
-
if (isNext(path))
|
|
108
|
-
return false;
|
|
109
|
-
|
|
110
|
-
return !isNext(path.parentPath) && isParentProgram(path.parentPath);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const isInsideIfWithoutElseInsideFn = (path) => {
|
|
114
|
-
return parentIfWithoutElse(path) && path.find(isMethodOrArrow);
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const isEmptyBodyNoNext = (path) => {
|
|
118
|
-
const {parentPath} = path;
|
|
119
|
-
return parentPath.isStatement() && !path.node.body.length && !isNext(parentPath);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const isLooksLikeInsideFn = ({parentPath}) => {
|
|
123
|
-
return /FunctionExpression/.test(parentPath.type);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const NEWLINE = true;
|
|
127
|
-
const NO_NEWLINE = false;
|
|
128
|
-
|
|
129
|
-
const isInsideDoWhile = ({parentPath}) => isDoWhileStatement(parentPath);
|
|
130
|
-
|
|
131
|
-
const isNoNewline = satisfy([
|
|
132
|
-
isInsideDoWhile,
|
|
133
|
-
isTopLevelWithNoNext,
|
|
134
|
-
insideIfWithNoBody,
|
|
135
|
-
]);
|
|
136
|
-
|
|
137
|
-
function shouldAddNewlineAfter(path) {
|
|
138
|
-
if (isParentBlock(path))
|
|
139
|
-
return NEWLINE;
|
|
140
|
-
|
|
141
|
-
if (isNoNewline(path))
|
|
142
|
-
return NO_NEWLINE;
|
|
143
|
-
|
|
144
|
-
if (isInsideIfWithoutElseInsideFn(path))
|
|
145
|
-
return NEWLINE;
|
|
146
|
-
|
|
147
|
-
if (isEmptyBodyNoNext(path))
|
|
148
|
-
return NO_NEWLINE;
|
|
149
|
-
|
|
150
|
-
if (isTry(path))
|
|
151
|
-
return NO_NEWLINE;
|
|
152
|
-
|
|
153
|
-
if (isLooksLikeInsideFn(path))
|
|
154
|
-
return NO_NEWLINE;
|
|
155
|
-
|
|
156
|
-
if (isLast(path))
|
|
157
|
-
return NO_NEWLINE;
|
|
158
|
-
|
|
159
|
-
if (isExportFunction(path))
|
|
160
|
-
return NO_NEWLINE;
|
|
161
|
-
|
|
162
|
-
return !isNextIfAlternate(path);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function isExportFunction(path) {
|
|
166
|
-
if (!isFunctionDeclaration(path.parentPath))
|
|
167
|
-
return false;
|
|
168
|
-
|
|
169
|
-
if (!isExportDeclaration(path.parentPath?.parentPath))
|
|
170
|
-
return false;
|
|
171
|
-
|
|
172
|
-
return !isNext(path.parentPath?.parentPath);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function isNextIfAlternate(path) {
|
|
176
|
-
const {parentPath} = path;
|
|
177
|
-
|
|
178
|
-
if (!parentPath.isIfStatement())
|
|
179
|
-
return false;
|
|
180
|
-
|
|
181
|
-
const alternate = parentPath.get('alternate');
|
|
182
|
-
|
|
183
|
-
if (path === alternate)
|
|
184
|
-
return false;
|
|
185
|
-
|
|
186
|
-
return exists(alternate);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function isTry({parentPath}) {
|
|
190
|
-
if (parentPath.isTryStatement())
|
|
191
|
-
return true;
|
|
192
|
-
|
|
193
|
-
return parentPath.parentPath?.isTryStatement();
|
|
194
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
isInsideBlock,
|
|
3
3
|
isNextParent,
|
|
4
4
|
isInsideIf,
|
|
5
5
|
isInsideLabel,
|
|
@@ -21,7 +21,7 @@ export const BreakStatement = {
|
|
|
21
21
|
print(';');
|
|
22
22
|
},
|
|
23
23
|
afterSatisfy: () => [
|
|
24
|
-
|
|
24
|
+
isInsideBlock,
|
|
25
25
|
isNextParent,
|
|
26
26
|
isInsideCase,
|
|
27
27
|
isInsideIf,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isNext,
|
|
3
3
|
isInsideIf,
|
|
4
|
-
|
|
4
|
+
isInsideBlock,
|
|
5
5
|
} from '#is';
|
|
6
6
|
|
|
7
7
|
export const DebuggerStatement = {
|
|
@@ -11,7 +11,7 @@ export const DebuggerStatement = {
|
|
|
11
11
|
},
|
|
12
12
|
afterSatisfy: () => [
|
|
13
13
|
isNext,
|
|
14
|
-
|
|
14
|
+
isInsideBlock,
|
|
15
15
|
isInsideIf,
|
|
16
16
|
],
|
|
17
17
|
after(path, {print}) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
import {printAttributes} from '#import-attributes';
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
isInsideBlock,
|
|
5
5
|
isNewlineBetweenSiblings,
|
|
6
6
|
exists,
|
|
7
7
|
isNext,
|
|
@@ -169,7 +169,7 @@ export const ExportNamedDeclaration = {
|
|
|
169
169
|
if (isNewlineBetweenSiblings(path))
|
|
170
170
|
return true;
|
|
171
171
|
|
|
172
|
-
return
|
|
172
|
+
return isInsideBlock(path);
|
|
173
173
|
},
|
|
174
174
|
after(path, {print, indent}) {
|
|
175
175
|
const next = path.getNextSibling();
|
|
@@ -2,7 +2,7 @@ import {types} from '@putout/babel';
|
|
|
2
2
|
import {
|
|
3
3
|
isNext,
|
|
4
4
|
isLast,
|
|
5
|
-
|
|
5
|
+
isInsideBlock,
|
|
6
6
|
isParentLast,
|
|
7
7
|
isNewlineBetweenSiblings,
|
|
8
8
|
satisfy,
|
|
@@ -42,7 +42,7 @@ const notInsideReturn = not(isInsideReturn);
|
|
|
42
42
|
|
|
43
43
|
const satisfyAfter = satisfy([
|
|
44
44
|
isNotLastOrParentLast,
|
|
45
|
-
|
|
45
|
+
isInsideBlock,
|
|
46
46
|
isNext,
|
|
47
47
|
isNextUp,
|
|
48
48
|
]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {isNext,
|
|
2
|
+
import {isNext, isInsideBlock} from '#is';
|
|
3
3
|
|
|
4
4
|
const {isBlockStatement} = types;
|
|
5
5
|
|
|
@@ -24,6 +24,6 @@ export const printTrailingCommentLine = (path, printer, semantics, {printComment
|
|
|
24
24
|
|
|
25
25
|
printComment();
|
|
26
26
|
|
|
27
|
-
if (hasNext ||
|
|
27
|
+
if (hasNext || isInsideBlock(path))
|
|
28
28
|
print.newline();
|
|
29
29
|
};
|
|
@@ -2,7 +2,7 @@ import {types} from '@putout/babel';
|
|
|
2
2
|
import {
|
|
3
3
|
isNext,
|
|
4
4
|
isNextTry,
|
|
5
|
-
|
|
5
|
+
isInsideBlock,
|
|
6
6
|
} from '#is';
|
|
7
7
|
|
|
8
8
|
const {isExpressionStatement} = types;
|
|
@@ -55,5 +55,5 @@ export const CatchClause = (path, {print, maybe}) => {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
print(body);
|
|
58
|
-
maybe.print.newline(
|
|
58
|
+
maybe.print.newline(isInsideBlock(parentPath));
|
|
59
59
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
2
|
import {hasPrevNewline} from '#mark';
|
|
3
|
+
import {createTypeChecker} from '#type-checker';
|
|
3
4
|
import {
|
|
4
5
|
isNext,
|
|
5
6
|
isCoupleLines,
|
|
@@ -7,27 +8,43 @@ import {
|
|
|
7
8
|
exists,
|
|
8
9
|
noTrailingComment,
|
|
9
10
|
isParentBlockLike,
|
|
11
|
+
isInsideIf,
|
|
12
|
+
isInsideBlock,
|
|
10
13
|
} from '#is';
|
|
11
14
|
import {maybeSpaceAfterKeyword} from './maybe-space-after-keyword.js';
|
|
12
15
|
import {isConcatenation} from '../../expressions/binary-expression/concatenate.js';
|
|
13
16
|
import {parseLeadingComments} from '../../comment/comment.js';
|
|
14
17
|
import {maybeDeclare} from '../../maybe/maybe-declare.js';
|
|
15
|
-
|
|
18
|
+
|
|
19
|
+
const isLast = (path) => path.parentPath?.isProgram() && !isNext(path);
|
|
16
20
|
|
|
17
21
|
const {isExportDeclaration} = types;
|
|
18
22
|
|
|
19
23
|
const isParentTSModuleBlock = (path) => path.parentPath.isTSModuleBlock();
|
|
20
24
|
const isParentSwitchCase = (path) => path.parentPath.isSwitchCase();
|
|
21
25
|
const isFirstInSwitch = (path) => path.parentPath.get('consequent.0') === path;
|
|
22
|
-
const isParentIf = (path) => path.parentPath.isIfStatement();
|
|
23
26
|
|
|
24
|
-
const
|
|
27
|
+
const isIsideParentLike = createTypeChecker('path.parentPath', [
|
|
25
28
|
'Program',
|
|
26
29
|
'BlockStatement',
|
|
27
30
|
'ExportNamedDeclaration',
|
|
28
31
|
'LabeledStatement',
|
|
29
32
|
]);
|
|
30
33
|
|
|
34
|
+
const isNeedSemicolon = createTypeChecker([
|
|
35
|
+
isIsideParentLike,
|
|
36
|
+
isParentSwitchCase,
|
|
37
|
+
isParentTSModuleBlock,
|
|
38
|
+
isInsideIf,
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
const isNeedNewline = createTypeChecker([
|
|
42
|
+
['-: -> !', isIsideParentLike],
|
|
43
|
+
['-: -> !', isNext],
|
|
44
|
+
['+', noTrailingComment],
|
|
45
|
+
['+', isNewlineBetweenSiblings],
|
|
46
|
+
]);
|
|
47
|
+
|
|
31
48
|
export const VariableDeclaration = {
|
|
32
49
|
beforeIf: shouldAddNewlineBefore,
|
|
33
50
|
before(path, {print}) {
|
|
@@ -78,9 +95,7 @@ export const VariableDeclaration = {
|
|
|
78
95
|
}
|
|
79
96
|
|
|
80
97
|
maybe.indent.dec(n);
|
|
81
|
-
|
|
82
|
-
if (isParentBlock(path) || isParentSwitchCase(path) || isParentTSModuleBlock(path) || isParentIf(path))
|
|
83
|
-
write(';');
|
|
98
|
+
maybe.write(isNeedSemicolon(path), ';');
|
|
84
99
|
|
|
85
100
|
let wasNewline = false;
|
|
86
101
|
|
|
@@ -91,7 +106,7 @@ export const VariableDeclaration = {
|
|
|
91
106
|
wasNewline = true;
|
|
92
107
|
}
|
|
93
108
|
|
|
94
|
-
if (
|
|
109
|
+
if (isNeedNewline(path)) {
|
|
95
110
|
write.newline();
|
|
96
111
|
wasNewline = true;
|
|
97
112
|
}
|
|
@@ -110,18 +125,23 @@ export const VariableDeclaration = {
|
|
|
110
125
|
notLastParentExport,
|
|
111
126
|
isParentTSModuleBlock,
|
|
112
127
|
],
|
|
113
|
-
after(path, {maybe, store}) {
|
|
128
|
+
after(path, {maybe, store, print}) {
|
|
114
129
|
const wasNewline = store();
|
|
115
130
|
|
|
116
|
-
if (
|
|
117
|
-
return
|
|
131
|
+
if (skipAfter(path))
|
|
132
|
+
return;
|
|
118
133
|
|
|
119
|
-
maybe.
|
|
120
|
-
|
|
134
|
+
maybe.indent(wasNewline);
|
|
135
|
+
print.newline();
|
|
121
136
|
maybe.markAfter(wasNewline, path);
|
|
122
137
|
},
|
|
123
138
|
};
|
|
124
139
|
|
|
140
|
+
const skipAfter = createTypeChecker([
|
|
141
|
+
['-: parentPath -> !', isLast],
|
|
142
|
+
['+: -> !', isInsideBlock],
|
|
143
|
+
]);
|
|
144
|
+
|
|
125
145
|
function noNextParentBlock(path) {
|
|
126
146
|
if (isNext(path))
|
|
127
147
|
return false;
|
|
@@ -169,8 +189,6 @@ function isNextCoupleLines(path) {
|
|
|
169
189
|
return isCoupleLines(next);
|
|
170
190
|
}
|
|
171
191
|
|
|
172
|
-
const isLast = (path) => path.parentPath?.isProgram() && !isNext(path);
|
|
173
|
-
|
|
174
192
|
function shouldAddNewlineBefore(path) {
|
|
175
193
|
if (isFirst(path))
|
|
176
194
|
return false;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const isFn = (a) => typeof a === 'function';
|
|
2
|
+
const isString = (a) => typeof a === 'string';
|
|
3
|
+
|
|
4
|
+
export const equal = (not, a, b) => {
|
|
5
|
+
if (!isString(b))
|
|
6
|
+
return false;
|
|
7
|
+
|
|
8
|
+
if (not)
|
|
9
|
+
return a !== b;
|
|
10
|
+
|
|
11
|
+
return a === b;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const maybeCall = (fn, not, a, options) => {
|
|
15
|
+
if (!isFn(fn))
|
|
16
|
+
return false;
|
|
17
|
+
|
|
18
|
+
const result = fn(a, options);
|
|
19
|
+
|
|
20
|
+
if (not)
|
|
21
|
+
return !result;
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function createTuple(typeName) {
|
|
2
|
+
const afterSplit = typeName.split(' ');
|
|
3
|
+
const typeWithNot = afterSplit.pop();
|
|
4
|
+
const array = typeWithNot.split('!');
|
|
5
|
+
const operation = afterSplit.join(' ');
|
|
6
|
+
|
|
7
|
+
if (array.length === 1)
|
|
8
|
+
return [
|
|
9
|
+
`${operation} `,
|
|
10
|
+
typeWithNot,
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
return [
|
|
14
|
+
`${operation} !`,
|
|
15
|
+
array[1],
|
|
16
|
+
];
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {isArray} from '@putout/compare/lib/is.js';
|
|
2
|
+
import {createTuple} from './create-tuple.js';
|
|
3
|
+
|
|
4
|
+
const isString = (a) => typeof a === 'string';
|
|
5
|
+
|
|
6
|
+
export const parseOperation = (operation) => {
|
|
7
|
+
const [result, command] = operation.split(':');
|
|
8
|
+
const parsedResult = parseResult(result);
|
|
9
|
+
|
|
10
|
+
if (!command)
|
|
11
|
+
return [parsedResult, '', ''];
|
|
12
|
+
|
|
13
|
+
const [selector, not] = command.split(' -> ');
|
|
14
|
+
|
|
15
|
+
return [parsedResult, selector.trim(), not];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const parseResult = (a) => a === '+';
|
|
19
|
+
|
|
20
|
+
export function parseTypeNames(typeNames) {
|
|
21
|
+
const tuples = [];
|
|
22
|
+
|
|
23
|
+
if (isArray(typeNames)) {
|
|
24
|
+
for (const typeName of typeNames) {
|
|
25
|
+
if (isArray(typeName)) {
|
|
26
|
+
tuples.push(typeName);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (isString(typeName) && typeName.includes(' -> ')) {
|
|
31
|
+
const tuple = createTuple(typeName);
|
|
32
|
+
tuples.push(tuple);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
tuples.push(['+', typeName]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return tuples;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const typeName of typeNames.include) {
|
|
43
|
+
tuples.push(['+', typeName]);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const typeName of typeNames.exclude) {
|
|
47
|
+
tuples.push(['-', typeName]);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return tuples;
|
|
51
|
+
}
|
|
@@ -1,31 +1,6 @@
|
|
|
1
1
|
import {jessy} from 'jessy';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const isString = (a) => typeof a === 'string';
|
|
6
|
-
const isFn = (a) => typeof a === 'function';
|
|
7
|
-
|
|
8
|
-
const equal = (not, a, b) => {
|
|
9
|
-
if (!isString(b))
|
|
10
|
-
return false;
|
|
11
|
-
|
|
12
|
-
if (not)
|
|
13
|
-
return a !== b;
|
|
14
|
-
|
|
15
|
-
return a === b;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const exec = (fn, not, a) => {
|
|
19
|
-
if (!isFn(fn))
|
|
20
|
-
return false;
|
|
21
|
-
|
|
22
|
-
const result = fn(a);
|
|
23
|
-
|
|
24
|
-
if (not)
|
|
25
|
-
return !result;
|
|
26
|
-
|
|
27
|
-
return result;
|
|
28
|
-
};
|
|
2
|
+
import {parseOperation, parseTypeNames} from './parsers.js';
|
|
3
|
+
import {equal, maybeCall} from './comparators.js';
|
|
29
4
|
|
|
30
5
|
export const createTypeChecker = (deepness, typeNames) => {
|
|
31
6
|
if (!typeNames) {
|
|
@@ -35,7 +10,7 @@ export const createTypeChecker = (deepness, typeNames) => {
|
|
|
35
10
|
|
|
36
11
|
const tuples = parseTypeNames(typeNames);
|
|
37
12
|
|
|
38
|
-
return (path) => {
|
|
13
|
+
return (path, options) => {
|
|
39
14
|
let i = deepness.split('.').length;
|
|
40
15
|
|
|
41
16
|
while (--i)
|
|
@@ -56,75 +31,10 @@ export const createTypeChecker = (deepness, typeNames) => {
|
|
|
56
31
|
if (equal(not, type, typeName))
|
|
57
32
|
return result;
|
|
58
33
|
|
|
59
|
-
if (
|
|
34
|
+
if (maybeCall(typeName, not, currentPath, options))
|
|
60
35
|
return result;
|
|
61
36
|
}
|
|
62
37
|
|
|
63
38
|
return false;
|
|
64
39
|
};
|
|
65
40
|
};
|
|
66
|
-
|
|
67
|
-
const parseOperation = (operation) => {
|
|
68
|
-
const [result, command] = operation.split(':');
|
|
69
|
-
const parsedResult = parseResult(result);
|
|
70
|
-
|
|
71
|
-
if (!command)
|
|
72
|
-
return [parsedResult, '', ''];
|
|
73
|
-
|
|
74
|
-
const [selector, not] = command.split(' -> ');
|
|
75
|
-
|
|
76
|
-
return [parsedResult, selector.trim(), not];
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const parseResult = (a) => a === '+';
|
|
80
|
-
|
|
81
|
-
function parseTypeNames(typeNames) {
|
|
82
|
-
const tuples = [];
|
|
83
|
-
|
|
84
|
-
if (isArray(typeNames)) {
|
|
85
|
-
for (const typeName of typeNames) {
|
|
86
|
-
if (isArray(typeName)) {
|
|
87
|
-
tuples.push(typeName);
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (isString(typeName) && typeName.includes(' -> ')) {
|
|
92
|
-
const tuple = createTuple(typeName);
|
|
93
|
-
tuples.push(tuple);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
tuples.push(['+', typeName]);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return tuples;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
for (const typeName of typeNames.include) {
|
|
104
|
-
tuples.push(['+', typeName]);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
for (const typeName of typeNames.exclude) {
|
|
108
|
-
tuples.push(['-', typeName]);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return tuples;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function createTuple(typeName) {
|
|
115
|
-
const afterSplit = typeName.split(' ');
|
|
116
|
-
const typeWithNot = afterSplit.pop();
|
|
117
|
-
const array = typeWithNot.split('!');
|
|
118
|
-
const operation = afterSplit.join(' ');
|
|
119
|
-
|
|
120
|
-
if (array.length === 1)
|
|
121
|
-
return [
|
|
122
|
-
`${operation} `,
|
|
123
|
-
typeWithNot,
|
|
124
|
-
];
|
|
125
|
-
|
|
126
|
-
return [
|
|
127
|
-
`${operation} !`,
|
|
128
|
-
array[1],
|
|
129
|
-
];
|
|
130
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@putout/printer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.1",
|
|
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",
|
|
@@ -62,14 +62,15 @@
|
|
|
62
62
|
"#maybe-parens": "./lib/tokenize/maybe/maybe-parens.js",
|
|
63
63
|
"#print-params": "./lib/tokenize/expressions/function/params.js",
|
|
64
64
|
"#import-attributes": "./lib/tokenize/statements/import-declaration/import-attribute.js",
|
|
65
|
-
"#types": "./lib/types.js"
|
|
65
|
+
"#types": "./lib/types.js",
|
|
66
|
+
"#type-checker": "./lib/tokenize/type-checker/type-checker.js"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@babel/parser": "^7.28.5",
|
|
69
70
|
"@putout/eslint": "^6.0.0",
|
|
70
71
|
"@putout/eslint-flat": "^4.0.0",
|
|
71
72
|
"@putout/plugin-minify": "^11.2.1",
|
|
72
|
-
"@putout/plugin-printer": "^
|
|
73
|
+
"@putout/plugin-printer": "^8.0.0",
|
|
73
74
|
"@putout/plugin-promises": "^19.0.0",
|
|
74
75
|
"@putout/plugin-react-hook-form": "^6.0.0",
|
|
75
76
|
"@putout/plugin-react-hooks": "^9.0.0",
|