{"_id":"@bupkis/from-jest","_rev":"6-b02feb6713c4c6abfeba1857e75adf98","name":"@bupkis/from-jest","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.1":{"name":"@bupkis/from-jest","version":"0.1.1","keywords":["bupkis","jest","codemod","migration","assertions","vitest"],"author":{"name":"Christopher Hiller","email":"boneskull@boneskull.com"},"license":"BlueOak-1.0.0","_id":"@bupkis/from-jest@0.1.1","maintainers":[{"name":"boneskull","email":"boneskull@boneskull.com"}],"homepage":"https://bupkis.zip","bugs":{"url":"https://github.com/boneskull/bupkis/issues"},"bin":{"bupkis-from-jest":"dist/cli.js"},"dist":{"shasum":"cc6323c53dc4c328fcabce5b91f9a98b4c276fe4","tarball":"https://registry.npmjs.org/@bupkis/from-jest/-/from-jest-0.1.1.tgz","fileCount":54,"integrity":"sha512-AepqTjOqika0DduwcXnaZdXyT3D7fyJxw8UvstaN9O4fKS+Yz8NIrvQJAvoQ6nU3yeOHVZk4+FtpOhcqGFqDng==","signatures":[{"sig":"MEYCIQCULt3XN7Dz2KUV6tGRB6uB/3w4U64dZnns1db8B6ntUgIhAOyggyDH9eTOxg6d50ta1P11AiBu19jytiVfKYkEd8uc","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116669},"type":"module","engines":{"node":"^20.19.0 || ^22.12.0 || >=23"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"ca2eb98497de0200e5861cb8b7de9d48ca26439d","scripts":{"test":"npm run test:base -- \"test/*/*.test.ts\"","build":"tsc","test:dev":"npm run test:base -- --watch \"test/*/*.test.ts\"","test:base":"node --test --test-reporter=spec --import tsx","test:node20":"npm run test:base -- test/*.test.ts","example:jest":"cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --config examples/jest.config.js","example:vitest":"vitest run examples/vitest-example.test.ts examples/vitest-example.transformed.test.ts","example:codemod":"npx tsx src/cli.ts --dry-run examples/jest-example.test.ts"},"_npmUser":{"name":"boneskull","email":"boneskull@boneskull.com"},"prettier":{"tsdoc":true,"plugins":["prettier-plugin-jsdoc","prettier-plugin-pkg","prettier-plugin-sort-json"],"singleQuote":true,"jsdocPreferCodeFences":true,"jsdocCommentLineStrategy":"keep"},"repository":{"url":"git+https://github.com/boneskull/bupkis.git","type":"git","directory":"packages/from-jest"},"_npmVersion":"11.6.2","description":"Migrate Jest and Vitest assertions to bupkis","directories":{},"_nodeVersion":"24.12.0","dependencies":{"ts-morph":"^25.0.0","@boneskull/bargs":"4.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"30.2.0","vitest":"4.0.16","ts-jest":"29.4.6","cross-env":"10.1.0","@jest/globals":"30.2.0"},"_npmOperationalInternal":{"tmp":"tmp/from-jest_0.1.1_1768432862249_0.7579230768254552","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bupkis/from-jest","version":"0.2.0","keywords":["bupkis","jest","codemod","migration","assertions","vitest"],"author":{"name":"Christopher Hiller","email":"boneskull@boneskull.com"},"license":"BlueOak-1.0.0","_id":"@bupkis/from-jest@0.2.0","maintainers":[{"name":"boneskull","email":"boneskull@boneskull.com"}],"homepage":"https://bupkis.zip","bugs":{"url":"https://github.com/boneskull/bupkis/issues"},"bin":{"bupkis-from-jest":"dist/cli.js"},"dist":{"shasum":"0bdc129ff3eb27d12abfa85086bad2ab23a1626d","tarball":"https://registry.npmjs.org/@bupkis/from-jest/-/from-jest-0.2.0.tgz","fileCount":59,"integrity":"sha512-VUKPxoguOykLXbdR+CB0RcTjj875TWFZ9sdYPrguZF8B7uV+vJVDSX65k6bDz59YsmciYibDE+5ehXd2zFXotg==","signatures":[{"sig":"MEYCIQCiv9/QbiQNFTZz27t5lPawVPMxcxTfmXTGHNAR7Hz4XQIhAM9jkDfeG4Djzq3H+8AxKW8+NRDQ4yCGPRgVd/dDI/sd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":161902},"type":"module","engines":{"node":"^20.19.0 || ^22.12.0 || >=23"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"f09ff1cfb21ceb03dee850971611a3d1e98086b4","scripts":{"test":"npm run test:base -- \"test/*/*.test.ts\"","build":"tsc","test:dev":"npm run test:base -- --watch \"test/*/*.test.ts\"","test:base":"node --test --test-reporter=spec --import tsx","test:node20":"npm run test:base -- test/*.test.ts","example:jest":"cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --config examples/jest.config.js","example:vitest":"vitest run examples/vitest-example.test.ts examples/vitest-example.transformed.test.ts","example:codemod":"npx tsx src/cli.ts --dry-run examples/jest-example.test.ts"},"_npmUser":{"name":"boneskull","email":"boneskull@boneskull.com"},"prettier":{"tsdoc":true,"plugins":["prettier-plugin-jsdoc","prettier-plugin-pkg"],"singleQuote":true,"jsdocPreferCodeFences":true,"jsdocCommentLineStrategy":"keep"},"repository":{"url":"git+https://github.com/boneskull/bupkis.git","type":"git","directory":"packages/from-jest"},"_npmVersion":"11.6.2","description":"Migrate Jest and Vitest assertions to bupkis","directories":{},"_nodeVersion":"24.12.0","dependencies":{"ts-morph":"^25.0.0","@boneskull/bargs":"4.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"30.2.0","vitest":"4.0.16","ts-jest":"29.4.6","cross-env":"10.1.0","@jest/globals":"30.2.0"},"_npmOperationalInternal":{"tmp":"tmp/from-jest_0.2.0_1768604260380_0.36258743481217537","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bupkis/from-jest","version":"0.3.0","keywords":["bupkis","jest","codemod","migration","assertions","vitest"],"author":{"name":"Christopher Hiller","email":"boneskull@boneskull.com"},"license":"BlueOak-1.0.0","_id":"@bupkis/from-jest@0.3.0","maintainers":[{"name":"boneskull","email":"boneskull@boneskull.com"}],"homepage":"https://bupkis.zip","bugs":{"url":"https://github.com/boneskull/bupkis/issues"},"bin":{"bupkis-from-jest":"dist/cli.js"},"dist":{"shasum":"54136a7f9b885388f61d4588ad7fb9cfad3066b9","tarball":"https://registry.npmjs.org/@bupkis/from-jest/-/from-jest-0.3.0.tgz","fileCount":59,"integrity":"sha512-XkFKih+kZQ2LK7IgGRCrTa8qxTqM9rA7LDvESuYjOba4lDgA4QzNPhEIJZalBBHWwy6sYlQWYQow3KoQSO6MBA==","signatures":[{"sig":"MEUCIQC7YKodVw3+L8TYFlPlr+BgOH5M5DS+v5OjneoJqSutrwIgXbiafHirEtwIuZRrfKOvGhugsDJsIsHlyswO7gUGyok=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":191447},"type":"module","engines":{"node":"^20.19.0 || ^22.12.0 || >=23"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"11c3b4a75d930898188835ece9f6f39b6d8eaf38","scripts":{"test":"npm run test:base -- \"test/*/*.test.ts\"","build":"tsc","test:dev":"npm run test:base -- --watch \"test/*/*.test.ts\"","test:base":"node --test --test-reporter=spec --import tsx","test:node20":"npm run test:base -- test/*.test.ts","example:jest":"cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --config examples/jest.config.js","example:vitest":"vitest run examples/vitest-example.test.ts examples/vitest-example.transformed.test.ts","example:codemod":"npx tsx src/cli.ts --dry-run examples/jest-example.test.ts"},"_npmUser":{"name":"boneskull","email":"boneskull@boneskull.com"},"prettier":{"tsdoc":true,"plugins":["prettier-plugin-jsdoc","prettier-plugin-pkg"],"singleQuote":true,"jsdocPreferCodeFences":true,"jsdocCommentLineStrategy":"keep"},"repository":{"url":"git+https://github.com/boneskull/bupkis.git","type":"git","directory":"packages/from-jest"},"_npmVersion":"11.6.2","description":"Migrate Jest and Vitest assertions to bupkis","directories":{},"_nodeVersion":"24.12.0","dependencies":{"ts-morph":"^25.0.0","@boneskull/bargs":"4.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"30.2.0","vitest":"4.0.16","ts-jest":"29.4.6","cross-env":"10.1.0","@jest/globals":"30.2.0"},"_npmOperationalInternal":{"tmp":"tmp/from-jest_0.3.0_1769896688946_0.2907437995150042","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@bupkis/from-jest","version":"0.3.2","keywords":["bupkis","jest","codemod","migration","assertions","vitest"],"author":{"name":"Christopher Hiller","email":"boneskull@boneskull.com"},"license":"BlueOak-1.0.0","_id":"@bupkis/from-jest@0.3.2","maintainers":[{"name":"boneskull","email":"boneskull@boneskull.com"}],"homepage":"https://bupkis.zip","bugs":{"url":"https://github.com/boneskull/bupkis/issues"},"bin":{"bupkis-from-jest":"dist/cli.js"},"dist":{"shasum":"35b2414b09c1d226e953be4a0a17a5c49d6c917f","tarball":"https://registry.npmjs.org/@bupkis/from-jest/-/from-jest-0.3.2.tgz","fileCount":59,"integrity":"sha512-UBHi2+5zoZTaKMSTBMuhYHoSi5kIxdJJQQcbIOrcStZO0c1UQ6eoku/6Nuug17aWzr3pMx2JZC1E5bEDJwdmFw==","signatures":[{"sig":"MEUCIQCFcbDSEDVrqS162rGNUDhsU5belTSnH5kcqYeKNj4d+wIgDreqIfKNmMt2J71RxVvyVOyxzrFx6rTh5svqcL4h4JQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":165678},"type":"module","engines":{"node":"^20.19.0 || ^22.12.0 || >=23"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"cb086f3b4bd6d657892e325e2984a073afaa57c9","scripts":{"test":"npm run test:base -- \"test/*/*.test.ts\"","build":"tsc","test:dev":"npm run test:base -- --watch \"test/*/*.test.ts\"","test:base":"node --test --test-reporter=spec --import tsx","test:node20":"npm run test:base -- test/*.test.ts","example:jest":"cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --config examples/jest.config.js","example:vitest":"vitest run examples/vitest-example.test.ts examples/vitest-example.transformed.test.ts","example:codemod":"npx tsx src/cli.ts --dry-run examples/jest-example.test.ts"},"_npmUser":{"name":"boneskull","email":"boneskull@boneskull.com"},"prettier":{"tsdoc":true,"plugins":["prettier-plugin-jsdoc","prettier-plugin-pkg"],"singleQuote":true,"jsdocPreferCodeFences":true,"jsdocCommentLineStrategy":"keep"},"repository":{"url":"git+https://github.com/boneskull/bupkis.git","type":"git","directory":"packages/from-jest"},"_npmVersion":"11.6.2","description":"Migrate Jest and Vitest assertions to bupkis","directories":{},"_nodeVersion":"24.12.0","dependencies":{"ts-morph":"^25.0.0","@boneskull/bargs":"4.0.0","@bupkis/codemod-core":"^0.1.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"30.2.0","vitest":"4.0.16","ts-jest":"29.4.6","cross-env":"10.1.0","@jest/globals":"30.2.0"},"_npmOperationalInternal":{"tmp":"tmp/from-jest_0.3.2_1771466556196_0.6163008366267884","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@bupkis/from-jest","version":"0.3.3","keywords":["bupkis","jest","codemod","migration","assertions","vitest"],"author":{"name":"Christopher Hiller","email":"boneskull@boneskull.com"},"license":"BlueOak-1.0.0","_id":"@bupkis/from-jest@0.3.3","maintainers":[{"name":"boneskull","email":"boneskull@boneskull.com"}],"homepage":"https://bupkis.zip","bugs":{"url":"https://github.com/boneskull/bupkis/issues"},"bin":{"bupkis-from-jest":"dist/cli.js"},"dist":{"shasum":"5e436f866d58e9727602ad8097d2b863a7ef5c27","tarball":"https://registry.npmjs.org/@bupkis/from-jest/-/from-jest-0.3.3.tgz","fileCount":15,"integrity":"sha512-Zs64bpudrXENxUCsRZyyhWOIjs/0OA+SYiAboLaIYUmxL/96i/xaFf3Wl3hnHQI37jvFwBwZcZnIc68NxcAcgA==","signatures":[{"sig":"MEUCIQD+vZKN9jUfuxjElof3xuh1JIAUss05n/XYwbjxC53dhgIgSsVAT2nZ4zO55nfiJ+7JllPMP/BEtBzkiG9BySUjf+I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":67001},"type":"module","engines":{"node":"^20.19.0 || ^22.12.0 || >=23"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"64ef732a58e91cc6c0808149500c8eb3de56c4e1","scripts":{"test":"npm run test:base -- \"test/*/*.test.ts\"","build":"tsc","test:dev":"npm run test:base -- --watch \"test/*/*.test.ts\"","test:base":"node --test --test-reporter=spec --import tsx","test:node20":"npm run test:base -- test/*.test.ts","example:jest":"cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --config examples/jest.config.js","example:vitest":"vitest run examples/vitest-example.test.ts examples/vitest-example.transformed.test.ts","example:codemod":"npx tsx src/cli.ts --dry-run examples/jest-example.test.ts"},"_npmUser":{"name":"boneskull","email":"boneskull@boneskull.com"},"prettier":{"tsdoc":true,"plugins":["prettier-plugin-jsdoc","prettier-plugin-pkg"],"singleQuote":true,"jsdocPreferCodeFences":true,"jsdocCommentLineStrategy":"keep"},"repository":{"url":"git+https://github.com/boneskull/bupkis.git","type":"git","directory":"packages/from-jest"},"_npmVersion":"11.16.0","description":"Migrate Jest and Vitest assertions to bupkis","directories":{},"_nodeVersion":"24.18.0","dependencies":{"ts-morph":"^28.0.0","@boneskull/bargs":"4.1.0","@bupkis/codemod-core":"^0.1.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"30.4.2","vitest":"4.1.9","ts-jest":"29.4.11","cross-env":"10.1.0","@jest/globals":"30.4.1"},"_npmOperationalInternal":{"tmp":"tmp/from-jest_0.3.3_1782785765632_0.7031528261858973","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@bupkis/from-jest","version":"1.0.0","type":"module","description":"Migrate Jest and Vitest assertions to bupkis","repository":{"directory":"packages/from-jest","type":"git","url":"git+https://github.com/boneskull/bupkis.git"},"homepage":"https://bupkis.zip","author":{"name":"Christopher Hiller","email":"boneskull@boneskull.com"},"license":"BlueOak-1.0.0","engines":{"node":"^22.13.0 || >=24.0.0"},"bin":{"bupkis-from-jest":"dist/cli.js"},"exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./package.json":"./package.json"},"keywords":["bupkis","jest","codemod","migration","assertions","vitest"],"scripts":{"build":"tsc","example:codemod":"npx tsx src/cli.ts --dry-run examples/jest-example.test.ts","example:jest":"cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --config examples/jest.config.js","example:vitest":"vitest run examples/vitest-example.test.ts examples/vitest-example.transformed.test.ts","test":"npm run test:base -- \"test/*/*.test.ts\"","test:base":"node --test --test-reporter=spec --import tsx","test:ci":"npm run test -- --test-reporter=node-test-github-reporter","test:coverage":"c8 --reporter=lcov --reporter=text npm test","test:dev":"npm run test -- --watch"},"dependencies":{"@boneskull/bargs":"4.1.0","@bupkis/codemod-core":"^1.0.0","ts-morph":"^28.0.0"},"devDependencies":{"@jest/globals":"30.4.1","cross-env":"10.1.0","jest":"30.4.2","ts-jest":"29.4.11","vitest":"4.1.9"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"prettier":{"jsdocCommentLineStrategy":"keep","jsdocPreferCodeFences":true,"plugins":["prettier-plugin-jsdoc","prettier-plugin-pkg"],"singleQuote":true,"tsdoc":true},"gitHead":"c0f3fcd74ca0f7e307d2a68ce12bba81b4059eb5","_id":"@bupkis/from-jest@1.0.0","bugs":{"url":"https://github.com/boneskull/bupkis/issues"},"_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-RuBh6oexhV/2cWrtSHeuj1zpzjjrJ7jAe+hxAtR0jVl4VfN33yvn9cQ/IY7ZR8Xr5vlrZC5swJUONSHcc3WbcA==","shasum":"a3bb11fd12a1f6ca8da10831314ebde03d31df00","tarball":"https://registry.npmjs.org/@bupkis/from-jest/-/from-jest-1.0.0.tgz","fileCount":59,"unpackedSize":166935,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC0c9vTqiwLNR6Vw+keqgl0YewCtvAoCjOcLBQHFyEzaQIgU9/jQlu70+D12VoZHypwDkN4WyvbcGELmTsrtSAHMSc="}]},"_npmUser":{"name":"boneskull","email":"boneskull@boneskull.com"},"directories":{},"maintainers":[{"name":"boneskull","email":"boneskull@boneskull.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/from-jest_1.0.0_1783650183892_0.1780404975006109"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-14T23:21:02.112Z","modified":"2026-07-10T02:23:04.193Z","0.1.1":"2026-01-14T23:21:02.413Z","0.2.0":"2026-01-16T22:57:40.537Z","0.3.0":"2026-01-31T21:58:09.083Z","0.3.2":"2026-02-19T02:02:36.350Z","0.3.3":"2026-06-30T02:16:05.768Z","1.0.0":"2026-07-10T02:23:04.073Z"},"bugs":{"url":"https://github.com/boneskull/bupkis/issues"},"author":{"name":"Christopher Hiller","email":"boneskull@boneskull.com"},"license":"BlueOak-1.0.0","homepage":"https://bupkis.zip","keywords":["bupkis","jest","codemod","migration","assertions","vitest"],"repository":{"directory":"packages/from-jest","type":"git","url":"git+https://github.com/boneskull/bupkis.git"},"description":"Migrate Jest and Vitest assertions to bupkis","maintainers":[{"name":"boneskull","email":"boneskull@boneskull.com"}],"readme":"# @bupkis/from-jest\n\nMigrate Jest and Vitest assertions to [bupkis](https://github.com/boneskull/bupkis) with a single command.\n\n## Installation\n\n```bash\nnpx @bupkis/from-jest\n```\n\nOr install globally:\n\n```bash\nnpm install -g @bupkis/from-jest\nbupkis-from-jest\n```\n\n## Usage\n\n```bash\n# Transform all test files in current directory\nnpx @bupkis/from-jest\n\n# Transform specific patterns\nnpx @bupkis/from-jest \"src/**/*.test.ts\" \"tests/**/*.spec.ts\"\n\n# Dry run (see what would change)\nnpx @bupkis/from-jest --dry-run\n\n# Strict mode (fail on any unsupported matcher)\nnpx @bupkis/from-jest --strict\n\n# Exclude patterns\nnpx @bupkis/from-jest -e \"**/fixtures/**\" -e \"**/snapshots/**\"\n\n# Transform mock/spy matchers using @bupkis/sinon\nnpx @bupkis/from-jest --sinon\n```\n\n## Modes\n\n- **`--best-effort`** (default): Transform what we can, add `// TODO: Manual migration needed` comments for complex cases\n- **`--strict`**: Fail immediately on any unsupported transformation\n- **`--interactive`**: Prompt for ambiguous cases (coming soon)\n\n## Supported Test Frameworks\n\n**Supported versions:**\n\n- **Jest 29+** (including Jest 30)\n- **Vitest 1+**\n\nThe codemod handles imports from:\n\n- **Jest**: `@jest/globals`\n- **Vitest**: `vitest`\n- **Global `expect`**: Adds `import { expect } from 'bupkis'`\n\nWhen transforming, the codemod:\n\n1. Removes `expect` from your test framework import\n2. Adds `import { expect } from 'bupkis'`\n3. Keeps other imports (`describe`, `it`, `test`, etc.) from your original framework\n\n> **Note:** Jest 30 removed several matcher aliases (e.g., `toThrowError` → `toThrow`, `toBeCalled` → `toHaveBeenCalled`). This codemod handles both the old aliases and the new canonical names.\n\n## Supported Matchers\n\n### Jest/Vitest Core\n\n| Jest                           | bupkis                                 |\n| ------------------------------ | -------------------------------------- |\n| `expect(x).toBe(y)`            | `expect(x, 'to be', y)`                |\n| `expect(x).toEqual(y)`         | `expect(x, 'to deep equal', y)`        |\n| `expect(x).toBeTruthy()`       | `expect(x, 'to be truthy')`            |\n| `expect(x).toBeFalsy()`        | `expect(x, 'to be falsy')`             |\n| `expect(x).toBeNull()`         | `expect(x, 'to be null')`              |\n| `expect(x).toBeUndefined()`    | `expect(x, 'to be undefined')`         |\n| `expect(x).toBeDefined()`      | `expect(x, 'to be defined')`           |\n| `expect(x).toBeInstanceOf(Y)`  | `expect(x, 'to be an instance of', Y)` |\n| `expect(x).toBeGreaterThan(y)` | `expect(x, 'to be greater than', y)`   |\n| `expect(x).toBeLessThan(y)`    | `expect(x, 'to be less than', y)`      |\n| `expect(x).toMatch(pattern)`   | `expect(x, 'to match', pattern)`       |\n| `expect(x).toContain(y)`       | `expect(x, 'to contain', y)`           |\n| `expect(x).toHaveLength(n)`    | `expect(x, 'to have length', n)`       |\n| `expect(x).toHaveProperty(k)`  | `expect(x, 'to have property', k)`     |\n| `expect(x).toMatchObject(y)`   | `expect(x, 'to satisfy', y)`           |\n| `expect(fn).toThrow()`         | `expect(fn, 'to throw')`               |\n\n### jest-extended\n\n| jest-extended              | bupkis                           |\n| -------------------------- | -------------------------------- |\n| `expect(x).toBeTrue()`     | `expect(x, 'to be true')`        |\n| `expect(x).toBeFalse()`    | `expect(x, 'to be false')`       |\n| `expect(x).toBeArray()`    | `expect(x, 'to be an array')`    |\n| `expect(x).toBeEmpty()`    | `expect(x, 'to be empty')`       |\n| `expect(x).toStartWith(s)` | `expect(x, 'to start with', s)`  |\n| `expect(x).toEndWith(s)`   | `expect(x, 'to end with', s)`    |\n| `expect(x).toBeOneOf(arr)` | `expect(x, 'to be one of', arr)` |\n\n### Promise Matchers (resolves/rejects)\n\nThe codemod transforms Jest's promise matchers to bupkis's `expectAsync`:\n\n| Jest                              | bupkis                                                                          |\n| --------------------------------- | ------------------------------------------------------------------------------- |\n| `expect(p).resolves.toBe(v)`      | `expectAsync(p, 'to fulfill with value satisfying', v)`                         |\n| `expect(p).resolves.toEqual(v)`   | `expectAsync(p, 'to fulfill with value satisfying', v)`                         |\n| `expect(p).resolves.toBeTruthy()` | `expectAsync(p, 'to fulfill with value satisfying', expect.it('to be truthy'))` |\n| `expect(p).rejects.toThrow()`     | `expectAsync(p, 'to reject')`                                                   |\n| `expect(p).rejects.toThrow(Err)`  | `expectAsync(p, 'to reject with a', Err)`                                       |\n| `expect(p).rejects.toThrow(msg)`  | `expectAsync(p, 'to reject with error satisfying', msg)`                        |\n\nFor matchers that check properties of the resolved/rejected value (like `toBeTruthy`, `toContain`, `toHaveLength`), the codemod wraps them in `expect.it()` to preserve the assertion semantics.\n\n**Example:**\n\n```javascript\n// Before (Jest)\nawait expect(fetchData()).resolves.toBe('success');\nawait expect(fetchData()).resolves.toContain('data');\nawait expect(badPromise).rejects.toThrow(TypeError);\n\n// After (bupkis)\nawait expectAsync(fetchData(), 'to fulfill with value satisfying', 'success');\nawait expectAsync(\n  fetchData(),\n  'to fulfill with value satisfying',\n  expect.it('to contain', 'data'),\n);\nawait expectAsync(badPromise, 'to reject with a', TypeError);\n```\n\n### Negation\n\nAll matchers support negation:\n\n```javascript\n// Jest/Vitest\nexpect(x).not.toBe(y);\nexpect(p).resolves.not.toBe(y);\n\n// bupkis\nexpect(x, 'not to be', y);\nexpectAsync(p, 'not to fulfill with value satisfying', y);\n```\n\n### Mock/Spy Matchers (with `--sinon`)\n\nWhen you use the `--sinon` flag, the codemod transforms Jest mock matchers to [`@bupkis/sinon`](https://github.com/boneskull/bupkis/tree/main/packages/sinon) assertions:\n\n| Jest (canonical)             | Jest 29 alias        | @bupkis/sinon                             |\n| ---------------------------- | -------------------- | ----------------------------------------- |\n| `toHaveBeenCalled()`         | `toBeCalled()`       | `'was called'`                            |\n| `toHaveBeenCalledTimes(n)`   | `toBeCalledTimes()`  | `'was called times', n`                   |\n| `toHaveBeenCalledWith(...)`  | `toBeCalledWith()`   | `'was called with', [...]`                |\n| `toHaveBeenLastCalledWith()` | `lastCalledWith()`   | `spy.lastCall, 'to have args', [...]`     |\n| `toHaveBeenNthCalledWith(n)` | `nthCalledWith()`    | `spy.getCall(n-1), 'to have args', [...]` |\n| `toHaveReturned()`           | `toReturn()`         | `'to have returned'`                      |\n| `toHaveReturnedTimes(n)`     | `toReturnTimes()`    | `'to have returned times', n`             |\n| `toHaveReturnedWith(v)`      | `toReturnWith()`     | `'to have returned with', v`              |\n| `toHaveLastReturnedWith(v)`  | `lastReturnedWith()` | `spy.lastCall, 'to have returned', v`     |\n| `toHaveNthReturnedWith(n,v)` | `nthReturnedWith()`  | `spy.getCall(n-1), 'to have returned', v` |\n\n> **Note:** The Jest 29 aliases were deprecated in Jest 26 and removed in Jest 30. This codemod handles both.\n\n**Example transformation:**\n\n```javascript\n// Before (Jest)\nexpect(mockFn).toHaveBeenCalled();\nexpect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');\nexpect(mockFn).toHaveBeenLastCalledWith('final');\n\n// After (bupkis + @bupkis/sinon)\nexpect(mockFn, 'was called');\nexpect(mockFn, 'was called with', ['arg1', 'arg2']);\nexpect(mockFn.lastCall, 'to have args', ['final']);\n```\n\n**Important:** The `--sinon` flag only transforms _assertions_. You must manually migrate your mock/spy creation from `jest.fn()` to Sinon:\n\n```javascript\n// Before\nconst mockFn = jest.fn();\n\n// After (manual migration required)\nimport sinon from 'sinon';\nconst mockFn = sinon.spy();\n```\n\nWhen mock matchers are detected without `--sinon`, the codemod will notify you and suggest using the flag.\n\n## Programmatic API\n\n```typescript\nimport { transform, transformCode } from '@bupkis/from-jest';\n\n// Transform a code string\nconst result = await transformCode(`expect(42).toBe(42);`);\nconsole.log(result.code); // expect(42, 'to be', 42);\n\n// Transform promise matchers\nconst promiseResult = await transformCode(`expect(p).resolves.toBe(42);`);\nconsole.log(promiseResult.code); // expectAsync(p, 'to fulfill with value satisfying', 42);\n\n// Transform with sinon support\nconst sinonResult = await transformCode(`expect(spy).toHaveBeenCalled();`, {\n  sinon: true,\n});\nconsole.log(sinonResult.code); // expect(spy, 'was called');\n\n// Transform files\nconst results = await transform({\n  include: ['src/**/*.test.ts'],\n  exclude: ['**/node_modules/**'],\n  mode: 'best-effort',\n  sinon: true, // Enable mock matcher transformation\n  write: true,\n});\n```\n\n## What Requires Manual Migration\n\nSome Jest/Vitest patterns cannot be automatically transformed:\n\n- **Mock/spy creation**: `jest.fn()`, `jest.spyOn()`, `vi.fn()` must be manually migrated to Sinon (`sinon.spy()`, `sinon.stub()`)\n- **DOM matchers**: `@testing-library/jest-dom` matchers like `toBeInTheDocument`\n- **Asymmetric matchers in promise chains**: `expect(p).resolves.toEqual(expect.anything())` needs manual migration\n- **Complex `toHaveProperty`**: When checking property value, not just existence\n\nThese cases will be marked with `// TODO: Manual migration needed` comments when using `--best-effort` mode.\n\n> **Tip:** Mock/spy _assertions_ can be transformed automatically with `--sinon`. See the [Mock/Spy Matchers](#mockspy-matchers-with---sinon) section.\n\n## License\n\nCopyright © 2025 Christopher Hiller. Licensed under [BlueOak-1.0.0](https://blueoakcouncil.org/license/1.0.0).\n","readmeFilename":"README.md"}