npm package: @schemashift/yup-zod
Description: Yup ↔ Zod bidirectional transformer for SchemaShift
Author: Joseph May
Latest version: 0.14.0

# @schemashift/yup-zod

Yup ↔ Zod transformer for SchemaShift. Supports both forward (Yup → Zod) and backward (Zod → Yup) migrations.

[![npm version](https://img.shields.io/npm/v/@schemashift/yup-zod.svg)](https://www.npmjs.com/package/@schemashift/yup-zod)
[![npm downloads](https://img.shields.io/npm/dm/@schemashift/yup-zod.svg)](https://www.npmjs.com/package/@schemashift/yup-zod)
[![CI](https://github.com/jdmay2/schemashift/actions/workflows/ci.yml/badge.svg)](https://github.com/jdmay2/schemashift/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

## Installation

```bash
npm install @schemashift/yup-zod
```

## Usage

```typescript
import { createYupToZodHandler, createZodToYupHandler } from '@schemashift/yup-zod';
import { TransformEngine } from '@schemashift/core';

const engine = new TransformEngine();
engine.registerHandler('yup', 'zod', createYupToZodHandler());
engine.registerHandler('zod', 'yup', createZodToYupHandler()); // Backward migration (Pro+)
```

### Backward Migration: Zod → Yup

AST-based transformer that converts Zod schemas back to Yup equivalents:

| Zod | Yup |
|-----|-----|
| `z.object({...})` | `yup.object({...})` |
| `z.string()` | `yup.string()` |
| `z.number()` | `yup.number()` |
| `z.boolean()` | `yup.boolean()` |
| `z.date()` | `yup.date()` |
| `z.array(s)` | `yup.array().of(s)` |
| `.optional()` | `.notRequired()` |
| `.nullable()` | `.nullable()` |
| `.refine(fn, msg)` | `.test('custom', msg, fn)` |
| `z.enum([...])` | `yup.mixed().oneOf([...])` |
| `z.union([...])` | `yup.mixed().oneOf([...])` |
| `z.literal(val)` | `yup.mixed().oneOf([val])` |
| `z.record(k, v)` | `yup.object()` (with TODO) |
| `z.tuple([...])` | `yup.array()` (with TODO) |

**Tier:** Pro+

## Transformation Mappings

### Imports

| Yup | Zod |
|-----|-----|
| `import * as yup from 'yup'` | `import { z } from 'zod'` |
| `import yup from 'yup'` | `import { z } from 'zod'` |

### Basic Types

| Yup | Zod |
|-----|-----|
| `yup.string()` | `z.string()` |
| `yup.number()` | `z.number()` |
| `yup.boolean()` | `z.boolean()` |
| `yup.date()` | `z.date()` |
| `yup.array()` | `z.array()` |
| `yup.object()` | `z.object()` |
| `yup.mixed()` | `z.unknown()` |

### Required/Optional

| Yup | Zod | Notes |
|-----|-----|-------|
| `.required()` | (removed) | Zod fields are required by default |
| `.notRequired()` | `.optional()` | |
| `.nullable()` | `.nullable()` | |
| `.defined()` | (removed) | Handled by Zod's type system |

### String Validations

| Yup | Zod |
|-----|-----|
| `.email()` | `.email()` |
| `.url()` | `.url()` |
| `.uuid()` | `.uuid()` |
| `.min(n)` | `.min(n)` |
| `.max(n)` | `.max(n)` |
| `.length(n)` | `.length(n)` |
| `.matches(regex)` | `.regex(regex)` |
| `.lowercase()` | `.toLowerCase()` |
| `.uppercase()` | `.toUpperCase()` |
| `.trim()` | `.trim()` |

### Number Validations

| Yup | Zod |
|-----|-----|
| `.min(n)` | `.min(n)` |
| `.max(n)` | `.max(n)` |
| `.positive()` | `.positive()` |
| `.negative()` | `.negative()` |
| `.integer()` | `.int()` |

### Array Validations

| Yup | Zod |
|-----|-----|
| `.min(n)` | `.min(n)` |
| `.max(n)` | `.max(n)` |
| `.length(n)` | `.length(n)` |
| `.of(schema)` | `z.array(schema)` |

### Object Methods

| Yup | Zod |
|-----|-----|
| `.shape({...})` | `z.object({...})` |
| `.pick([...])` | `.pick({...})` |
| `.omit([...])` | `.omit({...})` |
| `.partial()` | `.partial()` |
| `.strict()` | `.strict()` |
| `.passthrough()` | `.passthrough()` |

### Other

| Yup | Zod |
|-----|-----|
| `.default(value)` | `.default(value)` |
| `.oneOf([...])` | `z.enum([...])` or `z.literal().or(...)` |
| `.test(...)` | `.refine(...)` |
| `.transform(...)` | `.transform(...)` |

## Patterns Requiring Manual Review

The transformer generates actionable `.superRefine()` scaffolding for these patterns (not bare TODOs):

### `.when()` Conditionals

Yup's `.when()` doesn't have a direct Zod equivalent. The transformer generates a `.superRefine()` template with the original condition context:

```typescript
// Yup
const schema = yup.object({
  isBusiness: yup.boolean(),
  companyName: yup.string().when('isBusiness', {
    is: true,
    then: yup.string().required(),
  }),
});

// Generated output (with scaffolding)
/* TODO(schemashift): Convert conditional validation.
   Original: .when('isBusiness', { is: true, then: ..., otherwise: ... })
   Suggested Zod equivalent:
   .superRefine((data, ctx) => {
     if (data.isBusiness === true) {
       // Apply 'then' validation
     } else {
       // Apply 'otherwise' validation
     }
   })
*/
const schema = z.object({
  isBusiness: z.boolean(),
  companyName: z.string().optional(),
}).superRefine((data, ctx) => {
  if (data.isBusiness && !data.companyName) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: 'Company name required for business accounts',
      path: ['companyName'],
    });
  }
});
```

### `.test()` Custom Validations

Complex `.test()` calls may need adjustment for Zod's `.refine()` API.

```typescript
// Yup
yup.string().test('custom', 'Invalid', (value) => customValidation(value))

// Zod
z.string().refine((value) => customValidation(value), 'Invalid')
```

### Async Validations

Yup supports async validation in `.test()`. Zod requires explicit async handling.

```typescript
// Yup
yup.string().test('unique', 'Already exists', async (value) => {
  return await checkUnique(value);
})

// Zod
z.string().refine(async (value) => {
  return await checkUnique(value);
}, 'Already exists')
// Note: Use .parseAsync() instead of .parse()
```

## Related Packages

- [schemashift-cli](https://www.npmjs.com/package/schemashift-cli) — CLI tool for running migrations
- [@schemashift/core](https://www.npmjs.com/package/@schemashift/core) — Core analysis engine
- [@schemashift/zod-valibot](https://www.npmjs.com/package/@schemashift/zod-valibot) — Chain: Yup → Zod → Valibot
- [@schemashift/zod-v3-v4](https://www.npmjs.com/package/@schemashift/zod-v3-v4) — Upgrade Zod after migration

## License

MIT