zod-v3-to-v4 1.12.1 → 1.13.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 CHANGED
@@ -135,6 +135,7 @@ pnpm playground:interactive
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
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
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>
138
+ <td align="center" valign="top" width="14.28%"><a href="http://www.robertcooper.me"><img src="https://avatars.githubusercontent.com/u/16786990?v=4?s=100" width="100px;" alt="Robert Cooper"/><br /><sub><b>Robert Cooper</b></sub></a><br /><a href="https://github.com/nicoespeon/zod-v3-to-v4/issues?q=author%3Arobertcoopercode" title="Bug reports">🐛</a></td>
138
139
  </tr>
139
140
  </tbody>
140
141
  <tfoot>
@@ -25,16 +25,38 @@ export function getZodImport(importDeclaration) {
25
25
  ?.getNamedImports()
26
26
  .find((namedImport) => namedImport.getName() === "z");
27
27
  }
28
- export function collectZodReferences(importDeclarations) {
29
- return importDeclarations.flatMap((importDeclaration) => importDeclaration.getNamedImports().flatMap((namedImport) => {
30
- const namedNode = namedImport.getAliasNode() ?? namedImport.getNameNode();
31
- if (!namedNode.isKind(SyntaxKind.Identifier)) {
32
- return [];
28
+ export function collectZodReferences(sourceFile, importDeclarations) {
29
+ const identifierMap = buildIdentifierMap(sourceFile);
30
+ return {
31
+ zodReferences: importDeclarations.flatMap((importDeclaration) => importDeclaration.getNamedImports().flatMap((namedImport) => {
32
+ const namedNode = namedImport.getAliasNode() ?? namedImport.getNameNode();
33
+ if (!namedNode.isKind(SyntaxKind.Identifier)) {
34
+ return [];
35
+ }
36
+ const name = namedNode.getText();
37
+ const allReferences = identifierMap.get(name) ?? [];
38
+ return allReferences.filter((node) => node !== namedNode);
39
+ })),
40
+ identifierMap,
41
+ };
42
+ }
43
+ /**
44
+ * Build a map of identifier name -> all nodes with that name.
45
+ * This allows O(1) lookups instead of expensive findReferencesAsNodes() calls.
46
+ */
47
+ function buildIdentifierMap(sourceFile) {
48
+ const identifierMap = new Map();
49
+ for (const identifier of sourceFile.getDescendantsOfKind(SyntaxKind.Identifier)) {
50
+ const name = identifier.getText();
51
+ const existing = identifierMap.get(name);
52
+ if (existing) {
53
+ existing.push(identifier);
54
+ }
55
+ else {
56
+ identifierMap.set(name, [identifier]);
33
57
  }
34
- return namedNode
35
- .findReferencesAsNodes()
36
- .filter((node) => node !== namedNode);
37
- }));
58
+ }
59
+ return identifierMap;
38
60
  }
39
61
  /**
40
62
  * Collect references to variables that are derived from Zod schemas.
@@ -47,7 +69,7 @@ export function collectZodReferences(importDeclarations) {
47
69
  * This function will return references to `baseSchema` (like the one used
48
70
  * in `constrainedSchema`), so we can also migrate those.
49
71
  */
50
- export function collectDerivedZodSchemaReferences(zodReferences) {
72
+ export function collectDerivedZodSchemaReferences(zodReferences, identifierMap) {
51
73
  const derivedReferences = [];
52
74
  const visited = new Set();
53
75
  function collectFromReferences(refs) {
@@ -67,11 +89,9 @@ export function collectDerivedZodSchemaReferences(zodReferences) {
67
89
  if (!nameNode.isKind(SyntaxKind.Identifier)) {
68
90
  continue;
69
91
  }
70
- // Find all references to this variable (excluding the declaration itself)
71
- const variableReferences = nameNode
72
- .findReferencesAsNodes()
73
- .filter((node) => node !== nameNode)
74
- .filter((node) => node.isKind(SyntaxKind.Identifier));
92
+ // Find all references to this variable
93
+ const allReferences = identifierMap.get(variableName) ?? [];
94
+ const variableReferences = allReferences.filter((node) => node !== nameNode);
75
95
  derivedReferences.push(...variableReferences);
76
96
  // Recursively collect references from these derived schemas
77
97
  collectFromReferences(variableReferences);
package/dist/migrate.js CHANGED
@@ -25,8 +25,8 @@ export function migrateZodV3ToV4(sourceFile, options = {}) {
25
25
  }
26
26
  });
27
27
  // Collect references before modifying imports
28
- const zodReferences = collectZodReferences(importDeclarations);
29
- const derivedReferences = collectDerivedZodSchemaReferences(zodReferences);
28
+ const { zodReferences, identifierMap } = collectZodReferences(sourceFile, importDeclarations);
29
+ const derivedReferences = collectDerivedZodSchemaReferences(zodReferences, identifierMap);
30
30
  replaceDeletedTypes(importDeclarations, zodReferences);
31
31
  [...zodReferences, ...derivedReferences].forEach((node) => {
32
32
  if (node.wasForgotten()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-v3-to-v4",
3
- "version": "1.12.1",
3
+ "version": "1.13.0",
4
4
  "description": "Migrate Zod from v3 to v4",
5
5
  "keywords": [
6
6
  "zod",