ts-codemod-lib 3.3.0 → 3.3.2

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.
Files changed (86) hide show
  1. package/README.md +22 -0
  2. package/dist/entry-point.mjs +2 -24
  3. package/dist/entry-point.mjs.map +1 -1
  4. package/dist/functions/ast-transformers/append-as-const.mjs +330 -292
  5. package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
  6. package/dist/functions/ast-transformers/convert-interface-to-type.mjs +85 -70
  7. package/dist/functions/ast-transformers/convert-interface-to-type.mjs.map +1 -1
  8. package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
  9. package/dist/functions/ast-transformers/convert-to-readonly.mjs +971 -838
  10. package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
  11. package/dist/functions/ast-transformers/enable-no-unchecked-indexed-access.d.mts +32 -9
  12. package/dist/functions/ast-transformers/enable-no-unchecked-indexed-access.d.mts.map +1 -1
  13. package/dist/functions/ast-transformers/enable-no-unchecked-indexed-access.mjs +299 -134
  14. package/dist/functions/ast-transformers/enable-no-unchecked-indexed-access.mjs.map +1 -1
  15. package/dist/functions/ast-transformers/index.mjs +10 -12
  16. package/dist/functions/ast-transformers/index.mjs.map +1 -1
  17. package/dist/functions/ast-transformers/readonly-transformer-helpers/compare-union-types.mjs +14 -7
  18. package/dist/functions/ast-transformers/readonly-transformer-helpers/compare-union-types.mjs.map +1 -1
  19. package/dist/functions/ast-transformers/readonly-transformer-helpers/constants.mjs +12 -15
  20. package/dist/functions/ast-transformers/readonly-transformer-helpers/constants.mjs.map +1 -1
  21. package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.d.mts.map +1 -1
  22. package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs +70 -59
  23. package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs.map +1 -1
  24. package/dist/functions/ast-transformers/readonly-transformer-helpers/index.mjs +5 -5
  25. package/dist/functions/ast-transformers/readonly-transformer-helpers/index.mjs.map +1 -1
  26. package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.mjs +15 -20
  27. package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.mjs.map +1 -1
  28. package/dist/functions/ast-transformers/replace-any-with-unknown.mjs +30 -34
  29. package/dist/functions/ast-transformers/replace-any-with-unknown.mjs.map +1 -1
  30. package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs +197 -156
  31. package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs.map +1 -1
  32. package/dist/functions/ast-transformers/transform-source-code.mjs +74 -75
  33. package/dist/functions/ast-transformers/transform-source-code.mjs.map +1 -1
  34. package/dist/functions/ast-transformers/types.mjs +2 -2
  35. package/dist/functions/ast-transformers/types.mjs.map +1 -1
  36. package/dist/functions/constants/ignore-comment-text.mjs +11 -13
  37. package/dist/functions/constants/ignore-comment-text.mjs.map +1 -1
  38. package/dist/functions/constants/index.mjs +2 -2
  39. package/dist/functions/constants/index.mjs.map +1 -1
  40. package/dist/functions/functions/has-call-or-construct-signature.d.mts +18 -0
  41. package/dist/functions/functions/has-call-or-construct-signature.d.mts.map +1 -0
  42. package/dist/functions/functions/has-call-or-construct-signature.mjs +87 -0
  43. package/dist/functions/functions/has-call-or-construct-signature.mjs.map +1 -0
  44. package/dist/functions/functions/has-disable-next-line-comment.mjs +67 -38
  45. package/dist/functions/functions/has-disable-next-line-comment.mjs.map +1 -1
  46. package/dist/functions/functions/index.d.mts +1 -0
  47. package/dist/functions/functions/index.d.mts.map +1 -1
  48. package/dist/functions/functions/index.mjs +12 -11
  49. package/dist/functions/functions/index.mjs.map +1 -1
  50. package/dist/functions/functions/is-as-const-node.mjs +25 -20
  51. package/dist/functions/functions/is-as-const-node.mjs.map +1 -1
  52. package/dist/functions/functions/is-atomic-type-node.mjs +245 -25
  53. package/dist/functions/functions/is-atomic-type-node.mjs.map +1 -1
  54. package/dist/functions/functions/is-conditional-type-distribution-guard.mjs +34 -13
  55. package/dist/functions/functions/is-conditional-type-distribution-guard.mjs.map +1 -1
  56. package/dist/functions/functions/is-readonly-node.mjs +120 -14
  57. package/dist/functions/functions/is-readonly-node.mjs.map +1 -1
  58. package/dist/functions/functions/is-spread-parameter-node.mjs +5 -6
  59. package/dist/functions/functions/is-spread-parameter-node.mjs.map +1 -1
  60. package/dist/functions/functions/remove-parentheses.mjs +4 -4
  61. package/dist/functions/functions/remove-parentheses.mjs.map +1 -1
  62. package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs +23 -9
  63. package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs.map +1 -1
  64. package/dist/functions/functions/unwrap-readonly.mjs +3 -4
  65. package/dist/functions/functions/unwrap-readonly.mjs.map +1 -1
  66. package/dist/functions/functions/wrap-with-parentheses.d.mts +14 -5
  67. package/dist/functions/functions/wrap-with-parentheses.d.mts.map +1 -1
  68. package/dist/functions/functions/wrap-with-parentheses.mjs +67 -30
  69. package/dist/functions/functions/wrap-with-parentheses.mjs.map +1 -1
  70. package/dist/functions/index.mjs +5 -24
  71. package/dist/functions/index.mjs.map +1 -1
  72. package/dist/functions/utils/index.mjs +2 -2
  73. package/dist/functions/utils/index.mjs.map +1 -1
  74. package/dist/functions/utils/replace-with-debug.mjs +4 -6
  75. package/dist/functions/utils/replace-with-debug.mjs.map +1 -1
  76. package/dist/index.mjs +2 -24
  77. package/dist/index.mjs.map +1 -1
  78. package/package.json +18 -18
  79. package/src/functions/ast-transformers/convert-to-readonly.mts +19 -13
  80. package/src/functions/ast-transformers/convert-to-readonly.test.mts +129 -1
  81. package/src/functions/ast-transformers/enable-no-unchecked-indexed-access.mts +32 -9
  82. package/src/functions/ast-transformers/enable-no-unchecked-indexed-access.test.mts +76 -22
  83. package/src/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mts +8 -1
  84. package/src/functions/functions/has-call-or-construct-signature.mts +120 -0
  85. package/src/functions/functions/index.mts +1 -0
  86. package/src/functions/functions/wrap-with-parentheses.mts +32 -17
@@ -1,873 +1,1006 @@
1
- import { ISet, Arr, pipe, match, mapNullable, isString } from 'ts-data-forge';
1
+ import { Arr, ISet, isString, mapNullable, match, pipe, } from 'ts-data-forge';
2
2
  import * as tsm from 'ts-morph';
