@putout/printer 18.2.1 → 18.2.3
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/array-expression/array-expression.js +18 -17
- package/lib/tokenize/expressions/array-expression/newline.js +4 -6
- package/lib/tokenize/is.js +1 -0
- package/lib/tokenize/statements/expression-statement/expression-statement.js +0 -1
- package/lib/tokenize/type-checker/instrument.js +2 -3
- package/lib/tokenize/type-checker/report.js +82 -0
- package/lib/tokenize/type-checker/type-checker.js +1 -0
- package/package.json +7 -4
package/ChangeLog
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
2026.03.07, v18.2.3
|
|
2
|
+
|
|
3
|
+
fix:
|
|
4
|
+
- 355176d @putout/printer: instrument -> instrumentName
|
|
5
|
+
|
|
6
|
+
feature:
|
|
7
|
+
- 85a60d6 @putout/printer: type-checker: report
|
|
8
|
+
|
|
9
|
+
2026.03.07, v18.2.2
|
|
10
|
+
|
|
11
|
+
feature:
|
|
12
|
+
- 7633d10 @putout/printer: ArrayExpression: isSimpleAfterObject
|
|
13
|
+
- c57048d @putout/printer: ArrayExpression: isCurrentNewLine: simplify
|
|
14
|
+
|
|
1
15
|
2026.03.07, v18.2.1
|
|
2
16
|
|
|
3
17
|
fix:
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
isNextObject,
|
|
10
10
|
callWithNext,
|
|
11
11
|
isInsideArray,
|
|
12
|
+
callWithPrev,
|
|
12
13
|
} from '#is';
|
|
13
14
|
import {
|
|
14
15
|
isIncreaseIndent,
|
|
@@ -96,17 +97,18 @@ export const ArrayExpression = {
|
|
|
96
97
|
|
|
97
98
|
maybe.indent.inc(indented && shouldIncreaseIndent);
|
|
98
99
|
|
|
99
|
-
const
|
|
100
|
+
const needsNewline = isMultiLine(path, {
|
|
100
101
|
maxElementsInOneLine,
|
|
101
102
|
maxElementLengthInOneLine,
|
|
102
103
|
});
|
|
103
104
|
|
|
104
105
|
const n = elements.length - 1;
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
if (needsNewline)
|
|
108
|
+
print.newline();
|
|
107
109
|
|
|
108
110
|
for (const [index, element] of elements.entries()) {
|
|
109
|
-
const is =
|
|
111
|
+
const is = needsNewline && isCurrentNewLine(element);
|
|
110
112
|
|
|
111
113
|
if (isSimpleAfterObject(element))
|
|
112
114
|
print.newline();
|
|
@@ -139,10 +141,10 @@ export const ArrayExpression = {
|
|
|
139
141
|
const isHideIdent = !isAroundStrings(path) || parentCountTwo;
|
|
140
142
|
|
|
141
143
|
maybe.indent.dec(isHideIdent);
|
|
142
|
-
maybe.indent(elements.length &&
|
|
144
|
+
maybe.indent(elements.length && needsNewline);
|
|
143
145
|
maybe.indent.inc(isHideIdent);
|
|
144
146
|
} else if (!isArrayInsideArray(path) && !isObjectExpression(elements.at(-1))) {
|
|
145
|
-
maybe.indent(elements.length &&
|
|
147
|
+
maybe.indent(elements.length && needsNewline);
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
if (isSimpleAndNotEmptyObject(path) && !isSpreadElement(elements.at(-1)) && !isCallExpression(elements.at(-1))) {
|
|
@@ -173,15 +175,14 @@ export const ArrayExpression = {
|
|
|
173
175
|
},
|
|
174
176
|
};
|
|
175
177
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
178
|
+
const isSimple = createTypeChecker([
|
|
179
|
+
'-: -> SpreadElement',
|
|
180
|
+
'-: -> Identifier',
|
|
181
|
+
'+: -> !CallExpression',
|
|
182
|
+
]);
|
|
183
|
+
|
|
184
|
+
const isSimpleAfterObject = createTypeChecker([
|
|
185
|
+
['-', isSimple],
|
|
186
|
+
['-', callWithNext(isObjectExpression)],
|
|
187
|
+
['+', callWithPrev(isObjectExpression)],
|
|
188
|
+
]);
|
|
@@ -338,9 +338,7 @@ const isStringAndObject = (elements) => {
|
|
|
338
338
|
return isStringLiteral(first) && isObjectExpression(last);
|
|
339
339
|
};
|
|
340
340
|
|
|
341
|
-
export const isCurrentNewLine = (
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return !path.isObjectExpression();
|
|
346
|
-
};
|
|
341
|
+
export const isCurrentNewLine = createTypeChecker([
|
|
342
|
+
'+: -> SpreadElement',
|
|
343
|
+
'+: -> !ObjectExpression',
|
|
344
|
+
]);
|
package/lib/tokenize/is.js
CHANGED
|
@@ -31,6 +31,7 @@ export const isInsideTSModuleBlock = ({parentPath}) => isTSModuleBlock(parentPat
|
|
|
31
31
|
export const isInsideCall = ({parentPath}) => parentPath.isCallExpression();
|
|
32
32
|
export const isInsideReturn = ({parentPath}) => parentPath.isReturnStatement();
|
|
33
33
|
export const callWithNext = (fn) => (path) => fn(path.getNextSibling());
|
|
34
|
+
export const callWithPrev = (fn) => (path) => fn(path.getPrevSibling());
|
|
34
35
|
export const callWithParent = (fn) => (path) => fn(path.parentPath);
|
|
35
36
|
|
|
36
37
|
export const isNext = (path) => {
|
|
@@ -10,13 +10,13 @@ export const instrument = (typeNames, fn, overrides = {}) => {
|
|
|
10
10
|
const {
|
|
11
11
|
env = _env,
|
|
12
12
|
coverage = Coverage,
|
|
13
|
-
|
|
13
|
+
instrumentName = 'TYPE_CHECK',
|
|
14
14
|
} = overrides;
|
|
15
15
|
|
|
16
16
|
const {length} = typeNames;
|
|
17
17
|
const error = Error();
|
|
18
18
|
const location = parseCallLocation(error);
|
|
19
|
-
const on =
|
|
19
|
+
const on = env[instrumentName];
|
|
20
20
|
const covered = new Set();
|
|
21
21
|
|
|
22
22
|
if (on && !location.includes('type-checker.spec.js'))
|
|
@@ -37,4 +37,3 @@ export const instrument = (typeNames, fn, overrides = {}) => {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
export const getCoverage = () => Coverage;
|
|
40
|
-
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {styleText} from 'node:util';
|
|
2
|
+
import {codeFrameColumns} from '@putout/babel';
|
|
3
|
+
|
|
4
|
+
/* c8 ignore start */
|
|
5
|
+
const isString = (a) => typeof a === 'string';
|
|
6
|
+
const isFn = (a) => typeof a === 'function';
|
|
7
|
+
const difference = (a, b) => new Set(a).difference(new Set(b));
|
|
8
|
+
const red = (a) => styleText('red', String(a));
|
|
9
|
+
|
|
10
|
+
const SUCCESS = 0;
|
|
11
|
+
const FAIL = 1;
|
|
12
|
+
|
|
13
|
+
export const report = (coverage) => {
|
|
14
|
+
const lines = [];
|
|
15
|
+
const log = (a) => lines.push(a);
|
|
16
|
+
let exitCode = SUCCESS;
|
|
17
|
+
|
|
18
|
+
for (const [name, {length, covered, typeNames}] of coverage) {
|
|
19
|
+
if (length === covered.size)
|
|
20
|
+
continue;
|
|
21
|
+
|
|
22
|
+
for (const index of difference(fullSet(length), covered)) {
|
|
23
|
+
const currentType = typeNames[index];
|
|
24
|
+
const rawCode = createRawCode(currentType);
|
|
25
|
+
const code = codeFrameColumns(rawCode, {}, {
|
|
26
|
+
forceColor: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
log(`🧨 Uncovered Checkers found at index: ${red(index + 1)}`);
|
|
30
|
+
log(`${code}\n`);
|
|
31
|
+
log(`${setLine(name, index)}\n`);
|
|
32
|
+
exitCode = FAIL;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (exitCode === SUCCESS)
|
|
37
|
+
log('# 🌴 Checkers Covered');
|
|
38
|
+
|
|
39
|
+
return [exitCode, lines.join('\n')];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const setLine = (name, index) => {
|
|
43
|
+
const [at, uri, line, column] = name.split(':');
|
|
44
|
+
const newLine = Number(line) + index + 1;
|
|
45
|
+
|
|
46
|
+
return [
|
|
47
|
+
at,
|
|
48
|
+
uri,
|
|
49
|
+
newLine,
|
|
50
|
+
column,
|
|
51
|
+
].join(':');
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const fullSet = (n) => {
|
|
55
|
+
const result = new Set();
|
|
56
|
+
let i = 0;
|
|
57
|
+
|
|
58
|
+
do {
|
|
59
|
+
result.add(i++);
|
|
60
|
+
} while (i < n);
|
|
61
|
+
|
|
62
|
+
return result;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function createRawCode(currentType) {
|
|
66
|
+
if (isString(currentType))
|
|
67
|
+
return currentType;
|
|
68
|
+
|
|
69
|
+
if (isFn(currentType))
|
|
70
|
+
return currentType.name;
|
|
71
|
+
|
|
72
|
+
const [operator, fn] = currentType;
|
|
73
|
+
|
|
74
|
+
if (fn) {
|
|
75
|
+
const name = fn.name || fn;
|
|
76
|
+
return `['${operator}', ${name}]`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return operator;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* c8 ignore end */
|
|
@@ -12,6 +12,7 @@ export const createTypeChecker = (typeNames, overrides = {}) => {
|
|
|
12
12
|
const {
|
|
13
13
|
instrumentCoverage = _instrument,
|
|
14
14
|
} = overrides;
|
|
15
|
+
|
|
15
16
|
const tuples = parseTypeNames(typeNames);
|
|
16
17
|
const typeChecker = (path, options) => {
|
|
17
18
|
for (const [index, [operation, typeName]] of tuples.entries()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@putout/printer",
|
|
3
|
-
"version": "18.2.
|
|
3
|
+
"version": "18.2.3",
|
|
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",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
".": "./lib/printer.js",
|
|
11
11
|
"./is": "./lib/tokenize/is.js",
|
|
12
12
|
"./params": "./lib/tokenize/expressions/function/params.js",
|
|
13
|
-
"./type-checker": "./lib/tokenize/type-checker/type-checker.js"
|
|
13
|
+
"./type-checker": "./lib/tokenize/type-checker/type-checker.js",
|
|
14
|
+
"./type-checker/instrument": "./lib/tokenize/type-checker/instrument.js",
|
|
15
|
+
"./type-checker/report": "./lib/tokenize/type-checker/report.js"
|
|
14
16
|
},
|
|
15
17
|
"repository": {
|
|
16
18
|
"type": "git",
|
|
@@ -65,7 +67,8 @@
|
|
|
65
67
|
"#import-attributes": "./lib/tokenize/statements/import-declaration/import-attribute.js",
|
|
66
68
|
"#types": "./lib/types.js",
|
|
67
69
|
"#type-checker": "./lib/tokenize/type-checker/type-checker.js",
|
|
68
|
-
"#type-checker/instrument": "./lib/tokenize/type-checker/instrument.js"
|
|
70
|
+
"#type-checker/instrument": "./lib/tokenize/type-checker/instrument.js",
|
|
71
|
+
"#type-checker/report": "./lib/tokenize/type-checker/report.js"
|
|
69
72
|
},
|
|
70
73
|
"devDependencies": {
|
|
71
74
|
"@babel/parser": "^7.28.5",
|
|
@@ -98,7 +101,7 @@
|
|
|
98
101
|
},
|
|
99
102
|
"license": "MIT",
|
|
100
103
|
"engines": {
|
|
101
|
-
"node": ">=22"
|
|
104
|
+
"node": ">=22.13"
|
|
102
105
|
},
|
|
103
106
|
"publishConfig": {
|
|
104
107
|
"access": "public"
|