ts-codemod-lib 3.5.0 → 3.5.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/README.md +26 -7
- package/dist/functions/ast-transformers/append-as-const.d.mts.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.mjs +3 -0
- package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts +10 -0
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.mjs +118 -14
- package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.d.mts +7 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.d.mts.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs +25 -2
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs.map +1 -1
- package/package.json +19 -19
- package/src/functions/ast-transformers/append-as-const.mts +3 -0
- package/src/functions/ast-transformers/convert-to-readonly.mts +182 -20
- package/src/functions/ast-transformers/convert-to-readonly.test.mts +421 -12
- package/src/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mts +36 -5
package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group-union-types.mjs","sourceRoot":"","sources":["../../../../src/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EACL,2BAA2B,EAC3B,gBAAgB,EAChB,8BAA8B,EAC9B,2BAA2B,EAC3B,iBAAiB,GAKlB,MAAM,2BAA2B,CAAC;AAEnC
|
|
1
|
+
{"version":3,"file":"group-union-types.mjs","sourceRoot":"","sources":["../../../../src/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-codemod-lib",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -38,27 +38,27 @@
|
|
|
38
38
|
"LICENSE"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"ts-data-forge": "^14.
|
|
41
|
+
"ts-data-forge": "^14.10.0",
|
|
42
42
|
"ts-morph": "^28.0.0",
|
|
43
43
|
"ts-type-forge": "^9.2.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@types/node": "26.6.
|
|
47
|
-
"@vitest/browser-playwright": "5.0.
|
|
48
|
-
"@vitest/coverage-v8": "5.0.
|
|
49
|
-
"@vitest/ui": "5.0.
|
|
50
|
-
"cspell": "10.
|
|
46
|
+
"@types/node": "26.6.5",
|
|
47
|
+
"@vitest/browser-playwright": "5.0.5",
|
|
48
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
49
|
+
"@vitest/ui": "5.0.5",
|
|
50
|
+
"cspell": "10.4.0",
|
|
51
51
|
"dedent": "1.7.2",
|
|
52
52
|
"esbuild": "0.28.2",
|
|
53
|
-
"eslint": "10.
|
|
54
|
-
"eslint-config-typed": "5.
|
|
55
|
-
"eslint-plugin-ts-data-forge": "0.
|
|
56
|
-
"eslint-plugin-ts-fortress": "1.3.
|
|
57
|
-
"eslint-plugin-ts-type-forge": "0.8.
|
|
53
|
+
"eslint": "10.13.0",
|
|
54
|
+
"eslint-config-typed": "5.20.1",
|
|
55
|
+
"eslint-plugin-ts-data-forge": "0.10.4",
|
|
56
|
+
"eslint-plugin-ts-fortress": "1.3.9",
|
|
57
|
+
"eslint-plugin-ts-type-forge": "0.8.14",
|
|
58
58
|
"jiti": "2.7.0",
|
|
59
|
-
"npm-run-all2": "9.0.
|
|
60
|
-
"playwright": "1.64.
|
|
61
|
-
"prettier": "3.9.
|
|
59
|
+
"npm-run-all2": "9.0.4",
|
|
60
|
+
"playwright": "1.64.1",
|
|
61
|
+
"prettier": "3.9.10",
|
|
62
62
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
63
63
|
"prettier-plugin-packagejson": "3.0.2",
|
|
64
64
|
"ts-repo-utils": "10.7.1",
|
|
@@ -67,15 +67,15 @@
|
|
|
67
67
|
"typedoc-github-theme": "0.4.0",
|
|
68
68
|
"typescript": "6.0.3",
|
|
69
69
|
"typescript-native": "npm:typescript@7.0.2",
|
|
70
|
-
"vite": "8.3.
|
|
71
|
-
"vitest": "5.0.
|
|
70
|
+
"vite": "8.3.5",
|
|
71
|
+
"vitest": "5.0.5"
|
|
72
72
|
},
|
|
73
73
|
"engines": {
|
|
74
|
-
"node": ">=22.
|
|
74
|
+
"node": ">=22.23.4",
|
|
75
75
|
"pnpm": ">=9.0.0"
|
|
76
76
|
},
|
|
77
77
|
"volta": {
|
|
78
|
-
"node": "26.12.
|
|
78
|
+
"node": "26.12.1"
|
|
79
79
|
},
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public",
|
|
@@ -16,6 +16,9 @@ const TRANSFORMER_NAME = 'append-as-const';
|
|
|
16
16
|
export const appendAsConstTransformer = (
|
|
17
17
|
options?: AppendAsConstTransformerOptions,
|
|
18
18
|
): TsMorphTransformer => {
|
|
19
|
+
// The ESLint counterpart is `ignoredMutablePattern` in
|
|
20
|
+
// `libs/eslint-config-typed/src/rules/eslint-functional-rules.mts`; change
|
|
21
|
+
// the two together.
|
|
19
22
|
const ignorePrefixes = ISet.create(
|
|
20
23
|
options?.ignorePrefixes ?? ['mut_', '#mut_', '_mut_', 'draft'],
|
|
21
24
|
);
|
|
@@ -59,6 +59,10 @@ export const convertToReadonlyTransformer = (
|
|
|
59
59
|
const DeepReadonlyTypeName =
|
|
60
60
|
options?.DeepReadonly?.typeName ?? 'DeepReadonly';
|
|
61
61
|
|
|
62
|
+
// The ESLint counterpart is `ignoredMutablePattern` in
|
|
63
|
+
// `libs/eslint-config-typed/src/rules/eslint-functional-rules.mts`; change
|
|
64
|
+
// the two together. (ESLint matches a property access by its own
|
|
65
|
+
// `ignoreAccessorPattern`, `**.mut_**`, instead.)
|
|
62
66
|
const ignorePrefixes = ISet.create(
|
|
63
67
|
options?.ignorePrefixes ?? ['mut_', '#mut_', '_mut_', 'draft'],
|
|
64
68
|
);
|
|
@@ -139,6 +143,16 @@ export type ReadonlyTransformerOptions = DeepReadonly<{
|
|
|
139
143
|
*
|
|
140
144
|
* (e.g. `"mut_"`)
|
|
141
145
|
*
|
|
146
|
+
* A type literal with a property, a method or an accessor of such a prefix
|
|
147
|
+
* is not wrapped with `Readonly<...>`, which would make that member readonly
|
|
148
|
+
* too; its other members are marked `readonly` one by one instead, and a
|
|
149
|
+
* `Readonly<...>` written around it is taken off. It is wrapped as before
|
|
150
|
+
* when it also has a member that cannot be marked `readonly` by itself (a
|
|
151
|
+
* method signature or an accessor without such a prefix, or a property or
|
|
152
|
+
* index signature not yet `readonly` that an ignore comment skips), or when
|
|
153
|
+
* it is a member of a `Readonly<...>` intersection beside a type that may be
|
|
154
|
+
* an array.
|
|
155
|
+
*
|
|
142
156
|
* @default ['mut_', '#mut_', '_mut_', 'draft']
|
|
143
157
|
*/
|
|
144
158
|
ignorePrefixes?: string[];
|
|
@@ -421,6 +435,8 @@ const transformNode = (
|
|
|
421
435
|
* - `tr(Readonly<Readonly<E>>) |-> Readonly<tr(E)>`
|
|
422
436
|
* - `tr(DeepReadonly<Readonly<E>>) |-> DeepReadonly<tr(E)>`
|
|
423
437
|
* - `tr(Readonly<number>) |-> number`
|
|
438
|
+
* - `tr(Readonly<{ mut_x: X; y: Y }>) |-> { mut_x: X; readonly y: tr(Y) }` (see
|
|
439
|
+
* `isLeftUnwrapped`)
|
|
424
440
|
* - `tr(Readonly<E[]>) |-> readonly tr(E)[]`
|
|
425
441
|
* - `tr(Readonly<[E1, E2, E3]>) |-> readonly [tr(E1), tr(E2), tr(E3)]`
|
|
426
442
|
* - `tr(Readonly<readonly E[]>) |-> readonly tr(E)[]`
|
|
@@ -647,14 +663,29 @@ const transformTypeReferenceNode = (
|
|
|
647
663
|
);
|
|
648
664
|
}
|
|
649
665
|
|
|
666
|
+
// Read before the recursion, which may replace the node.
|
|
667
|
+
const typeArgumentBefore = removeParentheses(typeArguments[0]);
|
|
668
|
+
|
|
669
|
+
// Readonly<{ mut_x: X; y: Y }> -> { mut_x: X; readonly y: Y }
|
|
670
|
+
// `Readonly` would make the property of an ignored prefix readonly too, so
|
|
671
|
+
// it is taken off, and the literal is transformed where nothing wraps it,
|
|
672
|
+
// which marks its other members readonly in place. See `takesOffReadonly`.
|
|
673
|
+
const takesOffWrapper =
|
|
674
|
+
readonlyContext.type !== 'DeepReadonly' &&
|
|
675
|
+
readonlyContext.indexedAccessDepth === 0 &&
|
|
676
|
+
typeArgumentBefore.isKind(tsm.SyntaxKind.TypeLiteral) &&
|
|
677
|
+
takesOffReadonly(typeArgumentBefore, options);
|
|
678
|
+
|
|
650
679
|
// Recursive processing
|
|
651
680
|
transformNode(
|
|
652
681
|
typeArguments[0],
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
682
|
+
takesOffWrapper
|
|
683
|
+
? initialReadonlyContext
|
|
684
|
+
: nextReadonlyContext({
|
|
685
|
+
currentReadonlyContext: readonlyContext,
|
|
686
|
+
nextReadonlyContextType: 'Readonly',
|
|
687
|
+
indexedAccessDepthChange: 'keep',
|
|
688
|
+
}),
|
|
658
689
|
options,
|
|
659
690
|
);
|
|
660
691
|
|
|
@@ -695,6 +726,29 @@ const transformTypeReferenceNode = (
|
|
|
695
726
|
return;
|
|
696
727
|
}
|
|
697
728
|
|
|
729
|
+
// Readonly<Readonly<{ mut_x: X }>> -> { mut_x: X } as well: the inner
|
|
730
|
+
// `Readonly` has already been taken off the literal.
|
|
731
|
+
if (
|
|
732
|
+
takesOffWrapper ||
|
|
733
|
+
(T.isKind(tsm.SyntaxKind.TypeLiteral) && takesOffReadonly(T, options))
|
|
734
|
+
) {
|
|
735
|
+
// The comments after the literal, which nothing else carries over, go
|
|
736
|
+
// in front of it: a line comment after it would end the type with a
|
|
737
|
+
// line break, which a following `[]` cannot be parsed across.
|
|
738
|
+
const commentsAfterT = commentsBetween(
|
|
739
|
+
node.getSourceFile(),
|
|
740
|
+
T.getEnd(),
|
|
741
|
+
node.getEnd(),
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
options.replaceNode(
|
|
745
|
+
node,
|
|
746
|
+
`${commentsInFrontOfT}${commentsAfterT}${T.getText()}`,
|
|
747
|
+
);
|
|
748
|
+
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
|
|
698
752
|
// Readonly<Readonly<T>> -> Readonly<T>
|
|
699
753
|
if (isReadonlyTypeReferenceNode(T)) {
|
|
700
754
|
options.replaceNode(node, TText);
|
|
@@ -1085,10 +1139,13 @@ const transformTypeLiteralNode = (
|
|
|
1085
1139
|
const wrappingApplies =
|
|
1086
1140
|
readonlyContext.type === 'none' && readonlyContext.indexedAccessDepth === 0;
|
|
1087
1141
|
|
|
1088
|
-
// A call or construct signature does not survive `Readonly<T>`,
|
|
1089
|
-
//
|
|
1090
|
-
//
|
|
1091
|
-
|
|
1142
|
+
// A call or construct signature does not survive `Readonly<T>`, and a
|
|
1143
|
+
// property of an ignored prefix (`mut_`) must stay mutable, so a literal
|
|
1144
|
+
// carrying either is left unwrapped and marked readonly member by member
|
|
1145
|
+
// instead. See `hasCallOrConstructSignature` and `isLeftUnwrapped`.
|
|
1146
|
+
const skipWrapping =
|
|
1147
|
+
wrappingApplies &&
|
|
1148
|
+
(hasCallOrConstructSignature(node) || isLeftUnwrapped(node, options));
|
|
1092
1149
|
|
|
1093
1150
|
// Recursive processing
|
|
1094
1151
|
transformMembers(
|
|
@@ -1393,16 +1450,25 @@ const transformUnionOrIntersectionTypeNodeImpl = (
|
|
|
1393
1450
|
memberText: string,
|
|
1394
1451
|
): string => `${leadingCommentsOfMember(node, member)}${memberText}` as const;
|
|
1395
1452
|
|
|
1453
|
+
// Whether a type literal member is wrapped at all; under `DeepReadonly` or an
|
|
1454
|
+
// indexed access none is.
|
|
1455
|
+
const wrapsTypeLiterals =
|
|
1456
|
+
nextReadonlyContextValue.type !== 'DeepReadonly' &&
|
|
1457
|
+
nextReadonlyContextValue.indexedAccessDepth === 0;
|
|
1458
|
+
|
|
1459
|
+
// `Readonly<A & { b: B }>`: `A` stays under the `Readonly`, which the
|
|
1460
|
+
// handler of `Readonly` then takes off as redundant.
|
|
1461
|
+
const underReadonly =
|
|
1462
|
+
readonlyContext.type === 'Readonly' &&
|
|
1463
|
+
readonlyContext.indexedAccessDepth === 0 &&
|
|
1464
|
+
isTypeArgumentOfReadonly(node);
|
|
1465
|
+
|
|
1396
1466
|
const { primitives, arraysAndTuples, typeLiterals, others } =
|
|
1397
1467
|
groupUnionIntersectionTypes(newTypes, {
|
|
1398
1468
|
operator,
|
|
1399
|
-
|
|
1400
|
-
// handler of `Readonly` then takes off as redundant.
|
|
1401
|
-
underReadonly:
|
|
1402
|
-
readonlyContext.type === 'Readonly' &&
|
|
1403
|
-
readonlyContext.indexedAccessDepth === 0 &&
|
|
1404
|
-
isTypeArgumentOfReadonly(node),
|
|
1469
|
+
underReadonly,
|
|
1405
1470
|
deepReadonlyTypeName: options.DeepReadonly.typeName,
|
|
1471
|
+
keptUnwrapped: (t) => wrapsTypeLiterals && takesOffReadonly(t, options),
|
|
1406
1472
|
});
|
|
1407
1473
|
|
|
1408
1474
|
options.debugPrint({ primitives, arraysAndTuples, typeLiterals, others });
|
|
@@ -1445,9 +1511,7 @@ const transformUnionOrIntersectionTypeNodeImpl = (
|
|
|
1445
1511
|
),
|
|
1446
1512
|
),
|
|
1447
1513
|
op: operator,
|
|
1448
|
-
wrapWithReadonly:
|
|
1449
|
-
nextReadonlyContextValue.type !== 'DeepReadonly' &&
|
|
1450
|
-
nextReadonlyContextValue.indexedAccessDepth === 0,
|
|
1514
|
+
wrapWithReadonly: wrapsTypeLiterals,
|
|
1451
1515
|
}),
|
|
1452
1516
|
] as const);
|
|
1453
1517
|
|
|
@@ -1909,6 +1973,17 @@ const transformMembers = (
|
|
|
1909
1973
|
continue;
|
|
1910
1974
|
}
|
|
1911
1975
|
|
|
1976
|
+
// A method or an accessor of an ignored prefix is left as written, as in a
|
|
1977
|
+
// class.
|
|
1978
|
+
if (
|
|
1979
|
+
(mb.isKind(tsm.SyntaxKind.MethodSignature) ||
|
|
1980
|
+
mb.isKind(tsm.SyntaxKind.GetAccessor) ||
|
|
1981
|
+
mb.isKind(tsm.SyntaxKind.SetAccessor)) &&
|
|
1982
|
+
checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options)
|
|
1983
|
+
) {
|
|
1984
|
+
continue;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1912
1987
|
if (mb.isKind(tsm.SyntaxKind.IndexSignature)) {
|
|
1913
1988
|
transformIndexSignatureDeclaration(
|
|
1914
1989
|
mb,
|
|
@@ -2034,10 +2109,13 @@ const checkIfPropertyNameShouldBeIgnored = (
|
|
|
2034
2109
|
pipe(nameNode.getText()).map((nm) =>
|
|
2035
2110
|
options.ignoredPrefixes.some((p) => nm.startsWith(`#${p}`)),
|
|
2036
2111
|
).value) ||
|
|
2037
|
-
// [`mut_x`]: number[]
|
|
2112
|
+
// ['mut_x']: number[], [`mut_x`]: number[]
|
|
2038
2113
|
(nameNode.isKind(tsm.SyntaxKind.ComputedPropertyName) &&
|
|
2039
2114
|
pipe(nameNode.getExpression()).map((exp) => {
|
|
2040
|
-
if (
|
|
2115
|
+
if (
|
|
2116
|
+
exp.isKind(tsm.SyntaxKind.StringLiteral) ||
|
|
2117
|
+
exp.isKind(tsm.SyntaxKind.NoSubstitutionTemplateLiteral)
|
|
2118
|
+
) {
|
|
2041
2119
|
const nm = exp.getLiteralValue();
|
|
2042
2120
|
|
|
2043
2121
|
return options.ignoredPrefixes.some((p) => nm.startsWith(p));
|
|
@@ -2047,3 +2125,87 @@ const checkIfPropertyNameShouldBeIgnored = (
|
|
|
2047
2125
|
}).value)
|
|
2048
2126
|
);
|
|
2049
2127
|
};
|
|
2128
|
+
|
|
2129
|
+
/**
|
|
2130
|
+
* Whether a type literal is left without `Readonly<...>` and marked readonly
|
|
2131
|
+
* member by member, because it has a property, a method or an accessor of an
|
|
2132
|
+
* ignored prefix (`{ mut_x: X[] }`), which `transformMembers` leaves mutable
|
|
2133
|
+
* and `Readonly<T>` would not.
|
|
2134
|
+
*
|
|
2135
|
+
* It keeps its `Readonly<...>` when that would leave another member mutable,
|
|
2136
|
+
* since only a property or index signature can be marked `readonly` itself:
|
|
2137
|
+
*
|
|
2138
|
+
* - a method signature or an accessor, which `Readonly<T>` makes readonly too,
|
|
2139
|
+
* unless its name has an ignored prefix as well;
|
|
2140
|
+
* - a property or index signature the ignore comment skips (as
|
|
2141
|
+
* `transformMembers` does), which gets no `readonly` of its own, unless it
|
|
2142
|
+
* is `readonly` already.
|
|
2143
|
+
*/
|
|
2144
|
+
const isLeftUnwrapped = (
|
|
2145
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2146
|
+
node: tsm.TypeLiteralNode,
|
|
2147
|
+
options: ReadonlyTransformerOptionsInternal,
|
|
2148
|
+
): boolean => {
|
|
2149
|
+
const members = node.getMembers();
|
|
2150
|
+
|
|
2151
|
+
const isMethodOrAccessor = (
|
|
2152
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2153
|
+
mb: tsm.TypeElementTypes,
|
|
2154
|
+
): mb is
|
|
2155
|
+
| tsm.MethodSignature
|
|
2156
|
+
| tsm.GetAccessorDeclaration
|
|
2157
|
+
| tsm.SetAccessorDeclaration =>
|
|
2158
|
+
mb.isKind(tsm.SyntaxKind.MethodSignature) ||
|
|
2159
|
+
mb.isKind(tsm.SyntaxKind.GetAccessor) ||
|
|
2160
|
+
mb.isKind(tsm.SyntaxKind.SetAccessor);
|
|
2161
|
+
|
|
2162
|
+
const isIgnoredMember = (
|
|
2163
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2164
|
+
mb: tsm.TypeElementTypes,
|
|
2165
|
+
): boolean =>
|
|
2166
|
+
(mb.isKind(tsm.SyntaxKind.PropertySignature) || isMethodOrAccessor(mb)) &&
|
|
2167
|
+
checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options);
|
|
2168
|
+
|
|
2169
|
+
const needsReadonlyWrapper = (
|
|
2170
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2171
|
+
mb: tsm.TypeElementTypes,
|
|
2172
|
+
): boolean =>
|
|
2173
|
+
!isIgnoredMember(mb) &&
|
|
2174
|
+
(isMethodOrAccessor(mb) ||
|
|
2175
|
+
((mb.isKind(tsm.SyntaxKind.PropertySignature) ||
|
|
2176
|
+
mb.isKind(tsm.SyntaxKind.IndexSignature)) &&
|
|
2177
|
+
!mb.hasModifier(tsm.SyntaxKind.ReadonlyKeyword) &&
|
|
2178
|
+
hasDisableNextLineComment(mb)));
|
|
2179
|
+
|
|
2180
|
+
return members.some(isIgnoredMember) && !members.some(needsReadonlyWrapper);
|
|
2181
|
+
};
|
|
2182
|
+
|
|
2183
|
+
/** Whether `node`, or a parenthesized type around it, carries the ignore comment. */
|
|
2184
|
+
const hasDisableNextLineCommentAround = (node: tsm.Node): boolean => {
|
|
2185
|
+
if (hasDisableNextLineComment(node, TRANSFORMER_NAME)) {
|
|
2186
|
+
return true;
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
const parent = node.getParent();
|
|
2190
|
+
|
|
2191
|
+
return (
|
|
2192
|
+
parent?.isKind(tsm.SyntaxKind.ParenthesizedType) === true &&
|
|
2193
|
+
hasDisableNextLineCommentAround(parent)
|
|
2194
|
+
);
|
|
2195
|
+
};
|
|
2196
|
+
|
|
2197
|
+
/**
|
|
2198
|
+
* Whether a type literal that is already wrapped, or would be merged into the
|
|
2199
|
+
* `Readonly<...>` of a union or intersection, is taken out of it. See
|
|
2200
|
+
* `isLeftUnwrapped`; in addition, the ignore comment leaves the literal where
|
|
2201
|
+
* it is, and taking `Readonly` off one with a call or construct signature
|
|
2202
|
+
* would bring back the signature it dropped.
|
|
2203
|
+
*/
|
|
2204
|
+
const takesOffReadonly = (
|
|
2205
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2206
|
+
node: tsm.TypeLiteralNode,
|
|
2207
|
+
options: ReadonlyTransformerOptionsInternal,
|
|
2208
|
+
): boolean =>
|
|
2209
|
+
isLeftUnwrapped(node, options) &&
|
|
2210
|
+
!hasCallOrConstructSignature(node) &&
|
|
2211
|
+
!hasDisableNextLineCommentAround(node);
|