ts-codemod-lib 2.2.3 → 2.2.5
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/README.md +0 -12
- package/dist/cmd/append-as-const.mjs +1 -1
- package/dist/cmd/append-as-const.mjs.map +1 -1
- package/dist/cmd/convert-interface-to-type.mjs +1 -1
- package/dist/cmd/convert-interface-to-type.mjs.map +1 -1
- package/dist/cmd/convert-to-readonly.mjs +1 -1
- package/dist/cmd/convert-to-readonly.mjs.map +1 -1
- package/dist/cmd/replace-any-with-unknown.mjs +1 -1
- package/dist/cmd/replace-any-with-unknown.mjs.map +1 -1
- package/dist/cmd/replace-record-with-unknown-record.mjs +1 -1
- package/dist/cmd/replace-record-with-unknown-record.mjs.map +1 -1
- package/dist/cmd/run-transformer-cli.mjs +1 -1
- package/dist/cmd/run-transformer-cli.mjs.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.mjs +1 -1
- package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-interface-to-type.mjs +4 -4
- package/dist/functions/ast-transformers/convert-interface-to-type.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.mjs +12 -13
- package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.d.mts +3 -3
- package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.d.mts.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.mjs.map +1 -1
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.d.mts.map +1 -1
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs +13 -13
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs.map +1 -1
- package/dist/functions/ast-transformers/transform-source-code.mjs +2 -2
- package/dist/functions/ast-transformers/transform-source-code.mjs.map +1 -1
- package/dist/functions/functions/is-as-const-node.mjs +1 -1
- package/dist/functions/functions/is-as-const-node.mjs.map +1 -1
- package/dist/functions/functions/is-readonly-node.d.mts +5 -5
- package/dist/functions/functions/is-readonly-node.d.mts.map +1 -1
- package/dist/functions/functions/is-readonly-node.mjs +1 -1
- package/dist/functions/functions/is-readonly-node.mjs.map +1 -1
- package/dist/functions/functions/should-avoid-parentheses-for-readonly.d.mts.map +1 -1
- package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs +1 -4
- package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs.map +1 -1
- package/package.json +37 -40
- package/src/cmd/append-as-const.mts +1 -1
- package/src/cmd/convert-interface-to-type.mts +1 -1
- package/src/cmd/convert-to-readonly.mts +1 -1
- package/src/cmd/replace-any-with-unknown.mts +1 -1
- package/src/cmd/replace-record-with-unknown-record.mts +1 -1
- package/src/cmd/run-transformer-cli.mts +1 -1
- package/src/functions/ast-transformers/append-as-const.mts +1 -1
- package/src/functions/ast-transformers/convert-interface-to-type.mts +4 -4
- package/src/functions/ast-transformers/convert-to-readonly.mts +31 -33
- package/src/functions/ast-transformers/readonly-transformer-helpers/readonly-context.mts +3 -3
- package/src/functions/ast-transformers/replace-record-with-unknown-record.mts +18 -29
- package/src/functions/ast-transformers/transform-source-code.mts +2 -2
- package/src/functions/functions/is-as-const-node.mts +1 -1
- package/src/functions/functions/is-readonly-node.mts +6 -6
- package/src/functions/functions/should-avoid-parentheses-for-readonly.mts +1 -5
|
@@ -8,7 +8,12 @@ import {
|
|
|
8
8
|
pipe,
|
|
9
9
|
} from 'ts-data-forge';
|
|
10
10
|
import * as tsm from 'ts-morph';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
type DeepReadonly,
|
|
13
|
+
type SafeUintWithSmallInt,
|
|
14
|
+
type StrictExclude,
|
|
15
|
+
type StrictExtract,
|
|
16
|
+
} from 'ts-type-forge';
|
|
12
17
|
import {
|
|
13
18
|
hasDisableNextLineComment,
|
|
14
19
|
isAtomicTypeNode,
|
|
@@ -397,7 +402,7 @@ const transformNode = (
|
|
|
397
402
|
const transformTypeReferenceNode = (
|
|
398
403
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
399
404
|
node: tsm.TypeReferenceNode,
|
|
400
|
-
readonlyContext:
|
|
405
|
+
readonlyContext: StrictExclude<
|
|
401
406
|
ReadonlyContext,
|
|
402
407
|
Readonly<{ type: 'readonly'; indexedAccessDepth: SafeUintWithSmallInt }>
|
|
403
408
|
>,
|
|
@@ -409,7 +414,7 @@ const transformTypeReferenceNode = (
|
|
|
409
414
|
|
|
410
415
|
// Array<T> / ReadonlyArray<T> to readonly T[]
|
|
411
416
|
if (typeNameStr === 'Array' || typeNameStr === 'ReadonlyArray') {
|
|
412
|
-
if (!Arr.
|
|
417
|
+
if (!Arr.isFixedLengthArray(1, typeArguments)) {
|
|
413
418
|
throw new Error(
|
|
414
419
|
`Unexpected number of type arguments "${typeArguments.length}" for ${typeNameStr}.`,
|
|
415
420
|
);
|
|
@@ -442,7 +447,7 @@ const transformTypeReferenceNode = (
|
|
|
442
447
|
|
|
443
448
|
// Set<T> to ReadonlySet<T>
|
|
444
449
|
if (typeNameStr === 'Set') {
|
|
445
|
-
if (!Arr.
|
|
450
|
+
if (!Arr.isFixedLengthArray(1, typeArguments)) {
|
|
446
451
|
throw new Error(
|
|
447
452
|
`Unexpected number of type arguments "${typeArguments.length}" for Set.`,
|
|
448
453
|
);
|
|
@@ -468,7 +473,7 @@ const transformTypeReferenceNode = (
|
|
|
468
473
|
|
|
469
474
|
// Map<T> to ReadonlyMap<T>
|
|
470
475
|
if (typeNameStr === 'Map') {
|
|
471
|
-
if (!Arr.
|
|
476
|
+
if (!Arr.isFixedLengthArray(2, typeArguments)) {
|
|
472
477
|
throw new Error(
|
|
473
478
|
`Unexpected number of type arguments "${typeArguments.length}" for Map.`,
|
|
474
479
|
);
|
|
@@ -498,7 +503,7 @@ const transformTypeReferenceNode = (
|
|
|
498
503
|
|
|
499
504
|
// remove unnecessary `Readonly` wrapper or convert to readonly operator
|
|
500
505
|
if (typeNameStr === 'Readonly') {
|
|
501
|
-
if (!Arr.
|
|
506
|
+
if (!Arr.isFixedLengthArray(1, typeArguments)) {
|
|
502
507
|
throw new Error(
|
|
503
508
|
`Unexpected number of type arguments "${typeArguments.length}" for Readonly.`,
|
|
504
509
|
);
|
|
@@ -592,7 +597,7 @@ const transformTypeReferenceNode = (
|
|
|
592
597
|
|
|
593
598
|
// DeepReadonly
|
|
594
599
|
if (typeNameStr === options.DeepReadonly.typeName) {
|
|
595
|
-
if (!Arr.
|
|
600
|
+
if (!Arr.isFixedLengthArray(1, typeArguments)) {
|
|
596
601
|
throw new Error(
|
|
597
602
|
`Unexpected number of type arguments "${typeArguments.length}" for Readonly.`,
|
|
598
603
|
);
|
|
@@ -813,7 +818,7 @@ const transformRestTypeNode = (
|
|
|
813
818
|
const transformTypeOperatorNode = (
|
|
814
819
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
815
820
|
node: tsm.TypeOperatorTypeNode,
|
|
816
|
-
readonlyContext:
|
|
821
|
+
readonlyContext: StrictExclude<
|
|
817
822
|
ReadonlyContext,
|
|
818
823
|
Readonly<{ type: 'readonly'; indexedAccessDepth: SafeUintWithSmallInt }>
|
|
819
824
|
>,
|
|
@@ -852,16 +857,13 @@ const transformTypeOperatorNode = (
|
|
|
852
857
|
const transformTypeLiteralNode = (
|
|
853
858
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
854
859
|
node: tsm.TypeLiteralNode,
|
|
855
|
-
readonlyContext:
|
|
860
|
+
readonlyContext: StrictExclude<
|
|
856
861
|
ReadonlyContext,
|
|
857
862
|
Readonly<{ type: 'readonly'; indexedAccessDepth: SafeUintWithSmallInt }>
|
|
858
863
|
>,
|
|
859
864
|
options: ReadonlyTransformerOptionsInternal,
|
|
860
865
|
): void => {
|
|
861
|
-
if (
|
|
862
|
-
options.ignoreEmptyObjectTypes &&
|
|
863
|
-
Arr.isArrayOfLength(node.getMembers(), 0)
|
|
864
|
-
) {
|
|
866
|
+
if (options.ignoreEmptyObjectTypes && Arr.isEmpty(node.getMembers())) {
|
|
865
867
|
return;
|
|
866
868
|
}
|
|
867
869
|
|
|
@@ -930,7 +932,7 @@ const transformIndexedAccessTypeNode = (
|
|
|
930
932
|
const transformMappedTypeNode = (
|
|
931
933
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
932
934
|
node: tsm.MappedTypeNode,
|
|
933
|
-
readonlyContext:
|
|
935
|
+
readonlyContext: StrictExclude<
|
|
934
936
|
ReadonlyContext,
|
|
935
937
|
Readonly<{ type: 'readonly'; indexedAccessDepth: SafeUintWithSmallInt }>
|
|
936
938
|
>,
|
|
@@ -1112,7 +1114,7 @@ const transformConstructorParameter = (
|
|
|
1112
1114
|
const transformIntersectionTypeNode = (
|
|
1113
1115
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1114
1116
|
node: tsm.IntersectionTypeNode,
|
|
1115
|
-
readonlyContext:
|
|
1117
|
+
readonlyContext: StrictExclude<
|
|
1116
1118
|
ReadonlyContext,
|
|
1117
1119
|
Readonly<{ type: 'readonly'; indexedAccessDepth: SafeUintWithSmallInt }>
|
|
1118
1120
|
>,
|
|
@@ -1128,7 +1130,7 @@ const transformIntersectionTypeNode = (
|
|
|
1128
1130
|
const transformUnionTypeNode = (
|
|
1129
1131
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1130
1132
|
node: tsm.UnionTypeNode,
|
|
1131
|
-
readonlyContext:
|
|
1133
|
+
readonlyContext: StrictExclude<
|
|
1132
1134
|
ReadonlyContext,
|
|
1133
1135
|
Readonly<{ type: 'readonly'; indexedAccessDepth: SafeUintWithSmallInt }>
|
|
1134
1136
|
>,
|
|
@@ -1140,7 +1142,7 @@ const transformUnionTypeNode = (
|
|
|
1140
1142
|
const transformUnionOrIntersectionTypeNodeImpl = (
|
|
1141
1143
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1142
1144
|
node: tsm.IntersectionTypeNode | tsm.UnionTypeNode,
|
|
1143
|
-
readonlyContext:
|
|
1145
|
+
readonlyContext: StrictExclude<
|
|
1144
1146
|
ReadonlyContext,
|
|
1145
1147
|
Readonly<{ type: 'readonly'; indexedAccessDepth: SafeUintWithSmallInt }>
|
|
1146
1148
|
>,
|
|
@@ -1170,8 +1172,7 @@ const transformUnionOrIntersectionTypeNodeImpl = (
|
|
|
1170
1172
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1171
1173
|
n: tsm.TypeLiteralNode | ReadonlyTypeReferenceNode,
|
|
1172
1174
|
): boolean =>
|
|
1173
|
-
n.isKind(tsm.SyntaxKind.TypeLiteral) &&
|
|
1174
|
-
Arr.isArrayOfLength(n.getMembers(), 0);
|
|
1175
|
+
n.isKind(tsm.SyntaxKind.TypeLiteral) && Arr.isEmpty(n.getMembers());
|
|
1175
1176
|
|
|
1176
1177
|
const nonEmptyTypeLiterals =
|
|
1177
1178
|
typeLiterals === undefined
|
|
@@ -1183,11 +1184,10 @@ const transformUnionOrIntersectionTypeNodeImpl = (
|
|
|
1183
1184
|
const emptyTypeLiterals =
|
|
1184
1185
|
typeLiterals === undefined || !options.ignoreEmptyObjectTypes
|
|
1185
1186
|
? undefined
|
|
1186
|
-
: typeLiterals.nodes.filter(
|
|
1187
|
+
: typeLiterals.nodes.filter(isEmptyTypeLiteral);
|
|
1187
1188
|
|
|
1188
1189
|
const typeLiteralsWrappedWithReadonly: readonly [] | readonly [string] =
|
|
1189
|
-
nonEmptyTypeLiterals === undefined ||
|
|
1190
|
-
Arr.isArrayOfLength(nonEmptyTypeLiterals, 0)
|
|
1190
|
+
nonEmptyTypeLiterals === undefined || Arr.isEmpty(nonEmptyTypeLiterals)
|
|
1191
1191
|
? ([] as const)
|
|
1192
1192
|
: ([
|
|
1193
1193
|
unionToString({
|
|
@@ -1282,9 +1282,9 @@ const unionToString = ({
|
|
|
1282
1282
|
op: '&' | '|';
|
|
1283
1283
|
wrapWithReadonly: boolean | string;
|
|
1284
1284
|
}>): string =>
|
|
1285
|
-
Arr.
|
|
1285
|
+
Arr.isEmpty(types)
|
|
1286
1286
|
? 'never'
|
|
1287
|
-
: Arr.
|
|
1287
|
+
: Arr.isFixedLengthArray(1, types)
|
|
1288
1288
|
? wrapWithReadonly === false
|
|
1289
1289
|
? wrapWithParentheses(types[0])
|
|
1290
1290
|
: (`${isString(wrapWithReadonly) ? wrapWithReadonly : 'Readonly'}<${types[0]}>` as const)
|
|
@@ -1351,7 +1351,7 @@ const transformMembers = (
|
|
|
1351
1351
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1352
1352
|
members: readonly tsm.TypeElementTypes[],
|
|
1353
1353
|
readonlyModifier: 'add' | 'remove',
|
|
1354
|
-
readonlyContext:
|
|
1354
|
+
readonlyContext: StrictExtract<
|
|
1355
1355
|
ReadonlyContext,
|
|
1356
1356
|
Readonly<{
|
|
1357
1357
|
type: 'DeepReadonly' | 'none';
|
|
@@ -1392,8 +1392,6 @@ const transformMembers = (
|
|
|
1392
1392
|
}
|
|
1393
1393
|
|
|
1394
1394
|
transformNode(mb, readonlyContext, options);
|
|
1395
|
-
|
|
1396
|
-
continue;
|
|
1397
1395
|
}
|
|
1398
1396
|
};
|
|
1399
1397
|
|
|
@@ -1401,7 +1399,7 @@ const transformPropertySignature = (
|
|
|
1401
1399
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1402
1400
|
node: tsm.PropertySignature,
|
|
1403
1401
|
readonlyModifier: 'add' | 'remove',
|
|
1404
|
-
readonlyContext:
|
|
1402
|
+
readonlyContext: StrictExtract<
|
|
1405
1403
|
ReadonlyContext,
|
|
1406
1404
|
Readonly<{
|
|
1407
1405
|
type: 'DeepReadonly' | 'none';
|
|
@@ -1411,8 +1409,8 @@ const transformPropertySignature = (
|
|
|
1411
1409
|
options: ReadonlyTransformerOptionsInternal,
|
|
1412
1410
|
): void => {
|
|
1413
1411
|
if (
|
|
1414
|
-
|
|
1415
|
-
|
|
1412
|
+
readonlyModifier === 'remove' ||
|
|
1413
|
+
readonlyContext.type === 'DeepReadonly'
|
|
1416
1414
|
) {
|
|
1417
1415
|
node.setIsReadonly(false);
|
|
1418
1416
|
} else {
|
|
@@ -1432,7 +1430,7 @@ const transformIndexSignatureDeclaration = (
|
|
|
1432
1430
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1433
1431
|
node: tsm.IndexSignatureDeclaration,
|
|
1434
1432
|
readonlyModifier: 'add' | 'remove',
|
|
1435
|
-
readonlyContext:
|
|
1433
|
+
readonlyContext: StrictExtract<
|
|
1436
1434
|
ReadonlyContext,
|
|
1437
1435
|
Readonly<{
|
|
1438
1436
|
type: 'DeepReadonly' | 'none';
|
|
@@ -1448,8 +1446,8 @@ const transformIndexSignatureDeclaration = (
|
|
|
1448
1446
|
}
|
|
1449
1447
|
|
|
1450
1448
|
if (
|
|
1451
|
-
|
|
1452
|
-
|
|
1449
|
+
readonlyModifier === 'remove' ||
|
|
1450
|
+
readonlyContext.type === 'DeepReadonly'
|
|
1453
1451
|
) {
|
|
1454
1452
|
// node.setIsReadonly(false);
|
|
1455
1453
|
node.toggleModifier('readonly', false);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SafeUint, match } from 'ts-data-forge';
|
|
2
|
-
import { type SafeUintWithSmallInt } from 'ts-type-forge';
|
|
2
|
+
import { type SafeUintWithSmallInt, type StrictExtract } from 'ts-type-forge';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Controls whether to make a layer mutable during recursive transformation
|
|
@@ -37,7 +37,7 @@ export const nextReadonlyContext = <
|
|
|
37
37
|
indexedAccessDepthChange: 'decr' | 'incr' | 'keep' | 'infinity';
|
|
38
38
|
}
|
|
39
39
|
| {
|
|
40
|
-
nextReadonlyContextType:
|
|
40
|
+
nextReadonlyContextType: StrictExtract<
|
|
41
41
|
ReadonlyContext['type'],
|
|
42
42
|
'DeepReadonly'
|
|
43
43
|
>;
|
|
@@ -47,7 +47,7 @@ export const nextReadonlyContext = <
|
|
|
47
47
|
currentReadonlyContext: Curr;
|
|
48
48
|
}
|
|
49
49
|
>): Readonly<{
|
|
50
|
-
type:
|
|
50
|
+
type: Next | StrictExtract<ReadonlyContext['type'], 'DeepReadonly'>;
|
|
51
51
|
indexedAccessDepth: SafeUintWithSmallInt;
|
|
52
52
|
}> =>
|
|
53
53
|
curr.type === 'DeepReadonly'
|
|
@@ -24,9 +24,7 @@ export const replaceRecordWithUnknownRecordTransformer =
|
|
|
24
24
|
name: TRANSFORMER_NAME,
|
|
25
25
|
transform: (sourceAst) => {
|
|
26
26
|
const containerModifications = Arr.toUnshifted(
|
|
27
|
-
sourceAst
|
|
28
|
-
.getModules()
|
|
29
|
-
.map((namespace) => processDeclarations(namespace)),
|
|
27
|
+
sourceAst.getModules().map(processDeclarations),
|
|
30
28
|
processDeclarations(sourceAst),
|
|
31
29
|
);
|
|
32
30
|
|
|
@@ -53,7 +51,7 @@ const processDeclarations = (
|
|
|
53
51
|
|
|
54
52
|
const interfaceModifications = container
|
|
55
53
|
.getInterfaces()
|
|
56
|
-
.map(
|
|
54
|
+
.map(processInterfaceDeclaration);
|
|
57
55
|
|
|
58
56
|
return [...typeAliasModifications, ...interfaceModifications].includes(true);
|
|
59
57
|
};
|
|
@@ -81,10 +79,10 @@ const processInterfaceDeclaration = (
|
|
|
81
79
|
// (type parameters, extends clauses, declare modifier, default export).
|
|
82
80
|
if (
|
|
83
81
|
hasStringUnknownSignature &&
|
|
84
|
-
Arr.
|
|
85
|
-
Arr.
|
|
86
|
-
Arr.
|
|
87
|
-
Arr.
|
|
82
|
+
Arr.isEmpty(interfaceDecl.getProperties()) &&
|
|
83
|
+
Arr.isFixedLengthArray(1, indexSignatures) &&
|
|
84
|
+
Arr.isEmpty(interfaceDecl.getTypeParameters()) &&
|
|
85
|
+
Arr.isEmpty(interfaceDecl.getExtends()) &&
|
|
88
86
|
!interfaceDecl.hasDeclareKeyword() &&
|
|
89
87
|
!interfaceDecl.hasDefaultKeyword()
|
|
90
88
|
) {
|
|
@@ -118,7 +116,7 @@ const visitTypeNode = (node: tsm.TypeNode): boolean => {
|
|
|
118
116
|
if (node.getTypeName().getText() === 'Readonly') {
|
|
119
117
|
const typeArgs = node.getTypeArguments();
|
|
120
118
|
|
|
121
|
-
if (Arr.
|
|
119
|
+
if (Arr.isFixedLengthArray(1, typeArgs)) {
|
|
122
120
|
const typeArg = typeArgs[0];
|
|
123
121
|
|
|
124
122
|
if (tsm.Node.isTypeLiteral(typeArg)) {
|
|
@@ -130,8 +128,8 @@ const visitTypeNode = (node: tsm.TypeNode): boolean => {
|
|
|
130
128
|
|
|
131
129
|
// Check if it has only one index signature [k: string]: unknown
|
|
132
130
|
if (
|
|
133
|
-
Arr.
|
|
134
|
-
Arr.
|
|
131
|
+
Arr.isFixedLengthArray(1, members) &&
|
|
132
|
+
Arr.isFixedLengthArray(1, indexSigs) &&
|
|
135
133
|
isStringUnknownIndexSignature(indexSigs[0])
|
|
136
134
|
) {
|
|
137
135
|
node.replaceWithText('UnknownRecord');
|
|
@@ -158,8 +156,8 @@ const visitTypeNode = (node: tsm.TypeNode): boolean => {
|
|
|
158
156
|
|
|
159
157
|
// Check if it has only one index signature [k: string]: unknown
|
|
160
158
|
if (
|
|
161
|
-
Arr.
|
|
162
|
-
Arr.
|
|
159
|
+
Arr.isFixedLengthArray(1, members) &&
|
|
160
|
+
Arr.isFixedLengthArray(1, indexSigs) &&
|
|
163
161
|
isStringUnknownIndexSignature(indexSigs[0])
|
|
164
162
|
) {
|
|
165
163
|
node.replaceWithText('UnknownRecord');
|
|
@@ -188,10 +186,7 @@ const visitTypeNode = (node: tsm.TypeNode): boolean => {
|
|
|
188
186
|
|
|
189
187
|
// Recursively visit child type nodes
|
|
190
188
|
if (tsm.Node.isUnionTypeNode(node) || tsm.Node.isIntersectionTypeNode(node)) {
|
|
191
|
-
return node
|
|
192
|
-
.getTypeNodes()
|
|
193
|
-
.map((typeNode) => visitTypeNode(typeNode))
|
|
194
|
-
.includes(true);
|
|
189
|
+
return node.getTypeNodes().map(visitTypeNode).includes(true);
|
|
195
190
|
}
|
|
196
191
|
|
|
197
192
|
if (tsm.Node.isArrayTypeNode(node)) {
|
|
@@ -199,10 +194,7 @@ const visitTypeNode = (node: tsm.TypeNode): boolean => {
|
|
|
199
194
|
}
|
|
200
195
|
|
|
201
196
|
if (tsm.Node.isTupleTypeNode(node)) {
|
|
202
|
-
return node
|
|
203
|
-
.getElements()
|
|
204
|
-
.map((element) => visitTypeNode(element))
|
|
205
|
-
.includes(true);
|
|
197
|
+
return node.getElements().map(visitTypeNode).includes(true);
|
|
206
198
|
}
|
|
207
199
|
|
|
208
200
|
if (tsm.Node.isParenthesizedTypeNode(node)) {
|
|
@@ -244,7 +236,7 @@ const replaceIfRecordUnknown = (node: tsm.TypeReferenceNode): boolean => {
|
|
|
244
236
|
const typeArgs = node.getTypeArguments();
|
|
245
237
|
|
|
246
238
|
if (
|
|
247
|
-
Arr.
|
|
239
|
+
Arr.isFixedLengthArray(2, typeArgs) &&
|
|
248
240
|
typeArgs[0].getText() === 'string' &&
|
|
249
241
|
typeArgs[1].getText() === 'unknown'
|
|
250
242
|
) {
|
|
@@ -254,13 +246,13 @@ const replaceIfRecordUnknown = (node: tsm.TypeReferenceNode): boolean => {
|
|
|
254
246
|
}
|
|
255
247
|
|
|
256
248
|
// Recurse into type arguments (e.g. Record<string, Record<string, unknown>>)
|
|
257
|
-
return typeArgs.map(
|
|
249
|
+
return typeArgs.map(visitTypeNode).includes(true);
|
|
258
250
|
}
|
|
259
251
|
case 'Readonly': {
|
|
260
252
|
// Check if it's Readonly<Record<string, unknown>>
|
|
261
253
|
const typeArgs = node.getTypeArguments();
|
|
262
254
|
|
|
263
|
-
if (Arr.
|
|
255
|
+
if (Arr.isFixedLengthArray(1, typeArgs)) {
|
|
264
256
|
const innerType = typeArgs[0];
|
|
265
257
|
|
|
266
258
|
if (tsm.Node.isTypeReference(innerType)) {
|
|
@@ -270,7 +262,7 @@ const replaceIfRecordUnknown = (node: tsm.TypeReferenceNode): boolean => {
|
|
|
270
262
|
const innerTypeArgs = innerType.getTypeArguments();
|
|
271
263
|
|
|
272
264
|
if (
|
|
273
|
-
Arr.
|
|
265
|
+
Arr.isFixedLengthArray(2, innerTypeArgs) &&
|
|
274
266
|
innerTypeArgs[0].getText() === 'string' &&
|
|
275
267
|
innerTypeArgs[1].getText() === 'unknown'
|
|
276
268
|
) {
|
|
@@ -290,10 +282,7 @@ const replaceIfRecordUnknown = (node: tsm.TypeReferenceNode): boolean => {
|
|
|
290
282
|
|
|
291
283
|
default: {
|
|
292
284
|
// Recurse into type arguments for any other generic type
|
|
293
|
-
return node
|
|
294
|
-
.getTypeArguments()
|
|
295
|
-
.map((typeArg) => visitTypeNode(typeArg))
|
|
296
|
-
.includes(true);
|
|
285
|
+
return node.getTypeArguments().map(visitTypeNode).includes(true);
|
|
297
286
|
}
|
|
298
287
|
}
|
|
299
288
|
};
|
|
@@ -58,12 +58,12 @@ const shouldSkipFile = (
|
|
|
58
58
|
|
|
59
59
|
const hasFileIgnoreComment = patterns.some((regex) => regex.test(code));
|
|
60
60
|
|
|
61
|
-
if (Arr.
|
|
61
|
+
if (!hasFileIgnoreComment && Arr.isEmpty(ignoredTransformers)) {
|
|
62
62
|
return false;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// Empty array means ignore all transformers (file-level ignore without specific transformers)
|
|
66
|
-
if (Arr.
|
|
66
|
+
if (Arr.isEmpty(ignoredTransformers)) {
|
|
67
67
|
return true;
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -43,6 +43,6 @@ export const isAsConstNode = (
|
|
|
43
43
|
// and that there are no type arguments (as const doesn't have them)
|
|
44
44
|
return (
|
|
45
45
|
typeNameNode.getText() === 'const' &&
|
|
46
|
-
Arr.
|
|
46
|
+
Arr.isEmpty(typeNode.getTypeArguments())
|
|
47
47
|
);
|
|
48
48
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Arr, expectType } from 'ts-data-forge';
|
|
2
2
|
import * as tsm from 'ts-morph';
|
|
3
|
-
import { type DeepReadonly } from 'ts-type-forge';
|
|
3
|
+
import { type DeepReadonly, type StrictOmit } from 'ts-type-forge';
|
|
4
4
|
import { isAtomicTypeNode } from './is-atomic-type-node.mjs';
|
|
5
5
|
|
|
6
6
|
export const isShallowReadonlyTypeNode = (node: tsm.Node): boolean =>
|
|
@@ -17,7 +17,7 @@ export const isReadonlyTupleOrArrayTypeNode = (
|
|
|
17
17
|
node.getTypeNode().isKind(tsm.SyntaxKind.TupleType));
|
|
18
18
|
|
|
19
19
|
export type ReadonlyArrayTypeNode = tsm.TypeNode &
|
|
20
|
-
|
|
20
|
+
StrictOmit<tsm.TypeOperatorTypeNode, 'getOperator' | 'getTypeNode'> &
|
|
21
21
|
Readonly<{
|
|
22
22
|
getOperator: () => tsm.SyntaxKind.ReadonlyKeyword;
|
|
23
23
|
getTypeNode: () => tsm.ArrayTypeNode;
|
|
@@ -91,7 +91,7 @@ if (import.meta.vitest !== undefined) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
export type ReadonlyTupleTypeNode = tsm.TypeNode &
|
|
94
|
-
|
|
94
|
+
StrictOmit<tsm.TypeOperatorTypeNode, 'getOperator' | 'getTypeNode'> &
|
|
95
95
|
Readonly<{
|
|
96
96
|
getOperator: () => tsm.SyntaxKind.ReadonlyKeyword;
|
|
97
97
|
getTypeNode: () => tsm.TupleTypeNode;
|
|
@@ -153,9 +153,9 @@ if (import.meta.vitest !== undefined) {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
export type ReadonlyTypeReferenceNode = tsm.TypeNode &
|
|
156
|
-
|
|
156
|
+
StrictOmit<tsm.TypeReferenceNode, 'getTypeName' | 'getTypeArguments'> &
|
|
157
157
|
Readonly<{
|
|
158
|
-
getTypeName: () =>
|
|
158
|
+
getTypeName: () => StrictOmit<tsm.Identifier, 'getText'> &
|
|
159
159
|
Readonly<{
|
|
160
160
|
getText: () => 'Readonly';
|
|
161
161
|
}>;
|
|
@@ -176,7 +176,7 @@ export const isReadonlyTypeReferenceNode = (
|
|
|
176
176
|
return (
|
|
177
177
|
typeName.isKind(tsm.SyntaxKind.Identifier) &&
|
|
178
178
|
typeName.getText() === 'Readonly' &&
|
|
179
|
-
Arr.
|
|
179
|
+
Arr.isFixedLengthArray(1, typeArguments)
|
|
180
180
|
);
|
|
181
181
|
};
|
|
182
182
|
|
|
@@ -23,10 +23,6 @@ export const shouldAvoidParenthesesForReadonly = (node: tsm.Node): boolean => {
|
|
|
23
23
|
// Check if parent is TypePredicate: x is T
|
|
24
24
|
// In this case, we MUST avoid parentheses: x is readonly T (not x is (readonly T))
|
|
25
25
|
// because `x is (readonly T)` is a syntax error
|
|
26
|
-
if (parent.isKind(tsm.SyntaxKind.TypePredicate)) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
// For all other cases, keep parentheses for safety
|
|
31
|
-
return
|
|
27
|
+
return parent.isKind(tsm.SyntaxKind.TypePredicate);
|
|
32
28
|
};
|