zod-v3-to-v4 1.11.0 → 1.12.1
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 +2 -0
- package/dist/convert-name-to-top-level-api.js +52 -0
- package/dist/convert-zod-errors.js +36 -0
- package/dist/index.js +1 -1
- package/dist/migrate.js +3 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -133,6 +133,8 @@ pnpm playground:interactive
|
|
|
133
133
|
<td align="center" valign="top" width="14.28%"><a href="http://adam.doussan.info"><img src="https://avatars.githubusercontent.com/u/26745150?v=4?s=100" width="100px;" alt="acdoussan"/><br /><sub><b>acdoussan</b></sub></a><br /><a href="https://github.com/nicoespeon/zod-v3-to-v4/issues?q=author%3Aacdoussan" title="Bug reports">🐛</a></td>
|
|
134
134
|
<td align="center" valign="top" width="14.28%"><a href="http://matsjfunke.com"><img src="https://avatars.githubusercontent.com/u/125814808?v=4?s=100" width="100px;" alt="Mats Julius Funke"/><br /><sub><b>Mats Julius Funke</b></sub></a><br /><a href="#ideas-matsjfunke" title="Ideas, Planning, & Feedback">🤔</a></td>
|
|
135
135
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/popfendi"><img src="https://avatars.githubusercontent.com/u/84185235?v=4?s=100" width="100px;" alt="popfendi"/><br /><sub><b>popfendi</b></sub></a><br /><a href="https://github.com/nicoespeon/zod-v3-to-v4/issues?q=author%3Apopfendi" title="Bug reports">🐛</a></td>
|
|
136
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luis-azevedo-visma"><img src="https://avatars.githubusercontent.com/u/149402066?v=4?s=100" width="100px;" alt="Luís Azevedo"/><br /><sub><b>Luís Azevedo</b></sub></a><br /><a href="#ideas-luis-azevedo-visma" title="Ideas, Planning, & Feedback">🤔</a></td>
|
|
137
|
+
<td align="center" valign="top" width="14.28%"><a href="https://florian-lefebvre.dev"><img src="https://avatars.githubusercontent.com/u/69633530?v=4?s=100" width="100px;" alt="Florian Lefebvre"/><br /><sub><b>Florian Lefebvre</b></sub></a><br /><a href="https://github.com/nicoespeon/zod-v3-to-v4/issues?q=author%3Aflorian-lefebvre" title="Bug reports">🐛</a></td>
|
|
136
138
|
</tr>
|
|
137
139
|
</tbody>
|
|
138
140
|
<tfoot>
|
|
@@ -85,6 +85,8 @@ export function convertZCoercePatternsToTopLevelApi(node, zodName) {
|
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
export function convertZObjectPatternsToTopLevelApi(node, zodName) {
|
|
88
|
+
// First, convert z.object() methods like .strict() or .passthrough()
|
|
89
|
+
convertObjectMethodOnSchemaReference(node, zodName);
|
|
88
90
|
convertNameToTopLevelApi(node, {
|
|
89
91
|
zodName,
|
|
90
92
|
oldName: "object",
|
|
@@ -98,6 +100,56 @@ export function convertZObjectPatternsToTopLevelApi(node, zodName) {
|
|
|
98
100
|
});
|
|
99
101
|
convertZObjectMergeToExtend(node);
|
|
100
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* @example
|
|
105
|
+
* UserSchema.pick({ id: true }).strict()
|
|
106
|
+
* // becomes
|
|
107
|
+
* z.strictObject(UserSchema.pick({ id: true }).shape)
|
|
108
|
+
*/
|
|
109
|
+
function convertObjectMethodOnSchemaReference(node, zodName) {
|
|
110
|
+
const methodMappings = {
|
|
111
|
+
strict: "strictObject",
|
|
112
|
+
passthrough: "looseObject",
|
|
113
|
+
strip: "object",
|
|
114
|
+
nonstrict: "object",
|
|
115
|
+
};
|
|
116
|
+
const methodNames = Object.keys(methodMappings);
|
|
117
|
+
node
|
|
118
|
+
.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)
|
|
119
|
+
// Start from the deepest to handle nested cases
|
|
120
|
+
.reverse()
|
|
121
|
+
.filter((e) => methodNames.includes(e.getName()))
|
|
122
|
+
.forEach((propertyAccess) => {
|
|
123
|
+
const methodName = propertyAccess.getName();
|
|
124
|
+
const parent = propertyAccess.getFirstAncestorByKind(SyntaxKind.CallExpression);
|
|
125
|
+
if (!parent || parent.getExpression() !== propertyAccess) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const baseExpression = propertyAccess.getExpression();
|
|
129
|
+
const baseText = baseExpression.getText();
|
|
130
|
+
const hasZObjectInChain = baseExpression
|
|
131
|
+
.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)
|
|
132
|
+
.some((e) => e.getName() === "object" && e.getExpression().getText() === zodName);
|
|
133
|
+
if (hasZObjectInChain) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (baseExpression.isKind(SyntaxKind.CallExpression) &&
|
|
137
|
+
baseExpression
|
|
138
|
+
.getExpression()
|
|
139
|
+
.isKind(SyntaxKind.PropertyAccessExpression)) {
|
|
140
|
+
const propAccess = baseExpression.getExpression();
|
|
141
|
+
if (propAccess.isKind(SyntaxKind.PropertyAccessExpression) &&
|
|
142
|
+
propAccess.getName() === "object" &&
|
|
143
|
+
propAccess.getExpression().getText() === zodName) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// This is a schema reference with .strict(), etc.
|
|
148
|
+
// Transform it to `z.strictObject(schemaRef.shape)`
|
|
149
|
+
const newName = methodMappings[methodName];
|
|
150
|
+
parent.replaceWithText(`${zodName}.${newName}(${baseText}.shape)`);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
101
153
|
function convertZObjectMergeToExtend(node) {
|
|
102
154
|
node
|
|
103
155
|
.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)
|
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
import { SyntaxKind, } from "ts-morph";
|
|
2
2
|
import { getDirectDescendantsOfKind, isZodReference, } from "./zod-node.js";
|
|
3
|
+
export function convertSetErrorMapToConfig(sourceFile, zodName) {
|
|
4
|
+
sourceFile
|
|
5
|
+
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
6
|
+
.filter((expression) => {
|
|
7
|
+
const callee = expression.getExpression();
|
|
8
|
+
if (!callee.isKind(SyntaxKind.PropertyAccessExpression)) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const objectName = callee.getExpression().getText();
|
|
12
|
+
const methodName = callee.getName();
|
|
13
|
+
return objectName === zodName && methodName === "setErrorMap";
|
|
14
|
+
})
|
|
15
|
+
.forEach((expression) => {
|
|
16
|
+
const argument = expression.getArguments()[0];
|
|
17
|
+
if (!argument) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
expression.replaceWithText(`${zodName}.config({ customError: ${argument.getText()} })`);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export function convertZodErrorMapType(sourceFile, zodName) {
|
|
24
|
+
sourceFile
|
|
25
|
+
.getDescendantsOfKind(SyntaxKind.TypeReference)
|
|
26
|
+
.filter((typeRef) => {
|
|
27
|
+
const typeName = typeRef.getTypeName();
|
|
28
|
+
if (!typeName.isKind(SyntaxKind.QualifiedName)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const left = typeName.getLeft().getText();
|
|
32
|
+
const right = typeName.getRight().getText();
|
|
33
|
+
return left === zodName && right === "ZodErrorMap";
|
|
34
|
+
})
|
|
35
|
+
.forEach((typeRef) => {
|
|
36
|
+
typeRef.replaceWithText(`${zodName}.core.$ZodErrorMap`);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
3
39
|
export function convertErrorMapToErrorFunction(node) {
|
|
4
40
|
// Find all errorMap properties
|
|
5
41
|
getDirectDescendantsOfKind(node, SyntaxKind.Identifier)
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import * as fs from "node:fs";
|
|
|
5
5
|
import * as path from "node:path";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
import { Project } from "ts-morph";
|
|
8
|
-
import z from "zod";
|
|
8
|
+
import { z } from "zod";
|
|
9
9
|
import { migrateZodV3ToV4 } from "./migrate.js";
|
|
10
10
|
const execAsync = promisify(exec);
|
|
11
11
|
intro(`🏗️ Let's migrate Zod from v3 to v4`);
|
package/dist/migrate.js
CHANGED
|
@@ -3,7 +3,7 @@ import { findRootExpression } from "./ast.js";
|
|
|
3
3
|
import { AstroZodModuleSpecifiers, collectDerivedZodSchemaReferences, collectZodImportDeclarations, collectZodReferences, getZodName, } from "./collect-imports.js";
|
|
4
4
|
import { convertAstroDeprecatedZodImports } from "./convert-astro-imports.js";
|
|
5
5
|
import { convertZArrayPatternsToTopLevelApi, convertZCoercePatternsToTopLevelApi, convertZFunctionPatternsToTopLevelApi, convertZNumberPatternsToZInt, convertZObjectPatternsToTopLevelApi, convertZRecordPatternsToTopLevelApi, convertZStringPatternsToTopLevelApi, } from "./convert-name-to-top-level-api.js";
|
|
6
|
-
import { convertDeprecatedErrorKeysToErrorFunction, convertErrorMapToErrorFunction, convertMessageKeyToError, convertZodErrorAddIssueToDirectPushes, convertZodErrorToTreeifyError, } from "./convert-zod-errors.js";
|
|
6
|
+
import { convertDeprecatedErrorKeysToErrorFunction, convertErrorMapToErrorFunction, convertMessageKeyToError, convertSetErrorMapToConfig, convertZodErrorAddIssueToDirectPushes, convertZodErrorMapType, convertZodErrorToTreeifyError, } from "./convert-zod-errors.js";
|
|
7
7
|
import { replaceDeletedTypes } from "./replace-deleted-types.js";
|
|
8
8
|
import { isZodNode } from "./zod-node.js";
|
|
9
9
|
export function migrateZodV3ToV4(sourceFile, options = {}) {
|
|
@@ -56,6 +56,8 @@ export function migrateZodV3ToV4(sourceFile, options = {}) {
|
|
|
56
56
|
});
|
|
57
57
|
convertZodErrorToTreeifyError(sourceFile, zodName);
|
|
58
58
|
convertZodErrorAddIssueToDirectPushes(sourceFile, zodName);
|
|
59
|
+
convertSetErrorMapToConfig(sourceFile, zodName);
|
|
60
|
+
convertZodErrorMapType(sourceFile, zodName);
|
|
59
61
|
renameZSchemaEnumToLowercase(sourceFile, zodName);
|
|
60
62
|
convertAstroDeprecatedZodImports(importDeclarations);
|
|
61
63
|
return sourceFile.getFullText();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod-v3-to-v4",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"description": "Migrate Zod from v3 to v4",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zod",
|
|
@@ -44,22 +44,22 @@
|
|
|
44
44
|
"*": "prettier --ignore-unknown --write"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@clack/prompts": "1.0.0-alpha.
|
|
48
|
-
"ts-morph": "26.0.0"
|
|
47
|
+
"@clack/prompts": "1.0.0-alpha.9",
|
|
48
|
+
"ts-morph": "26.0.0",
|
|
49
|
+
"zod": "3.25.12"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
|
-
"@types/node": "
|
|
52
|
+
"@types/node": "25.0.3",
|
|
52
53
|
"husky": "9.1.7",
|
|
53
|
-
"lint-staged": "16.
|
|
54
|
+
"lint-staged": "16.2.7",
|
|
54
55
|
"prettier": "3.5.3",
|
|
55
56
|
"prettier-plugin-curly": "0.3.1",
|
|
56
57
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
57
58
|
"prettier-plugin-packagejson": "2.5.10",
|
|
58
|
-
"prettier-plugin-sh": "0.
|
|
59
|
+
"prettier-plugin-sh": "0.17.4",
|
|
59
60
|
"rimraf": "6.0.1",
|
|
60
|
-
"typescript": "5.
|
|
61
|
-
"vitest": "3.1.4"
|
|
62
|
-
"zod": "3.25.12"
|
|
61
|
+
"typescript": "5.9.3",
|
|
62
|
+
"vitest": "3.1.4"
|
|
63
63
|
},
|
|
64
64
|
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
|
|
65
65
|
}
|