ts-codemod-lib 1.4.0 → 1.4.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/dist/cmd/append-as-const.mjs +1 -1
- package/dist/cmd/convert-interface-to-type.mjs +1 -1
- package/dist/cmd/convert-to-readonly.mjs +1 -1
- package/dist/cmd/replace-any-with-unknown.mjs +1 -1
- package/dist/cmd/replace-record-with-unknown-record.mjs +1 -1
- package/dist/cmd/run-transformer-cli.mjs +1 -1
- package/dist/cmd/run-transformer-cli.mjs.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.d.mts +1 -1
- package/dist/functions/ast-transformers/append-as-const.d.mts.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.mjs +204 -81
- package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly-type.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cmd/append-as-const.mts +1 -1
- package/src/cmd/convert-interface-to-type.mts +1 -1
- package/src/cmd/convert-to-readonly.mts +1 -1
- package/src/cmd/replace-any-with-unknown.mts +1 -1
- package/src/cmd/replace-record-with-unknown-record.mts +1 -1
- package/src/cmd/run-transformer-cli.mts +1 -1
- package/src/functions/ast-transformers/append-as-const.mts +348 -98
- package/src/functions/ast-transformers/append-as-const.test.mts +637 -456
- package/src/functions/ast-transformers/convert-to-readonly-type.mts +1 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-template-curly-in-string */
|
|
1
2
|
/* eslint-disable import-x/namespace */
|
|
2
3
|
/* eslint-disable tree-shakable/import-star */
|
|
3
4
|
/* eslint-disable vitest/expect-expect */
|
|
@@ -26,7 +27,7 @@ const testFn = async ({
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const transformed = await formatter(
|
|
29
|
-
transformSourceCode(source, false, [appendAsConstTransformer()]),
|
|
30
|
+
transformSourceCode(source, false, [appendAsConstTransformer({ debug })]),
|
|
30
31
|
);
|
|
31
32
|
|
|
32
33
|
const expectedFormatted = await formatter(expected);
|
|
@@ -41,474 +42,654 @@ const formatter = (code: string): Promise<string> =>
|
|
|
41
42
|
});
|
|
42
43
|
|
|
43
44
|
describe(appendAsConstTransformer, () => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
name: 'Binary expression',
|
|
288
|
-
source: 'const sum = a + b;',
|
|
289
|
-
expected: 'const sum = a + b;',
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
name: 'Template literal',
|
|
293
|
-
// eslint-disable-next-line no-template-curly-in-string
|
|
294
|
-
source: 'const greeting = `Hello ${name}`;',
|
|
295
|
-
// eslint-disable-next-line no-template-curly-in-string
|
|
296
|
-
expected: 'const greeting = `Hello ${name}`;',
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
name: 'New expression',
|
|
300
|
-
source: 'const date = new Date();',
|
|
301
|
-
expected: 'const date = new Date();',
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
name: 'Already has as const - array',
|
|
305
|
-
source: 'const arr = [1, 2, 3] as const;',
|
|
306
|
-
expected: 'const arr = [1, 2, 3] as const;',
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
name: 'Already has as const - object',
|
|
310
|
-
source: 'const obj = { a: 1 } as const;',
|
|
311
|
-
expected: 'const obj = { a: 1 } as const;',
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
name: 'Primitive literal - number',
|
|
315
|
-
source: 'const num = 42;',
|
|
316
|
-
expected: 'const num = 42;',
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
name: 'Class declaration',
|
|
320
|
-
source: 'class MyClass { prop = 1; }',
|
|
321
|
-
expected: 'class MyClass { prop = 1; }',
|
|
322
|
-
},
|
|
45
|
+
describe('Primitive types (should not add as const)', () => {
|
|
46
|
+
test.each([
|
|
47
|
+
{
|
|
48
|
+
name: 'number literal',
|
|
49
|
+
source: 'const num = 42;',
|
|
50
|
+
expected: 'const num = 42;',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'BigInt literal',
|
|
54
|
+
source: 'const bigint = 100n as const;',
|
|
55
|
+
expected: 'const bigint = 100n;',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'string literal',
|
|
59
|
+
source: "const str = 'hello';",
|
|
60
|
+
expected: "const str = 'hello';",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'boolean literal',
|
|
64
|
+
source: 'const bool = true;',
|
|
65
|
+
expected: 'const bool = true;',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'null',
|
|
69
|
+
source: 'const n = null;',
|
|
70
|
+
expected: 'const n = null;',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'undefined',
|
|
74
|
+
source: 'const u = undefined;',
|
|
75
|
+
expected: 'const u = undefined;',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'constant declaration with primitive number initializer in parentheses',
|
|
79
|
+
source: 'const foo = (1) as const;',
|
|
80
|
+
expected: 'const foo = 1;',
|
|
81
|
+
},
|
|
82
|
+
])('$name', testFn);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('Template literals', () => {
|
|
86
|
+
test.each([
|
|
87
|
+
{
|
|
88
|
+
name: 'template expression without as const (should add)',
|
|
89
|
+
source: 'const greeting = `Hello ${name}`;',
|
|
90
|
+
expected: 'const greeting = `Hello ${name}` as const;',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'template expression with as const (should keep)',
|
|
94
|
+
source: 'const path = `/${variable}` as const;',
|
|
95
|
+
expected: 'const path = `/${variable}` as const;',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'no substitution template literal without as const (should keep)',
|
|
99
|
+
source: 'const greeting = `hello`;',
|
|
100
|
+
expected: 'const greeting = `hello`;',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'no substitution template literal with as const (should remove)',
|
|
104
|
+
source: 'const greeting = `hello` as const;',
|
|
105
|
+
expected: 'const greeting = `hello`;',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
source: dedent`
|
|
109
|
+
const x = "aaa";
|
|
110
|
+
const foo = \`\${x}bbb\`;
|
|
111
|
+
`,
|
|
112
|
+
expected: dedent`
|
|
113
|
+
const x = "aaa";
|
|
114
|
+
const foo = \`\${x}bbb\` as const;
|
|
115
|
+
`,
|
|
116
|
+
},
|
|
117
|
+
])('$name', testFn);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('Basic array and object transformations', () => {
|
|
121
|
+
test.each([
|
|
122
|
+
{
|
|
123
|
+
name: 'simple array',
|
|
124
|
+
source: 'const foo = [1, 2, 3];',
|
|
125
|
+
expected: 'const foo = [1, 2, 3] as const;',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'empty array',
|
|
129
|
+
source: 'const emptyArray = [];',
|
|
130
|
+
expected: 'const emptyArray = [] as const;',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'nested array',
|
|
134
|
+
source: 'const nested = [1, [2, 3], 4];',
|
|
135
|
+
expected: 'const nested = [1, [2, 3], 4] as const;',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'nested array',
|
|
139
|
+
source: 'const foo = [[1] as const] as const;',
|
|
140
|
+
expected: 'const foo = [[1]] as const;',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'nested array',
|
|
144
|
+
source: 'const nested = [1, [2, 3] as const, 4];',
|
|
145
|
+
expected: 'const nested = [1, [2, 3], 4] as const;',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'should remove nested as const from array literal',
|
|
149
|
+
source: 'const arr = [[1, 2] as const, [3, 4]] as const;',
|
|
150
|
+
expected: 'const arr = [[1, 2], [3, 4]] as const;',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'array with strings',
|
|
154
|
+
source: "const strArray = ['a', 'b', 'c'];",
|
|
155
|
+
expected: "const strArray = ['a', 'b', 'c'] as const;",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'array with mixed types',
|
|
159
|
+
source: "const mixed = [1, 'a', true, null];",
|
|
160
|
+
expected: "const mixed = [1, 'a', true, null] as const;",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'should remove as const from boolean literal inside array and add as const to top level',
|
|
164
|
+
source: 'const arr = [true as const, false];',
|
|
165
|
+
expected: 'const arr = [true, false] as const;',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'simple object',
|
|
169
|
+
source: 'const obj = { a: 1, b: 2 };',
|
|
170
|
+
expected: 'const obj = { a: 1, b: 2 } as const;',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: 'empty object',
|
|
174
|
+
source: 'const emptyObj = {};',
|
|
175
|
+
expected: 'const emptyObj = {} as const;',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'nested object',
|
|
179
|
+
source: 'const nestedObj = { a: 1, b: { c: 2 } };',
|
|
180
|
+
expected: 'const nestedObj = { a: 1, b: { c: 2 } } as const;',
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'object with array',
|
|
184
|
+
source: 'const objWithArray = { a: 1, b: [1, 2, 3] };',
|
|
185
|
+
expected: 'const objWithArray = { a: 1, b: [1, 2, 3] } as const;',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: 'array with objects',
|
|
189
|
+
source: 'const arrayWithObj = [{ a: 1 }, { b: 2 }];',
|
|
190
|
+
expected: 'const arrayWithObj = [{ a: 1 }, { b: 2 }] as const;',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: 'should remove as const from string literal inside object and add as const to top level',
|
|
194
|
+
source: 'const obj = { key: "value" as const };',
|
|
195
|
+
expected: 'const obj = { key: "value" } as const;',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: 'multiple variable declarations',
|
|
199
|
+
source: 'const a = [1, 2], b = { c: 3 };',
|
|
200
|
+
expected: 'const a = [1, 2] as const, b = { c: 3 } as const;',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'should remove nested as const from object literal',
|
|
204
|
+
source: 'const obj = { a: { b: 1 } as const, c: 2 } as const;',
|
|
205
|
+
expected: 'const obj = { a: { b: 1 }, c: 2 } as const;',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'should remove nested as const from mixed literals',
|
|
209
|
+
source: 'let mixed = [{ a: 1 } as const, [2] as const] as const;',
|
|
210
|
+
expected: 'let mixed = [{ a: 1 }, [2]] as const;',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: 'should remove deeply nested as const',
|
|
214
|
+
source: 'let deep = [[{ x: 1 as const }] as const] as const;',
|
|
215
|
+
expected: 'let deep = [[{ x: 1 }]] as const;',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'should remove multiple primitive as const inside literals and add as const to top level',
|
|
219
|
+
source:
|
|
220
|
+
'const mixed = [1 as const, { val: "str" as const }, false as const];',
|
|
221
|
+
expected: 'const mixed = [1, { val: "str" }, false] as const;',
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'should remove primitive as const even if parent already has as const',
|
|
225
|
+
source: 'const arr = [1 as const, 2] as const;',
|
|
226
|
+
expected: 'const arr = [1, 2] as const;',
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: 'should remove primitive as const in nested object and add as const to top level',
|
|
230
|
+
source: 'const obj = { data: { value: 123 as const } };',
|
|
231
|
+
expected: 'const obj = { data: { value: 123 } } as const;',
|
|
232
|
+
},
|
|
233
|
+
])('$name', testFn);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('Spread syntax', () => {
|
|
237
|
+
test.each([
|
|
238
|
+
{
|
|
239
|
+
name: 'simple spread in array',
|
|
240
|
+
source: dedent`
|
|
241
|
+
const flag = true as boolean;
|
|
242
|
+
const a = [0, ...[{ x: 1 }, 2]];
|
|
243
|
+
`,
|
|
244
|
+
expected: dedent`
|
|
245
|
+
const flag = true as boolean;
|
|
246
|
+
const a = [0, ...[{ x: 1 }, 2]] as const;
|
|
247
|
+
`,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: 'simple spread in array with as const inside',
|
|
251
|
+
source: dedent`
|
|
252
|
+
const flag = true as boolean;
|
|
253
|
+
const a = [0, ...([{ x: 1 } as const, 2] as const)] as const;
|
|
254
|
+
`,
|
|
255
|
+
expected: dedent`
|
|
256
|
+
const flag = true as boolean;
|
|
257
|
+
const a = [0, ...[{ x: 1 }, 2]] as const;
|
|
258
|
+
`,
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: 'simple spread in array with ternary expression inside',
|
|
262
|
+
source: dedent`
|
|
263
|
+
const flag = true as boolean;
|
|
264
|
+
const b = [0, ...(flag ? ([1, 2]) : ([]))];
|
|
265
|
+
`,
|
|
266
|
+
expected: dedent`
|
|
267
|
+
const flag = true as boolean;
|
|
268
|
+
const b = [0, ...(flag ? ([1, 2] as const) : ([] as const))] as const;
|
|
269
|
+
`,
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'simple spread in array with ternary expression inside',
|
|
273
|
+
source: dedent`
|
|
274
|
+
const flag = true as boolean;
|
|
275
|
+
const c = [0, ...([1, flag ? [2] : [3]] as const)] as const;
|
|
276
|
+
`,
|
|
277
|
+
expected: dedent`
|
|
278
|
+
const flag = true as boolean;
|
|
279
|
+
const c = [0, ...([1, flag ? [2] as const : [3] as const])] as const;
|
|
280
|
+
`,
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: 'Nested as const inside spread operator with conditional should be kept',
|
|
284
|
+
source: dedent`
|
|
285
|
+
const flag = true as boolean;
|
|
323
286
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
expected: 'const arr = [[1, 2], [3, 4]] as const;',
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
name: 'should remove nested as const from object literal',
|
|
332
|
-
source: 'const obj = { a: { b: 1 } as const, c: 2 } as const;',
|
|
333
|
-
expected: 'const obj = { a: { b: 1 }, c: 2 } as const;',
|
|
334
|
-
},
|
|
335
|
-
{
|
|
336
|
-
name: 'should remove nested as const from mixed literals',
|
|
337
|
-
source: 'const mixed = [{ a: 1 } as const, [2] as const] as const;',
|
|
338
|
-
expected: 'const mixed = [{ a: 1 }, [2]] as const;',
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
name: 'should remove deeply nested as const',
|
|
342
|
-
source: 'const deep = [[{ x: 1 as const }] as const] as const;',
|
|
343
|
-
expected: 'const deep = [[{ x: 1 }]] as const;',
|
|
344
|
-
},
|
|
287
|
+
type Elem =
|
|
288
|
+
| Readonly<{ a: 'str0' }>
|
|
289
|
+
| Readonly<{ b: 'str1' }>
|
|
290
|
+
| Readonly<{ c: 'str2' }>;
|
|
345
291
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
name: 'should remove as const from string literal inside object and add as const to top level',
|
|
354
|
-
source: 'const obj = { key: "value" as const };',
|
|
355
|
-
expected: 'const obj = { key: "value" } as const;',
|
|
356
|
-
},
|
|
357
|
-
{
|
|
358
|
-
name: 'should remove as const from boolean literal inside array and add as const to top level',
|
|
359
|
-
source: 'const arr = [true as const, false];',
|
|
360
|
-
expected: 'const arr = [true, false] as const;',
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
name: 'should remove multiple primitive as const inside literals and add as const to top level',
|
|
364
|
-
source:
|
|
365
|
-
'const mixed = [1 as const, { val: "str" as const }, false as const];',
|
|
366
|
-
expected: 'const mixed = [1, { val: "str" }, false] as const;',
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
name: 'should remove primitive as const even if parent already has as const',
|
|
370
|
-
source: 'const arr = [1 as const, 2] as const;',
|
|
371
|
-
expected: 'const arr = [1, 2] as const;',
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
name: 'should remove primitive as const in nested object and add as const to top level',
|
|
375
|
-
source: 'const obj = { data: { value: 123 as const } };',
|
|
376
|
-
expected: 'const obj = { data: { value: 123 } } as const;',
|
|
377
|
-
},
|
|
292
|
+
const a = [
|
|
293
|
+
{ a: 'str0' },
|
|
294
|
+
...(flag ? ([{ b: 'str1' }, { c: 'str2' }] as const) : []),
|
|
295
|
+
] as const satisfies readonly Elem[];
|
|
296
|
+
`,
|
|
297
|
+
expected: dedent`
|
|
298
|
+
const flag = true as boolean;
|
|
378
299
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
({
|
|
384
|
-
type: SomeTypeSymbol,
|
|
385
|
-
value
|
|
386
|
-
}) as const;
|
|
387
|
-
`,
|
|
388
|
-
expected: dedent`
|
|
389
|
-
export const some = <const S,>(value: S): Some<S> =>
|
|
390
|
-
({
|
|
391
|
-
type: SomeTypeSymbol,
|
|
392
|
-
value
|
|
393
|
-
}) as const;
|
|
394
|
-
`,
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
name: 'Nested as const inside spread operator with conditional should be kept',
|
|
398
|
-
source: dedent`
|
|
399
|
-
const flag = true as boolean;
|
|
300
|
+
type Elem =
|
|
301
|
+
| Readonly<{ a: 'str0' }>
|
|
302
|
+
| Readonly<{ b: 'str1' }>
|
|
303
|
+
| Readonly<{ c: 'str2' }>;
|
|
400
304
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
305
|
+
const a = [
|
|
306
|
+
{ a: 'str0' },
|
|
307
|
+
...(flag ? ([{ b: 'str1' }, { c: 'str2' }] as const) : [] as const),
|
|
308
|
+
] as const satisfies readonly Elem[];
|
|
309
|
+
`,
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: 'Spread with conditional without as const should add as const to inner array',
|
|
313
|
+
source: dedent`
|
|
314
|
+
const flag = true as boolean;
|
|
405
315
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
`,
|
|
411
|
-
expected: dedent`
|
|
412
|
-
const flag = true as boolean;
|
|
316
|
+
type Elem =
|
|
317
|
+
| Readonly<{ a: 'str0' }>
|
|
318
|
+
| Readonly<{ b: 'str1' }>
|
|
319
|
+
| Readonly<{ c: 'str2' }>;
|
|
413
320
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
321
|
+
const a = [
|
|
322
|
+
{ a: 'str0' },
|
|
323
|
+
...(flag ? [{ b: 'str1' }, { c: 'str2' }] : []),
|
|
324
|
+
] as const satisfies readonly Elem[];
|
|
325
|
+
`,
|
|
326
|
+
expected: dedent`
|
|
327
|
+
const flag = true as boolean;
|
|
418
328
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
`,
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
name: 'Spread with conditional without as const should add as const to inner array',
|
|
427
|
-
source: dedent`
|
|
428
|
-
const flag = true as boolean;
|
|
329
|
+
type Elem =
|
|
330
|
+
| Readonly<{ a: 'str0' }>
|
|
331
|
+
| Readonly<{ b: 'str1' }>
|
|
332
|
+
| Readonly<{ c: 'str2' }>;
|
|
429
333
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
334
|
+
const a = [
|
|
335
|
+
{ a: 'str0' },
|
|
336
|
+
...(flag ? [{ b: 'str1' }, { c: 'str2' }] as const : [] as const),
|
|
337
|
+
] as const satisfies readonly Elem[];
|
|
338
|
+
`,
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
name: 'Simple spread without conditional should remove inner as const',
|
|
342
|
+
source: dedent`
|
|
343
|
+
const a = [
|
|
344
|
+
1,
|
|
345
|
+
...[2, 3] as const,
|
|
346
|
+
] as const;
|
|
347
|
+
`,
|
|
348
|
+
expected: dedent`
|
|
349
|
+
const a = [
|
|
350
|
+
1,
|
|
351
|
+
...[2, 3],
|
|
352
|
+
] as const;
|
|
353
|
+
`,
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
name: 'Multiple simple spreads should remove inner as const',
|
|
357
|
+
source: dedent`
|
|
358
|
+
const c = [
|
|
359
|
+
...[1, 2] as const,
|
|
360
|
+
...[3, 4] as const,
|
|
361
|
+
] as const;
|
|
362
|
+
`,
|
|
363
|
+
expected: dedent`
|
|
364
|
+
const c = [
|
|
365
|
+
...[1, 2],
|
|
366
|
+
...[3, 4],
|
|
367
|
+
] as const;
|
|
368
|
+
`,
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: 'Nested as const inside spread operator without conditional statement should be removed',
|
|
372
|
+
source: dedent`
|
|
373
|
+
const flag = true as boolean;
|
|
434
374
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
`,
|
|
440
|
-
expected: dedent`
|
|
441
|
-
const flag = true as boolean;
|
|
375
|
+
type Elem =
|
|
376
|
+
| Readonly<{ a: 'str0' }>
|
|
377
|
+
| Readonly<{ b: 'str1' }>
|
|
378
|
+
| Readonly<{ c: 'str2' }>;
|
|
442
379
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
380
|
+
const a = [
|
|
381
|
+
{ a: 'str0' },
|
|
382
|
+
...([{ b: 'str1' }, { c: 'str2' }] as const),
|
|
383
|
+
] as const satisfies readonly Elem[];
|
|
384
|
+
`,
|
|
385
|
+
expected: dedent`
|
|
386
|
+
const flag = true as boolean;
|
|
447
387
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
`,
|
|
453
|
-
},
|
|
454
|
-
{
|
|
455
|
-
name: 'Simple spread without conditional should remove inner as const',
|
|
456
|
-
source: dedent`
|
|
457
|
-
const a = [
|
|
458
|
-
1,
|
|
459
|
-
...[2, 3] as const,
|
|
460
|
-
] as const;
|
|
461
|
-
`,
|
|
462
|
-
expected: dedent`
|
|
463
|
-
const a = [
|
|
464
|
-
1,
|
|
465
|
-
...[2, 3],
|
|
466
|
-
] as const;
|
|
467
|
-
`,
|
|
468
|
-
},
|
|
469
|
-
{
|
|
470
|
-
name: 'Multiple simple spreads should remove inner as const',
|
|
471
|
-
source: dedent`
|
|
472
|
-
const c = [
|
|
473
|
-
...[1, 2] as const,
|
|
474
|
-
...[3, 4] as const,
|
|
475
|
-
] as const;
|
|
476
|
-
`,
|
|
477
|
-
expected: dedent`
|
|
478
|
-
const c = [
|
|
479
|
-
...[1, 2],
|
|
480
|
-
...[3, 4],
|
|
481
|
-
] as const;
|
|
482
|
-
`,
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
name: 'Nested as const inside spread operator without conditional statement should be removed',
|
|
486
|
-
source: dedent`
|
|
487
|
-
const flag = true as boolean;
|
|
388
|
+
type Elem =
|
|
389
|
+
| Readonly<{ a: 'str0' }>
|
|
390
|
+
| Readonly<{ b: 'str1' }>
|
|
391
|
+
| Readonly<{ c: 'str2' }>;
|
|
488
392
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
393
|
+
const a = [
|
|
394
|
+
{ a: 'str0' },
|
|
395
|
+
...[{ b: 'str1' }, { c: 'str2' }],
|
|
396
|
+
] as const satisfies readonly Elem[];
|
|
397
|
+
`,
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
name: 'Object with spread operator',
|
|
401
|
+
source: 'const obj = { a: 1, ...{ b: 2 } };',
|
|
402
|
+
expected: 'const obj = { a: 1, ...{ b: 2 } } as const;',
|
|
403
|
+
},
|
|
404
|
+
])('$name', testFn);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
describe('Function contexts', () => {
|
|
408
|
+
test.each([
|
|
409
|
+
{
|
|
410
|
+
name: 'function return statement',
|
|
411
|
+
source: 'function foo() { return [1, 2, 3]; }',
|
|
412
|
+
expected: 'function foo() { return [1, 2, 3] as const; }',
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
name: 'arrow function return',
|
|
416
|
+
source: 'const foo = () => ({ a: 1, b: 2 });',
|
|
417
|
+
expected: 'const foo = () => ({ a: 1, b: 2 } as const);',
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: 'array already has as const',
|
|
421
|
+
source: 'const arr = [1, 2, 3] as const;',
|
|
422
|
+
expected: 'const arr = [1, 2, 3] as const;',
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
name: 'object already has as const',
|
|
426
|
+
source: 'const obj = { a: 1 } as const;',
|
|
427
|
+
expected: 'const obj = { a: 1 } as const;',
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
name: 'array in function parameter default value',
|
|
431
|
+
source: 'function foo(a = [1, 2]) { return a; }',
|
|
432
|
+
expected: 'function foo(a = [1, 2] as const) { return a; }',
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: 'object in function parameter default value',
|
|
436
|
+
source: 'function foo(a = { b: 1 }) { return a; }',
|
|
437
|
+
expected: 'function foo(a = { b: 1 } as const) { return a; }',
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
name: 'object in function call argument (not transformed with avoidInFunctionArgs)',
|
|
441
|
+
source: 'const a = foo({ b: 1 });',
|
|
442
|
+
expected: 'const a = foo({ b: 1 });',
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
name: 'arrow function with generic type parameter',
|
|
446
|
+
source: dedent`
|
|
447
|
+
export const some = <const S,>(value: S): Some<S> =>
|
|
448
|
+
({
|
|
449
|
+
type: SomeTypeSymbol,
|
|
450
|
+
value
|
|
451
|
+
});
|
|
452
|
+
`,
|
|
453
|
+
expected: dedent`
|
|
454
|
+
export const some = <const S,>(value: S): Some<S> =>
|
|
455
|
+
({
|
|
456
|
+
type: SomeTypeSymbol,
|
|
457
|
+
value
|
|
458
|
+
}) as const;
|
|
459
|
+
`,
|
|
460
|
+
},
|
|
461
|
+
])('$name', testFn);
|
|
462
|
+
});
|
|
493
463
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
464
|
+
describe('Transformer ignore comments', () => {
|
|
465
|
+
test.each([
|
|
466
|
+
{
|
|
467
|
+
name: 'generic transformer-ignore-next-line for array',
|
|
468
|
+
source: dedent`
|
|
469
|
+
// transformer-ignore-next-line
|
|
470
|
+
const skippedArray = [1, 2, 3];
|
|
471
|
+
`,
|
|
472
|
+
expected: dedent`
|
|
473
|
+
// transformer-ignore-next-line
|
|
474
|
+
const skippedArray = [1, 2, 3];
|
|
475
|
+
`,
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
name: 'generic transformer-ignore-next-line for object',
|
|
479
|
+
source: dedent`
|
|
480
|
+
// transformer-ignore-next-line
|
|
481
|
+
const skippedObject = { a: 1, b: "hello" };
|
|
482
|
+
`,
|
|
483
|
+
expected: dedent`
|
|
484
|
+
// transformer-ignore-next-line
|
|
485
|
+
const skippedObject = { a: 1, b: "hello" };
|
|
486
|
+
`,
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
name: 'transformer-ignore-next-line only affects immediate next line',
|
|
490
|
+
source: dedent`
|
|
491
|
+
const transformedArray = [10, 20]; // This should be transformed
|
|
492
|
+
// transformer-ignore-next-line
|
|
493
|
+
const skippedObject = { x: true }; // This should be skipped
|
|
494
|
+
const transformedObject = { y: false }; // This should be transformed
|
|
495
|
+
`,
|
|
496
|
+
expected: dedent`
|
|
497
|
+
const transformedArray = [10, 20] as const; // This should be transformed
|
|
498
|
+
// transformer-ignore-next-line
|
|
499
|
+
const skippedObject = { x: true }; // This should be skipped
|
|
500
|
+
const transformedObject = { y: false } as const; // This should be transformed
|
|
501
|
+
`,
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
name: 'file scope transformer-ignore',
|
|
505
|
+
source: dedent`
|
|
506
|
+
/* transformer-ignore */
|
|
507
|
+
const transformedArray = [10, 20]; // This should be skipped
|
|
508
|
+
const skippedObject = { x: true }; // This should be skipped
|
|
509
|
+
const transformedObject = { y: false }; // This should be skipped
|
|
510
|
+
`,
|
|
511
|
+
expected: dedent`
|
|
512
|
+
/* transformer-ignore */
|
|
513
|
+
const transformedArray = [10, 20]; // This should be skipped
|
|
514
|
+
const skippedObject = { x: true }; // This should be skipped
|
|
515
|
+
const transformedObject = { y: false }; // This should be skipped
|
|
516
|
+
`,
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
name: 'transformer-specific ignore (next line)',
|
|
520
|
+
source: dedent`
|
|
521
|
+
const a = [1, 2, 3];
|
|
522
|
+
// transformer-ignore-next-line append-as-const
|
|
523
|
+
const b = [4, 5, 6];
|
|
524
|
+
const c = [7, 8, 9];
|
|
525
|
+
`,
|
|
526
|
+
expected: dedent`
|
|
527
|
+
const a = [1, 2, 3] as const;
|
|
528
|
+
// transformer-ignore-next-line append-as-const
|
|
529
|
+
const b = [4, 5, 6];
|
|
530
|
+
const c = [7, 8, 9] as const;
|
|
531
|
+
`,
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: 'transformer-specific ignore (file scope)',
|
|
535
|
+
source: dedent`
|
|
536
|
+
/* transformer-ignore append-as-const */
|
|
537
|
+
const a = [1, 2, 3];
|
|
538
|
+
const b = { x: 1 };
|
|
539
|
+
`,
|
|
540
|
+
expected: dedent`
|
|
541
|
+
/* transformer-ignore append-as-const */
|
|
542
|
+
const a = [1, 2, 3];
|
|
543
|
+
const b = { x: 1 };
|
|
544
|
+
`,
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
name: 'multiple transformers in ignore comment',
|
|
548
|
+
source: dedent`
|
|
549
|
+
const a = [1, 2, 3];
|
|
550
|
+
// transformer-ignore-next-line append-as-const, replace-any-with-unknown
|
|
551
|
+
const b = [4, 5, 6];
|
|
552
|
+
const c = [7, 8, 9];
|
|
553
|
+
`,
|
|
554
|
+
expected: dedent`
|
|
555
|
+
const a = [1, 2, 3] as const;
|
|
556
|
+
// transformer-ignore-next-line append-as-const, replace-any-with-unknown
|
|
557
|
+
const b = [4, 5, 6];
|
|
558
|
+
const c = [7, 8, 9] as const;
|
|
559
|
+
`,
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
name: 'wrong transformer name should not affect transformation',
|
|
563
|
+
source: dedent`
|
|
564
|
+
const a = [1, 2, 3];
|
|
565
|
+
// transformer-ignore-next-line some-other-transformer
|
|
566
|
+
const b = [4, 5, 6];
|
|
567
|
+
const c = [7, 8, 9];
|
|
568
|
+
`,
|
|
569
|
+
expected: dedent`
|
|
570
|
+
const a = [1, 2, 3] as const;
|
|
571
|
+
// transformer-ignore-next-line some-other-transformer
|
|
572
|
+
const b = [4, 5, 6] as const;
|
|
573
|
+
const c = [7, 8, 9] as const;
|
|
574
|
+
`,
|
|
575
|
+
},
|
|
576
|
+
])('$name', testFn);
|
|
577
|
+
});
|
|
501
578
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
579
|
+
describe('ignorePrefixes option (mut_ prefix)', () => {
|
|
580
|
+
test.each([
|
|
581
|
+
{
|
|
582
|
+
name: 'single variable with mut_ prefix',
|
|
583
|
+
source: 'const mut_foo = [1, 2, 3];',
|
|
584
|
+
expected: 'const mut_foo = [1, 2, 3];',
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
name: 'multiple variables with mut_ prefix',
|
|
588
|
+
source: 'const mut_a = [1, 2], mut_b = { c: 3 };',
|
|
589
|
+
expected: 'const mut_a = [1, 2], mut_b = { c: 3 };',
|
|
590
|
+
},
|
|
591
|
+
])('$name', testFn);
|
|
592
|
+
});
|
|
506
593
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
594
|
+
describe('Additional edge cases', () => {
|
|
595
|
+
test.each([
|
|
596
|
+
{
|
|
597
|
+
name: 'type annotation (should be skipped)',
|
|
598
|
+
source: 'const a = 1 as 1;',
|
|
599
|
+
expected: 'const a = 1 as 1;',
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
name: 'variable reference',
|
|
603
|
+
source: 'const a = 1; const b = a;',
|
|
604
|
+
expected: 'const a = 1; const b = a;',
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
name: 'function call',
|
|
608
|
+
source: 'const result = foo();',
|
|
609
|
+
expected: 'const result = foo();',
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
name: 'method call',
|
|
613
|
+
source: 'const result = obj.method();',
|
|
614
|
+
expected: 'const result = obj.method();',
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
name: 'binary expression',
|
|
618
|
+
source: 'const sum = a + b;',
|
|
619
|
+
expected: 'const sum = a + b;',
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
name: 'new expression',
|
|
623
|
+
source: 'const date = new Date();',
|
|
624
|
+
expected: 'const date = new Date();',
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
name: 'class declaration',
|
|
628
|
+
source: 'class MyClass { prop = 1; }',
|
|
629
|
+
expected: 'class MyClass { prop = 1 as const; }',
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
name: 'class declaration with mut_ prefix',
|
|
633
|
+
source: 'class MyClass { mut_prop = 1; }',
|
|
634
|
+
expected: 'class MyClass { mut_prop = 1; }',
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
name: 'arrow function',
|
|
638
|
+
source: dedent`
|
|
639
|
+
export const some = <const S,>(value: S): Some<S> =>
|
|
640
|
+
({
|
|
641
|
+
type: SomeTypeSymbol,
|
|
642
|
+
value
|
|
643
|
+
}) as const;
|
|
644
|
+
`,
|
|
645
|
+
expected: dedent`
|
|
646
|
+
export const some = <const S,>(value: S): Some<S> =>
|
|
647
|
+
({
|
|
648
|
+
type: SomeTypeSymbol,
|
|
649
|
+
value
|
|
650
|
+
}) as const;
|
|
651
|
+
`,
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
name: 'Object with computed property',
|
|
655
|
+
source: "const obj = { ['key']: [1, 2] };",
|
|
656
|
+
expected: "const obj = { ['key']: [1, 2] } as const;",
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
name: 'Parenthesized array expression',
|
|
660
|
+
source: 'const arr = ([1, 2]);',
|
|
661
|
+
expected: 'const arr = [1, 2] as const;',
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
name: 'Parenthesized object expression',
|
|
665
|
+
source: 'const obj = ({ a: 1 });',
|
|
666
|
+
expected: 'const obj = { a: 1 } as const;',
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
name: 'Object with method that returns array (method body not transformed)',
|
|
670
|
+
source: 'const obj = { method() { return [1, 2]; } };',
|
|
671
|
+
expected: 'const obj = { method() { return [1, 2]; } } as const;',
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
name: 'Regex literal with as const should remove as const',
|
|
675
|
+
source: 'const regex = /test/ as const;',
|
|
676
|
+
expected: 'const regex = /test/;',
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
name: 'satisfies without as const should add as const',
|
|
680
|
+
source: 'const a = [1, 2] satisfies readonly number[];',
|
|
681
|
+
expected: 'const a = [1, 2] as const satisfies readonly number[];',
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
name: 'Object with getter (getter body not transformed)',
|
|
685
|
+
source: 'const obj = { get value() { return [1, 2]; } };',
|
|
686
|
+
expected: 'const obj = { get value() { return [1, 2]; } } as const;',
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
name: 'Object with setter',
|
|
690
|
+
source: 'const obj = { set value(v) { } };',
|
|
691
|
+
expected: 'const obj = { set value(v) { } } as const;',
|
|
692
|
+
},
|
|
693
|
+
])('$name', testFn);
|
|
694
|
+
});
|
|
514
695
|
});
|