@openrewrite/recipes-testing 0.1.0-20260313-092538

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.
@@ -0,0 +1,6 @@
1
+ import { CategoryDescriptor, RecipeMarketplace } from "@openrewrite/rewrite";
2
+ export declare const Testing: CategoryDescriptor[];
3
+ export declare const Migrate: CategoryDescriptor[];
4
+ export declare function activate(marketplace: RecipeMarketplace): Promise<void>;
5
+ export { JestToVitest } from "./jest-to-vitest";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,sBAAsB,CAAC;AAG3E,eAAO,MAAM,OAAO,EAAE,kBAAkB,EAA+B,CAAC;AACxE,eAAO,MAAM,OAAO,EAAE,kBAAkB,EAA2C,CAAC;AAEpF,wBAAsB,QAAQ,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;AAED,OAAO,EAAC,YAAY,EAAC,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.JestToVitest = exports.Migrate = exports.Testing = void 0;
13
+ exports.activate = activate;
14
+ const jest_to_vitest_1 = require("./jest-to-vitest");
15
+ exports.Testing = [{ displayName: "Testing" }];
16
+ exports.Migrate = [...exports.Testing, { displayName: "Migrate" }];
17
+ function activate(marketplace) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ yield marketplace.install(jest_to_vitest_1.JestToVitest, exports.Migrate);
20
+ });
21
+ }
22
+ var jest_to_vitest_2 = require("./jest-to-vitest");
23
+ Object.defineProperty(exports, "JestToVitest", { enumerable: true, get: function () { return jest_to_vitest_2.JestToVitest; } });
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAMA,4BAEC;AAPD,qDAA8C;AAEjC,QAAA,OAAO,GAAyB,CAAC,EAAC,WAAW,EAAE,SAAS,EAAC,CAAC,CAAC;AAC3D,QAAA,OAAO,GAAyB,CAAC,GAAG,eAAO,EAAE,EAAC,WAAW,EAAE,SAAS,EAAC,CAAC,CAAC;AAEpF,SAAsB,QAAQ,CAAC,WAA8B;;QACzD,MAAM,WAAW,CAAC,OAAO,CAAC,6BAAY,EAAE,eAAO,CAAC,CAAC;IACrD,CAAC;CAAA;AAED,mDAA8C;AAAtC,8GAAA,YAAY,OAAA"}
@@ -0,0 +1,8 @@
1
+ import { ExecutionContext, Recipe, TreeVisitor } from "@openrewrite/rewrite";
2
+ export declare class JestToVitest extends Recipe {
3
+ name: string;
4
+ displayName: string;
5
+ description: string;
6
+ editor(): Promise<TreeVisitor<any, ExecutionContext>>;
7
+ }
8
+ //# sourceMappingURL=jest-to-vitest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jest-to-vitest.d.ts","sourceRoot":"","sources":["../src/jest-to-vitest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAyC3E,qBAAa,YAAa,SAAQ,MAAM;IACpC,IAAI,SAAqD;IACzD,WAAW,SAA4B;IACvC,WAAW,SAEiD;IAEtD,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;CAG9D"}
@@ -0,0 +1,492 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.JestToVitest = void 0;
13
+ const rewrite_1 = require("@openrewrite/rewrite");
14
+ const javascript_1 = require("@openrewrite/rewrite/javascript");
15
+ const java_1 = require("@openrewrite/rewrite/java");
16
+ const JEST_CONFIG = {
17
+ dependencies: {
18
+ '@types/jest': '^29.5.13'
19
+ },
20
+ };
21
+ const VITEST_CONFIG = {
22
+ dependencies: {
23
+ 'vitest': '^2.0.0'
24
+ },
25
+ context: ['import { vi } from "vitest";',]
26
+ };
27
+ class JestToVitest extends rewrite_1.Recipe {
28
+ constructor() {
29
+ super(...arguments);
30
+ this.name = "org.openrewrite.javascript.testing.JestToVitest";
31
+ this.displayName = "Migrate Jest to Vitest";
32
+ this.description = "Migrates Jest test files to use Vitest as the testing framework. " +
33
+ "This includes updating imports, transforming global functions, and converting " +
34
+ "Jest-specific mocking patterns to Vitest equivalents.";
35
+ }
36
+ editor() {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ return new JestToVitestVisitor();
39
+ });
40
+ }
41
+ }
42
+ exports.JestToVitest = JestToVitest;
43
+ const transformationRules = {
44
+ fn: {
45
+ rule: (0, javascript_1.rewrite)(() => {
46
+ const args = (0, javascript_1.capture)({ variadic: true });
47
+ return {
48
+ before: (0, javascript_1.pattern) `jest.fn(${args})`.configure(JEST_CONFIG),
49
+ after: (0, javascript_1.template) `vi.fn(${args})`.configure(VITEST_CONFIG)
50
+ };
51
+ }),
52
+ imports: ['vi']
53
+ },
54
+ spyOn: {
55
+ rule: (0, javascript_1.rewrite)(() => {
56
+ const args = (0, javascript_1.capture)({ variadic: true });
57
+ return {
58
+ before: (0, javascript_1.pattern) `jest.spyOn(${args})`.configure(JEST_CONFIG),
59
+ after: (0, javascript_1.template) `vi.spyOn(${args})`.configure(VITEST_CONFIG)
60
+ };
61
+ }),
62
+ imports: ['vi']
63
+ },
64
+ mock: {
65
+ rule: (0, javascript_1.rewrite)(() => {
66
+ const path = (0, javascript_1.capture)('path');
67
+ const literalBody = (0, javascript_1.capture)({
68
+ name: 'literalBody',
69
+ constraint: (node) => node.kind === java_1.J.Kind.Literal
70
+ });
71
+ return {
72
+ before: (0, javascript_1.pattern) `jest.mock(${path}, () => ${literalBody})`.configure(JEST_CONFIG),
73
+ after: (0, javascript_1.template) `vi.mock(${path}, () => ({ default: ${literalBody} }))`.configure(VITEST_CONFIG)
74
+ };
75
+ }).orElse((0, javascript_1.rewrite)(() => {
76
+ const args = (0, javascript_1.capture)({ variadic: true });
77
+ return {
78
+ before: (0, javascript_1.pattern) `jest.mock(${args})`.configure(JEST_CONFIG),
79
+ after: (0, javascript_1.template) `vi.mock(${args})`.configure(VITEST_CONFIG)
80
+ };
81
+ })),
82
+ imports: ['vi']
83
+ },
84
+ unmock: {
85
+ rule: (0, javascript_1.rewrite)(() => {
86
+ const args = (0, javascript_1.capture)({ variadic: true });
87
+ return {
88
+ before: (0, javascript_1.pattern) `jest.unmock(${args})`.configure(JEST_CONFIG),
89
+ after: (0, javascript_1.template) `vi.unmock(${args})`.configure(VITEST_CONFIG)
90
+ };
91
+ }),
92
+ imports: ['vi']
93
+ },
94
+ clearAllMocks: {
95
+ rule: (0, javascript_1.rewrite)(() => ({
96
+ before: (0, javascript_1.pattern) `jest.clearAllMocks()`.configure(JEST_CONFIG),
97
+ after: (0, javascript_1.template) `vi.clearAllMocks()`.configure(VITEST_CONFIG)
98
+ })),
99
+ imports: ['vi']
100
+ },
101
+ resetAllMocks: {
102
+ rule: (0, javascript_1.rewrite)(() => ({
103
+ before: (0, javascript_1.pattern) `jest.resetAllMocks()`.configure(JEST_CONFIG),
104
+ after: (0, javascript_1.template) `vi.resetAllMocks()`.configure(VITEST_CONFIG)
105
+ })),
106
+ imports: ['vi']
107
+ },
108
+ restoreAllMocks: {
109
+ rule: (0, javascript_1.rewrite)(() => ({
110
+ before: (0, javascript_1.pattern) `jest.restoreAllMocks()`.configure(JEST_CONFIG),
111
+ after: (0, javascript_1.template) `vi.restoreAllMocks()`.configure(VITEST_CONFIG)
112
+ })),
113
+ imports: ['vi']
114
+ },
115
+ useFakeTimers: {
116
+ rule: (0, javascript_1.rewrite)(() => {
117
+ const args = (0, javascript_1.capture)({ variadic: true });
118
+ return {
119
+ before: (0, javascript_1.pattern) `jest.useFakeTimers(${args})`.configure(JEST_CONFIG),
120
+ after: (0, javascript_1.template) `vi.useFakeTimers(${args})`.configure(VITEST_CONFIG)
121
+ };
122
+ }),
123
+ imports: ['vi']
124
+ },
125
+ useRealTimers: {
126
+ rule: (0, javascript_1.rewrite)(() => ({
127
+ before: (0, javascript_1.pattern) `jest.useRealTimers()`.configure(JEST_CONFIG),
128
+ after: (0, javascript_1.template) `vi.useRealTimers()`.configure(VITEST_CONFIG)
129
+ })),
130
+ imports: ['vi']
131
+ },
132
+ runAllTimers: {
133
+ rule: (0, javascript_1.rewrite)(() => ({
134
+ before: (0, javascript_1.pattern) `jest.runAllTimers()`.configure(JEST_CONFIG),
135
+ after: (0, javascript_1.template) `vi.runAllTimers()`.configure(VITEST_CONFIG)
136
+ })),
137
+ imports: ['vi']
138
+ },
139
+ runOnlyPendingTimers: {
140
+ rule: (0, javascript_1.rewrite)(() => ({
141
+ before: (0, javascript_1.pattern) `jest.runOnlyPendingTimers()`.configure(JEST_CONFIG),
142
+ after: (0, javascript_1.template) `vi.runOnlyPendingTimers()`.configure(VITEST_CONFIG)
143
+ })),
144
+ imports: ['vi']
145
+ },
146
+ advanceTimersByTime: {
147
+ rule: (0, javascript_1.rewrite)(() => {
148
+ const args = (0, javascript_1.capture)({ variadic: true });
149
+ return {
150
+ before: (0, javascript_1.pattern) `jest.advanceTimersByTime(${args})`.configure(JEST_CONFIG),
151
+ after: (0, javascript_1.template) `vi.advanceTimersByTime(${args})`.configure(VITEST_CONFIG)
152
+ };
153
+ }),
154
+ imports: ['vi']
155
+ },
156
+ advanceTimersToNextTimer: {
157
+ rule: (0, javascript_1.rewrite)(() => {
158
+ const args = (0, javascript_1.capture)({ variadic: true });
159
+ return {
160
+ before: (0, javascript_1.pattern) `jest.advanceTimersToNextTimer(${args})`.configure(JEST_CONFIG),
161
+ after: (0, javascript_1.template) `vi.advanceTimersToNextTimer(${args})`.configure(VITEST_CONFIG)
162
+ };
163
+ }),
164
+ imports: ['vi']
165
+ },
166
+ clearAllTimers: {
167
+ rule: (0, javascript_1.rewrite)(() => ({
168
+ before: (0, javascript_1.pattern) `jest.clearAllTimers()`.configure(JEST_CONFIG),
169
+ after: (0, javascript_1.template) `vi.clearAllTimers()`.configure(VITEST_CONFIG)
170
+ })),
171
+ imports: ['vi']
172
+ },
173
+ getTimerCount: {
174
+ rule: (0, javascript_1.rewrite)(() => ({
175
+ before: (0, javascript_1.pattern) `jest.getTimerCount()`.configure(JEST_CONFIG),
176
+ after: (0, javascript_1.template) `vi.getTimerCount()`.configure(VITEST_CONFIG)
177
+ })),
178
+ imports: ['vi']
179
+ },
180
+ setSystemTime: {
181
+ rule: (0, javascript_1.rewrite)(() => {
182
+ const args = (0, javascript_1.capture)({ variadic: true });
183
+ return {
184
+ before: (0, javascript_1.pattern) `jest.setSystemTime(${args})`.configure(JEST_CONFIG),
185
+ after: (0, javascript_1.template) `vi.setSystemTime(${args})`.configure(VITEST_CONFIG)
186
+ };
187
+ }),
188
+ imports: ['vi']
189
+ },
190
+ getRealSystemTime: {
191
+ rule: (0, javascript_1.rewrite)(() => ({
192
+ before: (0, javascript_1.pattern) `jest.getRealSystemTime()`.configure(JEST_CONFIG),
193
+ after: (0, javascript_1.template) `vi.getRealSystemTime()`.configure(VITEST_CONFIG)
194
+ })),
195
+ imports: ['vi']
196
+ },
197
+ mocked: {
198
+ rule: (0, javascript_1.rewrite)(() => {
199
+ const args = (0, javascript_1.capture)({ variadic: true });
200
+ return {
201
+ before: (0, javascript_1.pattern) `jest.mocked(${args})`.configure(JEST_CONFIG),
202
+ after: (0, javascript_1.template) `vi.mocked(${args})`.configure(VITEST_CONFIG)
203
+ };
204
+ }),
205
+ imports: ['vi']
206
+ },
207
+ isMockFunction: {
208
+ rule: (0, javascript_1.rewrite)(() => {
209
+ const args = (0, javascript_1.capture)({ variadic: true });
210
+ return {
211
+ before: (0, javascript_1.pattern) `jest.isMockFunction(${args})`.configure(JEST_CONFIG),
212
+ after: (0, javascript_1.template) `vi.isMockFunction(${args})`.configure(VITEST_CONFIG)
213
+ };
214
+ }),
215
+ imports: ['vi']
216
+ },
217
+ doMock: {
218
+ rule: (0, javascript_1.rewrite)(() => {
219
+ const args = (0, javascript_1.capture)({ variadic: true });
220
+ return {
221
+ before: (0, javascript_1.pattern) `jest.doMock(${args})`.configure(JEST_CONFIG),
222
+ after: (0, javascript_1.template) `vi.doMock(${args})`.configure(VITEST_CONFIG)
223
+ };
224
+ }),
225
+ imports: ['vi']
226
+ },
227
+ doUnmock: {
228
+ rule: (0, javascript_1.rewrite)(() => {
229
+ const args = (0, javascript_1.capture)({ variadic: true });
230
+ return {
231
+ before: (0, javascript_1.pattern) `jest.doUnmock(${args})`.configure(JEST_CONFIG),
232
+ after: (0, javascript_1.template) `vi.doUnmock(${args})`.configure(VITEST_CONFIG)
233
+ };
234
+ }),
235
+ imports: ['vi']
236
+ },
237
+ requireActual: {
238
+ rule: (0, javascript_1.rewrite)(() => {
239
+ const args = (0, javascript_1.capture)({ variadic: true });
240
+ return {
241
+ before: (0, javascript_1.pattern) `jest.requireActual(${args})`.configure(JEST_CONFIG),
242
+ after: (0, javascript_1.template) `await vi.importActual(${args})`.configure(VITEST_CONFIG),
243
+ preMatch: (_node, { cursor }) => {
244
+ var _a, _b;
245
+ const enclosingMethod = cursor.firstEnclosing((n) => n.kind === java_1.J.Kind.MethodDeclaration);
246
+ if ((_a = enclosingMethod === null || enclosingMethod === void 0 ? void 0 : enclosingMethod.modifiers) === null || _a === void 0 ? void 0 : _a.some(m => m.keyword === 'async')) {
247
+ return true;
248
+ }
249
+ const enclosingArrow = cursor.firstEnclosing((n) => n.kind === javascript_1.JS.Kind.ArrowFunction);
250
+ if ((_b = enclosingArrow === null || enclosingArrow === void 0 ? void 0 : enclosingArrow.modifiers) === null || _b === void 0 ? void 0 : _b.some(m => m.keyword === 'async')) {
251
+ return true;
252
+ }
253
+ return false;
254
+ }
255
+ };
256
+ }).orElse((0, javascript_1.rewrite)(() => {
257
+ const args = (0, javascript_1.capture)({ variadic: true });
258
+ return {
259
+ before: (0, javascript_1.pattern) `jest.requireActual(${args})`.configure(JEST_CONFIG),
260
+ after: (0, javascript_1.template) `vi.importActual(${args})`.configure(VITEST_CONFIG)
261
+ };
262
+ })),
263
+ imports: ['vi']
264
+ },
265
+ setTimeout: {
266
+ rule: (0, javascript_1.rewrite)(() => {
267
+ const timeout = (0, javascript_1.capture)('timeout');
268
+ return {
269
+ before: (0, javascript_1.pattern) `jest.setTimeout(${timeout})`.configure(JEST_CONFIG),
270
+ after: (0, javascript_1.template) `vi.setConfig({ testTimeout: ${timeout} })`.configure(VITEST_CONFIG)
271
+ };
272
+ }),
273
+ imports: ['vi']
274
+ },
275
+ describe: {
276
+ rule: (0, javascript_1.rewrite)(() => {
277
+ const args = (0, javascript_1.capture)({ variadic: true });
278
+ return {
279
+ before: (0, javascript_1.pattern) `describe(${args})`.configure(JEST_CONFIG),
280
+ after: (0, javascript_1.template) `describe(${args})`.configure(VITEST_CONFIG)
281
+ };
282
+ }),
283
+ imports: ['describe']
284
+ },
285
+ it: {
286
+ rule: (0, javascript_1.rewrite)(() => {
287
+ const args = (0, javascript_1.capture)({ variadic: true });
288
+ return {
289
+ before: (0, javascript_1.pattern) `it(${args})`.configure(JEST_CONFIG),
290
+ after: (0, javascript_1.template) `it(${args})`.configure(VITEST_CONFIG)
291
+ };
292
+ }),
293
+ imports: ['it']
294
+ },
295
+ test: {
296
+ rule: (0, javascript_1.rewrite)(() => {
297
+ const args = (0, javascript_1.capture)({ variadic: true });
298
+ return {
299
+ before: (0, javascript_1.pattern) `test(${args})`.configure(JEST_CONFIG),
300
+ after: (0, javascript_1.template) `test(${args})`.configure(VITEST_CONFIG)
301
+ };
302
+ }),
303
+ imports: ['test']
304
+ },
305
+ expect: {
306
+ rule: (0, javascript_1.rewrite)(() => {
307
+ const args = (0, javascript_1.capture)({ variadic: true });
308
+ return {
309
+ before: (0, javascript_1.pattern) `expect(${args})`.configure(JEST_CONFIG),
310
+ after: (0, javascript_1.template) `expect(${args})`.configure(VITEST_CONFIG)
311
+ };
312
+ }),
313
+ imports: ['expect']
314
+ },
315
+ beforeEach: {
316
+ rule: (0, javascript_1.rewrite)(() => {
317
+ const args = (0, javascript_1.capture)({ variadic: true });
318
+ return {
319
+ before: (0, javascript_1.pattern) `beforeEach(${args})`.configure(JEST_CONFIG),
320
+ after: (0, javascript_1.template) `beforeEach(${args})`.configure(VITEST_CONFIG)
321
+ };
322
+ }),
323
+ imports: ['beforeEach']
324
+ },
325
+ afterEach: {
326
+ rule: (0, javascript_1.rewrite)(() => {
327
+ const args = (0, javascript_1.capture)({ variadic: true });
328
+ return {
329
+ before: (0, javascript_1.pattern) `afterEach(${args})`.configure(JEST_CONFIG),
330
+ after: (0, javascript_1.template) `afterEach(${args})`.configure(VITEST_CONFIG)
331
+ };
332
+ }),
333
+ imports: ['afterEach']
334
+ },
335
+ beforeAll: {
336
+ rule: (0, javascript_1.rewrite)(() => {
337
+ const args = (0, javascript_1.capture)({ variadic: true });
338
+ return {
339
+ before: (0, javascript_1.pattern) `beforeAll(${args})`.configure(JEST_CONFIG),
340
+ after: (0, javascript_1.template) `beforeAll(${args})`.configure(VITEST_CONFIG)
341
+ };
342
+ }),
343
+ imports: ['beforeAll']
344
+ },
345
+ afterAll: {
346
+ rule: (0, javascript_1.rewrite)(() => {
347
+ const args = (0, javascript_1.capture)({ variadic: true });
348
+ return {
349
+ before: (0, javascript_1.pattern) `afterAll(${args})`.configure(JEST_CONFIG),
350
+ after: (0, javascript_1.template) `afterAll(${args})`.configure(VITEST_CONFIG)
351
+ };
352
+ }),
353
+ imports: ['afterAll']
354
+ },
355
+ };
356
+ const transformationRuleKeys = new Set(Object.keys(transformationRules));
357
+ function vitestTypeConfig(vitestType) {
358
+ return {
359
+ dependencies: { 'vitest': '^2.0.0' },
360
+ context: [`import { ${vitestType} } from "vitest";`]
361
+ };
362
+ }
363
+ const typeTransformationRules = [
364
+ {
365
+ rule: (0, javascript_1.rewrite)(() => ({
366
+ before: (0, javascript_1.pattern) `jest.SpyInstance`.configure(JEST_CONFIG),
367
+ after: (0, javascript_1.template) `MockInstance`.configure(vitestTypeConfig('MockInstance'))
368
+ })),
369
+ vitestImport: 'MockInstance'
370
+ },
371
+ {
372
+ rule: (0, javascript_1.rewrite)(() => ({
373
+ before: (0, javascript_1.pattern) `jest.Mock`.configure(JEST_CONFIG),
374
+ after: (0, javascript_1.template) `Mock`.configure(vitestTypeConfig('Mock'))
375
+ })),
376
+ vitestImport: 'Mock'
377
+ },
378
+ {
379
+ rule: (0, javascript_1.rewrite)(() => ({
380
+ before: (0, javascript_1.pattern) `jest.Mocked`.configure(JEST_CONFIG),
381
+ after: (0, javascript_1.template) `Mocked`.configure(vitestTypeConfig('Mocked'))
382
+ })),
383
+ vitestImport: 'Mocked'
384
+ },
385
+ {
386
+ rule: (0, javascript_1.rewrite)(() => ({
387
+ before: (0, javascript_1.pattern) `jest.MockedFunction`.configure(JEST_CONFIG),
388
+ after: (0, javascript_1.template) `MockedFunction`.configure(vitestTypeConfig('MockedFunction'))
389
+ })),
390
+ vitestImport: 'MockedFunction'
391
+ },
392
+ {
393
+ rule: (0, javascript_1.rewrite)(() => ({
394
+ before: (0, javascript_1.pattern) `jest.MockedClass`.configure(JEST_CONFIG),
395
+ after: (0, javascript_1.template) `MockedClass`.configure(vitestTypeConfig('MockedClass'))
396
+ })),
397
+ vitestImport: 'MockedClass'
398
+ },
399
+ ];
400
+ class JestToVitestVisitor extends javascript_1.JavaScriptVisitor {
401
+ constructor() {
402
+ super(...arguments);
403
+ this.requiredImports = new Set();
404
+ this.requiredTypeImports = new Set();
405
+ }
406
+ tryTransformJestType(node) {
407
+ return __awaiter(this, void 0, void 0, function* () {
408
+ for (const typeRule of typeTransformationRules) {
409
+ const transformed = yield typeRule.rule.tryOn(this.cursor, node);
410
+ if (transformed) {
411
+ this.requiredTypeImports.add(typeRule.vitestImport);
412
+ return transformed;
413
+ }
414
+ }
415
+ return undefined;
416
+ });
417
+ }
418
+ visitFieldAccess(fieldAccess, ctx) {
419
+ const _super = Object.create(null, {
420
+ visitFieldAccess: { get: () => super.visitFieldAccess }
421
+ });
422
+ return __awaiter(this, void 0, void 0, function* () {
423
+ var _a;
424
+ fieldAccess = (yield _super.visitFieldAccess.call(this, fieldAccess, ctx));
425
+ if (fieldAccess.target.kind === java_1.J.Kind.Identifier &&
426
+ fieldAccess.target.simpleName === 'jest') {
427
+ return (_a = yield this.tryTransformJestType(fieldAccess)) !== null && _a !== void 0 ? _a : fieldAccess;
428
+ }
429
+ return fieldAccess;
430
+ });
431
+ }
432
+ visitParameterizedType(parameterizedType, ctx) {
433
+ const _super = Object.create(null, {
434
+ visitParameterizedType: { get: () => super.visitParameterizedType }
435
+ });
436
+ return __awaiter(this, void 0, void 0, function* () {
437
+ parameterizedType = (yield _super.visitParameterizedType.call(this, parameterizedType, ctx));
438
+ if (parameterizedType.class.kind === java_1.J.Kind.FieldAccess) {
439
+ const fieldAccess = parameterizedType.class;
440
+ if (fieldAccess.target.kind === java_1.J.Kind.Identifier &&
441
+ fieldAccess.target.simpleName === 'jest') {
442
+ const transformed = yield this.tryTransformJestType(fieldAccess);
443
+ if (transformed) {
444
+ const updated = Object.assign(Object.assign({}, parameterizedType), { class: transformed });
445
+ return updated;
446
+ }
447
+ }
448
+ }
449
+ return parameterizedType;
450
+ });
451
+ }
452
+ visitMethodInvocation(method, ctx) {
453
+ const _super = Object.create(null, {
454
+ visitMethodInvocation: { get: () => super.visitMethodInvocation }
455
+ });
456
+ return __awaiter(this, void 0, void 0, function* () {
457
+ method = (yield _super.visitMethodInvocation.call(this, method, ctx));
458
+ const simpleName = method.name.simpleName;
459
+ if (transformationRuleKeys.has(simpleName)) {
460
+ const transformation = transformationRules[simpleName];
461
+ const transformed = yield transformation.rule.tryOn(this.cursor, method);
462
+ if (transformed) {
463
+ for (const imp of transformation.imports) {
464
+ this.requiredImports.add(imp);
465
+ }
466
+ return transformed;
467
+ }
468
+ }
469
+ return method;
470
+ });
471
+ }
472
+ visitJsCompilationUnit(cu, ctx) {
473
+ const _super = Object.create(null, {
474
+ visitJsCompilationUnit: { get: () => super.visitJsCompilationUnit }
475
+ });
476
+ return __awaiter(this, void 0, void 0, function* () {
477
+ this.requiredImports.clear();
478
+ this.requiredTypeImports.clear();
479
+ (0, javascript_1.maybeRemoveImport)(this, 'jest');
480
+ (0, javascript_1.maybeRemoveImport)(this, '@jest/globals');
481
+ cu = (yield _super.visitJsCompilationUnit.call(this, cu, ctx));
482
+ for (const member of this.requiredImports) {
483
+ (0, javascript_1.maybeAddImport)(this, { module: 'vitest', member });
484
+ }
485
+ for (const member of this.requiredTypeImports) {
486
+ (0, javascript_1.maybeAddImport)(this, { module: 'vitest', member, onlyIfReferenced: false });
487
+ }
488
+ return cu;
489
+ });
490
+ }
491
+ }
492
+ //# sourceMappingURL=jest-to-vitest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jest-to-vitest.js","sourceRoot":"","sources":["../src/jest-to-vitest.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@openrewrite/recipes-testing",
3
+ "version": "0.1.0-20260313-092538",
4
+ "license": "Moderne Source Available License",
5
+ "description": "OpenRewrite recipes for JavaScript/TypeScript testing frameworks.",
6
+ "homepage": "https://github.com/moderneinc/recipes-javascript",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist/**",
11
+ "src/**"
12
+ ],
13
+ "exports": {
14
+ ".": "./dist/index.js"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "build": "rm -rf ./dist tsconfig.build.tsbuildinfo && tsc --build tsconfig.build.json",
21
+ "dev": "tsc --watch -p tsconfig.json",
22
+ "test": "npm run build && jest",
23
+ "ci:test": "jest"
24
+ },
25
+ "dependencies": {
26
+ "@openrewrite/rewrite": "next",
27
+ "immer": "^10.1.1"
28
+ },
29
+ "devDependencies": {
30
+ "@types/jest": "^29.5.13",
31
+ "@types/node": "^22.5.4",
32
+ "jest": "^29.7.0",
33
+ "jest-junit": "^16.0.0",
34
+ "tmp-promise": "^3.0.3",
35
+ "ts-jest": "^29.2.5",
36
+ "ts-node": "^10.9.2",
37
+ "typescript": "^5.6.2"
38
+ }
39
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ import {CategoryDescriptor, RecipeMarketplace} from "@openrewrite/rewrite";
2
+ import {JestToVitest} from "./jest-to-vitest";
3
+
4
+ export const Testing: CategoryDescriptor[] = [{displayName: "Testing"}];
5
+ export const Migrate: CategoryDescriptor[] = [...Testing, {displayName: "Migrate"}];
6
+
7
+ export async function activate(marketplace: RecipeMarketplace): Promise<void> {
8
+ await marketplace.install(JestToVitest, Migrate);
9
+ }
10
+
11
+ export {JestToVitest} from "./jest-to-vitest";
@@ -0,0 +1,557 @@
1
+ import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
2
+ import {
3
+ capture,
4
+ JavaScriptVisitor,
5
+ JS,
6
+ maybeAddImport,
7
+ maybeRemoveImport,
8
+ pattern,
9
+ rewrite,
10
+ template
11
+ } from "@openrewrite/rewrite/javascript";
12
+ import {J} from "@openrewrite/rewrite/java";
13
+
14
+ // Configuration for Jest patterns - for type attribution
15
+ // Note: Jest globals are available without imports, so we only specify dependencies
16
+ const JEST_CONFIG = {
17
+ dependencies: {
18
+ '@types/jest': '^29.5.13'
19
+ },
20
+ };
21
+
22
+ // Configuration for Vitest templates - for type attribution
23
+ // Note: Vitest requires explicit imports
24
+ const VITEST_CONFIG = {
25
+ dependencies: {
26
+ 'vitest': '^2.0.0'
27
+ },
28
+ context: ['import { vi } from "vitest";',]
29
+ };
30
+
31
+ /**
32
+ * Migrates Jest test files to Vitest.
33
+ *
34
+ * This recipe handles:
35
+ * - Renaming jest imports to vitest
36
+ * - Transforming Jest global functions (describe, it, test, expect, etc.) to use Vitest
37
+ * - Converting Jest mock patterns to Vitest equivalents
38
+ * - Updating jest.fn(), jest.spyOn(), etc. to vi.fn(), vi.spyOn()
39
+ * - Transforming jest.mock() to vi.mock()
40
+ * - Migrating Jest type references (jest.SpyInstance, jest.Mock, jest.Mocked, etc.) to Vitest equivalents
41
+ */
42
+ export class JestToVitest extends Recipe {
43
+ name = "org.openrewrite.javascript.testing.JestToVitest";
44
+ displayName = "Migrate Jest to Vitest";
45
+ description = "Migrates Jest test files to use Vitest as the testing framework. " +
46
+ "This includes updating imports, transforming global functions, and converting " +
47
+ "Jest-specific mocking patterns to Vitest equivalents.";
48
+
49
+ async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
50
+ return new JestToVitestVisitor();
51
+ }
52
+ }
53
+
54
+ /**
55
+ * A transformation rule with its associated import requirements
56
+ */
57
+ interface TransformationRule {
58
+ rule: ReturnType<typeof rewrite>;
59
+ imports: string[]; // Vitest members to import when this rule matches
60
+ }
61
+
62
+ // Transformation rules organized by the method/function name being invoked
63
+ // The key is the simple name of the method (e.g., 'fn' for jest.fn(), 'describe' for describe())
64
+ const transformationRules: Record<string, TransformationRule> = {
65
+ // Jest object method transformations (jest.X() -> vi.X())
66
+ fn: {
67
+ rule: rewrite(() => {
68
+ const args = capture({variadic: true});
69
+ return {
70
+ before: pattern`jest.fn(${args})`.configure(JEST_CONFIG),
71
+ after: template`vi.fn(${args})`.configure(VITEST_CONFIG)
72
+ };
73
+ }),
74
+ imports: ['vi']
75
+ },
76
+ spyOn: {
77
+ rule: rewrite(() => {
78
+ const args = capture({variadic: true});
79
+ return {
80
+ before: pattern`jest.spyOn(${args})`.configure(JEST_CONFIG),
81
+ after: template`vi.spyOn(${args})`.configure(VITEST_CONFIG)
82
+ };
83
+ }),
84
+ imports: ['vi']
85
+ },
86
+ mock: {
87
+ rule: rewrite(() => {
88
+ const path = capture('path');
89
+ const literalBody = capture<J.Literal>({
90
+ name: 'literalBody',
91
+ constraint: (node) => node.kind === J.Kind.Literal
92
+ });
93
+ // Match mock with arrow factory that returns a literal value
94
+ // jest.mock('./path', () => 'value') -> vi.mock('./path', () => ({ default: 'value' }))
95
+ return {
96
+ before: pattern`jest.mock(${path}, () => ${literalBody})`.configure(JEST_CONFIG),
97
+ after: template`vi.mock(${path}, () => ({ default: ${literalBody} }))`.configure(VITEST_CONFIG)
98
+ };
99
+ }).orElse(rewrite(() => {
100
+ // Fallback: general mock transformation for other cases (including object literals)
101
+ const args = capture({variadic: true});
102
+ return {
103
+ before: pattern`jest.mock(${args})`.configure(JEST_CONFIG),
104
+ after: template`vi.mock(${args})`.configure(VITEST_CONFIG)
105
+ };
106
+ })),
107
+ imports: ['vi']
108
+ },
109
+ unmock: {
110
+ rule: rewrite(() => {
111
+ const args = capture({variadic: true});
112
+ return {
113
+ before: pattern`jest.unmock(${args})`.configure(JEST_CONFIG),
114
+ after: template`vi.unmock(${args})`.configure(VITEST_CONFIG)
115
+ };
116
+ }),
117
+ imports: ['vi']
118
+ },
119
+ clearAllMocks: {
120
+ rule: rewrite(() => ({
121
+ before: pattern`jest.clearAllMocks()`.configure(JEST_CONFIG),
122
+ after: template`vi.clearAllMocks()`.configure(VITEST_CONFIG)
123
+ })),
124
+ imports: ['vi']
125
+ },
126
+ resetAllMocks: {
127
+ rule: rewrite(() => ({
128
+ before: pattern`jest.resetAllMocks()`.configure(JEST_CONFIG),
129
+ after: template`vi.resetAllMocks()`.configure(VITEST_CONFIG)
130
+ })),
131
+ imports: ['vi']
132
+ },
133
+ restoreAllMocks: {
134
+ rule: rewrite(() => ({
135
+ before: pattern`jest.restoreAllMocks()`.configure(JEST_CONFIG),
136
+ after: template`vi.restoreAllMocks()`.configure(VITEST_CONFIG)
137
+ })),
138
+ imports: ['vi']
139
+ },
140
+ useFakeTimers: {
141
+ rule: rewrite(() => {
142
+ const args = capture({variadic: true});
143
+ return {
144
+ before: pattern`jest.useFakeTimers(${args})`.configure(JEST_CONFIG),
145
+ after: template`vi.useFakeTimers(${args})`.configure(VITEST_CONFIG)
146
+ };
147
+ }),
148
+ imports: ['vi']
149
+ },
150
+ useRealTimers: {
151
+ rule: rewrite(() => ({
152
+ before: pattern`jest.useRealTimers()`.configure(JEST_CONFIG),
153
+ after: template`vi.useRealTimers()`.configure(VITEST_CONFIG)
154
+ })),
155
+ imports: ['vi']
156
+ },
157
+ runAllTimers: {
158
+ rule: rewrite(() => ({
159
+ before: pattern`jest.runAllTimers()`.configure(JEST_CONFIG),
160
+ after: template`vi.runAllTimers()`.configure(VITEST_CONFIG)
161
+ })),
162
+ imports: ['vi']
163
+ },
164
+ runOnlyPendingTimers: {
165
+ rule: rewrite(() => ({
166
+ before: pattern`jest.runOnlyPendingTimers()`.configure(JEST_CONFIG),
167
+ after: template`vi.runOnlyPendingTimers()`.configure(VITEST_CONFIG)
168
+ })),
169
+ imports: ['vi']
170
+ },
171
+ advanceTimersByTime: {
172
+ rule: rewrite(() => {
173
+ const args = capture({variadic: true});
174
+ return {
175
+ before: pattern`jest.advanceTimersByTime(${args})`.configure(JEST_CONFIG),
176
+ after: template`vi.advanceTimersByTime(${args})`.configure(VITEST_CONFIG)
177
+ };
178
+ }),
179
+ imports: ['vi']
180
+ },
181
+ advanceTimersToNextTimer: {
182
+ rule: rewrite(() => {
183
+ const args = capture({variadic: true});
184
+ return {
185
+ before: pattern`jest.advanceTimersToNextTimer(${args})`.configure(JEST_CONFIG),
186
+ after: template`vi.advanceTimersToNextTimer(${args})`.configure(VITEST_CONFIG)
187
+ };
188
+ }),
189
+ imports: ['vi']
190
+ },
191
+ clearAllTimers: {
192
+ rule: rewrite(() => ({
193
+ before: pattern`jest.clearAllTimers()`.configure(JEST_CONFIG),
194
+ after: template`vi.clearAllTimers()`.configure(VITEST_CONFIG)
195
+ })),
196
+ imports: ['vi']
197
+ },
198
+ getTimerCount: {
199
+ rule: rewrite(() => ({
200
+ before: pattern`jest.getTimerCount()`.configure(JEST_CONFIG),
201
+ after: template`vi.getTimerCount()`.configure(VITEST_CONFIG)
202
+ })),
203
+ imports: ['vi']
204
+ },
205
+ setSystemTime: {
206
+ rule: rewrite(() => {
207
+ const args = capture({variadic: true});
208
+ return {
209
+ before: pattern`jest.setSystemTime(${args})`.configure(JEST_CONFIG),
210
+ after: template`vi.setSystemTime(${args})`.configure(VITEST_CONFIG)
211
+ };
212
+ }),
213
+ imports: ['vi']
214
+ },
215
+ getRealSystemTime: {
216
+ rule: rewrite(() => ({
217
+ before: pattern`jest.getRealSystemTime()`.configure(JEST_CONFIG),
218
+ after: template`vi.getRealSystemTime()`.configure(VITEST_CONFIG)
219
+ })),
220
+ imports: ['vi']
221
+ },
222
+ mocked: {
223
+ rule: rewrite(() => {
224
+ const args = capture({variadic: true});
225
+ return {
226
+ before: pattern`jest.mocked(${args})`.configure(JEST_CONFIG),
227
+ after: template`vi.mocked(${args})`.configure(VITEST_CONFIG)
228
+ };
229
+ }),
230
+ imports: ['vi']
231
+ },
232
+ isMockFunction: {
233
+ rule: rewrite(() => {
234
+ const args = capture({variadic: true});
235
+ return {
236
+ before: pattern`jest.isMockFunction(${args})`.configure(JEST_CONFIG),
237
+ after: template`vi.isMockFunction(${args})`.configure(VITEST_CONFIG)
238
+ };
239
+ }),
240
+ imports: ['vi']
241
+ },
242
+ doMock: {
243
+ rule: rewrite(() => {
244
+ const args = capture({variadic: true});
245
+ return {
246
+ before: pattern`jest.doMock(${args})`.configure(JEST_CONFIG),
247
+ after: template`vi.doMock(${args})`.configure(VITEST_CONFIG)
248
+ };
249
+ }),
250
+ imports: ['vi']
251
+ },
252
+ doUnmock: {
253
+ rule: rewrite(() => {
254
+ const args = capture({variadic: true});
255
+ return {
256
+ before: pattern`jest.doUnmock(${args})`.configure(JEST_CONFIG),
257
+ after: template`vi.doUnmock(${args})`.configure(VITEST_CONFIG)
258
+ };
259
+ }),
260
+ imports: ['vi']
261
+ },
262
+ // vi.importActual() is async unlike jest.requireActual()
263
+ // When in async context, we add await; otherwise just rename and let developer handle it
264
+ requireActual: {
265
+ rule: rewrite(() => {
266
+ const args = capture({variadic: true});
267
+ return {
268
+ before: pattern`jest.requireActual(${args})`.configure(JEST_CONFIG),
269
+ after: template`await vi.importActual(${args})`.configure(VITEST_CONFIG),
270
+ preMatch: (_node, {cursor}) => {
271
+ // Check if we're inside an async function or async arrow function
272
+ const enclosingMethod = cursor.firstEnclosing(
273
+ (n): n is J.MethodDeclaration => n.kind === J.Kind.MethodDeclaration
274
+ );
275
+ if (enclosingMethod?.modifiers?.some(m => m.keyword === 'async')) {
276
+ return true;
277
+ }
278
+ const enclosingArrow = cursor.firstEnclosing(
279
+ (n): n is JS.ArrowFunction => n.kind === JS.Kind.ArrowFunction
280
+ );
281
+ if (enclosingArrow?.modifiers?.some(m => m.keyword === 'async')) {
282
+ return true;
283
+ }
284
+ return false;
285
+ }
286
+ };
287
+ }).orElse(rewrite(() => {
288
+ // Fallback: not in async context, just rename without await
289
+ const args = capture({variadic: true});
290
+ return {
291
+ before: pattern`jest.requireActual(${args})`.configure(JEST_CONFIG),
292
+ after: template`vi.importActual(${args})`.configure(VITEST_CONFIG)
293
+ };
294
+ })),
295
+ imports: ['vi']
296
+ },
297
+ setTimeout: {
298
+ rule: rewrite(() => {
299
+ const timeout = capture('timeout');
300
+ return {
301
+ before: pattern`jest.setTimeout(${timeout})`.configure(JEST_CONFIG),
302
+ after: template`vi.setConfig({ testTimeout: ${timeout} })`.configure(VITEST_CONFIG)
303
+ };
304
+ }),
305
+ imports: ['vi']
306
+ },
307
+
308
+ // Jest global function transformations (re-attribute types from Jest to Vitest)
309
+ describe: {
310
+ rule: rewrite(() => {
311
+ const args = capture({variadic: true});
312
+ return {
313
+ before: pattern`describe(${args})`.configure(JEST_CONFIG),
314
+ after: template`describe(${args})`.configure(VITEST_CONFIG)
315
+ };
316
+ }),
317
+ imports: ['describe']
318
+ },
319
+ it: {
320
+ rule: rewrite(() => {
321
+ const args = capture({variadic: true});
322
+ return {
323
+ before: pattern`it(${args})`.configure(JEST_CONFIG),
324
+ after: template`it(${args})`.configure(VITEST_CONFIG)
325
+ };
326
+ }),
327
+ imports: ['it']
328
+ },
329
+ test: {
330
+ rule: rewrite(() => {
331
+ const args = capture({variadic: true});
332
+ return {
333
+ before: pattern`test(${args})`.configure(JEST_CONFIG),
334
+ after: template`test(${args})`.configure(VITEST_CONFIG)
335
+ };
336
+ }),
337
+ imports: ['test']
338
+ },
339
+ expect: {
340
+ rule: rewrite(() => {
341
+ const args = capture({variadic: true});
342
+ return {
343
+ before: pattern`expect(${args})`.configure(JEST_CONFIG),
344
+ after: template`expect(${args})`.configure(VITEST_CONFIG)
345
+ };
346
+ }),
347
+ imports: ['expect']
348
+ },
349
+ beforeEach: {
350
+ rule: rewrite(() => {
351
+ const args = capture({variadic: true});
352
+ return {
353
+ before: pattern`beforeEach(${args})`.configure(JEST_CONFIG),
354
+ after: template`beforeEach(${args})`.configure(VITEST_CONFIG)
355
+ };
356
+ }),
357
+ imports: ['beforeEach']
358
+ },
359
+ afterEach: {
360
+ rule: rewrite(() => {
361
+ const args = capture({variadic: true});
362
+ return {
363
+ before: pattern`afterEach(${args})`.configure(JEST_CONFIG),
364
+ after: template`afterEach(${args})`.configure(VITEST_CONFIG)
365
+ };
366
+ }),
367
+ imports: ['afterEach']
368
+ },
369
+ beforeAll: {
370
+ rule: rewrite(() => {
371
+ const args = capture({variadic: true});
372
+ return {
373
+ before: pattern`beforeAll(${args})`.configure(JEST_CONFIG),
374
+ after: template`beforeAll(${args})`.configure(VITEST_CONFIG)
375
+ };
376
+ }),
377
+ imports: ['beforeAll']
378
+ },
379
+ afterAll: {
380
+ rule: rewrite(() => {
381
+ const args = capture({variadic: true});
382
+ return {
383
+ before: pattern`afterAll(${args})`.configure(JEST_CONFIG),
384
+ after: template`afterAll(${args})`.configure(VITEST_CONFIG)
385
+ };
386
+ }),
387
+ imports: ['afterAll']
388
+ },
389
+ };
390
+
391
+ // Pre-compute the set of valid transformation rule keys to avoid prototype chain issues
392
+ const transformationRuleKeys = new Set(Object.keys(transformationRules));
393
+
394
+ // Helper to create a Vitest config with the right import context for a given type
395
+ function vitestTypeConfig(vitestType: string) {
396
+ return {
397
+ dependencies: {'vitest': '^2.0.0'},
398
+ context: [`import { ${vitestType} } from "vitest";`]
399
+ };
400
+ }
401
+
402
+ // Jest type reference transformation rules (jest.X → VitestType)
403
+ // These handle type annotations like `let spy: jest.SpyInstance`
404
+ interface TypeTransformationRule {
405
+ rule: ReturnType<typeof rewrite>;
406
+ vitestImport: string; // The vitest type to import
407
+ }
408
+
409
+ const typeTransformationRules: TypeTransformationRule[] = [
410
+ {
411
+ rule: rewrite(() => ({
412
+ before: pattern`jest.SpyInstance`.configure(JEST_CONFIG),
413
+ after: template`MockInstance`.configure(vitestTypeConfig('MockInstance'))
414
+ })),
415
+ vitestImport: 'MockInstance'
416
+ },
417
+ {
418
+ rule: rewrite(() => ({
419
+ before: pattern`jest.Mock`.configure(JEST_CONFIG),
420
+ after: template`Mock`.configure(vitestTypeConfig('Mock'))
421
+ })),
422
+ vitestImport: 'Mock'
423
+ },
424
+ {
425
+ rule: rewrite(() => ({
426
+ before: pattern`jest.Mocked`.configure(JEST_CONFIG),
427
+ after: template`Mocked`.configure(vitestTypeConfig('Mocked'))
428
+ })),
429
+ vitestImport: 'Mocked'
430
+ },
431
+ {
432
+ rule: rewrite(() => ({
433
+ before: pattern`jest.MockedFunction`.configure(JEST_CONFIG),
434
+ after: template`MockedFunction`.configure(vitestTypeConfig('MockedFunction'))
435
+ })),
436
+ vitestImport: 'MockedFunction'
437
+ },
438
+ {
439
+ rule: rewrite(() => ({
440
+ before: pattern`jest.MockedClass`.configure(JEST_CONFIG),
441
+ after: template`MockedClass`.configure(vitestTypeConfig('MockedClass'))
442
+ })),
443
+ vitestImport: 'MockedClass'
444
+ },
445
+ ];
446
+
447
+ class JestToVitestVisitor extends JavaScriptVisitor<ExecutionContext> {
448
+ // Track which imports are needed based on transformations made
449
+ private requiredImports = new Set<string>();
450
+ // Track type imports separately (need onlyIfReferenced: false since type attribution may differ)
451
+ private requiredTypeImports = new Set<string>();
452
+
453
+ private async tryTransformJestType(node: J): Promise<J | undefined> {
454
+ for (const typeRule of typeTransformationRules) {
455
+ const transformed = await typeRule.rule.tryOn(this.cursor, node);
456
+ if (transformed) {
457
+ this.requiredTypeImports.add(typeRule.vitestImport);
458
+ return transformed;
459
+ }
460
+ }
461
+ return undefined;
462
+ }
463
+
464
+ protected async visitFieldAccess(
465
+ fieldAccess: J.FieldAccess,
466
+ ctx: ExecutionContext
467
+ ): Promise<J | undefined> {
468
+ fieldAccess = await super.visitFieldAccess(fieldAccess, ctx) as J.FieldAccess;
469
+
470
+ // Only try type transformations on jest.* field accesses
471
+ if (fieldAccess.target.kind === J.Kind.Identifier &&
472
+ (fieldAccess.target as J.Identifier).simpleName === 'jest') {
473
+ return await this.tryTransformJestType(fieldAccess) ?? fieldAccess;
474
+ }
475
+
476
+ return fieldAccess;
477
+ }
478
+
479
+ protected async visitParameterizedType(
480
+ parameterizedType: J.ParameterizedType,
481
+ ctx: ExecutionContext
482
+ ): Promise<J | undefined> {
483
+ parameterizedType = await super.visitParameterizedType(parameterizedType, ctx) as J.ParameterizedType;
484
+
485
+ // Check if the class name part is a jest type (e.g., jest.Mocked in jest.Mocked<T>)
486
+ if (parameterizedType.class.kind === J.Kind.FieldAccess) {
487
+ const fieldAccess = parameterizedType.class as J.FieldAccess;
488
+ if (fieldAccess.target.kind === J.Kind.Identifier &&
489
+ (fieldAccess.target as J.Identifier).simpleName === 'jest') {
490
+ const transformed = await this.tryTransformJestType(fieldAccess);
491
+ if (transformed) {
492
+ const updated: J.ParameterizedType = {
493
+ ...parameterizedType as J.ParameterizedType,
494
+ class: transformed as J.ParameterizedType['class']
495
+ };
496
+ return updated;
497
+ }
498
+ }
499
+ }
500
+
501
+ return parameterizedType;
502
+ }
503
+
504
+ protected async visitMethodInvocation(
505
+ method: J.MethodInvocation,
506
+ ctx: ExecutionContext
507
+ ): Promise<J | undefined> {
508
+ // Visit children first
509
+ method = await super.visitMethodInvocation(method, ctx) as J.MethodInvocation;
510
+
511
+ // Get the simple name of the method being invoked
512
+ const simpleName = method.name.simpleName;
513
+
514
+ // Look up the transformation rule by name (using Set to avoid prototype chain issues)
515
+ if (transformationRuleKeys.has(simpleName)) {
516
+ const transformation = transformationRules[simpleName as keyof typeof transformationRules];
517
+ const transformed = await transformation.rule.tryOn(this.cursor, method);
518
+ if (transformed) {
519
+ // Track the imports needed for this transformation
520
+ for (const imp of transformation.imports) {
521
+ this.requiredImports.add(imp);
522
+ }
523
+ return transformed;
524
+ }
525
+ }
526
+
527
+ return method;
528
+ }
529
+
530
+ protected async visitJsCompilationUnit(
531
+ cu: JS.CompilationUnit,
532
+ ctx: ExecutionContext
533
+ ): Promise<J | undefined> {
534
+ // Reset state for this file
535
+ this.requiredImports.clear();
536
+ this.requiredTypeImports.clear();
537
+
538
+ // Remove Jest imports
539
+ maybeRemoveImport(this, 'jest');
540
+ maybeRemoveImport(this, '@jest/globals');
541
+
542
+ // Visit the tree to collect required imports
543
+ cu = await super.visitJsCompilationUnit(cu, ctx) as JS.CompilationUnit;
544
+
545
+ // Add the required Vitest imports
546
+ for (const member of this.requiredImports) {
547
+ maybeAddImport(this, {module: 'vitest', member});
548
+ }
549
+ // Type imports use onlyIfReferenced: false because the type attribution
550
+ // on the replacement identifier may not match what AddImport expects
551
+ for (const member of this.requiredTypeImports) {
552
+ maybeAddImport(this, {module: 'vitest', member, onlyIfReferenced: false});
553
+ }
554
+
555
+ return cu;
556
+ }
557
+ }