@schemashift/zod-v3-v4 0.2.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # @schemashift/zod-v3-v4
2
+
3
+ Zod v3 to v4 upgrade transformer for SchemaShift. Handles 17+ breaking changes between Zod v3 and v4 with auto-transforms and runtime behavior warnings.
4
+
5
+ **Tier:** Individual
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @schemashift/zod-v3-v4
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { createZodV3ToV4Handler } from '@schemashift/zod-v3-v4';
17
+ import { TransformEngine } from '@schemashift/core';
18
+
19
+ const engine = new TransformEngine();
20
+ engine.registerHandler('zod-v3', 'v4', createZodV3ToV4Handler());
21
+ ```
22
+
23
+ ## Breaking Changes Handled
24
+
25
+ ### Auto-Transforms
26
+
27
+ These changes are automatically applied to your code:
28
+
29
+ | v3 Pattern | v4 Pattern | Notes |
30
+ |-----------|-----------|-------|
31
+ | `z.record(valueSchema)` | `z.record(z.string(), valueSchema)` | Explicit key type required |
32
+ | `schemaA.merge(schemaB)` | `schemaA.extend(schemaB.shape)` | `.merge()` deprecated |
33
+ | `z.nativeEnum(MyEnum)` | `z.enum(MyEnum)` | `nativeEnum` renamed |
34
+ | `.superRefine(fn)` | `.check(fn)` | Callback signature identical |
35
+ | `error.errors` | `error.issues` | Property renamed |
36
+ | `{ invalid_type_error: 'msg' }` | `{ error: 'msg' }` | Unified error param |
37
+ | `{ required_error: 'msg' }` | `{ error: 'msg' }` | Unified error param |
38
+ | Both error params | `{ error: (issue) => ... }` | Function-based error |
39
+
40
+ ### Deprecation Warnings
41
+
42
+ These methods still work but are deprecated in v4:
43
+
44
+ | Method | Replacement | Warning |
45
+ |--------|-------------|---------|
46
+ | `.superRefine()` | `.check()` | Auto-renamed, warning emitted |
47
+ | `.strict()` | `z.strictObject()` | Structural change, review needed |
48
+ | `.passthrough()` | `z.looseObject()` | Structural change, review needed |
49
+
50
+ ### Runtime Behavior Warnings
51
+
52
+ These changes do not cause compile-time errors but silently change runtime behavior:
53
+
54
+ | Pattern | Issue |
55
+ |---------|-------|
56
+ | `instanceof Error` on ZodError | `ZodError` no longer extends `Error` in v4 |
57
+ | `.refine()` followed by `.transform()` | `.transform()` now runs even when `.refine()` fails |
58
+ | `.default()` + `.optional()` | `.default()` always provides a value, making `.optional()` a no-op |
59
+ | `.pipe()` | Stricter type checking, may need explicit type annotations |
60
+
61
+ ### Other Detected Changes
62
+
63
+ | Pattern | Warning |
64
+ |---------|---------|
65
+ | `.flatten()` | Removed in v4, use `.format()` instead |
66
+ | `z.function()` | Input/output parameter changes |
67
+ | `.uuid()` | Stricter RFC 4122 validation |
68
+ | `z.discriminatedUnion()` | Stricter discriminator requirements |
69
+
70
+ ## Mappings Reference
71
+
72
+ ### Behavior Changes Set
73
+
74
+ Methods with changed behavior in v4: `default`, `uuid`, `record`, `discriminatedUnion`, `function`, `pipe`.
75
+
76
+ ### Deprecated Methods Set
77
+
78
+ Methods deprecated in v4: `merge`, `superRefine`, `strict`, `passthrough`.
79
+
80
+ ### Auto-Transformable Methods
81
+
82
+ Methods that are automatically renamed: `superRefine` → `.check()`.
83
+
84
+ ### Error Property Renames
85
+
86
+ | v3 | v4 |
87
+ |----|----|
88
+ | `.errors` | `.issues` |
89
+ | `.formErrors` | `.formErrors` (unchanged) |
90
+ | `.fieldErrors` | `.fieldErrors` (unchanged) |
91
+
92
+ ### Error Parameter Changes
93
+
94
+ v3 accepted `invalid_type_error` and `required_error` as separate properties. v4 unifies these under a single `error` property (string or function).
95
+
96
+ ## License
97
+
98
+ MIT
package/dist/index.cjs CHANGED
@@ -48,8 +48,24 @@ var BEHAVIOR_CHANGES = /* @__PURE__ */ new Set([
48
48
  // Requires key type
49
49
  "discriminatedUnion",
50
50
  // Stricter discriminator requirements
51
- "function"
51
+ "function",
52
52
  // Input/output parameter changes
53
+ "pipe"
54
+ // Stricter type checking in v4
55
+ ]);
56
+ var DEPRECATED_METHODS = /* @__PURE__ */ new Set([
57
+ "merge",
58
+ // Use .extend() instead
59
+ "superRefine",
60
+ // Use .check() instead
61
+ "strict",
62
+ // Use z.strictObject() instead
63
+ "passthrough"
64
+ // Use z.looseObject() instead
65
+ ]);
66
+ var AUTO_TRANSFORMABLE = /* @__PURE__ */ new Set([
67
+ "superRefine"
68
+ // -> .check()
53
69
  ]);
54
70
 
55
71
  // src/transformer.ts
@@ -63,8 +79,17 @@ var ZodV3ToV4Transformer = class {
63
79
  const originalCode = sourceFile.getFullText();
64
80
  try {
65
81
  this.transformRecordCalls(sourceFile);
82
+ this.transformMerge(sourceFile);
83
+ this.transformNativeEnum(sourceFile);
84
+ this.transformSuperRefine(sourceFile);
66
85
  this.transformErrorProperties(sourceFile);
86
+ this.transformErrorParams(sourceFile);
87
+ this.transformFlatten(sourceFile);
88
+ this.checkDeprecatedMethods(sourceFile);
67
89
  this.checkBehaviorChanges(sourceFile);
90
+ this.checkInstanceofError(sourceFile);
91
+ this.checkTransformRefineOrder(sourceFile);
92
+ this.checkDefaultOptional(sourceFile);
68
93
  return {
69
94
  success: this.errors.length === 0,
70
95
  filePath,
@@ -113,21 +138,297 @@ var ZodV3ToV4Transformer = class {
113
138
  });
114
139
  }
115
140
  /**
116
- * Transform error.errors to error.issues
141
+ * Transform error.errors to error.issues using AST-based detection
142
+ * instead of heuristic name matching.
117
143
  */
118
144
  transformErrorProperties(sourceFile) {
145
+ const filePath = sourceFile.getFilePath();
146
+ const zodErrorVars = /* @__PURE__ */ new Set();
147
+ sourceFile.forEachDescendant((node) => {
148
+ if (import_ts_morph.Node.isVariableDeclaration(node)) {
149
+ const typeNode = node.getTypeNode();
150
+ if (typeNode?.getText().includes("ZodError")) {
151
+ const name = node.getName();
152
+ zodErrorVars.add(name);
153
+ }
154
+ }
155
+ if (import_ts_morph.Node.isCatchClause(node)) {
156
+ const param = node.getVariableDeclaration();
157
+ if (param) {
158
+ const block = node.getBlock();
159
+ const blockText = block.getText();
160
+ if (blockText.includes("instanceof ZodError") || blockText.includes("ZodError")) {
161
+ zodErrorVars.add(param.getName());
162
+ }
163
+ }
164
+ }
165
+ if (import_ts_morph.Node.isVariableDeclaration(node)) {
166
+ const initializer = node.getInitializer();
167
+ if (initializer?.getText().includes(".safeParse(")) {
168
+ zodErrorVars.add(`${node.getName()}.error`);
169
+ }
170
+ }
171
+ if (import_ts_morph.Node.isNewExpression(node)) {
172
+ if (node.getExpression().getText() === "ZodError") {
173
+ const parent = node.getParent();
174
+ if (parent && import_ts_morph.Node.isVariableDeclaration(parent)) {
175
+ zodErrorVars.add(parent.getName());
176
+ }
177
+ }
178
+ }
179
+ });
119
180
  sourceFile.forEachDescendant((node) => {
120
181
  if (import_ts_morph.Node.isPropertyAccessExpression(node)) {
121
182
  const name = node.getName();
122
183
  if (name === "errors") {
123
184
  const object = node.getExpression();
124
185
  const objectText = object.getText();
125
- if (objectText.toLowerCase().includes("error") || objectText.toLowerCase().includes("err")) {
186
+ const isZodError = zodErrorVars.has(objectText) || // Also check if accessing .error.errors (safeParse pattern)
187
+ objectText.endsWith(".error") && zodErrorVars.has(`${objectText.replace(/\.error$/, "")}.error`);
188
+ if (isZodError) {
126
189
  const fullText = node.getText();
127
190
  const newText = fullText.replace(/\.errors$/, ".issues");
128
191
  node.replaceWithText(newText);
129
192
  this.warnings.push(
130
- `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: .errors renamed to .issues (ZodError property change)`
193
+ `${filePath}:${node.getStartLineNumber()}: .errors renamed to .issues (ZodError property change)`
194
+ );
195
+ }
196
+ }
197
+ }
198
+ });
199
+ }
200
+ /**
201
+ * Transform .flatten() usage — removed in v4.
202
+ */
203
+ transformFlatten(sourceFile) {
204
+ const filePath = sourceFile.getFilePath();
205
+ sourceFile.forEachDescendant((node) => {
206
+ if (import_ts_morph.Node.isCallExpression(node)) {
207
+ const expression = node.getExpression();
208
+ if (import_ts_morph.Node.isPropertyAccessExpression(expression) && expression.getName() === "flatten") {
209
+ const lineNumber = node.getStartLineNumber();
210
+ this.warnings.push(
211
+ `${filePath}:${lineNumber}: .flatten() is removed in v4. Use error.issues directly or implement custom flattening. See: https://zod.dev/v4/changelog#flatten-removed`
212
+ );
213
+ }
214
+ }
215
+ });
216
+ }
217
+ /**
218
+ * Transform .merge(otherSchema) to .extend(otherSchema.shape)
219
+ */
220
+ transformMerge(sourceFile) {
221
+ const filePath = sourceFile.getFilePath();
222
+ const nodesToTransform = [];
223
+ sourceFile.forEachDescendant((node) => {
224
+ if (import_ts_morph.Node.isCallExpression(node)) {
225
+ const expression = node.getExpression();
226
+ if (import_ts_morph.Node.isPropertyAccessExpression(expression) && expression.getName() === "merge") {
227
+ nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });
228
+ }
229
+ }
230
+ });
231
+ nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());
232
+ for (const { node, lineNumber } of nodesToTransform) {
233
+ const args = node.getArguments();
234
+ if (args.length === 1) {
235
+ const argText = args[0]?.getText();
236
+ if (argText) {
237
+ const expression = node.getExpression();
238
+ if (import_ts_morph.Node.isPropertyAccessExpression(expression)) {
239
+ const objectText = expression.getExpression().getText();
240
+ node.replaceWithText(`${objectText}.extend(${argText}.shape)`);
241
+ this.warnings.push(
242
+ `${filePath}:${lineNumber}: .merge() renamed to .extend() with .shape access. Verify the merged schema exposes .shape.`
243
+ );
244
+ }
245
+ }
246
+ }
247
+ }
248
+ }
249
+ /**
250
+ * Transform z.nativeEnum(X) to z.enum(X)
251
+ */
252
+ transformNativeEnum(sourceFile) {
253
+ const filePath = sourceFile.getFilePath();
254
+ const fullText = sourceFile.getFullText();
255
+ const newText = fullText.replace(/\bz\.nativeEnum\(/g, "z.enum(");
256
+ if (newText !== fullText) {
257
+ sourceFile.replaceWithText(newText);
258
+ this.warnings.push(
259
+ `${filePath}: z.nativeEnum() renamed to z.enum() in v4. Verify enum values are compatible.`
260
+ );
261
+ }
262
+ }
263
+ /**
264
+ * Check for deprecated methods and add warnings
265
+ */
266
+ checkDeprecatedMethods(sourceFile) {
267
+ const filePath = sourceFile.getFilePath();
268
+ sourceFile.forEachDescendant((node) => {
269
+ if (import_ts_morph.Node.isCallExpression(node)) {
270
+ const expression = node.getExpression();
271
+ if (import_ts_morph.Node.isPropertyAccessExpression(expression)) {
272
+ const name = expression.getName();
273
+ if (DEPRECATED_METHODS.has(name) && !AUTO_TRANSFORMABLE.has(name)) {
274
+ const lineNumber = node.getStartLineNumber();
275
+ switch (name) {
276
+ case "strict":
277
+ this.warnings.push(
278
+ `${filePath}:${lineNumber}: .strict() is deprecated in v4. Use z.strictObject() instead.`
279
+ );
280
+ break;
281
+ case "passthrough":
282
+ this.warnings.push(
283
+ `${filePath}:${lineNumber}: .passthrough() is deprecated in v4. Use z.looseObject() instead.`
284
+ );
285
+ break;
286
+ }
287
+ }
288
+ }
289
+ }
290
+ });
291
+ }
292
+ /**
293
+ * Auto-transform .superRefine() to .check() — callback signature is identical.
294
+ */
295
+ transformSuperRefine(sourceFile) {
296
+ const filePath = sourceFile.getFilePath();
297
+ const nodesToTransform = [];
298
+ sourceFile.forEachDescendant((node) => {
299
+ if (import_ts_morph.Node.isPropertyAccessExpression(node) && node.getName() === "superRefine") {
300
+ nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });
301
+ }
302
+ });
303
+ nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());
304
+ for (const { node, lineNumber } of nodesToTransform) {
305
+ const parent = node.getParent();
306
+ if (parent && import_ts_morph.Node.isCallExpression(parent)) {
307
+ const objectText = node.getExpression().getText();
308
+ const argsText = parent.getArguments().map((a) => a.getText()).join(", ");
309
+ parent.replaceWithText(`${objectText}.check(${argsText})`);
310
+ this.warnings.push(
311
+ `${filePath}:${lineNumber}: .superRefine() auto-transformed to .check() (deprecated in v4).`
312
+ );
313
+ }
314
+ }
315
+ }
316
+ /**
317
+ * Auto-transform invalid_type_error/required_error params to unified `error` param.
318
+ */
319
+ transformErrorParams(sourceFile) {
320
+ const filePath = sourceFile.getFilePath();
321
+ const nodesToTransform = [];
322
+ sourceFile.forEachDescendant((node) => {
323
+ if (import_ts_morph.Node.isObjectLiteralExpression(node)) {
324
+ const properties = node.getProperties();
325
+ const propNames = properties.filter((p) => import_ts_morph.Node.isPropertyAssignment(p)).map((p) => import_ts_morph.Node.isPropertyAssignment(p) ? p.getName() : "");
326
+ const hasInvalidType = propNames.includes("invalid_type_error");
327
+ const hasRequired = propNames.includes("required_error");
328
+ if (hasInvalidType || hasRequired) {
329
+ const parent = node.getParent();
330
+ if (parent && import_ts_morph.Node.isCallExpression(parent)) {
331
+ const expr = parent.getExpression();
332
+ if (import_ts_morph.Node.isPropertyAccessExpression(expr) && expr.getExpression().getText() === "z") {
333
+ nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });
334
+ }
335
+ }
336
+ }
337
+ }
338
+ });
339
+ nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());
340
+ for (const { node, lineNumber } of nodesToTransform) {
341
+ const properties = node.getProperties();
342
+ let invalidTypeValue;
343
+ let requiredValue;
344
+ const otherProps = [];
345
+ for (const prop of properties) {
346
+ if (import_ts_morph.Node.isPropertyAssignment(prop)) {
347
+ const name = prop.getName();
348
+ const value = prop.getInitializer()?.getText() ?? "";
349
+ if (name === "invalid_type_error") {
350
+ invalidTypeValue = value;
351
+ } else if (name === "required_error") {
352
+ requiredValue = value;
353
+ } else {
354
+ otherProps.push(prop.getText());
355
+ }
356
+ }
357
+ }
358
+ let errorValue;
359
+ if (invalidTypeValue && requiredValue) {
360
+ errorValue = `error: (issue) => issue.input === undefined ? ${requiredValue} : ${invalidTypeValue}`;
361
+ } else if (requiredValue) {
362
+ errorValue = `error: ${requiredValue}`;
363
+ } else if (invalidTypeValue) {
364
+ errorValue = `error: ${invalidTypeValue}`;
365
+ } else {
366
+ continue;
367
+ }
368
+ const allProps = [errorValue, ...otherProps].join(", ");
369
+ node.replaceWithText(`{ ${allProps} }`);
370
+ this.warnings.push(
371
+ `${filePath}:${lineNumber}: invalid_type_error/required_error auto-transformed to unified error param.`
372
+ );
373
+ }
374
+ }
375
+ /**
376
+ * Detect instanceof Error patterns in catch blocks that reference ZodError.
377
+ * In v4, ZodError no longer extends Error.
378
+ */
379
+ checkInstanceofError(sourceFile) {
380
+ const filePath = sourceFile.getFilePath();
381
+ sourceFile.forEachDescendant((node) => {
382
+ if (import_ts_morph.Node.isCatchClause(node)) {
383
+ const block = node.getBlock();
384
+ const blockText = block.getText();
385
+ if (blockText.includes("ZodError") && blockText.includes("instanceof Error")) {
386
+ const lineNumber = node.getStartLineNumber();
387
+ this.warnings.push(
388
+ `${filePath}:${lineNumber}: ZodError no longer extends Error in v4. \`instanceof Error\` checks on ZodError will return false. Use \`instanceof ZodError\` or check for \`.issues\` property instead.`
389
+ );
390
+ }
391
+ }
392
+ });
393
+ }
394
+ /**
395
+ * Detect .refine()/.superRefine() followed by .transform() in the same chain.
396
+ * In v4, .transform() runs even when .refine() fails.
397
+ */
398
+ checkTransformRefineOrder(sourceFile) {
399
+ const filePath = sourceFile.getFilePath();
400
+ sourceFile.forEachDescendant((node) => {
401
+ if (import_ts_morph.Node.isCallExpression(node)) {
402
+ const expression = node.getExpression();
403
+ if (import_ts_morph.Node.isPropertyAccessExpression(expression) && expression.getName() === "transform") {
404
+ const chainText = node.getText();
405
+ if (chainText.includes(".refine(") || chainText.includes(".superRefine(") || chainText.includes(".check(")) {
406
+ const lineNumber = node.getStartLineNumber();
407
+ this.warnings.push(
408
+ `${filePath}:${lineNumber}: In v4, .transform() executes even if preceding .refine() fails. Consider using .pipe() to sequence validation before transforms.`
409
+ );
410
+ }
411
+ }
412
+ }
413
+ });
414
+ }
415
+ /**
416
+ * Detect .default() combined with .optional() — behavior changed silently in v4.
417
+ * In v4, .default() always provides a value, making .optional() a no-op.
418
+ */
419
+ checkDefaultOptional(sourceFile) {
420
+ const filePath = sourceFile.getFilePath();
421
+ sourceFile.forEachDescendant((node) => {
422
+ if (import_ts_morph.Node.isCallExpression(node)) {
423
+ const expression = node.getExpression();
424
+ if (import_ts_morph.Node.isPropertyAccessExpression(expression) && (expression.getName() === "optional" || expression.getName() === "default")) {
425
+ const chainText = node.getText();
426
+ const hasDefault = chainText.includes(".default(");
427
+ const hasOptional = chainText.includes(".optional(");
428
+ if (hasDefault && hasOptional) {
429
+ const lineNumber = node.getStartLineNumber();
430
+ this.warnings.push(
431
+ `${filePath}:${lineNumber}: .default() + .optional() behavior changed in v4. .default() now always provides a value, making .optional() effectively a no-op. Review whether .optional() is still needed.`
131
432
  );
132
433
  }
133
434
  }
@@ -167,22 +468,22 @@ var ZodV3ToV4Transformer = class {
167
468
  `${filePath}:${lineNumber}: z.function() parameter handling has changed. Review input/output schema definitions.`
168
469
  );
169
470
  break;
471
+ case "pipe":
472
+ this.warnings.push(
473
+ `${filePath}:${lineNumber}: .pipe() has stricter type checking in v4. If you get type errors, add explicit type annotations to .transform() return types or cast through unknown as a last resort.`
474
+ );
475
+ break;
170
476
  }
171
477
  }
478
+ if (name === "format") {
479
+ const lineNumber = node.getStartLineNumber();
480
+ this.warnings.push(
481
+ `${filePath}:${lineNumber}: .format() is removed in v4. Use z.treeifyError() or custom error formatting. See: https://zod.dev/v4/changelog`
482
+ );
483
+ }
172
484
  }
173
485
  }
