zod-v3-to-v4 1.7.1 → 1.8.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/dist/migrate.js CHANGED
@@ -3,6 +3,7 @@ import { findRootExpression } from "./ast.js";
3
3
  import { collectZodImportDeclarations, collectZodReferences, getZodName, } from "./collect-imports.js";
4
4
  import { convertZArrayPatternsToTopLevelApi, convertZCoercePatternsToTopLevelApi, convertZFunctionPatternsToTopLevelApi, convertZNumberPatternsToZInt, convertZObjectPatternsToTopLevelApi, convertZRecordPatternsToTopLevelApi, convertZStringPatternsToTopLevelApi, } from "./convert-name-to-top-level-api.js";
5
5
  import { convertDeprecatedErrorKeysToErrorFunction, convertErrorMapToErrorFunction, convertMessageKeyToError, convertZodErrorAddIssueToDirectPushes, convertZodErrorToTreeifyError, } from "./convert-zod-errors.js";
6
+ import { replaceDeletedTypes } from "./replace-deleted-types.js";
6
7
  import { isZodNode } from "./zod-node.js";
7
8
  export function migrateZodV3ToV4(sourceFile, options = {}) {
8
9
  const importDeclarations = collectZodImportDeclarations(sourceFile);
@@ -17,7 +18,10 @@ export function migrateZodV3ToV4(sourceFile, options = {}) {
17
18
  declaration.setModuleSpecifier("zod/v4");
18
19
  }
19
20
  });
20
- collectZodReferences(importDeclarations).forEach((node) => {
21
+ // Collect references before modifying imports
22
+ const zodReferences = collectZodReferences(importDeclarations);
23
+ replaceDeletedTypes(importDeclarations, zodReferences);
24
+ zodReferences.forEach((node) => {
21
25
  if (node.wasForgotten()) {
22
26
  return;
23
27
  }
@@ -0,0 +1,75 @@
1
+ import { SyntaxKind } from "ts-morph";
2
+ const DELETED_TYPES = [
3
+ {
4
+ name: "AnyZodObject",
5
+ importName: "ZodRecord",
6
+ getReplacement: () => "ZodRecord<any, any>",
7
+ },
8
+ {
9
+ name: "SafeParseReturnType",
10
+ importName: "ZodSafeParseResult",
11
+ getReplacement: (node) => {
12
+ // SafeParseReturnType<I, O> -> ZodSafeParseResult<O>
13
+ // Keep only the second type argument for consistency
14
+ // See https://github.com/colinhacks/zod/issues/5195
15
+ const typeRef = node.getFirstAncestorByKind(SyntaxKind.TypeReference);
16
+ const secondArg = typeRef?.getTypeArguments()?.[1];
17
+ return secondArg
18
+ ? `ZodSafeParseResult<${secondArg.getText()}>`
19
+ : "ZodSafeParseResult<unknown>";
20
+ },
21
+ },
22
+ {
23
+ name: "ZodTypeAny",
24
+ importName: "ZodType",
25
+ getReplacement: () => "ZodType",
26
+ },
27
+ ];
28
+ export function replaceDeletedTypes(importDeclarations, zodReferences) {
29
+ // Update imports: remove deleted types and add replacements
30
+ importDeclarations.forEach((declaration) => {
31
+ for (const { name, importName } of DELETED_TYPES) {
32
+ const namedImports = declaration.getNamedImports();
33
+ const deletedImport = namedImports.find((i) => i.getName() === name);
34
+ if (deletedImport) {
35
+ const hasReplacementImport = namedImports.some((i) => i.getName() === importName);
36
+ deletedImport.remove();
37
+ if (!hasReplacementImport) {
38
+ declaration.addNamedImport(importName);
39
+ }
40
+ }
41
+ }
42
+ });
43
+ // Replace references in code
44
+ zodReferences.forEach((node) => {
45
+ if (node.wasForgotten()) {
46
+ return;
47
+ }
48
+ for (const { name, importName, getReplacement } of DELETED_TYPES) {
49
+ // Handle direct imports (e.g., `import { AnyZodObject }`)
50
+ if (node.getText() === name) {
51
+ const typeRef = node.getFirstAncestorByKind(SyntaxKind.TypeReference);
52
+ if (typeRef) {
53
+ typeRef.replaceWithText(getReplacement(node));
54
+ }
55
+ else {
56
+ node.replaceWithText(getReplacement(node));
57
+ }
58
+ return;
59
+ }
60
+ // Handle prefixed access (e.g., `z.AnyZodObject`)
61
+ const qualifiedName = node.getFirstAncestorByKind(SyntaxKind.QualifiedName);
62
+ if (qualifiedName?.getText().endsWith(`.${name}`)) {
63
+ const typeRef = qualifiedName.getFirstAncestorByKind(SyntaxKind.TypeReference);
64
+ const zodPrefix = node.getText();
65
+ if (typeRef) {
66
+ typeRef.replaceWithText(`${zodPrefix}.${getReplacement(node)}`);
67
+ }
68
+ else {
69
+ qualifiedName.replaceWithText(`${zodPrefix}.${importName}`);
70
+ }
71
+ return;
72
+ }
73
+ }
74
+ });
75
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-v3-to-v4",
3
- "version": "1.7.1",
3
+ "version": "1.8.0",
4
4
  "description": "Migrate Zod from v3 to v4",
5
5
  "keywords": [
6
6
  "zod",