@putout/printer 17.11.0 → 17.13.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 +14 -0
- package/lib/tokenize/expressions/assignment-expression/assignment-expression.js +5 -3
- package/lib/tokenize/expressions/class/class.js +6 -10
- package/lib/tokenize/expressions/function/function-declaration.js +23 -27
- package/lib/tokenize/is.js +21 -2
- package/lib/tokenize/statements/block-statement/block-statement.js +2 -3
- package/lib/tokenize/statements/debugger-statement.js +6 -4
- package/lib/tokenize/statements/if-statement/if-statement-comments.js +9 -4
- package/lib/tokenize/statements/if-statement/if-statement.js +3 -4
- package/lib/tokenize/statements/try-statement/try-statements.js +7 -6
- package/lib/tokenize/statements/variable-declaration/variable-declaration.js +10 -3
- package/lib/tokenize/type-checker/type-checker.js +130 -0
- package/package.json +2 -1
package/ChangeLog
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
2026.03.04, v17.13.0
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- 4af358d @putout/printer: type-checker: expression
|
|
5
|
+
- e3da216 @putout/printer: type-checker: improve dsl
|
|
6
|
+
- 93986ce @putout/printer: type checker: add
|
|
7
|
+
- 6a86e86 @putout/printer: type-checker: add
|
|
8
|
+
|
|
9
|
+
2026.03.03, v17.12.0
|
|
10
|
+
|
|
11
|
+
feature:
|
|
12
|
+
- aa951ef @putout/printer: IfStatement: trailing comments
|
|
13
|
+
- 3c15683 @putout/printer: isParentBlock: reuse
|
|
14
|
+
|
|
1
15
|
2026.03.03, v17.11.0
|
|
2
16
|
|
|
3
17
|
feature:
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import {maybeParens} from '#maybe-parens';
|
|
2
|
+
import {
|
|
3
|
+
isParentBlock,
|
|
4
|
+
isParentProgram,
|
|
5
|
+
} from '#is';
|
|
2
6
|
import {condition} from './maybe-parens-condition.js';
|
|
3
7
|
import {printSeparator} from './print-separator.js';
|
|
4
8
|
import {
|
|
@@ -8,8 +12,6 @@ import {
|
|
|
8
12
|
printLeadingCommentBlock,
|
|
9
13
|
} from './assignment-expression-comments.js';
|
|
10
14
|
|
|
11
|
-
const isInsideBlock = ({parentPath}) => /BlockStatement|Program/.test(parentPath.type);
|
|
12
|
-
|
|
13
15
|
export const AssignmentExpression = maybeParens({
|
|
14
16
|
checkParens: false,
|
|
15
17
|
condition,
|
|
@@ -25,7 +27,7 @@ export const AssignmentExpression = maybeParens({
|
|
|
25
27
|
printSeparator(path, printer);
|
|
26
28
|
print('__right');
|
|
27
29
|
|
|
28
|
-
if (
|
|
30
|
+
if (isParentBlock(path) || isParentProgram(path)) {
|
|
29
31
|
print(';');
|
|
30
32
|
print.breakline();
|
|
31
33
|
}
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
hasBody,
|
|
4
|
+
isInsideTSModuleBlock,
|
|
5
|
+
isNext,
|
|
6
|
+
} from '#is';
|
|
3
7
|
import {markAfter} from '#mark';
|
|
4
8
|
import {maybeDeclare} from '../../maybe/maybe-declare.js';
|
|
5
9
|
import {parseComments} from '../../comment/comment.js';
|
|
6
10
|
import {maybeDecorators} from '../../maybe/maybe-decorators.js';
|
|
7
11
|
|
|
8
|
-
const
|
|
9
|
-
return isTSModuleBlock(path.parentPath.parentPath);
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const {
|
|
13
|
-
isFunction,
|
|
14
|
-
isTSModuleBlock,
|
|
15
|
-
} = types;
|
|
12
|
+
const {isFunction} = types;
|
|
16
13
|
|
|
17
14
|
const isInsideExport = ({parentPath}) => parentPath.isExportDeclaration();
|
|
18
15
|
const isFunctionLike = (path) => isFunction(path.parentPath.parentPath);
|
|
19
|
-
const hasBody = ({node}) => node.body.body.length;
|
|
20
16
|
|
|
21
17
|
const classVisitor = maybeDecorators((path, printer, semantics) => {
|
|
22
18
|
const {
|
|
@@ -1,21 +1,36 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {isNext, isNextParent} from '#is';
|
|
3
2
|
import {printParams} from '#print-params';
|
|
4
3
|
import {markAfter} from '#mark';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
isInsideTSModuleBlock,
|
|
6
|
+
isNext,
|
|
7
|
+
isNextParent,
|
|
8
|
+
} from '#is';
|
|
9
|
+
import {createTypeChecker} from '../../type-checker/type-checker.js';
|
|
8
10
|
|
|
9
11
|
const {
|
|
10
12
|
isAssignmentExpression,
|
|
11
|
-
isTSModuleBlock,
|
|
12
|
-
isBlockStatement,
|
|
13
13
|
isExportNamedDeclaration,
|
|
14
14
|
isExpressionStatement,
|
|
15
15
|
isFunctionDeclaration,
|
|
16
|
-
isExportDefaultDeclaration,
|
|
17
16
|
} = types;
|
|
18
17
|
|
|
18
|
+
const hasFnBody = ({node}) => node.body.body.length;
|
|
19
|
+
|
|
20
|
+
const isInsideExportDefaultWithBody = createTypeChecker([
|
|
21
|
+
'-: parentPath -> !ExportDefaultDeclaration',
|
|
22
|
+
['+', hasFnBody],
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
const isInsideBlockLike = createTypeChecker([
|
|
26
|
+
['+', isInsideTSModuleBlock],
|
|
27
|
+
'-: parentPath -> !BlockStatement',
|
|
28
|
+
['+: -> !', hasFnBody],
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const not = (fn) => (...a) => !fn(...a);
|
|
32
|
+
const notInsideExportDefaultWithBody = not(isInsideExportDefaultWithBody);
|
|
33
|
+
|
|
19
34
|
const isInsideNamedExport = ({parentPath}) => isExportNamedDeclaration(parentPath);
|
|
20
35
|
|
|
21
36
|
export const FunctionDeclaration = {
|
|
@@ -51,7 +66,7 @@ export const FunctionDeclaration = {
|
|
|
51
66
|
print.space();
|
|
52
67
|
print('__body');
|
|
53
68
|
},
|
|
54
|
-
afterSatisfy: () => [isNext, isNextParent,
|
|
69
|
+
afterSatisfy: () => [isNext, isNextParent, isInsideBlockLike],
|
|
55
70
|
after(path, {indent, maybe}) {
|
|
56
71
|
if (isNextAssign(path) || isNextFunction(path) || isNext(path))
|
|
57
72
|
indent();
|
|
@@ -74,22 +89,3 @@ const isNextAssign = (path) => {
|
|
|
74
89
|
|
|
75
90
|
return isAssignmentExpression(next.node.expression);
|
|
76
91
|
};
|
|
77
|
-
|
|
78
|
-
function isInsideBlockStatement(path) {
|
|
79
|
-
const {parentPath} = path;
|
|
80
|
-
|
|
81
|
-
if (isTSModuleBlock(parentPath.parentPath))
|
|
82
|
-
return true;
|
|
83
|
-
|
|
84
|
-
if (!isBlockStatement(parentPath))
|
|
85
|
-
return false;
|
|
86
|
-
|
|
87
|
-
return !path.node.body.body.length;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function isInsideExportDefaultWithBody(path) {
|
|
91
|
-
if (!isExportDefaultDeclaration(path.parentPath))
|
|
92
|
-
return false;
|
|
93
|
-
|
|
94
|
-
return path.node.body.body.length;
|
|
95
|
-
}
|
package/lib/tokenize/is.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {createTypeChecker} from './type-checker/type-checker.js';
|
|
2
3
|
|
|
3
4
|
const {
|
|
4
5
|
isStringLiteral,
|
|
@@ -12,10 +13,24 @@ const {
|
|
|
12
13
|
isObjectExpression,
|
|
13
14
|
isLabeledStatement,
|
|
14
15
|
isTryStatement,
|
|
16
|
+
isProgram,
|
|
17
|
+
isBlockStatement,
|
|
18
|
+
isTSModuleBlock,
|
|
15
19
|
} = types;
|
|
16
20
|
|
|
17
|
-
export const isParentProgram = (path) => path.parentPath
|
|
18
|
-
export const isParentBlock = (path) => path.parentPath
|
|
21
|
+
export const isParentProgram = (path) => isProgram(path.parentPath);
|
|
22
|
+
export const isParentBlock = (path) => isBlockStatement(path.parentPath);
|
|
23
|
+
|
|
24
|
+
export const isParentBlockLike = createTypeChecker('path.parentPath', [
|
|
25
|
+
'Program',
|
|
26
|
+
'BlockStatement',
|
|
27
|
+
'TSModuleBlock',
|
|
28
|
+
'SwitchCase',
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
export const isInsideTSModuleBlock = ({parentPath}) => {
|
|
32
|
+
return isTSModuleBlock(parentPath?.parentPath);
|
|
33
|
+
};
|
|
19
34
|
|
|
20
35
|
export const isNext = (path) => {
|
|
21
36
|
const next = path.getNextSibling();
|
|
@@ -26,6 +41,10 @@ export const isNext = (path) => {
|
|
|
26
41
|
return !next.isEmptyStatement();
|
|
27
42
|
};
|
|
28
43
|
|
|
44
|
+
export const hasBody = ({node}) => node.body.body.length;
|
|
45
|
+
|
|
46
|
+
export const hasEmptyBody = (path) => !path.node.body.length;
|
|
47
|
+
|
|
29
48
|
export const isNextTry = (path) => {
|
|
30
49
|
return isTryStatement(path.getNextSibling());
|
|
31
50
|
};
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
isLast,
|
|
7
7
|
exists,
|
|
8
8
|
satisfy,
|
|
9
|
+
isParentBlock,
|
|
9
10
|
} from '#is';
|
|
10
11
|
import {parseComments} from '../../comment/comment.js';
|
|
11
12
|
import {insideIfWithNoBody} from './inside-if-with-no-body.js';
|
|
@@ -18,7 +19,6 @@ const {
|
|
|
18
19
|
isFunctionDeclaration,
|
|
19
20
|
isExportDeclaration,
|
|
20
21
|
isDoWhileStatement,
|
|
21
|
-
isBlockStatement,
|
|
22
22
|
isArrayExpression,
|
|
23
23
|
} = types;
|
|
24
24
|
|
|
@@ -127,7 +127,6 @@ const NEWLINE = true;
|
|
|
127
127
|
const NO_NEWLINE = false;
|
|
128
128
|
|
|
129
129
|
const isInsideDoWhile = ({parentPath}) => isDoWhileStatement(parentPath);
|
|
130
|
-
const isInsideBlock = ({parentPath}) => isBlockStatement(parentPath);
|
|
131
130
|
|
|
132
131
|
const isNoNewline = satisfy([
|
|
133
132
|
isInsideDoWhile,
|
|
@@ -136,7 +135,7 @@ const isNoNewline = satisfy([
|
|
|
136
135
|
]);
|
|
137
136
|
|
|
138
137
|
function shouldAddNewlineAfter(path) {
|
|
139
|
-
if (
|
|
138
|
+
if (isParentBlock(path))
|
|
140
139
|
return NEWLINE;
|
|
141
140
|
|
|
142
141
|
if (isNoNewline(path))
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
isNext,
|
|
3
|
+
isInsideIf,
|
|
4
|
+
isParentBlock,
|
|
5
|
+
} from '#is';
|
|
4
6
|
|
|
5
7
|
export const DebuggerStatement = {
|
|
6
8
|
print(path, {print, indent}) {
|
|
@@ -9,7 +11,7 @@ export const DebuggerStatement = {
|
|
|
9
11
|
},
|
|
10
12
|
afterSatisfy: () => [
|
|
11
13
|
isNext,
|
|
12
|
-
|
|
14
|
+
isParentBlock,
|
|
13
15
|
isInsideIf,
|
|
14
16
|
],
|
|
15
17
|
after(path, {print}) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {isNext} from '#is';
|
|
2
|
+
import {isNext, isParentBlock} from '#is';
|
|
3
3
|
|
|
4
4
|
const {isBlockStatement} = types;
|
|
5
5
|
|
|
@@ -12,13 +12,18 @@ export const printTrailingCommentBlock = (path, printer, semantics, {printCommen
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export const printTrailingCommentLine = (path, printer, semantics, {printComment}) => {
|
|
15
|
+
const hasNext = isNext(path);
|
|
15
16
|
const {consequent} = path.node;
|
|
16
17
|
const consequentIsBlock = isBlockStatement(consequent);
|
|
17
|
-
const {print
|
|
18
|
+
const {print} = printer;
|
|
18
19
|
|
|
19
20
|
print.indent();
|
|
20
|
-
|
|
21
|
+
|
|
22
|
+
if (!hasNext && !consequentIsBlock)
|
|
23
|
+
print.space();
|
|
21
24
|
|
|
22
25
|
printComment();
|
|
23
|
-
|
|
26
|
+
|
|
27
|
+
if (hasNext || isParentBlock(path))
|
|
28
|
+
print.newline();
|
|
24
29
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
+
import {markAfter} from '#mark';
|
|
2
3
|
import {
|
|
3
4
|
exists,
|
|
4
5
|
isNext,
|
|
5
6
|
isInsideIf,
|
|
7
|
+
hasEmptyBody,
|
|
6
8
|
} from '#is';
|
|
7
|
-
import {markAfter} from '#mark';
|
|
8
9
|
import {
|
|
9
10
|
printTrailingCommentBlock,
|
|
10
11
|
printTrailingCommentLine,
|
|
@@ -42,8 +43,6 @@ const isInsideNestedBody = ({parentPath}) => {
|
|
|
42
43
|
return parentPath.parentPath.type === 'BlockStatement';
|
|
43
44
|
};
|
|
44
45
|
|
|
45
|
-
const isEmptyBody = (path) => !path.node.body.length;
|
|
46
|
-
|
|
47
46
|
const isLastEmptyInsideBody = (path) => {
|
|
48
47
|
const {parentPath} = path;
|
|
49
48
|
|
|
@@ -85,7 +84,7 @@ export const IfStatement = {
|
|
|
85
84
|
print(consequent);
|
|
86
85
|
|
|
87
86
|
if (isInsideIf(path.parentPath) || isInsideNestedBody(path))
|
|
88
|
-
maybe.print.newline(
|
|
87
|
+
maybe.print.newline(hasEmptyBody(consequent));
|
|
89
88
|
} else {
|
|
90
89
|
const is = !isEmptyConsequent(path);
|
|
91
90
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import {types} from '@putout/babel';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
isNext,
|
|
4
|
+
isNextTry,
|
|
5
|
+
isParentBlock,
|
|
6
|
+
} from '#is';
|
|
3
7
|
|
|
4
8
|
const {isExpressionStatement} = types;
|
|
5
9
|
|
|
@@ -34,6 +38,7 @@ const isNextExpression = (path) => {
|
|
|
34
38
|
};
|
|
35
39
|
|
|
36
40
|
export const CatchClause = (path, {print, maybe}) => {
|
|
41
|
+
const {parentPath} = path;
|
|
37
42
|
const param = path.get('param');
|
|
38
43
|
const body = path.get('body');
|
|
39
44
|
|
|
@@ -50,9 +55,5 @@ export const CatchClause = (path, {print, maybe}) => {
|
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
print(body);
|
|
53
|
-
maybe.print.newline(
|
|
58
|
+
maybe.print.newline(isParentBlock(parentPath));
|
|
54
59
|
};
|
|
55
|
-
|
|
56
|
-
function isInsideBlock(path) {
|
|
57
|
-
return path.parentPath.parentPath.isBlockStatement();
|
|
58
|
-
}
|
|
@@ -6,21 +6,28 @@ import {
|
|
|
6
6
|
isNewlineBetweenSiblings,
|
|
7
7
|
exists,
|
|
8
8
|
noTrailingComment,
|
|
9
|
+
isParentBlockLike,
|
|
9
10
|
} from '#is';
|
|
10
11
|
import {maybeSpaceAfterKeyword} from './maybe-space-after-keyword.js';
|
|
11
12
|
import {isConcatenation} from '../../expressions/binary-expression/concatenate.js';
|
|
12
13
|
import {parseLeadingComments} from '../../comment/comment.js';
|
|
13
14
|
import {maybeDeclare} from '../../maybe/maybe-declare.js';
|
|
15
|
+
import {createTypeChecker} from '../../type-checker/type-checker.js';
|
|
14
16
|
|
|
15
17
|
const {isExportDeclaration} = types;
|
|
16
18
|
|
|
17
19
|
const isParentTSModuleBlock = (path) => path.parentPath.isTSModuleBlock();
|
|
18
|
-
const isParentBlock = (path) => /Program|BlockStatement|Export|LabeledStatement/.test(path.parentPath.type);
|
|
19
|
-
const isInsideBlock = (path) => /^(Program|BlockStatement|TSModuleBlock|SwitchCase)$/.test(path.parentPath.type);
|
|
20
20
|
const isParentSwitchCase = (path) => path.parentPath.isSwitchCase();
|
|
21
21
|
const isFirstInSwitch = (path) => path.parentPath.get('consequent.0') === path;
|
|
22
22
|
const isParentIf = (path) => path.parentPath.isIfStatement();
|
|
23
23
|
|
|
24
|
+
const isParentBlock = createTypeChecker('path.parentPath', [
|
|
25
|
+
'Program',
|
|
26
|
+
'BlockStatement',
|
|
27
|
+
'ExportNamedDeclaration',
|
|
28
|
+
'LabeledStatement',
|
|
29
|
+
]);
|
|
30
|
+
|
|
24
31
|
export const VariableDeclaration = {
|
|
25
32
|
beforeIf: shouldAddNewlineBefore,
|
|
26
33
|
before(path, {print}) {
|
|
@@ -29,7 +36,7 @@ export const VariableDeclaration = {
|
|
|
29
36
|
print: maybeDeclare((path, {maybe, store, write, traverse, print, indent}, semantics) => {
|
|
30
37
|
const {maxVariablesInOneLine} = semantics;
|
|
31
38
|
|
|
32
|
-
maybe.indent(
|
|
39
|
+
maybe.indent(isParentBlockLike(path));
|
|
33
40
|
|
|
34
41
|
write(path.node.kind);
|
|
35
42
|
maybeSpaceAfterKeyword(path, {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {jessy} from 'jessy';
|
|
2
|
+
|
|
3
|
+
const {isArray} = Array;
|
|
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
|
+
};
|
|
29
|
+
|
|
30
|
+
export const createTypeChecker = (deepness, typeNames) => {
|
|
31
|
+
if (!typeNames) {
|
|
32
|
+
typeNames = deepness;
|
|
33
|
+
deepness = '';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const tuples = parseTypeNames(typeNames);
|
|
37
|
+
|
|
38
|
+
return (path) => {
|
|
39
|
+
let i = deepness.split('.').length;
|
|
40
|
+
|
|
41
|
+
while (--i)
|
|
42
|
+
path = path?.parentPath;
|
|
43
|
+
|
|
44
|
+
if (!path)
|
|
45
|
+
return false;
|
|
46
|
+
|
|
47
|
+
for (const [operation, typeName] of tuples) {
|
|
48
|
+
const [result, selector, not] = parseOperation(operation);
|
|
49
|
+
let currentPath = path;
|
|
50
|
+
|
|
51
|
+
if (selector)
|
|
52
|
+
currentPath = jessy(selector, path);
|
|
53
|
+
|
|
54
|
+
const {type} = currentPath;
|
|
55
|
+
|
|
56
|
+
if (equal(not, type, typeName))
|
|
57
|
+
return result;
|
|
58
|
+
|
|
59
|
+
if (exec(typeName, not, currentPath))
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return false;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
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": "17.
|
|
3
|
+
"version": "17.13.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",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@putout/operate": "^15.0.0",
|
|
39
39
|
"@putout/operator-json": "^3.1.0",
|
|
40
40
|
"fullstore": "^4.0.0",
|
|
41
|
+
"jessy": "^5.0.0",
|
|
41
42
|
"just-snake-case": "^3.2.0",
|
|
42
43
|
"parse-import-specifiers": "^1.0.1",
|
|
43
44
|
"rendy": "^5.0.0"
|