174
486
  });
175
- const text = sourceFile.getFullText();
176
- if (text.includes(".flatten()")) {
177
- const matches = text.matchAll(/\.flatten\(\)/g);
178
- for (const match of matches) {
179
- const pos = match.index ?? 0;
180
- const lineNumber = sourceFile.getLineAndColumnAtPos(pos).line;
181
- this.warnings.push(
182
- `${filePath}:${lineNumber}: .flatten() is removed in v4. Use error.issues directly or implement custom flattening.`
183
- );
184
- }
185
- }
186
487
  }
187
488
  };
188
489
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/transformer.ts","../src/mappings.ts","../src/handler.ts"],"sourcesContent":["export { createZodV3ToV4Handler } from './handler.js';\nexport { BEHAVIOR_CHANGES, V3_TO_V4_PATTERNS } from './mappings.js';\nexport { ZodV3ToV4Transformer } from './transformer.js';\n","import type { TransformError, TransformResult } from '@schemashift/core';\nimport { Node, type SourceFile } from 'ts-morph';\nimport { BEHAVIOR_CHANGES } from './mappings.js';\n\n/**\n * Zod v3 to v4 Transformer\n *\n * Handles breaking changes between Zod v3 and v4:\n * - z.record() now requires explicit key type\n * - error.errors -> error.issues\n * - Stricter UUID validation\n * - Type inference changes in .default()\n */\nexport class ZodV3ToV4Transformer {\n private errors: TransformError[] = [];\n private warnings: string[] = [];\n\n transform(sourceFile: SourceFile): TransformResult {\n this.errors = [];\n this.warnings = [];\n\n const filePath = sourceFile.getFilePath();\n const originalCode = sourceFile.getFullText();\n\n try {\n this.transformRecordCalls(sourceFile);\n this.transformErrorProperties(sourceFile);\n this.checkBehaviorChanges(sourceFile);\n\n return {\n success: this.errors.length === 0,\n filePath,\n originalCode,\n transformedCode: sourceFile.getFullText(),\n errors: this.errors,\n warnings: this.warnings,\n };\n } catch (error) {\n this.errors.push({\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n return {\n success: false,\n filePath,\n originalCode,\n errors: this.errors,\n warnings: this.warnings,\n };\n }\n }\n\n /**\n * Transform z.record(valueSchema) to z.record(z.string(), valueSchema)\n */\n private transformRecordCalls(sourceFile: SourceFile): void {\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n // Check if this is z.record() call\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n const object = expression.getExpression();\n\n if (name === 'record' && object.getText() === 'z') {\n const args = node.getArguments();\n\n // If only one argument, add z.string() as key type\n if (args.length === 1) {\n const valueSchema = args[0]?.getText();\n if (valueSchema) {\n node.replaceWithText(`z.record(z.string(), ${valueSchema})`);\n\n this.warnings.push(\n `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: ` +\n 'z.record() updated to include explicit key type z.string()',\n );\n }\n }\n }\n }\n }\n });\n }\n\n /**\n * Transform error.errors to error.issues\n */\n private transformErrorProperties(sourceFile: SourceFile): void {\n sourceFile.forEachDescendant((node) => {\n if (Node.isPropertyAccessExpression(node)) {\n const name = node.getName();\n\n // Check for .errors property access that might be on ZodError\n if (name === 'errors') {\n const object = node.getExpression();\n const objectText = object.getText();\n\n // Heuristic: if the variable is named error, err, or zodError, likely a ZodError\n if (\n objectText.toLowerCase().includes('error') ||\n objectText.toLowerCase().includes('err')\n ) {\n // Replace .errors with .issues\n const fullText = node.getText();\n const newText = fullText.replace(/\\.errors$/, '.issues');\n node.replaceWithText(newText);\n\n this.warnings.push(\n `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: ` +\n '.errors renamed to .issues (ZodError property change)',\n );\n }\n }\n }\n });\n }\n\n /**\n * Check for methods with behavior changes and add warnings\n */\n private checkBehaviorChanges(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n\n if (BEHAVIOR_CHANGES.has(name)) {\n const lineNumber = node.getStartLineNumber();\n\n switch (name) {\n case 'default':\n this.warnings.push(\n `${filePath}:${lineNumber}: .default() has stricter type inference in v4. ` +\n 'Verify default value matches schema type exactly.',\n );\n break;\n\n case 'uuid':\n this.warnings.push(\n `${filePath}:${lineNumber}: .uuid() now enforces strict RFC 4122 compliance. ` +\n 'Non-standard UUIDs may fail validation.',\n );\n break;\n\n case 'discriminatedUnion':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.discriminatedUnion() now requires ` +\n 'a literal type for the discriminator property.',\n );\n break;\n\n case 'function':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.function() parameter handling has changed. ` +\n 'Review input/output schema definitions.',\n );\n break;\n }\n }\n }\n }\n });\n\n // Check for flatten() usage which is removed in v4\n const text = sourceFile.getFullText();\n if (text.includes('.flatten()')) {\n const matches = text.matchAll(/\\.flatten\\(\\)/g);\n for (const match of matches) {\n const pos = match.index ?? 0;\n const lineNumber = sourceFile.getLineAndColumnAtPos(pos).line;\n this.warnings.push(\n `${filePath}:${lineNumber}: .flatten() is removed in v4. ` +\n 'Use error.issues directly or implement custom flattening.',\n );\n }\n }\n }\n}\n","/**\n * Zod v3 to v4 Breaking Changes\n *\n * Key changes in Zod v4:\n * 1. z.record() now requires explicit key type\n * 2. .default() has stricter type inference\n * 3. error.errors renamed to error.issues\n * 4. .uuid() has stricter validation (RFC 4122 compliant)\n * 5. z.function() input/output changed\n * 6. Branded types use different syntax\n * 7. z.discriminatedUnion() requires literal discriminator\n */\n\n// Patterns that need transformation\nexport const V3_TO_V4_PATTERNS = {\n // z.record(valueSchema) -> z.record(z.string(), valueSchema)\n recordSingleArg: /z\\.record\\((?!z\\.string\\(\\)|z\\.number\\(\\)|z\\.symbol\\(\\))/g,\n\n // error.errors -> error.issues\n errorErrors: /\\.errors\\b/g,\n\n // .brand<T>() -> .brand<T>() (same but check for proper usage)\n brandUsage: /\\.brand<([^>]+)>\\(\\)/g,\n};\n\n// Methods that have changed behavior\nexport const BEHAVIOR_CHANGES = new Set([\n 'default', // Type inference changed\n 'uuid', // Stricter validation\n 'record', // Requires key type\n 'discriminatedUnion', // Stricter discriminator requirements\n 'function', // Input/output parameter changes\n]);\n\n// Error property renames\nexport const ERROR_RENAMES: Record<string, string> = {\n errors: 'issues',\n formErrors: 'formErrors', // Unchanged\n fieldErrors: 'fieldErrors', // Unchanged\n};\n\n// Methods that are deprecated in v4\nexport const DEPRECATED_METHODS = new Set([\n // Add any deprecated methods here\n]);\n","import type { TransformHandler, TransformOptions, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport { ZodV3ToV4Transformer } from './transformer.js';\n\nexport function createZodV3ToV4Handler(): TransformHandler {\n const transformer = new ZodV3ToV4Transformer();\n return {\n transform(sourceFile: SourceFile, _options: TransformOptions): TransformResult {\n return transformer.transform(sourceFile);\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/transformer.ts","../src/mappings.ts","../src/handler.ts"],"sourcesContent":["export { createZodV3ToV4Handler } from './handler.js';\nexport { BEHAVIOR_CHANGES, V3_TO_V4_PATTERNS } from './mappings.js';\nexport { ZodV3ToV4Transformer } from './transformer.js';\n","import type { TransformError, TransformResult } from '@schemashift/core';\nimport { Node, type SourceFile } from 'ts-morph';\nimport { AUTO_TRANSFORMABLE, BEHAVIOR_CHANGES, DEPRECATED_METHODS } from './mappings.js';\n\n/**\n * Zod v3 to v4 Transformer\n *\n * Handles breaking changes between Zod v3 and v4:\n * - z.record() now requires explicit key type\n * - error.errors -> error.issues\n * - Stricter UUID validation\n * - Type inference changes in .default()\n * - .flatten() removed\n * - z.preprocess() -> z.pipe() migration\n */\nexport class ZodV3ToV4Transformer {\n private errors: TransformError[] = [];\n private warnings: string[] = [];\n\n transform(sourceFile: SourceFile): TransformResult {\n this.errors = [];\n this.warnings = [];\n\n const filePath = sourceFile.getFilePath();\n const originalCode = sourceFile.getFullText();\n\n try {\n this.transformRecordCalls(sourceFile);\n this.transformMerge(sourceFile);\n this.transformNativeEnum(sourceFile);\n this.transformSuperRefine(sourceFile);\n this.transformErrorProperties(sourceFile);\n this.transformErrorParams(sourceFile);\n this.transformFlatten(sourceFile);\n this.checkDeprecatedMethods(sourceFile);\n this.checkBehaviorChanges(sourceFile);\n this.checkInstanceofError(sourceFile);\n this.checkTransformRefineOrder(sourceFile);\n this.checkDefaultOptional(sourceFile);\n\n return {\n success: this.errors.length === 0,\n filePath,\n originalCode,\n transformedCode: sourceFile.getFullText(),\n errors: this.errors,\n warnings: this.warnings,\n };\n } catch (error) {\n this.errors.push({\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n return {\n success: false,\n filePath,\n originalCode,\n errors: this.errors,\n warnings: this.warnings,\n };\n }\n }\n\n /**\n * Transform z.record(valueSchema) to z.record(z.string(), valueSchema)\n */\n private transformRecordCalls(sourceFile: SourceFile): void {\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n const object = expression.getExpression();\n\n if (name === 'record' && object.getText() === 'z') {\n const args = node.getArguments();\n\n // If only one argument, add z.string() as key type\n if (args.length === 1) {\n const valueSchema = args[0]?.getText();\n if (valueSchema) {\n node.replaceWithText(`z.record(z.string(), ${valueSchema})`);\n\n this.warnings.push(\n `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: ` +\n 'z.record() updated to include explicit key type z.string()',\n );\n }\n }\n }\n }\n }\n });\n }\n\n /**\n * Transform error.errors to error.issues using AST-based detection\n * instead of heuristic name matching.\n */\n private transformErrorProperties(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n // First, find all variables that are likely ZodError instances\n const zodErrorVars = new Set<string>();\n\n sourceFile.forEachDescendant((node) => {\n // Check variable declarations with ZodError type annotation\n if (Node.isVariableDeclaration(node)) {\n const typeNode = node.getTypeNode();\n if (typeNode?.getText().includes('ZodError')) {\n const name = node.getName();\n zodErrorVars.add(name);\n }\n }\n\n // Check catch clause parameters\n if (Node.isCatchClause(node)) {\n const param = node.getVariableDeclaration();\n if (param) {\n // Check if the catch block uses instanceof ZodError\n const block = node.getBlock();\n const blockText = block.getText();\n if (blockText.includes('instanceof ZodError') || blockText.includes('ZodError')) {\n zodErrorVars.add(param.getName());\n }\n }\n }\n\n // Check for .safeParse() result — the error is in result.error\n if (Node.isVariableDeclaration(node)) {\n const initializer = node.getInitializer();\n if (initializer?.getText().includes('.safeParse(')) {\n // The result of safeParse has a .error property that is ZodError\n zodErrorVars.add(`${node.getName()}.error`);\n }\n }\n\n // Check for import { ZodError } or new ZodError patterns\n if (Node.isNewExpression(node)) {\n if (node.getExpression().getText() === 'ZodError') {\n const parent = node.getParent();\n if (parent && Node.isVariableDeclaration(parent)) {\n zodErrorVars.add(parent.getName());\n }\n }\n }\n });\n\n // Now transform .errors -> .issues only on identified ZodError variables\n sourceFile.forEachDescendant((node) => {\n if (Node.isPropertyAccessExpression(node)) {\n const name = node.getName();\n if (name === 'errors') {\n const object = node.getExpression();\n const objectText = object.getText();\n\n // Check if this object is a known ZodError variable\n const isZodError =\n zodErrorVars.has(objectText) ||\n // Also check if accessing .error.errors (safeParse pattern)\n (objectText.endsWith('.error') &&\n zodErrorVars.has(`${objectText.replace(/\\.error$/, '')}.error`));\n\n if (isZodError) {\n const fullText = node.getText();\n const newText = fullText.replace(/\\.errors$/, '.issues');\n node.replaceWithText(newText);\n\n this.warnings.push(\n `${filePath}:${node.getStartLineNumber()}: ` +\n '.errors renamed to .issues (ZodError property change)',\n );\n }\n }\n }\n });\n }\n\n /**\n * Transform .flatten() usage — removed in v4.\n */\n private transformFlatten(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression) && expression.getName() === 'flatten') {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: .flatten() is removed in v4. ` +\n 'Use error.issues directly or implement custom flattening. ' +\n 'See: https://zod.dev/v4/changelog#flatten-removed',\n );\n }\n }\n });\n }\n\n /**\n * Transform .merge(otherSchema) to .extend(otherSchema.shape)\n */\n private transformMerge(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const nodesToTransform: Array<{ node: import('ts-morph').CallExpression; lineNumber: number }> =\n [];\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression) && expression.getName() === 'merge') {\n nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });\n }\n }\n });\n\n // Process in reverse order\n nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());\n\n for (const { node, lineNumber } of nodesToTransform) {\n const args = node.getArguments();\n if (args.length === 1) {\n const argText = args[0]?.getText();\n if (argText) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression)) {\n const objectText = expression.getExpression().getText();\n node.replaceWithText(`${objectText}.extend(${argText}.shape)`);\n this.warnings.push(\n `${filePath}:${lineNumber}: .merge() renamed to .extend() with .shape access. ` +\n 'Verify the merged schema exposes .shape.',\n );\n }\n }\n }\n }\n }\n\n /**\n * Transform z.nativeEnum(X) to z.enum(X)\n */\n private transformNativeEnum(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const fullText = sourceFile.getFullText();\n const newText = fullText.replace(/\\bz\\.nativeEnum\\(/g, 'z.enum(');\n if (newText !== fullText) {\n sourceFile.replaceWithText(newText);\n this.warnings.push(\n `${filePath}: z.nativeEnum() renamed to z.enum() in v4. ` +\n 'Verify enum values are compatible.',\n );\n }\n }\n\n /**\n * Check for deprecated methods and add warnings\n */\n private checkDeprecatedMethods(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n if (DEPRECATED_METHODS.has(name) && !AUTO_TRANSFORMABLE.has(name)) {\n const lineNumber = node.getStartLineNumber();\n switch (name) {\n case 'strict':\n this.warnings.push(\n `${filePath}:${lineNumber}: .strict() is deprecated in v4. ` +\n 'Use z.strictObject() instead.',\n );\n break;\n case 'passthrough':\n this.warnings.push(\n `${filePath}:${lineNumber}: .passthrough() is deprecated in v4. ` +\n 'Use z.looseObject() instead.',\n );\n break;\n // merge is handled by transformMerge\n }\n }\n }\n }\n });\n }\n\n /**\n * Auto-transform .superRefine() to .check() — callback signature is identical.\n */\n private transformSuperRefine(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const nodesToTransform: Array<{\n node: import('ts-morph').PropertyAccessExpression;\n lineNumber: number;\n }> = [];\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isPropertyAccessExpression(node) && node.getName() === 'superRefine') {\n nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });\n }\n });\n\n // Process in reverse to preserve positions\n nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());\n\n for (const { node, lineNumber } of nodesToTransform) {\n const parent = node.getParent();\n if (parent && Node.isCallExpression(parent)) {\n const objectText = node.getExpression().getText();\n const argsText = parent\n .getArguments()\n .map((a) => a.getText())\n .join(', ');\n parent.replaceWithText(`${objectText}.check(${argsText})`);\n this.warnings.push(\n `${filePath}:${lineNumber}: .superRefine() auto-transformed to .check() (deprecated in v4).`,\n );\n }\n }\n }\n\n /**\n * Auto-transform invalid_type_error/required_error params to unified `error` param.\n */\n private transformErrorParams(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const nodesToTransform: Array<{\n node: import('ts-morph').ObjectLiteralExpression;\n lineNumber: number;\n }> = [];\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isObjectLiteralExpression(node)) {\n const properties = node.getProperties();\n const propNames = properties\n .filter((p) => Node.isPropertyAssignment(p))\n .map((p) => (Node.isPropertyAssignment(p) ? p.getName() : ''));\n\n const hasInvalidType = propNames.includes('invalid_type_error');\n const hasRequired = propNames.includes('required_error');\n\n if (hasInvalidType || hasRequired) {\n // Only transform if this is an argument to a z.xxx() factory call\n const parent = node.getParent();\n if (parent && Node.isCallExpression(parent)) {\n const expr = parent.getExpression();\n if (Node.isPropertyAccessExpression(expr) && expr.getExpression().getText() === 'z') {\n nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });\n }\n }\n }\n }\n });\n\n // Process in reverse to preserve positions\n nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());\n\n for (const { node, lineNumber } of nodesToTransform) {\n const properties = node.getProperties();\n let invalidTypeValue: string | undefined;\n let requiredValue: string | undefined;\n const otherProps: string[] = [];\n\n for (const prop of properties) {\n if (Node.isPropertyAssignment(prop)) {\n const name = prop.getName();\n const value = prop.getInitializer()?.getText() ?? '';\n if (name === 'invalid_type_error') {\n invalidTypeValue = value;\n } else if (name === 'required_error') {\n requiredValue = value;\n } else {\n otherProps.push(prop.getText());\n }\n }\n }\n\n let errorValue: string;\n if (invalidTypeValue && requiredValue) {\n // Both present: generate error function\n errorValue = `error: (issue) => issue.input === undefined ? ${requiredValue} : ${invalidTypeValue}`;\n } else if (requiredValue) {\n errorValue = `error: ${requiredValue}`;\n } else if (invalidTypeValue) {\n errorValue = `error: ${invalidTypeValue}`;\n } else {\n continue;\n }\n\n const allProps = [errorValue, ...otherProps].join(', ');\n node.replaceWithText(`{ ${allProps} }`);\n\n this.warnings.push(\n `${filePath}:${lineNumber}: invalid_type_error/required_error auto-transformed to unified error param.`,\n );\n }\n }\n\n /**\n * Detect instanceof Error patterns in catch blocks that reference ZodError.\n * In v4, ZodError no longer extends Error.\n */\n private checkInstanceofError(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCatchClause(node)) {\n const block = node.getBlock();\n const blockText = block.getText();\n\n // Check if the catch block references ZodError AND uses instanceof Error\n if (blockText.includes('ZodError') && blockText.includes('instanceof Error')) {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: ZodError no longer extends Error in v4. ` +\n '`instanceof Error` checks on ZodError will return false. ' +\n 'Use `instanceof ZodError` or check for `.issues` property instead.',\n );\n }\n }\n });\n }\n\n /**\n * Detect .refine()/.superRefine() followed by .transform() in the same chain.\n * In v4, .transform() runs even when .refine() fails.\n */\n private checkTransformRefineOrder(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression) && expression.getName() === 'transform') {\n // Walk up the chain to see if .refine() or .superRefine() precedes\n const chainText = node.getText();\n if (\n chainText.includes('.refine(') ||\n chainText.includes('.superRefine(') ||\n chainText.includes('.check(')\n ) {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: In v4, .transform() executes even if preceding .refine() fails. ` +\n 'Consider using .pipe() to sequence validation before transforms.',\n );\n }\n }\n }\n });\n }\n\n /**\n * Detect .default() combined with .optional() — behavior changed silently in v4.\n * In v4, .default() always provides a value, making .optional() a no-op.\n */\n private checkDefaultOptional(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (\n Node.isPropertyAccessExpression(expression) &&\n (expression.getName() === 'optional' || expression.getName() === 'default')\n ) {\n const chainText = node.getText();\n const hasDefault = chainText.includes('.default(');\n const hasOptional = chainText.includes('.optional(');\n\n if (hasDefault && hasOptional) {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: .default() + .optional() behavior changed in v4. ` +\n '.default() now always provides a value, making .optional() effectively a no-op. ' +\n 'Review whether .optional() is still needed.',\n );\n }\n }\n }\n });\n }\n\n /**\n * Check for methods with behavior changes and add warnings\n */\n private checkBehaviorChanges(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n\n if (BEHAVIOR_CHANGES.has(name)) {\n const lineNumber = node.getStartLineNumber();\n\n switch (name) {\n case 'default':\n this.warnings.push(\n `${filePath}:${lineNumber}: .default() has stricter type inference in v4. ` +\n 'Verify default value matches schema type exactly.',\n );\n break;\n\n case 'uuid':\n this.warnings.push(\n `${filePath}:${lineNumber}: .uuid() now enforces strict RFC 4122 compliance. ` +\n 'Non-standard UUIDs may fail validation.',\n );\n break;\n\n case 'discriminatedUnion':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.discriminatedUnion() now requires ` +\n 'a literal type for the discriminator property.',\n );\n break;\n\n case 'function':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.function() parameter handling has changed. ` +\n 'Review input/output schema definitions.',\n );\n break;\n\n case 'pipe':\n this.warnings.push(\n `${filePath}:${lineNumber}: .pipe() has stricter type checking in v4. ` +\n 'If you get type errors, add explicit type annotations to .transform() return types ' +\n 'or cast through unknown as a last resort.',\n );\n break;\n }\n }\n\n // Check for .format() which was removed\n if (name === 'format') {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: .format() is removed in v4. ` +\n 'Use z.treeifyError() or custom error formatting. ' +\n 'See: https://zod.dev/v4/changelog',\n );\n }\n }\n }\n });\n }\n}\n","/**\n * Zod v3 to v4 Breaking Changes\n *\n * Key changes in Zod v4:\n * 1. z.record() now requires explicit key type\n * 2. .default() has stricter type inference\n * 3. error.errors renamed to error.issues\n * 4. .uuid() has stricter validation (RFC 4122 compliant)\n * 5. z.function() input/output changed\n * 6. Branded types use different syntax\n * 7. z.discriminatedUnion() requires literal discriminator\n */\n\n// Patterns that need transformation\nexport const V3_TO_V4_PATTERNS = {\n // z.record(valueSchema) -> z.record(z.string(), valueSchema)\n recordSingleArg: /z\\.record\\((?!z\\.string\\(\\)|z\\.number\\(\\)|z\\.symbol\\(\\))/g,\n\n // error.errors -> error.issues\n errorErrors: /\\.errors\\b/g,\n\n // .brand<T>() -> .brand<T>() (same but check for proper usage)\n brandUsage: /\\.brand<([^>]+)>\\(\\)/g,\n};\n\n// Methods that have changed behavior\nexport const BEHAVIOR_CHANGES = new Set([\n 'default', // Type inference changed\n 'uuid', // Stricter validation\n 'record', // Requires key type\n 'discriminatedUnion', // Stricter discriminator requirements\n 'function', // Input/output parameter changes\n 'pipe', // Stricter type checking in v4\n]);\n\n// Error property renames\nexport const ERROR_RENAMES: Record<string, string> = {\n errors: 'issues',\n formErrors: 'formErrors', // Unchanged\n fieldErrors: 'fieldErrors', // Unchanged\n};\n\n// Methods that are deprecated in v4\nexport const DEPRECATED_METHODS = new Set([\n 'merge', // Use .extend() instead\n 'superRefine', // Use .check() instead\n 'strict', // Use z.strictObject() instead\n 'passthrough', // Use z.looseObject() instead\n]);\n\n// Method renames in v4\nexport const METHOD_RENAMES: Record<string, string> = {\n merge: 'extend',\n};\n\n// Factory function renames in v4\nexport const FACTORY_RENAMES: Record<string, string> = {\n nativeEnum: 'enum',\n};\n\n// Error params that changed in v4 (unified under `error`)\nexport const ERROR_PARAM_NAMES = new Set(['invalid_type_error', 'required_error']);\n\n// Methods that can be automatically transformed (renamed) in v4\nexport const AUTO_TRANSFORMABLE = new Set([\n 'superRefine', // -> .check()\n]);\n\n// Runtime behavior patterns that silently break in v4 (no compile-time error)\nexport const RUNTIME_BREAK_PATTERNS = new Set([\n 'instanceofError', // ZodError no longer extends Error\n 'transformAfterRefine', // .transform() runs even when .refine() fails\n 'defaultOptional', // .default() + .optional() behavior change\n]);\n","import type { TransformHandler, TransformOptions, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport { ZodV3ToV4Transformer } from './transformer.js';\n\nexport function createZodV3ToV4Handler(): TransformHandler {\n const transformer = new ZodV3ToV4Transformer();\n return {\n transform(sourceFile: SourceFile, _options: TransformOptions): TransformResult {\n return transformer.transform(sourceFile);\n },\n };\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -30,6 +30,8 @@ declare const BEHAVIOR_CHANGES: Set<string>;
30
30
  * - error.errors -> error.issues
31
31
  * - Stricter UUID validation
32
32
  * - Type inference changes in .default()
33
+ * - .flatten() removed
34
+ * - z.preprocess() -> z.pipe() migration
33
35
  */
34
36
  declare class ZodV3ToV4Transformer {
35
37
  private errors;
@@ -40,9 +42,49 @@ declare class ZodV3ToV4Transformer {
40
42
  */
41
43
  private transformRecordCalls;
42
44
  /**
43
- * Transform error.errors to error.issues
45
+ * Transform error.errors to error.issues using AST-based detection
46
+ * instead of heuristic name matching.
44
47
  */
45
48
  private transformErrorProperties;
49
+ /**
50
+ * Transform .flatten() usage — removed in v4.
51
+ */
52
+ private transformFlatten;
53
+ /**
54
+ * Transform .merge(otherSchema) to .extend(otherSchema.shape)
55
+ */
56
+ private transformMerge;
57
+ /**
58
+ * Transform z.nativeEnum(X) to z.enum(X)
59
+ */
60
+ private transformNativeEnum;
61
+ /**
62
+ * Check for deprecated methods and add warnings
63
+ */
64
+ private checkDeprecatedMethods;
65
+ /**
66
+ * Auto-transform .superRefine() to .check() — callback signature is identical.
67
+ */
68
+ private transformSuperRefine;
69
+ /**
70
+ * Auto-transform invalid_type_error/required_error params to unified `error` param.
71
+ */
72
+ private transformErrorParams;
73
+ /**
74
+ * Detect instanceof Error patterns in catch blocks that reference ZodError.
75
+ * In v4, ZodError no longer extends Error.
76
+ */
77
+ private checkInstanceofError;
78
+ /**
79
+ * Detect .refine()/.superRefine() followed by .transform() in the same chain.
80
+ * In v4, .transform() runs even when .refine() fails.
81
+ */
82
+ private checkTransformRefineOrder;
83
+ /**
84
+ * Detect .default() combined with .optional() — behavior changed silently in v4.
85
+ * In v4, .default() always provides a value, making .optional() a no-op.
86
+ */
87
+ private checkDefaultOptional;
46
88
  /**
47
89
  * Check for methods with behavior changes and add warnings
48
90
  */
package/dist/index.d.ts CHANGED
@@ -30,6 +30,8 @@ declare const BEHAVIOR_CHANGES: Set<string>;
30
30
  * - error.errors -> error.issues
31
31
  * - Stricter UUID validation
32
32
  * - Type inference changes in .default()
33
+ * - .flatten() removed
34
+ * - z.preprocess() -> z.pipe() migration
33
35
  */
34
36
  declare class ZodV3ToV4Transformer {
35
37
  private errors;
@@ -40,9 +42,49 @@ declare class ZodV3ToV4Transformer {
40
42
  */
41
43
  private transformRecordCalls;
42
44
  /**
43
- * Transform error.errors to error.issues
45
+ * Transform error.errors to error.issues using AST-based detection
46
+ * instead of heuristic name matching.
44
47
  */
45
48
  private transformErrorProperties;
49
+ /**
50
+ * Transform .flatten() usage — removed in v4.
51
+ */
52
+ private transformFlatten;
53
+ /**
54
+ * Transform .merge(otherSchema) to .extend(otherSchema.shape)
55
+ */
56
+ private transformMerge;
57
+ /**
58
+ * Transform z.nativeEnum(X) to z.enum(X)
59
+ */
60
+ private transformNativeEnum;
61
+ /**
62
+ * Check for deprecated methods and add warnings
63
+ */
64
+ private checkDeprecatedMethods;
65
+ /**
66
+ * Auto-transform .superRefine() to .check() — callback signature is identical.
67
+ */
68
+ private transformSuperRefine;
69
+ /**
70
+ * Auto-transform invalid_type_error/required_error params to unified `error` param.
71
+ */
72
+ private transformErrorParams;
73
+ /**
74
+ * Detect instanceof Error patterns in catch blocks that reference ZodError.
75
+ * In v4, ZodError no longer extends Error.
76
+ */
77
+ private checkInstanceofError;
78
+ /**
79
+ * Detect .refine()/.superRefine() followed by .transform() in the same chain.
80
+ * In v4, .transform() runs even when .refine() fails.
81
+ */
82
+ private checkTransformRefineOrder;
83
+ /**
84
+ * Detect .default() combined with .optional() — behavior changed silently in v4.
85
+ * In v4, .default() always provides a value, making .optional() a no-op.
86
+ */
87
+ private checkDefaultOptional;
46
88
  /**
47
89
  * Check for methods with behavior changes and add warnings
48
90
  */
package/dist/index.js CHANGED
@@ -19,8 +19,24 @@ var BEHAVIOR_CHANGES = /* @__PURE__ */ new Set([
19
19
  // Requires key type
20
20
  "discriminatedUnion",
21
21
  // Stricter discriminator requirements
22
- "function"
22
+ "function",
23
23
  // Input/output parameter changes
24
+ "pipe"
25
+ // Stricter type checking in v4
26
+ ]);
27
+ var DEPRECATED_METHODS = /* @__PURE__ */ new Set([
28
+ "merge",
29
+ // Use .extend() instead
30
+ "superRefine",
31
+ // Use .check() instead
32
+ "strict",
33
+ // Use z.strictObject() instead
34
+ "passthrough"
35
+ // Use z.looseObject() instead
36
+ ]);
37
+ var AUTO_TRANSFORMABLE = /* @__PURE__ */ new Set([
38
+ "superRefine"
39
+ // -> .check()
24
40
  ]);
25
41
 
26
42
  // src/transformer.ts
@@ -34,8 +50,17 @@ var ZodV3ToV4Transformer = class {
34
50
  const originalCode = sourceFile.getFullText();
35
51
  try {
36
52
  this.transformRecordCalls(sourceFile);
53
+ this.transformMerge(sourceFile);
54
+ this.transformNativeEnum(sourceFile);
55
+ this.transformSuperRefine(sourceFile);
37
56
  this.transformErrorProperties(sourceFile);
57
+ this.transformErrorParams(sourceFile);
58
+ this.transformFlatten(sourceFile);
59
+ this.checkDeprecatedMethods(sourceFile);
38
60
  this.checkBehaviorChanges(sourceFile);
61
+ this.checkInstanceofError(sourceFile);
62
+ this.checkTransformRefineOrder(sourceFile);
63
+ this.checkDefaultOptional(sourceFile);
39
64
  return {
40
65
  success: this.errors.length === 0,
41
66
  filePath,
@@ -84,21 +109,297 @@ var ZodV3ToV4Transformer = class {
84
109
  });
85
110
  }
86
111
  /**
87
- * Transform error.errors to error.issues
112
+ * Transform error.errors to error.issues using AST-based detection
113
+ * instead of heuristic name matching.
88
114
  */
89
115
  transformErrorProperties(sourceFile) {
116
+ const filePath = sourceFile.getFilePath();
117
+ const zodErrorVars = /* @__PURE__ */ new Set();
118
+ sourceFile.forEachDescendant((node) => {
119
+ if (Node.isVariableDeclaration(node)) {
120
+ const typeNode = node.getTypeNode();
121
+ if (typeNode?.getText().includes("ZodError")) {
122
+ const name = node.getName();
123
+ zodErrorVars.add(name);
124
+ }
125
+ }
126
+ if (Node.isCatchClause(node)) {
127
+ const param = node.getVariableDeclaration();
128
+ if (param) {
129
+ const block = node.getBlock();
130
+ const blockText = block.getText();
131
+ if (blockText.includes("instanceof ZodError") || blockText.includes("ZodError")) {
132
+ zodErrorVars.add(param.getName());
133
+ }
134
+ }
135
+ }
136
+ if (Node.isVariableDeclaration(node)) {
137
+ const initializer = node.getInitializer();
138
+ if (initializer?.getText().includes(".safeParse(")) {
139
+ zodErrorVars.add(`${node.getName()}.error`);
140
+ }
141
+ }
142
+ if (Node.isNewExpression(node)) {
143
+ if (node.getExpression().getText() === "ZodError") {
144
+ const parent = node.getParent();
145
+ if (parent && Node.isVariableDeclaration(parent)) {
146
+ zodErrorVars.add(parent.getName());
147
+ }
148
+ }
149
+ }
150
+ });
90
151
  sourceFile.forEachDescendant((node) => {
91
152
  if (Node.isPropertyAccessExpression(node)) {
92
153
  const name = node.getName();
93
154
  if (name === "errors") {
94
155
  const object = node.getExpression();
95
156
  const objectText = object.getText();
96
- if (objectText.toLowerCase().includes("error") || objectText.toLowerCase().includes("err")) {
157
+ const isZodError = zodErrorVars.has(objectText) || // Also check if accessing .error.errors (safeParse pattern)
158
+ objectText.endsWith(".error") && zodErrorVars.has(`${objectText.replace(/\.error$/, "")}.error`);
159
+ if (isZodError) {
97
160
  const fullText = node.getText();
98
161
  const newText = fullText.replace(/\.errors$/, ".issues");
99
162
  node.replaceWithText(newText);
100
163
  this.warnings.push(
101
- `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: .errors renamed to .issues (ZodError property change)`
164
+ `${filePath}:${node.getStartLineNumber()}: .errors renamed to .issues (ZodError property change)`
165
+ );
166
+ }
167
+ }
168
+ }
169
+ });
170
+ }
171
+ /**
172
+ * Transform .flatten() usage — removed in v4.
173
+ */
174
+ transformFlatten(sourceFile) {
175
+ const filePath = sourceFile.getFilePath();
176
+ sourceFile.forEachDescendant((node) => {
177
+ if (Node.isCallExpression(node)) {
178
+ const expression = node.getExpression();
179
+ if (Node.isPropertyAccessExpression(expression) && expression.getName() === "flatten") {
180
+ const lineNumber = node.getStartLineNumber();
181
+ this.warnings.push(
182
+ `${filePath}:${lineNumber}: .flatten() is removed in v4. Use error.issues directly or implement custom flattening. See: https://zod.dev/v4/changelog#flatten-removed`
183
+ );
184
+ }
185
+ }
186
+ });
187
+ }
188
+ /**
189
+ * Transform .merge(otherSchema) to .extend(otherSchema.shape)
190
+ */
191
+ transformMerge(sourceFile) {
192
+ const filePath = sourceFile.getFilePath();
193
+ const nodesToTransform = [];
194
+ sourceFile.forEachDescendant((node) => {
195
+ if (Node.isCallExpression(node)) {
196
+ const expression = node.getExpression();
197
+ if (Node.isPropertyAccessExpression(expression) && expression.getName() === "merge") {
198
+ nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });
199
+ }
200
+ }
201
+ });
202
+ nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());
203
+ for (const { node, lineNumber } of nodesToTransform) {
204
+ const args = node.getArguments();
205
+ if (args.length === 1) {
206
+ const argText = args[0]?.getText();
207
+ if (argText) {
208
+ const expression = node.getExpression();
209
+ if (Node.isPropertyAccessExpression(expression)) {
210
+ const objectText = expression.getExpression().getText();
211
+ node.replaceWithText(`${objectText}.extend(${argText}.shape)`);
212
+ this.warnings.push(
213
+ `${filePath}:${lineNumber}: .merge() renamed to .extend() with .shape access. Verify the merged schema exposes .shape.`
214
+ );
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ /**
221
+ * Transform z.nativeEnum(X) to z.enum(X)
222
+ */
223
+ transformNativeEnum(sourceFile) {
224
+ const filePath = sourceFile.getFilePath();
225
+ const fullText = sourceFile.getFullText();
226
+ const newText = fullText.replace(/\bz\.nativeEnum\(/g, "z.enum(");
227
+ if (newText !== fullText) {
228
+ sourceFile.replaceWithText(newText);
229
+ this.warnings.push(
230
+ `${filePath}: z.nativeEnum() renamed to z.enum() in v4. Verify enum values are compatible.`
231
+ );
232
+ }
233
+ }
234
+ /**
235
+ * Check for deprecated methods and add warnings
236
+ */
237
+ checkDeprecatedMethods(sourceFile) {
238
+ const filePath = sourceFile.getFilePath();
239
+ sourceFile.forEachDescendant((node) => {
240
+ if (Node.isCallExpression(node)) {
241
+ const expression = node.getExpression();
242
+ if (Node.isPropertyAccessExpression(expression)) {
243
+ const name = expression.getName();
244
+ if (DEPRECATED_METHODS.has(name) && !AUTO_TRANSFORMABLE.has(name)) {
245
+ const lineNumber = node.getStartLineNumber();
246
+ switch (name) {
247
+ case "strict":
248
+ this.warnings.push(
249
+ `${filePath}:${lineNumber}: .strict() is deprecated in v4. Use z.strictObject() instead.`
250
+ );
251
+ break;
252
+ case "passthrough":
253
+ this.warnings.push(
254
+ `${filePath}:${lineNumber}: .passthrough() is deprecated in v4. Use z.looseObject() instead.`
255
+ );
256
+ break;
257
+ }
258
+ }
259
+ }
260
+ }
261
+ });
262
+ }
263
+ /**
264
+ * Auto-transform .superRefine() to .check() — callback signature is identical.
265
+ */
266
+ transformSuperRefine(sourceFile) {
267
+ const filePath = sourceFile.getFilePath();
268
+ const nodesToTransform = [];
269
+ sourceFile.forEachDescendant((node) => {
270
+ if (Node.isPropertyAccessExpression(node) && node.getName() === "superRefine") {
271
+ nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });
272
+ }
273
+ });
274
+ nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());
275
+ for (const { node, lineNumber } of nodesToTransform) {
276
+ const parent = node.getParent();
277
+ if (parent && Node.isCallExpression(parent)) {
278
+ const objectText = node.getExpression().getText();
279
+ const argsText = parent.getArguments().map((a) => a.getText()).join(", ");
280
+ parent.replaceWithText(`${objectText}.check(${argsText})`);
281
+ this.warnings.push(
282
+ `${filePath}:${lineNumber}: .superRefine() auto-transformed to .check() (deprecated in v4).`
283
+ );
284
+ }
285
+ }
286
+ }
287
+ /**
288
+ * Auto-transform invalid_type_error/required_error params to unified `error` param.
289
+ */
290
+ transformErrorParams(sourceFile) {
291
+ const filePath = sourceFile.getFilePath();
292
+ const nodesToTransform = [];
293
+ sourceFile.forEachDescendant((node) => {
294
+ if (Node.isObjectLiteralExpression(node)) {
295
+ const properties = node.getProperties();
296
+ const propNames = properties.filter((p) => Node.isPropertyAssignment(p)).map((p) => Node.isPropertyAssignment(p) ? p.getName() : "");
297
+ const hasInvalidType = propNames.includes("invalid_type_error");
298
+ const hasRequired = propNames.includes("required_error");
299
+ if (hasInvalidType || hasRequired) {
300
+ const parent = node.getParent();
301
+ if (parent && Node.isCallExpression(parent)) {
302
+ const expr = parent.getExpression();
303
+ if (Node.isPropertyAccessExpression(expr) && expr.getExpression().getText() === "z") {
304
+ nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });
305
+ }
306
+ }
307
+ }
308
+ }
309
+ });
310
+ nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());
311
+ for (const { node, lineNumber } of nodesToTransform) {
312
+ const properties = node.getProperties();
313
+ let invalidTypeValue;
314
+ let requiredValue;
315
+ const otherProps = [];
316
+ for (const prop of properties) {
317
+ if (Node.isPropertyAssignment(prop)) {
318
+ const name = prop.getName();
319
+ const value = prop.getInitializer()?.getText() ?? "";
320
+ if (name === "invalid_type_error") {
321
+ invalidTypeValue = value;
322
+ } else if (name === "required_error") {
323
+ requiredValue = value;
324
+ } else {
325
+ otherProps.push(prop.getText());
326
+ }
327
+ }
328
+ }
329
+ let errorValue;
330
+ if (invalidTypeValue && requiredValue) {
331
+ errorValue = `error: (issue) => issue.input === undefined ? ${requiredValue} : ${invalidTypeValue}`;
332
+ } else if (requiredValue) {
333
+ errorValue = `error: ${requiredValue}`;
334
+ } else if (invalidTypeValue) {
335
+ errorValue = `error: ${invalidTypeValue}`;
336
+ } else {
337
+ continue;
338
+ }
339
+ const allProps = [errorValue, ...otherProps].join(", ");
340
+ node.replaceWithText(`{ ${allProps} }`);
341
+ this.warnings.push(
342
+ `${filePath}:${lineNumber}: invalid_type_error/required_error auto-transformed to unified error param.`
343
+ );
344
+ }
345
+ }
346
+ /**
347
+ * Detect instanceof Error patterns in catch blocks that reference ZodError.
348
+ * In v4, ZodError no longer extends Error.
349
+ */
350
+ checkInstanceofError(sourceFile) {
351
+ const filePath = sourceFile.getFilePath();
352
+ sourceFile.forEachDescendant((node) => {
353
+ if (Node.isCatchClause(node)) {
354
+ const block = node.getBlock();
355
+ const blockText = block.getText();
356
+ if (blockText.includes("ZodError") && blockText.includes("instanceof Error")) {
357
+ const lineNumber = node.getStartLineNumber();
358
+ this.warnings.push(
359
+ `${filePath}:${lineNumber}: ZodError no longer extends Error in v4. \`instanceof Error\` checks on ZodError will return false. Use \`instanceof ZodError\` or check for \`.issues\` property instead.`
360
+ );
361
+ }
362
+ }
363
+ });
364
+ }
365
+ /**
366
+ * Detect .refine()/.superRefine() followed by .transform() in the same chain.
367
+ * In v4, .transform() runs even when .refine() fails.
368
+ */
369
+ checkTransformRefineOrder(sourceFile) {
370
+ const filePath = sourceFile.getFilePath();
371
+ sourceFile.forEachDescendant((node) => {
372
+ if (Node.isCallExpression(node)) {
373
+ const expression = node.getExpression();
374
+ if (Node.isPropertyAccessExpression(expression) && expression.getName() === "transform") {
375
+ const chainText = node.getText();
376
+ if (chainText.includes(".refine(") || chainText.includes(".superRefine(") || chainText.includes(".check(")) {
377
+ const lineNumber = node.getStartLineNumber();
378
+ this.warnings.push(
379
+ `${filePath}:${lineNumber}: In v4, .transform() executes even if preceding .refine() fails. Consider using .pipe() to sequence validation before transforms.`
380
+ );
381
+ }
382
+ }
383
+ }
384
+ });
385
+ }
386
+ /**
387
+ * Detect .default() combined with .optional() — behavior changed silently in v4.
388
+ * In v4, .default() always provides a value, making .optional() a no-op.
389
+ */
390
+ checkDefaultOptional(sourceFile) {
391
+ const filePath = sourceFile.getFilePath();
392
+ sourceFile.forEachDescendant((node) => {
393
+ if (Node.isCallExpression(node)) {
394
+ const expression = node.getExpression();
395
+ if (Node.isPropertyAccessExpression(expression) && (expression.getName() === "optional" || expression.getName() === "default")) {
396
+ const chainText = node.getText();
397
+ const hasDefault = chainText.includes(".default(");
398
+ const hasOptional = chainText.includes(".optional(");
399
+ if (hasDefault && hasOptional) {
400
+ const lineNumber = node.getStartLineNumber();
401
+ this.warnings.push(
402
+ `${filePath}:${lineNumber}: .default() + .optional() behavior changed in v4. .default() now always provides a value, making .optional() effectively a no-op. Review whether .optional() is still needed.`
102
403
  );
103
404
  }
104
405
  }
@@ -138,22 +439,22 @@ var ZodV3ToV4Transformer = class {
138
439
  `${filePath}:${lineNumber}: z.function() parameter handling has changed. Review input/output schema definitions.`
139
440
  );
140
441
  break;
442
+ case "pipe":
443
+ this.warnings.push(
444
+ `${filePath}:${lineNumber}: .pipe() has stricter type checking in v4. If you get type errors, add explicit type annotations to .transform() return types or cast through unknown as a last resort.`
445
+ );
446
+ break;
141
447
  }
142
448
  }
449
+ if (name === "format") {
450
+ const lineNumber = node.getStartLineNumber();
451
+ this.warnings.push(
452
+ `${filePath}:${lineNumber}: .format() is removed in v4. Use z.treeifyError() or custom error formatting. See: https://zod.dev/v4/changelog`
453
+ );
454
+ }
143
455
  }
144
456
  }
145
457
  });
146
- const text = sourceFile.getFullText();
147
- if (text.includes(".flatten()")) {
148
- const matches = text.matchAll(/\.flatten\(\)/g);
149
- for (const match of matches) {
150
- const pos = match.index ?? 0;
151
- const lineNumber = sourceFile.getLineAndColumnAtPos(pos).line;
152
- this.warnings.push(
153
- `${filePath}:${lineNumber}: .flatten() is removed in v4. Use error.issues directly or implement custom flattening.`
154
- );
155
- }
156
- }
157
458
  }
158
459
  };
159
460
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transformer.ts","../src/mappings.ts","../src/handler.ts"],"sourcesContent":["import type { TransformError, TransformResult } from '@schemashift/core';\nimport { Node, type SourceFile } from 'ts-morph';\nimport { BEHAVIOR_CHANGES } from './mappings.js';\n\n/**\n * Zod v3 to v4 Transformer\n *\n * Handles breaking changes between Zod v3 and v4:\n * - z.record() now requires explicit key type\n * - error.errors -> error.issues\n * - Stricter UUID validation\n * - Type inference changes in .default()\n */\nexport class ZodV3ToV4Transformer {\n private errors: TransformError[] = [];\n private warnings: string[] = [];\n\n transform(sourceFile: SourceFile): TransformResult {\n this.errors = [];\n this.warnings = [];\n\n const filePath = sourceFile.getFilePath();\n const originalCode = sourceFile.getFullText();\n\n try {\n this.transformRecordCalls(sourceFile);\n this.transformErrorProperties(sourceFile);\n this.checkBehaviorChanges(sourceFile);\n\n return {\n success: this.errors.length === 0,\n filePath,\n originalCode,\n transformedCode: sourceFile.getFullText(),\n errors: this.errors,\n warnings: this.warnings,\n };\n } catch (error) {\n this.errors.push({\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n return {\n success: false,\n filePath,\n originalCode,\n errors: this.errors,\n warnings: this.warnings,\n };\n }\n }\n\n /**\n * Transform z.record(valueSchema) to z.record(z.string(), valueSchema)\n */\n private transformRecordCalls(sourceFile: SourceFile): void {\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n // Check if this is z.record() call\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n const object = expression.getExpression();\n\n if (name === 'record' && object.getText() === 'z') {\n const args = node.getArguments();\n\n // If only one argument, add z.string() as key type\n if (args.length === 1) {\n const valueSchema = args[0]?.getText();\n if (valueSchema) {\n node.replaceWithText(`z.record(z.string(), ${valueSchema})`);\n\n this.warnings.push(\n `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: ` +\n 'z.record() updated to include explicit key type z.string()',\n );\n }\n }\n }\n }\n }\n });\n }\n\n /**\n * Transform error.errors to error.issues\n */\n private transformErrorProperties(sourceFile: SourceFile): void {\n sourceFile.forEachDescendant((node) => {\n if (Node.isPropertyAccessExpression(node)) {\n const name = node.getName();\n\n // Check for .errors property access that might be on ZodError\n if (name === 'errors') {\n const object = node.getExpression();\n const objectText = object.getText();\n\n // Heuristic: if the variable is named error, err, or zodError, likely a ZodError\n if (\n objectText.toLowerCase().includes('error') ||\n objectText.toLowerCase().includes('err')\n ) {\n // Replace .errors with .issues\n const fullText = node.getText();\n const newText = fullText.replace(/\\.errors$/, '.issues');\n node.replaceWithText(newText);\n\n this.warnings.push(\n `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: ` +\n '.errors renamed to .issues (ZodError property change)',\n );\n }\n }\n }\n });\n }\n\n /**\n * Check for methods with behavior changes and add warnings\n */\n private checkBehaviorChanges(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n\n if (BEHAVIOR_CHANGES.has(name)) {\n const lineNumber = node.getStartLineNumber();\n\n switch (name) {\n case 'default':\n this.warnings.push(\n `${filePath}:${lineNumber}: .default() has stricter type inference in v4. ` +\n 'Verify default value matches schema type exactly.',\n );\n break;\n\n case 'uuid':\n this.warnings.push(\n `${filePath}:${lineNumber}: .uuid() now enforces strict RFC 4122 compliance. ` +\n 'Non-standard UUIDs may fail validation.',\n );\n break;\n\n case 'discriminatedUnion':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.discriminatedUnion() now requires ` +\n 'a literal type for the discriminator property.',\n );\n break;\n\n case 'function':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.function() parameter handling has changed. ` +\n 'Review input/output schema definitions.',\n );\n break;\n }\n }\n }\n }\n });\n\n // Check for flatten() usage which is removed in v4\n const text = sourceFile.getFullText();\n if (text.includes('.flatten()')) {\n const matches = text.matchAll(/\\.flatten\\(\\)/g);\n for (const match of matches) {\n const pos = match.index ?? 0;\n const lineNumber = sourceFile.getLineAndColumnAtPos(pos).line;\n this.warnings.push(\n `${filePath}:${lineNumber}: .flatten() is removed in v4. ` +\n 'Use error.issues directly or implement custom flattening.',\n );\n }\n }\n }\n}\n","/**\n * Zod v3 to v4 Breaking Changes\n *\n * Key changes in Zod v4:\n * 1. z.record() now requires explicit key type\n * 2. .default() has stricter type inference\n * 3. error.errors renamed to error.issues\n * 4. .uuid() has stricter validation (RFC 4122 compliant)\n * 5. z.function() input/output changed\n * 6. Branded types use different syntax\n * 7. z.discriminatedUnion() requires literal discriminator\n */\n\n// Patterns that need transformation\nexport const V3_TO_V4_PATTERNS = {\n // z.record(valueSchema) -> z.record(z.string(), valueSchema)\n recordSingleArg: /z\\.record\\((?!z\\.string\\(\\)|z\\.number\\(\\)|z\\.symbol\\(\\))/g,\n\n // error.errors -> error.issues\n errorErrors: /\\.errors\\b/g,\n\n // .brand<T>() -> .brand<T>() (same but check for proper usage)\n brandUsage: /\\.brand<([^>]+)>\\(\\)/g,\n};\n\n// Methods that have changed behavior\nexport const BEHAVIOR_CHANGES = new Set([\n 'default', // Type inference changed\n 'uuid', // Stricter validation\n 'record', // Requires key type\n 'discriminatedUnion', // Stricter discriminator requirements\n 'function', // Input/output parameter changes\n]);\n\n// Error property renames\nexport const ERROR_RENAMES: Record<string, string> = {\n errors: 'issues',\n formErrors: 'formErrors', // Unchanged\n fieldErrors: 'fieldErrors', // Unchanged\n};\n\n// Methods that are deprecated in v4\nexport const DEPRECATED_METHODS = new Set([\n // Add any deprecated methods here\n]);\n","import type { TransformHandler, TransformOptions, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport { ZodV3ToV4Transformer } from './transformer.js';\n\nexport function createZodV3ToV4Handler(): TransformHandler {\n const transformer = new ZodV3ToV4Transformer();\n return {\n transform(sourceFile: SourceFile, _options: TransformOptions): TransformResult {\n return transformer.transform(sourceFile);\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/transformer.ts","../src/mappings.ts","../src/handler.ts"],"sourcesContent":["import type { TransformError, TransformResult } from '@schemashift/core';\nimport { Node, type SourceFile } from 'ts-morph';\nimport { AUTO_TRANSFORMABLE, BEHAVIOR_CHANGES, DEPRECATED_METHODS } from './mappings.js';\n\n/**\n * Zod v3 to v4 Transformer\n *\n * Handles breaking changes between Zod v3 and v4:\n * - z.record() now requires explicit key type\n * - error.errors -> error.issues\n * - Stricter UUID validation\n * - Type inference changes in .default()\n * - .flatten() removed\n * - z.preprocess() -> z.pipe() migration\n */\nexport class ZodV3ToV4Transformer {\n private errors: TransformError[] = [];\n private warnings: string[] = [];\n\n transform(sourceFile: SourceFile): TransformResult {\n this.errors = [];\n this.warnings = [];\n\n const filePath = sourceFile.getFilePath();\n const originalCode = sourceFile.getFullText();\n\n try {\n this.transformRecordCalls(sourceFile);\n this.transformMerge(sourceFile);\n this.transformNativeEnum(sourceFile);\n this.transformSuperRefine(sourceFile);\n this.transformErrorProperties(sourceFile);\n this.transformErrorParams(sourceFile);\n this.transformFlatten(sourceFile);\n this.checkDeprecatedMethods(sourceFile);\n this.checkBehaviorChanges(sourceFile);\n this.checkInstanceofError(sourceFile);\n this.checkTransformRefineOrder(sourceFile);\n this.checkDefaultOptional(sourceFile);\n\n return {\n success: this.errors.length === 0,\n filePath,\n originalCode,\n transformedCode: sourceFile.getFullText(),\n errors: this.errors,\n warnings: this.warnings,\n };\n } catch (error) {\n this.errors.push({\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n return {\n success: false,\n filePath,\n originalCode,\n errors: this.errors,\n warnings: this.warnings,\n };\n }\n }\n\n /**\n * Transform z.record(valueSchema) to z.record(z.string(), valueSchema)\n */\n private transformRecordCalls(sourceFile: SourceFile): void {\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n const object = expression.getExpression();\n\n if (name === 'record' && object.getText() === 'z') {\n const args = node.getArguments();\n\n // If only one argument, add z.string() as key type\n if (args.length === 1) {\n const valueSchema = args[0]?.getText();\n if (valueSchema) {\n node.replaceWithText(`z.record(z.string(), ${valueSchema})`);\n\n this.warnings.push(\n `${sourceFile.getFilePath()}:${node.getStartLineNumber()}: ` +\n 'z.record() updated to include explicit key type z.string()',\n );\n }\n }\n }\n }\n }\n });\n }\n\n /**\n * Transform error.errors to error.issues using AST-based detection\n * instead of heuristic name matching.\n */\n private transformErrorProperties(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n // First, find all variables that are likely ZodError instances\n const zodErrorVars = new Set<string>();\n\n sourceFile.forEachDescendant((node) => {\n // Check variable declarations with ZodError type annotation\n if (Node.isVariableDeclaration(node)) {\n const typeNode = node.getTypeNode();\n if (typeNode?.getText().includes('ZodError')) {\n const name = node.getName();\n zodErrorVars.add(name);\n }\n }\n\n // Check catch clause parameters\n if (Node.isCatchClause(node)) {\n const param = node.getVariableDeclaration();\n if (param) {\n // Check if the catch block uses instanceof ZodError\n const block = node.getBlock();\n const blockText = block.getText();\n if (blockText.includes('instanceof ZodError') || blockText.includes('ZodError')) {\n zodErrorVars.add(param.getName());\n }\n }\n }\n\n // Check for .safeParse() result — the error is in result.error\n if (Node.isVariableDeclaration(node)) {\n const initializer = node.getInitializer();\n if (initializer?.getText().includes('.safeParse(')) {\n // The result of safeParse has a .error property that is ZodError\n zodErrorVars.add(`${node.getName()}.error`);\n }\n }\n\n // Check for import { ZodError } or new ZodError patterns\n if (Node.isNewExpression(node)) {\n if (node.getExpression().getText() === 'ZodError') {\n const parent = node.getParent();\n if (parent && Node.isVariableDeclaration(parent)) {\n zodErrorVars.add(parent.getName());\n }\n }\n }\n });\n\n // Now transform .errors -> .issues only on identified ZodError variables\n sourceFile.forEachDescendant((node) => {\n if (Node.isPropertyAccessExpression(node)) {\n const name = node.getName();\n if (name === 'errors') {\n const object = node.getExpression();\n const objectText = object.getText();\n\n // Check if this object is a known ZodError variable\n const isZodError =\n zodErrorVars.has(objectText) ||\n // Also check if accessing .error.errors (safeParse pattern)\n (objectText.endsWith('.error') &&\n zodErrorVars.has(`${objectText.replace(/\\.error$/, '')}.error`));\n\n if (isZodError) {\n const fullText = node.getText();\n const newText = fullText.replace(/\\.errors$/, '.issues');\n node.replaceWithText(newText);\n\n this.warnings.push(\n `${filePath}:${node.getStartLineNumber()}: ` +\n '.errors renamed to .issues (ZodError property change)',\n );\n }\n }\n }\n });\n }\n\n /**\n * Transform .flatten() usage — removed in v4.\n */\n private transformFlatten(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression) && expression.getName() === 'flatten') {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: .flatten() is removed in v4. ` +\n 'Use error.issues directly or implement custom flattening. ' +\n 'See: https://zod.dev/v4/changelog#flatten-removed',\n );\n }\n }\n });\n }\n\n /**\n * Transform .merge(otherSchema) to .extend(otherSchema.shape)\n */\n private transformMerge(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const nodesToTransform: Array<{ node: import('ts-morph').CallExpression; lineNumber: number }> =\n [];\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression) && expression.getName() === 'merge') {\n nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });\n }\n }\n });\n\n // Process in reverse order\n nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());\n\n for (const { node, lineNumber } of nodesToTransform) {\n const args = node.getArguments();\n if (args.length === 1) {\n const argText = args[0]?.getText();\n if (argText) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression)) {\n const objectText = expression.getExpression().getText();\n node.replaceWithText(`${objectText}.extend(${argText}.shape)`);\n this.warnings.push(\n `${filePath}:${lineNumber}: .merge() renamed to .extend() with .shape access. ` +\n 'Verify the merged schema exposes .shape.',\n );\n }\n }\n }\n }\n }\n\n /**\n * Transform z.nativeEnum(X) to z.enum(X)\n */\n private transformNativeEnum(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const fullText = sourceFile.getFullText();\n const newText = fullText.replace(/\\bz\\.nativeEnum\\(/g, 'z.enum(');\n if (newText !== fullText) {\n sourceFile.replaceWithText(newText);\n this.warnings.push(\n `${filePath}: z.nativeEnum() renamed to z.enum() in v4. ` +\n 'Verify enum values are compatible.',\n );\n }\n }\n\n /**\n * Check for deprecated methods and add warnings\n */\n private checkDeprecatedMethods(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n if (DEPRECATED_METHODS.has(name) && !AUTO_TRANSFORMABLE.has(name)) {\n const lineNumber = node.getStartLineNumber();\n switch (name) {\n case 'strict':\n this.warnings.push(\n `${filePath}:${lineNumber}: .strict() is deprecated in v4. ` +\n 'Use z.strictObject() instead.',\n );\n break;\n case 'passthrough':\n this.warnings.push(\n `${filePath}:${lineNumber}: .passthrough() is deprecated in v4. ` +\n 'Use z.looseObject() instead.',\n );\n break;\n // merge is handled by transformMerge\n }\n }\n }\n }\n });\n }\n\n /**\n * Auto-transform .superRefine() to .check() — callback signature is identical.\n */\n private transformSuperRefine(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const nodesToTransform: Array<{\n node: import('ts-morph').PropertyAccessExpression;\n lineNumber: number;\n }> = [];\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isPropertyAccessExpression(node) && node.getName() === 'superRefine') {\n nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });\n }\n });\n\n // Process in reverse to preserve positions\n nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());\n\n for (const { node, lineNumber } of nodesToTransform) {\n const parent = node.getParent();\n if (parent && Node.isCallExpression(parent)) {\n const objectText = node.getExpression().getText();\n const argsText = parent\n .getArguments()\n .map((a) => a.getText())\n .join(', ');\n parent.replaceWithText(`${objectText}.check(${argsText})`);\n this.warnings.push(\n `${filePath}:${lineNumber}: .superRefine() auto-transformed to .check() (deprecated in v4).`,\n );\n }\n }\n }\n\n /**\n * Auto-transform invalid_type_error/required_error params to unified `error` param.\n */\n private transformErrorParams(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n const nodesToTransform: Array<{\n node: import('ts-morph').ObjectLiteralExpression;\n lineNumber: number;\n }> = [];\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isObjectLiteralExpression(node)) {\n const properties = node.getProperties();\n const propNames = properties\n .filter((p) => Node.isPropertyAssignment(p))\n .map((p) => (Node.isPropertyAssignment(p) ? p.getName() : ''));\n\n const hasInvalidType = propNames.includes('invalid_type_error');\n const hasRequired = propNames.includes('required_error');\n\n if (hasInvalidType || hasRequired) {\n // Only transform if this is an argument to a z.xxx() factory call\n const parent = node.getParent();\n if (parent && Node.isCallExpression(parent)) {\n const expr = parent.getExpression();\n if (Node.isPropertyAccessExpression(expr) && expr.getExpression().getText() === 'z') {\n nodesToTransform.push({ node, lineNumber: node.getStartLineNumber() });\n }\n }\n }\n }\n });\n\n // Process in reverse to preserve positions\n nodesToTransform.sort((a, b) => b.node.getStart() - a.node.getStart());\n\n for (const { node, lineNumber } of nodesToTransform) {\n const properties = node.getProperties();\n let invalidTypeValue: string | undefined;\n let requiredValue: string | undefined;\n const otherProps: string[] = [];\n\n for (const prop of properties) {\n if (Node.isPropertyAssignment(prop)) {\n const name = prop.getName();\n const value = prop.getInitializer()?.getText() ?? '';\n if (name === 'invalid_type_error') {\n invalidTypeValue = value;\n } else if (name === 'required_error') {\n requiredValue = value;\n } else {\n otherProps.push(prop.getText());\n }\n }\n }\n\n let errorValue: string;\n if (invalidTypeValue && requiredValue) {\n // Both present: generate error function\n errorValue = `error: (issue) => issue.input === undefined ? ${requiredValue} : ${invalidTypeValue}`;\n } else if (requiredValue) {\n errorValue = `error: ${requiredValue}`;\n } else if (invalidTypeValue) {\n errorValue = `error: ${invalidTypeValue}`;\n } else {\n continue;\n }\n\n const allProps = [errorValue, ...otherProps].join(', ');\n node.replaceWithText(`{ ${allProps} }`);\n\n this.warnings.push(\n `${filePath}:${lineNumber}: invalid_type_error/required_error auto-transformed to unified error param.`,\n );\n }\n }\n\n /**\n * Detect instanceof Error patterns in catch blocks that reference ZodError.\n * In v4, ZodError no longer extends Error.\n */\n private checkInstanceofError(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCatchClause(node)) {\n const block = node.getBlock();\n const blockText = block.getText();\n\n // Check if the catch block references ZodError AND uses instanceof Error\n if (blockText.includes('ZodError') && blockText.includes('instanceof Error')) {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: ZodError no longer extends Error in v4. ` +\n '`instanceof Error` checks on ZodError will return false. ' +\n 'Use `instanceof ZodError` or check for `.issues` property instead.',\n );\n }\n }\n });\n }\n\n /**\n * Detect .refine()/.superRefine() followed by .transform() in the same chain.\n * In v4, .transform() runs even when .refine() fails.\n */\n private checkTransformRefineOrder(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (Node.isPropertyAccessExpression(expression) && expression.getName() === 'transform') {\n // Walk up the chain to see if .refine() or .superRefine() precedes\n const chainText = node.getText();\n if (\n chainText.includes('.refine(') ||\n chainText.includes('.superRefine(') ||\n chainText.includes('.check(')\n ) {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: In v4, .transform() executes even if preceding .refine() fails. ` +\n 'Consider using .pipe() to sequence validation before transforms.',\n );\n }\n }\n }\n });\n }\n\n /**\n * Detect .default() combined with .optional() — behavior changed silently in v4.\n * In v4, .default() always provides a value, making .optional() a no-op.\n */\n private checkDefaultOptional(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n if (\n Node.isPropertyAccessExpression(expression) &&\n (expression.getName() === 'optional' || expression.getName() === 'default')\n ) {\n const chainText = node.getText();\n const hasDefault = chainText.includes('.default(');\n const hasOptional = chainText.includes('.optional(');\n\n if (hasDefault && hasOptional) {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: .default() + .optional() behavior changed in v4. ` +\n '.default() now always provides a value, making .optional() effectively a no-op. ' +\n 'Review whether .optional() is still needed.',\n );\n }\n }\n }\n });\n }\n\n /**\n * Check for methods with behavior changes and add warnings\n */\n private checkBehaviorChanges(sourceFile: SourceFile): void {\n const filePath = sourceFile.getFilePath();\n\n sourceFile.forEachDescendant((node) => {\n if (Node.isCallExpression(node)) {\n const expression = node.getExpression();\n\n if (Node.isPropertyAccessExpression(expression)) {\n const name = expression.getName();\n\n if (BEHAVIOR_CHANGES.has(name)) {\n const lineNumber = node.getStartLineNumber();\n\n switch (name) {\n case 'default':\n this.warnings.push(\n `${filePath}:${lineNumber}: .default() has stricter type inference in v4. ` +\n 'Verify default value matches schema type exactly.',\n );\n break;\n\n case 'uuid':\n this.warnings.push(\n `${filePath}:${lineNumber}: .uuid() now enforces strict RFC 4122 compliance. ` +\n 'Non-standard UUIDs may fail validation.',\n );\n break;\n\n case 'discriminatedUnion':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.discriminatedUnion() now requires ` +\n 'a literal type for the discriminator property.',\n );\n break;\n\n case 'function':\n this.warnings.push(\n `${filePath}:${lineNumber}: z.function() parameter handling has changed. ` +\n 'Review input/output schema definitions.',\n );\n break;\n\n case 'pipe':\n this.warnings.push(\n `${filePath}:${lineNumber}: .pipe() has stricter type checking in v4. ` +\n 'If you get type errors, add explicit type annotations to .transform() return types ' +\n 'or cast through unknown as a last resort.',\n );\n break;\n }\n }\n\n // Check for .format() which was removed\n if (name === 'format') {\n const lineNumber = node.getStartLineNumber();\n this.warnings.push(\n `${filePath}:${lineNumber}: .format() is removed in v4. ` +\n 'Use z.treeifyError() or custom error formatting. ' +\n 'See: https://zod.dev/v4/changelog',\n );\n }\n }\n }\n });\n }\n}\n","/**\n * Zod v3 to v4 Breaking Changes\n *\n * Key changes in Zod v4:\n * 1. z.record() now requires explicit key type\n * 2. .default() has stricter type inference\n * 3. error.errors renamed to error.issues\n * 4. .uuid() has stricter validation (RFC 4122 compliant)\n * 5. z.function() input/output changed\n * 6. Branded types use different syntax\n * 7. z.discriminatedUnion() requires literal discriminator\n */\n\n// Patterns that need transformation\nexport const V3_TO_V4_PATTERNS = {\n // z.record(valueSchema) -> z.record(z.string(), valueSchema)\n recordSingleArg: /z\\.record\\((?!z\\.string\\(\\)|z\\.number\\(\\)|z\\.symbol\\(\\))/g,\n\n // error.errors -> error.issues\n errorErrors: /\\.errors\\b/g,\n\n // .brand<T>() -> .brand<T>() (same but check for proper usage)\n brandUsage: /\\.brand<([^>]+)>\\(\\)/g,\n};\n\n// Methods that have changed behavior\nexport const BEHAVIOR_CHANGES = new Set([\n 'default', // Type inference changed\n 'uuid', // Stricter validation\n 'record', // Requires key type\n 'discriminatedUnion', // Stricter discriminator requirements\n 'function', // Input/output parameter changes\n 'pipe', // Stricter type checking in v4\n]);\n\n// Error property renames\nexport const ERROR_RENAMES: Record<string, string> = {\n errors: 'issues',\n formErrors: 'formErrors', // Unchanged\n fieldErrors: 'fieldErrors', // Unchanged\n};\n\n// Methods that are deprecated in v4\nexport const DEPRECATED_METHODS = new Set([\n 'merge', // Use .extend() instead\n 'superRefine', // Use .check() instead\n 'strict', // Use z.strictObject() instead\n 'passthrough', // Use z.looseObject() instead\n]);\n\n// Method renames in v4\nexport const METHOD_RENAMES: Record<string, string> = {\n merge: 'extend',\n};\n\n// Factory function renames in v4\nexport const FACTORY_RENAMES: Record<string, string> = {\n nativeEnum: 'enum',\n};\n\n// Error params that changed in v4 (unified under `error`)\nexport const ERROR_PARAM_NAMES = new Set(['invalid_type_error', 'required_error']);\n\n// Methods that can be automatically transformed (renamed) in v4\nexport const AUTO_TRANSFORMABLE = new Set([\n 'superRefine', // -> .check()\n]);\n\n// Runtime behavior patterns that silently break in v4 (no compile-time error)\nexport const RUNTIME_BREAK_PATTERNS = new Set([\n 'instanceofError', // ZodError no longer extends Error\n 'transformAfterRefine', // .transform() runs even when .refine() fails\n 'defaultOptional', // .default() + .optional() behavior change\n]);\n","import type { TransformHandler, TransformOptions, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport { ZodV3ToV4Transformer } from './transformer.js';\n\nexport function createZodV3ToV4Handler(): TransformHandler {\n const transformer = new ZodV3ToV4Transformer();\n return {\n transform(sourceFile: SourceFile, _options: TransformOptions): TransformResult {\n return transformer.transform(sourceFile);\n },\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,17 @@
1
1
  {
2
2
  "name": "@schemashift/zod-v3-v4",
3
- "version": "0.2.0",
3
+ "version": "0.7.0",
4
+ "description": "Zod v3 to v4 upgrade transformer for SchemaShift — handles 17+ breaking changes with auto-transforms and runtime warnings",
5
+ "keywords": [
6
+ "zod",
7
+ "v3",
8
+ "v4",
9
+ "migration",
10
+ "upgrade",
11
+ "breaking-changes",
12
+ "schema",
13
+ "transformer"
14
+ ],
4
15
  "type": "module",
5
16
  "main": "./dist/index.cjs",
6
17
  "module": "./dist/index.js",
@@ -26,7 +37,7 @@
26
37
  "typecheck": "tsc --noEmit"
27
38
  },
28
39
  "dependencies": {
29
- "@schemashift/core": "0.2.0",
40
+ "@schemashift/core": "0.7.0",
30
41
  "ts-morph": "27.0.2"
31
42
  },
32
43
  "publishConfig": {