ts-codemod-lib 3.5.1 → 4.0.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 +7 -3
- package/dist/functions/ast-transformers/append-as-const.d.mts +20 -12
- package/dist/functions/ast-transformers/append-as-const.d.mts.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.mjs +170 -88
- package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts +25 -6
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.mjs +272 -255
- package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
- package/dist/functions/ast-transformers/enable-no-unchecked-indexed-access.d.mts +8 -8
- package/dist/functions/ast-transformers/enable-no-unchecked-indexed-access.mjs +103 -104
- package/dist/functions/ast-transformers/enable-no-unchecked-indexed-access.mjs.map +1 -1
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.d.mts +2 -2
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs +51 -51
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs.map +1 -1
- package/dist/functions/ast-transformers/transform-source-code.d.mts.map +1 -1
- package/dist/functions/ast-transformers/transform-source-code.mjs +69 -69
- package/dist/functions/ast-transformers/transform-source-code.mjs.map +1 -1
- package/dist/functions/constants/index.d.mts +1 -0
- package/dist/functions/constants/index.d.mts.map +1 -1
- package/dist/functions/constants/index.mjs +1 -0
- package/dist/functions/constants/index.mjs.map +1 -1
- package/dist/functions/constants/mutable-prefixes.d.mts +23 -0
- package/dist/functions/constants/mutable-prefixes.d.mts.map +1 -0
- package/dist/functions/constants/mutable-prefixes.mjs +28 -0
- package/dist/functions/constants/mutable-prefixes.mjs.map +1 -0
- package/dist/functions/functions/has-disable-next-line-comment.mjs +23 -23
- package/dist/functions/functions/has-disable-next-line-comment.mjs.map +1 -1
- package/dist/functions/functions/is-readonly-node.d.mts +2 -2
- package/dist/functions/functions/is-readonly-node.d.mts.map +1 -1
- package/dist/functions/functions/is-readonly-node.mjs +13 -13
- package/dist/functions/functions/is-readonly-node.mjs.map +1 -1
- package/dist/functions/functions/wrap-with-parentheses.d.mts +2 -2
- package/dist/functions/functions/wrap-with-parentheses.d.mts.map +1 -1
- package/dist/functions/functions/wrap-with-parentheses.mjs +87 -32
- package/dist/functions/functions/wrap-with-parentheses.mjs.map +1 -1
- package/dist/functions/utils/replace-node-with-text.d.mts +10 -11
- package/dist/functions/utils/replace-node-with-text.d.mts.map +1 -1
- package/dist/functions/utils/replace-node-with-text.mjs +0 -1
- package/dist/functions/utils/replace-node-with-text.mjs.map +1 -1
- package/package.json +6 -6
- package/src/functions/ast-transformers/append-as-const.mts +319 -174
- package/src/functions/ast-transformers/append-as-const.test.mts +118 -7
- package/src/functions/ast-transformers/convert-to-readonly.mts +568 -489
- package/src/functions/ast-transformers/convert-to-readonly.test.mts +381 -74
- package/src/functions/ast-transformers/enable-no-unchecked-indexed-access.mts +178 -179
- package/src/functions/ast-transformers/enable-no-unchecked-indexed-access.test.mts +29 -29
- package/src/functions/ast-transformers/replace-any-with-unknown.test.mts +6 -6
- package/src/functions/ast-transformers/replace-record-with-unknown-record.mts +75 -75
- package/src/functions/ast-transformers/replace-record-with-unknown-record.test.mts +6 -6
- package/src/functions/ast-transformers/transform-source-code.mts +110 -110
- package/src/functions/ast-transformers/transformer-specific-ignore.test.mts +6 -6
- package/src/functions/constants/index.mts +1 -0
- package/src/functions/constants/mutable-prefixes.mts +28 -0
- package/src/functions/functions/has-disable-next-line-comment.mts +35 -35
- package/src/functions/functions/is-readonly-node.mts +25 -25
- package/src/functions/functions/wrap-with-parentheses.mts +138 -52
- package/src/functions/functions/wrap-with-parentheses.test.mts +115 -0
- package/src/functions/utils/replace-node-with-text.mts +10 -11
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Arr, ISet, isString, mapNullable, match, pipe, } from 'ts-data-forge';
|
|
1
|
+
import { Arr, ISet, isRecord, isString, mapNullable, match, pipe, } from 'ts-data-forge';
|
|
2
2
|
import * as tsm from 'ts-morph';
|
|
3
|
+
import { DEFAULT_MUTABLE_PREFIXES, DEFAULT_MUTABLE_TYPE_PREFIXES, } from '../constants/index.mjs';
|
|
3
4
|
import { hasCallOrConstructSignature, hasDisableNextLineComment, isAtomicTypeNode, isConditionalTypeDistributionGuard, isReadonlyArrayTypeNode, isReadonlyTupleOrArrayTypeNode, isReadonlyTupleTypeNode, isReadonlyTypeReferenceNode, removeParentheses, shouldAvoidParenthesesForReadonly, unwrapReadonlyTypeArgText, wrapWithParentheses, } from '../functions/index.mjs';
|
|
4
5
|
import { replaceNodeWithDebugPrint, replaceNodeWithText, } from '../utils/index.mjs';
|
|
5
6
|
import { groupUnionIntersectionTypes, invalidDeepReadonlyTypeName, isMergeableReadonlyTypeReferenceNode, nextReadonlyContext, } from './readonly-transformer-helpers/index.mjs';
|
|
@@ -11,17 +12,20 @@ export const convertToReadonlyTransformer = (options) => {
|
|
|
11
12
|
}
|
|
12
13
|
const DeepReadonlyTypeName = options?.DeepReadonly?.typeName ?? 'DeepReadonly';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const untypedOptions = options;
|
|
16
|
+
if (isRecord(untypedOptions) &&
|
|
17
|
+
untypedOptions['ignorePrefixes'] !== undefined) {
|
|
18
|
+
throw new Error(`The "ignorePrefixes" option of ${TRANSFORMER_NAME} was replaced by "mutableVariablePrefixes", "mutableTypePrefixes" and "mutablePropertyPrefixes".`);
|
|
19
|
+
}
|
|
18
20
|
const optionsInternal = {
|
|
19
21
|
DeepReadonly: {
|
|
20
22
|
typeName: DeepReadonlyTypeName,
|
|
21
23
|
applyLevel: 'keep',
|
|
22
24
|
},
|
|
23
25
|
ignoreEmptyObjectTypes: options?.ignoreEmptyObjectTypes ?? true,
|
|
24
|
-
|
|
26
|
+
mutableVariablePrefixes: ISet.create(options?.mutableVariablePrefixes ?? DEFAULT_MUTABLE_PREFIXES),
|
|
27
|
+
mutableTypePrefixes: ISet.create(options?.mutableTypePrefixes ?? DEFAULT_MUTABLE_TYPE_PREFIXES),
|
|
28
|
+
mutablePropertyPrefixes: ISet.create(options?.mutablePropertyPrefixes ?? DEFAULT_MUTABLE_PREFIXES),
|
|
25
29
|
recordStyle: options?.recordStyle ?? 'ReadonlyRecord',
|
|
26
30
|
debugPrint: options?.debug === true ? console.debug : () => { },
|
|
27
31
|
replaceNode: options?.debug === true
|
|
@@ -41,6 +45,18 @@ const initialReadonlyContext = {
|
|
|
41
45
|
type: 'none',
|
|
42
46
|
indexedAccessDepth: 0,
|
|
43
47
|
};
|
|
48
|
+
|
|
49
|
+
const hasMutableTypeName = (name, options) => name !== undefined &&
|
|
50
|
+
options.mutableTypePrefixes.some((p) => name.startsWith(p));
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
const mutablePrefixesOfParameter = (
|
|
56
|
+
|
|
57
|
+
param, options) => param.isParameterProperty()
|
|
58
|
+
? options.mutablePropertyPrefixes
|
|
59
|
+
: options.mutableVariablePrefixes;
|
|
44
60
|
const transformNode = (node, readonlyContext, options) => {
|
|
45
61
|
if (tsm.Node.isTypeNode(node) ||
|
|
46
62
|
node.isKind(tsm.SyntaxKind.InterfaceDeclaration) ||
|
|
@@ -58,10 +74,10 @@ const transformNode = (node, readonlyContext, options) => {
|
|
|
58
74
|
|
|
59
75
|
if (node.isKind(tsm.SyntaxKind.VariableDeclaration)) {
|
|
60
76
|
const nodeName = node.getName();
|
|
61
|
-
if (options.
|
|
77
|
+
if (options.mutableVariablePrefixes.some((p) => nodeName.startsWith(p))) {
|
|
62
78
|
|
|
63
79
|
|
|
64
|
-
options.debugPrint('skipped variable declaration by
|
|
80
|
+
options.debugPrint('skipped variable declaration by mutableVariablePrefixes');
|
|
65
81
|
return;
|
|
66
82
|
}
|
|
67
83
|
|
|
@@ -77,12 +93,12 @@ const transformNode = (node, readonlyContext, options) => {
|
|
|
77
93
|
|
|
78
94
|
if ((node.isKind(tsm.SyntaxKind.FunctionDeclaration) ||
|
|
79
95
|
node.isKind(tsm.SyntaxKind.FunctionExpression)) &&
|
|
80
|
-
options.
|
|
96
|
+
options.mutableVariablePrefixes.some((p) => node.getName()?.startsWith(p) === true)) {
|
|
81
97
|
return;
|
|
82
98
|
}
|
|
83
99
|
if (node.isKind(tsm.SyntaxKind.Parameter)) {
|
|
84
100
|
const nodeName = node.getName();
|
|
85
|
-
if (options.
|
|
101
|
+
if (mutablePrefixesOfParameter(node, options).some((p) => nodeName.startsWith(p))) {
|
|
86
102
|
|
|
87
103
|
|
|
88
104
|
return;
|
|
@@ -97,7 +113,7 @@ const transformNode = (node, readonlyContext, options) => {
|
|
|
97
113
|
|
|
98
114
|
|
|
99
115
|
if (node.isKind(tsm.SyntaxKind.TypeAliasDeclaration) &&
|
|
100
|
-
|
|
116
|
+
hasMutableTypeName(node.getName(), options)) {
|
|
101
117
|
return;
|
|
102
118
|
}
|
|
103
119
|
if (node.isKind(tsm.SyntaxKind.TypeReference)) {
|
|
@@ -147,16 +163,21 @@ const transformNode = (node, readonlyContext, options) => {
|
|
|
147
163
|
if (node.isKind(tsm.SyntaxKind.InterfaceDeclaration)) {
|
|
148
164
|
|
|
149
165
|
|
|
150
|
-
if (
|
|
166
|
+
if (hasMutableTypeName(node.getName(), options)) {
|
|
151
167
|
return;
|
|
152
168
|
}
|
|
153
169
|
transformInterfaceDeclarationNode(node, options);
|
|
154
170
|
return;
|
|
155
171
|
}
|
|
172
|
+
|
|
173
|
+
if (node.isKind(tsm.SyntaxKind.ClassExpression) &&
|
|
174
|
+
hasMutableTypeName(node.getName(), options)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
156
177
|
if (node.isKind(tsm.SyntaxKind.ClassDeclaration)) {
|
|
157
178
|
|
|
158
179
|
|
|
159
|
-
if (
|
|
180
|
+
if (hasMutableTypeName(node.getName(), options)) {
|
|
160
181
|
return;
|
|
161
182
|
}
|
|
162
183
|
transformClassDeclarationNode(node, options);
|
|
@@ -189,6 +210,137 @@ const transformNode = (node, readonlyContext, options) => {
|
|
|
189
210
|
|
|
190
211
|
|
|
191
212
|
|
|
213
|
+
const readonlyRecordText = (keyText, valueText, options) => options.recordStyle === 'ReadonlyRecord'
|
|
214
|
+
? `ReadonlyRecord<${keyText}, ${valueText}>`
|
|
215
|
+
: `Readonly<Record<${keyText}, ${valueText}>>`;
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
const commentsBetween = (
|
|
222
|
+
|
|
223
|
+
sourceFile, from, to) => {
|
|
224
|
+
if (to <= from) {
|
|
225
|
+
return '';
|
|
226
|
+
}
|
|
227
|
+
const scanner = tsm.ts.createScanner(tsm.ts.ScriptTarget.Latest, false, tsm.ts.LanguageVariant.Standard, sourceFile.getFullText(), undefined, from, to - from);
|
|
228
|
+
const mut_comments = [];
|
|
229
|
+
while (scanner.scan() !== tsm.ts.SyntaxKind.EndOfFileToken) {
|
|
230
|
+
const token = scanner.getToken();
|
|
231
|
+
|
|
232
|
+
const separator = token === tsm.ts.SyntaxKind.SingleLineCommentTrivia
|
|
233
|
+
? '\n'
|
|
234
|
+
: token === tsm.ts.SyntaxKind.MultiLineCommentTrivia
|
|
235
|
+
? ' '
|
|
236
|
+
: undefined;
|
|
237
|
+
if (separator !== undefined) {
|
|
238
|
+
mut_comments.push(`${scanner.getTokenText()}${separator}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return mut_comments.join('');
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const getDeepReadonlyTypeArg = (
|
|
245
|
+
|
|
246
|
+
node, deepReadonlyTypeName) => {
|
|
247
|
+
if (!node.isKind(tsm.SyntaxKind.TypeReference)) {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
const typeName = node.getTypeName();
|
|
251
|
+
const typeArguments = node.getTypeArguments();
|
|
252
|
+
return typeName.isKind(tsm.SyntaxKind.Identifier) &&
|
|
253
|
+
typeName.getText() === deepReadonlyTypeName &&
|
|
254
|
+
Arr.isFixedLengthArray(1, typeArguments)
|
|
255
|
+
? typeArguments[0]
|
|
256
|
+
: undefined;
|
|
257
|
+
};
|
|
258
|
+
const checkIfPropertyNameShouldBeIgnored = (
|
|
259
|
+
|
|
260
|
+
nameNode, options) => {
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
|
|
265
|
+
(nameNode.isKind(tsm.SyntaxKind.Identifier) &&
|
|
266
|
+
pipe(nameNode.getText()).map((nm) => options.mutablePropertyPrefixes.some((p) => nm.startsWith(p))).value) ||
|
|
267
|
+
|
|
268
|
+
(nameNode.isKind(tsm.SyntaxKind.StringLiteral) &&
|
|
269
|
+
pipe(nameNode.getLiteralValue()).map((nm) => options.mutablePropertyPrefixes.some((p) => nm.startsWith(p))).value) ||
|
|
270
|
+
|
|
271
|
+
(nameNode.isKind(tsm.SyntaxKind.PrivateIdentifier) &&
|
|
272
|
+
pipe(nameNode.getText()).map((nm) => options.mutablePropertyPrefixes.some((p) => nm.startsWith(p) || nm.startsWith(`#${p}`))).value) ||
|
|
273
|
+
|
|
274
|
+
(nameNode.isKind(tsm.SyntaxKind.ComputedPropertyName) &&
|
|
275
|
+
pipe(nameNode.getExpression()).map((exp) => {
|
|
276
|
+
if (exp.isKind(tsm.SyntaxKind.StringLiteral) ||
|
|
277
|
+
exp.isKind(tsm.SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
|
278
|
+
const nm = exp.getLiteralValue();
|
|
279
|
+
return options.mutablePropertyPrefixes.some((p) => nm.startsWith(p));
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}).value));
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
const isLeftUnwrapped = (
|
|
300
|
+
|
|
301
|
+
node, options) => {
|
|
302
|
+
const members = node.getMembers();
|
|
303
|
+
const isMethodOrAccessor = (
|
|
304
|
+
|
|
305
|
+
mb) => mb.isKind(tsm.SyntaxKind.MethodSignature) ||
|
|
306
|
+
mb.isKind(tsm.SyntaxKind.GetAccessor) ||
|
|
307
|
+
mb.isKind(tsm.SyntaxKind.SetAccessor);
|
|
308
|
+
const isIgnoredMember = (
|
|
309
|
+
|
|
310
|
+
mb) => (mb.isKind(tsm.SyntaxKind.PropertySignature) || isMethodOrAccessor(mb)) &&
|
|
311
|
+
checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options);
|
|
312
|
+
const needsReadonlyWrapper = (
|
|
313
|
+
|
|
314
|
+
mb) => !isIgnoredMember(mb) &&
|
|
315
|
+
(isMethodOrAccessor(mb) ||
|
|
316
|
+
((mb.isKind(tsm.SyntaxKind.PropertySignature) ||
|
|
317
|
+
mb.isKind(tsm.SyntaxKind.IndexSignature)) &&
|
|
318
|
+
!mb.hasModifier(tsm.SyntaxKind.ReadonlyKeyword) &&
|
|
319
|
+
hasDisableNextLineComment(mb)));
|
|
320
|
+
return members.some(isIgnoredMember) && !members.some(needsReadonlyWrapper);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const hasDisableNextLineCommentAround = (node) => {
|
|
324
|
+
if (hasDisableNextLineComment(node, TRANSFORMER_NAME)) {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
const parent = node.getParent();
|
|
328
|
+
return (parent?.isKind(tsm.SyntaxKind.ParenthesizedType) === true &&
|
|
329
|
+
hasDisableNextLineCommentAround(parent));
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
const takesOffReadonly = (
|
|
339
|
+
|
|
340
|
+
node, options) => isLeftUnwrapped(node, options) &&
|
|
341
|
+
!hasCallOrConstructSignature(node) &&
|
|
342
|
+
!hasDisableNextLineCommentAround(node);
|
|
343
|
+
|
|
192
344
|
|
|
193
345
|
|
|
194
346
|
|
|
@@ -511,10 +663,6 @@ node, readonlyContext, options) => {
|
|
|
511
663
|
}
|
|
512
664
|
};
|
|
513
665
|
|
|
514
|
-
const readonlyRecordText = (keyText, valueText, options) => options.recordStyle === 'ReadonlyRecord'
|
|
515
|
-
? `ReadonlyRecord<${keyText}, ${valueText}>`
|
|
516
|
-
: `Readonly<Record<${keyText}, ${valueText}>>`;
|
|
517
|
-
|
|
518
666
|
const transformArrayTypeNode = (
|
|
519
667
|
|
|
520
668
|
node, readonlyContext, options) => {
|
|
@@ -555,7 +703,7 @@ node, readonlyContext, options) => {
|
|
|
555
703
|
});
|
|
556
704
|
for (const el of node.getElements()) {
|
|
557
705
|
if (el.isKind(tsm.SyntaxKind.NamedTupleMember)) {
|
|
558
|
-
if (options.
|
|
706
|
+
if (options.mutablePropertyPrefixes.every((p) => !el.getName().startsWith(p))) {
|
|
559
707
|
transformNode(el.getTypeNode(), nextReadonlyContextValue, options);
|
|
560
708
|
}
|
|
561
709
|
}
|
|
@@ -781,7 +929,7 @@ param, options) => {
|
|
|
781
929
|
return;
|
|
782
930
|
}
|
|
783
931
|
const name = param.getName();
|
|
784
|
-
if (options.
|
|
932
|
+
if (mutablePrefixesOfParameter(param, options).some((p) => name.startsWith(p))) {
|
|
785
933
|
return;
|
|
786
934
|
}
|
|
787
935
|
|
|
@@ -819,104 +967,6 @@ const transformUnionTypeNode = (
|
|
|
819
967
|
node, readonlyContext, options) => {
|
|
820
968
|
transformUnionOrIntersectionTypeNodeImpl(node, readonlyContext, options, '|');
|
|
821
969
|
};
|
|
822
|
-
const transformUnionOrIntersectionTypeNodeImpl = (
|
|
823
|
-
|
|
824
|
-
node, readonlyContext, options, operator) => {
|
|
825
|
-
const nextReadonlyContextValue = nextReadonlyContext({
|
|
826
|
-
currentReadonlyContext: readonlyContext,
|
|
827
|
-
nextReadonlyContextType: 'none',
|
|
828
|
-
indexedAccessDepthChange: 'keep',
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
for (const n of node.getTypeNodes() ) {
|
|
832
|
-
transformNode(n, nextReadonlyContextValue, options);
|
|
833
|
-
}
|
|
834
|
-
const newTypes = node.getTypeNodes();
|
|
835
|
-
const withLeadingComments = (
|
|
836
|
-
|
|
837
|
-
member, memberText) => `${leadingCommentsOfMember(node, member)}${memberText}`;
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
const wrapsTypeLiterals = nextReadonlyContextValue.type !== 'DeepReadonly' &&
|
|
841
|
-
nextReadonlyContextValue.indexedAccessDepth === 0;
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
const underReadonly = readonlyContext.type === 'Readonly' &&
|
|
845
|
-
readonlyContext.indexedAccessDepth === 0 &&
|
|
846
|
-
isTypeArgumentOfReadonly(node);
|
|
847
|
-
const { primitives, arraysAndTuples, typeLiterals, others } = groupUnionIntersectionTypes(newTypes, {
|
|
848
|
-
operator,
|
|
849
|
-
underReadonly,
|
|
850
|
-
deepReadonlyTypeName: options.DeepReadonly.typeName,
|
|
851
|
-
keptUnwrapped: (t) => wrapsTypeLiterals && takesOffReadonly(t, options),
|
|
852
|
-
});
|
|
853
|
-
options.debugPrint({ primitives, arraysAndTuples, typeLiterals, others });
|
|
854
|
-
|
|
855
|
-
const isEmptyTypeLiteral = (
|
|
856
|
-
|
|
857
|
-
n) => n.isKind(tsm.SyntaxKind.TypeLiteral) && Arr.isEmpty(n.getMembers());
|
|
858
|
-
const nonEmptyTypeLiterals = typeLiterals === undefined
|
|
859
|
-
? undefined
|
|
860
|
-
: options.ignoreEmptyObjectTypes
|
|
861
|
-
? typeLiterals.nodes.filter((n) => !isEmptyTypeLiteral(n))
|
|
862
|
-
: typeLiterals.nodes;
|
|
863
|
-
const emptyTypeLiterals = typeLiterals === undefined || !options.ignoreEmptyObjectTypes
|
|
864
|
-
? undefined
|
|
865
|
-
: typeLiterals.nodes.filter(isEmptyTypeLiteral);
|
|
866
|
-
const typeLiteralsWrappedWithReadonly = nonEmptyTypeLiterals === undefined || Arr.isEmpty(nonEmptyTypeLiterals)
|
|
867
|
-
? []
|
|
868
|
-
: [
|
|
869
|
-
unionToString({
|
|
870
|
-
types: nonEmptyTypeLiterals.map((n) => withLeadingComments(n, isMergeableReadonlyTypeReferenceNode(n, operator)
|
|
871
|
-
?
|
|
872
|
-
|
|
873
|
-
readonlyTypeArgTextSplicedInto(n, operator)
|
|
874
|
-
: n.isKind(tsm.SyntaxKind.TypeLiteral)
|
|
875
|
-
? n.getText()
|
|
876
|
-
:
|
|
877
|
-
wrapWithParentheses(n.getText()))),
|
|
878
|
-
op: operator,
|
|
879
|
-
wrapWithReadonly: wrapsTypeLiterals,
|
|
880
|
-
}),
|
|
881
|
-
];
|
|
882
|
-
|
|
883
|
-
const sorted = [
|
|
884
|
-
mapNullable(primitives, (a) => [
|
|
885
|
-
a.nodes.map((n) => withLeadingComments(n, n.getText())),
|
|
886
|
-
a.firstPosition,
|
|
887
|
-
]),
|
|
888
|
-
mapNullable(arraysAndTuples, (a) => [
|
|
889
|
-
a.nodes.map((n) => withLeadingComments(n, n.getText())),
|
|
890
|
-
a.firstPosition,
|
|
891
|
-
]),
|
|
892
|
-
nonEmptyTypeLiterals !== undefined && Arr.isNonEmpty(nonEmptyTypeLiterals)
|
|
893
|
-
? mapNullable(typeLiterals, (a) => [typeLiteralsWrappedWithReadonly, a.firstPosition])
|
|
894
|
-
: undefined,
|
|
895
|
-
emptyTypeLiterals !== undefined && Arr.isNonEmpty(emptyTypeLiterals)
|
|
896
|
-
? mapNullable(typeLiterals, (a) => [
|
|
897
|
-
emptyTypeLiterals.map((n) => withLeadingComments(n, n.getText())),
|
|
898
|
-
|
|
899
|
-
a.firstPosition +
|
|
900
|
-
(nonEmptyTypeLiterals !== undefined &&
|
|
901
|
-
Arr.isNonEmpty(nonEmptyTypeLiterals)
|
|
902
|
-
? 0.5
|
|
903
|
-
: 0),
|
|
904
|
-
])
|
|
905
|
-
: undefined,
|
|
906
|
-
mapNullable(others, (a) => [
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
operator === '|'
|
|
910
|
-
? mergeDeepReadonlyUnionMembers(a.nodes, options.DeepReadonly.typeName, withLeadingComments)
|
|
911
|
-
: a.nodes.map((n) => withLeadingComments(n, wrapWithParentheses(n.getText()))),
|
|
912
|
-
a.firstPosition,
|
|
913
|
-
]),
|
|
914
|
-
]
|
|
915
|
-
.filter((x) => x !== undefined)
|
|
916
|
-
.toSorted((a, b) => a[1] - b[1])
|
|
917
|
-
.flatMap((a) => a[0]);
|
|
918
|
-
|
|
919
|
-
|
|
920
970
|
|
|
921
971
|
|
|
922
972
|
|
|
@@ -925,14 +975,28 @@ node, readonlyContext, options, operator) => {
|
|
|
925
975
|
|
|
926
976
|
|
|
927
977
|
|
|
978
|
+
const textWithoutParentheses = (
|
|
928
979
|
|
|
980
|
+
outer,
|
|
929
981
|
|
|
982
|
+
inner) => `${commentsBetween(outer.getSourceFile(), outer.getPos(), inner.getStart())}${inner.getText()}`;
|
|
983
|
+
const unionToStringImpl = ({ types, op, wrapWithReadonly, }) => Arr.isEmpty(types)
|
|
984
|
+
? 'never'
|
|
985
|
+
: Arr.isFixedLengthArray(1, types)
|
|
986
|
+
? wrapWithReadonly === false
|
|
987
|
+
? wrapWithParentheses(types[0])
|
|
988
|
+
: `${isString(wrapWithReadonly) ? wrapWithReadonly : 'Readonly'}<${types[0]}>`
|
|
989
|
+
: wrapWithReadonly === false
|
|
990
|
+
? wrapWithParentheses(types.join(` ${op} `))
|
|
991
|
+
: `${isString(wrapWithReadonly) ? wrapWithReadonly : 'Readonly'}<${types.join(` ${op} `)}>`;
|
|
992
|
+
const unionToString = ({ types: typesRaw, op, wrapWithReadonly, }) => {
|
|
930
993
|
|
|
931
994
|
|
|
932
995
|
|
|
933
996
|
|
|
934
997
|
|
|
935
|
-
|
|
998
|
+
const types = typesRaw.map((s) => s.trim());
|
|
999
|
+
return unionToStringImpl({ types, op, wrapWithReadonly });
|
|
936
1000
|
};
|
|
937
1001
|
|
|
938
1002
|
|
|
@@ -1052,79 +1116,121 @@ node, operator) => {
|
|
|
1052
1116
|
? textWithoutParentheses(typeArgument, T)
|
|
1053
1117
|
: unwrapReadonlyTypeArgText(node);
|
|
1054
1118
|
};
|
|
1119
|
+
const transformUnionOrIntersectionTypeNodeImpl = (
|
|
1055
1120
|
|
|
1121
|
+
node, readonlyContext, options, operator) => {
|
|
1122
|
+
const nextReadonlyContextValue = nextReadonlyContext({
|
|
1123
|
+
currentReadonlyContext: readonlyContext,
|
|
1124
|
+
nextReadonlyContextType: 'none',
|
|
1125
|
+
indexedAccessDepthChange: 'keep',
|
|
1126
|
+
});
|
|
1056
1127
|
|
|
1128
|
+
for (const n of node.getTypeNodes() ) {
|
|
1129
|
+
transformNode(n, nextReadonlyContextValue, options);
|
|
1130
|
+
}
|
|
1131
|
+
const newTypes = node.getTypeNodes();
|
|
1132
|
+
const withLeadingComments = (
|
|
1057
1133
|
|
|
1134
|
+
member, memberText) => `${leadingCommentsOfMember(node, member)}${memberText}`;
|
|
1058
1135
|
|
|
1059
1136
|
|
|
1137
|
+
const wrapsTypeLiterals = nextReadonlyContextValue.type !== 'DeepReadonly' &&
|
|
1138
|
+
nextReadonlyContextValue.indexedAccessDepth === 0;
|
|
1060
1139
|
|
|
1061
1140
|
|
|
1141
|
+
const underReadonly = readonlyContext.type === 'Readonly' &&
|
|
1142
|
+
readonlyContext.indexedAccessDepth === 0 &&
|
|
1143
|
+
isTypeArgumentOfReadonly(node);
|
|
1144
|
+
const { primitives, arraysAndTuples, typeLiterals, others } = groupUnionIntersectionTypes(newTypes, {
|
|
1145
|
+
operator,
|
|
1146
|
+
underReadonly,
|
|
1147
|
+
deepReadonlyTypeName: options.DeepReadonly.typeName,
|
|
1148
|
+
keptUnwrapped: (t) => wrapsTypeLiterals && takesOffReadonly(t, options),
|
|
1149
|
+
});
|
|
1150
|
+
options.debugPrint({ primitives, arraysAndTuples, typeLiterals, others });
|
|
1062
1151
|
|
|
1063
|
-
const
|
|
1152
|
+
const isEmptyTypeLiteral = (
|
|
1064
1153
|
|
|
1065
|
-
|
|
1154
|
+
n) => n.isKind(tsm.SyntaxKind.TypeLiteral) && Arr.isEmpty(n.getMembers());
|
|
1155
|
+
const nonEmptyTypeLiterals = typeLiterals === undefined
|
|
1156
|
+
? undefined
|
|
1157
|
+
: options.ignoreEmptyObjectTypes
|
|
1158
|
+
? typeLiterals.nodes.filter((n) => !isEmptyTypeLiteral(n))
|
|
1159
|
+
: typeLiterals.nodes;
|
|
1160
|
+
const emptyTypeLiterals = typeLiterals === undefined || !options.ignoreEmptyObjectTypes
|
|
1161
|
+
? undefined
|
|
1162
|
+
: typeLiterals.nodes.filter(isEmptyTypeLiteral);
|
|
1163
|
+
const typeLiteralsWrappedWithReadonly = nonEmptyTypeLiterals === undefined || Arr.isEmpty(nonEmptyTypeLiterals)
|
|
1164
|
+
? []
|
|
1165
|
+
: [
|
|
1166
|
+
unionToString({
|
|
1167
|
+
types: nonEmptyTypeLiterals.map((n) => withLeadingComments(n, isMergeableReadonlyTypeReferenceNode(n, operator)
|
|
1168
|
+
?
|
|
1066
1169
|
|
|
1067
|
-
|
|
1170
|
+
readonlyTypeArgTextSplicedInto(n, operator)
|
|
1171
|
+
: n.isKind(tsm.SyntaxKind.TypeLiteral)
|
|
1172
|
+
? n.getText()
|
|
1173
|
+
:
|
|
1174
|
+
wrapWithParentheses(n.getText()))),
|
|
1175
|
+
op: operator,
|
|
1176
|
+
wrapWithReadonly: wrapsTypeLiterals,
|
|
1177
|
+
}),
|
|
1178
|
+
];
|
|
1068
1179
|
|
|
1180
|
+
const sorted = [
|
|
1181
|
+
mapNullable(primitives, (a) => [
|
|
1182
|
+
a.nodes.map((n) => withLeadingComments(n, n.getText())),
|
|
1183
|
+
a.firstPosition,
|
|
1184
|
+
]),
|
|
1185
|
+
mapNullable(arraysAndTuples, (a) => [
|
|
1186
|
+
a.nodes.map((n) => withLeadingComments(n, n.getText())),
|
|
1187
|
+
a.firstPosition,
|
|
1188
|
+
]),
|
|
1189
|
+
nonEmptyTypeLiterals !== undefined && Arr.isNonEmpty(nonEmptyTypeLiterals)
|
|
1190
|
+
? mapNullable(typeLiterals, (a) => [typeLiteralsWrappedWithReadonly, a.firstPosition])
|
|
1191
|
+
: undefined,
|
|
1192
|
+
emptyTypeLiterals !== undefined && Arr.isNonEmpty(emptyTypeLiterals)
|
|
1193
|
+
? mapNullable(typeLiterals, (a) => [
|
|
1194
|
+
emptyTypeLiterals.map((n) => withLeadingComments(n, n.getText())),
|
|
1069
1195
|
|
|
1196
|
+
a.firstPosition +
|
|
1197
|
+
(nonEmptyTypeLiterals !== undefined &&
|
|
1198
|
+
Arr.isNonEmpty(nonEmptyTypeLiterals)
|
|
1199
|
+
? 0.5
|
|
1200
|
+
: 0),
|
|
1201
|
+
])
|
|
1202
|
+
: undefined,
|
|
1203
|
+
mapNullable(others, (a) => [
|
|
1070
1204
|
|
|
1071
1205
|
|
|
1206
|
+
operator === '|'
|
|
1207
|
+
? mergeDeepReadonlyUnionMembers(a.nodes, options.DeepReadonly.typeName, withLeadingComments)
|
|
1208
|
+
: a.nodes.map((n) => withLeadingComments(n, wrapWithParentheses(n.getText()))),
|
|
1209
|
+
a.firstPosition,
|
|
1210
|
+
]),
|
|
1211
|
+
]
|
|
1212
|
+
.filter((x) => x !== undefined)
|
|
1213
|
+
.toSorted((a, b) => a[1] - b[1])
|
|
1214
|
+
.flatMap((a) => a[0]);
|
|
1072
1215
|
|
|
1073
|
-
const commentsBetween = (
|
|
1074
1216
|
|
|
1075
|
-
sourceFile, from, to) => {
|
|
1076
|
-
if (to <= from) {
|
|
1077
|
-
return '';
|
|
1078
|
-
}
|
|
1079
|
-
const scanner = tsm.ts.createScanner(tsm.ts.ScriptTarget.Latest, false, tsm.ts.LanguageVariant.Standard, sourceFile.getFullText(), undefined, from, to - from);
|
|
1080
|
-
const mut_comments = [];
|
|
1081
|
-
while (scanner.scan() !== tsm.ts.SyntaxKind.EndOfFileToken) {
|
|
1082
|
-
const token = scanner.getToken();
|
|
1083
1217
|
|
|
1084
|
-
const separator = token === tsm.ts.SyntaxKind.SingleLineCommentTrivia
|
|
1085
|
-
? '\n'
|
|
1086
|
-
: token === tsm.ts.SyntaxKind.MultiLineCommentTrivia
|
|
1087
|
-
? ' '
|
|
1088
|
-
: undefined;
|
|
1089
|
-
if (separator !== undefined) {
|
|
1090
|
-
mut_comments.push(`${scanner.getTokenText()}${separator}`);
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
return mut_comments.join('');
|
|
1094
|
-
};
|
|
1095
1218
|
|
|
1096
|
-
const getDeepReadonlyTypeArg = (
|
|
1097
1219
|
|
|
1098
|
-
node, deepReadonlyTypeName) => {
|
|
1099
|
-
if (!node.isKind(tsm.SyntaxKind.TypeReference)) {
|
|
1100
|
-
return undefined;
|
|
1101
|
-
}
|
|
1102
|
-
const typeName = node.getTypeName();
|
|
1103
|
-
const typeArguments = node.getTypeArguments();
|
|
1104
|
-
return typeName.isKind(tsm.SyntaxKind.Identifier) &&
|
|
1105
|
-
typeName.getText() === deepReadonlyTypeName &&
|
|
1106
|
-
Arr.isFixedLengthArray(1, typeArguments)
|
|
1107
|
-
? typeArguments[0]
|
|
1108
|
-
: undefined;
|
|
1109
|
-
};
|
|
1110
|
-
const unionToString = ({ types: typesRaw, op, wrapWithReadonly, }) => {
|
|
1111
1220
|
|
|
1112
1221
|
|
|
1113
1222
|
|
|
1114
1223
|
|
|
1115
1224
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
|
|
1232
|
+
options.replaceNode(node, unionToString({ types: sorted, op: operator, wrapWithReadonly: false }));
|
|
1118
1233
|
};
|
|
1119
|
-
const unionToStringImpl = ({ types, op, wrapWithReadonly, }) => Arr.isEmpty(types)
|
|
1120
|
-
? 'never'
|
|
1121
|
-
: Arr.isFixedLengthArray(1, types)
|
|
1122
|
-
? wrapWithReadonly === false
|
|
1123
|
-
? wrapWithParentheses(types[0])
|
|
1124
|
-
: `${isString(wrapWithReadonly) ? wrapWithReadonly : 'Readonly'}<${types[0]}>`
|
|
1125
|
-
: wrapWithReadonly === false
|
|
1126
|
-
? wrapWithParentheses(types.join(` ${op} `))
|
|
1127
|
-
: `${isString(wrapWithReadonly) ? wrapWithReadonly : 'Readonly'}<${types.join(` ${op} `)}>`;
|
|
1128
1234
|
|
|
1129
1235
|
const transformParenthesizedTypeNode = (
|
|
1130
1236
|
|
|
@@ -1138,16 +1244,12 @@ node, readonlyContext, options) => {
|
|
|
1138
1244
|
const T = node.getTypeNode();
|
|
1139
1245
|
if (
|
|
1140
1246
|
|
|
1141
|
-
|
|
1142
1247
|
T.isKind(tsm.SyntaxKind.TypeReference) ||
|
|
1143
1248
|
|
|
1144
|
-
|
|
1145
1249
|
T.isKind(tsm.SyntaxKind.ArrayType) ||
|
|
1146
1250
|
|
|
1147
|
-
|
|
1148
1251
|
T.isKind(tsm.SyntaxKind.TupleType) ||
|
|
1149
1252
|
|
|
1150
|
-
|
|
1151
1253
|
isAtomicTypeNode(T) ||
|
|
1152
1254
|
|
|
1153
1255
|
|
|
@@ -1244,89 +1346,4 @@ node, readonlyModifier, readonlyContext, options) => {
|
|
|
1244
1346
|
}
|
|
1245
1347
|
}
|
|
1246
1348
|
};
|
|
1247
|
-
const checkIfPropertyNameShouldBeIgnored = (
|
|
1248
|
-
|
|
1249
|
-
nameNode, options) => {
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
return (
|
|
1253
|
-
|
|
1254
|
-
(nameNode.isKind(tsm.SyntaxKind.Identifier) &&
|
|
1255
|
-
pipe(nameNode.getText()).map((nm) => options.ignoredPrefixes.some((p) => nm.startsWith(p))).value) ||
|
|
1256
|
-
|
|
1257
|
-
(nameNode.isKind(tsm.SyntaxKind.StringLiteral) &&
|
|
1258
|
-
pipe(nameNode.getLiteralValue()).map((nm) => options.ignoredPrefixes.some((p) => nm.startsWith(p))).value) ||
|
|
1259
|
-
|
|
1260
|
-
(nameNode.isKind(tsm.SyntaxKind.PrivateIdentifier) &&
|
|
1261
|
-
pipe(nameNode.getText()).map((nm) => options.ignoredPrefixes.some((p) => nm.startsWith(`#${p}`))).value) ||
|
|
1262
|
-
|
|
1263
|
-
(nameNode.isKind(tsm.SyntaxKind.ComputedPropertyName) &&
|
|
1264
|
-
pipe(nameNode.getExpression()).map((exp) => {
|
|
1265
|
-
if (exp.isKind(tsm.SyntaxKind.StringLiteral) ||
|
|
1266
|
-
exp.isKind(tsm.SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
|
1267
|
-
const nm = exp.getLiteralValue();
|
|
1268
|
-
return options.ignoredPrefixes.some((p) => nm.startsWith(p));
|
|
1269
|
-
}
|
|
1270
|
-
return false;
|
|
1271
|
-
}).value));
|
|
1272
|
-
};
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
const isLeftUnwrapped = (
|
|
1289
|
-
|
|
1290
|
-
node, options) => {
|
|
1291
|
-
const members = node.getMembers();
|
|
1292
|
-
const isMethodOrAccessor = (
|
|
1293
|
-
|
|
1294
|
-
mb) => mb.isKind(tsm.SyntaxKind.MethodSignature) ||
|
|
1295
|
-
mb.isKind(tsm.SyntaxKind.GetAccessor) ||
|
|
1296
|
-
mb.isKind(tsm.SyntaxKind.SetAccessor);
|
|
1297
|
-
const isIgnoredMember = (
|
|
1298
|
-
|
|
1299
|
-
mb) => (mb.isKind(tsm.SyntaxKind.PropertySignature) || isMethodOrAccessor(mb)) &&
|
|
1300
|
-
checkIfPropertyNameShouldBeIgnored(mb.getNameNode(), options);
|
|
1301
|
-
const needsReadonlyWrapper = (
|
|
1302
|
-
|
|
1303
|
-
mb) => !isIgnoredMember(mb) &&
|
|
1304
|
-
(isMethodOrAccessor(mb) ||
|
|
1305
|
-
((mb.isKind(tsm.SyntaxKind.PropertySignature) ||
|
|
1306
|
-
mb.isKind(tsm.SyntaxKind.IndexSignature)) &&
|
|
1307
|
-
!mb.hasModifier(tsm.SyntaxKind.ReadonlyKeyword) &&
|
|
1308
|
-
hasDisableNextLineComment(mb)));
|
|
1309
|
-
return members.some(isIgnoredMember) && !members.some(needsReadonlyWrapper);
|
|
1310
|
-
};
|
|
1311
|
-
|
|
1312
|
-
const hasDisableNextLineCommentAround = (node) => {
|
|
1313
|
-
if (hasDisableNextLineComment(node, TRANSFORMER_NAME)) {
|
|
1314
|
-
return true;
|
|
1315
|
-
}
|
|
1316
|
-
const parent = node.getParent();
|
|
1317
|
-
return (parent?.isKind(tsm.SyntaxKind.ParenthesizedType) === true &&
|
|
1318
|
-
hasDisableNextLineCommentAround(parent));
|
|
1319
|
-
};
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
const takesOffReadonly = (
|
|
1328
|
-
|
|
1329
|
-
node, options) => isLeftUnwrapped(node, options) &&
|
|
1330
|
-
!hasCallOrConstructSignature(node) &&
|
|
1331
|
-
!hasDisableNextLineCommentAround(node);
|
|
1332
1349
|
//# sourceMappingURL=convert-to-readonly.mjs.map
|