3
- import { hasDisableNextLineComment } from '../functions/has-disable-next-line-comment.mjs';
4
- import { isAtomicTypeNode } from '../functions/is-atomic-type-node.mjs';
5
- import { isConditionalTypeDistributionGuard } from '../functions/is-conditional-type-distribution-guard.mjs';
6
- import { isReadonlyTypeReferenceNode, isReadonlyTupleOrArrayTypeNode, isReadonlyArrayTypeNode, isReadonlyTupleTypeNode } from '../functions/is-readonly-node.mjs';
7
- import { removeParentheses } from '../functions/remove-parentheses.mjs';
8
- import { shouldAvoidParenthesesForReadonly } from '../functions/should-avoid-parentheses-for-readonly.mjs';
9
- import { unwrapReadonlyTypeArgText } from '../functions/unwrap-readonly.mjs';
10
- import { wrapWithParentheses } from '../functions/wrap-with-parentheses.mjs';
11
- import { replaceNodeWithDebugPrint } from '../utils/replace-with-debug.mjs';
12
- import { invalidDeepReadonlyTypeName } from './readonly-transformer-helpers/constants.mjs';
13
- import { groupUnionIntersectionTypes } from './readonly-transformer-helpers/group-union-types.mjs';
14
- import { nextReadonlyContext } from './readonly-transformer-helpers/readonly-context.mjs';
15
-
16
- const TRANSFORMER_NAME = "convert-to-readonly";
17
- const convertToReadonlyTransformer = (options) => {
18
- if (options?.DeepReadonly?.typeName !== void 0 && invalidDeepReadonlyTypeName.has(options.DeepReadonly.typeName)) {
19
- throw new Error(
20
- `Invalid DeepReadonly typeName "${options.DeepReadonly.typeName}" passed to convertToReadonlyType`
21
- );
22
- }
23
- const DeepReadonlyTypeName = options?.DeepReadonly?.typeName ?? "DeepReadonly";
24
- const ignorePrefixes = ISet.create(
25
- options?.ignorePrefixes ?? ["mut_", "#mut_", "_mut_", "draft"]
26
- );
27
- const optionsInternal = {
28
- DeepReadonly: {
29
- typeName: DeepReadonlyTypeName,
30
- applyLevel: "keep"
31
- },
32
- ignoreEmptyObjectTypes: options?.ignoreEmptyObjectTypes ?? true,
33
- ignoredPrefixes: ignorePrefixes,
34
- recordStyle: options?.recordStyle ?? "ReadonlyRecord",
35
- debugPrint: options?.debug === true ? console.debug : () => {
36
- },
37
- replaceNode: options?.debug === true ? replaceNodeWithDebugPrint : (node, newNodeText) => node.replaceWithText(newNodeText)
38
- };
39
- return {
40
- name: TRANSFORMER_NAME,
41
- transform: (sourceAst) => {
42
- for (const node of sourceAst.getChildren()) {
43
- transformNode(node, initialReadonlyContext, optionsInternal);
44
- }
45
- }
46
- };
3
+ import { hasCallOrConstructSignature, hasDisableNextLineComment, isAtomicTypeNode, isConditionalTypeDistributionGuard, isReadonlyArrayTypeNode, isReadonlyTupleOrArrayTypeNode, isReadonlyTupleTypeNode, isReadonlyTypeReferenceNode, removeParentheses, shouldAvoidParenthesesForReadonly, unwrapReadonlyTypeArgText, wrapWithParentheses, } from '../functions/index.mjs';
4
+ import { replaceNodeWithDebugPrint } from '../utils/index.mjs';
5
+ import { groupUnionIntersectionTypes, invalidDeepReadonlyTypeName, nextReadonlyContext, } from './readonly-transformer-helpers/index.mjs';
6
+ const TRANSFORMER_NAME = 'convert-to-readonly';
7
+ export const convertToReadonlyTransformer = (options) => {
8
+ if (options?.DeepReadonly?.typeName !== undefined &&
9
+ invalidDeepReadonlyTypeName.has(options.DeepReadonly.typeName)) {
10
+ throw new Error(`Invalid DeepReadonly typeName "${options.DeepReadonly.typeName}" passed to convertToReadonlyType`);
11
+ }
12
+ const DeepReadonlyTypeName = options?.DeepReadonly?.typeName ?? 'DeepReadonly';
13
+ const ignorePrefixes = ISet.create(options?.ignorePrefixes ?? ['mut_', '#mut_', '_mut_', 'draft']);
14
+ const optionsInternal = {
15
+ DeepReadonly: {
16
+ typeName: DeepReadonlyTypeName,
17
+ applyLevel: 'keep',
18
+ },
19
+ ignoreEmptyObjectTypes: options?.ignoreEmptyObjectTypes ?? true,
20
+ ignoredPrefixes: ignorePrefixes,
21
+ recordStyle: options?.recordStyle ?? 'ReadonlyRecord',
22
+ debugPrint: options?.debug === true ? console.debug : () => { },
23
+ replaceNode: options?.debug === true
24
+ ? replaceNodeWithDebugPrint
25
+ : (node, newNodeText) => node.replaceWithText(newNodeText),
26
+ };
27
+ return {
28
+ name: TRANSFORMER_NAME,
29
+ transform: (sourceAst) => {
30
+ for (const node of sourceAst.getChildren()) {
31
+ transformNode(node, initialReadonlyContext, optionsInternal);
32
+ }
33
+ },
34
+ };
47
35
  };
48
36
  const initialReadonlyContext = {
49
- type: "none",
50
- indexedAccessDepth: 0
37
+ type: 'none',
38
+ indexedAccessDepth: 0,
51
39
  };
52
40
  const transformNode = (node, readonlyContext, options) => {
53
- if (tsm.Node.isTypeNode(node) || node.isKind(tsm.SyntaxKind.InterfaceDeclaration) || node.isKind(tsm.SyntaxKind.ClassDeclaration)) {
54
- options.debugPrint();
55
- options.debugPrint(`transformNode [${node.getKindName()}] `);
56
- options.debugPrint(node.getFullText());
57
- options.debugPrint({ readonlyContext });
58
- options.debugPrint();
59
- }
60
- if (hasDisableNextLineComment(node, TRANSFORMER_NAME)) {
61
- options.debugPrint("skipped by disable-next-line comment");
62
- return;
63
- }
64
- if (node.isKind(tsm.SyntaxKind.VariableDeclaration)) {
65
- const nodeName = node.getName();
66
- if (options.ignoredPrefixes.some((p) => nodeName.startsWith(p))) {
67
- options.debugPrint("skipped variable declaration by ignorePrefixes");
68
- return;
69
- }
70
- }
71
- if ((node.isKind(tsm.SyntaxKind.FunctionDeclaration) || node.isKind(tsm.SyntaxKind.FunctionExpression)) && options.ignoredPrefixes.some((p) => node.getName()?.startsWith(p) === true)) {
72
- return;
73
- }
74
- if (node.isKind(tsm.SyntaxKind.Parameter)) {
75
- const nodeName = node.getName();
76
- if (options.ignoredPrefixes.some((p) => nodeName.startsWith(p))) {
77
- return;
78
- }
79
- }
80
- if (node.isKind(tsm.SyntaxKind.TypeAliasDeclaration) && options.ignoredPrefixes.some((p) => node.getName().startsWith(p))) {
81
- return;
82
- }
83
- if (node.isKind(tsm.SyntaxKind.TypeReference)) {
84
- if (readonlyContext.type === "readonly") {
85
- throw new Error(
86
- 'Invalid readonlyContext "readonly" passed to TypeReferenceNode'
87
- );
88
- }
89
- transformTypeReferenceNode(node, readonlyContext, options);
90
- return;
91
- }
92
- if (node.isKind(tsm.SyntaxKind.ArrayType)) {
93
- transformArrayTypeNode(node, readonlyContext, options);
94
- return;
95
- }
96
- if (node.isKind(tsm.SyntaxKind.TupleType)) {
97
- transformTupleTypeNode(node, readonlyContext, options);
98
- return;
99
- }
100
- if (node.isKind(tsm.SyntaxKind.RestType)) {
101
- transformRestTypeNode(node, readonlyContext, options);
102
- return;
103
- }
104
- if (node.isKind(tsm.SyntaxKind.TypeOperator)) {
105
- if (readonlyContext.type === "readonly") {
106
- throw new Error(
107
- 'Invalid readonlyContext "readonly" passed to TypeOperatorNode'
108
- );
109
- }
110
- transformTypeOperatorNode(node, readonlyContext, options);
111
- return;
112
- }
113
- if (node.isKind(tsm.SyntaxKind.TypeLiteral)) {
114
- if (readonlyContext.type === "readonly") {
115
- throw new Error(
116
- 'Invalid readonlyContext "readonly" passed to TypeLiteralNode'
117
- );
118
- }
119
- transformTypeLiteralNode(node, readonlyContext, options);
120
- return;
121
- }
122
- if (node.isKind(tsm.SyntaxKind.IndexedAccessType)) {
123
- transformIndexedAccessTypeNode(node, readonlyContext, options);
124
- return;
125
- }
126
- if (node.isKind(tsm.SyntaxKind.MappedType)) {
127
- if (readonlyContext.type === "readonly") {
128
- throw new Error(
129
- 'Invalid readonlyContext "readonly" passed to MappedTypeNode'
130
- );
131
- }
132
- transformMappedTypeNode(node, readonlyContext, options);
133
- return;
134
- }
135
- if (node.isKind(tsm.SyntaxKind.InterfaceDeclaration)) {
136
- if (options.ignoredPrefixes.some((p) => node.getName().startsWith(p))) {
137
- return;
138
- }
139
- transformInterfaceDeclarationNode(node, options);
140
- return;
141
- }
142
- if (node.isKind(tsm.SyntaxKind.ClassDeclaration)) {
143
- if (options.ignoredPrefixes.some(
144
- (p) => node.getName()?.startsWith(p) === true
145
- )) {
146
- return;
147
- }
148
- transformClassDeclarationNode(node, options);
149
- return;
150
- }
151
- if (node.isKind(tsm.SyntaxKind.IntersectionType)) {
152
- if (readonlyContext.type === "readonly") {
153
- throw new Error(
154
- 'Invalid readonlyContext "readonly" passed to IntersectionTypeNode'
155
- );
156
- }
157
- transformIntersectionTypeNode(node, readonlyContext, options);
158
- return;
159
- }
160
- if (node.isKind(tsm.SyntaxKind.UnionType)) {
161
- if (readonlyContext.type === "readonly") {
162
- throw new Error(
163
- 'Invalid readonlyContext "readonly" passed to UnionTypeNode'
164
- );
165
- }
166
- transformUnionTypeNode(node, readonlyContext, options);
167
- return;
168
- }
169
- if (node.isKind(tsm.SyntaxKind.ParenthesizedType)) {
170
- transformParenthesizedTypeNode(node, readonlyContext, options);
171
- return;
172
- }
173
- for (const child of node.getChildren()) {
174
- transformNode(child, initialReadonlyContext, options);
175
- }
41
+ if (tsm.Node.isTypeNode(node) ||
42
+ node.isKind(tsm.SyntaxKind.InterfaceDeclaration) ||
43
+ node.isKind(tsm.SyntaxKind.ClassDeclaration)) {
44
+ options.debugPrint();
45
+ options.debugPrint(`transformNode [${node.getKindName()}] `);
46
+ options.debugPrint(node.getFullText());
47
+ options.debugPrint({ readonlyContext });
48
+ options.debugPrint();
49
+ }
50
+ if (hasDisableNextLineComment(node, TRANSFORMER_NAME)) {
51
+ options.debugPrint('skipped by disable-next-line comment');
52
+ return;
53
+ }
54
+
55
+ if (node.isKind(tsm.SyntaxKind.VariableDeclaration)) {
56
+ const nodeName = node.getName();
57
+ if (options.ignoredPrefixes.some((p) => nodeName.startsWith(p))) {
58
+
59
+
60
+ options.debugPrint('skipped variable declaration by ignorePrefixes');
61
+ return;
62
+ }
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+ }
72
+
73
+
74
+ if ((node.isKind(tsm.SyntaxKind.FunctionDeclaration) ||
75
+ node.isKind(tsm.SyntaxKind.FunctionExpression)) &&
76
+ options.ignoredPrefixes.some((p) => node.getName()?.startsWith(p) === true)) {
77
+ return;
78
+ }
79
+ if (node.isKind(tsm.SyntaxKind.Parameter)) {
80
+ const nodeName = node.getName();
81
+ if (options.ignoredPrefixes.some((p) => nodeName.startsWith(p))) {
82
+
83
+
84
+ return;
85
+ }
86
+
87
+
88
+
89
+
90
+
91
+
92
+ }
93
+
94
+
95
+ if (node.isKind(tsm.SyntaxKind.TypeAliasDeclaration) &&
96
+ options.ignoredPrefixes.some((p) => node.getName().startsWith(p))) {
97
+ return;
98
+ }
99
+ if (node.isKind(tsm.SyntaxKind.TypeReference)) {
100
+ if (readonlyContext.type === 'readonly') {
101
+ throw new Error('Invalid readonlyContext "readonly" passed to TypeReferenceNode');
102
+ }
103
+ transformTypeReferenceNode(node, readonlyContext, options);
104
+ return;
105
+ }
106
+ if (node.isKind(tsm.SyntaxKind.ArrayType)) {
107
+ transformArrayTypeNode(node, readonlyContext, options);
108
+ return;
109
+ }
110
+ if (node.isKind(tsm.SyntaxKind.TupleType)) {
111
+ transformTupleTypeNode(node, readonlyContext, options);
112
+ return;
113
+ }
114
+ if (node.isKind(tsm.SyntaxKind.RestType)) {
115
+ transformRestTypeNode(node, readonlyContext, options);
116
+ return;
117
+ }
118
+ if (node.isKind(tsm.SyntaxKind.TypeOperator)) {
119
+ if (readonlyContext.type === 'readonly') {
120
+ throw new Error('Invalid readonlyContext "readonly" passed to TypeOperatorNode');
121
+ }
122
+ transformTypeOperatorNode(node, readonlyContext, options);
123
+ return;
124
+ }
125
+ if (node.isKind(tsm.SyntaxKind.TypeLiteral)) {
126
+ if (readonlyContext.type === 'readonly') {
127
+ throw new Error('Invalid readonlyContext "readonly" passed to TypeLiteralNode');
128
+ }
129
+ transformTypeLiteralNode(node, readonlyContext, options);
130
+ return;
131
+ }
132
+ if (node.isKind(tsm.SyntaxKind.IndexedAccessType)) {
133
+ transformIndexedAccessTypeNode(node, readonlyContext, options);
134
+ return;
135
+ }
136
+ if (node.isKind(tsm.SyntaxKind.MappedType)) {
137
+ if (readonlyContext.type === 'readonly') {
138
+ throw new Error('Invalid readonlyContext "readonly" passed to MappedTypeNode');
139
+ }
140
+ transformMappedTypeNode(node, readonlyContext, options);
141
+ return;
142
+ }
143
+ if (node.isKind(tsm.SyntaxKind.InterfaceDeclaration)) {
144
+
145
+
146
+ if (options.ignoredPrefixes.some((p) => node.getName().startsWith(p))) {
147
+ return;
148
+ }
149
+ transformInterfaceDeclarationNode(node, options);
150
+ return;
151
+ }
152
+ if (node.isKind(tsm.SyntaxKind.ClassDeclaration)) {
153
+
154
+
155
+ if (options.ignoredPrefixes.some((p) => node.getName()?.startsWith(p) === true)) {
156
+ return;
157
+ }
158
+ transformClassDeclarationNode(node, options);
159
+ return;
160
+ }
161
+ if (node.isKind(tsm.SyntaxKind.IntersectionType)) {
162
+ if (readonlyContext.type === 'readonly') {
163
+ throw new Error('Invalid readonlyContext "readonly" passed to IntersectionTypeNode');
164
+ }
165
+ transformIntersectionTypeNode(node, readonlyContext, options);
166
+ return;
167
+ }
168
+ if (node.isKind(tsm.SyntaxKind.UnionType)) {
169
+ if (readonlyContext.type === 'readonly') {
170
+ throw new Error('Invalid readonlyContext "readonly" passed to UnionTypeNode');
171
+ }
172
+ transformUnionTypeNode(node, readonlyContext, options);
173
+ return;
174
+ }
175
+ if (node.isKind(tsm.SyntaxKind.ParenthesizedType)) {
176
+
177
+ transformParenthesizedTypeNode(node, readonlyContext, options);
178
+ return;
179
+ }
180
+ for (const child of node.getChildren()) {
181
+ transformNode(child, initialReadonlyContext, options);
182
+ }
176
183
  };
177
- const transformTypeReferenceNode = (node, readonlyContext, options) => {
178
- const typeNameStr = node.getTypeName().getText();
179
- const typeArguments = node.getTypeArguments();
180
- if (typeNameStr === "Array" || typeNameStr === "ReadonlyArray") {
181
- if (!Arr.isFixedLengthArray(1, typeArguments)) {
182
- throw new Error(
183
- `Unexpected number of type arguments "${typeArguments.length}" for ${typeNameStr}.`
184
- );
185
- }
186
- transformNode(
187
- typeArguments[0],
188
- {
189
- type: "none",
190
- indexedAccessDepth: readonlyContext.indexedAccessDepth
191
- },
192
- options
193
- );
194
- const T = node.getTypeArguments()[0];
195
- options.replaceNode(
196
- node,
197
- readonlyContext.type === "DeepReadonly" ? wrapWithParentheses(`${wrapWithParentheses(T.getFullText())}[]`) : wrapWithParentheses(
198
- `readonly ${wrapWithParentheses(T.getFullText())}[]`
199
- )
200
- );
201
- return;
202
- }
203
- if (typeNameStr === "Set") {
204
- if (!Arr.isFixedLengthArray(1, typeArguments)) {
205
- throw new Error(
206
- `Unexpected number of type arguments "${typeArguments.length}" for Set.`
207
- );
208
- }
209
- transformNode(
210
- typeArguments[0],
211
- {
212
- type: "none",
213
- indexedAccessDepth: readonlyContext.indexedAccessDepth
214
- },
215
- options
216
- );
217
- const T = node.getTypeArguments()[0];
218
- options.replaceNode(node, `ReadonlySet<${T.getFullText()}>`);
219
- return;
220
- }
221
- if (typeNameStr === "Map") {
222
- if (!Arr.isFixedLengthArray(2, typeArguments)) {
223
- throw new Error(
224
- `Unexpected number of type arguments "${typeArguments.length}" for Map.`
225
- );
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+ const transformTypeReferenceNode = (
203
+
204
+ node, readonlyContext, options) => {
205
+ const typeNameStr = node.getTypeName().getText();
206
+ const typeArguments = node.getTypeArguments();
207
+
208
+ if (typeNameStr === 'Array' || typeNameStr === 'ReadonlyArray') {
209
+ if (!Arr.isFixedLengthArray(1, typeArguments)) {
210
+ throw new Error(`Unexpected number of type arguments "${typeArguments.length}" for ${typeNameStr}.`);
211
+ }
212
+
213
+ transformNode(typeArguments[0], {
214
+ type: 'none',
215
+ indexedAccessDepth: readonlyContext.indexedAccessDepth,
216
+ }, options);
217
+
218
+ const T = node.getTypeArguments()[0];
219
+ options.replaceNode(node, readonlyContext.type === 'DeepReadonly'
220
+ ? wrapWithParentheses(`${wrapWithParentheses(T.getFullText())}[]`)
221
+ : wrapWithParentheses(`readonly ${wrapWithParentheses(T.getFullText())}[]`));
222
+ return;
226
223
  }
227
- const nextReadonlyContextValue = nextReadonlyContext({
228
- currentReadonlyContext: readonlyContext,
229
- nextReadonlyContextType: "none",
230
- indexedAccessDepthChange: "keep"
231
- });
232
- for (const t of typeArguments) {
233
- transformNode(t, nextReadonlyContextValue, options);
234
- }
235
- const [K, V] = node.getTypeArguments();
236
- options.replaceNode(
237
- node,
238
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
239
- `ReadonlyMap<${K.getFullText()}, ${V.getFullText()}>`
240
- );
241
- return;
242
- }
243
- if (typeNameStr === "Record") {
244
- if (!Arr.isFixedLengthArray(2, typeArguments)) {
245
- throw new Error(
246
- `Unexpected number of type arguments "${typeArguments.length}" for Record.`
247
- );
224
+
225
+ if (typeNameStr === 'Set') {
226
+ if (!Arr.isFixedLengthArray(1, typeArguments)) {
227
+ throw new Error(`Unexpected number of type arguments "${typeArguments.length}" for Set.`);
228
+ }
229
+
230
+ transformNode(typeArguments[0], {
231
+ type: 'none',
232
+ indexedAccessDepth: readonlyContext.indexedAccessDepth,
233
+ }, options);
234
+
235
+ const T = node.getTypeArguments()[0];
236
+ options.replaceNode(node, `ReadonlySet<${T.getFullText()}>`);
237
+ return;
248
238
  }
249
- const nextReadonlyContextValue = nextReadonlyContext({
250
- currentReadonlyContext: readonlyContext,
251
- nextReadonlyContextType: "none",
252
- indexedAccessDepthChange: "keep"
253
- });
254
- for (const t of typeArguments) {
255
- transformNode(t, nextReadonlyContextValue, options);
256
- }
257
- if (readonlyContext.type === "none" && readonlyContext.indexedAccessDepth === 0) {
258
- const [K, V] = node.getTypeArguments();
259
- options.replaceNode(
260
- node,
261
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
262
- readonlyRecordText(K.getFullText(), V.getFullText(), options)
263
- );
264
- }
265
- return;
266
- }
267
- if (typeNameStr === "ReadonlyRecord") {
268
- if (!Arr.isFixedLengthArray(2, typeArguments)) {
269
- throw new Error(
270
- `Unexpected number of type arguments "${typeArguments.length}" for ReadonlyRecord.`
271
- );
239
+
240
+ if (typeNameStr === 'Map') {
241
+ if (!Arr.isFixedLengthArray(2, typeArguments)) {
242
+ throw new Error(`Unexpected number of type arguments "${typeArguments.length}" for Map.`);
243
+ }
244
+ const nextReadonlyContextValue = nextReadonlyContext({
245
+ currentReadonlyContext: readonlyContext,
246
+ nextReadonlyContextType: 'none',
247
+ indexedAccessDepthChange: 'keep',
248
+ });
249
+
250
+ for (const t of typeArguments) {
251
+ transformNode(t, nextReadonlyContextValue, options);
252
+ }
253
+ const [K, V] = node.getTypeArguments();
254
+ options.replaceNode(node,
255
+
256
+ `ReadonlyMap<${K.getFullText()}, ${V.getFullText()}>`);
257
+ return;
272
258
  }
273
- const nextReadonlyContextValue = nextReadonlyContext({
274
- currentReadonlyContext: readonlyContext,
275
- nextReadonlyContextType: "none",
276
- indexedAccessDepthChange: "keep"
277
- });
278
- for (const t of typeArguments) {
279
- transformNode(t, nextReadonlyContextValue, options);
280
- }
281
- const [K, V] = node.getTypeArguments();
282
- const bareRecordText = (
283
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
284
- `Record<${K.getFullText()}, ${V.getFullText()}>`
285
- );
286
- if (readonlyContext.type === "Readonly" && readonlyContext.indexedAccessDepth === 0) {
287
- options.replaceNode(node, bareRecordText);
288
- return;
289
- }
290
- if (options.recordStyle === "Readonly<Record>") {
291
- if (readonlyContext.type !== "none" || readonlyContext.indexedAccessDepth > 0) {
292
- options.replaceNode(node, bareRecordText);
259
+
260
+ if (typeNameStr === 'Record') {
261
+ if (!Arr.isFixedLengthArray(2, typeArguments)) {
262
+ throw new Error(`Unexpected number of type arguments "${typeArguments.length}" for Record.`);
263
+ }
264
+ const nextReadonlyContextValue = nextReadonlyContext({
265
+ currentReadonlyContext: readonlyContext,
266
+ nextReadonlyContextType: 'none',
267
+ indexedAccessDepthChange: 'keep',
268
+ });
269
+
270
+ for (const t of typeArguments) {
271
+ transformNode(t, nextReadonlyContextValue, options);
272
+ }
273
+
274
+
275
+
276
+
277
+
278
+
279
+ if (readonlyContext.type === 'none' &&
280
+ readonlyContext.indexedAccessDepth === 0) {
281
+ const [K, V] = node.getTypeArguments();
282
+ options.replaceNode(node,
283
+
284
+ readonlyRecordText(K.getFullText(), V.getFullText(), options));
285
+ }
293
286
  return;
294
- }
295
- options.replaceNode(node, `Readonly<${bareRecordText}>`);
296
- return;
297
- }
298
- return;
299
- }
300
- if (typeNameStr === "Readonly") {
301
- if (!Arr.isFixedLengthArray(1, typeArguments)) {
302
- throw new Error(
303
- `Unexpected number of type arguments "${typeArguments.length}" for Readonly.`
304
- );
305
- }
306
- transformNode(
307
- typeArguments[0],
308
- nextReadonlyContext({
309
- currentReadonlyContext: readonlyContext,
310
- nextReadonlyContextType: "Readonly",
311
- indexedAccessDepthChange: "keep"
312
- }),
313
- options
314
- );
315
- const T = removeParentheses(node.getTypeArguments()[0]);
316
- if (readonlyContext.type === "DeepReadonly") {
317
- options.replaceNode(node, T.getFullText());
318
- return;
319
- }
320
- if (readonlyContext.indexedAccessDepth > 0) {
321
- options.replaceNode(node, T.getFullText());
322
- return;
323
- }
324
- if (isReadonlyTypeReferenceNode(T)) {
325
- options.replaceNode(node, T.getFullText());
326
- return;
327
- }
328
- if (isAtomicTypeNode(T)) {
329
- options.replaceNode(node, T.getFullText());
330
- return;
331
- }
332
- if (T.isKind(tsm.SyntaxKind.TypeReference) && T.getTypeName().getText() === "Record") {
333
- const recordTypeArguments = T.getTypeArguments();
334
- if (Arr.isFixedLengthArray(2, recordTypeArguments)) {
335
- options.replaceNode(
336
- node,
337
- readonlyRecordText(
338
- recordTypeArguments[0].getFullText(),
339
- recordTypeArguments[1].getFullText(),
340
- options
341
- )
342
- );
287
+ }
288
+
289
+ if (typeNameStr === 'ReadonlyRecord') {
290
+ if (!Arr.isFixedLengthArray(2, typeArguments)) {
291
+ throw new Error(`Unexpected number of type arguments "${typeArguments.length}" for ReadonlyRecord.`);
292
+ }
293
+ const nextReadonlyContextValue = nextReadonlyContext({
294
+ currentReadonlyContext: readonlyContext,
295
+ nextReadonlyContextType: 'none',
296
+ indexedAccessDepthChange: 'keep',
297
+ });
298
+
299
+ for (const t of typeArguments) {
300
+ transformNode(t, nextReadonlyContextValue, options);
301
+ }
302
+ const [K, V] = node.getTypeArguments();
303
+ const bareRecordText =
304
+
305
+ `Record<${K.getFullText()}, ${V.getFullText()}>`;
306
+
307
+
308
+
309
+ if (readonlyContext.type === 'Readonly' &&
310
+ readonlyContext.indexedAccessDepth === 0) {
311
+ options.replaceNode(node, bareRecordText);
312
+ return;
313
+ }
314
+ if (options.recordStyle === 'Readonly<Record>') {
315
+
316
+
317
+
318
+
319
+
320
+ if (readonlyContext.type !== 'none' ||
321
+ readonlyContext.indexedAccessDepth > 0) {
322
+ options.replaceNode(node, bareRecordText);
323
+ return;
324
+ }
325
+ options.replaceNode(node, `Readonly<${bareRecordText}>`);
326
+ return;
327
+ }
328
+
329
+
330
+
331
+
332
+
343
333
  return;
344
- }
345
- }
346
- if (T.isKind(tsm.SyntaxKind.ArrayType) || T.isKind(tsm.SyntaxKind.TupleType)) {
347
- const readonlyText = `readonly ${T.getFullText()}`;
348
- options.replaceNode(
349
- node,
350
- shouldAvoidParenthesesForReadonly(node) ? readonlyText : wrapWithParentheses(readonlyText)
351
- );
352
- return;
353
- }
354
- if (isReadonlyTupleOrArrayTypeNode(T)) {
355
- options.replaceNode(node, T.getFullText());
356
- return;
357
- }
358
- if (T.isKind(tsm.SyntaxKind.UnionType) || T.isKind(tsm.SyntaxKind.IntersectionType)) {
359
- options.replaceNode(node, T.getFullText());
360
- return;
361
- }
362
- return;
363
- }
364
- if (typeNameStr === options.DeepReadonly.typeName) {
365
- if (!Arr.isFixedLengthArray(1, typeArguments)) {
366
- throw new Error(
367
- `Unexpected number of type arguments "${typeArguments.length}" for Readonly.`
368
- );
369
- }
370
- transformNode(
371
- typeArguments[0],
372
- nextReadonlyContext({
373
- currentReadonlyContext: readonlyContext,
374
- nextReadonlyContextType: "DeepReadonly"
375
- }),
376
- options
377
- );
378
- const T = node.getTypeArguments()[0];
379
- if (readonlyContext.type === "DeepReadonly") {
380
- options.replaceNode(node, T.getFullText());
381
- return;
382
- }
383
- if (isAtomicTypeNode(T)) {
384
- options.replaceNode(node, T.getFullText());
385
- return;
386
- }
387
- if (T.isKind(tsm.SyntaxKind.ArrayType) && isAtomicTypeNode(T.getElementTypeNode())) {
388
- const readonlyText = `readonly ${T.getFullText()}`;
389
- options.replaceNode(
390
- node,
391
- shouldAvoidParenthesesForReadonly(node) ? readonlyText : wrapWithParentheses(readonlyText)
392
- );
393
- return;
394
- }
395
- if (T.isKind(tsm.SyntaxKind.TupleType) && T.getElements().every(isAtomicTypeNode)) {
396
- const readonlyText = `readonly ${T.getFullText()}`;
397
- options.replaceNode(
398
- node,
399
- shouldAvoidParenthesesForReadonly(node) ? readonlyText : wrapWithParentheses(readonlyText)
400
- );
401
- return;
402
- }
403
- return;
404
- }
405
- {
406
- const nextReadonlyContextValue = nextReadonlyContext({
407
- currentReadonlyContext: readonlyContext,
408
- nextReadonlyContextType: "none",
409
- indexedAccessDepthChange: "keep"
410
- });
411
- for (const t of node.getTypeArguments()) {
412
- transformNode(t, nextReadonlyContextValue, options);
413
334
  }
414
- }
335
+
336
+ if (typeNameStr === 'Readonly') {
337
+ if (!Arr.isFixedLengthArray(1, typeArguments)) {
338
+ throw new Error(`Unexpected number of type arguments "${typeArguments.length}" for Readonly.`);
339
+ }
340
+
341
+ transformNode(typeArguments[0], nextReadonlyContext({
342
+ currentReadonlyContext: readonlyContext,
343
+ nextReadonlyContextType: 'Readonly',
344
+ indexedAccessDepthChange: 'keep',
345
+ }), options);
346
+
347
+ const T = removeParentheses(node.getTypeArguments()[0]);
348
+
349
+ if (readonlyContext.type === 'DeepReadonly') {
350
+ options.replaceNode(node, T.getFullText());
351
+ return;
352
+ }
353
+
354
+ if (readonlyContext.indexedAccessDepth > 0) {
355
+ options.replaceNode(node, T.getFullText());
356
+ return;
357
+ }
358
+
359
+ if (isReadonlyTypeReferenceNode(T)) {
360
+ options.replaceNode(node, T.getFullText());
361
+ return;
362
+ }
363
+
364
+ if (isAtomicTypeNode(T)) {
365
+ options.replaceNode(node, T.getFullText());
366
+ return;
367
+ }
368
+
369
+
370
+ if (T.isKind(tsm.SyntaxKind.TypeReference) &&
371
+ T.getTypeName().getText() === 'Record') {
372
+ const recordTypeArguments = T.getTypeArguments();
373
+ if (Arr.isFixedLengthArray(2, recordTypeArguments)) {
374
+ options.replaceNode(node, readonlyRecordText(recordTypeArguments[0].getFullText(), recordTypeArguments[1].getFullText(), options));
375
+ return;
376
+ }
377
+ }
378
+
379
+
380
+
381
+
382
+
383
+ if (T.isKind(tsm.SyntaxKind.ArrayType) ||
384
+ T.isKind(tsm.SyntaxKind.TupleType)) {
385
+ const readonlyText = `readonly ${T.getFullText()}`;
386
+ options.replaceNode(node, shouldAvoidParenthesesForReadonly(node)
387
+ ? readonlyText
388
+ : wrapWithParentheses(readonlyText));
389
+ return;
390
+ }
391
+
392
+
393
+
394
+ if (isReadonlyTupleOrArrayTypeNode(T)) {
395
+ options.replaceNode(node, T.getFullText());
396
+ return;
397
+ }
398
+
399
+
400
+ if (T.isKind(tsm.SyntaxKind.UnionType) ||
401
+ T.isKind(tsm.SyntaxKind.IntersectionType)) {
402
+ options.replaceNode(node, T.getFullText());
403
+ return;
404
+ }
405
+ return;
406
+ }
407
+
408
+ if (typeNameStr === options.DeepReadonly.typeName) {
409
+ if (!Arr.isFixedLengthArray(1, typeArguments)) {
410
+ throw new Error(`Unexpected number of type arguments "${typeArguments.length}" for Readonly.`);
411
+ }
412
+
413
+ transformNode(typeArguments[0], nextReadonlyContext({
414
+ currentReadonlyContext: readonlyContext,
415
+ nextReadonlyContextType: 'DeepReadonly',
416
+ }), options);
417
+
418
+ const T = node.getTypeArguments()[0];
419
+
420
+ if (readonlyContext.type === 'DeepReadonly') {
421
+ options.replaceNode(node, T.getFullText());
422
+ return;
423
+ }
424
+
425
+ if (isAtomicTypeNode(T)) {
426
+ options.replaceNode(node, T.getFullText());
427
+ return;
428
+ }
429
+
430
+
431
+
432
+
433
+ if (T.isKind(tsm.SyntaxKind.ArrayType) &&
434
+ isAtomicTypeNode(T.getElementTypeNode())) {
435
+ const readonlyText = `readonly ${T.getFullText()}`;
436
+ options.replaceNode(node, shouldAvoidParenthesesForReadonly(node)
437
+ ? readonlyText
438
+ : wrapWithParentheses(readonlyText));
439
+ return;
440
+ }
441
+
442
+
443
+ if (T.isKind(tsm.SyntaxKind.TupleType) &&
444
+ T.getElements().every(isAtomicTypeNode)) {
445
+ const readonlyText = `readonly ${T.getFullText()}`;
446
+ options.replaceNode(node, shouldAvoidParenthesesForReadonly(node)
447
+ ? readonlyText
448
+ : wrapWithParentheses(readonlyText));
449
+ return;
450
+ }
451
+ return;
452
+ }
453
+ {
454
+ const nextReadonlyContextValue = nextReadonlyContext({
455
+ currentReadonlyContext: readonlyContext,
456
+ nextReadonlyContextType: 'none',
457
+ indexedAccessDepthChange: 'keep',
458
+ });
459
+
460
+ for (const t of node.getTypeArguments()) {
461
+ transformNode(t, nextReadonlyContextValue, options);
462
+ }
463
+ }
415
464
  };
416
- const readonlyRecordText = (keyText, valueText, options) => options.recordStyle === "ReadonlyRecord" ? `ReadonlyRecord<${keyText}, ${valueText}>` : `Readonly<Record<${keyText}, ${valueText}>>`;
417
- const transformArrayTypeNode = (node, readonlyContext, options) => {
418
- transformNode(
419
- node.getElementTypeNode(),
420
- nextReadonlyContext({
421
- currentReadonlyContext: readonlyContext,
422
- nextReadonlyContextType: "none",
423
- indexedAccessDepthChange: "decr"
424
- }),
425
- options
426
- );
427
- switch (readonlyContext.type) {
428
- case "DeepReadonly":
429
- case "readonly":
430
- return;
431
- // remain tr(E)[] as is
432
- // Unnecessary `Readonly` wrapper will be remove in transformTypeReferenceNode
433
- case "Readonly":
434
- case "none":
435
- if (readonlyContext.indexedAccessDepth === 0 && !isConditionalTypeDistributionGuard(node)) {
436
- const readonlyText = `readonly ${node.getFullText()}`;
437
- options.replaceNode(
438
- node,
439
- shouldAvoidParenthesesForReadonly(node) ? readonlyText : wrapWithParentheses(readonlyText)
440
- );
441
- }
442
- }
465
+
466
+ const readonlyRecordText = (keyText, valueText, options) => options.recordStyle === 'ReadonlyRecord'
467
+ ? `ReadonlyRecord<${keyText}, ${valueText}>`
468
+ : `Readonly<Record<${keyText}, ${valueText}>>`;
469
+
470
+ const transformArrayTypeNode = (
471
+
472
+ node, readonlyContext, options) => {
473
+
474
+ transformNode(node.getElementTypeNode(), nextReadonlyContext({
475
+ currentReadonlyContext: readonlyContext,
476
+ nextReadonlyContextType: 'none',
477
+ indexedAccessDepthChange: 'decr',
478
+ }), options);
479
+ switch (readonlyContext.type) {
480
+ case 'DeepReadonly':
481
+ case 'readonly':
482
+ return;
483
+
484
+ case 'Readonly':
485
+ case 'none':
486
+
487
+
488
+ if (readonlyContext.indexedAccessDepth === 0 &&
489
+ !isConditionalTypeDistributionGuard(node)) {
490
+ const readonlyText = `readonly ${node.getFullText()}`;
491
+ options.replaceNode(node, shouldAvoidParenthesesForReadonly(node)
492
+ ? readonlyText
493
+ : wrapWithParentheses(readonlyText));
494
+ }
495
+ }
443
496
  };
444
- const transformTupleTypeNode = (node, readonlyContext, options) => {
445
- {
446
- const nextReadonlyContextValue = nextReadonlyContext({
447
- currentReadonlyContext: readonlyContext,
448
- nextReadonlyContextType: "none",
449
- indexedAccessDepthChange: "decr"
450
- });
451
- for (const el of node.getElements()) {
452
- if (el.isKind(tsm.SyntaxKind.NamedTupleMember)) {
453
- if (options.ignoredPrefixes.every((p) => !el.getName().startsWith(p))) {
454
- transformNode(el.getTypeNode(), nextReadonlyContextValue, options);
455
- }
456
- } else {
457
- transformNode(el, nextReadonlyContextValue, options);
458
- }
459
- }
460
- }
461
- switch (readonlyContext.type) {
462
- case "DeepReadonly":
463
- case "readonly":
464
- return;
465
- // remain tr(E)[] as is
466
- // Unnecessary `Readonly` wrapper will be remove in transformTypeReferenceNode
467
- case "Readonly":
468
- case "none":
469
- if (readonlyContext.indexedAccessDepth === 0 && !isConditionalTypeDistributionGuard(node)) {
470
- const readonlyText = `readonly ${node.getFullText()}`;
471
- options.replaceNode(
472
- node,
473
- shouldAvoidParenthesesForReadonly(node) ? readonlyText : wrapWithParentheses(readonlyText)
474
- );
475
- }
476
- }
497
+
498
+ const transformTupleTypeNode = (
499
+
500
+ node, readonlyContext, options) => {
501
+
502
+ {
503
+ const nextReadonlyContextValue = nextReadonlyContext({
504
+ currentReadonlyContext: readonlyContext,
505
+ nextReadonlyContextType: 'none',
506
+ indexedAccessDepthChange: 'decr',
507
+ });
508
+ for (const el of node.getElements()) {
509
+ if (el.isKind(tsm.SyntaxKind.NamedTupleMember)) {
510
+ if (options.ignoredPrefixes.every((p) => !el.getName().startsWith(p))) {
511
+ transformNode(el.getTypeNode(), nextReadonlyContextValue, options);
512
+ }
513
+ }
514
+ else {
515
+ transformNode(el, nextReadonlyContextValue, options);
516
+ }
517
+ }
518
+ }
519
+ switch (readonlyContext.type) {
520
+ case 'DeepReadonly':
521
+ case 'readonly':
522
+ return;
523
+
524
+ case 'Readonly':
525
+ case 'none':
526
+
527
+
528
+ if (readonlyContext.indexedAccessDepth === 0 &&
529
+ !isConditionalTypeDistributionGuard(node)) {
530
+ const readonlyText = `readonly ${node.getFullText()}`;
531
+ options.replaceNode(node, shouldAvoidParenthesesForReadonly(node)
532
+ ? readonlyText
533
+ : wrapWithParentheses(readonlyText));
534
+ }
535
+ }
477
536
  };
478
- const transformRestTypeNode = (node, readonlyContext, options) => {
479
- transformNode(
480
- node.getTypeNode(),
481
- nextReadonlyContext({
482
- currentReadonlyContext: readonlyContext,
483
- nextReadonlyContextType: "none",
484
- indexedAccessDepthChange: "decr"
485
- }),
486
- options
487
- );
488
- const R = removeParentheses(node.getTypeNode());
489
- if (isReadonlyArrayTypeNode(R) || isReadonlyTupleTypeNode(R)) {
490
- options.replaceNode(
491
- node,
492
- `...${R.getTypeNode().getFullText()}`
493
- );
494
- }
537
+
538
+ const transformRestTypeNode = (
539
+
540
+ node, readonlyContext, options) => {
541
+
542
+ transformNode(node.getTypeNode() , nextReadonlyContext({
543
+ currentReadonlyContext: readonlyContext,
544
+ nextReadonlyContextType: 'none',
545
+ indexedAccessDepthChange: 'decr',
546
+ }), options);
547
+ const R = removeParentheses(node.getTypeNode());
548
+
549
+
550
+ if (isReadonlyArrayTypeNode(R) || isReadonlyTupleTypeNode(R)) {
551
+ options.replaceNode(node, `...${R.getTypeNode().getFullText()}` );
552
+ }
495
553
  };
496
- const transformTypeOperatorNode = (node, readonlyContext, options) => {
497
- transformNode(
498
- node.getTypeNode(),
499
- nextReadonlyContext({
500
- currentReadonlyContext: readonlyContext,
501
- nextReadonlyContextType: node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword ? "readonly" : "none",
502
- indexedAccessDepthChange: "decr"
503
- }),
504
- options
505
- );
506
- switch (readonlyContext.type) {
507
- // DeepReadonly<readonly E[]> -> DeepReadonly<E[]>
508
- case "DeepReadonly":
509
- options.replaceNode(node, node.getTypeNode().getFullText());
510
- return;
511
- case "Readonly":
512
- case "none":
513
- if (readonlyContext.indexedAccessDepth > 0) {
514
- options.replaceNode(node, node.getTypeNode().getFullText());
515
- }
516
- }
554
+
555
+
556
+
557
+
558
+ const transformTypeOperatorNode = (
559
+
560
+ node, readonlyContext, options) => {
561
+
562
+ transformNode(node.getTypeNode(), nextReadonlyContext({
563
+ currentReadonlyContext: readonlyContext,
564
+ nextReadonlyContextType: node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword
565
+ ? 'readonly'
566
+ : 'none',
567
+ indexedAccessDepthChange: 'decr',
568
+ }), options);
569
+ switch (readonlyContext.type) {
570
+
571
+ case 'DeepReadonly':
572
+ options.replaceNode(node, node.getTypeNode().getFullText());
573
+ return;
574
+ case 'Readonly':
575
+ case 'none':
576
+ if (readonlyContext.indexedAccessDepth > 0) {
577
+ options.replaceNode(node, node.getTypeNode().getFullText());
578
+ }
579
+ }
517
580
  };
518
- const transformTypeLiteralNode = (node, readonlyContext, options) => {
519
- if (options.ignoreEmptyObjectTypes && Arr.isEmpty(node.getMembers())) {
520
- return;
521
- }
522
- transformMembers(
523
- node.getMembers(),
524
- "remove",
525
- nextReadonlyContext({
526
- currentReadonlyContext: readonlyContext,
527
- nextReadonlyContextType: "none",
528
- indexedAccessDepthChange: "decr"
529
- }),
530
- options
531
- );
532
- switch (readonlyContext.type) {
533
- case "DeepReadonly":
534
- case "Readonly":
535
- return;
536
- case "none": {
537
- if (readonlyContext.indexedAccessDepth === 0) {
581
+
582
+ const transformTypeLiteralNode = (
583
+
584
+ node, readonlyContext, options) => {
585
+ if (options.ignoreEmptyObjectTypes && Arr.isEmpty(node.getMembers())) {
586
+ return;
587
+ }
588
+
589
+
590
+
591
+ const wrappingApplies = readonlyContext.type === 'none' && readonlyContext.indexedAccessDepth === 0;
592
+
593
+
594
+
595
+ const skipWrapping = wrappingApplies && hasCallOrConstructSignature(node);
596
+
597
+ transformMembers(node.getMembers(),
598
+
599
+
600
+
601
+ skipWrapping ? 'add' : 'remove', nextReadonlyContext({
602
+ currentReadonlyContext: readonlyContext,
603
+ nextReadonlyContextType: 'none',
604
+ indexedAccessDepthChange: 'decr',
605
+ }), options);
606
+ if (wrappingApplies && !skipWrapping) {
607
+
538
608
  options.replaceNode(node, `Readonly<${node.getFullText()}>`);
539
- }
540
609
  }
541
- }
542
- };
543
- const transformIndexedAccessTypeNode = (node, readonlyContext, options) => {
544
- transformNode(
545
- node.getObjectTypeNode(),
546
- nextReadonlyContext({
547
- currentReadonlyContext: readonlyContext,
548
- nextReadonlyContextType: "none",
549
- indexedAccessDepthChange: "incr"
550
- }),
551
- options
552
- );
553
- transformNode(
554
- node.getIndexTypeNode(),
555
- nextReadonlyContext({
556
- currentReadonlyContext: readonlyContext,
557
- nextReadonlyContextType: "Readonly",
558
- indexedAccessDepthChange: "decr"
559
- }),
560
- options
561
- );
562
610
  };
563
- const transformMappedTypeNode = (node, readonlyContext, options) => {
564
- const typeNode = node.getTypeNode();
565
- if (typeNode !== void 0) {
566
- transformNode(
567
- typeNode,
568
- nextReadonlyContext({
611
+
612
+ const transformIndexedAccessTypeNode = (
613
+
614
+ node, readonlyContext, options) => {
615
+
616
+ transformNode(node.getObjectTypeNode(), nextReadonlyContext({
569
617
  currentReadonlyContext: readonlyContext,
570
- nextReadonlyContextType: "none",
571
- indexedAccessDepthChange: "decr"
572
- }),
573
- options
574
- );
575
- }
576
- const questionTokenText = pipe(node.getQuestionToken()?.getText()).mapNullable(
577
- (t) => t === "?" ? "?" : t === "-" ? "-?" : t === "+" ? "+?" : void 0
578
- ).value ?? "";
579
- const nameTypeText = pipe(node.getNameTypeNode()?.getFullText()).mapNullable(
580
- (t) => ` as ${t.trim()}`
581
- ).value;
582
- const result = pipe(
583
- // remove readonlyToken
584
- `{ [${node.getTypeParameter().getFullText()}${nameTypeText ?? ""}]${questionTokenText}: ${node.getTypeNode()?.getFullText()} }`
585
- ).map(
586
- (mpt) => match(readonlyContext.type, {
587
- // Don't wrap with Readonly if already readonly or unnecessary
588
- DeepReadonly: mpt,
589
- Readonly: mpt,
590
- none: readonlyContext.indexedAccessDepth > 0 ? mpt : `Readonly<${mpt}>`
591
- })
592
- ).value;
593
- options.replaceNode(node, result);
618
+ nextReadonlyContextType: 'none',
619
+ indexedAccessDepthChange: 'incr',
620
+ }), options);
621
+ transformNode(node.getIndexTypeNode() , nextReadonlyContext({
622
+ currentReadonlyContext: readonlyContext,
623
+ nextReadonlyContextType: 'Readonly',
624
+ indexedAccessDepthChange: 'decr',
625
+ }), options);
594
626
  };
595
- const transformInterfaceDeclarationNode = (node, options) => {
596
- for (const param of node.getTypeParameters()) {
597
- transformNode(param, initialReadonlyContext, options);
598
- }
599
- for (const n of node.getHeritageClauses()) {
600
- transformNode(n, initialReadonlyContext, options);
601
- }
602
- transformMembers(node.getMembers(), "add", initialReadonlyContext, options);
627
+
628
+
629
+
630
+
631
+
632
+
633
+ const transformMappedTypeNode = (
634
+
635
+ node, readonlyContext, options) => {
636
+ const typeNode = node.getTypeNode();
637
+ if (typeNode !== undefined) {
638
+ transformNode(typeNode, nextReadonlyContext({
639
+ currentReadonlyContext: readonlyContext,
640
+ nextReadonlyContextType: 'none',
641
+ indexedAccessDepthChange: 'decr',
642
+ }), options);
643
+ }
644
+ const questionTokenText = pipe(node.getQuestionToken()?.getText()).mapNullable((t) => t === '?' ? '?' : t === '-' ? '-?' : t === '+' ? '+?' : undefined).value ?? '';
645
+
646
+
647
+ const nameTypeText = pipe(node.getNameTypeNode()?.getFullText()).mapNullable((t) => ` as ${t.trim()}`).value;
648
+ const result = pipe(
649
+
650
+ `{ [${node.getTypeParameter().getFullText()}${nameTypeText ?? ''}]${questionTokenText}: ${node.getTypeNode()?.getFullText()} }`).map((mpt) => match(readonlyContext.type, {
651
+
652
+ DeepReadonly: mpt,
653
+ Readonly: mpt,
654
+ none: readonlyContext.indexedAccessDepth > 0 ? mpt : `Readonly<${mpt}>`,
655
+ })).value;
656
+ options.replaceNode(node, result);
603
657
  };
604
- const transformClassDeclarationNode = (node, options) => {
605
- for (const n of node.getTypeParameters()) {
606
- transformNode(n, initialReadonlyContext, options);
607
- }
608
- for (const n of node.getHeritageClauses()) {
609
- transformNode(n, initialReadonlyContext, options);
610
- }
611
- for (const mb of node.getMembers()) {
612
- if (hasDisableNextLineComment(mb)) {
613
- options.debugPrint("skipped member by disable-next-line comment");
614
- continue;
615
- }
616
- if (mb.isKind(tsm.SyntaxKind.PropertyDeclaration)) {
617
- if (!checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options)) {
618
- mb.setIsReadonly(true);
619
- const type = mb.getTypeNode();
620
- if (type !== void 0) {
621
- transformNode(type, initialReadonlyContext, options);
622
- }
623
- const initializer = mb.getInitializer();
624
- if (initializer !== void 0) {
625
- transformNode(initializer, initialReadonlyContext, options);
626
- }
627
- }
628
- continue;
629
- }
630
- if ((mb.isKind(tsm.SyntaxKind.MethodDeclaration) || mb.isKind(tsm.SyntaxKind.GetAccessor) || mb.isKind(tsm.SyntaxKind.SetAccessor)) && checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options)) {
631
- options.debugPrint("skipped method by ignored prefix");
632
- continue;
633
- }
634
- transformNode(mb, initialReadonlyContext, options);
635
- }
636
- for (const mb of node.getChildrenOfKind(tsm.SyntaxKind.IndexSignature)) {
637
- transformIndexSignatureDeclaration(
638
- mb,
639
- "add",
640
- initialReadonlyContext,
641
- options
642
- );
643
- }
644
- for (const ctor of node.getConstructors()) {
645
- for (const param of ctor.getParameters()) {
646
- transformConstructorParameter(param, options);
647
- }
648
- const body = ctor.getBody();
649
- if (body !== void 0) {
650
- transformNode(body, initialReadonlyContext, options);
651
- }
652
- }
658
+
659
+ const transformInterfaceDeclarationNode = (
660
+
661
+ node, options) => {
662
+ for (const param of node.getTypeParameters()) {
663
+ transformNode(param, initialReadonlyContext, options);
664
+ }
665
+ for (const n of node.getHeritageClauses()) {
666
+ transformNode(n, initialReadonlyContext, options);
667
+ }
668
+ transformMembers(node.getMembers(), 'add', initialReadonlyContext, options);
653
669
  };
654
- const transformConstructorParameter = (param, options) => {
655
- if (hasDisableNextLineComment(param)) {
656
- options.debugPrint(
657
- "skipped class constructor parameter by disable-next-line comment"
658
- );
659
- return;
660
- }
661
- const name = param.getName();
662
- if (options.ignoredPrefixes.some((p) => name.startsWith(p))) {
663
- return;
664
- }
665
- const scope = param.getScope();
666
- if (scope === tsm.Scope.Public || scope === tsm.Scope.Protected || scope === tsm.Scope.Private) {
667
- param.setIsReadonly(true);
668
- }
669
- const type = param.getTypeNode();
670
- if (type !== void 0) {
671
- transformNode(type, initialReadonlyContext, options);
672
- }
670
+ const transformClassDeclarationNode = (
671
+
672
+ node, options) => {
673
+ for (const n of node.getTypeParameters()) {
674
+ transformNode(n, initialReadonlyContext, options);
675
+ }
676
+ for (const n of node.getHeritageClauses()) {
677
+ transformNode(n, initialReadonlyContext, options);
678
+ }
679
+ for (const mb of node.getMembers()) {
680
+ if (hasDisableNextLineComment(mb)) {
681
+ options.debugPrint('skipped member by disable-next-line comment');
682
+ continue;
683
+ }
684
+ if (mb.isKind(tsm.SyntaxKind.PropertyDeclaration)) {
685
+ if (!checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options)) {
686
+ mb.setIsReadonly(true);
687
+ const type = mb.getTypeNode();
688
+ if (type !== undefined) {
689
+ transformNode(type, initialReadonlyContext, options);
690
+ }
691
+ const initializer = mb.getInitializer();
692
+ if (initializer !== undefined) {
693
+ transformNode(initializer, initialReadonlyContext, options);
694
+ }
695
+ }
696
+ continue;
697
+ }
698
+
699
+
700
+ if ((mb.isKind(tsm.SyntaxKind.MethodDeclaration) ||
701
+ mb.isKind(tsm.SyntaxKind.GetAccessor) ||
702
+ mb.isKind(tsm.SyntaxKind.SetAccessor)) &&
703
+ checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options)) {
704
+ options.debugPrint('skipped method by ignored prefix');
705
+ continue;
706
+ }
707
+ transformNode(mb, initialReadonlyContext, options);
708
+ }
709
+ for (const mb of node.getChildrenOfKind(tsm.SyntaxKind.IndexSignature)) {
710
+ transformIndexSignatureDeclaration(mb, 'add', initialReadonlyContext, options);
711
+ }
712
+ for (const ctor of node.getConstructors()) {
713
+ for (const param of ctor.getParameters()) {
714
+ transformConstructorParameter(param, options);
715
+ }
716
+ const body = ctor.getBody();
717
+ if (body !== undefined) {
718
+ transformNode(body, initialReadonlyContext, options);
719
+ }
720
+ }
673
721
  };
674
- const transformIntersectionTypeNode = (node, readonlyContext, options) => {
675
- transformUnionOrIntersectionTypeNodeImpl(node, readonlyContext, options, "&");
722
+ const transformConstructorParameter = (
723
+
724
+ param, options) => {
725
+ if (hasDisableNextLineComment(param)) {
726
+ options.debugPrint('skipped class constructor parameter by disable-next-line comment');
727
+ return;
728
+ }
729
+ const name = param.getName();
730
+ if (options.ignoredPrefixes.some((p) => name.startsWith(p))) {
731
+ return;
732
+ }
733
+
734
+ const scope = param.getScope();
735
+
736
+
737
+
738
+ if (scope === tsm.Scope.Public ||
739
+ scope === tsm.Scope.Protected ||
740
+ scope === tsm.Scope.Private) {
741
+ param.setIsReadonly(true);
742
+ }
743
+ const type = param.getTypeNode();
744
+ if (type !== undefined) {
745
+ transformNode(type, initialReadonlyContext, options);
746
+ }
676
747
  };
677
- const transformUnionTypeNode = (node, readonlyContext, options) => {
678
- transformUnionOrIntersectionTypeNodeImpl(node, readonlyContext, options, "|");
748
+
749
+
750
+
751
+
752
+ const transformIntersectionTypeNode = (
753
+
754
+ node, readonlyContext, options) => {
755
+ transformUnionOrIntersectionTypeNodeImpl(node, readonlyContext, options, '&');
679
756
  };
680
- const transformUnionOrIntersectionTypeNodeImpl = (node, readonlyContext, options, operator) => {
681
- const nextReadonlyContextValue = nextReadonlyContext({
682
- currentReadonlyContext: readonlyContext,
683
- nextReadonlyContextType: "none",
684
- indexedAccessDepthChange: "keep"
685
- });
686
- for (const n of node.getTypeNodes()) {
687
- transformNode(n, nextReadonlyContextValue, options);
688
- }
689
- const newTypes = node.getTypeNodes();
690
- const { primitives, arraysAndTuples, typeLiterals, others } = groupUnionIntersectionTypes(newTypes);
691
- options.debugPrint({ primitives, arraysAndTuples, typeLiterals, others });
692
- const isEmptyTypeLiteral = (n) => n.isKind(tsm.SyntaxKind.TypeLiteral) && Arr.isEmpty(n.getMembers());
693
- const nonEmptyTypeLiterals = typeLiterals === void 0 ? void 0 : options.ignoreEmptyObjectTypes ? typeLiterals.nodes.filter((n) => !isEmptyTypeLiteral(n)) : typeLiterals.nodes;
694
- const emptyTypeLiterals = typeLiterals === void 0 || !options.ignoreEmptyObjectTypes ? void 0 : typeLiterals.nodes.filter(isEmptyTypeLiteral);
695
- const typeLiteralsWrappedWithReadonly = nonEmptyTypeLiterals === void 0 || Arr.isEmpty(nonEmptyTypeLiterals) ? [] : [
696
- unionToString({
697
- types: nonEmptyTypeLiterals.map(
698
- (n) => isReadonlyTypeReferenceNode(n) ? (
699
- // NOTE: Readonly<A & B> -> (A & B)
700
- unwrapReadonlyTypeArgText(n)
701
- ) : n.getFullText()
702
- ),
703
- op: operator,
704
- wrapWithReadonly: nextReadonlyContextValue.type !== "DeepReadonly" && nextReadonlyContextValue.indexedAccessDepth === 0
705
- })
706
- ];
707
- const sorted = [
708
- mapNullable(
709
- primitives,
710
- (a) => [a.nodes.map((n) => n.getFullText()), a.firstPosition]
711
- ),
712
- mapNullable(
713
- arraysAndTuples,
714
- (a) => [a.nodes.map((n) => n.getFullText()), a.firstPosition]
715
- ),
716
- nonEmptyTypeLiterals !== void 0 && Arr.isNonEmpty(nonEmptyTypeLiterals) ? mapNullable(
717
- typeLiterals,
718
- (a) => [typeLiteralsWrappedWithReadonly, a.firstPosition]
719
- ) : void 0,
720
- emptyTypeLiterals !== void 0 && Arr.isNonEmpty(emptyTypeLiterals) ? mapNullable(
721
- typeLiterals,
722
- (a) => [
723
- emptyTypeLiterals.map((n) => n.getFullText()),
724
- // Use a position after non-empty type literals if they exist
725
- a.firstPosition + (nonEmptyTypeLiterals !== void 0 && Arr.isNonEmpty(nonEmptyTypeLiterals) ? 0.5 : 0)
726
- ]
727
- ) : void 0,
728
- mapNullable(
729
- others,
730
- (a) => [
731
- a.nodes.map((n) => wrapWithParentheses(n.getFullText())),
732
- a.firstPosition
733
- ]
734
- )
735
- ].filter((x) => x !== void 0).toSorted((a, b) => a[1] - b[1]).flatMap((a) => a[0]);
736
- options.replaceNode(
737
- node,
738
- unionToString({ types: sorted, op: operator, wrapWithReadonly: false })
739
- );
757
+
758
+
759
+
760
+
761
+ const transformUnionTypeNode = (
762
+
763
+ node, readonlyContext, options) => {
764
+ transformUnionOrIntersectionTypeNodeImpl(node, readonlyContext, options, '|');
740
765
  };
741
- const unionToString = ({
742
- types: typesRaw,
743
- op,
744
- wrapWithReadonly
745
- }) => {
746
- const types = typesRaw.map((s) => s.trim());
747
- return unionToStringImpl({ types, op, wrapWithReadonly });
766
+ const transformUnionOrIntersectionTypeNodeImpl = (
767
+
768
+ node, readonlyContext, options, operator) => {
769
+ const nextReadonlyContextValue = nextReadonlyContext({
770
+ currentReadonlyContext: readonlyContext,
771
+ nextReadonlyContextType: 'none',
772
+ indexedAccessDepthChange: 'keep',
773
+ });
774
+
775
+ for (const n of node.getTypeNodes() ) {
776
+ transformNode(n, nextReadonlyContextValue, options);
777
+ }
778
+ const newTypes = node.getTypeNodes();
779
+ const { primitives, arraysAndTuples, typeLiterals, others } = groupUnionIntersectionTypes(newTypes);
780
+ options.debugPrint({ primitives, arraysAndTuples, typeLiterals, others });
781
+
782
+ const isEmptyTypeLiteral = (
783
+
784
+ n) => n.isKind(tsm.SyntaxKind.TypeLiteral) && Arr.isEmpty(n.getMembers());
785
+ const nonEmptyTypeLiterals = typeLiterals === undefined
786
+ ? undefined
787
+ : options.ignoreEmptyObjectTypes
788
+ ? typeLiterals.nodes.filter((n) => !isEmptyTypeLiteral(n))
789
+ : typeLiterals.nodes;
790
+ const emptyTypeLiterals = typeLiterals === undefined || !options.ignoreEmptyObjectTypes
791
+ ? undefined
792
+ : typeLiterals.nodes.filter(isEmptyTypeLiteral);
793
+ const typeLiteralsWrappedWithReadonly = nonEmptyTypeLiterals === undefined || Arr.isEmpty(nonEmptyTypeLiterals)
794
+ ? []
795
+ : [
796
+ unionToString({
797
+ types: nonEmptyTypeLiterals.map((n) => isReadonlyTypeReferenceNode(n)
798
+ ?
799
+ unwrapReadonlyTypeArgText(n)
800
+ : n.getFullText()),
801
+ op: operator,
802
+ wrapWithReadonly: nextReadonlyContextValue.type !== 'DeepReadonly' &&
803
+ nextReadonlyContextValue.indexedAccessDepth === 0,
804
+ }),
805
+ ];
806
+
807
+ const sorted = [
808
+ mapNullable(primitives, (a) => [a.nodes.map((n) => n.getFullText()), a.firstPosition]),
809
+ mapNullable(arraysAndTuples, (a) => [a.nodes.map((n) => n.getFullText()), a.firstPosition]),
810
+ nonEmptyTypeLiterals !== undefined && Arr.isNonEmpty(nonEmptyTypeLiterals)
811
+ ? mapNullable(typeLiterals, (a) => [typeLiteralsWrappedWithReadonly, a.firstPosition])
812
+ : undefined,
813
+ emptyTypeLiterals !== undefined && Arr.isNonEmpty(emptyTypeLiterals)
814
+ ? mapNullable(typeLiterals, (a) => [
815
+ emptyTypeLiterals.map((n) => n.getFullText()),
816
+
817
+ a.firstPosition +
818
+ (nonEmptyTypeLiterals !== undefined &&
819
+ Arr.isNonEmpty(nonEmptyTypeLiterals)
820
+ ? 0.5
821
+ : 0),
822
+ ])
823
+ : undefined,
824
+ mapNullable(others, (a) => [
825
+ a.nodes.map((n) => wrapWithParentheses(n.getFullText())),
826
+ a.firstPosition,
827
+ ]),
828
+ ]
829
+ .filter((x) => x !== undefined)
830
+ .toSorted((a, b) => a[1] - b[1])
831
+ .flatMap((a) => a[0]);
832
+
833
+
834
+
835
+
836
+
837
+
838
+
839
+
840
+
841
+
842
+
843
+
844
+
845
+
846
+
847
+
848
+
849
+ options.replaceNode(node, unionToString({ types: sorted, op: operator, wrapWithReadonly: false }));
748
850
  };
749
- const unionToStringImpl = ({
750
- types,
751
- op,
752
- wrapWithReadonly
753
- }) => Arr.isEmpty(types) ? "never" : Arr.isFixedLengthArray(1, types) ? wrapWithReadonly === false ? wrapWithParentheses(types[0]) : `${isString(wrapWithReadonly) ? wrapWithReadonly : "Readonly"}<${types[0]}>` : wrapWithReadonly === false ? wrapWithParentheses(types.join(` ${op} `)) : `${isString(wrapWithReadonly) ? wrapWithReadonly : "Readonly"}<${types.join(` ${op} `)}>`;
754
- const transformParenthesizedTypeNode = (node, readonlyContext, options) => {
755
- const typeNode = node.getTypeNode();
756
- if (typeNode.isKind(tsm.SyntaxKind.ParenthesizedType)) {
757
- transformParenthesizedTypeNode(typeNode, readonlyContext, options);
758
- }
759
- transformNode(node.getTypeNode(), readonlyContext, options);
760
- const T = node.getTypeNode();
761
- if (
762
- // remove () if T is TypeReferenceNode
763
- // e.g. `(Readonly<A>) |-> Readonly<A>`
764
- T.isKind(tsm.SyntaxKind.TypeReference) || // remove () if T is ArrayTypeNode
765
- // e.g. `(A[]) |-> A[]`
766
- T.isKind(tsm.SyntaxKind.ArrayType) || // remove () if T is TupleTypeNode
767
- // e.g. `([A]) |-> [A]`
768
- T.isKind(tsm.SyntaxKind.TupleType) || // remove () if T is PrimitiveTypeNode
769
- // e.g. `(number) |-> number`
770
- isAtomicTypeNode(T) || // remove () if T is TypeLiteralNode
771
- // e.g. `({ member: V }) |-> { member: V }`
772
- T.isKind(tsm.SyntaxKind.TypeLiteral) || // collapse redundant nested parentheses if T is itself a ParenthesizedType
773
- // e.g. `((X)) |-> (X)`
774
- //
775
- // This is what makes the transform terminate on nested parentheses. The
776
- // union/intersection handler defensively wraps its result in parentheses
777
- // for precedence safety, which turns `(A | B)` into `((A | B))` when the
778
- // union already sits inside a `ParenthesizedType`. Collapsing the redundant
779
- // outer layer here means each pass removes exactly the layer the wrapping
780
- // added, so the parentheses no longer grow without bound (which previously
781
- // overflowed the parser stack on inputs like `type T = (('a' | 'b'))`).
782
- T.isKind(tsm.SyntaxKind.ParenthesizedType)
783
- ) {
784
- options.replaceNode(node, T.getFullText());
785
- }
851
+ const unionToString = ({ types: typesRaw, op, wrapWithReadonly, }) => {
852
+
853
+
854
+
855
+
856
+
857
+
858
+ const types = typesRaw.map((s) => s.trim());
859
+ return unionToStringImpl({ types, op, wrapWithReadonly });
786
860
  };
787
- const transformMembers = (members, readonlyModifier, readonlyContext, options) => {
788
- for (const mb of members) {
789
- if (hasDisableNextLineComment(mb)) {
790
- options.debugPrint("skipped by member disable-next-line comment");
791
- continue;
792
- }
793
- if (mb.isKind(tsm.SyntaxKind.PropertySignature)) {
794
- if (!checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options)) {
795
- transformPropertySignature(
796
- mb,
797
- readonlyModifier,
798
- readonlyContext,
799
- options
800
- );
801
- }
802
- continue;
803
- }
804
- if (mb.isKind(tsm.SyntaxKind.IndexSignature)) {
805
- transformIndexSignatureDeclaration(
806
- mb,
807
- readonlyModifier,
808
- readonlyContext,
809
- options
810
- );
811
- continue;
812
- }
813
- transformNode(mb, readonlyContext, options);
814
- }
861
+ const unionToStringImpl = ({ types, op, wrapWithReadonly, }) => Arr.isEmpty(types)
862
+ ? 'never'
863
+ : Arr.isFixedLengthArray(1, types)
864
+ ? wrapWithReadonly === false
865
+ ? wrapWithParentheses(types[0])
866
+ : `${isString(wrapWithReadonly) ? wrapWithReadonly : 'Readonly'}<${types[0]}>`
867
+ : wrapWithReadonly === false
868
+ ? wrapWithParentheses(types.join(` ${op} `))
869
+ : `${isString(wrapWithReadonly) ? wrapWithReadonly : 'Readonly'}<${types.join(` ${op} `)}>`;
870
+
871
+ const transformParenthesizedTypeNode = (
872
+
873
+ node, readonlyContext, options) => {
874
+ const typeNode = node.getTypeNode();
875
+ if (typeNode.isKind(tsm.SyntaxKind.ParenthesizedType)) {
876
+
877
+ transformParenthesizedTypeNode(typeNode, readonlyContext, options);
878
+ }
879
+ transformNode(node.getTypeNode(), readonlyContext, options);
880
+ const T = node.getTypeNode();
881
+ if (
882
+
883
+
884
+ T.isKind(tsm.SyntaxKind.TypeReference) ||
885
+
886
+
887
+ T.isKind(tsm.SyntaxKind.ArrayType) ||
888
+
889
+
890
+ T.isKind(tsm.SyntaxKind.TupleType) ||
891
+
892
+
893
+ isAtomicTypeNode(T) ||
894
+
895
+
896
+ T.isKind(tsm.SyntaxKind.TypeLiteral) ||
897
+
898
+
899
+
900
+
901
+
902
+
903
+
904
+
905
+
906
+
907
+ T.isKind(tsm.SyntaxKind.ParenthesizedType)) {
908
+ options.replaceNode(node, T.getFullText());
909
+ }
815
910
  };
816
- const transformPropertySignature = (node, readonlyModifier, readonlyContext, options) => {
817
- if (readonlyModifier === "remove" || readonlyContext.type === "DeepReadonly") {
818
- node.setIsReadonly(false);
819
- } else {
820
- node.setIsReadonly(true);
821
- }
822
- {
823
- const type = node.getTypeNode();
824
- if (type !== void 0) {
825
- transformNode(type, readonlyContext, options);
826
- }
827
- }
911
+
912
+
913
+
914
+
915
+
916
+ const transformMembers = (
917
+
918
+ members, readonlyModifier, readonlyContext, options) => {
919
+ for (const mb of members) {
920
+ if (hasDisableNextLineComment(mb)) {
921
+ options.debugPrint('skipped by member disable-next-line comment');
922
+ continue;
923
+ }
924
+ if (mb.isKind(tsm.SyntaxKind.PropertySignature)) {
925
+ if (!checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options)) {
926
+ transformPropertySignature(mb, readonlyModifier, readonlyContext, options);
927
+ }
928
+ continue;
929
+ }
930
+ if (mb.isKind(tsm.SyntaxKind.IndexSignature)) {
931
+ transformIndexSignatureDeclaration(mb, readonlyModifier, readonlyContext, options);
932
+ continue;
933
+ }
934
+ transformNode(mb, readonlyContext, options);
935
+ }
828
936
  };
829
- const transformIndexSignatureDeclaration = (node, readonlyModifier, readonlyContext, options) => {
830
- if (hasDisableNextLineComment(node, TRANSFORMER_NAME)) {
831
- options.debugPrint("skipped index signature by disable-next-line comment");
832
- return;
833
- }
834
- if (readonlyModifier === "remove" || readonlyContext.type === "DeepReadonly") {
835
- node.toggleModifier("readonly", false);
836
- } else {
837
- node.toggleModifier("readonly", true);
838
- }
839
- {
840
- const key = node.getKeyTypeNode();
841
- transformNode(key, readonlyContext, options);
842
- }
843
- {
844
- const ret = node.getReturnTypeNode();
845
- if (ret !== void 0) {
846
- transformNode(ret, readonlyContext, options);
847
- }
848
- }
937
+ const transformPropertySignature = (
938
+
939
+ node, readonlyModifier, readonlyContext, options) => {
940
+ if (readonlyModifier === 'remove' ||
941
+ readonlyContext.type === 'DeepReadonly') {
942
+ node.setIsReadonly(false);
943
+ }
944
+ else {
945
+ node.setIsReadonly(true);
946
+ }
947
+ {
948
+ const type = node.getTypeNode();
949
+ if (type !== undefined) {
950
+ transformNode(type, readonlyContext, options);
951
+ }
952
+ }
849
953
  };
850
- const checkIfPropertyNameShouldBeIgnored = (nameNode, options) => {
851
- return (
852
- // mut_x: number[]
853
- nameNode.isKind(tsm.SyntaxKind.Identifier) && pipe(nameNode.getText()).map(
854
- (nm) => options.ignoredPrefixes.some((p) => nm.startsWith(p))
855
- ).value || // "mut_x": number[]
856
- nameNode.isKind(tsm.SyntaxKind.StringLiteral) && pipe(nameNode.getLiteralValue()).map(
857
- (nm) => options.ignoredPrefixes.some((p) => nm.startsWith(p))
858
- ).value || // #memberName: number[] (class only)
859
- nameNode.isKind(tsm.SyntaxKind.PrivateIdentifier) && pipe(nameNode.getText()).map(
860
- (nm) => options.ignoredPrefixes.some((p) => nm.startsWith(`#${p}`))
861
- ).value || // [`mut_x`]: number[]
862
- nameNode.isKind(tsm.SyntaxKind.ComputedPropertyName) && pipe(nameNode.getExpression()).map((exp) => {
863
- if (exp.isKind(tsm.SyntaxKind.StringLiteral)) {
864
- const nm = exp.getLiteralValue();
865
- return options.ignoredPrefixes.some((p) => nm.startsWith(p));
866
- }
867
- return false;
868
- }).value
869
- );
954
+ const transformIndexSignatureDeclaration = (
955
+
956
+ node, readonlyModifier, readonlyContext, options) => {
957
+ if (hasDisableNextLineComment(node, TRANSFORMER_NAME)) {
958
+ options.debugPrint('skipped index signature by disable-next-line comment');
959
+ return;
960
+ }
961
+ if (readonlyModifier === 'remove' ||
962
+ readonlyContext.type === 'DeepReadonly') {
963
+
964
+ node.toggleModifier('readonly', false);
965
+ }
966
+ else {
967
+ node.toggleModifier('readonly', true);
968
+
969
+ }
970
+ {
971
+ const key = node.getKeyTypeNode();
972
+ transformNode(key, readonlyContext, options);
973
+ }
974
+ {
975
+ const ret = node.getReturnTypeNode();
976
+ if (ret !== undefined) {
977
+ transformNode(ret, readonlyContext, options);
978
+ }
979
+ }
870
980
  };
981
+ const checkIfPropertyNameShouldBeIgnored = (
982
+
983
+ nameNode, options) => {
871
984
 
872
- export { convertToReadonlyTransformer };
873
- //# sourceMappingURL=convert-to-readonly.mjs.map
985
+
986
+ return (
987
+
988
+ (nameNode.isKind(tsm.SyntaxKind.Identifier) &&
989
+ pipe(nameNode.getText()).map((nm) => options.ignoredPrefixes.some((p) => nm.startsWith(p))).value) ||
990
+
991
+ (nameNode.isKind(tsm.SyntaxKind.StringLiteral) &&
992
+ pipe(nameNode.getLiteralValue()).map((nm) => options.ignoredPrefixes.some((p) => nm.startsWith(p))).value) ||
993
+
994
+ (nameNode.isKind(tsm.SyntaxKind.PrivateIdentifier) &&
995
+ pipe(nameNode.getText()).map((nm) => options.ignoredPrefixes.some((p) => nm.startsWith(`#${p}`))).value) ||
996
+
997
+ (nameNode.isKind(tsm.SyntaxKind.ComputedPropertyName) &&
998
+ pipe(nameNode.getExpression()).map((exp) => {
999
+ if (exp.isKind(tsm.SyntaxKind.StringLiteral)) {
1000
+ const nm = exp.getLiteralValue();
1001
+ return options.ignoredPrefixes.some((p) => nm.startsWith(p));
1002
+ }
1003
+ return false;
1004
+ }).value));
1005
+ };
1006
+ //# sourceMappingURL=convert-to-readonly.mjs.map